Skip to content

Commit

Permalink
Handle input geom with infinitely thin peninsula
Browse files Browse the repository at this point in the history
Handle the situation where one of the input polygons has an infinitely
thin 'peninsula' just before its last coordinate.

Fixes #85
  • Loading branch information
mfogel committed Aug 16, 2019
1 parent e7ab60d commit 3a67c13
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
23 changes: 12 additions & 11 deletions src/clean-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,23 @@ export const cleanMultiPoly = multipoly => {
* WARN: input modified directly */
export const cleanRing = ring => {
if (ring.length === 0) return
const firstPt = ring[0]
const lastPt = ring[ring.length - 1]
if (firstPt.x === lastPt.x && firstPt.y === lastPt.y) ring.pop()

const isPointUncessary = (prevPt, pt, nextPt) =>
(prevPt.x === pt.x && prevPt.y === pt.y) ||
(nextPt.x === pt.x && nextPt.y === pt.y) ||
compareVectorAngles(pt, prevPt, nextPt) === 0

let i = 0
let prevPt, nextPt
let pt, prevPt, nextPt
while (i < ring.length) {
pt = ring[i]
prevPt = (i === 0 ? ring[ring.length - 1] : ring[i - 1])
if (pt.x === prevPt.x && pt.y === prevPt.y) {
ring.splice(i - 1, 1)
continue
}
nextPt = (i === ring.length - 1 ? ring[0] : ring[i + 1])
if (isPointUncessary(prevPt, ring[i], nextPt)) ring.splice(i, 1)
else i++
if (compareVectorAngles(pt, prevPt, nextPt) === 0) {
ring.splice(i, 1)
if (i > 0) i--
continue
}
i++
}

// if our ring has less than 3 distinct points now (so is degenerate)
Expand Down
35 changes: 35 additions & 0 deletions test/clean-input.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,41 @@ describe('cleanRing()', () => {
cleanRing(ringBad)
expect(ringBad).toEqual([])
})

test('removes last two when colinear', () => {
const ringBad = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 0, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: 0 },
]
const ringGood = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
]
cleanRing(ringBad)
expect(ringBad).toEqual(ringGood)
})

test('removes last two when repeats', () => {
const ringBad = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 0, y: 0 },
{ x: 0, y: 0 },
]
const ringGood = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
]
cleanRing(ringBad)
expect(ringBad).toEqual(ringGood)
})
})

describe('pointsAsObjects()', () => {
Expand Down
24 changes: 24 additions & 0 deletions test/end-to-end/issue-85/args.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": null,
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[0.11978, 18.32302],
[0.14685, 17.90202],
[0.15809, 18.11877],
[0.11978, 18.32302],
[0.11978, 18.32306],
[0.11978, 18.32302]
]
]
]
}
}
]
}
17 changes: 17 additions & 0 deletions test/end-to-end/issue-85/union.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[0.11978, 18.32302],
[0.14685, 17.90202],
[0.15809, 18.11877],
[0.11978, 18.32302]
]
]
]
}
}

0 comments on commit 3a67c13

Please sign in to comment.