@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.
Files changed (471) hide show
  1. package/.circleci/config.yml +45 -0
  2. package/.dockerignore +1 -0
  3. package/.gitmodules +3 -0
  4. package/CHANGELOG.md +33 -0
  5. package/LICENSE +201 -0
  6. package/README.md +147 -0
  7. package/binding.gyp +170 -0
  8. package/docker/Dockerfile.node20.test +8 -0
  9. package/docker/Dockerfile.node22.test +8 -0
  10. package/docker/Dockerfile.node24.test +8 -0
  11. package/index.d.ts +117 -0
  12. package/index.js +6 -0
  13. package/jest.config.js +184 -0
  14. package/package.json +43 -0
  15. package/publish-linux.sh +18 -0
  16. package/publish-osx.sh +19 -0
  17. package/src/builder.cc +84 -0
  18. package/src/builder.h +29 -0
  19. package/src/cell.cc +71 -0
  20. package/src/cell.h +26 -0
  21. package/src/cell_id.cc +210 -0
  22. package/src/cell_id.h +44 -0
  23. package/src/cell_union.cc +237 -0
  24. package/src/cell_union.h +34 -0
  25. package/src/earth.cc +185 -0
  26. package/src/earth.h +33 -0
  27. package/src/latlng.cc +132 -0
  28. package/src/latlng.h +28 -0
  29. package/src/loop.cc +51 -0
  30. package/src/loop.h +21 -0
  31. package/src/point.cc +69 -0
  32. package/src/point.h +23 -0
  33. package/src/polygon.cc +36 -0
  34. package/src/polygon.h +20 -0
  35. package/src/polyline.cc +186 -0
  36. package/src/polyline.h +34 -0
  37. package/src/region_coverer.cc +450 -0
  38. package/src/region_coverer.h +56 -0
  39. package/src/s2.cc +27 -0
  40. package/test/Cell.test.js +37 -0
  41. package/test/CellId.test.js +135 -0
  42. package/test/CellUnion.test.js +150 -0
  43. package/test/Earth.test.js +62 -0
  44. package/test/LatLng.test.js +45 -0
  45. package/test/Point.test.js +14 -0
  46. package/test/Polyline.test.js +78 -0
  47. package/test/RegionCoverer.test.js +301 -0
  48. package/test.sh +16 -0
  49. package/third_party/s2geometry/.travis.yml +163 -0
  50. package/third_party/s2geometry/AUTHORS +13 -0
  51. package/third_party/s2geometry/CONTRIBUTING.md +65 -0
  52. package/third_party/s2geometry/CONTRIBUTORS +30 -0
  53. package/third_party/s2geometry/LICENSE +202 -0
  54. package/third_party/s2geometry/NOTICE +5 -0
  55. package/third_party/s2geometry/README.md +127 -0
  56. package/third_party/s2geometry/doc/examples/point_index.cc +44 -0
  57. package/third_party/s2geometry/doc/examples/term_index.cc +99 -0
  58. package/third_party/s2geometry/doc/examples/term_index.py +101 -0
  59. package/third_party/s2geometry/src/python/coder.i +125 -0
  60. package/third_party/s2geometry/src/python/pywraps2_test.py +786 -0
  61. package/third_party/s2geometry/src/python/s2.i +37 -0
  62. package/third_party/s2geometry/src/python/s2_common.i +756 -0
  63. package/third_party/s2geometry/src/s2/_fp_contract_off.h +60 -0
  64. package/third_party/s2geometry/src/s2/base/casts.h +318 -0
  65. package/third_party/s2geometry/src/s2/base/commandlineflags.h +67 -0
  66. package/third_party/s2geometry/src/s2/base/integral_types.h +31 -0
  67. package/third_party/s2geometry/src/s2/base/log_severity.h +40 -0
  68. package/third_party/s2geometry/src/s2/base/logging.h +173 -0
  69. package/third_party/s2geometry/src/s2/base/mutex.h +61 -0
  70. package/third_party/s2geometry/src/s2/base/port.h +999 -0
  71. package/third_party/s2geometry/src/s2/base/spinlock.h +60 -0
  72. package/third_party/s2geometry/src/s2/base/stringprintf.cc +107 -0
  73. package/third_party/s2geometry/src/s2/base/stringprintf.h +53 -0
  74. package/third_party/s2geometry/src/s2/base/strtoint.cc +65 -0
  75. package/third_party/s2geometry/src/s2/base/strtoint.h +106 -0
  76. package/third_party/s2geometry/src/s2/base/timer.h +50 -0
  77. package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector.cc +164 -0
  78. package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector.h +110 -0
  79. package/third_party/s2geometry/src/s2/encoded_s2cell_id_vector_test.cc +232 -0
  80. package/third_party/s2geometry/src/s2/encoded_s2point_vector.cc +838 -0
  81. package/third_party/s2geometry/src/s2/encoded_s2point_vector.h +140 -0
  82. package/third_party/s2geometry/src/s2/encoded_s2point_vector_test.cc +344 -0
  83. package/third_party/s2geometry/src/s2/encoded_s2shape_index.cc +181 -0
  84. package/third_party/s2geometry/src/s2/encoded_s2shape_index.h +276 -0
  85. package/third_party/s2geometry/src/s2/encoded_s2shape_index_test.cc +244 -0
  86. package/third_party/s2geometry/src/s2/encoded_string_vector.cc +66 -0
  87. package/third_party/s2geometry/src/s2/encoded_string_vector.h +164 -0
  88. package/third_party/s2geometry/src/s2/encoded_string_vector_test.cc +69 -0
  89. package/third_party/s2geometry/src/s2/encoded_uint_vector.h +299 -0
  90. package/third_party/s2geometry/src/s2/encoded_uint_vector_test.cc +124 -0
  91. package/third_party/s2geometry/src/s2/id_set_lexicon.cc +81 -0
  92. package/third_party/s2geometry/src/s2/id_set_lexicon.h +199 -0
  93. package/third_party/s2geometry/src/s2/id_set_lexicon_test.cc +70 -0
  94. package/third_party/s2geometry/src/s2/mutable_s2shape_index.cc +1585 -0
  95. package/third_party/s2geometry/src/s2/mutable_s2shape_index.h +600 -0
  96. package/third_party/s2geometry/src/s2/mutable_s2shape_index_test.cc +589 -0
  97. package/third_party/s2geometry/src/s2/r1interval.h +220 -0
  98. package/third_party/s2geometry/src/s2/r1interval_test.cc +185 -0
  99. package/third_party/s2geometry/src/s2/r2.h +26 -0
  100. package/third_party/s2geometry/src/s2/r2rect.cc +93 -0
  101. package/third_party/s2geometry/src/s2/r2rect.h +234 -0
  102. package/third_party/s2geometry/src/s2/r2rect_test.cc +228 -0
  103. package/third_party/s2geometry/src/s2/s1angle.cc +54 -0
  104. package/third_party/s2geometry/src/s2/s1angle.h +336 -0
  105. package/third_party/s2geometry/src/s2/s1angle_test.cc +185 -0
  106. package/third_party/s2geometry/src/s2/s1chord_angle.cc +159 -0
  107. package/third_party/s2geometry/src/s2/s1chord_angle.h +369 -0
  108. package/third_party/s2geometry/src/s2/s1chord_angle_test.cc +207 -0
  109. package/third_party/s2geometry/src/s2/s1interval.cc +296 -0
  110. package/third_party/s2geometry/src/s2/s1interval.h +266 -0
  111. package/third_party/s2geometry/src/s2/s1interval_test.cc +469 -0
  112. package/third_party/s2geometry/src/s2/s2boolean_operation.cc +2391 -0
  113. package/third_party/s2geometry/src/s2/s2boolean_operation.h +501 -0
  114. package/third_party/s2geometry/src/s2/s2boolean_operation_test.cc +1400 -0
  115. package/third_party/s2geometry/src/s2/s2builder.cc +1828 -0
  116. package/third_party/s2geometry/src/s2/s2builder.h +1057 -0
  117. package/third_party/s2geometry/src/s2/s2builder_graph.cc +1084 -0
  118. package/third_party/s2geometry/src/s2/s2builder_graph.h +799 -0
  119. package/third_party/s2geometry/src/s2/s2builder_graph_test.cc +462 -0
  120. package/third_party/s2geometry/src/s2/s2builder_layer.h +50 -0
  121. package/third_party/s2geometry/src/s2/s2builder_test.cc +1329 -0
  122. package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer.cc +313 -0
  123. package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer.h +221 -0
  124. package/third_party/s2geometry/src/s2/s2builderutil_closed_set_normalizer_test.cc +261 -0
  125. package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies.cc +392 -0
  126. package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies.h +86 -0
  127. package/third_party/s2geometry/src/s2/s2builderutil_find_polygon_degeneracies_test.cc +182 -0
  128. package/third_party/s2geometry/src/s2/s2builderutil_graph_shape.h +57 -0
  129. package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer.cc +212 -0
  130. package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer.h +218 -0
  131. package/third_party/s2geometry/src/s2/s2builderutil_lax_polygon_layer_test.cc +367 -0
  132. package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer.cc +74 -0
  133. package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer.h +122 -0
  134. package/third_party/s2geometry/src/s2/s2builderutil_s2point_vector_layer_test.cc +167 -0
  135. package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer.cc +191 -0
  136. package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer.h +211 -0
  137. package/third_party/s2geometry/src/s2/s2builderutil_s2polygon_layer_test.cc +312 -0
  138. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer.cc +105 -0
  139. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer.h +174 -0
  140. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_layer_test.cc +220 -0
  141. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer.cc +98 -0
  142. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer.h +292 -0
  143. package/third_party/s2geometry/src/s2/s2builderutil_s2polyline_vector_layer_test.cc +233 -0
  144. package/third_party/s2geometry/src/s2/s2builderutil_snap_functions.cc +354 -0
  145. package/third_party/s2geometry/src/s2/s2builderutil_snap_functions.h +239 -0
  146. package/third_party/s2geometry/src/s2/s2builderutil_snap_functions_test.cc +716 -0
  147. package/third_party/s2geometry/src/s2/s2builderutil_testing.cc +37 -0
  148. package/third_party/s2geometry/src/s2/s2builderutil_testing.h +100 -0
  149. package/third_party/s2geometry/src/s2/s2builderutil_testing_test.cc +85 -0
  150. package/third_party/s2geometry/src/s2/s2cap.cc +347 -0
  151. package/third_party/s2geometry/src/s2/s2cap.h +286 -0
  152. package/third_party/s2geometry/src/s2/s2cap_test.cc +379 -0
  153. package/third_party/s2geometry/src/s2/s2cell.cc +552 -0
  154. package/third_party/s2geometry/src/s2/s2cell.h +249 -0
  155. package/third_party/s2geometry/src/s2/s2cell_id.cc +619 -0
  156. package/third_party/s2geometry/src/s2/s2cell_id.h +705 -0
  157. package/third_party/s2geometry/src/s2/s2cell_id_test.cc +633 -0
  158. package/third_party/s2geometry/src/s2/s2cell_index.cc +149 -0
  159. package/third_party/s2geometry/src/s2/s2cell_index.h +660 -0
  160. package/third_party/s2geometry/src/s2/s2cell_index_test.cc +411 -0
  161. package/third_party/s2geometry/src/s2/s2cell_test.cc +687 -0
  162. package/third_party/s2geometry/src/s2/s2cell_union.cc +515 -0
  163. package/third_party/s2geometry/src/s2/s2cell_union.h +399 -0
  164. package/third_party/s2geometry/src/s2/s2cell_union_test.cc +598 -0
  165. package/third_party/s2geometry/src/s2/s2centroids.cc +84 -0
  166. package/third_party/s2geometry/src/s2/s2centroids.h +87 -0
  167. package/third_party/s2geometry/src/s2/s2centroids_test.cc +82 -0
  168. package/third_party/s2geometry/src/s2/s2closest_cell_query.cc +123 -0
  169. package/third_party/s2geometry/src/s2/s2closest_cell_query.h +385 -0
  170. package/third_party/s2geometry/src/s2/s2closest_cell_query_base.h +841 -0
  171. package/third_party/s2geometry/src/s2/s2closest_cell_query_base_test.cc +63 -0
  172. package/third_party/s2geometry/src/s2/s2closest_cell_query_test.cc +412 -0
  173. package/third_party/s2geometry/src/s2/s2closest_edge_query.cc +106 -0
  174. package/third_party/s2geometry/src/s2/s2closest_edge_query.h +421 -0
  175. package/third_party/s2geometry/src/s2/s2closest_edge_query_base.h +946 -0
  176. package/third_party/s2geometry/src/s2/s2closest_edge_query_base_test.cc +59 -0
  177. package/third_party/s2geometry/src/s2/s2closest_edge_query_test.cc +505 -0
  178. package/third_party/s2geometry/src/s2/s2closest_edge_query_testing.h +91 -0
  179. package/third_party/s2geometry/src/s2/s2closest_point_query.cc +66 -0
  180. package/third_party/s2geometry/src/s2/s2closest_point_query.h +465 -0
  181. package/third_party/s2geometry/src/s2/s2closest_point_query_base.h +767 -0
  182. package/third_party/s2geometry/src/s2/s2closest_point_query_base_test.cc +63 -0
  183. package/third_party/s2geometry/src/s2/s2closest_point_query_test.cc +312 -0
  184. package/third_party/s2geometry/src/s2/s2contains_point_query.h +328 -0
  185. package/third_party/s2geometry/src/s2/s2contains_point_query_test.cc +159 -0
  186. package/third_party/s2geometry/src/s2/s2contains_vertex_query.cc +39 -0
  187. package/third_party/s2geometry/src/s2/s2contains_vertex_query.h +66 -0
  188. package/third_party/s2geometry/src/s2/s2contains_vertex_query_test.cc +67 -0
  189. package/third_party/s2geometry/src/s2/s2convex_hull_query.cc +198 -0
  190. package/third_party/s2geometry/src/s2/s2convex_hull_query.h +110 -0
  191. package/third_party/s2geometry/src/s2/s2convex_hull_query_test.cc +208 -0
  192. package/third_party/s2geometry/src/s2/s2coords.cc +146 -0
  193. package/third_party/s2geometry/src/s2/s2coords.h +459 -0
  194. package/third_party/s2geometry/src/s2/s2coords_internal.h +71 -0
  195. package/third_party/s2geometry/src/s2/s2coords_test.cc +218 -0
  196. package/third_party/s2geometry/src/s2/s2crossing_edge_query.cc +380 -0
  197. package/third_party/s2geometry/src/s2/s2crossing_edge_query.h +220 -0
  198. package/third_party/s2geometry/src/s2/s2crossing_edge_query_test.cc +382 -0
  199. package/third_party/s2geometry/src/s2/s2debug.cc +23 -0
  200. package/third_party/s2geometry/src/s2/s2debug.h +69 -0
  201. package/third_party/s2geometry/src/s2/s2distance_target.h +165 -0
  202. package/third_party/s2geometry/src/s2/s2earth.cc +52 -0
  203. package/third_party/s2geometry/src/s2/s2earth.h +268 -0
  204. package/third_party/s2geometry/src/s2/s2earth_test.cc +146 -0
  205. package/third_party/s2geometry/src/s2/s2edge_clipping.cc +462 -0
  206. package/third_party/s2geometry/src/s2/s2edge_clipping.h +183 -0
  207. package/third_party/s2geometry/src/s2/s2edge_clipping_test.cc +335 -0
  208. package/third_party/s2geometry/src/s2/s2edge_crosser.cc +85 -0
  209. package/third_party/s2geometry/src/s2/s2edge_crosser.h +343 -0
  210. package/third_party/s2geometry/src/s2/s2edge_crosser_test.cc +264 -0
  211. package/third_party/s2geometry/src/s2/s2edge_crossings.cc +515 -0
  212. package/third_party/s2geometry/src/s2/s2edge_crossings.h +138 -0
  213. package/third_party/s2geometry/src/s2/s2edge_crossings_internal.h +59 -0
  214. package/third_party/s2geometry/src/s2/s2edge_crossings_test.cc +246 -0
  215. package/third_party/s2geometry/src/s2/s2edge_distances.cc +419 -0
  216. package/third_party/s2geometry/src/s2/s2edge_distances.h +192 -0
  217. package/third_party/s2geometry/src/s2/s2edge_distances_test.cc +539 -0
  218. package/third_party/s2geometry/src/s2/s2edge_tessellator.cc +276 -0
  219. package/third_party/s2geometry/src/s2/s2edge_tessellator.h +101 -0
  220. package/third_party/s2geometry/src/s2/s2edge_tessellator_test.cc +492 -0
  221. package/third_party/s2geometry/src/s2/s2edge_vector_shape.h +85 -0
  222. package/third_party/s2geometry/src/s2/s2edge_vector_shape_test.cc +66 -0
  223. package/third_party/s2geometry/src/s2/s2error.cc +29 -0
  224. package/third_party/s2geometry/src/s2/s2error.h +147 -0
  225. package/third_party/s2geometry/src/s2/s2error_test.cc +31 -0
  226. package/third_party/s2geometry/src/s2/s2furthest_edge_query.cc +117 -0
  227. package/third_party/s2geometry/src/s2/s2furthest_edge_query.h +439 -0
  228. package/third_party/s2geometry/src/s2/s2furthest_edge_query_test.cc +487 -0
  229. package/third_party/s2geometry/src/s2/s2latlng.cc +90 -0
  230. package/third_party/s2geometry/src/s2/s2latlng.h +234 -0
  231. package/third_party/s2geometry/src/s2/s2latlng_rect.cc +727 -0
  232. package/third_party/s2geometry/src/s2/s2latlng_rect.h +434 -0
  233. package/third_party/s2geometry/src/s2/s2latlng_rect_bounder.cc +344 -0
  234. package/third_party/s2geometry/src/s2/s2latlng_rect_bounder.h +89 -0
  235. package/third_party/s2geometry/src/s2/s2latlng_rect_bounder_test.cc +306 -0
  236. package/third_party/s2geometry/src/s2/s2latlng_rect_test.cc +1030 -0
  237. package/third_party/s2geometry/src/s2/s2latlng_test.cc +165 -0
  238. package/third_party/s2geometry/src/s2/s2lax_loop_shape.cc +104 -0
  239. package/third_party/s2geometry/src/s2/s2lax_loop_shape.h +153 -0
  240. package/third_party/s2geometry/src/s2/s2lax_loop_shape_test.cc +101 -0
  241. package/third_party/s2geometry/src/s2/s2lax_polygon_shape.cc +348 -0
  242. package/third_party/s2geometry/src/s2/s2lax_polygon_shape.h +183 -0
  243. package/third_party/s2geometry/src/s2/s2lax_polygon_shape_test.cc +234 -0
  244. package/third_party/s2geometry/src/s2/s2lax_polyline_shape.cc +118 -0
  245. package/third_party/s2geometry/src/s2/s2lax_polyline_shape.h +124 -0
  246. package/third_party/s2geometry/src/s2/s2lax_polyline_shape_test.cc +62 -0
  247. package/third_party/s2geometry/src/s2/s2loop.cc +1509 -0
  248. package/third_party/s2geometry/src/s2/s2loop.h +711 -0
  249. package/third_party/s2geometry/src/s2/s2loop_measures.cc +313 -0
  250. package/third_party/s2geometry/src/s2/s2loop_measures.h +280 -0
  251. package/third_party/s2geometry/src/s2/s2loop_measures_test.cc +367 -0
  252. package/third_party/s2geometry/src/s2/s2loop_test.cc +1371 -0
  253. package/third_party/s2geometry/src/s2/s2max_distance_targets.cc +265 -0
  254. package/third_party/s2geometry/src/s2/s2max_distance_targets.h +241 -0
  255. package/third_party/s2geometry/src/s2/s2max_distance_targets_test.cc +367 -0
  256. package/third_party/s2geometry/src/s2/s2measures.cc +128 -0
  257. package/third_party/s2geometry/src/s2/s2measures.h +78 -0
  258. package/third_party/s2geometry/src/s2/s2measures_test.cc +135 -0
  259. package/third_party/s2geometry/src/s2/s2metrics.cc +122 -0
  260. package/third_party/s2geometry/src/s2/s2metrics.h +199 -0
  261. package/third_party/s2geometry/src/s2/s2metrics_test.cc +127 -0
  262. package/third_party/s2geometry/src/s2/s2min_distance_targets.cc +295 -0
  263. package/third_party/s2geometry/src/s2/s2min_distance_targets.h +273 -0
  264. package/third_party/s2geometry/src/s2/s2min_distance_targets_test.cc +239 -0
  265. package/third_party/s2geometry/src/s2/s2padded_cell.cc +162 -0
  266. package/third_party/s2geometry/src/s2/s2padded_cell.h +108 -0
  267. package/third_party/s2geometry/src/s2/s2padded_cell_test.cc +138 -0
  268. package/third_party/s2geometry/src/s2/s2point.h +38 -0
  269. package/third_party/s2geometry/src/s2/s2point_compression.cc +388 -0
  270. package/third_party/s2geometry/src/s2/s2point_compression.h +78 -0
  271. package/third_party/s2geometry/src/s2/s2point_compression_test.cc +305 -0
  272. package/third_party/s2geometry/src/s2/s2point_index.h +345 -0
  273. package/third_party/s2geometry/src/s2/s2point_index_test.cc +147 -0
  274. package/third_party/s2geometry/src/s2/s2point_region.cc +72 -0
  275. package/third_party/s2geometry/src/s2/s2point_region.h +76 -0
  276. package/third_party/s2geometry/src/s2/s2point_region_test.cc +100 -0
  277. package/third_party/s2geometry/src/s2/s2point_span.h +57 -0
  278. package/third_party/s2geometry/src/s2/s2point_test.cc +47 -0
  279. package/third_party/s2geometry/src/s2/s2point_vector_shape.h +127 -0
  280. package/third_party/s2geometry/src/s2/s2point_vector_shape_test.cc +59 -0
  281. package/third_party/s2geometry/src/s2/s2pointutil.cc +131 -0
  282. package/third_party/s2geometry/src/s2/s2pointutil.h +138 -0
  283. package/third_party/s2geometry/src/s2/s2pointutil_test.cc +157 -0
  284. package/third_party/s2geometry/src/s2/s2polygon.cc +1569 -0
  285. package/third_party/s2geometry/src/s2/s2polygon.h +934 -0
  286. package/third_party/s2geometry/src/s2/s2polygon_test.cc +3025 -0
  287. package/third_party/s2geometry/src/s2/s2polyline.cc +645 -0
  288. package/third_party/s2geometry/src/s2/s2polyline.h +379 -0
  289. package/third_party/s2geometry/src/s2/s2polyline_alignment.cc +414 -0
  290. package/third_party/s2geometry/src/s2/s2polyline_alignment.h +245 -0
  291. package/third_party/s2geometry/src/s2/s2polyline_alignment_internal.h +158 -0
  292. package/third_party/s2geometry/src/s2/s2polyline_alignment_test.cc +610 -0
  293. package/third_party/s2geometry/src/s2/s2polyline_measures.cc +42 -0
  294. package/third_party/s2geometry/src/s2/s2polyline_measures.h +53 -0
  295. package/third_party/s2geometry/src/s2/s2polyline_measures_test.cc +57 -0
  296. package/third_party/s2geometry/src/s2/s2polyline_simplifier.cc +187 -0
  297. package/third_party/s2geometry/src/s2/s2polyline_simplifier.h +109 -0
  298. package/third_party/s2geometry/src/s2/s2polyline_simplifier_test.cc +165 -0
  299. package/third_party/s2geometry/src/s2/s2polyline_test.cc +554 -0
  300. package/third_party/s2geometry/src/s2/s2predicates.cc +1486 -0
  301. package/third_party/s2geometry/src/s2/s2predicates.h +282 -0
  302. package/third_party/s2geometry/src/s2/s2predicates_internal.h +135 -0
  303. package/third_party/s2geometry/src/s2/s2predicates_test.cc +1427 -0
  304. package/third_party/s2geometry/src/s2/s2projections.cc +109 -0
  305. package/third_party/s2geometry/src/s2/s2projections.h +161 -0
  306. package/third_party/s2geometry/src/s2/s2projections_test.cc +78 -0
  307. package/third_party/s2geometry/src/s2/s2r2rect.cc +88 -0
  308. package/third_party/s2geometry/src/s2/s2r2rect.h +292 -0
  309. package/third_party/s2geometry/src/s2/s2r2rect_test.cc +312 -0
  310. package/third_party/s2geometry/src/s2/s2region.cc +26 -0
  311. package/third_party/s2geometry/src/s2/s2region.h +142 -0
  312. package/third_party/s2geometry/src/s2/s2region_coverer.cc +514 -0
  313. package/third_party/s2geometry/src/s2/s2region_coverer.h +356 -0
  314. package/third_party/s2geometry/src/s2/s2region_coverer_test.cc +509 -0
  315. package/third_party/s2geometry/src/s2/s2region_intersection.cc +84 -0
  316. package/third_party/s2geometry/src/s2/s2region_intersection.h +79 -0
  317. package/third_party/s2geometry/src/s2/s2region_term_indexer.cc +270 -0
  318. package/third_party/s2geometry/src/s2/s2region_term_indexer.h +299 -0
  319. package/third_party/s2geometry/src/s2/s2region_term_indexer_test.cc +209 -0
  320. package/third_party/s2geometry/src/s2/s2region_test.cc +370 -0
  321. package/third_party/s2geometry/src/s2/s2region_union.cc +90 -0
  322. package/third_party/s2geometry/src/s2/s2region_union.h +83 -0
  323. package/third_party/s2geometry/src/s2/s2region_union_test.cc +89 -0
  324. package/third_party/s2geometry/src/s2/s2shape.h +283 -0
  325. package/third_party/s2geometry/src/s2/s2shape_index.cc +321 -0
  326. package/third_party/s2geometry/src/s2/s2shape_index.h +781 -0
  327. package/third_party/s2geometry/src/s2/s2shape_index_buffered_region.cc +113 -0
  328. package/third_party/s2geometry/src/s2/s2shape_index_buffered_region.h +135 -0
  329. package/third_party/s2geometry/src/s2/s2shape_index_buffered_region_test.cc +162 -0
  330. package/third_party/s2geometry/src/s2/s2shape_index_measures.cc +92 -0
  331. package/third_party/s2geometry/src/s2/s2shape_index_measures.h +100 -0
  332. package/third_party/s2geometry/src/s2/s2shape_index_measures_test.cc +136 -0
  333. package/third_party/s2geometry/src/s2/s2shape_index_region.h +350 -0
  334. package/third_party/s2geometry/src/s2/s2shape_index_region_test.cc +161 -0
  335. package/third_party/s2geometry/src/s2/s2shape_index_test.cc +24 -0
  336. package/third_party/s2geometry/src/s2/s2shape_measures.cc +138 -0
  337. package/third_party/s2geometry/src/s2/s2shape_measures.h +95 -0
  338. package/third_party/s2geometry/src/s2/s2shape_measures_test.cc +139 -0
  339. package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries.cc +120 -0
  340. package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries.h +66 -0
  341. package/third_party/s2geometry/src/s2/s2shapeutil_build_polygon_boundaries_test.cc +170 -0
  342. package/third_party/s2geometry/src/s2/s2shapeutil_coding.cc +253 -0
  343. package/third_party/s2geometry/src/s2/s2shapeutil_coding.h +283 -0
  344. package/third_party/s2geometry/src/s2/s2shapeutil_coding_test.cc +54 -0
  345. package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force.cc +40 -0
  346. package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force.h +41 -0
  347. package/third_party/s2geometry/src/s2/s2shapeutil_contains_brute_force_test.cc +55 -0
  348. package/third_party/s2geometry/src/s2/s2shapeutil_count_edges.h +57 -0
  349. package/third_party/s2geometry/src/s2/s2shapeutil_count_edges_test.cc +43 -0
  350. package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator.cc +45 -0
  351. package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator.h +72 -0
  352. package/third_party/s2geometry/src/s2/s2shapeutil_edge_iterator_test.cc +116 -0
  353. package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point.cc +107 -0
  354. package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point.h +48 -0
  355. package/third_party/s2geometry/src/s2/s2shapeutil_get_reference_point_test.cc +104 -0
  356. package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator.cc +58 -0
  357. package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator.h +65 -0
  358. package/third_party/s2geometry/src/s2/s2shapeutil_range_iterator_test.cc +61 -0
  359. package/third_party/s2geometry/src/s2/s2shapeutil_shape_edge.h +58 -0
  360. package/third_party/s2geometry/src/s2/s2shapeutil_shape_edge_id.h +97 -0
  361. package/third_party/s2geometry/src/s2/s2shapeutil_testing.cc +104 -0
  362. package/third_party/s2geometry/src/s2/s2shapeutil_testing.h +36 -0
  363. package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs.cc +440 -0
  364. package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs.h +72 -0
  365. package/third_party/s2geometry/src/s2/s2shapeutil_visit_crossing_edge_pairs_test.cc +184 -0
  366. package/third_party/s2geometry/src/s2/s2testing.cc +464 -0
  367. package/third_party/s2geometry/src/s2/s2testing.h +385 -0
  368. package/third_party/s2geometry/src/s2/s2testing_test.cc +166 -0
  369. package/third_party/s2geometry/src/s2/s2text_format.cc +506 -0
  370. package/third_party/s2geometry/src/s2/s2text_format.h +289 -0
  371. package/third_party/s2geometry/src/s2/s2text_format_test.cc +417 -0
  372. package/third_party/s2geometry/src/s2/s2wedge_relations.cc +80 -0
  373. package/third_party/s2geometry/src/s2/s2wedge_relations.h +64 -0
  374. package/third_party/s2geometry/src/s2/s2wedge_relations_test.cc +89 -0
  375. package/third_party/s2geometry/src/s2/sequence_lexicon.h +296 -0
  376. package/third_party/s2geometry/src/s2/sequence_lexicon_test.cc +113 -0
  377. package/third_party/s2geometry/src/s2/strings/ostringstream.cc +35 -0
  378. package/third_party/s2geometry/src/s2/strings/ostringstream.h +105 -0
  379. package/third_party/s2geometry/src/s2/strings/serialize.cc +46 -0
  380. package/third_party/s2geometry/src/s2/strings/serialize.h +40 -0
  381. package/third_party/s2geometry/src/s2/third_party/absl/algorithm/algorithm.h +187 -0
  382. package/third_party/s2geometry/src/s2/third_party/absl/base/attributes.h +666 -0
  383. package/third_party/s2geometry/src/s2/third_party/absl/base/casts.h +189 -0
  384. package/third_party/s2geometry/src/s2/third_party/absl/base/config.h +462 -0
  385. package/third_party/s2geometry/src/s2/third_party/absl/base/dynamic_annotations.cc +129 -0
  386. package/third_party/s2geometry/src/s2/third_party/absl/base/dynamic_annotations.h +394 -0
  387. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/atomic_hook.h +168 -0
  388. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/identity.h +33 -0
  389. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/inline_variable.h +117 -0
  390. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/invoke.h +188 -0
  391. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/raw_logging.cc +254 -0
  392. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/raw_logging.h +205 -0
  393. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/throw_delegate.cc +106 -0
  394. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/throw_delegate.h +71 -0
  395. package/third_party/s2geometry/src/s2/third_party/absl/base/internal/unaligned_access.h +322 -0
  396. package/third_party/s2geometry/src/s2/third_party/absl/base/log_severity.h +77 -0
  397. package/third_party/s2geometry/src/s2/third_party/absl/base/macros.h +236 -0
  398. package/third_party/s2geometry/src/s2/third_party/absl/base/optimization.h +177 -0
  399. package/third_party/s2geometry/src/s2/third_party/absl/base/policy_checks.h +124 -0
  400. package/third_party/s2geometry/src/s2/third_party/absl/base/port.h +97 -0
  401. package/third_party/s2geometry/src/s2/third_party/absl/base/thread_annotations.h +277 -0
  402. package/third_party/s2geometry/src/s2/third_party/absl/container/fixed_array.h +523 -0
  403. package/third_party/s2geometry/src/s2/third_party/absl/container/inlined_vector.h +1453 -0
  404. package/third_party/s2geometry/src/s2/third_party/absl/container/internal/compressed_tuple.h +191 -0
  405. package/third_party/s2geometry/src/s2/third_party/absl/container/internal/container_memory.h +424 -0
  406. package/third_party/s2geometry/src/s2/third_party/absl/container/internal/layout.h +739 -0
  407. package/third_party/s2geometry/src/s2/third_party/absl/memory/memory.h +755 -0
  408. package/third_party/s2geometry/src/s2/third_party/absl/meta/type_traits.h +436 -0
  409. package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128.cc +232 -0
  410. package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128.h +656 -0
  411. package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128_have_intrinsic.inc +3 -0
  412. package/third_party/s2geometry/src/s2/third_party/absl/numeric/int128_no_intrinsic.inc +3 -0
  413. package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii.cc +198 -0
  414. package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii.h +239 -0
  415. package/third_party/s2geometry/src/s2/third_party/absl/strings/ascii_ctype.h +66 -0
  416. package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/bits.h +53 -0
  417. package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/memutil.cc +110 -0
  418. package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/memutil.h +146 -0
  419. package/third_party/s2geometry/src/s2/third_party/absl/strings/internal/resize_uninitialized.h +72 -0
  420. package/third_party/s2geometry/src/s2/third_party/absl/strings/match.cc +38 -0
  421. package/third_party/s2geometry/src/s2/third_party/absl/strings/match.h +89 -0
  422. package/third_party/s2geometry/src/s2/third_party/absl/strings/numbers.cc +909 -0
  423. package/third_party/s2geometry/src/s2/third_party/absl/strings/numbers.h +187 -0
  424. package/third_party/s2geometry/src/s2/third_party/absl/strings/str_cat.cc +240 -0
  425. package/third_party/s2geometry/src/s2/third_party/absl/strings/str_cat.h +398 -0
  426. package/third_party/s2geometry/src/s2/third_party/absl/strings/str_join.h +22 -0
  427. package/third_party/s2geometry/src/s2/third_party/absl/strings/str_split.cc +47 -0
  428. package/third_party/s2geometry/src/s2/third_party/absl/strings/str_split.h +43 -0
  429. package/third_party/s2geometry/src/s2/third_party/absl/strings/string_view.cc +245 -0
  430. package/third_party/s2geometry/src/s2/third_party/absl/strings/string_view.h +602 -0
  431. package/third_party/s2geometry/src/s2/third_party/absl/strings/strip.cc +42 -0
  432. package/third_party/s2geometry/src/s2/third_party/absl/strings/strip.h +130 -0
  433. package/third_party/s2geometry/src/s2/third_party/absl/types/span.h +793 -0
  434. package/third_party/s2geometry/src/s2/third_party/absl/utility/utility.h +299 -0
  435. package/third_party/s2geometry/src/s2/util/bits/bit-interleave.cc +274 -0
  436. package/third_party/s2geometry/src/s2/util/bits/bit-interleave.h +53 -0
  437. package/third_party/s2geometry/src/s2/util/bits/bits.cc +155 -0
  438. package/third_party/s2geometry/src/s2/util/bits/bits.h +745 -0
  439. package/third_party/s2geometry/src/s2/util/coding/coder.cc +83 -0
  440. package/third_party/s2geometry/src/s2/util/coding/coder.h +553 -0
  441. package/third_party/s2geometry/src/s2/util/coding/nth-derivative.h +134 -0
  442. package/third_party/s2geometry/src/s2/util/coding/transforms.h +62 -0
  443. package/third_party/s2geometry/src/s2/util/coding/varint.cc +289 -0
  444. package/third_party/s2geometry/src/s2/util/coding/varint.h +476 -0
  445. package/third_party/s2geometry/src/s2/util/endian/endian.h +859 -0
  446. package/third_party/s2geometry/src/s2/util/gtl/btree.h +2471 -0
  447. package/third_party/s2geometry/src/s2/util/gtl/btree_container.h +411 -0
  448. package/third_party/s2geometry/src/s2/util/gtl/btree_map.h +79 -0
  449. package/third_party/s2geometry/src/s2/util/gtl/btree_set.h +73 -0
  450. package/third_party/s2geometry/src/s2/util/gtl/compact_array.h +653 -0
  451. package/third_party/s2geometry/src/s2/util/gtl/container_logging.h +291 -0
  452. package/third_party/s2geometry/src/s2/util/gtl/dense_hash_set.h +358 -0
  453. package/third_party/s2geometry/src/s2/util/gtl/densehashtable.h +1493 -0
  454. package/third_party/s2geometry/src/s2/util/gtl/hashtable_common.h +253 -0
  455. package/third_party/s2geometry/src/s2/util/gtl/layout.h +28 -0
  456. package/third_party/s2geometry/src/s2/util/gtl/legacy_random_shuffle.h +77 -0
  457. package/third_party/s2geometry/src/s2/util/hash/mix.h +76 -0
  458. package/third_party/s2geometry/src/s2/util/math/exactfloat/exactfloat.cc +832 -0
  459. package/third_party/s2geometry/src/s2/util/math/exactfloat/exactfloat.h +646 -0
  460. package/third_party/s2geometry/src/s2/util/math/mathutil.cc +75 -0
  461. package/third_party/s2geometry/src/s2/util/math/mathutil.h +189 -0
  462. package/third_party/s2geometry/src/s2/util/math/matrix3x3.h +574 -0
  463. package/third_party/s2geometry/src/s2/util/math/vector.h +569 -0
  464. package/third_party/s2geometry/src/s2/util/math/vector3_hash.h +54 -0
  465. package/third_party/s2geometry/src/s2/util/units/length-units.cc +21 -0
  466. package/third_party/s2geometry/src/s2/util/units/length-units.h +135 -0
  467. package/third_party/s2geometry/src/s2/util/units/physical-units.h +313 -0
  468. package/third_party/s2geometry/src/s2/value_lexicon.h +234 -0
  469. package/third_party/s2geometry/src/s2/value_lexicon_test.cc +121 -0
  470. package/third_party/s2geometry/third_party/cmake/FindGFlags.cmake +48 -0
  471. package/third_party/s2geometry/third_party/cmake/FindGlog.cmake +48 -0
