@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,1084 @@
|
|
|
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_graph.h"
|
|
19
|
+
|
|
20
|
+
#include <algorithm>
|
|
21
|
+
#include <limits>
|
|
22
|
+
#include <memory>
|
|
23
|
+
#include <numeric>
|
|
24
|
+
#include <vector>
|
|
25
|
+
#include "s2/base/logging.h"
|
|
26
|
+
#include "s2/util/gtl/btree_map.h"
|
|
27
|
+
#include "s2/id_set_lexicon.h"
|
|
28
|
+
#include "s2/s2builder.h"
|
|
29
|
+
#include "s2/s2error.h"
|
|
30
|
+
#include "s2/s2predicates.h"
|
|
31
|
+
|
|
32
|
+
using std::make_pair;
|
|
33
|
+
using std::max;
|
|
34
|
+
using std::min;
|
|
35
|
+
using std::pair;
|
|
36
|
+
using std::vector;
|
|
37
|
+
|
|
38
|
+
using Graph = S2Builder::Graph;
|
|
39
|
+
using GraphOptions = S2Builder::GraphOptions;
|
|
40
|
+
using DegenerateEdges = GraphOptions::DegenerateEdges;
|
|
41
|
+
using DuplicateEdges = GraphOptions::DuplicateEdges;
|
|
42
|
+
using SiblingPairs = GraphOptions::SiblingPairs;
|
|
43
|
+
|
|
44
|
+
Graph::Graph(const GraphOptions& options,
|
|
45
|
+
const vector<S2Point>* vertices,
|
|
46
|
+
const vector<Edge>* edges,
|
|
47
|
+
const vector<InputEdgeIdSetId>* input_edge_id_set_ids,
|
|
48
|
+
const IdSetLexicon* input_edge_id_set_lexicon,
|
|
49
|
+
const vector<LabelSetId>* label_set_ids,
|
|
50
|
+
const IdSetLexicon* label_set_lexicon,
|
|
51
|
+
IsFullPolygonPredicate is_full_polygon_predicate)
|
|
52
|
+
: options_(options), num_vertices_(vertices->size()), vertices_(vertices),
|
|
53
|
+
edges_(edges), input_edge_id_set_ids_(input_edge_id_set_ids),
|
|
54
|
+
input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
|
|
55
|
+
label_set_ids_(label_set_ids),
|
|
56
|
+
label_set_lexicon_(label_set_lexicon),
|
|
57
|
+
is_full_polygon_predicate_(std::move(is_full_polygon_predicate)) {
|
|
58
|
+
S2_DCHECK(std::is_sorted(edges->begin(), edges->end()));
|
|
59
|
+
S2_DCHECK_EQ(edges->size(), input_edge_id_set_ids->size());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
vector<Graph::EdgeId> Graph::GetInEdgeIds() const {
|
|
63
|
+
vector<EdgeId> in_edge_ids(num_edges());
|
|
64
|
+
std::iota(in_edge_ids.begin(), in_edge_ids.end(), 0);
|
|
65
|
+
std::sort(in_edge_ids.begin(), in_edge_ids.end(),
|
|
66
|
+
[this](EdgeId ai, EdgeId bi) {
|
|
67
|
+
return StableLessThan(reverse(edge(ai)), reverse(edge(bi)), ai, bi);
|
|
68
|
+
});
|
|
69
|
+
return in_edge_ids;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
vector<Graph::EdgeId> Graph::GetSiblingMap() const {
|
|
73
|
+
vector<EdgeId> in_edge_ids = GetInEdgeIds();
|
|
74
|
+
MakeSiblingMap(&in_edge_ids);
|
|
75
|
+
return in_edge_ids;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void Graph::MakeSiblingMap(vector<Graph::EdgeId>* in_edge_ids) const {
|
|
79
|
+
S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
|
|
80
|
+
options_.sibling_pairs() == SiblingPairs::CREATE ||
|
|
81
|
+
options_.edge_type() == EdgeType::UNDIRECTED);
|
|
82
|
+
for (EdgeId e = 0; e < num_edges(); ++e) {
|
|
83
|
+
S2_DCHECK(edge(e) == reverse(edge((*in_edge_ids)[e])));
|
|
84
|
+
}
|
|
85
|
+
if (options_.edge_type() == EdgeType::DIRECTED) return;
|
|
86
|
+
if (options_.degenerate_edges() == DegenerateEdges::DISCARD) return;
|
|
87
|
+
|
|
88
|
+
for (EdgeId e = 0; e < num_edges(); ++e) {
|
|
89
|
+
VertexId v = edge(e).first;
|
|
90
|
+
if (edge(e).second == v) {
|
|
91
|
+
S2_DCHECK_LT(e + 1, num_edges());
|
|
92
|
+
S2_DCHECK_EQ(edge(e + 1).first, v);
|
|
93
|
+
S2_DCHECK_EQ(edge(e + 1).second, v);
|
|
94
|
+
S2_DCHECK_EQ((*in_edge_ids)[e], e);
|
|
95
|
+
S2_DCHECK_EQ((*in_edge_ids)[e + 1], e + 1);
|
|
96
|
+
(*in_edge_ids)[e] = e + 1;
|
|
97
|
+
(*in_edge_ids)[e + 1] = e;
|
|
98
|
+
++e;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void Graph::VertexOutMap::Init(const Graph& g) {
|
|
104
|
+
edges_ = &g.edges();
|
|
105
|
+
edge_begins_.reserve(g.num_vertices() + 1);
|
|
106
|
+
EdgeId e = 0;
|
|
107
|
+
for (VertexId v = 0; v <= g.num_vertices(); ++v) {
|
|
108
|
+
while (e < g.num_edges() && g.edge(e).first < v) ++e;
|
|
109
|
+
edge_begins_.push_back(e);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void Graph::VertexInMap::Init(const Graph& g) {
|
|
114
|
+
in_edge_ids_ = g.GetInEdgeIds();
|
|
115
|
+
in_edge_begins_.reserve(g.num_vertices() + 1);
|
|
116
|
+
EdgeId e = 0;
|
|
117
|
+
for (VertexId v = 0; v <= g.num_vertices(); ++v) {
|
|
118
|
+
while (e < g.num_edges() && g.edge(in_edge_ids_[e]).second < v) ++e;
|
|
119
|
+
in_edge_begins_.push_back(e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void Graph::LabelFetcher::Init(const Graph& g, S2Builder::EdgeType edge_type) {
|
|
124
|
+
g_ = &g;
|
|
125
|
+
edge_type_ = edge_type;
|
|
126
|
+
if (edge_type == EdgeType::UNDIRECTED) sibling_map_ = g.GetSiblingMap();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
void Graph::LabelFetcher::Fetch(EdgeId e, vector<S2Builder::Label>* labels) {
|
|
130
|
+
labels->clear();
|
|
131
|
+
for (InputEdgeId input_edge_id : g_->input_edge_ids(e)) {
|
|
132
|
+
for (Label label : g_->labels(input_edge_id)) {
|
|
133
|
+
labels->push_back(label);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (edge_type_ == EdgeType::UNDIRECTED) {
|
|
137
|
+
for (InputEdgeId input_edge_id : g_->input_edge_ids(sibling_map_[e])) {
|
|
138
|
+
for (Label label : g_->labels(input_edge_id)) {
|
|
139
|
+
labels->push_back(label);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (labels->size() > 1) {
|
|
144
|
+
std::sort(labels->begin(), labels->end());
|
|
145
|
+
labels->erase(std::unique(labels->begin(), labels->end()), labels->end());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
S2Builder::InputEdgeId Graph::min_input_edge_id(EdgeId e) const {
|
|
150
|
+
IdSetLexicon::IdSet id_set = input_edge_ids(e);
|
|
151
|
+
return (id_set.size() == 0) ? kNoInputEdgeId : *id_set.begin();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
vector<S2Builder::InputEdgeId> Graph::GetMinInputEdgeIds() const {
|
|
155
|
+
vector<InputEdgeId> min_input_ids(num_edges());
|
|
156
|
+
for (EdgeId e = 0; e < num_edges(); ++e) {
|
|
157
|
+
min_input_ids[e] = min_input_edge_id(e);
|
|
158
|
+
}
|
|
159
|
+
return min_input_ids;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
vector<Graph::EdgeId> Graph::GetInputEdgeOrder(
|
|
163
|
+
const vector<InputEdgeId>& input_ids) const {
|
|
164
|
+
vector<EdgeId> order(input_ids.size());
|
|
165
|
+
std::iota(order.begin(), order.end(), 0);
|
|
166
|
+
std::sort(order.begin(), order.end(), [&input_ids](EdgeId a, EdgeId b) {
|
|
167
|
+
// Comparison function ensures sort is stable.
|
|
168
|
+
return make_pair(input_ids[a], a) < make_pair(input_ids[b], b);
|
|
169
|
+
});
|
|
170
|
+
return order;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// A struct for sorting the incoming and outgoing edges around a vertex "v0".
|
|
174
|
+
struct VertexEdge {
|
|
175
|
+
VertexEdge(bool _incoming, Graph::EdgeId _index,
|
|
176
|
+
Graph::VertexId _endpoint, int32 _rank)
|
|
177
|
+
: incoming(_incoming), index(_index),
|
|
178
|
+
endpoint(_endpoint), rank(_rank) {
|
|
179
|
+
}
|
|
180
|
+
bool incoming; // Is this an incoming edge to "v0"?
|
|
181
|
+
Graph::EdgeId index; // Index of this edge in "edges_" or "in_edge_ids"
|
|
182
|
+
Graph::VertexId endpoint; // The other (not "v0") endpoint of this edge
|
|
183
|
+
int32 rank; // Secondary key for edges with the same endpoint
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Given a set of duplicate outgoing edges (v0, v1) and a set of duplicate
|
|
187
|
+
// incoming edges (v1, v0), this method assigns each edge an integer "rank" so
|
|
188
|
+
// that the edges are sorted in a consistent order with respect to their
|
|
189
|
+
// orderings around "v0" and "v1". Usually there is just one edge, in which
|
|
190
|
+
// case this is easy. Sometimes there is one edge in each direction, in which
|
|
191
|
+
// case the outgoing edge is always ordered before the incoming edge.
|
|
192
|
+
//
|
|
193
|
+
// In general, we allow any number of duplicate edges in each direction, in
|
|
194
|
+
// which case outgoing edges are interleaved with incoming edges so as to
|
|
195
|
+
// create as many degenerate (two-edge) loops as possible. In order to get a
|
|
196
|
+
// consistent ordering around "v0" and "v1", we move forwards through the list
|
|
197
|
+
// of outgoing edges and backwards through the list of incoming edges. If
|
|
198
|
+
// there are more incoming edges, they go at the beginning of the ordering,
|
|
199
|
+
// while if there are more outgoing edges then they go at the end.
|
|
200
|
+
//
|
|
201
|
+
// For example, suppose there are 2 edges "a,b" from "v0" to "v1", and 4 edges
|
|
202
|
+
// "w,x,y,z" from "v1" to "v0". Using lower/upper case letters to represent
|
|
203
|
+
// incoming/outgoing edges, the clockwise ordering around v0 would be zyAxBw,
|
|
204
|
+
// and the clockwise ordering around v1 would be WbXaYZ. (Try making a
|
|
205
|
+
// diagram with each edge as a separate arc.)
|
|
206
|
+
static void AddVertexEdges(Graph::EdgeId out_begin, Graph::EdgeId out_end,
|
|
207
|
+
Graph::EdgeId in_begin, Graph::EdgeId in_end,
|
|
208
|
+
Graph::VertexId v1, vector<VertexEdge>* v0_edges) {
|
|
209
|
+
int rank = 0;
|
|
210
|
+
// Any extra incoming edges go at the beginning of the ordering.
|
|
211
|
+
while (in_end - in_begin > out_end - out_begin) {
|
|
212
|
+
v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
|
|
213
|
+
}
|
|
214
|
+
// Next we interleave as many outgoing and incoming edges as possible.
|
|
215
|
+
while (in_end > in_begin) {
|
|
216
|
+
v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
|
|
217
|
+
v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
|
|
218
|
+
}
|
|
219
|
+
// Any extra outgoing edges to at the end of the ordering.
|
|
220
|
+
while (out_end > out_begin) {
|
|
221
|
+
v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
bool Graph::GetLeftTurnMap(const vector<EdgeId>& in_edge_ids,
|
|
226
|
+
vector<EdgeId>* left_turn_map,
|
|
227
|
+
S2Error* error) const {
|
|
228
|
+
left_turn_map->assign(num_edges(), -1);
|
|
229
|
+
if (num_edges() == 0) return true;
|
|
230
|
+
|
|
231
|
+
// Declare vectors outside the loop to avoid reallocating them each time.
|
|
232
|
+
vector<VertexEdge> v0_edges;
|
|
233
|
+
vector<EdgeId> e_in, e_out;
|
|
234
|
+
|
|
235
|
+
// Walk through the two sorted arrays of edges (outgoing and incoming) and
|
|
236
|
+
// gather all the edges incident to each vertex. Then we sort those edges
|
|
237
|
+
// and add an entry to the left turn map from each incoming edge to the
|
|
238
|
+
// immediately following outgoing edge in clockwise order.
|
|
239
|
+
int out = 0, in = 0;
|
|
240
|
+
const Edge* out_edge = &edge(out);
|
|
241
|
+
const Edge* in_edge = &edge(in_edge_ids[in]);
|
|
242
|
+
Edge sentinel(num_vertices(), num_vertices());
|
|
243
|
+
Edge min_edge = min(*out_edge, reverse(*in_edge));
|
|
244
|
+
while (min_edge != sentinel) {
|
|
245
|
+
// Gather all incoming and outgoing edges around vertex "v0".
|
|
246
|
+
VertexId v0 = min_edge.first;
|
|
247
|
+
for (; min_edge.first == v0; min_edge = min(*out_edge, reverse(*in_edge))) {
|
|
248
|
+
VertexId v1 = min_edge.second;
|
|
249
|
+
// Count the number of copies of "min_edge" in each direction.
|
|
250
|
+
int out_begin = out, in_begin = in;
|
|
251
|
+
while (*out_edge == min_edge) {
|
|
252
|
+
out_edge = (++out == num_edges()) ? &sentinel : &edge(out);
|
|
253
|
+
}
|
|
254
|
+
while (reverse(*in_edge) == min_edge) {
|
|
255
|
+
in_edge = (++in == num_edges()) ? &sentinel : &edge(in_edge_ids[in]);
|
|
256
|
+
}
|
|
257
|
+
if (v0 != v1) {
|
|
258
|
+
AddVertexEdges(out_begin, out, in_begin, in, v1, &v0_edges);
|
|
259
|
+
} else {
|
|
260
|
+
// Each degenerate edge becomes its own loop.
|
|
261
|
+
for (; in_begin < in; ++in_begin) {
|
|
262
|
+
(*left_turn_map)[in_begin] = in_begin;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (v0_edges.empty()) continue;
|
|
267
|
+
|
|
268
|
+
// Sort the edges in clockwise order around "v0".
|
|
269
|
+
VertexId min_endpoint = v0_edges.front().endpoint;
|
|
270
|
+
std::sort(v0_edges.begin() + 1, v0_edges.end(),
|
|
271
|
+
[v0, min_endpoint, this](const VertexEdge& a,
|
|
272
|
+
const VertexEdge& b) {
|
|
273
|
+
if (a.endpoint == b.endpoint) return a.rank < b.rank;
|
|
274
|
+
if (a.endpoint == min_endpoint) return true;
|
|
275
|
+
if (b.endpoint == min_endpoint) return false;
|
|
276
|
+
return !s2pred::OrderedCCW(vertex(a.endpoint), vertex(b.endpoint),
|
|
277
|
+
vertex(min_endpoint), vertex(v0));
|
|
278
|
+
});
|
|
279
|
+
// Match incoming with outgoing edges. We do this by keeping a stack of
|
|
280
|
+
// unmatched incoming edges. We also keep a stack of outgoing edges with
|
|
281
|
+
// no previous incoming edge, and match these at the end by wrapping
|
|
282
|
+
// around circularly to the start of the edge ordering.
|
|
283
|
+
for (const VertexEdge& e : v0_edges) {
|
|
284
|
+
if (e.incoming) {
|
|
285
|
+
e_in.push_back(in_edge_ids[e.index]);
|
|
286
|
+
} else if (!e_in.empty()) {
|
|
287
|
+
(*left_turn_map)[e_in.back()] = e.index;
|
|
288
|
+
e_in.pop_back();
|
|
289
|
+
} else {
|
|
290
|
+
e_out.push_back(e.index); // Matched below.
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Pair up additional edges using the fact that the ordering is circular.
|
|
294
|
+
std::reverse(e_out.begin(), e_out.end());
|
|
295
|
+
for (; !e_out.empty() && !e_in.empty(); e_out.pop_back(), e_in.pop_back()) {
|
|
296
|
+
(*left_turn_map)[e_in.back()] = e_out.back();
|
|
297
|
+
}
|
|
298
|
+
// We only need to process unmatched incoming edges, since we are only
|
|
299
|
+
// responsible for creating left turn map entries for those edges.
|
|
300
|
+
if (!e_in.empty() && error->ok()) {
|
|
301
|
+
error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
|
|
302
|
+
"Given edges do not form loops (indegree != outdegree)");
|
|
303
|
+
}
|
|
304
|
+
e_in.clear();
|
|
305
|
+
e_out.clear();
|
|
306
|
+
v0_edges.clear();
|
|
307
|
+
}
|
|
308
|
+
return error->ok();
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void Graph::CanonicalizeLoopOrder(const vector<InputEdgeId>& min_input_ids,
|
|
312
|
+
vector<EdgeId>* loop) {
|
|
313
|
+
if (loop->empty()) return;
|
|
314
|
+
// Find the position of the element with the highest input edge id. If
|
|
315
|
+
// there are multiple such elements together (i.e., the edge was split
|
|
316
|
+
// into several pieces by snapping it to several vertices), then we choose
|
|
317
|
+
// the last such position in cyclic order (this attempts to preserve the
|
|
318
|
+
// original loop order even when new vertices are added). For example, if
|
|
319
|
+
// the input edge id sequence is (7, 7, 4, 5, 6, 7) then we would rotate
|
|
320
|
+
// it to obtain (4, 5, 6, 7, 7, 7).
|
|
321
|
+
|
|
322
|
+
// The reason that we put the highest-numbered edge last, rather than the
|
|
323
|
+
// lowest-numbered edge first, is that S2Loop::Invert() reverses the loop
|
|
324
|
+
// edge order *except* for the last edge. For example, the loop ABCD (with
|
|
325
|
+
// edges AB, BC, CD, DA) becomes DCBA (with edges DC, CB, BA, AD). Note
|
|
326
|
+
// that the last edge is the same except for its direction (DA vs. AD).
|
|
327
|
+
// This has the advantage that if an undirected loop is assembled with the
|
|
328
|
+
// wrong orientation and later inverted (e.g. by S2Polygon::InitOriented),
|
|
329
|
+
// we still end up preserving the original cyclic vertex order.
|
|
330
|
+
int pos = 0;
|
|
331
|
+
bool saw_gap = false;
|
|
332
|
+
for (int i = 1; i < loop->size(); ++i) {
|
|
333
|
+
int cmp = min_input_ids[(*loop)[i]] - min_input_ids[(*loop)[pos]];
|
|
334
|
+
if (cmp < 0) {
|
|
335
|
+
saw_gap = true;
|
|
336
|
+
} else if (cmp > 0 || !saw_gap) {
|
|
337
|
+
pos = i;
|
|
338
|
+
saw_gap = false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (++pos == loop->size()) pos = 0; // Convert loop end to loop start.
|
|
342
|
+
std::rotate(loop->begin(), loop->begin() + pos, loop->end());
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void Graph::CanonicalizeVectorOrder(const vector<InputEdgeId>& min_input_ids,
|
|
346
|
+
vector<vector<EdgeId>>* chains) {
|
|
347
|
+
std::sort(chains->begin(), chains->end(),
|
|
348
|
+
[&min_input_ids](const vector<EdgeId>& a, const vector<EdgeId>& b) {
|
|
349
|
+
return min_input_ids[a[0]] < min_input_ids[b[0]];
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
bool Graph::GetDirectedLoops(LoopType loop_type, vector<EdgeLoop>* loops,
|
|
354
|
+
S2Error* error) const {
|
|
355
|
+
S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
|
|
356
|
+
options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
|
|
357
|
+
S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);
|
|
358
|
+
|
|
359
|
+
vector<EdgeId> left_turn_map;
|
|
360
|
+
if (!GetLeftTurnMap(GetInEdgeIds(), &left_turn_map, error)) return false;
|
|
361
|
+
vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
|
|
362
|
+
|
|
363
|
+
// If we are breaking loops at repeated vertices, we maintain a map from
|
|
364
|
+
// VertexId to its position in "path".
|
|
365
|
+
vector<int> path_index;
|
|
366
|
+
if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
|
|
367
|
+
|
|
368
|
+
// Visit edges in arbitrary order, and try to build a loop from each edge.
|
|
369
|
+
vector<EdgeId> path;
|
|
370
|
+
for (EdgeId start = 0; start < num_edges(); ++start) {
|
|
371
|
+
if (left_turn_map[start] < 0) continue;
|
|
372
|
+
|
|
373
|
+
// Build a loop by making left turns at each vertex until we return to
|
|
374
|
+
// "start". We use "left_turn_map" to keep track of which edges have
|
|
375
|
+
// already been visited by setting its entries to -1 as we go along. If
|
|
376
|
+
// we are building vertex cycles, then whenever we encounter a vertex that
|
|
377
|
+
// is already part of the path, we "peel off" a loop by removing those
|
|
378
|
+
// edges from the path so far.
|
|
379
|
+
for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
|
|
380
|
+
path.push_back(e);
|
|
381
|
+
next = left_turn_map[e];
|
|
382
|
+
left_turn_map[e] = -1;
|
|
383
|
+
if (loop_type == LoopType::SIMPLE) {
|
|
384
|
+
path_index[edge(e).first] = path.size() - 1;
|
|
385
|
+
int loop_start = path_index[edge(e).second];
|
|
386
|
+
if (loop_start < 0) continue;
|
|
387
|
+
// Peel off a loop from the path.
|
|
388
|
+
vector<EdgeId> loop(path.begin() + loop_start, path.end());
|
|
389
|
+
path.erase(path.begin() + loop_start, path.end());
|
|
390
|
+
for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
|
|
391
|
+
CanonicalizeLoopOrder(min_input_ids, &loop);
|
|
392
|
+
loops->push_back(std::move(loop));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (loop_type == LoopType::SIMPLE) {
|
|
396
|
+
S2_DCHECK(path.empty()); // Invariant.
|
|
397
|
+
} else {
|
|
398
|
+
CanonicalizeLoopOrder(min_input_ids, &path);
|
|
399
|
+
loops->push_back(std::move(path));
|
|
400
|
+
path.clear();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
CanonicalizeVectorOrder(min_input_ids, loops);
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
bool Graph::GetDirectedComponents(
|
|
408
|
+
DegenerateBoundaries degenerate_boundaries,
|
|
409
|
+
vector<DirectedComponent>* components, S2Error* error) const {
|
|
410
|
+
S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
|
|
411
|
+
(options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
|
|
412
|
+
degenerate_boundaries == DegenerateBoundaries::KEEP));
|
|
413
|
+
S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
|
|
414
|
+
options_.sibling_pairs() == SiblingPairs::CREATE);
|
|
415
|
+
S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED); // Implied by above.
|
|
416
|
+
|
|
417
|
+
vector<EdgeId> sibling_map = GetInEdgeIds();
|
|
418
|
+
vector<EdgeId> left_turn_map;
|
|
419
|
+
if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
|
|
420
|
+
MakeSiblingMap(&sibling_map);
|
|
421
|
+
vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
|
|
422
|
+
vector<EdgeId> frontier; // Unexplored sibling edges.
|
|
423
|
+
|
|
424
|
+
// A map from EdgeId to the position of that edge in "path". Only needed if
|
|
425
|
+
// degenerate boundaries are being discarded.
|
|
426
|
+
vector<int> path_index;
|
|
427
|
+
if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
|
|
428
|
+
path_index.assign(num_edges(), -1);
|
|
429
|
+
}
|
|
430
|
+
for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
|
|
431
|
+
if (left_turn_map[min_start] < 0) continue; // Already used.
|
|
432
|
+
|
|
433
|
+
// Build a connected component by keeping a stack of unexplored siblings
|
|
434
|
+
// of the edges used so far.
|
|
435
|
+
DirectedComponent component;
|
|
436
|
+
frontier.push_back(min_start);
|
|
437
|
+
while (!frontier.empty()) {
|
|
438
|
+
EdgeId start = frontier.back();
|
|
439
|
+
frontier.pop_back();
|
|
440
|
+
if (left_turn_map[start] < 0) continue; // Already used.
|
|
441
|
+
|
|
442
|
+
// Build a path by making left turns at each vertex until we return to
|
|
443
|
+
// "start". Whenever we encounter an edge that is a sibling of an edge
|
|
444
|
+
// that is already on the path, we "peel off" a loop consisting of any
|
|
445
|
+
// edges that were between these two edges.
|
|
446
|
+
vector<EdgeId> path;
|
|
447
|
+
for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
|
|
448
|
+
path.push_back(e);
|
|
449
|
+
next = left_turn_map[e];
|
|
450
|
+
left_turn_map[e] = -1;
|
|
451
|
+
// If the sibling hasn't been visited yet, add it to the frontier.
|
|
452
|
+
EdgeId sibling = sibling_map[e];
|
|
453
|
+
if (left_turn_map[sibling] >= 0) {
|
|
454
|
+
frontier.push_back(sibling);
|
|
455
|
+
}
|
|
456
|
+
if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
|
|
457
|
+
path_index[e] = path.size() - 1;
|
|
458
|
+
int sibling_index = path_index[sibling];
|
|
459
|
+
if (sibling_index < 0) continue;
|
|
460
|
+
|
|
461
|
+
// Common special case: the edge and its sibling are adjacent, in
|
|
462
|
+
// which case we can simply remove them from the path and continue.
|
|
463
|
+
if (sibling_index == path.size() - 2) {
|
|
464
|
+
path.resize(sibling_index);
|
|
465
|
+
// We don't need to update "path_index" for these two edges
|
|
466
|
+
// because both edges of the sibling pair have now been used.
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
// Peel off a loop from the path.
|
|
470
|
+
vector<EdgeId> loop(path.begin() + sibling_index + 1, path.end() - 1);
|
|
471
|
+
path.erase(path.begin() + sibling_index, path.end());
|
|
472
|
+
// Mark the edges that are no longer part of the path.
|
|
473
|
+
for (EdgeId e2 : loop) path_index[e2] = -1;
|
|
474
|
+
CanonicalizeLoopOrder(min_input_ids, &loop);
|
|
475
|
+
component.push_back(std::move(loop));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// Mark the edges that are no longer part of the path.
|
|
479
|
+
if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
|
|
480
|
+
for (EdgeId e2 : path) path_index[e2] = -1;
|
|
481
|
+
}
|
|
482
|
+
CanonicalizeLoopOrder(min_input_ids, &path);
|
|
483
|
+
component.push_back(std::move(path));
|
|
484
|
+
}
|
|
485
|
+
CanonicalizeVectorOrder(min_input_ids, &component);
|
|
486
|
+
components->push_back(std::move(component));
|
|
487
|
+
}
|
|
488
|
+
// Sort the components to correspond to the input edge ordering.
|
|
489
|
+
std::sort(components->begin(), components->end(),
|
|
490
|
+
[&min_input_ids](const DirectedComponent& a,
|
|
491
|
+
const DirectedComponent& b) {
|
|
492
|
+
return min_input_ids[a[0][0]] < min_input_ids[b[0][0]];
|
|
493
|
+
});
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Encodes the index of one of the two complements of each component
|
|
498
|
+
// (a.k.a. the "slot", either 0 or 1) as a negative EdgeId.
|
|
499
|
+
inline static Graph::EdgeId MarkEdgeUsed(int slot) { return -1 - slot; }
|
|
500
|
+
|
|
501
|
+
bool Graph::GetUndirectedComponents(LoopType loop_type,
|
|
502
|
+
vector<UndirectedComponent>* components,
|
|
503
|
+
S2Error* error) const {
|
|
504
|
+
S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
|
|
505
|
+
options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
|
|
506
|
+
S2_DCHECK(options_.edge_type() == EdgeType::UNDIRECTED);
|
|
507
|
+
|
|
508
|
+
vector<EdgeId> sibling_map = GetInEdgeIds();
|
|
509
|
+
vector<EdgeId> left_turn_map;
|
|
510
|
+
if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
|
|
511
|
+
MakeSiblingMap(&sibling_map);
|
|
512
|
+
vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
|
|
513
|
+
|
|
514
|
+
// A stack of unexplored sibling edges. Each sibling edge has a "slot"
|
|
515
|
+
// (0 or 1) that indicates which of the two complements it belongs to.
|
|
516
|
+
vector<pair<EdgeId, int>> frontier;
|
|
517
|
+
|
|
518
|
+
// If we are breaking loops at repeated vertices, we maintain a map from
|
|
519
|
+
// VertexId to its position in "path".
|
|
520
|
+
vector<int> path_index;
|
|
521
|
+
if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
|
|
522
|
+
|
|
523
|
+
for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
|
|
524
|
+
if (left_turn_map[min_start] < 0) continue; // Already used.
|
|
525
|
+
|
|
526
|
+
// Build a connected component by keeping a stack of unexplored siblings
|
|
527
|
+
// of the edges used so far.
|
|
528
|
+
UndirectedComponent component;
|
|
529
|
+
frontier.push_back(make_pair(min_start, 0));
|
|
530
|
+
while (!frontier.empty()) {
|
|
531
|
+
EdgeId start = frontier.back().first;
|
|
532
|
+
int slot = frontier.back().second;
|
|
533
|
+
frontier.pop_back();
|
|
534
|
+
if (left_turn_map[start] < 0) continue; // Already used.
|
|
535
|
+
|
|
536
|
+
// Build a path by making left turns at each vertex until we return to
|
|
537
|
+
// "start". We use "left_turn_map" to keep track of which edges have
|
|
538
|
+
// already been visited, and which complement they were assigned to, by
|
|
539
|
+
// setting its entries to negative values as we go along.
|
|
540
|
+
vector<EdgeId> path;
|
|
541
|
+
for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
|
|
542
|
+
path.push_back(e);
|
|
543
|
+
next = left_turn_map[e];
|
|
544
|
+
left_turn_map[e] = MarkEdgeUsed(slot);
|
|
545
|
+
// If the sibling hasn't been visited yet, add it to the frontier.
|
|
546
|
+
EdgeId sibling = sibling_map[e];
|
|
547
|
+
if (left_turn_map[sibling] >= 0) {
|
|
548
|
+
frontier.push_back(make_pair(sibling, 1 - slot));
|
|
549
|
+
} else if (left_turn_map[sibling] != MarkEdgeUsed(1 - slot)) {
|
|
550
|
+
// Two siblings edges can only belong the same complement if the
|
|
551
|
+
// given undirected edges do not form loops.
|
|
552
|
+
error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
|
|
553
|
+
"Given undirected edges do not form loops");
|
|
554
|
+
return false;
|
|
555
|
+
}
|
|
556
|
+
if (loop_type == LoopType::SIMPLE) {
|
|
557
|
+
// Whenever we encounter a vertex that is already part of the path,
|
|
558
|
+
// we "peel off" a loop by removing those edges from the path.
|
|
559
|
+
path_index[edge(e).first] = path.size() - 1;
|
|
560
|
+
int loop_start = path_index[edge(e).second];
|
|
561
|
+
if (loop_start < 0) continue;
|
|
562
|
+
vector<EdgeId> loop(path.begin() + loop_start, path.end());
|
|
563
|
+
path.erase(path.begin() + loop_start, path.end());
|
|
564
|
+
// Mark the vertices that are no longer part of the path.
|
|
565
|
+
for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
|
|
566
|
+
CanonicalizeLoopOrder(min_input_ids, &loop);
|
|
567
|
+
component[slot].push_back(std::move(loop));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (loop_type == LoopType::SIMPLE) {
|
|
571
|
+
S2_DCHECK(path.empty()); // Invariant.
|
|
572
|
+
} else {
|
|
573
|
+
CanonicalizeLoopOrder(min_input_ids, &path);
|
|
574
|
+
component[slot].push_back(std::move(path));
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
CanonicalizeVectorOrder(min_input_ids, &component[0]);
|
|
578
|
+
CanonicalizeVectorOrder(min_input_ids, &component[1]);
|
|
579
|
+
// To save some work in S2PolygonLayer, we swap the two loop sets of the
|
|
580
|
+
// component so that the loop set whose first loop most closely follows
|
|
581
|
+
// the input edge ordering is first. (If the input was a valid S2Polygon,
|
|
582
|
+
// then this component will contain normalized loops.)
|
|
583
|
+
if (min_input_ids[component[0][0][0]] > min_input_ids[component[1][0][0]]) {
|
|
584
|
+
component[0].swap(component[1]);
|
|
585
|
+
}
|
|
586
|
+
components->push_back(std::move(component));
|
|
587
|
+
}
|
|
588
|
+
// Sort the components to correspond to the input edge ordering.
|
|
589
|
+
std::sort(components->begin(), components->end(),
|
|
590
|
+
[&min_input_ids](const UndirectedComponent& a,
|
|
591
|
+
const UndirectedComponent& b) {
|
|
592
|
+
return min_input_ids[a[0][0][0]] < min_input_ids[b[0][0][0]];
|
|
593
|
+
});
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
class Graph::PolylineBuilder {
|
|
598
|
+
public:
|
|
599
|
+
explicit PolylineBuilder(const Graph& g);
|
|
600
|
+
vector<EdgePolyline> BuildPaths();
|
|
601
|
+
vector<EdgePolyline> BuildWalks();
|
|
602
|
+
|
|
603
|
+
private:
|
|
604
|
+
bool is_interior(VertexId v);
|
|
605
|
+
int excess_degree(VertexId v);
|
|
606
|
+
EdgePolyline BuildPath(EdgeId e);
|
|
607
|
+
EdgePolyline BuildWalk(VertexId v);
|
|
608
|
+
void MaximizeWalk(EdgePolyline* polyline);
|
|
609
|
+
|
|
610
|
+
const Graph& g_;
|
|
611
|
+
Graph::VertexInMap in_;
|
|
612
|
+
Graph::VertexOutMap out_;
|
|
613
|
+
vector<EdgeId> sibling_map_;
|
|
614
|
+
vector<InputEdgeId> min_input_ids_;
|
|
615
|
+
bool directed_;
|
|
616
|
+
int edges_left_;
|
|
617
|
+
vector<bool> used_;
|
|
618
|
+
// A map of (outdegree(v) - indegree(v)) considering used edges only.
|
|
619
|
+
gtl::btree_map<VertexId, int> excess_used_;
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
vector<Graph::EdgePolyline> Graph::GetPolylines(
|
|
623
|
+
PolylineType polyline_type) const {
|
|
624
|
+
S2_DCHECK(options_.sibling_pairs() == SiblingPairs::DISCARD ||
|
|
625
|
+
options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS ||
|
|
626
|
+
options_.sibling_pairs() == SiblingPairs::KEEP);
|
|
627
|
+
PolylineBuilder builder(*this);
|
|
628
|
+
if (polyline_type == PolylineType::PATH) {
|
|
629
|
+
return builder.BuildPaths();
|
|
630
|
+
} else {
|
|
631
|
+
return builder.BuildWalks();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
Graph::PolylineBuilder::PolylineBuilder(const Graph& g)
|
|
636
|
+
: g_(g), in_(g), out_(g),
|
|
637
|
+
min_input_ids_(g.GetMinInputEdgeIds()),
|
|
638
|
+
directed_(g_.options().edge_type() == EdgeType::DIRECTED),
|
|
639
|
+
edges_left_(g.num_edges() / (directed_ ? 1 : 2)),
|
|
640
|
+
used_(g.num_edges(), false) {
|
|
641
|
+
if (!directed_) {
|
|
642
|
+
sibling_map_ = in_.in_edge_ids();
|
|
643
|
+
g.MakeSiblingMap(&sibling_map_);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
inline bool Graph::PolylineBuilder::is_interior(VertexId v) {
|
|
648
|
+
if (directed_) {
|
|
649
|
+
return in_.degree(v) == 1 && out_.degree(v) == 1;
|
|
650
|
+
} else {
|
|
651
|
+
return out_.degree(v) == 2;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
inline int Graph::PolylineBuilder::excess_degree(VertexId v) {
|
|
656
|
+
return directed_ ? out_.degree(v) - in_.degree(v) : out_.degree(v) % 2;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildPaths() {
|
|
660
|
+
// First build polylines starting at all the vertices that cannot be in the
|
|
661
|
+
// polyline interior (i.e., indegree != 1 or outdegree != 1 for directed
|
|
662
|
+
// edges, or degree != 2 for undirected edges). We consider the possible
|
|
663
|
+
// starting edges in input edge id order so that we preserve the input path
|
|
664
|
+
// direction even when undirected edges are used. (Undirected edges are
|
|
665
|
+
// represented by sibling pairs where only the edge in the input direction
|
|
666
|
+
// is labeled with an input edge id.)
|
|
667
|
+
vector<EdgePolyline> polylines;
|
|
668
|
+
vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
|
|
669
|
+
for (EdgeId e : edges) {
|
|
670
|
+
if (!used_[e] && !is_interior(g_.edge(e).first)) {
|
|
671
|
+
polylines.push_back(BuildPath(e));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// If there are any edges left, they form non-intersecting loops. We build
|
|
675
|
+
// each loop and then canonicalize its edge order. We consider candidate
|
|
676
|
+
// starting edges in input edge id order in order to preserve the input
|
|
677
|
+
// direction of undirected loops. Even so, we still need to canonicalize
|
|
678
|
+
// the edge order to ensure that when an input edge is split into an edge
|
|
679
|
+
// chain, the loop does not start in the middle of such a chain.
|
|
680
|
+
for (EdgeId e : edges) {
|
|
681
|
+
if (edges_left_ == 0) break;
|
|
682
|
+
if (used_[e]) continue;
|
|
683
|
+
EdgePolyline polyline = BuildPath(e);
|
|
684
|
+
CanonicalizeLoopOrder(min_input_ids_, &polyline);
|
|
685
|
+
polylines.push_back(std::move(polyline));
|
|
686
|
+
}
|
|
687
|
+
S2_DCHECK_EQ(0, edges_left_);
|
|
688
|
+
|
|
689
|
+
// Sort the polylines to correspond to the input order (if possible).
|
|
690
|
+
CanonicalizeVectorOrder(min_input_ids_, &polylines);
|
|
691
|
+
return polylines;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
Graph::EdgePolyline Graph::PolylineBuilder::BuildPath(EdgeId e) {
|
|
695
|
+
// We simply follow edges until either we reach a vertex where there is a
|
|
696
|
+
// choice about which way to go (where is_interior(v) is false), or we
|
|
697
|
+
// return to the starting vertex (if the polyline is actually a loop).
|
|
698
|
+
EdgePolyline polyline;
|
|
699
|
+
VertexId start = g_.edge(e).first;
|
|
700
|
+
for (;;) {
|
|
701
|
+
polyline.push_back(e);
|
|
702
|
+
S2_DCHECK(!used_[e]);
|
|
703
|
+
used_[e] = true;
|
|
704
|
+
if (!directed_) used_[sibling_map_[e]] = true;
|
|
705
|
+
--edges_left_;
|
|
706
|
+
VertexId v = g_.edge(e).second;
|
|
707
|
+
if (!is_interior(v) || v == start) break;
|
|
708
|
+
if (directed_) {
|
|
709
|
+
S2_DCHECK_EQ(1, out_.degree(v));
|
|
710
|
+
e = *out_.edge_ids(v).begin();
|
|
711
|
+
} else {
|
|
712
|
+
S2_DCHECK_EQ(2, out_.degree(v));
|
|
713
|
+
for (EdgeId e2 : out_.edge_ids(v)) if (!used_[e2]) e = e2;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return polyline;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildWalks() {
|
|
720
|
+
// Note that some of this code is worst-case quadratic in the maximum vertex
|
|
721
|
+
// degree. This could be fixed with a few extra arrays, but it should not
|
|
722
|
+
// be a problem in practice.
|
|
723
|
+
|
|
724
|
+
// First, build polylines from all vertices where outdegree > indegree (or
|
|
725
|
+
// for undirected edges, vertices whose degree is odd). We consider the
|
|
726
|
+
// possible starting edges in input edge id order, for idempotency in the
|
|
727
|
+
// case where multiple input polylines share vertices or edges.
|
|
728
|
+
vector<EdgePolyline> polylines;
|
|
729
|
+
vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
|
|
730
|
+
for (EdgeId e : edges) {
|
|
731
|
+
if (used_[e]) continue;
|
|
732
|
+
VertexId v = g_.edge(e).first;
|
|
733
|
+
int excess = excess_degree(v);
|
|
734
|
+
if (excess <= 0) continue;
|
|
735
|
+
excess -= excess_used_[v];
|
|
736
|
+
if (directed_ ? (excess <= 0) : (excess % 2 == 0)) continue;
|
|
737
|
+
++excess_used_[v];
|
|
738
|
+
polylines.push_back(BuildWalk(v));
|
|
739
|
+
--excess_used_[g_.edge(polylines.back().back()).second];
|
|
740
|
+
}
|
|
741
|
+
// Now all vertices have outdegree == indegree (or even degree if undirected
|
|
742
|
+
// edges are being used). Therefore all remaining edges can be assembled
|
|
743
|
+
// into loops. We first try to expand the existing polylines if possible by
|
|
744
|
+
// adding loops to them.
|
|
745
|
+
if (edges_left_ > 0) {
|
|
746
|
+
for (EdgePolyline& polyline : polylines) {
|
|
747
|
+
MaximizeWalk(&polyline);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// Finally, if there are still unused edges then we build loops. If the
|
|
751
|
+
// input is a polyline that forms a loop, then for idempotency we need to
|
|
752
|
+
// start from the edge with minimum input edge id. If the minimal input
|
|
753
|
+
// edge was split into several edges, then we start from the first edge of
|
|
754
|
+
// the chain.
|
|
755
|
+
for (int i = 0; i < edges.size() && edges_left_ > 0; ++i) {
|
|
756
|
+
EdgeId e = edges[i];
|
|
757
|
+
if (used_[e]) continue;
|
|
758
|
+
|
|
759
|
+
// Determine whether the origin of this edge is the start of an edge
|
|
760
|
+
// chain. To do this, we test whether (outdegree - indegree == 1) for the
|
|
761
|
+
// origin, considering only unused edges with the same minimum input edge
|
|
762
|
+
// id. (Undirected edges have input edge ids in one direction only.)
|
|
763
|
+
VertexId v = g_.edge(e).first;
|
|
764
|
+
InputEdgeId id = min_input_ids_[e];
|
|
765
|
+
int excess = 0;
|
|
766
|
+
for (int j = i; j < edges.size() && min_input_ids_[edges[j]] == id; ++j) {
|
|
767
|
+
EdgeId e2 = edges[j];
|
|
768
|
+
if (used_[e2]) continue;
|
|
769
|
+
if (g_.edge(e2).first == v) ++excess;
|
|
770
|
+
if (g_.edge(e2).second == v) --excess;
|
|
771
|
+
}
|
|
772
|
+
// It is also acceptable to start a polyline from any degenerate edge.
|
|
773
|
+
if (excess == 1 || g_.edge(e).second == v) {
|
|
774
|
+
EdgePolyline polyline = BuildWalk(v);
|
|
775
|
+
MaximizeWalk(&polyline);
|
|
776
|
+
polylines.push_back(std::move(polyline));
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
S2_DCHECK_EQ(0, edges_left_);
|
|
780
|
+
|
|
781
|
+
// Sort the polylines to correspond to the input order (if possible).
|
|
782
|
+
CanonicalizeVectorOrder(min_input_ids_, &polylines);
|
|
783
|
+
return polylines;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
Graph::EdgePolyline Graph::PolylineBuilder::BuildWalk(VertexId v) {
|
|
787
|
+
EdgePolyline polyline;
|
|
788
|
+
for (;;) {
|
|
789
|
+
// Follow the edge with the smallest input edge id.
|
|
790
|
+
EdgeId best_edge = -1;
|
|
791
|
+
InputEdgeId best_out_id = std::numeric_limits<InputEdgeId>::max();
|
|
792
|
+
for (EdgeId e : out_.edge_ids(v)) {
|
|
793
|
+
if (used_[e] || min_input_ids_[e] >= best_out_id) continue;
|
|
794
|
+
best_out_id = min_input_ids_[e];
|
|
795
|
+
best_edge = e;
|
|
796
|
+
}
|
|
797
|
+
if (best_edge < 0) return polyline;
|
|
798
|
+
// For idempotency when there are multiple input polylines, we stop the
|
|
799
|
+
// walk early if "best_edge" might be a continuation of a different
|
|
800
|
+
// incoming edge.
|
|
801
|
+
int excess = excess_degree(v) - excess_used_[v];
|
|
802
|
+
if (directed_ ? (excess < 0) : (excess % 2) == 1) {
|
|
803
|
+
for (EdgeId e : in_.edge_ids(v)) {
|
|
804
|
+
if (!used_[e] && min_input_ids_[e] <= best_out_id) {
|
|
805
|
+
return polyline;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
polyline.push_back(best_edge);
|
|
810
|
+
used_[best_edge] = true;
|
|
811
|
+
if (!directed_) used_[sibling_map_[best_edge]] = true;
|
|
812
|
+
--edges_left_;
|
|
813
|
+
v = g_.edge(best_edge).second;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
void Graph::PolylineBuilder::MaximizeWalk(EdgePolyline* polyline) {
|
|
818
|
+
// Examine all vertices of the polyline and check whether there are any
|
|
819
|
+
// unused outgoing edges. If so, then build a loop starting at that vertex
|
|
820
|
+
// and insert it into the polyline. (The walk is guaranteed to be a loop
|
|
821
|
+
// because this method is only called when all vertices have equal numbers
|
|
822
|
+
// of unused incoming and outgoing edges.)
|
|
823
|
+
for (int i = 0; i <= polyline->size(); ++i) {
|
|
824
|
+
VertexId v = (i == 0 ? g_.edge((*polyline)[i]).first
|
|
825
|
+
: g_.edge((*polyline)[i - 1]).second);
|
|
826
|
+
for (EdgeId e : out_.edge_ids(v)) {
|
|
827
|
+
if (!used_[e]) {
|
|
828
|
+
EdgePolyline loop = BuildWalk(v);
|
|
829
|
+
S2_DCHECK_EQ(v, g_.edge(loop.back()).second);
|
|
830
|
+
polyline->insert(polyline->begin() + i, loop.begin(), loop.end());
|
|
831
|
+
S2_DCHECK(used_[e]); // All outgoing edges from "v" are now used.
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
class Graph::EdgeProcessor {
|
|
839
|
+
public:
|
|
840
|
+
EdgeProcessor(const GraphOptions& options,
|
|
841
|
+
vector<Edge>* edges,
|
|
842
|
+
vector<InputEdgeIdSetId>* input_ids,
|
|
843
|
+
IdSetLexicon* id_set_lexicon);
|
|
844
|
+
void Run(S2Error* error);
|
|
845
|
+
|
|
846
|
+
private:
|
|
847
|
+
void AddEdge(const Edge& edge, InputEdgeIdSetId input_edge_id_set_id);
|
|
848
|
+
void AddEdges(int num_edges, const Edge& edge,
|
|
849
|
+
InputEdgeIdSetId input_edge_id_set_id);
|
|
850
|
+
void CopyEdges(int out_begin, int out_end);
|
|
851
|
+
InputEdgeIdSetId MergeInputIds(int out_begin, int out_end);
|
|
852
|
+
|
|
853
|
+
GraphOptions options_;
|
|
854
|
+
vector<Edge>& edges_;
|
|
855
|
+
vector<InputEdgeIdSetId>& input_ids_;
|
|
856
|
+
IdSetLexicon* id_set_lexicon_;
|
|
857
|
+
vector<EdgeId> out_edges_;
|
|
858
|
+
vector<EdgeId> in_edges_;
|
|
859
|
+
|
|
860
|
+
vector<Edge> new_edges_;
|
|
861
|
+
vector<InputEdgeIdSetId> new_input_ids_;
|
|
862
|
+
|
|
863
|
+
vector<InputEdgeId> tmp_ids_;
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
void Graph::ProcessEdges(
|
|
867
|
+
GraphOptions* options, std::vector<Edge>* edges,
|
|
868
|
+
std::vector<InputEdgeIdSetId>* input_ids, IdSetLexicon* id_set_lexicon,
|
|
869
|
+
S2Error* error) {
|
|
870
|
+
EdgeProcessor processor(*options, edges, input_ids, id_set_lexicon);
|
|
871
|
+
processor.Run(error);
|
|
872
|
+
// Certain values of sibling_pairs() discard half of the edges and change
|
|
873
|
+
// the edge_type() to DIRECTED (see the description of GraphOptions).
|
|
874
|
+
if (options->sibling_pairs() == SiblingPairs::REQUIRE ||
|
|
875
|
+
options->sibling_pairs() == SiblingPairs::CREATE) {
|
|
876
|
+
options->set_edge_type(EdgeType::DIRECTED);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
Graph::EdgeProcessor::EdgeProcessor(const GraphOptions& options,
|
|
881
|
+
vector<Edge>* edges,
|
|
882
|
+
vector<InputEdgeIdSetId>* input_ids,
|
|
883
|
+
IdSetLexicon* id_set_lexicon)
|
|
884
|
+
: options_(options), edges_(*edges),
|
|
885
|
+
input_ids_(*input_ids), id_set_lexicon_(id_set_lexicon),
|
|
886
|
+
out_edges_(edges_.size()), in_edges_(edges_.size()) {
|
|
887
|
+
// Sort the outgoing and incoming edges in lexigraphic order. We use a
|
|
888
|
+
// stable sort to ensure that each undirected edge becomes a sibling pair,
|
|
889
|
+
// even if there are multiple identical input edges.
|
|
890
|
+
std::iota(out_edges_.begin(), out_edges_.end(), 0);
|
|
891
|
+
std::sort(out_edges_.begin(), out_edges_.end(), [this](EdgeId a, EdgeId b) {
|
|
892
|
+
return StableLessThan(edges_[a], edges_[b], a, b);
|
|
893
|
+
});
|
|
894
|
+
std::iota(in_edges_.begin(), in_edges_.end(), 0);
|
|
895
|
+
std::sort(in_edges_.begin(), in_edges_.end(), [this](EdgeId a, EdgeId b) {
|
|
896
|
+
return StableLessThan(reverse(edges_[a]), reverse(edges_[b]), a, b);
|
|
897
|
+
});
|
|
898
|
+
new_edges_.reserve(edges_.size());
|
|
899
|
+
new_input_ids_.reserve(edges_.size());
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
inline void Graph::EdgeProcessor::AddEdge(
|
|
903
|
+
const Edge& edge, InputEdgeIdSetId input_edge_id_set_id) {
|
|
904
|
+
new_edges_.push_back(edge);
|
|
905
|
+
new_input_ids_.push_back(input_edge_id_set_id);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
void Graph::EdgeProcessor::AddEdges(int num_edges, const Edge& edge,
|
|
909
|
+
InputEdgeIdSetId input_edge_id_set_id) {
|
|
910
|
+
for (int i = 0; i < num_edges; ++i) {
|
|
911
|
+
AddEdge(edge, input_edge_id_set_id);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
void Graph::EdgeProcessor::CopyEdges(int out_begin, int out_end) {
|
|
916
|
+
for (int i = out_begin; i < out_end; ++i) {
|
|
917
|
+
AddEdge(edges_[out_edges_[i]], input_ids_[out_edges_[i]]);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
S2Builder::InputEdgeIdSetId Graph::EdgeProcessor::MergeInputIds(
|
|
922
|
+
int out_begin, int out_end) {
|
|
923
|
+
if (out_end - out_begin == 1) {
|
|
924
|
+
return input_ids_[out_edges_[out_begin]];
|
|
925
|
+
}
|
|
926
|
+
tmp_ids_.clear();
|
|
927
|
+
for (int i = out_begin; i < out_end; ++i) {
|
|
928
|
+
for (auto id : id_set_lexicon_->id_set(input_ids_[out_edges_[i]])) {
|
|
929
|
+
tmp_ids_.push_back(id);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return id_set_lexicon_->Add(tmp_ids_);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
void Graph::EdgeProcessor::Run(S2Error* error) {
|
|
936
|
+
int num_edges = edges_.size();
|
|
937
|
+
if (num_edges == 0) return;
|
|
938
|
+
|
|
939
|
+
// Walk through the two sorted arrays performing a merge join. For each
|
|
940
|
+
// edge, gather all the duplicate copies of the edge in both directions
|
|
941
|
+
// (outgoing and incoming). Then decide what to do based on "options_" and
|
|
942
|
+
// how many copies of the edge there are in each direction.
|
|
943
|
+
int out = 0, in = 0;
|
|
944
|
+
const Edge* out_edge = &edges_[out_edges_[out]];
|
|
945
|
+
const Edge* in_edge = &edges_[in_edges_[in]];
|
|
946
|
+
Edge sentinel(std::numeric_limits<VertexId>::max(),
|
|
947
|
+
std::numeric_limits<VertexId>::max());
|
|
948
|
+
for (;;) {
|
|
949
|
+
Edge edge = min(*out_edge, reverse(*in_edge));
|
|
950
|
+
if (edge == sentinel) break;
|
|
951
|
+
|
|
952
|
+
int out_begin = out, in_begin = in;
|
|
953
|
+
while (*out_edge == edge) {
|
|
954
|
+
out_edge = (++out == num_edges) ? &sentinel : &edges_[out_edges_[out]];
|
|
955
|
+
}
|
|
956
|
+
while (reverse(*in_edge) == edge) {
|
|
957
|
+
in_edge = (++in == num_edges) ? &sentinel : &edges_[in_edges_[in]];
|
|
958
|
+
}
|
|
959
|
+
int n_out = out - out_begin;
|
|
960
|
+
int n_in = in - in_begin;
|
|
961
|
+
if (edge.first == edge.second) {
|
|
962
|
+
S2_DCHECK_EQ(n_out, n_in);
|
|
963
|
+
if (options_.degenerate_edges() == DegenerateEdges::DISCARD) {
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
if (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
|
|
967
|
+
((out_begin > 0 &&
|
|
968
|
+
edges_[out_edges_[out_begin - 1]].first == edge.first) ||
|
|
969
|
+
(out < num_edges && edges_[out_edges_[out]].first == edge.first) ||
|
|
970
|
+
(in_begin > 0 &&
|
|
971
|
+
edges_[in_edges_[in_begin - 1]].second == edge.first) ||
|
|
972
|
+
(in < num_edges && edges_[in_edges_[in]].second == edge.first))) {
|
|
973
|
+
continue; // There were non-degenerate incident edges, so discard.
|
|
974
|
+
}
|
|
975
|
+
if (options_.edge_type() == EdgeType::UNDIRECTED &&
|
|
976
|
+
(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
|
|
977
|
+
options_.sibling_pairs() == SiblingPairs::CREATE)) {
|
|
978
|
+
// When we have undirected edges and are guaranteed to have siblings,
|
|
979
|
+
// we cut the number of edges in half (see s2builder.h).
|
|
980
|
+
S2_DCHECK_EQ(0, n_out & 1); // Number of edges is always even.
|
|
981
|
+
AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
|
|
982
|
+
1 : (n_out / 2), edge, MergeInputIds(out_begin, out));
|
|
983
|
+
} else if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
|
|
984
|
+
AddEdges(options_.edge_type() == EdgeType::UNDIRECTED ? 2 : 1,
|
|
985
|
+
edge, MergeInputIds(out_begin, out));
|
|
986
|
+
} else if (options_.sibling_pairs() == SiblingPairs::DISCARD ||
|
|
987
|
+
options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
|
|
988
|
+
// Any SiblingPair option that discards edges causes the labels of all
|
|
989
|
+
// duplicate edges to be merged together (see s2builder.h).
|
|
990
|
+
AddEdges(n_out, edge, MergeInputIds(out_begin, out));
|
|
991
|
+
} else {
|
|
992
|
+
CopyEdges(out_begin, out);
|
|
993
|
+
}
|
|
994
|
+
} else if (options_.sibling_pairs() == SiblingPairs::KEEP) {
|
|
995
|
+
if (n_out > 1 && options_.duplicate_edges() == DuplicateEdges::MERGE) {
|
|
996
|
+
AddEdge(edge, MergeInputIds(out_begin, out));
|
|
997
|
+
} else {
|
|
998
|
+
CopyEdges(out_begin, out);
|
|
999
|
+
}
|
|
1000
|
+
} else if (options_.sibling_pairs() == SiblingPairs::DISCARD) {
|
|
1001
|
+
if (options_.edge_type() == EdgeType::DIRECTED) {
|
|
1002
|
+
// If n_out == n_in: balanced sibling pairs
|
|
1003
|
+
// If n_out < n_in: unbalanced siblings, in the form AB, BA, BA
|
|
1004
|
+
// If n_out > n_in: unbalanced siblings, in the form AB, AB, BA
|
|
1005
|
+
if (n_out <= n_in) continue;
|
|
1006
|
+
// Any option that discards edges causes the labels of all duplicate
|
|
1007
|
+
// edges to be merged together (see s2builder.h).
|
|
1008
|
+
AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
|
|
1009
|
+
1 : (n_out - n_in), edge, MergeInputIds(out_begin, out));
|
|
1010
|
+
} else {
|
|
1011
|
+
if ((n_out & 1) == 0) continue;
|
|
1012
|
+
AddEdge(edge, MergeInputIds(out_begin, out));
|
|
1013
|
+
}
|
|
1014
|
+
} else if (options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
|
|
1015
|
+
if (options_.edge_type() == EdgeType::DIRECTED) {
|
|
1016
|
+
// See comments above. The only difference is that if there are
|
|
1017
|
+
// balanced sibling pairs, we want to keep one such pair.
|
|
1018
|
+
if (n_out < n_in) continue;
|
|
1019
|
+
AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
|
|
1020
|
+
1 : max(1, n_out - n_in), edge, MergeInputIds(out_begin, out));
|
|
1021
|
+
} else {
|
|
1022
|
+
AddEdges((n_out & 1) ? 1 : 2, edge, MergeInputIds(out_begin, out));
|
|
1023
|
+
}
|
|
1024
|
+
} else {
|
|
1025
|
+
S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
|
|
1026
|
+
options_.sibling_pairs() == SiblingPairs::CREATE);
|
|
1027
|
+
if (error->ok() && options_.sibling_pairs() == SiblingPairs::REQUIRE &&
|
|
1028
|
+
(options_.edge_type() == EdgeType::DIRECTED ? (n_out != n_in)
|
|
1029
|
+
: ((n_out & 1) != 0))) {
|
|
1030
|
+
error->Init(S2Error::BUILDER_MISSING_EXPECTED_SIBLING_EDGES,
|
|
1031
|
+
"Expected all input edges to have siblings, "
|
|
1032
|
+
"but some were missing");
|
|
1033
|
+
}
|
|
1034
|
+
if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
|
|
1035
|
+
AddEdge(edge, MergeInputIds(out_begin, out));
|
|
1036
|
+
} else if (options_.edge_type() == EdgeType::UNDIRECTED) {
|
|
1037
|
+
// Convert graph to use directed edges instead (see documentation of
|
|
1038
|
+
// REQUIRE/CREATE for undirected edges).
|
|
1039
|
+
AddEdges((n_out + 1) / 2, edge, MergeInputIds(out_begin, out));
|
|
1040
|
+
} else {
|
|
1041
|
+
CopyEdges(out_begin, out);
|
|
1042
|
+
if (n_in > n_out) {
|
|
1043
|
+
// Automatically created edges have no input edge ids or labels.
|
|
1044
|
+
AddEdges(n_in - n_out, edge, IdSetLexicon::EmptySetId());
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
edges_.swap(new_edges_);
|
|
1050
|
+
edges_.shrink_to_fit();
|
|
1051
|
+
input_ids_.swap(new_input_ids_);
|
|
1052
|
+
input_ids_.shrink_to_fit();
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
vector<S2Point> Graph::FilterVertices(const vector<S2Point>& vertices,
|
|
1056
|
+
std::vector<Edge>* edges,
|
|
1057
|
+
vector<VertexId>* tmp) {
|
|
1058
|
+
// Gather the vertices that are actually used.
|
|
1059
|
+
vector<VertexId> used;
|
|
1060
|
+
used.reserve(2 * edges->size());
|
|
1061
|
+
for (const Edge& e : *edges) {
|
|
1062
|
+
used.push_back(e.first);
|
|
1063
|
+
used.push_back(e.second);
|
|
1064
|
+
}
|
|
1065
|
+
// Sort the vertices and find the distinct ones.
|
|
1066
|
+
std::sort(used.begin(), used.end());
|
|
1067
|
+
used.erase(std::unique(used.begin(), used.end()), used.end());
|
|
1068
|
+
|
|
1069
|
+
// Build the list of new vertices, and generate a map from old vertex id to
|
|
1070
|
+
// new vertex id.
|
|
1071
|
+
vector<VertexId>& vmap = *tmp;
|
|
1072
|
+
vmap.resize(vertices.size());
|
|
1073
|
+
vector<S2Point> new_vertices(used.size());
|
|
1074
|
+
for (int i = 0; i < used.size(); ++i) {
|
|
1075
|
+
new_vertices[i] = vertices[used[i]];
|
|
1076
|
+
vmap[used[i]] = i;
|
|
1077
|
+
}
|
|
1078
|
+
// Update the edges.
|
|
1079
|
+
for (Edge& e : *edges) {
|
|
1080
|
+
e.first = vmap[e.first];
|
|
1081
|
+
e.second = vmap[e.second];
|
|
1082
|
+
}
|
|
1083
|
+
return new_vertices;
|
|
1084
|
+
}
|