@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,414 @@
|
|
|
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
|
+
|
|
17
|
+
#include "s2/s2polyline_alignment.h"
|
|
18
|
+
#include "s2/s2polyline_alignment_internal.h"
|
|
19
|
+
|
|
20
|
+
#include <algorithm>
|
|
21
|
+
#include <numeric>
|
|
22
|
+
#include <sstream>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <utility>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
#include "s2/base/logging.h"
|
|
28
|
+
#include "s2/third_party/absl/memory/memory.h"
|
|
29
|
+
#include "s2/util/math/mathutil.h"
|
|
30
|
+
|
|
31
|
+
namespace s2polyline_alignment {
|
|
32
|
+
|
|
33
|
+
Window::Window(const std::vector<ColumnStride>& strides) {
|
|
34
|
+
S2_DCHECK(!strides.empty()) << "Cannot construct empty window.";
|
|
35
|
+
S2_DCHECK(strides[0].start == 0) << "First element of start_cols is non-zero.";
|
|
36
|
+
strides_ = strides;
|
|
37
|
+
rows_ = strides.size();
|
|
38
|
+
cols_ = strides.back().end;
|
|
39
|
+
S2_DCHECK(this->IsValid()) << "Constructor validity check fail.";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Window::Window(const WarpPath& warp_path) {
|
|
43
|
+
S2_DCHECK(!warp_path.empty()) << "Cannot construct window from empty warp path.";
|
|
44
|
+
S2_DCHECK(warp_path.front() == std::make_pair(0, 0)) << "Must start at (0, 0).";
|
|
45
|
+
rows_ = warp_path.back().first + 1;
|
|
46
|
+
S2_DCHECK(rows_ > 0) << "Must have at least one row.";
|
|
47
|
+
cols_ = warp_path.back().second + 1;
|
|
48
|
+
S2_DCHECK(cols_ > 0) << "Must have at least one column.";
|
|
49
|
+
strides_.resize(rows_);
|
|
50
|
+
|
|
51
|
+
int prev_row = 0;
|
|
52
|
+
int curr_row = 0;
|
|
53
|
+
int stride_start = 0;
|
|
54
|
+
int stride_stop = 0;
|
|
55
|
+
for (const auto& pair : warp_path) {
|
|
56
|
+
curr_row = pair.first;
|
|
57
|
+
if (curr_row > prev_row) {
|
|
58
|
+
strides_[prev_row] = {stride_start, stride_stop};
|
|
59
|
+
stride_start = pair.second;
|
|
60
|
+
prev_row = curr_row;
|
|
61
|
+
}
|
|
62
|
+
stride_stop = pair.second + 1;
|
|
63
|
+
}
|
|
64
|
+
S2_DCHECK_EQ(curr_row, rows_ - 1);
|
|
65
|
+
strides_[rows_ - 1] = {stride_start, stride_stop};
|
|
66
|
+
S2_DCHECK(this->IsValid()) << "Constructor validity check fail.";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Window Window::Upsample(const int new_rows, const int new_cols) const {
|
|
70
|
+
S2_DCHECK(new_rows >= rows_) << "Upsampling: New_rows < current_rows";
|
|
71
|
+
S2_DCHECK(new_cols >= cols_) << "Upsampling: New_cols < current_cols";
|
|
72
|
+
const double row_scale = static_cast<double>(new_rows) / rows_;
|
|
73
|
+
const double col_scale = static_cast<double>(new_cols) / cols_;
|
|
74
|
+
std::vector<ColumnStride> new_strides(new_rows);
|
|
75
|
+
ColumnStride from_stride;
|
|
76
|
+
for (int row = 0; row < new_rows; ++row) {
|
|
77
|
+
from_stride = strides_[static_cast<int>((row + 0.5) / row_scale)];
|
|
78
|
+
new_strides[row] = {static_cast<int>(col_scale * from_stride.start + 0.5),
|
|
79
|
+
static_cast<int>(col_scale * from_stride.end + 0.5)};
|
|
80
|
+
}
|
|
81
|
+
return Window(new_strides);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// This code takes advantage of the fact that the dilation window is square to
|
|
85
|
+
// ensure that we can compute the stride for each output row in constant time.
|
|
86
|
+
// TODO (mrdmnd): a potential optimization might be to combine this method and
|
|
87
|
+
// the Upsample method into a single "Expand" method. For the sake of
|
|
88
|
+
// testing, I haven't done that here, but I think it would be fairly
|
|
89
|
+
// straightforward to do so. This method generally isn't very expensive so it
|
|
90
|
+
// feels unnecessary to combine them.
|
|
91
|
+
Window Window::Dilate(const int radius) const {
|
|
92
|
+
S2_DCHECK(radius >= 0) << "Negative dilation radius.";
|
|
93
|
+
std::vector<ColumnStride> new_strides(rows_);
|
|
94
|
+
int prev_row, next_row;
|
|
95
|
+
for (int row = 0; row < rows_; ++row) {
|
|
96
|
+
prev_row = std::max(0, row - radius);
|
|
97
|
+
next_row = std::min(row + radius, rows_ - 1);
|
|
98
|
+
new_strides[row] = {std::max(0, strides_[prev_row].start - radius),
|
|
99
|
+
std::min(strides_[next_row].end + radius, cols_)};
|
|
100
|
+
}
|
|
101
|
+
return Window(new_strides);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Debug string implemented primarily for testing purposes.
|
|
105
|
+
string Window::DebugString() const {
|
|
106
|
+
std::stringstream buffer;
|
|
107
|
+
for (int row = 0; row < rows_; ++row) {
|
|
108
|
+
for (int col = 0; col < cols_; ++col) {
|
|
109
|
+
buffer << (strides_[row].InRange(col) ? " *" : " .");
|
|
110
|
+
}
|
|
111
|
+
buffer << std::endl;
|
|
112
|
+
}
|
|
113
|
+
return buffer.str();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Valid Windows require the following structural conditions to hold:
|
|
117
|
+
// 1) All rows must consist of a single contiguous stride of `true` values.
|
|
118
|
+
// 2) All strides are greater than zero length (i.e. no empty rows).
|
|
119
|
+
// 3) The index of the first `true` column in a row must be at least as
|
|
120
|
+
// large as the index of the first `true` column in the previous row.
|
|
121
|
+
// 4) The index of the last `true` column in a row must be at least as large
|
|
122
|
+
// as the index of the last `true` column in the previous row.
|
|
123
|
+
// 5) strides[0].start = 0 (the first cell is always filled).
|
|
124
|
+
// 6) strides[n_rows-1].end = n_cols (the last cell is filled).
|
|
125
|
+
bool Window::IsValid() const {
|
|
126
|
+
if (rows_ <= 0 || cols_ <= 0 || strides_.front().start != 0 ||
|
|
127
|
+
strides_.back().end != cols_) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
ColumnStride prev = {-1, -1};
|
|
132
|
+
for (const auto& curr : strides_) {
|
|
133
|
+
if (curr.end <= curr.start || curr.start < prev.start ||
|
|
134
|
+
curr.end < prev.end) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
prev = curr;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
inline double BoundsCheckedTableCost(const int row, const int col,
|
|
143
|
+
const ColumnStride& stride,
|
|
144
|
+
const CostTable& table) {
|
|
145
|
+
if (row < 0 && col < 0) {
|
|
146
|
+
return 0.0;
|
|
147
|
+
} else if (row < 0 || col < 0 || !stride.InRange(col)) {
|
|
148
|
+
return DOUBLE_MAX;
|
|
149
|
+
} else {
|
|
150
|
+
return table[row][col];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Perform dynamic timewarping by filling in the DP table on cells that are
|
|
155
|
+
// inside our search window. For an exact (all-squares) evaluation, this
|
|
156
|
+
// incurs bounds checking overhead - we don't need to ensure that we're inside
|
|
157
|
+
// the appropriate cells in the window, because it's guaranteed. Structuring
|
|
158
|
+
// the program to reuse code for both the EXACT and WINDOWED cases by
|
|
159
|
+
// abstracting EXACT as a window with full-covering strides is done for
|
|
160
|
+
// maintainability reasons. One potential optimization here might be to overload
|
|
161
|
+
// this function to skip bounds checking when the window is full.
|
|
162
|
+
//
|
|
163
|
+
// As a note of general interest, the Dynamic Timewarp algorithm as stated here
|
|
164
|
+
// prefers shorter warp paths, when two warp paths might be equally costly. This
|
|
165
|
+
// is because it favors progressing in the sequences simultaneously due to the
|
|
166
|
+
// equal weighting of a diagonal step in the cost table with a horizontal or
|
|
167
|
+
// vertical step. This may be counterintuitive, but represents the standard
|
|
168
|
+
// implementation of this algorithm. TODO(user) - future implementations could
|
|
169
|
+
// allow weights on the lookup costs to mitigate this.
|
|
170
|
+
//
|
|
171
|
+
// This is the hottest routine in the whole package, please be careful to
|
|
172
|
+
// profile any future changes made here.
|
|
173
|
+
//
|
|
174
|
+
// This method takes time proportional to the number of cells in the window,
|
|
175
|
+
// which can range from O(max(a, b)) cells (best) to O(a*b) cells (worst)
|
|
176
|
+
VertexAlignment DynamicTimewarp(const S2Polyline& a, const S2Polyline& b,
|
|
177
|
+
const Window& w) {
|
|
178
|
+
const int rows = a.num_vertices();
|
|
179
|
+
const int cols = b.num_vertices();
|
|
180
|
+
auto costs = CostTable(rows, std::vector<double>(cols));
|
|
181
|
+
|
|
182
|
+
ColumnStride curr;
|
|
183
|
+
ColumnStride prev = ColumnStride::All();
|
|
184
|
+
for (int row = 0; row < rows; ++row) {
|
|
185
|
+
curr = w.GetColumnStride(row);
|
|
186
|
+
for (int col = curr.start; col < curr.end; ++col) {
|
|
187
|
+
double d_cost = BoundsCheckedTableCost(row - 1, col - 1, prev, costs);
|
|
188
|
+
double u_cost = BoundsCheckedTableCost(row - 1, col - 0, prev, costs);
|
|
189
|
+
double l_cost = BoundsCheckedTableCost(row - 0, col - 1, curr, costs);
|
|
190
|
+
costs[row][col] = std::min({d_cost, u_cost, l_cost}) +
|
|
191
|
+
(a.vertex(row) - b.vertex(col)).Norm2();
|
|
192
|
+
}
|
|
193
|
+
prev = curr;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Now we walk back through the cost table and build up the warp path.
|
|
197
|
+
// Somewhat surprisingly, it is faster to recover the path this way than it
|
|
198
|
+
// is to save the comparisons from the computation we *already did* to get the
|
|
199
|
+
// direction we came from. The author speculates that this behavior is
|
|
200
|
+
// assignment-cost-related: to persist direction, we have to do extra
|
|
201
|
+
// stores/loads of "directional" information, and the extra assignment cost
|
|
202
|
+
// this incurs is larger than the cost to simply redo the comparisons.
|
|
203
|
+
// It's probably worth revisiting this assumption in the future.
|
|
204
|
+
// As it turns out, the following code ends up effectively free.
|
|
205
|
+
WarpPath warp_path;
|
|
206
|
+
warp_path.reserve(std::max(a.num_vertices(), b.num_vertices()));
|
|
207
|
+
int row = a.num_vertices() - 1;
|
|
208
|
+
int col = b.num_vertices() - 1;
|
|
209
|
+
curr = w.GetCheckedColumnStride(row);
|
|
210
|
+
prev = w.GetCheckedColumnStride(row - 1);
|
|
211
|
+
while (row >= 0 && col >= 0) {
|
|
212
|
+
warp_path.push_back({row, col});
|
|
213
|
+
double d_cost = BoundsCheckedTableCost(row - 1, col - 1, prev, costs);
|
|
214
|
+
double u_cost = BoundsCheckedTableCost(row - 1, col - 0, prev, costs);
|
|
215
|
+
double l_cost = BoundsCheckedTableCost(row - 0, col - 1, curr, costs);
|
|
216
|
+
if (d_cost <= u_cost && d_cost <= l_cost) {
|
|
217
|
+
row -= 1;
|
|
218
|
+
col -= 1;
|
|
219
|
+
curr = w.GetCheckedColumnStride(row);
|
|
220
|
+
prev = w.GetCheckedColumnStride(row - 1);
|
|
221
|
+
} else if (u_cost <= l_cost) {
|
|
222
|
+
row -= 1;
|
|
223
|
+
curr = w.GetCheckedColumnStride(row);
|
|
224
|
+
prev = w.GetCheckedColumnStride(row - 1);
|
|
225
|
+
} else {
|
|
226
|
+
col -= 1;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
std::reverse(warp_path.begin(), warp_path.end());
|
|
230
|
+
return VertexAlignment(costs.back().back(), warp_path);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
std::unique_ptr<S2Polyline> HalfResolution(const S2Polyline& in) {
|
|
234
|
+
const int n = in.num_vertices();
|
|
235
|
+
std::vector<S2Point> vertices;
|
|
236
|
+
vertices.reserve(n / 2);
|
|
237
|
+
for (int i = 0; i < n; i += 2) {
|
|
238
|
+
vertices.push_back(in.vertex(i));
|
|
239
|
+
}
|
|
240
|
+
return absl::make_unique<S2Polyline>(vertices);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Helper methods for GetMedoidPolyline and GetConsensusPolyline to auto-select
|
|
244
|
+
// appropriate cost function / alignment functions.
|
|
245
|
+
double CostFn(const S2Polyline& a, const S2Polyline& b, bool approx) {
|
|
246
|
+
return approx ? GetApproxVertexAlignment(a, b).alignment_cost
|
|
247
|
+
: GetExactVertexAlignmentCost(a, b);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
VertexAlignment AlignmentFn(const S2Polyline& a, const S2Polyline& b,
|
|
251
|
+
bool approx) {
|
|
252
|
+
return approx ? GetApproxVertexAlignment(a, b)
|
|
253
|
+
: GetExactVertexAlignment(a, b);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// PUBLIC API IMPLEMENTATION DETAILS
|
|
257
|
+
|
|
258
|
+
// This is the constant-space implementation of Dynamic Timewarp that can
|
|
259
|
+
// compute the alignment cost, but not the warp path.
|
|
260
|
+
double GetExactVertexAlignmentCost(const S2Polyline& a, const S2Polyline& b) {
|
|
261
|
+
const int a_n = a.num_vertices();
|
|
262
|
+
const int b_n = b.num_vertices();
|
|
263
|
+
S2_CHECK(a_n > 0) << "A is empty polyline.";
|
|
264
|
+
S2_CHECK(b_n > 0) << "B is empty polyline.";
|
|
265
|
+
std::vector<double> cost(b_n, DOUBLE_MAX);
|
|
266
|
+
double left_diag_min_cost = 0;
|
|
267
|
+
for (int row = 0; row < a_n; ++row) {
|
|
268
|
+
for (int col = 0; col < b_n; ++col) {
|
|
269
|
+
double up_cost = cost[col];
|
|
270
|
+
cost[col] = std::min(left_diag_min_cost, up_cost) +
|
|
271
|
+
(a.vertex(row) - b.vertex(col)).Norm2();
|
|
272
|
+
left_diag_min_cost = std::min(cost[col], up_cost);
|
|
273
|
+
}
|
|
274
|
+
left_diag_min_cost = DOUBLE_MAX;
|
|
275
|
+
}
|
|
276
|
+
return cost.back();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
VertexAlignment GetExactVertexAlignment(const S2Polyline& a,
|
|
280
|
+
const S2Polyline& b) {
|
|
281
|
+
const int a_n = a.num_vertices();
|
|
282
|
+
const int b_n = b.num_vertices();
|
|
283
|
+
S2_CHECK(a_n > 0) << "A is empty polyline.";
|
|
284
|
+
S2_CHECK(b_n > 0) << "B is empty polyline.";
|
|
285
|
+
const auto w = Window(std::vector<ColumnStride>(a_n, {0, b_n}));
|
|
286
|
+
return DynamicTimewarp(a, b, w);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
|
|
290
|
+
const S2Polyline& b,
|
|
291
|
+
const int radius) {
|
|
292
|
+
// Determined experimentally, through benchmarking, as about the points at
|
|
293
|
+
// which ExactAlignment is faster than ApproxAlignment, so we use these as
|
|
294
|
+
// our switchover points to exact computation mode.
|
|
295
|
+
const int kSizeSwitchover = 32;
|
|
296
|
+
const double kDensitySwitchover = 0.85;
|
|
297
|
+
const int a_n = a.num_vertices();
|
|
298
|
+
const int b_n = b.num_vertices();
|
|
299
|
+
S2_CHECK(a_n > 0) << "A is empty polyline.";
|
|
300
|
+
S2_CHECK(b_n > 0) << "B is empty polyline.";
|
|
301
|
+
S2_CHECK(radius >= 0) << "Radius is negative.";
|
|
302
|
+
|
|
303
|
+
// If we've hit the point where doing a full, direct solve is guaranteed to
|
|
304
|
+
// be faster, then terminate the recursion and do that.
|
|
305
|
+
if (a_n - radius < kSizeSwitchover || b_n - radius < kSizeSwitchover) {
|
|
306
|
+
return GetExactVertexAlignment(a, b);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// If we've hit the point where the window will be probably be so full that we
|
|
310
|
+
// might as well compute an exact solution, then terminate recursion to do so.
|
|
311
|
+
if (std::max(a_n, b_n) * (2 * radius + 1) > a_n * b_n * kDensitySwitchover) {
|
|
312
|
+
return GetExactVertexAlignment(a, b);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Otherwise, shrink the input polylines, recursively compute the vertex
|
|
316
|
+
// alignment using this method, and then compute the final alignment using
|
|
317
|
+
// the projected alignment `proj` on an upsampled, dilated window.
|
|
318
|
+
const auto a_half = HalfResolution(a);
|
|
319
|
+
const auto b_half = HalfResolution(b);
|
|
320
|
+
const auto proj = GetApproxVertexAlignment(*a_half, *b_half, radius);
|
|
321
|
+
const auto w = Window(proj.warp_path).Upsample(a_n, b_n).Dilate(radius);
|
|
322
|
+
return DynamicTimewarp(a, b, w);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// This method calls the approx method with a reasonable default for radius.
|
|
326
|
+
VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
|
|
327
|
+
const S2Polyline& b) {
|
|
328
|
+
const int max_length = std::max(a.num_vertices(), b.num_vertices());
|
|
329
|
+
const int radius = static_cast<int>(std::pow(max_length, 0.25));
|
|
330
|
+
return GetApproxVertexAlignment(a, b, radius);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// We use some of the symmetry of our metric to avoid computing all N^2
|
|
334
|
+
// alignments. Specifically, because cost_fn(a, b) = cost_fn(b, a), and
|
|
335
|
+
// cost_fn(a, a) = 0, we can compute only the lower triangle of cost matrix
|
|
336
|
+
// and then mirror it across the diagonal to save on cost_fn invocations.
|
|
337
|
+
int GetMedoidPolyline(const std::vector<std::unique_ptr<S2Polyline>>& polylines,
|
|
338
|
+
const MedoidOptions options) {
|
|
339
|
+
const int num_polylines = polylines.size();
|
|
340
|
+
const bool approx = options.approx();
|
|
341
|
+
S2_CHECK_GT(num_polylines, 0);
|
|
342
|
+
|
|
343
|
+
// costs[i] stores total cost of aligning [i] with all other polylines.
|
|
344
|
+
std::vector<double> costs(num_polylines, 0.0);
|
|
345
|
+
for (int i = 0; i < num_polylines; ++i) {
|
|
346
|
+
for (int j = i + 1; j < num_polylines; ++j) {
|
|
347
|
+
double cost = CostFn(*polylines[i], *polylines[j], approx);
|
|
348
|
+
costs[i] += cost;
|
|
349
|
+
costs[j] += cost;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return std::min_element(costs.begin(), costs.end()) - costs.begin();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Implements Iterative Dynamic Timewarp Barycenter Averaging algorithm from
|
|
356
|
+
//
|
|
357
|
+
// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
|
|
358
|
+
//
|
|
359
|
+
// Algorithm:
|
|
360
|
+
// Initialize consensus sequence with either the medoid or an arbitrary
|
|
361
|
+
// element (chosen here to be the first element in the input collection).
|
|
362
|
+
// While the consensus polyline `consensus` hasn't converged and we haven't
|
|
363
|
+
// exceeded our iteration cap:
|
|
364
|
+
// For each polyline `p` in the input,
|
|
365
|
+
// Compute vertex alignment from the current consensus to `p`.
|
|
366
|
+
// For each (c_index, p_index) pair in the warp path,
|
|
367
|
+
// Add the S2Point pts->vertex(p_index) to S2Point consensus[c_index]
|
|
368
|
+
// Normalize (compute centroid) of each consensus point.
|
|
369
|
+
// Determine if consensus is converging; if no vertex has moved or we've hit
|
|
370
|
+
// the iteration cap, halt.
|
|
371
|
+
//
|
|
372
|
+
// This algorithm takes O(iteration_cap * num_polylines) pairwise alignments.
|
|
373
|
+
|
|
374
|
+
std::unique_ptr<S2Polyline> GetConsensusPolyline(
|
|
375
|
+
const std::vector<std::unique_ptr<S2Polyline>>& polylines,
|
|
376
|
+
const ConsensusOptions options) {
|
|
377
|
+
const int num_polylines = polylines.size();
|
|
378
|
+
S2_CHECK_GT(num_polylines, 0);
|
|
379
|
+
const bool approx = options.approx();
|
|
380
|
+
|
|
381
|
+
// Seed a consensus polyline, either arbitrarily with first element, or with
|
|
382
|
+
// the medoid. If seeding with medoid, inherit approx parameter from options.
|
|
383
|
+
int seed_index = 0;
|
|
384
|
+
if (options.seed_medoid()) {
|
|
385
|
+
MedoidOptions medoid_options;
|
|
386
|
+
medoid_options.set_approx(approx);
|
|
387
|
+
seed_index = GetMedoidPolyline(polylines, medoid_options);
|
|
388
|
+
}
|
|
389
|
+
auto consensus = std::unique_ptr<S2Polyline>(polylines[seed_index]->Clone());
|
|
390
|
+
const int num_consensus_vertices = consensus->num_vertices();
|
|
391
|
+
S2_DCHECK_GT(num_consensus_vertices, 1);
|
|
392
|
+
|
|
393
|
+
bool converged = false;
|
|
394
|
+
int iterations = 0;
|
|
395
|
+
while (!converged && iterations < options.iteration_cap()) {
|
|
396
|
+
std::vector<S2Point> points(num_consensus_vertices, S2Point());
|
|
397
|
+
for (const auto& polyline : polylines) {
|
|
398
|
+
const auto alignment = AlignmentFn(*consensus, *polyline, approx);
|
|
399
|
+
for (const auto& pair : alignment.warp_path) {
|
|
400
|
+
points[pair.first] += polyline->vertex(pair.second);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
for (S2Point& p : points) {
|
|
404
|
+
p = p.Normalize();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
++iterations;
|
|
408
|
+
auto new_consensus = absl::make_unique<S2Polyline>(points);
|
|
409
|
+
converged = new_consensus->ApproxEquals(*consensus);
|
|
410
|
+
consensus = std::move(new_consensus);
|
|
411
|
+
}
|
|
412
|
+
return consensus;
|
|
413
|
+
}
|
|
414
|
+
} // namespace s2polyline_alignment
|
|
@@ -0,0 +1,245 @@
|
|
|
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
|
+
|
|
17
|
+
#ifndef S2_S2POLYLINE_ALIGNMENT_H_
|
|
18
|
+
#define S2_S2POLYLINE_ALIGNMENT_H_
|
|
19
|
+
|
|
20
|
+
#include <memory>
|
|
21
|
+
#include <vector>
|
|
22
|
+
|
|
23
|
+
#include "s2/s2polyline.h"
|
|
24
|
+
|
|
25
|
+
// This library provides code to compute vertex alignments between S2Polylines.
|
|
26
|
+
//
|
|
27
|
+
// A vertex "alignment" or "warp" between two polylines is a matching between
|
|
28
|
+
// pairs of their vertices. Users can imagine pairing each vertex from
|
|
29
|
+
// S2Polyline `a` with at least one other vertex in S2Polyline `b`. The "cost"
|
|
30
|
+
// of an arbitrary alignment is defined as the summed value of the squared
|
|
31
|
+
// chordal distance between each pair of points in the warp path. An "optimal
|
|
32
|
+
// alignment" for a pair of polylines is defined as the alignment with least
|
|
33
|
+
// cost. Note: optimal alignments are not necessarily unique. The standard way
|
|
34
|
+
// of computing an optimal alignment between two sequences is the use of the
|
|
35
|
+
// `Dynamic Timewarp` algorithm.
|
|
36
|
+
//
|
|
37
|
+
// We provide three methods for computing (via Dynamic Timewarp) the optimal
|
|
38
|
+
// alignment between two S2Polylines. These methods are performance-sensitive,
|
|
39
|
+
// and have been reasonably optimized for space- and time- usage. On modern
|
|
40
|
+
// hardware, it is possible to compute exact alignments between 4096x4096
|
|
41
|
+
// element polylines in ~70ms, and approximate alignments much more quickly.
|
|
42
|
+
//
|
|
43
|
+
// The results of an alignment operation are captured in a VertexAlignment
|
|
44
|
+
// object. In particular, a VertexAlignment keeps track of the total cost of
|
|
45
|
+
// alignment, as well as the warp path (a sequence of pairs of indices into each
|
|
46
|
+
// polyline whose vertices are linked together in the optimal alignment)
|
|
47
|
+
//
|
|
48
|
+
// For a worked example, consider the polylines
|
|
49
|
+
//
|
|
50
|
+
// a = [(1, 0), (5, 0), (6, 0), (9, 0)] and
|
|
51
|
+
// b = [(2, 0), (7, 0), (8, 0)].
|
|
52
|
+
//
|
|
53
|
+
// The "cost matrix" between these two polylines (using squared chordal
|
|
54
|
+
// distance, .Norm2(), as our distance function) looks like this:
|
|
55
|
+
//
|
|
56
|
+
// (2, 0) (7, 0) (8, 0)
|
|
57
|
+
// (1, 0) 1 36 49
|
|
58
|
+
// (5, 0) 9 4 9
|
|
59
|
+
// (6, 0) 16 1 4
|
|
60
|
+
// (9, 0) 49 4 1
|
|
61
|
+
//
|
|
62
|
+
// The Dynamic Timewarp DP table for this cost matrix has cells defined by
|
|
63
|
+
//
|
|
64
|
+
// table[i][j] = cost(i,j) + min(table[i-1][j-1], table[i][j-1], table[i-1, j])
|
|
65
|
+
//
|
|
66
|
+
// (2, 0) (7, 0) (8, 0)
|
|
67
|
+
// (1, 0) 1 37 86
|
|
68
|
+
// (5, 0) 10 5 14
|
|
69
|
+
// (6, 0) 26 6 9
|
|
70
|
+
// (9, 0) 75 10 7
|
|
71
|
+
//
|
|
72
|
+
// Starting at the bottom right corner of the DP table, we can work our way
|
|
73
|
+
// backwards to the upper left corner to recover the reverse of the warp path:
|
|
74
|
+
// (3, 2) -> (2, 1) -> (1, 1) -> (0, 0). The VertexAlignment produced containing
|
|
75
|
+
// this has alignment_cost = 7 and warp_path = {(0, 0), (1, 1), (2, 1), (3, 2)}.
|
|
76
|
+
//
|
|
77
|
+
// We also provide methods for performing alignment of multiple sequences. These
|
|
78
|
+
// methods return a single, representative polyline from a non-empty collection
|
|
79
|
+
// of polylines, for various definitions of "representative."
|
|
80
|
+
//
|
|
81
|
+
// GetMedoidPolyline() returns a new polyline (point-for-point-equal to some
|
|
82
|
+
// existing polyline from the collection) that minimizes the summed vertex
|
|
83
|
+
// alignment cost to all other polylines in the collection.
|
|
84
|
+
//
|
|
85
|
+
// GetConsensusPolyline() returns a new polyline (unlikely to be present in the
|
|
86
|
+
// input collection) that represents a "weighted consensus" polyline. This
|
|
87
|
+
// polyline is constructed iteratively using the Dynamic Timewarp Barycenter
|
|
88
|
+
// Averaging algorithm of F. Petitjean, A. Ketterlin, and P. Gancarski, which
|
|
89
|
+
// can be found here:
|
|
90
|
+
// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
|
|
91
|
+
|
|
92
|
+
namespace s2polyline_alignment {
|
|
93
|
+
|
|
94
|
+
typedef std::vector<std::pair<int, int>> WarpPath;
|
|
95
|
+
|
|
96
|
+
struct VertexAlignment {
|
|
97
|
+
// `alignment_cost` represents the sum of the squared chordal distances
|
|
98
|
+
// between each pair of vertices in the warp path. Specifically,
|
|
99
|
+
// cost = sum_{(i, j) \in path} (a.vertex(i) - b.vertex(j)).Norm2();
|
|
100
|
+
// This means that the units of alignment_cost are "squared distance". This is
|
|
101
|
+
// an optimization to avoid the (expensive) atan computation of the true
|
|
102
|
+
// spherical angular distance between the points, as well as an unnecessary
|
|
103
|
+
// square root. All we need to compute vertex alignment is a metric that
|
|
104
|
+
// satisifies the triangle inequality, and squared chordal distance works as
|
|
105
|
+
// well as spherical S1Angle distance for this purpose.
|
|
106
|
+
double alignment_cost;
|
|
107
|
+
|
|
108
|
+
// Each entry (i, j) of `warp_path` represents a pairing between vertex
|
|
109
|
+
// a.vertex(i) and vertex b.vertex(j) in the optimal alignment.
|
|
110
|
+
// The warp_path is defined in forward order, such that the result of
|
|
111
|
+
// aligning polylines `a` and `b` is always a warp_path with warp_path.front()
|
|
112
|
+
// = {0,0} and warp_path.back() = {a.num_vertices() - 1, b.num_vertices() - 1}
|
|
113
|
+
// Note that this DOES NOT define an alignment from a point sequence to an
|
|
114
|
+
// edge sequence. That functionality may come at a later date.
|
|
115
|
+
WarpPath warp_path;
|
|
116
|
+
|
|
117
|
+
VertexAlignment(const double cost, const WarpPath& path)
|
|
118
|
+
: alignment_cost(cost), warp_path(path) {}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// GetExactVertexAlignment takes two non-empty polylines as input, and returns
|
|
122
|
+
// the VertexAlignment corresponding to the optimal alignment between them. This
|
|
123
|
+
// method is quadratic O(A*B) in both space and time complexity.
|
|
124
|
+
VertexAlignment GetExactVertexAlignment(const S2Polyline& a,
|
|
125
|
+
const S2Polyline& b);
|
|
126
|
+
|
|
127
|
+
// GetExactVertexAlignmentCost takes two non-empty polylines as input, and
|
|
128
|
+
// returns the *cost* of their optimal alignment. A standard, traditional
|
|
129
|
+
// dynamic timewarp algorithm can output both a warp path and a cost, but
|
|
130
|
+
// requires quadratic space to reconstruct the path by walking back through the
|
|
131
|
+
// Dynamic Programming cost table. If all you really need is the warp cost (i.e.
|
|
132
|
+
// you're inducing a similarity metric between S2Polylines, or something
|
|
133
|
+
// equivalent), you can overwrite the DP table and use constant space -
|
|
134
|
+
// O(max(A,B)). This method provides that space-efficiency optimization.
|
|
135
|
+
double GetExactVertexAlignmentCost(const S2Polyline& a, const S2Polyline& b);
|
|
136
|
+
|
|
137
|
+
// GetApproxVertexAlignment takes two non-empty polylines `a` and `b` as input,
|
|
138
|
+
// and a `radius` paramater GetApproxVertexAlignment (quickly) computes an
|
|
139
|
+
// approximately optimal vertex alignment of points between polylines `a` and
|
|
140
|
+
// `b` by implementing the algorithm described in `FastDTW: Toward Accurate
|
|
141
|
+
// Dynamic Time Warping in Linear Time and Space` by Stan Salvador and Philip
|
|
142
|
+
// Chan. Details can be found below:
|
|
143
|
+
//
|
|
144
|
+
// https://pdfs.semanticscholar.org/05a2/0cde15e172fc82f32774dd0cf4fe5827cad2.pdf
|
|
145
|
+
//
|
|
146
|
+
// The `radius` parameter controls the distance we search outside of the
|
|
147
|
+
// projected warp path during the refining step. Smaller values of `radius`
|
|
148
|
+
// correspond to a smaller search window, and therefore distance computation on
|
|
149
|
+
// fewer cells, which leads to a faster (but worse) approximation.
|
|
150
|
+
// This method is O(max(A, B)) in both space and time complexity.
|
|
151
|
+
VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
|
|
152
|
+
const S2Polyline& b, const int radius);
|
|
153
|
+
|
|
154
|
+
// A convience overload for GetApproxVertexAlignment which computes and uses
|
|
155
|
+
// suggested default parameter of radius = max(a.size(), b.size())^0.25
|
|
156
|
+
VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
|
|
157
|
+
const S2Polyline& b);
|
|
158
|
+
|
|
159
|
+
// GetMedoidPolyline returns the index `p` of a "medoid" polyline from a
|
|
160
|
+
// non-empty collection of `polylines` such that
|
|
161
|
+
//
|
|
162
|
+
// sum_{all j in `polylines`} VertexAlignmentCost(p, j) is minimized.
|
|
163
|
+
//
|
|
164
|
+
// In the case of a tie for minimal summed alignment cost, we return the lowest
|
|
165
|
+
// index - this tie is guaranteed to happen in the two-polyline-input case.
|
|
166
|
+
//
|
|
167
|
+
// ASYMPTOTIC BEHAVIOR:
|
|
168
|
+
// Computation may require up to (N^2 - N) / 2 alignment cost function
|
|
169
|
+
// evaluations, for N input polylines. For polylines of length U, V, the
|
|
170
|
+
// alignment cost function evaluation is O(U+V) if options.approx = true and
|
|
171
|
+
// O(U*V) if options.approx = false.
|
|
172
|
+
|
|
173
|
+
class MedoidOptions {
|
|
174
|
+
public:
|
|
175
|
+
// If options.approx = false, we compute vertex alignment costs exactly.
|
|
176
|
+
// If options.approx = true, we use approximate vertex alignment
|
|
177
|
+
// computation, called with the default radius parameter.
|
|
178
|
+
bool approx() const { return approx_; }
|
|
179
|
+
void set_approx(bool approx) { approx_ = approx; }
|
|
180
|
+
|
|
181
|
+
private:
|
|
182
|
+
bool approx_ = true;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
int GetMedoidPolyline(const std::vector<std::unique_ptr<S2Polyline>>& polylines,
|
|
186
|
+
const MedoidOptions options);
|
|
187
|
+
|
|
188
|
+
// GetConsensusPolyline allocates and returns a new "consensus" polyline from a
|
|
189
|
+
// non-empty collection of polylines. We iteratively apply Dynamic Timewarp
|
|
190
|
+
// Barycenter Averaging to an initial `seed` polyline, which improves the
|
|
191
|
+
// consensus alignment quality each iteration. For implementation details, see
|
|
192
|
+
//
|
|
193
|
+
// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
|
|
194
|
+
//
|
|
195
|
+
// The returned polyline from this method is unlikely to be point-for-point
|
|
196
|
+
// equal to an input polyline, whereas a polyline returned from
|
|
197
|
+
// GetMedoidPolyline() is guaranteed to match an input polyline point-for-point.
|
|
198
|
+
// NOTE: the number of points in our returned consensus polyline is always equal
|
|
199
|
+
// to the number of points in the initial seed, which is implementation-defined.
|
|
200
|
+
// If the collection of polylines has a large resolution distribution, it might
|
|
201
|
+
// be a good idea to reinterpolate them to have about the same number of points.
|
|
202
|
+
// In practice, this doesn't seem to matter, but is probably worth noting.
|
|
203
|
+
//
|
|
204
|
+
// ASYMPTOTIC BEHAVIOR:
|
|
205
|
+
// Seeding this algorithm requires O(1) vertex alignments if seed_medoid =
|
|
206
|
+
// false, and O(N^2) vertex alignments if seed_medoid = true. Once the seed
|
|
207
|
+
// polyline is chosen, computing the consensus polyline requires at most
|
|
208
|
+
// (iteration_cap)*N vertex alignments. For polylines of length U, V, the
|
|
209
|
+
// alignment cost function evaluation is O(U+V) if options.approx = true, and
|
|
210
|
+
// O(U*V) if options.approx = false.
|
|
211
|
+
|
|
212
|
+
class ConsensusOptions {
|
|
213
|
+
public:
|
|
214
|
+
// If options.approx = false, vertex alignments are computed with
|
|
215
|
+
// GetExactVertexAlignment. If options.approx = true, vertex alignments are
|
|
216
|
+
// computed with GetApproxVertexAlignment, called with default radius
|
|
217
|
+
// parameter.
|
|
218
|
+
bool approx() const { return approx_; }
|
|
219
|
+
void set_approx(bool approx) { approx_ = approx; }
|
|
220
|
+
|
|
221
|
+
// If options.seed_medoid = true, we seed the consensus polyline with the
|
|
222
|
+
// medoid of the collection. This is a more expensive approach, but may result
|
|
223
|
+
// in higher quality consensus sequences by avoiding bad arbitrary initial
|
|
224
|
+
// seeds. Seeding with the medoid will incur up to (N^2 - N) / 2 evaluations
|
|
225
|
+
// of the vertex alignment function. If options.seed_medoid = false, we seed
|
|
226
|
+
// the consensus polyline by taking an arbitrary element from the collection.
|
|
227
|
+
bool seed_medoid() const { return seed_medoid_; }
|
|
228
|
+
void set_seed_medoid(bool seed_medoid) { seed_medoid_ = seed_medoid; }
|
|
229
|
+
|
|
230
|
+
// options.iteration_cap controls the maximum number of DBA refining steps we
|
|
231
|
+
// apply to the initial seed.
|
|
232
|
+
int iteration_cap() const { return iteration_cap_; }
|
|
233
|
+
void set_iteration_cap(int iteration_cap) { iteration_cap_ = iteration_cap; }
|
|
234
|
+
|
|
235
|
+
private:
|
|
236
|
+
bool approx_ = true;
|
|
237
|
+
bool seed_medoid_ = false;
|
|
238
|
+
int iteration_cap_ = 5;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
std::unique_ptr<S2Polyline> GetConsensusPolyline(
|
|
242
|
+
const std::vector<std::unique_ptr<S2Polyline>>& polylines,
|
|
243
|
+
const ConsensusOptions options);
|
|
244
|
+
} // namespace s2polyline_alignment
|
|
245
|
+
#endif // S2_S2POLYLINE_ALIGNMENT_H_
|