@sentryware/s2-node 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +45 -0
- package/.dockerignore +1 -0
- package/.gitmodules +3 -0
- package/CHANGELOG.md +33 -0
- package/LICENSE +201 -0
- package/README.md +147 -0
- package/binding.gyp +170 -0
- package/docker/Dockerfile.node20.test +8 -0
- package/docker/Dockerfile.node22.test +8 -0
- package/docker/Dockerfile.node24.test +8 -0
- package/index.d.ts +117 -0
- package/index.js +6 -0
- package/jest.config.js +184 -0
- package/package.json +43 -0
- package/publish-linux.sh +18 -0
- package/publish-osx.sh +19 -0
- package/src/builder.cc +84 -0
- package/src/builder.h +29 -0
- package/src/cell.cc +71 -0
- package/src/cell.h +26 -0
- package/src/cell_id.cc +210 -0
- package/src/cell_id.h +44 -0
- package/src/cell_union.cc +237 -0
- package/src/cell_union.h +34 -0
- package/src/earth.cc +185 -0
- package/src/earth.h +33 -0
- package/src/latlng.cc +132 -0
- package/src/latlng.h +28 -0
- package/src/loop.cc +51 -0
- package/src/loop.h +21 -0
- package/src/point.cc +69 -0
- package/src/point.h +23 -0
- package/src/polygon.cc +36 -0
- package/src/polygon.h +20 -0
- package/src/polyline.cc +186 -0
- package/src/polyline.h +34 -0
- package/src/region_coverer.cc +450 -0
- package/src/region_coverer.h +56 -0
- package/src/s2.cc +27 -0
- package/test/Cell.test.js +37 -0
- package/test/CellId.test.js +135 -0
- package/test/CellUnion.test.js +150 -0
- package/test/Earth.test.js +62 -0
- package/test/LatLng.test.js +45 -0
- package/test/Point.test.js +14 -0
- package/test/Polyline.test.js +78 -0
- package/test/RegionCoverer.test.js +301 -0
- package/test.sh +16 -0
- package/third_party/s2geometry/.travis.yml +163 -0
- package/third_party/s2geometry/AUTHORS +13 -0
- package/third_party/s2geometry/CONTRIBUTING.md +65 -0
- package/third_party/s2geometry/CONTRIBUTORS +30 -0
- package/third_party/s2geometry/LICENSE +202 -0
- package/third_party/s2geometry/NOTICE +5 -0
- package/third_party/s2geometry/README.md +127 -0
- package/third_party/s2geometry/doc/examples/point_index.cc +44 -0
- package/third_party/s2geometry/doc/examples/term_index.cc +99 -0
- package/third_party/s2geometry/doc/examples/term_index.py +101 -0
- package/third_party/s2geometry/src/python/coder.i +125 -0
- package/third_party/s2geometry/src/python/pywraps2_test.py +786 -0
- package/third_party/s2geometry/src/python/s2.i +37 -0
- package/third_party/s2geometry/src/python/s2_common.i +756 -0
- package/third_party/s2geometry/src/s2/_fp_contract_off.h +60 -0
- package/third_party/s2geometry/src/s2/base/casts.h +318 -0
- package/third_party/s2geometry/src/s2/base/commandlineflags.h +67 -0
- package/third_party/s2geometry/src/s2/base/integral_types.h +31 -0
- package/third_party/s2geometry/src/s2/base/log_severity.h +40 -0
- package/third_party/s2geometry/src/s2/base/logging.h +173 -0
- package/third_party/s2geometry/src/s2/base/mutex.h +61 -0
- package/third_party/s2geometry/src/s2/base/port.h +999 -0
- package/third_party/s2geometry/src/s2/base/spinlock.h +60 -0
- package/third_party/s2geometry/src/s2/base/stringprintf.cc +107 -0
- package/third_party/s2geometry/src/s2/base/stringprintf.h +53 -0
- package/third_party/s2geometry/src/s2/base/strtoint.cc +65 -0
- package/third_party/s2geometry/src/s2/base/strtoint.h +106 -0
- package/third_party/s2geometry/src/s2/base/timer.h +50 -0
- package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector.cc +164 -0
- package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector.h +110 -0
- package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector_test.cc +232 -0
- package/third_party/s2geometry/src/s2/encoded_s2point_vector.cc +838 -0
- package/third_party/s2geometry/src/s2/encoded_s2point_vector.h +140 -0
- package/third_party/s2geometry/src/s2/encoded_s2point_vector_test.cc +344 -0
- package/third_party/s2geometry/src/s2/encoded_s2shape_index.cc +181 -0
- package/third_party/s2geometry/src/s2/encoded_s2shape_index.h +276 -0
- package/third_party/s2geometry/src/s2/encoded_s2shape_index_test.cc +244 -0
- package/third_party/s2geometry/src/s2/encoded_string_vector.cc +66 -0
- package/third_party/s2geometry/src/s2/encoded_string_vector.h +164 -0
- package/third_party/s2geometry/src/s2/encoded_string_vector_test.cc +69 -0
- package/third_party/s2geometry/src/s2/encoded_uint_vector.h +299 -0
- package/third_party/s2geometry/src/s2/encoded_uint_vector_test.cc +124 -0
- package/third_party/s2geometry/src/s2/id_set_lexicon.cc +81 -0
- package/third_party/s2geometry/src/s2/id_set_lexicon.h +199 -0
- package/third_party/s2geometry/src/s2/id_set_lexicon_test.cc +70 -0
- package/third_party/s2geometry/src/s2/mutable_s2shape_index.cc +1585 -0
- package/third_party/s2geometry/src/s2/mutable_s2shape_index.h +600 -0
- package/third_party/s2geometry/src/s2/mutable_s2shape_index_test.cc +589 -0
- package/third_party/s2geometry/src/s2/r1interval.h +220 -0
- package/third_party/s2geometry/src/s2/r1interval_test.cc +185 -0
- package/third_party/s2geometry/src/s2/r2.h +26 -0
- package/third_party/s2geometry/src/s2/r2rect.cc +93 -0
- package/third_party/s2geometry/src/s2/r2rect.h +234 -0
- package/third_party/s2geometry/src/s2/r2rect_test.cc +228 -0
- package/third_party/s2geometry/src/s2/s1angle.cc +54 -0
- package/third_party/s2geometry/src/s2/s1angle.h +336 -0
- package/third_party/s2geometry/src/s2/s1angle_test.cc +185 -0
- package/third_party/s2geometry/src/s2/s1chord_angle.cc +159 -0
- package/third_party/s2geometry/src/s2/s1chord_angle.h +369 -0
- package/third_party/s2geometry/src/s2/s1chord_angle_test.cc +207 -0
- package/third_party/s2geometry/src/s2/s1interval.cc +296 -0
- package/third_party/s2geometry/src/s2/s1interval.h +266 -0
- package/third_party/s2geometry/src/s2/s1interval_test.cc +469 -0
- package/third_party/s2geometry/src/s2/s2boolean_operation.cc +2391 -0
- package/third_party/s2geometry/src/s2/s2boolean_operation.h +501 -0
- package/third_party/s2geometry/src/s2/s2boolean_operation_test.cc +1400 -0
- package/third_party/s2geometry/src/s2/s2builder.cc +1828 -0
- package/third_party/s2geometry/src/s2/s2builder.h +1057 -0
- package/third_party/s2geometry/src/s2/s2builder_graph.cc +1084 -0
- package/third_party/s2geometry/src/s2/s2builder_graph.h +799 -0
- package/third_party/s2geometry/src/s2/s2builder_graph_test.cc +462 -0
- package/third_party/s2geometry/src/s2/s2builder_layer.h +50 -0
- package/third_party/s2geometry/src/s2/s2builder_test.cc +1329 -0
- package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer.cc +313 -0
- package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer.h +221 -0
- package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer_test.cc +261 -0
- package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies.cc +392 -0
- package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies.h +86 -0
- package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies_test.cc +182 -0
- package/third_party/s2geometry/src/s2/s2builderutil_graph_shape.h +57 -0
- package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer.cc +212 -0
- package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer.h +218 -0
- package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer_test.cc +367 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer.cc +74 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer.h +122 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer_test.cc +167 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer.cc +191 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer.h +211 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer_test.cc +312 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer.cc +105 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer.h +174 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer_test.cc +220 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer.cc +98 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer.h +292 -0
- package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer_test.cc +233 -0
- package/third_party/s2geometry/src/s2/s2builderutil_snap_functions.cc +354 -0
- package/third_party/s2geometry/src/s2/s2builderutil_snap_functions.h +239 -0
- package/third_party/s2geometry/src/s2/s2builderutil_snap_functions_test.cc +716 -0
- package/third_party/s2geometry/src/s2/s2builderutil_testing.cc +37 -0
- package/third_party/s2geometry/src/s2/s2builderutil_testing.h +100 -0
- package/third_party/s2geometry/src/s2/s2builderutil_testing_test.cc +85 -0
- package/third_party/s2geometry/src/s2/s2cap.cc +347 -0
- package/third_party/s2geometry/src/s2/s2cap.h +286 -0
- package/third_party/s2geometry/src/s2/s2cap_test.cc +379 -0
- package/third_party/s2geometry/src/s2/s2cell.cc +552 -0
- package/third_party/s2geometry/src/s2/s2cell.h +249 -0
- package/third_party/s2geometry/src/s2/s2cell_id.cc +619 -0
- package/third_party/s2geometry/src/s2/s2cell_id.h +705 -0
- package/third_party/s2geometry/src/s2/s2cell_id_test.cc +633 -0
- package/third_party/s2geometry/src/s2/s2cell_index.cc +149 -0
- package/third_party/s2geometry/src/s2/s2cell_index.h +660 -0
- package/third_party/s2geometry/src/s2/s2cell_index_test.cc +411 -0
- package/third_party/s2geometry/src/s2/s2cell_test.cc +687 -0
- package/third_party/s2geometry/src/s2/s2cell_union.cc +515 -0
- package/third_party/s2geometry/src/s2/s2cell_union.h +399 -0
- package/third_party/s2geometry/src/s2/s2cell_union_test.cc +598 -0
- package/third_party/s2geometry/src/s2/s2centroids.cc +84 -0
- package/third_party/s2geometry/src/s2/s2centroids.h +87 -0
- package/third_party/s2geometry/src/s2/s2centroids_test.cc +82 -0
- package/third_party/s2geometry/src/s2/s2closest_cell_query.cc +123 -0
- package/third_party/s2geometry/src/s2/s2closest_cell_query.h +385 -0
- package/third_party/s2geometry/src/s2/s2closest_cell_query_base.h +841 -0
- package/third_party/s2geometry/src/s2/s2closest_cell_query_base_test.cc +63 -0
- package/third_party/s2geometry/src/s2/s2closest_cell_query_test.cc +412 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query.cc +106 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query.h +421 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query_base.h +946 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query_base_test.cc +59 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query_test.cc +505 -0
- package/third_party/s2geometry/src/s2/s2closest_edge_query_testing.h +91 -0
- package/third_party/s2geometry/src/s2/s2closest_point_query.cc +66 -0
- package/third_party/s2geometry/src/s2/s2closest_point_query.h +465 -0
- package/third_party/s2geometry/src/s2/s2closest_point_query_base.h +767 -0
- package/third_party/s2geometry/src/s2/s2closest_point_query_base_test.cc +63 -0
- package/third_party/s2geometry/src/s2/s2closest_point_query_test.cc +312 -0
- package/third_party/s2geometry/src/s2/s2contains_point_query.h +328 -0
- package/third_party/s2geometry/src/s2/s2contains_point_query_test.cc +159 -0
- package/third_party/s2geometry/src/s2/s2contains_vertex_query.cc +39 -0
- package/third_party/s2geometry/src/s2/s2contains_vertex_query.h +66 -0
- package/third_party/s2geometry/src/s2/s2contains_vertex_query_test.cc +67 -0
- package/third_party/s2geometry/src/s2/s2convex_hull_query.cc +198 -0
- package/third_party/s2geometry/src/s2/s2convex_hull_query.h +110 -0
- package/third_party/s2geometry/src/s2/s2convex_hull_query_test.cc +208 -0
- package/third_party/s2geometry/src/s2/s2coords.cc +146 -0
- package/third_party/s2geometry/src/s2/s2coords.h +459 -0
- package/third_party/s2geometry/src/s2/s2coords_internal.h +71 -0
- package/third_party/s2geometry/src/s2/s2coords_test.cc +218 -0
- package/third_party/s2geometry/src/s2/s2crossing_edge_query.cc +380 -0
- package/third_party/s2geometry/src/s2/s2crossing_edge_query.h +220 -0
- package/third_party/s2geometry/src/s2/s2crossing_edge_query_test.cc +382 -0
- package/third_party/s2geometry/src/s2/s2debug.cc +23 -0
- package/third_party/s2geometry/src/s2/s2debug.h +69 -0
- package/third_party/s2geometry/src/s2/s2distance_target.h +165 -0
- package/third_party/s2geometry/src/s2/s2earth.cc +52 -0
- package/third_party/s2geometry/src/s2/s2earth.h +268 -0
- package/third_party/s2geometry/src/s2/s2earth_test.cc +146 -0
- package/third_party/s2geometry/src/s2/s2edge_clipping.cc +462 -0
- package/third_party/s2geometry/src/s2/s2edge_clipping.h +183 -0
- package/third_party/s2geometry/src/s2/s2edge_clipping_test.cc +335 -0
- package/third_party/s2geometry/src/s2/s2edge_crosser.cc +85 -0
- package/third_party/s2geometry/src/s2/s2edge_crosser.h +343 -0
- package/third_party/s2geometry/src/s2/s2edge_crosser_test.cc +264 -0
- package/third_party/s2geometry/src/s2/s2edge_crossings.cc +515 -0
- package/third_party/s2geometry/src/s2/s2edge_crossings.h +138 -0
- package/third_party/s2geometry/src/s2/s2edge_crossings_internal.h +59 -0
- package/third_party/s2geometry/src/s2/s2edge_crossings_test.cc +246 -0
- package/third_party/s2geometry/src/s2/s2edge_distances.cc +419 -0
- package/third_party/s2geometry/src/s2/s2edge_distances.h +192 -0
- package/third_party/s2geometry/src/s2/s2edge_distances_test.cc +539 -0
- package/third_party/s2geometry/src/s2/s2edge_tessellator.cc +276 -0
- package/third_party/s2geometry/src/s2/s2edge_tessellator.h +101 -0
- package/third_party/s2geometry/src/s2/s2edge_tessellator_test.cc +492 -0
- package/third_party/s2geometry/src/s2/s2edge_vector_shape.h +85 -0
- package/third_party/s2geometry/src/s2/s2edge_vector_shape_test.cc +66 -0
- package/third_party/s2geometry/src/s2/s2error.cc +29 -0
- package/third_party/s2geometry/src/s2/s2error.h +147 -0
- package/third_party/s2geometry/src/s2/s2error_test.cc +31 -0
- package/third_party/s2geometry/src/s2/s2furthest_edge_query.cc +117 -0
- package/third_party/s2geometry/src/s2/s2furthest_edge_query.h +439 -0
- package/third_party/s2geometry/src/s2/s2furthest_edge_query_test.cc +487 -0
- package/third_party/s2geometry/src/s2/s2latlng.cc +90 -0
- package/third_party/s2geometry/src/s2/s2latlng.h +234 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect.cc +727 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect.h +434 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect_bounder.cc +344 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect_bounder.h +89 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect_bounder_test.cc +306 -0
- package/third_party/s2geometry/src/s2/s2latlng_rect_test.cc +1030 -0
- package/third_party/s2geometry/src/s2/s2latlng_test.cc +165 -0
- package/third_party/s2geometry/src/s2/s2lax_loop_shape.cc +104 -0
- package/third_party/s2geometry/src/s2/s2lax_loop_shape.h +153 -0
- package/third_party/s2geometry/src/s2/s2lax_loop_shape_test.cc +101 -0
- package/third_party/s2geometry/src/s2/s2lax_polygon_shape.cc +348 -0
- package/third_party/s2geometry/src/s2/s2lax_polygon_shape.h +183 -0
- package/third_party/s2geometry/src/s2/s2lax_polygon_shape_test.cc +234 -0
- package/third_party/s2geometry/src/s2/s2lax_polyline_shape.cc +118 -0
- package/third_party/s2geometry/src/s2/s2lax_polyline_shape.h +124 -0
- package/third_party/s2geometry/src/s2/s2lax_polyline_shape_test.cc +62 -0
- package/third_party/s2geometry/src/s2/s2loop.cc +1509 -0
- package/third_party/s2geometry/src/s2/s2loop.h +711 -0
- package/third_party/s2geometry/src/s2/s2loop_measures.cc +313 -0
- package/third_party/s2geometry/src/s2/s2loop_measures.h +280 -0
- package/third_party/s2geometry/src/s2/s2loop_measures_test.cc +367 -0
- package/third_party/s2geometry/src/s2/s2loop_test.cc +1371 -0
- package/third_party/s2geometry/src/s2/s2max_distance_targets.cc +265 -0
- package/third_party/s2geometry/src/s2/s2max_distance_targets.h +241 -0
- package/third_party/s2geometry/src/s2/s2max_distance_targets_test.cc +367 -0
- package/third_party/s2geometry/src/s2/s2measures.cc +128 -0
- package/third_party/s2geometry/src/s2/s2measures.h +78 -0
- package/third_party/s2geometry/src/s2/s2measures_test.cc +135 -0
- package/third_party/s2geometry/src/s2/s2metrics.cc +122 -0
- package/third_party/s2geometry/src/s2/s2metrics.h +199 -0
- package/third_party/s2geometry/src/s2/s2metrics_test.cc +127 -0
- package/third_party/s2geometry/src/s2/s2min_distance_targets.cc +295 -0
- package/third_party/s2geometry/src/s2/s2min_distance_targets.h +273 -0
- package/third_party/s2geometry/src/s2/s2min_distance_targets_test.cc +239 -0
- package/third_party/s2geometry/src/s2/s2padded_cell.cc +162 -0
- package/third_party/s2geometry/src/s2/s2padded_cell.h +108 -0
- package/third_party/s2geometry/src/s2/s2padded_cell_test.cc +138 -0
- package/third_party/s2geometry/src/s2/s2point.h +38 -0
- package/third_party/s2geometry/src/s2/s2point_compression.cc +388 -0
- package/third_party/s2geometry/src/s2/s2point_compression.h +78 -0
- package/third_party/s2geometry/src/s2/s2point_compression_test.cc +305 -0
- package/third_party/s2geometry/src/s2/s2point_index.h +345 -0
- package/third_party/s2geometry/src/s2/s2point_index_test.cc +147 -0
- package/third_party/s2geometry/src/s2/s2point_region.cc +72 -0
- package/third_party/s2geometry/src/s2/s2point_region.h +76 -0
- package/third_party/s2geometry/src/s2/s2point_region_test.cc +100 -0
- package/third_party/s2geometry/src/s2/s2point_span.h +57 -0
- package/third_party/s2geometry/src/s2/s2point_test.cc +47 -0
- package/third_party/s2geometry/src/s2/s2point_vector_shape.h +127 -0
- package/third_party/s2geometry/src/s2/s2point_vector_shape_test.cc +59 -0
- package/third_party/s2geometry/src/s2/s2pointutil.cc +131 -0
- package/third_party/s2geometry/src/s2/s2pointutil.h +138 -0
- package/third_party/s2geometry/src/s2/s2pointutil_test.cc +157 -0
- package/third_party/s2geometry/src/s2/s2polygon.cc +1569 -0
- package/third_party/s2geometry/src/s2/s2polygon.h +934 -0
- package/third_party/s2geometry/src/s2/s2polygon_test.cc +3025 -0
- package/third_party/s2geometry/src/s2/s2polyline.cc +645 -0
- package/third_party/s2geometry/src/s2/s2polyline.h +379 -0
- package/third_party/s2geometry/src/s2/s2polyline_alignment.cc +414 -0
- package/third_party/s2geometry/src/s2/s2polyline_alignment.h +245 -0
- package/third_party/s2geometry/src/s2/s2polyline_alignment_internal.h +158 -0
- package/third_party/s2geometry/src/s2/s2polyline_alignment_test.cc +610 -0
- package/third_party/s2geometry/src/s2/s2polyline_measures.cc +42 -0
- package/third_party/s2geometry/src/s2/s2polyline_measures.h +53 -0
- package/third_party/s2geometry/src/s2/s2polyline_measures_test.cc +57 -0
- package/third_party/s2geometry/src/s2/s2polyline_simplifier.cc +187 -0
- package/third_party/s2geometry/src/s2/s2polyline_simplifier.h +109 -0
- package/third_party/s2geometry/src/s2/s2polyline_simplifier_test.cc +165 -0
- package/third_party/s2geometry/src/s2/s2polyline_test.cc +554 -0
- package/third_party/s2geometry/src/s2/s2predicates.cc +1486 -0
- package/third_party/s2geometry/src/s2/s2predicates.h +282 -0
- package/third_party/s2geometry/src/s2/s2predicates_internal.h +135 -0
- package/third_party/s2geometry/src/s2/s2predicates_test.cc +1427 -0
- package/third_party/s2geometry/src/s2/s2projections.cc +109 -0
- package/third_party/s2geometry/src/s2/s2projections.h +161 -0
- package/third_party/s2geometry/src/s2/s2projections_test.cc +78 -0
- package/third_party/s2geometry/src/s2/s2r2rect.cc +88 -0
- package/third_party/s2geometry/src/s2/s2r2rect.h +292 -0
- package/third_party/s2geometry/src/s2/s2r2rect_test.cc +312 -0
- package/third_party/s2geometry/src/s2/s2region.cc +26 -0
- package/third_party/s2geometry/src/s2/s2region.h +142 -0
- package/third_party/s2geometry/src/s2/s2region_coverer.cc +514 -0
- package/third_party/s2geometry/src/s2/s2region_coverer.h +356 -0
- package/third_party/s2geometry/src/s2/s2region_coverer_test.cc +509 -0
- package/third_party/s2geometry/src/s2/s2region_intersection.cc +84 -0
- package/third_party/s2geometry/src/s2/s2region_intersection.h +79 -0
- package/third_party/s2geometry/src/s2/s2region_term_indexer.cc +270 -0
- package/third_party/s2geometry/src/s2/s2region_term_indexer.h +299 -0
- package/third_party/s2geometry/src/s2/s2region_term_indexer_test.cc +209 -0
- package/third_party/s2geometry/src/s2/s2region_test.cc +370 -0
- package/third_party/s2geometry/src/s2/s2region_union.cc +90 -0
- package/third_party/s2geometry/src/s2/s2region_union.h +83 -0
- package/third_party/s2geometry/src/s2/s2region_union_test.cc +89 -0
- package/third_party/s2geometry/src/s2/s2shape.h +283 -0
- package/third_party/s2geometry/src/s2/s2shape_index.cc +321 -0
- package/third_party/s2geometry/src/s2/s2shape_index.h +781 -0
- package/third_party/s2geometry/src/s2/s2shape_index_buffered_region.cc +113 -0
- package/third_party/s2geometry/src/s2/s2shape_index_buffered_region.h +135 -0
- package/third_party/s2geometry/src/s2/s2shape_index_buffered_region_test.cc +162 -0
- package/third_party/s2geometry/src/s2/s2shape_index_measures.cc +92 -0
- package/third_party/s2geometry/src/s2/s2shape_index_measures.h +100 -0
- package/third_party/s2geometry/src/s2/s2shape_index_measures_test.cc +136 -0
- package/third_party/s2geometry/src/s2/s2shape_index_region.h +350 -0
- package/third_party/s2geometry/src/s2/s2shape_index_region_test.cc +161 -0
- package/third_party/s2geometry/src/s2/s2shape_index_test.cc +24 -0
- package/third_party/s2geometry/src/s2/s2shape_measures.cc +138 -0
- package/third_party/s2geometry/src/s2/s2shape_measures.h +95 -0
- package/third_party/s2geometry/src/s2/s2shape_measures_test.cc +139 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries.cc +120 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries.h +66 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries_test.cc +170 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_coding.cc +253 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_coding.h +283 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_coding_test.cc +54 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force.cc +40 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force.h +41 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force_test.cc +55 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_count_edges.h +57 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_count_edges_test.cc +43 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator.cc +45 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator.h +72 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator_test.cc +116 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point.cc +107 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point.h +48 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point_test.cc +104 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator.cc +58 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator.h +65 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator_test.cc +61 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_shape_edge.h +58 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_shape_edge_id.h +97 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_testing.cc +104 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_testing.h +36 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs.cc +440 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs.h +72 -0
- package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs_test.cc +184 -0
- package/third_party/s2geometry/src/s2/s2testing.cc +464 -0
- package/third_party/s2geometry/src/s2/s2testing.h +385 -0
- package/third_party/s2geometry/src/s2/s2testing_test.cc +166 -0
- package/third_party/s2geometry/src/s2/s2text_format.cc +506 -0
- package/third_party/s2geometry/src/s2/s2text_format.h +289 -0
- package/third_party/s2geometry/src/s2/s2text_format_test.cc +417 -0
- package/third_party/s2geometry/src/s2/s2wedge_relations.cc +80 -0
- package/third_party/s2geometry/src/s2/s2wedge_relations.h +64 -0
- package/third_party/s2geometry/src/s2/s2wedge_relations_test.cc +89 -0
- package/third_party/s2geometry/src/s2/sequence_lexicon.h +296 -0
- package/third_party/s2geometry/src/s2/sequence_lexicon_test.cc +113 -0
- package/third_party/s2geometry/src/s2/strings/ostringstream.cc +35 -0
- package/third_party/s2geometry/src/s2/strings/ostringstream.h +105 -0
- package/third_party/s2geometry/src/s2/strings/serialize.cc +46 -0
- package/third_party/s2geometry/src/s2/strings/serialize.h +40 -0
- package/third_party/s2geometry/src/s2/third_party/absl/algorithm/algorithm.h +187 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/attributes.h +666 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/casts.h +189 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/config.h +462 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/dynamic_annotations.cc +129 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/dynamic_annotations.h +394 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/atomic_hook.h +168 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/identity.h +33 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/inline_variable.h +117 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/invoke.h +188 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/raw_logging.cc +254 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/raw_logging.h +205 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/throw_delegate.cc +106 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/throw_delegate.h +71 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/internal/unaligned_access.h +322 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/log_severity.h +77 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/macros.h +236 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/optimization.h +177 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/policy_checks.h +124 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/port.h +97 -0
- package/third_party/s2geometry/src/s2/third_party/absl/base/thread_annotations.h +277 -0
- package/third_party/s2geometry/src/s2/third_party/absl/container/fixed_array.h +523 -0
- package/third_party/s2geometry/src/s2/third_party/absl/container/inlined_vector.h +1453 -0
- package/third_party/s2geometry/src/s2/third_party/absl/container/internal/compressed_tuple.h +191 -0
- package/third_party/s2geometry/src/s2/third_party/absl/container/internal/container_memory.h +424 -0
- package/third_party/s2geometry/src/s2/third_party/absl/container/internal/layout.h +739 -0
- package/third_party/s2geometry/src/s2/third_party/absl/memory/memory.h +755 -0
- package/third_party/s2geometry/src/s2/third_party/absl/meta/type_traits.h +436 -0
- package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128.cc +232 -0
- package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128.h +656 -0
- package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128_have_intrinsic.inc +3 -0
- package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128_no_intrinsic.inc +3 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii.cc +198 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii.h +239 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii_ctype.h +66 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/bits.h +53 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/memutil.cc +110 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/memutil.h +146 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/resize_uninitialized.h +72 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/match.cc +38 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/match.h +89 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/numbers.cc +909 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/numbers.h +187 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/str_cat.cc +240 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/str_cat.h +398 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/str_join.h +22 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/str_split.cc +47 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/str_split.h +43 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/string_view.cc +245 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/string_view.h +602 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/strip.cc +42 -0
- package/third_party/s2geometry/src/s2/third_party/absl/strings/strip.h +130 -0
- package/third_party/s2geometry/src/s2/third_party/absl/types/span.h +793 -0
- package/third_party/s2geometry/src/s2/third_party/absl/utility/utility.h +299 -0
- package/third_party/s2geometry/src/s2/util/bits/bit-interleave.cc +274 -0
- package/third_party/s2geometry/src/s2/util/bits/bit-interleave.h +53 -0
- package/third_party/s2geometry/src/s2/util/bits/bits.cc +155 -0
- package/third_party/s2geometry/src/s2/util/bits/bits.h +745 -0
- package/third_party/s2geometry/src/s2/util/coding/coder.cc +83 -0
- package/third_party/s2geometry/src/s2/util/coding/coder.h +553 -0
- package/third_party/s2geometry/src/s2/util/coding/nth-derivative.h +134 -0
- package/third_party/s2geometry/src/s2/util/coding/transforms.h +62 -0
- package/third_party/s2geometry/src/s2/util/coding/varint.cc +289 -0
- package/third_party/s2geometry/src/s2/util/coding/varint.h +476 -0
- package/third_party/s2geometry/src/s2/util/endian/endian.h +859 -0
- package/third_party/s2geometry/src/s2/util/gtl/btree.h +2471 -0
- package/third_party/s2geometry/src/s2/util/gtl/btree_container.h +411 -0
- package/third_party/s2geometry/src/s2/util/gtl/btree_map.h +79 -0
- package/third_party/s2geometry/src/s2/util/gtl/btree_set.h +73 -0
- package/third_party/s2geometry/src/s2/util/gtl/compact_array.h +653 -0
- package/third_party/s2geometry/src/s2/util/gtl/container_logging.h +291 -0
- package/third_party/s2geometry/src/s2/util/gtl/dense_hash_set.h +358 -0
- package/third_party/s2geometry/src/s2/util/gtl/densehashtable.h +1493 -0
- package/third_party/s2geometry/src/s2/util/gtl/hashtable_common.h +253 -0
- package/third_party/s2geometry/src/s2/util/gtl/layout.h +28 -0
- package/third_party/s2geometry/src/s2/util/gtl/legacy_random_shuffle.h +77 -0
- package/third_party/s2geometry/src/s2/util/hash/mix.h +76 -0
- package/third_party/s2geometry/src/s2/util/math/exactfloat/exactfloat.cc +832 -0
- package/third_party/s2geometry/src/s2/util/math/exactfloat/exactfloat.h +646 -0
- package/third_party/s2geometry/src/s2/util/math/mathutil.cc +75 -0
- package/third_party/s2geometry/src/s2/util/math/mathutil.h +189 -0
- package/third_party/s2geometry/src/s2/util/math/matrix3x3.h +574 -0
- package/third_party/s2geometry/src/s2/util/math/vector.h +569 -0
- package/third_party/s2geometry/src/s2/util/math/vector3_hash.h +54 -0
- package/third_party/s2geometry/src/s2/util/units/length-units.cc +21 -0
- package/third_party/s2geometry/src/s2/util/units/length-units.h +135 -0
- package/third_party/s2geometry/src/s2/util/units/physical-units.h +313 -0
- package/third_party/s2geometry/src/s2/value_lexicon.h +234 -0
- package/third_party/s2geometry/src/s2/value_lexicon_test.cc +121 -0
- package/third_party/s2geometry/third_party/cmake/FindGFlags.cmake +48 -0
- package/third_party/s2geometry/third_party/cmake/FindGlog.cmake +48 -0
|
@@ -0,0 +1,1329 @@
|
|
|
1
|
+
// Copyright 2016 Google Inc. All Rights Reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
//
|
|
15
|
+
|
|
16
|
+
// Author: ericv@google.com (Eric Veach)
|
|
17
|
+
|
|
18
|
+
#include "s2/s2builder.h"
|
|
19
|
+
|
|
20
|
+
#include <algorithm>
|
|
21
|
+
#include <cinttypes>
|
|
22
|
+
#include <cmath>
|
|
23
|
+
#include <cstdint>
|
|
24
|
+
#include <iostream>
|
|
25
|
+
#include <memory>
|
|
26
|
+
#include <string>
|
|
27
|
+
#include <vector>
|
|
28
|
+
|
|
29
|
+
#include "s2/base/commandlineflags.h"
|
|
30
|
+
#include "s2/base/log_severity.h"
|
|
31
|
+
#include "s2/base/timer.h"
|
|
32
|
+
#include <gtest/gtest.h>
|
|
33
|
+
#include "s2/third_party/absl/memory/memory.h"
|
|
34
|
+
#include "s2/third_party/absl/strings/str_cat.h"
|
|
35
|
+
#include "s2/third_party/absl/strings/str_join.h"
|
|
36
|
+
#include "s2/s2builder_layer.h"
|
|
37
|
+
#include "s2/s2builderutil_s2polygon_layer.h"
|
|
38
|
+
#include "s2/s2builderutil_s2polyline_layer.h"
|
|
39
|
+
#include "s2/s2builderutil_s2polyline_vector_layer.h"
|
|
40
|
+
#include "s2/s2builderutil_snap_functions.h"
|
|
41
|
+
#include "s2/s2builderutil_testing.h"
|
|
42
|
+
#include "s2/s2cap.h"
|
|
43
|
+
#include "s2/s2cell_id.h"
|
|
44
|
+
#include "s2/s2debug.h"
|
|
45
|
+
#include "s2/s2edge_crossings.h"
|
|
46
|
+
#include "s2/s2edge_distances.h"
|
|
47
|
+
#include "s2/s2latlng.h"
|
|
48
|
+
#include "s2/s2loop.h"
|
|
49
|
+
#include "s2/s2polygon.h"
|
|
50
|
+
#include "s2/s2polyline.h"
|
|
51
|
+
#include "s2/s2predicates.h"
|
|
52
|
+
#include "s2/s2testing.h"
|
|
53
|
+
#include "s2/s2text_format.h"
|
|
54
|
+
|
|
55
|
+
using absl::StrAppend;
|
|
56
|
+
using absl::StrCat;
|
|
57
|
+
using absl::make_unique;
|
|
58
|
+
using std::cout;
|
|
59
|
+
using std::endl;
|
|
60
|
+
using std::make_pair;
|
|
61
|
+
using std::min;
|
|
62
|
+
using std::pair;
|
|
63
|
+
using std::unique_ptr;
|
|
64
|
+
using std::vector;
|
|
65
|
+
using s2builderutil::GraphClone;
|
|
66
|
+
using s2builderutil::IdentitySnapFunction;
|
|
67
|
+
using s2builderutil::IntLatLngSnapFunction;
|
|
68
|
+
using s2builderutil::S2CellIdSnapFunction;
|
|
69
|
+
using s2builderutil::S2PolygonLayer;
|
|
70
|
+
using s2builderutil::S2PolylineLayer;
|
|
71
|
+
using s2builderutil::S2PolylineVectorLayer;
|
|
72
|
+
using s2textformat::MakePointOrDie;
|
|
73
|
+
using s2textformat::MakePolygonOrDie;
|
|
74
|
+
using s2textformat::MakePolylineOrDie;
|
|
75
|
+
using EdgeType = S2Builder::EdgeType;
|
|
76
|
+
using InputEdgeId = S2Builder::Graph::InputEdgeId;
|
|
77
|
+
using Graph = S2Builder::Graph;
|
|
78
|
+
using GraphOptions = S2Builder::GraphOptions;;
|
|
79
|
+
|
|
80
|
+
S2_DEFINE_int32(iteration_multiplier, 1,
|
|
81
|
+
"Iteration multiplier for randomized tests");
|
|
82
|
+
|
|
83
|
+
namespace {
|
|
84
|
+
|
|
85
|
+
void ExpectPolygonsEqual(const S2Polygon& expected,
|
|
86
|
+
const S2Polygon& actual) {
|
|
87
|
+
EXPECT_TRUE(expected.Equals(&actual))
|
|
88
|
+
<< "\nExpected:\n" << s2textformat::ToString(expected)
|
|
89
|
+
<< "\nActual:\n" << s2textformat::ToString(actual);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void ExpectPolygonsApproxEqual(const S2Polygon& expected,
|
|
93
|
+
const S2Polygon& actual,
|
|
94
|
+
S1Angle tolerance) {
|
|
95
|
+
EXPECT_TRUE(expected.BoundaryApproxEquals(actual, tolerance))
|
|
96
|
+
<< "\nExpected: " << s2textformat::ToString(expected)
|
|
97
|
+
<< "\nActual: " << s2textformat::ToString(actual)
|
|
98
|
+
<< "\nTolerance: " << tolerance.degrees();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void ExpectPolylinesEqual(const S2Polyline& expected,
|
|
102
|
+
const S2Polyline& actual) {
|
|
103
|
+
EXPECT_TRUE(expected.Equals(&actual))
|
|
104
|
+
<< "\nExpected:\n" << s2textformat::ToString(expected)
|
|
105
|
+
<< "\nActual:\n" << s2textformat::ToString(actual);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
TEST(S2Builder, AddShape) {
|
|
109
|
+
S2Builder builder{S2Builder::Options()};
|
|
110
|
+
S2Polygon output;
|
|
111
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
112
|
+
auto input = MakePolygonOrDie("0:0, 0:5, 5:5, 5:0; 1:1, 1:4, 4:4, 4:1");
|
|
113
|
+
builder.AddShape(*input->index().shape(0));
|
|
114
|
+
S2Error error;
|
|
115
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
116
|
+
ExpectPolygonsEqual(*input, output);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
TEST(S2Builder, SimpleVertexMerging) {
|
|
120
|
+
// When IdentitySnapFunction is used (i.e., no special requirements on
|
|
121
|
+
// vertex locations), check that vertices closer together than the snap
|
|
122
|
+
// radius are merged together.
|
|
123
|
+
|
|
124
|
+
S1Angle snap_radius = S1Angle::Degrees(0.5);
|
|
125
|
+
S2Builder builder{S2Builder::Options(IdentitySnapFunction(snap_radius))};
|
|
126
|
+
S2Polygon output;
|
|
127
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
128
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
129
|
+
"0:0, 0.2:0.2, 0.1:0.2, 0.1:0.9, 0:1, 0.1:1.1, 0.9:1, 1:1, 1:0.9");
|
|
130
|
+
builder.AddPolygon(*input);
|
|
131
|
+
S2Error error;
|
|
132
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
133
|
+
unique_ptr<S2Polygon> expected = MakePolygonOrDie("0:0, 0:1, 1:0.9");
|
|
134
|
+
ExpectPolygonsApproxEqual(*expected, output, snap_radius);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
TEST(S2Builder, SimpleS2CellIdSnapping) {
|
|
138
|
+
// When S2CellIdSnapFunction is used, check that all output vertices are the
|
|
139
|
+
// centers of S2CellIds at the specified level level.
|
|
140
|
+
|
|
141
|
+
int level = S2CellIdSnapFunction::LevelForMaxSnapRadius(S1Angle::Degrees(1));
|
|
142
|
+
S2CellIdSnapFunction snap_function(level);
|
|
143
|
+
S2Builder builder{S2Builder::Options(snap_function)};
|
|
144
|
+
S2Polygon output;
|
|
145
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
146
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
147
|
+
"2:2, 3:4, 2:6, 4:5, 6:6, 5:4, 6:2, 4:3");
|
|
148
|
+
builder.AddPolygon(*input);
|
|
149
|
+
S2Error error;
|
|
150
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
151
|
+
ASSERT_EQ(1, output.num_loops());
|
|
152
|
+
const S2Loop* loop = output.loop(0);
|
|
153
|
+
for (int i = 0; i < loop->num_vertices(); ++i) {
|
|
154
|
+
EXPECT_EQ(S2CellId(loop->vertex(i)).parent(level).ToPoint(),
|
|
155
|
+
loop->vertex(i));
|
|
156
|
+
}
|
|
157
|
+
ExpectPolygonsApproxEqual(*input, output, snap_function.snap_radius());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
TEST(S2Builder, SimpleIntLatLngSnapping) {
|
|
161
|
+
S2Builder builder(S2Builder::Options(IntLatLngSnapFunction(0))); // E0 coords
|
|
162
|
+
S2Polygon output;
|
|
163
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
164
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
165
|
+
"2.01:2.09, 3.24:4.49, 1.78:6.25, 3.51:5.49, 6.11:6.11, "
|
|
166
|
+
"5.22:3.88, 5.55:2.49, 4.49:2.51");
|
|
167
|
+
unique_ptr<S2Polygon> expected = MakePolygonOrDie(
|
|
168
|
+
"2:2, 3:4, 2:6, 4:5, 6:6, 5:4, 6:2, 4:3");
|
|
169
|
+
builder.AddPolygon(*input);
|
|
170
|
+
S2Error error;
|
|
171
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
172
|
+
ASSERT_EQ(1, output.num_loops());
|
|
173
|
+
ExpectPolygonsEqual(*expected, output);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
TEST(S2Builder, VerticesMoveLessThanSnapRadius) {
|
|
177
|
+
// Check that chains of closely spaced vertices do not collapse into a
|
|
178
|
+
// single vertex.
|
|
179
|
+
|
|
180
|
+
S1Angle snap_radius = S1Angle::Degrees(1);
|
|
181
|
+
S2Builder builder{S2Builder::Options{IdentitySnapFunction(snap_radius)}};
|
|
182
|
+
S2Polygon output;
|
|
183
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
184
|
+
// The spacing between input vertices is about 2*pi*20/1000 = 0.125 degrees.
|
|
185
|
+
// The output vertices are spaced between 1 and 2 degrees apart; the average
|
|
186
|
+
// spacing is about 1.33 degrees.
|
|
187
|
+
S2Polygon input(
|
|
188
|
+
S2Loop::MakeRegularLoop(S2Point(1, 0, 0), S1Angle::Degrees(20), 1000));
|
|
189
|
+
builder.AddPolygon(input);
|
|
190
|
+
S2Error error;
|
|
191
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
192
|
+
ASSERT_EQ(1, output.num_loops());
|
|
193
|
+
EXPECT_GE(output.loop(0)->num_vertices(), 90);
|
|
194
|
+
EXPECT_LE(output.loop(0)->num_vertices(), 100);
|
|
195
|
+
EXPECT_TRUE(output.BoundaryNear(input, snap_radius));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
TEST(S2Builder, MinEdgeVertexSeparation) {
|
|
199
|
+
// Check that edges are separted from non-incident vertices by at least
|
|
200
|
+
// min_edge_vertex_separation(). This requires adding new vertices (not
|
|
201
|
+
// present in the input) in some cases.
|
|
202
|
+
|
|
203
|
+
// The input is a skinny right triangle with two legs of length 10 and 1,
|
|
204
|
+
// and whose diagonal is subdivided into 10 short edges. Using a snap
|
|
205
|
+
// radius of 0.5, about half of the long leg is snapped onto the diagonal
|
|
206
|
+
// (which causes that part of the polygon to be removed). But the real
|
|
207
|
+
// problem is that the remaining part of the long leg gets too close to the
|
|
208
|
+
// remaining vertices on the diagonal, i.e. it would violate the minimum
|
|
209
|
+
// edge-vertex separation guarantee. S2Builder handles this by creating at
|
|
210
|
+
// least one vertex along the original long leg, to keep the snapped edge
|
|
211
|
+
// far enough away from the diagonal.
|
|
212
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
213
|
+
"0:0, 0:1, 1:.9, 2:.8, 3:.7, 4:.6, 5:.5, 6:.4, 7:.3, 8:.2, 9:.1, 10:0");
|
|
214
|
+
unique_ptr<S2Polygon> expected = MakePolygonOrDie(
|
|
215
|
+
"0:0, 0:1, 1:.9, 2:.8, 3:.7, 4:.6, 5:.5, 4.00021862252687:0");
|
|
216
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
|
|
217
|
+
S2Builder builder(options);
|
|
218
|
+
S2Polygon output;
|
|
219
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
220
|
+
builder.AddPolygon(*input);
|
|
221
|
+
S2Error error;
|
|
222
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
223
|
+
ExpectPolygonsApproxEqual(*expected, output, S1Angle::Radians(1e-15));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
TEST(S2Builder, IdempotencySnapsInadequatelySeparatedVertices) {
|
|
227
|
+
// This test checks that when vertices are closer together than
|
|
228
|
+
// min_vertex_separation() then they are snapped together even when
|
|
229
|
+
// options.idempotent() is true.
|
|
230
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1.0)));
|
|
231
|
+
S2Builder builder(options);
|
|
232
|
+
S2Polyline output;
|
|
233
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output));
|
|
234
|
+
builder.AddPolyline(*MakePolylineOrDie("0:0, 0:0.9, 0:2"));
|
|
235
|
+
S2Error error;
|
|
236
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
237
|
+
const char* expected = "0:0, 0:2";
|
|
238
|
+
EXPECT_EQ(expected, s2textformat::ToString(output));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
TEST(S2Builder, IdempotencySnapsIdenticalVerticesWithZeroSnapRadius) {
|
|
242
|
+
// This test checks that even when the snap radius is zero, identical
|
|
243
|
+
// vertices are snapped together.
|
|
244
|
+
S2Builder builder{S2Builder::Options()};
|
|
245
|
+
S2Polygon output;
|
|
246
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
247
|
+
builder.AddPolyline(*MakePolylineOrDie("0:1, 1:0"));
|
|
248
|
+
builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1"));
|
|
249
|
+
builder.AddEdge(MakePointOrDie("0:1"), MakePointOrDie("0:1"));
|
|
250
|
+
builder.AddPolyline(*MakePolylineOrDie("1:0, 0:0"));
|
|
251
|
+
S2Error error;
|
|
252
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
253
|
+
const char* expected = "0:0, 0:1, 1:0";
|
|
254
|
+
EXPECT_EQ(expected, s2textformat::ToString(output));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
TEST(S2Builder,
|
|
258
|
+
IdempotencySnapsIdenticalVerticesWithZeroSnapRadiusEdgeSplitting) {
|
|
259
|
+
// This test checks that identical vertices are snapped together even when
|
|
260
|
+
// the snap radius is zero and options.split_crossing_edges() is true.
|
|
261
|
+
S2Builder::Options options;
|
|
262
|
+
options.set_split_crossing_edges(true);
|
|
263
|
+
S2Builder builder(options);
|
|
264
|
+
S2Polygon output;
|
|
265
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
266
|
+
builder.AddPolyline(*MakePolylineOrDie("0:1, 1:0"));
|
|
267
|
+
builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1"));
|
|
268
|
+
builder.AddEdge(MakePointOrDie("0:1"), MakePointOrDie("0:1"));
|
|
269
|
+
builder.AddPolyline(*MakePolylineOrDie("1:0, 0:0"));
|
|
270
|
+
S2Error error;
|
|
271
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
272
|
+
const char* expected = "0:0, 0:1, 1:0";
|
|
273
|
+
EXPECT_EQ(expected, s2textformat::ToString(output));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
TEST(S2Builder, IdempotencySnapsUnsnappedVertices) {
|
|
277
|
+
// When idempotency is requested, no snapping is done unless S2Builder finds
|
|
278
|
+
// at least one vertex or edge that could not be the output of a previous
|
|
279
|
+
// snapping operation. This test checks that S2Builder detects vertices
|
|
280
|
+
// that are not at a valid location returned by the given snap function.
|
|
281
|
+
|
|
282
|
+
// In this example we snap two vertices to integer lat/lng coordinates. The
|
|
283
|
+
// two vertices are far enough apart (more than min_vertex_separation) so
|
|
284
|
+
// that they might be the result of a previous snapping operation, but one
|
|
285
|
+
// of the two vertices does not have integer lat/lng coordinates. We use
|
|
286
|
+
// internal knowledge of how snap sites are chosen (namely, that candidates
|
|
287
|
+
// are considered in S2CellId order) to construct two different cases, one
|
|
288
|
+
// where the snapped vertex is processed first and one where the unsnapped
|
|
289
|
+
// vertex is processed first. This exercises two different code paths.
|
|
290
|
+
IntLatLngSnapFunction snap_function(0);
|
|
291
|
+
EXPECT_GE(snap_function.snap_radius(), S1Angle::Degrees(0.7));
|
|
292
|
+
EXPECT_LE(snap_function.min_vertex_separation(), S1Angle::Degrees(0.35));
|
|
293
|
+
S2Builder builder{S2Builder::Options(snap_function)};
|
|
294
|
+
|
|
295
|
+
// In this example, the snapped vertex (0, 0) is processed first and is
|
|
296
|
+
// selected as a Voronoi site (i.e., output vertex). The second vertex is
|
|
297
|
+
// closer than min_(), therefore it is snapped to the first vertex
|
|
298
|
+
// and the polyline becomes degenerate.
|
|
299
|
+
S2Point a = S2LatLng::FromDegrees(0, 0).ToPoint();
|
|
300
|
+
S2Point b = S2LatLng::FromDegrees(0.01, 0.6).ToPoint();
|
|
301
|
+
EXPECT_LT(S2CellId(a), S2CellId(b));
|
|
302
|
+
S2Polyline input1(vector<S2Point>{a, b}), output1;
|
|
303
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output1));
|
|
304
|
+
builder.AddPolyline(input1);
|
|
305
|
+
S2Error error;
|
|
306
|
+
ASSERT_TRUE(builder.Build(&error));
|
|
307
|
+
EXPECT_EQ("0:0, 0:1", s2textformat::ToString(output1));
|
|
308
|
+
|
|
309
|
+
// In this example the unsnapped vertex is processed first and is snapped to
|
|
310
|
+
// (0, 0). The second vertex is further than snap_radius() away, so it is
|
|
311
|
+
// also snapped (which does nothing) and is left at (0, 1).
|
|
312
|
+
S2Point c = S2LatLng::FromDegrees(0.01, 0.4).ToPoint();
|
|
313
|
+
S2Point d = S2LatLng::FromDegrees(0, 1).ToPoint();
|
|
314
|
+
EXPECT_LT(S2CellId(c), S2CellId(d));
|
|
315
|
+
S2Polyline input2(vector<S2Point>{c, d}), output2;
|
|
316
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output2));
|
|
317
|
+
builder.AddPolyline(input2);
|
|
318
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
319
|
+
EXPECT_EQ("0:0, 0:1", s2textformat::ToString(output2));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
TEST(S2Builder, IdempotencySnapsEdgesWithTinySnapRadius) {
|
|
323
|
+
// When idempotency is requested, no snapping is done unless S2Builder finds
|
|
324
|
+
// at least one vertex or edge that could not be the output of a previous
|
|
325
|
+
// snapping operation. This test checks that S2Builder detects edges that
|
|
326
|
+
// are too close to vertices even when the snap radius is very small
|
|
327
|
+
// (e.g., S2::kIntersectionError).
|
|
328
|
+
//
|
|
329
|
+
// Previously S2Builder used a conservative approximation to decide whether
|
|
330
|
+
// edges were too close to vertices; unfortunately this meant that when the
|
|
331
|
+
// snap radius was very small then no snapping would be done at all, because
|
|
332
|
+
// even an edge/vertex distance of zero was considered far enough apart.
|
|
333
|
+
//
|
|
334
|
+
// This tests that the current code (which uses exact predicates) handles
|
|
335
|
+
// this situation correctly (i.e., that an edge separated from a
|
|
336
|
+
// non-incident vertex by a distance of zero cannot be the output of a
|
|
337
|
+
// previous snapping operation).
|
|
338
|
+
S2Builder::Options options;
|
|
339
|
+
options.set_snap_function(
|
|
340
|
+
s2builderutil::IdentitySnapFunction(S2::kIntersectionError));
|
|
341
|
+
S2PolylineVectorLayer::Options layer_options;
|
|
342
|
+
layer_options.set_duplicate_edges(
|
|
343
|
+
S2PolylineVectorLayer::Options::DuplicateEdges::MERGE);
|
|
344
|
+
S2Builder builder(options);
|
|
345
|
+
vector<unique_ptr<S2Polyline>> output;
|
|
346
|
+
builder.StartLayer(
|
|
347
|
+
make_unique<S2PolylineVectorLayer>(&output, layer_options));
|
|
348
|
+
builder.AddPolyline(*MakePolylineOrDie("0:0, 0:10"));
|
|
349
|
+
builder.AddPolyline(*MakePolylineOrDie("0:5, 0:7"));
|
|
350
|
+
S2Error error;
|
|
351
|
+
ASSERT_TRUE(builder.Build(&error));
|
|
352
|
+
ASSERT_EQ(1, output.size());
|
|
353
|
+
EXPECT_EQ("0:0, 0:5, 0:7, 0:10", s2textformat::ToString(*output[0]));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
TEST(S2Builder, IdempotencyDoesNotSnapAdequatelySeparatedEdges) {
|
|
357
|
+
// When idempotency is requested, no snapping is done unless S2Builder finds
|
|
358
|
+
// at least one vertex or edge that could not be the output of a previous
|
|
359
|
+
// snapping operation. This test checks that when an edge is further away
|
|
360
|
+
// than min_edge_vertex_separation() then no snapping is done.
|
|
361
|
+
S2Builder::Options options(IntLatLngSnapFunction(0));
|
|
362
|
+
options.set_idempotent(true); // Test fails if this is "false".
|
|
363
|
+
S2Builder builder(options);
|
|
364
|
+
S2Polygon output1, output2;
|
|
365
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output1));
|
|
366
|
+
builder.AddPolygon(*MakePolygonOrDie("1.49:0, 0:2, 0.49:3"));
|
|
367
|
+
S2Error error;
|
|
368
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
369
|
+
const char* expected = "1:0, 0:2, 0:3";
|
|
370
|
+
EXPECT_EQ(expected, s2textformat::ToString(output1));
|
|
371
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output2));
|
|
372
|
+
builder.AddPolygon(output1);
|
|
373
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
374
|
+
EXPECT_EQ(expected, s2textformat::ToString(output2));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
TEST(S2Builder, kMaxSnapRadiusCanSnapAtLevel0) {
|
|
378
|
+
// Verify that kMaxSnapRadius will allow snapping at S2CellId level 0.
|
|
379
|
+
EXPECT_LE(S2CellIdSnapFunction::MinSnapRadiusForLevel(0),
|
|
380
|
+
S2Builder::SnapFunction::kMaxSnapRadius());
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
TEST(S2Builder, S2CellIdSnappingAtAllLevels) {
|
|
384
|
+
unique_ptr<const S2Polygon> input = MakePolygonOrDie(
|
|
385
|
+
"0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0");
|
|
386
|
+
for (int level = 0; level <= S2CellId::kMaxLevel; ++level) {
|
|
387
|
+
S2CellIdSnapFunction snap_function(level);
|
|
388
|
+
S2Builder builder{S2Builder::Options(snap_function)};
|
|
389
|
+
S2Polygon output;
|
|
390
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
391
|
+
builder.AddPolygon(*input);
|
|
392
|
+
S2Error error;
|
|
393
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
394
|
+
EXPECT_TRUE(output.IsValid());
|
|
395
|
+
// The ApproxContains calls below are not guaranteed to succeed in general
|
|
396
|
+
// because ApproxContains works by snapping both polygons together using
|
|
397
|
+
// the given tolerance and then checking for containment. Since
|
|
398
|
+
// ApproxContains snaps to an arbitrary subset of the input vertices
|
|
399
|
+
// rather than to S2CellId centers at the current level, this means that
|
|
400
|
+
// corresponding vertices in "input" and "output" can snap to different
|
|
401
|
+
// sites, which causes the containment test to fail. Nevertheless, by
|
|
402
|
+
// using a larger tolerance of 2 * snap_radius, all calls in this test
|
|
403
|
+
// succeed (and would be likely to succeed in other similar tests).
|
|
404
|
+
// (To guarantee correctness we would need to use S2CellIdSnapFunction
|
|
405
|
+
// within the ApproxContains implementation.)
|
|
406
|
+
S1Angle tolerance = min(2 * snap_function.snap_radius(),
|
|
407
|
+
snap_function.kMaxSnapRadius());
|
|
408
|
+
EXPECT_TRUE(output.ApproxContains(input.get(), tolerance));
|
|
409
|
+
EXPECT_TRUE(input->ApproxContains(&output, tolerance));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
TEST(S2Builder, SnappingDoesNotRotateVertices) {
|
|
414
|
+
// This is already tested extensively elsewhere.
|
|
415
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
416
|
+
"49.9305505:-124.8345463, 49.9307448:-124.8299657, "
|
|
417
|
+
"49.9332101:-124.8301996, 49.9331224:-124.8341368; "
|
|
418
|
+
"49.9311087:-124.8327042, 49.9318176:-124.8312621, "
|
|
419
|
+
"49.9318866:-124.8334451");
|
|
420
|
+
S2Builder::Options options((S2CellIdSnapFunction()));
|
|
421
|
+
S2Builder builder(options);
|
|
422
|
+
S2Polygon output1, output2;
|
|
423
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output1));
|
|
424
|
+
builder.AddPolygon(*input);
|
|
425
|
+
S2Error error;
|
|
426
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
427
|
+
// This checks that the vertices are in the same cyclic order, and that
|
|
428
|
+
// vertices have not moved by more than "snap_radius".
|
|
429
|
+
ExpectPolygonsApproxEqual(*input, output1,
|
|
430
|
+
options.snap_function().snap_radius());
|
|
431
|
+
|
|
432
|
+
// Check that snapping twice doesn't rotate the vertices. This also
|
|
433
|
+
// verifies that S2Builder can be used again after Build() is called.
|
|
434
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output2));
|
|
435
|
+
builder.AddPolygon(output1);
|
|
436
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
437
|
+
ExpectPolygonsEqual(output1, output2);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
TEST(S2Builder, SelfIntersectingPolyline) {
|
|
441
|
+
// Check that when two edges of a polyline cross, the intersection point is
|
|
442
|
+
// added to both edges.
|
|
443
|
+
|
|
444
|
+
S2Builder::Options options;
|
|
445
|
+
IntLatLngSnapFunction snap_function(1); // Snap to E1 coordinates
|
|
446
|
+
options.set_snap_function(snap_function);
|
|
447
|
+
options.set_split_crossing_edges(true);
|
|
448
|
+
S2Builder builder(options);
|
|
449
|
+
S2Polyline output;
|
|
450
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output));
|
|
451
|
+
unique_ptr<S2Polyline> input = MakePolylineOrDie("3:1, 1:3, 1:1, 3:3");
|
|
452
|
+
unique_ptr<S2Polyline> expected =
|
|
453
|
+
MakePolylineOrDie("3:1, 2:2, 1:3, 1:1, 2:2, 3:3");
|
|
454
|
+
builder.AddPolyline(*input);
|
|
455
|
+
S2Error error;
|
|
456
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
457
|
+
ExpectPolylinesEqual(*expected, output);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
TEST(S2Builder, SelfIntersectingPolygon) {
|
|
461
|
+
// Check that when two edge of a polygon cross, the intersection point is
|
|
462
|
+
// added to both edges, and that the resulting (undirected) edges can be
|
|
463
|
+
// assembled into a valid polygon.
|
|
464
|
+
|
|
465
|
+
IntLatLngSnapFunction snap_function(1); // Snap to E1 coordinates
|
|
466
|
+
S2Builder::Options options;
|
|
467
|
+
options.set_snap_function(snap_function);
|
|
468
|
+
options.set_split_crossing_edges(true);
|
|
469
|
+
S2Builder builder(options);
|
|
470
|
+
S2Polygon output;
|
|
471
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(
|
|
472
|
+
&output, S2PolygonLayer::Options(EdgeType::UNDIRECTED)));
|
|
473
|
+
unique_ptr<S2Polyline> input = MakePolylineOrDie("3:1, 1:3, 1:1, 3:3, 3:1");
|
|
474
|
+
unique_ptr<S2Polygon> expected = MakePolygonOrDie("1:1, 1:3, 2:2; 3:3, 3:1, 2:2");
|
|
475
|
+
builder.AddPolyline(*input);
|
|
476
|
+
S2Error error;
|
|
477
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
478
|
+
ExpectPolygonsEqual(*expected, output);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
TEST(S2Builder, TieBreakingIsConsistent) {
|
|
482
|
+
// Check that when an edge passes between two equally distant vertices, that
|
|
483
|
+
// the choice of which one to snap to does not depend on the edge direction.
|
|
484
|
+
|
|
485
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(2)));
|
|
486
|
+
options.set_idempotent(false);
|
|
487
|
+
S2Builder builder(options);
|
|
488
|
+
builder.ForceVertex(S2LatLng::FromDegrees(1, 0).ToPoint());
|
|
489
|
+
builder.ForceVertex(S2LatLng::FromDegrees(-1, 0).ToPoint());
|
|
490
|
+
S2Polyline output1, output2;
|
|
491
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output1));
|
|
492
|
+
builder.AddPolyline(*MakePolylineOrDie("0:-5, 0:5"));
|
|
493
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output2));
|
|
494
|
+
builder.AddPolyline(*MakePolylineOrDie("0:5, 0:-5"));
|
|
495
|
+
S2Error error;
|
|
496
|
+
EXPECT_TRUE(builder.Build(&error)) << error;
|
|
497
|
+
EXPECT_EQ(3, output1.num_vertices());
|
|
498
|
+
EXPECT_EQ(3, output2.num_vertices());
|
|
499
|
+
for (int i = 0; i < 3; ++i) {
|
|
500
|
+
EXPECT_EQ(output1.vertex(i), output2.vertex(2 - i));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Verifies that two graphs have the same vertices and edges.
|
|
505
|
+
void ExpectGraphsEqual(const S2Builder::Graph& expected,
|
|
506
|
+
const S2Builder::Graph& actual) {
|
|
507
|
+
ASSERT_EQ(expected.vertices(), actual.vertices());
|
|
508
|
+
ASSERT_EQ(expected.edges(), actual.edges());
|
|
509
|
+
ASSERT_EQ(expected.input_edge_id_set_ids(),
|
|
510
|
+
actual.input_edge_id_set_ids());
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// This layer makes both a shallow and a deep copy of the Graph object passed
|
|
514
|
+
// to its Build() method and appends them to two vectors. Furthermore, it
|
|
515
|
+
// verifies that the shallow and deep copies of any graphs previously appended
|
|
516
|
+
// to those vectors are still identical.
|
|
517
|
+
class GraphPersistenceLayer : public S2Builder::Layer {
|
|
518
|
+
public:
|
|
519
|
+
GraphPersistenceLayer(
|
|
520
|
+
const S2Builder::GraphOptions& graph_options,
|
|
521
|
+
std::vector<S2Builder::Graph>* graphs,
|
|
522
|
+
std::vector<std::unique_ptr<GraphClone>>* clones)
|
|
523
|
+
: graph_options_(graph_options), graphs_(graphs), clones_(clones) {}
|
|
524
|
+
|
|
525
|
+
S2Builder::GraphOptions graph_options() const override {
|
|
526
|
+
return graph_options_;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
void Build(const S2Builder::Graph& g, S2Error* error) override {
|
|
530
|
+
// Verify that all graphs built so far are unchanged.
|
|
531
|
+
for (int i = 0; i < graphs_->size(); ++i) {
|
|
532
|
+
ExpectGraphsEqual((*clones_)[i]->graph(), (*graphs_)[i]);
|
|
533
|
+
}
|
|
534
|
+
graphs_->push_back(g);
|
|
535
|
+
clones_->push_back(absl::make_unique<GraphClone>(g));
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private:
|
|
539
|
+
GraphOptions graph_options_;
|
|
540
|
+
std::vector<S2Builder::Graph>* graphs_; // Shallow copies.
|
|
541
|
+
std::vector<std::unique_ptr<GraphClone>>* clones_; // Deep copies.
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
TEST(S2Builder, GraphPersistence) {
|
|
545
|
+
// Ensure that the Graph objects passed to S2Builder::Layer::Build() methods
|
|
546
|
+
// remain valid until all layers have been built.
|
|
547
|
+
vector<Graph> graphs;
|
|
548
|
+
vector<unique_ptr<GraphClone>> clones;
|
|
549
|
+
S2Builder builder{S2Builder::Options()};
|
|
550
|
+
for (int i = 0; i < 20; ++i) {
|
|
551
|
+
builder.StartLayer(make_unique<GraphPersistenceLayer>(
|
|
552
|
+
GraphOptions(), &graphs, &clones));
|
|
553
|
+
for (int n = S2Testing::rnd.Uniform(10); n > 0; --n) {
|
|
554
|
+
builder.AddEdge(S2Testing::RandomPoint(), S2Testing::RandomPoint());
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
S2Error error;
|
|
558
|
+
EXPECT_TRUE(builder.Build(&error));
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
void TestPolylineLayers(
|
|
562
|
+
const vector<const char*>& input_strs,
|
|
563
|
+
const vector<const char*>& expected_strs,
|
|
564
|
+
const S2PolylineLayer::Options& layer_options,
|
|
565
|
+
const S2Builder::Options& builder_options = S2Builder::Options()) {
|
|
566
|
+
SCOPED_TRACE(layer_options.edge_type() == EdgeType::DIRECTED ?
|
|
567
|
+
"DIRECTED" : "UNDIRECTED");
|
|
568
|
+
S2Builder builder(builder_options);
|
|
569
|
+
vector<unique_ptr<S2Polyline>> output;
|
|
570
|
+
for (auto input_str : input_strs) {
|
|
571
|
+
output.emplace_back(new S2Polyline);
|
|
572
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(output.back().get(),
|
|
573
|
+
layer_options));
|
|
574
|
+
builder.AddPolyline(*MakePolylineOrDie(input_str));
|
|
575
|
+
}
|
|
576
|
+
S2Error error;
|
|
577
|
+
ASSERT_TRUE(builder.Build(&error));
|
|
578
|
+
vector<string> output_strs;
|
|
579
|
+
for (const auto& polyline : output) {
|
|
580
|
+
output_strs.push_back(s2textformat::ToString(*polyline));
|
|
581
|
+
}
|
|
582
|
+
EXPECT_EQ(absl::StrJoin(expected_strs, "; "),
|
|
583
|
+
absl::StrJoin(output_strs, "; "));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
void TestPolylineVector(
|
|
587
|
+
const vector<const char*>& input_strs,
|
|
588
|
+
const vector<const char*>& expected_strs,
|
|
589
|
+
const S2PolylineVectorLayer::Options& layer_options,
|
|
590
|
+
const S2Builder::Options& builder_options = S2Builder::Options()) {
|
|
591
|
+
S2Builder builder(builder_options);
|
|
592
|
+
vector<unique_ptr<S2Polyline>> output;
|
|
593
|
+
builder.StartLayer(
|
|
594
|
+
make_unique<S2PolylineVectorLayer>(&output, layer_options));
|
|
595
|
+
for (auto input_str : input_strs) {
|
|
596
|
+
builder.AddPolyline(*MakePolylineOrDie(input_str));
|
|
597
|
+
}
|
|
598
|
+
S2Error error;
|
|
599
|
+
ASSERT_TRUE(builder.Build(&error));
|
|
600
|
+
vector<string> output_strs;
|
|
601
|
+
for (const auto& polyline : output) {
|
|
602
|
+
output_strs.push_back(s2textformat::ToString(*polyline));
|
|
603
|
+
}
|
|
604
|
+
EXPECT_EQ(absl::StrJoin(expected_strs, "; "),
|
|
605
|
+
absl::StrJoin(output_strs, "; "));
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
void TestPolylineLayersBothEdgeTypes(
|
|
609
|
+
const vector<const char*>& input_strs,
|
|
610
|
+
const vector<const char*>& expected_strs,
|
|
611
|
+
S2PolylineLayer::Options layer_options, // by value
|
|
612
|
+
const S2Builder::Options& builder_options = S2Builder::Options()) {
|
|
613
|
+
layer_options.set_edge_type(EdgeType::DIRECTED);
|
|
614
|
+
TestPolylineLayers(input_strs, expected_strs, layer_options, builder_options);
|
|
615
|
+
layer_options.set_edge_type(EdgeType::UNDIRECTED);
|
|
616
|
+
TestPolylineLayers(input_strs, expected_strs, layer_options, builder_options);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
TEST(S2Builder, SimplifyOneEdge) {
|
|
620
|
+
// Simplify a perturbed edge chain into a single edge.
|
|
621
|
+
|
|
622
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1)));
|
|
623
|
+
options.set_simplify_edge_chains(true);
|
|
624
|
+
TestPolylineLayersBothEdgeTypes({"0:0, 1:0.5, 2:-0.5, 3:0.5, 4:-0.5, 5:0"},
|
|
625
|
+
{"0:0, 5:0"},
|
|
626
|
+
S2PolylineLayer::Options(), options);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
TEST(S2Builder, SimplifyTwoLayers) {
|
|
630
|
+
// Construct two layers, each containing a polyline that could be simplified
|
|
631
|
+
// to a single edge on its own. However the two polylines actually cross,
|
|
632
|
+
// so make sure that the output still contains the intersection vertex.
|
|
633
|
+
|
|
634
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
|
|
635
|
+
options.set_split_crossing_edges(true);
|
|
636
|
+
options.set_simplify_edge_chains(true);
|
|
637
|
+
TestPolylineLayersBothEdgeTypes(
|
|
638
|
+
{"-2:-1, -1:0, 1:0, 2:1", "1:-2, 0:-1, 0:1, -1:2"},
|
|
639
|
+
{"-2:-1, 0:0, 2:1", "1:-2, 0:0, -1:2"},
|
|
640
|
+
S2PolylineLayer::Options(), options);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
TEST(S2Builder, SimplifyOneLoop) {
|
|
644
|
+
// Simplify a regular loop with 1000 vertices and a radius of 20 degrees.
|
|
645
|
+
// Turning on edge chain simplification yields a dramatically smaller number
|
|
646
|
+
// of vertices than snapping alone (10 vertices vs 95 vertices using a snap
|
|
647
|
+
// radius of 1 degree). This is because snapping alone yields vertices that
|
|
648
|
+
// stay within 1 degree of the input *vertices*, while simplifying edge
|
|
649
|
+
// chains yields edges that stay within 1 degree of the input *edges*.
|
|
650
|
+
|
|
651
|
+
for (int i = 0; i < 2; ++i) {
|
|
652
|
+
EdgeType edge_type = static_cast<EdgeType>(i);
|
|
653
|
+
S1Angle snap_radius = S1Angle::Degrees(1);
|
|
654
|
+
S2Builder::Options options((IdentitySnapFunction(snap_radius)));
|
|
655
|
+
options.set_simplify_edge_chains(true);
|
|
656
|
+
S2Builder builder(options);
|
|
657
|
+
S2Polygon output;
|
|
658
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(
|
|
659
|
+
&output, S2PolygonLayer::Options(edge_type)));
|
|
660
|
+
// Spacing between vertices: approximately 2*pi*20/1000 = 0.125 degrees.
|
|
661
|
+
S2Polygon input(
|
|
662
|
+
S2Loop::MakeRegularLoop(S2Point(1, 0, 0), S1Angle::Degrees(20), 1000));
|
|
663
|
+
builder.AddPolygon(input);
|
|
664
|
+
S2Error error;
|
|
665
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
666
|
+
ASSERT_EQ(1, output.num_loops());
|
|
667
|
+
EXPECT_GE(output.loop(0)->num_vertices(), 10);
|
|
668
|
+
EXPECT_LE(output.loop(0)->num_vertices(), 12);
|
|
669
|
+
EXPECT_TRUE(output.BoundaryNear(input, snap_radius));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
TEST(S2Builder, SimplifyOppositeDirections) {
|
|
674
|
+
// We build two layers with two polylines that follow the same circular arc
|
|
675
|
+
// in opposite directions, and verify that they are snapped identically.
|
|
676
|
+
// (The snap radius is adjusted so that the arc is simplified into a long
|
|
677
|
+
// edge and a short edge, and therefore we would get a different result if
|
|
678
|
+
// the two layers followed the edge chain in different directions.)
|
|
679
|
+
|
|
680
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
|
|
681
|
+
options.set_simplify_edge_chains(true);
|
|
682
|
+
TestPolylineLayersBothEdgeTypes(
|
|
683
|
+
{"-4:0.83, -3:0.46, -2:0.2, -1:0.05, 0:0, 1:0.5, 2:0.2, 3:0.46, 4:0.83",
|
|
684
|
+
"4:.83, 3:.46, 2:.2, 1:.05, 0:0, -1:.5, -2:.2, -3:.46, -4:.83"},
|
|
685
|
+
{"-4:0.83, -2:0.2, 4:0.83", "4:0.83, -2:0.2, -4:0.83"},
|
|
686
|
+
S2PolylineLayer::Options(), options);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
TEST(S2Builder, SimplifyKeepsEdgeVertexSeparation) {
|
|
690
|
+
// We build two layers each containing a polyline, such that the polyline in
|
|
691
|
+
// the first layer could be simplified to a straight line except that then
|
|
692
|
+
// it would create an intersection with the second polyline.
|
|
693
|
+
|
|
694
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1.0)));
|
|
695
|
+
options.set_simplify_edge_chains(true);
|
|
696
|
+
TestPolylineLayersBothEdgeTypes(
|
|
697
|
+
{"0:-10, 0.99:0, 0:10", "-5:-5, -0.2:0, -5:5"},
|
|
698
|
+
{"0:-10, 0.99:0, 0:10", "-5:-5, -0.2:0, -5:5"},
|
|
699
|
+
S2PolylineLayer::Options(), options);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
TEST(S2Builder, SimplifyBacktrackingEdgeChain) {
|
|
703
|
+
// Test simplifying an edge chain that backtracks on itself.
|
|
704
|
+
S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
|
|
705
|
+
options.set_simplify_edge_chains(true);
|
|
706
|
+
TestPolylineLayersBothEdgeTypes(
|
|
707
|
+
{"0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 4:0, 3:0, "
|
|
708
|
+
"2:0, 3:0, 4:0, 5:0, 6:0, 7:0"},
|
|
709
|
+
{"0:0, 2:0, 5:0, 2:0, 5:0, 7:0"},
|
|
710
|
+
S2PolylineLayer::Options(), options);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
TEST(S2Builder, SimplifyLimitsEdgeDeviation) {
|
|
714
|
+
// Make sure that simplification does not create long edges such that the
|
|
715
|
+
// midpoint of the edge might be further than max_edge_deviation() from an
|
|
716
|
+
// input edge. In the example below, vertices are snapped to integer
|
|
717
|
+
// lat/lng coordinates, and the snap radius is approximately 0.707 degrees.
|
|
718
|
+
// Snapping moves the input vertices perpendicular to the input edge by just
|
|
719
|
+
// slightly less than the snap radius (0.693 degrees). Now the midpoint of
|
|
720
|
+
// the snapped edge is about 0.98 degrees from the input edge, which causes
|
|
721
|
+
// an extra site to be added at the midpoint of the original edge.
|
|
722
|
+
//
|
|
723
|
+
// When simplify_edge_chains() is enabled, then usually an extra site like
|
|
724
|
+
// this would be simplified away (because the simplified edge would still be
|
|
725
|
+
// within snap_radius() of all the input vertices) except that there is an
|
|
726
|
+
// explicit check in S2Builder that prevents this. (If the check is removed
|
|
727
|
+
// then this test fails.)
|
|
728
|
+
|
|
729
|
+
S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coordinates
|
|
730
|
+
options.set_simplify_edge_chains(true);
|
|
731
|
+
TestPolylineLayersBothEdgeTypes(
|
|
732
|
+
{"-30.49:-29.51, 29.51:30.49"}, {"-30:-30, -1:1, 30:30"},
|
|
733
|
+
S2PolylineLayer::Options(), options);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
TEST(S2Builder, SimplifyPreservesTopology) {
|
|
737
|
+
// Crate several nested concentric loops, and verify that the loops are
|
|
738
|
+
// still nested after simplification.
|
|
739
|
+
|
|
740
|
+
const int kNumLoops = 20;
|
|
741
|
+
const int kNumVerticesPerLoop = 1000;
|
|
742
|
+
const S1Angle kBaseRadius = S1Angle::Degrees(5);
|
|
743
|
+
const S1Angle kSnapRadius = S1Angle::Degrees(0.1);
|
|
744
|
+
S2Builder::Options options((IdentitySnapFunction(kSnapRadius)));
|
|
745
|
+
options.set_simplify_edge_chains(true);
|
|
746
|
+
S2Builder builder(options);
|
|
747
|
+
vector<unique_ptr<S2Polygon>> input, output;
|
|
748
|
+
for (int j = 0; j < kNumLoops; ++j) {
|
|
749
|
+
// Spacing between vertices: approximately 2*pi*20/1000 = 0.125 degrees.
|
|
750
|
+
S1Angle radius = kBaseRadius + 0.7 * j * j / kNumLoops * kSnapRadius;
|
|
751
|
+
input.emplace_back(new S2Polygon(S2Loop::MakeRegularLoop(
|
|
752
|
+
S2Point(1, 0, 0), radius, kNumVerticesPerLoop)));
|
|
753
|
+
output.emplace_back(new S2Polygon);
|
|
754
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(output.back().get()));
|
|
755
|
+
builder.AddPolygon(*input.back());
|
|
756
|
+
}
|
|
757
|
+
S2Error error;
|
|
758
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
759
|
+
for (int j = 0; j < kNumLoops; ++j) {
|
|
760
|
+
EXPECT_TRUE(output[j]->BoundaryNear(*input[j], kSnapRadius));
|
|
761
|
+
if (j > 0) EXPECT_TRUE(output[j]->Contains(output[j - 1].get()));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
TEST(S2Builder, SimplifyRemovesSiblingPairs) {
|
|
766
|
+
S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coords
|
|
767
|
+
S2PolylineVectorLayer::Options layer_options;
|
|
768
|
+
layer_options.set_sibling_pairs(GraphOptions::SiblingPairs::DISCARD);
|
|
769
|
+
|
|
770
|
+
// Check that there is no sibling pair without simplification.
|
|
771
|
+
TestPolylineVector(
|
|
772
|
+
{"0:0, 0:10", "0:10, 0.6:5, 0:0"},
|
|
773
|
+
{"0:0, 0:10, 1:5, 0:0"}, layer_options, options);
|
|
774
|
+
|
|
775
|
+
// Now check that (1) simplification produces a sibling pair,
|
|
776
|
+
// and (2) the sibling pair is removed (since we requested it).
|
|
777
|
+
options.set_simplify_edge_chains(true);
|
|
778
|
+
TestPolylineVector(
|
|
779
|
+
{"0:0, 0:10", "0:10, 0.6:5, 0:0"},
|
|
780
|
+
{}, layer_options, options);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
TEST(S2Builder, SimplifyMergesDuplicateEdges) {
|
|
784
|
+
S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coords
|
|
785
|
+
S2PolylineVectorLayer::Options layer_options;
|
|
786
|
+
layer_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
|
|
787
|
+
|
|
788
|
+
// Check that there are no duplicate edges without simplification.
|
|
789
|
+
TestPolylineVector(
|
|
790
|
+
{"0:0, 0:10", "0:0, 0.6:5, 0:10"},
|
|
791
|
+
{"0:0, 0:10", "0:0, 1:5, 0:10"}, layer_options, options);
|
|
792
|
+
|
|
793
|
+
// Now check that (1) simplification produces a duplicate edge pair,
|
|
794
|
+
// and (2) the duplicate pair is merged (since we requested it).
|
|
795
|
+
options.set_simplify_edge_chains(true);
|
|
796
|
+
TestPolylineVector(
|
|
797
|
+
{"0:0, 0:10", "0:0, 0.6:5, 0:10"},
|
|
798
|
+
{"0:0, 0:10"}, layer_options, options);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
TEST(S2Builder, SimplifyKeepsForcedVertices) {
|
|
802
|
+
S2Builder::Options options{IdentitySnapFunction(S1Angle::Radians(1e-15))};
|
|
803
|
+
options.set_simplify_edge_chains(true);
|
|
804
|
+
S2Builder builder(options);
|
|
805
|
+
S2Polyline output;
|
|
806
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output));
|
|
807
|
+
builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1, 0:2, 0:3"));
|
|
808
|
+
builder.ForceVertex(MakePointOrDie("0:1"));
|
|
809
|
+
S2Error error;
|
|
810
|
+
ASSERT_TRUE(builder.Build(&error));
|
|
811
|
+
EXPECT_EQ("0:0, 0:1, 0:3", s2textformat::ToString(output));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// A set of (edge string, vector<InputEdgeId>) pairs representing the
|
|
815
|
+
// InputEdgeIds attached to the edges of a graph. Edges are in
|
|
816
|
+
// s2textformat::ToString() format, such as "1:3, 4:5".
|
|
817
|
+
using EdgeInputEdgeIds = vector<pair<string, vector<int>>>;
|
|
818
|
+
|
|
819
|
+
S2Error::Code INPUT_EDGE_ID_MISMATCH = S2Error::USER_DEFINED_START;
|
|
820
|
+
|
|
821
|
+
class InputEdgeIdCheckingLayer : public S2Builder::Layer {
|
|
822
|
+
public:
|
|
823
|
+
InputEdgeIdCheckingLayer(const EdgeInputEdgeIds& expected,
|
|
824
|
+
const GraphOptions& graph_options)
|
|
825
|
+
: expected_(expected), graph_options_(graph_options) {
|
|
826
|
+
}
|
|
827
|
+
GraphOptions graph_options() const override { return graph_options_; }
|
|
828
|
+
void Build(const Graph& g, S2Error* error) override;
|
|
829
|
+
|
|
830
|
+
private:
|
|
831
|
+
string ToString(const pair<string, vector<int>>& p) {
|
|
832
|
+
string r = StrCat(" (", p.first, ")={");
|
|
833
|
+
if (!p.second.empty()) {
|
|
834
|
+
for (int id : p.second) {
|
|
835
|
+
StrAppend(&r, id, ", ");
|
|
836
|
+
}
|
|
837
|
+
r.erase(r.size() - 2, 2);
|
|
838
|
+
}
|
|
839
|
+
r += "}\n";
|
|
840
|
+
return r;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
EdgeInputEdgeIds expected_;
|
|
844
|
+
GraphOptions graph_options_;
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
void InputEdgeIdCheckingLayer::Build(const Graph& g, S2Error* error) {
|
|
848
|
+
EdgeInputEdgeIds actual;
|
|
849
|
+
vector<S2Point> vertices;
|
|
850
|
+
for (Graph::EdgeId e = 0; e < g.num_edges(); ++e) {
|
|
851
|
+
vertices.clear();
|
|
852
|
+
vertices.push_back(g.vertex(g.edge(e).first));
|
|
853
|
+
vertices.push_back(g.vertex(g.edge(e).second));
|
|
854
|
+
string edge = s2textformat::ToString(
|
|
855
|
+
vector<S2Point>{g.vertex(g.edge(e).first),
|
|
856
|
+
g.vertex(g.edge(e).second)});
|
|
857
|
+
auto ids = g.input_edge_ids(e);
|
|
858
|
+
actual.push_back(make_pair(
|
|
859
|
+
edge, vector<InputEdgeId>(ids.begin(), ids.end())));
|
|
860
|
+
}
|
|
861
|
+
// This comparison doesn't consider multiplicity, but that's fine.
|
|
862
|
+
string missing, extra;
|
|
863
|
+
for (const auto& p : expected_) {
|
|
864
|
+
if (std::count(actual.begin(), actual.end(), p) > 0) continue;
|
|
865
|
+
missing += ToString(p);
|
|
866
|
+
}
|
|
867
|
+
for (const auto& p : actual) {
|
|
868
|
+
if (std::count(expected_.begin(), expected_.end(), p) > 0) continue;
|
|
869
|
+
extra += ToString(p);
|
|
870
|
+
}
|
|
871
|
+
if (!missing.empty() || !extra.empty()) {
|
|
872
|
+
error->Init(INPUT_EDGE_ID_MISMATCH, "Missing:\n%sExtra:\n%s\n",
|
|
873
|
+
missing.c_str(), extra.c_str());
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
void TestInputEdgeIds(
|
|
878
|
+
const vector<const char*>& input_strs, const EdgeInputEdgeIds& expected,
|
|
879
|
+
const GraphOptions& graph_options, const S2Builder::Options& options) {
|
|
880
|
+
S2Builder builder(options);
|
|
881
|
+
builder.StartLayer(make_unique<InputEdgeIdCheckingLayer>(expected,
|
|
882
|
+
graph_options));
|
|
883
|
+
for (auto input_str : input_strs) {
|
|
884
|
+
builder.AddPolyline(*MakePolylineOrDie(input_str));
|
|
885
|
+
}
|
|
886
|
+
S2Error error;
|
|
887
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
TEST(S2Builder, InputEdgeIdAssignment) {
|
|
891
|
+
// Check that input edge ids are assigned in order.
|
|
892
|
+
TestInputEdgeIds({"0:0, 0:1, 0:2"}, {{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}}},
|
|
893
|
+
GraphOptions(), S2Builder::Options());
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
TEST(S2Builder, UndirectedSiblingsDontHaveInputEdgeIds) {
|
|
897
|
+
// Check that the siblings of undirected edges do not have InputEdgeIds.
|
|
898
|
+
GraphOptions graph_options;
|
|
899
|
+
graph_options.set_edge_type(EdgeType::UNDIRECTED);
|
|
900
|
+
TestInputEdgeIds({"0:0, 0:1, 0:2"},
|
|
901
|
+
{{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}},
|
|
902
|
+
{"0:1, 0:0", {}}, {"0:2, 0:1", {}}},
|
|
903
|
+
graph_options, S2Builder::Options());
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
TEST(S2Builder, CreatedSiblingsDontHaveInputEdgeIds) {
|
|
907
|
+
// Check that edges created by SiblingPairs::CREATE do not have
|
|
908
|
+
// InputEdgeIds.
|
|
909
|
+
GraphOptions graph_options;
|
|
910
|
+
graph_options.set_sibling_pairs(GraphOptions::SiblingPairs::CREATE);
|
|
911
|
+
TestInputEdgeIds({"0:0, 0:1, 0:2"}, {{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}}},
|
|
912
|
+
GraphOptions(), S2Builder::Options());
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
TEST(S2Builder, EdgeMergingDirected) {
|
|
916
|
+
// Tests that input edge ids are merged when directed edges are merged.
|
|
917
|
+
GraphOptions graph_options;
|
|
918
|
+
graph_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
|
|
919
|
+
TestInputEdgeIds({"0:0, 0:1", "0:0, 0:1"}, {{"0:0, 0:1", {0, 1}}},
|
|
920
|
+
graph_options, S2Builder::Options());
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
TEST(S2Builder, EdgeMergingUndirected) {
|
|
924
|
+
// Tests that input edge ids are merged when undirected edges are merged.
|
|
925
|
+
GraphOptions graph_options;
|
|
926
|
+
graph_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
|
|
927
|
+
graph_options.set_sibling_pairs(GraphOptions::SiblingPairs::KEEP);
|
|
928
|
+
TestInputEdgeIds({"0:0, 0:1, 0:2", "0:0, 0:1", "0:2, 0:1"}, {
|
|
929
|
+
{"0:0, 0:1", {0, 2}}, {"0:1, 0:2", {1}}, {"0:2, 0:1", {3}}
|
|
930
|
+
}, graph_options, S2Builder::Options());
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
TEST(S2Builder, SimplifyDegenerateEdgeMergingEasy) {
|
|
934
|
+
// Check that when an input edge is snapped to a chain that includes
|
|
935
|
+
// degenerate edges, and the edge chain is simplified, that the InputEdgeIds
|
|
936
|
+
// attached to those degenerate edges are transferred to the simplified
|
|
937
|
+
// edge. For example (using integers for vertices), an edge chain 1->2,
|
|
938
|
+
// 2->2, 2->3 that is simplified to 1->3 should get the InputEdgeIds
|
|
939
|
+
// associated with all three original edges. (This ensures that the labels
|
|
940
|
+
// attached to those edges are also transferred.)
|
|
941
|
+
//
|
|
942
|
+
// This also tests that degenerate edges at the start and end of the
|
|
943
|
+
// simplified chain are *not* merged. (It's up to the output layer to
|
|
944
|
+
// decide what to do with these edges. The only reason we merge degenerate
|
|
945
|
+
// edges in the interior of the interior of the simplified edge is because
|
|
946
|
+
// those edges are being removed from the graph.)
|
|
947
|
+
GraphOptions graph_options;
|
|
948
|
+
graph_options.set_degenerate_edges(GraphOptions::DegenerateEdges::KEEP);
|
|
949
|
+
S2Builder::Options options(IntLatLngSnapFunction(0));
|
|
950
|
+
options.set_simplify_edge_chains(true);
|
|
951
|
+
TestInputEdgeIds({"0:0, 0:0.1, 0:1.1, 0:1, 0:0.9, 0:2, 0:2.1"}, {
|
|
952
|
+
{"0:0, 0:0", {0}}, {"0:0, 0:2", {1, 2, 3, 4}}, {"0:2, 0:2", {5}}
|
|
953
|
+
}, graph_options, options);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
TEST(S2Builder, SimplifyDegenerateEdgeMergingHard) {
|
|
957
|
+
// This is a harder version of the test above. Now there are several edge
|
|
958
|
+
// chains that overlap each other in both directions, and several degenerate
|
|
959
|
+
// edges at that middle vertex. This tests that if exactly one edge chain
|
|
960
|
+
// contains a degenerate edge in input edge order (e.g., the input order was
|
|
961
|
+
// AB, BB, BC), then the degenerate edge is assigned to that edge chain.
|
|
962
|
+
// Otherwise the edge is assigned to an arbitrary chain.
|
|
963
|
+
GraphOptions graph_options; // Default options keep everything.
|
|
964
|
+
S2Builder::Options options(IntLatLngSnapFunction(0));
|
|
965
|
+
options.set_simplify_edge_chains(true);
|
|
966
|
+
vector<const char*> input {
|
|
967
|
+
"0:1, 0:1.1", "0:0, 0:1, 0:2", // Degenerate edge defined before chain
|
|
968
|
+
"0:0, 0:0.9, 0:1, 0:1.1, 0:2", // Degenerate edge defined in chain
|
|
969
|
+
"0:2, 0:1, 0:0.9, 0:0", // Defined in chain, chain reversed
|
|
970
|
+
"0:2, 0:1, 0:0", "0:1.1, 0:1", "0:1, 0:1.1", // Defined after chain
|
|
971
|
+
};
|
|
972
|
+
EdgeInputEdgeIds expected {
|
|
973
|
+
{"0:0, 0:2", {0, 1, 2}}, {"0:0, 0:2", {3, 4, 5, 6}},
|
|
974
|
+
{"0:2, 0:0", {7, 8, 9}}, {"0:2, 0:0", {10, 11, 12, 13}}
|
|
975
|
+
};
|
|
976
|
+
TestInputEdgeIds(input, expected, graph_options, options);
|
|
977
|
+
|
|
978
|
+
// Now try the same test with undirected edges. This results in four more
|
|
979
|
+
// simplified edges that are not labelled with any input edge ids.
|
|
980
|
+
expected.insert(expected.end(), {
|
|
981
|
+
{"0:0, 0:2", {}}, {"0:0, 0:2", {}}, {"0:2, 0:0", {}}, {"0:2, 0:0", {}}
|
|
982
|
+
});
|
|
983
|
+
graph_options.set_edge_type(EdgeType::UNDIRECTED);
|
|
984
|
+
TestInputEdgeIds(input, expected, graph_options, options);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
TEST(S2Builder, SimplifyDegenerateEdgeMergingMultipleLayers) {
|
|
988
|
+
// Check that degenerate edges are assigned to an edge in the correct layer
|
|
989
|
+
// when multiple edge chains in different layers are simplified in the same
|
|
990
|
+
// way (i.e., yielding a set of identical or reversed edges in different
|
|
991
|
+
// layers).
|
|
992
|
+
GraphOptions graph_options; // Default options keep everything.
|
|
993
|
+
S2Builder::Options options(IntLatLngSnapFunction(0));
|
|
994
|
+
options.set_simplify_edge_chains(true);
|
|
995
|
+
|
|
996
|
+
// Note below that the edge chains in different layers have different vertex
|
|
997
|
+
// locations, different number of interior vertices, different degenerate
|
|
998
|
+
// edges, etc, and yet they can all be simplified together.
|
|
999
|
+
vector<vector<const char*>> input { {
|
|
1000
|
+
"0.1:5, 0:5.2", "0.1:0, 0:9.9", // Defined before chain
|
|
1001
|
+
"0:10.1, 0:0.1", "0:3.1, 0:2.9", // Defined after chain
|
|
1002
|
+
}, {
|
|
1003
|
+
"0.1:3, 0:3.2", "-0.1:0, 0:4.1, 0:9.9", // Defined before chain
|
|
1004
|
+
"0.1:9.9, 0:7, 0.1:6.9, 0.1:0.2", // Defined inside chain
|
|
1005
|
+
}, {
|
|
1006
|
+
"0.2:0.3, 0.1:6, 0:5.9, 0.1:10.2", // Defined inside chain
|
|
1007
|
+
"0.1:0.1, 0:9.8", "0.1:2, 0:2.1", // Defined after chain
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
vector<EdgeInputEdgeIds> expected { {
|
|
1011
|
+
{"0:0, 0:10", {0, 1}}, {"0:10, 0:0", {2, 3}}
|
|
1012
|
+
}, {
|
|
1013
|
+
{"0:0, 0:10", {4, 5, 6}}, {"0:10, 0:0", {7, 8, 9}}
|
|
1014
|
+
}, {
|
|
1015
|
+
{"0:0, 0:10", {10, 11, 12}}, {"0:0, 0:10", {13, 14}}
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
S2Builder builder(options);
|
|
1019
|
+
for (int i = 0; i < input.size(); ++i) {
|
|
1020
|
+
builder.StartLayer(make_unique<InputEdgeIdCheckingLayer>(expected[i],
|
|
1021
|
+
graph_options));
|
|
1022
|
+
for (auto input_str : input[i]) {
|
|
1023
|
+
builder.AddPolyline(*MakePolylineOrDie(input_str));
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
S2Error error;
|
|
1027
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
TEST(S2Builder, HighPrecisionPredicates) {
|
|
1031
|
+
// To produce correct output in this example, the algorithm needs fall back
|
|
1032
|
+
// to high precision predicates when the output of the normal predicates is
|
|
1033
|
+
// uncertain.
|
|
1034
|
+
vector<S2Point> vertices = {
|
|
1035
|
+
{-0.1053119128423491, -0.80522217121852213, 0.58354661852470235},
|
|
1036
|
+
{-0.10531192039134209, -0.80522217309706012, 0.58354661457019508},
|
|
1037
|
+
{-0.10531192039116592, -0.80522217309701472, 0.58354661457028933},
|
|
1038
|
+
};
|
|
1039
|
+
S2Polyline input(vertices);
|
|
1040
|
+
S1Angle snap_radius = S2::kIntersectionMergeRadius;
|
|
1041
|
+
S2Builder::Options options((IdentitySnapFunction(snap_radius)));
|
|
1042
|
+
options.set_idempotent(false);
|
|
1043
|
+
S2Builder builder(options);
|
|
1044
|
+
S2Polyline output;
|
|
1045
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output));
|
|
1046
|
+
builder.ForceVertex(S2Point(
|
|
1047
|
+
-0.10531192039134191, -0.80522217309705857, 0.58354661457019719));
|
|
1048
|
+
builder.AddPolyline(input);
|
|
1049
|
+
S2Error error;
|
|
1050
|
+
EXPECT_TRUE(builder.Build(&error)) << error;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Chooses a random S2Point that is often near the intersection of one of the
|
|
1054
|
+
// coodinates planes or coordinate axes with the unit sphere. (It is possible
|
|
1055
|
+
// to represent very small perturbations near such points.)
|
|
1056
|
+
S2Point ChoosePoint() {
|
|
1057
|
+
S2Point x = S2Testing::RandomPoint();
|
|
1058
|
+
for (int i = 0; i < 3; ++i) {
|
|
1059
|
+
if (S2Testing::rnd.OneIn(3)) {
|
|
1060
|
+
x[i] *= pow(1e-50, S2Testing::rnd.RandDouble());
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return x.Normalize();
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
TEST(S2Builder, HighPrecisionStressTest) {
|
|
1067
|
+
// This test constructs many small, random inputs such that the output is
|
|
1068
|
+
// likely to be inconsistent unless high-precision predicates are used.
|
|
1069
|
+
|
|
1070
|
+
S1Angle snap_radius = S2::kIntersectionMergeRadius;
|
|
1071
|
+
// Some S2Builder calculations use an upper bound that takes into account
|
|
1072
|
+
// S1ChordAngle errors. We sometimes try perturbing points by very close to
|
|
1073
|
+
// that distance in an attempt to expose errors.
|
|
1074
|
+
S1ChordAngle ca(snap_radius);
|
|
1075
|
+
S1Angle snap_radius_with_error = ca.PlusError(
|
|
1076
|
+
ca.GetS1AngleConstructorMaxError() +
|
|
1077
|
+
S2::GetUpdateMinDistanceMaxError(ca)).ToAngle();
|
|
1078
|
+
|
|
1079
|
+
auto& rnd = S2Testing::rnd;
|
|
1080
|
+
int non_degenerate = 0;
|
|
1081
|
+
const int kIters = 8000 * FLAGS_iteration_multiplier;
|
|
1082
|
+
for (int iter = 0; iter < kIters; ++iter) {
|
|
1083
|
+
// TODO(ericv): This test fails with a random seed of 96. Change this
|
|
1084
|
+
// back to "iter + 1" once all the exact predicates are implemented.
|
|
1085
|
+
rnd.Reset(iter + 1); // Easier to reproduce a specific case.
|
|
1086
|
+
|
|
1087
|
+
// We construct a nearly degenerate triangle where one of the edges is
|
|
1088
|
+
// sometimes very short. Then we add a forced vertex somewhere near the
|
|
1089
|
+
// shortest edge. Then after snapping, we check that (1) the edges still
|
|
1090
|
+
// form a loop, and (2) if the loop is non-degenerate, then it has the
|
|
1091
|
+
// same orientation as the original triangle.
|
|
1092
|
+
//
|
|
1093
|
+
// v1 is located randomly. (v0,v1) is the longest of the three edges.
|
|
1094
|
+
// v2 is located along (v0,v1) but is perturbed by up to 2 * snap_radius.
|
|
1095
|
+
S2Point v1 = ChoosePoint(), v0_dir = ChoosePoint();
|
|
1096
|
+
double d0 = pow(1e-16, rnd.RandDouble());
|
|
1097
|
+
S2Point v0 = S2::InterpolateAtDistance(S1Angle::Radians(d0), v1, v0_dir);
|
|
1098
|
+
double d2 = 0.5 * d0 * pow(1e-16, pow(rnd.RandDouble(), 2));
|
|
1099
|
+
S2Point v2 = S2::InterpolateAtDistance(S1Angle::Radians(d2), v1, v0_dir);
|
|
1100
|
+
v2 = S2Testing::SamplePoint(S2Cap(v2, 2 * snap_radius));
|
|
1101
|
+
// Vary the edge directions by randomly swapping v0 and v2.
|
|
1102
|
+
if (rnd.OneIn(2)) std::swap(v0, v2);
|
|
1103
|
+
|
|
1104
|
+
// The forced vertex (v3) is either located near the (v1, v2) edge.
|
|
1105
|
+
// We perturb it either in a random direction from v1 or v2, or
|
|
1106
|
+
// perpendicular to (v1, v2) starting from an interior edge point.
|
|
1107
|
+
S1Angle d3 = rnd.OneIn(2) ? snap_radius : snap_radius_with_error;
|
|
1108
|
+
if (rnd.OneIn(3)) d3 = 1.5 * rnd.RandDouble() * d3;
|
|
1109
|
+
S2Point v3;
|
|
1110
|
+
if (rnd.OneIn(5)) {
|
|
1111
|
+
v3 = rnd.OneIn(2) ? v1 : v2;
|
|
1112
|
+
v3 = S2::InterpolateAtDistance(d3, v3, ChoosePoint());
|
|
1113
|
+
} else {
|
|
1114
|
+
v3 = S2::Interpolate(pow(1e-16, rnd.RandDouble()), v1, v2);
|
|
1115
|
+
v3 = S2::InterpolateAtDistance(d3, v3, v1.CrossProd(v2).Normalize());
|
|
1116
|
+
}
|
|
1117
|
+
S2Builder::Options options((IdentitySnapFunction(snap_radius)));
|
|
1118
|
+
options.set_idempotent(false);
|
|
1119
|
+
S2Builder builder(options);
|
|
1120
|
+
S2Polygon output;
|
|
1121
|
+
output.set_s2debug_override(S2Debug::DISABLE);
|
|
1122
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
1123
|
+
builder.ForceVertex(v3);
|
|
1124
|
+
builder.AddEdge(v0, v1);
|
|
1125
|
+
builder.AddEdge(v1, v2);
|
|
1126
|
+
builder.AddEdge(v2, v0);
|
|
1127
|
+
S2Error error;
|
|
1128
|
+
if (!builder.Build(&error)) {
|
|
1129
|
+
S2_LOG(ERROR) << "d0=" << d0 << ", d2=" << d2 << ", d3=" << d3;
|
|
1130
|
+
}
|
|
1131
|
+
if (error.ok() && !output.is_empty()) {
|
|
1132
|
+
EXPECT_EQ(1, output.num_loops());
|
|
1133
|
+
if (output.num_loops() == 1) {
|
|
1134
|
+
EXPECT_TRUE(output.IsValid());
|
|
1135
|
+
EXPECT_EQ(s2pred::Sign(v0, v1, v2) > 0, output.loop(0)->IsNormalized())
|
|
1136
|
+
<< "d0=" << d0 << ", d2=" << d2 << ", d3=" << d3;
|
|
1137
|
+
++non_degenerate;
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
S2_LOG(INFO) << non_degenerate << " non-degenerate out of " << kIters;
|
|
1142
|
+
EXPECT_GE(non_degenerate, kIters / 10);
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
TEST(S2Builder, SelfIntersectionStressTest) {
|
|
1146
|
+
const int kIters = 50 * FLAGS_iteration_multiplier;
|
|
1147
|
+
for (int iter = 0; iter < kIters; ++iter) {
|
|
1148
|
+
S2Testing::rnd.Reset(iter + 1); // Easier to reproduce a specific case.
|
|
1149
|
+
CycleTimer timer;
|
|
1150
|
+
timer.Start();
|
|
1151
|
+
|
|
1152
|
+
// The minimum radius is about 36cm on the Earth's surface. The
|
|
1153
|
+
// performance is reduced for radii much smaller than this because
|
|
1154
|
+
// S2ShapeIndex only indexes regions down to about 1cm across.
|
|
1155
|
+
S2Cap cap = S2Testing::GetRandomCap(1e-14, 1e-2);
|
|
1156
|
+
|
|
1157
|
+
S2Builder::Options options;
|
|
1158
|
+
options.set_split_crossing_edges(true);
|
|
1159
|
+
if (S2Testing::rnd.OneIn(2)) {
|
|
1160
|
+
S1Angle radius = cap.GetRadius();
|
|
1161
|
+
int min_exp = IntLatLngSnapFunction::ExponentForMaxSnapRadius(radius);
|
|
1162
|
+
int exponent = min(IntLatLngSnapFunction::kMaxExponent,
|
|
1163
|
+
min_exp + S2Testing::rnd.Uniform(5));
|
|
1164
|
+
options.set_snap_function(IntLatLngSnapFunction(exponent));
|
|
1165
|
+
}
|
|
1166
|
+
S2Builder builder(options);
|
|
1167
|
+
|
|
1168
|
+
// Note that the number of intersections (and the running time) is
|
|
1169
|
+
// quadratic in the number of vertices. With 200 input vertices, the
|
|
1170
|
+
// output consists of about 2300 loops and 9000 vertices.
|
|
1171
|
+
S2Polygon output;
|
|
1172
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(
|
|
1173
|
+
&output, S2PolygonLayer::Options(EdgeType::UNDIRECTED)));
|
|
1174
|
+
vector<S2Point> vertices(google::DEBUG_MODE ? 50 : 200);
|
|
1175
|
+
for (S2Point& vertex : vertices) {
|
|
1176
|
+
vertex = S2Testing::SamplePoint(cap);
|
|
1177
|
+
}
|
|
1178
|
+
vertices.back() = vertices.front();
|
|
1179
|
+
S2Polyline input(vertices);
|
|
1180
|
+
builder.AddPolyline(input);
|
|
1181
|
+
S2Error error;
|
|
1182
|
+
EXPECT_TRUE(builder.Build(&error)) << error;
|
|
1183
|
+
EXPECT_FALSE(output.FindValidationError(&error)) << error;
|
|
1184
|
+
if (iter == -1) {
|
|
1185
|
+
cout << "S2Polyline: " << s2textformat::ToString(input) << endl;
|
|
1186
|
+
cout << "S2Polygon: " << s2textformat::ToString(output) << endl;
|
|
1187
|
+
}
|
|
1188
|
+
if (iter < 50) {
|
|
1189
|
+
printf("iter=%4d: ms=%4" PRId64 ", radius=%8.3g, loops=%d, vertices=%d\n",
|
|
1190
|
+
iter, static_cast<int64_t>(timer.GetInMs()),
|
|
1191
|
+
cap.GetRadius().radians(), output.num_loops(),
|
|
1192
|
+
output.num_vertices());
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
TEST(S2Builder, FractalStressTest) {
|
|
1198
|
+
const int kIters = (google::DEBUG_MODE ? 100 : 1000) * FLAGS_iteration_multiplier;
|
|
1199
|
+
for (int iter = 0; iter < kIters; ++iter) {
|
|
1200
|
+
S2Testing::rnd.Reset(iter + 1); // Easier to reproduce a specific case.
|
|
1201
|
+
S2Testing::Fractal fractal;
|
|
1202
|
+
fractal.SetLevelForApproxMaxEdges(google::DEBUG_MODE ? 800 : 12800);
|
|
1203
|
+
fractal.SetLevelForApproxMinEdges(12);
|
|
1204
|
+
fractal.set_fractal_dimension(1.5 + 0.5 * S2Testing::rnd.RandDouble());
|
|
1205
|
+
S2Polygon input(fractal.MakeLoop(S2Testing::GetRandomFrame(),
|
|
1206
|
+
S1Angle::Degrees(20)));
|
|
1207
|
+
S2Builder::Options options;
|
|
1208
|
+
if (S2Testing::rnd.OneIn(3)) {
|
|
1209
|
+
int exponent = S2Testing::rnd.Uniform(11);
|
|
1210
|
+
options.set_snap_function(IntLatLngSnapFunction(exponent));
|
|
1211
|
+
} else if (S2Testing::rnd.OneIn(2)) {
|
|
1212
|
+
int level = S2Testing::rnd.Uniform(20);
|
|
1213
|
+
options.set_snap_function(S2CellIdSnapFunction(level));
|
|
1214
|
+
} else {
|
|
1215
|
+
options.set_snap_function(IdentitySnapFunction(
|
|
1216
|
+
S1Angle::Degrees(10 * pow(1e-4, S2Testing::rnd.RandDouble()))));
|
|
1217
|
+
}
|
|
1218
|
+
S2Builder builder(options);
|
|
1219
|
+
S2Polygon output;
|
|
1220
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
1221
|
+
builder.AddPolygon(input);
|
|
1222
|
+
S2Error error;
|
|
1223
|
+
EXPECT_TRUE(builder.Build(&error)) << error;
|
|
1224
|
+
EXPECT_FALSE(output.FindValidationError(&error)) << error;
|
|
1225
|
+
if (iter == -1) {
|
|
1226
|
+
cout << "S2Polygon: " << s2textformat::ToString(input) << endl;
|
|
1227
|
+
cout << "S2Polygon: " << s2textformat::ToString(output) << endl;
|
|
1228
|
+
}
|
|
1229
|
+
if (iter < 50) {
|
|
1230
|
+
printf("iter=%4d: in_vertices=%d, out_vertices=%d\n",
|
|
1231
|
+
iter, input.num_vertices(), output.num_vertices());
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
void TestSnappingWithForcedVertices(const char* input_str,
|
|
1237
|
+
S1Angle snap_radius,
|
|
1238
|
+
const char* vertices_str,
|
|
1239
|
+
const char* expected_str) {
|
|
1240
|
+
S2Builder builder{S2Builder::Options{IdentitySnapFunction(snap_radius)}};
|
|
1241
|
+
vector<S2Point> vertices = s2textformat::ParsePoints(vertices_str);
|
|
1242
|
+
for (const auto& vertex : vertices) {
|
|
1243
|
+
builder.ForceVertex(vertex);
|
|
1244
|
+
}
|
|
1245
|
+
S2Polyline output;
|
|
1246
|
+
builder.StartLayer(make_unique<S2PolylineLayer>(&output));
|
|
1247
|
+
builder.AddPolyline(*MakePolylineOrDie(input_str));
|
|
1248
|
+
S2Error error;
|
|
1249
|
+
EXPECT_TRUE(builder.Build(&error)) << error;
|
|
1250
|
+
EXPECT_EQ(expected_str, s2textformat::ToString(output));
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
TEST(S2Builder, AdjacentCoverageIntervalsSpanMoreThan90Degrees) {
|
|
1254
|
+
// The test for whether one Voronoi site excludes another along a given
|
|
1255
|
+
// input edge boils down to a test of whether two angle intervals "a" and
|
|
1256
|
+
// "b" overlap. Let "ra" and "rb" be the semi-widths of the two intervals,
|
|
1257
|
+
// and let "d" be the angle between their centers. Then "a" contains "b" if
|
|
1258
|
+
// (rb + d <= ra), and "b" contains "a" if (rb - d >= ra). However the
|
|
1259
|
+
// actual code uses the sines of the angles, e.g. sin(rb + d) <= sin(ra).
|
|
1260
|
+
// This works fine most of the time, but the first condition (rb + d <= ra)
|
|
1261
|
+
// also needs to check that rb + d < 90 degrees. This test verifies that
|
|
1262
|
+
// case.
|
|
1263
|
+
|
|
1264
|
+
// The following 3 tests have d < 90, d = 90, and d > 90 degrees, but in all
|
|
1265
|
+
// 3 cases rb + d > 90 degrees.
|
|
1266
|
+
TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
|
|
1267
|
+
"0:0, 0:70", "0:0, 0:70");
|
|
1268
|
+
TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
|
|
1269
|
+
"0:0, 0:90", "0:0, 0:90");
|
|
1270
|
+
TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
|
|
1271
|
+
"0:0, 0:110", "0:0, 0:110");
|
|
1272
|
+
|
|
1273
|
+
// This test has d = 180 degrees, i.e. the two sites project to points that
|
|
1274
|
+
// are 180 degrees apart along the input edge. The snapped edge doesn't
|
|
1275
|
+
// stay within max_edge_deviation() of the input edge, so an extra site is
|
|
1276
|
+
// added and it is snapped again (yielding two edges). The case we are
|
|
1277
|
+
// testing here is the first call to SnapEdge() before adding the site.
|
|
1278
|
+
TestSnappingWithForcedVertices("0:10, 0:170", S1Angle::Degrees(50),
|
|
1279
|
+
"47:0, 49:180", "47:0, 0:90, 49:180");
|
|
1280
|
+
|
|
1281
|
+
// This test has d = 220 degrees, i.e. when the input edge is snapped it
|
|
1282
|
+
// goes the "wrong way" around the sphere. Again, the snapped edge is too
|
|
1283
|
+
// far from the input edge so an extra site is added and it is resnapped.
|
|
1284
|
+
TestSnappingWithForcedVertices("0:10, 0:170", S1Angle::Degrees(70),
|
|
1285
|
+
"0:-20, 0:-160", "0:-20, 0:90, 0:-160");
|
|
1286
|
+
|
|
1287
|
+
// Without using forced vertices, the maximum angle between the coverage
|
|
1288
|
+
// interval centers is d = 300 degrees. This would use an edge 180 degrees
|
|
1289
|
+
// long, and then place two sites 60 degrees past either endpoint. With
|
|
1290
|
+
// forced vertices we can increase the snap radius to 70 degrees and get an
|
|
1291
|
+
// angle of up to d = 320 degrees, but the sites are only 40 degrees apart
|
|
1292
|
+
// (which is why it requires forced vertices). The test below is an
|
|
1293
|
+
// approximation of this situation with d = 319.6 degrees.
|
|
1294
|
+
TestSnappingWithForcedVertices("0:0.1, 0:179.9", S1Angle::Degrees(70),
|
|
1295
|
+
"0:-69.8, 0:-110.2",
|
|
1296
|
+
"0:-69.8, 0:90, 0:-110.2");
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
TEST(S2Builder, OldS2PolygonBuilderBug) {
|
|
1300
|
+
// This is a polygon that caused the obsolete S2PolygonBuilder class to
|
|
1301
|
+
// generate an invalid output polygon (duplicate edges).
|
|
1302
|
+
unique_ptr<S2Polygon> input = MakePolygonOrDie(
|
|
1303
|
+
"32.2983095:72.3416582, 32.2986281:72.3423059, "
|
|
1304
|
+
"32.2985238:72.3423743, 32.2987176:72.3427807, "
|
|
1305
|
+
"32.2988174:72.3427056, 32.2991269:72.3433480, "
|
|
1306
|
+
"32.2991881:72.3433077, 32.2990668:72.3430462, "
|
|
1307
|
+
"32.2991745:72.3429778, 32.2995078:72.3436725, "
|
|
1308
|
+
"32.2996075:72.3436269, 32.2985465:72.3413832, "
|
|
1309
|
+
"32.2984558:72.3414530, 32.2988015:72.3421839, "
|
|
1310
|
+
"32.2991552:72.3429416, 32.2990498:72.3430073, "
|
|
1311
|
+
"32.2983764:72.3416059");
|
|
1312
|
+
ASSERT_TRUE(input->IsValid());
|
|
1313
|
+
|
|
1314
|
+
S1Angle snap_radius = S2Testing::MetersToAngle(20/0.866);
|
|
1315
|
+
S2Builder builder{S2Builder::Options(IdentitySnapFunction(snap_radius))};
|
|
1316
|
+
S2Polygon output;
|
|
1317
|
+
builder.StartLayer(make_unique<S2PolygonLayer>(&output));
|
|
1318
|
+
builder.AddPolygon(*input);
|
|
1319
|
+
S2Error error;
|
|
1320
|
+
ASSERT_TRUE(builder.Build(&error)) << error;
|
|
1321
|
+
EXPECT_TRUE(output.IsValid());
|
|
1322
|
+
unique_ptr<S2Polygon> expected = MakePolygonOrDie(
|
|
1323
|
+
"32.2991552:72.3429416, 32.2991881:72.3433077, 32.2996075:72.3436269; "
|
|
1324
|
+
"32.2988015:72.3421839, 32.2985465:72.3413832, 32.2983764:72.3416059, "
|
|
1325
|
+
"32.2985238:72.3423743, 32.2987176:72.3427807");
|
|
1326
|
+
ExpectPolygonsEqual(*expected, output);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
} // namespace
|