Skip to content

Commit

Permalink
Share more between linked sweep events
Browse files Browse the repository at this point in the history
Closes #26
  • Loading branch information
mfogel committed Sep 18, 2018
1 parent d0ce1ef commit babe799
Show file tree
Hide file tree
Showing 8 changed files with 523 additions and 592 deletions.
12 changes: 5 additions & 7 deletions src/geom-in.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@ export class RingIn {
this.poly = poly
this.segments = []

const endTwinsSE = SweepEvent.makeTwins(geomRing[0])
let prevSE = endTwinsSE[0]
let twinsSE
let prevPoint = geomRing[0]
for (let i = 1, iMax = geomRing.length; i < iMax; i++) {
twinsSE = SweepEvent.makeTwins(geomRing[i])
this.segments.push(Segment.fromRing(prevSE, twinsSE[0], this))
prevSE = twinsSE[1]
let point = geomRing[i]
this.segments.push(Segment.fromRing(prevPoint, point, this))
prevPoint = point
}
this.segments.push(Segment.fromRing(prevSE, endTwinsSE[1], this))
this.segments.push(Segment.fromRing(prevPoint, geomRing[0], this))
}

getSweepEvents () {
Expand Down
10 changes: 5 additions & 5 deletions src/geom-out.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class RingOut {
let nextEvent = segment.rightSE
const events = [event]

const startingLE = event.linkedEvents
const startingPoint = event.point
const intersectionLEs = []

/* Walk the chain of linked events to form a closed ring */
Expand All @@ -25,7 +25,7 @@ export class RingOut {
events.push(event)

/* Is the ring complete? */
if (event.linkedEvents === startingLE) break
if (event.point === startingPoint) break

while (true) {
const availableLEs = event.getAvailableLinkedEvents()
Expand All @@ -37,7 +37,7 @@ export class RingOut {
const lastPt = events[events.length - 1].point
throw new Error(
`Unable to complete output ring starting at [${firstPt.x},` +
` ${firstPt.y}]. Last matching segment found ends at ` +
` ${firstPt.y}]. Last matching segment found ends at` +
` [${lastPt.x}, ${lastPt.y}].`
)
}
Expand All @@ -51,7 +51,7 @@ export class RingOut {
/* We must have an intersection. Check for a completed loop */
let indexLE = null
for (let j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
if (intersectionLEs[j].linkedEvents === event.linkedEvents) {
if (intersectionLEs[j].point === event.point) {
indexLE = j
break
}
Expand All @@ -67,7 +67,7 @@ export class RingOut {
/* register the intersection */
intersectionLEs.push({
index: events.length,
linkedEvents: event.linkedEvents
point: event.point,
})
/* Choose the left-most option to continue the walk */
const comparator = event.getLeftmostComparator(prevEvent)
Expand Down
44 changes: 20 additions & 24 deletions src/segment.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,32 @@ export default class Segment {
)
}

constructor (ringIn) {
constructor (leftSE, rightSE, ringIn) {
this.leftSE = leftSE
if (leftSE !== null) leftSE.segment = this
this.rightSE = rightSE
if (rightSE !== null) rightSE.segment = this
this.ringIn = ringIn
this.leftSE = null
this.rightSE = null
this.ringOut = null
this.coincidents = [this]
this._clearCache()
}

static fromRing(se1, se2, ring) {
const seg = new Segment(ring)
const ptCmp = cmpPoints(se1.point, se2.point)
static fromRing(point1, point2, ring) {
let leftSE, rightSE
const ptCmp = cmpPoints(point1, point2)
if (ptCmp < 0) {
seg.leftSE = se1
seg.rightSE = se2
leftSE = new SweepEvent(point1)
rightSE = new SweepEvent(point2)
} else if (ptCmp > 0) {
seg.leftSE = se2
seg.rightSE = se1
leftSE = new SweepEvent(point2)
rightSE = new SweepEvent(point1)
} else {
throw new Error(
`Tried to create degenerate segment at [${se1.point.x}, ${se2.point.y}]`
`Tried to create degenerate segment at [${point1.x}, ${point2.y}]`
)
}
seg.leftSE.segment = seg
seg.rightSE.segment = seg
return seg
return new Segment(leftSE, rightSE, ring)
}

get bbox () {
Expand Down Expand Up @@ -236,17 +236,13 @@ export default class Segment {
const newEvents = []
for (let i = 0, iMax = this.coincidents.length; i < iMax; i++) {
const thisSeg = this.coincidents[i]
const newSeg = new Segment(thisSeg.ringIn)
const twinsSE = SweepEvent.makeTwins(point)
newSeg.leftSE = twinsSE[0]
newSeg.leftSE.segment = newSeg
newSeg.rightSE = thisSeg.rightSE
thisSeg.rightSE.segment = newSeg
thisSeg.rightSE = twinsSE[1]
const newLeftSE = new SweepEvent(point)
const newRightSE = new SweepEvent(point)
newSegments.push(new Segment(newLeftSE, thisSeg.rightSE, thisSeg.ringIn))
thisSeg.rightSE = newRightSE
thisSeg.rightSE.segment = thisSeg
newSegments.push(newSeg)
newEvents.push(thisSeg.rightSE)
newEvents.push(newSeg.leftSE)
newEvents.push(newRightSE)
newEvents.push(newLeftSE)
}

for (let i = 1, iMax = newSegments.length; i < iMax; i++) {
Expand Down
32 changes: 15 additions & 17 deletions src/sweep-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default class SweepEvent {
static compare (a, b) {

// if the events are already linked, then we know the points are equal
if (a.linkedEvents !== b.linkedEvents) {
if (a.point !== b.point) {

// favor event with a point that the sweep line hits first
const cmpX = cmp(a.point.x, b.point.x)
Expand Down Expand Up @@ -49,35 +49,33 @@ export default class SweepEvent {
)
}

static makeTwins(point) {
const se1 = new SweepEvent
const se2 = new SweepEvent
se1.point = se2.point = point
return se1.linkedEvents = se2.linkedEvents = [se1, se2]
// Warning: input will be modified and re-used (for performance)
constructor (point) {
if (point.events === undefined) point.events = [this]
else point.events.push(this)
this.point = point
}

link (other) {
const otherLE = other.linkedEvents
if (otherLE === this.linkedEvents) {
if (other.point === this.point) {
throw new Error(`Tried to link already linked events`)
}
for (let i = 0, iMax = otherLE.length; i < iMax; i++) {
const evt = otherLE[i]
this.linkedEvents.push(evt)
evt.linkedEvents = this.linkedEvents
const otherEvents = other.point.events
for (let i = 0, iMax = otherEvents.length; i < iMax; i++) {
const evt = otherEvents[i]
this.point.events.push(evt)
evt.point = this.point
if (this.otherSE.linkedEvents === evt.otherSE.linkedEvents) {
if (this.otherSE.point === evt.otherSE.point) {
this.segment.registerCoincident(evt.segment)
}
}
}

getAvailableLinkedEvents () {
if (this.linkedEvents.length === 1) return []

// point.events is always of length 2 or greater
const events = []
for (let i = 0, iMax = this.linkedEvents.length; i < iMax; i++) {
const evt = this.linkedEvents[i]
for (let i = 0, iMax = this.point.events.length; i < iMax; i++) {
const evt = this.point.events[i]
if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult) {
events.push(evt)
}
Expand Down
Loading

0 comments on commit babe799

Please sign in to comment.