Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Everytype #10

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,47 @@ var inside = require('./');
var Benchmark = require('benchmark');
var fs = require('fs');
var point = require('turf-point');
var linestring = require('turf-linestring');
var polygon = require('turf-polygon');
var multipoint = require('turf-multipoint');
var multilinestring = require('turf-multilinestring');
var multipolygon = require('turf-multipolygon');
var geometrycollection = require('turf-geometrycollection');
var featurecollection = require('turf-featurecollection');

var poly = polygon([[[0,0], [0,100], [100,100], [100,0]]]);
var ptIn = point(50, 50);
var ptOut = point(140, 150);
var ptIn = point([50, 50]);

var pt = point([50, 50]);
var multipt = multipoint([[0,0], [50,50]]);
var line = linestring([[86,42],[66,25],[93,23],[0,16],[-40,5],[16,-20],[1,1]]);
var multiline = multilinestring([[[86,42],[66,25],[93,23]], [[1,1],[-40,5],[16,-20],[0,16]]]);
var poly = polygon([[[0,0], [0,100], [100,100], [100,0], [0,0]]]);
var multipoly = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[0,16],[-40,5],[16,-20],[0,16]]]]);
var fc = featurecollection([poly, multiline]);

var suite = new Benchmark.Suite('turf-inside');
suite
.add('turf-inside',function () {
.add('turf-inside - point',function () {
inside(ptIn, pt);
})
.add('turf-inside - multipoint',function () {
inside(ptIn, multipt);
})
.add('turf-inside - linestring',function () {
inside(ptIn, line);
})
.add('turf-inside - multilinestring',function () {
inside(ptIn, multiline);
})
.add('turf-inside - polygon',function () {
inside(ptIn, poly);
})
.add('turf-inside - multipolygon',function () {
inside(ptIn, multipoly);
})
.add('turf-inside - featurecollection',function () {
inside(ptIn, fc);
})
.on('cycle', function (event) {
console.log(String(event.target));
})
Expand Down
110 changes: 93 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
var invariant = require('turf-invariant');
var normalize = require('turf-normalize');
var flatten = require('turf-flatten');

// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js
Expand Down Expand Up @@ -62,33 +64,107 @@ var invariant = require('turf-invariant');
* var isInside2 = turf.inside(pt2, poly);
* //=isInside2
*/
module.exports = function(point, polygon) {
module.exports = function(point, surface) {
invariant.featureOf(point, 'Point', 'inside');
var polys = polygon.geometry.coordinates;

if(surface.type === 'Feature' &&
(surface.geometry.type === 'Polygon' ||
surface.geometry.type === 'LineString' ||
surface.geometry.type === 'Point')) return pointInSingle(point, surface);
else {
var fc = normalize(flatten(surface));
var isInside = false;
for(var i = 0; i < fc.features.length; i++) {
if(fc.features[i].geometry.type === 'MultiPolygon' ||
fc.features[i].geometry.type === 'MultiLineString' ||
fc.features[i].geometry.type === 'MultiPoint') {
var multiFC = flatten(normalize(fc.features[i]));

for(var k = 0; k < multiFC.features.length; k++) {
if(pointInSingle(point, multiFC.features[k])) {
isInside = true;
break;
}
}
} else {
if(pointInSingle(point, fc.features[i])) {
isInside = true;
break;
}
}
}
return isInside;
}
};

function pointInSingle(point, feature) {
if(feature.geometry.type === 'Point') return pointInPoint(point, feature);
if(feature.geometry.type === 'LineString') return pointInLineString(point, feature);
else if(feature.geometry.type === 'Polygon') return pointInPolygon(point, feature);
}

function pointInPolygon (point, polygon) {
var poly = polygon.geometry.coordinates;
var pt = [point.geometry.coordinates[0], point.geometry.coordinates[1]];
// normalize to multipolygon
if (polygon.geometry.type === 'Polygon') polys = [polys];

var insidePoly = false;
var i = 0;
while (i < polys.length && !insidePoly) {
// check if it is in the outer ring first
if(inRing(pt, polys[i][0])) {
var inHole = false;
var k = 1;
// check for the point in any of the holes
while(k < polys[i].length && !inHole) {
if(inRing(pt, polys[i][k])) {
inHole = true;
}
k++;
if(inRing(pt, poly[0])) {
var inHole = false;
var k = 1;
// check for the point in any of the holes
while(k < poly.length && !inHole) {
if(inRing(pt, poly[k])) {
inHole = true;
break;
}
if(!inHole) insidePoly = true;
k++;
}
i++;
if(!inHole) insidePoly = true;
}

return insidePoly;
};
}

function pointInPoint (pt1, pt2) {
if(pt1.geometry.coordinates[0] === pt2.geometry.coordinates[0] &&
pt1.geometry.coordinates[1] === pt2.geometry.coordinates[1]) {
return true;
} else {
return false;
}
}

function pointInLineString (point, line) {
var onLine = false;
var k = 0;
while(!onLine && k < line.geometry.coordinates.length - 1) {
var x = point.geometry.coordinates[0];
var y = point.geometry.coordinates[1];
var x1 = line.geometry.coordinates[k][0];
var y1 = line.geometry.coordinates[k][1];
var x2 = line.geometry.coordinates[k+1][0];
var y2 = line.geometry.coordinates[k+1][1];
if((x === x1 && y === y1) ||
(x === x2 && y === y2) ||
pointOnSegment(x, y, x1, y1, x2, y2)) {
onLine = true;
break;
}
k++;
}
return onLine;
}

function pointOnSegment (x, y, x1, y1, x2, y2) {
var ab = Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
var ap = Math.sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
var pb = Math.sqrt((x2-x)*(x2-x)+(y2-y)*(y2-y));
if(ab === ap + pb) {
return true;
}
}

// pt is [x,y] and ring is [[x,y], [x,y],..]
function inRing (pt, ring) {
Expand Down
16 changes: 12 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,22 @@
"bin": {},
"dependencies": {
"minimist": "^1.1.0",
"turf-invariant": "^1.0.3"
"turf-flatten": "^1.0.0",
"turf-invariant": "^1.0.3",
"turf-normalize": "^1.0.2"
},
"devDependencies": {
"benchmark": "^1.0.0",
"dox": "^0.6.1",
"doxme": "^1.4.3",
"tape": "^3.5.0",
"turf-featurecollection": "^1.0.1",
"turf-geometrycollection": "^1.0.0",
"turf-linestring": "^1.0.2",
"turf-multilinestring": "^1.0.2",
"turf-multipoint": "^1.0.0",
"turf-multipolygon": "^1.0.1",
"turf-point": "^2.0.0",
"turf-polygon": "^1.0.2",
"dox": "^0.6.1",
"doxme": "^1.4.3"
"turf-polygon": "^1.0.2"
}
}
109 changes: 100 additions & 9 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
var test = require('tape');
var inside = require('./');
var point = require('turf-point');
var linestring = require('turf-linestring');
var polygon = require('turf-polygon');
var multipoint = require('turf-multipoint');
var multilinestring = require('turf-multilinestring');
var multipolygon = require('turf-multipolygon');
var geometrycollection = require('turf-geometrycollection');
var featurecollection = require('turf-featurecollection');
var fs = require('fs');

test('bad type', function (t) {
Expand All @@ -14,7 +20,7 @@ test('bad type', function (t) {
t.end();
});

test('featureCollection', function (t) {
test('concave/convex polygons', function (t) {
// test for a simple polygon
var poly = polygon([[[0,0], [0,100], [100,100], [100,0], [0,0]]]);
var ptIn = point([50, 50]);
Expand All @@ -40,9 +46,9 @@ test('poly with hole', function (t) {
var ptOutsidePoly = point([-86.75079345703125, 36.18527313913089]);
var polyHole = JSON.parse(fs.readFileSync(__dirname + '/fixtures/poly-with-hole.geojson'));

t.false(inside(ptInHole, polyHole));
t.true(inside(ptInPoly, polyHole));
t.false(inside(ptOutsidePoly, polyHole));
t.false(inside(ptInHole, polyHole), 'out');
t.true(inside(ptInPoly, polyHole), 'in');
t.false(inside(ptOutsidePoly, polyHole), 'out');

t.end();
});
Expand All @@ -54,11 +60,96 @@ test('multipolygon with hole', function (t) {
var ptOutsidePoly = point([-86.75302505493164, 36.23015046460186]);
var multiPolyHole = JSON.parse(fs.readFileSync(__dirname + '/fixtures/multipoly-with-hole.geojson'));

t.false(inside(ptInHole, multiPolyHole));
t.true(inside(ptInPoly, multiPolyHole));
t.true(inside(ptInPoly2, multiPolyHole));
t.true(inside(ptInPoly, multiPolyHole));
t.false(inside(ptOutsidePoly, multiPolyHole));
t.false(inside(ptInHole, multiPolyHole), 'out');
t.true(inside(ptInPoly, multiPolyHole), 'in');
t.true(inside(ptInPoly2, multiPolyHole), 'in');
t.true(inside(ptInPoly, multiPolyHole), 'in');
t.false(inside(ptOutsidePoly, multiPolyHole), 'out');

t.end();
});

test('point', function (t) {
var pt1 = point([-86.69208526611328, 36.20373274711739]);
var pt2 = point([-86.72229766845702, 36.20258997094334]);

t.true(inside(pt1, pt1), 'in');
t.false(inside(pt1, pt2), 'out');

t.end();
});

test('linestring', function (t) {
var pt = point([1,1]);
var line1 = linestring([[86,42],[66,25],[93,23],[0,16],[-40,5],[16,-20],[1,1]]);
var line2 = linestring([[86,42],[66,25],[93,23],[86,42],[-54,63],[-80,53],[-60,52],[-54,63]]);

t.true(inside(pt, line1), 'in');
t.false(inside(pt, line2), 'out');

t.end();
});

test('multipoint', function (t) {
var pt = point([1,1]);
var multipt1 = multipoint([[0,0], [1,1]], 'in');
var multipt2 = multipoint([[0,0], [2,2]], 'out');

t.true(inside(pt, multipt1), 'in');
t.false(inside(pt, multipt2), 'out');

t.end();
});

test('multilinestring', function (t) {
var pt = point([1,1]);
var multiline1 = multilinestring([[[86,42],[66,25],[93,23]], [[1,1],[-40,5],[16,-20],[0,16]]]);
var multiline2 = multilinestring([[[86,42],[66,25],[93,23]], [[-54,63],[-80,53],[-60,52]]]);

t.true(inside(pt, multiline1), 'in');
t.false(inside(pt, multiline2), 'out');

t.end();
});

test('multipolygon', function (t) {
var pt = point([1,1]);
var multipoly1 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[0,16],[-40,5],[16,-20],[0,16]]]]);
var multipoly2 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[-54,63],[-80,53],[-60,52],[-54,63]]]]);

t.true(inside(pt, multipoly1), 'in');
t.false(inside(pt, multipoly2), 'out');

t.end();
});

test('geometrycollection', function (t) {
var pt = point([1,1]);
var multipoly1 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[0,16],[-40,5],[16,-20],[0,16]]]]);
var multipoly2 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[-54,63],[-80,53],[-60,52],[-54,63]]]]);

var gc1 = geometrycollection([point([0,0]).geometry, multipoly1.geometry]);
var gc2 = geometrycollection([point([0,0]).geometry, multipoly2.geometry]);
var gc3 = geometrycollection([point([1,1]).geometry, multipoly2.geometry]);
t.true(inside(pt, gc1), 'in');
t.false(inside(pt, gc2), 'out');
t.true(inside(pt, gc3), 'in');

t.end();
});

test('featurecollection', function (t) {
var pt = point([1,1]);
var multipoly1 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[0,16],[-40,5],[16,-20],[0,16]]]]);
var multipoly2 = multipolygon([[[[86,42],[66,25],[93,23],[86,42]]], [[[-54,63],[-80,53],[-60,52],[-54,63]]]]);

var fc1 = featurecollection([point([0,0]), multipoly1]);
var fc2 = featurecollection([point([0,0]), multipoly2]);
var fc3 = featurecollection([point([1,1]), multipoly2]);

t.true(inside(pt, fc1), 'in');
t.false(inside(pt, fc2), 'out');
t.true(inside(pt, fc3), 'in');

t.end();
});