Merge pull request #692 from ahocevar/pnpoly
Point-in-polygon improvements. r=@bartvde
This commit is contained in:
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<h4 id="title">Vector layer example</h4>
|
<h4 id="title">Vector layer example</h4>
|
||||||
<p id="shortdesc">Example of a vector layer.</p>
|
<p id="shortdesc">Example of a countries vector layer with country information on hover.</p>
|
||||||
<div id="docs">
|
<div id="docs">
|
||||||
<p>See the <a href="vector-layer.js" target="_blank">vector-layer.js source</a> to see how this is done.</p>
|
<p>See the <a href="vector-layer.js" target="_blank">vector-layer.js source</a> to see how this is done.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,31 +42,3 @@ ol.geom.squaredDistanceToSegment = function(coordinate, segment) {
|
|||||||
return ol.coordinate.squaredDistance(coordinate,
|
return ol.coordinate.squaredDistance(coordinate,
|
||||||
[v[0] + t * (w[0] - v[0]), v[1] + t * (w[1] - v[1])]);
|
[v[0] + t * (w[0] - v[0]), v[1] + t * (w[1] - v[1])]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate whether a point falls inside a polygon.
|
|
||||||
*
|
|
||||||
* @param {ol.Coordinate} coordinate Coordinate of the point.
|
|
||||||
* @param {Array.<ol.Coordinate>} vertices Vertices of the polygon.
|
|
||||||
* @return {boolean} Whether the point falls inside the polygon.
|
|
||||||
*/
|
|
||||||
ol.geom.pointInPolygon = function(coordinate, vertices) {
|
|
||||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
|
||||||
var x = coordinate[0], y = coordinate[1];
|
|
||||||
var inside = false;
|
|
||||||
var xi, yi, xj, yj, intersect;
|
|
||||||
var numVertices = vertices.length;
|
|
||||||
for (var i = 0, j = numVertices - 1; i < numVertices; j = i++) {
|
|
||||||
xi = vertices[i][0];
|
|
||||||
yi = vertices[i][1];
|
|
||||||
xj = vertices[j][0];
|
|
||||||
yj = vertices[j][1];
|
|
||||||
intersect = ((yi > y) != (yj > y)) &&
|
|
||||||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
|
||||||
if (intersect) {
|
|
||||||
inside = !inside;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return inside;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -33,3 +33,33 @@ goog.inherits(ol.geom.LinearRing, ol.geom.LineString);
|
|||||||
ol.geom.LinearRing.prototype.getType = function() {
|
ol.geom.LinearRing.prototype.getType = function() {
|
||||||
return ol.geom.GeometryType.LINEARRING;
|
return ol.geom.GeometryType.LINEARRING;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given coordinate is inside this ring. Note that this is a
|
||||||
|
* fast and simple check - points on an edge or vertex of the ring are either
|
||||||
|
* classified inside or outside.
|
||||||
|
*
|
||||||
|
* @param {ol.Coordinate} coordinate Coordinate.
|
||||||
|
* @return {boolean} Whether the coordinate is inside the ring.
|
||||||
|
*/
|
||||||
|
ol.geom.LinearRing.prototype.containsCoordinate = function(coordinate) {
|
||||||
|
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||||
|
var x = coordinate[0], y = coordinate[1];
|
||||||
|
var vertices = this.getCoordinates();
|
||||||
|
var inside = false;
|
||||||
|
var xi, yi, xj, yj, intersect;
|
||||||
|
var numVertices = vertices.length;
|
||||||
|
for (var i = 0, j = numVertices - 1; i < numVertices; j = i++) {
|
||||||
|
xi = vertices[i][0];
|
||||||
|
yi = vertices[i][1];
|
||||||
|
xj = vertices[j][0];
|
||||||
|
yj = vertices[j][1];
|
||||||
|
intersect = ((yi > y) != (yj > y)) &&
|
||||||
|
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||||
|
if (intersect) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
};
|
||||||
|
|||||||
+13
-10
@@ -91,22 +91,25 @@ ol.geom.Polygon.prototype.getType = function() {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a given coordinate is inside this polygon.
|
* Check whether a given coordinate is inside this polygon. Note that this is a
|
||||||
|
* fast and simple check - points on an edge or vertex of the polygon or one of
|
||||||
|
* its inner rings are either classified inside or outside.
|
||||||
*
|
*
|
||||||
* @param {ol.Coordinate} coordinate Coordinate.
|
* @param {ol.Coordinate} coordinate Coordinate.
|
||||||
* @return {boolean} Whether the coordinate is inside the polygon.
|
* @return {boolean} Whether the coordinate is inside the polygon.
|
||||||
*/
|
*/
|
||||||
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
|
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
|
||||||
var rings = this.rings;
|
var rings = this.rings;
|
||||||
var containsCoordinate = ol.geom.pointInPolygon(coordinate,
|
/** @type {boolean} */
|
||||||
rings[0].getCoordinates());
|
var containsCoordinate;
|
||||||
if (containsCoordinate) {
|
for (var i = 0, ii = rings.length; i < ii; ++i) {
|
||||||
// if inner ring contains point, polygon does not contain it
|
containsCoordinate = rings[i].containsCoordinate(coordinate);
|
||||||
for (var i = 1, ii = rings.length; i < ii; ++i) {
|
// if inner ring (i > 0) contains coordinate, polygon does not contain it
|
||||||
if (ol.geom.pointInPolygon(coordinate, rings[i].getCoordinates())) {
|
if (i > 0) {
|
||||||
containsCoordinate = false;
|
containsCoordinate = !containsCoordinate;
|
||||||
break;
|
}
|
||||||
}
|
if (!containsCoordinate) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return containsCoordinate;
|
return containsCoordinate;
|
||||||
|
|||||||
@@ -40,6 +40,71 @@ describe('ol.geom.LinearRing', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#containsCoordinate()', function() {
|
||||||
|
|
||||||
|
it('knows when a point coordinate is inside a ring', function() {
|
||||||
|
/**
|
||||||
|
* The ring:
|
||||||
|
* edge 3
|
||||||
|
* (5, 10) __________ (15, 10)
|
||||||
|
* / /
|
||||||
|
* edge 4 / / edge 2
|
||||||
|
* / /
|
||||||
|
* (0, 0) /_________/ (10, 0)
|
||||||
|
* edge 1
|
||||||
|
*/
|
||||||
|
var ring = new ol.geom.LinearRing(
|
||||||
|
[[0, 0], [10, 0], [15, 10], [5, 10]]);
|
||||||
|
|
||||||
|
// contains: 1 (touches - not implemented), true (within), false (outside)
|
||||||
|
var cases = [{
|
||||||
|
point: [5, 5], contains: true
|
||||||
|
}, {
|
||||||
|
point: [20, 20], contains: false
|
||||||
|
}, {
|
||||||
|
point: [15, 15], contains: false
|
||||||
|
}/*, {
|
||||||
|
point: [0, 0], contains: 1 // lower left corner
|
||||||
|
}, {
|
||||||
|
point: [10, 0], contains: 1 // lower right corner
|
||||||
|
}, {
|
||||||
|
point: [15, 10], contains: 1 // upper right corner
|
||||||
|
}, {
|
||||||
|
point: [5, 10], contains: 1 // upper left corner
|
||||||
|
}, {
|
||||||
|
point: [5, 0], contains: 1 // on edge 1
|
||||||
|
}*/, {
|
||||||
|
point: [5, -0.1], contains: false // below edge 1
|
||||||
|
}, {
|
||||||
|
point: [5, 0.1], contains: true // above edge 1
|
||||||
|
}/*, {
|
||||||
|
point: [12.5, 5], contains: 1 // on edge 2
|
||||||
|
}*/, {
|
||||||
|
point: [12.4, 5], contains: true // left of edge 2
|
||||||
|
}, {
|
||||||
|
point: [12.6, 5], contains: false // right of edge 2
|
||||||
|
}/*, {
|
||||||
|
point: [10, 10], contains: 1 // on edge 3
|
||||||
|
}*/, {
|
||||||
|
point: [10, 9.9], contains: true // below edge 3
|
||||||
|
}, {
|
||||||
|
point: [10, 10.1], contains: false // above edge 3
|
||||||
|
}/*, {
|
||||||
|
point: [2.5, 5], contains: 1 // on edge 4
|
||||||
|
}*/, {
|
||||||
|
point: [2.4, 5], contains: false // left of edge 4
|
||||||
|
}, {
|
||||||
|
point: [2.6, 5], contains: true // right of edge 4
|
||||||
|
}];
|
||||||
|
|
||||||
|
var c;
|
||||||
|
for (var i = 0, ii = cases.length; i < ii; ++i) {
|
||||||
|
c = cases[i];
|
||||||
|
expect(ring.containsCoordinate(c.point)).to.be(c.contains);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
goog.require('ol.geom.LinearRing');
|
goog.require('ol.geom.LinearRing');
|
||||||
|
|||||||
Reference in New Issue
Block a user