@@ -0,0 +1,1828 @@
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
+ // The algorithm is based on the idea of choosing a set of sites and computing
19
+ // their "limited radius Voronoi diagram", which is obtained by intersecting
20
+ // each Voronoi region with a disc of fixed radius (the "snap radius")
21
+ // centered around the corresponding site.
22
+ //
23
+ // For each input edge, we then determine the sequence of Voronoi regions
24
+ // crossed by that edge, and snap the edge to the corresponding sequence of
25
+ // sites. (In other words, each input edge is replaced by an edge chain.)
26
+ //
27
+ // The sites are chosen by starting with the set of input vertices, optionally
28
+ // snapping them to discrete point set (such as S2CellId centers or lat/lng E7
29
+ // coordinates), and then choosing a subset such that no two sites are closer
30
+ // than the given "snap_radius". Note that the sites do not need to be spaced
31
+ // regularly -- their positions are completely arbitrary.
32
+ //
33
+ // Rather than computing the full limited radius Voronoi diagram, instead we
34
+ // compute on demand the sequence of Voronoi regions intersected by each edge.
35
+ // We do this by first finding all the sites that are within "snap_radius" of
36
+ // the edge, sorting them by distance from the edge origin, and then using an
37
+ // incremental algorithm.
38
+ //
39
+ // We implement the minimum edge-vertex separation property by snapping all
40
+ // the input edges and checking whether any site (the "site to avoid") would
41
+ // then be too close to the edge. If so we add another site (the "separation
42
+ // site") along the input edge, positioned so that the new snapped edge is
43
+ // guaranteed to be far enough away from the site to avoid. We then find all
44
+ // the input edges that are within "snap_radius" of the new site, and resnap
45
+ // those edges. (It is very rare that we need to add a separation site, even
46
+ // when sites are densely spaced.)
47
+ //
48
+ // Idempotency is implemented by explicitly checking whether the input
49
+ // geometry already meets the output criteria. This is not as sophisticated
50
+ // as Stable Snap Rounding (Hershberger); I have worked out the details and it
51
+ // is possible to adapt those ideas here, but it would make the implementation
52
+ // significantly more complex.
53
+ //
54
+ // The only way that different output layers interact is in the choice of
55
+ // Voronoi sites:
56
+ //
57
+ // - Vertices from all layers contribute to the initial selection of sites.
58
+ //
59
+ // - Edges in any layer that pass too close to a site can cause new sites to
60
+ // be added (which affects snapping in all layers).
61
+ //
62
+ // - Simplification can be thought of as removing sites. A site can be
63
+ // removed only if the snapped edges stay within the error bounds of the
64
+ // corresponding input edges in all layers.
65
+ //
66
+ // Otherwise all layers are processed independently. For example, sibling
67
+ // edge pairs can only cancel each other within a single layer (if desired).
68
+
69
+ #include "s2/s2builder.h"
70
+
71
+ #include <algorithm>
72
+ #include <cfloat>
73
+ #include <cmath>
74
+ #include <iostream>
75
+ #include <memory>
76
+ #include <numeric>
77
+ #include <string>
78
+ #include <vector>
79
+
80
+ #include "s2/base/casts.h"
81
+ #include "s2/base/logging.h"
82
+ #include "s2/third_party/absl/memory/memory.h"
83
+ #include "s2/util/bits/bits.h"
84
+ #include "s2/id_set_lexicon.h"
85
+ #include "s2/mutable_s2shape_index.h"
86
+ #include "s2/s1angle.h"
87
+ #include "s2/s1chord_angle.h"
88
+ #include "s2/s2builder_graph.h"
89
+ #include "s2/s2builder_layer.h"
90
+ #include "s2/s2builderutil_snap_functions.h"
91
+ #include "s2/s2closest_edge_query.h"
92
+ #include "s2/s2closest_point_query.h"
93
+ #include "s2/s2edge_crossings.h"
94
+ #include "s2/s2edge_distances.h"
95
+ #include "s2/s2error.h"
96
+ #include "s2/s2loop.h"
97
+ #include "s2/s2point_index.h"
98
+ #include "s2/s2pointutil.h"
99
+ #include "s2/s2polygon.h"
100
+ #include "s2/s2polyline.h"
101
+ #include "s2/s2polyline_simplifier.h"
102
+ #include "s2/s2predicates.h"
103
+ #include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
104
+ #include "s2/s2text_format.h"
105
+
106
+ using absl::make_unique;
107
+ using gtl::compact_array;
108
+ using std::max;
109
+ using std::pair;
110
+ using std::unique_ptr;
111
+ using std::vector;
112
+
113
+ // Internal flag intended to be set from within a debugger.
114
+ bool s2builder_verbose = false;
115
+
116
+ S1Angle S2Builder::SnapFunction::max_edge_deviation() const {
117
+ // We want max_edge_deviation() to be large enough compared to snap_radius()
118
+ // such that edge splitting is rare.
119
+ //
120
+ // Using spherical trigonometry, if the endpoints of an edge of length L
121
+ // move by at most a distance R, the center of the edge moves by at most
122
+ // asin(sin(R) / cos(L / 2)). Thus the (max_edge_deviation / snap_radius)
123
+ // ratio increases with both the snap radius R and the edge length L.
124
+ //
125
+ // We arbitrarily limit the edge deviation to be at most 10% more than the
126
+ // snap radius. With the maximum allowed snap radius of 70 degrees, this
127
+ // means that edges up to 30.6 degrees long are never split. For smaller
128
+ // snap radii, edges up to 49 degrees long are never split. (Edges of any
129
+ // length are not split unless their endpoints move far enough so that the
130
+ // actual edge deviation exceeds the limit; in practice, splitting is rare
131
+ // even with long edges.) Note that it is always possible to split edges
132
+ // when max_edge_deviation() is exceeded; see MaybeAddExtraSites().
133
+ S2_DCHECK_LE(snap_radius(), kMaxSnapRadius());
134
+ const double kMaxEdgeDeviationRatio = 1.1;
135
+ return kMaxEdgeDeviationRatio * snap_radius();
136
+ }
137
+
138
+ S2Builder::Options::Options()
139
+ : snap_function_(
140
+ make_unique<s2builderutil::IdentitySnapFunction>(S1Angle::Zero())) {
141
+ }
142
+
143
+ S2Builder::Options::Options(const SnapFunction& snap_function)
144
+ : snap_function_(snap_function.Clone()) {
145
+ }
146
+
147
+ S2Builder::Options::Options(const Options& options)
148
+ : snap_function_(options.snap_function_->Clone()),
149
+ split_crossing_edges_(options.split_crossing_edges_),
150
+ simplify_edge_chains_(options.simplify_edge_chains_),
151
+ idempotent_(options.idempotent_) {
152
+ }
153
+
154
+ S2Builder::Options& S2Builder::Options::operator=(const Options& options) {
155
+ snap_function_ = options.snap_function_->Clone();
156
+ split_crossing_edges_ = options.split_crossing_edges_;
157
+ simplify_edge_chains_ = options.simplify_edge_chains_;
158
+ idempotent_ = options.idempotent_;
159
+ return *this;
160
+ }
161
+
162
+ bool operator==(const S2Builder::GraphOptions& x,
163
+ const S2Builder::GraphOptions& y) {
164
+ return (x.edge_type() == y.edge_type() &&
165
+ x.degenerate_edges() == y.degenerate_edges() &&
166
+ x.duplicate_edges() == y.duplicate_edges() &&
167
+ x.sibling_pairs() == y.sibling_pairs() &&
168
+ x.allow_vertex_filtering() == y.allow_vertex_filtering());
169
+ }
170
+
171
+ // Helper functions for computing error bounds:
172
+
173
+ static S1ChordAngle RoundUp(S1Angle a) {
174
+ S1ChordAngle ca(a);
175
+ return ca.PlusError(ca.GetS1AngleConstructorMaxError());
176
+ }
177
+
178
+ static S1ChordAngle AddPointToPointError(S1ChordAngle ca) {
179
+ return ca.PlusError(ca.GetS2PointConstructorMaxError());
180
+ }
181
+
182
+ static S1ChordAngle AddPointToEdgeError(S1ChordAngle ca) {
183
+ return ca.PlusError(S2::GetUpdateMinDistanceMaxError(ca));
184
+ }
185
+
186
+ S2Builder::S2Builder() {
187
+ }
188
+
189
+ S2Builder::S2Builder(const Options& options) {
190
+ Init(options);
191
+ }
192
+
193
+ void S2Builder::Init(const Options& options) {
194
+ options_ = options;
195
+ const SnapFunction& snap_function = options.snap_function();
196
+ S1Angle snap_radius = snap_function.snap_radius();
197
+ S2_DCHECK_LE(snap_radius, SnapFunction::kMaxSnapRadius());
198
+
199
+ // Convert the snap radius to an S1ChordAngle. This is the "true snap
200
+ // radius" used when evaluating exact predicates (s2predicates.h).
201
+ site_snap_radius_ca_ = S1ChordAngle(snap_radius);
202
+
203
+ // When split_crossing_edges() is true, we need to use a larger snap radius
204
+ // for edges than for vertices to ensure that both edges are snapped to the
205
+ // edge intersection location. This is because the computed intersection
206
+ // point is not exact; it may be up to kIntersectionError away from its true
207
+ // position. The computed intersection point might then be snapped to some
208
+ // other vertex up to snap_radius away. So to ensure that both edges are
209
+ // snapped to a common vertex, we need to increase the snap radius for edges
210
+ // to at least the sum of these two values (calculated conservatively).
211
+ S1Angle edge_snap_radius = snap_radius;
212
+ if (!options.split_crossing_edges()) {
213
+ edge_snap_radius_ca_ = site_snap_radius_ca_;
214
+ } else {
215
+ edge_snap_radius += S2::kIntersectionError;
216
+ edge_snap_radius_ca_ = RoundUp(edge_snap_radius);
217
+ }
218
+ snapping_requested_ = (edge_snap_radius > S1Angle::Zero());
219
+
220
+ // Compute the maximum distance that a vertex can be separated from an
221
+ // edge while still affecting how that edge is snapped.
222
+ max_edge_deviation_ = snap_function.max_edge_deviation();
223
+ edge_site_query_radius_ca_ = S1ChordAngle(
224
+ max_edge_deviation_ + snap_function.min_edge_vertex_separation());
225
+
226
+ // Compute the maximum edge length such that even if both endpoints move by
227
+ // the maximum distance allowed (i.e., snap_radius), the center of the edge
228
+ // will still move by less than max_edge_deviation(). This saves us a lot
229
+ // of work since then we don't need to check the actual deviation.
230
+ min_edge_length_to_split_ca_ = S1ChordAngle::Radians(
231
+ 2 * acos(sin(snap_radius) / sin(max_edge_deviation_)));
232
+
233
+ // If the condition below is violated, then AddExtraSites() needs to be
234
+ // modified to check that snapped edges pass on the same side of each "site
235
+ // to avoid" as the input edge. Currently it doesn't need to do this
236
+ // because the condition below guarantees that if the snapped edge passes on
237
+ // the wrong side of the site then it is also too close, which will cause a
238
+ // separation site to be added.
239
+ //
240
+ // Currently max_edge_deviation() is at most 1.1 * snap_radius(), whereas
241
+ // min_edge_vertex_separation() is at least 0.219 * snap_radius() (based on
242
+ // S2CellIdSnapFunction, which is currently the worst case).
243
+ S2_DCHECK_LE(snap_function.max_edge_deviation(),
244
+ snap_function.snap_radius() +
245
+ snap_function.min_edge_vertex_separation());
246
+
247
+ // To implement idempotency, we check whether the input geometry could
248
+ // possibly be the output of a previous S2Builder invocation. This involves
249
+ // testing whether any site/site or edge/site pairs are too close together.
250
+ // This is done using exact predicates, which require converting the minimum
251
+ // separation values to an S1ChordAngle.
252
+ min_site_separation_ = snap_function.min_vertex_separation();
253
+ min_site_separation_ca_ = S1ChordAngle(min_site_separation_);
254
+ min_edge_site_separation_ca_ =
255
+ S1ChordAngle(snap_function.min_edge_vertex_separation());
256
+
257
+ // This is an upper bound on the distance computed by S2ClosestPointQuery
258
+ // where the true distance might be less than min_edge_site_separation_ca_.
259
+ min_edge_site_separation_ca_limit_ =
260
+ AddPointToEdgeError(min_edge_site_separation_ca_);
261
+
262
+ // Compute the maximum possible distance between two sites whose Voronoi
263
+ // regions touch. (The maximum radius of each Voronoi region is
264
+ // edge_snap_radius_.) Then increase this bound to account for errors.
265
+ max_adjacent_site_separation_ca_ =
266
+ AddPointToPointError(RoundUp(2 * edge_snap_radius));
267
+
268
+ // Finally, we also precompute sin^2(edge_snap_radius), which is simply the
269
+ // squared distance between a vertex and an edge measured perpendicular to
270
+ // the plane containing the edge, and increase this value by the maximum
271
+ // error in the calculation to compare this distance against the bound.
272
+ double d = sin(edge_snap_radius);
273
+ edge_snap_radius_sin2_ = d * d;
274
+ edge_snap_radius_sin2_ += ((9.5 * d + 2.5 + 2 * sqrt(3)) * d +
275
+ 9 * DBL_EPSILON) * DBL_EPSILON;
276
+
277
+ // Initialize the current label set.
278
+ label_set_id_ = label_set_lexicon_.EmptySetId();
279
+ label_set_modified_ = false;
280
+
281
+ // If snapping was requested, we try to determine whether the input geometry
282
+ // already meets the output requirements. This is necessary for
283
+ // idempotency, and can also save work. If we discover any reason that the
284
+ // input geometry needs to be modified, snapping_needed_ is set to true.
285
+ snapping_needed_ = false;
286
+ }
287
+
288
+ void S2Builder::clear_labels() {
289
+ label_set_.clear();
290
+ label_set_modified_ = true;
291
+ }
292
+
293
+ void S2Builder::push_label(Label label) {
294
+ S2_DCHECK_GE(label, 0);
295
+ label_set_.push_back(label);
296
+ label_set_modified_ = true;
297
+ }
298
+
299
+ void S2Builder::pop_label() {
300
+ label_set_.pop_back();
301
+ label_set_modified_ = true;
302
+ }
303
+
304
+ void S2Builder::set_label(Label label) {
305
+ S2_DCHECK_GE(label, 0);
306
+ label_set_.resize(1);
307
+ label_set_[0] = label;
308
+ label_set_modified_ = true;
309
+ }
310
+
311
+ bool S2Builder::IsFullPolygonUnspecified(const S2Builder::Graph& g,
312
+ S2Error* error) {
313
+ error->Init(S2Error::BUILDER_IS_FULL_PREDICATE_NOT_SPECIFIED,
314
+ "A degenerate polygon was found, but no predicate was specified "
315
+ "to determine whether the polygon is empty or full. Call "
316
+ "S2Builder::AddIsFullPolygonPredicate() to fix this problem.");
317
+ return false; // Assumes the polygon is empty.
318
+ }
319
+
320
+ S2Builder::IsFullPolygonPredicate S2Builder::IsFullPolygon(bool is_full) {
321
+ return [is_full](const S2Builder::Graph& g, S2Error* error) {
322
+ return is_full;
323
+ };
324
+ }
325
+
326
+ void S2Builder::StartLayer(unique_ptr<Layer> layer) {
327
+ layer_options_.push_back(layer->graph_options());
328
+ layer_begins_.push_back(input_edges_.size());
329
+ layer_is_full_polygon_predicates_.push_back(IsFullPolygon(false));
330
+ layers_.push_back(std::move(layer));
331
+ }
332
+
333
+ // Input vertices are stored in a vector, with some removal of duplicates.
334
+ // Edges are represented as (VertexId, VertexId) pairs. All edges are stored
335
+ // in a single vector; each layer corresponds to a contiguous range.
336
+
337
+ S2Builder::InputVertexId S2Builder::AddVertex(const S2Point& v) {
338
+ // Remove duplicate vertices that follow the pattern AB, BC, CD. If we want
339
+ // to do anything more sophisticated, either use a ValueLexicon, or sort the
340
+ // vertices once they have all been added, remove duplicates, and update the
341
+ // edges.
342
+ if (input_vertices_.empty() || v != input_vertices_.back()) {
343
+ input_vertices_.push_back(v);
344
+ }
345
+ return input_vertices_.size() - 1;
346
+ }
347
+
348
+ void S2Builder::AddEdge(const S2Point& v0, const S2Point& v1) {
349
+ S2_DCHECK(!layers_.empty()) << "Call StartLayer before adding any edges";
350
+
351
+ if (v0 == v1 && (layer_options_.back().degenerate_edges() ==
352
+ GraphOptions::DegenerateEdges::DISCARD)) {
353
+ return;
354
+ }
355
+ InputVertexId j0 = AddVertex(v0);
356
+ InputVertexId j1 = AddVertex(v1);
357
+ input_edges_.push_back(InputEdge(j0, j1));
358
+
359
+ // If there are any labels, then attach them to this input edge.
360
+ if (label_set_modified_) {
361
+ if (label_set_ids_.empty()) {
362
+ // Populate the missing entries with empty label sets.
363
+ label_set_ids_.assign(input_edges_.size() - 1, label_set_id_);
364
+ }
365
+ label_set_id_ = label_set_lexicon_.Add(label_set_);
366
+ label_set_ids_.push_back(label_set_id_);
367
+ label_set_modified_ = false;
368
+ } else if (!label_set_ids_.empty()) {
369
+ label_set_ids_.push_back(label_set_id_);
370
+ }
371
+ }
372
+
373
+ void S2Builder::AddPolyline(const S2Polyline& polyline) {
374
+ const int n = polyline.num_vertices();
375
+ for (int i = 1; i < n; ++i) {
376
+ AddEdge(polyline.vertex(i - 1), polyline.vertex(i));
377
+ }
378
+ }
379
+
380
+ void S2Builder::AddLoop(const S2Loop& loop) {
381
+ // Ignore loops that do not have a boundary.
382
+ if (loop.is_empty_or_full()) return;
383
+
384
+ // For loops that represent holes, we add the edge from vertex n-1 to vertex
385
+ // n-2 first. This is because these edges will be assembled into a
386
+ // clockwise loop, which will eventually be normalized in S2Polygon by
387
+ // calling S2Loop::Invert(). S2Loop::Invert() reverses the order of the
388
+ // vertices, so to end up with the original vertex order (0, 1, ..., n-1) we
389
+ // need to build a clockwise loop with vertex order (n-1, n-2, ..., 0).
390
+ // This is done by adding the edge (n-1, n-2) first, and then ensuring that
391
+ // Build() assembles loops starting from edges in the order they were added.
392
+ const int n = loop.num_vertices();
393
+ for (int i = 0; i < n; ++i) {
394
+ AddEdge(loop.oriented_vertex(i), loop.oriented_vertex(i + 1));
395
+ }
396
+ }
397
+
398
+ void S2Builder::AddPolygon(const S2Polygon& polygon) {
399
+ for (int i = 0; i < polygon.num_loops(); ++i) {
400
+ AddLoop(*polygon.loop(i));
401
+ }
402
+ }
403
+
404
+ void S2Builder::AddShape(const S2Shape& shape) {
405
+ for (int e = 0, n = shape.num_edges(); e < n; ++e) {
406
+ S2Shape::Edge edge = shape.edge(e);
407
+ AddEdge(edge.v0, edge.v1);
408
+ }
409
+ }
410
+
411
+ void S2Builder::AddIsFullPolygonPredicate(IsFullPolygonPredicate predicate) {
412
+ layer_is_full_polygon_predicates_.back() = std::move(predicate);
413
+ }
414
+
415
+ void S2Builder::ForceVertex(const S2Point& vertex) {
416
+ sites_.push_back(vertex);
417
+ }
418
+
419
+ // An S2Shape used to represent the entire collection of S2Builder input edges.
420
+ // Vertices are specified as indices into a vertex vector to save space.
421
+ namespace {
422
+ class VertexIdEdgeVectorShape final : public S2Shape {
423
+ public:
424
+ // Requires that "edges" is constant for the lifetime of this object.
425
+ VertexIdEdgeVectorShape(const vector<pair<int32, int32>>& edges,
426
+ const vector<S2Point>& vertices)
427
+ : edges_(edges), vertices_(vertices) {
428
+ }
429
+
430
+ const S2Point& vertex0(int e) const { return vertex(edges_[e].first); }
431
+ const S2Point& vertex1(int e) const { return vertex(edges_[e].second); }
432
+
433
+ // S2Shape interface:
434
+ int num_edges() const override { return edges_.size(); }
435
+ Edge edge(int e) const override {
436
+ return Edge(vertices_[edges_[e].first], vertices_[edges_[e].second]);
437
+ }
438
+ int dimension() const override { return 1; }
439
+ ReferencePoint GetReferencePoint() const override {
440
+ return ReferencePoint::Contained(false);
441
+ }
442
+ int num_chains() const override { return edges_.size(); }
443
+ Chain chain(int i) const override { return Chain(i, 1); }
444
+ Edge chain_edge(int i, int j) const override { return edge(i); }
445
+ ChainPosition chain_position(int e) const override {
446
+ return ChainPosition(e, 0);
447
+ }
448
+
449
+ private:
450
+ const S2Point& vertex(int i) const { return vertices_[i]; }
451
+
452
+ const vector<std::pair<int32, int32>>& edges_;
453
+ const vector<S2Point>& vertices_;
454
+ };
455
+ } // namespace
456
+
457
+ bool S2Builder::Build(S2Error* error) {
458
+ // S2_CHECK rather than S2_DCHECK because this is friendlier than crashing on the
459
+ // "error->ok()" call below. It would be easy to allow (error == nullptr)
460
+ // by declaring a local "tmp_error", but it seems better to make clients
461
+ // think about error handling.
462
+ S2_CHECK(error != nullptr);
463
+ error->Clear();
464
+ error_ = error;
465
+
466
+ // Mark the end of the last layer.
467
+ layer_begins_.push_back(input_edges_.size());
468
+
469
+ // See the algorithm overview at the top of this file.
470
+ if (snapping_requested_ && !options_.idempotent()) {
471
+ snapping_needed_ = true;
472
+ }
473
+ ChooseSites();
474
+ BuildLayers();
475
+ Reset();
476
+ return error->ok();
477
+ }
478
+
479
+ void S2Builder::Reset() {
480
+ input_vertices_.clear();
481
+ input_edges_.clear();
482
+ layers_.clear();
483
+ layer_options_.clear();
484
+ layer_begins_.clear();
485
+ layer_is_full_polygon_predicates_.clear();
486
+ label_set_ids_.clear();
487
+ label_set_lexicon_.Clear();
488
+ label_set_.clear();
489
+ label_set_modified_ = false;
490
+ sites_.clear();
491
+ edge_sites_.clear();
492
+ snapping_needed_ = false;
493
+ }
494
+
495
+ void S2Builder::ChooseSites() {
496
+ if (input_vertices_.empty()) return;
497
+
498
+ MutableS2ShapeIndex input_edge_index;
499
+ input_edge_index.Add(make_unique<VertexIdEdgeVectorShape>(
500
+ input_edges_, input_vertices_));
501
+ if (options_.split_crossing_edges()) {
502
+ AddEdgeCrossings(input_edge_index);
503
+ }
504
+ if (snapping_requested_) {
505
+ S2PointIndex<SiteId> site_index;
506
+ AddForcedSites(&site_index);
507
+ ChooseInitialSites(&site_index);
508
+ CollectSiteEdges(site_index);
509
+ }
510
+ if (snapping_needed_) {
511
+ AddExtraSites(input_edge_index);
512
+ } else {
513
+ CopyInputEdges();
514
+ }
515
+ }
516
+
517
+ void S2Builder::CopyInputEdges() {
518
+ // Sort the input vertices, discard duplicates, and update the input edges
519
+ // to refer to the pruned vertex list. (We sort in the same order used by
520
+ // ChooseInitialSites() to avoid inconsistencies in tests.)
521
+ vector<InputVertexKey> sorted = SortInputVertices();
522
+ vector<InputVertexId> vmap(input_vertices_.size());
523
+ sites_.clear();
524
+ sites_.reserve(input_vertices_.size());
525
+ for (int in = 0; in < sorted.size(); ) {
526
+ const S2Point& site = input_vertices_[sorted[in].second];
527
+ vmap[sorted[in].second] = sites_.size();
528
+ while (++in < sorted.size() && input_vertices_[sorted[in].second] == site) {
529
+ vmap[sorted[in].second] = sites_.size();
530
+ }
531
+ sites_.push_back(site);
532
+ }
533
+ input_vertices_ = sites_;
534
+ for (InputEdge& e : input_edges_) {
535
+ e.first = vmap[e.first];
536
+ e.second = vmap[e.second];
537
+ }
538
+ }
539
+
540
+ vector<S2Builder::InputVertexKey> S2Builder::SortInputVertices() {
541
+ // Sort all the input vertices in the order that we wish to consider them as
542
+ // candidate Voronoi sites. Any sort order will produce correct output, so
543
+ // we have complete flexibility in choosing the sort key. We could even
544
+ // leave them unsorted, although this would have the disadvantage that
545
+ // changing the order of the input edges could cause S2Builder to snap to a
546
+ // different set of Voronoi sites.
547
+ //
548
+ // We have chosen to sort them primarily by S2CellId since this improves the
549
+ // performance of many S2Builder phases (due to better spatial locality).
550
+ // It also allows the possibility of replacing the current S2PointIndex
551
+ // approach with a more efficient recursive divide-and-conquer algorithm.
552
+ //
553
+ // However, sorting by leaf S2CellId alone has two small disadvantages in
554
+ // the case where the candidate sites are densely spaced relative to the
555
+ // snap radius (e.g., when using the IdentitySnapFunction, or when snapping
556
+ // to E6/E7 near the poles, or snapping to S2CellId/E6/E7 using a snap
557
+ // radius larger than the minimum value required):
558
+ //
559
+ // - First, it tends to bias the Voronoi site locations towards points that
560
+ // are earlier on the S2CellId Hilbert curve. For example, suppose that
561
+ // there are two parallel rows of input vertices on opposite sides of the
562
+ // edge between two large S2Cells, and the rows are separated by less
563
+ // than the snap radius. Then only vertices from the cell with the
564
+ // smaller S2CellId are selected, because they are considered first and
565
+ // prevent us from selecting the sites from the other cell (because they
566
+ // are closer than "snap_radius" to an existing site).
567
+ //
568
+ // - Second, it tends to choose more Voronoi sites than necessary, because
569
+ // at each step we choose the first site along the Hilbert curve that is
570
+ // at least "snap_radius" away from all previously selected sites. This
571
+ // tends to yield sites whose "coverage discs" overlap quite a bit,
572
+ // whereas it would be better to cover all the input vertices with a
573
+ // smaller set of coverage discs that don't overlap as much. (This is
574
+ // the "geometric set cover problem", which is NP-hard.)
575
+ //
576
+ // It is not worth going to much trouble to fix these problems, because they
577
+ // really aren't that important (and don't affect the guarantees made by the
578
+ // algorithm), but here are a couple of heuristics that might help:
579
+ //
580
+ // 1. Sort the input vertices by S2CellId at a coarse level (down to cells
581
+ // that are O(snap_radius) in size), and then sort by a fingerprint of the
582
+ // S2Point coordinates (i.e., quasi-randomly). This would retain most of
583
+ // the advantages of S2CellId sorting, but makes it more likely that we will
584
+ // select sites that are further apart.
585
+ //
586
+ // 2. Rather than choosing the first uncovered input vertex and snapping it
587
+ // to obtain the next Voronoi site, instead look ahead through following
588
+ // candidates in S2CellId order and choose the furthest candidate whose
589
+ // snapped location covers all previous uncovered input vertices.
590
+ //
591
+ // TODO(ericv): Experiment with these approaches.
592
+
593
+ vector<InputVertexKey> keys;
594
+ keys.reserve(input_vertices_.size());
595
+ for (InputVertexId i = 0; i < input_vertices_.size(); ++i) {
596
+ keys.push_back(InputVertexKey(S2CellId(input_vertices_[i]), i));
597
+ }
598
+ std::sort(keys.begin(), keys.end(),
599
+ [this](const InputVertexKey& a, const InputVertexKey& b) {
600
+ if (a.first < b.first) return true;
601
+ if (b.first < a.first) return false;
602
+ return input_vertices_[a.second] < input_vertices_[b.second];
603
+ });
604
+ return keys;
605
+ }
606
+
607
+ // Check all edge pairs for crossings, and add the corresponding intersection
608
+ // points to input_vertices_. (The intersection points will be snapped and
609
+ // merged with the other vertices during site selection.)
610
+ void S2Builder::AddEdgeCrossings(const MutableS2ShapeIndex& input_edge_index) {
611
+ // We need to build a list of intersections and add them afterwards so that
612
+ // we don't reallocate vertices_ during the VisitCrossings() call.
613
+ vector<S2Point> new_vertices;
614
+ s2shapeutil::VisitCrossingEdgePairs(
615
+ input_edge_index, s2shapeutil::CrossingType::INTERIOR,
616
+ [&new_vertices](const s2shapeutil::ShapeEdge& a,
617
+ const s2shapeutil::ShapeEdge& b, bool) {
618
+ new_vertices.push_back(
619
+ S2::GetIntersection(a.v0(), a.v1(), b.v0(), b.v1()));
620
+ return true; // Continue visiting.
621
+ });
622
+ if (!new_vertices.empty()) {
623
+ snapping_needed_ = true;
624
+ for (const auto& vertex : new_vertices) AddVertex(vertex);
625
+ }
626
+ }
627
+
628
+ void S2Builder::AddForcedSites(S2PointIndex<SiteId>* site_index) {
629
+ // Sort the forced sites and remove duplicates.
630
+ std::sort(sites_.begin(), sites_.end());
631
+ sites_.erase(std::unique(sites_.begin(), sites_.end()), sites_.end());
632
+ // Add the forced sites to the index.
633
+ for (SiteId id = 0; id < sites_.size(); ++id) {
634
+ site_index->Add(sites_[id], id);
635
+ }
636
+ num_forced_sites_ = sites_.size();
637
+ }
638
+
639
+ void S2Builder::ChooseInitialSites(S2PointIndex<SiteId>* site_index) {
640
+ // Find all points whose distance is <= min_site_separation_ca_.
641
+ S2ClosestPointQueryOptions options;
642
+ options.set_conservative_max_distance(min_site_separation_ca_);
643
+ S2ClosestPointQuery<SiteId> site_query(site_index, options);
644
+ vector<S2ClosestPointQuery<SiteId>::Result> results;
645
+
646
+ // Apply the snap_function() to each input vertex, then check whether any
647
+ // existing site is closer than min_vertex_separation(). If not, then add a
648
+ // new site.
649
+ //
650
+ // NOTE(ericv): There are actually two reasonable algorithms, which we call
651
+ // "snap first" (the one above) and "snap last". The latter checks for each
652
+ // input vertex whether any existing site is closer than snap_radius(), and
653
+ // only then applies the snap_function() and adds a new site. "Snap last"
654
+ // can yield slightly fewer sites in some cases, but it is also more
655
+ // expensive and can produce surprising results. For example, if you snap
656
+ // the polyline "0:0, 0:0.7" using IntLatLngSnapFunction(0), the result is
657
+ // "0:0, 0:0" rather than the expected "0:0, 0:1", because the snap radius
658
+ // is approximately sqrt(2) degrees and therefore it is legal to snap both
659
+ // input points to "0:0". "Snap first" produces "0:0, 0:1" as expected.
660
+ for (const InputVertexKey& key : SortInputVertices()) {
661
+ const S2Point& vertex = input_vertices_[key.second];
662
+ S2Point site = SnapSite(vertex);
663
+ // If any vertex moves when snapped, the output cannot be idempotent.
664
+ snapping_needed_ = snapping_needed_ || site != vertex;
665
+
666
+ // FindClosestPoints() measures distances conservatively, so we need to
667
+ // recheck the distances using exact predicates.
668
+ //
669
+ // NOTE(ericv): When the snap radius is large compared to the average
670
+ // vertex spacing, we could possibly avoid the call the FindClosestPoints
671
+ // by checking whether sites_.back() is close enough.
672
+ S2ClosestPointQueryPointTarget target(site);
673
+ site_query.FindClosestPoints(&target, &results);
674
+ bool add_site = true;
675
+ for (const auto& result : results) {
676
+ if (s2pred::CompareDistance(site, result.point(),
677
+ min_site_separation_ca_) <= 0) {
678
+ add_site = false;
679
+ // This pair of sites is too close. If the sites are distinct, then
680
+ // the output cannot be idempotent.
681
+ snapping_needed_ = snapping_needed_ || site != result.point();
682
+ }
683
+ }
684
+ if (add_site) {
685
+ site_index->Add(site, sites_.size());
686
+ sites_.push_back(site);
687
+ site_query.ReInit();
688
+ }
689
+ }
690
+ }
691
+
692
+ S2Point S2Builder::SnapSite(const S2Point& point) const {
693
+ if (!snapping_requested_) return point;
694
+ S2Point site = options_.snap_function().SnapPoint(point);
695
+ S1ChordAngle dist_moved(site, point);
696
+ if (dist_moved > site_snap_radius_ca_) {
697
+ error_->Init(S2Error::BUILDER_SNAP_RADIUS_TOO_SMALL,
698
+ "Snap function moved vertex (%.15g, %.15g, %.15g) "
699
+ "by %.15g, which is more than the specified snap "
700
+ "radius of %.15g", point.x(), point.y(), point.z(),
701
+ dist_moved.ToAngle().radians(),
702
+ site_snap_radius_ca_.ToAngle().radians());
703
+ }
704
+ return site;
705
+ }
706
+
707
+ // For each edge, find all sites within min_edge_site_query_radius_ca_ and
708
+ // store them in edge_sites_. Also, to implement idempotency this method also
709
+ // checks whether the input vertices and edges may already satisfy the output
710
+ // criteria. If any problems are found then snapping_needed_ is set to true.
711
+ void S2Builder::CollectSiteEdges(const S2PointIndex<SiteId>& site_index) {
712
+ // Find all points whose distance is <= edge_site_query_radius_ca_.
713
+ S2ClosestPointQueryOptions options;
714
+ options.set_conservative_max_distance(edge_site_query_radius_ca_);
715
+ S2ClosestPointQuery<SiteId> site_query(&site_index, options);
716
+ vector<S2ClosestPointQuery<SiteId>::Result> results;
717
+ edge_sites_.resize(input_edges_.size());
718
+ for (InputEdgeId e = 0; e < input_edges_.size(); ++e) {
719
+ const InputEdge& edge = input_edges_[e];
720
+ const S2Point& v0 = input_vertices_[edge.first];
721
+ const S2Point& v1 = input_vertices_[edge.second];
722
+ if (s2builder_verbose) {
723
+ std::cout << "S2Polyline: " << s2textformat::ToString(v0)
724
+ << ", " << s2textformat::ToString(v1) << "\n";
725
+ }
726
+ S2ClosestPointQueryEdgeTarget target(v0, v1);
727
+ site_query.FindClosestPoints(&target, &results);
728
+ auto* sites = &edge_sites_[e];
729
+ sites->reserve(results.size());
730
+ for (const auto& result : results) {
731
+ sites->push_back(result.data());
732
+ if (!snapping_needed_ &&
733
+ result.distance() < min_edge_site_separation_ca_limit_ &&
734
+ result.point() != v0 && result.point() != v1 &&
735
+ s2pred::CompareEdgeDistance(result.point(), v0, v1,
736
+ min_edge_site_separation_ca_) < 0) {
737
+ snapping_needed_ = true;
738
+ }
739
+ }
740
+ SortSitesByDistance(v0, sites);
741
+ }
742
+ }
743
+
744
+ void S2Builder::SortSitesByDistance(const S2Point& x,
745
+ compact_array<SiteId>* sites) const {
746
+ // Sort sites in increasing order of distance to X.
747
+ std::sort(sites->begin(), sites->end(),
748
+ [&x, this](SiteId i, SiteId j) {
749
+ return s2pred::CompareDistances(x, sites_[i], sites_[j]) < 0;
750
+ });
751
+ }
752
+
753
+ // There are two situatons where we need to add extra Voronoi sites in order
754
+ // to ensure that the snapped edges meet the output requirements:
755
+ //
756
+ // (1) If a snapped edge deviates from its input edge by more than
757
+ // max_edge_deviation(), we add a new site on the input edge near the
758
+ // middle of the snapped edge. This causes the snapped edge to split
759
+ // into two pieces, so that it follows the input edge more closely.
760
+ //
761
+ // (2) If a snapped edge is closer than min_edge_vertex_separation() to any
762
+ // nearby site (the "site to avoid"), then we add a new site (the
763
+ // "separation site") on the input edge near the site to avoid. This
764
+ // causes the snapped edge to follow the input edge more closely and is
765
+ // guaranteed to increase the separation to the required distance.
766
+ //
767
+ // We check these conditions by snapping all the input edges to a chain of
768
+ // Voronoi sites and then testing each edge in the chain. If a site needs to
769
+ // be added, we mark all nearby edges for re-snapping.
770
+ void S2Builder::AddExtraSites(const MutableS2ShapeIndex& input_edge_index) {
771
+ // When options_.split_crossing_edges() is true, this function may be called
772
+ // even when site_snap_radius_ca_ == 0 (because edge_snap_radius_ca_ > 0).
773
+ // However neither of the conditions above apply in that case.
774
+ if (site_snap_radius_ca_ == S1ChordAngle::Zero()) return;
775
+
776
+ vector<SiteId> chain; // Temporary
777
+ vector<InputEdgeId> snap_queue;
778
+ for (InputEdgeId max_e = 0; max_e < input_edges_.size(); ++max_e) {
779
+ snap_queue.push_back(max_e);
780
+ while (!snap_queue.empty()) {
781
+ InputEdgeId e = snap_queue.back();
782
+ snap_queue.pop_back();
783
+ SnapEdge(e, &chain);
784
+ // We could save the snapped chain here in a snapped_chains_ vector, to
785
+ // avoid resnapping it in AddSnappedEdges() below, however currently
786
+ // SnapEdge only accounts for less than 5% of the runtime.
787
+ MaybeAddExtraSites(e, max_e, chain, input_edge_index, &snap_queue);
788
+ }
789
+ }
790
+ }
791
+
792
+ void S2Builder::MaybeAddExtraSites(InputEdgeId edge_id,
793
+ InputEdgeId max_edge_id,
794
+ const vector<SiteId>& chain,
795
+ const MutableS2ShapeIndex& input_edge_index,
796
+ vector<InputEdgeId>* snap_queue) {
797
+ // The snapped chain is always a *subsequence* of the nearby sites
798
+ // (edge_sites_), so we walk through the two arrays in parallel looking for
799
+ // sites that weren't snapped. We also keep track of the current snapped
800
+ // edge, since it is the only edge that can be too close.
801
+ int i = 0;
802
+ for (SiteId id : edge_sites_[edge_id]) {
803
+ if (id == chain[i]) {
804
+ if (++i == chain.size()) break;
805
+ // Check whether this snapped edge deviates too far from its original
806
+ // position. If so, we split the edge by adding an extra site.
807
+ const S2Point& v0 = sites_[chain[i - 1]];
808
+ const S2Point& v1 = sites_[chain[i]];
809
+ if (S1ChordAngle(v0, v1) < min_edge_length_to_split_ca_) continue;
810
+
811
+ const InputEdge& edge = input_edges_[edge_id];
812
+ const S2Point& a0 = input_vertices_[edge.first];
813
+ const S2Point& a1 = input_vertices_[edge.second];
814
+ if (!S2::IsEdgeBNearEdgeA(a0, a1, v0, v1, max_edge_deviation_)) {
815
+ // Add a new site on the input edge, positioned so that it splits the
816
+ // snapped edge into two approximately equal pieces. Then we find all
817
+ // the edges near the new site (including this one) and add them to
818
+ // the snap queue.
819
+ //
820
+ // Note that with large snap radii, it is possible that the snapped
821
+ // edge wraps around the sphere the "wrong way". To handle this we
822
+ // find the preferred split location by projecting both endpoints onto
823
+ // the input edge and taking their midpoint.
824
+ S2Point mid = (S2::Project(v0, a0, a1) +
825
+ S2::Project(v1, a0, a1)).Normalize();
826
+ S2Point new_site = GetSeparationSite(mid, v0, v1, edge_id);
827
+ AddExtraSite(new_site, max_edge_id, input_edge_index, snap_queue);
828
+ return;
829
+ }
830
+ } else if (i > 0 && id >= num_forced_sites_) {
831
+ // Check whether this "site to avoid" is closer to the snapped edge than
832
+ // min_edge_vertex_separation(). Note that this is the only edge of the
833
+ // chain that can be too close because its vertices must span the point
834
+ // where "site_to_avoid" projects onto the input edge XY (this claim
835
+ // relies on the fact that all sites are separated by at least the snap
836
+ // radius). We don't try to avoid sites added using ForceVertex()
837
+ // because we don't guarantee any minimum separation from such sites.
838
+ const S2Point& site_to_avoid = sites_[id];
839
+ const S2Point& v0 = sites_[chain[i - 1]];
840
+ const S2Point& v1 = sites_[chain[i]];
841
+ if (s2pred::CompareEdgeDistance(
842
+ site_to_avoid, v0, v1, min_edge_site_separation_ca_) < 0) {
843
+ // A snapped edge can only approach a site too closely when there are
844
+ // no sites near the input edge near that point. We fix that by
845
+ // adding a new site along the input edge (a "separation site"), then
846
+ // we find all the edges near the new site (including this one) and
847
+ // add them to the snap queue.
848
+ S2Point new_site = GetSeparationSite(site_to_avoid, v0, v1, edge_id);
849
+ S2_DCHECK_NE(site_to_avoid, new_site);
850
+ AddExtraSite(new_site, max_edge_id, input_edge_index, snap_queue);
851
+ return;
852
+ }
853
+ }
854
+ }
855
+ }
856
+
857
+ // Adds a new site, then updates "edge_sites"_ for all edges near the new site
858
+ // and adds them to "snap_queue" for resnapping (unless their edge id exceeds
859
+ // "max_edge_id", since those edges have not been snapped the first time yet).
860
+ void S2Builder::AddExtraSite(const S2Point& new_site,
861
+ InputEdgeId max_edge_id,
862
+ const MutableS2ShapeIndex& input_edge_index,
863
+ vector<InputEdgeId>* snap_queue) {
864
+ SiteId new_site_id = sites_.size();
865
+ sites_.push_back(new_site);
866
+ // Find all edges whose distance is <= edge_site_query_radius_ca_.
867
+ S2ClosestEdgeQuery::Options options;
868
+ options.set_conservative_max_distance(edge_site_query_radius_ca_);
869
+ options.set_include_interiors(false);
870
+ S2ClosestEdgeQuery query(&input_edge_index, options);
871
+ S2ClosestEdgeQuery::PointTarget target(new_site);
872
+ for (const auto& result : query.FindClosestEdges(&target)) {
873
+ InputEdgeId e = result.edge_id();
874
+ auto* site_ids = &edge_sites_[e];
875
+ site_ids->push_back(new_site_id);
876
+ SortSitesByDistance(input_vertices_[input_edges_[e].first], site_ids);
877
+ if (e <= max_edge_id) snap_queue->push_back(e);
878
+ }
879
+ }
880
+
881
+ S2Point S2Builder::GetSeparationSite(const S2Point& site_to_avoid,
882
+ const S2Point& v0, const S2Point& v1,
883
+ InputEdgeId input_edge_id) const {
884
+ // Define the "coverage disc" of a site S to be the disc centered at S with
885
+ // radius "snap_radius". Similarly, define the "coverage interval" of S for
886
+ // an edge XY to be the intersection of XY with the coverage disc of S. The
887
+ // SnapFunction implementations guarantee that the only way that a snapped
888
+ // edge can be closer than min_edge_vertex_separation() to a non-snapped
889
+ // site (i.e., site_to_avoid) if is there is a gap in the coverage of XY
890
+ // near this site. We can fix this problem simply by adding a new site to
891
+ // fill this gap, located as closely as possible to the site to avoid.
892
+ //
893
+ // To calculate the coverage gap, we look at the two snapped sites on
894
+ // either side of site_to_avoid, and find the endpoints of their coverage
895
+ // intervals. The we place a new site in the gap, located as closely as
896
+ // possible to the site to avoid. Note that the new site may move when it
897
+ // is snapped by the snap_function, but it is guaranteed not to move by
898
+ // more than snap_radius and therefore its coverage interval will still
899
+ // intersect the gap.
900
+ const InputEdge& edge = input_edges_[input_edge_id];
901
+ const S2Point& x = input_vertices_[edge.first];
902
+ const S2Point& y = input_vertices_[edge.second];
903
+ Vector3_d xy_dir = y - x;
904
+ S2Point n = S2::RobustCrossProd(x, y);
905
+ S2Point new_site = S2::Project(site_to_avoid, x, y, n);
906
+ S2Point gap_min = GetCoverageEndpoint(v0, x, y, n);
907
+ S2Point gap_max = GetCoverageEndpoint(v1, y, x, -n);
908
+ if ((new_site - gap_min).DotProd(xy_dir) < 0) {
909
+ new_site = gap_min;
910
+ } else if ((gap_max - new_site).DotProd(xy_dir) < 0) {
911
+ new_site = gap_max;
912
+ }
913
+ new_site = SnapSite(new_site);
914
+ S2_DCHECK_NE(v0, new_site);
915
+ S2_DCHECK_NE(v1, new_site);
916
+ return new_site;
917
+ }
918
+
919
+ // Given a site P and an edge XY with normal N, intersect XY with the disc of
920
+ // radius snap_radius() around P, and return the intersection point that is
921
+ // further along the edge XY toward Y.
922
+ S2Point S2Builder::GetCoverageEndpoint(const S2Point& p, const S2Point& x,
923
+ const S2Point& y, const S2Point& n)
924
+ const {
925
+ // Consider the plane perpendicular to P that cuts off a spherical cap of
926
+ // radius snap_radius(). This plane intersects the plane through the edge
927
+ // XY (perpendicular to N) along a line, and that line intersects the unit
928
+ // sphere at two points Q and R, and we want to return the point R that is
929
+ // further along the edge XY toward Y.
930
+ //
931
+ // Let M be the midpoint of QR. This is the point along QR that is closest
932
+ // to P. We can now express R as the sum of two perpendicular vectors OM
933
+ // and MR in the plane XY. Vector MR is in the direction N x P, while
934
+ // vector OM is in the direction (N x P) x N, where N = X x Y.
935
+ //
936
+ // The length of OM can be found using the Pythagorean theorem on triangle
937
+ // OPM, and the length of MR can be found using the Pythagorean theorem on
938
+ // triangle OMR.
939
+ //
940
+ // In the calculations below, we save some work by scaling all the vectors
941
+ // by n.CrossProd(p).Norm2(), and normalizing at the end.
942
+ double n2 = n.Norm2();
943
+ double nDp = n.DotProd(p);
944
+ S2Point nXp = n.CrossProd(p);
945
+ S2Point nXpXn = n2 * p - nDp * n;
946
+ Vector3_d om = sqrt(1 - edge_snap_radius_sin2_) * nXpXn;
947
+ double mr2 = edge_snap_radius_sin2_ * n2 - nDp * nDp;
948
+
949
+ // MR is constructed so that it points toward Y (rather than X).
950
+ Vector3_d mr = sqrt(max(0.0, mr2)) * nXp;
951
+ return (om + mr).Normalize();
952
+ }
953
+
954
+ void S2Builder::SnapEdge(InputEdgeId e, vector<SiteId>* chain) const {
955
+ chain->clear();
956
+ const InputEdge& edge = input_edges_[e];
957
+ if (!snapping_needed_) {
958
+ chain->push_back(edge.first);
959
+ chain->push_back(edge.second);
960
+ return;
961
+ }
962
+
963
+ const S2Point& x = input_vertices_[edge.first];
964
+ const S2Point& y = input_vertices_[edge.second];
965
+
966
+ // Optimization: if there is only one nearby site, return.
967
+ // Optimization: if there are exactly two nearby sites, and one is close
968
+ // enough to each vertex, then return.
969
+
970
+ // Now iterate through the sites. We keep track of the sequence of sites
971
+ // that are visited.
972
+ const auto& candidates = edge_sites_[e];
973
+ for (SiteId site_id : candidates) {
974
+ const S2Point& c = sites_[site_id];
975
+ // Skip any sites that are too far away. (There will be some of these,
976
+ // because we also keep track of "sites to avoid".) Note that some sites
977
+ // may be close enough to the line containing the edge, but not to the
978
+ // edge itself, so we can just use the dot product with the edge normal.
979
+ if (s2pred::CompareEdgeDistance(c, x, y, edge_snap_radius_ca_) > 0) {
980
+ continue;
981
+ }
982
+ // Check whether the new site C excludes the previous site B. If so,
983
+ // repeat with the previous site, and so on.
984
+ bool add_site_c = true;
985
+ for (; !chain->empty(); chain->pop_back()) {
986
+ S2Point b = sites_[chain->back()];
987
+
988
+ // First, check whether B and C are so far apart that their clipped
989
+ // Voronoi regions can't intersect.
990
+ S1ChordAngle bc(b, c);
991
+ if (bc >= max_adjacent_site_separation_ca_) break;
992
+
993
+ // Otherwise, we want to check whether site C prevents the Voronoi
994
+ // region of B from intersecting XY, or vice versa. This can be
995
+ // determined by computing the "coverage interval" (the segment of XY
996
+ // intersected by the coverage disc of radius snap_radius) for each
997
+ // site. If the coverage interval of one site contains the coverage
998
+ // interval of the other, then the contained site can be excluded.
999
+ s2pred::Excluded result = s2pred::GetVoronoiSiteExclusion(
1000
+ b, c, x, y, edge_snap_radius_ca_);
1001
+ if (result == s2pred::Excluded::FIRST) continue; // Site B excluded by C
1002
+ if (result == s2pred::Excluded::SECOND) {
1003
+ add_site_c = false; // Site C is excluded by B.
1004
+ break;
1005
+ }
1006
+ S2_DCHECK_EQ(s2pred::Excluded::NEITHER, result);
1007
+
1008
+ // Otherwise check whether the previous site A is close enough to B and
1009
+ // C that it might further clip the Voronoi region of B.
1010
+ if (chain->size() < 2) break;
1011
+ S2Point a = sites_[chain->end()[-2]];
1012
+ S1ChordAngle ac(a, c);
1013
+ if (ac >= max_adjacent_site_separation_ca_) break;
1014
+
1015
+ // If triangles ABC and XYB have the same orientation, the circumcenter
1016
+ // Z of ABC is guaranteed to be on the same side of XY as B.
1017
+ int xyb = s2pred::Sign(x, y, b);
1018
+ if (s2pred::Sign(a, b, c) == xyb) {
1019
+ break; // The circumcenter is on the same side as B but further away.
1020
+ }
1021
+ // Other possible optimizations:
1022
+ // - if AB > max_adjacent_site_separation_ca_ then keep B.
1023
+ // - if d(B, XY) < 0.5 * min(AB, BC) then keep B.
1024
+
1025
+ // If the circumcenter of ABC is on the same side of XY as B, then B is
1026
+ // excluded by A and C combined. Otherwise B is needed and we can exit.
1027
+ if (s2pred::EdgeCircumcenterSign(x, y, a, b, c) != xyb) break;
1028
+ }
1029
+ if (add_site_c) {
1030
+ chain->push_back(site_id);
1031
+ }
1032
+ }
1033
+ S2_DCHECK(!chain->empty());
1034
+ if (google::DEBUG_MODE) {
1035
+ for (SiteId site_id : candidates) {
1036
+ if (s2pred::CompareDistances(y, sites_[chain->back()],
1037
+ sites_[site_id]) > 0) {
1038
+ S2_LOG(ERROR) << "Snapping invariant broken!";
1039
+ }
1040
+ }
1041
+ }
1042
+ if (s2builder_verbose) {
1043
+ std::cout << "(" << edge.first << "," << edge.second << "): ";
1044
+ for (SiteId id : *chain) std::cout << id << " ";
1045
+ std::cout << std::endl;
1046
+ }
1047
+ }
1048
+
1049
+ void S2Builder::BuildLayers() {
1050
+ // Each output edge has an "input edge id set id" (an int32) representing
1051
+ // the set of input edge ids that were snapped to this edge. The actual
1052
+ // InputEdgeIds can be retrieved using "input_edge_id_set_lexicon".
1053
+ vector<vector<Edge>> layer_edges;
1054
+ vector<vector<InputEdgeIdSetId>> layer_input_edge_ids;
1055
+ IdSetLexicon input_edge_id_set_lexicon;
1056
+ BuildLayerEdges(&layer_edges, &layer_input_edge_ids,
1057
+ &input_edge_id_set_lexicon);
1058
+
1059
+ // At this point we have no further need for the input geometry or nearby
1060
+ // site data, so we clear those fields to save space.
1061
+ vector<S2Point>().swap(input_vertices_);
1062
+ vector<InputEdge>().swap(input_edges_);
1063
+ vector<compact_array<SiteId>>().swap(edge_sites_);
1064
+
1065
+ // If there are a large number of layers, then we build a minimal subset of
1066
+ // vertices for each layer. This ensures that layer types that iterate over
1067
+ // vertices will run in time proportional to the size of that layer rather
1068
+ // than the size of all layers combined.
1069
+ vector<vector<S2Point>> layer_vertices;
1070
+ static const int kMinLayersForVertexFiltering = 10;
1071
+ if (layers_.size() >= kMinLayersForVertexFiltering) {
1072
+ // Disable vertex filtering if it is disallowed by any layer. (This could
1073
+ // be optimized, but in current applications either all layers allow
1074
+ // filtering or none of them do.)
1075
+ bool allow_vertex_filtering = false;
1076
+ for (const auto& options : layer_options_) {
1077
+ allow_vertex_filtering &= options.allow_vertex_filtering();
1078
+ }
1079
+ if (allow_vertex_filtering) {
1080
+ vector<Graph::VertexId> filter_tmp; // Temporary used by FilterVertices.
1081
+ layer_vertices.resize(layers_.size());
1082
+ for (int i = 0; i < layers_.size(); ++i) {
1083
+ layer_vertices[i] = Graph::FilterVertices(sites_, &layer_edges[i],
1084
+ &filter_tmp);
1085
+ }
1086
+ vector<S2Point>().swap(sites_); // Release memory
1087
+ }
1088
+ }
1089
+ for (int i = 0; i < layers_.size(); ++i) {
1090
+ const vector<S2Point>& vertices = (layer_vertices.empty() ?
1091
+ sites_ : layer_vertices[i]);
1092
+ Graph graph(layer_options_[i], &vertices, &layer_edges[i],
1093
+ &layer_input_edge_ids[i], &input_edge_id_set_lexicon,
1094
+ &label_set_ids_, &label_set_lexicon_,
1095
+ layer_is_full_polygon_predicates_[i]);
1096
+ layers_[i]->Build(graph, error_);
1097
+ // Don't free the layer data until all layers have been built, in order to
1098
+ // support building multiple layers at once (e.g. ClosedSetNormalizer).
1099
+ }
1100
+ }
1101
+
1102
+ static void DumpEdges(const vector<S2Builder::Graph::Edge>& edges,
1103
+ const vector<S2Point>& vertices) {
1104
+ for (const auto& e : edges) {
1105
+ vector<S2Point> v;
1106
+ v.push_back(vertices[e.first]);
1107
+ v.push_back(vertices[e.second]);
1108
+ std::cout << "S2Polyline: " << s2textformat::ToString(v)
1109
+ << "(" << e.first << "," << e.second << ")" << std::endl;
1110
+ }
1111
+ }
1112
+
1113
+ // Snaps and possibly simplifies the edges for each layer, populating the
1114
+ // given output arguments. The resulting edges can be used to construct an
1115
+ // S2Builder::Graph directly (no further processing is necessary).
1116
+ //
1117
+ // This method is not "const" because Graph::ProcessEdges can modify
1118
+ // layer_options_ in some cases (changing undirected edges to directed ones).
1119
+ void S2Builder::BuildLayerEdges(
1120
+ vector<vector<Edge>>* layer_edges,
1121
+ vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
1122
+ IdSetLexicon* input_edge_id_set_lexicon) {
1123
+ // Edge chains are simplified only when a non-zero snap radius is specified.
1124
+ // If so, we build a map from each site to the set of input vertices that
1125
+ // snapped to that site.
1126
+ vector<compact_array<InputVertexId>> site_vertices;
1127
+ bool simplify = snapping_needed_ && options_.simplify_edge_chains();
1128
+ if (simplify) site_vertices.resize(sites_.size());
1129
+
1130
+ layer_edges->resize(layers_.size());
1131
+ layer_input_edge_ids->resize(layers_.size());
1132
+ for (int i = 0; i < layers_.size(); ++i) {
1133
+ AddSnappedEdges(layer_begins_[i], layer_begins_[i+1], layer_options_[i],
1134
+ &(*layer_edges)[i], &(*layer_input_edge_ids)[i],
1135
+ input_edge_id_set_lexicon, &site_vertices);
1136
+ }
1137
+ if (simplify) {
1138
+ SimplifyEdgeChains(site_vertices, layer_edges, layer_input_edge_ids,
1139
+ input_edge_id_set_lexicon);
1140
+ }
1141
+ // We simplify edge chains before processing the per-layer GraphOptions
1142
+ // because simplification can create duplicate edges and/or sibling edge
1143
+ // pairs which may need to be removed.
1144
+ for (int i = 0; i < layers_.size(); ++i) {
1145
+ // The errors generated by ProcessEdges are really warnings, so we simply
1146
+ // record them and continue.
1147
+ Graph::ProcessEdges(&layer_options_[i], &(*layer_edges)[i],
1148
+ &(*layer_input_edge_ids)[i],
1149
+ input_edge_id_set_lexicon, error_);
1150
+ }
1151
+ }
1152
+
1153
+ // Snaps all the input edges for a given layer, populating the given output
1154
+ // arguments. If (*site_vertices) is non-empty then it is updated so that
1155
+ // (*site_vertices)[site] contains a list of all input vertices that were
1156
+ // snapped to that site.
1157
+ void S2Builder::AddSnappedEdges(
1158
+ InputEdgeId begin, InputEdgeId end, const GraphOptions& options,
1159
+ vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids,
1160
+ IdSetLexicon* input_edge_id_set_lexicon,
1161
+ vector<compact_array<InputVertexId>>* site_vertices) const {
1162
+ bool discard_degenerate_edges = (options.degenerate_edges() ==
1163
+ GraphOptions::DegenerateEdges::DISCARD);
1164
+ vector<SiteId> chain;
1165
+ for (InputEdgeId e = begin; e < end; ++e) {
1166
+ InputEdgeIdSetId id = input_edge_id_set_lexicon->AddSingleton(e);
1167
+ SnapEdge(e, &chain);
1168
+ MaybeAddInputVertex(input_edges_[e].first, chain[0], site_vertices);
1169
+ if (chain.size() == 1) {
1170
+ if (discard_degenerate_edges) continue;
1171
+ AddSnappedEdge(chain[0], chain[0], id, options.edge_type(),
1172
+ edges, input_edge_ids);
1173
+ } else {
1174
+ MaybeAddInputVertex(input_edges_[e].second, chain.back(), site_vertices);
1175
+ for (int i = 1; i < chain.size(); ++i) {
1176
+ AddSnappedEdge(chain[i-1], chain[i], id, options.edge_type(),
1177
+ edges, input_edge_ids);
1178
+ }
1179
+ }
1180
+ }
1181
+ if (s2builder_verbose) DumpEdges(*edges, sites_);
1182
+ }
1183
+
1184
+ // If "site_vertices" is non-empty, ensures that (*site_vertices)[id] contains
1185
+ // "v". Duplicate entries are allowed.
1186
+ inline void S2Builder::MaybeAddInputVertex(
1187
+ InputVertexId v, SiteId id,
1188
+ vector<compact_array<InputVertexId>>* site_vertices) const {
1189
+ if (site_vertices->empty()) return;
1190
+
1191
+ // Optimization: check if we just added this vertex. This is worthwhile
1192
+ // because the input edges usually form a continuous chain, i.e. the
1193
+ // destination of one edge is the same as the source of the next edge.
1194
+ auto& vertices = (*site_vertices)[id];
1195
+ if (vertices.empty() || vertices.back() != v) {
1196
+ vertices.push_back(v);
1197
+ }
1198
+ }
1199
+
1200
+ // Adds the given edge to "edges" and "input_edge_ids". If undirected edges
1201
+ // are being used, also adds an edge in the opposite direction.
1202
+ inline void S2Builder::AddSnappedEdge(
1203
+ SiteId src, SiteId dst, InputEdgeIdSetId id, EdgeType edge_type,
1204
+ vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids) const {
1205
+ edges->push_back(Edge(src, dst));
1206
+ input_edge_ids->push_back(id);
1207
+ if (edge_type == EdgeType::UNDIRECTED) {
1208
+ edges->push_back(Edge(dst, src));
1209
+ // Automatically created edges do not have input edge ids or labels. This
1210
+ // can be used to distinguish the original direction of the undirected edge.
1211
+ input_edge_ids->push_back(IdSetLexicon::EmptySetId());
1212
+ }
1213
+ }
1214
+
1215
+ // A class that encapsulates the state needed for simplifying edge chains.
1216
+ class S2Builder::EdgeChainSimplifier {
1217
+ public:
1218
+ // The graph "g" contains all edges from all layers. "edge_layers"
1219
+ // indicates the original layer for each edge. "site_vertices" is a map
1220
+ // from SiteId to the set of InputVertexIds that were snapped to that site.
1221
+ // "layer_edges" and "layer_input_edge_ids" are output arguments where the
1222
+ // simplified edge chains will be placed. The input and output edges are
1223
+ // not sorted.
1224
+ EdgeChainSimplifier(
1225
+ const S2Builder& builder, const Graph& g,
1226
+ const vector<int>& edge_layers,
1227
+ const vector<compact_array<InputVertexId>>& site_vertices,
1228
+ vector<vector<Edge>>* layer_edges,
1229
+ vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
1230
+ IdSetLexicon* input_edge_id_set_lexicon);
1231
+
1232
+ void Run();
1233
+
1234
+ private:
1235
+ using VertexId = Graph::VertexId;
1236
+
1237
+ class InteriorVertexMatcher;
1238
+ void OutputEdge(EdgeId e);
1239
+ int graph_edge_layer(EdgeId e) const;
1240
+ int input_edge_layer(InputEdgeId id) const;
1241
+ bool IsInterior(VertexId v);
1242
+ void SimplifyChain(VertexId v0, VertexId v1);
1243
+ Graph::VertexId FollowChain(VertexId v0, VertexId v1) const;
1244
+ void OutputAllEdges(VertexId v0, VertexId v1);
1245
+ bool TargetInputVertices(VertexId v, S2PolylineSimplifier* simplifier) const;
1246
+ bool AvoidSites(VertexId v0, VertexId v1, VertexId v2,
1247
+ S2PolylineSimplifier* simplifier) const;
1248
+ void MergeChain(const vector<VertexId>& vertices);
1249
+ void AssignDegenerateEdges(
1250
+ const vector<InputEdgeId>& degenerate_ids,
1251
+ vector<vector<InputEdgeId>>* merged_input_ids) const;
1252
+
1253
+ const S2Builder& builder_;
1254
+ const Graph& g_;
1255
+ Graph::VertexInMap in_;
1256
+ Graph::VertexOutMap out_;
1257
+ vector<int> edge_layers_;
1258
+ const vector<compact_array<InputVertexId>>& site_vertices_;
1259
+ vector<vector<Edge>>* layer_edges_;
1260
+ vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids_;
1261
+ IdSetLexicon* input_edge_id_set_lexicon_;
1262
+
1263
+ // Convenience member copied from builder_.
1264
+ const std::vector<InputEdgeId>& layer_begins_;
1265
+
1266
+ // is_interior_[v] indicates that VertexId "v" is eligible to be an interior
1267
+ // vertex of a simplified edge chain. You can think of it as vertex whose
1268
+ // indegree and outdegree are both 1 (although the actual definition is a
1269
+ // bit more complicated because of duplicate edges and layers).
1270
+ vector<bool> is_interior_;
1271
+
1272
+ // used_[e] indicates that EdgeId "e" has already been processed.
1273
+ vector<bool> used_;
1274
+
1275
+ // Temporary vectors, declared here to avoid repeated allocation.
1276
+ vector<VertexId> tmp_vertices_;
1277
+ vector<EdgeId> tmp_edges_;
1278
+
1279
+ // The output edges after simplification.
1280
+ vector<Edge> new_edges_;
1281
+ vector<InputEdgeIdSetId> new_input_edge_ids_;
1282
+ vector<int> new_edge_layers_;
1283
+ };
1284
+
1285
+ // Simplifies edge chains, updating its input/output arguments as necessary.
1286
+ void S2Builder::SimplifyEdgeChains(
1287
+ const vector<compact_array<InputVertexId>>& site_vertices,
1288
+ vector<vector<Edge>>* layer_edges,
1289
+ vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
1290
+ IdSetLexicon* input_edge_id_set_lexicon) const {
1291
+ if (layers_.empty()) return;
1292
+
1293
+ // Merge the edges from all layers (in order to build a single graph).
1294
+ vector<Edge> merged_edges;
1295
+ vector<InputEdgeIdSetId> merged_input_edge_ids;
1296
+ vector<int> merged_edge_layers;
1297
+ MergeLayerEdges(*layer_edges, *layer_input_edge_ids,
1298
+ &merged_edges, &merged_input_edge_ids, &merged_edge_layers);
1299
+
1300
+ // The following fields will be reconstructed by EdgeChainSimplifier.
1301
+ for (auto& edges : *layer_edges) edges.clear();
1302
+ for (auto& input_edge_ids : *layer_input_edge_ids) input_edge_ids.clear();
1303
+
1304
+ // The graph options are irrelevant for edge chain simplification, but we
1305
+ // try to set them appropriately anyway.
1306
+ S2Builder::GraphOptions graph_options(EdgeType::DIRECTED,
1307
+ GraphOptions::DegenerateEdges::KEEP,
1308
+ GraphOptions::DuplicateEdges::KEEP,
1309
+ GraphOptions::SiblingPairs::KEEP);
1310
+ Graph graph(graph_options, &sites_, &merged_edges, &merged_input_edge_ids,
1311
+ input_edge_id_set_lexicon, nullptr, nullptr,
1312
+ IsFullPolygonPredicate());
1313
+ EdgeChainSimplifier simplifier(
1314
+ *this, graph, merged_edge_layers, site_vertices,
1315
+ layer_edges, layer_input_edge_ids, input_edge_id_set_lexicon);
1316
+ simplifier.Run();
1317
+ }
1318
+
1319
+ // Merges the edges from all layers and sorts them in lexicographic order so
1320
+ // that we can construct a single graph. The sort is stable, which means that
1321
+ // any duplicate edges within each layer will still be sorted by InputEdgeId.
1322
+ void S2Builder::MergeLayerEdges(
1323
+ const vector<vector<Edge>>& layer_edges,
1324
+ const vector<vector<InputEdgeIdSetId>>& layer_input_edge_ids,
1325
+ vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids,
1326
+ vector<int>* edge_layers) const {
1327
+ vector<LayerEdgeId> order;
1328
+ for (int i = 0; i < layer_edges.size(); ++i) {
1329
+ for (int e = 0; e < layer_edges[i].size(); ++e) {
1330
+ order.push_back(LayerEdgeId(i, e));
1331
+ }
1332
+ }
1333
+ std::sort(order.begin(), order.end(),
1334
+ [&layer_edges](const LayerEdgeId& ai, const LayerEdgeId& bi) {
1335
+ return StableLessThan(layer_edges[ai.first][ai.second],
1336
+ layer_edges[bi.first][bi.second], ai, bi);
1337
+ });
1338
+ edges->reserve(order.size());
1339
+ input_edge_ids->reserve(order.size());
1340
+ edge_layers->reserve(order.size());
1341
+ for (const LayerEdgeId& id : order) {
1342
+ edges->push_back(layer_edges[id.first][id.second]);
1343
+ input_edge_ids->push_back(layer_input_edge_ids[id.first][id.second]);
1344
+ edge_layers->push_back(id.first);
1345
+ }
1346
+ }
1347
+
1348
+ // A comparison function that allows stable sorting with std::sort (which is
1349
+ // fast but not stable). It breaks ties between equal edges by comparing
1350
+ // their LayerEdgeIds.
1351
+ inline bool S2Builder::StableLessThan(
1352
+ const Edge& a, const Edge& b,
1353
+ const LayerEdgeId& ai, const LayerEdgeId& bi) {
1354
+ // The compiler doesn't optimize this as well as it should:
1355
+ // return make_pair(a, ai) < make_pair(b, bi);
1356
+ if (a.first < b.first) return true;
1357
+ if (b.first < a.first) return false;
1358
+ if (a.second < b.second) return true;
1359
+ if (b.second < a.second) return false;
1360
+ return ai < bi; // Stable sort.
1361
+ }
1362
+
1363
+ S2Builder::EdgeChainSimplifier::EdgeChainSimplifier(
1364
+ const S2Builder& builder, const Graph& g, const vector<int>& edge_layers,
1365
+ const vector<compact_array<InputVertexId>>& site_vertices,
1366
+ vector<vector<Edge>>* layer_edges,
1367
+ vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
1368
+ IdSetLexicon* input_edge_id_set_lexicon)
1369
+ : builder_(builder), g_(g), in_(g), out_(g), edge_layers_(edge_layers),
1370
+ site_vertices_(site_vertices), layer_edges_(layer_edges),
1371
+ layer_input_edge_ids_(layer_input_edge_ids),
1372
+ input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
1373
+ layer_begins_(builder_.layer_begins_),
1374
+ is_interior_(g.num_vertices()), used_(g.num_edges()) {
1375
+ new_edges_.reserve(g.num_edges());
1376
+ new_input_edge_ids_.reserve(g.num_edges());
1377
+ new_edge_layers_.reserve(g.num_edges());
1378
+ }
1379
+
1380
+ void S2Builder::EdgeChainSimplifier::Run() {
1381
+ // Determine which vertices can be interior vertices of an edge chain.
1382
+ for (VertexId v = 0; v < g_.num_vertices(); ++v) {
1383
+ is_interior_[v] = IsInterior(v);
1384
+ }
1385
+ // Attempt to simplify all edge chains that start from a non-interior
1386
+ // vertex. (This takes care of all chains except loops.)
1387
+ for (EdgeId e = 0; e < g_.num_edges(); ++e) {
1388
+ if (used_[e]) continue;
1389
+ Edge edge = g_.edge(e);
1390
+ if (is_interior_[edge.first]) continue;
1391
+ if (!is_interior_[edge.second]) {
1392
+ OutputEdge(e); // An edge between two non-interior vertices.
1393
+ } else {
1394
+ SimplifyChain(edge.first, edge.second);
1395
+ }
1396
+ }
1397
+ // If there are any edges left, they form one or more disjoint loops where
1398
+ // all vertices are interior vertices.
1399
+ //
1400
+ // TODO(ericv): It would be better to start from the edge with the smallest
1401
+ // min_input_edge_id(), since that would make the output more predictable
1402
+ // for testing purposes. It also means that we won't create an edge that
1403
+ // spans the start and end of a polyline if the polyline is snapped into a
1404
+ // loop. (Unfortunately there are pathological examples that prevent us
1405
+ // from guaranteeing this in general, e.g. there could be two polylines in
1406
+ // different layers that snap to the same loop but start at different
1407
+ // positions. In general we only consider input edge ids to be a hint
1408
+ // towards the preferred output ordering.)
1409
+ for (EdgeId e = 0; e < g_.num_edges(); ++e) {
1410
+ if (used_[e]) continue;
1411
+ Edge edge = g_.edge(e);
1412
+ if (edge.first == edge.second) {
1413
+ // Note that it is safe to output degenerate edges as we go along,
1414
+ // because this vertex has at least one non-degenerate outgoing edge and
1415
+ // therefore we will (or just did) start an edge chain here.
1416
+ OutputEdge(e);
1417
+ } else {
1418
+ SimplifyChain(edge.first, edge.second);
1419
+ }
1420
+ }
1421
+
1422
+ // Finally, copy the output edges into the appropriate layers. They don't
1423
+ // need to be sorted because the input edges were also unsorted.
1424
+ for (int e = 0; e < new_edges_.size(); ++e) {
1425
+ int layer = new_edge_layers_[e];
1426
+ (*layer_edges_)[layer].push_back(new_edges_[e]);
1427
+ (*layer_input_edge_ids_)[layer].push_back(new_input_edge_ids_[e]);
1428
+ }
1429
+ }
1430
+
1431
+ // Copies the given edge to the output and marks it as used.
1432
+ inline void S2Builder::EdgeChainSimplifier::OutputEdge(EdgeId e) {
1433
+ new_edges_.push_back(g_.edge(e));
1434
+ new_input_edge_ids_.push_back(g_.input_edge_id_set_id(e));
1435
+ new_edge_layers_.push_back(edge_layers_[e]);
1436
+ used_[e] = true;
1437
+ }
1438
+
1439
+ // Returns the layer that a given graph edge belongs to.
1440
+ inline int S2Builder::EdgeChainSimplifier::graph_edge_layer(EdgeId e) const {
1441
+ return edge_layers_[e];
1442
+ }
1443
+
1444
+ // Returns the layer than a given input edge belongs to.
1445
+ int S2Builder::EdgeChainSimplifier::input_edge_layer(InputEdgeId id) const {
1446
+ // NOTE(ericv): If this method shows up in profiling, the result could be
1447
+ // stored with each edge (i.e., edge_layers_ and new_edge_layers_).
1448
+ S2_DCHECK_GE(id, 0);
1449
+ return (std::upper_bound(layer_begins_.begin(), layer_begins_.end(), id) -
1450
+ (layer_begins_.begin() + 1));
1451
+ }
1452
+
1453
+ // A helper class for determining whether a vertex can be an interior vertex
1454
+ // of a simplified edge chain. Such a vertex must be adjacent to exactly two
1455
+ // vertices (across all layers combined), and in each layer the number of
1456
+ // incoming edges from one vertex must equal the number of outgoing edges to
1457
+ // the other vertex (in both directions). Furthermore the vertex cannot have
1458
+ // any degenerate edges in a given layer unless it has at least one
1459
+ // non-degenerate edge in that layer as well. (Note that usually there will
1460
+ // not be any degenerate edges at all, since most layer types discard them.)
1461
+ //
1462
+ // The last condition is necessary to prevent the following: suppose that one
1463
+ // layer has a chain ABC and another layer has a degenerate edge BB (with no
1464
+ // other edges incident to B). Then we can't simplify ABC to AC because there
1465
+ // would be no suitable replacement for the edge BB (since the input edge that
1466
+ // mapped to BB can't be replaced by any of the edges AA, AC, or CC without
1467
+ // moving further than snap_radius).
1468
+ class S2Builder::EdgeChainSimplifier::InteriorVertexMatcher {
1469
+ public:
1470
+ // Checks whether "v0" can be an interior vertex of an edge chain.
1471
+ explicit InteriorVertexMatcher(VertexId v0)
1472
+ : v0_(v0), v1_(-1), v2_(-1), n0_(0), n1_(0), n2_(0), excess_out_(0),
1473
+ too_many_endpoints_(false) {
1474
+ }
1475
+
1476
+ // Starts analyzing the edges of a new layer.
1477
+ void StartLayer() {
1478
+ excess_out_ = n0_ = n1_ = n2_ = 0;
1479
+ }
1480
+
1481
+ // This method should be called for each edge incident to "v0" in a given
1482
+ // layer. (For degenerate edges, it should be called twice.)
1483
+ void Tally(VertexId v, bool outgoing) {
1484
+ excess_out_ += outgoing ? 1 : -1; // outdegree - indegree
1485
+ if (v == v0_) {
1486
+ ++n0_; // Counts both endpoints of each degenerate edge.
1487
+ } else {
1488
+ // We keep track of the total number of edges (incoming or outgoing)
1489
+ // connecting v0 to up to two adjacent vertices.
1490
+ if (v1_ < 0) v1_ = v;
1491
+ if (v1_ == v) {
1492
+ ++n1_;
1493
+ } else {
1494
+ if (v2_ < 0) v2_ = v;
1495
+ if (v2_ == v) {
1496
+ ++n2_;
1497
+ } else {
1498
+ too_many_endpoints_ = true;
1499
+ }
1500
+ }
1501
+ }
1502
+ }
1503
+
1504
+ // This method should be called after processing the edges for each layer.
1505
+ // It returns true if "v0" is an interior vertex based on the edges so far.
1506
+ bool Matches() const {
1507
+ // We check that there are the same number of incoming and outgoing edges
1508
+ // in each direction by verifying that (1) indegree(v0) == outdegree(v0)
1509
+ // and (2) the total number of edges (incoming and outgoing) to "v1" and
1510
+ // "v2" are equal. We also check the condition on degenerate edges that
1511
+ // is documented above.
1512
+ return (!too_many_endpoints_ && excess_out_ == 0 && n1_ == n2_ &&
1513
+ (n0_ == 0 || n1_ > 0));
1514
+ }
1515
+
1516
+ private:
1517
+ VertexId v0_, v1_, v2_;
1518
+ int n0_, n1_, n2_;
1519
+ int excess_out_; // outdegree(v0) - indegree(v0)
1520
+ bool too_many_endpoints_; // Have we seen more than two adjacent vertices?
1521
+ };
1522
+
1523
+ // Returns true if VertexId "v" can be an interior vertex of a simplified edge
1524
+ // chain. (See the InteriorVertexMatcher class for what this implies.)
1525
+ bool S2Builder::EdgeChainSimplifier::IsInterior(VertexId v) {
1526
+ // Check a few simple prerequisites.
1527
+ if (out_.degree(v) == 0) return false;
1528
+ if (out_.degree(v) != in_.degree(v)) return false;
1529
+ if (v < builder_.num_forced_sites_) return false; // Keep forced vertices.
1530
+
1531
+ // Sort the edges so that they are grouped by layer.
1532
+ vector<EdgeId>& edges = tmp_edges_; // Avoid allocating each time.
1533
+ edges.clear();
1534
+ for (EdgeId e : out_.edge_ids(v)) edges.push_back(e);
1535
+ for (EdgeId e : in_.edge_ids(v)) edges.push_back(e);
1536
+ std::sort(edges.begin(), edges.end(), [this](EdgeId x, EdgeId y) {
1537
+ return graph_edge_layer(x) < graph_edge_layer(y);
1538
+ });
1539
+ // Now feed the edges in each layer to the InteriorVertexMatcher.
1540
+ InteriorVertexMatcher matcher(v);
1541
+ for (auto e = edges.begin(); e != edges.end(); ) {
1542
+ int layer = graph_edge_layer(*e);
1543
+ matcher.StartLayer();
1544
+ for (; e != edges.end() && graph_edge_layer(*e) == layer; ++e) {
1545
+ Edge edge = g_.edge(*e);
1546
+ if (edge.first == v) matcher.Tally(edge.second, true /*outgoing*/);
1547
+ if (edge.second == v) matcher.Tally(edge.first, false /*outgoing*/);
1548
+ }
1549
+ if (!matcher.Matches()) return false;
1550
+ }
1551
+ return true;
1552
+ }
1553
+
1554
+ // Follows the edge chain starting with (v0, v1) until either we find a
1555
+ // non-interior vertex or we return to the original vertex v0. At each vertex
1556
+ // we simplify a subchain of edges that is as long as possible.
1557
+ void S2Builder::EdgeChainSimplifier::SimplifyChain(VertexId v0, VertexId v1) {
1558
+ // Avoid allocating "chain" each time by reusing it.
1559
+ vector<VertexId>& chain = tmp_vertices_;
1560
+ S2PolylineSimplifier simplifier;
1561
+ VertexId vstart = v0;
1562
+ bool done = false;
1563
+ do {
1564
+ // Simplify a subchain of edges starting (v0, v1).
1565
+ simplifier.Init(g_.vertex(v0));
1566
+ AvoidSites(v0, v0, v1, &simplifier);
1567
+ chain.push_back(v0);
1568
+ do {
1569
+ chain.push_back(v1);
1570
+ done = !is_interior_[v1] || v1 == vstart;
1571
+ if (done) break;
1572
+
1573
+ // Attempt to extend the chain to the next vertex.
1574
+ VertexId vprev = v0;
1575
+ v0 = v1;
1576
+ v1 = FollowChain(vprev, v0);
1577
+ } while (TargetInputVertices(v0, &simplifier) &&
1578
+ AvoidSites(chain[0], v0, v1, &simplifier) &&
1579
+ simplifier.Extend(g_.vertex(v1)));
1580
+
1581
+ if (chain.size() == 2) {
1582
+ OutputAllEdges(chain[0], chain[1]); // Could not simplify.
1583
+ } else {
1584
+ MergeChain(chain);
1585
+ }
1586
+ // Note that any degenerate edges that were not merged into a chain are
1587
+ // output by EdgeChainSimplifier::Run().
1588
+ chain.clear();
1589
+ } while (!done);
1590
+ }
1591
+
1592
+ // Given an edge (v0, v1) where v1 is an interior vertex, returns the (unique)
1593
+ // next vertex in the edge chain.
1594
+ S2Builder::Graph::VertexId S2Builder::EdgeChainSimplifier::FollowChain(
1595
+ VertexId v0, VertexId v1) const {
1596
+ S2_DCHECK(is_interior_[v1]);
1597
+ for (EdgeId e : out_.edge_ids(v1)) {
1598
+ VertexId v = g_.edge(e).second;
1599
+ if (v != v0 && v != v1) return v;
1600
+ }
1601
+ S2_LOG(FATAL) << "Could not find next edge in edge chain";
1602
+ }
1603
+
1604
+ // Copies all input edges between v0 and v1 (in both directions) to the output.
1605
+ void S2Builder::EdgeChainSimplifier::OutputAllEdges(VertexId v0, VertexId v1) {
1606
+ for (EdgeId e : out_.edge_ids(v0, v1)) OutputEdge(e);
1607
+ for (EdgeId e : out_.edge_ids(v1, v0)) OutputEdge(e);
1608
+ }
1609
+
1610
+ // Ensures that the simplified edge passes within "edge_snap_radius" of all
1611
+ // the *input* vertices that snapped to the given vertex "v".
1612
+ bool S2Builder::EdgeChainSimplifier::TargetInputVertices(
1613
+ VertexId v, S2PolylineSimplifier* simplifier) const {
1614
+ for (InputVertexId i : site_vertices_[v]) {
1615
+ if (!simplifier->TargetDisc(builder_.input_vertices_[i],
1616
+ builder_.edge_snap_radius_ca_)) {
1617
+ return false;
1618
+ }
1619
+ }
1620
+ return true;
1621
+ }
1622
+
1623
+ // Given the starting vertex v0 and last edge (v1, v2) of an edge chain,
1624
+ // restricts the allowable range of angles in order to ensure that all sites
1625
+ // near the edge (v1, v2) are avoided by at least min_edge_vertex_separation.
1626
+ bool S2Builder::EdgeChainSimplifier::AvoidSites(
1627
+ VertexId v0, VertexId v1, VertexId v2,
1628
+ S2PolylineSimplifier* simplifier) const {
1629
+ const S2Point& p0 = g_.vertex(v0);
1630
+ const S2Point& p1 = g_.vertex(v1);
1631
+ const S2Point& p2 = g_.vertex(v2);
1632
+ S1ChordAngle r1(p0, p1);
1633
+ S1ChordAngle r2(p0, p2);
1634
+
1635
+ // The distance from the start of the edge chain must increase monotonically
1636
+ // for each vertex, since we don't want to simplify chains that backtrack on
1637
+ // themselves (we want a parametric approximation, not a geometric one).
1638
+ if (r2 < r1) return false;
1639
+
1640
+ // We also limit the maximum edge length in order to guarantee that the
1641
+ // simplified edge stays with max_edge_deviation() of all the input edges
1642
+ // that snap to it.
1643
+ if (r2 >= builder_.min_edge_length_to_split_ca_) return false;
1644
+
1645
+ // Otherwise it is sufficient to consider the nearby sites (edge_sites_) for
1646
+ // a single input edge that snapped to (v1, v2) or (v2, v1). This is
1647
+ // because each edge has a list of all sites within (max_edge_deviation +
1648
+ // min_edge_vertex_separation), and since the output edge is within
1649
+ // max_edge_deviation of all input edges, this list includes all sites
1650
+ // within min_edge_vertex_separation of the output edge.
1651
+ //
1652
+ // Usually there is only one edge to choose from, but it's not much more
1653
+ // effort to choose the edge with the shortest list of edge_sites_.
1654
+ InputEdgeId best = -1;
1655
+ const auto& edge_sites = builder_.edge_sites_;
1656
+ for (EdgeId e : out_.edge_ids(v1, v2)) {
1657
+ for (InputEdgeId id : g_.input_edge_ids(e)) {
1658
+ if (best < 0 || edge_sites[id].size() < edge_sites[best].size())
1659
+ best = id;
1660
+ }
1661
+ }
1662
+ for (EdgeId e : out_.edge_ids(v2, v1)) {
1663
+ for (InputEdgeId id : g_.input_edge_ids(e)) {
1664
+ if (best < 0 || edge_sites[id].size() < edge_sites[best].size())
1665
+ best = id;
1666
+ }
1667
+ }
1668
+ S2_DCHECK_GE(best, 0); // Because there is at least one outgoing edge.
1669
+
1670
+ for (VertexId v : edge_sites[best]) {
1671
+ // This test is optional since these sites are excluded below anyway.
1672
+ if (v == v0 || v == v1 || v == v2) continue;
1673
+
1674
+ // We are only interested in sites whose distance from "p0" is in the
1675
+ // range (r1, r2). Sites closer than "r1" have already been processed,
1676
+ // and sites further than "r2" aren't relevant yet.
1677
+ const S2Point& p = g_.vertex(v);
1678
+ S1ChordAngle r(p0, p);
1679
+ if (r <= r1 || r >= r2) continue;
1680
+
1681
+ // We need to figure out whether this site is to the left or right of the
1682
+ // edge chain. For the first edge this is easy. Otherwise, since we are
1683
+ // only considering sites in the radius range (r1, r2), we can do this by
1684
+ // checking whether the site is to the left of the wedge (p0, p1, p2).
1685
+ bool disc_on_left = (v1 == v0) ? (s2pred::Sign(p1, p2, p) > 0)
1686
+ : s2pred::OrderedCCW(p0, p2, p, p1);
1687
+ if (!simplifier->AvoidDisc(p, builder_.min_edge_site_separation_ca_,
1688
+ disc_on_left)) {
1689
+ return false;
1690
+ }
1691
+ }
1692
+ return true;
1693
+ }
1694
+
1695
+ // Given the vertices in a simplified edge chain, adds the corresponding
1696
+ // simplified edge(s) to the output. Note that (1) the edge chain may exist
1697
+ // in multiple layers, (2) the edge chain may exist in both directions, (3)
1698
+ // there may be more than one copy of an edge chain (in either direction)
1699
+ // within a single layer.
1700
+ void S2Builder::EdgeChainSimplifier::MergeChain(
1701
+ const vector<VertexId>& vertices) {
1702
+ // Suppose that all interior vertices have M outgoing edges and N incoming
1703
+ // edges. Our goal is to group the edges into M outgoing chains and N
1704
+ // incoming chains, and then replace each chain by a single edge.
1705
+ vector<vector<InputEdgeId>> merged_input_ids;
1706
+ vector<InputEdgeId> degenerate_ids;
1707
+ int num_out; // Edge count in the outgoing direction.
1708
+ for (int i = 1; i < vertices.size(); ++i) {
1709
+ VertexId v0 = vertices[i-1];
1710
+ VertexId v1 = vertices[i];
1711
+ auto out_edges = out_.edge_ids(v0, v1);
1712
+ auto in_edges = out_.edge_ids(v1, v0);
1713
+ if (i == 1) {
1714
+ // Allocate space to store the input edge ids associated with each edge.
1715
+ num_out = out_edges.size();
1716
+ merged_input_ids.resize(num_out + in_edges.size());
1717
+ for (vector<InputEdgeId>& ids : merged_input_ids) {
1718
+ ids.reserve(vertices.size() - 1);
1719
+ }
1720
+ } else {
1721
+ // For each interior vertex, we build a list of input edge ids
1722
+ // associated with degenerate edges. Each input edge ids will be
1723
+ // assigned to one of the output edges later. (Normally there are no
1724
+ // degenerate edges at all since most layer types don't want them.)
1725
+ S2_DCHECK(is_interior_[v0]);
1726
+ for (EdgeId e : out_.edge_ids(v0, v0)) {
1727
+ for (InputEdgeId id : g_.input_edge_ids(e)) {
1728
+ degenerate_ids.push_back(id);
1729
+ }
1730
+ used_[e] = true;
1731
+ }
1732
+ }
1733
+ // Because the edges were created in layer order, and all sorts used are
1734
+ // stable, the edges are still in layer order. Therefore we can simply
1735
+ // merge together all the edges in the same relative position.
1736
+ int j = 0;
1737
+ for (EdgeId e : out_edges) {
1738
+ for (InputEdgeId id : g_.input_edge_ids(e)) {
1739
+ merged_input_ids[j].push_back(id);
1740
+ }
1741
+ used_[e] = true;
1742
+ ++j;
1743
+ }
1744
+ for (EdgeId e : in_edges) {
1745
+ for (InputEdgeId id : g_.input_edge_ids(e)) {
1746
+ merged_input_ids[j].push_back(id);
1747
+ }
1748
+ used_[e] = true;
1749
+ ++j;
1750
+ }
1751
+ S2_DCHECK_EQ(merged_input_ids.size(), j);
1752
+ }
1753
+ if (!degenerate_ids.empty()) {
1754
+ std::sort(degenerate_ids.begin(), degenerate_ids.end());
1755
+ AssignDegenerateEdges(degenerate_ids, &merged_input_ids);
1756
+ }
1757
+ // Output the merged edges.
1758
+ VertexId v0 = vertices[0], v1 = vertices[1], vb = vertices.back();
1759
+ for (EdgeId e : out_.edge_ids(v0, v1)) {
1760
+ new_edges_.push_back(Edge(v0, vb));
1761
+ new_edge_layers_.push_back(graph_edge_layer(e));
1762
+ }
1763
+ for (EdgeId e : out_.edge_ids(v1, v0)) {
1764
+ new_edges_.push_back(Edge(vb, v0));
1765
+ new_edge_layers_.push_back(graph_edge_layer(e));
1766
+ }
1767
+ for (const auto& ids : merged_input_ids) {
1768
+ new_input_edge_ids_.push_back(input_edge_id_set_lexicon_->Add(ids));
1769
+ }
1770
+ }
1771
+
1772
+ // Given a list of the input edge ids associated with degenerate edges in the
1773
+ // interior of an edge chain, assigns each input edge id to one of the output
1774
+ // edges.
1775
+ void S2Builder::EdgeChainSimplifier::AssignDegenerateEdges(
1776
+ const vector<InputEdgeId>& degenerate_ids,
1777
+ vector<vector<InputEdgeId>>* merged_ids) const {
1778
+ // Each degenerate edge is assigned to an output edge in the appropriate
1779
+ // layer. If there is more than one candidate, we use heuristics so that if
1780
+ // the input consists of a chain of edges provided in consecutive order
1781
+ // (some of which became degenerate), then all those input edges are
1782
+ // assigned to the same output edge. For example, suppose that one output
1783
+ // edge is labeled with input edges 3,4,7,8, while another output edge is
1784
+ // labeled with input edges 50,51,54,57. Then if we encounter degenerate
1785
+ // edges labeled with input edges 5 and 6, we would prefer to assign them to
1786
+ // the first edge (yielding the continuous range 3,4,5,6,7,8).
1787
+ //
1788
+ // The heuristic below is only smart enough to handle the case where the
1789
+ // candidate output edges have non-overlapping ranges of input edges.
1790
+ // (Otherwise there is probably not a good heuristic for assigning the
1791
+ // degenerate edges in any case.)
1792
+
1793
+ // Duplicate edge ids don't affect the heuristic below, so we don't bother
1794
+ // removing them. (They will be removed by IdSetLexicon::Add.)
1795
+ for (auto& ids : *merged_ids) std::sort(ids.begin(), ids.end());
1796
+
1797
+ // Sort the output edges by their minimum input edge id. This is sufficient
1798
+ // for the purpose of determining which layer they belong to. With
1799
+ // EdgeType::UNDIRECTED, some edges might not have any input edge ids (i.e.,
1800
+ // if they consist entirely of siblings of input edges). We simply remove
1801
+ // such edges from the lists of candidates.
1802
+ vector<unsigned> order;
1803
+ order.reserve(merged_ids->size());
1804
+ for (int i = 0; i < merged_ids->size(); ++i) {
1805
+ if (!(*merged_ids)[i].empty()) order.push_back(i);
1806
+ }
1807
+ std::sort(order.begin(), order.end(), [&merged_ids](int i, int j) {
1808
+ return (*merged_ids)[i][0] < (*merged_ids)[j][0];
1809
+ });
1810
+
1811
+ // Now determine where each degenerate edge should be assigned.
1812
+ for (InputEdgeId degenerate_id : degenerate_ids) {
1813
+ int layer = input_edge_layer(degenerate_id);
1814
+
1815
+ // Find the first output edge whose range of input edge ids starts after
1816
+ // "degenerate_id". If the previous edge belongs to the correct layer,
1817
+ // then we assign the degenerate edge to it.
1818
+ auto it = std::upper_bound(order.begin(), order.end(), degenerate_id,
1819
+ [&merged_ids](InputEdgeId x, unsigned y) {
1820
+ return x < (*merged_ids)[y][0];
1821
+ });
1822
+ if (it != order.begin()) {
1823
+ if ((*merged_ids)[it[-1]][0] >= layer_begins_[layer]) --it;
1824
+ }
1825
+ S2_DCHECK_EQ(layer, input_edge_layer((*merged_ids)[it[0]][0]));
1826
+ (*merged_ids)[it[0]].push_back(degenerate_id);
1827
+ }
1828
+ }