@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,1329 @@
1
+ // Copyright 2016 Google Inc. All Rights Reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS-IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+
16
+ // Author: ericv@google.com (Eric Veach)
17
+
18
+ #include "s2/s2builder.h"
19
+
20
+ #include <algorithm>
21
+ #include <cinttypes>
22
+ #include <cmath>
23
+ #include <cstdint>
24
+ #include <iostream>
25
+ #include <memory>
26
+ #include <string>
27
+ #include <vector>
28
+
29
+ #include "s2/base/commandlineflags.h"
30
+ #include "s2/base/log_severity.h"
31
+ #include "s2/base/timer.h"
32
+ #include <gtest/gtest.h>
33
+ #include "s2/third_party/absl/memory/memory.h"
34
+ #include "s2/third_party/absl/strings/str_cat.h"
35
+ #include "s2/third_party/absl/strings/str_join.h"
36
+ #include "s2/s2builder_layer.h"
37
+ #include "s2/s2builderutil_s2polygon_layer.h"
38
+ #include "s2/s2builderutil_s2polyline_layer.h"
39
+ #include "s2/s2builderutil_s2polyline_vector_layer.h"
40
+ #include "s2/s2builderutil_snap_functions.h"
41
+ #include "s2/s2builderutil_testing.h"
42
+ #include "s2/s2cap.h"
43
+ #include "s2/s2cell_id.h"
44
+ #include "s2/s2debug.h"
45
+ #include "s2/s2edge_crossings.h"
46
+ #include "s2/s2edge_distances.h"
47
+ #include "s2/s2latlng.h"
48
+ #include "s2/s2loop.h"
49
+ #include "s2/s2polygon.h"
50
+ #include "s2/s2polyline.h"
51
+ #include "s2/s2predicates.h"
52
+ #include "s2/s2testing.h"
53
+ #include "s2/s2text_format.h"
54
+
55
+ using absl::StrAppend;
56
+ using absl::StrCat;
57
+ using absl::make_unique;
58
+ using std::cout;
59
+ using std::endl;
60
+ using std::make_pair;
61
+ using std::min;
62
+ using std::pair;
63
+ using std::unique_ptr;
64
+ using std::vector;
65
+ using s2builderutil::GraphClone;
66
+ using s2builderutil::IdentitySnapFunction;
67
+ using s2builderutil::IntLatLngSnapFunction;
68
+ using s2builderutil::S2CellIdSnapFunction;
69
+ using s2builderutil::S2PolygonLayer;
70
+ using s2builderutil::S2PolylineLayer;
71
+ using s2builderutil::S2PolylineVectorLayer;
72
+ using s2textformat::MakePointOrDie;
73
+ using s2textformat::MakePolygonOrDie;
74
+ using s2textformat::MakePolylineOrDie;
75
+ using EdgeType = S2Builder::EdgeType;
76
+ using InputEdgeId = S2Builder::Graph::InputEdgeId;
77
+ using Graph = S2Builder::Graph;
78
+ using GraphOptions = S2Builder::GraphOptions;;
79
+
80
+ S2_DEFINE_int32(iteration_multiplier, 1,
81
+ "Iteration multiplier for randomized tests");
82
+
83
+ namespace {
84
+
85
+ void ExpectPolygonsEqual(const S2Polygon& expected,
86
+ const S2Polygon& actual) {
87
+ EXPECT_TRUE(expected.Equals(&actual))
88
+ << "\nExpected:\n" << s2textformat::ToString(expected)
89
+ << "\nActual:\n" << s2textformat::ToString(actual);
90
+ }
91
+
92
+ void ExpectPolygonsApproxEqual(const S2Polygon& expected,
93
+ const S2Polygon& actual,
94
+ S1Angle tolerance) {
95
+ EXPECT_TRUE(expected.BoundaryApproxEquals(actual, tolerance))
96
+ << "\nExpected: " << s2textformat::ToString(expected)
97
+ << "\nActual: " << s2textformat::ToString(actual)
98
+ << "\nTolerance: " << tolerance.degrees();
99
+ }
100
+
101
+ void ExpectPolylinesEqual(const S2Polyline& expected,
102
+ const S2Polyline& actual) {
103
+ EXPECT_TRUE(expected.Equals(&actual))
104
+ << "\nExpected:\n" << s2textformat::ToString(expected)
105
+ << "\nActual:\n" << s2textformat::ToString(actual);
106
+ }
107
+
108
+ TEST(S2Builder, AddShape) {
109
+ S2Builder builder{S2Builder::Options()};
110
+ S2Polygon output;
111
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
112
+ auto input = MakePolygonOrDie("0:0, 0:5, 5:5, 5:0; 1:1, 1:4, 4:4, 4:1");
113
+ builder.AddShape(*input->index().shape(0));
114
+ S2Error error;
115
+ ASSERT_TRUE(builder.Build(&error)) << error;
116
+ ExpectPolygonsEqual(*input, output);
117
+ }
118
+
119
+ TEST(S2Builder, SimpleVertexMerging) {
120
+ // When IdentitySnapFunction is used (i.e., no special requirements on
121
+ // vertex locations), check that vertices closer together than the snap
122
+ // radius are merged together.
123
+
124
+ S1Angle snap_radius = S1Angle::Degrees(0.5);
125
+ S2Builder builder{S2Builder::Options(IdentitySnapFunction(snap_radius))};
126
+ S2Polygon output;
127
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
128
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
129
+ "0:0, 0.2:0.2, 0.1:0.2, 0.1:0.9, 0:1, 0.1:1.1, 0.9:1, 1:1, 1:0.9");
130
+ builder.AddPolygon(*input);
131
+ S2Error error;
132
+ ASSERT_TRUE(builder.Build(&error)) << error;
133
+ unique_ptr<S2Polygon> expected = MakePolygonOrDie("0:0, 0:1, 1:0.9");
134
+ ExpectPolygonsApproxEqual(*expected, output, snap_radius);
135
+ }
136
+
137
+ TEST(S2Builder, SimpleS2CellIdSnapping) {
138
+ // When S2CellIdSnapFunction is used, check that all output vertices are the
139
+ // centers of S2CellIds at the specified level level.
140
+
141
+ int level = S2CellIdSnapFunction::LevelForMaxSnapRadius(S1Angle::Degrees(1));
142
+ S2CellIdSnapFunction snap_function(level);
143
+ S2Builder builder{S2Builder::Options(snap_function)};
144
+ S2Polygon output;
145
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
146
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
147
+ "2:2, 3:4, 2:6, 4:5, 6:6, 5:4, 6:2, 4:3");
148
+ builder.AddPolygon(*input);
149
+ S2Error error;
150
+ ASSERT_TRUE(builder.Build(&error)) << error;
151
+ ASSERT_EQ(1, output.num_loops());
152
+ const S2Loop* loop = output.loop(0);
153
+ for (int i = 0; i < loop->num_vertices(); ++i) {
154
+ EXPECT_EQ(S2CellId(loop->vertex(i)).parent(level).ToPoint(),
155
+ loop->vertex(i));
156
+ }
157
+ ExpectPolygonsApproxEqual(*input, output, snap_function.snap_radius());
158
+ }
159
+
160
+ TEST(S2Builder, SimpleIntLatLngSnapping) {
161
+ S2Builder builder(S2Builder::Options(IntLatLngSnapFunction(0))); // E0 coords
162
+ S2Polygon output;
163
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
164
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
165
+ "2.01:2.09, 3.24:4.49, 1.78:6.25, 3.51:5.49, 6.11:6.11, "
166
+ "5.22:3.88, 5.55:2.49, 4.49:2.51");
167
+ unique_ptr<S2Polygon> expected = MakePolygonOrDie(
168
+ "2:2, 3:4, 2:6, 4:5, 6:6, 5:4, 6:2, 4:3");
169
+ builder.AddPolygon(*input);
170
+ S2Error error;
171
+ ASSERT_TRUE(builder.Build(&error)) << error;
172
+ ASSERT_EQ(1, output.num_loops());
173
+ ExpectPolygonsEqual(*expected, output);
174
+ }
175
+
176
+ TEST(S2Builder, VerticesMoveLessThanSnapRadius) {
177
+ // Check that chains of closely spaced vertices do not collapse into a
178
+ // single vertex.
179
+
180
+ S1Angle snap_radius = S1Angle::Degrees(1);
181
+ S2Builder builder{S2Builder::Options{IdentitySnapFunction(snap_radius)}};
182
+ S2Polygon output;
183
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
184
+ // The spacing between input vertices is about 2*pi*20/1000 = 0.125 degrees.
185
+ // The output vertices are spaced between 1 and 2 degrees apart; the average
186
+ // spacing is about 1.33 degrees.
187
+ S2Polygon input(
188
+ S2Loop::MakeRegularLoop(S2Point(1, 0, 0), S1Angle::Degrees(20), 1000));
189
+ builder.AddPolygon(input);
190
+ S2Error error;
191
+ ASSERT_TRUE(builder.Build(&error)) << error;
192
+ ASSERT_EQ(1, output.num_loops());
193
+ EXPECT_GE(output.loop(0)->num_vertices(), 90);
194
+ EXPECT_LE(output.loop(0)->num_vertices(), 100);
195
+ EXPECT_TRUE(output.BoundaryNear(input, snap_radius));
196
+ }
197
+
198
+ TEST(S2Builder, MinEdgeVertexSeparation) {
199
+ // Check that edges are separted from non-incident vertices by at least
200
+ // min_edge_vertex_separation(). This requires adding new vertices (not
201
+ // present in the input) in some cases.
202
+
203
+ // The input is a skinny right triangle with two legs of length 10 and 1,
204
+ // and whose diagonal is subdivided into 10 short edges. Using a snap
205
+ // radius of 0.5, about half of the long leg is snapped onto the diagonal
206
+ // (which causes that part of the polygon to be removed). But the real
207
+ // problem is that the remaining part of the long leg gets too close to the
208
+ // remaining vertices on the diagonal, i.e. it would violate the minimum
209
+ // edge-vertex separation guarantee. S2Builder handles this by creating at
210
+ // least one vertex along the original long leg, to keep the snapped edge
211
+ // far enough away from the diagonal.
212
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
213
+ "0:0, 0:1, 1:.9, 2:.8, 3:.7, 4:.6, 5:.5, 6:.4, 7:.3, 8:.2, 9:.1, 10:0");
214
+ unique_ptr<S2Polygon> expected = MakePolygonOrDie(
215
+ "0:0, 0:1, 1:.9, 2:.8, 3:.7, 4:.6, 5:.5, 4.00021862252687:0");
216
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
217
+ S2Builder builder(options);
218
+ S2Polygon output;
219
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
220
+ builder.AddPolygon(*input);
221
+ S2Error error;
222
+ ASSERT_TRUE(builder.Build(&error)) << error;
223
+ ExpectPolygonsApproxEqual(*expected, output, S1Angle::Radians(1e-15));
224
+ }
225
+
226
+ TEST(S2Builder, IdempotencySnapsInadequatelySeparatedVertices) {
227
+ // This test checks that when vertices are closer together than
228
+ // min_vertex_separation() then they are snapped together even when
229
+ // options.idempotent() is true.
230
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1.0)));
231
+ S2Builder builder(options);
232
+ S2Polyline output;
233
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output));
234
+ builder.AddPolyline(*MakePolylineOrDie("0:0, 0:0.9, 0:2"));
235
+ S2Error error;
236
+ ASSERT_TRUE(builder.Build(&error)) << error;
237
+ const char* expected = "0:0, 0:2";
238
+ EXPECT_EQ(expected, s2textformat::ToString(output));
239
+ }
240
+
241
+ TEST(S2Builder, IdempotencySnapsIdenticalVerticesWithZeroSnapRadius) {
242
+ // This test checks that even when the snap radius is zero, identical
243
+ // vertices are snapped together.
244
+ S2Builder builder{S2Builder::Options()};
245
+ S2Polygon output;
246
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
247
+ builder.AddPolyline(*MakePolylineOrDie("0:1, 1:0"));
248
+ builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1"));
249
+ builder.AddEdge(MakePointOrDie("0:1"), MakePointOrDie("0:1"));
250
+ builder.AddPolyline(*MakePolylineOrDie("1:0, 0:0"));
251
+ S2Error error;
252
+ ASSERT_TRUE(builder.Build(&error)) << error;
253
+ const char* expected = "0:0, 0:1, 1:0";
254
+ EXPECT_EQ(expected, s2textformat::ToString(output));
255
+ }
256
+
257
+ TEST(S2Builder,
258
+ IdempotencySnapsIdenticalVerticesWithZeroSnapRadiusEdgeSplitting) {
259
+ // This test checks that identical vertices are snapped together even when
260
+ // the snap radius is zero and options.split_crossing_edges() is true.
261
+ S2Builder::Options options;
262
+ options.set_split_crossing_edges(true);
263
+ S2Builder builder(options);
264
+ S2Polygon output;
265
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
266
+ builder.AddPolyline(*MakePolylineOrDie("0:1, 1:0"));
267
+ builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1"));
268
+ builder.AddEdge(MakePointOrDie("0:1"), MakePointOrDie("0:1"));
269
+ builder.AddPolyline(*MakePolylineOrDie("1:0, 0:0"));
270
+ S2Error error;
271
+ ASSERT_TRUE(builder.Build(&error)) << error;
272
+ const char* expected = "0:0, 0:1, 1:0";
273
+ EXPECT_EQ(expected, s2textformat::ToString(output));
274
+ }
275
+
276
+ TEST(S2Builder, IdempotencySnapsUnsnappedVertices) {
277
+ // When idempotency is requested, no snapping is done unless S2Builder finds
278
+ // at least one vertex or edge that could not be the output of a previous
279
+ // snapping operation. This test checks that S2Builder detects vertices
280
+ // that are not at a valid location returned by the given snap function.
281
+
282
+ // In this example we snap two vertices to integer lat/lng coordinates. The
283
+ // two vertices are far enough apart (more than min_vertex_separation) so
284
+ // that they might be the result of a previous snapping operation, but one
285
+ // of the two vertices does not have integer lat/lng coordinates. We use
286
+ // internal knowledge of how snap sites are chosen (namely, that candidates
287
+ // are considered in S2CellId order) to construct two different cases, one
288
+ // where the snapped vertex is processed first and one where the unsnapped
289
+ // vertex is processed first. This exercises two different code paths.
290
+ IntLatLngSnapFunction snap_function(0);
291
+ EXPECT_GE(snap_function.snap_radius(), S1Angle::Degrees(0.7));
292
+ EXPECT_LE(snap_function.min_vertex_separation(), S1Angle::Degrees(0.35));
293
+ S2Builder builder{S2Builder::Options(snap_function)};
294
+
295
+ // In this example, the snapped vertex (0, 0) is processed first and is
296
+ // selected as a Voronoi site (i.e., output vertex). The second vertex is
297
+ // closer than min_(), therefore it is snapped to the first vertex
298
+ // and the polyline becomes degenerate.
299
+ S2Point a = S2LatLng::FromDegrees(0, 0).ToPoint();
300
+ S2Point b = S2LatLng::FromDegrees(0.01, 0.6).ToPoint();
301
+ EXPECT_LT(S2CellId(a), S2CellId(b));
302
+ S2Polyline input1(vector<S2Point>{a, b}), output1;
303
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output1));
304
+ builder.AddPolyline(input1);
305
+ S2Error error;
306
+ ASSERT_TRUE(builder.Build(&error));
307
+ EXPECT_EQ("0:0, 0:1", s2textformat::ToString(output1));
308
+
309
+ // In this example the unsnapped vertex is processed first and is snapped to
310
+ // (0, 0). The second vertex is further than snap_radius() away, so it is
311
+ // also snapped (which does nothing) and is left at (0, 1).
312
+ S2Point c = S2LatLng::FromDegrees(0.01, 0.4).ToPoint();
313
+ S2Point d = S2LatLng::FromDegrees(0, 1).ToPoint();
314
+ EXPECT_LT(S2CellId(c), S2CellId(d));
315
+ S2Polyline input2(vector<S2Point>{c, d}), output2;
316
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output2));
317
+ builder.AddPolyline(input2);
318
+ ASSERT_TRUE(builder.Build(&error)) << error;
319
+ EXPECT_EQ("0:0, 0:1", s2textformat::ToString(output2));
320
+ }
321
+
322
+ TEST(S2Builder, IdempotencySnapsEdgesWithTinySnapRadius) {
323
+ // When idempotency is requested, no snapping is done unless S2Builder finds
324
+ // at least one vertex or edge that could not be the output of a previous
325
+ // snapping operation. This test checks that S2Builder detects edges that
326
+ // are too close to vertices even when the snap radius is very small
327
+ // (e.g., S2::kIntersectionError).
328
+ //
329
+ // Previously S2Builder used a conservative approximation to decide whether
330
+ // edges were too close to vertices; unfortunately this meant that when the
331
+ // snap radius was very small then no snapping would be done at all, because
332
+ // even an edge/vertex distance of zero was considered far enough apart.
333
+ //
334
+ // This tests that the current code (which uses exact predicates) handles
335
+ // this situation correctly (i.e., that an edge separated from a
336
+ // non-incident vertex by a distance of zero cannot be the output of a
337
+ // previous snapping operation).
338
+ S2Builder::Options options;
339
+ options.set_snap_function(
340
+ s2builderutil::IdentitySnapFunction(S2::kIntersectionError));
341
+ S2PolylineVectorLayer::Options layer_options;
342
+ layer_options.set_duplicate_edges(
343
+ S2PolylineVectorLayer::Options::DuplicateEdges::MERGE);
344
+ S2Builder builder(options);
345
+ vector<unique_ptr<S2Polyline>> output;
346
+ builder.StartLayer(
347
+ make_unique<S2PolylineVectorLayer>(&output, layer_options));
348
+ builder.AddPolyline(*MakePolylineOrDie("0:0, 0:10"));
349
+ builder.AddPolyline(*MakePolylineOrDie("0:5, 0:7"));
350
+ S2Error error;
351
+ ASSERT_TRUE(builder.Build(&error));
352
+ ASSERT_EQ(1, output.size());
353
+ EXPECT_EQ("0:0, 0:5, 0:7, 0:10", s2textformat::ToString(*output[0]));
354
+ }
355
+
356
+ TEST(S2Builder, IdempotencyDoesNotSnapAdequatelySeparatedEdges) {
357
+ // When idempotency is requested, no snapping is done unless S2Builder finds
358
+ // at least one vertex or edge that could not be the output of a previous
359
+ // snapping operation. This test checks that when an edge is further away
360
+ // than min_edge_vertex_separation() then no snapping is done.
361
+ S2Builder::Options options(IntLatLngSnapFunction(0));
362
+ options.set_idempotent(true); // Test fails if this is "false".
363
+ S2Builder builder(options);
364
+ S2Polygon output1, output2;
365
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output1));
366
+ builder.AddPolygon(*MakePolygonOrDie("1.49:0, 0:2, 0.49:3"));
367
+ S2Error error;
368
+ ASSERT_TRUE(builder.Build(&error)) << error;
369
+ const char* expected = "1:0, 0:2, 0:3";
370
+ EXPECT_EQ(expected, s2textformat::ToString(output1));
371
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output2));
372
+ builder.AddPolygon(output1);
373
+ ASSERT_TRUE(builder.Build(&error)) << error;
374
+ EXPECT_EQ(expected, s2textformat::ToString(output2));
375
+ }
376
+
377
+ TEST(S2Builder, kMaxSnapRadiusCanSnapAtLevel0) {
378
+ // Verify that kMaxSnapRadius will allow snapping at S2CellId level 0.
379
+ EXPECT_LE(S2CellIdSnapFunction::MinSnapRadiusForLevel(0),
380
+ S2Builder::SnapFunction::kMaxSnapRadius());
381
+ }
382
+
383
+ TEST(S2Builder, S2CellIdSnappingAtAllLevels) {
384
+ unique_ptr<const S2Polygon> input = MakePolygonOrDie(
385
+ "0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0");
386
+ for (int level = 0; level <= S2CellId::kMaxLevel; ++level) {
387
+ S2CellIdSnapFunction snap_function(level);
388
+ S2Builder builder{S2Builder::Options(snap_function)};
389
+ S2Polygon output;
390
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
391
+ builder.AddPolygon(*input);
392
+ S2Error error;
393
+ ASSERT_TRUE(builder.Build(&error)) << error;
394
+ EXPECT_TRUE(output.IsValid());
395
+ // The ApproxContains calls below are not guaranteed to succeed in general
396
+ // because ApproxContains works by snapping both polygons together using
397
+ // the given tolerance and then checking for containment. Since
398
+ // ApproxContains snaps to an arbitrary subset of the input vertices
399
+ // rather than to S2CellId centers at the current level, this means that
400
+ // corresponding vertices in "input" and "output" can snap to different
401
+ // sites, which causes the containment test to fail. Nevertheless, by
402
+ // using a larger tolerance of 2 * snap_radius, all calls in this test
403
+ // succeed (and would be likely to succeed in other similar tests).
404
+ // (To guarantee correctness we would need to use S2CellIdSnapFunction
405
+ // within the ApproxContains implementation.)
406
+ S1Angle tolerance = min(2 * snap_function.snap_radius(),
407
+ snap_function.kMaxSnapRadius());
408
+ EXPECT_TRUE(output.ApproxContains(input.get(), tolerance));
409
+ EXPECT_TRUE(input->ApproxContains(&output, tolerance));
410
+ }
411
+ }
412
+
413
+ TEST(S2Builder, SnappingDoesNotRotateVertices) {
414
+ // This is already tested extensively elsewhere.
415
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
416
+ "49.9305505:-124.8345463, 49.9307448:-124.8299657, "
417
+ "49.9332101:-124.8301996, 49.9331224:-124.8341368; "
418
+ "49.9311087:-124.8327042, 49.9318176:-124.8312621, "
419
+ "49.9318866:-124.8334451");
420
+ S2Builder::Options options((S2CellIdSnapFunction()));
421
+ S2Builder builder(options);
422
+ S2Polygon output1, output2;
423
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output1));
424
+ builder.AddPolygon(*input);
425
+ S2Error error;
426
+ ASSERT_TRUE(builder.Build(&error)) << error;
427
+ // This checks that the vertices are in the same cyclic order, and that
428
+ // vertices have not moved by more than "snap_radius".
429
+ ExpectPolygonsApproxEqual(*input, output1,
430
+ options.snap_function().snap_radius());
431
+
432
+ // Check that snapping twice doesn't rotate the vertices. This also
433
+ // verifies that S2Builder can be used again after Build() is called.
434
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output2));
435
+ builder.AddPolygon(output1);
436
+ ASSERT_TRUE(builder.Build(&error)) << error;
437
+ ExpectPolygonsEqual(output1, output2);
438
+ }
439
+
440
+ TEST(S2Builder, SelfIntersectingPolyline) {
441
+ // Check that when two edges of a polyline cross, the intersection point is
442
+ // added to both edges.
443
+
444
+ S2Builder::Options options;
445
+ IntLatLngSnapFunction snap_function(1); // Snap to E1 coordinates
446
+ options.set_snap_function(snap_function);
447
+ options.set_split_crossing_edges(true);
448
+ S2Builder builder(options);
449
+ S2Polyline output;
450
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output));
451
+ unique_ptr<S2Polyline> input = MakePolylineOrDie("3:1, 1:3, 1:1, 3:3");
452
+ unique_ptr<S2Polyline> expected =
453
+ MakePolylineOrDie("3:1, 2:2, 1:3, 1:1, 2:2, 3:3");
454
+ builder.AddPolyline(*input);
455
+ S2Error error;
456
+ ASSERT_TRUE(builder.Build(&error)) << error;
457
+ ExpectPolylinesEqual(*expected, output);
458
+ }
459
+
460
+ TEST(S2Builder, SelfIntersectingPolygon) {
461
+ // Check that when two edge of a polygon cross, the intersection point is
462
+ // added to both edges, and that the resulting (undirected) edges can be
463
+ // assembled into a valid polygon.
464
+
465
+ IntLatLngSnapFunction snap_function(1); // Snap to E1 coordinates
466
+ S2Builder::Options options;
467
+ options.set_snap_function(snap_function);
468
+ options.set_split_crossing_edges(true);
469
+ S2Builder builder(options);
470
+ S2Polygon output;
471
+ builder.StartLayer(make_unique<S2PolygonLayer>(
472
+ &output, S2PolygonLayer::Options(EdgeType::UNDIRECTED)));
473
+ unique_ptr<S2Polyline> input = MakePolylineOrDie("3:1, 1:3, 1:1, 3:3, 3:1");
474
+ unique_ptr<S2Polygon> expected = MakePolygonOrDie("1:1, 1:3, 2:2; 3:3, 3:1, 2:2");
475
+ builder.AddPolyline(*input);
476
+ S2Error error;
477
+ ASSERT_TRUE(builder.Build(&error)) << error;
478
+ ExpectPolygonsEqual(*expected, output);
479
+ }
480
+
481
+ TEST(S2Builder, TieBreakingIsConsistent) {
482
+ // Check that when an edge passes between two equally distant vertices, that
483
+ // the choice of which one to snap to does not depend on the edge direction.
484
+
485
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(2)));
486
+ options.set_idempotent(false);
487
+ S2Builder builder(options);
488
+ builder.ForceVertex(S2LatLng::FromDegrees(1, 0).ToPoint());
489
+ builder.ForceVertex(S2LatLng::FromDegrees(-1, 0).ToPoint());
490
+ S2Polyline output1, output2;
491
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output1));
492
+ builder.AddPolyline(*MakePolylineOrDie("0:-5, 0:5"));
493
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output2));
494
+ builder.AddPolyline(*MakePolylineOrDie("0:5, 0:-5"));
495
+ S2Error error;
496
+ EXPECT_TRUE(builder.Build(&error)) << error;
497
+ EXPECT_EQ(3, output1.num_vertices());
498
+ EXPECT_EQ(3, output2.num_vertices());
499
+ for (int i = 0; i < 3; ++i) {
500
+ EXPECT_EQ(output1.vertex(i), output2.vertex(2 - i));
501
+ }
502
+ }
503
+
504
+ // Verifies that two graphs have the same vertices and edges.
505
+ void ExpectGraphsEqual(const S2Builder::Graph& expected,
506
+ const S2Builder::Graph& actual) {
507
+ ASSERT_EQ(expected.vertices(), actual.vertices());
508
+ ASSERT_EQ(expected.edges(), actual.edges());
509
+ ASSERT_EQ(expected.input_edge_id_set_ids(),
510
+ actual.input_edge_id_set_ids());
511
+ }
512
+
513
+ // This layer makes both a shallow and a deep copy of the Graph object passed
514
+ // to its Build() method and appends them to two vectors. Furthermore, it
515
+ // verifies that the shallow and deep copies of any graphs previously appended
516
+ // to those vectors are still identical.
517
+ class GraphPersistenceLayer : public S2Builder::Layer {
518
+ public:
519
+ GraphPersistenceLayer(
520
+ const S2Builder::GraphOptions& graph_options,
521
+ std::vector<S2Builder::Graph>* graphs,
522
+ std::vector<std::unique_ptr<GraphClone>>* clones)
523
+ : graph_options_(graph_options), graphs_(graphs), clones_(clones) {}
524
+
525
+ S2Builder::GraphOptions graph_options() const override {
526
+ return graph_options_;
527
+ }
528
+
529
+ void Build(const S2Builder::Graph& g, S2Error* error) override {
530
+ // Verify that all graphs built so far are unchanged.
531
+ for (int i = 0; i < graphs_->size(); ++i) {
532
+ ExpectGraphsEqual((*clones_)[i]->graph(), (*graphs_)[i]);
533
+ }
534
+ graphs_->push_back(g);
535
+ clones_->push_back(absl::make_unique<GraphClone>(g));
536
+ }
537
+
538
+ private:
539
+ GraphOptions graph_options_;
540
+ std::vector<S2Builder::Graph>* graphs_; // Shallow copies.
541
+ std::vector<std::unique_ptr<GraphClone>>* clones_; // Deep copies.
542
+ };
543
+
544
+ TEST(S2Builder, GraphPersistence) {
545
+ // Ensure that the Graph objects passed to S2Builder::Layer::Build() methods
546
+ // remain valid until all layers have been built.
547
+ vector<Graph> graphs;
548
+ vector<unique_ptr<GraphClone>> clones;
549
+ S2Builder builder{S2Builder::Options()};
550
+ for (int i = 0; i < 20; ++i) {
551
+ builder.StartLayer(make_unique<GraphPersistenceLayer>(
552
+ GraphOptions(), &graphs, &clones));
553
+ for (int n = S2Testing::rnd.Uniform(10); n > 0; --n) {
554
+ builder.AddEdge(S2Testing::RandomPoint(), S2Testing::RandomPoint());
555
+ }
556
+ }
557
+ S2Error error;
558
+ EXPECT_TRUE(builder.Build(&error));
559
+ }
560
+
561
+ void TestPolylineLayers(
562
+ const vector<const char*>& input_strs,
563
+ const vector<const char*>& expected_strs,
564
+ const S2PolylineLayer::Options& layer_options,
565
+ const S2Builder::Options& builder_options = S2Builder::Options()) {
566
+ SCOPED_TRACE(layer_options.edge_type() == EdgeType::DIRECTED ?
567
+ "DIRECTED" : "UNDIRECTED");
568
+ S2Builder builder(builder_options);
569
+ vector<unique_ptr<S2Polyline>> output;
570
+ for (auto input_str : input_strs) {
571
+ output.emplace_back(new S2Polyline);
572
+ builder.StartLayer(make_unique<S2PolylineLayer>(output.back().get(),
573
+ layer_options));
574
+ builder.AddPolyline(*MakePolylineOrDie(input_str));
575
+ }
576
+ S2Error error;
577
+ ASSERT_TRUE(builder.Build(&error));
578
+ vector<string> output_strs;
579
+ for (const auto& polyline : output) {
580
+ output_strs.push_back(s2textformat::ToString(*polyline));
581
+ }
582
+ EXPECT_EQ(absl::StrJoin(expected_strs, "; "),
583
+ absl::StrJoin(output_strs, "; "));
584
+ }
585
+
586
+ void TestPolylineVector(
587
+ const vector<const char*>& input_strs,
588
+ const vector<const char*>& expected_strs,
589
+ const S2PolylineVectorLayer::Options& layer_options,
590
+ const S2Builder::Options& builder_options = S2Builder::Options()) {
591
+ S2Builder builder(builder_options);
592
+ vector<unique_ptr<S2Polyline>> output;
593
+ builder.StartLayer(
594
+ make_unique<S2PolylineVectorLayer>(&output, layer_options));
595
+ for (auto input_str : input_strs) {
596
+ builder.AddPolyline(*MakePolylineOrDie(input_str));
597
+ }
598
+ S2Error error;
599
+ ASSERT_TRUE(builder.Build(&error));
600
+ vector<string> output_strs;
601
+ for (const auto& polyline : output) {
602
+ output_strs.push_back(s2textformat::ToString(*polyline));
603
+ }
604
+ EXPECT_EQ(absl::StrJoin(expected_strs, "; "),
605
+ absl::StrJoin(output_strs, "; "));
606
+ }
607
+
608
+ void TestPolylineLayersBothEdgeTypes(
609
+ const vector<const char*>& input_strs,
610
+ const vector<const char*>& expected_strs,
611
+ S2PolylineLayer::Options layer_options, // by value
612
+ const S2Builder::Options& builder_options = S2Builder::Options()) {
613
+ layer_options.set_edge_type(EdgeType::DIRECTED);
614
+ TestPolylineLayers(input_strs, expected_strs, layer_options, builder_options);
615
+ layer_options.set_edge_type(EdgeType::UNDIRECTED);
616
+ TestPolylineLayers(input_strs, expected_strs, layer_options, builder_options);
617
+ }
618
+
619
+ TEST(S2Builder, SimplifyOneEdge) {
620
+ // Simplify a perturbed edge chain into a single edge.
621
+
622
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1)));
623
+ options.set_simplify_edge_chains(true);
624
+ TestPolylineLayersBothEdgeTypes({"0:0, 1:0.5, 2:-0.5, 3:0.5, 4:-0.5, 5:0"},
625
+ {"0:0, 5:0"},
626
+ S2PolylineLayer::Options(), options);
627
+ }
628
+
629
+ TEST(S2Builder, SimplifyTwoLayers) {
630
+ // Construct two layers, each containing a polyline that could be simplified
631
+ // to a single edge on its own. However the two polylines actually cross,
632
+ // so make sure that the output still contains the intersection vertex.
633
+
634
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
635
+ options.set_split_crossing_edges(true);
636
+ options.set_simplify_edge_chains(true);
637
+ TestPolylineLayersBothEdgeTypes(
638
+ {"-2:-1, -1:0, 1:0, 2:1", "1:-2, 0:-1, 0:1, -1:2"},
639
+ {"-2:-1, 0:0, 2:1", "1:-2, 0:0, -1:2"},
640
+ S2PolylineLayer::Options(), options);
641
+ }
642
+
643
+ TEST(S2Builder, SimplifyOneLoop) {
644
+ // Simplify a regular loop with 1000 vertices and a radius of 20 degrees.
645
+ // Turning on edge chain simplification yields a dramatically smaller number
646
+ // of vertices than snapping alone (10 vertices vs 95 vertices using a snap
647
+ // radius of 1 degree). This is because snapping alone yields vertices that
648
+ // stay within 1 degree of the input *vertices*, while simplifying edge
649
+ // chains yields edges that stay within 1 degree of the input *edges*.
650
+
651
+ for (int i = 0; i < 2; ++i) {
652
+ EdgeType edge_type = static_cast<EdgeType>(i);
653
+ S1Angle snap_radius = S1Angle::Degrees(1);
654
+ S2Builder::Options options((IdentitySnapFunction(snap_radius)));
655
+ options.set_simplify_edge_chains(true);
656
+ S2Builder builder(options);
657
+ S2Polygon output;
658
+ builder.StartLayer(make_unique<S2PolygonLayer>(
659
+ &output, S2PolygonLayer::Options(edge_type)));
660
+ // Spacing between vertices: approximately 2*pi*20/1000 = 0.125 degrees.
661
+ S2Polygon input(
662
+ S2Loop::MakeRegularLoop(S2Point(1, 0, 0), S1Angle::Degrees(20), 1000));
663
+ builder.AddPolygon(input);
664
+ S2Error error;
665
+ ASSERT_TRUE(builder.Build(&error)) << error;
666
+ ASSERT_EQ(1, output.num_loops());
667
+ EXPECT_GE(output.loop(0)->num_vertices(), 10);
668
+ EXPECT_LE(output.loop(0)->num_vertices(), 12);
669
+ EXPECT_TRUE(output.BoundaryNear(input, snap_radius));
670
+ }
671
+ }
672
+
673
+ TEST(S2Builder, SimplifyOppositeDirections) {
674
+ // We build two layers with two polylines that follow the same circular arc
675
+ // in opposite directions, and verify that they are snapped identically.
676
+ // (The snap radius is adjusted so that the arc is simplified into a long
677
+ // edge and a short edge, and therefore we would get a different result if
678
+ // the two layers followed the edge chain in different directions.)
679
+
680
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
681
+ options.set_simplify_edge_chains(true);
682
+ TestPolylineLayersBothEdgeTypes(
683
+ {"-4:0.83, -3:0.46, -2:0.2, -1:0.05, 0:0, 1:0.5, 2:0.2, 3:0.46, 4:0.83",
684
+ "4:.83, 3:.46, 2:.2, 1:.05, 0:0, -1:.5, -2:.2, -3:.46, -4:.83"},
685
+ {"-4:0.83, -2:0.2, 4:0.83", "4:0.83, -2:0.2, -4:0.83"},
686
+ S2PolylineLayer::Options(), options);
687
+ }
688
+
689
+ TEST(S2Builder, SimplifyKeepsEdgeVertexSeparation) {
690
+ // We build two layers each containing a polyline, such that the polyline in
691
+ // the first layer could be simplified to a straight line except that then
692
+ // it would create an intersection with the second polyline.
693
+
694
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(1.0)));
695
+ options.set_simplify_edge_chains(true);
696
+ TestPolylineLayersBothEdgeTypes(
697
+ {"0:-10, 0.99:0, 0:10", "-5:-5, -0.2:0, -5:5"},
698
+ {"0:-10, 0.99:0, 0:10", "-5:-5, -0.2:0, -5:5"},
699
+ S2PolylineLayer::Options(), options);
700
+ }
701
+
702
+ TEST(S2Builder, SimplifyBacktrackingEdgeChain) {
703
+ // Test simplifying an edge chain that backtracks on itself.
704
+ S2Builder::Options options(IdentitySnapFunction(S1Angle::Degrees(0.5)));
705
+ options.set_simplify_edge_chains(true);
706
+ TestPolylineLayersBothEdgeTypes(
707
+ {"0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 4:0, 3:0, "
708
+ "2:0, 3:0, 4:0, 5:0, 6:0, 7:0"},
709
+ {"0:0, 2:0, 5:0, 2:0, 5:0, 7:0"},
710
+ S2PolylineLayer::Options(), options);
711
+ }
712
+
713
+ TEST(S2Builder, SimplifyLimitsEdgeDeviation) {
714
+ // Make sure that simplification does not create long edges such that the
715
+ // midpoint of the edge might be further than max_edge_deviation() from an
716
+ // input edge. In the example below, vertices are snapped to integer
717
+ // lat/lng coordinates, and the snap radius is approximately 0.707 degrees.
718
+ // Snapping moves the input vertices perpendicular to the input edge by just
719
+ // slightly less than the snap radius (0.693 degrees). Now the midpoint of
720
+ // the snapped edge is about 0.98 degrees from the input edge, which causes
721
+ // an extra site to be added at the midpoint of the original edge.
722
+ //
723
+ // When simplify_edge_chains() is enabled, then usually an extra site like
724
+ // this would be simplified away (because the simplified edge would still be
725
+ // within snap_radius() of all the input vertices) except that there is an
726
+ // explicit check in S2Builder that prevents this. (If the check is removed
727
+ // then this test fails.)
728
+
729
+ S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coordinates
730
+ options.set_simplify_edge_chains(true);
731
+ TestPolylineLayersBothEdgeTypes(
732
+ {"-30.49:-29.51, 29.51:30.49"}, {"-30:-30, -1:1, 30:30"},
733
+ S2PolylineLayer::Options(), options);
734
+ }
735
+
736
+ TEST(S2Builder, SimplifyPreservesTopology) {
737
+ // Crate several nested concentric loops, and verify that the loops are
738
+ // still nested after simplification.
739
+
740
+ const int kNumLoops = 20;
741
+ const int kNumVerticesPerLoop = 1000;
742
+ const S1Angle kBaseRadius = S1Angle::Degrees(5);
743
+ const S1Angle kSnapRadius = S1Angle::Degrees(0.1);
744
+ S2Builder::Options options((IdentitySnapFunction(kSnapRadius)));
745
+ options.set_simplify_edge_chains(true);
746
+ S2Builder builder(options);
747
+ vector<unique_ptr<S2Polygon>> input, output;
748
+ for (int j = 0; j < kNumLoops; ++j) {
749
+ // Spacing between vertices: approximately 2*pi*20/1000 = 0.125 degrees.
750
+ S1Angle radius = kBaseRadius + 0.7 * j * j / kNumLoops * kSnapRadius;
751
+ input.emplace_back(new S2Polygon(S2Loop::MakeRegularLoop(
752
+ S2Point(1, 0, 0), radius, kNumVerticesPerLoop)));
753
+ output.emplace_back(new S2Polygon);
754
+ builder.StartLayer(make_unique<S2PolygonLayer>(output.back().get()));
755
+ builder.AddPolygon(*input.back());
756
+ }
757
+ S2Error error;
758
+ ASSERT_TRUE(builder.Build(&error)) << error;
759
+ for (int j = 0; j < kNumLoops; ++j) {
760
+ EXPECT_TRUE(output[j]->BoundaryNear(*input[j], kSnapRadius));
761
+ if (j > 0) EXPECT_TRUE(output[j]->Contains(output[j - 1].get()));
762
+ }
763
+ }
764
+
765
+ TEST(S2Builder, SimplifyRemovesSiblingPairs) {
766
+ S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coords
767
+ S2PolylineVectorLayer::Options layer_options;
768
+ layer_options.set_sibling_pairs(GraphOptions::SiblingPairs::DISCARD);
769
+
770
+ // Check that there is no sibling pair without simplification.
771
+ TestPolylineVector(
772
+ {"0:0, 0:10", "0:10, 0.6:5, 0:0"},
773
+ {"0:0, 0:10, 1:5, 0:0"}, layer_options, options);
774
+
775
+ // Now check that (1) simplification produces a sibling pair,
776
+ // and (2) the sibling pair is removed (since we requested it).
777
+ options.set_simplify_edge_chains(true);
778
+ TestPolylineVector(
779
+ {"0:0, 0:10", "0:10, 0.6:5, 0:0"},
780
+ {}, layer_options, options);
781
+ }
782
+
783
+ TEST(S2Builder, SimplifyMergesDuplicateEdges) {
784
+ S2Builder::Options options(IntLatLngSnapFunction(0)); // E0 coords
785
+ S2PolylineVectorLayer::Options layer_options;
786
+ layer_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
787
+
788
+ // Check that there are no duplicate edges without simplification.
789
+ TestPolylineVector(
790
+ {"0:0, 0:10", "0:0, 0.6:5, 0:10"},
791
+ {"0:0, 0:10", "0:0, 1:5, 0:10"}, layer_options, options);
792
+
793
+ // Now check that (1) simplification produces a duplicate edge pair,
794
+ // and (2) the duplicate pair is merged (since we requested it).
795
+ options.set_simplify_edge_chains(true);
796
+ TestPolylineVector(
797
+ {"0:0, 0:10", "0:0, 0.6:5, 0:10"},
798
+ {"0:0, 0:10"}, layer_options, options);
799
+ }
800
+
801
+ TEST(S2Builder, SimplifyKeepsForcedVertices) {
802
+ S2Builder::Options options{IdentitySnapFunction(S1Angle::Radians(1e-15))};
803
+ options.set_simplify_edge_chains(true);
804
+ S2Builder builder(options);
805
+ S2Polyline output;
806
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output));
807
+ builder.AddPolyline(*MakePolylineOrDie("0:0, 0:1, 0:2, 0:3"));
808
+ builder.ForceVertex(MakePointOrDie("0:1"));
809
+ S2Error error;
810
+ ASSERT_TRUE(builder.Build(&error));
811
+ EXPECT_EQ("0:0, 0:1, 0:3", s2textformat::ToString(output));
812
+ }
813
+
814
+ // A set of (edge string, vector<InputEdgeId>) pairs representing the
815
+ // InputEdgeIds attached to the edges of a graph. Edges are in
816
+ // s2textformat::ToString() format, such as "1:3, 4:5".
817
+ using EdgeInputEdgeIds = vector<pair<string, vector<int>>>;
818
+
819
+ S2Error::Code INPUT_EDGE_ID_MISMATCH = S2Error::USER_DEFINED_START;
820
+
821
+ class InputEdgeIdCheckingLayer : public S2Builder::Layer {
822
+ public:
823
+ InputEdgeIdCheckingLayer(const EdgeInputEdgeIds& expected,
824
+ const GraphOptions& graph_options)
825
+ : expected_(expected), graph_options_(graph_options) {
826
+ }
827
+ GraphOptions graph_options() const override { return graph_options_; }
828
+ void Build(const Graph& g, S2Error* error) override;
829
+
830
+ private:
831
+ string ToString(const pair<string, vector<int>>& p) {
832
+ string r = StrCat(" (", p.first, ")={");
833
+ if (!p.second.empty()) {
834
+ for (int id : p.second) {
835
+ StrAppend(&r, id, ", ");
836
+ }
837
+ r.erase(r.size() - 2, 2);
838
+ }
839
+ r += "}\n";
840
+ return r;
841
+ }
842
+
843
+ EdgeInputEdgeIds expected_;
844
+ GraphOptions graph_options_;
845
+ };
846
+
847
+ void InputEdgeIdCheckingLayer::Build(const Graph& g, S2Error* error) {
848
+ EdgeInputEdgeIds actual;
849
+ vector<S2Point> vertices;
850
+ for (Graph::EdgeId e = 0; e < g.num_edges(); ++e) {
851
+ vertices.clear();
852
+ vertices.push_back(g.vertex(g.edge(e).first));
853
+ vertices.push_back(g.vertex(g.edge(e).second));
854
+ string edge = s2textformat::ToString(
855
+ vector<S2Point>{g.vertex(g.edge(e).first),
856
+ g.vertex(g.edge(e).second)});
857
+ auto ids = g.input_edge_ids(e);
858
+ actual.push_back(make_pair(
859
+ edge, vector<InputEdgeId>(ids.begin(), ids.end())));
860
+ }
861
+ // This comparison doesn't consider multiplicity, but that's fine.
862
+ string missing, extra;
863
+ for (const auto& p : expected_) {
864
+ if (std::count(actual.begin(), actual.end(), p) > 0) continue;
865
+ missing += ToString(p);
866
+ }
867
+ for (const auto& p : actual) {
868
+ if (std::count(expected_.begin(), expected_.end(), p) > 0) continue;
869
+ extra += ToString(p);
870
+ }
871
+ if (!missing.empty() || !extra.empty()) {
872
+ error->Init(INPUT_EDGE_ID_MISMATCH, "Missing:\n%sExtra:\n%s\n",
873
+ missing.c_str(), extra.c_str());
874
+ }
875
+ }
876
+
877
+ void TestInputEdgeIds(
878
+ const vector<const char*>& input_strs, const EdgeInputEdgeIds& expected,
879
+ const GraphOptions& graph_options, const S2Builder::Options& options) {
880
+ S2Builder builder(options);
881
+ builder.StartLayer(make_unique<InputEdgeIdCheckingLayer>(expected,
882
+ graph_options));
883
+ for (auto input_str : input_strs) {
884
+ builder.AddPolyline(*MakePolylineOrDie(input_str));
885
+ }
886
+ S2Error error;
887
+ ASSERT_TRUE(builder.Build(&error)) << error;
888
+ }
889
+
890
+ TEST(S2Builder, InputEdgeIdAssignment) {
891
+ // Check that input edge ids are assigned in order.
892
+ TestInputEdgeIds({"0:0, 0:1, 0:2"}, {{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}}},
893
+ GraphOptions(), S2Builder::Options());
894
+ }
895
+
896
+ TEST(S2Builder, UndirectedSiblingsDontHaveInputEdgeIds) {
897
+ // Check that the siblings of undirected edges do not have InputEdgeIds.
898
+ GraphOptions graph_options;
899
+ graph_options.set_edge_type(EdgeType::UNDIRECTED);
900
+ TestInputEdgeIds({"0:0, 0:1, 0:2"},
901
+ {{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}},
902
+ {"0:1, 0:0", {}}, {"0:2, 0:1", {}}},
903
+ graph_options, S2Builder::Options());
904
+ }
905
+
906
+ TEST(S2Builder, CreatedSiblingsDontHaveInputEdgeIds) {
907
+ // Check that edges created by SiblingPairs::CREATE do not have
908
+ // InputEdgeIds.
909
+ GraphOptions graph_options;
910
+ graph_options.set_sibling_pairs(GraphOptions::SiblingPairs::CREATE);
911
+ TestInputEdgeIds({"0:0, 0:1, 0:2"}, {{"0:0, 0:1", {0}}, {"0:1, 0:2", {1}}},
912
+ GraphOptions(), S2Builder::Options());
913
+ }
914
+
915
+ TEST(S2Builder, EdgeMergingDirected) {
916
+ // Tests that input edge ids are merged when directed edges are merged.
917
+ GraphOptions graph_options;
918
+ graph_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
919
+ TestInputEdgeIds({"0:0, 0:1", "0:0, 0:1"}, {{"0:0, 0:1", {0, 1}}},
920
+ graph_options, S2Builder::Options());
921
+ }
922
+
923
+ TEST(S2Builder, EdgeMergingUndirected) {
924
+ // Tests that input edge ids are merged when undirected edges are merged.
925
+ GraphOptions graph_options;
926
+ graph_options.set_duplicate_edges(GraphOptions::DuplicateEdges::MERGE);
927
+ graph_options.set_sibling_pairs(GraphOptions::SiblingPairs::KEEP);
928
+ TestInputEdgeIds({"0:0, 0:1, 0:2", "0:0, 0:1", "0:2, 0:1"}, {
929
+ {"0:0, 0:1", {0, 2}}, {"0:1, 0:2", {1}}, {"0:2, 0:1", {3}}
930
+ }, graph_options, S2Builder::Options());
931
+ }
932
+
933
+ TEST(S2Builder, SimplifyDegenerateEdgeMergingEasy) {
934
+ // Check that when an input edge is snapped to a chain that includes
935
+ // degenerate edges, and the edge chain is simplified, that the InputEdgeIds
936
+ // attached to those degenerate edges are transferred to the simplified
937
+ // edge. For example (using integers for vertices), an edge chain 1->2,
938
+ // 2->2, 2->3 that is simplified to 1->3 should get the InputEdgeIds
939
+ // associated with all three original edges. (This ensures that the labels
940
+ // attached to those edges are also transferred.)
941
+ //
942
+ // This also tests that degenerate edges at the start and end of the
943
+ // simplified chain are *not* merged. (It's up to the output layer to
944
+ // decide what to do with these edges. The only reason we merge degenerate
945
+ // edges in the interior of the interior of the simplified edge is because
946
+ // those edges are being removed from the graph.)
947
+ GraphOptions graph_options;
948
+ graph_options.set_degenerate_edges(GraphOptions::DegenerateEdges::KEEP);
949
+ S2Builder::Options options(IntLatLngSnapFunction(0));
950
+ options.set_simplify_edge_chains(true);
951
+ TestInputEdgeIds({"0:0, 0:0.1, 0:1.1, 0:1, 0:0.9, 0:2, 0:2.1"}, {
952
+ {"0:0, 0:0", {0}}, {"0:0, 0:2", {1, 2, 3, 4}}, {"0:2, 0:2", {5}}
953
+ }, graph_options, options);
954
+ }
955
+
956
+ TEST(S2Builder, SimplifyDegenerateEdgeMergingHard) {
957
+ // This is a harder version of the test above. Now there are several edge
958
+ // chains that overlap each other in both directions, and several degenerate
959
+ // edges at that middle vertex. This tests that if exactly one edge chain
960
+ // contains a degenerate edge in input edge order (e.g., the input order was
961
+ // AB, BB, BC), then the degenerate edge is assigned to that edge chain.
962
+ // Otherwise the edge is assigned to an arbitrary chain.
963
+ GraphOptions graph_options; // Default options keep everything.
964
+ S2Builder::Options options(IntLatLngSnapFunction(0));
965
+ options.set_simplify_edge_chains(true);
966
+ vector<const char*> input {
967
+ "0:1, 0:1.1", "0:0, 0:1, 0:2", // Degenerate edge defined before chain
968
+ "0:0, 0:0.9, 0:1, 0:1.1, 0:2", // Degenerate edge defined in chain
969
+ "0:2, 0:1, 0:0.9, 0:0", // Defined in chain, chain reversed
970
+ "0:2, 0:1, 0:0", "0:1.1, 0:1", "0:1, 0:1.1", // Defined after chain
971
+ };
972
+ EdgeInputEdgeIds expected {
973
+ {"0:0, 0:2", {0, 1, 2}}, {"0:0, 0:2", {3, 4, 5, 6}},
974
+ {"0:2, 0:0", {7, 8, 9}}, {"0:2, 0:0", {10, 11, 12, 13}}
975
+ };
976
+ TestInputEdgeIds(input, expected, graph_options, options);
977
+
978
+ // Now try the same test with undirected edges. This results in four more
979
+ // simplified edges that are not labelled with any input edge ids.
980
+ expected.insert(expected.end(), {
981
+ {"0:0, 0:2", {}}, {"0:0, 0:2", {}}, {"0:2, 0:0", {}}, {"0:2, 0:0", {}}
982
+ });
983
+ graph_options.set_edge_type(EdgeType::UNDIRECTED);
984
+ TestInputEdgeIds(input, expected, graph_options, options);
985
+ }
986
+
987
+ TEST(S2Builder, SimplifyDegenerateEdgeMergingMultipleLayers) {
988
+ // Check that degenerate edges are assigned to an edge in the correct layer
989
+ // when multiple edge chains in different layers are simplified in the same
990
+ // way (i.e., yielding a set of identical or reversed edges in different
991
+ // layers).
992
+ GraphOptions graph_options; // Default options keep everything.
993
+ S2Builder::Options options(IntLatLngSnapFunction(0));
994
+ options.set_simplify_edge_chains(true);
995
+
996
+ // Note below that the edge chains in different layers have different vertex
997
+ // locations, different number of interior vertices, different degenerate
998
+ // edges, etc, and yet they can all be simplified together.
999
+ vector<vector<const char*>> input { {
1000
+ "0.1:5, 0:5.2", "0.1:0, 0:9.9", // Defined before chain
1001
+ "0:10.1, 0:0.1", "0:3.1, 0:2.9", // Defined after chain
1002
+ }, {
1003
+ "0.1:3, 0:3.2", "-0.1:0, 0:4.1, 0:9.9", // Defined before chain
1004
+ "0.1:9.9, 0:7, 0.1:6.9, 0.1:0.2", // Defined inside chain
1005
+ }, {
1006
+ "0.2:0.3, 0.1:6, 0:5.9, 0.1:10.2", // Defined inside chain
1007
+ "0.1:0.1, 0:9.8", "0.1:2, 0:2.1", // Defined after chain
1008
+ }
1009
+ };
1010
+ vector<EdgeInputEdgeIds> expected { {
1011
+ {"0:0, 0:10", {0, 1}}, {"0:10, 0:0", {2, 3}}
1012
+ }, {
1013
+ {"0:0, 0:10", {4, 5, 6}}, {"0:10, 0:0", {7, 8, 9}}
1014
+ }, {
1015
+ {"0:0, 0:10", {10, 11, 12}}, {"0:0, 0:10", {13, 14}}
1016
+ }
1017
+ };
1018
+ S2Builder builder(options);
1019
+ for (int i = 0; i < input.size(); ++i) {
1020
+ builder.StartLayer(make_unique<InputEdgeIdCheckingLayer>(expected[i],
1021
+ graph_options));
1022
+ for (auto input_str : input[i]) {
1023
+ builder.AddPolyline(*MakePolylineOrDie(input_str));
1024
+ }
1025
+ }
1026
+ S2Error error;
1027
+ ASSERT_TRUE(builder.Build(&error)) << error;
1028
+ }
1029
+
1030
+ TEST(S2Builder, HighPrecisionPredicates) {
1031
+ // To produce correct output in this example, the algorithm needs fall back
1032
+ // to high precision predicates when the output of the normal predicates is
1033
+ // uncertain.
1034
+ vector<S2Point> vertices = {
1035
+ {-0.1053119128423491, -0.80522217121852213, 0.58354661852470235},
1036
+ {-0.10531192039134209, -0.80522217309706012, 0.58354661457019508},
1037
+ {-0.10531192039116592, -0.80522217309701472, 0.58354661457028933},
1038
+ };
1039
+ S2Polyline input(vertices);
1040
+ S1Angle snap_radius = S2::kIntersectionMergeRadius;
1041
+ S2Builder::Options options((IdentitySnapFunction(snap_radius)));
1042
+ options.set_idempotent(false);
1043
+ S2Builder builder(options);
1044
+ S2Polyline output;
1045
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output));
1046
+ builder.ForceVertex(S2Point(
1047
+ -0.10531192039134191, -0.80522217309705857, 0.58354661457019719));
1048
+ builder.AddPolyline(input);
1049
+ S2Error error;
1050
+ EXPECT_TRUE(builder.Build(&error)) << error;
1051
+ }
1052
+
1053
+ // Chooses a random S2Point that is often near the intersection of one of the
1054
+ // coodinates planes or coordinate axes with the unit sphere. (It is possible
1055
+ // to represent very small perturbations near such points.)
1056
+ S2Point ChoosePoint() {
1057
+ S2Point x = S2Testing::RandomPoint();
1058
+ for (int i = 0; i < 3; ++i) {
1059
+ if (S2Testing::rnd.OneIn(3)) {
1060
+ x[i] *= pow(1e-50, S2Testing::rnd.RandDouble());
1061
+ }
1062
+ }
1063
+ return x.Normalize();
1064
+ }
1065
+
1066
+ TEST(S2Builder, HighPrecisionStressTest) {
1067
+ // This test constructs many small, random inputs such that the output is
1068
+ // likely to be inconsistent unless high-precision predicates are used.
1069
+
1070
+ S1Angle snap_radius = S2::kIntersectionMergeRadius;
1071
+ // Some S2Builder calculations use an upper bound that takes into account
1072
+ // S1ChordAngle errors. We sometimes try perturbing points by very close to
1073
+ // that distance in an attempt to expose errors.
1074
+ S1ChordAngle ca(snap_radius);
1075
+ S1Angle snap_radius_with_error = ca.PlusError(
1076
+ ca.GetS1AngleConstructorMaxError() +
1077
+ S2::GetUpdateMinDistanceMaxError(ca)).ToAngle();
1078
+
1079
+ auto& rnd = S2Testing::rnd;
1080
+ int non_degenerate = 0;
1081
+ const int kIters = 8000 * FLAGS_iteration_multiplier;
1082
+ for (int iter = 0; iter < kIters; ++iter) {
1083
+ // TODO(ericv): This test fails with a random seed of 96. Change this
1084
+ // back to "iter + 1" once all the exact predicates are implemented.
1085
+ rnd.Reset(iter + 1); // Easier to reproduce a specific case.
1086
+
1087
+ // We construct a nearly degenerate triangle where one of the edges is
1088
+ // sometimes very short. Then we add a forced vertex somewhere near the
1089
+ // shortest edge. Then after snapping, we check that (1) the edges still
1090
+ // form a loop, and (2) if the loop is non-degenerate, then it has the
1091
+ // same orientation as the original triangle.
1092
+ //
1093
+ // v1 is located randomly. (v0,v1) is the longest of the three edges.
1094
+ // v2 is located along (v0,v1) but is perturbed by up to 2 * snap_radius.
1095
+ S2Point v1 = ChoosePoint(), v0_dir = ChoosePoint();
1096
+ double d0 = pow(1e-16, rnd.RandDouble());
1097
+ S2Point v0 = S2::InterpolateAtDistance(S1Angle::Radians(d0), v1, v0_dir);
1098
+ double d2 = 0.5 * d0 * pow(1e-16, pow(rnd.RandDouble(), 2));
1099
+ S2Point v2 = S2::InterpolateAtDistance(S1Angle::Radians(d2), v1, v0_dir);
1100
+ v2 = S2Testing::SamplePoint(S2Cap(v2, 2 * snap_radius));
1101
+ // Vary the edge directions by randomly swapping v0 and v2.
1102
+ if (rnd.OneIn(2)) std::swap(v0, v2);
1103
+
1104
+ // The forced vertex (v3) is either located near the (v1, v2) edge.
1105
+ // We perturb it either in a random direction from v1 or v2, or
1106
+ // perpendicular to (v1, v2) starting from an interior edge point.
1107
+ S1Angle d3 = rnd.OneIn(2) ? snap_radius : snap_radius_with_error;
1108
+ if (rnd.OneIn(3)) d3 = 1.5 * rnd.RandDouble() * d3;
1109
+ S2Point v3;
1110
+ if (rnd.OneIn(5)) {
1111
+ v3 = rnd.OneIn(2) ? v1 : v2;
1112
+ v3 = S2::InterpolateAtDistance(d3, v3, ChoosePoint());
1113
+ } else {
1114
+ v3 = S2::Interpolate(pow(1e-16, rnd.RandDouble()), v1, v2);
1115
+ v3 = S2::InterpolateAtDistance(d3, v3, v1.CrossProd(v2).Normalize());
1116
+ }
1117
+ S2Builder::Options options((IdentitySnapFunction(snap_radius)));
1118
+ options.set_idempotent(false);
1119
+ S2Builder builder(options);
1120
+ S2Polygon output;
1121
+ output.set_s2debug_override(S2Debug::DISABLE);
1122
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
1123
+ builder.ForceVertex(v3);
1124
+ builder.AddEdge(v0, v1);
1125
+ builder.AddEdge(v1, v2);
1126
+ builder.AddEdge(v2, v0);
1127
+ S2Error error;
1128
+ if (!builder.Build(&error)) {
1129
+ S2_LOG(ERROR) << "d0=" << d0 << ", d2=" << d2 << ", d3=" << d3;
1130
+ }
1131
+ if (error.ok() && !output.is_empty()) {
1132
+ EXPECT_EQ(1, output.num_loops());
1133
+ if (output.num_loops() == 1) {
1134
+ EXPECT_TRUE(output.IsValid());
1135
+ EXPECT_EQ(s2pred::Sign(v0, v1, v2) > 0, output.loop(0)->IsNormalized())
1136
+ << "d0=" << d0 << ", d2=" << d2 << ", d3=" << d3;
1137
+ ++non_degenerate;
1138
+ }
1139
+ }
1140
+ }
1141
+ S2_LOG(INFO) << non_degenerate << " non-degenerate out of " << kIters;
1142
+ EXPECT_GE(non_degenerate, kIters / 10);
1143
+ }
1144
+
1145
+ TEST(S2Builder, SelfIntersectionStressTest) {
1146
+ const int kIters = 50 * FLAGS_iteration_multiplier;
1147
+ for (int iter = 0; iter < kIters; ++iter) {
1148
+ S2Testing::rnd.Reset(iter + 1); // Easier to reproduce a specific case.
1149
+ CycleTimer timer;
1150
+ timer.Start();
1151
+
1152
+ // The minimum radius is about 36cm on the Earth's surface. The
1153
+ // performance is reduced for radii much smaller than this because
1154
+ // S2ShapeIndex only indexes regions down to about 1cm across.
1155
+ S2Cap cap = S2Testing::GetRandomCap(1e-14, 1e-2);
1156
+
1157
+ S2Builder::Options options;
1158
+ options.set_split_crossing_edges(true);
1159
+ if (S2Testing::rnd.OneIn(2)) {
1160
+ S1Angle radius = cap.GetRadius();
1161
+ int min_exp = IntLatLngSnapFunction::ExponentForMaxSnapRadius(radius);
1162
+ int exponent = min(IntLatLngSnapFunction::kMaxExponent,
1163
+ min_exp + S2Testing::rnd.Uniform(5));
1164
+ options.set_snap_function(IntLatLngSnapFunction(exponent));
1165
+ }
1166
+ S2Builder builder(options);
1167
+
1168
+ // Note that the number of intersections (and the running time) is
1169
+ // quadratic in the number of vertices. With 200 input vertices, the
1170
+ // output consists of about 2300 loops and 9000 vertices.
1171
+ S2Polygon output;
1172
+ builder.StartLayer(make_unique<S2PolygonLayer>(
1173
+ &output, S2PolygonLayer::Options(EdgeType::UNDIRECTED)));
1174
+ vector<S2Point> vertices(google::DEBUG_MODE ? 50 : 200);
1175
+ for (S2Point& vertex : vertices) {
1176
+ vertex = S2Testing::SamplePoint(cap);
1177
+ }
1178
+ vertices.back() = vertices.front();
1179
+ S2Polyline input(vertices);
1180
+ builder.AddPolyline(input);
1181
+ S2Error error;
1182
+ EXPECT_TRUE(builder.Build(&error)) << error;
1183
+ EXPECT_FALSE(output.FindValidationError(&error)) << error;
1184
+ if (iter == -1) {
1185
+ cout << "S2Polyline: " << s2textformat::ToString(input) << endl;
1186
+ cout << "S2Polygon: " << s2textformat::ToString(output) << endl;
1187
+ }
1188
+ if (iter < 50) {
1189
+ printf("iter=%4d: ms=%4" PRId64 ", radius=%8.3g, loops=%d, vertices=%d\n",
1190
+ iter, static_cast<int64_t>(timer.GetInMs()),
1191
+ cap.GetRadius().radians(), output.num_loops(),
1192
+ output.num_vertices());
1193
+ }
1194
+ }
1195
+ }
1196
+
1197
+ TEST(S2Builder, FractalStressTest) {
1198
+ const int kIters = (google::DEBUG_MODE ? 100 : 1000) * FLAGS_iteration_multiplier;
1199
+ for (int iter = 0; iter < kIters; ++iter) {
1200
+ S2Testing::rnd.Reset(iter + 1); // Easier to reproduce a specific case.
1201
+ S2Testing::Fractal fractal;
1202
+ fractal.SetLevelForApproxMaxEdges(google::DEBUG_MODE ? 800 : 12800);
1203
+ fractal.SetLevelForApproxMinEdges(12);
1204
+ fractal.set_fractal_dimension(1.5 + 0.5 * S2Testing::rnd.RandDouble());
1205
+ S2Polygon input(fractal.MakeLoop(S2Testing::GetRandomFrame(),
1206
+ S1Angle::Degrees(20)));
1207
+ S2Builder::Options options;
1208
+ if (S2Testing::rnd.OneIn(3)) {
1209
+ int exponent = S2Testing::rnd.Uniform(11);
1210
+ options.set_snap_function(IntLatLngSnapFunction(exponent));
1211
+ } else if (S2Testing::rnd.OneIn(2)) {
1212
+ int level = S2Testing::rnd.Uniform(20);
1213
+ options.set_snap_function(S2CellIdSnapFunction(level));
1214
+ } else {
1215
+ options.set_snap_function(IdentitySnapFunction(
1216
+ S1Angle::Degrees(10 * pow(1e-4, S2Testing::rnd.RandDouble()))));
1217
+ }
1218
+ S2Builder builder(options);
1219
+ S2Polygon output;
1220
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
1221
+ builder.AddPolygon(input);
1222
+ S2Error error;
1223
+ EXPECT_TRUE(builder.Build(&error)) << error;
1224
+ EXPECT_FALSE(output.FindValidationError(&error)) << error;
1225
+ if (iter == -1) {
1226
+ cout << "S2Polygon: " << s2textformat::ToString(input) << endl;
1227
+ cout << "S2Polygon: " << s2textformat::ToString(output) << endl;
1228
+ }
1229
+ if (iter < 50) {
1230
+ printf("iter=%4d: in_vertices=%d, out_vertices=%d\n",
1231
+ iter, input.num_vertices(), output.num_vertices());
1232
+ }
1233
+ }
1234
+ }
1235
+
1236
+ void TestSnappingWithForcedVertices(const char* input_str,
1237
+ S1Angle snap_radius,
1238
+ const char* vertices_str,
1239
+ const char* expected_str) {
1240
+ S2Builder builder{S2Builder::Options{IdentitySnapFunction(snap_radius)}};
1241
+ vector<S2Point> vertices = s2textformat::ParsePoints(vertices_str);
1242
+ for (const auto& vertex : vertices) {
1243
+ builder.ForceVertex(vertex);
1244
+ }
1245
+ S2Polyline output;
1246
+ builder.StartLayer(make_unique<S2PolylineLayer>(&output));
1247
+ builder.AddPolyline(*MakePolylineOrDie(input_str));
1248
+ S2Error error;
1249
+ EXPECT_TRUE(builder.Build(&error)) << error;
1250
+ EXPECT_EQ(expected_str, s2textformat::ToString(output));
1251
+ }
1252
+
1253
+ TEST(S2Builder, AdjacentCoverageIntervalsSpanMoreThan90Degrees) {
1254
+ // The test for whether one Voronoi site excludes another along a given
1255
+ // input edge boils down to a test of whether two angle intervals "a" and
1256
+ // "b" overlap. Let "ra" and "rb" be the semi-widths of the two intervals,
1257
+ // and let "d" be the angle between their centers. Then "a" contains "b" if
1258
+ // (rb + d <= ra), and "b" contains "a" if (rb - d >= ra). However the
1259
+ // actual code uses the sines of the angles, e.g. sin(rb + d) <= sin(ra).
1260
+ // This works fine most of the time, but the first condition (rb + d <= ra)
1261
+ // also needs to check that rb + d < 90 degrees. This test verifies that
1262
+ // case.
1263
+
1264
+ // The following 3 tests have d < 90, d = 90, and d > 90 degrees, but in all
1265
+ // 3 cases rb + d > 90 degrees.
1266
+ TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
1267
+ "0:0, 0:70", "0:0, 0:70");
1268
+ TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
1269
+ "0:0, 0:90", "0:0, 0:90");
1270
+ TestSnappingWithForcedVertices("0:0, 0:80", S1Angle::Degrees(60),
1271
+ "0:0, 0:110", "0:0, 0:110");
1272
+
1273
+ // This test has d = 180 degrees, i.e. the two sites project to points that
1274
+ // are 180 degrees apart along the input edge. The snapped edge doesn't
1275
+ // stay within max_edge_deviation() of the input edge, so an extra site is
1276
+ // added and it is snapped again (yielding two edges). The case we are
1277
+ // testing here is the first call to SnapEdge() before adding the site.
1278
+ TestSnappingWithForcedVertices("0:10, 0:170", S1Angle::Degrees(50),
1279
+ "47:0, 49:180", "47:0, 0:90, 49:180");
1280
+
1281
+ // This test has d = 220 degrees, i.e. when the input edge is snapped it
1282
+ // goes the "wrong way" around the sphere. Again, the snapped edge is too
1283
+ // far from the input edge so an extra site is added and it is resnapped.
1284
+ TestSnappingWithForcedVertices("0:10, 0:170", S1Angle::Degrees(70),
1285
+ "0:-20, 0:-160", "0:-20, 0:90, 0:-160");
1286
+
1287
+ // Without using forced vertices, the maximum angle between the coverage
1288
+ // interval centers is d = 300 degrees. This would use an edge 180 degrees
1289
+ // long, and then place two sites 60 degrees past either endpoint. With
1290
+ // forced vertices we can increase the snap radius to 70 degrees and get an
1291
+ // angle of up to d = 320 degrees, but the sites are only 40 degrees apart
1292
+ // (which is why it requires forced vertices). The test below is an
1293
+ // approximation of this situation with d = 319.6 degrees.
1294
+ TestSnappingWithForcedVertices("0:0.1, 0:179.9", S1Angle::Degrees(70),
1295
+ "0:-69.8, 0:-110.2",
1296
+ "0:-69.8, 0:90, 0:-110.2");
1297
+ }
1298
+
1299
+ TEST(S2Builder, OldS2PolygonBuilderBug) {
1300
+ // This is a polygon that caused the obsolete S2PolygonBuilder class to
1301
+ // generate an invalid output polygon (duplicate edges).
1302
+ unique_ptr<S2Polygon> input = MakePolygonOrDie(
1303
+ "32.2983095:72.3416582, 32.2986281:72.3423059, "
1304
+ "32.2985238:72.3423743, 32.2987176:72.3427807, "
1305
+ "32.2988174:72.3427056, 32.2991269:72.3433480, "
1306
+ "32.2991881:72.3433077, 32.2990668:72.3430462, "
1307
+ "32.2991745:72.3429778, 32.2995078:72.3436725, "
1308
+ "32.2996075:72.3436269, 32.2985465:72.3413832, "
1309
+ "32.2984558:72.3414530, 32.2988015:72.3421839, "
1310
+ "32.2991552:72.3429416, 32.2990498:72.3430073, "
1311
+ "32.2983764:72.3416059");
1312
+ ASSERT_TRUE(input->IsValid());
1313
+
1314
+ S1Angle snap_radius = S2Testing::MetersToAngle(20/0.866);
1315
+ S2Builder builder{S2Builder::Options(IdentitySnapFunction(snap_radius))};
1316
+ S2Polygon output;
1317
+ builder.StartLayer(make_unique<S2PolygonLayer>(&output));
1318
+ builder.AddPolygon(*input);
1319
+ S2Error error;
1320
+ ASSERT_TRUE(builder.Build(&error)) << error;
1321
+ EXPECT_TRUE(output.IsValid());
1322
+ unique_ptr<S2Polygon> expected = MakePolygonOrDie(
1323
+ "32.2991552:72.3429416, 32.2991881:72.3433077, 32.2996075:72.3436269; "
1324
+ "32.2988015:72.3421839, 32.2985465:72.3413832, 32.2983764:72.3416059, "
1325
+ "32.2985238:72.3423743, 32.2987176:72.3427807");
1326
+ ExpectPolygonsEqual(*expected, output);
1327
+ }
1328
+
1329
+ } // namespace