From 80ac56a0b39da9867bcbfe36b0f00ed5f7471586 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Mon, 11 Dec 2023 11:00:03 -0800 Subject: [PATCH 1/3] Don't use longitude wraparound detection if it makes a contradictory geometry --- CHANGELOG.md | 2 + serial.cpp | 99 ++++++++++++++----- tests/wraparound-gap/in.json | 1 + .../-z0_--detect-longitude-wraparound.json | 20 ++++ 4 files changed, 97 insertions(+), 25 deletions(-) create mode 100644 tests/wraparound-gap/in.json create mode 100644 tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 130e3e944..893f77aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* Don't use longitude wraparound detection if it makes a self-contradictory geometry + # 2.37.1 * Reduce maximum memory used for vertex sorting diff --git a/serial.cpp b/serial.cpp index b2a6bdcae..09e16a8c3 100644 --- a/serial.cpp +++ b/serial.cpp @@ -314,39 +314,88 @@ serial_feature deserialize_feature(std::string &geoms, unsigned z, unsigned tx, } static long long scale_geometry(struct serialization_state *sst, long long *bbox, drawvec &geom) { - long long offset = 0; - long long prev = 0; - bool has_prev = false; double scale = 1.0 / (1 << geometry_scale); - for (size_t i = 0; i < geom.size(); i++) { - if (geom[i].op == VT_MOVETO || geom[i].op == VT_LINETO) { - long long x = geom[i].x; - long long y = geom[i].y; + if (additional[A_DETECT_WRAPAROUND]) { + drawvec out; - if (additional[A_DETECT_WRAPAROUND]) { - if (geom[i].op == VT_LINETO) { - x += offset; - if (has_prev) { - // jumps at least 180° but not exactly 360°, - // which in some data sets is an intentional - // line across the world - if (x - prev > (1LL << 31) && x - prev != (1LL << 32)) { - offset -= 1LL << 32; - x -= 1LL << 32; - } else if (prev - x > (1LL << 31) && prev - x != (1LL << 32)) { - offset += 1LL << 32; - x += 1LL << 32; + for (size_t i = 0; i < geom.size(); i++) { + if (geom[i].op == VT_MOVETO) { + size_t j = 0; + for (j = i + 1; j < geom.size(); j++) { + if (geom[j].op != VT_LINETO) { + break; + } + } + + long long prev_x = geom[i].x; + long long offset = 0; + bool balanced = true; + + drawvec ring; + for (size_t k = i; k < j; k++) { + draw op = geom[k]; + op.x += offset; + + // jumps at least 180° but not exactly 360°, + // which in some data sets is an intentional + // line across the world + if (op.x - prev_x > (1LL << 31) && op.x - prev_x != (1LL << 32)) { + if (offset < 0) { + // already shifted left, but seems to need another shift left + balanced = false; + break; } + + offset -= 1LL << 32; + op.x -= 1LL << 32; + } else if (prev_x - op.x > (1LL << 31) && prev_x - op.x != (1LL << 32)) { + if (offset > 0) { + // already shifted right, but seems to need another shift right + balanced = false; + break; + } + + offset += 1LL << 32; + op.x += 1LL << 32; } - has_prev = true; - prev = x; - } else { - offset = 0; - prev = x; + ring.push_back(op); + prev_x = op.x; + } + + if (geom[j - 1] == geom[i]) { + if (offset != 0) { + // first and last points are supposed to be the same + // but there is an unresolved antimeridian shift still + balanced = false; + } + } + + if (!balanced) { + ring.clear(); + for (size_t k = i; k < j; k++) { + ring.push_back(geom[k]); + } } + + for (auto const &g : ring) { + out.push_back(g); + } + + i = j - 1; + } else if (geom[i].op == VT_CLOSEPATH) { + out.push_back(geom[i]); } + } + + geom = std::move(out); + } + + for (size_t i = 0; i < geom.size(); i++) { + if (geom[i].op == VT_MOVETO || geom[i].op == VT_LINETO) { + long long x = geom[i].x; + long long y = geom[i].y; if (x < bbox[0]) { bbox[0] = x; diff --git a/tests/wraparound-gap/in.json b/tests/wraparound-gap/in.json new file mode 100644 index 000000000..e36e28923 --- /dev/null +++ b/tests/wraparound-gap/in.json @@ -0,0 +1 @@ +{ "type": "Feature", "properties": { "felt:color": "#C93535", "felt:fillOpacity": 0.25, "felt:id": "fdd67048-a864-48d1-9596-fe332d5e2fd8", "felt:locked": 0, "felt:ordering": 1701884658553581, "felt:showArea": 0, "felt:strokeOpacity": 1, "felt:strokeStyle": "solid", "felt:strokeWidth": 2, "felt:type": "Polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 0.5081782, 22.9870329 ], [ -0.0738751, 24.2847819 ], [ -0.6691349, 25.571479 ], [ -1.27847, 26.846946 ], [ -1.9027968, 28.1109962 ], [ -2.5430829, 29.3634334 ], [ -3.2003511, 30.6040503 ], [ -3.8756828, 31.8326271 ], [ -4.5702221, 33.0489296 ], [ -5.2851804, 34.2527081 ], [ -6.0218407, 35.4436947 ], [ -6.7815616, 36.6216016 ], [ -7.5657823, 37.7861189 ], [ -8.3760274, 38.9369118 ], [ -9.2139111, 40.073618 ], [ -10.0811417, 41.1958448 ], [ -10.9795262, 42.3031659 ], [ -11.9109739, 43.3951181 ], [ -12.8774999, 44.4711972 ], [ -13.8812276, 45.5308545 ], [ -14.9243899, 46.5734923 ], [ -16.0093299, 47.5984594 ], [ -17.1384983, 48.6050467 ], [ -18.3144501, 49.5924819 ], [ -19.5398367, 50.5599248 ], [ -20.8173955, 51.5064616 ], [ -22.1499346, 52.4311004 ], [ -23.540312, 53.3327659 ], [ -24.9914084, 54.2102946 ], [ -26.5060921, 55.0624307 ], [ -28.0871763, 55.887823 ], [ -29.737365, 56.6850223 ], [ -31.4591894, 57.4524808 ], [ -33.2549322, 58.1885532 ], [ -35.12654, 58.8915003 ], [ -37.0755248, 59.5594957 ], [ -39.1028551, 60.1906358 ], [ -41.2088389, 60.7829536 ], [ -43.3930029, 61.3344378 ], [ -45.6539736, 61.8430557 ], [ -47.9893655, 62.3067817 ], [ -50.3956866, 62.7236299 ], [ -52.8682696, 63.0916915 ], [ -55.4012381, 63.4091742 ], [ -57.9875169, 63.6744443 ], [ -60.6188936, 63.8860685 ], [ -63.2861344, 64.0428524 ], [ -65.9791536, 64.1438757 ], [ -68.687232, 64.1885201 ], [ -71.3992725, 64.1764882 ], [ -74.1040795, 64.1078133 ], [ -76.7906446, 63.9828573 ], [ -79.4484197, 63.8022993 ], [ -82.067563, 63.5671136 ], [ -84.6391426, 63.2785398 ], [ -87.1552901, 62.9380471 ], [ -89.6092989, 62.547294 ], [ -91.9956692, 62.1080872 ], [ -94.3101039, 61.6223399 ], [ -96.549463, 61.0920327 ], [ -98.7116854, 60.5191781 ], [ -100.7956881, 59.9057889 ], [ -102.8012518, 59.2538513 ], [ -104.7289002, 58.5653032 ], [ -106.5797799, 57.8420165 ], [ -108.3555463, 57.0857848 ], [ -110.0582571, 56.2983138 ], [ -111.6902772, 55.4812158 ], [ -113.2541951, 54.6360068 ], [ -114.7527508, 53.7641057 ], [ -116.1887754, 52.8668357 ], [ -117.5651406, 51.9454264 ], [ -118.8847188, 51.0010179 ], [ -120.1503501, 50.0346645 ], [ -121.3648176, 49.0473396 ], [ -122.5308284, 48.039941 ], [ -123.6509997, 47.0132954 ], [ -124.7278497, 45.9681637 ], [ -125.7637908, 44.9052463 ], [ -126.7611269, 43.8251872 ], [ -127.7220517, 42.7285794 ], [ -128.6486497, 41.6159683 ], [ -129.5428978, 40.4878568 ], [ -130.4066684, 39.3447083 ], [ -131.2417324, 38.1869507 ], [ -132.0497639, 37.0149798 ], [ -132.8323442, 35.829162 ], [ -133.5909664, 34.6298374 ], [ -134.3270401, 33.4173223 ], [ -135.0418957, 32.1919118 ], [ -135.7367896, 30.9538818 ], [ -136.4129082, 29.7034911 ], [ -137.0713723, 28.4409832 ], [ -137.7132415, 27.1665881 ], [ -138.3395178, 25.8805239 ], [ -138.95115, 24.5829981 ], [ -139.5490368, 23.2742089 ], [ -140.1340309, 21.9543464 ], [ -140.7069416, 20.6235939 ], [ -141.2685386, 19.2821286 ], [ -141.8195545, 17.9301227 ], [ -142.3606881, 16.5677439 ], [ -142.8926067, 15.1951567 ], [ -143.415949, 13.8125227 ], [ -157.9356012, -6.1122922 ], [ -159.116992, -7.0063682 ], [ -160.2948114, -7.8977761 ], [ -161.4696087, -8.7861312 ], [ -162.6419267, -9.6710625 ], [ -163.8123021, -10.5522125 ], [ -164.9812652, -11.4292357 ], [ -166.149341, -12.3017988 ], [ -167.3170488, -13.1695799 ], [ -168.4849028, -14.0322678 ], [ -169.6534122, -14.8895615 ], [ -170.8230821, -15.7411698 ], [ -171.994413, -16.5868104 ], [ -173.1679018, -17.4262095 ], [ -174.3440416, -18.2591015 ], [ -175.5233227, -19.0852277 ], [ -176.7062321, -19.9043366 ], [ -177.8932543, -20.7161825 ], [ -179.0848716, -21.5205254 ], [ -179.0848716, -90.0 ], [ 179.7184362, -90.0 ], [ 179.7184362, -22.3171303 ], [ 178.5161908, -23.1057665 ], [ 177.3079159, -23.8862071 ], [ 176.0931365, -24.6582283 ], [ 174.8713794, -25.4216086 ], [ 173.6421725, -26.1761285 ], [ 172.4050452, -26.9215698 ], [ 171.1595285, -27.6577146 ], [ 169.9051549, -28.384345 ], [ 168.6414585, -29.1012424 ], [ 167.3679757, -29.8081866 ], [ 166.0842452, -30.5049554 ], [ 164.7898088, -31.1913237 ], [ 163.4842115, -31.8670632 ], [ 162.1670027, -32.5319413 ], [ 160.8377366, -33.1857206 ], [ 159.4959737, -33.8281584 ], [ 158.1412811, -34.459006 ], [ 156.7732345, -35.0780079 ], [ 155.3914193, -35.6849017 ], [ 153.9954323, -36.2794169 ], [ 152.5848832, -36.8612749 ], [ 151.1593968, -37.4301883 ], [ 149.7186153, -37.9858605 ], [ 148.2622002, -38.5279855 ], [ 146.7898353, -39.0562472 ], [ 145.301229, -39.5703198 ], [ 143.7961176, -40.0698671 ], [ 137.1909486, -41.5152352 ], [ 135.5467304, -41.7051681 ], [ 133.9013226, -41.8761156 ], [ 132.2553607, -42.0282118 ], [ 130.6094771, -42.161606 ], [ 128.9642978, -42.276462 ], [ 127.3204389, -42.3729568 ], [ 125.6785042, -42.4512795 ], [ 124.0390817, -42.5116301 ], [ 122.4027415, -42.5542183 ], [ 120.7700331, -42.5792621 ], [ 119.1414833, -42.5869867 ], [ 117.5175946, -42.5776231 ], [ 115.8988435, -42.5514069 ], [ 114.2856789, -42.508577 ], [ 112.6785214, -42.4493745 ], [ 111.0777626, -42.3740411 ], [ 109.4837643, -42.2828187 ], [ 107.8968585, -42.1759477 ], [ 106.3173472, -42.0536663 ], [ 104.745503, -41.9162092 ], [ 103.1815689, -41.7638075 ], [ 101.6257595, -41.5966869 ], [ 100.0782615, -41.415068 ], [ 98.5392343, -41.2191649 ], [ 97.0088117, -41.0091851 ], [ 95.4871024, -40.785329 ], [ 93.9741914, -40.5477895 ], [ 92.4701411, -40.2967516 ], [ 90.9749927, -40.0323925 ], [ 89.4887676, -39.7548812 ], [ 88.0114683, -39.4643788 ], [ 86.5430798, -39.1610381 ], [ 85.0835712, -38.8450043 ], [ 83.6328963, -38.5164145 ], [ 82.190995, -38.1753985 ], [ 80.7577946, -37.8220789 ], [ 79.3332105, -37.4565714 ], [ 77.9171474, -37.0789851 ], [ 76.5094999, -36.6894233 ], [ 75.1101536, -36.2879836 ], [ 73.7189857, -35.8747587 ], [ 72.3358656, -35.4498365 ], [ 70.9606556, -35.0133014 ], [ 69.5932114, -34.565234 ], [ 68.2333825, -34.1057126 ], [ 66.8810123, -33.6348129 ], [ 65.5359388, -33.1526095 ], [ 64.1979949, -32.6591758 ], [ 62.867008, -32.1545852 ], [ 61.5428006, -31.6389112 ], [ 60.2251903, -31.1122286 ], [ 58.9139895, -30.5746136 ], [ 57.6090059, -30.0261448 ], [ 56.310042, -29.4669037 ], [ 55.0168951, -28.896975 ], [ 53.7293574, -28.3164477 ], [ 52.4472155, -27.7254154 ], [ 51.1702505, -27.1239768 ], [ 49.8982375, -26.5122364 ], [ 48.6309458, -25.890305 ], [ 47.3681383, -25.2583001 ], [ 46.1095715, -24.6163467 ], [ 44.854995, -23.9645774 ], [ 43.6041515, -23.3031331 ], [ 42.3567766, -22.6321636 ], [ 41.1125983, -21.9518276 ], [ 39.8713369, -21.2622938 ], [ 38.6327046, -20.5637405 ], [ 37.3964057, -19.8563568 ], [ 36.1621359, -19.1403426 ], [ 34.9295822, -18.4159089 ], [ 33.6984229, -17.6832785 ], [ 32.4683271, -16.9426861 ], [ 31.2389549, -16.1943788 ], [ 30.0099567, -15.4386166 ], [ 28.7809737, -14.6756723 ], [ 27.5516372, -13.9058324 ], [ 26.3215688, -13.1293972 ], [ 25.0903803, -12.346681 ], [ 23.8576735, -11.5580128 ], [ 22.6230401, -10.7637362 ], [ 21.3860621, -9.9642103 ], [ 20.1463113, -9.1598096 ], [ 18.9033497, -8.3509245 ], [ 17.6567294, -7.5379618 ], [ 16.4434371, -6.7467394 ], [ 15.8260496, -5.4803404 ], [ 15.1920087, -4.1870889 ], [ 14.5570289, -2.8991695 ], [ 13.9205008, -1.616738 ], [ 13.2818199, -0.3399496 ], [ 12.6403841, 0.9310404 ], [ 11.9955916, 2.196076 ], [ 11.3468394, 3.4550004 ], [ 10.6935208, 4.707655 ], [ 10.0350242, 5.953879 ], [ 9.3707308, 7.1935089 ], [ 8.700013, 8.4263777 ], [ 8.0222329, 9.6523142 ], [ 7.3367401, 10.8711426 ], [ 6.6428705, 12.0826816 ], [ 5.9399441, 13.2867437 ], [ 5.2272637, 14.4831343 ], [ 4.5041128, 15.6716509 ], [ 3.7697543, 16.8520823 ], [ 0.5081782, 22.9870329 ] ] ] ] } } diff --git a/tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json b/tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json new file mode 100644 index 000000000..7cdd5a096 --- /dev/null +++ b/tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json @@ -0,0 +1,20 @@ +{ "type": "FeatureCollection", "properties": { +"antimeridian_adjusted_bounds": "-179.084872,-42.586987,179.718436,64.188520", +"bounds": "-179.084872,-85.051129,179.718436,64.188520", +"center": "0.000000,0.000000,0", +"description": "tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json.check.mbtiles", +"format": "pbf", +"generator_options": "./tippecanoe -q -a@ -f -o tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json.check.mbtiles -z0 --detect-longitude-wraparound tests/wraparound-gap/in.json", +"json": "{\"vector_layers\":[{\"id\":\"in\",\"description\":\"\",\"minzoom\":0,\"maxzoom\":0,\"fields\":{\"felt:color\":\"String\",\"felt:fillOpacity\":\"Number\",\"felt:id\":\"String\",\"felt:locked\":\"Number\",\"felt:ordering\":\"Number\",\"felt:showArea\":\"Number\",\"felt:strokeOpacity\":\"Number\",\"felt:strokeStyle\":\"String\",\"felt:strokeWidth\":\"Number\",\"felt:type\":\"String\"}}],\"tilestats\":{\"layerCount\":1,\"layers\":[{\"layer\":\"in\",\"count\":1,\"geometry\":\"Polygon\",\"attributeCount\":10,\"attributes\":[{\"attribute\":\"felt:color\",\"count\":1,\"type\":\"string\",\"values\":[\"#C93535\"]},{\"attribute\":\"felt:fillOpacity\",\"count\":1,\"type\":\"number\",\"values\":[0.25],\"min\":0.25,\"max\":0.25},{\"attribute\":\"felt:id\",\"count\":1,\"type\":\"string\",\"values\":[\"fdd67048-a864-48d1-9596-fe332d5e2fd8\"]},{\"attribute\":\"felt:locked\",\"count\":1,\"type\":\"number\",\"values\":[0],\"min\":0,\"max\":0},{\"attribute\":\"felt:ordering\",\"count\":1,\"type\":\"number\",\"values\":[1701884658553581],\"min\":1701884658553581,\"max\":1701884658553581},{\"attribute\":\"felt:showArea\",\"count\":1,\"type\":\"number\",\"values\":[0],\"min\":0,\"max\":0},{\"attribute\":\"felt:strokeOpacity\",\"count\":1,\"type\":\"number\",\"values\":[1],\"min\":1,\"max\":1},{\"attribute\":\"felt:strokeStyle\",\"count\":1,\"type\":\"string\",\"values\":[\"solid\"]},{\"attribute\":\"felt:strokeWidth\",\"count\":1,\"type\":\"number\",\"values\":[2],\"min\":2,\"max\":2},{\"attribute\":\"felt:type\",\"count\":1,\"type\":\"string\",\"values\":[\"Polygon\"]}]}]}}", +"maxzoom": "0", +"minzoom": "0", +"name": "tests/wraparound-gap/out/-z0_--detect-longitude-wraparound.json.check.mbtiles", +"type": "overlay", +"version": "2" +}, "features": [ +{ "type": "FeatureCollection", "properties": { "zoom": 0, "x": 0, "y": 0 }, "features": [ +{ "type": "FeatureCollection", "properties": { "layer": "in", "version": 2, "extent": 4096 }, "features": [ +{ "type": "Feature", "properties": { "felt:color": "#C93535", "felt:fillOpacity": 0.25, "felt:id": "fdd67048-a864-48d1-9596-fe332d5e2fd8", "felt:locked": 0, "felt:ordering": 1701884658553581, "felt:showArea": 0, "felt:strokeOpacity": 1, "felt:strokeStyle": "solid", "felt:strokeWidth": 2, "felt:type": "Polygon" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -68.730469, 64.206377 ], [ -63.281250, 64.052978 ], [ -60.644531, 63.898731 ], [ -55.371094, 63.391522 ], [ -52.910156, 63.074866 ], [ -50.361328, 62.714462 ], [ -45.615234, 61.856149 ], [ -41.220703, 60.802064 ], [ -37.089844, 59.578851 ], [ -35.156250, 58.904646 ], [ -29.707031, 56.704506 ], [ -24.960938, 54.213861 ], [ -19.511719, 50.569283 ], [ -15.996094, 47.576526 ], [ -10.986328, 42.293564 ], [ -8.349609, 38.959409 ], [ -3.164062, 30.600094 ], [ 0.527344, 22.998852 ], [ 3.779297, 16.888660 ], [ 6.679688, 12.125264 ], [ 10.722656, 4.740675 ], [ 16.435547, -6.751896 ], [ 25.048828, -12.382928 ], [ 37.353516, -19.890723 ], [ 44.824219, -23.966176 ], [ 55.019531, -28.921631 ], [ 64.160156, -32.694866 ], [ 70.927734, -35.029996 ], [ 75.146484, -36.315125 ], [ 82.177734, -38.203655 ], [ 89.472656, -39.774769 ], [ 93.955078, -40.580585 ], [ 98.525391, -41.244772 ], [ 103.183594, -41.771312 ], [ 109.511719, -42.293564 ], [ 115.927734, -42.553080 ], [ 122.431641, -42.553080 ], [ 128.935547, -42.293564 ], [ 133.857422, -41.902277 ], [ 137.197266, -41.508577 ], [ 143.789062, -40.044438 ], [ 145.283203, -39.571822 ], [ 151.171875, -37.439974 ], [ 156.796875, -35.101934 ], [ 166.113281, -30.524413 ], [ 173.671875, -26.194877 ], [ 179.736328, -22.350076 ], [ 179.736328, -85.622069 ], [ -179.121094, -85.622069 ], [ -179.121094, -21.534847 ], [ -157.939453, -6.140555 ], [ -143.437500, 13.838080 ], [ -140.712891, 20.632784 ], [ -137.109375, 28.459033 ], [ -133.593750, 34.597042 ], [ -130.429688, 39.368279 ], [ -128.671875, 41.640078 ], [ -123.662109, 47.040182 ], [ -118.916016, 51.013755 ], [ -117.597656, 51.944265 ], [ -113.291016, 54.622978 ], [ -110.039062, 56.316537 ], [ -106.611328, 57.844751 ], [ -102.832031, 59.265881 ], [ -96.591797, 61.100789 ], [ -92.021484, 62.103883 ], [ -87.187500, 62.955223 ], [ -84.638672, 63.273182 ], [ -79.453125, 63.821288 ], [ -76.816406, 63.975961 ], [ -71.367188, 64.168107 ], [ -68.730469, 64.206377 ] ] ], [ [ [ 187.031250, -17.224758 ], [ 187.031250, -85.622069 ], [ 180.878906, -85.622069 ], [ 180.878906, -21.534847 ], [ 187.031250, -17.224758 ] ] ], [ [ [ -180.263672, -22.350076 ], [ -180.263672, -85.622069 ], [ -187.031250, -85.622069 ], [ -187.031250, -26.588527 ], [ -180.263672, -22.350076 ] ] ] ] } } +] } +] } +] } From f53d9f77d284b86d60674e238c1af4de5aeda890 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Mon, 11 Dec 2023 12:07:42 -0800 Subject: [PATCH 2/3] Add more comments --- serial.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/serial.cpp b/serial.cpp index 09e16a8c3..f80504193 100644 --- a/serial.cpp +++ b/serial.cpp @@ -364,14 +364,21 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox prev_x = op.x; } + // If this is a polygon, in which the first and last + // points of each ring are supposed to be identical, + // make sure the antimeridian wraparound detection + // preserves that expectation. If it doesn't, it means + // we have detected something wrongly. if (geom[j - 1] == geom[i]) { if (offset != 0) { // first and last points are supposed to be the same - // but there is an unresolved antimeridian shift still + // but there is an unresolved antimeridian shift balanced = false; } } + // If something contradictory happened in longitude + // wraparound detection, restore the original geometry if (!balanced) { ring.clear(); for (size_t k = i; k < j; k++) { From 02e9e4e95221c2af0cfeb15d91867ecdd4b9d3b3 Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Mon, 11 Dec 2023 13:38:54 -0800 Subject: [PATCH 3/3] Only accept longitude corrections that give rings the right winding --- serial.cpp | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/serial.cpp b/serial.cpp index f80504193..e4ab11d8d 100644 --- a/serial.cpp +++ b/serial.cpp @@ -313,11 +313,12 @@ serial_feature deserialize_feature(std::string &geoms, unsigned z, unsigned tx, return sf; } -static long long scale_geometry(struct serialization_state *sst, long long *bbox, drawvec &geom) { +static long long scale_geometry(struct serialization_state *sst, long long *bbox, drawvec &geom, int t) { double scale = 1.0 / (1 << geometry_scale); if (additional[A_DETECT_WRAPAROUND]) { drawvec out; + bool outer = true; // first ring is expected to be outer for (size_t i = 0; i < geom.size(); i++) { if (geom[i].op == VT_MOVETO) { @@ -333,6 +334,7 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox bool balanced = true; drawvec ring; + bool changed = false; for (size_t k = i; k < j; k++) { draw op = geom[k]; op.x += offset; @@ -349,6 +351,7 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox offset -= 1LL << 32; op.x -= 1LL << 32; + changed = true; } else if (prev_x - op.x > (1LL << 31) && prev_x - op.x != (1LL << 32)) { if (offset > 0) { // already shifted right, but seems to need another shift right @@ -358,22 +361,40 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox offset += 1LL << 32; op.x += 1LL << 32; + changed = true; } ring.push_back(op); prev_x = op.x; } - // If this is a polygon, in which the first and last - // points of each ring are supposed to be identical, - // make sure the antimeridian wraparound detection - // preserves that expectation. If it doesn't, it means - // we have detected something wrongly. - if (geom[j - 1] == geom[i]) { - if (offset != 0) { - // first and last points are supposed to be the same - // but there is an unresolved antimeridian shift - balanced = false; + if (changed && balanced) { + // If this is a polygon, in which the first and last + // points of each ring are supposed to be identical, + // make sure the antimeridian wraparound detection + // preserves that expectation. If it doesn't, it means + // we have detected something wrongly. + if (geom[j - 1] == geom[i]) { + if (offset != 0) { + // first and last points are supposed to be the same + // but there is an unresolved antimeridian shift + balanced = false; + } + } + + if (t == VT_POLYGON) { + // don't accept longitude corrections that would give + // a ring a winding counter to what the geojson structure + // says the winding should be + + double area_after = get_area(ring, 0, ring.size()); + if ((outer && area_after < 0) || + (!outer && area_after > 0)) { + // wraparound detection gave a ring a winding different from + // what its position in the GeoJSON structure indicates that + // it should have. + balanced = false; + } } } @@ -391,8 +412,10 @@ static long long scale_geometry(struct serialization_state *sst, long long *bbox } i = j - 1; + outer = false; } else if (geom[i].op == VT_CLOSEPATH) { out.push_back(geom[i]); + outer = true; } } @@ -520,7 +543,7 @@ int serialize_feature(struct serialization_state *sst, serial_feature &sf) { // try to remind myself that the geometry in this function is in SCALED COORDINATES drawvec scaled_geometry = sf.geometry; sf.geometry.clear(); - scale_geometry(sst, sf.bbox, scaled_geometry); + scale_geometry(sst, sf.bbox, scaled_geometry, sf.t); // This has to happen after scaling so that the wraparound detection has happened first. // Otherwise the inner/outer calculation will be confused by bad geometries.