diff --git a/src/Event.js b/src/Event.js index ef6d452..e9d796b 100644 --- a/src/Event.js +++ b/src/Event.js @@ -1,7 +1,7 @@ export default class Event { - constructor (p, featureId, ringId, eventId) { + constructor (p, featureId, ringId, eventId, vertexId) { this.p = { x: p[0], y: p[1] @@ -9,6 +9,7 @@ export default class Event { this.featureId = featureId this.ringId = ringId this.eventId = eventId + this.vertexId = vertexId this.otherEvent = null this.isLeftEndpoint = null diff --git a/src/Segment.js b/src/Segment.js index b503126..830dc20 100644 --- a/src/Segment.js +++ b/src/Segment.js @@ -1,7 +1,16 @@ export default class Segment { - constructor (event) { + constructor (event, segmentId) { this.leftSweepEvent = event this.rightSweepEvent = event.otherEvent + this.segmentId = segmentId + } + + get earliestVertexId () { + return Math.min(this.leftSweepEvent.vertexId, this.rightSweepEvent.vertexId) + } + + get isPartOfOuterRing () { + return this.leftSweepEvent.ringId === 0 } } diff --git a/src/fillQueue.js b/src/fillQueue.js index 7dddac9..4fee9c7 100644 --- a/src/fillQueue.js +++ b/src/fillQueue.js @@ -5,17 +5,16 @@ export default function fillEventQueue (geojson, eventQueue) { if (geojson.type === 'FeatureCollection') { const features = geojson.features for (let i = 0; i < features.length; i++) { - processFeature(features[i], eventQueue) + processFeature(features[i], eventQueue, i) } } else { - processFeature(geojson, eventQueue) + processFeature(geojson, eventQueue, 0) } } -let featureId = 0 -let ringId = 0 -let eventId = 0 -function processFeature (featureOrGeometry, eventQueue) { +function processFeature (featureOrGeometry, eventQueue, featureId) { + let eventId = 0 + const geom = featureOrGeometry.type === 'Feature' ? featureOrGeometry.geometry : featureOrGeometry let coords = geom.coordinates // standardise the input @@ -26,12 +25,11 @@ function processFeature (featureOrGeometry, eventQueue) { for (let ii = 0; ii < coords[i].length; ii++) { let currentP = coords[i][ii][0] let nextP = null - ringId = ringId + 1 for (let iii = 0; iii < coords[i][ii].length - 1; iii++) { nextP = coords[i][ii][iii + 1] - const e1 = new Event(currentP, featureId, ringId, eventId) - const e2 = new Event(nextP, featureId, ringId, eventId + 1) + const e1 = new Event(currentP, featureId, ii, eventId, iii) + const e2 = new Event(nextP, featureId, ii, eventId + 1, iii + 1) e1.otherEvent = e2 e2.otherEvent = e1 @@ -51,5 +49,4 @@ function processFeature (featureOrGeometry, eventQueue) { } } } - featureId = featureId + 1 } diff --git a/src/runCheck.js b/src/runCheck.js index 97b14d5..fe39804 100644 --- a/src/runCheck.js +++ b/src/runCheck.js @@ -10,12 +10,13 @@ export default function runCheck (eventQueue, ignoreSelfIntersections) { const intersectionPoints = [] const outQueue = new TinyQueue([], checkWhichSegmentHasRightEndpointFirst) - + let segmentId = 0 while (eventQueue.length) { const event = eventQueue.pop() if (event.isLeftEndpoint) { // debugEventAndSegments(event.p, outQueue.data) - const segment = new Segment(event) + const segment = new Segment(event, segmentId) + segmentId = segmentId + 1 for (let i = 0; i < outQueue.data.length; i++) { const otherSeg = outQueue.data[i] if (ignoreSelfIntersections) { diff --git a/src/utils.js b/src/utils.js index eae7f04..463cbda 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,5 @@ +import {orient2d} from 'robust-predicates' + export function testSegmentIntersect (seg1, seg2) { if (seg1 === null || seg2 === null) return false @@ -17,6 +19,12 @@ export function testSegmentIntersect (seg1, seg2) { const x4 = seg2.rightSweepEvent.p.x const y4 = seg2.rightSweepEvent.p.y + const score1 = orient2d(x1, y1, x2, y2, x3, y3) + const score2 = orient2d(x1, y1, x2, y2, x4, y4) + if (score1 === score2) { + return false + } + const denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)) const numeA = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)) const numeB = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3)) @@ -32,7 +40,24 @@ export function testSegmentIntersect (seg1, seg2) { if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) { const x = x1 + (uA * (x2 - x1)) const y = y1 + (uA * (y2 - y1)) - return [x, y] + + const seg1Start = seg1.leftSweepEvent.vertexId < seg1.rightSweepEvent.vertexId ? seg1.leftSweepEvent : seg1.rightSweepEvent + const seg2Start = seg2.leftSweepEvent.vertexId < seg2.rightSweepEvent.vertexId ? seg2.leftSweepEvent : seg2.rightSweepEvent + return { + seg1, + seg2, + intersection: [x, y], + distanceFromSeg1Start: distance([seg1Start.p.x, seg1Start.p.y], [x, y]), + distanceFromSeg2Start: distance([seg2Start.p.x, seg2Start.p.y], [x, y]) + } } return false } + +function distance (p1, p2) { + let xs = p2[0] - p1[0] + let ys = p2[1] - p1[1] + xs *= xs + ys *= ys + return Math.sqrt(xs + ys) +} diff --git a/test/test.e2e.js b/test/test.e2e.js index f50253a..2d01845 100644 --- a/test/test.e2e.js +++ b/test/test.e2e.js @@ -42,5 +42,5 @@ test('ignoreSelfIntersections param works', (t) => { const intersections = sweepline(geojson, false) t.is(intersections.length, 3) - t.deepEqual(intersections[0], [19.88085507071179, -9.98118374351003]) + t.deepEqual(intersections[0].intersection, [19.88085507071179, -9.98118374351003]) })