Implement forEachLayerAtPixel for webgl
This commit is contained in:
@@ -7,10 +7,13 @@ goog.require('ol.Coordinate');
|
|||||||
goog.require('ol.Extent');
|
goog.require('ol.Extent');
|
||||||
goog.require('ol.ImageBase');
|
goog.require('ol.ImageBase');
|
||||||
goog.require('ol.ViewHint');
|
goog.require('ol.ViewHint');
|
||||||
|
goog.require('ol.dom');
|
||||||
goog.require('ol.extent');
|
goog.require('ol.extent');
|
||||||
goog.require('ol.layer.Image');
|
goog.require('ol.layer.Image');
|
||||||
goog.require('ol.proj');
|
goog.require('ol.proj');
|
||||||
goog.require('ol.renderer.webgl.Layer');
|
goog.require('ol.renderer.webgl.Layer');
|
||||||
|
goog.require('ol.source.ImageVector');
|
||||||
|
goog.require('ol.vec.Mat4');
|
||||||
goog.require('ol.webgl.Context');
|
goog.require('ol.webgl.Context');
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +35,18 @@ ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {
|
|||||||
*/
|
*/
|
||||||
this.image_ = null;
|
this.image_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {CanvasRenderingContext2D}
|
||||||
|
*/
|
||||||
|
this.hitCanvasContext_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {?goog.vec.Mat4.Number}
|
||||||
|
*/
|
||||||
|
this.hitTransformationMatrix_ = null;
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer);
|
goog.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer);
|
||||||
|
|
||||||
@@ -143,6 +158,7 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
|
|||||||
|
|
||||||
this.updateProjectionMatrix_(canvas.width, canvas.height,
|
this.updateProjectionMatrix_(canvas.width, canvas.height,
|
||||||
viewCenter, viewResolution, viewRotation, image.getExtent());
|
viewCenter, viewResolution, viewRotation, image.getExtent());
|
||||||
|
this.hitTransformationMatrix_ = null;
|
||||||
|
|
||||||
// Translate and scale to flip the Y coord.
|
// Translate and scale to flip the Y coord.
|
||||||
var texCoordMatrix = this.texCoordMatrix;
|
var texCoordMatrix = this.texCoordMatrix;
|
||||||
@@ -204,3 +220,103 @@ ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtPixel =
|
|||||||
coordinate, frameState, goog.functions.TRUE, this);
|
coordinate, frameState, goog.functions.TRUE, this);
|
||||||
return goog.isDef(hasFeature);
|
return goog.isDef(hasFeature);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel =
|
||||||
|
function(coordinate, frameState, callback, thisArg) {
|
||||||
|
if (goog.isNull(this.image_) || goog.isNull(this.image_.getImage())) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
|
||||||
|
// for ImageVector sources use the original hit-detection logic,
|
||||||
|
// so that for example also transparent polygons are detected
|
||||||
|
var hasFeature = this.forEachFeatureAtPixel(
|
||||||
|
coordinate, frameState, goog.functions.TRUE, this);
|
||||||
|
|
||||||
|
if (hasFeature) {
|
||||||
|
return callback.call(thisArg, this.getLayer());
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var imageSize =
|
||||||
|
[this.image_.getImage().width, this.image_.getImage().height];
|
||||||
|
|
||||||
|
if (goog.isNull(this.hitTransformationMatrix_)) {
|
||||||
|
this.hitTransformationMatrix_ = this.getHitTransformationMatrix_(
|
||||||
|
frameState.size, imageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pixelOnMap = this.getMap().getPixelFromCoordinate(coordinate);
|
||||||
|
var pixelOnFrameBuffer = [0, 0];
|
||||||
|
ol.vec.Mat4.multVec2(
|
||||||
|
this.hitTransformationMatrix_, pixelOnMap, pixelOnFrameBuffer);
|
||||||
|
|
||||||
|
if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] ||
|
||||||
|
pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) {
|
||||||
|
// outside the image, no need to check
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goog.isNull(this.hitCanvasContext_)) {
|
||||||
|
this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hitCanvasContext_.clearRect(0, 0, 1, 1);
|
||||||
|
this.hitCanvasContext_.drawImage(this.image_.getImage(),
|
||||||
|
pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1);
|
||||||
|
|
||||||
|
var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;
|
||||||
|
if (imageData[3] > 0) {
|
||||||
|
return callback.call(thisArg, this.getLayer());
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The transformation matrix to get the pixel on the image for a
|
||||||
|
* pixel on the map.
|
||||||
|
* @param {ol.Size} mapSize
|
||||||
|
* @param {ol.Size} imageSize
|
||||||
|
* @return {goog.vec.Mat4.Number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ =
|
||||||
|
function(mapSize, imageSize) {
|
||||||
|
// the first matrix takes a map pixel, flips the y-axis and scales to
|
||||||
|
// a range between -1 ... 1
|
||||||
|
var mapCoordMatrix = goog.vec.Mat4.createNumber();
|
||||||
|
goog.vec.Mat4.makeIdentity(mapCoordMatrix);
|
||||||
|
goog.vec.Mat4.translate(mapCoordMatrix, -1, -1, 0);
|
||||||
|
goog.vec.Mat4.scale(mapCoordMatrix, 2 / mapSize[0], 2 / mapSize[1], 1);
|
||||||
|
goog.vec.Mat4.translate(mapCoordMatrix, 0, mapSize[1], 0);
|
||||||
|
goog.vec.Mat4.scale(mapCoordMatrix, 1, -1, 1);
|
||||||
|
|
||||||
|
// the second matrix is the inverse of the projection matrix used in the
|
||||||
|
// shader for drawing
|
||||||
|
var projectionMatrixInv = goog.vec.Mat4.createNumber();
|
||||||
|
goog.vec.Mat4.invert(this.projectionMatrix, projectionMatrixInv);
|
||||||
|
|
||||||
|
// the third matrix scales to the image dimensions and flips the y-axis again
|
||||||
|
var imageCoordMatrix = goog.vec.Mat4.createNumber();
|
||||||
|
goog.vec.Mat4.makeIdentity(imageCoordMatrix);
|
||||||
|
goog.vec.Mat4.translate(imageCoordMatrix, 0, imageSize[1], 0);
|
||||||
|
goog.vec.Mat4.scale(imageCoordMatrix, 1, -1, 1);
|
||||||
|
goog.vec.Mat4.scale(imageCoordMatrix, imageSize[0] / 2, imageSize[1] / 2, 1);
|
||||||
|
goog.vec.Mat4.translate(imageCoordMatrix, 1, 1, 0);
|
||||||
|
|
||||||
|
var transformMatrix = goog.vec.Mat4.createNumber();
|
||||||
|
goog.vec.Mat4.multMat(
|
||||||
|
imageCoordMatrix, projectionMatrixInv, transformMatrix);
|
||||||
|
goog.vec.Mat4.multMat(
|
||||||
|
transformMatrix, mapCoordMatrix, transformMatrix);
|
||||||
|
|
||||||
|
return transformMatrix;
|
||||||
|
};
|
||||||
|
|||||||
@@ -648,6 +648,57 @@ ol.renderer.webgl.Map.prototype.hasFeatureAtPixel =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.renderer.webgl.Map.prototype.forEachLayerAtPixel =
|
||||||
|
function(coordinate, frameState, callback, thisArg,
|
||||||
|
layerFilter, thisArg2) {
|
||||||
|
if (this.getGL().isContextLost()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = this.getContext();
|
||||||
|
var viewState = frameState.viewState;
|
||||||
|
var result;
|
||||||
|
|
||||||
|
// do the hit-detection for the overlays first
|
||||||
|
if (!goog.isNull(this.replayGroup)) {
|
||||||
|
// use default color values
|
||||||
|
var d = ol.renderer.webgl.Map.DEFAULT_COLOR_VALUES_;
|
||||||
|
|
||||||
|
var hasFeature = this.replayGroup.hasFeatureAtPixel(context,
|
||||||
|
viewState.center, viewState.resolution, viewState.rotation,
|
||||||
|
frameState.size, frameState.pixelRatio,
|
||||||
|
d.opacity, d.brightness, d.contrast, d.hue, d.saturation, {},
|
||||||
|
coordinate);
|
||||||
|
if (hasFeature) {
|
||||||
|
result = callback.call(thisArg, null);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var layerStates = frameState.layerStatesArray;
|
||||||
|
var numLayers = layerStates.length;
|
||||||
|
var i;
|
||||||
|
for (i = numLayers - 1; i >= 0; --i) {
|
||||||
|
var layerState = layerStates[i];
|
||||||
|
var layer = layerState.layer;
|
||||||
|
if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
|
||||||
|
layerFilter.call(thisArg, layer)) {
|
||||||
|
var layerRenderer = this.getLayerRenderer(layer);
|
||||||
|
result = layerRenderer.forEachLayerAtPixel(
|
||||||
|
coordinate, frameState, callback, thisArg);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @const
|
* @const
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ goog.require('ol.math');
|
|||||||
goog.require('ol.renderer.webgl.Layer');
|
goog.require('ol.renderer.webgl.Layer');
|
||||||
goog.require('ol.renderer.webgl.tilelayer.shader');
|
goog.require('ol.renderer.webgl.tilelayer.shader');
|
||||||
goog.require('ol.tilecoord');
|
goog.require('ol.tilecoord');
|
||||||
|
goog.require('ol.vec.Mat4');
|
||||||
goog.require('ol.webgl.Buffer');
|
goog.require('ol.webgl.Buffer');
|
||||||
|
|
||||||
|
|
||||||
@@ -326,3 +327,39 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame =
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel =
|
||||||
|
function(coordinate, frameState, callback, thisArg) {
|
||||||
|
if (goog.isNull(this.framebuffer)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
var mapSize = this.getMap().getSize();
|
||||||
|
|
||||||
|
var pixelOnMap = this.getMap().getPixelFromCoordinate(coordinate);
|
||||||
|
var pixelOnMapScaled = [
|
||||||
|
pixelOnMap[0] / mapSize[0],
|
||||||
|
(mapSize[1] - pixelOnMap[1]) / mapSize[1]];
|
||||||
|
|
||||||
|
var pixelOnFrameBufferScaled = [0, 0];
|
||||||
|
ol.vec.Mat4.multVec2(
|
||||||
|
this.texCoordMatrix, pixelOnMapScaled, pixelOnFrameBufferScaled);
|
||||||
|
var pixelOnFrameBuffer = [
|
||||||
|
pixelOnFrameBufferScaled[0] * this.framebufferDimension,
|
||||||
|
pixelOnFrameBufferScaled[1] * this.framebufferDimension];
|
||||||
|
|
||||||
|
var gl = this.getWebGLMapRenderer().getContext().getGL();
|
||||||
|
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
|
||||||
|
var imageData = new Uint8Array(4);
|
||||||
|
gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1,
|
||||||
|
gl.RGBA, gl.UNSIGNED_BYTE, imageData);
|
||||||
|
|
||||||
|
if (imageData[3] > 0) {
|
||||||
|
return callback.call(thisArg, this.getLayer());
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -162,6 +162,21 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtPixel =
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel =
|
||||||
|
function(coordinate, frameState, callback, thisArg) {
|
||||||
|
var hasFeature = this.hasFeatureAtPixel(coordinate, frameState);
|
||||||
|
|
||||||
|
if (hasFeature) {
|
||||||
|
return callback.call(thisArg, this.getLayer());
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle changes in image style state.
|
* Handle changes in image style state.
|
||||||
* @param {goog.events.Event} event Image style change event.
|
* @param {goog.events.Event} event Image style change event.
|
||||||
|
|||||||
Reference in New Issue
Block a user