Skip to content

Commit

Permalink
Merge pull request #155 from ondras/contains-fix
Browse files Browse the repository at this point in the history
fix geoContains for LineStrings
  • Loading branch information
Fil authored Jun 21, 2019
2 parents 65d30d2 + 7a6cf8c commit 89d31fa
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 5 deletions.
23 changes: 18 additions & 5 deletions src/contains.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {default as polygonContains} from "./polygonContains";
import {default as distance} from "./distance";
import {epsilon, radians} from "./math";
import {epsilon2, radians} from "./math";

var containsObjectType = {
Feature: function(object, point) {
Expand Down Expand Up @@ -59,10 +59,23 @@ function containsPoint(coordinates, point) {
}

function containsLine(coordinates, point) {
var ab = distance(coordinates[0], coordinates[1]),
ao = distance(coordinates[0], point),
ob = distance(point, coordinates[1]);
return ao + ob <= ab + epsilon;
var ao, bo, ab;
for (var i = 0, n = coordinates.length; i < n; i++) {
bo = distance(coordinates[i], point);
if (bo === 0) return true;
if (i > 0) {
ab = distance(coordinates[i], coordinates[i - 1]);
if (
ab > 0 &&
ao <= ab &&
bo <= ab &&
(ao + bo - ab) * (1 - ((ao - bo) / ab) ** 2) < epsilon2 * ab
)
return true;
}
ao = bo;
}
return false;
}

function containsPolygon(coordinates, point) {
Expand Down
30 changes: 30 additions & 0 deletions test/contains-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,35 @@ tape("a LineString contains any point on the Great Circle path", function(test)
test.end();
});

tape("a LineString with 2+ points contains those points", function(test) {
var points = [[0, 0], [1,2], [3, 4], [5, 6]];
var feature = {type: "LineString", coordinates: points};
points.forEach(point => {
test.equal(d3.geoContains(feature, point), true);
});
test.end();
});

tape("a LineString contains epsilon-distant points", function(test) {
var epsilon = 1e-6;
var line = [[0, 0], [0, 10], [10, 10], [10, 0]];
var points = [[0, 5], [epsilon * 1, 5], [0, epsilon], [epsilon * 1, epsilon]];
points.forEach(point => {
test.true(d3.geoContains({type:"LineString", coordinates: line}, point));
});
test.end();
});

tape("a LineString does not contain 10*epsilon-distant points", function(test) {
var epsilon = 1e-6;
var line = [[0, 0], [0, 10], [10, 10], [10, 0]];
var points = [[epsilon * 10, 5], [epsilon * 10, epsilon]];
points.forEach(point => {
test.false(d3.geoContains({type:"LineString", coordinates: line}, point));
});
test.end();
});

tape("a MultiLineString contains any point on one of its components", function(test) {
test.equal(d3.geoContains({type: "MultiLineString", coordinates: [[[0, 0], [1,2]], [[2, 3], [4,5]]]}, [2, 3]), true);
test.equal(d3.geoContains({type: "MultiLineString", coordinates: [[[0, 0], [1,2]], [[2, 3], [4,5]]]}, [5, 6]), false);
Expand Down Expand Up @@ -113,3 +142,4 @@ tape("null contains nothing", function(test) {
test.equal(d3.geoContains(null, [0, 0]), false);
test.end();
});

0 comments on commit 89d31fa

Please sign in to comment.