Merge pull request #1959 from elemoine/feature-box-selection

Add a feature box selection example
This commit is contained in:
Éric Lemoine
2014-09-17 15:02:23 +02:00
18 changed files with 702 additions and 25 deletions

View File

@@ -159,8 +159,7 @@ ol.extent.closestSquaredDistanceXY = function(extent, x, y) {
* @api stable
*/
ol.extent.containsCoordinate = function(extent, coordinate) {
return extent[0] <= coordinate[0] && coordinate[0] <= extent[2] &&
extent[1] <= coordinate[1] && coordinate[1] <= extent[3];
return ol.extent.containsXY(extent, coordinate[0], coordinate[1]);
};
@@ -178,6 +177,20 @@ ol.extent.containsExtent = function(extent1, extent2) {
};
/**
* Checks if the passed coordinate is contained or on the edge of the extent.
*
* @param {ol.Extent} extent Extent.
* @param {number} x X coordinate.
* @param {number} y Y coordinate.
* @return {boolean} Contains.
* @api stable
*/
ol.extent.containsXY = function(extent, x, y) {
return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];
};
/**
* Get the relationship between a coordinate and extent.
* @param {ol.Extent} extent The extent.
@@ -426,6 +439,38 @@ ol.extent.extendXY = function(extent, x, y) {
};
/**
* This function calls `callback` for each corner of the extent. If the
* callback returns a truthy value the function returns that value
* immediately. Otherwise the function returns `false`.
* @param {ol.Extent} extent Extent.
* @param {function(this:T, ol.Coordinate): S} callback Callback.
* @param {T=} opt_this Value to use as `this` when executing `callback`.
* @return {S|boolean} Value.
* @template S, T
*/
ol.extent.forEachCorner = function(extent, callback, opt_this) {
var val;
val = callback.call(opt_this, ol.extent.getBottomLeft(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getBottomRight(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getTopRight(extent));
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getBottomRight(extent));
if (val) {
return val;
}
return false;
};
/**
* @param {ol.Extent} extent Extent.
* @return {number} Area.
@@ -729,7 +774,7 @@ ol.extent.scaleFromCenter = function(extent, value) {
* @param {ol.Coordinate} end Segment end coordinate.
* @return {boolean} The segment intersects the extent.
*/
ol.extent.segmentIntersects = function(extent, start, end) {
ol.extent.intersectsSegment = function(extent, start, end) {
var intersects = false;
var startRel = ol.extent.coordinateRelationship(extent, start);
var endRel = ol.extent.coordinateRelationship(extent, end);

View File

@@ -1,6 +1,29 @@
goog.provide('ol.geom.flat.contains');
goog.require('goog.asserts');
goog.require('ol.extent');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} Contains extent.
*/
ol.geom.flat.contains.linearRingContainsExtent =
function(flatCoordinates, offset, end, stride, extent) {
var outside = ol.extent.forEachCorner(extent,
/**
* @param {ol.Coordinate} coordinate Coordinate.
*/
function(coordinate) {
return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates,
offset, end, stride, coordinate[0], coordinate[1]);
});
return !outside;
};
/**

View File

@@ -0,0 +1,154 @@
goog.provide('ol.geom.flat.intersectsextent');
goog.require('goog.asserts');
goog.require('ol.extent');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.segments');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.lineString =
function(flatCoordinates, offset, end, stride, extent) {
var coordinatesExtent = ol.extent.extendFlatCoordinates(
ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
if (!ol.extent.intersects(extent, coordinatesExtent)) {
return false;
}
if (ol.extent.containsExtent(extent, coordinatesExtent)) {
return true;
}
if (coordinatesExtent[0] >= extent[0] &&
coordinatesExtent[2] <= extent[2]) {
return true;
}
if (coordinatesExtent[1] >= extent[1] &&
coordinatesExtent[3] <= extent[3]) {
return true;
}
return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
/**
* @param {ol.Coordinate} point1 Start point.
* @param {ol.Coordinate} point2 End point.
* @return {boolean} `true` if the segment and the extent intersect,
* `false` otherwise.
*/
function(point1, point2) {
return ol.extent.intersectsSegment(extent, point1, point2);
});
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.lineStrings =
function(flatCoordinates, offset, ends, stride, extent) {
var i, ii;
for (i = 0, ii = ends.length; i < ii; ++i) {
if (ol.geom.flat.intersectsextent.lineString(
flatCoordinates, offset, ends[i], stride, extent)) {
return true;
}
offset = ends[i];
}
return false;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRing =
function(flatCoordinates, offset, end, stride, extent) {
if (ol.geom.flat.intersectsextent.lineString(
flatCoordinates, offset, end, stride, extent)) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[0], extent[1])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[0], extent[3])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[2], extent[1])) {
return true;
}
if (ol.geom.flat.contains.linearRingContainsXY(
flatCoordinates, offset, end, stride, extent[2], extent[3])) {
return true;
}
return false;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<number>} ends Ends.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRings =
function(flatCoordinates, offset, ends, stride, extent) {
goog.asserts.assert(ends.length > 0);
if (!ol.geom.flat.intersectsextent.linearRing(
flatCoordinates, offset, ends[0], stride, extent)) {
return false;
}
if (ends.length === 1) {
return true;
}
var i, ii;
for (i = 1, ii = ends.length; i < ii; ++i) {
if (ol.geom.flat.contains.linearRingContainsExtent(
flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
return false;
}
}
return true;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {Array.<Array.<number>>} endss Endss.
* @param {number} stride Stride.
* @param {ol.Extent} extent Extent.
* @return {boolean} True if the geometry and the extent intersect.
*/
ol.geom.flat.intersectsextent.linearRingss =
function(flatCoordinates, offset, endss, stride, extent) {
goog.asserts.assert(endss.length > 0);
var i, ii;
for (i = 0, ii = endss.length; i < ii; ++i) {
var ends = endss[i];
if (ol.geom.flat.intersectsextent.linearRings(
flatCoordinates, offset, ends, stride, extent)) {
return true;
}
offset = ends[ends.length - 1];
}
return false;
};

View File

@@ -0,0 +1,33 @@
goog.provide('ol.geom.flat.segments');
/**
* This function calls `callback` for each segment of the flat coordinates
* array. If the callback returns a truthy value the function returns that
* value immediately. Otherwise the function returns `false`.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {function(ol.Coordinate, ol.Coordinate): T} callback Function
* called for each segment.
* @return {T|boolean} Value.
* @template T
*/
ol.geom.flat.segments.forEach =
function(flatCoordinates, offset, end, stride, callback) {
var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];
var point2 = [];
var ret;
for (; (offset + stride) < end; offset += stride) {
point2[0] = flatCoordinates[offset + stride];
point2[1] = flatCoordinates[offset + stride + 1];
ret = callback(point1, point2);
if (ret) {
return ret;
}
point1[0] = point2[0];
point1[1] = point2[1];
}
return false;
};

View File

@@ -184,6 +184,16 @@ ol.geom.Geometry.prototype.getType = goog.abstractMethod;
ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;
/**
* Test if the geometry and the passed extent intersect.
* @param {ol.Extent} extent Extent.
* @return {boolean} `true` if the geometry and the extent intersect.
* @function
* @api
*/
ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod;
/**
* Transform each coordinate of the geometry from one coordinate reference
* system to another. The geometry is modified in place.

View File

@@ -218,6 +218,22 @@ ol.geom.GeometryCollection.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) {
var geometries = this.geometries_;
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].intersectsExtent(extent)) {
return true;
}
}
return false;
};
/**
* @return {boolean} Is empty.
*/

View File

@@ -9,6 +9,7 @@ goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.length');
goog.require('ol.geom.flat.simplify');
@@ -190,6 +191,17 @@ ol.geom.LineString.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.LineString.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.lineString(
this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
extent);
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -10,6 +10,7 @@ goog.require('ol.geom.flat.closest');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interpolate');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.simplify');
@@ -244,6 +245,16 @@ ol.geom.MultiLineString.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.lineStrings(
this.flatCoordinates, 0, this.ends_, this.stride, extent);
};
/**
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -142,6 +142,25 @@ ol.geom.MultiPoint.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) {
var flatCoordinates = this.flatCoordinates;
var stride = this.stride;
var i, ii, x, y;
for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
x = flatCoordinates[i];
y = flatCoordinates[i + 1];
if (ol.extent.containsXY(extent, x, y)) {
return true;
}
}
return false;
};
/**
* @param {Array.<ol.Coordinate>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -14,6 +14,7 @@ goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interiorpoint');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.orient');
goog.require('ol.geom.flat.simplify');
@@ -315,6 +316,16 @@ ol.geom.MultiPolygon.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.linearRingss(
this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
};
/**
* @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -93,6 +93,16 @@ ol.geom.Point.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.Point.prototype.intersectsExtent = function(extent) {
return ol.extent.containsXY(extent,
this.flatCoordinates[0], this.flatCoordinates[1]);
};
/**
* @param {ol.Coordinate} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -14,6 +14,7 @@ goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.deflate');
goog.require('ol.geom.flat.inflate');
goog.require('ol.geom.flat.interiorpoint');
goog.require('ol.geom.flat.intersectsextent');
goog.require('ol.geom.flat.orient');
goog.require('ol.geom.flat.simplify');
@@ -296,6 +297,16 @@ ol.geom.Polygon.prototype.getType = function() {
};
/**
* @inheritDoc
* @api
*/
ol.geom.Polygon.prototype.intersectsExtent = function(extent) {
return ol.geom.flat.intersectsextent.linearRings(
this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
};
/**
* @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.

View File

@@ -247,6 +247,39 @@ ol.source.Vector.prototype.forEachFeatureInExtentAtResolution =
};
/**
* This function executes the `callback` function once for each feature
* intersecting the `extent` until `callback` returns a truthy value. When
* `callback` returns a truthy value the function immediately returns that
* value. Otherwise the function returns `undefined`.
* @param {ol.Extent} extent Extent.
* @param {function(this: T, ol.Feature): S} f Callback.
* @param {T=} opt_this The object to use as `this` in `f`.
* @return {S|undefined}
* @template T,S
* @api
*/
ol.source.Vector.prototype.forEachFeatureIntersectingExtent =
function(extent, f, opt_this) {
return this.forEachFeatureInExtent(extent,
/**
* @param {ol.Feature} feature Feature.
* @return {S|undefined}
* @template S
*/
function(feature) {
var geometry = feature.getGeometry();
goog.asserts.assert(goog.isDefAndNotNull(geometry));
if (geometry.intersectsExtent(extent)) {
var result = f.call(opt_this, feature);
if (result) {
return result;
}
}
});
};
/**
* @return {Array.<ol.Feature>} Features.
* @api stable