@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,1585 @@
1
+ // Copyright 2012 Google Inc. All Rights Reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS-IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ //
15
+
16
+ // Author: ericv@google.com (Eric Veach)
17
+
18
+ #include "s2/mutable_s2shape_index.h"
19
+
20
+ #include <algorithm>
21
+ #include <atomic>
22
+ #include <cmath>
23
+
24
+ #include "s2/base/casts.h"
25
+ #include "s2/base/commandlineflags.h"
26
+ #include "s2/base/spinlock.h"
27
+ #include "s2/encoded_s2cell_id_vector.h"
28
+ #include "s2/encoded_string_vector.h"
29
+ #include "s2/r1interval.h"
30
+ #include "s2/r2.h"
31
+ #include "s2/r2rect.h"
32
+ #include "s2/s2cell_id.h"
33
+ #include "s2/s2cell_union.h"
34
+ #include "s2/s2coords.h"
35
+ #include "s2/s2edge_clipping.h"
36
+ #include "s2/s2edge_crosser.h"
37
+ #include "s2/s2metrics.h"
38
+ #include "s2/s2padded_cell.h"
39
+ #include "s2/s2pointutil.h"
40
+ #include "s2/s2shapeutil_contains_brute_force.h"
41
+
42
+ using std::fabs;
43
+ using std::max;
44
+ using std::unique_ptr;
45
+ using std::vector;
46
+
47
+ // FLAGS_s2shape_index_default_max_edges_per_cell
48
+ //
49
+ // The default maximum number of edges per cell (not counting "long" edges).
50
+ // If a cell has more than this many edges, and it is not a leaf cell, then it
51
+ // is subdivided. This flag can be overridden via MutableS2ShapeIndex::Options.
52
+ // Reasonable values range from 10 to about 50 or so.
53
+ S2_DEFINE_int32(
54
+ s2shape_index_default_max_edges_per_cell, 10,
55
+ "Default maximum number of edges (not counting 'long' edges) per cell; "
56
+ "reasonable values range from 10 to 50. Small values makes queries "
57
+ "faster, while large values make construction faster and use less "
58
+ "memory.");
59
+
60
+ // FLAGS_s2shape_index_tmp_memory_budget_mb
61
+ //
62
+ // Attempt to limit the amount of temporary memory allocated while building or
63
+ // updating a MutableS2ShapeIndex to at most this value. This is achieved by
64
+ // splitting the updates into multiple batches when necessary. (The memory
65
+ // required is proportional to the number of edges being updated at once.)
66
+ //
67
+ // Note that this limit is not a hard guarantee, for several reasons:
68
+ // (1) the memory estimates are only approximations;
69
+ // (2) all edges in a given shape are added or removed at once, so shapes
70
+ // with huge numbers of edges may exceed the budget;
71
+ // (3) shapes being removed are always processed in a single batch. (This
72
+ // could be fixed, but it seems better to keep the code simpler for now.)
73
+ S2_DEFINE_int32(
74
+ s2shape_index_tmp_memory_budget_mb, 100,
75
+ "Attempts to limit the amount of temporary memory used by "
76
+ "MutableS2ShapeIndex when creating or updating very large indexes "
77
+ "to at most this value. If more memory than this is needed, updates "
78
+ "will automatically be split into batches internally.");
79
+
80
+ // FLAGS_s2shape_index_cell_size_to_long_edge_ratio
81
+ //
82
+ // The cell size relative to the length of an edge at which it is first
83
+ // considered to be "long". Long edges do not contribute toward the decision
84
+ // to subdivide a cell further. For example, a value of 2.0 means that the
85
+ // cell must be at least twice the size of the edge in order for that edge to
86
+ // be counted. There are two reasons for not counting long edges: (1) such
87
+ // edges typically need to be propagated to several children, which increases
88
+ // time and memory costs without much benefit, and (2) in pathological cases,
89
+ // many long edges close together could force subdivision to continue all the
90
+ // way to the leaf cell level.
91
+ S2_DEFINE_double(
92
+ s2shape_index_cell_size_to_long_edge_ratio, 1.0,
93
+ "The cell size relative to the length of an edge at which it is first "
94
+ "considered to be 'long'. Long edges do not contribute to the decision "
95
+ "to subdivide a cell further. The size and speed of the index are "
96
+ "typically not very sensitive to this parameter. Reasonable values range "
97
+ "from 0.1 to 10, with smaller values causing more aggressive subdivision "
98
+ "of long edges grouped closely together.");
99
+
100
+ // The total error when clipping an edge comes from two sources:
101
+ // (1) Clipping the original spherical edge to a cube face (the "face edge").
102
+ // The maximum error in this step is S2::kFaceClipErrorUVCoord.
103
+ // (2) Clipping the face edge to the u- or v-coordinate of a cell boundary.
104
+ // The maximum error in this step is S2::kEdgeClipErrorUVCoord.
105
+ // Finally, since we encounter the same errors when clipping query edges, we
106
+ // double the total error so that we only need to pad edges during indexing
107
+ // and not at query time.
108
+ const double MutableS2ShapeIndex::kCellPadding =
109
+ 2 * (S2::kFaceClipErrorUVCoord + S2::kEdgeClipErrorUVCoord);
110
+
111
+ MutableS2ShapeIndex::Options::Options()
112
+ : max_edges_per_cell_(FLAGS_s2shape_index_default_max_edges_per_cell) {
113
+ }
114
+
115
+ void MutableS2ShapeIndex::Options::set_max_edges_per_cell(
116
+ int max_edges_per_cell) {
117
+ max_edges_per_cell_ = max_edges_per_cell;
118
+ }
119
+
120
+ bool MutableS2ShapeIndex::Iterator::Locate(const S2Point& target) {
121
+ return LocateImpl(target, this);
122
+ }
123
+
124
+ MutableS2ShapeIndex::CellRelation MutableS2ShapeIndex::Iterator::Locate(
125
+ S2CellId target) {
126
+ return LocateImpl(target, this);
127
+ }
128
+
129
+ const S2ShapeIndexCell* MutableS2ShapeIndex::Iterator::GetCell() const {
130
+ S2_LOG(DFATAL) << "Should never be called";
131
+ return nullptr;
132
+ }
133
+
134
+ unique_ptr<MutableS2ShapeIndex::IteratorBase>
135
+ MutableS2ShapeIndex::Iterator::Clone() const {
136
+ return absl::make_unique<Iterator>(*this);
137
+ }
138
+
139
+ void MutableS2ShapeIndex::Iterator::Copy(const IteratorBase& other) {
140
+ *this = *down_cast<const Iterator*>(&other);
141
+ }
142
+
143
+ // Defines the initial focus point of MutableS2ShapeIndex::InteriorTracker
144
+ // (the start of the S2CellId space-filling curve).
145
+ //
146
+ // TODO(ericv): Move InteriorTracker here to avoid the need for this method.
147
+ static S2Point kInteriorTrackerOrigin() {
148
+ return S2::FaceUVtoXYZ(0, -1, -1).Normalize();
149
+ }
150
+
151
+ MutableS2ShapeIndex::MutableS2ShapeIndex()
152
+ : index_status_(FRESH) {
153
+ }
154
+
155
+ MutableS2ShapeIndex::MutableS2ShapeIndex(const Options& options)
156
+ : options_(options),
157
+ index_status_(FRESH) {
158
+ }
159
+
160
+ void MutableS2ShapeIndex::Init(const Options& options) {
161
+ S2_DCHECK(shapes_.empty());
162
+ options_ = options;
163
+ }
164
+
165
+ MutableS2ShapeIndex::~MutableS2ShapeIndex() {
166
+ Clear();
167
+ }
168
+
169
+ void MutableS2ShapeIndex::Minimize() {
170
+ // TODO(ericv): Implement. In theory we should be able to discard the
171
+ // entire index and rebuild it the next time it is needed.
172
+ }
173
+
174
+ int MutableS2ShapeIndex::Add(unique_ptr<S2Shape> shape) {
175
+ // Additions are processed lazily by ApplyUpdates().
176
+ const int id = shapes_.size();
177
+ shape->id_ = id;
178
+ shapes_.push_back(std::move(shape));
179
+ index_status_.store(STALE, std::memory_order_relaxed);
180
+ return id;
181
+ }
182
+
183
+ unique_ptr<S2Shape> MutableS2ShapeIndex::Release(int shape_id) {
184
+ // This class updates itself lazily, because it is much more efficient to
185
+ // process additions and removals in batches. However this means that when
186
+ // a shape is removed, we need to make a copy of all its edges, since the
187
+ // client is free to delete "shape" once this call is finished.
188
+
189
+ S2_DCHECK(shapes_[shape_id] != nullptr);
190
+ auto shape = std::move(shapes_[shape_id]);
191
+ if (shape_id >= pending_additions_begin_) {
192
+ // We are removing a shape that has not yet been added to the index,
193
+ // so there is nothing else to do.
194
+ } else {
195
+ if (!pending_removals_) {
196
+ pending_removals_.reset(new vector<RemovedShape>);
197
+ }
198
+ // We build the new RemovedShape in place, since it includes a potentially
199
+ // large vector of edges that might be expensive to copy.
200
+ pending_removals_->push_back(RemovedShape());
201
+ RemovedShape* removed = &pending_removals_->back();
202
+ removed->shape_id = shape->id();
203
+ removed->has_interior = (shape->dimension() == 2);
204
+ removed->contains_tracker_origin =
205
+ s2shapeutil::ContainsBruteForce(*shape, kInteriorTrackerOrigin());
206
+ int num_edges = shape->num_edges();
207
+ removed->edges.reserve(num_edges);
208
+ for (int e = 0; e < num_edges; ++e) {
209
+ removed->edges.push_back(shape->edge(e));
210
+ }
211
+ }
212
+ index_status_.store(STALE, std::memory_order_relaxed);
213
+ return shape;
214
+ }
215
+
216
+ vector<unique_ptr<S2Shape>> MutableS2ShapeIndex::ReleaseAll() {
217
+ Iterator it;
218
+ for (it.InitStale(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
219
+ delete &it.cell();
220
+ }
221
+ cell_map_.clear();
222
+ pending_additions_begin_ = 0;
223
+ pending_removals_.reset();
224
+ S2_DCHECK(update_state_ == nullptr);
225
+ index_status_.store(FRESH, std::memory_order_relaxed);
226
+ vector<unique_ptr<S2Shape>> result;
227
+ result.swap(shapes_);
228
+ return result;
229
+ }
230
+
231
+ void MutableS2ShapeIndex::Clear() {
232
+ ReleaseAll();
233
+ }
234
+
235
+ // FaceEdge and ClippedEdge store temporary edge data while the index is being
236
+ // updated. FaceEdge represents an edge that has been projected onto a given
237
+ // face, while ClippedEdge represents the portion of that edge that has been
238
+ // clipped to a given S2Cell.
239
+ //
240
+ // While it would be possible to combine all the edge information into one
241
+ // structure, there are two good reasons for separating it:
242
+ //
243
+ // - Memory usage. Separating the two classes means that we only need to
244
+ // store one copy of the per-face data no matter how many times an edge is
245
+ // subdivided, and it also lets us delay computing bounding boxes until
246
+ // they are needed for processing each face (when the dataset spans
247
+ // multiple faces).
248
+ //
249
+ // - Performance. UpdateEdges is significantly faster on large polygons when
250
+ // the data is separated, because it often only needs to access the data in
251
+ // ClippedEdge and this data is cached more successfully.
252
+
253
+ struct MutableS2ShapeIndex::FaceEdge {
254
+ int32 shape_id; // The shape that this edge belongs to
255
+ int32 edge_id; // Edge id within that shape
256
+ int32 max_level; // Not desirable to subdivide this edge beyond this level
257
+ bool has_interior; // Belongs to a shape of dimension 2.
258
+ R2Point a, b; // The edge endpoints, clipped to a given face
259
+ S2Shape::Edge edge; // The edge endpoints
260
+ };
261
+
262
+ struct MutableS2ShapeIndex::ClippedEdge {
263
+ const FaceEdge* face_edge; // The original unclipped edge
264
+ R2Rect bound; // Bounding box for the clipped portion
265
+ };
266
+
267
+ // Given a set of shapes, InteriorTracker keeps track of which shapes contain
268
+ // a particular point (the "focus"). It provides an efficient way to move the
269
+ // focus from one point to another and incrementally update the set of shapes
270
+ // which contain it. We use this to compute which shapes contain the center
271
+ // of every S2CellId in the index, by advancing the focus from one cell center
272
+ // to the next.
273
+ //
274
+ // Initially the focus is at the start of the S2CellId space-filling curve.
275
+ // We then visit all the cells that are being added to the MutableS2ShapeIndex
276
+ // in increasing order of S2CellId. For each cell, we draw two edges: one
277
+ // from the entry vertex to the center, and another from the center to the
278
+ // exit vertex (where "entry" and "exit" refer to the points where the
279
+ // space-filling curve enters and exits the cell). By counting edge crossings
280
+ // we can incrementally compute which shapes contain the cell center. Note
281
+ // that the same set of shapes will always contain the exit point of one cell
282
+ // and the entry point of the next cell in the index, because either (a) these
283
+ // two points are actually the same, or (b) the intervening cells in S2CellId
284
+ // order are all empty, and therefore there are no edge crossings if we follow
285
+ // this path from one cell to the other.
286
+ class MutableS2ShapeIndex::InteriorTracker {
287
+ public:
288
+ // Constructs the InteriorTracker. You must call AddShape() for each shape
289
+ // that will be tracked before calling MoveTo() or DrawTo().
290
+ InteriorTracker();
291
+
292
+ // Returns the initial focus point when the InteriorTracker is constructed
293
+ // (corresponding to the start of the S2CellId space-filling curve).
294
+ static S2Point Origin();
295
+
296
+ // Returns the current focus point (see above).
297
+ const S2Point& focus() { return b_; }
298
+
299
+ // Returns true if any shapes are being tracked.
300
+ bool is_active() const { return is_active_; }
301
+
302
+ // Adds a shape whose interior should be tracked. "is_inside" indicates
303
+ // whether the current focus point is inside the shape. Alternatively, if
304
+ // the focus point is in the process of being moved (via MoveTo/DrawTo), you
305
+ // can also specify "is_inside" at the old focus point and call TestEdge()
306
+ // for every edge of the shape that might cross the current DrawTo() line.
307
+ // This updates the state to correspond to the new focus point.
308
+ //
309
+ // REQUIRES: shape->dimension() == 2
310
+ void AddShape(int32 shape_id, bool is_inside);
311
+
312
+ // Moves the focus to the given point. This method should only be used when
313
+ // it is known that there are no edge crossings between the old and new
314
+ // focus locations; otherwise use DrawTo().
315
+ void MoveTo(const S2Point& b) { b_ = b; }
316
+
317
+ // Moves the focus to the given point. After this method is called,
318
+ // TestEdge() should be called with all edges that may cross the line
319
+ // segment between the old and new focus locations.
320
+ void DrawTo(const S2Point& b);
321
+
322
+ // Indicates that the given edge of the given shape may cross the line
323
+ // segment between the old and new focus locations (see DrawTo).
324
+ // REQUIRES: shape->dimension() == 2
325
+ inline void TestEdge(int32 shape_id, const S2Shape::Edge& edge);
326
+
327
+ // The set of shape ids that contain the current focus.
328
+ const ShapeIdSet& shape_ids() const { return shape_ids_; }
329
+
330
+ // Indicates that the last argument to MoveTo() or DrawTo() was the entry
331
+ // vertex of the given S2CellId, i.e. the tracker is positioned at the start
332
+ // of this cell. By using this method together with at_cellid(), the caller
333
+ // can avoid calling MoveTo() in cases where the exit vertex of the previous
334
+ // cell is the same as the entry vertex of the current cell.
335
+ void set_next_cellid(S2CellId next_cellid) {
336
+ next_cellid_ = next_cellid.range_min();
337
+ }
338
+
339
+ // Returns true if the focus is already at the entry vertex of the given
340
+ // S2CellId (provided that the caller calls set_next_cellid() as each cell
341
+ // is processed).
342
+ bool at_cellid(S2CellId cellid) const {
343
+ return cellid.range_min() == next_cellid_;
344
+ }
345
+
346
+ // Makes an internal copy of the state for shape ids below the given limit,
347
+ // and then clear the state for those shapes. This is used during
348
+ // incremental updates to track the state of added and removed shapes
349
+ // separately.
350
+ void SaveAndClearStateBefore(int32 limit_shape_id);
351
+
352
+ // Restores the state previously saved by SaveAndClearStateBefore(). This
353
+ // only affects the state for shape_ids below "limit_shape_id".
354
+ void RestoreStateBefore(int32 limit_shape_id);
355
+
356
+ private:
357
+ // Removes "shape_id" from shape_ids_ if it exists, otherwise insert it.
358
+ void ToggleShape(int shape_id);
359
+
360
+ // Returns a pointer to the first entry "x" where x >= shape_id.
361
+ ShapeIdSet::iterator lower_bound(int32 shape_id);
362
+
363
+ bool is_active_;
364
+ S2Point a_, b_;
365
+ S2CellId next_cellid_;
366
+ S2EdgeCrosser crosser_;
367
+ ShapeIdSet shape_ids_;
368
+
369
+ // Shape ids saved by SaveAndClearStateBefore(). The state is never saved
370
+ // recursively so we don't need to worry about maintaining a stack.
371
+ ShapeIdSet saved_ids_;
372
+ };
373
+
374
+ // As shapes are added, we compute which ones contain the start of the
375
+ // S2CellId space-filling curve by drawing an edge from S2::Origin() to this
376
+ // point and counting how many shape edges cross this edge.
377
+ MutableS2ShapeIndex::InteriorTracker::InteriorTracker()
378
+ : is_active_(false), b_(Origin()),
379
+ next_cellid_(S2CellId::Begin(S2CellId::kMaxLevel)) {
380
+ }
381
+
382
+ S2Point MutableS2ShapeIndex::InteriorTracker::Origin() {
383
+ // The start of the S2CellId space-filling curve.
384
+ return S2::FaceUVtoXYZ(0, -1, -1).Normalize();
385
+ }
386
+
387
+ void MutableS2ShapeIndex::InteriorTracker::AddShape(int32 shape_id,
388
+ bool contains_focus) {
389
+ is_active_ = true;
390
+ if (contains_focus) {
391
+ ToggleShape(shape_id);
392
+ }
393
+ }
394
+
395
+ void MutableS2ShapeIndex::InteriorTracker::ToggleShape(int shape_id) {
396
+ // Since shape_ids_.size() is typically *very* small (0, 1, or 2), it turns
397
+ // out to be significantly faster to maintain a sorted array rather than
398
+ // using an STL set or btree_set.
399
+ if (shape_ids_.empty()) {
400
+ shape_ids_.push_back(shape_id);
401
+ } else if (shape_ids_[0] == shape_id) {
402
+ shape_ids_.erase(shape_ids_.begin());
403
+ } else {
404
+ ShapeIdSet::iterator pos = shape_ids_.begin();
405
+ while (*pos < shape_id) {
406
+ if (++pos == shape_ids_.end()) {
407
+ shape_ids_.push_back(shape_id);
408
+ return;
409
+ }
410
+ }
411
+ if (*pos == shape_id) {
412
+ shape_ids_.erase(pos);
413
+ } else {
414
+ shape_ids_.insert(pos, shape_id);
415
+ }
416
+ }
417
+ }
418
+
419
+ void MutableS2ShapeIndex::InteriorTracker::DrawTo(const S2Point& b) {
420
+ a_ = b_;
421
+ b_ = b;
422
+ crosser_.Init(&a_, &b_);
423
+ }
424
+
425
+ inline void MutableS2ShapeIndex::InteriorTracker::TestEdge(
426
+ int32 shape_id, const S2Shape::Edge& edge) {
427
+ if (crosser_.EdgeOrVertexCrossing(&edge.v0, &edge.v1)) {
428
+ ToggleShape(shape_id);
429
+ }
430
+ }
431
+
432
+ // Like std::lower_bound(shape_ids_.begin(), shape_ids_.end(), shape_id), but
433
+ // implemented with linear rather than binary search because the number of
434
+ // shapes being tracked is typically very small.
435
+ inline MutableS2ShapeIndex::ShapeIdSet::iterator
436
+ MutableS2ShapeIndex::InteriorTracker::lower_bound(int32 shape_id) {
437
+ ShapeIdSet::iterator pos = shape_ids_.begin();
438
+ while (pos != shape_ids_.end() && *pos < shape_id) { ++pos; }
439
+ return pos;
440
+ }
441
+
442
+ void MutableS2ShapeIndex::InteriorTracker::SaveAndClearStateBefore(
443
+ int32 limit_shape_id) {
444
+ S2_DCHECK(saved_ids_.empty());
445
+ ShapeIdSet::iterator limit = lower_bound(limit_shape_id);
446
+ saved_ids_.assign(shape_ids_.begin(), limit);
447
+ shape_ids_.erase(shape_ids_.begin(), limit);
448
+ }
449
+
450
+ void MutableS2ShapeIndex::InteriorTracker::RestoreStateBefore(
451
+ int32 limit_shape_id) {
452
+ shape_ids_.erase(shape_ids_.begin(), lower_bound(limit_shape_id));
453
+ shape_ids_.insert(shape_ids_.begin(), saved_ids_.begin(), saved_ids_.end());
454
+ saved_ids_.clear();
455
+ }
456
+
457
+ // Apply any pending updates in a thread-safe way.
458
+ void MutableS2ShapeIndex::ApplyUpdatesThreadSafe() {
459
+ lock_.Lock();
460
+ if (index_status_.load(std::memory_order_relaxed) == FRESH) {
461
+ lock_.Unlock();
462
+ } else if (index_status_.load(std::memory_order_relaxed) == UPDATING) {
463
+ // Wait until the updating thread is finished. We do this by attempting
464
+ // to lock a mutex that is held by the updating thread. When this mutex
465
+ // is unlocked the index_status_ is guaranteed to be FRESH.
466
+ ++update_state_->num_waiting;
467
+ lock_.Unlock();
468
+ update_state_->wait_mutex.Lock();
469
+ lock_.Lock();
470
+ --update_state_->num_waiting;
471
+ UnlockAndSignal(); // Notify other waiting threads.
472
+ } else {
473
+ S2_DCHECK_EQ(STALE, index_status_);
474
+ index_status_.store(UPDATING, std::memory_order_relaxed);
475
+ // Allocate the extra state needed for thread synchronization. We keep
476
+ // the spinlock held while doing this, because (1) memory allocation is
477
+ // fast, so the chance of a context switch while holding the lock is low;
478
+ // (2) by far the most common situation is that there is no contention,
479
+ // and this saves an extra lock and unlock step; (3) even in the rare case
480
+ // where there is contention, the main side effect is that some other
481
+ // thread will burn a few CPU cycles rather than sleeping.
482
+ update_state_.reset(new UpdateState);
483
+ // lock_.Lock wait_mutex *before* calling Unlock() to ensure that all other
484
+ // threads will block on it.
485
+ update_state_->wait_mutex.Lock();
486
+ // Release the spinlock before doing any real work.
487
+ lock_.Unlock();
488
+ ApplyUpdatesInternal();
489
+ lock_.Lock();
490
+ // index_status_ can be updated to FRESH only while locked *and* using
491
+ // an atomic store operation, so that MaybeApplyUpdates() can check
492
+ // whether the index is FRESH without acquiring the spinlock.
493
+ index_status_.store(FRESH, std::memory_order_release);
494
+ UnlockAndSignal(); // Notify any waiting threads.
495
+ }
496
+ }
497
+
498
+ // Releases lock_ and wakes up any waiting threads by releasing wait_mutex.
499
+ // If this was the last waiting thread, also deletes update_state_.
500
+ // REQUIRES: lock_ is held.
501
+ // REQUIRES: wait_mutex is held.
502
+ inline void MutableS2ShapeIndex::UnlockAndSignal() {
503
+ S2_DCHECK_EQ(FRESH, index_status_);
504
+ int num_waiting = update_state_->num_waiting;
505
+ lock_.Unlock();
506
+ // Allow another waiting thread to proceed. Note that no new threads can
507
+ // start waiting because the index_status_ is now FRESH, and the caller is
508
+ // required to prevent any new mutations from occurring while these const
509
+ // methods are running.
510
+ //
511
+ // We need to unlock wait_mutex before destroying it even if there are no
512
+ // waiting threads.
513
+ update_state_->wait_mutex.Unlock();
514
+ if (num_waiting == 0) {
515
+ update_state_.reset();
516
+ }
517
+ }
518
+
519
+ void MutableS2ShapeIndex::ForceBuild() {
520
+ // No locks required because this is not a const method. It is the client's
521
+ // responsibility to ensure correct thread synchronization.
522
+ if (index_status_.load(std::memory_order_relaxed) != FRESH) {
523
+ ApplyUpdatesInternal();
524
+ index_status_.store(FRESH, std::memory_order_relaxed);
525
+ }
526
+ }
527
+
528
+ // A BatchDescriptor represents a set of pending updates that will be applied
529
+ // at the same time. The batch consists of all updates with shape ids between
530
+ // the current value of "ShapeIndex::pending_additions_begin_" (inclusive) and
531
+ // "additions_end" (exclusive). The first batch to be processed also
532
+ // implicitly includes all shapes being removed. "num_edges" is the total
533
+ // number of edges that will be added or removed in this batch.
534
+ struct MutableS2ShapeIndex::BatchDescriptor {
535
+ BatchDescriptor(int _additions_end, int _num_edges)
536
+ : additions_end(_additions_end), num_edges(_num_edges) {
537
+ }
538
+ int additions_end;
539
+ int num_edges;
540
+ };
541
+
542
+ // This method updates the index by applying all pending additions and
543
+ // removals. It does *not* update index_status_ (see ApplyUpdatesThreadSafe).
544
+ void MutableS2ShapeIndex::ApplyUpdatesInternal() {
545
+ // Check whether we have so many edges to process that we should process
546
+ // them in multiple batches to save memory. Building the index can use up
547
+ // to 20x as much memory (per edge) as the final index size.
548
+ vector<BatchDescriptor> batches;
549
+ GetUpdateBatches(&batches);
550
+ int i = 0;
551
+ for (const BatchDescriptor& batch : batches) {
552
+ vector<FaceEdge> all_edges[6];
553
+ S2_VLOG(1) << "Batch " << i++ << ": shape_limit=" << batch.additions_end
554
+ << ", edges=" << batch.num_edges;
555
+
556
+ ReserveSpace(batch, all_edges);
557
+ InteriorTracker tracker;
558
+ if (pending_removals_) {
559
+ // The first batch implicitly includes all shapes being removed.
560
+ for (const auto& pending_removal : *pending_removals_) {
561
+ RemoveShape(pending_removal, all_edges, &tracker);
562
+ }
563
+ pending_removals_.reset(nullptr);
564
+ }
565
+ for (int id = pending_additions_begin_; id < batch.additions_end; ++id) {
566
+ AddShape(id, all_edges, &tracker);
567
+ }
568
+ for (int face = 0; face < 6; ++face) {
569
+ UpdateFaceEdges(face, all_edges[face], &tracker);
570
+ // Save memory by clearing vectors after we are done with them.
571
+ vector<FaceEdge>().swap(all_edges[face]);
572
+ }
573
+ pending_additions_begin_ = batch.additions_end;
574
+ }
575
+ // It is the caller's responsibility to update index_status_.
576
+ }
577
+
578
+ // Count the number of edges being updated, and break them into several
579
+ // batches if necessary to reduce the amount of memory needed. (See the
580
+ // documentation for FLAGS_s2shape_index_tmp_memory_budget_mb.)
581
+ void MutableS2ShapeIndex::GetUpdateBatches(vector<BatchDescriptor>* batches)
582
+ const {
583
+ // Count the edges being removed and added.
584
+ int num_edges_removed = 0;
585
+ if (pending_removals_) {
586
+ for (const auto& pending_removal : *pending_removals_) {
587
+ num_edges_removed += pending_removal.edges.size();
588
+ }
589
+ }
590
+ int num_edges_added = 0;
591
+ for (int id = pending_additions_begin_; id < shapes_.size(); ++id) {
592
+ const S2Shape* shape = this->shape(id);
593
+ if (shape == nullptr) continue;
594
+ num_edges_added += shape->num_edges();
595
+ }
596
+ int num_edges = num_edges_removed + num_edges_added;
597
+
598
+ // The following memory estimates are based on heap profiling.
599
+ //
600
+ // The final size of a MutableS2ShapeIndex depends mainly on how finely the
601
+ // index is subdivided, as controlled by Options::max_edges_per_cell() and
602
+ // --s2shape_index_default_max_edges_per_cell. For realistic values of
603
+ // max_edges_per_cell() and shapes with moderate numbers of edges, it is
604
+ // difficult to get much below 8 bytes per edge. [The minimum possible size
605
+ // is 4 bytes per edge (to store a 32-bit edge id in an S2ClippedShape) plus
606
+ // 24 bytes per shape (for the S2ClippedShape itself plus a pointer in the
607
+ // shapes_ vector.]
608
+ //
609
+ // The temporary memory consists mainly of the FaceEdge and ClippedEdge
610
+ // structures plus a ClippedEdge pointer for every level of recursive
611
+ // subdivision. For very large indexes this can be 200 bytes per edge.
612
+ const size_t kFinalBytesPerEdge = 8;
613
+ const size_t kTmpBytesPerEdge = 200;
614
+ const size_t kTmpMemoryBudgetBytes =
615
+ static_cast<size_t>(FLAGS_s2shape_index_tmp_memory_budget_mb) << 20;
616
+
617
+ // We arbitrarily limit the number of batches just as a safety measure.
618
+ // With the current default memory budget of 100 MB, this limit is not
619
+ // reached even when building an index of 350 million edges.
620
+ const int kMaxUpdateBatches = 100;
621
+
622
+ if (num_edges * kTmpBytesPerEdge <= kTmpMemoryBudgetBytes) {
623
+ // We can update all edges at once without exceeding kTmpMemoryBudgetBytes.
624
+ batches->push_back(BatchDescriptor(shapes_.size(), num_edges));
625
+ return;
626
+ }
627
+ // Otherwise, break the updates into up to several batches, where the size
628
+ // of each batch is chosen so that all batches use approximately the same
629
+ // high-water memory. GetBatchSizes() returns the recommended number of
630
+ // edges in each batch.
631
+ vector<int> batch_sizes;
632
+ GetBatchSizes(num_edges, kMaxUpdateBatches, kFinalBytesPerEdge,
633
+ kTmpBytesPerEdge, kTmpMemoryBudgetBytes, &batch_sizes);
634
+
635
+ // We always process removed edges in a single batch, since (1) they already
636
+ // take up a lot of memory because we have copied all their edges, and (2)
637
+ // AbsorbIndexCell() uses (shapes_[id] == nullptr) to detect when a shape is
638
+ // being removed, so in order to split the removals into batches we would
639
+ // need a different approach (e.g., temporarily add fake entries to shapes_
640
+ // and restore them back to nullptr as shapes are actually removed).
641
+ num_edges = 0;
642
+ if (pending_removals_) {
643
+ num_edges += num_edges_removed;
644
+ if (num_edges >= batch_sizes[0]) {
645
+ batches->push_back(BatchDescriptor(pending_additions_begin_, num_edges));
646
+ num_edges = 0;
647
+ }
648
+ }
649
+ // Keep adding shapes to each batch until the recommended number of edges
650
+ // for that batch is reached, then move on to the next batch.
651
+ for (int id = pending_additions_begin_; id < shapes_.size(); ++id) {
652
+ const S2Shape* shape = this->shape(id);
653
+ if (shape == nullptr) continue;
654
+ num_edges += shape->num_edges();
655
+ if (num_edges >= batch_sizes[batches->size()]) {
656
+ batches->push_back(BatchDescriptor(id + 1, num_edges));
657
+ num_edges = 0;
658
+ }
659
+ }
660
+ // Some shapes have no edges. If a shape with no edges is the last shape to
661
+ // be added or removed, then the final batch may not include it, so we fix
662
+ // that problem here.
663
+ batches->back().additions_end = shapes_.size();
664
+ S2_DCHECK_LE(batches->size(), kMaxUpdateBatches);
665
+ }
666
+
667
+ // Given "num_items" items, each of which uses "tmp_bytes_per_item" while it
668
+ // is being updated but only "final_bytes_per_item" in the end, divide the
669
+ // items into batches that have approximately the same *total* memory usage
670
+ // consisting of the temporary memory needed for the items in the current
671
+ // batch plus the final size of all the items that have already been
672
+ // processed. Use the fewest number of batches (but never more than
673
+ // "max_batches") such that the total memory usage does not exceed the
674
+ // combined final size of all the items plus "tmp_memory_budget_bytes".
675
+ /* static */
676
+ void MutableS2ShapeIndex::GetBatchSizes(int num_items, int max_batches,
677
+ double final_bytes_per_item,
678
+ double tmp_bytes_per_item,
679
+ double tmp_memory_budget_bytes,
680
+ vector<int>* batch_sizes) {
681
+ // This code tries to fit all the data into the same memory space
682
+ // ("total_budget_bytes") at every iteration. The data consists of some
683
+ // number of processed items (at "final_bytes_per_item" each), plus some
684
+ // number being updated (at "tmp_bytes_per_item" each). The space occupied
685
+ // by the items being updated is the "free space". At each iteration, the
686
+ // free space is multiplied by (1 - final_bytes_per_item/tmp_bytes_per_item)
687
+ // as the items are converted into their final form.
688
+ double final_bytes = num_items * final_bytes_per_item;
689
+ double final_bytes_ratio = final_bytes_per_item / tmp_bytes_per_item;
690
+ double free_space_multiplier = 1 - final_bytes_ratio;
691
+
692
+ // The total memory budget is the greater of the final size plus the allowed
693
+ // temporary memory, or the minimum amount of memory required to limit the
694
+ // number of batches to "max_batches".
695
+ double total_budget_bytes = max(
696
+ final_bytes + tmp_memory_budget_bytes,
697
+ final_bytes / (1 - pow(free_space_multiplier, max_batches)));
698
+
699
+ // "max_batch_items" is the number of items in the current batch.
700
+ double max_batch_items = total_budget_bytes / tmp_bytes_per_item;
701
+ batch_sizes->clear();
702
+ for (int i = 0; i + 1 < max_batches && num_items > 0; ++i) {
703
+ int batch_items =
704
+ std::min(num_items, static_cast<int>(max_batch_items + 1));
705
+ batch_sizes->push_back(batch_items);
706
+ num_items -= batch_items;
707
+ max_batch_items *= free_space_multiplier;
708
+ }
709
+ S2_DCHECK_LE(batch_sizes->size(), max_batches);
710
+ }
711
+
712
+ // Reserve an appropriate amount of space for the top-level face edges in the
713
+ // current batch. This data structure uses about half of the temporary memory
714
+ // needed during index construction. Furthermore, if the arrays are grown via
715
+ // push_back() then up to 10% of the total run time consists of copying data
716
+ // as these arrays grow, so it is worthwhile to preallocate space for them.
717
+ void MutableS2ShapeIndex::ReserveSpace(const BatchDescriptor& batch,
718
+ vector<FaceEdge> all_edges[6]) const {
719
+ // If the number of edges is relatively small, then the fastest approach is
720
+ // to simply reserve space on every face for the maximum possible number of
721
+ // edges. We use a different threshold for this calculation than for
722
+ // deciding when to break updates into batches, because the cost/benefit
723
+ // ratio is different. (Here the only extra expense is that we need to
724
+ // sample the edges to estimate how many edges per face there are.)
725
+ const size_t kMaxCheapBytes = 30 << 20; // 30 MB
726
+ const int kMaxCheapEdges = kMaxCheapBytes / (6 * sizeof(FaceEdge));
727
+ if (batch.num_edges <= kMaxCheapEdges) {
728
+ for (int face = 0; face < 6; ++face) {
729
+ all_edges[face].reserve(batch.num_edges);
730
+ }
731
+ return;
732
+ }
733
+ // Otherwise we estimate the number of edges on each face by taking a random
734
+ // sample. The goal is to come up with an estimate that is fast and
735
+ // accurate for non-pathological geometry. If our estimates happen to be
736
+ // wrong, the vector will still grow automatically - the main side effects
737
+ // are that memory usage will be larger (by up to a factor of 3), and
738
+ // constructing the index will be about 10% slower.
739
+ //
740
+ // Given a desired sample size, we choose equally spaced edges from
741
+ // throughout the entire data set. We use a Bresenham-type algorithm to
742
+ // choose the samples.
743
+ const int kDesiredSampleSize = 10000;
744
+ const int sample_interval = max(1, batch.num_edges / kDesiredSampleSize);
745
+
746
+ // Initialize "edge_id" to be midway through the first sample interval.
747
+ // Because samples are equally spaced the actual sample size may differ
748
+ // slightly from the desired sample size.
749
+ int edge_id = sample_interval / 2;
750
+ const int actual_sample_size = (batch.num_edges + edge_id) / sample_interval;
751
+ int face_count[6] = { 0, 0, 0, 0, 0, 0 };
752
+ if (pending_removals_) {
753
+ for (const RemovedShape& removed : *pending_removals_) {
754
+ edge_id += removed.edges.size();
755
+ while (edge_id >= sample_interval) {
756
+ edge_id -= sample_interval;
757
+ face_count[S2::GetFace(removed.edges[edge_id].v0)] += 1;
758
+ }
759
+ }
760
+ }
761
+ for (int id = pending_additions_begin_; id < batch.additions_end; ++id) {
762
+ const S2Shape* shape = this->shape(id);
763
+ if (shape == nullptr) continue;
764
+ edge_id += shape->num_edges();
765
+ while (edge_id >= sample_interval) {
766
+ edge_id -= sample_interval;
767
+ // For speed, we only count the face containing one endpoint of the
768
+ // edge. In general the edge could span all 6 faces (with padding), but
769
+ // it's not worth the expense to compute this more accurately.
770
+ face_count[S2::GetFace(shape->edge(edge_id).v0)] += 1;
771
+ }
772
+ }
773
+ // Now given the raw face counts, compute a confidence interval such that we
774
+ // will be unlikely to allocate too little space. Computing accurate
775
+ // binomial confidence intervals is expensive and not really necessary.
776
+ // Instead we use a simple approximation:
777
+ // - For any face with at least 1 sample, we use at least a 4-sigma
778
+ // confidence interval. (The chosen width is adequate for the worst case
779
+ // accuracy, which occurs when the face contains approximately 50% of the
780
+ // edges.) Assuming that our sample is representative, the probability of
781
+ // reserving too little space is approximately 1 in 30,000.
782
+ // - For faces with no samples at all, we don't bother reserving space.
783
+ // It is quite likely that such faces are truly empty, so we save time
784
+ // and memory this way. If the face does contain some edges, there will
785
+ // only be a few so it is fine to let the vector grow automatically.
786
+ // On average, we reserve 2% extra space for each face that has geometry.
787
+
788
+ // kMaxSemiWidth is the maximum semi-width over all probabilities p of a
789
+ // 4-sigma binomial confidence interval with a sample size of 10,000.
790
+ const double kMaxSemiWidth = 0.02;
791
+ const double sample_ratio = 1.0 / actual_sample_size;
792
+ for (int face = 0; face < 6; ++face) {
793
+ if (face_count[face] == 0) continue;
794
+ double fraction = sample_ratio * face_count[face] + kMaxSemiWidth;
795
+ all_edges[face].reserve(fraction * batch.num_edges);
796
+ }
797
+ }
798
+
799
+ // Clip all edges of the given shape to the six cube faces, add the clipped
800
+ // edges to "all_edges", and start tracking its interior if necessary.
801
+ void MutableS2ShapeIndex::AddShape(int id, vector<FaceEdge> all_edges[6],
802
+ InteriorTracker* tracker) const {
803
+ const S2Shape* shape = this->shape(id);
804
+ if (shape == nullptr) {
805
+ return; // This shape has already been removed.
806
+ }
807
+ // Construct a template for the edges to be added.
808
+ FaceEdge edge;
809
+ edge.shape_id = id;
810
+ edge.has_interior = (shape->dimension() == 2);
811
+ if (edge.has_interior) {
812
+ tracker->AddShape(id, s2shapeutil::ContainsBruteForce(*shape,
813
+ tracker->focus()));
814
+ }
815
+ int num_edges = shape->num_edges();
816
+ for (int e = 0; e < num_edges; ++e) {
817
+ edge.edge_id = e;
818
+ edge.edge = shape->edge(e);
819
+ edge.max_level = GetEdgeMaxLevel(edge.edge);
820
+ AddFaceEdge(&edge, all_edges);
821
+ }
822
+ }
823
+
824
+ void MutableS2ShapeIndex::RemoveShape(const RemovedShape& removed,
825
+ vector<FaceEdge> all_edges[6],
826
+ InteriorTracker* tracker) const {
827
+ FaceEdge edge;
828
+ edge.edge_id = -1; // Not used or needed for removed edges.
829
+ edge.shape_id = removed.shape_id;
830
+ edge.has_interior = removed.has_interior;
831
+ if (edge.has_interior) {
832
+ tracker->AddShape(edge.shape_id, removed.contains_tracker_origin);
833
+ }
834
+ for (const auto& removed_edge : removed.edges) {
835
+ edge.edge = removed_edge;
836
+ edge.max_level = GetEdgeMaxLevel(edge.edge);
837
+ AddFaceEdge(&edge, all_edges);
838
+ }
839
+ }
840
+
841
+ inline void MutableS2ShapeIndex::AddFaceEdge(
842
+ FaceEdge* edge, vector<FaceEdge> all_edges[6]) const {
843
+ // Fast path: both endpoints are on the same face, and are far enough from
844
+ // the edge of the face that don't intersect any (padded) adjacent face.
845
+ int a_face = S2::GetFace(edge->edge.v0);
846
+ if (a_face == S2::GetFace(edge->edge.v1)) {
847
+ S2::ValidFaceXYZtoUV(a_face, edge->edge.v0, &edge->a);
848
+ S2::ValidFaceXYZtoUV(a_face, edge->edge.v1, &edge->b);
849
+ const double kMaxUV = 1 - kCellPadding;
850
+ if (fabs(edge->a[0]) <= kMaxUV && fabs(edge->a[1]) <= kMaxUV &&
851
+ fabs(edge->b[0]) <= kMaxUV && fabs(edge->b[1]) <= kMaxUV) {
852
+ all_edges[a_face].push_back(*edge);
853
+ return;
854
+ }
855
+ }
856
+ // Otherwise we simply clip the edge to all six faces.
857
+ for (int face = 0; face < 6; ++face) {
858
+ if (S2::ClipToPaddedFace(edge->edge.v0, edge->edge.v1, face,
859
+ kCellPadding, &edge->a, &edge->b)) {
860
+ all_edges[face].push_back(*edge);
861
+ }
862
+ }
863
+ }
864
+
865
+ // Return the first level at which the edge will *not* contribute towards
866
+ // the decision to subdivide.
867
+ int MutableS2ShapeIndex::GetEdgeMaxLevel(const S2Shape::Edge& edge) const {
868
+ // Compute the maximum cell size for which this edge is considered "long".
869
+ // The calculation does not need to be perfectly accurate, so we use Norm()
870
+ // rather than Angle() for speed.
871
+ double cell_size = ((edge.v0 - edge.v1).Norm() *
872
+ FLAGS_s2shape_index_cell_size_to_long_edge_ratio);
873
+ // Now return the first level encountered during subdivision where the
874
+ // average cell size is at most "cell_size".
875
+ return S2::kAvgEdge.GetLevelForMaxValue(cell_size);
876
+ }
877
+
878
+ // EdgeAllocator provides temporary storage for new ClippedEdges that are
879
+ // created during indexing. It is essentially a stack model, where edges are
880
+ // allocated as the recursion does down and freed as it comes back up.
881
+ //
882
+ // It also provides a mutable vector of FaceEdges that is used when
883
+ // incrementally updating the index (see AbsorbIndexCell).
884
+ class MutableS2ShapeIndex::EdgeAllocator {
885
+ public:
886
+ EdgeAllocator() : size_(0) {}
887
+
888
+ // Return a pointer to a newly allocated edge. The EdgeAllocator
889
+ // retains ownership.
890
+ ClippedEdge* NewClippedEdge() {
891
+ if (size_ == clipped_edges_.size()) {
892
+ clipped_edges_.emplace_back(new ClippedEdge);
893
+ }
894
+ return clipped_edges_[size_++].get();
895
+ }
896
+ // Return the number of allocated edges.
897
+ size_t size() const { return size_; }
898
+
899
+ // Reset the allocator to only contain the first "size" allocated edges.
900
+ void Reset(size_t size) { size_ = size; }
901
+
902
+ vector<FaceEdge>* mutable_face_edges() {
903
+ return &face_edges_;
904
+ }
905
+
906
+ private:
907
+ // We can't use vector<ClippedEdge> because edges are not allowed to move
908
+ // once they have been allocated. Instead we keep a pool of allocated edges
909
+ // that are all deleted together at the end.
910
+ size_t size_;
911
+ vector<unique_ptr<ClippedEdge>> clipped_edges_;
912
+
913
+ // On the other hand, we can use vector<FaceEdge> because they are allocated
914
+ // only at one level during the recursion (namely, the level at which we
915
+ // absorb an existing index cell).
916
+ vector<FaceEdge> face_edges_;
917
+
918
+ EdgeAllocator(const EdgeAllocator&) = delete;
919
+ void operator=(const EdgeAllocator&) = delete;
920
+ };
921
+
922
+ // Given a face and a vector of edges that intersect that face, add or remove
923
+ // all the edges from the index. (An edge is added if shapes_[id] is not
924
+ // nullptr, and removed otherwise.)
925
+ void MutableS2ShapeIndex::UpdateFaceEdges(int face,
926
+ const vector<FaceEdge>& face_edges,
927
+ InteriorTracker* tracker) {
928
+ int num_edges = face_edges.size();
929
+ if (num_edges == 0 && tracker->shape_ids().empty()) return;
930
+
931
+ // Create the initial ClippedEdge for each FaceEdge. Additional clipped
932
+ // edges are created when edges are split between child cells. We create
933
+ // two arrays, one containing the edge data and another containing pointers
934
+ // to those edges, so that during the recursion we only need to copy
935
+ // pointers in order to propagate an edge to the correct child.
936
+ vector<ClippedEdge> clipped_edge_storage;
937
+ vector<const ClippedEdge*> clipped_edges;
938
+ clipped_edge_storage.reserve(num_edges);
939
+ clipped_edges.reserve(num_edges);
940
+ R2Rect bound = R2Rect::Empty();
941
+ for (int e = 0; e < num_edges; ++e) {
942
+ ClippedEdge clipped;
943
+ clipped.face_edge = &face_edges[e];
944
+ clipped.bound = R2Rect::FromPointPair(face_edges[e].a, face_edges[e].b);
945
+ clipped_edge_storage.push_back(clipped);
946
+ clipped_edges.push_back(&clipped_edge_storage.back());
947
+ bound.AddRect(clipped.bound);
948
+ }
949
+ // Construct the initial face cell containing all the edges, and then update
950
+ // all the edges in the index recursively.
951
+ EdgeAllocator alloc;
952
+ S2CellId face_id = S2CellId::FromFace(face);
953
+ S2PaddedCell pcell(face_id, kCellPadding);
954
+
955
+ // "disjoint_from_index" means that the current cell being processed (and
956
+ // all its descendants) are not already present in the index.
957
+ bool disjoint_from_index = is_first_update();
958
+ if (num_edges > 0) {
959
+ S2CellId shrunk_id = ShrinkToFit(pcell, bound);
960
+ if (shrunk_id != pcell.id()) {
961
+ // All the edges are contained by some descendant of the face cell. We
962
+ // can save a lot of work by starting directly with that cell, but if we
963
+ // are in the interior of at least one shape then we need to create
964
+ // index entries for the cells we are skipping over.
965
+ SkipCellRange(face_id.range_min(), shrunk_id.range_min(),
966
+ tracker, &alloc, disjoint_from_index);
967
+ pcell = S2PaddedCell(shrunk_id, kCellPadding);
968
+ UpdateEdges(pcell, &clipped_edges, tracker, &alloc, disjoint_from_index);
969
+ SkipCellRange(shrunk_id.range_max().next(), face_id.range_max().next(),
970
+ tracker, &alloc, disjoint_from_index);
971
+ return;
972
+ }
973
+ }
974
+ // Otherwise (no edges, or no shrinking is possible), subdivide normally.
975
+ UpdateEdges(pcell, &clipped_edges, tracker, &alloc, disjoint_from_index);
976
+ }
977
+
978
+ inline S2CellId MutableS2ShapeIndex::ShrinkToFit(const S2PaddedCell& pcell,
979
+ const R2Rect& bound) const {
980
+ S2CellId shrunk_id = pcell.ShrinkToFit(bound);
981
+ if (!is_first_update() && shrunk_id != pcell.id()) {
982
+ // Don't shrink any smaller than the existing index cells, since we need
983
+ // to combine the new edges with those cells.
984
+ // Use InitStale() to avoid applying updated recursively.
985
+ Iterator iter;
986
+ iter.InitStale(this);
987
+ CellRelation r = iter.Locate(shrunk_id);
988
+ if (r == INDEXED) { shrunk_id = iter.id(); }
989
+ }
990
+ return shrunk_id;
991
+ }
992
+
993
+ // Skip over the cells in the given range, creating index cells if we are
994
+ // currently in the interior of at least one shape.
995
+ void MutableS2ShapeIndex::SkipCellRange(S2CellId begin, S2CellId end,
996
+ InteriorTracker* tracker,
997
+ EdgeAllocator* alloc,
998
+ bool disjoint_from_index) {
999
+ // If we aren't in the interior of a shape, then skipping over cells is easy.
1000
+ if (tracker->shape_ids().empty()) return;
1001
+
1002
+ // Otherwise generate the list of cell ids that we need to visit, and create
1003
+ // an index entry for each one.
1004
+ for (S2CellId skipped_id : S2CellUnion::FromBeginEnd(begin, end)) {
1005
+ vector<const ClippedEdge*> clipped_edges;
1006
+ UpdateEdges(S2PaddedCell(skipped_id, kCellPadding),
1007
+ &clipped_edges, tracker, alloc, disjoint_from_index);
1008
+ }
1009
+ }
1010
+
1011
+ // Given a cell and a set of ClippedEdges whose bounding boxes intersect that
1012
+ // cell, add or remove all the edges from the index. Temporary space for
1013
+ // edges that need to be subdivided is allocated from the given EdgeAllocator.
1014
+ // "disjoint_from_index" is an optimization hint indicating that cell_map_
1015
+ // does not contain any entries that overlap the given cell.
1016
+ void MutableS2ShapeIndex::UpdateEdges(const S2PaddedCell& pcell,
1017
+ vector<const ClippedEdge*>* edges,
1018
+ InteriorTracker* tracker,
1019
+ EdgeAllocator* alloc,
1020
+ bool disjoint_from_index) {
1021
+ // Cases where an index cell is not needed should be detected before this.
1022
+ S2_DCHECK(!edges->empty() || !tracker->shape_ids().empty());
1023
+
1024
+ // This function is recursive with a maximum recursion depth of 30
1025
+ // (S2CellId::kMaxLevel). Note that using an explicit stack does not seem
1026
+ // to be any faster based on profiling.
1027
+
1028
+ // Incremental updates are handled as follows. All edges being added or
1029
+ // removed are combined together in "edges", and all shapes with interiors
1030
+ // are tracked using "tracker". We subdivide recursively as usual until we
1031
+ // encounter an existing index cell. At this point we "absorb" the index
1032
+ // cell as follows:
1033
+ //
1034
+ // - Edges and shapes that are being removed are deleted from "edges" and
1035
+ // "tracker".
1036
+ // - All remaining edges and shapes from the index cell are added to
1037
+ // "edges" and "tracker".
1038
+ // - Continue subdividing recursively, creating new index cells as needed.
1039
+ // - When the recursion gets back to the cell that was absorbed, we
1040
+ // restore "edges" and "tracker" to their previous state.
1041
+ //
1042
+ // Note that the only reason that we include removed shapes in the recursive
1043
+ // subdivision process is so that we can find all of the index cells that
1044
+ // contain those shapes efficiently, without maintaining an explicit list of
1045
+ // index cells for each shape (which would be expensive in terms of memory).
1046
+ bool index_cell_absorbed = false;
1047
+ if (!disjoint_from_index) {
1048
+ // There may be existing index cells contained inside "pcell". If we
1049
+ // encounter such a cell, we need to combine the edges being updated with
1050
+ // the existing cell contents by "absorbing" the cell.
1051
+ // Use InitStale() to avoid applying updated recursively.
1052
+ Iterator iter;
1053
+ iter.InitStale(this);
1054
+ CellRelation r = iter.Locate(pcell.id());
1055
+ if (r == DISJOINT) {
1056
+ disjoint_from_index = true;
1057
+ } else if (r == INDEXED) {
1058
+ // Absorb the index cell by transferring its contents to "edges" and
1059
+ // deleting it. We also start tracking the interior of any new shapes.
1060
+ AbsorbIndexCell(pcell, iter, edges, tracker, alloc);
1061
+ index_cell_absorbed = true;
1062
+ disjoint_from_index = true;
1063
+ } else {
1064
+ S2_DCHECK_EQ(SUBDIVIDED, r);
1065
+ }
1066
+ }
1067
+
1068
+ // If there are existing index cells below us, then we need to keep
1069
+ // subdividing so that we can merge with those cells. Otherwise,
1070
+ // MakeIndexCell checks if the number of edges is small enough, and creates
1071
+ // an index cell if possible (returning true when it does so).
1072
+ if (!disjoint_from_index || !MakeIndexCell(pcell, *edges, tracker)) {
1073
+ // Reserve space for the edges that will be passed to each child. This is
1074
+ // important since otherwise the running time is dominated by the time
1075
+ // required to grow the vectors. The amount of memory involved is
1076
+ // relatively small, so we simply reserve the maximum space for every child.
1077
+ vector<const ClippedEdge*> child_edges[2][2]; // [i][j]
1078
+ int num_edges = edges->size();
1079
+ for (int i = 0; i < 2; ++i) {
1080
+ for (int j = 0; j < 2; ++j) {
1081
+ child_edges[i][j].reserve(num_edges);
1082
+ }
1083
+ }
1084
+
1085
+ // Remember the current size of the EdgeAllocator so that we can free any
1086
+ // edges that are allocated during edge splitting.
1087
+ size_t alloc_size = alloc->size();
1088
+
1089
+ // Compute the middle of the padded cell, defined as the rectangle in
1090
+ // (u,v)-space that belongs to all four (padded) children. By comparing
1091
+ // against the four boundaries of "middle" we can determine which children
1092
+ // each edge needs to be propagated to.
1093
+ const R2Rect& middle = pcell.middle();
1094
+
1095
+ // Build up a vector edges to be passed to each child cell. The (i,j)
1096
+ // directions are left (i=0), right (i=1), lower (j=0), and upper (j=1).
1097
+ // Note that the vast majority of edges are propagated to a single child.
1098
+ // This case is very fast, consisting of between 2 and 4 floating-point
1099
+ // comparisons and copying one pointer. (ClipVAxis is inline.)
1100
+ for (int e = 0; e < num_edges; ++e) {
1101
+ const ClippedEdge* edge = (*edges)[e];
1102
+ if (edge->bound[0].hi() <= middle[0].lo()) {
1103
+ // Edge is entirely contained in the two left children.
1104
+ ClipVAxis(edge, middle[1], child_edges[0], alloc);
1105
+ } else if (edge->bound[0].lo() >= middle[0].hi()) {
1106
+ // Edge is entirely contained in the two right children.
1107
+ ClipVAxis(edge, middle[1], child_edges[1], alloc);
1108
+ } else if (edge->bound[1].hi() <= middle[1].lo()) {
1109
+ // Edge is entirely contained in the two lower children.
1110
+ child_edges[0][0].push_back(ClipUBound(edge, 1, middle[0].hi(), alloc));
1111
+ child_edges[1][0].push_back(ClipUBound(edge, 0, middle[0].lo(), alloc));
1112
+ } else if (edge->bound[1].lo() >= middle[1].hi()) {
1113
+ // Edge is entirely contained in the two upper children.
1114
+ child_edges[0][1].push_back(ClipUBound(edge, 1, middle[0].hi(), alloc));
1115
+ child_edges[1][1].push_back(ClipUBound(edge, 0, middle[0].lo(), alloc));
1116
+ } else {
1117
+ // The edge bound spans all four children. The edge itself intersects
1118
+ // either three or four (padded) children.
1119
+ const ClippedEdge* left = ClipUBound(edge, 1, middle[0].hi(), alloc);
1120
+ ClipVAxis(left, middle[1], child_edges[0], alloc);
1121
+ const ClippedEdge* right = ClipUBound(edge, 0, middle[0].lo(), alloc);
1122
+ ClipVAxis(right, middle[1], child_edges[1], alloc);
1123
+ }
1124
+ }
1125
+ // Free any memory reserved for children that turned out to be empty. This
1126
+ // step is cheap and reduces peak memory usage by about 10% when building
1127
+ // large indexes (> 10M edges).
1128
+ for (int i = 0; i < 2; ++i) {
1129
+ for (int j = 0; j < 2; ++j) {
1130
+ if (child_edges[i][j].empty()) {
1131
+ vector<const ClippedEdge*>().swap(child_edges[i][j]);
1132
+ }
1133
+ }
1134
+ }
1135
+ // Now recursively update the edges in each child. We call the children in
1136
+ // increasing order of S2CellId so that when the index is first constructed,
1137
+ // all insertions into cell_map_ are at the end (which is much faster).
1138
+ for (int pos = 0; pos < 4; ++pos) {
1139
+ int i, j;
1140
+ pcell.GetChildIJ(pos, &i, &j);
1141
+ if (!child_edges[i][j].empty() || !tracker->shape_ids().empty()) {
1142
+ UpdateEdges(S2PaddedCell(pcell, i, j), &child_edges[i][j],
1143
+ tracker, alloc, disjoint_from_index);
1144
+ }
1145
+ }
1146
+ // Free any temporary edges that were allocated during clipping.
1147
+ alloc->Reset(alloc_size);
1148
+ }
1149
+ if (index_cell_absorbed) {
1150
+ // Restore the state for any edges being removed that we are tracking.
1151
+ tracker->RestoreStateBefore(pending_additions_begin_);
1152
+ }
1153
+ }
1154
+
1155
+ // Given an edge and an interval "middle" along the v-axis, clip the edge
1156
+ // against the boundaries of "middle" and add the edge to the corresponding
1157
+ // children.
1158
+ /* static */
1159
+ inline void MutableS2ShapeIndex::ClipVAxis(
1160
+ const ClippedEdge* edge,
1161
+ const R1Interval& middle,
1162
+ vector<const ClippedEdge*> child_edges[2],
1163
+ EdgeAllocator* alloc) {
1164
+ if (edge->bound[1].hi() <= middle.lo()) {
1165
+ // Edge is entirely contained in the lower child.
1166
+ child_edges[0].push_back(edge);
1167
+ } else if (edge->bound[1].lo() >= middle.hi()) {
1168
+ // Edge is entirely contained in the upper child.
1169
+ child_edges[1].push_back(edge);
1170
+ } else {
1171
+ // The edge bound spans both children.
1172
+ child_edges[0].push_back(ClipVBound(edge, 1, middle.hi(), alloc));
1173
+ child_edges[1].push_back(ClipVBound(edge, 0, middle.lo(), alloc));
1174
+ }
1175
+ }
1176
+
1177
+ // Given an edge, clip the given endpoint (lo=0, hi=1) of the u-axis so that
1178
+ // it does not extend past the given value.
1179
+ /* static */
1180
+ const MutableS2ShapeIndex::ClippedEdge*
1181
+ MutableS2ShapeIndex::ClipUBound(const ClippedEdge* edge, int u_end, double u,
1182
+ EdgeAllocator* alloc) {
1183
+ // First check whether the edge actually requires any clipping. (Sometimes
1184
+ // this method is called when clipping is not necessary, e.g. when one edge
1185
+ // endpoint is in the overlap area between two padded child cells.)
1186
+ if (u_end == 0) {
1187
+ if (edge->bound[0].lo() >= u) return edge;
1188
+ } else {
1189
+ if (edge->bound[0].hi() <= u) return edge;
1190
+ }
1191
+ // We interpolate the new v-value from the endpoints of the original edge.
1192
+ // This has two advantages: (1) we don't need to store the clipped endpoints
1193
+ // at all, just their bounding box; and (2) it avoids the accumulation of
1194
+ // roundoff errors due to repeated interpolations. The result needs to be
1195
+ // clamped to ensure that it is in the appropriate range.
1196
+ const FaceEdge& e = *edge->face_edge;
1197
+ double v = edge->bound[1].Project(
1198
+ S2::InterpolateDouble(u, e.a[0], e.b[0], e.a[1], e.b[1]));
1199
+
1200
+ // Determine which endpoint of the v-axis bound to update. If the edge
1201
+ // slope is positive we update the same endpoint, otherwise we update the
1202
+ // opposite endpoint.
1203
+ int v_end = u_end ^ ((e.a[0] > e.b[0]) != (e.a[1] > e.b[1]));
1204
+ return UpdateBound(edge, u_end, u, v_end, v, alloc);
1205
+ }
1206
+
1207
+ // Given an edge, clip the given endpoint (lo=0, hi=1) of the v-axis so that
1208
+ // it does not extend past the given value.
1209
+ /* static */
1210
+ const MutableS2ShapeIndex::ClippedEdge*
1211
+ MutableS2ShapeIndex::ClipVBound(const ClippedEdge* edge, int v_end, double v,
1212
+ EdgeAllocator* alloc) {
1213
+ // See comments in ClipUBound.
1214
+ if (v_end == 0) {
1215
+ if (edge->bound[1].lo() >= v) return edge;
1216
+ } else {
1217
+ if (edge->bound[1].hi() <= v) return edge;
1218
+ }
1219
+ const FaceEdge& e = *edge->face_edge;
1220
+ double u = edge->bound[0].Project(
1221
+ S2::InterpolateDouble(v, e.a[1], e.b[1], e.a[0], e.b[0]));
1222
+ int u_end = v_end ^ ((e.a[0] > e.b[0]) != (e.a[1] > e.b[1]));
1223
+ return UpdateBound(edge, u_end, u, v_end, v, alloc);
1224
+ }
1225
+
1226
+ // Given an edge and two bound endpoints that need to be updated, allocate and
1227
+ // return a new edge with the updated bound.
1228
+ /* static */
1229
+ inline const MutableS2ShapeIndex::ClippedEdge*
1230
+ MutableS2ShapeIndex::UpdateBound(const ClippedEdge* edge, int u_end, double u,
1231
+ int v_end, double v, EdgeAllocator* alloc) {
1232
+ ClippedEdge* clipped = alloc->NewClippedEdge();
1233
+ clipped->face_edge = edge->face_edge;
1234
+ clipped->bound[0][u_end] = u;
1235
+ clipped->bound[1][v_end] = v;
1236
+ clipped->bound[0][1-u_end] = edge->bound[0][1-u_end];
1237
+ clipped->bound[1][1-v_end] = edge->bound[1][1-v_end];
1238
+ S2_DCHECK(!clipped->bound.is_empty());
1239
+ S2_DCHECK(edge->bound.Contains(clipped->bound));
1240
+ return clipped;
1241
+ }
1242
+
1243
+ // Absorb an index cell by transferring its contents to "edges" and/or
1244
+ // "tracker", and then delete this cell from the index. If "edges" includes
1245
+ // any edges that are being removed, this method also updates their
1246
+ // InteriorTracker state to correspond to the exit vertex of this cell, and
1247
+ // saves the InteriorTracker state by calling SaveAndClearStateBefore(). It
1248
+ // is the caller's responsibility to restore this state by calling
1249
+ // RestoreStateBefore() when processing of this cell is finished.
1250
+ void MutableS2ShapeIndex::AbsorbIndexCell(const S2PaddedCell& pcell,
1251
+ const Iterator& iter,
1252
+ vector<const ClippedEdge*>* edges,
1253
+ InteriorTracker* tracker,
1254
+ EdgeAllocator* alloc) {
1255
+ S2_DCHECK_EQ(pcell.id(), iter.id());
1256
+
1257
+ // When we absorb a cell, we erase all the edges that are being removed.
1258
+ // However when we are finished with this cell, we want to restore the state
1259
+ // of those edges (since that is how we find all the index cells that need
1260
+ // to be updated). The edges themselves are restored automatically when
1261
+ // UpdateEdges returns from its recursive call, but the InteriorTracker
1262
+ // state needs to be restored explicitly.
1263
+ //
1264
+ // Here we first update the InteriorTracker state for removed edges to
1265
+ // correspond to the exit vertex of this cell, and then save the
1266
+ // InteriorTracker state. This state will be restored by UpdateEdges when
1267
+ // it is finished processing the contents of this cell.
1268
+ if (tracker->is_active() && !edges->empty() &&
1269
+ is_shape_being_removed((*edges)[0]->face_edge->shape_id)) {
1270
+ // We probably need to update the InteriorTracker. ("Probably" because
1271
+ // it's possible that all shapes being removed do not have interiors.)
1272
+ if (!tracker->at_cellid(pcell.id())) {
1273
+ tracker->MoveTo(pcell.GetEntryVertex());
1274
+ }
1275
+ tracker->DrawTo(pcell.GetExitVertex());
1276
+ tracker->set_next_cellid(pcell.id().next());
1277
+ for (const ClippedEdge* edge : *edges) {
1278
+ const FaceEdge* face_edge = edge->face_edge;
1279
+ if (!is_shape_being_removed(face_edge->shape_id)) {
1280
+ break; // All shapes being removed come first.
1281
+ }
1282
+ if (face_edge->has_interior) {
1283
+ tracker->TestEdge(face_edge->shape_id, face_edge->edge);
1284
+ }
1285
+ }
1286
+ }
1287
+ // Save the state of the edges being removed, so that it can be restored
1288
+ // when we are finished processing this cell and its children. We don't
1289
+ // need to save the state of the edges being added because they aren't being
1290
+ // removed from "edges" and will therefore be updated normally as we visit
1291
+ // this cell and its children.
1292
+ tracker->SaveAndClearStateBefore(pending_additions_begin_);
1293
+
1294
+ // Create a FaceEdge for each edge in this cell that isn't being removed.
1295
+ vector<FaceEdge>* face_edges = alloc->mutable_face_edges();
1296
+ face_edges->clear();
1297
+ bool tracker_moved = false;
1298
+ const S2ShapeIndexCell& cell = iter.cell();
1299
+ for (int s = 0; s < cell.num_clipped(); ++s) {
1300
+ const S2ClippedShape& clipped = cell.clipped(s);
1301
+ int shape_id = clipped.shape_id();
1302
+ const S2Shape* shape = this->shape(shape_id);
1303
+ if (shape == nullptr) continue; // This shape is being removed.
1304
+ int num_edges = clipped.num_edges();
1305
+
1306
+ // If this shape has an interior, start tracking whether we are inside the
1307
+ // shape. UpdateEdges() wants to know whether the entry vertex of this
1308
+ // cell is inside the shape, but we only know whether the center of the
1309
+ // cell is inside the shape, so we need to test all the edges against the
1310
+ // line segment from the cell center to the entry vertex.
1311
+ FaceEdge edge;
1312
+ edge.shape_id = shape->id();
1313
+ edge.has_interior = (shape->dimension() == 2);
1314
+ if (edge.has_interior) {
1315
+ tracker->AddShape(shape_id, clipped.contains_center());
1316
+ // There might not be any edges in this entire cell (i.e., it might be
1317
+ // in the interior of all shapes), so we delay updating the tracker
1318
+ // until we see the first edge.
1319
+ if (!tracker_moved && num_edges > 0) {
1320
+ tracker->MoveTo(pcell.GetCenter());
1321
+ tracker->DrawTo(pcell.GetEntryVertex());
1322
+ tracker->set_next_cellid(pcell.id());
1323
+ tracker_moved = true;
1324
+ }
1325
+ }
1326
+ for (int i = 0; i < num_edges; ++i) {
1327
+ int e = clipped.edge(i);
1328
+ edge.edge_id = e;
1329
+ edge.edge = shape->edge(e);
1330
+ edge.max_level = GetEdgeMaxLevel(edge.edge);
1331
+ if (edge.has_interior) tracker->TestEdge(shape_id, edge.edge);
1332
+ if (!S2::ClipToPaddedFace(edge.edge.v0, edge.edge.v1, pcell.id().face(),
1333
+ kCellPadding, &edge.a, &edge.b)) {
1334
+ S2_LOG(DFATAL) << "Invariant failure in MutableS2ShapeIndex";
1335
+ }
1336
+ face_edges->push_back(edge);
1337
+ }
1338
+ }
1339
+ // Now create a ClippedEdge for each FaceEdge, and put them in "new_edges".
1340
+ vector<const ClippedEdge*> new_edges;
1341
+ for (const FaceEdge& face_edge : *face_edges) {
1342
+ ClippedEdge* clipped = alloc->NewClippedEdge();
1343
+ clipped->face_edge = &face_edge;
1344
+ clipped->bound = S2::GetClippedEdgeBound(face_edge.a, face_edge.b,
1345
+ pcell.bound());
1346
+ new_edges.push_back(clipped);
1347
+ }
1348
+ // Discard any edges from "edges" that are being removed, and append the
1349
+ // remainder to "new_edges". (This keeps the edges sorted by shape id.)
1350
+ for (int i = 0; i < edges->size(); ++i) {
1351
+ const ClippedEdge* clipped = (*edges)[i];
1352
+ if (!is_shape_being_removed(clipped->face_edge->shape_id)) {
1353
+ new_edges.insert(new_edges.end(), edges->begin() + i, edges->end());
1354
+ break;
1355
+ }
1356
+ }
1357
+ // Update the edge list and delete this cell from the index.
1358
+ edges->swap(new_edges);
1359
+ cell_map_.erase(pcell.id());
1360
+ delete &cell;
1361
+ }
1362
+
1363
+ // Attempt to build an index cell containing the given edges, and return true
1364
+ // if successful. (Otherwise the edges should be subdivided further.)
1365
+ bool MutableS2ShapeIndex::MakeIndexCell(const S2PaddedCell& pcell,
1366
+ const vector<const ClippedEdge*>& edges,
1367
+ InteriorTracker* tracker) {
1368
+ if (edges.empty() && tracker->shape_ids().empty()) {
1369
+ // No index cell is needed. (In most cases this situation is detected
1370
+ // before we get to this point, but this can happen when all shapes in a
1371
+ // cell are removed.)
1372
+ return true;
1373
+ }
1374
+
1375
+ // Count the number of edges that have not reached their maximum level yet.
1376
+ // Return false if there are too many such edges.
1377
+ int count = 0;
1378
+ for (const ClippedEdge* edge : edges) {
1379
+ count += (pcell.level() < edge->face_edge->max_level);
1380
+ if (count > options_.max_edges_per_cell())
1381
+ return false;
1382
+ }
1383
+
1384
+ // Possible optimization: Continue subdividing as long as exactly one child
1385
+ // of "pcell" intersects the given edges. This can be done by finding the
1386
+ // bounding box of all the edges and calling ShrinkToFit():
1387
+ //
1388
+ // S2CellId cellid = pcell.ShrinkToFit(GetRectBound(edges));
1389
+ //
1390
+ // Currently this is not beneficial; it slows down construction by 4-25%
1391
+ // (mainly computing the union of the bounding rectangles) and also slows
1392
+ // down queries (since more recursive clipping is required to get down to
1393
+ // the level of a spatial index cell). But it may be worth trying again
1394
+ // once "contains_center" is computed and all algorithms are modified to
1395
+ // take advantage of it.
1396
+
1397
+ // We update the InteriorTracker as follows. For every S2Cell in the index
1398
+ // we construct two edges: one edge from entry vertex of the cell to its
1399
+ // center, and one from the cell center to its exit vertex. Here "entry"
1400
+ // and "exit" refer the S2CellId ordering, i.e. the order in which points
1401
+ // are encountered along the S2 space-filling curve. The exit vertex then
1402
+ // becomes the entry vertex for the next cell in the index, unless there are
1403
+ // one or more empty intervening cells, in which case the InteriorTracker
1404
+ // state is unchanged because the intervening cells have no edges.
1405
+
1406
+ // Shift the InteriorTracker focus point to the center of the current cell.
1407
+ if (tracker->is_active() && !edges.empty()) {
1408
+ if (!tracker->at_cellid(pcell.id())) {
1409
+ tracker->MoveTo(pcell.GetEntryVertex());
1410
+ }
1411
+ tracker->DrawTo(pcell.GetCenter());
1412
+ TestAllEdges(edges, tracker);
1413
+ }
1414
+ // Allocate and fill a new index cell. To get the total number of shapes we
1415
+ // need to merge the shapes associated with the intersecting edges together
1416
+ // with the shapes that happen to contain the cell center.
1417
+ const ShapeIdSet& cshape_ids = tracker->shape_ids();
1418
+ int num_shapes = CountShapes(edges, cshape_ids);
1419
+ S2ShapeIndexCell* cell = new S2ShapeIndexCell;
1420
+ S2ClippedShape* base = cell->add_shapes(num_shapes);
1421
+
1422
+ // To fill the index cell we merge the two sources of shapes: "edge shapes"
1423
+ // (those that have at least one edge that intersects this cell), and
1424
+ // "containing shapes" (those that contain the cell center). We keep track
1425
+ // of the index of the next intersecting edge and the next containing shape
1426
+ // as we go along. Both sets of shape ids are already sorted.
1427
+ int enext = 0;
1428
+ ShapeIdSet::const_iterator cnext = cshape_ids.begin();
1429
+ for (int i = 0; i < num_shapes; ++i) {
1430
+ S2ClippedShape* clipped = base + i;
1431
+ int eshape_id = num_shape_ids(), cshape_id = eshape_id; // Sentinels
1432
+ if (enext != edges.size()) {
1433
+ eshape_id = edges[enext]->face_edge->shape_id;
1434
+ }
1435
+ if (cnext != cshape_ids.end()) {
1436
+ cshape_id = *cnext;
1437
+ }
1438
+ int ebegin = enext;
1439
+ if (cshape_id < eshape_id) {
1440
+ // The entire cell is in the shape interior.
1441
+ clipped->Init(cshape_id, 0);
1442
+ clipped->set_contains_center(true);
1443
+ ++cnext;
1444
+ } else {
1445
+ // Count the number of edges for this shape and allocate space for them.
1446
+ while (enext < edges.size() &&
1447
+ edges[enext]->face_edge->shape_id == eshape_id) {
1448
+ ++enext;
1449
+ }
1450
+ clipped->Init(eshape_id, enext - ebegin);
1451
+ for (int e = ebegin; e < enext; ++e) {
1452
+ clipped->set_edge(e - ebegin, edges[e]->face_edge->edge_id);
1453
+ }
1454
+ if (cshape_id == eshape_id) {
1455
+ clipped->set_contains_center(true);
1456
+ ++cnext;
1457
+ }
1458
+ }
1459
+ }
1460
+ // UpdateEdges() visits cells in increasing order of S2CellId, so during
1461
+ // initial construction of the index all insertions happen at the end. It
1462
+ // is much faster to give an insertion hint in this case. Otherwise the
1463
+ // hint doesn't do much harm. With more effort we could provide a hint even
1464
+ // during incremental updates, but this is probably not worth the effort.
1465
+ cell_map_.insert(cell_map_.end(), std::make_pair(pcell.id(), cell));
1466
+
1467
+ // Shift the InteriorTracker focus point to the exit vertex of this cell.
1468
+ if (tracker->is_active() && !edges.empty()) {
1469
+ tracker->DrawTo(pcell.GetExitVertex());
1470
+ TestAllEdges(edges, tracker);
1471
+ tracker->set_next_cellid(pcell.id().next());
1472
+ }
1473
+ return true;
1474
+ }
1475
+
1476
+ // Call tracker->TestEdge() on all edges from shapes that have interiors.
1477
+ /* static */
1478
+ void MutableS2ShapeIndex::TestAllEdges(const vector<const ClippedEdge*>& edges,
1479
+ InteriorTracker* tracker) {
1480
+ for (const ClippedEdge* edge : edges) {
1481
+ const FaceEdge* face_edge = edge->face_edge;
1482
+ if (face_edge->has_interior) {
1483
+ tracker->TestEdge(face_edge->shape_id, face_edge->edge);
1484
+ }
1485
+ }
1486
+ }
1487
+
1488
+ // Return the number of distinct shapes that are either associated with the
1489
+ // given edges, or that are currently stored in the InteriorTracker.
1490
+ /* static */
1491
+ int MutableS2ShapeIndex::CountShapes(const vector<const ClippedEdge*>& edges,
1492
+ const ShapeIdSet& cshape_ids) {
1493
+ int count = 0;
1494
+ int last_shape_id = -1;
1495
+ ShapeIdSet::const_iterator cnext = cshape_ids.begin(); // Next shape
1496
+ for (const ClippedEdge* edge : edges) {
1497
+ if (edge->face_edge->shape_id != last_shape_id) {
1498
+ ++count;
1499
+ last_shape_id = edge->face_edge->shape_id;
1500
+ // Skip over any containing shapes up to and including this one,
1501
+ // updating "count" appropriately.
1502
+ for (; cnext != cshape_ids.end(); ++cnext) {
1503
+ if (*cnext > last_shape_id) break;
1504
+ if (*cnext < last_shape_id) ++count;
1505
+ }
1506
+ }
1507
+ }
1508
+ // Count any remaining containing shapes.
1509
+ count += (cshape_ids.end() - cnext);
1510
+ return count;
1511
+ }
1512
+
1513
+ size_t MutableS2ShapeIndex::SpaceUsed() const {
1514
+ size_t size = sizeof(*this);
1515
+ size += shapes_.capacity() * sizeof(std::unique_ptr<S2Shape>);
1516
+ // cell_map_ itself is already included in sizeof(*this).
1517
+ size += cell_map_.bytes_used() - sizeof(cell_map_);
1518
+ size += cell_map_.size() * sizeof(S2ShapeIndexCell);
1519
+ Iterator it;
1520
+ for (it.InitStale(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
1521
+ const S2ShapeIndexCell& cell = it.cell();
1522
+ size += cell.shapes_.capacity() * sizeof(S2ClippedShape);
1523
+ for (int s = 0; s < cell.num_clipped(); ++s) {
1524
+ const S2ClippedShape& clipped = cell.clipped(s);
1525
+ if (!clipped.is_inline()) {
1526
+ size += clipped.num_edges() * sizeof(int32);
1527
+ }
1528
+ }
1529
+ }
1530
+ if (pending_removals_ != nullptr) {
1531
+ size += pending_removals_->capacity() * sizeof(RemovedShape);
1532
+ }
1533
+
1534
+ return size;
1535
+ }
1536
+
1537
+ void MutableS2ShapeIndex::Encode(Encoder* encoder) const {
1538
+ // The version number is encoded in 2 bits, under the assumption that by the
1539
+ // time we need 5 versions the first version can be permanently retired.
1540
+ // This only saves 1 byte, but that's significant for very small indexes.
1541
+ encoder->Ensure(Varint::kMax64);
1542
+ uint64 max_edges = options_.max_edges_per_cell();
1543
+ encoder->put_varint64(max_edges << 2 | kCurrentEncodingVersionNumber);
1544
+
1545
+ vector<S2CellId> cell_ids;
1546
+ cell_ids.reserve(cell_map_.size());
1547
+ s2coding::StringVectorEncoder encoded_cells;
1548
+ for (Iterator it(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
1549
+ cell_ids.push_back(it.id());
1550
+ it.cell().Encode(num_shape_ids(), encoded_cells.AddViaEncoder());
1551
+ }
1552
+ s2coding::EncodeS2CellIdVector(cell_ids, encoder);
1553
+ encoded_cells.Encode(encoder);
1554
+ }
1555
+
1556
+ bool MutableS2ShapeIndex::Init(Decoder* decoder,
1557
+ const ShapeFactory& shape_factory) {
1558
+ Clear();
1559
+ uint64 max_edges_version;
1560
+ if (!decoder->get_varint64(&max_edges_version)) return false;
1561
+ int version = max_edges_version & 3;
1562
+ if (version != kCurrentEncodingVersionNumber) return false;
1563
+ options_.set_max_edges_per_cell(max_edges_version >> 2);
1564
+ uint32 num_shapes = shape_factory.size();
1565
+ shapes_.reserve(num_shapes);
1566
+ for (int shape_id = 0; shape_id < num_shapes; ++shape_id) {
1567
+ auto shape = shape_factory[shape_id];
1568
+ if (shape) shape->id_ = shape_id;
1569
+ shapes_.push_back(std::move(shape));
1570
+ }
1571
+
1572
+ s2coding::EncodedS2CellIdVector cell_ids;
1573
+ s2coding::EncodedStringVector encoded_cells;
1574
+ if (!cell_ids.Init(decoder)) return false;
1575
+ if (!encoded_cells.Init(decoder)) return false;
1576
+
1577
+ for (int i = 0; i < cell_ids.size(); ++i) {
1578
+ S2CellId id = cell_ids[i];
1579
+ S2ShapeIndexCell* cell = new S2ShapeIndexCell;
1580
+ Decoder decoder = encoded_cells.GetDecoder(i);
1581
+ if (!cell->Decode(num_shapes, &decoder)) return false;
1582
+ cell_map_.insert(cell_map_.end(), std::make_pair(id, cell));
1583
+ }
1584
+ return true;
1585
+ }