@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,3025 @@
1
+ // Copyright 2005 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
+
19
+ #include "s2/s2polygon.h"
20
+
21
+ #include <algorithm>
22
+ #include <cmath>
23
+ #include <cstdlib>
24
+ #include <limits>
25
+ #include <memory>
26
+ #include <set>
27
+ #include <string>
28
+ #include <utility>
29
+ #include <vector>
30
+
31
+ #include <gtest/gtest.h>
32
+
33
+ #include "s2/base/casts.h"
34
+ #include "s2/base/commandlineflags.h"
35
+ #include "s2/base/logging.h"
36
+ #include "s2/mutable_s2shape_index.h"
37
+ #include "s2/r1interval.h"
38
+ #include "s2/s1angle.h"
39
+ #include "s2/s2builder.h"
40
+ #include "s2/s2builderutil_s2polygon_layer.h"
41
+ #include "s2/s2builderutil_snap_functions.h"
42
+ #include "s2/s2cap.h"
43
+ #include "s2/s2cell.h"
44
+ #include "s2/s2cell_id.h"
45
+ #include "s2/s2cell_union.h"
46
+ #include "s2/s2closest_edge_query.h"
47
+ #include "s2/s2coords.h"
48
+ #include "s2/s2debug.h"
49
+ #include "s2/s2edge_crossings.h"
50
+ #include "s2/s2edge_distances.h"
51
+ #include "s2/s2error.h"
52
+ #include "s2/s2latlng.h"
53
+ #include "s2/s2loop.h"
54
+ #include "s2/s2metrics.h"
55
+ #include "s2/s2padded_cell.h"
56
+ #include "s2/s2pointutil.h"
57
+ #include "s2/s2polyline.h"
58
+ #include "s2/s2region_coverer.h"
59
+ #include "s2/s2testing.h"
60
+ #include "s2/s2text_format.h"
61
+ #include "s2/strings/serialize.h"
62
+ #include "s2/third_party/absl/base/macros.h"
63
+ #include "s2/third_party/absl/container/fixed_array.h"
64
+ #include "s2/third_party/absl/memory/memory.h"
65
+ #include "s2/third_party/absl/strings/str_cat.h"
66
+ #include "s2/util/coding/coder.h"
67
+ #include "s2/util/gtl/legacy_random_shuffle.h"
68
+ #include "s2/util/math/matrix3x3.h"
69
+
70
+ using absl::StrCat;
71
+ using absl::make_unique;
72
+ using s2builderutil::IntLatLngSnapFunction;
73
+ using s2builderutil::S2PolygonLayer;
74
+ using std::max;
75
+ using std::min;
76
+ using std::numeric_limits;
77
+ using std::swap;
78
+ using std::unique_ptr;
79
+ using std::vector;
80
+
81
+ // A set of nested loops around the point 0:0 (lat:lng).
82
+ // Every vertex of kNear0 is a vertex of kNear1.
83
+ const char kNearPoint[] = "0:0";
84
+ const string kNear0 = "-1:0, 0:1, 1:0, 0:-1;";
85
+ const string kNear1 = "-1:-1, -1:0, -1:1, 0:1, 1:1, 1:0, 1:-1, 0:-1;";
86
+ const string kNear2 = "-1:-2, -2:5, 5:-2;";
87
+ const string kNear3 = "-2:-2, -3:6, 6:-3;";
88
+ const string kNearHemi = "0:-90, -90:0, 0:90, 90:0;";
89
+
90
+ // A set of nested loops around the point 0:180 (lat:lng).
91
+ // Every vertex of kFar0 and kFar2 belongs to kFar1, and all
92
+ // the loops except kFar2 are non-convex.
93
+ const string kFar0 = "0:179, 1:180, 0:-179, 2:-180;";
94
+ const string kFar1 =
95
+ "0:179, -1:179, 1:180, -1:-179, 0:-179, 3:-178, 2:-180, 3:178;";
96
+ const string kFar2 = "3:-178, 3:178, -1:179, -1:-179;";
97
+ const string kFar3 = "-3:-178, 4:-177, 4:177, -3:178, -2:179;";
98
+ const string kFarHemi = "0:-90, 60:90, -60:90;";
99
+
100
+ // A set of nested loops around the point -90:0 (lat:lng).
101
+ const string kSouthPoint = "-89.9999:0.001";
102
+ const string kSouth0a = "-90:0, -89.99:0.01, -89.99:0;";
103
+ const string kSouth0b = "-90:0, -89.99:0.03, -89.99:0.02;";
104
+ const string kSouth0c = "-90:0, -89.99:0.05, -89.99:0.04;";
105
+ const string kSouth1 = "-90:0, -89.9:0.1, -89.9:-0.1;";
106
+ const string kSouth2 = "-90:0, -89.8:0.2, -89.8:-0.2;";
107
+ const string kSouthHemi = "0:-180, 0:60, 0:-60;";
108
+
109
+ // Two different loops that surround all the Near and Far loops except
110
+ // for the hemispheres.
111
+ const string kNearFar1 = "-1:-9, -9:-9, -9:9, 9:9, 9:-9, 1:-9, "
112
+ "1:-175, 9:-175, 9:175, -9:175, -9:-175, -1:-175;";
113
+ const string kNearFar2 = "-2:15, -2:170, -8:-175, 8:-175, "
114
+ "2:170, 2:15, 8:-4, -8:-4;";
115
+
116
+ // Loops that result from intersection of other loops.
117
+ const string kFarHSouthH = "0:-180, 0:90, -60:90, 0:-90;";
118
+
119
+ // Rectangles that form a cross, with only shared vertices, no crossing edges.
120
+ // Optional holes outside the intersecting region.
121
+ const string kCross1 = "-2:1, -1:1, 1:1, 2:1, 2:-1, 1:-1, -1:-1, -2:-1;";
122
+ const string kCross1SideHole = "-1.5:0.5, -1.2:0.5, -1.2:-0.5, -1.5:-0.5;";
123
+ const string kCross2 = "1:-2, 1:-1, 1:1, 1:2, -1:2, -1:1, -1:-1, -1:-2;";
124
+ const string kCross2SideHole = "0.5:-1.5, 0.5:-1.2, -0.5:-1.2, -0.5:-1.5;";
125
+ const string kCrossCenterHole = "-0.5:0.5, 0.5:0.5, 0.5:-0.5, -0.5:-0.5;";
126
+
127
+ // Two rectangles that intersect, but no edges cross and there's always
128
+ // local containment (rather than crossing) at each shared vertex.
129
+ // In this ugly ASCII art, 1 is A+B, 2 is B+C:
130
+ // +---+---+---+
131
+ // | A | B | C |
132
+ // +---+---+---+
133
+ const string kOverlap1 = "0:1, 1:1, 2:1, 2:0, 1:0, 0:0;";
134
+ const string kOverlap1SideHole = "0.2:0.8, 0.8:0.8, 0.8:0.2, 0.2:0.2;";
135
+ const string kOverlap2 = "1:1, 2:1, 3:1, 3:0, 2:0, 1:0;";
136
+ const string kOverlap2SideHole = "2.2:0.8, 2.8:0.8, 2.8:0.2, 2.2:0.2;";
137
+ const string kOverlapCenterHole = "1.2:0.8, 1.8:0.8, 1.8:0.2, 1.2:0.2;";
138
+
139
+ // An empty polygon.
140
+ const string kEmpty = "";
141
+ // By symmetry, the intersection of the two polygons has almost half the area
142
+ // of either polygon.
143
+ const string kOverlap3 = "-10:10, 0:10, 0:-10, -10:-10, -10:0";
144
+ const string kOverlap4 = "-10:0, 10:0, 10:-10, -10:-10";
145
+
146
+ class S2PolygonTestBase : public testing::Test {
147
+ public:
148
+ S2PolygonTestBase();
149
+
150
+ protected:
151
+ // Some standard polygons to use in the tests.
152
+ const unique_ptr<const S2Polygon> empty_;
153
+ const unique_ptr<const S2Polygon> full_;
154
+ const unique_ptr<const S2Polygon> near_0_;
155
+ const unique_ptr<const S2Polygon> near_10_;
156
+ const unique_ptr<const S2Polygon> near_30_;
157
+ const unique_ptr<const S2Polygon> near_32_;
158
+ const unique_ptr<const S2Polygon> near_3210_;
159
+ const unique_ptr<const S2Polygon> near_H3210_;
160
+
161
+ const unique_ptr<const S2Polygon> far_10_;
162
+ const unique_ptr<const S2Polygon> far_21_;
163
+ const unique_ptr<const S2Polygon> far_321_;
164
+ const unique_ptr<const S2Polygon> far_H20_;
165
+ const unique_ptr<const S2Polygon> far_H3210_;
166
+
167
+ const unique_ptr<const S2Polygon> south_0ab_;
168
+ const unique_ptr<const S2Polygon> south_2_;
169
+ const unique_ptr<const S2Polygon> south_210b_;
170
+ const unique_ptr<const S2Polygon> south_H21_;
171
+ const unique_ptr<const S2Polygon> south_H20abc_;
172
+
173
+ const unique_ptr<const S2Polygon> nf1_n10_f2_s10abc_;
174
+
175
+ const unique_ptr<const S2Polygon> nf2_n2_f210_s210ab_;
176
+
177
+ const unique_ptr<const S2Polygon> f32_n0_;
178
+ const unique_ptr<const S2Polygon> n32_s0b_;
179
+
180
+ const unique_ptr<const S2Polygon> cross1_;
181
+ const unique_ptr<const S2Polygon> cross1_side_hole_;
182
+ const unique_ptr<const S2Polygon> cross1_center_hole_;
183
+ const unique_ptr<const S2Polygon> cross2_;
184
+ const unique_ptr<const S2Polygon> cross2_side_hole_;
185
+ const unique_ptr<const S2Polygon> cross2_center_hole_;
186
+
187
+ const unique_ptr<const S2Polygon> overlap1_;
188
+ const unique_ptr<const S2Polygon> overlap1_side_hole_;
189
+ const unique_ptr<const S2Polygon> overlap1_center_hole_;
190
+ const unique_ptr<const S2Polygon> overlap2_;
191
+ const unique_ptr<const S2Polygon> overlap2_side_hole_;
192
+ const unique_ptr<const S2Polygon> overlap2_center_hole_;
193
+
194
+ const unique_ptr<const S2Polygon> far_H_;
195
+ const unique_ptr<const S2Polygon> south_H_;
196
+ const unique_ptr<const S2Polygon> far_H_south_H_;
197
+ };
198
+
199
+ static bool TestEncodeDecode(const S2Polygon* src) {
200
+ Encoder encoder;
201
+ src->Encode(&encoder);
202
+ Decoder decoder(encoder.base(), encoder.length());
203
+ S2Polygon dst;
204
+ dst.Decode(&decoder);
205
+ return src->Equals(&dst);
206
+ }
207
+
208
+ static unique_ptr<S2Polygon> MakePolygon(const string& str) {
209
+ unique_ptr<S2Polygon> polygon(s2textformat::MakeVerbatimPolygon(str));
210
+
211
+ // Check that InitToSnapped() is idempotent.
212
+ S2Polygon snapped1, snapped2;
213
+ snapped1.InitToSnapped(polygon.get());
214
+ snapped2.InitToSnapped(&snapped1);
215
+ EXPECT_TRUE(snapped1.Equals(&snapped2));
216
+
217
+ // Check that Decode(Encode(x)) is the identity function.
218
+ EXPECT_TRUE(TestEncodeDecode(polygon.get()));
219
+ return polygon;
220
+ }
221
+
222
+ static void CheckContains(const string& a_str, const string& b_str) {
223
+ unique_ptr<S2Polygon> a = MakePolygon(a_str);
224
+ unique_ptr<S2Polygon> b = MakePolygon(b_str);
225
+ EXPECT_TRUE(a->Contains(b.get()));
226
+ EXPECT_TRUE(a->ApproxContains(b.get(), S1Angle::Radians(1e-15)));
227
+ EXPECT_FALSE(a->ApproxDisjoint(b.get(), S1Angle::Radians(1e-15)));
228
+ }
229
+
230
+ static void CheckContainsPoint(const string& a_str, const string& b_str) {
231
+ unique_ptr<S2Polygon> a(s2textformat::MakePolygon(a_str));
232
+ EXPECT_TRUE(a->Contains(s2textformat::MakePoint(b_str)))
233
+ << " " << a_str << " did not contain " << b_str;
234
+ }
235
+
236
+ TEST(S2Polygon, Init) {
237
+ CheckContains(kNear1, kNear0);
238
+ CheckContains(kNear2, kNear1);
239
+ CheckContains(kNear3, kNear2);
240
+ CheckContains(kNearHemi, kNear3);
241
+ CheckContains(kFar1, kFar0);
242
+ CheckContains(kFar2, kFar1);
243
+ CheckContains(kFar3, kFar2);
244
+ CheckContains(kFarHemi, kFar3);
245
+ CheckContains(kSouth1, kSouth0a);
246
+ CheckContains(kSouth1, kSouth0b);
247
+ CheckContains(kSouth1, kSouth0c);
248
+ CheckContains(kSouthHemi, kSouth2);
249
+ CheckContains(kNearFar1, kNear3);
250
+ CheckContains(kNearFar1, kFar3);
251
+ CheckContains(kNearFar2, kNear3);
252
+ CheckContains(kNearFar2, kFar3);
253
+
254
+ CheckContainsPoint(kNear0, kNearPoint);
255
+ CheckContainsPoint(kNear1, kNearPoint);
256
+ CheckContainsPoint(kNear2, kNearPoint);
257
+ CheckContainsPoint(kNear3, kNearPoint);
258
+ CheckContainsPoint(kNearHemi, kNearPoint);
259
+ CheckContainsPoint(kSouth0a, kSouthPoint);
260
+ CheckContainsPoint(kSouth1, kSouthPoint);
261
+ CheckContainsPoint(kSouth2, kSouthPoint);
262
+ CheckContainsPoint(kSouthHemi, kSouthPoint);
263
+ }
264
+
265
+ TEST(S2Polygon, OverlapFractions) {
266
+ unique_ptr<S2Polygon> a(MakePolygon(kEmpty));
267
+ unique_ptr<S2Polygon> b(MakePolygon(kEmpty));
268
+ auto result = S2Polygon::GetOverlapFractions(a.get(), b.get());
269
+ EXPECT_DOUBLE_EQ(1.0, result.first);
270
+ EXPECT_DOUBLE_EQ(1.0, result.second);
271
+
272
+ b = MakePolygon(kOverlap3);
273
+ result = S2Polygon::GetOverlapFractions(a.get(), b.get());
274
+ EXPECT_DOUBLE_EQ(1.0, result.first);
275
+ EXPECT_DOUBLE_EQ(0.0, result.second);
276
+
277
+ a = MakePolygon(kOverlap4);
278
+ result = S2Polygon::GetOverlapFractions(a.get(), b.get());
279
+ EXPECT_NEAR(0.5, result.first, 1e-14);
280
+ EXPECT_NEAR(0.5, result.second, 1e-14);
281
+ }
282
+
283
+ TEST(S2Polygon, OriginNearPole) {
284
+ // S2Polygon operations are more efficient if S2::Origin() is near a pole.
285
+ // (Loops that contain a pole tend to have very loose bounding boxes because
286
+ // they span the full longitude range. S2Polygon canonicalizes all loops so
287
+ // that they don't contain S2::Origin(), thus by placing S2::Origin() near a
288
+ // pole we minimize the number of canonical loops which contain that pole.)
289
+ EXPECT_GE(S2LatLng::Latitude(S2::Origin()).degrees(), 80);
290
+ }
291
+
292
+ S2PolygonTestBase::S2PolygonTestBase()
293
+ : empty_(new S2Polygon()),
294
+ full_(MakePolygon("full")),
295
+ near_0_(MakePolygon(kNear0)),
296
+ near_10_(MakePolygon(kNear0 + kNear1)),
297
+ near_30_(MakePolygon(kNear3 + kNear0)),
298
+ near_32_(MakePolygon(kNear2 + kNear3)),
299
+ near_3210_(MakePolygon(kNear0 + kNear2 + kNear3 + kNear1)),
300
+ near_H3210_(MakePolygon(kNear0 + kNear2 + kNear3 + kNearHemi + kNear1)),
301
+
302
+ far_10_(MakePolygon(kFar0 + kFar1)),
303
+ far_21_(MakePolygon(kFar2 + kFar1)),
304
+ far_321_(MakePolygon(kFar2 + kFar3 + kFar1)),
305
+ far_H20_(MakePolygon(kFar2 + kFarHemi + kFar0)),
306
+ far_H3210_(MakePolygon(kFar2 + kFarHemi + kFar0 + kFar1 + kFar3)),
307
+
308
+ south_0ab_(MakePolygon(kSouth0a + kSouth0b)),
309
+ south_2_(MakePolygon(kSouth2)),
310
+ south_210b_(MakePolygon(kSouth2 + kSouth0b + kSouth1)),
311
+ south_H21_(MakePolygon(kSouth2 + kSouthHemi + kSouth1)),
312
+ south_H20abc_(MakePolygon(kSouth2 + kSouth0b + kSouthHemi +
313
+ kSouth0a + kSouth0c)),
314
+
315
+ nf1_n10_f2_s10abc_(MakePolygon(kSouth0c + kFar2 + kNear1 + kNearFar1 +
316
+ kNear0 + kSouth1 + kSouth0b + kSouth0a)),
317
+
318
+ nf2_n2_f210_s210ab_(MakePolygon(kFar2 + kSouth0a + kFar1 + kSouth1 + kFar0 +
319
+ kSouth0b + kNearFar2 + kSouth2 + kNear2)),
320
+
321
+ f32_n0_(MakePolygon(kFar2 + kNear0 + kFar3)),
322
+ n32_s0b_(MakePolygon(kNear3 + kSouth0b + kNear2)),
323
+
324
+ cross1_(MakePolygon(kCross1)),
325
+ cross1_side_hole_(MakePolygon(kCross1 + kCross1SideHole)),
326
+ cross1_center_hole_(MakePolygon(kCross1 + kCrossCenterHole)),
327
+ cross2_(MakePolygon(kCross2)),
328
+ cross2_side_hole_(MakePolygon(kCross2 + kCross2SideHole)),
329
+ cross2_center_hole_(MakePolygon(kCross2 + kCrossCenterHole)),
330
+
331
+ overlap1_(MakePolygon(kOverlap1)),
332
+ overlap1_side_hole_(MakePolygon(kOverlap1 + kOverlap1SideHole)),
333
+ overlap1_center_hole_(MakePolygon(kOverlap1 + kOverlapCenterHole)),
334
+ overlap2_(MakePolygon(kOverlap2)),
335
+ overlap2_side_hole_(MakePolygon(kOverlap2 + kOverlap2SideHole)),
336
+ overlap2_center_hole_(MakePolygon(kOverlap2 + kOverlapCenterHole)),
337
+
338
+ far_H_(MakePolygon(kFarHemi)),
339
+ south_H_(MakePolygon(kSouthHemi)),
340
+ far_H_south_H_(MakePolygon(kFarHSouthH)) {
341
+ }
342
+
343
+ static void CheckEqual(const S2Polygon& a, const S2Polygon& b,
344
+ S1Angle max_error = S1Angle::Zero()) {
345
+ if (a.BoundaryApproxEquals(b, max_error)) return;
346
+ S2Builder builder{S2Builder::Options()};
347
+ S2Polygon a2, b2;
348
+ builder.StartLayer(make_unique<S2PolygonLayer>(&a2));
349
+ builder.AddPolygon(a);
350
+ S2Error error;
351
+ ASSERT_TRUE(builder.Build(&error)) << error;
352
+ builder.StartLayer(make_unique<S2PolygonLayer>(&b2));
353
+ builder.AddPolygon(b);
354
+ ASSERT_TRUE(builder.Build(&error)) << error;
355
+ EXPECT_TRUE(a2.BoundaryApproxEquals(b2, max_error))
356
+ << "\na: " << s2textformat::ToString(a)
357
+ << "\nb: " << s2textformat::ToString(b)
358
+ << "\na2: " << s2textformat::ToString(a2)
359
+ << "\nb2: " << s2textformat::ToString(b2);
360
+ }
361
+
362
+ static void CheckComplementary(const S2Polygon& a, const S2Polygon& b) {
363
+ S2Polygon b1;
364
+ b1.InitToComplement(&b);
365
+ CheckEqual(a, b1);
366
+ }
367
+
368
+ TEST(S2Polygon, TestApproxContainsAndDisjoint) {
369
+ // We repeatedly choose a random cell id and intersect its bounding polygon
370
+ // "A" with the bounding polygon "B" of one its child cells. The result may
371
+ // not be contained by either A or B, because the vertices of B near the
372
+ // edge midpoints of A may be slightly outside A, and even when the crossing
373
+ // edges are intersected, the intersection point may also be slightly
374
+ // outside A and/or B.
375
+ //
376
+ // We repeat the test many times and expect that some fraction of the exact
377
+ // tests should fail, while all of the approximate test should succeed.
378
+ const int kIters = 1000;
379
+ int exact_contains = 0, exact_disjoint = 0;
380
+ S2Testing::rnd.Reset(FLAGS_s2_random_seed);
381
+ for (int iter = 0; iter < kIters; ++iter) {
382
+ S2CellId id = S2Testing::GetRandomCellId(10);
383
+ S2Polygon parent_polygon((S2Cell(id)));
384
+ S2Polygon child_polygon(S2Cell(id.child(0)));
385
+
386
+ // Get the intersection. There is no guarantee that the intersection will
387
+ // be contained by A or B. Similarly, the intersection may slightly
388
+ // overlap an adjacent disjoint polygon C.
389
+ S2Polygon intersection;
390
+ intersection.InitToIntersection(&parent_polygon, &child_polygon);
391
+ if (parent_polygon.Contains(&intersection)) {
392
+ ++exact_contains;
393
+ }
394
+ EXPECT_TRUE(parent_polygon.ApproxContains(
395
+ &intersection, S2::kIntersectionMergeRadius));
396
+
397
+ S2Polygon adjacent_polygon(S2Cell(id.child(1)));
398
+ if (!adjacent_polygon.Intersects(&intersection)) {
399
+ ++exact_disjoint;
400
+ }
401
+ EXPECT_TRUE(adjacent_polygon.ApproxDisjoint(
402
+ &intersection, S2::kIntersectionMergeRadius));
403
+ }
404
+ // All of the approximate results are true, so we check that at least some
405
+ // of the exact results are false in order to make sure that this test
406
+ // actually tests something.
407
+ //
408
+ // There are two vertices in each child cell that have a 50% chance of being
409
+ // outside the parent cell. When a vertex is outside, an intersection point
410
+ // is computed near that vertex that also has a 50% chance of being
411
+ // outside. Snapping used to choose one of these vertices at random, but
412
+ // currently the vertex whose S2CellId is smaller is always chosen. For the
413
+ // exact containment test, it turns out that one vertex is adjacent to a
414
+ // lower-numbered S2CellId and the other is adjacent to a higher-numbered
415
+ // S2CellId, which means that one vertex will always be chosen outside the
416
+ // parent if possible, and the other will always be chosen inside if
417
+ // possible. This works out to an expectation that 0.5 * 0.75 = 37.5% of
418
+ // the exact containment tests will succeed.
419
+ //
420
+ // For the exact disjoint test, there is one shared vertex that might be
421
+ // replaced by a computed intersection point. The shared vertex is inside
422
+ // the parent 50% of the time. Otherwise there is a 50% chance that the
423
+ // intersection point will not be chosen for snapping because it has a
424
+ // higher S2CellId that the shared vertex, and otherwise there is still a
425
+ // 50% chance that intersection point is on the side of the shared edge that
426
+ // results in no intersection. This works out to an expectation that
427
+ // (1 - 0.5 * 0.5 * 0.5) = 87.5% of the exact disjoint tests will succeed.
428
+ EXPECT_LT(exact_contains, 0.40 * kIters); // about 37.5% succeed
429
+ EXPECT_LT(exact_disjoint, 0.90 * kIters); // about 87.5% succeed
430
+ }
431
+
432
+ // Given a pair of polygons where A contains B, check that various identities
433
+ // involving union, intersection, and difference operations hold true.
434
+ static void TestOneNestedPair(const S2Polygon& a, const S2Polygon& b) {
435
+ EXPECT_TRUE(a.Contains(&b));
436
+ EXPECT_EQ(!b.is_empty(), a.Intersects(&b));
437
+ EXPECT_EQ(!b.is_empty(), b.Intersects(&a));
438
+
439
+ S2Polygon c, d, e, f, g;
440
+ c.InitToUnion(&a, &b);
441
+ CheckEqual(c, a);
442
+
443
+ d.InitToIntersection(&a, &b);
444
+ CheckEqual(d, b);
445
+
446
+ e.InitToDifference(&b, &a);
447
+ EXPECT_TRUE(e.is_empty());
448
+
449
+ f.InitToDifference(&a, &b);
450
+ g.InitToSymmetricDifference(&a, &b);
451
+ CheckEqual(f, g);
452
+ }
453
+
454
+ // Given a pair of disjoint polygons A and B, check that various identities
455
+ // involving union, intersection, and difference operations hold true.
456
+ static void TestOneDisjointPair(const S2Polygon& a, const S2Polygon& b) {
457
+ EXPECT_FALSE(a.Intersects(&b));
458
+ EXPECT_FALSE(b.Intersects(&a));
459
+ EXPECT_EQ(b.is_empty(), a.Contains(&b));
460
+ EXPECT_EQ(a.is_empty(), b.Contains(&a));
461
+
462
+ S2Polygon ab, c, d, e, f, g;
463
+ S2Builder builder{S2Builder::Options()};
464
+ builder.StartLayer(make_unique<S2PolygonLayer>(&ab));
465
+ builder.AddPolygon(a);
466
+ builder.AddPolygon(b);
467
+ S2Error error;
468
+ ASSERT_TRUE(builder.Build(&error)) << error;
469
+
470
+ c.InitToUnion(&a, &b);
471
+ CheckEqual(c, ab);
472
+
473
+ d.InitToIntersection(&a, &b);
474
+ EXPECT_TRUE(d.is_empty());
475
+
476
+ e.InitToDifference(&a, &b);
477
+ CheckEqual(e, a);
478
+
479
+ f.InitToDifference(&b, &a);
480
+ CheckEqual(f, b);
481
+
482
+ g.InitToSymmetricDifference(&a, &b);
483
+ CheckEqual(g, ab);
484
+ }
485
+
486
+ // Given polygons A and B whose union covers the sphere, check that various
487
+ // identities involving union, intersection, and difference hold true.
488
+ static void TestOneCoveringPair(const S2Polygon& a, const S2Polygon& b) {
489
+ EXPECT_EQ(a.is_full(), a.Contains(&b));
490
+ EXPECT_EQ(b.is_full(), b.Contains(&a));
491
+
492
+ S2Polygon c, d, e, f;
493
+ c.InitToUnion(&a, &b);
494
+ EXPECT_TRUE(c.is_full());
495
+ }
496
+
497
+ // Given polygons A and B such that both A and its complement intersect both B
498
+ // and its complement, check that various identities involving union,
499
+ // intersection, and difference hold true.
500
+ static void TestOneOverlappingPair(const S2Polygon& a, const S2Polygon& b) {
501
+ EXPECT_FALSE(a.Contains(&b));
502
+ EXPECT_FALSE(b.Contains(&a));
503
+ EXPECT_TRUE(a.Intersects(&b));
504
+
505
+ S2Polygon c, d, e, f, g, h;
506
+ c.InitToUnion(&a, &b);
507
+ EXPECT_FALSE(c.is_full());
508
+
509
+ d.InitToIntersection(&a, &b);
510
+ EXPECT_FALSE(d.is_empty());
511
+
512
+ e.InitToDifference(&b, &a);
513
+ EXPECT_FALSE(e.is_empty());
514
+
515
+ f.InitToDifference(&a, &b);
516
+ g.InitToUnion(&e, &f);
517
+ h.InitToSymmetricDifference(&a, &b);
518
+ CheckEqual(g, h);
519
+ }
520
+
521
+ // Given a pair of polygons where A contains B, test various identities
522
+ // involving A, B, and their complements.
523
+ static void TestNestedPair(const S2Polygon& a, const S2Polygon& b) {
524
+ S2Polygon a1, b1;
525
+ a1.InitToComplement(&a);
526
+ b1.InitToComplement(&b);
527
+
528
+ TestOneNestedPair(a, b);
529
+ TestOneNestedPair(b1, a1);
530
+ TestOneDisjointPair(a1, b);
531
+ TestOneCoveringPair(a, b1);
532
+ }
533
+
534
+ // Given a pair of disjoint polygons A and B, test various identities
535
+ // involving A, B, and their complements.
536
+ static void TestDisjointPair(const S2Polygon& a, const S2Polygon& b) {
537
+ S2Polygon a1, b1;
538
+ a1.InitToComplement(&a);
539
+ b1.InitToComplement(&b);
540
+
541
+ TestOneDisjointPair(a, b);
542
+ TestOneCoveringPair(a1, b1);
543
+ TestOneNestedPair(a1, b);
544
+ TestOneNestedPair(b1, a);
545
+ }
546
+
547
+ // Given polygons A and B such that both A and its complement intersect both B
548
+ // and its complement, test various identities involving these four polygons.
549
+ static void TestOverlappingPair(const S2Polygon& a, const S2Polygon& b) {
550
+ S2Polygon a1, b1;
551
+ a1.InitToComplement(&a);
552
+ b1.InitToComplement(&b);
553
+
554
+ TestOneOverlappingPair(a, b);
555
+ TestOneOverlappingPair(a1, b1);
556
+ TestOneOverlappingPair(a1, b);
557
+ TestOneOverlappingPair(a, b1);
558
+ }
559
+
560
+ // "a1" is the complement of "a", and "b1" is the complement of "b".
561
+ static void TestOneComplementPair(const S2Polygon& a, const S2Polygon& a1,
562
+ const S2Polygon& b, const S2Polygon& b1) {
563
+ // Check DeMorgan's Law and that subtraction is the same as intersection
564
+ // with the complement. This function is called multiple times in order to
565
+ // test the various combinations of complements.
566
+
567
+ S2Polygon a1_or_b, a_and_b1, a_minus_b;
568
+ a_and_b1.InitToIntersection(&a, &b1);
569
+ a1_or_b.InitToUnion(&a1, &b);
570
+ a_minus_b.InitToDifference(&a, &b);
571
+
572
+ CheckComplementary(a1_or_b, a_and_b1);
573
+ CheckEqual(a_minus_b, a_and_b1);
574
+ }
575
+
576
+ // Test identities that should hold for any pair of polygons A, B and their
577
+ // complements.
578
+ static void TestComplements(const S2Polygon& a, const S2Polygon& b) {
579
+ S2Polygon a1, b1;
580
+ a1.InitToComplement(&a);
581
+ b1.InitToComplement(&b);
582
+
583
+ TestOneComplementPair(a, a1, b, b1);
584
+ TestOneComplementPair(a1, a, b, b1);
585
+ TestOneComplementPair(a, a1, b1, b);
586
+ TestOneComplementPair(a1, a, b1, b);
587
+
588
+ // There is a lot of redundancy if we do this test for each complementary
589
+ // pair, so we just do it once instead.
590
+ S2Polygon a_xor_b1, a1_xor_b;
591
+ a_xor_b1.InitToSymmetricDifference(&a, &b1);
592
+ a1_xor_b.InitToSymmetricDifference(&a1, &b);
593
+ CheckEqual(a_xor_b1, a1_xor_b);
594
+ }
595
+
596
+ static void TestDestructiveUnion(const S2Polygon& a, const S2Polygon& b) {
597
+ S2Polygon c;
598
+ c.InitToUnion(&a, &b);
599
+ vector<unique_ptr<S2Polygon>> polygons;
600
+ polygons.emplace_back(a.Clone());
601
+ polygons.emplace_back(b.Clone());
602
+ unique_ptr<S2Polygon> c_destructive =
603
+ S2Polygon::DestructiveUnion(std::move(polygons));
604
+ CheckEqual(c, *c_destructive);
605
+ }
606
+
607
+ static void TestRelationWithDesc(const S2Polygon& a, const S2Polygon& b,
608
+ bool contains, bool contained,
609
+ bool intersects, const char* description) {
610
+ SCOPED_TRACE(description);
611
+ EXPECT_EQ(contains, a.Contains(&b));
612
+ EXPECT_EQ(contained, b.Contains(&a));
613
+ EXPECT_EQ(intersects, a.Intersects(&b));
614
+ if (contains) TestNestedPair(a, b);
615
+ if (contained) TestNestedPair(b, a);
616
+ if (!intersects) TestDisjointPair(a, b);
617
+ if (intersects && !(contains | contained)) {
618
+ TestOverlappingPair(a, b); // See TestOverlappingPair for definition
619
+ }
620
+ TestDestructiveUnion(a, b);
621
+ TestComplements(a, b);
622
+ }
623
+
624
+ TEST_F(S2PolygonTestBase, Relations) {
625
+ #define TestRelation(a, b, contains, contained, intersects) \
626
+ TestRelationWithDesc(a, b, contains, contained, intersects, \
627
+ "args " #a ", " #b)
628
+
629
+ TestRelation(*near_10_, *empty_, true, false, false);
630
+ TestRelation(*near_10_, *near_10_, true, true, true);
631
+ TestRelation(*full_, *near_10_, true, false, true);
632
+ TestRelation(*near_10_, *near_30_, false, true, true);
633
+ TestRelation(*near_10_, *near_32_, false, false, false);
634
+ TestRelation(*near_10_, *near_3210_, false, true, true);
635
+ TestRelation(*near_10_, *near_H3210_, false, false, false);
636
+ TestRelation(*near_30_, *near_32_, true, false, true);
637
+ TestRelation(*near_30_, *near_3210_, true, false, true);
638
+ TestRelation(*near_30_, *near_H3210_, false, false, true);
639
+ TestRelation(*near_32_, *near_3210_, false, true, true);
640
+ TestRelation(*near_32_, *near_H3210_, false, false, false);
641
+ TestRelation(*near_3210_, *near_H3210_, false, false, false);
642
+
643
+ TestRelation(*far_10_, *far_21_, false, false, false);
644
+ TestRelation(*far_10_, *far_321_, false, true, true);
645
+ TestRelation(*far_10_, *far_H20_, false, false, false);
646
+ TestRelation(*far_10_, *far_H3210_, false, false, false);
647
+ TestRelation(*far_21_, *far_321_, false, false, false);
648
+ TestRelation(*far_21_, *far_H20_, false, false, false);
649
+ TestRelation(*far_21_, *far_H3210_, false, true, true);
650
+ TestRelation(*far_321_, *far_H20_, false, false, true);
651
+ TestRelation(*far_321_, *far_H3210_, false, false, true);
652
+ TestRelation(*far_H20_, *far_H3210_, false, false, true);
653
+
654
+ TestRelation(*south_0ab_, *south_2_, false, true, true);
655
+ TestRelation(*south_0ab_, *south_210b_, false, false, true);
656
+ TestRelation(*south_0ab_, *south_H21_, false, true, true);
657
+ TestRelation(*south_0ab_, *south_H20abc_, false, true, true);
658
+ TestRelation(*south_2_, *south_210b_, true, false, true);
659
+ TestRelation(*south_2_, *south_H21_, false, false, true);
660
+ TestRelation(*south_2_, *south_H20abc_, false, false, true);
661
+ TestRelation(*south_210b_, *south_H21_, false, false, true);
662
+ TestRelation(*south_210b_, *south_H20abc_, false, false, true);
663
+ TestRelation(*south_H21_, *south_H20abc_, true, false, true);
664
+
665
+ TestRelation(*nf1_n10_f2_s10abc_, *nf2_n2_f210_s210ab_, false, false, true);
666
+ TestRelation(*nf1_n10_f2_s10abc_, *near_32_, true, false, true);
667
+ TestRelation(*nf1_n10_f2_s10abc_, *far_21_, false, false, false);
668
+ TestRelation(*nf1_n10_f2_s10abc_, *south_0ab_, false, false, false);
669
+ TestRelation(*nf1_n10_f2_s10abc_, *f32_n0_, true, false, true);
670
+
671
+ TestRelation(*nf2_n2_f210_s210ab_, *near_10_, false, false, false);
672
+ TestRelation(*nf2_n2_f210_s210ab_, *far_10_, true, false, true);
673
+ TestRelation(*nf2_n2_f210_s210ab_, *south_210b_, true, false, true);
674
+ TestRelation(*nf2_n2_f210_s210ab_, *south_0ab_, true, false, true);
675
+ TestRelation(*nf2_n2_f210_s210ab_, *n32_s0b_, true, false, true);
676
+
677
+ TestRelation(*cross1_, *cross2_, false, false, true);
678
+ TestRelation(*cross1_side_hole_, *cross2_, false, false, true);
679
+ TestRelation(*cross1_center_hole_, *cross2_, false, false, true);
680
+ TestRelation(*cross1_, *cross2_side_hole_, false, false, true);
681
+ TestRelation(*cross1_, *cross2_center_hole_, false, false, true);
682
+ TestRelation(*cross1_side_hole_, *cross2_side_hole_, false, false, true);
683
+ TestRelation(*cross1_center_hole_, *cross2_side_hole_, false, false, true);
684
+ TestRelation(*cross1_side_hole_, *cross2_center_hole_, false, false, true);
685
+ TestRelation(*cross1_center_hole_, *cross2_center_hole_, false, false, true);
686
+
687
+ // These cases_, when either polygon has a hole, test a different code path
688
+ // from the other cases.
689
+ TestRelation(*overlap1_, *overlap2_, false, false, true);
690
+ TestRelation(*overlap1_side_hole_, *overlap2_, false, false, true);
691
+ TestRelation(*overlap1_center_hole_, *overlap2_, false, false, true);
692
+ TestRelation(*overlap1_, *overlap2_side_hole_, false, false, true);
693
+ TestRelation(*overlap1_, *overlap2_center_hole_, false, false, true);
694
+ TestRelation(*overlap1_side_hole_, *overlap2_side_hole_, false, false, true);
695
+ TestRelation(*overlap1_center_hole_, *overlap2_side_hole_,
696
+ false, false, true);
697
+ TestRelation(*overlap1_side_hole_, *overlap2_center_hole_,
698
+ false, false, true);
699
+ TestRelation(*overlap1_center_hole_, *overlap2_center_hole_,
700
+ false, false, true);
701
+ #undef TestRelation
702
+ }
703
+
704
+ TEST_F(S2PolygonTestBase, EmptyAndFull) {
705
+ EXPECT_TRUE(empty_->is_empty());
706
+ EXPECT_FALSE(full_->is_empty());
707
+ EXPECT_FALSE(empty_->is_full());
708
+ EXPECT_TRUE(full_->is_full());
709
+
710
+ TestNestedPair(*empty_, *empty_);
711
+ TestNestedPair(*full_, *empty_);
712
+ TestNestedPair(*full_, *full_);
713
+ }
714
+
715
+ struct TestCase {
716
+ const char* a;
717
+ const char* b;
718
+ const char* a_and_b;
719
+ const char* a_or_b;
720
+ const char* a_minus_b;
721
+ const char* a_xor_b;
722
+ };
723
+
724
+ TestCase test_cases[] = {
725
+ // Two triangles that share an edge.
726
+ { "4:2, 3:1, 3:3;",
727
+
728
+ "3:1, 2:2, 3:3;",
729
+
730
+ "", // and
731
+
732
+ "4:2, 3:1, 2:2, 3:3;", // or
733
+
734
+ "4:2, 3:1, 3:3;", // minus
735
+
736
+ "4:2, 3:1, 2:2, 3:3;" // xor
737
+ },
738
+
739
+ // Two vertical bars and a horizontal bar connecting them.
740
+ { "0:0, 0:2, 3:2, 3:0; 0:3, 0:5, 3:5, 3:3;",
741
+
742
+ "1:1, 1:4, 2:4, 2:1;",
743
+
744
+ "1:1, 1:2, 2:2, 2:1; 1:3, 1:4, 2:4, 2:3;", // and
745
+
746
+ "0:0, 0:2, 1:2, 1:3, 0:3, 0:5, 3:5, 3:3, 2:3, 2:2, 3:2, 3:0;", // or
747
+
748
+ "0:0, 0:2, 1:2, 1:1, 2:1, 2:2, 3:2, 3:0; " // minus
749
+ "0:3, 0:5, 3:5, 3:3, 2:3, 2:4, 1:4, 1:3;",
750
+
751
+ "0:0, 0:2, 1:2, 1:1, 2:1, 2:2, 3:2, 3:0; " // xor
752
+ "0:3, 0:5, 3:5, 3:3, 2:3, 2:4, 1:4, 1:3; "
753
+ "1:2, 1:3, 2:3, 2:2"
754
+ },
755
+
756
+ // Two vertical bars and two horizontal bars.
757
+ { "1:88, 1:93, 2:93, 2:88; -1:88, -1:93, 0:93, 0:88;",
758
+
759
+ "-2:89, -2:90, 3:90, 3:89; -2:91, -2:92, 3:92, 3:91;",
760
+
761
+ "1:89, 1:90, 2:90, 2:89; 1:91, 1:92, 2:92, 2:91; " // and
762
+ "-1:89, -1:90, 0:90, 0:89; -1:91, -1:92, 0:92, 0:91;",
763
+
764
+ "-1:88, -1:89, -2:89, -2:90, -1:90, -1:91, -2:91, -2:92, -1:92, " // or
765
+ "-1:93, 0:93, 0:92, 1:92, 1:93, 2:93, 2:92, 3:92, 3:91, 2:91, "
766
+ "2:90, 3:90, 3:89, 2:89, 2:88, 1:88, 1:89, 0:89, 0:88; "
767
+ "0:90, 0:91, 1:91, 1:90;",
768
+
769
+ "1:88, 1:89, 2:89, 2:88; 1:90, 1:91, 2:91, 2:90; " // minus
770
+ "1:92, 1:93, 2:93, 2:92; -1:88, -1:89, 0:89, 0:88; "
771
+ "-1:90, -1:91, 0:91, 0:90; -1:92, -1:93, 0:93, 0:92;",
772
+
773
+ "1:88, 1:89, 2:89, 2:88; -1:88, -1:89, 0:89, 0:88; " // xor
774
+ "1:90, 1:91, 2:91, 2:90; -1:90, -1:91, 0:91, 0:90; "
775
+ "1:92, 1:93, 2:93, 2:92; -1:92, -1:93, 0:93, 0:92; "
776
+ "-2:89, -2:90, -1:90, -1:89; -2:91, -2:92, -1:92, -1:91; "
777
+ "0:89, 0:90, 1:90, 1:89; 0:91, 0:92, 1:92, 1:91; "
778
+ "2:89, 2:90, 3:90, 3:89; 2:91, 2:92, 3:92, 3:91;"
779
+ },
780
+
781
+ // Two interlocking square doughnuts.
782
+ { "-1:-93, -1:-89, 3:-89, 3:-93; 0:-92, 0:-90, 2:-90, 2:-92;",
783
+
784
+ "-3:-91, -3:-87, 1:-87, 1:-91; -2:-90, -2:-88, 0:-88, 0:-90;",
785
+
786
+ "-1:-91, -1:-90, 0:-90, 0:-91; 0:-90, 0:-89, 1:-89, 1:-90;", // and
787
+
788
+ "-1:-93, -1:-91, -3:-91, -3:-87, 1:-87, 1:-89, 3:-89, 3:-93; " // or
789
+ "0:-92, 0:-91, 1:-91, 1:-90, 2:-90, 2:-92; "
790
+ "-2:-90, -2:-88, 0:-88, 0:-89, -1:-89, -1:-90;",
791
+
792
+ "-1:-93, -1:-91, 0:-91, 0:-92, 2:-92, 2:-90, " // minus
793
+ "1:-90, 1:-89, 3:-89, 3:-93; "
794
+ "-1:-90, -1:-89, 0:-89, 0:-90;",
795
+
796
+ "-1:-93, -1:-91, 0:-91, 0:-92, 2:-92, 2:-90, " // xor
797
+ "1:-90, 1:-89, 3:-89, 3:-93; "
798
+ "-3:-91, -3:-87, 1:-87, 1:-89, 0:-89, 0:-88, "
799
+ "-2:-88, -2:-90, -1:-90, -1:-91; "
800
+ "-1:-90, -1:-89, 0:-89, 0:-90; "
801
+ "1:-91, 0:-91, 0:-90, 1:-90;"
802
+ },
803
+
804
+ // An incredibly thin triangle intersecting a square, such that the two
805
+ // intersection points of the triangle with the square are identical.
806
+ // This results in a degenerate loop that needs to be handled correctly.
807
+ { "10:44, 10:46, 12:46, 12:44;",
808
+
809
+ "11:45, 89:45.00000000000001, 90:45;",
810
+
811
+ "", // Empty intersection!
812
+
813
+ // Original square with extra vertex, and triangle disappears (due to
814
+ // default vertex_merge_radius of S2::kIntersectionMergeRadius).
815
+ "10:44, 10:46, 12:46, 12:45.001774937, 12:44;", // or
816
+
817
+ "10:44, 10:46, 12:46, 12:45.001774937, 12:44;", // minus
818
+
819
+ "10:44, 10:46, 12:46, 12:45.001774937, 12:44;", // xor
820
+ },
821
+ };
822
+
823
+ TEST_F(S2PolygonTestBase, Operations) {
824
+ S2Polygon far_south;
825
+ far_south.InitToIntersection(far_H_.get(), south_H_.get());
826
+ CheckEqual(far_south, *far_H_south_H_, S1Angle::Radians(1e-15));
827
+
828
+ int i = 0;
829
+ for (const TestCase& test : test_cases) {
830
+ SCOPED_TRACE(StrCat("Polygon operation test case ", i++));
831
+ unique_ptr<S2Polygon> a(MakePolygon(test.a));
832
+ unique_ptr<S2Polygon> b(MakePolygon(test.b));
833
+ unique_ptr<S2Polygon> expected_a_and_b(MakePolygon(test.a_and_b));
834
+ unique_ptr<S2Polygon> expected_a_or_b(MakePolygon(test.a_or_b));
835
+ unique_ptr<S2Polygon> expected_a_minus_b(MakePolygon(test.a_minus_b));
836
+ unique_ptr<S2Polygon> expected_a_xor_b(MakePolygon(test.a_xor_b));
837
+
838
+ // The intersections in the "expected" data were computed in lat-lng
839
+ // space, while the actual intersections are computed using geodesics.
840
+ // The error due to this depends on the length and direction of the line
841
+ // segment being intersected, and how close the intersection is to the
842
+ // endpoints of the segment. The worst case is for a line segment between
843
+ // two points at the same latitude, where the intersection point is in the
844
+ // middle of the segment. In this case the error is approximately
845
+ // (p * t^2) / 8, where "p" is the absolute latitude in radians, "t" is
846
+ // the longitude difference in radians, and both "p" and "t" are small.
847
+ // The test cases all have small latitude and longitude differences.
848
+ // If "p" and "t" are converted to degrees, the following error bound is
849
+ // valid as long as (p * t^2 < 150).
850
+
851
+ static const S1Angle kMaxError = S1Angle::Radians(1e-4);
852
+
853
+ S2Polygon a_and_b, a_or_b, a_minus_b, a_xor_b;
854
+ a_and_b.InitToIntersection(a.get(), b.get());
855
+ CheckEqual(a_and_b, *expected_a_and_b, kMaxError);
856
+ a_or_b.InitToUnion(a.get(), b.get());
857
+ CheckEqual(a_or_b, *expected_a_or_b, kMaxError);
858
+ TestDestructiveUnion(*a, *b);
859
+ a_minus_b.InitToDifference(a.get(), b.get());
860
+ CheckEqual(a_minus_b, *expected_a_minus_b, kMaxError);
861
+ a_xor_b.InitToSymmetricDifference(a.get(), b.get());
862
+ CheckEqual(a_xor_b, *expected_a_xor_b, kMaxError);
863
+ }
864
+ }
865
+
866
+ TEST(S2Polygon, IntersectionSnapFunction) {
867
+ // This tests that an intersection point is rounded to the nearest allowable
868
+ // vertex position (using E0 coordinates, i.e. integer lat/lng values).
869
+ unique_ptr<S2Polygon> a = MakePolygon("0:0, 0:10, 1:10, 1:0");
870
+ unique_ptr<S2Polygon> b = MakePolygon("0:0, 0:10, 3:0");
871
+ unique_ptr<S2Polygon> expected = MakePolygon("0:0, 0:10, 1:7, 1:0");
872
+ S2Polygon actual;
873
+ actual.InitToIntersection(*a, *b, IntLatLngSnapFunction(0)); // E0 coords
874
+ CheckEqual(*expected, actual);
875
+ }
876
+
877
+ TEST(S2Polygon, IntersectionPreservesLoopOrder) {
878
+ unique_ptr<S2Polygon> a = MakePolygon("0:0, 0:10, 10:10, 10:0");
879
+ unique_ptr<S2Polygon> b = MakePolygon("1:1, 1:9, 9:5; 2:2, 2:8, 8:5");
880
+ S2Polygon actual;
881
+ actual.InitToIntersection(a.get(), b.get());
882
+ EXPECT_EQ(s2textformat::ToString(*b), s2textformat::ToString(actual));
883
+ }
884
+
885
+ // Verifies that S2Polygon does not destroy or replace pointers to S2Loop, so
886
+ // caller can rely on using raw pointers.
887
+ TEST(S2Polygon, LoopPointers) {
888
+ vector<unique_ptr<S2Loop>> loops;
889
+ loops.emplace_back(s2textformat::MakeLoop("4:4, 4:6, 6:6, 6:4"));
890
+ loops.emplace_back(s2textformat::MakeLoop("3:3, 3:7, 7:7, 7:3"));
891
+ loops.emplace_back(s2textformat::MakeLoop("2:2, 2:8, 8:8, 8:2"));
892
+ loops.emplace_back(s2textformat::MakeLoop("1:1, 1:9, 9:9, 9:1"));
893
+ loops.emplace_back(s2textformat::MakeLoop("10:10, 15:15, 20:10"));
894
+ loops.emplace_back(s2textformat::MakeLoop("-1:-1, -9:-1, -9:-9, -1:-9"));
895
+ loops.emplace_back(s2textformat::MakeLoop("-5:-5, -6:-5, -6:-6, -5:-6"));
896
+
897
+ std::set<const S2Loop*> loops_raw_ptrs;
898
+ for (auto& loop : loops) {
899
+ loops_raw_ptrs.insert(loop.get());
900
+ }
901
+ S2Polygon polygon(std::move(loops));
902
+
903
+ // Check that loop pointers didn't change (but could've gotten reordered).
904
+ EXPECT_EQ(loops_raw_ptrs.size(), polygon.num_loops());
905
+ for (int i = 0; i < polygon.num_loops(); i++) {
906
+ EXPECT_EQ(1, loops_raw_ptrs.count(polygon.loop(i))) << "loop " << i;
907
+ }
908
+ }
909
+
910
+ static vector<unique_ptr<S2Loop>> MakeLoops(
911
+ const vector<vector<S2Point>>& loop_vertices) {
912
+ vector<unique_ptr<S2Loop>> result;
913
+ for (const auto& vertices : loop_vertices) {
914
+ result.emplace_back(new S2Loop(vertices));
915
+ S2Error error;
916
+ EXPECT_FALSE(result.back()->FindValidationError(&error))
917
+ << "Loop " << result.size() - 1 << ": " << error;
918
+ }
919
+ return result;
920
+ }
921
+
922
+ // The "Bug" tests are regression tests from previous versions of the algorithm.
923
+ TEST(S2Polygon, Bug1) {
924
+ vector<vector<S2Point>> a_vertices = {
925
+ {
926
+ {-0.10531193335759943, -0.80522214810955617, 0.58354664670985534},
927
+ {-0.10531194840431297, -0.80522215192439039, 0.58354663873039425},
928
+ {-0.10531192794033867, -0.80522217497559767, 0.58354661061568747},
929
+ {-0.10531191284235047, -0.80522217121852058, 0.58354661852470402}
930
+ },
931
+ };
932
+ vector<vector<S2Point>> b_vertices = {
933
+ {
934
+ {-0.10531174240075937, -0.80522236320875284, 0.58354638436119843},
935
+ {-0.1053119128423491, -0.80522217121852213, 0.58354661852470235},
936
+ {-0.10531192039134209, -0.80522217309706012, 0.58354661457019508}, // A
937
+ {-0.10531191288915481, -0.80522217116640804, 0.5835466185881667}, // B
938
+ {-0.10531191288915592, -0.8052221711664066, 0.58354661858816803}, // B
939
+ {-0.10531192039151964, -0.80522217309710431, 0.58354661457010204}, // A
940
+ {-0.10531192794033779, -0.80522217497559878, 0.58354661061568636},
941
+ {-0.1053117575499668, -0.80522236690813498, 0.58354637652254981},
942
+ },
943
+ };
944
+ S2Polygon a(MakeLoops(a_vertices));
945
+ S2Polygon b(MakeLoops(b_vertices));
946
+ S2Polygon c;
947
+ c.InitToUnion(&a, &b);
948
+ // Given edges do not form loops (indegree != outdegree)
949
+ EXPECT_FALSE(c.is_empty())
950
+ << "\nS2Polygon: " << s2textformat::ToString(a)
951
+ << "\nS2Polygon: " << s2textformat::ToString(b);
952
+ }
953
+
954
+ TEST(S2Polygon, Bug2) {
955
+ vector<vector<S2Point>> a_vertices = {
956
+ {
957
+ {-0.10618951389689163, -0.80546461394606728, 0.58305277875939732},
958
+ {-0.10618904764039243, -0.8054645437464607, 0.58305296065497536},
959
+ {-0.10618862643748632, -0.80546451917975415, 0.58305307130470341},
960
+ {-0.10617606798507535, -0.80544758470051458, 0.58307875187433833},
961
+ },
962
+ };
963
+ vector<vector<S2Point>> b_vertices = {
964
+ {
965
+ {-0.10618668131028208, -0.80544613076731553, 0.58307882755616247},
966
+ {-0.10618910658843225, -0.80546454998744921, 0.58305294129732887},
967
+ {-0.10618904764039225, -0.80546454374646081, 0.58305296065497536},
968
+ {-0.10618898834264634, -0.80546453817003949, 0.58305297915823251},
969
+ },
970
+ };
971
+ S2Polygon a(MakeLoops(a_vertices));
972
+ S2Polygon b(MakeLoops(b_vertices));
973
+ S2Polygon c;
974
+ c.InitToUnion(&a, &b);
975
+ // Given edges do not form loops (indegree != outdegree)
976
+ EXPECT_FALSE(c.is_empty())
977
+ << "\nS2Polygon: " << s2textformat::ToString(a)
978
+ << "\nS2Polygon: " << s2textformat::ToString(b);
979
+ }
980
+
981
+ TEST(S2Polygon, Bug3) {
982
+ vector<vector<S2Point>> a_vertices = {
983
+ {
984
+ {-0.10703494861068318, -0.80542232562508131, 0.58295659972299307},
985
+ {-0.10703494998722708, -0.80542232255642865, 0.58295660370995028},
986
+ {-0.10703495367938694, -0.80542232008675829, 0.58295660644418046},
987
+ {-0.10703495869785147, -0.80542231887781635, 0.58295660719304865},
988
+ {-0.10703496369792719, -0.80542231925353791, 0.58295660575589636},
989
+ {-0.10703496733984781, -0.80542232111324863, 0.58295660251780734},
990
+ {-0.10703496864776367, -0.80542232395864055, 0.58295659834642488},
991
+ {-0.10703496727121976, -0.80542232702729322, 0.58295659435946767},
992
+ {-0.10703496357905991, -0.80542232949696357, 0.5829565916252375},
993
+ {-0.10703495856059538, -0.80542233070590552, 0.58295659087636931},
994
+ {-0.10703495356051966, -0.80542233033018396, 0.58295659231352159},
995
+ {-0.10703494991859903, -0.80542232847047324, 0.58295659555161061},
996
+ },
997
+ };
998
+ vector<vector<S2Point>> b_vertices = {
999
+ {
1000
+ {-0.10703494861068762, -0.80542232562508098, 0.58295659972299274},
1001
+ {-0.10703494998723152, -0.80542232255642832, 0.58295660370994995},
1002
+ {-0.10703495367939138, -0.80542232008675796, 0.58295660644418013},
1003
+ {-0.10703495869785591, -0.80542231887781601, 0.58295660719304832},
1004
+ {-0.10703496369793163, -0.80542231925353758, 0.58295660575589603},
1005
+ {-0.10703496733985225, -0.8054223211132483, 0.58295660251780701},
1006
+ {-0.10703496864776811, -0.80542232395864022, 0.58295659834642455},
1007
+ {-0.1070349672712242, -0.80542232702729288, 0.58295659435946734},
1008
+ {-0.10703496357906438, -0.80542232949696346, 0.58295659162523727},
1009
+ {-0.10703495856059982, -0.80542233070590519, 0.58295659087636897},
1010
+ {-0.1070349535605241, -0.80542233033018362, 0.58295659231352126},
1011
+ {-0.10703494991860348, -0.8054223284704729, 0.58295659555161028},
1012
+ },
1013
+ };
1014
+ S2Polygon a(MakeLoops(a_vertices));
1015
+ S2Polygon b(MakeLoops(b_vertices));
1016
+ S2Polygon c;
1017
+ c.InitToUnion(&a, &b);
1018
+ // Given edges do not form loops (indegree != outdegree)
1019
+ EXPECT_FALSE(c.is_empty())
1020
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1021
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1022
+ }
1023
+
1024
+ TEST(S2Polygon, Bug4) {
1025
+ vector<vector<S2Point>> a_vertices = {
1026
+ {
1027
+ {-0.10667065556339718, -0.80657502337947207, 0.58142764201754193},
1028
+ {-0.10667064691895933, -0.80657502457251051, 0.58142764194845853},
1029
+ {-0.10667064691930939, -0.80657502457246333, 0.58142764194845975},
1030
+ {-0.10667065556339746, -0.80657502337947395, 0.5814276420175396},
1031
+ {-0.10667077559567185, -0.80657589269604968, 0.58142641405029793},
1032
+ {-0.10667077059539463, -0.80657589232162286, 0.58142641548708696},
1033
+ {-0.10667063827452879, -0.80657502576554818, 0.58142764187937435},
1034
+ {-0.10667063169531328, -0.80657498170361974, 0.58142770421053058},
1035
+ {-0.10667064898418178, -0.8065749793175444, 0.58142770434869739},
1036
+ },
1037
+ {
1038
+ {-0.10667064691897719, -0.80657502457250896, 0.58142764194845697},
1039
+ {-0.10667063827452879, -0.80657502576554818, 0.58142764187937435},
1040
+ {-0.10667064691861985, -0.80657502457255736, 0.58142764194845586},
1041
+ },
1042
+ };
1043
+ vector<vector<S2Point>> b_vertices = {
1044
+ {
1045
+ {-0.10667064691896312, -0.80657502457251107, 0.58142764194845697},
1046
+ {-0.10667064691896297, -0.80657502457251007, 0.58142764194845853},
1047
+ {-0.10667064033974753, -0.80657498051058207, 0.58142770427961399},
1048
+ {-0.10667064076268165, -0.80657498045444342, 0.58142770427989865},
1049
+ {-0.10667051785242875, -0.80657409963649807, 0.58142894872603923},
1050
+ {-0.1066707756642685, -0.80657588679775971, 0.58142642222003538},
1051
+ },
1052
+ };
1053
+ S2Polygon a(MakeLoops(a_vertices));
1054
+ S2Polygon b(MakeLoops(b_vertices));
1055
+ S2Polygon c;
1056
+ c.InitToUnion(&a, &b);
1057
+ // Loop 1: Edge 1 crosses edge 3
1058
+ EXPECT_FALSE(c.is_empty())
1059
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1060
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1061
+ }
1062
+
1063
+ TEST(S2Polygon, Bug5) {
1064
+ vector<vector<S2Point>> a_vertices = {
1065
+ {
1066
+ {-0.10574444273627338, -0.80816264611829447, 0.57938868667714882},
1067
+ {-0.10574444845633162, -0.80816268110163325, 0.57938863683652475},
1068
+ {-0.10574444825833453, -0.80816268112970524, 0.57938863683350494},
1069
+ {-0.10574444253827629, -0.80816264614636646, 0.57938868667412902},
1070
+ {-0.10574408792844124, -0.80816047738475361, 0.57939177648757634},
1071
+ {-0.10574408812643833, -0.80816047735668162, 0.57939177649059592},
1072
+ },
1073
+ };
1074
+ vector<vector<S2Point>> b_vertices = {
1075
+ {
1076
+ {-0.1057440881264381, -0.80816047735668017, 0.57939177649059825},
1077
+ {-0.10574408802743954, -0.80816047737071606, 0.57939177648908835},
1078
+ {-0.10574408812649677, -0.8081604773570521, 0.57939177649006868},
1079
+ {-0.10574408812649701, -0.80816047735705354, 0.57939177649006646},
1080
+ {-0.10574408802703171, -0.80816047737077379, 0.57939177648908202},
1081
+ {-0.10574408792844098, -0.80816047738475194, 0.57939177648757834},
1082
+ {-0.10574408792838257, -0.80816047738438168, 0.5793917764881058},
1083
+ {-0.1057440879283823, -0.80816047738438002, 0.57939177648810791},
1084
+ {-0.10574407993470979, -0.80816042849578984, 0.57939184613891748},
1085
+ {-0.10574408013270691, -0.80816042846771807, 0.57939184614193739},
1086
+ },
1087
+ };
1088
+ S2Polygon a(MakeLoops(a_vertices));
1089
+ S2Polygon b(MakeLoops(b_vertices));
1090
+ S2Polygon c;
1091
+ c.InitToUnion(&a, &b);
1092
+ // Loop 0 edge 8 crosses loop 1 edge 0
1093
+ EXPECT_FALSE(c.is_empty())
1094
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1095
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1096
+ }
1097
+
1098
+ TEST(S2Polygon, Bug6) {
1099
+ vector<vector<S2Point>> a_vertices = {
1100
+ {
1101
+ {-0.10618849949725141, -0.80552159562437586, 0.58297423747304822},
1102
+ {-0.10618849959636036, -0.80552159561106063, 0.58297423747339361},
1103
+ {-0.10618849949722192, -0.80552159562415893, 0.5829742374733532},
1104
+ {-0.10618834540082922, -0.80552043435619214, 0.58297587011440333},
1105
+ {-0.10618834559910612, -0.80552043432999554, 0.58297587011448437},
1106
+ {-0.10618849969546933, -0.80552159559774539, 0.58297423747373922},
1107
+ {-0.10618849969546955, -0.80552159559774716, 0.582974237473737},
1108
+ {-0.10618849969549882, -0.80552159559796233, 0.58297423747343424},
1109
+ {-0.10618849959710704, -0.80552159561096182, 0.58297423747339394},
1110
+ {-0.10618849949725161, -0.80552159562437742, 0.58297423747304589},
1111
+ },
1112
+ };
1113
+ vector<vector<S2Point>> b_vertices = {
1114
+ {
1115
+ {-0.10618856154870562, -0.80552206324314812, 0.58297358004005528},
1116
+ {-0.10618849949722212, -0.80552159562416048, 0.58297423747335086},
1117
+ {-0.10618849969549901, -0.80552159559796388, 0.58297423747343191},
1118
+ {-0.10618856174698249, -0.8055220632169513, 0.58297358004013622},
1119
+ {-0.10618857104277038, -0.80552213326985989, 0.58297348155149287},
1120
+ {-0.10618857084449349, -0.80552213329605649, 0.58297348155141182},
1121
+ },
1122
+ };
1123
+ S2Polygon a(MakeLoops(a_vertices));
1124
+ S2Polygon b(MakeLoops(b_vertices));
1125
+ S2Polygon c;
1126
+ c.InitToUnion(&a, &b);
1127
+ // Loop 0 edge 0 crosses loop 1 edge 4
1128
+ EXPECT_FALSE(c.is_empty())
1129
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1130
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1131
+ }
1132
+
1133
+ TEST(S2Polygon, Bug7) {
1134
+ vector<vector<S2Point>> a_vertices = {
1135
+ {
1136
+ {-0.10651728339354898, -0.80806023027835039, 0.57938996589599123},
1137
+ {-0.10651728368541774, -0.80806023024121265, 0.57938996589412783},
1138
+ {-0.10651743884289547, -0.80806147782022508, 0.5793881973990701},
1139
+ {-0.1065172793067945, -0.80806153133252501, 0.5793881520963412},
1140
+ {-0.10651707335497011, -0.80806158532388361, 0.57938811465868356},
1141
+ {-0.10651593657771009, -0.80806167503227055, 0.57938819853274059},
1142
+ {-0.10651567693742285, -0.80806182530835402, 0.57938803667826444},
1143
+ {-0.10651496089498214, -0.80806213485510237, 0.57938773659696563},
1144
+ {-0.10651453461919227, -0.80806229235522298, 0.57938759530083062},
1145
+ {-0.10651448583749658, -0.80806230280784852, 0.57938758969074455},
1146
+ {-0.10651428153471061, -0.80806061225022852, 0.57938998503506256},
1147
+ {-0.10651428161845182, -0.8080606122395747, 0.57938998503452654},
1148
+ {-0.10651427761078044, -0.80806057978063328, 0.57939003104095654},
1149
+ {-0.10651427761077951, -0.80806057978062562, 0.57939003104096709},
1150
+ {-0.10651387099203104, -0.8080572864940091, 0.5793946988282096},
1151
+ {-0.10651387099202798, -0.80805728649398445, 0.57939469882824468},
1152
+ {-0.10651386444607201, -0.80805723347699177, 0.57939477397218053},
1153
+ {-0.10651386444607169, -0.8080572334769891, 0.57939477397218409},
1154
+ {-0.106513765993723, -0.80805643609199118, 0.57939590414857456},
1155
+ {-0.10651376671438624, -0.8080564359989727, 0.57939590414581921},
1156
+ {-0.10651368187839319, -0.80805575808078389, 0.57939686520139033},
1157
+ {-0.10651465698432123, -0.80805552598235797, 0.57939700963750851},
1158
+ {-0.1065149024434091, -0.80805548225095913, 0.57939702550292815},
1159
+ {-0.10651504788182964, -0.80805555533715756, 0.5793968968362615},
1160
+ {-0.10651511658091152, -0.80805559604710031, 0.57939682743066534},
1161
+ {-0.10651517919248171, -0.80805562751022852, 0.57939677204023521},
1162
+ {-0.10651528575974038, -0.80805561374213786, 0.57939677165077275},
1163
+ {-0.10651648823358072, -0.80805539171529139, 0.57939686023850034},
1164
+ {-0.10651666406737116, -0.80805537863686483, 0.57939684615295572},
1165
+ {-0.10651674780673852, -0.80805605121551227, 0.57939589274577097},
1166
+ {-0.10651674667750256, -0.80805605136137271, 0.57939589274994641},
1167
+ {-0.10651678418140036, -0.80805634336988752, 0.57939547860450136},
1168
+ {-0.10651680240261223, -0.80805648524178364, 0.57939527739240138},
1169
+ {-0.10651680240261237, -0.80805648524178486, 0.57939527739239993},
1170
+ },
1171
+ };
1172
+ vector<vector<S2Point>> b_vertices = {
1173
+ {
1174
+ {-0.10651727337444802, -0.80806023111043901, 0.57938996657744879},
1175
+ {-0.10651727440799089, -0.80806022882029649, 0.57938996958144073},
1176
+ {-0.10651679374955145, -0.80805648637258243, 0.57939527740611751},
1177
+ {-0.10651677552833975, -0.80805634450068775, 0.57939547861821594},
1178
+ {-0.10651673802444192, -0.80805605249217261, 0.57939589276366099},
1179
+ {-0.10651674651102909, -0.80805605138312775, 0.5793958927502102},
1180
+ {-0.10651673915225639, -0.80805605233507238, 0.57939589277542292},
1181
+ {-0.10651665541288889, -0.80805537975642383, 0.57939684618260878},
1182
+ {-0.10651667272185343, -0.80805537751730583, 0.57939684612330267},
1183
+ {-0.1065167564612207, -0.8080560500959526, 0.57939589271611924},
1184
+ {-0.1065167553320342, -0.80805605024202609, 0.57939589271998793},
1185
+ {-0.10651679283446101, -0.80805634223908773, 0.57939547859078699},
1186
+ {-0.10651681105567287, -0.80805648411098374, 0.57939527737868723},
1187
+ {-0.10651680240318392, -0.80805648524170914, 0.5793952773924006},
1188
+ {-0.10651680240261234, -0.80805648524178475, 0.57939527739239982},
1189
+ {-0.1065168110556733, -0.80805648411098718, 0.57939527737868224},
1190
+ {-0.10651729169518892, -0.80806022641135866, 0.57938996976297907},
1191
+ {-0.10651729210462238, -0.80806022661896348, 0.579389969398166},
1192
+ {-0.1065172934126499, -0.80806022944626155, 0.57938996521453356},
1193
+ {-0.10651729203606744, -0.80806023249651726, 0.57938996121349717},
1194
+ {-0.1065172883437291, -0.80806023495241674, 0.57938995846713126},
1195
+ {-0.10651728332499401, -0.80806023615590394, 0.5793899577113224},
1196
+ {-0.10651727832462815, -0.80806023578450537, 0.57938995914858893},
1197
+ {-0.10651727468247554, -0.80806023393773707, 0.57938996239381635},
1198
+ },
1199
+ {
1200
+ {-0.10651680240204828, -0.80805648524185858, 0.57939527739240082},
1201
+ {-0.10651679861449742, -0.80805648573682254, 0.57939527739840524},
1202
+ {-0.10651680240261419, -0.80805648524178353, 0.57939527739240138},
1203
+ },
1204
+ };
1205
+ S2Polygon a(MakeLoops(a_vertices));
1206
+ S2Polygon b(MakeLoops(b_vertices));
1207
+ S2Polygon c;
1208
+ c.InitToUnion(&a, &b);
1209
+ // Loop 0: Edge 33 crosses edge 35
1210
+ EXPECT_FALSE(c.is_empty())
1211
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1212
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1213
+ }
1214
+
1215
+ TEST(S2Polygon, Bug8) {
1216
+ vector<vector<S2Point>> a_vertices = {
1217
+ {
1218
+ {-0.10703872198218529, -0.80846112144645677, 0.57873424566545062},
1219
+ {-0.10703872122182066, -0.80846111957630917, 0.57873424841857957},
1220
+ {-0.10703873813385757, -0.80846111582010538, 0.57873425053786276},
1221
+ {-0.1070387388942222, -0.80846111769025297, 0.57873424778473381},
1222
+ {-0.10703873050793056, -0.80846111955286837, 0.57873424673382978},
1223
+ {-0.1070387388942227, -0.80846111769025419, 0.57873424778473193},
1224
+ {-0.10703919382477994, -0.80846223660916783, 0.57873260056976505},
1225
+ {-0.10703917691274406, -0.80846224036537406, 0.57873259845047831},
1226
+ },
1227
+ };
1228
+ vector<vector<S2Point>> b_vertices = {
1229
+ {
1230
+ {-0.10703917691274355, -0.80846224036537273, 0.57873259845047997},
1231
+ {-0.1070391853685064, -0.8084622384873289, 0.57873259951008804},
1232
+ {-0.10703919381027188, -0.80846223657409677, 0.57873260062144094},
1233
+ {-0.10703919381027233, -0.80846223657409788, 0.57873260062143939},
1234
+ {-0.10703918536876245, -0.80846223848727206, 0.57873259951012024},
1235
+ {-0.10703919382478132, -0.80846223660917116, 0.57873260056976017},
1236
+ {-0.10703957146434441, -0.80846316542623331, 0.57873123320737097},
1237
+ {-0.10703955455230836, -0.8084631691824391, 0.57873123108808489},
1238
+ },
1239
+ };
1240
+ S2Polygon a(MakeLoops(a_vertices));
1241
+ S2Polygon b(MakeLoops(b_vertices));
1242
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(a);
1243
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(b);
1244
+ S2Polygon c;
1245
+ c.InitToUnion(&a, &b);
1246
+ // Loop 1: Edge 1 crosses edge 3
1247
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(c);
1248
+ }
1249
+
1250
+ TEST(S2Polygon, Bug9) {
1251
+ vector<vector<S2Point>> a_vertices = {
1252
+ {
1253
+ {-0.10639937100501309, -0.80810205676564995, 0.57935329437301375},
1254
+ {-0.10639937101137514, -0.80810205688156922, 0.57935329421015713},
1255
+ {-0.10639937101137305, -0.80810205688156944, 0.57935329421015713},
1256
+ {-0.106399371005011, -0.80810205676565017, 0.57935329437301375},
1257
+ },
1258
+ };
1259
+ vector<vector<S2Point>> b_vertices = {
1260
+ {
1261
+ {-0.10639937099530022, -0.8081020567669569, 0.57935329437297489},
1262
+ {-0.10639937102108385, -0.80810205688026293, 0.5793532942101961},
1263
+ {-0.10639937102108181, -0.80810205688026326, 0.5793532942101961},
1264
+ {-0.10639937099529816, -0.80810205676695701, 0.57935329437297478},
1265
+ },
1266
+ };
1267
+ S2Polygon a(MakeLoops(a_vertices));
1268
+ S2Polygon b(MakeLoops(b_vertices));
1269
+ S2Polygon c;
1270
+ c.InitToUnion(&a, &b);
1271
+ // Given edges do not form loops (indegree != outdegree)
1272
+ EXPECT_FALSE(c.is_empty())
1273
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1274
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1275
+ }
1276
+
1277
+ TEST(S2Polygon, Bug10) {
1278
+ vector<vector<S2Point>> a_vertices = {
1279
+ {
1280
+ {-0.10592889932808099, -0.80701394501854917, 0.58095400922339757},
1281
+ {-0.10592787800899696, -0.8070140771413753, 0.58095401191158469},
1282
+ {-0.1059270044681431, -0.80701419014619669, 0.58095401421031945},
1283
+ {-0.10592685562894633, -0.80701420940058122, 0.58095401460194696},
1284
+ {-0.10592685502239066, -0.80701420947920588, 0.58095401460332308},
1285
+ {-0.10592681668594067, -0.80701421444855337, 0.5809540146902914},
1286
+ {-0.10592586497682262, -0.8070143378130904, 0.58095401684902004},
1287
+ {-0.10592586434121586, -0.80701433789547994, 0.58095401685046155},
1288
+ {-0.10592585898876766, -0.80701428569270217, 0.58095409034224832},
1289
+ {-0.10592585898876755, -0.80701428569270128, 0.58095409034224987},
1290
+ {-0.10592571912106936, -0.8070129215545373, 0.58095601078971082},
1291
+ {-0.10592571912106795, -0.80701292155452331, 0.58095601078973025},
1292
+ {-0.10592546626664477, -0.80701045545315664, 0.58095948256783148},
1293
+ {-0.10592546630689463, -0.80701045544795602, 0.58095948256771723},
1294
+ {-0.10592538513536764, -0.80700975616910509, 0.58096046873415197},
1295
+ {-0.10592564439344856, -0.80700971612782446, 0.58096047708524956},
1296
+ {-0.1059267844512099, -0.80700966174311928, 0.58096034476466896},
1297
+ {-0.10592686088387009, -0.80700965393230761, 0.58096034167862642},
1298
+ {-0.10592691331665709, -0.80700961093727019, 0.58096039184274961},
1299
+ {-0.10592705773734933, -0.80700947507458121, 0.58096055423665138},
1300
+ {-0.10592721940752658, -0.80700934249808198, 0.58096070892049412},
1301
+ {-0.10592756003095027, -0.80700933299293154, 0.58096066001769275},
1302
+ {-0.10592832507751106, -0.80700935762745474, 0.58096048630521868},
1303
+ {-0.1059284165295875, -0.80701007424011018, 0.58095947418602778},
1304
+ {-0.10592841614913188, -0.80701007428931704, 0.58095947418704452},
1305
+ {-0.10592864947042728, -0.8070119434176124, 0.58095683523192998},
1306
+ {-0.1059286884898481, -0.80701225600079662, 0.58095639390519271},
1307
+ {-0.10592868927069989, -0.80701225581371527, 0.58095639402269295},
1308
+ {-0.10592869427137827, -0.80701225619024619, 0.58095639258785126},
1309
+ {-0.10592869791375134, -0.80701225804491505, 0.58095638934738025},
1310
+ {-0.10592869922184817, -0.80701226088076483, 0.5809563851695615},
1311
+ {-0.10592869922184843, -0.80701226088076705, 0.58095638516955805},
1312
+ {-0.10592869784516552, -0.80701226393793402, 0.58095638117383475},
1313
+ {-0.10592869415258396, -0.80701226639725276, 0.58095637843085768},
1314
+ {-0.10592868991437976, -0.80701226741266929, 0.58095637779310561},
1315
+ },
1316
+ };
1317
+ vector<vector<S2Point>> b_vertices = {
1318
+ {
1319
+ {-0.10592564460843924, -0.80700972122716552, 0.58096046996257766},
1320
+ {-0.10592539435053176, -0.80700975987840939, 0.58096046190138972},
1321
+ {-0.10592547496472972, -0.80701045435596641, 0.58095948250602925},
1322
+ {-0.10592546630689462, -0.80701045544795591, 0.58095948256771723},
1323
+ {-0.10592546630693271, -0.80701045544826022, 0.58095948256728758},
1324
+ {-0.1059254749287661, -0.80701045440038255, 0.5809594824508878},
1325
+ {-0.10592572778318898, -0.80701292050174633, 0.58095601067279068},
1326
+ {-0.1059257191207934, -0.80701292155455673, 0.58095601078973391},
1327
+ {-0.1059257194541381, -0.80701292151405679, 0.58095601078521419},
1328
+ {-0.10592572778319062, -0.80701292050176254, 0.58095601067276803},
1329
+ {-0.10592586765088864, -0.80701428463992497, 0.58095409022530931},
1330
+ {-0.10592585899855227, -0.80701428569151201, 0.58095409034211776},
1331
+ {-0.10592585898857355, -0.80701428569272593, 0.58095409034225098},
1332
+ {-0.10592586765088888, -0.80701428463992686, 0.58095409022530675},
1333
+ {-0.10592587247896063, -0.80701433172842685, 0.58095402393347073},
1334
+ {-0.10592681605007616, -0.80701420941876889, 0.58095402179319922},
1335
+ {-0.10592685438651758, -0.80701420444942229, 0.58095402170623067},
1336
+ {-0.10592685499307326, -0.80701420437079774, 0.58095402170485466},
1337
+ {-0.10592685562894634, -0.80701420940058122, 0.58095401460194696},
1338
+ {-0.10592685499689927, -0.80701420437030225, 0.58095402170484534},
1339
+ {-0.10592700383609792, -0.80701418511591771, 0.58095402131321794},
1340
+ {-0.10592787737695626, -0.80701407211109533, 0.58095401901448296},
1341
+ {-0.10592889869604118, -0.80701393998826909, 0.58095401632629584},
1342
+ {-0.10592889996012077, -0.80701395004882903, 0.58095400212049919},
1343
+ {-0.10592787864104941, -0.80701408217165349, 0.58095400480868631},
1344
+ {-0.10592787800903029, -0.80701407714164064, 0.58095401191120999},
1345
+ {-0.10592787864103763, -0.80701408217165482, 0.5809540048086862},
1346
+ {-0.10592700510019466, -0.80701419517647521, 0.58095400710742118},
1347
+ {-0.1059270044681431, -0.80701419014619669, 0.58095401421031934},
1348
+ {-0.10592700510018833, -0.8070141951764761, 0.58095400710742118},
1349
+ {-0.10592685626275877, -0.80701421443063182, 0.58095400749904391},
1350
+ {-0.10592685565826369, -0.80701421450898914, 0.58095400750041526},
1351
+ {-0.10592685502239063, -0.80701420947920566, 0.58095401460332308},
1352
+ {-0.10592685565826078, -0.80701421450898947, 0.58095400750041526},
1353
+ {-0.10592681732181129, -0.80701421947833718, 0.58095400758738369},
1354
+ {-0.10592681668594069, -0.80701421444855348, 0.58095401469029151},
1355
+ {-0.10592681732180521, -0.80701421947833796, 0.58095400758738369},
1356
+ {-0.10592586561269894, -0.80701434284287321, 0.58095400974611222},
1357
+ {-0.10592586497746249, -0.80701433781815202, 0.58095401684187198},
1358
+ {-0.10592586561268771, -0.80701434284287465, 0.58095400974611222},
1359
+ {-0.10592586497708102, -0.80701434292526464, 0.58095400974755396},
1360
+ {-0.10592586434121586, -0.80701433789548005, 0.58095401685046166},
1361
+ {-0.10592585567909471, -0.80701433894825569, 0.58095401696740323},
1362
+ {-0.1059258503266465, -0.80701428674547793, 0.58095409045919011},
1363
+ {-0.10592571045894811, -0.80701292260731206, 0.58095601090665361},
1364
+ {-0.10592571912060067, -0.80701292155459425, 0.58095601078971715},
1365
+ {-0.10592571878923682, -0.80701292159485349, 0.58095601079421},
1366
+ {-0.10592571045894694, -0.80701292260730051, 0.58095601090666993},
1367
+ {-0.10592545760452345, -0.80701045650593073, 0.58095948268477515},
1368
+ {-0.10592545764454649, -0.80701045650106651, 0.58095948268423492},
1369
+ {-0.10592537647753246, -0.80700975726109381, 0.58096046879584118},
1370
+ {-0.10592538513536764, -0.80700975616910509, 0.58096046873415197},
1371
+ {-0.10592538413784101, -0.80700975119062324, 0.58096047583161736},
1372
+ {-0.10592564339592514, -0.80700971114934217, 0.58096048418271495},
1373
+ {-0.10592564439344856, -0.80700971612782446, 0.58096047708524956},
1374
+ {-0.10592564496449927, -0.80700971099098684, 0.58096048411668999},
1375
+ {-0.10592678502227458, -0.80700965660628099, 0.58096035179610783},
1376
+ {-0.10592678388014524, -0.80700966687995779, 0.58096033773323019},
1377
+ },
1378
+ {
1379
+ {-0.10592585898876757, -0.80701428569270128, 0.58095409034224987},
1380
+ {-0.10592585897888845, -0.80701428569390288, 0.58095409034238166},
1381
+ {-0.1059258503266465, -0.80701428674547793, 0.58095409045919011},
1382
+ },
1383
+ {
1384
+ {-0.10592546626664477, -0.80701045545315664, 0.58095948256783148},
1385
+ {-0.10592546623958927, -0.8070104554564449, 0.58095948256819674},
1386
+ {-0.10592546626662946, -0.80701045545303429, 0.580959482568004},
1387
+ },
1388
+ };
1389
+ S2Polygon a(MakeLoops(a_vertices));
1390
+ S2Polygon b(MakeLoops(b_vertices));
1391
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(a);
1392
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(b);
1393
+ S2Polygon c;
1394
+ c.InitToUnion(&a, &b);
1395
+ // Inconsistent loop orientations detected
1396
+ S2_VLOG(1) << "\nS2Polygon: " << s2textformat::ToString(c);
1397
+ }
1398
+
1399
+ TEST(S2Polygon, Bug11) {
1400
+ vector<vector<S2Point>> a_vertices = {
1401
+ {
1402
+ {-0.10727349803435572, -0.80875763107088172, 0.57827631008375979},
1403
+ {-0.10727349807040805, -0.80875763112192245, 0.57827631000568813},
1404
+ {-0.10727349807040625, -0.80875763112192278, 0.57827631000568813},
1405
+ },
1406
+ {
1407
+ {-0.1072729603486537, -0.80875606054879057, 0.57827860629945249},
1408
+ {-0.10727299870478688, -0.80875633377729705, 0.57827821705818028},
1409
+ {-0.10727299875560981, -0.80875633413933223, 0.57827821654242495},
1410
+ {-0.10727309272230967, -0.80875700360375646, 0.57827726282438607},
1411
+ {-0.10727318660000487, -0.80875767243400742, 0.57827631000742785},
1412
+ {-0.10727349802669105, -0.80875763101356435, 0.57827631016534387},
1413
+ {-0.10727349803435525, -0.80875763107087817, 0.57827631008376468},
1414
+ {-0.10727349803435572, -0.80875763107088172, 0.57827631008375979},
1415
+ {-0.1072734980420204, -0.80875763112819909, 0.57827631000217561},
1416
+ {-0.10727318657570066, -0.80875767255391384, 0.57827630984423972},
1417
+ {-0.10727318651657966, -0.80875767256177711, 0.57827630984420975},
1418
+ {-0.10727318650891528, -0.80875767250445951, 0.57827630992579371},
1419
+ {-0.10727318640981781, -0.80875767251785957, 0.57827630992543622},
1420
+ {-0.10727309252411468, -0.80875700363055636, 0.57827726282367087},
1421
+ {-0.10727299855741491, -0.8087563341661328, 0.57827821654170874},
1422
+ {-0.10727299850659211, -0.8087563338040985, 0.57827821705746318},
1423
+ {-0.10727296014242577, -0.80875606051836801, 0.57827860638025652},
1424
+ {-0.10727296024152315, -0.80875606050496729, 0.57827860638061501},
1425
+ {-0.10727296023340849, -0.8087560604477102, 0.57827860646219797},
1426
+ {-0.10727348576547496, -0.80875598914629976, 0.57827860869282954},
1427
+ {-0.1072734857817042, -0.80875598926081438, 0.57827860852966395},
1428
+ },
1429
+ };
1430
+ vector<vector<S2Point>> b_vertices = {
1431
+ {
1432
+ {-0.1072734857735896, -0.80875598920355718, 0.5782786086112468},
1433
+ {-0.10727348576547457, -0.80875598914629976, 0.57827860869282954},
1434
+ {-0.10727839137361543, -0.80875532356817348, 0.57827862950694298},
1435
+ {-0.10727839137881608, -0.80875532356471602, 0.57827862951081388},
1436
+ {-0.10727839143632178, -0.80875532355090063, 0.5782786295194674},
1437
+ {-0.10727839149361706, -0.80875532355509905, 0.57827862950296649},
1438
+ {-0.1072783915353497, -0.80875532357618651, 0.57827862946573261},
1439
+ {-0.10727839154773799, -0.80875532360290581, 0.57827862942606567},
1440
+ {-0.10727848921795155, -0.80875531035110082, 0.57827862984032907},
1441
+ {-0.1072784892332832, -0.80875531046514559, 0.57827862967798682},
1442
+ {-0.10727971608197531, -0.8087551454635169, 0.57827863284376713},
1443
+ {-0.10727986275126807, -0.80875539440654376, 0.57827825747332484},
1444
+ {-0.10727959167812619, -0.80875599171505064, 0.57827747239052929},
1445
+ {-0.10727974196569352, -0.80875625444235633, 0.57827707706958686},
1446
+ {-0.10727993501555312, -0.80875677560355186, 0.57827631237878363},
1447
+ {-0.10727870858143702, -0.80875693828645479, 0.57827631237896882},
1448
+ {-0.1072787085493927, -0.80875693804871851, 0.5782763127174031},
1449
+ {-0.10727615977928232, -0.80875727704955946, 0.57827631143112901},
1450
+ {-0.10727615977915911, -0.80875727704957578, 0.57827631143112901},
1451
+ {-0.10727349803435751, -0.80875763107088128, 0.57827631008375968},
1452
+ {-0.10727349803435574, -0.80875763107088183, 0.57827631008375979},
1453
+ {-0.10727318656803594, -0.80875767249659658, 0.57827630992582391},
1454
+ {-0.10727318650891531, -0.80875767250445962, 0.57827630992579382},
1455
+ {-0.10727309262321218, -0.80875700361715641, 0.57827726282402847},
1456
+ {-0.10727299865651231, -0.80875633415273218, 0.57827821654206735},
1457
+ {-0.10727299860568951, -0.80875633379069789, 0.57827821705782179},
1458
+ {-0.10727296024152314, -0.80875606050496718, 0.57827860638061501},
1459
+ },
1460
+ };
1461
+ S2Polygon a(MakeLoops(a_vertices));
1462
+ S2Polygon b(MakeLoops(b_vertices));
1463
+ S2Polygon c;
1464
+ c.InitToUnion(&a, &b);
1465
+ // Given edges do not form loops (indegree != outdegree)
1466
+ EXPECT_FALSE(c.is_empty())
1467
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1468
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1469
+ }
1470
+
1471
+ TEST(S2Polygon, Bug12) {
1472
+ vector<vector<S2Point>> a_vertices = {
1473
+ {
1474
+ {-0.10772916872905106, -0.80699542608967267, 0.58064861015531188},
1475
+ {-0.10772916892726483, -0.80699542606300401, 0.58064861015560143},
1476
+ {-0.10772916892726613, -0.80699542606301333, 0.58064861015558844},
1477
+ {-0.10772916872905235, -0.806995426089682, 0.58064861015529889},
1478
+ },
1479
+ };
1480
+ vector<vector<S2Point>> b_vertices = {
1481
+ {
1482
+ {-0.10772916872905348, -0.80699542608969022, 0.58064861015528724},
1483
+ {-0.10772916892726496, -0.80699542606300489, 0.58064861015559999},
1484
+ {-0.10772930108168739, -0.80699639165138115, 0.58064724364290399},
1485
+ {-0.10772930088347589, -0.80699639167806647, 0.58064724364259113},
1486
+ },
1487
+ };
1488
+ S2Polygon a(MakeLoops(a_vertices));
1489
+ S2Polygon b(MakeLoops(b_vertices));
1490
+ S2Polygon c;
1491
+ c.InitToUnion(&a, &b);
1492
+ // Given edges do not form loops (indegree != outdegree)
1493
+ EXPECT_FALSE(c.is_empty())
1494
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1495
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1496
+ }
1497
+
1498
+ TEST(S2Polygon, Bug13) {
1499
+ // This test exercises a rare special case in GetCrossedVertexIndex where
1500
+ // two crossing edge chains snap to a different permutation of the same
1501
+ // vertices. In this example one input edge crosses another edge from right
1502
+ // to left, the first edge snaps to BCD and the second snaps to ABDC, and
1503
+ // triangle BCD is CCW. Since BCD is to the right of BD, this means that
1504
+ // the first edge has not yet crossed the second at vertex B, leaving C or D
1505
+ // as the possible crossing vertices.
1506
+ vector<vector<S2Point>> a_vertices = {
1507
+ {
1508
+ {-0.38306437985388492, -0.74921955334206214, 0.54030708099846292},
1509
+ {-0.3830643798552798, -0.74921955334134249, 0.5403070809984718},
1510
+ {-0.38306437985529124, -0.74921955334136414, 0.54030708099843361},
1511
+ {-0.38306437985389635, -0.74921955334208379, 0.54030708099842473},
1512
+ },
1513
+ };
1514
+ vector<vector<S2Point>> b_vertices = {
1515
+ {
1516
+ {-0.38306437985390962, -0.74921955334210588, 0.54030708099838465},
1517
+ {-0.38306437985527797, -0.74921955334134205, 0.54030708099847369},
1518
+ {-0.38306437985527941, -0.74921955334134405, 0.54030708099847014},
1519
+ {-0.38306437985391095, -0.74921955334210777, 0.54030708099838098},
1520
+ },
1521
+ };
1522
+ S2Polygon a(MakeLoops(a_vertices));
1523
+ S2Polygon b(MakeLoops(b_vertices));
1524
+ S2Polygon c;
1525
+ c.InitToUnion(&a, &b);
1526
+ // Given edges do not form loops (indegree != outdegree)
1527
+ EXPECT_FALSE(c.is_empty())
1528
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1529
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1530
+ }
1531
+
1532
+ TEST(S2Polygon, Bug14) {
1533
+ // This test exercises another rare case where the crossing vertices chosen
1534
+ // by GetCrossedVertexIndex() are not ordered correctly along the edge being
1535
+ // crossed. This is handled by adding extra edges to the output in order to
1536
+ // link up the crossings in the correct order.
1537
+ vector<vector<S2Point>> a_vertices = {
1538
+ {
1539
+ {-0.3837392878495085, -0.7477800800281974, 0.5418201831546835},
1540
+ {-0.38373928785696076, -0.7477800800212292, 0.54182018315902258},
1541
+ {-0.38373928785701278, -0.74778008002124685, 0.5418201831589613},
1542
+ {-0.38373928785703426, -0.7477800800212544, 0.54182018315893576},
1543
+ {-0.38373947205489456, -0.74778014227795497, 0.5418199667802881},
1544
+ {-0.38373947204434411, -0.74778014228781997, 0.54181996677414512},
1545
+ {-0.38373947205872994, -0.74778014228185352, 0.54181996677219124},
1546
+ {-0.38373947218468357, -0.74778014288930306, 0.54181996584462788},
1547
+ {-0.3837396702525171, -0.74778021044361542, 0.54181973233114322},
1548
+ {-0.38373967023137123, -0.74778021046333043, 0.54181973231891067},
1549
+ {-0.38373947216030285, -0.74778014290791484, 0.54181996583620895},
1550
+ {-0.38373947217087578, -0.74778014289805739, 0.54181996584232528},
1551
+ {-0.38373947215649007, -0.74778014290402395, 0.54181996584427927},
1552
+ {-0.3837394720305386, -0.74778014229658485, 0.5418199667718262},
1553
+ {-0.38373928783585998, -0.74778008004095942, 0.54182018314673686},
1554
+ {-0.38373928784641037, -0.7477800800310942, 0.54182018315287972},
1555
+ {-0.38373928783578648, -0.74778008004093421, 0.54182018314682368},
1556
+ {-0.383739287835765, -0.74778008004092666, 0.54182018314684921},
1557
+ },
1558
+ };
1559
+ vector<vector<S2Point>> b_vertices = {
1560
+ {
1561
+ {-0.38373923813692823, -0.7477800632164362, 0.54182024156551456},
1562
+ {-0.3837392878569364, -0.74778008002122087, 0.54182018315905123},
1563
+ {-0.38373928784640354, -0.74778008003106944, 0.54182018315291858},
1564
+ {-0.38373928784638789, -0.74778008003108642, 0.54182018315290648},
1565
+ {-0.38373928784638023, -0.74778008003109453, 0.54182018315290048},
1566
+ {-0.38373928783692102, -0.74778008004124585, 0.54182018314559},
1567
+ {-0.38373928783691913, -0.74778008004124541, 0.54182018314559188},
1568
+ {-0.38373928784636568, -0.74778008003110774, 0.54182018315289271},
1569
+ {-0.38373928784637329, -0.74778008003109953, 0.54182018315289848},
1570
+ {-0.38373928783583561, -0.74778008004095109, 0.5418201831467655},
1571
+ {-0.38373923811582744, -0.74778006323616641, 0.54182024155322883},
1572
+ {-0.38373857650312843, -0.74777983961840766, 0.54182101875399913},
1573
+ {-0.38373857652422921, -0.74777983959867744, 0.54182101876628486},
1574
+ },
1575
+ };
1576
+ S2Polygon a(MakeLoops(a_vertices));
1577
+ S2Polygon b(MakeLoops(b_vertices));
1578
+ S2Polygon c;
1579
+ c.InitToUnion(&a, &b);
1580
+ // Given edges do not form loops (indegree != outdegree)
1581
+ EXPECT_FALSE(c.is_empty())
1582
+ << "\nS2Polygon: " << s2textformat::ToString(a)
1583
+ << "\nS2Polygon: " << s2textformat::ToString(b);
1584
+ }
1585
+
1586
+ static void PolylineIntersectionSharedEdgeTest(const S2Polygon& p,
1587
+ int start_vertex,
1588
+ int direction) {
1589
+ SCOPED_TRACE(StrCat("Polyline intersection shared edge test"
1590
+ " start=", start_vertex,
1591
+ " direction=", direction));
1592
+ vector<S2Point> points = {p.loop(0)->vertex(start_vertex),
1593
+ p.loop(0)->vertex(start_vertex + direction)};
1594
+ S2Polyline polyline(points);
1595
+ vector<unique_ptr<S2Polyline>> polylines;
1596
+ if (direction < 0) {
1597
+ polylines = p.IntersectWithPolyline(polyline);
1598
+ EXPECT_EQ(0, polylines.size());
1599
+ polylines = p.SubtractFromPolyline(polyline);
1600
+ ASSERT_EQ(1, polylines.size());
1601
+ ASSERT_EQ(2, polylines[0]->num_vertices());
1602
+ EXPECT_EQ(points[0], polylines[0]->vertex(0));
1603
+ EXPECT_EQ(points[1], polylines[0]->vertex(1));
1604
+ EXPECT_FALSE(p.Intersects(polyline));
1605
+ EXPECT_FALSE(p.Contains(polyline));
1606
+ } else {
1607
+ polylines = p.IntersectWithPolyline(polyline);
1608
+ ASSERT_EQ(1, polylines.size());
1609
+ ASSERT_EQ(2, polylines[0]->num_vertices());
1610
+ EXPECT_EQ(points[0], polylines[0]->vertex(0));
1611
+ EXPECT_EQ(points[1], polylines[0]->vertex(1));
1612
+ polylines = p.SubtractFromPolyline(polyline);
1613
+ EXPECT_EQ(0, polylines.size());
1614
+ EXPECT_TRUE(p.Intersects(polyline));
1615
+ EXPECT_TRUE(p.Contains(polyline));
1616
+ }
1617
+ }
1618
+
1619
+ // This tests polygon-polyline intersections.
1620
+ // It covers the same edge cases as TestOperations and also adds some
1621
+ // extra tests for shared edges.
1622
+ TEST_F(S2PolygonTestBase, PolylineIntersection) {
1623
+ for (int v = 0; v < 3; ++v) {
1624
+ PolylineIntersectionSharedEdgeTest(*cross1_, v, 1);
1625
+ PolylineIntersectionSharedEdgeTest(*cross1_, v + 1, -1);
1626
+ PolylineIntersectionSharedEdgeTest(*cross1_side_hole_, v, 1);
1627
+ PolylineIntersectionSharedEdgeTest(*cross1_side_hole_, v + 1, -1);
1628
+ }
1629
+
1630
+ // See comments in TestOperations about the vlue of this constant.
1631
+ static const S1Angle kMaxError = S1Angle::Radians(1e-4);
1632
+
1633
+ // This duplicates some of the tests in TestOperations by
1634
+ // converting the outline of polygon A to a polyline then intersecting
1635
+ // it with the polygon B. It then converts B to a polyline and intersects
1636
+ // it with A. It then feeds all of the results into a polygon builder and
1637
+ // tests that the output is equal to doing an intersection between A and B.
1638
+ int i = 0;
1639
+ for (const TestCase& test : test_cases) {
1640
+ SCOPED_TRACE(StrCat("Polyline intersection test case ", i++));
1641
+ unique_ptr<S2Polygon> a(MakePolygon(test.a));
1642
+ unique_ptr<S2Polygon> b(MakePolygon(test.b));
1643
+ unique_ptr<S2Polygon> expected_a_and_b(MakePolygon(test.a_and_b));
1644
+
1645
+ vector<S2Point> points;
1646
+ vector<unique_ptr<S2Polyline>> polylines;
1647
+ for (int ab = 0; ab < 2; ab++) {
1648
+ S2Polygon *tmp = ab ? a.get() : b.get();
1649
+ S2Polygon *tmp2 = ab ? b.get() : a.get();
1650
+ for (int l = 0; l < tmp->num_loops(); l++) {
1651
+ points.clear();
1652
+ if (tmp->loop(l)->is_hole()) {
1653
+ for (int v = tmp->loop(l)->num_vertices(); v >=0 ; v--) {
1654
+ points.push_back(tmp->loop(l)->vertex(v));
1655
+ }
1656
+ } else {
1657
+ for (int v = 0; v <= tmp->loop(l)->num_vertices(); v++) {
1658
+ points.push_back(tmp->loop(l)->vertex(v));
1659
+ }
1660
+ }
1661
+ S2Polyline polyline(points);
1662
+ vector<unique_ptr<S2Polyline>> tmp =
1663
+ tmp2->IntersectWithPolyline(polyline);
1664
+ polylines.insert(polylines.end(),
1665
+ std::make_move_iterator(tmp.begin()),
1666
+ std::make_move_iterator(tmp.end()));
1667
+ }
1668
+ }
1669
+
1670
+ S2Builder builder{S2Builder::Options()};
1671
+ S2Polygon a_and_b;
1672
+ builder.StartLayer(make_unique<s2builderutil::S2PolygonLayer>(&a_and_b));
1673
+ for (const auto& polyline : polylines) {
1674
+ builder.AddPolyline(*polyline);
1675
+ }
1676
+
1677
+ S2Error error;
1678
+ ASSERT_TRUE(builder.Build(&error)) << error;
1679
+ CheckEqual(a_and_b, *expected_a_and_b, kMaxError);
1680
+ }
1681
+ }
1682
+
1683
+ static void CheckCoveringIsConservative(const S2Polygon& polygon,
1684
+ const vector<S2CellId>& cells) {
1685
+ // Check that Contains(S2Cell) and MayIntersect(S2Cell) are implemented
1686
+ // conservatively, by comparing against the Contains/Intersect result with
1687
+ // the "cell polygon" defined by the four cell vertices. Please note that
1688
+ // the cell polygon is *not* an exact representation of the S2Cell: cell
1689
+ // vertices are rounded from their true mathematical positions, which leads
1690
+ // to tiny cracks and overlaps between the cell polygons at different cell
1691
+ // levels. That is why Contains(S2Cell) and MayIntersect(S2Cell) cannot be
1692
+ // implemented by simply converting the cell to an S2Polygon. But it is
1693
+ // still useful to do this as a sanity check. In particular:
1694
+ //
1695
+ // - If Contains(cell) is true, the polygon must contain the cell polygon.
1696
+ // - If the polygon intersects the cell polygon, then MayIntersect(cell)
1697
+ // must return true.
1698
+ //
1699
+ for (S2CellId cell_id : cells) {
1700
+ S2Cell cell(cell_id);
1701
+ S2Polygon cell_poly(cell);
1702
+ if (polygon.Contains(cell)) {
1703
+ EXPECT_TRUE(polygon.Contains(&cell_poly));
1704
+ }
1705
+ if (polygon.Intersects(&cell_poly)) {
1706
+ EXPECT_TRUE(polygon.MayIntersect(cell));
1707
+ }
1708
+ }
1709
+ }
1710
+
1711
+ // Remove a random polygon from "pieces" and return it.
1712
+ static unique_ptr<S2Polygon> ChoosePiece(
1713
+ vector<unique_ptr<S2Polygon>> *pieces) {
1714
+ int i = S2Testing::rnd.Uniform(pieces->size());
1715
+ unique_ptr<S2Polygon> result = std::move((*pieces)[i]);
1716
+ pieces->erase(pieces->begin() + i);
1717
+ return result;
1718
+ }
1719
+
1720
+ static void SplitAndAssemble(const S2Polygon& polygon) {
1721
+ // Normalize the polygon's loop structure by rebuilding it with S2Builder.
1722
+ S2Builder builder{S2Builder::Options()};
1723
+ S2Polygon expected;
1724
+ builder.StartLayer(make_unique<s2builderutil::S2PolygonLayer>(&expected));
1725
+ builder.AddPolygon(polygon);
1726
+
1727
+ S2Error error;
1728
+ ASSERT_TRUE(builder.Build(&error)) << error;
1729
+
1730
+ for (int iter = 0; iter < (google::DEBUG_MODE ? 3 : 10); ++iter) {
1731
+ S2RegionCoverer coverer;
1732
+ // Compute the minimum level such that the polygon's bounding
1733
+ // cap is guaranteed to be cut.
1734
+ double diameter = 2 * polygon.GetCapBound().GetRadius().radians();
1735
+ int min_level = S2::kMaxWidth.GetLevelForMaxValue(diameter);
1736
+
1737
+ // Now choose a level that has up to 500 cells in the covering.
1738
+ int level = min_level + S2Testing::rnd.Uniform(google::DEBUG_MODE ? 4 : 6);
1739
+ coverer.mutable_options()->set_min_level(min_level);
1740
+ coverer.mutable_options()->set_max_level(level);
1741
+ coverer.mutable_options()->set_max_cells(500);
1742
+
1743
+ vector<S2CellId> cells;
1744
+ coverer.GetCovering(polygon, &cells);
1745
+ S2CellUnion covering;
1746
+ covering.Init(cells);
1747
+ S2Testing::CheckCovering(polygon, covering, false);
1748
+ CheckCoveringIsConservative(polygon, cells);
1749
+ S2_VLOG(2) << cells.size() << " cells in covering";
1750
+ vector<unique_ptr<S2Polygon>> pieces;
1751
+ int i = 0;
1752
+ for (S2CellId cell_id : cells) {
1753
+ S2Cell cell(cell_id);
1754
+ S2Polygon window(cell);
1755
+ auto piece = make_unique<S2Polygon>();
1756
+ piece->InitToIntersection(&polygon, &window);
1757
+ S2_VLOG(4) << "\nPiece " << i++ << ":\n Window: "
1758
+ << s2textformat::ToString(window)
1759
+ << "\n Piece: " << s2textformat::ToString(*piece);
1760
+ pieces.push_back(std::move(piece));
1761
+ }
1762
+
1763
+ // Now we repeatedly remove two random pieces, compute their union, and
1764
+ // insert the result as a new piece until only one piece is left.
1765
+ //
1766
+ // We don't use S2Polygon::DestructiveUnion() because it joins the pieces
1767
+ // in a mostly deterministic order. We don't just call random_shuffle()
1768
+ // on the pieces and repeatedly join the last two pieces in the vector
1769
+ // because this always joins a single original piece to the current union
1770
+ // rather than doing the unions according to a random tree structure.
1771
+ while (pieces.size() > 1) {
1772
+ unique_ptr<S2Polygon> a(ChoosePiece(&pieces));
1773
+ unique_ptr<S2Polygon> b(ChoosePiece(&pieces));
1774
+ auto c = make_unique<S2Polygon>();
1775
+ c->InitToUnion(a.get(), b.get());
1776
+ S2_VLOG(4) << "\nJoining piece a: " << s2textformat::ToString(*a)
1777
+ << "\n With piece b: " << s2textformat::ToString(*b)
1778
+ << "\n To get piece c: " << s2textformat::ToString(*c);
1779
+ pieces.push_back(std::move(c));
1780
+ }
1781
+ unique_ptr<S2Polygon> result(std::move(pieces[0]));
1782
+ pieces.pop_back();
1783
+
1784
+ // The moment of truth!
1785
+ EXPECT_TRUE(expected.BoundaryNear(*result, S1Angle::Radians(2e-15)))
1786
+ << "\nActual:\n" << s2textformat::ToString(*result)
1787
+ << "\nExpected:\n" << s2textformat::ToString(expected);
1788
+
1789
+ // Check that ApproxEquals produces the same result.
1790
+ if (!expected.ApproxEquals(result.get(),
1791
+ S2::kIntersectionMergeRadius)) {
1792
+ S2Polygon symmetric_difference;
1793
+ symmetric_difference.InitToApproxSymmetricDifference(
1794
+ &expected, result.get(), S2::kIntersectionMergeRadius);
1795
+ ADD_FAILURE() << s2textformat::ToString(symmetric_difference);
1796
+ }
1797
+ }
1798
+ }
1799
+
1800
+ TEST_F(S2PolygonTestBase, Splitting) {
1801
+ // It takes too long to test all the polygons in debug mode, so we just pick
1802
+ // out some of the more interesting ones.
1803
+
1804
+ SplitAndAssemble(*near_10_);
1805
+ SplitAndAssemble(*near_H3210_);
1806
+ SplitAndAssemble(*far_H3210_);
1807
+ SplitAndAssemble(*south_0ab_);
1808
+ SplitAndAssemble(*south_210b_);
1809
+ SplitAndAssemble(*south_H20abc_);
1810
+ SplitAndAssemble(*nf1_n10_f2_s10abc_);
1811
+ SplitAndAssemble(*nf2_n2_f210_s210ab_);
1812
+ SplitAndAssemble(*far_H_);
1813
+ SplitAndAssemble(*south_H_);
1814
+ SplitAndAssemble(*far_H_south_H_);
1815
+ }
1816
+
1817
+ TEST(S2Polygon, InitToCellUnionBorder) {
1818
+ // Test S2Polygon::InitToCellUnionBorder().
1819
+ // The main thing to check is that adjacent cells of different sizes get
1820
+ // merged correctly. To do this we generate two random adjacent cells,
1821
+ // convert to polygon, and make sure the polygon only has a single loop.
1822
+ for (int iter = 0; iter < 200; ++iter) {
1823
+ SCOPED_TRACE(StrCat("Iteration ", iter));
1824
+
1825
+ // Choose a random non-leaf cell.
1826
+ S2CellId big_cell =
1827
+ S2Testing::GetRandomCellId(S2Testing::rnd.Uniform(S2CellId::kMaxLevel));
1828
+ // Get all neighbors at some smaller level.
1829
+ int small_level = big_cell.level() +
1830
+ S2Testing::rnd.Uniform(min(16, S2CellId::kMaxLevel - big_cell.level()));
1831
+ vector<S2CellId> neighbors;
1832
+ big_cell.AppendAllNeighbors(small_level, &neighbors);
1833
+ // Pick one at random.
1834
+ S2CellId small_cell = neighbors[S2Testing::rnd.Uniform(neighbors.size())];
1835
+ // If it's diagonally adjacent, bail out.
1836
+ S2CellId edge_neighbors[4];
1837
+ big_cell.GetEdgeNeighbors(edge_neighbors);
1838
+ bool diagonal = true;
1839
+ for (int i = 0; i < 4; ++i) {
1840
+ if (edge_neighbors[i].contains(small_cell)) {
1841
+ diagonal = false;
1842
+ }
1843
+ }
1844
+ S2_VLOG(3) << iter << ": big_cell " << big_cell <<
1845
+ " small_cell " << small_cell;
1846
+ if (diagonal) {
1847
+ S2_VLOG(3) << " diagonal - bailing out!";
1848
+ continue;
1849
+ }
1850
+
1851
+ vector<S2CellId> cells;
1852
+ cells.push_back(big_cell);
1853
+ cells.push_back(small_cell);
1854
+ S2CellUnion cell_union;
1855
+ cell_union.Init(cells);
1856
+ EXPECT_EQ(2, cell_union.num_cells());
1857
+ S2Polygon poly;
1858
+ poly.InitToCellUnionBorder(cell_union);
1859
+ EXPECT_EQ(1, poly.num_loops());
1860
+ // If the conversion were perfect we could test containment, but due to
1861
+ // rounding the polygon won't always exactly contain both cells. We can
1862
+ // at least test intersection.
1863
+ EXPECT_TRUE(poly.MayIntersect(S2Cell(big_cell)));
1864
+ EXPECT_TRUE(poly.MayIntersect(S2Cell(small_cell)));
1865
+ }
1866
+ }
1867
+
1868
+ TEST(S2Polygon, UnionWithAmbgiuousCrossings) {
1869
+ vector<S2Point> a_vertices = {
1870
+ S2Point(0.044856812877680216, -0.80679210859571904, 0.5891301722422051),
1871
+ S2Point(0.044851868273159699, -0.80679240802900054, 0.5891301386444033),
1872
+ S2Point(0.044854246527738666, -0.80679240292188514, 0.58912996457145106)
1873
+ };
1874
+ vector<S2Point> b_vertices = {
1875
+ S2Point(0.044849715793028468, -0.80679253837178111, 0.58913012401412856),
1876
+ S2Point(0.044855344598821352, -0.80679219751320641, 0.589130162266992),
1877
+ S2Point(0.044854017712818696, -0.80679210327223405, 0.58913039235179754)
1878
+ };
1879
+ S2Polygon a(make_unique<S2Loop>(a_vertices));
1880
+ S2Polygon b(make_unique<S2Loop>(b_vertices));
1881
+ S2Polygon c;
1882
+ c.InitToUnion(&a, &b);
1883
+ EXPECT_FALSE(c.is_empty());
1884
+ }
1885
+
1886
+ TEST(S2Polygon, InitToSloppySupportsEmptyPolygons) {
1887
+ S2Polygon empty_polygon;
1888
+ S2Polygon polygon;
1889
+ polygon.InitToSnapped(&empty_polygon);
1890
+ // InitToSloppy is further tested by SnapSplitsPolygon.
1891
+ }
1892
+
1893
+ TEST(S2Polygon, InitToSnappedDoesNotRotateVertices) {
1894
+ // This particular example came from MapFacts, but in fact InitToSnapped
1895
+ // used to cyclically rotate the vertices of all "hole" loops.
1896
+ unique_ptr<S2Polygon> polygon(s2textformat::MakePolygon(
1897
+ "49.9305505:-124.8345463, 49.9307448:-124.8299657, "
1898
+ "49.9332101:-124.8301996, 49.9331224:-124.8341368; "
1899
+ "49.9311087:-124.8327042, 49.9318176:-124.8312621, "
1900
+ "49.9318866:-124.8334451"));
1901
+ S2Polygon polygon2, polygon3;
1902
+ polygon2.InitToSnapped(polygon.get());
1903
+
1904
+ // Check that the first vertex is the same when converted to E7.
1905
+ EXPECT_EQ(S2LatLng::Latitude(polygon->loop(0)->vertex(0)).e7(),
1906
+ S2LatLng::Latitude(polygon2.loop(0)->vertex(0)).e7());
1907
+ EXPECT_EQ(S2LatLng::Longitude(polygon->loop(0)->vertex(0)).e7(),
1908
+ S2LatLng::Longitude(polygon2.loop(0)->vertex(0)).e7());
1909
+
1910
+ // Check that snapping twice doesn't rotate the vertices.
1911
+ polygon3.InitToSnapped(&polygon2);
1912
+ EXPECT_TRUE(polygon2.Equals(&polygon3));
1913
+ }
1914
+
1915
+ TEST(S2Polygon, InitToSnappedWithSnapLevel) {
1916
+ const unique_ptr<const S2Polygon> polygon(
1917
+ s2textformat::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0"));
1918
+ for (int level = 0; level <= S2CellId::kMaxLevel; ++level) {
1919
+ S2Polygon snapped_polygon;
1920
+ snapped_polygon.InitToSnapped(polygon.get(), level);
1921
+ EXPECT_TRUE(snapped_polygon.IsValid());
1922
+ S1Angle merge_radius = min(S1Angle::Radians(S2::kMaxDiag.GetValue(level)),
1923
+ S2Builder::SnapFunction::kMaxSnapRadius());
1924
+ EXPECT_TRUE(snapped_polygon.ApproxContains(polygon.get(), merge_radius));
1925
+ }
1926
+ }
1927
+
1928
+ TEST(S2Polygon, InitToSnappedIsValid_A) {
1929
+ std::unique_ptr<S2Polygon> poly(s2textformat::MakePolygon(
1930
+ "53.1328020478452:6.39444903453293, 53.1328019:6.394449, "
1931
+ "53.1327091:6.3961766, 53.1313753:6.3958652, 53.1312825:6.3975924, "
1932
+ "53.132616:6.3979042, 53.1326161348736:6.39790423150577"));
1933
+ S2_LOG(INFO) << "\nInput: " << s2textformat::ToString(*poly);
1934
+ EXPECT_TRUE(poly->IsValid());
1935
+ S2Polygon poly_snapped;
1936
+ poly_snapped.set_s2debug_override(S2Debug::DISABLE);
1937
+ poly_snapped.InitToSnapped(poly.get());
1938
+ S2_LOG(INFO) << "\nSnapped: " << s2textformat::ToString(poly_snapped);
1939
+ S2Error error;
1940
+ EXPECT_FALSE(poly_snapped.FindValidationError(&error)) << error;
1941
+ }
1942
+
1943
+ TEST(S2Polygon, InitToSnappedIsValid_B) {
1944
+ std::unique_ptr<S2Polygon> poly(s2textformat::MakePolygon(
1945
+ "51.6621651:4.9858102, 51.6620965:4.9874227, 51.662028:4.9890355, "
1946
+ "51.6619796006122:4.99017864445347, 51.6622335420397:4.98419752545216, "
1947
+ "51.6622334:4.9841975; 51.66189957578:4.99206198576131, "
1948
+ "51.6618911:4.9922612, 51.6618224:4.9938741, 51.6605122:4.993639, "
1949
+ "51.6604437:4.9952519, 51.6603751:4.9968648, 51.6603064:4.9984777, "
1950
+ "51.6602379:5.0000907, 51.660169:5.0017037, 51.6601003:5.0033165, "
1951
+ "51.6600318:5.0049298, 51.659963:5.0065427, 51.6598943:5.0081561, "
1952
+ "51.6612044207178:5.00839208571886, 51.6612732068132:5.00677860122814, "
1953
+ "51.6612732:5.0067786, 51.6613418:5.0051654, 51.6614106:5.0035525, "
1954
+ "51.6614793:5.0019393, 51.6615479:5.0003263, "
1955
+ "51.6615946694783:4.99923124520759, 51.6616389353165:4.99819106536521, "
1956
+ "51.6616852:4.9971, 51.6617538:4.995487, "
1957
+ "51.661753964726:4.99548702962593"));
1958
+ S2_LOG(INFO) << "\nInput: " << s2textformat::ToString(*poly);
1959
+ EXPECT_TRUE(poly->IsValid());
1960
+ S2Polygon poly_snapped;
1961
+ poly_snapped.set_s2debug_override(S2Debug::DISABLE);
1962
+ poly_snapped.InitToSnapped(poly.get());
1963
+ S2_LOG(INFO) << "\nSnapped: " << s2textformat::ToString(poly_snapped);
1964
+ S2Error error;
1965
+ EXPECT_FALSE(poly_snapped.FindValidationError(&error)) << error;
1966
+ }
1967
+
1968
+ TEST(S2Polygon, InitToSnappedIsValid_C) {
1969
+ std::unique_ptr<S2Polygon> poly(s2textformat::MakePolygon(
1970
+ "53.5316236236404:19.5841192796855, 53.5416584:19.5915903, "
1971
+ "53.5416584189104:19.5915901888287; 53.5416584:19.5915903, "
1972
+ "53.5363122:19.62299, 53.5562817:19.6378935, 53.5616342:19.606474; "
1973
+ "53.5616342:19.606474, 53.5916039:19.6288326, 53.5912689:19.6307982, "
1974
+ "53.5925176:19.6317308, 53.5928526:19.6297652, 53.6015949:19.6362943, "
1975
+ "53.6015950436033:19.6362944072725, 53.6015950814439:19.6362941852262, "
1976
+ "53.5616342380536:19.6064737764314"));
1977
+ S2_LOG(INFO) << "\nInput: " << s2textformat::ToString(*poly);
1978
+ EXPECT_TRUE(poly->IsValid());
1979
+ S2Polygon poly_snapped;
1980
+ poly_snapped.set_s2debug_override(S2Debug::DISABLE);
1981
+ poly_snapped.InitToSnapped(poly.get());
1982
+ S2_LOG(INFO) << "\nSnapped: " << s2textformat::ToString(poly_snapped);
1983
+ S2Error error;
1984
+ EXPECT_FALSE(poly_snapped.FindValidationError(&error)) << error;
1985
+ }
1986
+
1987
+ TEST(S2Polygon, InitToSnappedIsValid_D) {
1988
+ std::unique_ptr<S2Polygon> poly(s2textformat::MakePolygon(
1989
+ "52.0909316:4.8673826, 52.0909317627574:4.86738262858533, "
1990
+ "52.0911338452911:4.86248482549567, 52.0911337:4.8624848, "
1991
+ "52.0910665:4.8641176, 52.090999:4.8657502"));
1992
+ S2_LOG(INFO) << "\nInput: " << s2textformat::ToString(*poly);
1993
+ EXPECT_TRUE(poly->IsValid());
1994
+ S2Polygon poly_snapped;
1995
+ poly_snapped.set_s2debug_override(S2Debug::DISABLE);
1996
+ poly_snapped.InitToSnapped(poly.get());
1997
+ S2_LOG(INFO) << "\nSnapped: " << s2textformat::ToString(poly_snapped);
1998
+ S2Error error;
1999
+ EXPECT_FALSE(poly_snapped.FindValidationError(&error)) << error;
2000
+ }
2001
+
2002
+ TEST(S2Polygon, MultipleInit) {
2003
+ unique_ptr<S2Polygon> polygon(s2textformat::MakePolygon("0:0, 0:2, 2:0"));
2004
+ EXPECT_EQ(1, polygon->num_loops());
2005
+ EXPECT_EQ(3, polygon->num_vertices());
2006
+ S2LatLngRect bound1 = polygon->GetRectBound();
2007
+
2008
+ vector<unique_ptr<S2Loop>> loops;
2009
+ loops.push_back(s2textformat::MakeLoop("10:0, -10:-20, -10:20"));
2010
+ loops.push_back(s2textformat::MakeLoop("40:30, 20:10, 20:50"));
2011
+ polygon->InitNested(std::move(loops));
2012
+ EXPECT_TRUE(polygon->IsValid());
2013
+ EXPECT_EQ(2, polygon->num_loops());
2014
+ EXPECT_EQ(6, polygon->num_vertices());
2015
+ EXPECT_TRUE(bound1 != polygon->GetRectBound());
2016
+ }
2017
+
2018
+ TEST(S2Polygon, InitSingleLoop) {
2019
+ S2Polygon polygon(make_unique<S2Loop>(S2Loop::kEmpty()));
2020
+ EXPECT_TRUE(polygon.is_empty());
2021
+ polygon.Init(make_unique<S2Loop>(S2Loop::kFull()));
2022
+ EXPECT_TRUE(polygon.is_full());
2023
+ polygon.Init(s2textformat::MakeLoop("0:0, 0:10, 10:0"));
2024
+ EXPECT_EQ(3, polygon.num_vertices());
2025
+ }
2026
+
2027
+ TEST_F(S2PolygonTestBase, TestSimpleEncodeDecode) {
2028
+ Encoder encoder;
2029
+ cross1_->Encode(&encoder);
2030
+ Decoder decoder(encoder.base(), encoder.length());
2031
+ S2Polygon decoded_polygon;
2032
+ ASSERT_TRUE(decoded_polygon.Decode(&decoder));
2033
+ EXPECT_TRUE(cross1_->BoundaryEquals(&decoded_polygon));
2034
+ EXPECT_EQ(cross1_->GetRectBound(), decoded_polygon.GetRectBound());
2035
+ }
2036
+
2037
+ TEST(S2Polygon, TestEncodeDecodeDefaultPolygon) {
2038
+ S2Polygon polygon;
2039
+ EXPECT_TRUE(TestEncodeDecode(&polygon));
2040
+ }
2041
+
2042
+ TEST(S2Polygon, CompressedEmptyPolygonRequires3Bytes) {
2043
+ S2Polygon empty_polygon;
2044
+ Encoder encoder;
2045
+
2046
+ S2Polygon snapped_empty_polygon;
2047
+ snapped_empty_polygon.InitToSnapped(&empty_polygon);
2048
+
2049
+ snapped_empty_polygon.Encode(&encoder);
2050
+ // 1 byte for version, 1 for the level, 1 for the length.
2051
+ EXPECT_EQ(1 + 1 + 1, encoder.length());
2052
+
2053
+ EXPECT_TRUE(snapped_empty_polygon.is_empty());
2054
+ EXPECT_EQ(S2LatLngRect::Empty(), snapped_empty_polygon.GetRectBound());
2055
+ }
2056
+
2057
+ TEST(S2Polygon, CompressedEncodedPolygonRequires69Bytes) {
2058
+ const unique_ptr<const S2Polygon> polygon(
2059
+ s2textformat::MakePolygon("0:0, 0:2, 2:0; 0:0, 0:-2, -2:-2, -2:0"));
2060
+
2061
+ S2Polygon snapped_polygon;
2062
+ snapped_polygon.InitToSnapped(polygon.get());
2063
+
2064
+ Encoder encoder;
2065
+ snapped_polygon.Encode(&encoder);
2066
+
2067
+ // 2 loops, one with 3 vertices, one with 4.
2068
+ // Polygon:
2069
+ // 1 byte for version
2070
+ // 1 byte for level
2071
+ // 1 byte for num_loops
2072
+ // Loops:
2073
+ // 5 bytes overhead
2074
+ // 8 bytes per vertex
2075
+ EXPECT_EQ(1 + 1 + 1 + 2 * 5 + 7 * 8, encoder.length());
2076
+ }
2077
+
2078
+ TEST_F(S2PolygonTestBase, CompressedEncodedPolygonDecodesApproxEqual) {
2079
+ // To compare the boundaries, etc we want to snap first.
2080
+ S2Polygon snapped;
2081
+ snapped.InitToSnapped(near_30_.get());
2082
+ ASSERT_EQ(2, snapped.num_loops());
2083
+ EXPECT_EQ(0, snapped.loop(0)->depth());
2084
+ EXPECT_EQ(1, snapped.loop(1)->depth());
2085
+
2086
+ Encoder encoder;
2087
+ snapped.Encode(&encoder);
2088
+
2089
+ Decoder decoder(encoder.base(), encoder.length());
2090
+
2091
+ S2Polygon decoded_polygon;
2092
+ ASSERT_TRUE(decoded_polygon.Decode(&decoder));
2093
+ ASSERT_TRUE(decoded_polygon.IsValid());
2094
+ EXPECT_TRUE(snapped.BoundaryEquals(&decoded_polygon));
2095
+ EXPECT_EQ(snapped.GetRectBound(), decoded_polygon.GetRectBound());
2096
+ EXPECT_EQ(snapped.num_vertices(), decoded_polygon.num_vertices());
2097
+ EXPECT_EQ(2, decoded_polygon.num_loops());
2098
+ EXPECT_EQ(0, decoded_polygon.loop(0)->depth());
2099
+ EXPECT_EQ(1, decoded_polygon.loop(1)->depth());
2100
+ }
2101
+
2102
+ // This test checks that S2Polygons created directly from S2Cells behave
2103
+ // identically to S2Polygons created from the vertices of those cells; this
2104
+ // previously was not the case, because S2Cells calculate their bounding
2105
+ // rectangles slightly differently, and S2Polygons created from them just
2106
+ // copied the S2Cell bounds.
2107
+ TEST(S2Polygon, TestS2CellConstructorAndContains) {
2108
+ S2LatLng latlng(S1Angle::E6(40565459), S1Angle::E6(-74645276));
2109
+ S2Cell cell(latlng);
2110
+ S2Polygon cell_as_polygon(cell);
2111
+ S2Polygon empty;
2112
+ S2Polygon polygon_copy;
2113
+ polygon_copy.InitToUnion(&cell_as_polygon, &empty);
2114
+ EXPECT_TRUE(polygon_copy.Contains(&cell_as_polygon));
2115
+ EXPECT_TRUE(cell_as_polygon.Contains(&polygon_copy));
2116
+ }
2117
+
2118
+ TEST(S2PolygonTest, Project) {
2119
+ unique_ptr<S2Polygon> polygon(MakePolygon(kNear0 + kNear2));
2120
+ S2Point point;
2121
+ S2Point projected;
2122
+
2123
+ // The point inside the polygon should be projected into itself.
2124
+ point = s2textformat::MakePoint("1.1:0");
2125
+ projected = polygon->Project(point);
2126
+ EXPECT_TRUE(S2::ApproxEquals(point, projected));
2127
+
2128
+ // The point is on the outside of the polygon.
2129
+ point = s2textformat::MakePoint("5.1:-2");
2130
+ projected = polygon->Project(point);
2131
+ EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("5:-2"), projected));
2132
+
2133
+ // The point is inside the hole in the polygon.
2134
+ point = s2textformat::MakePoint("-0.49:-0.49");
2135
+ projected = polygon->Project(point);
2136
+ EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("-0.5:-0.5"),
2137
+ projected, S1Angle::Radians(1e-6)));
2138
+
2139
+ point = s2textformat::MakePoint("0:-3");
2140
+ projected = polygon->Project(point);
2141
+ EXPECT_TRUE(S2::ApproxEquals(s2textformat::MakePoint("0:-2"), projected));
2142
+ }
2143
+
2144
+ // Helper function for testing the distance methods. "boundary_x" is the
2145
+ // expected result of projecting "x" onto the polygon boundary. For
2146
+ // convenience it can be set to S2Point() to indicate that (boundary_x == x).
2147
+ static void TestDistanceMethods(const S2Polygon& polygon, const S2Point& x,
2148
+ S2Point boundary_x) {
2149
+ // This error is not guaranteed by the implementation but is okay for tests.
2150
+ const S1Angle kMaxError = S1Angle::Radians(1e-15);
2151
+
2152
+ if (boundary_x == S2Point()) boundary_x = x;
2153
+ EXPECT_LE(S1Angle(boundary_x, polygon.ProjectToBoundary(x)), kMaxError);
2154
+
2155
+ if (polygon.is_empty() || polygon.is_full()) {
2156
+ EXPECT_EQ(S1Angle::Infinity(), polygon.GetDistanceToBoundary(x));
2157
+ } else {
2158
+ // EXPECT_NEAR only works with doubles.
2159
+ EXPECT_NEAR(S1Angle(x, boundary_x).degrees(),
2160
+ polygon.GetDistanceToBoundary(x).degrees(),
2161
+ kMaxError.degrees());
2162
+ }
2163
+ if (polygon.Contains(x)) {
2164
+ EXPECT_EQ(S1Angle::Zero(), polygon.GetDistance(x));
2165
+ EXPECT_EQ(x, polygon.Project(x));
2166
+ } else {
2167
+ EXPECT_EQ(polygon.GetDistanceToBoundary(x), polygon.GetDistance(x));
2168
+ EXPECT_EQ(polygon.ProjectToBoundary(x), polygon.Project(x));
2169
+ }
2170
+ }
2171
+
2172
+ TEST_F(S2PolygonTestBase, GetDistance) {
2173
+ // The empty and full loops don't have boundaries.
2174
+ TestDistanceMethods(*empty_, S2Point(0, 1, 0), S2Point());
2175
+ TestDistanceMethods(*full_, S2Point(0, 1, 0), S2Point());
2176
+
2177
+ // A polygon consisting of two nested rectangles centered around
2178
+ // S2LatLng(0,0). Note that because lines of latitude are curved on the
2179
+ // sphere, it is not straightforward to project points onto any edge except
2180
+ // along the equator. (The equator is the only line of latitude that is
2181
+ // also a geodesic.)
2182
+ unique_ptr<S2Polygon> nested(s2textformat::MakePolygon(
2183
+ "3:1, 3:-1, -3:-1, -3:1; 4:2, 4:-2, -4:-2, -4:2;"));
2184
+
2185
+ // All points on the boundary of the polygon should be at distance zero.
2186
+ for (int i = 0; i < nested->num_loops(); i++) {
2187
+ const S2Loop* loop = nested->loop(i);
2188
+ for (int j = 0; j < loop->num_vertices(); j++) {
2189
+ // A vertex.
2190
+ TestDistanceMethods(*nested, loop->vertex(j), S2Point());
2191
+ // A point along an edge.
2192
+ TestDistanceMethods(*nested, S2::Interpolate(
2193
+ S2Testing::rnd.RandDouble(), loop->vertex(j), loop->vertex(j+1)),
2194
+ S2Point());
2195
+ }
2196
+ }
2197
+ // A point outside the outer shell that projects to an edge.
2198
+ TestDistanceMethods(*nested, S2LatLng::FromDegrees(0, -4.7).ToPoint(),
2199
+ S2LatLng::FromDegrees(0, -2).ToPoint());
2200
+ // A point outside the outer shell that projects to a vertex.
2201
+ TestDistanceMethods(*nested, S2LatLng::FromDegrees(6, -3).ToPoint(),
2202
+ S2LatLng::FromDegrees(4, -2).ToPoint());
2203
+ // A point inside the polygon that projects to an outer edge.
2204
+ TestDistanceMethods(*nested, S2LatLng::FromDegrees(0, 1.7).ToPoint(),
2205
+ S2LatLng::FromDegrees(0, 2).ToPoint());
2206
+ // A point inside the polygon that projects to an inner vertex.
2207
+ TestDistanceMethods(*nested, S2LatLng::FromDegrees(-3.3, -1.3).ToPoint(),
2208
+ S2LatLng::FromDegrees(-3, -1).ToPoint());
2209
+ // A point inside the inner hole.
2210
+ TestDistanceMethods(*nested, S2LatLng::FromDegrees(0, 0.1).ToPoint(),
2211
+ S2LatLng::FromDegrees(0, 1).ToPoint());
2212
+ }
2213
+
2214
+ TEST_F(S2PolygonTestBase, Area) {
2215
+ EXPECT_DOUBLE_EQ(0.0, empty_->GetArea());
2216
+ EXPECT_DOUBLE_EQ(4 * M_PI, full_->GetArea());
2217
+ EXPECT_DOUBLE_EQ(2 * M_PI, south_H_->GetArea());
2218
+ EXPECT_DOUBLE_EQ(M_PI, far_H_south_H_->GetArea());
2219
+
2220
+ unique_ptr<S2Polygon> two_shells(
2221
+ MakePolygon(kCross1SideHole + kCrossCenterHole));
2222
+ EXPECT_DOUBLE_EQ(
2223
+ two_shells->loop(0)->GetArea() + two_shells->loop(1)->GetArea(),
2224
+ two_shells->GetArea());
2225
+
2226
+ unique_ptr<S2Polygon> holey_shell(MakePolygon(kCross1 + kCrossCenterHole));
2227
+ EXPECT_DOUBLE_EQ(
2228
+ holey_shell->loop(0)->GetArea() - holey_shell->loop(1)->GetArea(),
2229
+ holey_shell->GetArea());
2230
+ }
2231
+
2232
+ TEST(S2Polygon, UninitializedIsValid) {
2233
+ S2Polygon polygon;
2234
+ EXPECT_TRUE(polygon.IsValid());
2235
+ }
2236
+
2237
+ class IsValidTest : public testing::Test {
2238
+ public:
2239
+ IsValidTest() {
2240
+ init_oriented_ = false;
2241
+ modify_polygon_hook_ = nullptr;
2242
+ rnd_ = &S2Testing::rnd;
2243
+ rnd_->Reset(FLAGS_s2_random_seed);
2244
+ }
2245
+
2246
+ ~IsValidTest() override { Reset(); }
2247
+
2248
+ vector<S2Point>* AddLoop() {
2249
+ vloops_.push_back(make_unique<vector<S2Point>>());
2250
+ return vloops_.back().get();
2251
+ }
2252
+
2253
+ // Create "num_loops" nested regular loops around a common center point.
2254
+ // All loops have the same number of vertices (at least "min_vertices").
2255
+ // Furthermore, the vertices at the same index position are collinear with
2256
+ // the common center point of all the loops. The loop radii decrease
2257
+ // exponentially in order to prevent accidental loop crossings when one of
2258
+ // the loops is modified.
2259
+ void AddConcentricLoops(int num_loops, int min_vertices) {
2260
+ S2_DCHECK_LE(num_loops, 10); // Because radii decrease exponentially.
2261
+ S2Point center = S2Testing::RandomPoint();
2262
+ int num_vertices = min_vertices + rnd_->Uniform(10);
2263
+ for (int i = 0; i < num_loops; ++i) {
2264
+ S1Angle radius = S1Angle::Degrees(80 * pow(0.1, i));
2265
+ *AddLoop() = S2Testing::MakeRegularPoints(center, radius, num_vertices);
2266
+ }
2267
+ }
2268
+
2269
+ void Reset() {
2270
+ vloops_.clear();
2271
+ }
2272
+
2273
+ void CheckInvalid(const string& snippet) {
2274
+ vector<unique_ptr<S2Loop>> loops;
2275
+ for (const auto& vloop : vloops_) {
2276
+ loops.push_back(make_unique<S2Loop>(*vloop, S2Debug::DISABLE));
2277
+ }
2278
+ // Cannot replace with std::shuffle (b/65670707) since this uses an
2279
+ // incompatible random source which is also used as a source of randomness
2280
+ // in the surrounding code.
2281
+ // NOLINTNEXTLINE
2282
+ gtl::legacy_random_shuffle(loops.begin(), loops.end(), *rnd_);
2283
+ S2Polygon polygon;
2284
+ polygon.set_s2debug_override(S2Debug::DISABLE);
2285
+ if (init_oriented_) {
2286
+ polygon.InitOriented(std::move(loops));
2287
+ } else {
2288
+ polygon.InitNested(std::move(loops));
2289
+ }
2290
+ if (modify_polygon_hook_) (*modify_polygon_hook_)(&polygon);
2291
+ S2Error error;
2292
+ EXPECT_TRUE(polygon.FindValidationError(&error));
2293
+ EXPECT_TRUE(error.text().find(snippet) != string::npos)
2294
+ << "\nActual error: " << error << "\nExpected substring: " << snippet;
2295
+ Reset();
2296
+ }
2297
+
2298
+ protected:
2299
+ static const int kIters = 100;
2300
+
2301
+ bool init_oriented_;
2302
+ void (*modify_polygon_hook_)(S2Polygon*);
2303
+ S2Testing::Random* rnd_;
2304
+ vector<unique_ptr<vector<S2Point>>> vloops_;
2305
+ };
2306
+
2307
+ TEST_F(IsValidTest, UnitLength) {
2308
+ // This test can only be run in optimized builds because there are
2309
+ // S2_DCHECK(IsUnitLength()) calls scattered throughout the S2 code.
2310
+ if (google::DEBUG_MODE) return;
2311
+ for (int iter = 0; iter < kIters; ++iter) {
2312
+ AddConcentricLoops(1 + rnd_->Uniform(6), 3 /*min_vertices*/);
2313
+ vector<S2Point>* vloop = vloops_[rnd_->Uniform(vloops_.size())].get();
2314
+ S2Point* p = &(*vloop)[rnd_->Uniform(vloop->size())];
2315
+ switch (rnd_->Uniform(3)) {
2316
+ case 0: *p = S2Point(0, 0, 0); break;
2317
+ case 1: *p *= 1e-30 * pow(1e60, rnd_->RandDouble()); break;
2318
+ case 2: *p = numeric_limits<double>::quiet_NaN() * S2Point(); break;
2319
+ }
2320
+ CheckInvalid("unit length");
2321
+ }
2322
+ }
2323
+
2324
+ TEST_F(IsValidTest, VertexCount) {
2325
+ for (int iter = 0; iter < kIters; ++iter) {
2326
+ vector<S2Point>* vloop = AddLoop();
2327
+ if (rnd_->OneIn(2)) {
2328
+ vloop->push_back(S2Testing::RandomPoint());
2329
+ vloop->push_back(S2Testing::RandomPoint());
2330
+ }
2331
+ CheckInvalid("at least 3 vertices");
2332
+ }
2333
+ }
2334
+
2335
+ TEST_F(IsValidTest, DuplicateVertex) {
2336
+ for (int iter = 0; iter < kIters; ++iter) {
2337
+ AddConcentricLoops(1, 3 /*min_vertices*/);
2338
+ vector<S2Point>* vloop = vloops_[0].get();
2339
+ int n = vloop->size();
2340
+ int i = rnd_->Uniform(n);
2341
+ int j = rnd_->Uniform(n - 1);
2342
+ (*vloop)[i] = (*vloop)[j + (j >= i)];
2343
+ CheckInvalid("duplicate vertex");
2344
+ }
2345
+ }
2346
+
2347
+ TEST_F(IsValidTest, SelfIntersection) {
2348
+ for (int iter = 0; iter < kIters; ++iter) {
2349
+ // Use multiple loops so that we can test both holes and shells. We need
2350
+ // at least 5 vertices so that the modified edges don't intersect any
2351
+ // nested loops.
2352
+ AddConcentricLoops(1 + rnd_->Uniform(6), 5 /*min_vertices*/);
2353
+ vector<S2Point>* vloop = vloops_[rnd_->Uniform(vloops_.size())].get();
2354
+ int n = vloop->size();
2355
+ int i = rnd_->Uniform(n);
2356
+ swap((*vloop)[i], (*vloop)[(i+1) % n]);
2357
+ CheckInvalid("crosses edge");
2358
+ }
2359
+ }
2360
+
2361
+ TEST_F(IsValidTest, EmptyLoop) {
2362
+ for (int iter = 0; iter < kIters; ++iter) {
2363
+ AddConcentricLoops(rnd_->Uniform(5), 3 /*min_vertices*/);
2364
+ *AddLoop() = S2Loop::kEmpty();
2365
+ CheckInvalid("empty loop");
2366
+ }
2367
+ }
2368
+
2369
+ TEST_F(IsValidTest, FullLoop) {
2370
+ for (int iter = 0; iter < kIters; ++iter) {
2371
+ // This is only an error if there is at least one other loop.
2372
+ AddConcentricLoops(1 + rnd_->Uniform(5), 3 /*min_vertices*/);
2373
+ *AddLoop() = S2Loop::kFull();
2374
+ CheckInvalid("full loop");
2375
+ }
2376
+ }
2377
+
2378
+ TEST_F(IsValidTest, LoopsCrossing) {
2379
+ for (int iter = 0; iter < kIters; ++iter) {
2380
+ AddConcentricLoops(2, 4 /*min_vertices*/);
2381
+ // Both loops have the same number of vertices, and vertices at the same
2382
+ // index position are collinear with the center point, so we can create a
2383
+ // crossing by simply exchanging two vertices at the same index position.
2384
+ int n = vloops_[0]->size();
2385
+ int i = rnd_->Uniform(n);
2386
+ swap((*vloops_[0])[i], (*vloops_[1])[i]);
2387
+ if (rnd_->OneIn(2)) {
2388
+ // By copy the two adjacent vertices from one loop to the other, we can
2389
+ // ensure that the crossings happen at vertices rather than edges.
2390
+ (*vloops_[0])[(i+1) % n] = (*vloops_[1])[(i+1) % n];
2391
+ (*vloops_[0])[(i+n-1) % n] = (*vloops_[1])[(i+n-1) % n];
2392
+ }
2393
+ CheckInvalid("crosses loop");
2394
+ }
2395
+ }
2396
+
2397
+ TEST_F(IsValidTest, DuplicateEdge) {
2398
+ for (int iter = 0; iter < kIters; ++iter) {
2399
+ AddConcentricLoops(2, 4 /*min_vertices*/);
2400
+ int n = vloops_[0]->size();
2401
+ if (rnd_->OneIn(2)) {
2402
+ // Create a shared edge (same direction in both loops).
2403
+ int i = rnd_->Uniform(n);
2404
+ (*vloops_[0])[i] = (*vloops_[1])[i];
2405
+ (*vloops_[0])[(i+1) % n] = (*vloops_[1])[(i+1) % n];
2406
+ } else {
2407
+ // Create a reversed edge (opposite direction in each loop) by cutting
2408
+ // loop 0 into two halves along one of its diagonals and replacing both
2409
+ // loops with the result.
2410
+ int split = 2 + rnd_->Uniform(n - 3);
2411
+ vloops_[1]->clear();
2412
+ vloops_[1]->push_back((*vloops_[0])[0]);
2413
+ for (int i = split; i < n; ++i) {
2414
+ vloops_[1]->push_back((*vloops_[0])[i]);
2415
+ }
2416
+ vloops_[0]->resize(split + 1);
2417
+ }
2418
+ CheckInvalid("has duplicate");
2419
+ }
2420
+ }
2421
+
2422
+ TEST_F(IsValidTest, InconsistentOrientations) {
2423
+ for (int iter = 0; iter < kIters; ++iter) {
2424
+ AddConcentricLoops(2 + rnd_->Uniform(5), 3 /*min_vertices*/);
2425
+ init_oriented_ = true;
2426
+ CheckInvalid("Inconsistent loop orientations");
2427
+ }
2428
+ }
2429
+
2430
+ static void SetInvalidLoopDepth(S2Polygon* polygon) {
2431
+ int i = S2Testing::rnd.Uniform(polygon->num_loops());
2432
+ if (i == 0 || S2Testing::rnd.OneIn(3)) {
2433
+ polygon->loop(i)->set_depth(-1);
2434
+ } else {
2435
+ polygon->loop(i)->set_depth(polygon->loop(i-1)->depth() + 2);
2436
+ }
2437
+ }
2438
+
2439
+ TEST_F(IsValidTest, LoopDepthNegative) {
2440
+ modify_polygon_hook_ = SetInvalidLoopDepth;
2441
+ for (int iter = 0; iter < kIters; ++iter) {
2442
+ AddConcentricLoops(1 + rnd_->Uniform(4), 3 /*min_vertices*/);
2443
+ CheckInvalid("invalid loop depth");
2444
+ }
2445
+ }
2446
+
2447
+ static void SetInvalidLoopNesting(S2Polygon* polygon) {
2448
+ int i = S2Testing::rnd.Uniform(polygon->num_loops());
2449
+ polygon->loop(i)->Invert();
2450
+ }
2451
+
2452
+ TEST_F(IsValidTest, LoopNestingInvalid) {
2453
+ modify_polygon_hook_ = SetInvalidLoopNesting;
2454
+ for (int iter = 0; iter < kIters; ++iter) {
2455
+ AddConcentricLoops(2 + rnd_->Uniform(4), 3 /*min_vertices*/);
2456
+ // Randomly invert all the loops in order to generate cases where the
2457
+ // outer loop encompasses almost the entire sphere. This tests different
2458
+ // code paths because bounding box checks are not as useful.
2459
+ if (rnd_->OneIn(2)) {
2460
+ for (const auto& loop : vloops_) {
2461
+ std::reverse(loop->begin(), loop->end());
2462
+ }
2463
+ }
2464
+ CheckInvalid("Invalid nesting");
2465
+ }
2466
+ }
2467
+
2468
+ TEST_F(IsValidTest, FuzzTest) {
2469
+ // Check that the S2Loop/S2Polygon constructors and IsValid() don't crash
2470
+ // when they receive arbitrary invalid input. (We don't test large inputs;
2471
+ // it is assumed that the client enforces their own size limits before even
2472
+ // attempting to construct geometric objects.)
2473
+ if (google::DEBUG_MODE)
2474
+ return; // Requires unit length vertices.
2475
+ for (int iter = 0; iter < kIters; ++iter) {
2476
+ int num_loops = 1 + rnd_->Uniform(10);
2477
+ for (int i = 0; i < num_loops; ++i) {
2478
+ int num_vertices = rnd_->Uniform(10);
2479
+ vector<S2Point>* vloop = AddLoop();
2480
+ while (vloop->size() < num_vertices) {
2481
+ // Since the number of vertices is random, we automatically test empty
2482
+ // loops, full loops, and invalid vertex counts. Also since most
2483
+ // vertices are random, we automatically get self-intersections and
2484
+ // loop crossings. That leaves zero and NaN vertices, duplicate
2485
+ // vertices, and duplicate edges to be created explicitly.
2486
+ if (rnd_->OneIn(10)) {
2487
+ // Zero vertex.
2488
+ vloop->push_back(S2Point(0, 0, 0));
2489
+ } else if (rnd_->OneIn(10)) {
2490
+ // NaN vertex.
2491
+ vloop->push_back(numeric_limits<double>::quiet_NaN() * S2Point());
2492
+ } else if (rnd_->OneIn(10) && !vloop->empty()) {
2493
+ // Duplicate vertex.
2494
+ vloop->push_back((*vloop)[rnd_->Uniform(vloop->size())]);
2495
+ } else if (rnd_->OneIn(10) && vloop->size() + 2 <= num_vertices) {
2496
+ // Try to copy an edge from a random loop.
2497
+ vector<S2Point>* other = vloops_[rnd_->Uniform(vloops_.size())].get();
2498
+ int n = other->size();
2499
+ if (n >= 2) {
2500
+ int k0 = rnd_->Uniform(n);
2501
+ int k1 = (k0 + 1) % n;
2502
+ if (rnd_->OneIn(2)) swap(k0, k1); // Copy reversed edge.
2503
+ vloop->push_back((*other)[k0]);
2504
+ vloop->push_back((*other)[k1]);
2505
+ }
2506
+ } else {
2507
+ // Random non-unit-length point.
2508
+ S2Point p = S2Testing::RandomPoint();
2509
+ vloop->push_back(1e-30 * pow(1e60, rnd_->RandDouble()) * p);
2510
+ }
2511
+ }
2512
+ }
2513
+ CheckInvalid(""); // We could get any error message.
2514
+ }
2515
+ }
2516
+
2517
+ // Returns the diameter of a loop (maximum distance between any two
2518
+ // points in the loop).
2519
+ S1Angle LoopDiameter(const S2Loop& loop) {
2520
+ S1Angle diameter;
2521
+ for (int i = 0; i < loop.num_vertices(); ++i) {
2522
+ S2Point test_point = loop.vertex(i);
2523
+ for (int j = i + 1; j < loop.num_vertices(); ++j) {
2524
+ diameter = max(diameter,
2525
+ S2::GetDistance(test_point, loop.vertex(j),
2526
+ loop.vertex(j+1)));
2527
+ }
2528
+ }
2529
+ return diameter;
2530
+ }
2531
+
2532
+ // Returns the maximum distance from any vertex of poly_a to poly_b, that is,
2533
+ // the directed Haussdorf distance of the set of vertices of poly_a to the
2534
+ // boundary of poly_b.
2535
+ //
2536
+ // Doesn't consider loops from poly_a that have diameter less than min_diameter
2537
+ // in degrees.
2538
+ double MaximumDistanceInDegrees(const S2Polygon& poly_a,
2539
+ const S2Polygon& poly_b,
2540
+ double min_diameter_in_degrees) {
2541
+ double min_distance = 360;
2542
+ bool has_big_loops = false;
2543
+ for (int l = 0; l < poly_a.num_loops(); ++l) {
2544
+ const S2Loop* a_loop = poly_a.loop(l);
2545
+ if (LoopDiameter(*a_loop).degrees() <= min_diameter_in_degrees) {
2546
+ continue;
2547
+ }
2548
+ has_big_loops = true;
2549
+ for (int v = 0; v < a_loop->num_vertices(); ++v) {
2550
+ double distance = poly_b.GetDistance(a_loop->vertex(v)).degrees();
2551
+ if (distance < min_distance) {
2552
+ min_distance = distance;
2553
+ }
2554
+ }
2555
+ }
2556
+ if (has_big_loops) {
2557
+ return min_distance;
2558
+ } else {
2559
+ return 0.; // As if the first polygon were empty.
2560
+ }
2561
+ }
2562
+
2563
+ class S2PolygonSimplifierTest : public ::testing::Test {
2564
+ protected:
2565
+ void SetInput(unique_ptr<S2Polygon> poly, double tolerance_in_degrees) {
2566
+ original = std::move(poly);
2567
+
2568
+ simplified = make_unique<S2Polygon>();
2569
+ simplified->InitToSimplified(*original,
2570
+ s2builderutil::IdentitySnapFunction(
2571
+ S1Angle::Degrees(tolerance_in_degrees)));
2572
+ }
2573
+
2574
+ void SetInput(const string& poly, double tolerance_in_degrees) {
2575
+ SetInput(s2textformat::MakePolygon(poly), tolerance_in_degrees);
2576
+ }
2577
+
2578
+ unique_ptr<S2Polygon> simplified;
2579
+ unique_ptr<S2Polygon> original;
2580
+ };
2581
+
2582
+ TEST_F(S2PolygonSimplifierTest, NoSimplification) {
2583
+ SetInput("0:0, 0:20, 20:20, 20:0", 1.0);
2584
+ EXPECT_EQ(4, simplified->num_vertices());
2585
+
2586
+ EXPECT_EQ(0, MaximumDistanceInDegrees(*simplified, *original, 0));
2587
+ EXPECT_EQ(0, MaximumDistanceInDegrees(*original, *simplified, 0));
2588
+ }
2589
+
2590
+ // Here, 10:-2 will be removed and 0:0-20:0 will intersect two edges.
2591
+ // (The resulting polygon will in fact probably have more edges.)
2592
+ TEST_F(S2PolygonSimplifierTest, SimplifiedLoopSelfIntersects) {
2593
+ SetInput("0:0, 0:20, 10:-0.1, 20:20, 20:0, 10:-0.2", 0.22);
2594
+
2595
+ // The simplified polygon has the same number of vertices but it should now
2596
+ // consists of two loops rather than one.
2597
+ EXPECT_EQ(2, simplified->num_loops());
2598
+ EXPECT_GE(0.22, MaximumDistanceInDegrees(*simplified, *original, 0));
2599
+ EXPECT_GE(0.22, MaximumDistanceInDegrees(*original, *simplified, 0.22));
2600
+ }
2601
+
2602
+ TEST_F(S2PolygonSimplifierTest, NoSimplificationManyLoops) {
2603
+ SetInput("0:0, 0:1, 1:0; 0:20, 0:21, 1:20; "
2604
+ "20:20, 20:21, 21:20; 20:0, 20:1, 21:0", 0.01);
2605
+ EXPECT_EQ(0, MaximumDistanceInDegrees(*simplified, *original, 0));
2606
+ EXPECT_EQ(0, MaximumDistanceInDegrees(*original, *simplified, 0));
2607
+ }
2608
+
2609
+ TEST_F(S2PolygonSimplifierTest, TinyLoopDisappears) {
2610
+ SetInput("0:0, 0:1, 1:1, 1:0", 1.1);
2611
+ EXPECT_TRUE(simplified->is_empty());
2612
+ }
2613
+
2614
+ TEST_F(S2PolygonSimplifierTest, StraightLinesAreSimplified) {
2615
+ SetInput("0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0,"
2616
+ "6:1, 5:1, 4:1, 3:1, 2:1, 1:1, 0:1", 0.01);
2617
+ EXPECT_EQ(4, simplified->num_vertices());
2618
+ }
2619
+
2620
+ TEST_F(S2PolygonSimplifierTest, EdgeSplitInManyPieces) {
2621
+ // near_square's right four-point side will be simplified to a vertical
2622
+ // line at lng=7.9, that will cut the 9 teeth of the saw (the edge will
2623
+ // therefore be broken into 19 pieces).
2624
+ const string saw =
2625
+ "1:1, 1:8, 2:2, 2:8, 3:2, 3:8, 4:2, 4:8, 5:2, 5:8,"
2626
+ "6:2, 6:8, 7:2, 7:8, 8:2, 8:8, 9:2, 9:8, 10:1";
2627
+ const string near_square =
2628
+ "0:0, 0:7.9, 1:8.1, 10:8.1, 11:7.9, 11:0";
2629
+ SetInput(saw + ";" + near_square, 0.21);
2630
+
2631
+ EXPECT_TRUE(simplified->IsValid());
2632
+ EXPECT_GE(0.11, MaximumDistanceInDegrees(*simplified, *original, 0));
2633
+ EXPECT_GE(0.11, MaximumDistanceInDegrees(*original, *simplified, 0));
2634
+ // The resulting polygon's 9 little teeth are very small and disappear
2635
+ // due to the vertex_merge_radius of the polygon builder. There remains
2636
+ // nine loops.
2637
+ EXPECT_EQ(9, simplified->num_loops());
2638
+ }
2639
+
2640
+ TEST_F(S2PolygonSimplifierTest, EdgesOverlap) {
2641
+ // Two loops, One edge of the second one ([0:1 - 0:2]) is part of an
2642
+ // edge of the first one..
2643
+ SetInput("0:0, 0:3, 1:0; 0:1, -1:1, 0:2", 0.01);
2644
+ unique_ptr<S2Polygon> true_poly(
2645
+ s2textformat::MakePolygon("0:3, 1:0, 0:0, 0:1, -1:1, 0:2"));
2646
+ EXPECT_TRUE(simplified->BoundaryApproxEquals(*true_poly,
2647
+ S1Angle::Radians(1e-15)));
2648
+ }
2649
+
2650
+ // Creates a polygon from loops specified as a comma separated list of u:v
2651
+ // coordinates relative to a cell. The loop "0:0, 1:0, 1:1, 0:1" is
2652
+ // counter-clockwise.
2653
+ unique_ptr<S2Polygon> MakeCellPolygon(
2654
+ const S2Cell& cell, const vector<const char *>& strs) {
2655
+ vector<unique_ptr<S2Loop>> loops;
2656
+ for (auto str : strs) {
2657
+ vector<S2LatLng> points = s2textformat::ParseLatLngs(str);
2658
+ vector<S2Point> loop_vertices;
2659
+ R2Rect uv = cell.GetBoundUV();
2660
+ for (const S2LatLng& p : points) {
2661
+ double u = p.lat().degrees(), v = p.lng().degrees();
2662
+ loop_vertices.push_back(
2663
+ S2::FaceUVtoXYZ(cell.face(),
2664
+ uv[0][0] * (1 - u) + uv[0][1] * u,
2665
+ uv[1][0] * (1 - v) + uv[1][1] * v).Normalize());
2666
+ }
2667
+ loops.emplace_back(new S2Loop(loop_vertices));
2668
+ }
2669
+ return make_unique<S2Polygon>(std::move(loops));
2670
+ }
2671
+
2672
+ TEST(InitToSimplifiedInCell, PointsOnCellBoundaryKept) {
2673
+ S2Cell cell(S2CellId::FromToken("89c25c"));
2674
+ auto polygon = MakeCellPolygon(cell, {"0.1:0, 0.2:0, 0.2:0.5"});
2675
+ S1Angle tolerance =
2676
+ S1Angle(polygon->loop(0)->vertex(0), polygon->loop(0)->vertex(1)) * 1.1;
2677
+ S2Polygon simplified;
2678
+ simplified.InitToSimplified(*polygon,
2679
+ s2builderutil::IdentitySnapFunction(tolerance));
2680
+ EXPECT_TRUE(simplified.is_empty());
2681
+ S2Polygon simplified_in_cell;
2682
+ simplified_in_cell.InitToSimplifiedInCell(polygon.get(), cell, tolerance);
2683
+ EXPECT_TRUE(simplified_in_cell.BoundaryEquals(polygon.get()));
2684
+ EXPECT_EQ(3, simplified_in_cell.num_vertices());
2685
+ EXPECT_EQ(-1, simplified.GetSnapLevel());
2686
+ }
2687
+
2688
+ TEST(InitToSimplifiedInCell, PointsInsideCellSimplified) {
2689
+ S2CellId cell_id = S2CellId::FromToken("89c25c");
2690
+ S2Cell cell(cell_id);
2691
+ auto polygon = MakeCellPolygon(
2692
+ cell, {"0.3:0, 0.4:0, 0.4:0.5, 0.4:0.8, 0.2:0.8"});
2693
+ S1Angle tolerance =
2694
+ S1Angle(polygon->loop(0)->vertex(0), polygon->loop(0)->vertex(1)) * 1.1;
2695
+ S2Polygon simplified;
2696
+ simplified.InitToSimplifiedInCell(polygon.get(), cell, tolerance);
2697
+ EXPECT_TRUE(simplified.BoundaryNear(*polygon, S1Angle::Radians(1e-15)));
2698
+ EXPECT_EQ(4, simplified.num_vertices());
2699
+ EXPECT_EQ(-1, simplified.GetSnapLevel());
2700
+ }
2701
+
2702
+ TEST(InitToSimplifiedInCell, CellCornerKept) {
2703
+ S2Cell cell(S2CellId::FromToken("00001"));
2704
+ auto input = MakeCellPolygon(cell, {"1:0, 1:0.05, 0.99:0"});
2705
+ S1Angle tolerance = 0.02 * S1Angle(cell.GetVertex(0), cell.GetVertex(1));
2706
+ S2Polygon simplified;
2707
+ simplified.InitToSimplifiedInCell(input.get(), cell, tolerance);
2708
+ EXPECT_TRUE(simplified.BoundaryNear(*input, S1Angle::Radians(1e-15)));
2709
+ }
2710
+
2711
+ TEST(InitToSimplifiedInCell, NarrowStripRemoved) {
2712
+ S2Cell cell(S2CellId::FromToken("00001"));
2713
+ auto input = MakeCellPolygon(cell, {"0.9:0, 0.91:0, 0.91:1, 0.9:1"});
2714
+ S1Angle tolerance = 0.02 * S1Angle(cell.GetVertex(0), cell.GetVertex(1));
2715
+ S2Polygon simplified;
2716
+ simplified.InitToSimplifiedInCell(input.get(), cell, tolerance);
2717
+ EXPECT_TRUE(simplified.is_empty());
2718
+ }
2719
+
2720
+ TEST(InitToSimplifiedInCell, NarrowGapRemoved) {
2721
+ S2Cell cell(S2CellId::FromToken("00001"));
2722
+ auto input = MakeCellPolygon(
2723
+ cell, {"0.7:0, 0.75:0, 0.75:1, 0.7:1", "0.76:0, 0.8:0, 0.8:1, 0.76:1"});
2724
+ auto expected = MakeCellPolygon(cell, {"0.7:0, 0.8:0, 0.8:1, 0.7:1"});
2725
+ S1Angle tolerance = 0.02 * S1Angle(cell.GetVertex(0), cell.GetVertex(1));
2726
+ S2Polygon simplified;
2727
+ simplified.InitToSimplifiedInCell(input.get(), cell, tolerance);
2728
+ EXPECT_TRUE(simplified.BoundaryNear(*expected, S1Angle::Radians(1e-15)));
2729
+ }
2730
+
2731
+ TEST(InitToSimplifiedInCell, CloselySpacedEdgeVerticesKept) {
2732
+ S2Cell cell(S2CellId::FromToken("00001"));
2733
+ auto input = MakeCellPolygon(
2734
+ cell, {"0:0.303, 0:0.302, 0:0.301, 0:0.3, 0.1:0.3, 0.1:0.4"});
2735
+ S1Angle tolerance = 0.02 * S1Angle(cell.GetVertex(0), cell.GetVertex(1));
2736
+ S2Polygon simplified;
2737
+ simplified.InitToSimplifiedInCell(input.get(), cell, tolerance);
2738
+ EXPECT_TRUE(simplified.BoundaryApproxEquals(*input, S1Angle::Radians(1e-15)));
2739
+ }
2740
+
2741
+ TEST(InitToSimplifiedInCell, PolylineAssemblyBug) {
2742
+ S2Cell cell(S2CellId::FromToken("5701"));
2743
+ auto polygon = MakePolygon(
2744
+ "55.8699252:-163.9412145, " // South-west corner of 5701
2745
+ "54.7672352:-166.7579678, " // North-east corner of 5701
2746
+ /* Offending part: a tiny triangle near south-east corner */
2747
+ "54.7109214:-164.6376338, " // forced vertex, on edge 4
2748
+ "54.7140193:-164.6398404, "
2749
+ "54.7113202:-164.6374015"); // forced vertex, on edge 4
2750
+ S1Angle tolerance = S1Angle::Radians(2.138358e-05); // 136.235m
2751
+ S1Angle max_dist = S1Angle::Radians(2.821947e-09); // 18mm
2752
+ S2Polygon simplified_in_cell;
2753
+ simplified_in_cell.InitToSimplifiedInCell(polygon.get(), cell, tolerance,
2754
+ max_dist);
2755
+ EXPECT_FALSE(simplified_in_cell.is_empty());
2756
+ }
2757
+
2758
+ TEST(InitToSimplifiedInCell, InteriorEdgesSnappedToBoundary) {
2759
+ auto polygon = s2textformat::MakePolygonOrDie(
2760
+ "37.8011672:-122.3247322, 37.8011648:-122.3247399, "
2761
+ "37.8011647:-122.3247403, 37.8011646:-122.3247408, "
2762
+ "37.8011645:-122.3247411, 37.8011633:-122.3247449, "
2763
+ "37.8011621:-122.3247334");
2764
+ S2Cell cell(S2CellId::FromDebugString("4/001013300"));
2765
+ S1Angle snap_radius = S2Testing::MetersToAngle(1.0);
2766
+ S1Angle boundary_tolerance =
2767
+ S1Angle::Radians(0.5 * S2::kMaxWidth.GetValue(S2CellId::kMaxLevel - 1)) +
2768
+ s2builderutil::IntLatLngSnapFunction::MinSnapRadiusForExponent(7);
2769
+ S2Polygon simplified_polygon;
2770
+ simplified_polygon.set_s2debug_override(S2Debug::DISABLE);
2771
+ simplified_polygon.InitToSimplifiedInCell(polygon.get(), cell, snap_radius,
2772
+ boundary_tolerance);
2773
+ S2Error error;
2774
+ EXPECT_FALSE(simplified_polygon.FindValidationError(&error)) << error;
2775
+ }
2776
+
2777
+
2778
+ unique_ptr<S2Polygon> MakeRegularPolygon(
2779
+ const string& center, int num_points, double radius_in_degrees) {
2780
+ S1Angle radius = S1Angle::Degrees(radius_in_degrees);
2781
+ return make_unique<S2Polygon>(S2Loop::MakeRegularLoop(
2782
+ s2textformat::MakePoint(center), radius, num_points));
2783
+ }
2784
+
2785
+ // Tests that a regular polygon with many points gets simplified
2786
+ // enough.
2787
+ TEST_F(S2PolygonSimplifierTest, LargeRegularPolygon) {
2788
+ const double kRadius = 2.; // in degrees
2789
+ const int num_initial_points = 1000;
2790
+ const int num_desired_points = 250;
2791
+ double tolerance = 1.05 * kRadius * (1 - cos(M_PI / num_desired_points));
2792
+
2793
+ SetInput(MakeRegularPolygon("0:0", num_initial_points, kRadius), tolerance);
2794
+
2795
+ EXPECT_GE(tolerance, MaximumDistanceInDegrees(*simplified, *original, 0));
2796
+ EXPECT_GE(tolerance, MaximumDistanceInDegrees(*original, *simplified, 0));
2797
+ EXPECT_GE(250, simplified->num_vertices());
2798
+ EXPECT_LE(200, simplified->num_vertices());
2799
+ }
2800
+
2801
+ class S2PolygonDecodeTest : public ::testing::Test {
2802
+ protected:
2803
+ S2PolygonDecodeTest() : data_array_(kMaxBytes) {
2804
+ encoder_.reset(data_array_.data(), kMaxBytes);
2805
+ }
2806
+
2807
+ ~S2PolygonDecodeTest() override {}
2808
+
2809
+ void AppendByte(int value) {
2810
+ encoder_.put8(value);
2811
+ }
2812
+
2813
+ void AppendInt32(int value) {
2814
+ encoder_.put32(value);
2815
+ }
2816
+
2817
+ void AppendRandomData(int size) {
2818
+ for (int i = 0; i < size && encoder_.avail() > 0; ++i) {
2819
+ AppendByte(random_.Uniform(256));
2820
+ }
2821
+ }
2822
+
2823
+ void AppendRandomData() {
2824
+ AppendRandomData(random_.Uniform(kMaxBytes));
2825
+ }
2826
+
2827
+ void AppendFakeUncompressedEncodingData() {
2828
+ AppendByte(1); // polygon number
2829
+ AppendByte(0); // unused
2830
+ AppendByte(0); // "has holes" flag
2831
+ AppendInt32(PickRandomCount()); // num loops
2832
+ AppendByte(1); // loop version
2833
+ AppendInt32(PickRandomCount()); // num vertices
2834
+ AppendRandomData(); // junk to fill out the buffer
2835
+ }
2836
+
2837
+ void AppendFakeCompressedEncodingData() {
2838
+ AppendByte(4); // polygon number
2839
+ AppendByte(random_.Uniform(50)); // snap level
2840
+ AppendInt32(PickRandomCount()); // num loops
2841
+ AppendInt32(PickRandomCount()); // num vertices
2842
+ AppendRandomData(); // junk to fill out the buffer
2843
+ }
2844
+
2845
+ int32 PickRandomCount() {
2846
+ if (random_.OneIn(10)) {
2847
+ return -1;
2848
+ }
2849
+ if (random_.OneIn(10)) {
2850
+ return 0;
2851
+ }
2852
+ if (random_.OneIn(10)) {
2853
+ return 1000000000;
2854
+ }
2855
+ if (random_.OneIn(2)) {
2856
+ return random_.Uniform(1000000000);
2857
+ }
2858
+ return random_.Uniform(1000);
2859
+ }
2860
+
2861
+ bool Test() {
2862
+ decoder_.reset(data_array_.data(), encoder_.length());
2863
+ encoder_.clear();
2864
+ S2Polygon polygon;
2865
+ polygon.set_s2debug_override(S2Debug::DISABLE);
2866
+ return polygon.Decode(&decoder_);
2867
+ }
2868
+
2869
+ // Random number generator.
2870
+ S2Testing::Random random_;
2871
+
2872
+ // Maximum size of the data array.
2873
+ const int kMaxBytes = 256;
2874
+
2875
+ // The data array.
2876
+ absl::FixedArray<int8> data_array_;
2877
+
2878
+ // Encoder that is used to put data into the array.
2879
+ Encoder encoder_;
2880
+
2881
+ // Decoder used to extract data from the array.
2882
+ Decoder decoder_;
2883
+ };
2884
+
2885
+ TEST_F(S2PolygonDecodeTest, FuzzUncompressedEncoding) {
2886
+ // Some parts of the S2 library S2_DCHECK on invalid data, even if we set
2887
+ // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we
2888
+ // only run this test in opt mode.
2889
+ #ifdef NDEBUG
2890
+ for (int i = 0; i < 100000; ++i) {
2891
+ AppendFakeUncompressedEncodingData();
2892
+ Test();
2893
+ }
2894
+ #endif
2895
+ }
2896
+
2897
+ TEST_F(S2PolygonDecodeTest, FuzzCompressedEncoding) {
2898
+ // Some parts of the S2 library S2_DCHECK on invalid data, even if we set
2899
+ // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we
2900
+ // only run this test in opt mode.
2901
+ #ifdef NDEBUG
2902
+ for (int i = 0; i < 100000; ++i) {
2903
+ AppendFakeCompressedEncodingData();
2904
+ Test();
2905
+ }
2906
+ #endif
2907
+ }
2908
+
2909
+ TEST_F(S2PolygonDecodeTest, FuzzEverything) {
2910
+ // Some parts of the S2 library S2_DCHECK on invalid data, even if we set
2911
+ // FLAGS_s2debug to false or use S2Polygon::set_s2debug_override. So we
2912
+ // only run this test in opt mode.
2913
+ #ifdef NDEBUG
2914
+ for (int i = 0; i < 100000; ++i) {
2915
+ AppendRandomData();
2916
+ Test();
2917
+ }
2918
+ #endif
2919
+ }
2920
+
2921
+ TEST_F(S2PolygonTestBase, FullPolygonShape) {
2922
+ S2Polygon::Shape shape(full_.get());
2923
+ EXPECT_EQ(0, shape.num_edges());
2924
+ EXPECT_EQ(2, shape.dimension());
2925
+ EXPECT_FALSE(shape.is_empty());
2926
+ EXPECT_TRUE(shape.is_full());
2927
+ EXPECT_EQ(1, shape.num_chains());
2928
+ EXPECT_EQ(0, shape.chain(0).start);
2929
+ EXPECT_EQ(0, shape.chain(0).length);
2930
+ EXPECT_TRUE(shape.GetReferencePoint().contained);
2931
+ }
2932
+
2933
+ TEST_F(S2PolygonTestBase, EmptyPolygonShape) {
2934
+ S2Polygon::Shape shape(empty_.get());
2935
+ EXPECT_EQ(0, shape.num_edges());
2936
+ EXPECT_EQ(2, shape.dimension());
2937
+ EXPECT_TRUE(shape.is_empty());
2938
+ EXPECT_FALSE(shape.is_full());
2939
+ EXPECT_EQ(0, shape.num_chains());
2940
+ EXPECT_FALSE(shape.GetReferencePoint().contained);
2941
+ }
2942
+
2943
+ void TestPolygonShape(const S2Polygon& polygon) {
2944
+ S2_DCHECK(!polygon.is_full());
2945
+ S2Polygon::Shape shape(&polygon);
2946
+ EXPECT_EQ(&polygon, shape.polygon());
2947
+ EXPECT_EQ(polygon.num_vertices(), shape.num_edges());
2948
+ EXPECT_EQ(polygon.num_loops(), shape.num_chains());
2949
+ for (int e = 0, i = 0; i < polygon.num_loops(); ++i) {
2950
+ const S2Loop* loop_i = polygon.loop(i);
2951
+ EXPECT_EQ(e, shape.chain(i).start);
2952
+ EXPECT_EQ(loop_i->num_vertices(), shape.chain(i).length);
2953
+ for (int j = 0; j < loop_i->num_vertices(); ++j, ++e) {
2954
+ auto edge = shape.edge(e);
2955
+ EXPECT_EQ(loop_i->oriented_vertex(j), edge.v0);
2956
+ EXPECT_EQ(loop_i->oriented_vertex(j+1), edge.v1);
2957
+ }
2958
+ }
2959
+ EXPECT_EQ(2, shape.dimension());
2960
+ EXPECT_FALSE(shape.is_empty());
2961
+ EXPECT_FALSE(shape.is_full());
2962
+ EXPECT_EQ(polygon.Contains(S2::Origin()),
2963
+ shape.GetReferencePoint().contained);
2964
+ }
2965
+
2966
+ TEST_F(S2PolygonTestBase, OneLoopPolygonShape) {
2967
+ TestPolygonShape(*near_0_);
2968
+ }
2969
+
2970
+ TEST_F(S2PolygonTestBase, SeveralLoopPolygonShape) {
2971
+ TestPolygonShape(*near_3210_);
2972
+ }
2973
+
2974
+ TEST(S2Polygon, ManyLoopPolygonShape) {
2975
+ const int kNumLoops = 100;
2976
+ const int kNumVerticesPerLoop = 6;
2977
+ S2Polygon polygon;
2978
+ S2Testing::ConcentricLoopsPolygon(S2Point(1, 0, 0), kNumLoops,
2979
+ kNumVerticesPerLoop, &polygon);
2980
+ TestPolygonShape(polygon);
2981
+ }
2982
+
2983
+ TEST(S2PolygonOwningShape, Ownership) {
2984
+ // Debug mode builds will catch any memory leak below.
2985
+ vector<unique_ptr<S2Loop>> loops;
2986
+ auto polygon = make_unique<S2Polygon>(std::move(loops));
2987
+ S2Polygon::OwningShape shape(std::move(polygon));
2988
+ }
2989
+
2990
+ TEST(S2Polygon, PointInBigLoop) {
2991
+ // This code used to demonstrate a bug in S2ShapeIndex.
2992
+ S2LatLng center = S2LatLng::FromRadians(0.3, 2);
2993
+ S1Angle radius = S1Angle::Degrees(80);
2994
+ S2Polygon poly(S2Loop::MakeRegularLoop(center.ToPoint(), radius, 10));
2995
+ EXPECT_TRUE(poly.MayIntersect(S2Cell(S2CellId(center))));
2996
+ }
2997
+
2998
+ TEST(S2Polygon, Sizes) {
2999
+ // This isn't really a test. It just prints the sizes of various classes.
3000
+ S2_LOG(INFO) << "sizeof(S2Loop): " << sizeof(S2Loop);
3001
+ S2_LOG(INFO) << "sizeof(S2Polygon): " << sizeof(S2Polygon);
3002
+ S2_LOG(INFO) << "sizeof(S2Polyline): " << sizeof(S2Polyline);
3003
+ S2_LOG(INFO) << "sizeof(MutableS2ShapeIndex): " << sizeof(MutableS2ShapeIndex);
3004
+ S2_LOG(INFO) << "sizeof(S2Polygon::Shape): " << sizeof(S2Polygon::Shape);
3005
+ S2_LOG(INFO) << "sizeof(S2Cell): " << sizeof(S2Cell);
3006
+ S2_LOG(INFO) << "sizeof(S2PaddedCell): " << sizeof(S2PaddedCell);
3007
+ }
3008
+
3009
+ TEST_F(S2PolygonTestBase, IndexContainsOnePolygonShape) {
3010
+ const MutableS2ShapeIndex& index = near_0_->index();
3011
+ ASSERT_EQ(1, index.num_shape_ids());
3012
+ S2Polygon::Shape* shape = down_cast<S2Polygon::Shape*>(index.shape(0));
3013
+ EXPECT_EQ(near_0_.get(), shape->polygon());
3014
+ }
3015
+
3016
+ TEST_F(S2PolygonTestBase, PolygonPolygonDistance) {
3017
+ // Verify that the example code for S2Polygon::index() actually works.
3018
+ const S2Polygon& polygon1 = *near_0_;
3019
+ const S2Polygon& polygon2 = *far_10_;
3020
+ S2ClosestEdgeQuery query(&polygon1.index());
3021
+ S2ClosestEdgeQuery::ShapeIndexTarget target(&polygon2.index());
3022
+ S1ChordAngle distance = query.GetDistance(&target);
3023
+ EXPECT_GT(distance, S1ChordAngle(S1Angle::Degrees(175)));
3024
+ }
3025
+