diff --git a/src/main/java/com/mapconductor/core/polygon/PolygonHoleUnion.kt b/src/main/java/com/mapconductor/core/polygon/PolygonHoleUnion.kt index 35d6245..aa0ad07 100644 --- a/src/main/java/com/mapconductor/core/polygon/PolygonHoleUnion.kt +++ b/src/main/java/com/mapconductor/core/polygon/PolygonHoleUnion.kt @@ -5,9 +5,12 @@ import com.mapconductor.core.features.GeoPointInterface import kotlin.math.PI import kotlin.math.abs import kotlin.math.atan2 +import kotlin.math.ceil +import kotlin.math.floor import kotlin.math.hypot import kotlin.math.min import kotlin.math.roundToLong +import kotlin.math.sqrt /** * 重なり合う穴リング同士を平面(経度緯度)座標系で結合する。外部ジオメトリライブラリ非依存。 @@ -71,6 +74,9 @@ private const val Q = 1e-9 // フィーチャースケール座標での平行・共線・線分上判定の許容誤差。 private const val EPS = 1e-12 +// 中点からこれより近い部分辺はその中点を通っている(度。Q よりはるかに小さい)。 +private const val ON_EDGE = 1e-12 + private fun unionRings(rings: List>): List> { // 全リングの有向辺(閉じたものとして扱う)。 val edges = mutableListOf() @@ -87,9 +93,127 @@ private fun unionRings(rings: List>): List> { return traceRings(boundary) } +// intersectionPoints が線分の外接矩形の外まで拾う距離(度)。共線判定は直線から EPS / |seg| までの +// 辺を受け入れ、sqrt(EPS) = 1e-6 より短い線分はそこで除かれるので、高々 2e-6。 +private const val MEET_PAD = 4e-6 + +// 部分辺の中点から左右の標本点までの距離の上限の 2 倍(度)。 +private const val CLEARANCE_CAP = 2e-5 + +/** + * 辺を外接矩形で一様格子に登録し、探索をすべての辺ではなく矩形の近くの辺だけに絞る。 + * 辺の矩形が触れるすべてのセルに登録するので、矩形が触れるセルを全部見れば、 + * その矩形と出会い得る辺はすべて見つかる。 + */ +private class EdgeGrid( + edges: List, + pad: Double, +) { + private val side: Int + private val minX: Double + private val minY: Double + private val cellW: Double + private val cellH: Double + private val cells = HashMap() + private val seen = IntArray(edges.size) + private var stamp = 0 + + init { + var x0 = Double.POSITIVE_INFINITY + var y0 = Double.POSITIVE_INFINITY + var x1 = Double.NEGATIVE_INFINITY + var y1 = Double.NEGATIVE_INFINITY + for (e in edges) { + x0 = minOf(x0, e.a.x, e.b.x) + x1 = maxOf(x1, e.a.x, e.b.x) + y0 = minOf(y0, e.a.y, e.b.y) + y1 = maxOf(y1, e.a.y, e.b.y) + } + side = ceil(sqrt(edges.size.toDouble())).toInt().coerceIn(1, 1024) + minX = x0 + minY = y0 + cellW = ((x1 - x0) / side).let { if (it > 0.0) it else 1.0 } + cellH = ((y1 - y0) / side).let { if (it > 0.0) it else 1.0 } + for (i in edges.indices) { + val e = edges[i] + forCells( + minOf(e.a.x, e.b.x) - pad, + minOf(e.a.y, e.b.y) - pad, + maxOf(e.a.x, e.b.x) + pad, + maxOf(e.a.y, e.b.y) + pad, + ) { key -> cells.getOrPut(key) { IntArrayList() }.add(i) } + } + } + + /** 矩形が触れるセルに登録された辺の番号。各辺 1 回、順序は不定。 */ + fun near( + minX: Double, + minY: Double, + maxX: Double, + maxY: Double, + out: IntArrayList, + ): IntArrayList { + out.clear() + val current = ++stamp + forCells(minX, minY, maxX, maxY) { key -> + val bucket = cells[key] ?: return@forCells + for (k in 0 until bucket.size) { + val i = bucket[k] + if (seen[i] == current) continue + seen[i] = current + out.add(i) + } + } + return out + } + + private inline fun forCells( + minX: Double, + minY: Double, + maxX: Double, + maxY: Double, + visit: (Int) -> Unit, + ) { + val cx0 = cell(minX, this.minX, cellW) + val cx1 = cell(maxX, this.minX, cellW) + val cy0 = cell(minY, this.minY, cellH) + val cy1 = cell(maxY, this.minY, cellH) + for (cx in cx0..cx1) { + for (cy in cy0..cy1) visit(cx * side + cy) + } + } + + private fun cell( + v: Double, + min: Double, + size: Double, + ): Int = floor((v - min) / size).coerceIn(0.0, (side - 1).toDouble()).toInt() +} + +/** 箱詰めしない Int の可変長配列。 */ +private class IntArrayList { + private var items = IntArray(4) + var size = 0 + private set + + operator fun get(index: Int): Int = items[index] + + fun add(value: Int) { + if (size == items.size) items = items.copyOf(size * 2) + items[size++] = value + } + + fun clear() { + size = 0 + } +} + /** 各辺を、他の辺が交差・接触する全ての点で分割する。 */ private fun splitEdges(edges: List): List { val result = mutableListOf() + // この辺の矩形から MEET_PAD 以内に矩形が来る辺だけが、この辺と出会い得る。 + val grid = EdgeGrid(edges, MEET_PAD) + val near = IntArrayList() for (i in edges.indices) { val seg = edges[i] val dir = sub(seg.b, seg.a) @@ -105,7 +229,15 @@ private fun splitEdges(edges: List): List { } add(seg.a) add(seg.b) - for (j in edges.indices) { + grid.near( + minOf(seg.a.x, seg.b.x) - MEET_PAD, + minOf(seg.a.y, seg.b.y) - MEET_PAD, + maxOf(seg.a.x, seg.b.x) + MEET_PAD, + maxOf(seg.a.y, seg.b.y) + MEET_PAD, + near, + ) + for (k in 0 until near.size) { + val j = near[k] if (i == j) continue for (p in intersectionPoints(seg, edges[j])) add(p) } @@ -133,6 +265,9 @@ private fun classifyBoundary( ): List { val out = mutableListOf() val seen = HashSet>() + val grid = EdgeGrid(subEdges, 0.0) + val near = IntArrayList() + val ringsBounds = rings.map(::ringBounds) for (seg in subEdges) { val dir = sub(seg.b, seg.a) val len = hypot(dir.x, dir.y) @@ -140,12 +275,15 @@ private fun classifyBoundary( val mid = add2(seg.a, scale(dir, 0.5)) // 単位左法線。中点の左右すぐ横でカバレッジを標本化する。分割後は他の辺が - // この部分辺の内部を横切らないため、微小オフセットはこの辺が隔てる 2 セル内に収まる。 + // この部分辺の内部を横切らないため、最寄りの他の辺までの距離より短いオフセットなら + // この辺が隔てる 2 セル内に収まる。固定オフセットでは収まらない: 別の穴がそれより + // 近くを通る(1e-5 度離れた 2 つの穴)と標本点がその穴に入り、辺が両側とも内部に + // 見えて落とされ、繋ぎ直したリングが穴を横切る。 val nx = -dir.y / len val ny = dir.x / len - val off = min(len * 0.25, 1e-5) - val leftInside = coverage(Vec(mid.x + nx * off, mid.y + ny * off), rings) > 0 - val rightInside = coverage(Vec(mid.x - nx * off, mid.y - ny * off), rings) > 0 + val off = min(len * 0.25, 0.5 * clearance(mid, CLEARANCE_CAP, subEdges, grid, near)) + val leftInside = coverage(Vec(mid.x + nx * off, mid.y + ny * off), rings, ringsBounds) > 0 + val rightInside = coverage(Vec(mid.x - nx * off, mid.y - ny * off), rings, ringsBounds) > 0 if (leftInside == rightInside) continue // 両側とも内部、または両側とも外部 // 内部が左側に来る向きへ揃える。 @@ -158,6 +296,46 @@ private fun classifyBoundary( return out } +/** + * `point`(部分辺の中点)から、それを通らない最寄りの部分辺までの距離。`cap` より近いものが + * 無ければ `cap`。その部分辺自身と、他のリングから来た同じ部分辺は中点を通るので除く。 + * 点のまわり `cap` の矩形の近くに登録された部分辺だけを調べる。`cap` より近いものはその中にある。 + */ +private fun clearance( + point: Vec, + cap: Double, + subEdges: List, + grid: EdgeGrid, + near: IntArrayList, +): Double { + var best = cap + grid.near(point.x - cap, point.y - cap, point.x + cap, point.y + cap, near) + for (k in 0 until near.size) { + val e = subEdges[near[k]] + if (minOf(e.a.x, e.b.x) > point.x + best || + maxOf(e.a.x, e.b.x) < point.x - best || + minOf(e.a.y, e.b.y) > point.y + best || + maxOf(e.a.y, e.b.y) < point.y - best + ) { + continue + } + val d = distanceToSegment(point, e) + if (d > ON_EDGE && d < best) best = d + } + return best +} + +private fun distanceToSegment( + p: Vec, + e: Edge, +): Double { + val d = sub(e.b, e.a) + val lenSq = dot(d, d) + val t = if (lenSq > 0.0) clamp01(dot(sub(p, e.a), d) / lenSq) else 0.0 + val q = add2(e.a, scale(d, t)) + return hypot(p.x - q.x, p.y - q.y) +} + /** 有向境界辺を連結して閉リングにする。 */ private fun traceRings(edges: List): List> { val byStart = HashMap>() @@ -250,11 +428,23 @@ private fun intersectionPoints( return listOf(add2(seg.a, scale(r, clamp01(t)))) } -/** 点を内部に含むリングの数。 */ +/** + * 点を内部に含むリングの数。緯度の範囲が点の緯度をまたがないリングには pointInRing が数える辺が + * 無いので飛ばす。 + */ private fun coverage( point: Vec, rings: List>, -): Int = rings.count { pointInRing(point, it) } + bounds: List, +): Int { + var count = 0 + for (i in rings.indices) { + val b = bounds[i] + if (point.y < b[1] || point.y >= b[3]) continue + if (pointInRing(point, rings[i])) count++ + } + return count +} /** 偶奇規則のレイキャスティングによる点包含判定(巻き方向に依存しない)。 */ private fun pointInRing( @@ -307,6 +497,21 @@ private fun toRing( return if (points.size >= 3) points else null } +/** リングの外接矩形 [minX, minY, maxX, maxY]。 */ +private fun ringBounds(ring: List): DoubleArray { + var minX = Double.POSITIVE_INFINITY + var minY = Double.POSITIVE_INFINITY + var maxX = Double.NEGATIVE_INFINITY + var maxY = Double.NEGATIVE_INFINITY + for (p in ring) { + if (p.x < minX) minX = p.x + if (p.x > maxX) maxX = p.x + if (p.y < minY) minY = p.y + if (p.y > maxY) maxY = p.y + } + return doubleArrayOf(minX, minY, maxX, maxY) +} + private fun signedArea(ring: List): Double { var area = 0.0 for (i in ring.indices) { diff --git a/src/test/java/com/mapconductor/core/polygon/PolygonHoleUnionFixtureTest.kt b/src/test/java/com/mapconductor/core/polygon/PolygonHoleUnionFixtureTest.kt new file mode 100644 index 0000000..79055bd --- /dev/null +++ b/src/test/java/com/mapconductor/core/polygon/PolygonHoleUnionFixtureTest.kt @@ -0,0 +1,101 @@ +package com.mapconductor.core.polygon + +import com.mapconductor.core.features.GeoPoint +import com.mapconductor.core.features.GeoPointInterface +import org.junit.Assert.assertSame +import org.junit.Assert.assertTrue +import org.junit.Test +import kotlin.math.abs + +/** + * unionHoleRings keeps the area of the union of the holes: holes that touch at a + * point or share (part of) an edge add up, overlaps count once. + * + * js-sdk-core (`PolygonHoleUnion.test.mjs`) and ios-sdk-core + * (`PolygonHoleUnionFixtureTests`) read the same `polygon-hole-union-fixture.txt`; + * the expected areas are shapely's unary_union. + */ +class PolygonHoleUnionFixtureTest { + private class Case( + val name: String, + val unit: Double, + val originLon: Double, + val originLat: Double, + val unionArea: Double, + ) { + var outer: List? = null + val holes = mutableListOf>() + + fun toGeo(flat: List): List = + flat.chunked(2).map { (x, y) -> + GeoPoint.fromLatLong(latitude = originLat + y * unit, longitude = originLon + x * unit) + } + + /** Planar area in grid units². */ + fun areaInUnits(ring: List): Double { + var a = 0.0 + for (i in ring.indices) { + val p = ring[i] + val q = ring[(i + 1) % ring.size] + val px = (p.longitude - originLon) / unit + val py = (p.latitude - originLat) / unit + val qx = (q.longitude - originLon) / unit + val qy = (q.latitude - originLat) / unit + a += px * qy - qx * py + } + return a / 2.0 + } + } + + private fun readCases(): List { + val stream = + requireNotNull(javaClass.classLoader?.getResourceAsStream("polygon-hole-union-fixture.txt")) { + "polygon-hole-union-fixture.txt not on the test classpath" + } + val cases = mutableListOf() + stream.bufferedReader().forEachLine { line -> + if (line.isBlank() || line.startsWith("#")) return@forEachLine + val parts = line.split("|") + when (parts[0]) { + "case" -> + cases.add( + Case( + name = parts[1], + unit = parts[2].toDouble(), + originLon = parts[3].toDouble(), + originLat = parts[4].toDouble(), + unionArea = parts[5].toDouble(), + ), + ) + "outer" -> cases.last().outer = parts[1].split(",").map { it.toDouble() } + "hole" -> cases.last().holes.add(parts[1].split(",").map { it.toDouble() }) + } + } + return cases + } + + @Test + fun unionKeepsTheAreaOfTheUnion() { + val cases = readCases() + assertTrue("fixture has cases", cases.size >= 20) + val failures = mutableListOf() + for (c in cases) { + val holes = c.holes.map { c.toGeo(it) } + val result = + c.outer?.let { outer -> + val state = PolygonState(points = c.toGeo(outer), holes = holes) + val unioned = state.unionHoles() + assertSame("${c.name}: the outline is left alone", state.points, unioned.points) + unioned.holes + } ?: unionHoleRings(holes) + val area = result.sumOf { abs(c.areaInUnits(it)) } + if (abs(area - c.unionArea) > 1e-6 * c.unionArea) { + failures.add("${c.name}: area $area != union ${c.unionArea} (${result.size} rings from ${holes.size})") + } + if (result.any { c.areaInUnits(it) >= 0.0 }) { + failures.add("${c.name}: a hole came back counter-clockwise") + } + } + assertTrue(failures.joinToString("\n"), failures.isEmpty()) + } +} diff --git a/src/test/resources/polygon-hole-union-fixture.txt b/src/test/resources/polygon-hole-union-fixture.txt new file mode 100644 index 0000000..1156d86 --- /dev/null +++ b/src/test/resources/polygon-hole-union-fixture.txt @@ -0,0 +1,231 @@ +# Hole-union fixture. The same file in js-sdk-core, android-sdk-core and ios-sdk-core. +# +# unionHoleRings must keep the area of the union of the holes: holes that touch +# at a point or share an edge (or part of one) add up, an overlap counts once. +# unionArea is shapely's unary_union of the holes. +# +# case|name|unit|originLongitude|originLatitude|unionArea +# outer|x,y,x,y,... (optional: the polygon's outline) +# hole|x,y,x,y,... (one line per hole, not closed) +# +# A vertex is (originLongitude + x * unit, originLatitude + y * unit) degrees, +# and areas are in unit². The Boston street parcels are Analyze Boston's +# Parcels 2025 (ODC PDDL) rounded to 1e-5 degree, before their holes were +# moved apart (examples/basic/tools/boston/pack.py in react-sdk). + +case|corner touch (1e-05 degree grid)|1e-05|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,10,20,10,20,20,10,20 + +case|shared edge (1e-05 degree grid)|1e-05|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,0,20,0,20,10,10,10 + +case|part of an edge shared (1e-05 degree grid)|1e-05|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,5,20,5,20,15,10,15 + +case|chain of four: edge, corner, part of an edge (1e-05 degree grid)|1e-05|-71.06|42.36|400.0 +hole|0,0,10,0,10,10,0,10 +hole|10,0,20,0,20,10,10,10 +hole|20,10,30,10,30,20,20,20 +hole|25,20,35,20,35,30,25,30 + +case|three around one vertex (1e-05 degree grid)|1e-05|-71.06|42.36|300.0 +hole|0,0,10,0,10,10,0,10 +hole|10,10,20,10,20,20,10,20 +hole|0,10,10,10,10,20,0,20 + +case|overlap (1e-05 degree grid)|1e-05|-71.06|42.36|175.0 +hole|0,0,10,0,10,10,0,10 +hole|5,5,15,5,15,15,5,15 + +case|three overlapping (1e-05 degree grid)|1e-05|-71.06|42.36|221.0 +hole|0,0,10,0,10,10,0,10 +hole|5,5,15,5,15,15,5,15 +hole|8,0,18,0,18,7,8,7 + +case|touching pair beside a hole one unit away (1e-05 degree grid)|1e-05|-71.06|42.36|700.0 +hole|0,0,30,0,30,10,0,10 +hole|30,0,40,0,40,10,30,10 +hole|0,11,30,11,30,21,0,21 + +case|slanted holes one unit apart, one touching a third (1e-05 degree grid)|1e-05|-71.06|42.36|274.0 +hole|0,0,29,-10,32,-7,3,3 +hole|3,4,32,-6,35,-3,6,7 +hole|32,-12,40,-12,40,-7,32,-7 + +case|two holes one unit apart, none touching (1e-05 degree grid)|1e-05|-71.06|42.36|600.0 +hole|0,0,30,0,30,10,0,10 +hole|0,11,30,11,30,21,0,21 + +case|one-unit edges: a diamond across a square, and a square at their corner (1e-05 degree grid)|1e-05|-71.06|42.36|3.5 +hole|1,0,2,1,1,2,0,1 +hole|0,0,1,0,1,1,0,1 +hole|1,-1,2,-1,2,0,1,0 + +case|hole touching the outline, sharing an edge with another hole (1e-05 degree grid)|1e-05|-71.06|42.36|200.0 +outer|-10,-10,50,-10,50,50,-10,50 +hole|-10,0,0,0,0,10,-10,10 +hole|0,0,10,0,10,10,0,10 + +case|corner touch (1e-06 degree grid)|1e-06|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,10,20,10,20,20,10,20 + +case|shared edge (1e-06 degree grid)|1e-06|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,0,20,0,20,10,10,10 + +case|part of an edge shared (1e-06 degree grid)|1e-06|-71.06|42.36|200.0 +hole|0,0,10,0,10,10,0,10 +hole|10,5,20,5,20,15,10,15 + +case|chain of four: edge, corner, part of an edge (1e-06 degree grid)|1e-06|-71.06|42.36|400.0 +hole|0,0,10,0,10,10,0,10 +hole|10,0,20,0,20,10,10,10 +hole|20,10,30,10,30,20,20,20 +hole|25,20,35,20,35,30,25,30 + +case|three around one vertex (1e-06 degree grid)|1e-06|-71.06|42.36|300.0 +hole|0,0,10,0,10,10,0,10 +hole|10,10,20,10,20,20,10,20 +hole|0,10,10,10,10,20,0,20 + +case|overlap (1e-06 degree grid)|1e-06|-71.06|42.36|175.0 +hole|0,0,10,0,10,10,0,10 +hole|5,5,15,5,15,15,5,15 + +case|three overlapping (1e-06 degree grid)|1e-06|-71.06|42.36|221.0 +hole|0,0,10,0,10,10,0,10 +hole|5,5,15,5,15,15,5,15 +hole|8,0,18,0,18,7,8,7 + +case|touching pair beside a hole one unit away (1e-06 degree grid)|1e-06|-71.06|42.36|700.0 +hole|0,0,30,0,30,10,0,10 +hole|30,0,40,0,40,10,30,10 +hole|0,11,30,11,30,21,0,21 + +case|slanted holes one unit apart, one touching a third (1e-06 degree grid)|1e-06|-71.06|42.36|274.0 +hole|0,0,29,-10,32,-7,3,3 +hole|3,4,32,-6,35,-3,6,7 +hole|32,-12,40,-12,40,-7,32,-7 + +case|two holes one unit apart, none touching (1e-06 degree grid)|1e-06|-71.06|42.36|600.0 +hole|0,0,30,0,30,10,0,10 +hole|0,11,30,11,30,21,0,21 + +case|one-unit edges: a diamond across a square, and a square at their corner (1e-06 degree grid)|1e-06|-71.06|42.36|3.5 +hole|1,0,2,1,1,2,0,1 +hole|0,0,1,0,1,1,0,1 +hole|1,-1,2,-1,2,0,1,0 + +case|hole touching the outline, sharing an edge with another hole (1e-06 degree grid)|1e-06|-71.06|42.36|200.0 +outer|-10,-10,50,-10,50,50,-10,50 +hole|-10,0,0,0,0,10,-10,10 +hole|0,0,10,0,10,10,0,10 + +case|Boston street parcel 97811, rounded to 1e-5 degree|1e-05|-71.03209|42.37859|376417.41510416666 +hole|3,-46,9,-43,24,-65,26,-70,41,-92,21,-99,-8,-110,-16,-114,-49,-126,-82,-138,-103,-147,-120,-122,-140,-129,-153,-135,-173,-142,-190,-117,-124,-93,-110,-88,-103,-85,-66,-71,-11,-51,-4,-48 +hole|53,-108,58,-104,78,-116,83,-120,89,-123,94,-127,76,-142,70,-148,57,-158,-13,-219,-39,-241,-75,-218 +hole|101,-138,106,-134,142,-157,100,-194,93,-199,76,-215,63,-225,40,-245,3,-222,34,-196,64,-170,92,-146 +hole|155,-176,161,-170,206,-199,189,-214,176,-224,146,-251,121,-271,107,-284,73,-313,51,-298,28,-284,46,-269,64,-253,83,-238,101,-222,120,-205,125,-201,147,-216,147,-215,148,-215,125,-201 +hole|38,-309,50,-316,55,-320,61,-323,31,-350,18,-360,-7,-382,-25,-397,-31,-403,-38,-408,-71,-438,-117,-408,-111,-404,-92,-387,-63,-362,-39,-342,-20,-325,-3,-310,4,-305,16,-294 +hole|-100,-437,-95,-441,-83,-448,-114,-474,-119,-479,-132,-489,-144,-500,-198,-546,-216,-562,-265,-604,-309,-575,-262,-534,-226,-503,-219,-498,-208,-487,-203,-484,-184,-467,-164,-450,-129,-420 +hole|-298,-600,-277,-614,-281,-618,-287,-622,-306,-639,-316,-648,-321,-651,-325,-656,-350,-676,-367,-692,-379,-701,-398,-718,-407,-726,-413,-730,-427,-743,-432,-747,-444,-740,-432,-747,-446,-759,-457,-751,-491,-731,-472,-714,-448,-694,-443,-689,-436,-684,-406,-658,-376,-633,-370,-627,-339,-602,-332,-595,-321,-586 +hole|-492,-767,-479,-756,-469,-763,-463,-766,-458,-770,-484,-793,-491,-798,-499,-806,-521,-792,-512,-785 +hole|-523,-792,-500,-806,-536,-837,-548,-848,-565,-862,-585,-880,-637,-857,-578,-806,-558,-788,-552,-784,-543,-775,-537,-771,-523,-758,-508,-746,-503,-741,-481,-755,-487,-759,-501,-772,-521,-789 +hole|-624,-878,-598,-889,-660,-967,-669,-979,-683,-996,-703,-987,-735,-974,-719,-955,-701,-931,-696,-926,-663,-883,-658,-878,-650,-867 +hole|-755,-967,-759,-967,-759,-966,-761,-966,-763,-964,-764,-964,-766,-957,-765,-957,-765,-955,-692,-863,-691,-863,-691,-862,-689,-862,-687,-861,-679,-861,-677,-862,-676,-862,-676,-863,-674,-864,-673,-866,-672,-866,-672,-868,-671,-869,-744,-963,-745,-963,-745,-964,-748,-965,-748,-966,-750,-966,-752,-967 +hole|-765,-932,-782,-953,-833,-931,-808,-898,-757,-921 +hole|-845,-918,-849,-924,-869,-915,-881,-910,-900,-901,-892,-891,-873,-900,-873,-899,-891,-890,-883,-879,-879,-875,-869,-862,-828,-811,-824,-805,-805,-813,-804,-812,-817,-806,-823,-804,-815,-794,-789,-806,-764,-817,-772,-828,-798,-816,-802,-822,-801,-823,-798,-818,-773,-828,-777,-834,-785,-843,-806,-871,-815,-881,-823,-892,-832,-902,-840,-913 +hole|-866,-831,-917,-894,-969,-871,-918,-808 +hole|-971,-850,-984,-865,-1037,-841,-951,-736,-898,-759,-935,-804 +hole|-999,-772,-1050,-836,-1103,-812,-1052,-749 +hole|-1031,-702,-1116,-807,-1168,-784,-1083,-678 +hole|-982,-707,-1007,-695,-997,-683,-985,-689,-984,-688,-972,-694,-971,-692,-995,-681,-985,-667,-982,-664,-930,-686,-941,-699,-944,-704,-956,-718 +hole|-967,-666,-979,-661,-905,-567,-854,-590,-918,-670,-921,-675,-928,-683,-941,-678,-941,-677 +hole|-835,-567,-845,-579,-896,-556,-853,-501,-835,-480,-785,-417,-770,-423,-769,-424,-735,-439,-785,-503,-818,-546 +hole|-687,-432,-687,-418,-658,-417,-656,-416,-659,-416,-657,-413,-661,-416,-687,-416,-687,-409,-682,-401,-673,-391,-668,-384,-592,-431,-598,-437,-604,-441,-652,-483,-668,-473,-668,-475,-665,-476,-653,-484,-677,-504,-686,-500 +hole|-734,-408,-736,-409,-743,-409,-748,-407,-752,-404,-758,-391,-759,-381,-760,-377,-760,-372,-759,-368,-759,-363,-755,-349,-751,-342,-745,-336,-739,-333,-736,-333,-734,-332,-726,-334,-721,-337,-717,-344,-716,-348,-715,-352,-714,-362,-714,-373,-715,-378,-719,-392,-727,-405 +hole|-664,-344,-691,-304,-662,-294,-644,-287,-612,-275,-595,-269,-586,-265,-520,-241,-511,-237,-504,-235,-487,-228,-470,-253,-437,-241,-454,-216,-421,-204,-388,-253,-414,-263,-445,-274,-470,-283,-486,-290,-528,-305,-578,-324,-595,-300,-578,-324,-657,-353,-661,-349 +hole|-464,-249,-470,-251,-486,-228,-468,-221,-461,-219,-454,-216,-439,-240,-451,-244,-457,-247 +hole|-395,-212,-405,-197,-382,-189,-371,-185,-360,-180,-355,-179,-339,-172,-272,-148,-256,-173,-255,-172,-270,-150,-271,-147,-259,-143,-253,-140,-246,-138,-206,-123,-173,-173,-191,-180,-201,-164,-202,-164,-205,-160,-192,-180,-239,-197,-255,-204,-338,-234,-371,-247,-379,-234 +hole|-169,-148,-173,-143,-153,-135,-143,-150,-137,-159,-156,-167 +hole|-129,-156,-136,-159,-151,-135,-126,-126,-120,-123,-104,-147 +hole|-70,-149,-46,-140,2,-122,7,-126,1,-132,-5,-136,-19,-149,-35,-162,-71,-194,-89,-209,-103,-200,-111,-196,-124,-187,-142,-176,-135,-173,-128,-171,-106,-162,-77,-152 +hole|-122,-206,-101,-220,-135,-248,-157,-268,-164,-273,-182,-289,-204,-308,-211,-313,-220,-322,-235,-334,-269,-312,-292,-297,-279,-287,-261,-271,-254,-266,-237,-251,-223,-261,-221,-259,-235,-249,-231,-245,-225,-241,-213,-230,-206,-225,-200,-219,-193,-214,-158,-183 +hole|-94,-234,-88,-228,-51,-252,-99,-293,-117,-309,-184,-366,-220,-343,-142,-275,-124,-259,-111,-249 +hole|-20,-253,-27,-248,-15,-237,-3,-228,3,-222,40,-246,28,-255,23,-260,9,-271,-5,-262,-13,-258 +hole|-23,-269,-3,-282,-28,-303,-58,-330,-81,-349,-87,-355,-94,-360,-111,-376,-118,-381,-136,-397,-151,-387,-159,-383,-172,-374,-130,-337,-123,-332,-106,-316,-99,-311,-40,-259 +hole|-163,-397,-147,-407,-184,-438,-189,-443,-190,-443,-224,-473,-233,-480,-233,-481,-239,-485,-242,-489,-260,-477,-263,-480,-246,-491,-256,-499,-256,-500,-294,-476,-281,-485,-295,-497,-313,-485,-316,-488,-298,-499,-300,-501,-275,-516,-281,-521,-281,-522,-330,-563,-415,-510,-366,-467,-365,-467,-360,-462,-359,-462,-263,-379,-252,-370,-248,-365,-233,-353,-224,-358,-219,-362,-211,-366,-205,-371,-197,-375 +hole|-283,-491,-278,-487,-256,-500,-261,-505,-267,-509,-272,-514,-294,-500 +hole|-386,-562,-353,-584,-390,-615,-412,-601,-407,-596,-401,-592,-401,-591,-388,-580,-393,-577,-417,-598,-432,-588,-435,-590,-393,-617,-404,-627,-414,-636,-446,-616,-457,-610,-464,-605,-468,-608,-438,-626,-418,-639,-433,-651,-438,-656,-445,-661,-457,-672,-481,-692,-505,-714,-511,-718,-526,-709,-542,-698,-553,-692,-595,-665,-487,-571,-481,-567,-462,-550,-438,-530,-424,-538,-395,-557 +hole|-544,-715,-522,-729,-537,-741,-558,-760,-577,-748,-578,-748,-559,-760,-574,-773,-597,-757,-609,-750,-658,-719,-633,-698,-608,-714,-605,-712,-630,-695,-620,-687,-606,-695,-611,-699,-610,-700,-605,-696,-595,-703,-594,-702,-604,-695,-619,-686,-607,-675 +hole|-601,-769,-582,-781,-589,-786,-607,-802,-644,-779,-650,-776,-677,-775,-678,-737,-667,-727,-613,-762 +hole|-632,-799,-627,-795,-611,-805,-620,-813,-637,-803 +hole|-642,-808,-637,-803,-621,-814,-640,-830,-655,-821,-653,-816,-652,-809,-653,-796,-655,-796,-655,-812,-657,-822,-641,-831,-660,-848,-667,-844,-675,-841,-676,-813,-677,-802,-677,-779,-655,-779,-652,-780,-628,-794,-648,-811,-647,-812,-643,-808 +hole|-720,-836,-696,-846,-717,-871,-768,-849,-759,-837,-745,-844,-731,-850,-730,-848,-758,-836,-749,-824 +hole|-774,-856,-722,-878,-725,-882,-726,-882,-733,-891,-732,-891,-736,-897,-737,-896,-746,-907,-745,-907,-747,-909,-798,-887 +hole|-698,-816,-698,-825,-704,-828,-739,-813,-719,-786,-709,-774,-699,-779 +hole|-745,-794,-755,-806,-768,-800,-749,-776,-751,-776,-770,-799,-806,-783,-771,-739,-767,-733,-766,-733,-721,-676,-704,-656,-703,-656,-700,-737,-741,-788 +hole|-832,-788,-859,-821,-911,-798,-884,-765 +hole|-775,-717,-822,-776,-874,-754,-771,-626,-720,-648,-739,-672,-743,-676,-746,-681,-751,-686,-761,-700 +hole|-879,-734,-890,-748,-921,-733,-941,-725,-929,-710,-904,-721,-903,-720,-928,-709,-908,-683,-898,-672,-880,-648,-828,-671,-847,-695,-861,-712,-874,-729 +hole|-965,-730,-988,-759,-1041,-735,-1018,-706 +hole|-849,-652,-854,-658,-878,-647,-847,-607,-843,-603,-839,-597,-788,-619,-807,-643,-834,-631,-841,-639,-839,-639 +hole|-797,-599,-810,-593,-823,-588,-829,-585,-738,-470,-728,-459,-718,-446,-708,-449,-708,-476,-707,-484,-708,-490,-707,-504,-706,-519,-717,-532,-727,-545,-734,-553,-742,-564,-747,-569,-754,-579,-762,-588,-766,-594,-778,-608 +hole|-653,-505,-566,-430,-509,-466,-521,-476,-452,-521,-548,-604,-555,-609,-555,-610,-560,-615,-579,-630,-608,-656,-665,-620,-635,-594,-634,-594,-621,-582,-592,-558,-568,-537,-557,-528,-538,-515,-559,-520,-568,-523,-569,-524,-571,-524,-575,-527,-577,-528,-580,-527,-679,-611,-682,-609,-684,-531,-663,-513,-643,-525,-642,-525,-662,-513 +hole|-486,-445,-499,-456,-554,-420,-529,-399,-511,-383,-476,-352,-453,-367,-451,-365,-460,-359,-454,-355,-455,-354,-460,-358,-474,-350,-452,-331,-445,-326,-418,-343,-416,-342,-428,-334,-421,-327,-422,-327,-429,-333,-444,-324,-409,-295,-397,-284,-388,-276,-382,-272,-378,-267,-373,-263,-359,-272,-378,-289,-377,-290,-382,-294,-380,-295,-371,-287,-365,-283,-355,-274,-345,-281,-357,-291,-334,-306,-333,-305,-339,-302,-355,-291,-344,-282,-333,-288,-322,-296,-316,-299,-353,-331,-389,-362,-402,-372,-420,-388,-461,-423,-489,-405,-491,-408,-463,-425 +hole|-557,-401,-568,-410,-579,-404,-589,-397,-595,-394,-583,-384,-568,-394,-562,-397 +hole|-583,-381,-596,-393,-617,-379,-643,-363,-618,-353,-589,-343,-569,-335,-554,-357,-568,-335,-544,-326,-535,-323,-518,-334,-518,-335,-496,-349,-555,-399 +hole|-510,-332,-515,-335,-534,-323,-518,-317,-506,-312,-491,-307,-482,-303,-472,-300,-464,-296,-445,-290,-437,-286,-428,-283,-424,-286,-435,-296,-454,-312,-477,-333,-492,-324,-485,-319,-487,-319 +hole|-496,-326,-492,-324,-478,-333,-496,-349,-513,-338,-509,-335,-510,-334,-505,-331,-504,-332 +hole|-345,-264,-358,-256,-338,-249,-329,-245,-321,-243,-299,-235,-287,-230,-280,-228,-270,-242,-289,-248,-302,-253,-304,-253,-280,-268,-305,-290,-321,-279,-327,-276,-333,-271 +hole|-266,-237,-271,-239,-279,-227,-254,-218,-249,-216,-241,-228 +hole|-232,-227,-237,-231,-248,-216,-213,-203,-209,-207 +hole|-255,-234,-241,-229,-237,-231,-256,-247,-268,-239 +hole|-275,-244,-268,-241,-257,-248,-270,-260,-279,-268,-301,-254 +hole|-315,-319,-303,-308,-290,-316,-327,-348,-326,-349,-289,-317,-277,-324,-314,-356,-311,-358,-295,-343,-289,-339,-275,-326,-253,-339,-246,-344,-324,-411,-325,-411,-331,-417,-332,-417,-355,-438,-368,-448,-379,-459,-392,-469,-404,-480,-429,-501,-483,-465,-437,-424,-429,-418,-411,-402,-369,-366,-363,-360,-362,-360,-343,-343 +hole|-649,-648,-621,-666,-653,-694,-660,-688,-659,-682,-660,-682,-663,-689,-654,-695,-675,-713,-679,-711,-680,-660,-662,-660,-662,-659,-681,-659,-681,-634,-677,-630 +hole|-705,-597,-704,-629,-710,-637,-762,-614,-744,-592,-740,-586,-727,-571,-718,-559,-705,-565 +hole|-827,-639,-809,-646,-820,-661,-828,-670,-852,-659,-833,-636 + +case|Boston street parcel 98014, rounded to 1e-5 degree|1e-05|-71.11716|42.30025|378410.0 +hole|-554,-698,-554,-696,-553,-694,-553,-684,-552,-684,-552,-683,-550,-683,-515,-704,-489,-719,-463,-735,-438,-749,-481,-789,-517,-767,-530,-760,-542,-752,-580,-730,-557,-705 +hole|-401,-741,-371,-712,-341,-729,-332,-721,-362,-704,-322,-666,-266,-698,-254,-706,-235,-716,-235,-717,-234,-717,-295,-810,-296,-810,-296,-811,-302,-811,-302,-810,-407,-749,-408,-749,-408,-747,-407,-747 +hole|-288,-672,-312,-658,-272,-619,-234,-642,-207,-657,-202,-659,-202,-660,-201,-660,-211,-680,-225,-703,-225,-704,-226,-704,-226,-705,-232,-705,-232,-704 +hole|-239,-625,-263,-610,-225,-576,-225,-575,-219,-575,-185,-595,-174,-600,-174,-601,-173,-601,-173,-602,-172,-602,-172,-606,-181,-625,-188,-624,-194,-646,-195,-646,-195,-647,-198,-648,-200,-648,-200,-647,-212,-641 +hole|-189,-578,-211,-566,-211,-565,-212,-565,-212,-562,-211,-562,-211,-561,-173,-526,-151,-504,-149,-531,-152,-553,-165,-586,-166,-586,-166,-587,-167,-587,-167,-588,-172,-588 +hole|-333,-810,-318,-818,-316,-819,-316,-820,-315,-820,-315,-821,-314,-821,-314,-822,-313,-822,-313,-828,-314,-828,-330,-853,-336,-866,-339,-875,-325,-879,-326,-889,-326,-900,-321,-917,-366,-903,-524,-856,-420,-759,-371,-787,-416,-829,-435,-847,-421,-851,-360,-794 +hole|-361,-915,-349,-919,-315,-928,-306,-941,-303,-943,-301,-946,-298,-948,-319,-964,-330,-974,-336,-984,-411,-962,-424,-959,-439,-954,-469,-946,-495,-938,-553,-922,-579,-907,-533,-865,-483,-880,-470,-883,-455,-888,-439,-892,-408,-902 +hole|-614,-914,-726,-1020,-756,-1048,-811,-1100,-861,-1146,-861,-1147,-863,-1147,-863,-1148,-868,-1148,-868,-1147,-870,-1147,-870,-1146,-871,-1146,-869,-1135,-864,-1121,-861,-1108,-859,-1089,-859,-1072,-856,-1054,-854,-1048,-847,-1036,-841,-1029,-841,-1028,-798,-988,-788,-980,-779,-971,-769,-963,-760,-954,-729,-927,-715,-913,-703,-899,-692,-881,-687,-873,-674,-842,-669,-835,-667,-830,-663,-824,-662,-824,-635,-791,-595,-814,-595,-815,-542,-846 +hole|-652,-976,-641,-966,-640,-966,-640,-965,-639,-965,-639,-966,-638,-966,-611,-982,-602,-985,-543,-1000,-527,-1005,-512,-1008,-495,-1013,-478,-1017,-421,-1033,-372,-1045,-372,-1046,-370,-1046,-370,-1047,-369,-1047,-369,-1048,-368,-1048,-368,-1053,-377,-1086,-378,-1086,-378,-1087,-381,-1088,-384,-1088,-426,-1078,-523,-1055,-538,-1052,-580,-1041,-610,-1035,-623,-1031,-651,-1025,-659,-1021,-683,-1006 +hole|-445,-1086,-433,-1088,-403,-1095,-392,-1098,-391,-1098,-391,-1099,-390,-1099,-390,-1102,-391,-1102,-391,-1103,-428,-1133,-429,-1133,-429,-1134,-434,-1134,-451,-1130,-478,-1125,-576,-1104,-689,-1080,-699,-1077,-711,-1071,-736,-1056,-693,-1015,-659,-1035,-628,-1042,-614,-1046,-586,-1052,-572,-1056,-514,-1069,-500,-1073,-459,-1082 +hole|-606,-793,-626,-782,-588,-740,-526,-776,-515,-783,-490,-797,-532,-837,-557,-823 +hole|-869,-1181,-860,-1173,-840,-1184,-805,-1206,-793,-1212,-747,-1239,-721,-1255,-709,-1261,-675,-1282,-663,-1288,-630,-1308,-649,-1323,-671,-1342,-672,-1342,-672,-1343,-675,-1343,-677,-1344,-678,-1344,-678,-1343,-681,-1343,-681,-1342,-763,-1294,-776,-1287,-789,-1278,-801,-1272,-813,-1264,-859,-1237,-902,-1211 +hole|-595,-1298,-570,-1278,-568,-1277,-564,-1275,-559,-1273,-554,-1272,-552,-1272,-551,-1271,-490,-1273,-488,-1274,-483,-1275,-481,-1276,-477,-1278,-475,-1280,-464,-1286,-484,-1304,-505,-1322,-516,-1330,-546,-1356,-559,-1366,-620,-1419,-627,-1424,-656,-1451,-729,-1512,-740,-1522,-752,-1531,-789,-1563,-789,-1564,-791,-1564,-791,-1565,-797,-1565,-797,-1564,-799,-1564,-799,-1563,-800,-1563,-845,-1529,-874,-1511,-874,-1510,-875,-1510,-875,-1508,-874,-1506,-824,-1482,-722,-1403,-648,-1341,-638,-1334,-629,-1326,-619,-1319,-597,-1301 +hole|-476,-1313,-455,-1295,-451,-1295,-403,-1328,-456,-1371,-480,-1392,-494,-1403,-549,-1379,-549,-1378,-550,-1378,-550,-1376,-506,-1338 +hole|-398,-1314,-413,-1303,-388,-1283,-376,-1272,-326,-1231,-269,-1266,-321,-1309,-332,-1319,-359,-1341,-373,-1332,-386,-1322 +hole|-421,-1357,-394,-1334,-358,-1359,-336,-1383,-398,-1416,-418,-1437,-483,-1408,-465,-1394 +hole|-346,-1401,-329,-1391,-314,-1412,-310,-1419,-310,-1422,-308,-1424,-308,-1426,-306,-1430,-306,-1432,-304,-1437,-304,-1455,-309,-1469,-312,-1476,-312,-1477,-313,-1477,-313,-1478,-315,-1478,-315,-1479,-317,-1479,-319,-1480,-322,-1480,-322,-1479,-324,-1479,-369,-1459,-386,-1451,-408,-1442,-388,-1422,-380,-1419 +hole|-353,-1477,-321,-1492,-357,-1546,-412,-1522,-427,-1514,-464,-1498,-415,-1450,-402,-1456,-386,-1462 +hole|-336,-1536,-328,-1524,-261,-1544,-270,-1589,-328,-1585,-336,-1551,-339,-1540 +hole|-350,-1560,-348,-1560,-330,-1634,-340,-1762,-343,-1786,-346,-1830,-428,-1787,-450,-1773,-440,-1758,-432,-1742,-424,-1714,-422,-1701,-421,-1700,-412,-1668,-402,-1645,-352,-1561,-351,-1561,-351,-1560 +hole|-381,-1821,-362,-1832,-348,-1839,-348,-1841,-347,-1841,-352,-1886,-356,-1935,-357,-1935,-357,-1937,-358,-1937,-358,-1938,-360,-1938,-362,-1939,-365,-1939,-365,-1938,-367,-1938,-380,-1928,-512,-1842,-512,-1841,-513,-1841,-513,-1837,-512,-1837,-512,-1836,-493,-1820,-482,-1808,-456,-1783,-455,-1783,-455,-1782,-451,-1782,-451,-1783 +hole|-515,-1825,-521,-1830,-522,-1830,-522,-1831,-528,-1831,-542,-1822,-540,-1820,-584,-1791,-571,-1780,-557,-1789,-541,-1763,-533,-1752,-504,-1762,-506,-1765,-469,-1781,-486,-1799 +hole|-585,-1771,-571,-1780,-584,-1791,-599,-1782,-625,-1764,-640,-1755,-642,-1757,-664,-1738,-671,-1730,-673,-1727,-665,-1716,-619,-1733,-626,-1744 +hole|-660,-1688,-679,-1718,-689,-1699,-691,-1691,-699,-1672,-707,-1656,-720,-1636,-720,-1632,-712,-1624,-695,-1604,-680,-1589,-664,-1570,-622,-1524,-622,-1523,-621,-1523,-621,-1522,-619,-1522,-617,-1521,-613,-1521,-613,-1522,-611,-1522,-611,-1523,-572,-1549,-640,-1655 +hole|-685,-1579,-723,-1620,-723,-1621,-724,-1621,-724,-1622,-731,-1622,-731,-1621,-732,-1621,-747,-1605,-767,-1587,-776,-1581,-779,-1578,-780,-1578,-781,-1573,-780,-1573,-780,-1572,-779,-1572,-755,-1551,-692,-1498,-672,-1481,-625,-1513,-664,-1555,-671,-1564,-672,-1564 +hole|-821,-1570,-806,-1581,-891,-1654,-935,-1692,-936,-1692,-936,-1693,-938,-1693,-938,-1692,-940,-1692,-940,-1691,-941,-1691,-966,-1611,-973,-1591,-975,-1582,-989,-1541,-962,-1543,-947,-1543,-899,-1519,-894,-1519,-874,-1533,-856,-1544 +hole|-649,-1481,-662,-1473,-614,-1431,-586,-1450,-582,-1453,-580,-1454,-576,-1456,-575,-1456,-575,-1457,-570,-1458,-567,-1459,-563,-1459,-561,-1460,-556,-1460,-554,-1459,-550,-1459,-548,-1458,-546,-1458,-535,-1452,-535,-1451,-514,-1436,-492,-1416,-490,-1416,-426,-1445,-474,-1491,-505,-1499,-520,-1502,-536,-1507,-545,-1509,-566,-1539,-585,-1525,-613,-1507,-626,-1497,-639,-1489 +hole|-581,-1440,-605,-1423,-561,-1385,-502,-1411,-544,-1446,-549,-1448,-552,-1449,-555,-1449,-557,-1450,-560,-1450,-562,-1449,-566,-1449,-568,-1448,-574,-1445 +hole|-537,-1516,-482,-1501,-403,-1537,-362,-1555,-398,-1615,-448,-1594,-480,-1579,-495,-1573,-541,-1552,-556,-1546,-556,-1545,-557,-1545,-557,-1543,-556,-1543 +hole|-430,-1614,-405,-1625,-419,-1653,-423,-1662,-425,-1670,-428,-1676,-432,-1689,-441,-1730,-451,-1755,-453,-1757,-455,-1762,-465,-1775,-502,-1759,-504,-1761,-533,-1751,-525,-1740,-519,-1729,-518,-1729,-506,-1707,-494,-1677,-491,-1664,-490,-1663,-490,-1652,-493,-1646,-493,-1644,-499,-1637,-501,-1636,-501,-1635,-503,-1634,-505,-1632,-521,-1625,-522,-1625,-522,-1624,-523,-1624,-523,-1621,-502,-1610,-479,-1596,-477,-1596,-477,-1595,-472,-1595,-472,-1596 +hole|-546,-1747,-560,-1768,-561,-1768,-561,-1769,-566,-1769,-566,-1768,-606,-1742,-607,-1742,-607,-1739,-606,-1739,-590,-1713,-575,-1686,-560,-1650,-557,-1644,-556,-1644,-556,-1643,-555,-1643,-555,-1642,-554,-1642,-554,-1641,-553,-1641,-553,-1640,-551,-1639,-547,-1636,-542,-1634,-540,-1634,-538,-1633,-533,-1633,-531,-1634,-529,-1634,-520,-1638,-518,-1638,-518,-1639,-516,-1639,-510,-1644,-509,-1644,-507,-1648,-506,-1648,-506,-1650,-505,-1650,-505,-1653,-504,-1653,-504,-1660,-510,-1680,-527,-1717 +hole|-608,-1716,-618,-1730,-640,-1723,-664,-1714,-635,-1668,-624,-1649,-606,-1623,-599,-1610,-588,-1594,-564,-1555,-492,-1586,-491,-1586,-491,-1590,-492,-1590,-551,-1625,-554,-1626,-564,-1633,-565,-1635,-567,-1636,-573,-1644,-590,-1685,-599,-1701 +hole|-858,-1483,-889,-1498,-889,-1499,-894,-1499,-894,-1498,-896,-1498,-937,-1471,-924,-1459,-902,-1440,-881,-1421,-813,-1362,-775,-1385,-745,-1402,-795,-1441,-804,-1447,-813,-1455,-836,-1472 +hole|-136,-497,-139,-502,-140,-494,-131,-486 +hole|-166,-491,-208,-468,-170,-430,-157,-484,-164,-491 +hole|-134,-461,-150,-477,-163,-424,-136,-398,-103,-368,-62,-393 +hole|-106,-353,-165,-409,-167,-397,-164,-387,-159,-377,-151,-368,-146,-364,-118,-346,-77,-317,2,-266,61,-229,104,-201,108,-203,119,-196,78,-257,32,-302,6,-329,-30,-363,-57,-389,-61,-379