diff --git a/src/clean-input.js b/src/clean-input.js index cf737d4..fa1dcf5 100644 --- a/src/clean-input.js +++ b/src/clean-input.js @@ -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) diff --git a/test/clean-input.test.js b/test/clean-input.test.js index 84f0df4..d9ce45b 100644 --- a/test/clean-input.test.js +++ b/test/clean-input.test.js @@ -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()', () => { diff --git a/test/end-to-end/issue-85/args.geojson b/test/end-to-end/issue-85/args.geojson new file mode 100644 index 0000000..b2ea9ee --- /dev/null +++ b/test/end-to-end/issue-85/args.geojson @@ -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] + ] + ] + ] + } + } + ] +} diff --git a/test/end-to-end/issue-85/union.geojson b/test/end-to-end/issue-85/union.geojson new file mode 100644 index 0000000..ce56f38 --- /dev/null +++ b/test/end-to-end/issue-85/union.geojson @@ -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] + ] + ] + ] + } +}