Skip to content

Commit

Permalink
Use rings/polys/multipolyg before/after segment
Browse files Browse the repository at this point in the history
  • Loading branch information
mfogel committed Nov 17, 2018
1 parent 03469ec commit fe1fd9f
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 387 deletions.
57 changes: 0 additions & 57 deletions src/geom-in.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,6 @@ export class RingIn {
get isInterior () {
return this.poly.exteriorRing !== this
}

/* Given a segment on this rings with these relationships to other rings,
* is it a valid segment of the ring's poly? */
isValid (ringsSameSLER, ringsDiffSLER, ringsInsideOf) {
const exterior = this.poly.exteriorRing
const interiors = this.poly.interiorRings

if (this === exterior) {
// exterior segments inside or interior, nope
for (let i = 0, iMax = ringsInsideOf.length; i < iMax; i++) {
if (interiors.includes(ringsInsideOf[i])) return false
}

// overlap with an interior of same SWL orientatio, nope
for (let i = 0, iMax = ringsSameSLER.length; i < iMax; i++) {
if (interiors.includes(ringsSameSLER[i])) return false
}

return true
}

// interior rings that aren't inside the exterior nor
// overlapping with different SWE
if (!ringsInsideOf.includes(exterior)) {
if (!ringsDiffSLER.includes(exterior)) return false
}

// interior rings inside another interior, nope
for (let i = 0, iMax = ringsInsideOf.length; i < iMax; i++) {
if (interiors.includes(ringsInsideOf[i])) return false
}

// overlapping interiors with different sweep line orientation, nope
for (let i = 0, iMax = ringsDiffSLER.length; i < iMax; i++) {
if (interiors.includes(ringsDiffSLER[i])) return false
}

return true
}
}

export class PolyIn {
Expand All @@ -98,24 +59,6 @@ export class PolyIn {
}
return sweepEvents
}

/* Given a segment with these rings, is that segment inside this polygon? */
isInside (ringsOnEdgeOf, ringsInsideOf) {
// if we're on an edge, we can't be inside
for (let i = 0, iMax = ringsOnEdgeOf.length; i < iMax; i++) {
if (ringsOnEdgeOf[i].poly === this) return false
}

// we need to be inside the exterior, and nothing else
let isInsideExterior = false
for (let i = 0, iMax = ringsInsideOf.length; i < iMax; i++) {
const ring = ringsInsideOf[i]
if (ring.poly !== this) continue
if (ring.isInterior) return false
isInsideExterior = true
}
return isInsideExterior
}
}

