Skip to content

Commit

Permalink
Merge pull request #2636 from 01100100/dw/ignore-self-intersections-o…
Browse files Browse the repository at this point in the history
…ption

Expose `options` parameter to @turf/boolean-intersects and @turf/booean-disjoint to add option of ignoring self intersections.
  • Loading branch information
mfedderly authored Aug 5, 2024
2 parents d57be0c + cf8eb31 commit e3fb086
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 30 deletions.
9 changes: 7 additions & 2 deletions packages/turf-boolean-disjoint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Boolean-disjoint returns (TRUE) if the intersection of the two geometries is an

* `feature1` **([Geometry][1] | [Feature][2]\<any>)** GeoJSON Feature or Geometry
* `feature2` **([Geometry][1] | [Feature][2]\<any>)** GeoJSON Feature or Geometry
* `options` **[Object][3]** Optional parameters (optional, default `{}`)

* `options.ignoreSelfIntersections` **[boolean][4]** ignores self-intersections on input features (optional, default `false`)

### Examples

Expand All @@ -21,13 +24,15 @@ turf.booleanDisjoint(line, point);
//=true
```

Returns **[boolean][3]** true/false
Returns **[boolean][4]** true if the intersection is an empty set, false otherwise

[1]: https://tools.ietf.org/html/rfc7946#section-3.1

[2]: https://tools.ietf.org/html/rfc7946#section-3.2

[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object

[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean

<!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->

Expand Down
83 changes: 61 additions & 22 deletions packages/turf-boolean-disjoint/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Feature, Geometry, LineString, Point, Polygon } from "geojson";
import {
Feature,
Geometry,
LineString,
Point,
Polygon,
Position,
} from "geojson";
import { booleanPointInPolygon } from "@turf/boolean-point-in-polygon";
import { lineIntersect } from "@turf/line-intersect";
import { flattenEach } from "@turf/meta";
Expand All @@ -10,7 +17,9 @@ import { polygonToLine } from "@turf/polygon-to-line";
* @name booleanDisjoint
* @param {Geometry|Feature<any>} feature1 GeoJSON Feature or Geometry
* @param {Geometry|Feature<any>} feature2 GeoJSON Feature or Geometry
* @returns {boolean} true/false
* @param {Object} [options={}] Optional parameters
* @param {boolean} [options.ignoreSelfIntersections=false] ignores self-intersections on input features
* @returns {boolean} true if the intersection is an empty set, false otherwise
* @example
* var point = turf.point([2, 2]);
* var line = turf.lineString([[1, 1], [1, 2], [1, 3], [1, 4]]);
Expand All @@ -20,15 +29,25 @@ import { polygonToLine } from "@turf/polygon-to-line";
*/
function booleanDisjoint(
feature1: Feature<any> | Geometry,
feature2: Feature<any> | Geometry
feature2: Feature<any> | Geometry,
options: {
ignoreSelfIntersections?: boolean;
} = {}
): boolean {
const ignoreSelfIntersections: boolean =
options.ignoreSelfIntersections ?? false;

let bool = true;
flattenEach(feature1, (flatten1) => {
flattenEach(feature2, (flatten2) => {
if (bool === false) {
return false;
}
bool = disjoint(flatten1.geometry, flatten2.geometry);
bool = disjoint(
flatten1.geometry,
flatten2.geometry,
ignoreSelfIntersections
);
});
});
return bool;
Expand All @@ -40,11 +59,13 @@ function booleanDisjoint(
* @private
* @param {Geometry<any>} geom1 GeoJSON Geometry
* @param {Geometry<any>} geom2 GeoJSON Geometry
* @returns {boolean} true/false
* @param {boolean} ignoreSelfIntersections ignore self-intersections on input features
* @returns {boolean} true if disjoint, false otherwise
*/
function disjoint(geom1: any, geom2: any) {
function disjoint(geom1: any, geom2: any, ignoreSelfIntersections: boolean) {
switch (geom1.type) {
case "Point":
/* eslint-disable @typescript-eslint/no-unused-vars */
switch (geom2.type) {
case "Point":
return !compareCoords(geom1.coordinates, geom2.coordinates);
Expand All @@ -60,9 +81,9 @@ function disjoint(geom1: any, geom2: any) {
case "Point":
return !isPointOnLine(geom1, geom2);
case "LineString":
return !isLineOnLine(geom1, geom2);
return !isLineOnLine(geom1, geom2, ignoreSelfIntersections);
case "Polygon":
return !isLineInPoly(geom2, geom1);
return !isLineInPoly(geom2, geom1, ignoreSelfIntersections);
}
/* istanbul ignore next */
break;
Expand All @@ -71,9 +92,9 @@ function disjoint(geom1: any, geom2: any) {
case "Point":
return !booleanPointInPolygon(geom2, geom1);
case "LineString":
return !isLineInPoly(geom1, geom2);
return !isLineInPoly(geom1, geom2, ignoreSelfIntersections);
case "Polygon":
return !isPolyInPoly(geom2, geom1);
return !isPolyInPoly(geom2, geom1, ignoreSelfIntersections);
}
}
return false;
Expand All @@ -95,21 +116,33 @@ function isPointOnLine(lineString: LineString, pt: Point) {
return false;
}

function isLineOnLine(lineString1: LineString, lineString2: LineString) {
const doLinesIntersect = lineIntersect(lineString1, lineString2);
function isLineOnLine(
lineString1: LineString,
lineString2: LineString,
ignoreSelfIntersections: boolean
) {
const doLinesIntersect = lineIntersect(lineString1, lineString2, {
ignoreSelfIntersections,
});
if (doLinesIntersect.features.length > 0) {
return true;
}
return false;
}

function isLineInPoly(polygon: Polygon, lineString: LineString) {
function isLineInPoly(
polygon: Polygon,
lineString: LineString,
ignoreSelfIntersections: boolean
) {
for (const coord of lineString.coordinates) {
if (booleanPointInPolygon(coord, polygon)) {
return true;
}
}
const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon));
const doLinesIntersect = lineIntersect(lineString, polygonToLine(polygon), {
ignoreSelfIntersections,
});
if (doLinesIntersect.features.length > 0) {
return true;
}
Expand All @@ -124,9 +157,14 @@ function isLineInPoly(polygon: Polygon, lineString: LineString) {
* @private
* @param {Geometry|Feature<Polygon>} feature1 Polygon1
* @param {Geometry|Feature<Polygon>} feature2 Polygon2
* @returns {boolean} true/false
* @param {boolean} ignoreSelfIntersections ignore self-intersections on input features
* @returns {boolean} true if geom1 is in geom2, false otherwise
*/
function isPolyInPoly(feature1: Polygon, feature2: Polygon) {
function isPolyInPoly(
feature1: Polygon,
feature2: Polygon,
ignoreSelfIntersections: boolean
) {
for (const coord1 of feature1.coordinates[0]) {
if (booleanPointInPolygon(coord1, feature2)) {
return true;
Expand All @@ -139,7 +177,8 @@ function isPolyInPoly(feature1: Polygon, feature2: Polygon) {
}
const doLinesIntersect = lineIntersect(
polygonToLine(feature1),
polygonToLine(feature2)
polygonToLine(feature2),
{ ignoreSelfIntersections }
);
if (doLinesIntersect.features.length > 0) {
return true;
Expand All @@ -148,9 +187,9 @@ function isPolyInPoly(feature1: Polygon, feature2: Polygon) {
}

function isPointOnLineSegment(
lineSegmentStart: number[],
lineSegmentEnd: number[],
pt: number[]
lineSegmentStart: Position,
lineSegmentEnd: Position,
pt: Position
) {
const dxc = pt[0] - lineSegmentStart[0];
const dyc = pt[1] - lineSegmentStart[1];
Expand Down Expand Up @@ -179,9 +218,9 @@ function isPointOnLineSegment(
* @private
* @param {Position} pair1 point [x,y]
* @param {Position} pair2 point [x,y]
* @returns {boolean} true/false if coord pairs match
* @returns {boolean} true if coord pairs match, false otherwise
*/
function compareCoords(pair1: number[], pair2: number[]) {
function compareCoords(pair1: Position, pair2: Position) {
return pair1[0] === pair2[0] && pair1[1] === pair2[1];
}

Expand Down
136 changes: 136 additions & 0 deletions packages/turf-boolean-disjoint/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,139 @@ test("turf-boolean-disjoint", (t) => {
});
t.end();
});

test("turf-boolean-disjoin with ignoreSelfIntersections option", (t) => {
const selfIntersectingLineString: GeoJSON.Feature<GeoJSON.LineString> = {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[1, 1],
[2, 2],
[1, 2],
[2, 1],
],
},
};

const nonIntersectingLineString: GeoJSON.Feature<GeoJSON.LineString> = {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[0, 1],
[0, 0],
],
},
};

const intersectingLineString: GeoJSON.Feature<GeoJSON.LineString> = {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[0, 1],
[4, 2],
],
},
};

const intersectingPolygon: GeoJSON.Feature<GeoJSON.Polygon> = {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
[
[1.5, 1],
[2, 1.5],

[3, 0.5],
[1.5, 1],
],
],
},
};

const nonIntersectingPolygon: GeoJSON.Feature<GeoJSON.Polygon> = {
type: "Feature",
properties: {},
geometry: {
type: "Polygon",
coordinates: [
[
[0.5, 0],
[1, 0.5],

[2, -0.5],
[0.5, 0],
],
],
},
};

// Test without ignoringSelfIntersections option (default behavior)
let result = disjoint(selfIntersectingLineString, nonIntersectingLineString);
t.false(
result,
"[false] " +
"selfIntersectingLineString-LineString (ignoreSelfIntersections=false)"
);
result = disjoint(selfIntersectingLineString, intersectingLineString);
t.false(
result,
"[false] " +
"selfIntersectingLineString-LineString (ignoreSelfIntersections=false)"
);
result = disjoint(selfIntersectingLineString, intersectingPolygon);
t.false(
result,
"[false] " +
"selfIntersectingLineString-Polygon (ignoreSelfIntersections=false)"
);
result = disjoint(selfIntersectingLineString, nonIntersectingPolygon);
t.false(
result,
"[false] " +
"selfIntersectingLineString-Polygon (ignoreSelfIntersections=false)"
);

// Test with ignoringSelfIntersections option
result = disjoint(selfIntersectingLineString, nonIntersectingLineString, {
ignoreSelfIntersections: true,
});
t.true(
result,
"[true] " +
"selfIntersectingLineString-LineString (ignoreSelfIntersections=true)"
);
result = disjoint(selfIntersectingLineString, intersectingLineString, {
ignoreSelfIntersections: true,
});
t.false(
result,
"[false] " +
"selfIntersectingLineString-LineString (ignoreSelfIntersections=true)"
);
result = disjoint(selfIntersectingLineString, intersectingPolygon, {
ignoreSelfIntersections: true,
});
t.false(
result,
"[false] " +
"selfIntersectingLineString-Polygon (ignoreSelfIntersections=true)"
);
result = disjoint(selfIntersectingLineString, nonIntersectingPolygon, {
ignoreSelfIntersections: true,
});
t.true(
result,
"[true] " +
"selfIntersectingLineString-Polygon (ignoreSelfIntersections=true)"
);

t.end();
});
9 changes: 7 additions & 2 deletions packages/turf-boolean-intersects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Boolean-intersects returns (TRUE) if the intersection of the two geometries is N

* `feature1` **([Geometry][1] | [Feature][2]\<any>)** GeoJSON Feature or Geometry
* `feature2` **([Geometry][1] | [Feature][2]\<any>)** GeoJSON Feature or Geometry
* `options` **[Object][3]** Optional parameters (optional, default `{}`)

* `options.ignoreSelfIntersections` **[boolean][4]** ignores self-intersections on input features (optional, default `false`)

### Examples

Expand All @@ -30,13 +33,15 @@ point1.properties['marker-color'] = '#f00'
point2.properties['marker-color'] = '#0f0'
```

Returns **[boolean][3]** true/false
Returns **[boolean][4]** true if geometries intersect, false otherwise

[1]: https://tools.ietf.org/html/rfc7946#section-3.1

[2]: https://tools.ietf.org/html/rfc7946#section-3.2

[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object

[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean

<!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->

Expand Down
Loading

0 comments on commit e3fb086

Please sign in to comment.