@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,946 @@
|
|
|
1
|
+
// Copyright 2017 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
|
+
#ifndef S2_S2CLOSEST_EDGE_QUERY_BASE_H_
|
|
19
|
+
#define S2_S2CLOSEST_EDGE_QUERY_BASE_H_
|
|
20
|
+
|
|
21
|
+
#include <memory>
|
|
22
|
+
#include <vector>
|
|
23
|
+
|
|
24
|
+
#include "s2/base/logging.h"
|
|
25
|
+
#include "s2/util/gtl/btree_set.h"
|
|
26
|
+
#include "s2/third_party/absl/container/inlined_vector.h"
|
|
27
|
+
#include "s2/_fp_contract_off.h"
|
|
28
|
+
#include "s2/s1angle.h"
|
|
29
|
+
#include "s2/s1chord_angle.h"
|
|
30
|
+
#include "s2/s2cap.h"
|
|
31
|
+
#include "s2/s2cell.h"
|
|
32
|
+
#include "s2/s2cell_id.h"
|
|
33
|
+
#include "s2/s2cell_union.h"
|
|
34
|
+
#include "s2/s2distance_target.h"
|
|
35
|
+
#include "s2/s2region_coverer.h"
|
|
36
|
+
#include "s2/s2shape_index.h"
|
|
37
|
+
#include "s2/s2shapeutil_count_edges.h"
|
|
38
|
+
#include "s2/s2shapeutil_shape_edge_id.h"
|
|
39
|
+
#include "s2/util/gtl/dense_hash_set.h"
|
|
40
|
+
|
|
41
|
+
// S2ClosestEdgeQueryBase is a templatized class for finding the closest
|
|
42
|
+
// edge(s) between two geometries. It is not intended to be used directly,
|
|
43
|
+
// but rather to serve as the implementation of various specialized classes
|
|
44
|
+
// with more convenient APIs (such as S2ClosestEdgeQuery). It is flexible
|
|
45
|
+
// enough so that it can be adapted to compute maximum distances and even
|
|
46
|
+
// potentially Hausdorff distances.
|
|
47
|
+
//
|
|
48
|
+
// By using the appropriate options, this class can answer questions such as:
|
|
49
|
+
//
|
|
50
|
+
// - Find the minimum distance between two geometries A and B.
|
|
51
|
+
// - Find all edges of geometry A that are within a distance D of geometry B.
|
|
52
|
+
// - Find the k edges of geometry A that are closest to a given point P.
|
|
53
|
+
//
|
|
54
|
+
// You can also specify whether polygons should include their interiors (i.e.,
|
|
55
|
+
// if a point is contained by a polygon, should the distance be zero or should
|
|
56
|
+
// it be measured to the polygon boundary?)
|
|
57
|
+
//
|
|
58
|
+
// The input geometries may consist of any number of points, polylines, and
|
|
59
|
+
// polygons (collectively referred to as "shapes"). Shapes do not need to be
|
|
60
|
+
// disjoint; they may overlap or intersect arbitrarily. The implementation is
|
|
61
|
+
// designed to be fast for both simple and complex geometries.
|
|
62
|
+
//
|
|
63
|
+
// The Distance template argument is used to represent distances. Usually it
|
|
64
|
+
// is a thin wrapper around S1ChordAngle, but another distance type may be
|
|
65
|
+
// used as long as it implements the Distance concept described in
|
|
66
|
+
// s2distance_targets.h. For example this can be used to measure maximum
|
|
67
|
+
// distances, to get more accuracy, or to measure non-spheroidal distances.
|
|
68
|
+
template <class Distance>
|
|
69
|
+
class S2ClosestEdgeQueryBase {
|
|
70
|
+
public:
|
|
71
|
+
using Delta = typename Distance::Delta;
|
|
72
|
+
|
|
73
|
+
// Options that control the set of edges returned. Note that by default
|
|
74
|
+
// *all* edges are returned, so you will always want to set either the
|
|
75
|
+
// max_results() option or the max_distance() option (or both).
|
|
76
|
+
class Options {
|
|
77
|
+
public:
|
|
78
|
+
Options();
|
|
79
|
+
|
|
80
|
+
// Specifies that at most "max_results" edges should be returned.
|
|
81
|
+
//
|
|
82
|
+
// REQUIRES: max_results >= 1
|
|
83
|
+
// DEFAULT: kMaxMaxResults
|
|
84
|
+
int max_results() const;
|
|
85
|
+
void set_max_results(int max_results);
|
|
86
|
+
static constexpr int kMaxMaxResults = std::numeric_limits<int>::max();
|
|
87
|
+
|
|
88
|
+
// Specifies that only edges whose distance to the target is less than
|
|
89
|
+
// "max_distance" should be returned.
|
|
90
|
+
//
|
|
91
|
+
// Note that edges whose distance is exactly equal to "max_distance" are
|
|
92
|
+
// not returned. In most cases this doesn't matter (since distances are
|
|
93
|
+
// not computed exactly in the first place), but if such edges are needed
|
|
94
|
+
// then you can retrieve them by specifying "max_distance" as the next
|
|
95
|
+
// largest representable Distance. For example, if Distance is an
|
|
96
|
+
// S1ChordAngle then you can specify max_distance.Successor().
|
|
97
|
+
//
|
|
98
|
+
// DEFAULT: Distance::Infinity()
|
|
99
|
+
Distance max_distance() const;
|
|
100
|
+
void set_max_distance(Distance max_distance);
|
|
101
|
+
|
|
102
|
+
// Specifies that edges up to max_error() further away than the true
|
|
103
|
+
// closest edges may be substituted in the result set, as long as such
|
|
104
|
+
// edges satisfy all the remaining search criteria (such as max_distance).
|
|
105
|
+
// This option only has an effect if max_results() is also specified;
|
|
106
|
+
// otherwise all edges closer than max_distance() will always be returned.
|
|
107
|
+
//
|
|
108
|
+
// Note that this does not affect how the distance between edges is
|
|
109
|
+
// computed; it simply gives the algorithm permission to stop the search
|
|
110
|
+
// early as soon as the best possible improvement drops below max_error().
|
|
111
|
+
//
|
|
112
|
+
// This can be used to implement distance predicates efficiently. For
|
|
113
|
+
// example, to determine whether the minimum distance is less than D, set
|
|
114
|
+
// max_results() == 1 and max_distance() == max_error() == D. This causes
|
|
115
|
+
// the algorithm to terminate as soon as it finds any edge whose distance
|
|
116
|
+
// is less than D, rather than continuing to search for an edge that is
|
|
117
|
+
// even closer.
|
|
118
|
+
//
|
|
119
|
+
// DEFAULT: Distance::Delta::Zero()
|
|
120
|
+
Delta max_error() const;
|
|
121
|
+
void set_max_error(Delta max_error);
|
|
122
|
+
|
|
123
|
+
// Specifies that polygon interiors should be included when measuring
|
|
124
|
+
// distances. In other words, polygons that contain the target should
|
|
125
|
+
// have a distance of zero. (For targets consisting of multiple connected
|
|
126
|
+
// components, the distance is zero if any component is contained.) This
|
|
127
|
+
// is indicated in the results by returning a (shape_id, edge_id) pair
|
|
128
|
+
// with edge_id == -1, i.e. this value denotes the polygons's interior.
|
|
129
|
+
//
|
|
130
|
+
// Note that for efficiency, any polygon that intersects the target may or
|
|
131
|
+
// may not have an (edge_id == -1) result. Such results are optional
|
|
132
|
+
// because in that case the distance to the polygon is already zero.
|
|
133
|
+
//
|
|
134
|
+
// DEFAULT: true
|
|
135
|
+
bool include_interiors() const;
|
|
136
|
+
void set_include_interiors(bool include_interiors);
|
|
137
|
+
|
|
138
|
+
// Specifies that distances should be computed by examining every edge
|
|
139
|
+
// rather than using the S2ShapeIndex. This is useful for testing,
|
|
140
|
+
// benchmarking, and debugging.
|
|
141
|
+
//
|
|
142
|
+
// DEFAULT: false
|
|
143
|
+
bool use_brute_force() const;
|
|
144
|
+
void set_use_brute_force(bool use_brute_force);
|
|
145
|
+
|
|
146
|
+
private:
|
|
147
|
+
Distance max_distance_ = Distance::Infinity();
|
|
148
|
+
Delta max_error_ = Delta::Zero();
|
|
149
|
+
int max_results_ = kMaxMaxResults;
|
|
150
|
+
bool include_interiors_ = true;
|
|
151
|
+
bool use_brute_force_ = false;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// The Target class represents the geometry to which the distance is
|
|
155
|
+
// measured. For example, there can be subtypes for measuring the distance
|
|
156
|
+
// to a point, an edge, or to an S2ShapeIndex (an arbitrary collection of
|
|
157
|
+
// geometry).
|
|
158
|
+
//
|
|
159
|
+
// Implementations do *not* need to be thread-safe. They may cache data or
|
|
160
|
+
// allocate temporary data structures in order to improve performance.
|
|
161
|
+
using Target = S2DistanceTarget<Distance>;
|
|
162
|
+
|
|
163
|
+
// Each "Result" object represents a closest edge. Note the following
|
|
164
|
+
// special cases:
|
|
165
|
+
//
|
|
166
|
+
// - (shape_id() >= 0) && (edge_id() < 0) represents the interior of a shape.
|
|
167
|
+
// Such results may be returned when options.include_interiors() is true.
|
|
168
|
+
// Such results can be identified using the is_interior() method.
|
|
169
|
+
//
|
|
170
|
+
// - (shape_id() < 0) && (edge_id() < 0) is returned by `FindClosestEdge`
|
|
171
|
+
// to indicate that no edge satisfies the given query options. Such
|
|
172
|
+
// results can be identified using is_empty() method.
|
|
173
|
+
class Result {
|
|
174
|
+
public:
|
|
175
|
+
// The default constructor yields an empty result, with a distance() of
|
|
176
|
+
// Infinity() and shape_id == edge_id == -1.
|
|
177
|
+
Result() : distance_(Distance::Infinity()), shape_id_(-1), edge_id_(-1) {}
|
|
178
|
+
|
|
179
|
+
// Constructs a Result object for the given arguments.
|
|
180
|
+
Result(Distance distance, int32 shape_id, int32 edge_id)
|
|
181
|
+
: distance_(distance), shape_id_(shape_id), edge_id_(edge_id) {}
|
|
182
|
+
|
|
183
|
+
// The distance from the target to this edge.
|
|
184
|
+
Distance distance() const { return distance_; }
|
|
185
|
+
|
|
186
|
+
// Identifies an indexed shape.
|
|
187
|
+
int32 shape_id() const { return shape_id_; }
|
|
188
|
+
|
|
189
|
+
// Identifies an edge within the shape.
|
|
190
|
+
int32 edge_id() const { return edge_id_; }
|
|
191
|
+
|
|
192
|
+
// Returns true if this Result object represents the interior of a shape.
|
|
193
|
+
// (Such results may be returned when options.include_interiors() is true.)
|
|
194
|
+
bool is_interior() const { return shape_id_ >= 0 && edge_id_ < 0; }
|
|
195
|
+
|
|
196
|
+
// Returns true if this Result object indicates that no edge satisfies the
|
|
197
|
+
// given query options. (This result is only returned in one special
|
|
198
|
+
// case, namely when FindClosestEdge() does not find any suitable edges.
|
|
199
|
+
// It is never returned by methods that return a vector of results.)
|
|
200
|
+
bool is_empty() const { return shape_id_ < 0; }
|
|
201
|
+
|
|
202
|
+
// Returns true if two Result objects are identical.
|
|
203
|
+
friend bool operator==(const Result& x, const Result& y) {
|
|
204
|
+
return (x.distance_ == y.distance_ &&
|
|
205
|
+
x.shape_id_ == y.shape_id_ &&
|
|
206
|
+
x.edge_id_ == y.edge_id_);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Compares edges first by distance, then by (shape_id, edge_id).
|
|
210
|
+
friend bool operator<(const Result& x, const Result& y) {
|
|
211
|
+
if (x.distance_ < y.distance_) return true;
|
|
212
|
+
if (y.distance_ < x.distance_) return false;
|
|
213
|
+
if (x.shape_id_ < y.shape_id_) return true;
|
|
214
|
+
if (y.shape_id_ < x.shape_id_) return false;
|
|
215
|
+
return x.edge_id_ < y.edge_id_;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Indicates that linear rather than binary search should be used when this
|
|
219
|
+
// type is used as the key in gtl::btree data structures.
|
|
220
|
+
using goog_btree_prefer_linear_node_search = std::true_type;
|
|
221
|
+
|
|
222
|
+
private:
|
|
223
|
+
Distance distance_; // The distance from the target to this edge.
|
|
224
|
+
int32 shape_id_; // Identifies an indexed shape.
|
|
225
|
+
int32 edge_id_; // Identifies an edge within the shape.
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Default constructor; requires Init() to be called.
|
|
229
|
+
S2ClosestEdgeQueryBase();
|
|
230
|
+
~S2ClosestEdgeQueryBase();
|
|
231
|
+
|
|
232
|
+
// Convenience constructor that calls Init().
|
|
233
|
+
explicit S2ClosestEdgeQueryBase(const S2ShapeIndex* index);
|
|
234
|
+
|
|
235
|
+
// S2ClosestEdgeQueryBase is not copyable.
|
|
236
|
+
S2ClosestEdgeQueryBase(const S2ClosestEdgeQueryBase&) = delete;
|
|
237
|
+
void operator=(const S2ClosestEdgeQueryBase&) = delete;
|
|
238
|
+
|
|
239
|
+
// Initializes the query.
|
|
240
|
+
// REQUIRES: ReInit() must be called if "index" is modified.
|
|
241
|
+
void Init(const S2ShapeIndex* index);
|
|
242
|
+
|
|
243
|
+
// Reinitializes the query. This method must be called whenever the
|
|
244
|
+
// underlying index is modified.
|
|
245
|
+
void ReInit();
|
|
246
|
+
|
|
247
|
+
// Returns a reference to the underlying S2ShapeIndex.
|
|
248
|
+
const S2ShapeIndex& index() const;
|
|
249
|
+
|
|
250
|
+
// Returns the closest edges to the given target that satisfy the given
|
|
251
|
+
// options. This method may be called multiple times.
|
|
252
|
+
//
|
|
253
|
+
// Note that if options().include_interiors() is true, the result vector may
|
|
254
|
+
// include some entries with edge_id == -1. This indicates that the target
|
|
255
|
+
// intersects the indexed polygon with the given shape_id.
|
|
256
|
+
std::vector<Result> FindClosestEdges(Target* target, const Options& options);
|
|
257
|
+
|
|
258
|
+
// This version can be more efficient when this method is called many times,
|
|
259
|
+
// since it does not require allocating a new vector on each call.
|
|
260
|
+
void FindClosestEdges(Target* target, const Options& options,
|
|
261
|
+
std::vector<Result>* results);
|
|
262
|
+
|
|
263
|
+
// Convenience method that returns exactly one edge. If no edges satisfy
|
|
264
|
+
// the given search criteria, then a Result with distance == Infinity() and
|
|
265
|
+
// shape_id == edge_id == -1 is returned.
|
|
266
|
+
//
|
|
267
|
+
// Note that if options.include_interiors() is true, edge_id == -1 is also
|
|
268
|
+
// used to indicate that the target intersects an indexed polygon (but in
|
|
269
|
+
// that case distance == Zero() and shape_id >= 0).
|
|
270
|
+
//
|
|
271
|
+
// REQUIRES: options.max_results() == 1
|
|
272
|
+
Result FindClosestEdge(Target* target, const Options& options);
|
|
273
|
+
|
|
274
|
+
private:
|
|
275
|
+
struct QueueEntry;
|
|
276
|
+
|
|
277
|
+
const Options& options() const { return *options_; }
|
|
278
|
+
void FindClosestEdgesInternal(Target* target, const Options& options);
|
|
279
|
+
void FindClosestEdgesBruteForce();
|
|
280
|
+
void FindClosestEdgesOptimized();
|
|
281
|
+
void InitQueue();
|
|
282
|
+
void InitCovering();
|
|
283
|
+
void AddInitialRange(const S2ShapeIndex::Iterator& first,
|
|
284
|
+
const S2ShapeIndex::Iterator& last);
|
|
285
|
+
void MaybeAddResult(const S2Shape& shape, int edge_id);
|
|
286
|
+
void AddResult(const Result& result);
|
|
287
|
+
void ProcessEdges(const QueueEntry& entry);
|
|
288
|
+
void ProcessOrEnqueue(S2CellId id);
|
|
289
|
+
void ProcessOrEnqueue(S2CellId id, const S2ShapeIndexCell* index_cell);
|
|
290
|
+
|
|
291
|
+
const S2ShapeIndex* index_;
|
|
292
|
+
const Options* options_;
|
|
293
|
+
Target* target_;
|
|
294
|
+
|
|
295
|
+
// True if max_error() must be subtracted from priority queue cell distances
|
|
296
|
+
// in order to ensure that such distances are measured conservatively. This
|
|
297
|
+
// is true only if the target takes advantage of max_error() in order to
|
|
298
|
+
// return faster results, and 0 < max_error() < distance_limit_.
|
|
299
|
+
bool use_conservative_cell_distance_;
|
|
300
|
+
|
|
301
|
+
// For the optimized algorihm we precompute the top-level S2CellIds that
|
|
302
|
+
// will be added to the priority queue. There can be at most 6 of these
|
|
303
|
+
// cells. Essentially this is just a covering of the indexed edges, except
|
|
304
|
+
// that we also store pointers to the corresponding S2ShapeIndexCells to
|
|
305
|
+
// reduce the number of index seeks required.
|
|
306
|
+
//
|
|
307
|
+
// The covering needs to be stored in a std::vector so that we can use
|
|
308
|
+
// S2CellUnion::GetIntersection().
|
|
309
|
+
std::vector<S2CellId> index_covering_;
|
|
310
|
+
absl::InlinedVector<const S2ShapeIndexCell*, 6> index_cells_;
|
|
311
|
+
|
|
312
|
+
// The decision about whether to use the brute force algorithm is based on
|
|
313
|
+
// counting the total number of edges in the index. However if the index
|
|
314
|
+
// contains a large number of shapes, this in itself might take too long.
|
|
315
|
+
// So instead we only count edges up to (max_brute_force_index_size() + 1)
|
|
316
|
+
// for the current target type (stored as index_num_edges_limit_).
|
|
317
|
+
int index_num_edges_;
|
|
318
|
+
int index_num_edges_limit_;
|
|
319
|
+
|
|
320
|
+
// The distance beyond which we can safely ignore further candidate edges.
|
|
321
|
+
// (Candidates that are exactly at the limit are ignored; this is more
|
|
322
|
+
// efficient for UpdateMinDistance() and should not affect clients since
|
|
323
|
+
// distance measurements have a small amount of error anyway.)
|
|
324
|
+
//
|
|
325
|
+
// Initially this is the same as the maximum distance specified by the user,
|
|
326
|
+
// but it can also be updated by the algorithm (see MaybeAddResult).
|
|
327
|
+
Distance distance_limit_;
|
|
328
|
+
|
|
329
|
+
// The current result set is stored in one of three ways:
|
|
330
|
+
//
|
|
331
|
+
// - If max_results() == 1, the best result is kept in result_singleton_.
|
|
332
|
+
//
|
|
333
|
+
// - If max_results() == "infinity", results are appended to result_vector_
|
|
334
|
+
// and sorted/uniqued at the end.
|
|
335
|
+
//
|
|
336
|
+
// - Otherwise results are kept in a btree_set so that we can progressively
|
|
337
|
+
// reduce the distance limit once max_results() results have been found.
|
|
338
|
+
// (A priority queue is not sufficient because we need to be able to
|
|
339
|
+
// check whether a candidate edge is already in the result set.)
|
|
340
|
+
//
|
|
341
|
+
// TODO(ericv): Check whether it would be faster to use avoid_duplicates_
|
|
342
|
+
// when result_set_ is used so that we could use a priority queue instead.
|
|
343
|
+
Result result_singleton_;
|
|
344
|
+
std::vector<Result> result_vector_;
|
|
345
|
+
gtl::btree_set<Result> result_set_;
|
|
346
|
+
|
|
347
|
+
// When the result edges are stored in a btree_set (see above), usually
|
|
348
|
+
// duplicates can be removed simply by inserting candidate edges in the
|
|
349
|
+
// current set. However this is not true if Options::max_error() > 0 and
|
|
350
|
+
// the Target subtype takes advantage of this by returning suboptimal
|
|
351
|
+
// distances. This is because when UpdateMinDistance() is called with
|
|
352
|
+
// different "min_dist" parameters (i.e., the distance to beat), the
|
|
353
|
+
// implementation may return a different distance for the same edge. Since
|
|
354
|
+
// the btree_set is keyed by (distance, shape_id, edge_id) this can create
|
|
355
|
+
// duplicate edges in the results.
|
|
356
|
+
//
|
|
357
|
+
// The flag below is true when duplicates must be avoided explicitly. This
|
|
358
|
+
// is achieved by maintaining a separate set keyed by (shape_id, edge_id)
|
|
359
|
+
// only, and checking whether each edge is in that set before computing the
|
|
360
|
+
// distance to it.
|
|
361
|
+
//
|
|
362
|
+
// TODO(ericv): Check whether it is faster to avoid duplicates by default
|
|
363
|
+
// (even when Options::max_results() == 1), rather than just when we need to.
|
|
364
|
+
bool avoid_duplicates_;
|
|
365
|
+
using ShapeEdgeId = s2shapeutil::ShapeEdgeId;
|
|
366
|
+
gtl::dense_hash_set<ShapeEdgeId, s2shapeutil::ShapeEdgeIdHash> tested_edges_;
|
|
367
|
+
|
|
368
|
+
// The algorithm maintains a priority queue of unprocessed S2CellIds, sorted
|
|
369
|
+
// in increasing order of distance from the target.
|
|
370
|
+
struct QueueEntry {
|
|
371
|
+
// A lower bound on the distance from the target to "id". This is the key
|
|
372
|
+
// of the priority queue.
|
|
373
|
+
Distance distance;
|
|
374
|
+
|
|
375
|
+
// The cell being queued.
|
|
376
|
+
S2CellId id;
|
|
377
|
+
|
|
378
|
+
// If "id" belongs to the index, this field stores the corresponding
|
|
379
|
+
// S2ShapeIndexCell. Otherwise "id" is a proper ancestor of one or more
|
|
380
|
+
// S2ShapeIndexCells and this field stores nullptr. The purpose of this
|
|
381
|
+
// field is to avoid an extra Seek() when the queue entry is processed.
|
|
382
|
+
const S2ShapeIndexCell* index_cell;
|
|
383
|
+
|
|
384
|
+
QueueEntry(Distance _distance, S2CellId _id,
|
|
385
|
+
const S2ShapeIndexCell* _index_cell)
|
|
386
|
+
: distance(_distance), id(_id), index_cell(_index_cell) {
|
|
387
|
+
}
|
|
388
|
+
bool operator<(const QueueEntry& other) const {
|
|
389
|
+
// The priority queue returns the largest elements first, so we want the
|
|
390
|
+
// "largest" entry to have the smallest distance.
|
|
391
|
+
return other.distance < distance;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
using CellQueue =
|
|
395
|
+
std::priority_queue<QueueEntry, absl::InlinedVector<QueueEntry, 16>>;
|
|
396
|
+
CellQueue queue_;
|
|
397
|
+
|
|
398
|
+
// Temporaries, defined here to avoid multiple allocations / initializations.
|
|
399
|
+
|
|
400
|
+
S2ShapeIndex::Iterator iter_;
|
|
401
|
+
std::vector<S2CellId> max_distance_covering_;
|
|
402
|
+
std::vector<S2CellId> initial_cells_;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
////////////////// Implementation details follow ////////////////////
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
template <class Distance>
|
|
410
|
+
inline S2ClosestEdgeQueryBase<Distance>::Options::Options() {
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
template <class Distance>
|
|
414
|
+
inline int S2ClosestEdgeQueryBase<Distance>::Options::max_results() const {
|
|
415
|
+
return max_results_;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
template <class Distance>
|
|
419
|
+
inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_results(
|
|
420
|
+
int max_results) {
|
|
421
|
+
S2_DCHECK_GE(max_results, 1);
|
|
422
|
+
max_results_ = max_results;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
template <class Distance>
|
|
426
|
+
inline Distance S2ClosestEdgeQueryBase<Distance>::Options::max_distance()
|
|
427
|
+
const {
|
|
428
|
+
return max_distance_;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
template <class Distance>
|
|
432
|
+
inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_distance(
|
|
433
|
+
Distance max_distance) {
|
|
434
|
+
max_distance_ = max_distance;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
template <class Distance>
|
|
438
|
+
inline typename Distance::Delta
|
|
439
|
+
S2ClosestEdgeQueryBase<Distance>::Options::max_error() const {
|
|
440
|
+
return max_error_;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
template <class Distance>
|
|
444
|
+
inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_error(
|
|
445
|
+
Delta max_error) {
|
|
446
|
+
max_error_ = max_error;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
template <class Distance>
|
|
450
|
+
inline bool S2ClosestEdgeQueryBase<Distance>::Options::include_interiors()
|
|
451
|
+
const {
|
|
452
|
+
return include_interiors_;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
template <class Distance>
|
|
456
|
+
inline void S2ClosestEdgeQueryBase<Distance>::Options::set_include_interiors(
|
|
457
|
+
bool include_interiors) {
|
|
458
|
+
include_interiors_ = include_interiors;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
template <class Distance>
|
|
462
|
+
inline bool S2ClosestEdgeQueryBase<Distance>::Options::use_brute_force() const {
|
|
463
|
+
return use_brute_force_;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
template <class Distance>
|
|
467
|
+
inline void S2ClosestEdgeQueryBase<Distance>::Options::set_use_brute_force(
|
|
468
|
+
bool use_brute_force) {
|
|
469
|
+
use_brute_force_ = use_brute_force;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
template <class Distance>
|
|
473
|
+
S2ClosestEdgeQueryBase<Distance>::S2ClosestEdgeQueryBase()
|
|
474
|
+
: tested_edges_(1) /* expected_max_elements*/ {
|
|
475
|
+
tested_edges_.set_empty_key(ShapeEdgeId(-1, -1));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
template <class Distance>
|
|
479
|
+
S2ClosestEdgeQueryBase<Distance>::~S2ClosestEdgeQueryBase() {
|
|
480
|
+
// Prevent inline destructor bloat by providing a definition.
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
template <class Distance>
|
|
484
|
+
inline S2ClosestEdgeQueryBase<Distance>::S2ClosestEdgeQueryBase(
|
|
485
|
+
const S2ShapeIndex* index) : S2ClosestEdgeQueryBase() {
|
|
486
|
+
Init(index);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
template <class Distance>
|
|
490
|
+
void S2ClosestEdgeQueryBase<Distance>::Init(const S2ShapeIndex* index) {
|
|
491
|
+
index_ = index;
|
|
492
|
+
ReInit();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
template <class Distance>
|
|
496
|
+
void S2ClosestEdgeQueryBase<Distance>::ReInit() {
|
|
497
|
+
index_num_edges_ = 0;
|
|
498
|
+
index_num_edges_limit_ = 0;
|
|
499
|
+
index_covering_.clear();
|
|
500
|
+
index_cells_.clear();
|
|
501
|
+
// We don't initialize iter_ here to make queries on small indexes a bit
|
|
502
|
+
// faster (i.e., where brute force is used).
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
template <class Distance>
|
|
506
|
+
inline const S2ShapeIndex& S2ClosestEdgeQueryBase<Distance>::index() const {
|
|
507
|
+
return *index_;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
template <class Distance>
|
|
511
|
+
inline std::vector<typename S2ClosestEdgeQueryBase<Distance>::Result>
|
|
512
|
+
S2ClosestEdgeQueryBase<Distance>::FindClosestEdges(Target* target,
|
|
513
|
+
const Options& options) {
|
|
514
|
+
std::vector<Result> results;
|
|
515
|
+
FindClosestEdges(target, options, &results);
|
|
516
|
+
return results;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
template <class Distance>
|
|
520
|
+
typename S2ClosestEdgeQueryBase<Distance>::Result
|
|
521
|
+
S2ClosestEdgeQueryBase<Distance>::FindClosestEdge(Target* target,
|
|
522
|
+
const Options& options) {
|
|
523
|
+
S2_DCHECK_EQ(options.max_results(), 1);
|
|
524
|
+
FindClosestEdgesInternal(target, options);
|
|
525
|
+
return result_singleton_;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
template <class Distance>
|
|
529
|
+
void S2ClosestEdgeQueryBase<Distance>::FindClosestEdges(
|
|
530
|
+
Target* target, const Options& options,
|
|
531
|
+
std::vector<Result>* results) {
|
|
532
|
+
FindClosestEdgesInternal(target, options);
|
|
533
|
+
results->clear();
|
|
534
|
+
if (options.max_results() == 1) {
|
|
535
|
+
if (result_singleton_.shape_id() >= 0) {
|
|
536
|
+
results->push_back(result_singleton_);
|
|
537
|
+
}
|
|
538
|
+
} else if (options.max_results() == Options::kMaxMaxResults) {
|
|
539
|
+
std::sort(result_vector_.begin(), result_vector_.end());
|
|
540
|
+
std::unique_copy(result_vector_.begin(), result_vector_.end(),
|
|
541
|
+
std::back_inserter(*results));
|
|
542
|
+
result_vector_.clear();
|
|
543
|
+
} else {
|
|
544
|
+
results->assign(result_set_.begin(), result_set_.end());
|
|
545
|
+
result_set_.clear();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
template <class Distance>
|
|
550
|
+
void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesInternal(
|
|
551
|
+
Target* target, const Options& options) {
|
|
552
|
+
target_ = target;
|
|
553
|
+
options_ = &options;
|
|
554
|
+
|
|
555
|
+
tested_edges_.clear();
|
|
556
|
+
distance_limit_ = options.max_distance();
|
|
557
|
+
result_singleton_ = Result();
|
|
558
|
+
S2_DCHECK(result_vector_.empty());
|
|
559
|
+
S2_DCHECK(result_set_.empty());
|
|
560
|
+
S2_DCHECK_GE(target->max_brute_force_index_size(), 0);
|
|
561
|
+
if (distance_limit_ == Distance::Zero()) return;
|
|
562
|
+
|
|
563
|
+
if (options.max_results() == Options::kMaxMaxResults &&
|
|
564
|
+
options.max_distance() == Distance::Infinity()) {
|
|
565
|
+
S2_LOG(WARNING) << "Returning all edges (max_results/max_distance not set)";
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (options.include_interiors()) {
|
|
569
|
+
gtl::btree_set<int32> shape_ids;
|
|
570
|
+
(void) target->VisitContainingShapes(
|
|
571
|
+
*index_, [&shape_ids, &options](S2Shape* containing_shape,
|
|
572
|
+
const S2Point& target_point) {
|
|
573
|
+
shape_ids.insert(containing_shape->id());
|
|
574
|
+
return shape_ids.size() < options.max_results();
|
|
575
|
+
});
|
|
576
|
+
for (int shape_id : shape_ids) {
|
|
577
|
+
AddResult(Result(Distance::Zero(), shape_id, -1));
|
|
578
|
+
}
|
|
579
|
+
if (distance_limit_ == Distance::Zero()) return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// If max_error() > 0 and the target takes advantage of this, then we may
|
|
583
|
+
// need to adjust the distance estimates to the priority queue cells to
|
|
584
|
+
// ensure that they are always a lower bound on the true distance. For
|
|
585
|
+
// example, suppose max_distance == 100, max_error == 30, and we compute the
|
|
586
|
+
// distance to the target from some cell C0 as d(C0) == 80. Then because
|
|
587
|
+
// the target takes advantage of max_error(), the true distance could be as
|
|
588
|
+
// low as 50. In order not to miss edges contained by such cells, we need
|
|
589
|
+
// to subtract max_error() from the distance estimates. This behavior is
|
|
590
|
+
// controlled by the use_conservative_cell_distance_ flag.
|
|
591
|
+
//
|
|
592
|
+
// However there is one important case where this adjustment is not
|
|
593
|
+
// necessary, namely when max_distance() < max_error(). This is because
|
|
594
|
+
// max_error() only affects the algorithm once at least max_results() edges
|
|
595
|
+
// have been found that satisfy the given distance limit. At that point,
|
|
596
|
+
// max_error() is subtracted from distance_limit_ in order to ensure that
|
|
597
|
+
// any further matches are closer by at least that amount. But when
|
|
598
|
+
// max_distance() < max_error(), this reduces the distance limit to 0,
|
|
599
|
+
// i.e. all remaining candidate cells and edges can safely be discarded.
|
|
600
|
+
// (Note that this is how IsDistanceLess() and friends are implemented.)
|
|
601
|
+
//
|
|
602
|
+
// Note that Distance::Delta only supports operator==.
|
|
603
|
+
bool target_uses_max_error = (!(options.max_error() == Delta::Zero()) &&
|
|
604
|
+
target_->set_max_error(options.max_error()));
|
|
605
|
+
|
|
606
|
+
// Note that we can't compare max_error() and distance_limit_ directly
|
|
607
|
+
// because one is a Delta and one is a Distance. Instead we subtract them.
|
|
608
|
+
use_conservative_cell_distance_ = target_uses_max_error &&
|
|
609
|
+
(distance_limit_ == Distance::Infinity() ||
|
|
610
|
+
Distance::Zero() < distance_limit_ - options.max_error());
|
|
611
|
+
|
|
612
|
+
// Use the brute force algorithm if the index is small enough. To avoid
|
|
613
|
+
// spending too much time counting edges when there are many shapes, we stop
|
|
614
|
+
// counting once there are too many edges. We may need to recount the edges
|
|
615
|
+
// if we later see a target with a larger brute force edge threshold.
|
|
616
|
+
int min_optimized_edges = target_->max_brute_force_index_size() + 1;
|
|
617
|
+
if (min_optimized_edges > index_num_edges_limit_ &&
|
|
618
|
+
index_num_edges_ >= index_num_edges_limit_) {
|
|
619
|
+
index_num_edges_ = s2shapeutil::CountEdgesUpTo(*index_,
|
|
620
|
+
min_optimized_edges);
|
|
621
|
+
index_num_edges_limit_ = min_optimized_edges;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (options.use_brute_force() || index_num_edges_ < min_optimized_edges) {
|
|
625
|
+
// The brute force algorithm considers each edge exactly once.
|
|
626
|
+
avoid_duplicates_ = false;
|
|
627
|
+
FindClosestEdgesBruteForce();
|
|
628
|
+
} else {
|
|
629
|
+
// If the target takes advantage of max_error() then we need to avoid
|
|
630
|
+
// duplicate edges explicitly. (Otherwise it happens automatically.)
|
|
631
|
+
avoid_duplicates_ = (target_uses_max_error && options.max_results() > 1);
|
|
632
|
+
FindClosestEdgesOptimized();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
template <class Distance>
|
|
637
|
+
void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesBruteForce() {
|
|
638
|
+
for (S2Shape* shape : *index_) {
|
|
639
|
+
if (shape == nullptr) continue;
|
|
640
|
+
int num_edges = shape->num_edges();
|
|
641
|
+
for (int e = 0; e < num_edges; ++e) {
|
|
642
|
+
MaybeAddResult(*shape, e);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
template <class Distance>
|
|
648
|
+
void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesOptimized() {
|
|
649
|
+
InitQueue();
|
|
650
|
+
// Repeatedly find the closest S2Cell to "target" and either split it into
|
|
651
|
+
// its four children or process all of its edges.
|
|
652
|
+
while (!queue_.empty()) {
|
|
653
|
+
// We need to copy the top entry before removing it, and we need to
|
|
654
|
+
// remove it before adding any new entries to the queue.
|
|
655
|
+
QueueEntry entry = queue_.top();
|
|
656
|
+
queue_.pop();
|
|
657
|
+
// Work around weird parse error in gcc 4.9 by using a local variable for
|
|
658
|
+
// entry.distance.
|
|
659
|
+
Distance distance = entry.distance;
|
|
660
|
+
if (!(distance < distance_limit_)) {
|
|
661
|
+
queue_ = CellQueue(); // Clear any remaining entries.
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
// If this is already known to be an index cell, just process it.
|
|
665
|
+
if (entry.index_cell != nullptr) {
|
|
666
|
+
ProcessEdges(entry);
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
// Otherwise split the cell into its four children. Before adding a
|
|
670
|
+
// child back to the queue, we first check whether it is empty. We do
|
|
671
|
+
// this in two seek operations rather than four by seeking to the key
|
|
672
|
+
// between children 0 and 1 and to the key between children 2 and 3.
|
|
673
|
+
S2CellId id = entry.id;
|
|
674
|
+
iter_.Seek(id.child(1).range_min());
|
|
675
|
+
if (!iter_.done() && iter_.id() <= id.child(1).range_max()) {
|
|
676
|
+
ProcessOrEnqueue(id.child(1));
|
|
677
|
+
}
|
|
678
|
+
if (iter_.Prev() && iter_.id() >= id.range_min()) {
|
|
679
|
+
ProcessOrEnqueue(id.child(0));
|
|
680
|
+
}
|
|
681
|
+
iter_.Seek(id.child(3).range_min());
|
|
682
|
+
if (!iter_.done() && iter_.id() <= id.range_max()) {
|
|
683
|
+
ProcessOrEnqueue(id.child(3));
|
|
684
|
+
}
|
|
685
|
+
if (iter_.Prev() && iter_.id() >= id.child(2).range_min()) {
|
|
686
|
+
ProcessOrEnqueue(id.child(2));
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
template <class Distance>
|
|
692
|
+
void S2ClosestEdgeQueryBase<Distance>::InitQueue() {
|
|
693
|
+
S2_DCHECK(queue_.empty());
|
|
694
|
+
if (index_covering_.empty()) {
|
|
695
|
+
// We delay iterator initialization until now to make queries on very
|
|
696
|
+
// small indexes a bit faster (i.e., where brute force is used).
|
|
697
|
+
iter_.Init(index_, S2ShapeIndex::UNPOSITIONED);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Optimization: if the user is searching for just the closest edge, and the
|
|
701
|
+
// center of the target's bounding cap happens to intersect an index cell,
|
|
702
|
+
// then we try to limit the search region to a small disc by first
|
|
703
|
+
// processing the edges in that cell. This sets distance_limit_ based on
|
|
704
|
+
// the closest edge in that cell, which we can then use to limit the search
|
|
705
|
+
// area. This means that the cell containing "target" will be processed
|
|
706
|
+
// twice, but in general this is still faster.
|
|
707
|
+
//
|
|
708
|
+
// TODO(ericv): Even if the cap center is not contained, we could still
|
|
709
|
+
// process one or both of the adjacent index cells in S2CellId order,
|
|
710
|
+
// provided that those cells are closer than distance_limit_.
|
|
711
|
+
S2Cap cap = target_->GetCapBound();
|
|
712
|
+
if (cap.is_empty()) return; // Empty target.
|
|
713
|
+
if (options().max_results() == 1 && iter_.Locate(cap.center())) {
|
|
714
|
+
ProcessEdges(QueueEntry(Distance::Zero(), iter_.id(), &iter_.cell()));
|
|
715
|
+
// Skip the rest of the algorithm if we found an intersecting edge.
|
|
716
|
+
if (distance_limit_ == Distance::Zero()) return;
|
|
717
|
+
}
|
|
718
|
+
if (index_covering_.empty()) InitCovering();
|
|
719
|
+
if (distance_limit_ == Distance::Infinity()) {
|
|
720
|
+
// Start with the precomputed index covering.
|
|
721
|
+
for (int i = 0; i < index_covering_.size(); ++i) {
|
|
722
|
+
ProcessOrEnqueue(index_covering_[i], index_cells_[i]);
|
|
723
|
+
}
|
|
724
|
+
} else {
|
|
725
|
+
// Compute a covering of the search disc and intersect it with the
|
|
726
|
+
// precomputed index covering.
|
|
727
|
+
S2RegionCoverer coverer;
|
|
728
|
+
coverer.mutable_options()->set_max_cells(4);
|
|
729
|
+
S1ChordAngle radius = cap.radius() + distance_limit_.GetChordAngleBound();
|
|
730
|
+
S2Cap search_cap(cap.center(), radius);
|
|
731
|
+
coverer.GetFastCovering(search_cap, &max_distance_covering_);
|
|
732
|
+
S2CellUnion::GetIntersection(index_covering_, max_distance_covering_,
|
|
733
|
+
&initial_cells_);
|
|
734
|
+
|
|
735
|
+
// Now we need to clean up the initial cells to ensure that they all
|
|
736
|
+
// contain at least one cell of the S2ShapeIndex. (Some may not intersect
|
|
737
|
+
// the index at all, while other may be descendants of an index cell.)
|
|
738
|
+
for (int i = 0, j = 0; i < initial_cells_.size(); ) {
|
|
739
|
+
S2CellId id_i = initial_cells_[i];
|
|
740
|
+
// Find the top-level cell that contains this initial cell.
|
|
741
|
+
while (index_covering_[j].range_max() < id_i) ++j;
|
|
742
|
+
S2CellId id_j = index_covering_[j];
|
|
743
|
+
if (id_i == id_j) {
|
|
744
|
+
// This initial cell is one of the top-level cells. Use the
|
|
745
|
+
// precomputed S2ShapeIndexCell pointer to avoid an index seek.
|
|
746
|
+
ProcessOrEnqueue(id_j, index_cells_[j]);
|
|
747
|
+
++i, ++j;
|
|
748
|
+
} else {
|
|
749
|
+
// This initial cell is a proper descendant of a top-level cell.
|
|
750
|
+
// Check how it is related to the cells of the S2ShapeIndex.
|
|
751
|
+
S2ShapeIndex::CellRelation r = iter_.Locate(id_i);
|
|
752
|
+
if (r == S2ShapeIndex::INDEXED) {
|
|
753
|
+
// This cell is a descendant of an index cell. Enqueue it and skip
|
|
754
|
+
// any other initial cells that are also descendants of this cell.
|
|
755
|
+
ProcessOrEnqueue(iter_.id(), &iter_.cell());
|
|
756
|
+
const S2CellId last_id = iter_.id().range_max();
|
|
757
|
+
while (++i < initial_cells_.size() && initial_cells_[i] <= last_id)
|
|
758
|
+
continue;
|
|
759
|
+
} else {
|
|
760
|
+
// Enqueue the cell only if it contains at least one index cell.
|
|
761
|
+
if (r == S2ShapeIndex::SUBDIVIDED) ProcessOrEnqueue(id_i, nullptr);
|
|
762
|
+
++i;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
template <class Distance>
|
|
770
|
+
void S2ClosestEdgeQueryBase<Distance>::InitCovering() {
|
|
771
|
+
// Find the range of S2Cells spanned by the index and choose a level such
|
|
772
|
+
// that the entire index can be covered with just a few cells. These are
|
|
773
|
+
// the "top-level" cells. There are two cases:
|
|
774
|
+
//
|
|
775
|
+
// - If the index spans more than one face, then there is one top-level cell
|
|
776
|
+
// per spanned face, just big enough to cover the index cells on that face.
|
|
777
|
+
//
|
|
778
|
+
// - If the index spans only one face, then we find the smallest cell "C"
|
|
779
|
+
// that covers the index cells on that face (just like the case above).
|
|
780
|
+
// Then for each of the 4 children of "C", if the child contains any index
|
|
781
|
+
// cells then we create a top-level cell that is big enough to just fit
|
|
782
|
+
// those index cells (i.e., shrinking the child as much as possible to fit
|
|
783
|
+
// its contents). This essentially replicates what would happen if we
|
|
784
|
+
// started with "C" as the top-level cell, since "C" would immediately be
|
|
785
|
+
// split, except that we take the time to prune the children further since
|
|
786
|
+
// this will save work on every subsequent query.
|
|
787
|
+
|
|
788
|
+
// Don't need to reserve index_cells_ since it is an InlinedVector.
|
|
789
|
+
index_covering_.reserve(6);
|
|
790
|
+
|
|
791
|
+
// TODO(ericv): Use a single iterator (iter_) below and save position
|
|
792
|
+
// information using pair<S2CellId, const S2ShapeIndexCell*> type.
|
|
793
|
+
S2ShapeIndex::Iterator next(index_, S2ShapeIndex::BEGIN);
|
|
794
|
+
S2ShapeIndex::Iterator last(index_, S2ShapeIndex::END);
|
|
795
|
+
last.Prev();
|
|
796
|
+
if (next.id() != last.id()) {
|
|
797
|
+
// The index has at least two cells. Choose a level such that the entire
|
|
798
|
+
// index can be spanned with at most 6 cells (if the index spans multiple
|
|
799
|
+
// faces) or 4 cells (it the index spans a single face).
|
|
800
|
+
int level = next.id().GetCommonAncestorLevel(last.id()) + 1;
|
|
801
|
+
|
|
802
|
+
// Visit each potential top-level cell except the last (handled below).
|
|
803
|
+
S2CellId last_id = last.id().parent(level);
|
|
804
|
+
for (S2CellId id = next.id().parent(level); id != last_id; id = id.next()) {
|
|
805
|
+
// Skip any top-level cells that don't contain any index cells.
|
|
806
|
+
if (id.range_max() < next.id()) continue;
|
|
807
|
+
|
|
808
|
+
// Find the range of index cells contained by this top-level cell and
|
|
809
|
+
// then shrink the cell if necessary so that it just covers them.
|
|
810
|
+
S2ShapeIndex::Iterator cell_first = next;
|
|
811
|
+
next.Seek(id.range_max().next());
|
|
812
|
+
S2ShapeIndex::Iterator cell_last = next;
|
|
813
|
+
cell_last.Prev();
|
|
814
|
+
AddInitialRange(cell_first, cell_last);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
AddInitialRange(next, last);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Add an entry to index_covering_ and index_cells_ that covers the given
|
|
821
|
+
// inclusive range of cells.
|
|
822
|
+
//
|
|
823
|
+
// REQUIRES: "first" and "last" have a common ancestor.
|
|
824
|
+
template <class Distance>
|
|
825
|
+
void S2ClosestEdgeQueryBase<Distance>::AddInitialRange(
|
|
826
|
+
const S2ShapeIndex::Iterator& first,
|
|
827
|
+
const S2ShapeIndex::Iterator& last) {
|
|
828
|
+
if (first.id() == last.id()) {
|
|
829
|
+
// The range consists of a single index cell.
|
|
830
|
+
index_covering_.push_back(first.id());
|
|
831
|
+
index_cells_.push_back(&first.cell());
|
|
832
|
+
} else {
|
|
833
|
+
// Add the lowest common ancestor of the given range.
|
|
834
|
+
int level = first.id().GetCommonAncestorLevel(last.id());
|
|
835
|
+
S2_DCHECK_GE(level, 0);
|
|
836
|
+
index_covering_.push_back(first.id().parent(level));
|
|
837
|
+
index_cells_.push_back(nullptr);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
template <class Distance>
|
|
842
|
+
void S2ClosestEdgeQueryBase<Distance>::MaybeAddResult(
|
|
843
|
+
const S2Shape& shape, int edge_id) {
|
|
844
|
+
if (avoid_duplicates_ &&
|
|
845
|
+
!tested_edges_.insert(ShapeEdgeId(shape.id(), edge_id)).second) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
auto edge = shape.edge(edge_id);
|
|
849
|
+
Distance distance = distance_limit_;
|
|
850
|
+
if (target_->UpdateMinDistance(edge.v0, edge.v1, &distance)) {
|
|
851
|
+
AddResult(Result(distance, shape.id(), edge_id));
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
template <class Distance>
|
|
856
|
+
void S2ClosestEdgeQueryBase<Distance>::AddResult(const Result& result) {
|
|
857
|
+
if (options().max_results() == 1) {
|
|
858
|
+
// Optimization for the common case where only the closest edge is wanted.
|
|
859
|
+
result_singleton_ = result;
|
|
860
|
+
distance_limit_ = result.distance() - options().max_error();
|
|
861
|
+
} else if (options().max_results() == Options::kMaxMaxResults) {
|
|
862
|
+
result_vector_.push_back(result); // Sort/unique at end.
|
|
863
|
+
} else {
|
|
864
|
+
// Add this edge to result_set_. Note that even if we already have enough
|
|
865
|
+
// edges, we can't erase an element before insertion because the "new"
|
|
866
|
+
// edge might in fact be a duplicate.
|
|
867
|
+
result_set_.insert(result);
|
|
868
|
+
int size = result_set_.size();
|
|
869
|
+
if (size >= options().max_results()) {
|
|
870
|
+
if (size > options().max_results()) {
|
|
871
|
+
result_set_.erase(--result_set_.end());
|
|
872
|
+
}
|
|
873
|
+
distance_limit_ = (--result_set_.end())->distance() -
|
|
874
|
+
options().max_error();
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Return the number of edges in the given index cell.
|
|
880
|
+
inline static int CountEdges(const S2ShapeIndexCell* cell) {
|
|
881
|
+
int count = 0;
|
|
882
|
+
for (int s = 0; s < cell->num_clipped(); ++s) {
|
|
883
|
+
count += cell->clipped(s).num_edges();
|
|
884
|
+
}
|
|
885
|
+
return count;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Process all the edges of the given index cell.
|
|
889
|
+
template <class Distance>
|
|
890
|
+
void S2ClosestEdgeQueryBase<Distance>::ProcessEdges(const QueueEntry& entry) {
|
|
891
|
+
const S2ShapeIndexCell* index_cell = entry.index_cell;
|
|
892
|
+
for (int s = 0; s < index_cell->num_clipped(); ++s) {
|
|
893
|
+
const S2ClippedShape& clipped = index_cell->clipped(s);
|
|
894
|
+
const S2Shape* shape = index_->shape(clipped.shape_id());
|
|
895
|
+
for (int j = 0; j < clipped.num_edges(); ++j) {
|
|
896
|
+
MaybeAddResult(*shape, clipped.edge(j));
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Enqueue the given cell id.
|
|
902
|
+
// REQUIRES: iter_ is positioned at a cell contained by "id".
|
|
903
|
+
template <class Distance>
|
|
904
|
+
inline void S2ClosestEdgeQueryBase<Distance>::ProcessOrEnqueue(
|
|
905
|
+
S2CellId id) {
|
|
906
|
+
S2_DCHECK(id.contains(iter_.id()));
|
|
907
|
+
if (iter_.id() == id) {
|
|
908
|
+
ProcessOrEnqueue(id, &iter_.cell());
|
|
909
|
+
} else {
|
|
910
|
+
ProcessOrEnqueue(id, nullptr);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Add the given cell id to the queue. "index_cell" is the corresponding
|
|
915
|
+
// S2ShapeIndexCell, or nullptr if "id" is not an index cell.
|
|
916
|
+
//
|
|
917
|
+
// This version is called directly only by InitQueue().
|
|
918
|
+
template <class Distance>
|
|
919
|
+
void S2ClosestEdgeQueryBase<Distance>::ProcessOrEnqueue(
|
|
920
|
+
S2CellId id, const S2ShapeIndexCell* index_cell) {
|
|
921
|
+
if (index_cell) {
|
|
922
|
+
// If this index cell has only a few edges, then it is faster to check
|
|
923
|
+
// them directly rather than computing the minimum distance to the S2Cell
|
|
924
|
+
// and inserting it into the queue.
|
|
925
|
+
static const int kMinEdgesToEnqueue = 10;
|
|
926
|
+
int num_edges = CountEdges(index_cell);
|
|
927
|
+
if (num_edges == 0) return;
|
|
928
|
+
if (num_edges < kMinEdgesToEnqueue) {
|
|
929
|
+
// Set "distance" to zero to avoid the expense of computing it.
|
|
930
|
+
ProcessEdges(QueueEntry(Distance::Zero(), id, index_cell));
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
// Otherwise compute the minimum distance to any point in the cell and add
|
|
935
|
+
// it to the priority queue.
|
|
936
|
+
S2Cell cell(id);
|
|
937
|
+
Distance distance = distance_limit_;
|
|
938
|
+
if (!target_->UpdateMinDistance(cell, &distance)) return;
|
|
939
|
+
if (use_conservative_cell_distance_) {
|
|
940
|
+
// Ensure that "distance" is a lower bound on the true distance to the cell.
|
|
941
|
+
distance = distance - options().max_error(); // operator-=() not defined.
|
|
942
|
+
}
|
|
943
|
+
queue_.push(QueueEntry(distance, id, index_cell));
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
#endif // S2_S2CLOSEST_EDGE_QUERY_BASE_H_
|