@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,1486 @@
|
|
|
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/s2predicates.h"
|
|
19
|
+
#include "s2/s2predicates_internal.h"
|
|
20
|
+
|
|
21
|
+
#include <algorithm>
|
|
22
|
+
#include <cfloat>
|
|
23
|
+
#include <cmath>
|
|
24
|
+
#include <ostream>
|
|
25
|
+
#include "s2/s1chord_angle.h"
|
|
26
|
+
#include "s2/util/math/exactfloat/exactfloat.h"
|
|
27
|
+
#include "s2/util/math/vector.h"
|
|
28
|
+
|
|
29
|
+
using std::fabs;
|
|
30
|
+
using std::max;
|
|
31
|
+
using std::min;
|
|
32
|
+
using std::sqrt;
|
|
33
|
+
|
|
34
|
+
namespace s2pred {
|
|
35
|
+
|
|
36
|
+
// All error bounds in this file are expressed in terms of the maximum
|
|
37
|
+
// rounding error for a floating-point type. The rounding error is half of
|
|
38
|
+
// the numeric_limits<T>::epsilon() value.
|
|
39
|
+
constexpr double DBL_ERR = rounding_epsilon<double>();
|
|
40
|
+
constexpr long double LD_ERR = rounding_epsilon<long double>();
|
|
41
|
+
|
|
42
|
+
// A predefined S1ChordAngle representing (approximately) 45 degrees.
|
|
43
|
+
static const S1ChordAngle k45Degrees = S1ChordAngle::FromLength2(2 - M_SQRT2);
|
|
44
|
+
|
|
45
|
+
int Sign(const S2Point& a, const S2Point& b, const S2Point& c) {
|
|
46
|
+
// We don't need RobustCrossProd() here because Sign() does its own
|
|
47
|
+
// error estimation and calls ExpensiveSign() if there is any uncertainty
|
|
48
|
+
// about the result.
|
|
49
|
+
return Sign(a, b, c, a.CrossProd(b));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Compute the determinant in a numerically stable way. Unlike TriageSign(),
|
|
53
|
+
// this method can usually compute the correct determinant sign even when all
|
|
54
|
+
// three points are as collinear as possible. For example if three points are
|
|
55
|
+
// spaced 1km apart along a random line on the Earth's surface using the
|
|
56
|
+
// nearest representable points, there is only a 0.4% chance that this method
|
|
57
|
+
// will not be able to find the determinant sign. The probability of failure
|
|
58
|
+
// decreases as the points get closer together; if the collinear points are
|
|
59
|
+
// 1 meter apart, the failure rate drops to 0.0004%.
|
|
60
|
+
//
|
|
61
|
+
// This method could be extended to also handle nearly-antipodal points (and
|
|
62
|
+
// in fact an earlier version of this code did exactly that), but antipodal
|
|
63
|
+
// points are rare in practice so it seems better to simply fall back to
|
|
64
|
+
// exact arithmetic in that case.
|
|
65
|
+
int StableSign(const S2Point& a, const S2Point& b, const S2Point& c) {
|
|
66
|
+
Vector3_d ab = b - a;
|
|
67
|
+
Vector3_d bc = c - b;
|
|
68
|
+
Vector3_d ca = a - c;
|
|
69
|
+
double ab2 = ab.Norm2();
|
|
70
|
+
double bc2 = bc.Norm2();
|
|
71
|
+
double ca2 = ca.Norm2();
|
|
72
|
+
|
|
73
|
+
// Now compute the determinant ((A-C)x(B-C)).C, where the vertices have been
|
|
74
|
+
// cyclically permuted if necessary so that AB is the longest edge. (This
|
|
75
|
+
// minimizes the magnitude of cross product.) At the same time we also
|
|
76
|
+
// compute the maximum error in the determinant. Using a similar technique
|
|
77
|
+
// to the one used for kMaxDetError, the error is at most
|
|
78
|
+
//
|
|
79
|
+
// |d| <= (3 + 6/sqrt(3)) * |A-C| * |B-C| * e
|
|
80
|
+
//
|
|
81
|
+
// where e = 0.5 * DBL_EPSILON. If the determinant magnitude is larger than
|
|
82
|
+
// this value then we know its sign with certainty.
|
|
83
|
+
const double kDetErrorMultiplier = 3.2321 * DBL_EPSILON; // see above
|
|
84
|
+
double det, max_error;
|
|
85
|
+
if (ab2 >= bc2 && ab2 >= ca2) {
|
|
86
|
+
// AB is the longest edge, so compute (A-C)x(B-C).C.
|
|
87
|
+
det = -(ca.CrossProd(bc).DotProd(c));
|
|
88
|
+
max_error = kDetErrorMultiplier * sqrt(ca2 * bc2);
|
|
89
|
+
} else if (bc2 >= ca2) {
|
|
90
|
+
// BC is the longest edge, so compute (B-A)x(C-A).A.
|
|
91
|
+
det = -(ab.CrossProd(ca).DotProd(a));
|
|
92
|
+
max_error = kDetErrorMultiplier * sqrt(ab2 * ca2);
|
|
93
|
+
} else {
|
|
94
|
+
// CA is the longest edge, so compute (C-B)x(A-B).B.
|
|
95
|
+
det = -(bc.CrossProd(ab).DotProd(b));
|
|
96
|
+
max_error = kDetErrorMultiplier * sqrt(bc2 * ab2);
|
|
97
|
+
}
|
|
98
|
+
return (fabs(det) <= max_error) ? 0 : (det > 0) ? 1 : -1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// The following function returns the sign of the determinant of three points
|
|
102
|
+
// A, B, C under a model where every possible S2Point is slightly perturbed by
|
|
103
|
+
// a unique infinitesmal amount such that no three perturbed points are
|
|
104
|
+
// collinear and no four points are coplanar. The perturbations are so small
|
|
105
|
+
// that they do not change the sign of any determinant that was non-zero
|
|
106
|
+
// before the perturbations, and therefore can be safely ignored unless the
|
|
107
|
+
// determinant of three points is exactly zero (using multiple-precision
|
|
108
|
+
// arithmetic).
|
|
109
|
+
//
|
|
110
|
+
// Since the symbolic perturbation of a given point is fixed (i.e., the
|
|
111
|
+
// perturbation is the same for all calls to this method and does not depend
|
|
112
|
+
// on the other two arguments), the results of this method are always
|
|
113
|
+
// self-consistent. It will never return results that would correspond to an
|
|
114
|
+
// "impossible" configuration of non-degenerate points.
|
|
115
|
+
//
|
|
116
|
+
// Requirements:
|
|
117
|
+
// The 3x3 determinant of A, B, C must be exactly zero.
|
|
118
|
+
// The points must be distinct, with A < B < C in lexicographic order.
|
|
119
|
+
//
|
|
120
|
+
// Returns:
|
|
121
|
+
// +1 or -1 according to the sign of the determinant after the symbolic
|
|
122
|
+
// perturbations are taken into account.
|
|
123
|
+
//
|
|
124
|
+
// Reference:
|
|
125
|
+
// "Simulation of Simplicity" (Edelsbrunner and Muecke, ACM Transactions on
|
|
126
|
+
// Graphics, 1990).
|
|
127
|
+
//
|
|
128
|
+
int SymbolicallyPerturbedSign(
|
|
129
|
+
const Vector3_xf& a, const Vector3_xf& b,
|
|
130
|
+
const Vector3_xf& c, const Vector3_xf& b_cross_c) {
|
|
131
|
+
// This method requires that the points are sorted in lexicographically
|
|
132
|
+
// increasing order. This is because every possible S2Point has its own
|
|
133
|
+
// symbolic perturbation such that if A < B then the symbolic perturbation
|
|
134
|
+
// for A is much larger than the perturbation for B.
|
|
135
|
+
//
|
|
136
|
+
// Alternatively, we could sort the points in this method and keep track of
|
|
137
|
+
// the sign of the permutation, but it is more efficient to do this before
|
|
138
|
+
// converting the inputs to the multi-precision representation, and this
|
|
139
|
+
// also lets us re-use the result of the cross product B x C.
|
|
140
|
+
S2_DCHECK(a < b && b < c);
|
|
141
|
+
|
|
142
|
+
// Every input coordinate x[i] is assigned a symbolic perturbation dx[i].
|
|
143
|
+
// We then compute the sign of the determinant of the perturbed points,
|
|
144
|
+
// i.e.
|
|
145
|
+
// | a[0]+da[0] a[1]+da[1] a[2]+da[2] |
|
|
146
|
+
// | b[0]+db[0] b[1]+db[1] b[2]+db[2] |
|
|
147
|
+
// | c[0]+dc[0] c[1]+dc[1] c[2]+dc[2] |
|
|
148
|
+
//
|
|
149
|
+
// The perturbations are chosen such that
|
|
150
|
+
//
|
|
151
|
+
// da[2] > da[1] > da[0] > db[2] > db[1] > db[0] > dc[2] > dc[1] > dc[0]
|
|
152
|
+
//
|
|
153
|
+
// where each perturbation is so much smaller than the previous one that we
|
|
154
|
+
// don't even need to consider it unless the coefficients of all previous
|
|
155
|
+
// perturbations are zero. In fact, it is so small that we don't need to
|
|
156
|
+
// consider it unless the coefficient of all products of the previous
|
|
157
|
+
// perturbations are zero. For example, we don't need to consider the
|
|
158
|
+
// coefficient of db[1] unless the coefficient of db[2]*da[0] is zero.
|
|
159
|
+
//
|
|
160
|
+
// The follow code simply enumerates the coefficients of the perturbations
|
|
161
|
+
// (and products of perturbations) that appear in the determinant above, in
|
|
162
|
+
// order of decreasing perturbation magnitude. The first non-zero
|
|
163
|
+
// coefficient determines the sign of the result. The easiest way to
|
|
164
|
+
// enumerate the coefficients in the correct order is to pretend that each
|
|
165
|
+
// perturbation is some tiny value "eps" raised to a power of two:
|
|
166
|
+
//
|
|
167
|
+
// eps** 1 2 4 8 16 32 64 128 256
|
|
168
|
+
// da[2] da[1] da[0] db[2] db[1] db[0] dc[2] dc[1] dc[0]
|
|
169
|
+
//
|
|
170
|
+
// Essentially we can then just count in binary and test the corresponding
|
|
171
|
+
// subset of perturbations at each step. So for example, we must test the
|
|
172
|
+
// coefficient of db[2]*da[0] before db[1] because eps**12 > eps**16.
|
|
173
|
+
//
|
|
174
|
+
// Of course, not all products of these perturbations appear in the
|
|
175
|
+
// determinant above, since the determinant only contains the products of
|
|
176
|
+
// elements in distinct rows and columns. Thus we don't need to consider
|
|
177
|
+
// da[2]*da[1], db[1]*da[1], etc. Furthermore, sometimes different pairs of
|
|
178
|
+
// perturbations have the same coefficient in the determinant; for example,
|
|
179
|
+
// da[1]*db[0] and db[1]*da[0] have the same coefficient (c[2]). Therefore
|
|
180
|
+
// we only need to test this coefficient the first time we encounter it in
|
|
181
|
+
// the binary order above (which will be db[1]*da[0]).
|
|
182
|
+
//
|
|
183
|
+
// The sequence of tests below also appears in Table 4-ii of the paper
|
|
184
|
+
// referenced above, if you just want to look it up, with the following
|
|
185
|
+
// translations: [a,b,c] -> [i,j,k] and [0,1,2] -> [1,2,3]. Also note that
|
|
186
|
+
// some of the signs are different because the opposite cross product is
|
|
187
|
+
// used (e.g., B x C rather than C x B).
|
|
188
|
+
|
|
189
|
+
int det_sign = b_cross_c[2].sgn(); // da[2]
|
|
190
|
+
if (det_sign != 0) return det_sign;
|
|
191
|
+
det_sign = b_cross_c[1].sgn(); // da[1]
|
|
192
|
+
if (det_sign != 0) return det_sign;
|
|
193
|
+
det_sign = b_cross_c[0].sgn(); // da[0]
|
|
194
|
+
if (det_sign != 0) return det_sign;
|
|
195
|
+
|
|
196
|
+
det_sign = (c[0]*a[1] - c[1]*a[0]).sgn(); // db[2]
|
|
197
|
+
if (det_sign != 0) return det_sign;
|
|
198
|
+
det_sign = c[0].sgn(); // db[2] * da[1]
|
|
199
|
+
if (det_sign != 0) return det_sign;
|
|
200
|
+
det_sign = -(c[1].sgn()); // db[2] * da[0]
|
|
201
|
+
if (det_sign != 0) return det_sign;
|
|
202
|
+
det_sign = (c[2]*a[0] - c[0]*a[2]).sgn(); // db[1]
|
|
203
|
+
if (det_sign != 0) return det_sign;
|
|
204
|
+
det_sign = c[2].sgn(); // db[1] * da[0]
|
|
205
|
+
if (det_sign != 0) return det_sign;
|
|
206
|
+
// The following test is listed in the paper, but it is redundant because
|
|
207
|
+
// the previous tests guarantee that C == (0, 0, 0).
|
|
208
|
+
S2_DCHECK_EQ(0, (c[1]*a[2] - c[2]*a[1]).sgn()); // db[0]
|
|
209
|
+
|
|
210
|
+
det_sign = (a[0]*b[1] - a[1]*b[0]).sgn(); // dc[2]
|
|
211
|
+
if (det_sign != 0) return det_sign;
|
|
212
|
+
det_sign = -(b[0].sgn()); // dc[2] * da[1]
|
|
213
|
+
if (det_sign != 0) return det_sign;
|
|
214
|
+
det_sign = b[1].sgn(); // dc[2] * da[0]
|
|
215
|
+
if (det_sign != 0) return det_sign;
|
|
216
|
+
det_sign = a[0].sgn(); // dc[2] * db[1]
|
|
217
|
+
if (det_sign != 0) return det_sign;
|
|
218
|
+
return 1; // dc[2] * db[1] * da[0]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Compute the determinant using exact arithmetic and/or symbolic
|
|
222
|
+
// permutations. Requires that the three points are distinct.
|
|
223
|
+
int ExactSign(const S2Point& a, const S2Point& b, const S2Point& c,
|
|
224
|
+
bool perturb) {
|
|
225
|
+
S2_DCHECK(a != b && b != c && c != a);
|
|
226
|
+
|
|
227
|
+
// Sort the three points in lexicographic order, keeping track of the sign
|
|
228
|
+
// of the permutation. (Each exchange inverts the sign of the determinant.)
|
|
229
|
+
int perm_sign = 1;
|
|
230
|
+
const S2Point *pa = &a, *pb = &b, *pc = &c;
|
|
231
|
+
using std::swap;
|
|
232
|
+
if (*pa > *pb) { swap(pa, pb); perm_sign = -perm_sign; }
|
|
233
|
+
if (*pb > *pc) { swap(pb, pc); perm_sign = -perm_sign; }
|
|
234
|
+
if (*pa > *pb) { swap(pa, pb); perm_sign = -perm_sign; }
|
|
235
|
+
S2_DCHECK(*pa < *pb && *pb < *pc);
|
|
236
|
+
|
|
237
|
+
// Construct multiple-precision versions of the sorted points and compute
|
|
238
|
+
// their exact 3x3 determinant.
|
|
239
|
+
Vector3_xf xa = Vector3_xf::Cast(*pa);
|
|
240
|
+
Vector3_xf xb = Vector3_xf::Cast(*pb);
|
|
241
|
+
Vector3_xf xc = Vector3_xf::Cast(*pc);
|
|
242
|
+
Vector3_xf xb_cross_xc = xb.CrossProd(xc);
|
|
243
|
+
ExactFloat det = xa.DotProd(xb_cross_xc);
|
|
244
|
+
|
|
245
|
+
// The precision of ExactFloat is high enough that the result should always
|
|
246
|
+
// be exact (no rounding was performed).
|
|
247
|
+
S2_DCHECK(!det.is_nan());
|
|
248
|
+
S2_DCHECK_LT(det.prec(), det.max_prec());
|
|
249
|
+
|
|
250
|
+
// If the exact determinant is non-zero, we're done.
|
|
251
|
+
int det_sign = det.sgn();
|
|
252
|
+
if (det_sign == 0 && perturb) {
|
|
253
|
+
// Otherwise, we need to resort to symbolic perturbations to resolve the
|
|
254
|
+
// sign of the determinant.
|
|
255
|
+
det_sign = SymbolicallyPerturbedSign(xa, xb, xc, xb_cross_xc);
|
|
256
|
+
S2_DCHECK_NE(0, det_sign);
|
|
257
|
+
}
|
|
258
|
+
return perm_sign * det_sign;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ExpensiveSign() uses arbitrary-precision arithmetic and the "simulation of
|
|
262
|
+
// simplicity" technique in order to be completely robust (i.e., to return
|
|
263
|
+
// consistent results for all possible inputs).
|
|
264
|
+
//
|
|
265
|
+
// Below we define a floating-point type with enough precision so that it can
|
|
266
|
+
// represent the exact determinant of any 3x3 matrix of floating-point
|
|
267
|
+
// numbers. It uses ExactFloat, which is based on the OpenSSL Bignum library
|
|
268
|
+
// and therefore has a permissive BSD-style license. (At one time we also
|
|
269
|
+
// supported an option based on MPFR, but that has an LGPL license and is
|
|
270
|
+
// therefore not suited for some applications.)
|
|
271
|
+
|
|
272
|
+
using Vector3_xf = Vector3<ExactFloat>;
|
|
273
|
+
|
|
274
|
+
int ExpensiveSign(const S2Point& a, const S2Point& b, const S2Point& c,
|
|
275
|
+
bool perturb) {
|
|
276
|
+
// Return zero if and only if two points are the same. This ensures (1).
|
|
277
|
+
if (a == b || b == c || c == a) return 0;
|
|
278
|
+
|
|
279
|
+
// Next we try recomputing the determinant still using floating-point
|
|
280
|
+
// arithmetic but in a more precise way. This is more expensive than the
|
|
281
|
+
// simple calculation done by TriageSign(), but it is still *much* cheaper
|
|
282
|
+
// than using arbitrary-precision arithmetic. This optimization is able to
|
|
283
|
+
// compute the correct determinant sign in virtually all cases except when
|
|
284
|
+
// the three points are truly collinear (e.g., three points on the equator).
|
|
285
|
+
int det_sign = StableSign(a, b, c);
|
|
286
|
+
if (det_sign != 0) return det_sign;
|
|
287
|
+
|
|
288
|
+
// TODO(ericv): Create a templated version of StableSign so that we can
|
|
289
|
+
// retry in "long double" precision before falling back to ExactFloat.
|
|
290
|
+
|
|
291
|
+
// TODO(ericv): Optimize ExactFloat so that it stores up to 32 bytes of
|
|
292
|
+
// mantissa inline (without requiring memory allocation).
|
|
293
|
+
|
|
294
|
+
// Otherwise fall back to exact arithmetic and symbolic permutations.
|
|
295
|
+
return ExactSign(a, b, c, perturb);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
bool OrderedCCW(const S2Point& a, const S2Point& b, const S2Point& c,
|
|
299
|
+
const S2Point& o) {
|
|
300
|
+
// The last inequality below is ">" rather than ">=" so that we return true
|
|
301
|
+
// if A == B or B == C, and otherwise false if A == C. Recall that
|
|
302
|
+
// Sign(x,y,z) == -Sign(z,y,x) for all x,y,z.
|
|
303
|
+
|
|
304
|
+
int sum = 0;
|
|
305
|
+
if (Sign(b, o, a) >= 0) ++sum;
|
|
306
|
+
if (Sign(c, o, b) >= 0) ++sum;
|
|
307
|
+
if (Sign(a, o, c) > 0) ++sum;
|
|
308
|
+
return sum >= 2;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Returns cos(XY), and sets "error" to the maximum error in the result.
|
|
312
|
+
// REQUIRES: "x" and "y" satisfy S2::IsNormalized().
|
|
313
|
+
inline double GetCosDistance(const S2Point& x, const S2Point& y,
|
|
314
|
+
double* error) {
|
|
315
|
+
double c = x.DotProd(y);
|
|
316
|
+
*error = 9.5 * DBL_ERR * fabs(c) + 1.5 * DBL_ERR;
|
|
317
|
+
return c;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// A high precision "long double" version of the function above.
|
|
321
|
+
inline long double GetCosDistance(const Vector3_ld& x, const Vector3_ld& y,
|
|
322
|
+
long double* error) {
|
|
323
|
+
// With "long double" precision it is worthwhile to compensate for length
|
|
324
|
+
// errors in "x" and "y", since they are only unit length to within the
|
|
325
|
+
// precision of "double". (This would also reduce the error constant
|
|
326
|
+
// slightly in the method above but is not worth the additional effort.)
|
|
327
|
+
long double c = x.DotProd(y) / sqrt(x.Norm2() * y.Norm2());
|
|
328
|
+
*error = 7 * LD_ERR * fabs(c) + 1.5 * LD_ERR;
|
|
329
|
+
return c;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Returns sin**2(XY), where XY is the angle between X and Y, and sets "error"
|
|
333
|
+
// to the maximum error in the result.
|
|
334
|
+
//
|
|
335
|
+
// REQUIRES: "x" and "y" satisfy S2::IsNormalized().
|
|
336
|
+
inline double GetSin2Distance(const S2Point& x, const S2Point& y,
|
|
337
|
+
double* error) {
|
|
338
|
+
// The (x-y).CrossProd(x+y) trick eliminates almost all of error due to "x"
|
|
339
|
+
// and "y" being not quite unit length. This method is extremely accurate
|
|
340
|
+
// for small distances; the *relative* error in the result is O(DBL_ERR) for
|
|
341
|
+
// distances as small as DBL_ERR.
|
|
342
|
+
S2Point n = (x - y).CrossProd(x + y);
|
|
343
|
+
double d2 = 0.25 * n.Norm2();
|
|
344
|
+
*error = ((21 + 4 * sqrt(3)) * DBL_ERR * d2 +
|
|
345
|
+
32 * sqrt(3) * DBL_ERR * DBL_ERR * sqrt(d2) +
|
|
346
|
+
768 * DBL_ERR * DBL_ERR * DBL_ERR * DBL_ERR);
|
|
347
|
+
return d2;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// A high precision "long double" version of the function above.
|
|
351
|
+
inline long double GetSin2Distance(const Vector3_ld& x, const Vector3_ld& y,
|
|
352
|
+
long double* error) {
|
|
353
|
+
// In "long double" precision it is worthwhile to compensate for length
|
|
354
|
+
// errors in "x" and "y", since they are only unit length to within the
|
|
355
|
+
// precision of "double". Otherwise the "d2" error coefficient below would
|
|
356
|
+
// be (16 * DBL_ERR + (5 + 4 * sqrt(3)) * LD_ERR), which is much larger.
|
|
357
|
+
// (Dividing by the squared norms of "x" and "y" would also reduce the error
|
|
358
|
+
// constant slightly in the double-precision version, but this is not worth
|
|
359
|
+
// the additional effort.)
|
|
360
|
+
Vector3_ld n = (x - y).CrossProd(x + y);
|
|
361
|
+
long double d2 = 0.25 * n.Norm2() / (x.Norm2() * y.Norm2());
|
|
362
|
+
*error = ((13 + 4 * sqrt(3)) * LD_ERR * d2 +
|
|
363
|
+
32 * sqrt(3) * DBL_ERR * LD_ERR * sqrt(d2) +
|
|
364
|
+
768 * DBL_ERR * DBL_ERR * LD_ERR * LD_ERR);
|
|
365
|
+
return d2;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
template <class T>
|
|
369
|
+
int TriageCompareCosDistances(const Vector3<T>& x,
|
|
370
|
+
const Vector3<T>& a, const Vector3<T>& b) {
|
|
371
|
+
T cos_ax_error, cos_bx_error;
|
|
372
|
+
T cos_ax = GetCosDistance(a, x, &cos_ax_error);
|
|
373
|
+
T cos_bx = GetCosDistance(b, x, &cos_bx_error);
|
|
374
|
+
T diff = cos_ax - cos_bx;
|
|
375
|
+
T error = cos_ax_error + cos_bx_error;
|
|
376
|
+
return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
template <class T>
|
|
380
|
+
int TriageCompareSin2Distances(const Vector3<T>& x,
|
|
381
|
+
const Vector3<T>& a, const Vector3<T>& b) {
|
|
382
|
+
T sin2_ax_error, sin2_bx_error;
|
|
383
|
+
T sin2_ax = GetSin2Distance(a, x, &sin2_ax_error);
|
|
384
|
+
T sin2_bx = GetSin2Distance(b, x, &sin2_bx_error);
|
|
385
|
+
T diff = sin2_ax - sin2_bx;
|
|
386
|
+
T error = sin2_ax_error + sin2_bx_error;
|
|
387
|
+
return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
int ExactCompareDistances(const Vector3_xf& x,
|
|
391
|
+
const Vector3_xf& a, const Vector3_xf& b) {
|
|
392
|
+
// This code produces the same result as though all points were reprojected
|
|
393
|
+
// to lie exactly on the surface of the unit sphere. It is based on testing
|
|
394
|
+
// whether x.DotProd(a.Normalize()) < x.DotProd(b.Normalize()), reformulated
|
|
395
|
+
// so that it can be evaluated using exact arithmetic.
|
|
396
|
+
ExactFloat cos_ax = x.DotProd(a);
|
|
397
|
+
ExactFloat cos_bx = x.DotProd(b);
|
|
398
|
+
// If the two values have different signs, we need to handle that case now
|
|
399
|
+
// before squaring them below.
|
|
400
|
+
int a_sign = cos_ax.sgn(), b_sign = cos_bx.sgn();
|
|
401
|
+
if (a_sign != b_sign) {
|
|
402
|
+
return (a_sign > b_sign) ? -1 : 1; // If cos(AX) > cos(BX), then AX < BX.
|
|
403
|
+
}
|
|
404
|
+
ExactFloat cmp = cos_bx * cos_bx * a.Norm2() - cos_ax * cos_ax * b.Norm2();
|
|
405
|
+
return a_sign * cmp.sgn();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Given three points such that AX == BX (exactly), returns -1, 0, or +1
|
|
409
|
+
// according whether AX < BX, AX == BX, or AX > BX after symbolic
|
|
410
|
+
// perturbations are taken into account.
|
|
411
|
+
int SymbolicCompareDistances(const S2Point& x,
|
|
412
|
+
const S2Point& a, const S2Point& b) {
|
|
413
|
+
// Our symbolic perturbation strategy is based on the following model.
|
|
414
|
+
// Similar to "simulation of simplicity", we assign a perturbation to every
|
|
415
|
+
// point such that if A < B, then the symbolic perturbation for A is much,
|
|
416
|
+
// much larger than the symbolic perturbation for B. We imagine that
|
|
417
|
+
// rather than projecting every point to lie exactly on the unit sphere,
|
|
418
|
+
// instead each point is positioned on its own tiny pedestal that raises it
|
|
419
|
+
// just off the surface of the unit sphere. This means that the distance AX
|
|
420
|
+
// is actually the true distance AX plus the (symbolic) heights of the
|
|
421
|
+
// pedestals for A and X. The pedestals are infinitesmally thin, so they do
|
|
422
|
+
// not affect distance measurements except at the two endpoints. If several
|
|
423
|
+
// points project to exactly the same point on the unit sphere, we imagine
|
|
424
|
+
// that they are placed on separate pedestals placed close together, where
|
|
425
|
+
// the distance between pedestals is much, much less than the height of any
|
|
426
|
+
// pedestal. (There are a finite number of S2Points, and therefore a finite
|
|
427
|
+
// number of pedestals, so this is possible.)
|
|
428
|
+
//
|
|
429
|
+
// If A < B, then A is on a higher pedestal than B, and therefore AX > BX.
|
|
430
|
+
return (a < b) ? 1 : (a > b) ? -1 : 0;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
static int CompareSin2Distances(const S2Point& x,
|
|
434
|
+
const S2Point& a, const S2Point& b) {
|
|
435
|
+
int sign = TriageCompareSin2Distances(x, a, b);
|
|
436
|
+
if (sign != 0) return sign;
|
|
437
|
+
return TriageCompareSin2Distances(ToLD(x), ToLD(a), ToLD(b));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
int CompareDistances(const S2Point& x, const S2Point& a, const S2Point& b) {
|
|
441
|
+
// We start by comparing distances using dot products (i.e., cosine of the
|
|
442
|
+
// angle), because (1) this is the cheapest technique, and (2) it is valid
|
|
443
|
+
// over the entire range of possible angles. (We can only use the sin^2
|
|
444
|
+
// technique if both angles are less than 90 degrees or both angles are
|
|
445
|
+
// greater than 90 degrees.)
|
|
446
|
+
int sign = TriageCompareCosDistances(x, a, b);
|
|
447
|
+
if (sign != 0) return sign;
|
|
448
|
+
|
|
449
|
+
// Optimization for (a == b) to avoid falling back to exact arithmetic.
|
|
450
|
+
if (a == b) return 0;
|
|
451
|
+
|
|
452
|
+
// It is much better numerically to compare distances using cos(angle) if
|
|
453
|
+
// the distances are near 90 degrees and sin^2(angle) if the distances are
|
|
454
|
+
// near 0 or 180 degrees. We only need to check one of the two angles when
|
|
455
|
+
// making this decision because the fact that the test above failed means
|
|
456
|
+
// that angles "a" and "b" are very close together.
|
|
457
|
+
double cos_ax = a.DotProd(x);
|
|
458
|
+
if (cos_ax > M_SQRT1_2) {
|
|
459
|
+
// Angles < 45 degrees.
|
|
460
|
+
sign = CompareSin2Distances(x, a, b);
|
|
461
|
+
} else if (cos_ax < -M_SQRT1_2) {
|
|
462
|
+
// Angles > 135 degrees. sin^2(angle) is decreasing in this range.
|
|
463
|
+
sign = -CompareSin2Distances(x, a, b);
|
|
464
|
+
} else {
|
|
465
|
+
// We've already tried double precision, so continue with "long double".
|
|
466
|
+
sign = TriageCompareCosDistances(ToLD(x), ToLD(a), ToLD(b));
|
|
467
|
+
}
|
|
468
|
+
if (sign != 0) return sign;
|
|
469
|
+
sign = ExactCompareDistances(ToExact(x), ToExact(a), ToExact(b));
|
|
470
|
+
if (sign != 0) return sign;
|
|
471
|
+
return SymbolicCompareDistances(x, a, b);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
template <class T>
|
|
475
|
+
int TriageCompareCosDistance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
|
|
476
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
477
|
+
T cos_xy_error;
|
|
478
|
+
T cos_xy = GetCosDistance(x, y, &cos_xy_error);
|
|
479
|
+
T cos_r = 1 - 0.5 * r2;
|
|
480
|
+
T cos_r_error = 2 * T_ERR * cos_r;
|
|
481
|
+
T diff = cos_xy - cos_r;
|
|
482
|
+
T error = cos_xy_error + cos_r_error;
|
|
483
|
+
return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
template <class T>
|
|
487
|
+
int TriageCompareSin2Distance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
|
|
488
|
+
S2_DCHECK_LT(r2, 2.0); // Only valid for distance limits < 90 degrees.
|
|
489
|
+
|
|
490
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
491
|
+
T sin2_xy_error;
|
|
492
|
+
T sin2_xy = GetSin2Distance(x, y, &sin2_xy_error);
|
|
493
|
+
T sin2_r = r2 * (1 - 0.25 * r2);
|
|
494
|
+
T sin2_r_error = 3 * T_ERR * sin2_r;
|
|
495
|
+
T diff = sin2_xy - sin2_r;
|
|
496
|
+
T error = sin2_xy_error + sin2_r_error;
|
|
497
|
+
return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
int ExactCompareDistance(const Vector3_xf& x, const Vector3_xf& y,
|
|
501
|
+
const ExactFloat& r2) {
|
|
502
|
+
// This code produces the same result as though all points were reprojected
|
|
503
|
+
// to lie exactly on the surface of the unit sphere. It is based on
|
|
504
|
+
// comparing the cosine of the angle XY (when both points are projected to
|
|
505
|
+
// lie exactly on the sphere) to the given threshold.
|
|
506
|
+
ExactFloat cos_xy = x.DotProd(y);
|
|
507
|
+
ExactFloat cos_r = 1 - 0.5 * r2;
|
|
508
|
+
// If the two values have different signs, we need to handle that case now
|
|
509
|
+
// before squaring them below.
|
|
510
|
+
int xy_sign = cos_xy.sgn(), r_sign = cos_r.sgn();
|
|
511
|
+
if (xy_sign != r_sign) {
|
|
512
|
+
return (xy_sign > r_sign) ? -1 : 1; // If cos(XY) > cos(r), then XY < r.
|
|
513
|
+
}
|
|
514
|
+
ExactFloat cmp = cos_r * cos_r * x.Norm2() * y.Norm2() - cos_xy * cos_xy;
|
|
515
|
+
return xy_sign * cmp.sgn();
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
int CompareDistance(const S2Point& x, const S2Point& y, S1ChordAngle r) {
|
|
519
|
+
// As with CompareDistances(), we start by comparing dot products because
|
|
520
|
+
// the sin^2 method is only valid when the distance XY and the limit "r" are
|
|
521
|
+
// both less than 90 degrees.
|
|
522
|
+
int sign = TriageCompareCosDistance(x, y, r.length2());
|
|
523
|
+
if (sign != 0) return sign;
|
|
524
|
+
|
|
525
|
+
// Unlike with CompareDistances(), it's not worth using the sin^2 method
|
|
526
|
+
// when the distance limit is near 180 degrees because the S1ChordAngle
|
|
527
|
+
// representation itself has has a rounding error of up to 2e-8 radians for
|
|
528
|
+
// distances near 180 degrees.
|
|
529
|
+
if (r < k45Degrees) {
|
|
530
|
+
sign = TriageCompareSin2Distance(x, y, r.length2());
|
|
531
|
+
if (sign != 0) return sign;
|
|
532
|
+
sign = TriageCompareSin2Distance(ToLD(x), ToLD(y), ToLD(r.length2()));
|
|
533
|
+
} else {
|
|
534
|
+
sign = TriageCompareCosDistance(ToLD(x), ToLD(y), ToLD(r.length2()));
|
|
535
|
+
}
|
|
536
|
+
if (sign != 0) return sign;
|
|
537
|
+
return ExactCompareDistance(ToExact(x), ToExact(y), r.length2());
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Helper function that compares the distance XY against the squared chord
|
|
541
|
+
// distance "r2" using the given precision "T".
|
|
542
|
+
template <class T>
|
|
543
|
+
int TriageCompareDistance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
|
|
544
|
+
// The Sin2 method is much more accurate for small distances, but it is only
|
|
545
|
+
// valid when the actual distance and the distance limit are both less than
|
|
546
|
+
// 90 degrees. So we always start with the Cos method.
|
|
547
|
+
int sign = TriageCompareCosDistance(x, y, r2);
|
|
548
|
+
if (sign == 0 && r2 < k45Degrees.length2()) {
|
|
549
|
+
sign = TriageCompareSin2Distance(x, y, r2);
|
|
550
|
+
}
|
|
551
|
+
return sign;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Helper function that returns "a0" or "a1", whichever is closer to "x".
|
|
555
|
+
// Also returns the squared distance from the returned point to "x" in "ax2".
|
|
556
|
+
template <class T>
|
|
557
|
+
inline Vector3<T> GetClosestVertex(const Vector3<T>& x, const Vector3<T>& a0,
|
|
558
|
+
const Vector3<T>& a1, T* ax2) {
|
|
559
|
+
T a0x2 = (a0 - x).Norm2();
|
|
560
|
+
T a1x2 = (a1 - x).Norm2();
|
|
561
|
+
if (a0x2 < a1x2 || (a0x2 == a1x2 && a0 < a1)) {
|
|
562
|
+
*ax2 = a0x2;
|
|
563
|
+
return a0;
|
|
564
|
+
} else {
|
|
565
|
+
*ax2 = a1x2;
|
|
566
|
+
return a1;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Helper function that returns -1, 0, or +1 according to whether the distance
|
|
571
|
+
// from "x" to the great circle through (a0, a1) is less than, equal to, or
|
|
572
|
+
// greater than the given squared chord length "r2". This method computes the
|
|
573
|
+
// squared sines of the distances involved, which is more accurate when the
|
|
574
|
+
// distances are small (less than 45 degrees).
|
|
575
|
+
//
|
|
576
|
+
// The remaining parameters are functions of (a0, a1) and are passed in
|
|
577
|
+
// because they have already been computed: n = (a0 - a1) x (a0 + a1),
|
|
578
|
+
// n1 = n.Norm(), and n2 = n.Norm2().
|
|
579
|
+
template <class T>
|
|
580
|
+
int TriageCompareLineSin2Distance(const Vector3<T>& x, const Vector3<T>& a0,
|
|
581
|
+
const Vector3<T>& a1, T r2,
|
|
582
|
+
const Vector3<T>& n, T n1, T n2) {
|
|
583
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
584
|
+
|
|
585
|
+
// The minimum distance is to a point on the edge interior. Since the true
|
|
586
|
+
// distance to the edge is always less than 90 degrees, we can return
|
|
587
|
+
// immediately if the limit is 90 degrees or larger.
|
|
588
|
+
if (r2 >= 2.0) return -1; // distance < limit
|
|
589
|
+
|
|
590
|
+
// Otherwise we compute sin^2(distance to edge) to get the best accuracy
|
|
591
|
+
// when the distance limit is small (e.g., S2::kIntersectionError).
|
|
592
|
+
T n2sin2_r = n2 * r2 * (1 - 0.25 * r2);
|
|
593
|
+
T n2sin2_r_error = 6 * T_ERR * n2sin2_r;
|
|
594
|
+
T ax2, xDn = (x - GetClosestVertex(x, a0, a1, &ax2)).DotProd(n);
|
|
595
|
+
T xDn2 = xDn * xDn;
|
|
596
|
+
const T c1 = (((3.5 + 2 * sqrt(3)) * n1 + 32 * sqrt(3) * DBL_ERR) *
|
|
597
|
+
T_ERR * sqrt(ax2));
|
|
598
|
+
T xDn2_error = 4 * T_ERR * xDn2 + (2 * fabs(xDn) + c1) * c1;
|
|
599
|
+
|
|
600
|
+
// If we are using extended precision, then it is worthwhile to recompute
|
|
601
|
+
// the length of X more accurately. Otherwise we use the fact that X is
|
|
602
|
+
// guaranteed to be unit length to with a tolerance of 4 * DBL_ERR.
|
|
603
|
+
if (T_ERR < DBL_ERR) {
|
|
604
|
+
n2sin2_r *= x.Norm2();
|
|
605
|
+
n2sin2_r_error += 4 * T_ERR * n2sin2_r;
|
|
606
|
+
} else {
|
|
607
|
+
n2sin2_r_error += 8 * DBL_ERR * n2sin2_r;
|
|
608
|
+
}
|
|
609
|
+
T diff = xDn2 - n2sin2_r;
|
|
610
|
+
T error = xDn2_error + n2sin2_r_error;
|
|
611
|
+
return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Like TriageCompareLineSin2Distance, but this method computes the squared
|
|
615
|
+
// cosines of the distances involved. It is more accurate when the distances
|
|
616
|
+
// are large (greater than 45 degrees).
|
|
617
|
+
template <class T>
|
|
618
|
+
int TriageCompareLineCos2Distance(const Vector3<T>& x, const Vector3<T>& a0,
|
|
619
|
+
const Vector3<T>& a1, T r2,
|
|
620
|
+
const Vector3<T>& n, T n1, T n2) {
|
|
621
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
622
|
+
|
|
623
|
+
// The minimum distance is to a point on the edge interior. Since the true
|
|
624
|
+
// distance to the edge is always less than 90 degrees, we can return
|
|
625
|
+
// immediately if the limit is 90 degrees or larger.
|
|
626
|
+
if (r2 >= 2.0) return -1; // distance < limit
|
|
627
|
+
|
|
628
|
+
// Otherwise we compute cos^2(distance to edge).
|
|
629
|
+
T cos_r = 1 - 0.5 * r2;
|
|
630
|
+
T n2cos2_r = n2 * cos_r * cos_r;
|
|
631
|
+
T n2cos2_r_error = 7 * T_ERR * n2cos2_r;
|
|
632
|
+
|
|
633
|
+
// The length of M = X.CrossProd(N) is the cosine of the distance.
|
|
634
|
+
T m2 = x.CrossProd(n).Norm2();
|
|
635
|
+
T m1 = sqrt(m2);
|
|
636
|
+
T m1_error = ((1 + 8 / sqrt(3)) * n1 + 32 * sqrt(3) * DBL_ERR) * T_ERR;
|
|
637
|
+
T m2_error = 3 * T_ERR * m2 + (2 * m1 + m1_error) * m1_error;
|
|
638
|
+
|
|
639
|
+
// If we are using extended precision, then it is worthwhile to recompute
|
|
640
|
+
// the length of X more accurately. Otherwise we use the fact that X is
|
|
641
|
+
// guaranteed to be unit length to within a tolerance of 4 * DBL_ERR.
|
|
642
|
+
if (T_ERR < DBL_ERR) {
|
|
643
|
+
n2cos2_r *= x.Norm2();
|
|
644
|
+
n2cos2_r_error += 4 * T_ERR * n2cos2_r;
|
|
645
|
+
} else {
|
|
646
|
+
n2cos2_r_error += 8 * DBL_ERR * n2cos2_r;
|
|
647
|
+
}
|
|
648
|
+
T diff = m2 - n2cos2_r;
|
|
649
|
+
T error = m2_error + n2cos2_r_error;
|
|
650
|
+
return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
template <class T>
|
|
654
|
+
inline int TriageCompareLineDistance(const Vector3<T>& x, const Vector3<T>& a0,
|
|
655
|
+
const Vector3<T>& a1, T r2,
|
|
656
|
+
const Vector3<T>& n, T n1, T n2) {
|
|
657
|
+
if (r2 < k45Degrees.length2()) {
|
|
658
|
+
return TriageCompareLineSin2Distance(x, a0, a1, r2, n, n1, n2);
|
|
659
|
+
} else {
|
|
660
|
+
return TriageCompareLineCos2Distance(x, a0, a1, r2, n, n1, n2);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
template <class T>
|
|
665
|
+
int TriageCompareEdgeDistance(const Vector3<T>& x, const Vector3<T>& a0,
|
|
666
|
+
const Vector3<T>& a1, T r2) {
|
|
667
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
668
|
+
|
|
669
|
+
// First we need to decide whether the closest point is an edge endpoint or
|
|
670
|
+
// somewhere in the interior. To determine this we compute a plane
|
|
671
|
+
// perpendicular to (a0, a1) that passes through X. Letting M be the normal
|
|
672
|
+
// to this plane, the closest point is in the edge interior if and only if
|
|
673
|
+
// a0.M < 0 and a1.M > 0. Note that we can use "<" rather than "<=" because
|
|
674
|
+
// if a0.M or a1.M is zero exactly then it doesn't matter which code path we
|
|
675
|
+
// follow (since the distance to an endpoint and the distance to the edge
|
|
676
|
+
// interior are exactly the same in this case).
|
|
677
|
+
Vector3<T> n = (a0 - a1).CrossProd(a0 + a1);
|
|
678
|
+
Vector3<T> m = n.CrossProd(x);
|
|
679
|
+
// For better accuracy when the edge (a0,a1) is very short, we subtract "x"
|
|
680
|
+
// before computing the dot products with M.
|
|
681
|
+
Vector3<T> a0_dir = a0 - x;
|
|
682
|
+
Vector3<T> a1_dir = a1 - x;
|
|
683
|
+
T a0_sign = a0_dir.DotProd(m);
|
|
684
|
+
T a1_sign = a1_dir.DotProd(m);
|
|
685
|
+
T n2 = n.Norm2();
|
|
686
|
+
T n1 = sqrt(n2);
|
|
687
|
+
T n1_error = ((3.5 + 8 / sqrt(3)) * n1 + 32 * sqrt(3) * DBL_ERR) * T_ERR;
|
|
688
|
+
T a0_sign_error = n1_error * a0_dir.Norm();
|
|
689
|
+
T a1_sign_error = n1_error * a1_dir.Norm();
|
|
690
|
+
if (fabs(a0_sign) < a0_sign_error || fabs(a1_sign) < a1_sign_error) {
|
|
691
|
+
// It is uncertain whether minimum distance is to an edge vertex or to the
|
|
692
|
+
// edge interior. We handle this by computing both distances and checking
|
|
693
|
+
// whether they yield the same result.
|
|
694
|
+
int vertex_sign = min(TriageCompareDistance(x, a0, r2),
|
|
695
|
+
TriageCompareDistance(x, a1, r2));
|
|
696
|
+
int line_sign = TriageCompareLineDistance(x, a0, a1, r2, n, n1, n2);
|
|
697
|
+
return (vertex_sign == line_sign) ? line_sign : 0;
|
|
698
|
+
}
|
|
699
|
+
if (a0_sign >= 0 || a1_sign <= 0) {
|
|
700
|
+
// The minimum distance is to an edge endpoint.
|
|
701
|
+
return min(TriageCompareDistance(x, a0, r2),
|
|
702
|
+
TriageCompareDistance(x, a1, r2));
|
|
703
|
+
} else {
|
|
704
|
+
// The minimum distance is to the edge interior.
|
|
705
|
+
return TriageCompareLineDistance(x, a0, a1, r2, n, n1, n2);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// REQUIRES: the closest point to "x" is in the interior of edge (a0, a1).
|
|
710
|
+
int ExactCompareLineDistance(const Vector3_xf& x, const Vector3_xf& a0,
|
|
711
|
+
const Vector3_xf& a1, const ExactFloat& r2) {
|
|
712
|
+
// Since we are given that the closest point is in the edge interior, the
|
|
713
|
+
// true distance is always less than 90 degrees (which corresponds to a
|
|
714
|
+
// squared chord length of 2.0).
|
|
715
|
+
if (r2 >= 2.0) return -1; // distance < limit
|
|
716
|
+
|
|
717
|
+
// Otherwise compute the edge normal
|
|
718
|
+
Vector3_xf n = a0.CrossProd(a1);
|
|
719
|
+
ExactFloat sin_d = x.DotProd(n);
|
|
720
|
+
ExactFloat sin2_r = r2 * (1 - 0.25 * r2);
|
|
721
|
+
ExactFloat cmp = sin_d * sin_d - sin2_r * x.Norm2() * n.Norm2();
|
|
722
|
+
return cmp.sgn();
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
int ExactCompareEdgeDistance(const S2Point& x, const S2Point& a0,
|
|
726
|
+
const S2Point& a1, S1ChordAngle r) {
|
|
727
|
+
// Even if previous calculations were uncertain, we might not need to do
|
|
728
|
+
// *all* the calculations in exact arithmetic here. For example it may be
|
|
729
|
+
// easy to determine whether "x" is closer to an endpoint or the edge
|
|
730
|
+
// interior. The only calculation where we always use exact arithmetic is
|
|
731
|
+
// when measuring the distance to the extended line (great circle) through
|
|
732
|
+
// "a0" and "a1", since it is virtually certain that the previous floating
|
|
733
|
+
// point calculations failed in that case.
|
|
734
|
+
//
|
|
735
|
+
// CompareEdgeDirections also checks that no edge has antipodal endpoints.
|
|
736
|
+
if (CompareEdgeDirections(a0, a1, a0, x) > 0 &&
|
|
737
|
+
CompareEdgeDirections(a0, a1, x, a1) > 0) {
|
|
738
|
+
// The closest point to "x" is along the interior of the edge.
|
|
739
|
+
return ExactCompareLineDistance(ToExact(x), ToExact(a0), ToExact(a1),
|
|
740
|
+
r.length2());
|
|
741
|
+
} else {
|
|
742
|
+
// The closest point to "x" is one of the edge endpoints.
|
|
743
|
+
return min(CompareDistance(x, a0, r), CompareDistance(x, a1, r));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
int CompareEdgeDistance(const S2Point& x, const S2Point& a0, const S2Point& a1,
|
|
748
|
+
S1ChordAngle r) {
|
|
749
|
+
// Check that the edge does not consist of antipodal points. (This catches
|
|
750
|
+
// the most common case -- the full test is in ExactCompareEdgeDistance.)
|
|
751
|
+
S2_DCHECK_NE(a0, -a1);
|
|
752
|
+
|
|
753
|
+
int sign = TriageCompareEdgeDistance(x, a0, a1, r.length2());
|
|
754
|
+
if (sign != 0) return sign;
|
|
755
|
+
|
|
756
|
+
// Optimization for the case where the edge is degenerate.
|
|
757
|
+
if (a0 == a1) return CompareDistance(x, a0, r);
|
|
758
|
+
|
|
759
|
+
sign = TriageCompareEdgeDistance(ToLD(x), ToLD(a0), ToLD(a1),
|
|
760
|
+
ToLD(r.length2()));
|
|
761
|
+
if (sign != 0) return sign;
|
|
762
|
+
return ExactCompareEdgeDistance(x, a0, a1, r);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
template <class T>
|
|
766
|
+
int TriageCompareEdgeDirections(
|
|
767
|
+
const Vector3<T>& a0, const Vector3<T>& a1,
|
|
768
|
+
const Vector3<T>& b0, const Vector3<T>& b1) {
|
|
769
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
770
|
+
Vector3<T> na = (a0 - a1).CrossProd(a0 + a1);
|
|
771
|
+
Vector3<T> nb = (b0 - b1).CrossProd(b0 + b1);
|
|
772
|
+
T na_len = na.Norm(), nb_len = nb.Norm();
|
|
773
|
+
T cos_ab = na.DotProd(nb);
|
|
774
|
+
T cos_ab_error = ((5 + 4 * sqrt(3)) * na_len * nb_len +
|
|
775
|
+
32 * sqrt(3) * DBL_ERR * (na_len + nb_len)) * T_ERR;
|
|
776
|
+
return (cos_ab > cos_ab_error) ? 1 : (cos_ab < -cos_ab_error) ? -1 : 0;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
bool ArePointsLinearlyDependent(const Vector3_xf& x, const Vector3_xf& y) {
|
|
780
|
+
Vector3_xf n = x.CrossProd(y);
|
|
781
|
+
return n[0].sgn() == 0 && n[1].sgn() == 0 && n[2].sgn() == 0;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
bool ArePointsAntipodal(const Vector3_xf& x, const Vector3_xf& y) {
|
|
785
|
+
return ArePointsLinearlyDependent(x, y) && x.DotProd(y).sgn() < 0;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
int ExactCompareEdgeDirections(const Vector3_xf& a0, const Vector3_xf& a1,
|
|
789
|
+
const Vector3_xf& b0, const Vector3_xf& b1) {
|
|
790
|
+
S2_DCHECK(!ArePointsAntipodal(a0, a1));
|
|
791
|
+
S2_DCHECK(!ArePointsAntipodal(b0, b1));
|
|
792
|
+
return a0.CrossProd(a1).DotProd(b0.CrossProd(b1)).sgn();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
int CompareEdgeDirections(const S2Point& a0, const S2Point& a1,
|
|
796
|
+
const S2Point& b0, const S2Point& b1) {
|
|
797
|
+
// Check that no edge consists of antipodal points. (This catches the most
|
|
798
|
+
// common case -- the full test is in ExactCompareEdgeDirections.)
|
|
799
|
+
S2_DCHECK_NE(a0, -a1);
|
|
800
|
+
S2_DCHECK_NE(b0, -b1);
|
|
801
|
+
|
|
802
|
+
int sign = TriageCompareEdgeDirections(a0, a1, b0, b1);
|
|
803
|
+
if (sign != 0) return sign;
|
|
804
|
+
|
|
805
|
+
// Optimization for the case where either edge is degenerate.
|
|
806
|
+
if (a0 == a1 || b0 == b1) return 0;
|
|
807
|
+
|
|
808
|
+
sign = TriageCompareEdgeDirections(ToLD(a0), ToLD(a1), ToLD(b0), ToLD(b1));
|
|
809
|
+
if (sign != 0) return sign;
|
|
810
|
+
return ExactCompareEdgeDirections(ToExact(a0), ToExact(a1),
|
|
811
|
+
ToExact(b0), ToExact(b1));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// If triangle ABC has positive sign, returns its circumcenter. If ABC has
|
|
815
|
+
// negative sign, returns the negated circumcenter.
|
|
816
|
+
template <class T>
|
|
817
|
+
Vector3<T> GetCircumcenter(const Vector3<T>& a, const Vector3<T>& b,
|
|
818
|
+
const Vector3<T>& c, T* error) {
|
|
819
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
820
|
+
|
|
821
|
+
// We compute the circumcenter using the intersection of the perpendicular
|
|
822
|
+
// bisectors of AB and BC. The formula is essentially
|
|
823
|
+
//
|
|
824
|
+
// Z = ((A x B) x (A + B)) x ((B x C) x (B + C)),
|
|
825
|
+
//
|
|
826
|
+
// except that we compute the cross product (A x B) as (A - B) x (A + B)
|
|
827
|
+
// (and similarly for B x C) since this is much more stable when the inputs
|
|
828
|
+
// are unit vectors.
|
|
829
|
+
Vector3<T> ab_diff = a - b, ab_sum = a + b;
|
|
830
|
+
Vector3<T> bc_diff = b - c, bc_sum = b + c;
|
|
831
|
+
Vector3<T> nab = ab_diff.CrossProd(ab_sum);
|
|
832
|
+
T nab_len = nab.Norm();
|
|
833
|
+
T ab_len = ab_diff.Norm();
|
|
834
|
+
Vector3<T> nbc = bc_diff.CrossProd(bc_sum);
|
|
835
|
+
T nbc_len = nbc.Norm();
|
|
836
|
+
T bc_len = bc_diff.Norm();
|
|
837
|
+
Vector3<T> mab = nab.CrossProd(ab_sum);
|
|
838
|
+
Vector3<T> mbc = nbc.CrossProd(bc_sum);
|
|
839
|
+
*error = (((16 + 24 * sqrt(3)) * T_ERR +
|
|
840
|
+
8 * DBL_ERR * (ab_len + bc_len)) * nab_len * nbc_len +
|
|
841
|
+
128 * sqrt(3) * DBL_ERR * T_ERR * (nab_len + nbc_len) +
|
|
842
|
+
3 * 4096 * DBL_ERR * DBL_ERR * T_ERR * T_ERR);
|
|
843
|
+
return mab.CrossProd(mbc);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
template <class T>
|
|
847
|
+
int TriageEdgeCircumcenterSign(const Vector3<T>& x0, const Vector3<T>& x1,
|
|
848
|
+
const Vector3<T>& a, const Vector3<T>& b,
|
|
849
|
+
const Vector3<T>& c, int abc_sign) {
|
|
850
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
851
|
+
|
|
852
|
+
// Compute the circumcenter Z of triangle ABC, and then test which side of
|
|
853
|
+
// edge X it lies on.
|
|
854
|
+
T z_error;
|
|
855
|
+
Vector3<T> z = GetCircumcenter(a, b, c, &z_error);
|
|
856
|
+
Vector3<T> nx = (x0 - x1).CrossProd(x0 + x1);
|
|
857
|
+
// If the sign of triangle ABC is negative, then we have computed -Z and the
|
|
858
|
+
// result should be negated.
|
|
859
|
+
T result = abc_sign * nx.DotProd(z);
|
|
860
|
+
|
|
861
|
+
T z_len = z.Norm();
|
|
862
|
+
T nx_len = nx.Norm();
|
|
863
|
+
T nx_error = ((1 + 2 * sqrt(3)) * nx_len + 32 * sqrt(3) * DBL_ERR) * T_ERR;
|
|
864
|
+
T result_error = ((3 * T_ERR * nx_len + nx_error) * z_len + z_error * nx_len);
|
|
865
|
+
return (result > result_error) ? 1 : (result < -result_error) ? -1 : 0;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
int ExactEdgeCircumcenterSign(const Vector3_xf& x0, const Vector3_xf& x1,
|
|
869
|
+
const Vector3_xf& a, const Vector3_xf& b,
|
|
870
|
+
const Vector3_xf& c, int abc_sign) {
|
|
871
|
+
// Return zero if the edge X is degenerate. (Also see the comments in
|
|
872
|
+
// SymbolicEdgeCircumcenterSign.)
|
|
873
|
+
if (ArePointsLinearlyDependent(x0, x1)) {
|
|
874
|
+
S2_DCHECK_GT(x0.DotProd(x1), 0); // Antipodal edges not allowed.
|
|
875
|
+
return 0;
|
|
876
|
+
}
|
|
877
|
+
// The simplest predicate for testing whether the sign is positive is
|
|
878
|
+
//
|
|
879
|
+
// (1) (X0 x X1) . (|C|(A x B) + |A|(B x C) + |B|(C x A)) > 0
|
|
880
|
+
//
|
|
881
|
+
// where |A| denotes A.Norm() and the expression after the "." represents
|
|
882
|
+
// the circumcenter of triangle ABC. (This predicate is terrible from a
|
|
883
|
+
// numerical accuracy point of view, but that doesn't matter since we are
|
|
884
|
+
// going to use exact arithmetic.) This predicate also assumes that
|
|
885
|
+
// triangle ABC is CCW (positive sign); we correct for that below.
|
|
886
|
+
//
|
|
887
|
+
// The only problem with evaluating this inequality is that computing |A|,
|
|
888
|
+
// |B| and |C| requires square roots. To avoid this problem we use the
|
|
889
|
+
// standard technique of rearranging the inequality to isolate at least one
|
|
890
|
+
// square root and then squaring both sides. We need to repeat this process
|
|
891
|
+
// twice in order to eliminate all the square roots, which leads to a
|
|
892
|
+
// polynomial predicate of degree 20 in the input arguments.
|
|
893
|
+
//
|
|
894
|
+
// Rearranging (1) we get
|
|
895
|
+
//
|
|
896
|
+
// (X0 x X1) . (|C|(A x B) + |A|(B x C)) > |B|(X0 x X1) . (A x C)
|
|
897
|
+
//
|
|
898
|
+
// Before squaring we need to check the sign of each side. If the signs are
|
|
899
|
+
// different then we know the result without squaring, and if the signs are
|
|
900
|
+
// both negative then after squaring both sides we need to invert the
|
|
901
|
+
// result. Define
|
|
902
|
+
//
|
|
903
|
+
// dAB = (X0 x X1) . (A x B)
|
|
904
|
+
// dBC = (X0 x X1) . (B x C)
|
|
905
|
+
// dCA = (X0 x X1) . (C x A)
|
|
906
|
+
//
|
|
907
|
+
// Then we can now write the inequality above as
|
|
908
|
+
//
|
|
909
|
+
// (2) |C| dAB + |A| dBC > -|B| dCA
|
|
910
|
+
//
|
|
911
|
+
// The RHS of (2) is positive if dCA < 0, and the LHS of (2) is positive if
|
|
912
|
+
// (|C| dAB + |A| dBC) > 0. Since the LHS has square roots, we need to
|
|
913
|
+
// eliminate them using the same process. Rewriting the LHS as
|
|
914
|
+
//
|
|
915
|
+
// (3) |C| dAB > -|A| dBC
|
|
916
|
+
//
|
|
917
|
+
// we again need to check the signs of both sides. Let's start with that.
|
|
918
|
+
// We also precompute the following values because they are used repeatedly
|
|
919
|
+
// when squaring various expressions below:
|
|
920
|
+
//
|
|
921
|
+
// abc2 = |A|^2 dBC^2
|
|
922
|
+
// bca2 = |B|^2 dCA^2
|
|
923
|
+
// cab2 = |C|^2 dAB^2
|
|
924
|
+
Vector3_xf nx = x0.CrossProd(x1);
|
|
925
|
+
ExactFloat dab = nx.DotProd(a.CrossProd(b));
|
|
926
|
+
ExactFloat dbc = nx.DotProd(b.CrossProd(c));
|
|
927
|
+
ExactFloat dca = nx.DotProd(c.CrossProd(a));
|
|
928
|
+
ExactFloat abc2 = a.Norm2() * (dbc * dbc);
|
|
929
|
+
ExactFloat bca2 = b.Norm2() * (dca * dca);
|
|
930
|
+
ExactFloat cab2 = c.Norm2() * (dab * dab);
|
|
931
|
+
|
|
932
|
+
// If the two sides of (3) have different signs (including the case where
|
|
933
|
+
// one side is zero) then we know the result. Also, if both sides are zero
|
|
934
|
+
// then we know the result. The following logic encodes this.
|
|
935
|
+
int lhs3_sgn = dab.sgn(), rhs3_sgn = -dbc.sgn();
|
|
936
|
+
int lhs2_sgn = max(-1, min(1, lhs3_sgn - rhs3_sgn));
|
|
937
|
+
if (lhs2_sgn == 0 && lhs3_sgn != 0) {
|
|
938
|
+
// Both sides of (3) have the same non-zero sign, so square both sides.
|
|
939
|
+
// If both sides were negative then invert the result.
|
|
940
|
+
lhs2_sgn = (cab2 - abc2).sgn() * lhs3_sgn;
|
|
941
|
+
}
|
|
942
|
+
// Now if the two sides of (2) have different signs then we know the result
|
|
943
|
+
// of this entire function.
|
|
944
|
+
int rhs2_sgn = -dca.sgn();
|
|
945
|
+
int result = max(-1, min(1, lhs2_sgn - rhs2_sgn));
|
|
946
|
+
if (result == 0 && lhs2_sgn != 0) {
|
|
947
|
+
// Both sides of (2) have the same non-zero sign, so square both sides.
|
|
948
|
+
// (If both sides were negative then we invert the result below.)
|
|
949
|
+
// This gives
|
|
950
|
+
//
|
|
951
|
+
// |C|^2 dAB^2 + |A|^2 dBC^2 + 2 |A| |C| dAB dBC > |B|^2 dCA^2
|
|
952
|
+
//
|
|
953
|
+
// This expression still has square roots (|A| and |C|), so we rewrite as
|
|
954
|
+
//
|
|
955
|
+
// (4) 2 |A| |C| dAB dBC > |B|^2 dCA^2 - |C|^2 dAB^2 - |A|^2 dBC^2 .
|
|
956
|
+
//
|
|
957
|
+
// Again, if the two sides have different signs then we know the result.
|
|
958
|
+
int lhs4_sgn = dab.sgn() * dbc.sgn();
|
|
959
|
+
ExactFloat rhs4 = bca2 - cab2 - abc2;
|
|
960
|
+
result = max(-1, min(1, lhs4_sgn - rhs4.sgn()));
|
|
961
|
+
if (result == 0 && lhs4_sgn != 0) {
|
|
962
|
+
// Both sides of (4) have the same non-zero sign, so square both sides.
|
|
963
|
+
// If both sides were negative then invert the result.
|
|
964
|
+
result = (4 * abc2 * cab2 - rhs4 * rhs4).sgn() * lhs4_sgn;
|
|
965
|
+
}
|
|
966
|
+
// Correct the sign if both sides of (2) were negative.
|
|
967
|
+
result *= lhs2_sgn;
|
|
968
|
+
}
|
|
969
|
+
// If the sign of triangle ABC is negative, then we have computed -Z and the
|
|
970
|
+
// result should be negated.
|
|
971
|
+
return abc_sign * result;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Like Sign, except this method does not use symbolic perturbations when
|
|
975
|
+
// the input points are exactly coplanar with the origin (i.e., linearly
|
|
976
|
+
// dependent). Clients should never use this method, but it is useful here in
|
|
977
|
+
// order to implement the combined pedestal/axis-aligned perturbation scheme
|
|
978
|
+
// used by some methods (such as EdgeCircumcenterSign).
|
|
979
|
+
int UnperturbedSign(const S2Point& a, const S2Point& b, const S2Point& c) {
|
|
980
|
+
int sign = TriageSign(a, b, c, a.CrossProd(b));
|
|
981
|
+
if (sign == 0) sign = ExpensiveSign(a, b, c, false /*perturb*/);
|
|
982
|
+
return sign;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// Given arguments such that ExactEdgeCircumcenterSign(x0, x1, a, b, c) == 0,
|
|
986
|
+
// returns the value of Sign(X0, X1, Z) (where Z is the circumcenter of
|
|
987
|
+
// triangle ABC) after symbolic perturbations are taken into account. The
|
|
988
|
+
// result is zero only if X0 == X1, A == B, B == C, or C == A. (It is nonzero
|
|
989
|
+
// if these pairs are exactly proportional to each other but not equal.)
|
|
990
|
+
int SymbolicEdgeCircumcenterSign(
|
|
991
|
+
const S2Point& x0, const S2Point& x1,
|
|
992
|
+
const S2Point& a_arg, const S2Point& b_arg, const S2Point& c_arg) {
|
|
993
|
+
// We use the same perturbation strategy as SymbolicCompareDistances. Note
|
|
994
|
+
// that pedestal perturbations of X0 and X1 do not affect the result,
|
|
995
|
+
// because Sign(X0, X1, Z) does not change when its arguments are scaled
|
|
996
|
+
// by a positive factor. Therefore we only need to consider A, B, C.
|
|
997
|
+
// Suppose that A is the smallest lexicographically and therefore has the
|
|
998
|
+
// largest perturbation. This has the effect of perturbing the circumcenter
|
|
999
|
+
// of ABC slightly towards A, and since the circumcenter Z was previously
|
|
1000
|
+
// exactly collinear with edge X, this implies that after the perturbation
|
|
1001
|
+
// Sign(X0, X1, Z) == UnperturbedSign(X0, X1, A). (We want the result
|
|
1002
|
+
// to be zero if X0, X1, and A are linearly dependent, rather than using
|
|
1003
|
+
// symbolic perturbations, because these perturbations are defined to be
|
|
1004
|
+
// much, much smaller than the pedestal perturbation of B and C that are
|
|
1005
|
+
// considered below.)
|
|
1006
|
+
//
|
|
1007
|
+
// If A is also exactly collinear with edge X, then we move on to the next
|
|
1008
|
+
// smallest point lexicographically out of {B, C}. It is easy to see that
|
|
1009
|
+
// as long as A, B, C are all distinct, one of these three Sign calls
|
|
1010
|
+
// will be nonzero, because if A, B, C are all distinct and collinear with
|
|
1011
|
+
// edge X then their circumcenter Z coincides with the normal of X, and
|
|
1012
|
+
// therefore Sign(X0, X1, Z) is nonzero.
|
|
1013
|
+
//
|
|
1014
|
+
// This function could be extended to handle the case where X0 and X1 are
|
|
1015
|
+
// linearly dependent as follows. First, suppose that every point has both
|
|
1016
|
+
// a pedestal peturbation as described above, and also the three
|
|
1017
|
+
// axis-aligned perturbations described in the "Simulation of Simplicity"
|
|
1018
|
+
// paper, where all pedestal perturbations are defined to be much, much
|
|
1019
|
+
// larger than any axis-aligned perturbation. Note that since pedestal
|
|
1020
|
+
// perturbations have no effect on Sign, we can use this model for *all*
|
|
1021
|
+
// the S2 predicates, which ensures that all the various predicates are
|
|
1022
|
+
// fully consistent with each other.
|
|
1023
|
+
//
|
|
1024
|
+
// With this model, the strategy described above yields the correct result
|
|
1025
|
+
// unless X0 and X1 are exactly linearly dependent. When that happens, then
|
|
1026
|
+
// no perturbation (pedestal or axis-aligned) of A,B,C affects the result,
|
|
1027
|
+
// and no pedestal perturbation of X0 or X1 affects the result, therefore we
|
|
1028
|
+
// need to consider the smallest axis-aligned perturbation of X0 or X1. The
|
|
1029
|
+
// first perturbation that makes X0 and X1 linearly independent yields the
|
|
1030
|
+
// result. Supposing that X0 < X1, this is the perturbation of X0[2] unless
|
|
1031
|
+
// both points are multiples of [0, 0, 1], in which case it is the
|
|
1032
|
+
// perturbation of X0[1]. The sign test can be implemented by computing the
|
|
1033
|
+
// perturbed cross product of X0 and X1 and taking the dot product with the
|
|
1034
|
+
// exact value of Z. For example if X0[2] is perturbed, the perturbed cross
|
|
1035
|
+
// product is proportional to (0, 0, 1) x X1 = (-X1[1], x1[0], 0). Note
|
|
1036
|
+
// that if the dot product with Z is exactly zero, then it is still
|
|
1037
|
+
// necessary to fall back to pedestal perturbations of A, B, C, but one of
|
|
1038
|
+
// these perturbations is now guaranteed to succeed.
|
|
1039
|
+
|
|
1040
|
+
// If any two triangle vertices are equal, the result is zero.
|
|
1041
|
+
if (a_arg == b_arg || b_arg == c_arg || c_arg == a_arg) return 0;
|
|
1042
|
+
|
|
1043
|
+
// Sort A, B, C in lexicographic order.
|
|
1044
|
+
const S2Point *a = &a_arg, *b = &b_arg, *c = &c_arg;
|
|
1045
|
+
if (*b < *a) std::swap(a, b);
|
|
1046
|
+
if (*c < *b) std::swap(b, c);
|
|
1047
|
+
if (*b < *a) std::swap(a, b);
|
|
1048
|
+
|
|
1049
|
+
// Now consider the perturbations in decreasing order of size.
|
|
1050
|
+
int sign = UnperturbedSign(x0, x1, *a);
|
|
1051
|
+
if (sign != 0) return sign;
|
|
1052
|
+
sign = UnperturbedSign(x0, x1, *b);
|
|
1053
|
+
if (sign != 0) return sign;
|
|
1054
|
+
return UnperturbedSign(x0, x1, *c);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
int EdgeCircumcenterSign(const S2Point& x0, const S2Point& x1,
|
|
1058
|
+
const S2Point& a, const S2Point& b,
|
|
1059
|
+
const S2Point& c) {
|
|
1060
|
+
// Check that the edge does not consist of antipodal points. (This catches
|
|
1061
|
+
// the most common case -- the full test is in ExactEdgeCircumcenterSign.)
|
|
1062
|
+
S2_DCHECK_NE(x0, -x1);
|
|
1063
|
+
|
|
1064
|
+
int abc_sign = Sign(a, b, c);
|
|
1065
|
+
int sign = TriageEdgeCircumcenterSign(x0, x1, a, b, c, abc_sign);
|
|
1066
|
+
if (sign != 0) return sign;
|
|
1067
|
+
|
|
1068
|
+
// Optimization for the cases that are going to return zero anyway, in order
|
|
1069
|
+
// to avoid falling back to exact arithmetic.
|
|
1070
|
+
if (x0 == x1 || a == b || b == c || c == a) return 0;
|
|
1071
|
+
|
|
1072
|
+
sign = TriageEdgeCircumcenterSign(
|
|
1073
|
+
ToLD(x0), ToLD(x1), ToLD(a), ToLD(b), ToLD(c), abc_sign);
|
|
1074
|
+
if (sign != 0) return sign;
|
|
1075
|
+
sign = ExactEdgeCircumcenterSign(
|
|
1076
|
+
ToExact(x0), ToExact(x1), ToExact(a), ToExact(b), ToExact(c), abc_sign);
|
|
1077
|
+
if (sign != 0) return sign;
|
|
1078
|
+
|
|
1079
|
+
// Unlike the other methods, SymbolicEdgeCircumcenterSign does not depend
|
|
1080
|
+
// on the sign of triangle ABC.
|
|
1081
|
+
return SymbolicEdgeCircumcenterSign(x0, x1, a, b, c);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
template <class T>
|
|
1085
|
+
Excluded TriageVoronoiSiteExclusion(const Vector3<T>& a, const Vector3<T>& b,
|
|
1086
|
+
const Vector3<T>& x0, const Vector3<T>& x1,
|
|
1087
|
+
T r2) {
|
|
1088
|
+
constexpr T T_ERR = rounding_epsilon<T>();
|
|
1089
|
+
|
|
1090
|
+
// Define the "coverage disc" of a site S to be the disc centered at S with
|
|
1091
|
+
// radius r (i.e., squared chord angle length r2). Similarly, define the
|
|
1092
|
+
// "coverage interval" of S along an edge X to be the intersection of X with
|
|
1093
|
+
// the coverage disc of S. The coverage interval can be represented as the
|
|
1094
|
+
// point at the center of the interval and an angle that measures the
|
|
1095
|
+
// semi-width or "radius" of the interval.
|
|
1096
|
+
//
|
|
1097
|
+
// To test whether site A excludes site B along the input edge X, we test
|
|
1098
|
+
// whether the coverage interval of A contains the coverage interval of B.
|
|
1099
|
+
// Let "ra" and "rb" be the radii (semi-widths) of the two intervals, and
|
|
1100
|
+
// let "d" be the angle between their center points. Then "a" properly
|
|
1101
|
+
// contains "b" if (ra - rb > d), and "b" contains "a" if (rb - ra > d).
|
|
1102
|
+
// Note that only one of these conditions can be true. Therefore we can
|
|
1103
|
+
// determine whether one site excludes the other by checking whether
|
|
1104
|
+
//
|
|
1105
|
+
// (1) |rb - ra| > d
|
|
1106
|
+
//
|
|
1107
|
+
// and use the sign of (rb - ra) to determine which site is excluded.
|
|
1108
|
+
//
|
|
1109
|
+
// The actual code is based on the following. Let A1 and B1 be the unit
|
|
1110
|
+
// vectors A and B scaled by cos(r) (these points are inside the sphere).
|
|
1111
|
+
// The planes perpendicular to OA1 and OA2 cut off two discs of radius r
|
|
1112
|
+
// around A and B. Now consider the two lines (inside the sphere) where
|
|
1113
|
+
// these planes intersect the plane containing the input edge X, and let A2
|
|
1114
|
+
// and B2 be the points on these lines that are closest to A and B. The
|
|
1115
|
+
// coverage intervals of A and B can be represented as an interval along
|
|
1116
|
+
// each of these lines, centered at A2 and B2. Let P1 and P2 be the
|
|
1117
|
+
// endpoints of the coverage interval for A, and let Q1 and Q2 be the
|
|
1118
|
+
// endpoints of the coverage interval for B. We can view each coverage
|
|
1119
|
+
// interval as either a chord through the sphere's interior, or as a segment
|
|
1120
|
+
// of the original edge X (by projecting the chord onto the sphere's
|
|
1121
|
+
// surface).
|
|
1122
|
+
//
|
|
1123
|
+
// To check whether B's interval is contained by A's interval, we test
|
|
1124
|
+
// whether both endpoints of B's interval (Q1 and Q2) are contained by A's
|
|
1125
|
+
// interval. E.g., we could test whether Qi.DotProd(A2) > A2.Norm2().
|
|
1126
|
+
//
|
|
1127
|
+
// However rather than constructing the actual points A1, A2, and so on, it
|
|
1128
|
+
// turns out to be more efficient to compute the sines and cosines
|
|
1129
|
+
// ("components") of the various angles and then use trigonometric
|
|
1130
|
+
// identities. Predicate (1) can be expressed as
|
|
1131
|
+
//
|
|
1132
|
+
// |sin(rb - ra)| > sin(d)
|
|
1133
|
+
//
|
|
1134
|
+
// provided that |d| <= Pi/2 (which must be checked), and then expanded to
|
|
1135
|
+
//
|
|
1136
|
+
// (2) |sin(rb) cos(ra) - sin(ra) cos(rb)| > sin(d) .
|
|
1137
|
+
//
|
|
1138
|
+
// The components of the various angles can be expressed using dot and cross
|
|
1139
|
+
// products based on the construction above:
|
|
1140
|
+
//
|
|
1141
|
+
// sin(ra) = sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2) / |aXn|
|
|
1142
|
+
// cos(ra) = cos(r) |a| |n| / |aXn|
|
|
1143
|
+
// sin(rb) = sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) / |bXn|
|
|
1144
|
+
// cos(rb) = cos(r) |b| |n| / |bXn|
|
|
1145
|
+
// sin(d) = (aXb).n |n| / (|aXn| |bXn|)
|
|
1146
|
+
// cos(d) = (aXn).(bXn) / (|aXn| |bXn|)
|
|
1147
|
+
//
|
|
1148
|
+
// Also, the squared chord length r2 is equal to 4 * sin^2(r / 2), which
|
|
1149
|
+
// yields the following relationships:
|
|
1150
|
+
//
|
|
1151
|
+
// sin(r) = sqrt(r2 (1 - r2 / 4))
|
|
1152
|
+
// cos(r) = 1 - r2 / 2
|
|
1153
|
+
//
|
|
1154
|
+
// We then scale both sides of (2) by |aXn| |bXn| / |n| (in order to
|
|
1155
|
+
// minimize the number of calculations and to avoid divisions), which gives:
|
|
1156
|
+
//
|
|
1157
|
+
// cos(r) ||a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) -
|
|
1158
|
+
// |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)| > (aXb).n
|
|
1159
|
+
//
|
|
1160
|
+
// Furthermore we can substitute |a| = |b| = 1 (as long as this is taken
|
|
1161
|
+
// into account in the error bounds), yielding
|
|
1162
|
+
//
|
|
1163
|
+
// (3) cos(r) |sqrt(sin^2(r) |n|^2 - |b.n|^2) -
|
|
1164
|
+
// sqrt(sin^2(r) |n|^2 - |a.n|^2)| > (aXb).n
|
|
1165
|
+
//
|
|
1166
|
+
// The code below is more complicated than this because many expressions
|
|
1167
|
+
// have been modified for better numerical stability. For example, dot
|
|
1168
|
+
// products between unit vectors are computed using (x - y).DotProd(x + y),
|
|
1169
|
+
// and the dot product between a point P and the normal N of an edge X is
|
|
1170
|
+
// measured using (P - Xi).DotProd(N) where Xi is the endpoint of X that is
|
|
1171
|
+
// closer to P.
|
|
1172
|
+
|
|
1173
|
+
Vector3<T> n = (x0 - x1).CrossProd(x0 + x1); // 2 * x0.CrossProd(x1)
|
|
1174
|
+
T n2 = n.Norm2();
|
|
1175
|
+
T n1 = sqrt(n2);
|
|
1176
|
+
// This factor is used in the error terms of dot products with "n" below.
|
|
1177
|
+
T Dn_error = ((3.5 + 2 * sqrt(3)) * n1 + 32 * sqrt(3) * DBL_ERR) * T_ERR;
|
|
1178
|
+
|
|
1179
|
+
T cos_r = 1 - 0.5 * r2;
|
|
1180
|
+
T sin2_r = r2 * (1 - 0.25 * r2);
|
|
1181
|
+
T n2sin2_r = n2 * sin2_r;
|
|
1182
|
+
|
|
1183
|
+
// "ra" and "rb" denote sin(ra) and sin(rb) after the scaling above.
|
|
1184
|
+
T ax2, aDn = (a - GetClosestVertex(a, x0, x1, &ax2)).DotProd(n);
|
|
1185
|
+
T aDn2 = aDn * aDn;
|
|
1186
|
+
T aDn_error = Dn_error * sqrt(ax2);
|
|
1187
|
+
T ra2 = n2sin2_r - aDn2;
|
|
1188
|
+
T ra2_error = (8 * DBL_ERR + 4 * T_ERR) * aDn2 +
|
|
1189
|
+
(2 * fabs(aDn) + aDn_error) * aDn_error + 6 * T_ERR * n2sin2_r;
|
|
1190
|
+
// This is the minimum possible value of ra2, which is used to bound the
|
|
1191
|
+
// derivative of sqrt(ra2) in computing ra_error below.
|
|
1192
|
+
T min_ra2 = ra2 - ra2_error;
|
|
1193
|
+
if (min_ra2 < 0) return Excluded::UNCERTAIN;
|
|
1194
|
+
T ra = sqrt(ra2);
|
|
1195
|
+
// Includes the ra2 subtraction error above.
|
|
1196
|
+
T ra_error = 1.5 * T_ERR * ra + 0.5 * ra2_error / sqrt(min_ra2);
|
|
1197
|
+
|
|
1198
|
+
T bx2, bDn = (b - GetClosestVertex(b, x0, x1, &bx2)).DotProd(n);
|
|
1199
|
+
T bDn2 = bDn * bDn;
|
|
1200
|
+
T bDn_error = Dn_error * sqrt(bx2);
|
|
1201
|
+
T rb2 = n2sin2_r - bDn2;
|
|
1202
|
+
T rb2_error = (8 * DBL_ERR + 4 * T_ERR) * bDn2 +
|
|
1203
|
+
(2 * fabs(bDn) + bDn_error) * bDn_error + 6 * T_ERR * n2sin2_r;
|
|
1204
|
+
T min_rb2 = rb2 - rb2_error;
|
|
1205
|
+
if (min_rb2 < 0) return Excluded::UNCERTAIN;
|
|
1206
|
+
T rb = sqrt(rb2);
|
|
1207
|
+
// Includes the rb2 subtraction error above.
|
|
1208
|
+
T rb_error = 1.5 * T_ERR * rb + 0.5 * rb2_error / sqrt(min_rb2);
|
|
1209
|
+
|
|
1210
|
+
// The sign of LHS(3) determines which site may be excluded by the other.
|
|
1211
|
+
T lhs3 = cos_r * (rb - ra);
|
|
1212
|
+
T abs_lhs3 = fabs(lhs3);
|
|
1213
|
+
T lhs3_error = cos_r * (ra_error + rb_error) + 3 * T_ERR * abs_lhs3;
|
|
1214
|
+
|
|
1215
|
+
// Now we evaluate the RHS of (3), which is proportional to sin(d).
|
|
1216
|
+
Vector3<T> aXb = (a - b).CrossProd(a + b); // 2 * a.CrossProd(b)
|
|
1217
|
+
T aXb1 = aXb.Norm();
|
|
1218
|
+
T sin_d = 0.5 * aXb.DotProd(n);
|
|
1219
|
+
T sin_d_error = (4 * DBL_ERR + (2.5 + 2 * sqrt(3)) * T_ERR) * aXb1 * n1 +
|
|
1220
|
+
16 * sqrt(3) * DBL_ERR * T_ERR * (aXb1 + n1);
|
|
1221
|
+
|
|
1222
|
+
// If LHS(3) is definitely less than RHS(3), neither site excludes the other.
|
|
1223
|
+
T result = abs_lhs3 - sin_d;
|
|
1224
|
+
T result_error = lhs3_error + sin_d_error;
|
|
1225
|
+
if (result < -result_error) return Excluded::NEITHER;
|
|
1226
|
+
|
|
1227
|
+
// Otherwise, before proceeding further we need to check that |d| <= Pi/2.
|
|
1228
|
+
// In fact, |d| < Pi/2 is enough because of the requirement that r < Pi/2.
|
|
1229
|
+
// The following expression represents cos(d) after scaling; it is
|
|
1230
|
+
// equivalent to (aXn).(bXn) but has about 30% less error.
|
|
1231
|
+
T cos_d = a.DotProd(b) * n2 - aDn * bDn;
|
|
1232
|
+
T cos_d_error =
|
|
1233
|
+
((8 * DBL_ERR + 5 * T_ERR) * fabs(aDn) + aDn_error) * fabs(bDn) +
|
|
1234
|
+
(fabs(aDn) + aDn_error) * bDn_error + (8 * DBL_ERR + 8 * T_ERR) * n2;
|
|
1235
|
+
if (cos_d <= -cos_d_error) return Excluded::NEITHER;
|
|
1236
|
+
|
|
1237
|
+
// Potential optimization: if the sign of cos(d) is uncertain, then instead
|
|
1238
|
+
// we could check whether cos(d) >= cos(r). Unfortunately this is fairly
|
|
1239
|
+
// expensive since it requires computing denominator |aXn||bXn| of cos(d)
|
|
1240
|
+
// and the associated error bounds. In any case this case is relatively
|
|
1241
|
+
// rare so it seems better to punt.
|
|
1242
|
+
if (cos_d < cos_d_error) return Excluded::UNCERTAIN;
|
|
1243
|
+
|
|
1244
|
+
// Normally we have d > 0 because the sites are sorted so that A is closer
|
|
1245
|
+
// to X0 and B is closer to X1. However if the edge X is longer than Pi/2,
|
|
1246
|
+
// and the sites A and B are beyond its endpoints, then AB can wrap around
|
|
1247
|
+
// the sphere in the opposite direction from X. In this situation d < 0 but
|
|
1248
|
+
// each site is closest to one endpoint of X, so neither excludes the other.
|
|
1249
|
+
//
|
|
1250
|
+
// It turns out that this can happen only when the site that is further away
|
|
1251
|
+
// from edge X is less than 90 degrees away from whichever endpoint of X it
|
|
1252
|
+
// is closer to. It is provable that if this distance is less than 90
|
|
1253
|
+
// degrees, then it is also less than r2, and therefore the Voronoi regions
|
|
1254
|
+
// of both sites intersect the edge.
|
|
1255
|
+
if (sin_d < -sin_d_error) {
|
|
1256
|
+
T r90 = S1ChordAngle::Right().length2();
|
|
1257
|
+
// "ca" is negative if Voronoi region A definitely intersects edge X.
|
|
1258
|
+
int ca = (lhs3 < -lhs3_error) ? -1 : TriageCompareCosDistance(a, x0, r90);
|
|
1259
|
+
int cb = (lhs3 > lhs3_error) ? -1 : TriageCompareCosDistance(b, x1, r90);
|
|
1260
|
+
if (ca < 0 && cb < 0) return Excluded::NEITHER;
|
|
1261
|
+
if (ca <= 0 && cb <= 0) return Excluded::UNCERTAIN;
|
|
1262
|
+
if (abs_lhs3 <= lhs3_error) return Excluded::UNCERTAIN;
|
|
1263
|
+
} else if (sin_d <= sin_d_error) {
|
|
1264
|
+
return Excluded::UNCERTAIN;
|
|
1265
|
+
}
|
|
1266
|
+
// Now we can finish checking the results of predicate (3).
|
|
1267
|
+
if (result <= result_error) return Excluded::UNCERTAIN;
|
|
1268
|
+
S2_DCHECK_GT(abs_lhs3, lhs3_error);
|
|
1269
|
+
return (lhs3 > 0) ? Excluded::FIRST : Excluded::SECOND;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
Excluded ExactVoronoiSiteExclusion(const Vector3_xf& a, const Vector3_xf& b,
|
|
1273
|
+
const Vector3_xf& x0, const Vector3_xf& x1,
|
|
1274
|
+
const ExactFloat& r2) {
|
|
1275
|
+
S2_DCHECK(!ArePointsAntipodal(x0, x1));
|
|
1276
|
+
|
|
1277
|
+
// Recall that one site excludes the other if
|
|
1278
|
+
//
|
|
1279
|
+
// (1) |sin(rb - ra)| > sin(d)
|
|
1280
|
+
//
|
|
1281
|
+
// and that the sign of (rb - ra) determines which site is excluded (see the
|
|
1282
|
+
// comments in TriageVoronoiSiteExclusion). To evaluate this using exact
|
|
1283
|
+
// arithmetic, we expand this to the same predicate as before:
|
|
1284
|
+
//
|
|
1285
|
+
// (2) cos(r) ||a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) -
|
|
1286
|
+
// |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)| > (aXb).n
|
|
1287
|
+
//
|
|
1288
|
+
// We also need to verify that d <= Pi/2, which is implemented by checking
|
|
1289
|
+
// that sin(d) >= 0 and cos(d) >= 0.
|
|
1290
|
+
//
|
|
1291
|
+
// To eliminate the square roots we use the standard technique of
|
|
1292
|
+
// rearranging the inequality to isolate at least one square root and then
|
|
1293
|
+
// squaring both sides. We need to repeat this process twice in order to
|
|
1294
|
+
// eliminate all the square roots, which leads to a polynomial predicate of
|
|
1295
|
+
// degree 20 in the input arguments (i.e., degree 4 in each of "a", "b",
|
|
1296
|
+
// "x0", "x1", and "r2").
|
|
1297
|
+
//
|
|
1298
|
+
// Before squaring we need to check the sign of each side. We also check
|
|
1299
|
+
// the condition that cos(d) >= 0. Given what else we need to compute, it
|
|
1300
|
+
// is cheaper use the identity (aXn).(bXn) = (a.b) |n|^2 - (a.n)(b.n) .
|
|
1301
|
+
Vector3_xf n = x0.CrossProd(x1);
|
|
1302
|
+
ExactFloat n2 = n.Norm2();
|
|
1303
|
+
ExactFloat aDn = a.DotProd(n);
|
|
1304
|
+
ExactFloat bDn = b.DotProd(n);
|
|
1305
|
+
ExactFloat cos_d = a.DotProd(b) * n2 - aDn * bDn;
|
|
1306
|
+
if (cos_d.sgn() < 0) return Excluded::NEITHER;
|
|
1307
|
+
|
|
1308
|
+
// Otherwise we continue evaluating the LHS of (2), defining
|
|
1309
|
+
// sa = |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)
|
|
1310
|
+
// sb = |a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) .
|
|
1311
|
+
// The sign of the LHS of (2) (before taking the absolute value) determines
|
|
1312
|
+
// which coverage interval is larger and therefore which site is potentially
|
|
1313
|
+
// being excluded.
|
|
1314
|
+
ExactFloat a2 = a.Norm2();
|
|
1315
|
+
ExactFloat b2 = b.Norm2();
|
|
1316
|
+
ExactFloat n2sin2_r = r2 * (1 - 0.25 * r2) * n2;
|
|
1317
|
+
ExactFloat sa2 = b2 * (n2sin2_r * a2 - aDn * aDn);
|
|
1318
|
+
ExactFloat sb2 = a2 * (n2sin2_r * b2 - bDn * bDn);
|
|
1319
|
+
int lhs2_sgn = (sb2 - sa2).sgn();
|
|
1320
|
+
|
|
1321
|
+
// If the RHS of (2) is negative (corresponding to sin(d) < 0), then we need
|
|
1322
|
+
// to consider the possibility that the edge AB wraps around the sphere in
|
|
1323
|
+
// the opposite direction from edge X, with the result that neither site
|
|
1324
|
+
// excludes the other (see TriageVoronoiSiteExclusion).
|
|
1325
|
+
ExactFloat rhs2 = a.CrossProd(b).DotProd(n);
|
|
1326
|
+
int rhs2_sgn = rhs2.sgn();
|
|
1327
|
+
if (rhs2_sgn < 0) {
|
|
1328
|
+
ExactFloat r90 = S1ChordAngle::Right().length2();
|
|
1329
|
+
int ca = (lhs2_sgn < 0) ? -1 : ExactCompareDistance(a, x0, r90);
|
|
1330
|
+
int cb = (lhs2_sgn > 0) ? -1 : ExactCompareDistance(b, x1, r90);
|
|
1331
|
+
if (ca <= 0 && cb <= 0) return Excluded::NEITHER;
|
|
1332
|
+
S2_DCHECK(ca != 1 || cb != 1);
|
|
1333
|
+
return ca == 1 ? Excluded::FIRST : Excluded::SECOND;
|
|
1334
|
+
}
|
|
1335
|
+
if (lhs2_sgn == 0) {
|
|
1336
|
+
// If the RHS of (2) is zero as well (i.e., d == 0) then both sites are
|
|
1337
|
+
// equidistant from every point on edge X. This case requires symbolic
|
|
1338
|
+
// perturbations, but it should already have been handled in
|
|
1339
|
+
// GetVoronoiSiteExclusion() (see the call to CompareDistances).
|
|
1340
|
+
S2_DCHECK_GT(rhs2_sgn, 0);
|
|
1341
|
+
return Excluded::NEITHER;
|
|
1342
|
+
}
|
|
1343
|
+
// Next we square both sides of (2), yielding
|
|
1344
|
+
//
|
|
1345
|
+
// cos^2(r) (sb^2 + sa^2 - 2 sa sb) > (aXb.n)^2
|
|
1346
|
+
//
|
|
1347
|
+
// which can be rearranged to give
|
|
1348
|
+
//
|
|
1349
|
+
// (3) cos^2(r) (sb^2 + sa^2) - (aXb.n)^2 > 2 cos^2(r) sa sb .
|
|
1350
|
+
//
|
|
1351
|
+
// The RHS of (3) is always non-negative, but we still need to check the
|
|
1352
|
+
// sign of the LHS.
|
|
1353
|
+
ExactFloat cos_r = 1 - 0.5 * r2;
|
|
1354
|
+
ExactFloat cos2_r = cos_r * cos_r;
|
|
1355
|
+
ExactFloat lhs3 = cos2_r * (sa2 + sb2) - rhs2 * rhs2;
|
|
1356
|
+
if (lhs3.sgn() < 0) return Excluded::NEITHER;
|
|
1357
|
+
|
|
1358
|
+
// Otherwise we square both sides of (3) to obtain:
|
|
1359
|
+
//
|
|
1360
|
+
// (4) LHS(3)^2 > 4 cos^4(r) sa^2 sb^2
|
|
1361
|
+
ExactFloat lhs4 = lhs3 * lhs3;
|
|
1362
|
+
ExactFloat rhs4 = 4 * cos2_r * cos2_r * sa2 * sb2;
|
|
1363
|
+
int result = (lhs4 - rhs4).sgn();
|
|
1364
|
+
if (result < 0) return Excluded::NEITHER;
|
|
1365
|
+
if (result == 0) {
|
|
1366
|
+
// We have |rb - ra| = d and d > 0. This implies that one coverage
|
|
1367
|
+
// interval contains the other, but not properly: the two intervals share
|
|
1368
|
+
// a common endpoint. The distance from each site to that point is
|
|
1369
|
+
// exactly "r", therefore we need to use symbolic perturbations. Recall
|
|
1370
|
+
// that site A is considered closer to an equidistant point if and only if
|
|
1371
|
+
// A > B. Therefore if (rb > ra && A > B) or (ra > rb && B > A) then each
|
|
1372
|
+
// site is closer to at least one point and neither site is excluded.
|
|
1373
|
+
//
|
|
1374
|
+
// Ideally this logic would be in a separate SymbolicVoronoiSiteExclusion
|
|
1375
|
+
// method for better testing, but this is not convenient because it needs
|
|
1376
|
+
// lhs_sgn (which requires exact arithmetic to compute).
|
|
1377
|
+
if ((lhs2_sgn > 0) == (a > b)) return Excluded::NEITHER;
|
|
1378
|
+
}
|
|
1379
|
+
// At this point we know that one of the two sites is excluded. The sign of
|
|
1380
|
+
// the LHS of (2) (before the absolute value) determines which one.
|
|
1381
|
+
return (lhs2_sgn > 0) ? Excluded::FIRST : Excluded::SECOND;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
Excluded GetVoronoiSiteExclusion(const S2Point& a, const S2Point& b,
|
|
1385
|
+
const S2Point& x0, const S2Point& x1,
|
|
1386
|
+
S1ChordAngle r) {
|
|
1387
|
+
S2_DCHECK_LT(r, S1ChordAngle::Right());
|
|
1388
|
+
S2_DCHECK_LT(s2pred::CompareDistances(x0, a, b), 0); // (implies a != b)
|
|
1389
|
+
S2_DCHECK_LE(s2pred::CompareEdgeDistance(a, x0, x1, r), 0);
|
|
1390
|
+
S2_DCHECK_LE(s2pred::CompareEdgeDistance(b, x0, x1, r), 0);
|
|
1391
|
+
// Check that the edge does not consist of antipodal points. (This catches
|
|
1392
|
+
// the most common case -- the full test is in ExactVoronoiSiteExclusion.)
|
|
1393
|
+
S2_DCHECK_NE(x0, -x1);
|
|
1394
|
+
|
|
1395
|
+
// If one site is closer than the other to both endpoints of X, then it is
|
|
1396
|
+
// closer to every point on X. Note that this also handles the case where A
|
|
1397
|
+
// and B are equidistant from every point on X (i.e., X is the perpendicular
|
|
1398
|
+
// bisector of AB), because CompareDistances uses symbolic perturbations to
|
|
1399
|
+
// ensure that either A or B is considered closer (in a consistent way).
|
|
1400
|
+
// This also ensures that the choice of A or B does not depend on the
|
|
1401
|
+
// direction of X.
|
|
1402
|
+
if (s2pred::CompareDistances(x1, a, b) < 0) {
|
|
1403
|
+
return Excluded::SECOND; // Site A is closer to every point on X.
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
Excluded result = TriageVoronoiSiteExclusion(a, b, x0, x1, r.length2());
|
|
1407
|
+
if (result != Excluded::UNCERTAIN) return result;
|
|
1408
|
+
|
|
1409
|
+
result = TriageVoronoiSiteExclusion(ToLD(a), ToLD(b), ToLD(x0), ToLD(x1),
|
|
1410
|
+
ToLD(r.length2()));
|
|
1411
|
+
if (result != Excluded::UNCERTAIN) return result;
|
|
1412
|
+
|
|
1413
|
+
return ExactVoronoiSiteExclusion(ToExact(a), ToExact(b), ToExact(x0),
|
|
1414
|
+
ToExact(x1), r.length2());
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
std::ostream& operator<<(std::ostream& os, Excluded excluded) {
|
|
1418
|
+
switch (excluded) {
|
|
1419
|
+
case Excluded::FIRST: return os << "FIRST";
|
|
1420
|
+
case Excluded::SECOND: return os << "SECOND";
|
|
1421
|
+
case Excluded::NEITHER: return os << "NEITHER";
|
|
1422
|
+
case Excluded::UNCERTAIN: return os << "UNCERTAIN";
|
|
1423
|
+
default: return os << "Unknown enum value";
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// Explicitly instantiate all of the template functions above so that the
|
|
1428
|
+
// tests can use them without putting all the definitions in a header file.
|
|
1429
|
+
|
|
1430
|
+
template int TriageCompareCosDistances<double>(
|
|
1431
|
+
const S2Point&, const S2Point&, const S2Point&);
|
|
1432
|
+
|
|
1433
|
+
template int TriageCompareCosDistances<long double>(
|
|
1434
|
+
const Vector3_ld&, const Vector3_ld&, const Vector3_ld&);
|
|
1435
|
+
|
|
1436
|
+
template int TriageCompareSin2Distances<double>(
|
|
1437
|
+
const S2Point&, const S2Point&, const S2Point&);
|
|
1438
|
+
|
|
1439
|
+
template int TriageCompareSin2Distances<long double>(
|
|
1440
|
+
const Vector3_ld&, const Vector3_ld&, const Vector3_ld&);
|
|
1441
|
+
|
|
1442
|
+
template int TriageCompareCosDistance<double>(
|
|
1443
|
+
const S2Point&, const S2Point&, double r2);
|
|
1444
|
+
|
|
1445
|
+
template int TriageCompareCosDistance<long double>(
|
|
1446
|
+
const Vector3_ld&, const Vector3_ld&, long double r2);
|
|
1447
|
+
|
|
1448
|
+
template int TriageCompareSin2Distance<double>(
|
|
1449
|
+
const S2Point&, const S2Point&, double r2);
|
|
1450
|
+
|
|
1451
|
+
template int TriageCompareSin2Distance<long double>(
|
|
1452
|
+
const Vector3_ld&, const Vector3_ld&, long double r2);
|
|
1453
|
+
|
|
1454
|
+
template int TriageCompareEdgeDistance<double>(
|
|
1455
|
+
const S2Point& x, const S2Point& a0, const S2Point& a1, double r2);
|
|
1456
|
+
|
|
1457
|
+
template int TriageCompareEdgeDistance<long double>(
|
|
1458
|
+
const Vector3_ld& x, const Vector3_ld& a0, const Vector3_ld& a1,
|
|
1459
|
+
long double r2);
|
|
1460
|
+
|
|
1461
|
+
template int TriageCompareEdgeDirections<double>(
|
|
1462
|
+
const S2Point& a0, const S2Point& a1,
|
|
1463
|
+
const S2Point& b0, const S2Point& b1);
|
|
1464
|
+
|
|
1465
|
+
template int TriageCompareEdgeDirections<long double>(
|
|
1466
|
+
const Vector3_ld& a0, const Vector3_ld& a1,
|
|
1467
|
+
const Vector3_ld& b0, const Vector3_ld& b1);
|
|
1468
|
+
|
|
1469
|
+
template int TriageEdgeCircumcenterSign<double>(
|
|
1470
|
+
const S2Point& x0, const S2Point& x1,
|
|
1471
|
+
const S2Point& a, const S2Point& b, const S2Point& c, int abc_sign);
|
|
1472
|
+
|
|
1473
|
+
template int TriageEdgeCircumcenterSign<long double>(
|
|
1474
|
+
const Vector3_ld& x0, const Vector3_ld& x1,
|
|
1475
|
+
const Vector3_ld& a, const Vector3_ld& b, const Vector3_ld& c,
|
|
1476
|
+
int abc_sign);
|
|
1477
|
+
|
|
1478
|
+
template Excluded TriageVoronoiSiteExclusion(
|
|
1479
|
+
const S2Point& a, const S2Point& b,
|
|
1480
|
+
const S2Point& x0, const S2Point& x1, double r2);
|
|
1481
|
+
|
|
1482
|
+
template Excluded TriageVoronoiSiteExclusion(
|
|
1483
|
+
const Vector3_ld& a, const Vector3_ld& b,
|
|
1484
|
+
const Vector3_ld& x0, const Vector3_ld& x1, long double r2);
|
|
1485
|
+
|
|
1486
|
+
} // namespace s2pred
|