Implement forEachLayerAtPixel for webgl

This commit is contained in:
tsauerwein
2015-01-23 17:35:07 +01:00
parent 6cc5bd466d
commit dce4210a5b
4 changed files with 219 additions and 0 deletions
@@ -7,10 +7,13 @@ goog.require('ol.Coordinate');
goog.require('ol.Extent');
goog.require('ol.ImageBase');
goog.require('ol.ViewHint');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.proj');
goog.require('ol.renderer.webgl.Layer');
goog.require('ol.source.ImageVector');
goog.require('ol.vec.Mat4');
goog.require('ol.webgl.Context');
@@ -32,6 +35,18 @@ ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {
*/
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);
@@ -143,6 +158,7 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
this.updateProjectionMatrix_(canvas.width, canvas.height,
viewCenter, viewResolution, viewRotation, image.getExtent());
this.hitTransformationMatrix_ = null;
// Translate and scale to flip the Y coord.
var texCoordMatrix = this.texCoordMatrix;
@@ -204,3 +220,103 @@ ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtPixel =
coordinate, frameState, goog.functions.TRUE, this);
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;
};