Skip to content

Commit

Permalink
Add ignoreSelfIntersections argument
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanwins committed Jun 16, 2021
1 parent db34410 commit 8de7023
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 19 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.3.1
- Bug fix for unintended output.

## 1.3.0
- Add a second argument, `ignoreSelfIntersections` which only checks for intersections between different features.

## 1.2.2
- Fix the missing dist files for the class-based approach

Expand Down
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ npm install sweepline-intersections
````

### Basic Use
Valid inputs: Geojson `Feature` or `Geometry` including `Polygon`, `LineString`, `MultiPolygon`, `MultiLineString`, as well as `FeatureCollection`'s.
Valid inputs: Geojson `Feature` or `Geometry` including `Polygon`, `LineString`, `MultiPolygon`, `MultiLineString`, as well as `FeatureCollection`.

Returns an array of intersection points eg, [[x1, y1], [x2, y2]]

Expand All @@ -18,11 +18,19 @@ Returns an array of intersection points eg, [[x1, y1], [x2, y2]]

const box = {type: 'Polygon', coordinates: [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]}
const intersections = findIntersections(box)
// returns an array of intersection points
// returns an array of self-intersection points
````

Also accepts an optional boolean argument second which when set to true means the module won't detect self-intersections and will only report intersections between different features. This defaults to false.
eg
````js
const findIntersections = require('sweepline-intersections')
const intersectionsBetweenFeature = findIntersections(featureCollection, true)
// returns an array of intersection points between features
````

### Complex Use
This library also provide a class-based approach which is helpful if you need to check multiple geometries against a single geometry. This allows you to save the state of the initial event queue with the primary geometry.
This library also provide a class-based approach which is helpful if you want to check multiple geometries against a single geometry. This allows you to save the state of the initial event queue with the primary geometry.

````js
import SweeplineIntersectionsClass from 'sweepline-intersections/dist/SweeplineIntersectionsClass'
Expand All @@ -40,7 +48,8 @@ This library also provide a class-based approach which is helpful if you need to
// add another feature to test against your original data
sl.addData(feature, origQueue)
// check if those two features intersect
const intersectionPoints = sl.getIntersections()
// add an optional boolean argument to ignore self-intersections
const intersectionPoints = sl.getIntersections(true)
})
````

Expand All @@ -51,7 +60,7 @@ This library also provide a class-based approach which is helpful if you need to

`.cloneEventQueue()` - clones the state of the existing event queue that's been populated with geojson. Returns a queue that you can pass to the `addData` method

`.intersect()` - Checks for segment intersections. Returns `true` if there are no segment intersections or `false` if there are intersections.
`.getIntersections(ignoreSelfIntersections)` - Checks for segment intersections. Accepts an optional boolean argument to ignore self intersections are only report intersections between features.


## Benchmarks
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sweepline-intersections",
"version": "1.2.2",
"version": "1.3.1",
"description": "A module to check if a polygon self-intersects using a sweepline algorithm",
"main": "dist/sweeplineIntersections.js",
"module": "dist/sweeplineIntersections.esm.js",
Expand Down
4 changes: 3 additions & 1 deletion src/Event.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

export default class Event {

constructor (p, ringId) {
constructor (p, featureId, ringId, eventId) {
this.p = {
x: p[0],
y: p[1]
}
this.featureId = featureId
this.ringId = ringId
this.eventId = eventId

this.otherEvent = null
this.isLeftEndpoint = null
Expand Down
4 changes: 2 additions & 2 deletions src/SweeplineIntersections.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class SweeplineIntersections {
return newQueue
}

getIntersections () {
return runCheck(this._eventQueue)
getIntersections (ignoreSelfIntersections) {
return runCheck(this._eventQueue, ignoreSelfIntersections)
}
}
8 changes: 6 additions & 2 deletions src/fillQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export default function fillEventQueue (geojson, eventQueue) {
}
}

let featureId = 0
let ringId = 0
let eventId = 0
function processFeature (featureOrGeometry, eventQueue) {
const geom = featureOrGeometry.type === 'Feature' ? featureOrGeometry.geometry : featureOrGeometry
let coords = geom.coordinates
Expand All @@ -28,8 +30,8 @@ function processFeature (featureOrGeometry, eventQueue) {
for (let iii = 0; iii < coords[i][ii].length - 1; iii++) {
nextP = coords[i][ii][iii + 1]

const e1 = new Event(currentP, ringId)
const e2 = new Event(nextP, ringId)
const e1 = new Event(currentP, featureId, ringId, eventId)
const e2 = new Event(nextP, featureId, ringId, eventId + 1)

e1.otherEvent = e2
e2.otherEvent = e1
Expand All @@ -45,7 +47,9 @@ function processFeature (featureOrGeometry, eventQueue) {
eventQueue.push(e2)

currentP = nextP
eventId = eventId + 1
}
}
}
featureId = featureId + 1
}
4 changes: 2 additions & 2 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {checkWhichEventIsLeft} from './compareEvents'
import fillEventQueue from './fillQueue'
import runCheck from './runCheck'

export default function sweeplineIntersections (geojson) {
export default function sweeplineIntersections (geojson, ignoreSelfIntersections) {
const eventQueue = new TinyQueue([], checkWhichEventIsLeft)
fillEventQueue(geojson, eventQueue)
return runCheck(eventQueue)
return runCheck(eventQueue, ignoreSelfIntersections)
}

10 changes: 8 additions & 2 deletions src/runCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import {checkWhichSegmentHasRightEndpointFirst} from './compareEvents'
import {testSegmentIntersect} from './utils'
// import {debugEventAndSegments, debugRemovingSegment} from './debug'

export default function runCheck (eventQueue) {
export default function runCheck (eventQueue, ignoreSelfIntersections) {
ignoreSelfIntersections = ignoreSelfIntersections ? ignoreSelfIntersections : false

const intersectionPoints = []
const outQueue = new TinyQueue([], checkWhichSegmentHasRightEndpointFirst)

Expand All @@ -15,7 +17,11 @@ export default function runCheck (eventQueue) {
// debugEventAndSegments(event.p, outQueue.data)
const segment = new Segment(event)
for (let i = 0; i < outQueue.data.length; i++) {
const intersection = testSegmentIntersect(segment, outQueue.data[i])
const otherSeg = outQueue.data[i]
if (ignoreSelfIntersections) {
if (otherSeg.leftSweepEvent.featureId === event.featureId) continue
}
const intersection = testSegmentIntersect(segment, otherSeg)
if (intersection !== false) intersectionPoints.push(intersection)
}
outQueue.push(segment)
Expand Down
4 changes: 0 additions & 4 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export function areCoordsSame (p1, p2) {
return Math.abs(p1 - p2) < Number.EPSILON
}

export function testSegmentIntersect (seg1, seg2) {
if (seg1 === null || seg2 === null) return false

Expand Down
10 changes: 10 additions & 0 deletions test/test.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,13 @@ test('input data is not modified', (t) => {
sweepline(geojson)
t.deepEqual(geojson, clonedData)
})

test('ignoreSelfIntersections param works', (t) => {
const geojson = load.sync(path.join(__dirname, 'fixtures', 'notSimple', 'example.geojson'))
const selfIntersectionsIgnored = sweepline(geojson, true)
t.is(selfIntersectionsIgnored.length, 0)

const intersections = sweepline(geojson, false)
t.is(intersections.length, 3)
t.deepEqual(intersections[0], [19.88085507071179, -9.98118374351003])
})

0 comments on commit 8de7023

Please sign in to comment.