diff --git a/examples/box-selection.html b/examples/box-selection.html new file mode 100644 index 0000000000..78aa899294 --- /dev/null +++ b/examples/box-selection.html @@ -0,0 +1,59 @@ + + + + + + + + + + + Box selection example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Box selection example

+

Using a DragBox interaction to select features.

+
+

This example shows how to use a DragBox interaction to select features. Selected features are added + to the feature overlay of a select interaction (ol.interaction.Select) for highlighting.

+

Use SHIFT+drag to draw boxes.

+

See the box-selection.js source to see how this is done.

+
+
DragBox, feature, selection, box
+
+
+
+   +
+
+ +
+ +
+ + + + + + + diff --git a/examples/box-selection.js b/examples/box-selection.js new file mode 100644 index 0000000000..09db36e0b6 --- /dev/null +++ b/examples/box-selection.js @@ -0,0 +1,81 @@ +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.events.condition'); +goog.require('ol.interaction'); +goog.require('ol.interaction.DragBox'); +goog.require('ol.interaction.Select'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.GeoJSON'); +goog.require('ol.source.OSM'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + + +var vectorSource = new ol.source.GeoJSON({ + projection: 'EPSG:3857', + url: 'data/geojson/countries.geojson' +}); + + +var map = new ol.Map({ + layers: [ + new ol.layer.Tile({ + source: new ol.source.OSM() + }), + new ol.layer.Vector({ + source: vectorSource + }) + ], + renderer: 'canvas', + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 2 + }) +}); + +// a normal select interaction to handle click +var select = new ol.interaction.Select(); +map.addInteraction(select); + +var selectedFeatures = select.getFeatures(); + +// a DragBox interaction used to select features by drawing boxes +var dragBox = new ol.interaction.DragBox({ + condition: ol.events.condition.shiftKeyOnly, + style: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: [0, 0, 255, 1] + }) + }) +}); + +map.addInteraction(dragBox); + +var infoBox = document.getElementById('info'); + +dragBox.on('boxend', function(e) { + // features that intersect the box are added to the collection of + // selected features, and their names are displayed in the "info" + // div + var info = []; + var extent = dragBox.getGeometry().getExtent(); + vectorSource.forEachFeatureIntersectingExtent(extent, function(feature) { + selectedFeatures.push(feature); + info.push(feature.get('name')); + }); + if (info.length > 0) { + infoBox.innerHTML = info.join(', '); + } +}); + +// clear selection when drawing a new box and when clicking on the map +dragBox.on('boxstart', function(e) { + selectedFeatures.clear(); + infoBox.innerHTML = ' '; +}); +map.on('click', function() { + selectedFeatures.clear(); + infoBox.innerHTML = ' '; +}); diff --git a/src/ol/extent.js b/src/ol/extent.js index 97f52c2611..5209ac9313 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -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); diff --git a/src/ol/geom/flat/containsflatgeom.js b/src/ol/geom/flat/containsflatgeom.js index 5b5c93aacb..18379450ac 100644 --- a/src/ol/geom/flat/containsflatgeom.js +++ b/src/ol/geom/flat/containsflatgeom.js @@ -1,6 +1,29 @@ goog.provide('ol.geom.flat.contains'); goog.require('goog.asserts'); +goog.require('ol.extent'); + + +/** + * @param {Array.} 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; +}; /** diff --git a/src/ol/geom/flat/intersectsextent.js b/src/ol/geom/flat/intersectsextent.js new file mode 100644 index 0000000000..a86ca4f2ff --- /dev/null +++ b/src/ol/geom/flat/intersectsextent.js @@ -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.} 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.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.} 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.} 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.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.} 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.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.>} 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; +}; diff --git a/src/ol/geom/flat/segmentsflatgeom.js b/src/ol/geom/flat/segmentsflatgeom.js new file mode 100644 index 0000000000..8c6aac24fd --- /dev/null +++ b/src/ol/geom/flat/segmentsflatgeom.js @@ -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.} 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; +}; diff --git a/src/ol/geom/geometry.js b/src/ol/geom/geometry.js index fd78792fcd..90d04778d2 100644 --- a/src/ol/geom/geometry.js +++ b/src/ol/geom/geometry.js @@ -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. diff --git a/src/ol/geom/geometrycollection.js b/src/ol/geom/geometrycollection.js index ace6adfdf8..e6130bd673 100644 --- a/src/ol/geom/geometrycollection.js +++ b/src/ol/geom/geometrycollection.js @@ -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. */ diff --git a/src/ol/geom/linestring.js b/src/ol/geom/linestring.js index a7027e4b72..7e2bcf74c5 100644 --- a/src/ol/geom/linestring.js +++ b/src/ol/geom/linestring.js @@ -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.} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. diff --git a/src/ol/geom/multilinestring.js b/src/ol/geom/multilinestring.js index a2b2e3dc3c..728168b198 100644 --- a/src/ol/geom/multilinestring.js +++ b/src/ol/geom/multilinestring.js @@ -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.>} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. diff --git a/src/ol/geom/multipoint.js b/src/ol/geom/multipoint.js index b1b414ffbd..f19dfd6dfd 100644 --- a/src/ol/geom/multipoint.js +++ b/src/ol/geom/multipoint.js @@ -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.} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index e546877f65..b881e2eb12 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -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.>>} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. diff --git a/src/ol/geom/point.js b/src/ol/geom/point.js index d030d7a8aa..07ba09ace6 100644 --- a/src/ol/geom/point.js +++ b/src/ol/geom/point.js @@ -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. diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index 7e91e80ba5..52d55ff1fd 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -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.>} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index e82ade9da9..7720f746c0 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -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.} Features. * @api stable diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index 8cde8720e5..ee5c384326 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -349,7 +349,7 @@ describe('ol.extent', function() { }); }); - describe('segmentIntersects()', function() { + describe('intersectsSegment()', function() { var extent = [-180, -90, 180, 90]; var north = [0, 100]; @@ -368,107 +368,107 @@ describe('ol.extent', function() { var inside = [10, 10]; it('returns true if contained', function() { - var intersects = ol.extent.segmentIntersects(extent, center, inside); + var intersects = ol.extent.intersectsSegment(extent, center, inside); expect(intersects).to.be(true); }); it('returns true if crosses top', function() { - var intersects = ol.extent.segmentIntersects(extent, center, north); + var intersects = ol.extent.intersectsSegment(extent, center, north); expect(intersects).to.be(true); }); it('returns true if crosses right', function() { - var intersects = ol.extent.segmentIntersects(extent, center, east); + var intersects = ol.extent.intersectsSegment(extent, center, east); expect(intersects).to.be(true); }); it('returns true if crosses bottom', function() { - var intersects = ol.extent.segmentIntersects(extent, center, south); + var intersects = ol.extent.intersectsSegment(extent, center, south); expect(intersects).to.be(true); }); it('returns true if crosses left', function() { - var intersects = ol.extent.segmentIntersects(extent, center, west); + var intersects = ol.extent.intersectsSegment(extent, center, west); expect(intersects).to.be(true); }); it('returns false if above', function() { - var intersects = ol.extent.segmentIntersects(extent, northwest, north); + var intersects = ol.extent.intersectsSegment(extent, northwest, north); expect(intersects).to.be(false); }); it('returns false if right', function() { - var intersects = ol.extent.segmentIntersects(extent, northeast, east); + var intersects = ol.extent.intersectsSegment(extent, northeast, east); expect(intersects).to.be(false); }); it('returns false if below', function() { - var intersects = ol.extent.segmentIntersects(extent, south, southwest); + var intersects = ol.extent.intersectsSegment(extent, south, southwest); expect(intersects).to.be(false); }); it('returns false if left', function() { - var intersects = ol.extent.segmentIntersects(extent, west, southwest); + var intersects = ol.extent.intersectsSegment(extent, west, southwest); expect(intersects).to.be(false); }); it('returns true if crosses top to bottom', function() { - var intersects = ol.extent.segmentIntersects(extent, north, south); + var intersects = ol.extent.intersectsSegment(extent, north, south); expect(intersects).to.be(true); }); it('returns true if crosses bottom to top', function() { - var intersects = ol.extent.segmentIntersects(extent, south, north); + var intersects = ol.extent.intersectsSegment(extent, south, north); expect(intersects).to.be(true); }); it('returns true if crosses left to right', function() { - var intersects = ol.extent.segmentIntersects(extent, west, east); + var intersects = ol.extent.intersectsSegment(extent, west, east); expect(intersects).to.be(true); }); it('returns true if crosses right to left', function() { - var intersects = ol.extent.segmentIntersects(extent, east, west); + var intersects = ol.extent.intersectsSegment(extent, east, west); expect(intersects).to.be(true); }); it('returns true if crosses northwest to east', function() { - var intersects = ol.extent.segmentIntersects(extent, northwest, east); + var intersects = ol.extent.intersectsSegment(extent, northwest, east); expect(intersects).to.be(true); }); it('returns true if crosses south to west', function() { - var intersects = ol.extent.segmentIntersects(extent, south, west); + var intersects = ol.extent.intersectsSegment(extent, south, west); expect(intersects).to.be(true); }); it('returns true if touches top', function() { - var intersects = ol.extent.segmentIntersects(extent, northwest, top); + var intersects = ol.extent.intersectsSegment(extent, northwest, top); expect(intersects).to.be(true); }); it('returns true if touches right', function() { - var intersects = ol.extent.segmentIntersects(extent, southeast, right); + var intersects = ol.extent.intersectsSegment(extent, southeast, right); expect(intersects).to.be(true); }); it('returns true if touches bottom', function() { - var intersects = ol.extent.segmentIntersects(extent, bottom, south); + var intersects = ol.extent.intersectsSegment(extent, bottom, south); expect(intersects).to.be(true); }); it('returns true if touches left', function() { - var intersects = ol.extent.segmentIntersects(extent, left, west); + var intersects = ol.extent.intersectsSegment(extent, left, west); expect(intersects).to.be(true); }); it('works for zero length inside', function() { - var intersects = ol.extent.segmentIntersects(extent, center, center); + var intersects = ol.extent.intersectsSegment(extent, center, center); expect(intersects).to.be(true); }); it('works for zero length outside', function() { - var intersects = ol.extent.segmentIntersects(extent, north, north); + var intersects = ol.extent.intersectsSegment(extent, north, north); expect(intersects).to.be(false); }); diff --git a/test/spec/ol/geom/flat/intersectsextentflatgeom.test.js b/test/spec/ol/geom/flat/intersectsextentflatgeom.test.js new file mode 100644 index 0000000000..e929efc08e --- /dev/null +++ b/test/spec/ol/geom/flat/intersectsextentflatgeom.test.js @@ -0,0 +1,92 @@ +goog.provide('ol.test.geom.flat.intersectsextent'); + +describe('ol.geom.flat.intersectsextent', function() { + + describe('ol.geom.flat.intersectsextent.lineString', function() { + var flatCoordinates; + beforeEach(function() { + flatCoordinates = [0, 0, 1, 1, 2, 2]; + }); + describe('linestring envelope does not intersect the extent', function() { + it('returns false', function() { + var extent = [3, 3, 4, 4]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(false); + }); + }); + describe('linestring envelope within the extent', function() { + it('returns true', function() { + var extent = [-1, -1, 3, 3]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(true); + }); + }); + describe('linestring envelope bisected by an edge of the extent', + function() { + it('returns true', function() { + var extent = [-0.1, 0.1, 2.1, 0.1]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(true); + }); + }); + describe('a segment intersects the extent', function() { + it('returns true', function() { + var extent = [-0.5, -0.5, 0.5, 0.5]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(true); + }); + }); + describe('no segments intersect the extent', function() { + it('returns false', function() { + var extent = [0.5, 1.5, 1, 1.75]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(false); + }); + it('returns false', function() { + var extent = [1, 0.25, 1.5, 0.5]; + var r = ol.geom.flat.intersectsextent.lineString( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(false); + }); + }); + }); + + describe('ol.geom.flat.intersectsextent.linearRing', function() { + var flatCoordinates; + beforeEach(function() { + flatCoordinates = [0, 0, 1, 1, 2, 0, 1, -1, 0, 0]; + }); + describe('boundary intersects the extent', function() { + it('returns true', function() { + var extent = [1.5, 0.0, 2.5, 1.0]; + var r = ol.geom.flat.intersectsextent.linearRing( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(true); + }); + }); + describe('boundary does not intersect the extent and ring does not ' + + 'contain a corner of the extent', function() { + it('returns false', function() { + var extent = [2.0, 0.5, 3, 1.5]; + var r = ol.geom.flat.intersectsextent.linearRing( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(false); + }); + }); + describe('ring contains the extent', function() { + it('returns true', function() { + var extent = [0.75, -0.25, 1.25, 0.25]; + var r = ol.geom.flat.intersectsextent.linearRing( + flatCoordinates, 0, flatCoordinates.length, 2, extent); + expect(r).to.be(true); + }); + }); + }); +}); + +goog.require('ol.geom.flat.intersectsextent'); diff --git a/test/spec/ol/geom/flat/segmentsflatgeom.test.js b/test/spec/ol/geom/flat/segmentsflatgeom.test.js new file mode 100644 index 0000000000..18a70f56e7 --- /dev/null +++ b/test/spec/ol/geom/flat/segmentsflatgeom.test.js @@ -0,0 +1,57 @@ +goog.provide('ol.test.geom.flat.segments'); + +describe('ol.geom.flat.segments', function() { + + describe('ol.geom.flat.segments.forEach', function() { + var flatCoordinates, offset, end, stride; + beforeEach(function() { + flatCoordinates = [0, 0, 1, 1, 2, 2, 3, 3]; + offset = 0; + end = 8; + stride = 2; + }); + describe('callback returns undefined', function() { + it('executes the callback for each segment', function() { + var args = []; + var spy = sinon.spy(function(point1, point2) { + args.push([point1[0], point1[1], point2[0], point2[1]]); + }); + var ret = ol.geom.flat.segments.forEach( + flatCoordinates, offset, end, stride, spy); + expect(spy.callCount).to.be(3); + expect(args[0][0]).to.be(0); + expect(args[0][1]).to.be(0); + expect(args[0][2]).to.be(1); + expect(args[0][3]).to.be(1); + expect(args[1][0]).to.be(1); + expect(args[1][1]).to.be(1); + expect(args[1][2]).to.be(2); + expect(args[1][3]).to.be(2); + expect(args[2][0]).to.be(2); + expect(args[2][1]).to.be(2); + expect(args[2][2]).to.be(3); + expect(args[2][3]).to.be(3); + expect(ret).to.be(false); + }); + }); + describe('callback returns true', function() { + it('executes the callback for the first segment', function() { + var args = []; + var spy = sinon.spy(function(point1, point2) { + args.push([point1[0], point1[1], point2[0], point2[1]]); + return true; + }); + var ret = ol.geom.flat.segments.forEach( + flatCoordinates, offset, end, stride, spy); + expect(spy.callCount).to.be(1); + expect(args[0][0]).to.be(0); + expect(args[0][1]).to.be(0); + expect(args[0][2]).to.be(1); + expect(args[0][3]).to.be(1); + expect(ret).to.be(true); + }); + }); + }); +}); + +goog.require('ol.geom.flat.segments');