export class MultiPolyIn {
Expand Down
167 changes: 37 additions & 130 deletions src/segment.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ export default class Segment {
if (rightSE !== null) rightSE.segment = this
this.ringIn = ringIn
this.ringOut = null
this.prev = null
this.coincidents = [this]
this._clearCache()
this._cache = {}
}

static fromRing(point1, point2, ring) {
Expand Down Expand Up @@ -271,7 +272,6 @@ export default class Segment {

registerPrev (other) {
this.prev = other
this._clearCache()
}

registerRingOut (ring) {
Expand All @@ -298,90 +298,9 @@ export default class Segment {
}

_prevInResult () {
let prev = this.prev
while (prev && !prev.isInResult) prev = prev.prev
return prev
}

/* Does this segment 'open' its' ring for the sweep line?
* For non-vertical segments, this means they're along a bottom of the ring.
* For vertical segments, this means they're along a left side of the ring. */
get opensRing () {
const key = 'opensRing'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

_opensRing () {
return ! this.ringsBefore.includes(this.ringIn)
}

/* Does this segment 'open' its' poly for the sweep line ? */
get opensPoly () {
return this.ringIn.isExterior === this.opensRing
}

/* Array of input rings this segment is inside of (not on boundary) */
get ringsInsideOf () {
const key = 'ringsInsideOf'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

_ringsInsideOf () {
const rings = []
const ringsBefore = this.ringsBefore
const ringsAfter = this.ringsAfter
for (let i = 0, iMax = ringsBefore.length; i < iMax; i++) {
const ring = ringsBefore[i]
if (ringsAfter.includes(ring) && !rings.includes(ring)) rings.push(ring)
}
for (let i = 0, iMax = ringsAfter.length; i < iMax; i++) {
const ring = ringsAfter[i]
if (ringsBefore.includes(ring) && !rings.includes(ring)) rings.push(ring)
}
return rings
}

/* Array of input rings this segment is on boundary of */
get ringsOnEdgeOf () {
const key = 'ringsOnEdgeOf'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

_ringsOnEdgeOf() {
const rings = []
const ringsBefore = this.ringsBefore
const ringsAfter = this.ringsAfter
for (let i = 0, iMax = ringsBefore.length; i < iMax; i++) {
const ring = ringsBefore[i]
if (!ringsAfter.includes(ring) && !rings.includes(ring)) rings.push(ring)
}
for (let i = 0, iMax = ringsAfter.length; i < iMax; i++) {
const ring = ringsAfter[i]
if (!ringsBefore.includes(ring) && !rings.includes(ring)) rings.push(ring)
}
return rings
}

/* Arrays of the rings for which this segment, and its' coincidents,
* open and close */
get ringsOpensCloses () {
const key = 'ringsOpensCloses'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

_ringsOpensCloses () {
const ringsOpens = []
const ringsCloses = []
for (let i = 0, iMax = this.coincidents.length; i < iMax; i++) {
const segment = this.coincidents[i]
if (segment.opensRing) ringsOpens.push(segment.ringIn)
else ringsCloses.push(segment.ringIn)
}
return [ringsOpens, ringsCloses]
if (this.prev === null) return null
if (this.prev.isInResult) return this.prev
return this.prev.prevInResult
}

get ringsBefore () {
Expand Down Expand Up @@ -413,54 +332,46 @@ export default class Segment {
return rings
}

/* Is this segment valid on our own polygon? (ie not outside exterior ring) */
get isValidEdgeForPoly () {
const key = 'isValidEdgeForPoly'
get multiPolysBefore () {
const key = 'multiPolysBefore'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

_isValidEdgeForPoly () {
// SLER: sweep line entering orientation
let sameSLER
let diffSLER
if (this.opensRing) {
sameSLER = this.ringsOpensCloses[0]
diffSLER = this.ringsOpensCloses[1]
} else {
diffSLER = this.ringsOpensCloses[0]
sameSLER = this.ringsOpensCloses[1]
}
return this.ringIn.isValid(sameSLER, diffSLER, this.ringsInsideOf)
_multiPolysBefore () {
if (!this.prev) return []
if (this.coincidents === this.prev.coincidents) return this.prev.multiPolysBefore
return this.prev.multiPolysAfter
}

/* Array of multipolys this segment is inside of */
getMultiPolysInsideOf () {
const mps = []
for (let i = 0, iMax = this.ringsInsideOf.length; i < iMax; i++) {
const poly = this.ringsInsideOf[i].poly
if (mps.includes(poly.multiPoly)) continue
if (!poly.isInside(this.ringsOnEdgeOf, this.ringsInsideOf)) continue
mps.push(poly.multiPoly)
}
return mps
get multiPolysAfter () {
const key = 'multiPolysAfter'
if (this._cache[key] === undefined) this._cache[key] = this[`_${key}`]()
return this._cache[key]
}

/* Combine the above two functions for efficient looping */
getMultiPolysBeforeAndAfter () {
const mpsBefore = this.getMultiPolysInsideOf()
const mpsAfter = mpsBefore.slice(0)
for (let i = 0, iMax = this.coincidents.length; i < iMax; i++) {
const seg = this.coincidents[i]
if (!seg.isValidEdgeForPoly) continue
const mp = seg.ringIn.poly.multiPoly
if (seg.opensPoly) {
if (!mpsAfter.includes(mp)) mpsAfter.push(mp)
} else {
if (!mpsBefore.includes(mp)) mpsBefore.push(mp)
_multiPolysAfter () {
// first calcualte our polysAfter
const polysAfter = []
const polysExclude = []
for (let i = 0, iMax = this.ringsAfter.length; i < iMax; i++) {
const ring = this.ringsAfter[i]
const poly = ring.poly
if (polysExclude.includes(poly)) continue
if (ring.isExterior) polysAfter.push(poly)
else {
if (! polysExclude.includes(poly)) polysExclude.push(poly)
const index = polysAfter.indexOf(ring.poly)
if (index !== -1) polysAfter.splice(index, 1)
}
}
return [mpsBefore, mpsAfter]
// now calculate our multiPolysAfter
const mps = []
for (let i = 0, iMax = polysAfter.length; i < iMax; i++) {
const mp = polysAfter[i].multiPoly
if (!mps.includes(mp)) mps.push(mp)
}
return mps
}

/* Is this segment part of the final result? */
Expand All @@ -474,9 +385,8 @@ export default class Segment {
// if it's not the coincidence winner, it's not in the resul
if (this !== this.coincidents[0]) return false

const mpsBeforeAfter = this.getMultiPolysBeforeAndAfter()
const mpsBefore = mpsBeforeAfter[0]
const mpsAfter = mpsBeforeAfter[1]
const mpsBefore = this.multiPolysBefore
const mpsAfter = this.multiPolysAfter

switch (operation.type) {
case operation.types.UNION:
Expand Down Expand Up @@ -521,7 +431,4 @@ export default class Segment {
}
}

_clearCache () {
this._cache = {}
}
}

0 comments on commit fe1fd9f

Please sign in to comment.