/src/s2geometry/src/s2/s2loop.cc
Line | Count | Source |
1 | | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS-IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | |
16 | | // Author: ericv@google.com (Eric Veach) |
17 | | |
18 | | #include "s2/s2loop.h" |
19 | | |
20 | | #include <algorithm> |
21 | | #include <atomic> |
22 | | #include <bitset> |
23 | | #include <cmath> |
24 | | #include <cstddef> |
25 | | #include <cstdint> |
26 | | #include <memory> |
27 | | #include <utility> |
28 | | #include <vector> |
29 | | |
30 | | #include "absl/container/flat_hash_set.h" |
31 | | #include "absl/flags/flag.h" |
32 | | #include "absl/log/absl_check.h" |
33 | | #include "absl/log/absl_log.h" |
34 | | #include "absl/strings/str_format.h" |
35 | | #include "absl/types/span.h" |
36 | | #include "absl/utility/utility.h" |
37 | | |
38 | | #include "s2/base/casts.h" |
39 | | #include "s2/mutable_s2shape_index.h" |
40 | | #include "s2/r1interval.h" |
41 | | #include "s2/r2.h" |
42 | | #include "s2/r2rect.h" |
43 | | #include "s2/s1angle.h" |
44 | | #include "s2/s1chord_angle.h" |
45 | | #include "s2/s1interval.h" |
46 | | #include "s2/s2cap.h" |
47 | | #include "s2/s2cell.h" |
48 | | #include "s2/s2cell_id.h" |
49 | | #include "s2/s2cell_union.h" |
50 | | #include "s2/s2closest_edge_query.h" |
51 | | #include "s2/s2coords.h" |
52 | | #include "s2/s2crossing_edge_query.h" |
53 | | #include "s2/s2debug.h" |
54 | | #include "s2/s2edge_clipping.h" |
55 | | #include "s2/s2edge_crosser.h" |
56 | | #include "s2/s2edge_crossings.h" |
57 | | #include "s2/s2edge_distances.h" |
58 | | #include "s2/s2error.h" |
59 | | #include "s2/s2latlng_rect.h" |
60 | | #include "s2/s2latlng_rect_bounder.h" |
61 | | #include "s2/s2loop_measures.h" |
62 | | #include "s2/s2padded_cell.h" |
63 | | #include "s2/s2point.h" |
64 | | #include "s2/s2point_compression.h" |
65 | | #include "s2/s2pointutil.h" |
66 | | #include "s2/s2predicates.h" |
67 | | #include "s2/s2region.h" |
68 | | #include "s2/s2shape.h" |
69 | | #include "s2/s2shape_index.h" |
70 | | #include "s2/s2shapeutil_visit_crossing_edge_pairs.h" |
71 | | #include "s2/s2wedge_relations.h" |
72 | | #include "s2/util/coding/coder.h" |
73 | | #include "s2/util/math/matrix3x3.h" |
74 | | |
75 | | using absl::flat_hash_set; |
76 | | using absl::MakeSpan; |
77 | | using absl::Span; |
78 | | using std::make_unique; |
79 | | using std::pair; |
80 | | using std::unique_ptr; |
81 | | using std::vector; |
82 | | |
83 | | // The maximum number of vertices we'll allow when decoding a loop. |
84 | | // The default value of 50 million is about 30x bigger than the number of |
85 | 0 | ABSL_FLAG(int32_t, s2polygon_decode_max_num_vertices, 50000000, Unexecuted instantiation: AbslFlagDefaultGenFors2polygon_decode_max_num_vertices::Gen(void*) Unexecuted instantiation: AbslFlagHelpGenFors2polygon_decode_max_num_vertices::Value(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: AbslFlagHelpGenFors2polygon_decode_max_num_vertices::NonConst() |
86 | 0 | "The upper limit on the number of loops that are allowed by the " |
87 | 0 | "S2Polygon::Decode method."); |
88 | 0 |
|
89 | 0 | static const unsigned char kCurrentLosslessEncodingVersionNumber = 1; |
90 | 0 |
|
91 | 0 | // Boolean properties for compressed loops. |
92 | 0 | // See GetCompressedEncodingProperties. |
93 | 0 | enum CompressedLoopProperty { |
94 | 0 | kOriginInside, |
95 | 0 | kBoundEncoded, |
96 | 0 | kNumProperties |
97 | 0 | }; |
98 | 0 |
|
99 | 0 | // These could be constexpr in s2loop.h, but gcc-13 gives an error. |
100 | 0 | const S2Point S2Loop::kEmptyVertex(0, 0, 1); |
101 | 0 | const S2Point S2Loop::kFullVertex(0, 0, -1); |
102 | 0 |
|
103 | 0 | S2Loop::S2Loop() { |
104 | | // The loop is not valid until Init() is called. |
105 | 0 | } |
106 | | |
107 | | S2Loop::S2Loop(S2Loop&& b) noexcept |
108 | | // S2Region has no members, so does not need to be moved. |
109 | 0 | : depth_(std::exchange(b.depth_, 0)), |
110 | 0 | num_vertices_(std::exchange(b.num_vertices_, 0)), |
111 | 0 | vertices_(std::move(b.vertices_)), |
112 | 0 | s2debug_override_(std::move(b.s2debug_override_)), |
113 | 0 | origin_inside_(std::move(b.origin_inside_)), |
114 | 0 | unindexed_contains_calls_( |
115 | 0 | b.unindexed_contains_calls_.exchange(0, std::memory_order_relaxed)), |
116 | 0 | bound_(std::move(b.bound_)), |
117 | 0 | subregion_bound_(std::move(b.subregion_bound_)), |
118 | 0 | index_(std::move(b.index_)) { |
119 | | // Our index points to S2Loop::Shape instances which point back to S2Loop, |
120 | | // we need to update those S2Loop pointers now that we've moved. |
121 | 0 | for (const S2Shape* shape : index_) { |
122 | 0 | const_cast<Shape*>(down_cast<const Shape*>(shape))->loop_ = this; |
123 | 0 | } |
124 | 0 | } |
125 | | |
126 | 0 | S2Loop& S2Loop::operator=(S2Loop&& b) noexcept { |
127 | | // S2Region has no members, so does not need to be assigned. |
128 | 0 | depth_ = std::exchange(b.depth_, 0); |
129 | 0 | num_vertices_ = std::exchange(b.num_vertices_, 0); |
130 | 0 | vertices_ = std::move(b.vertices_); |
131 | 0 | s2debug_override_ = std::move(b.s2debug_override_); |
132 | 0 | origin_inside_ = std::move(b.origin_inside_); |
133 | 0 | unindexed_contains_calls_.store( |
134 | 0 | b.unindexed_contains_calls_.exchange(0, std::memory_order_relaxed), |
135 | 0 | std::memory_order_relaxed); |
136 | 0 | bound_ = std::move(b.bound_); |
137 | 0 | subregion_bound_ = std::move(b.subregion_bound_); |
138 | 0 | index_ = std::move(b.index_); |
139 | | |
140 | | // Our index points to S2Loop::Shape instances which point back to S2Loop, |
141 | | // we need to update those S2Loop pointers now that we've moved. |
142 | 0 | for (const S2Shape* shape : index_) { |
143 | 0 | const_cast<Shape*>(down_cast<const Shape*>(shape))->loop_ = this; |
144 | 0 | } |
145 | |
|
146 | 0 | return *this; |
147 | 0 | } |
148 | | |
149 | | S2Loop::S2Loop(Span<const S2Point> vertices) |
150 | 0 | : S2Loop(vertices, S2Debug::ALLOW) {} |
151 | | |
152 | | S2Loop::S2Loop(Span<const S2Point> vertices, S2Debug override) |
153 | 0 | : s2debug_override_(override) { |
154 | 0 | Init(vertices); |
155 | 0 | } |
156 | | |
157 | 0 | void S2Loop::set_s2debug_override(S2Debug override) { |
158 | 0 | s2debug_override_ = override; |
159 | 0 | } |
160 | | |
161 | 0 | S2Debug S2Loop::s2debug_override() const { |
162 | 0 | return s2debug_override_; |
163 | 0 | } |
164 | | |
165 | 0 | void S2Loop::ClearIndex() { |
166 | 0 | unindexed_contains_calls_.store(0, std::memory_order_relaxed); |
167 | 0 | index_.Clear(); |
168 | 0 | } |
169 | | |
170 | 0 | void S2Loop::Init(Span<const S2Point> vertices) { |
171 | 0 | ClearIndex(); |
172 | 0 | num_vertices_ = vertices.size(); |
173 | 0 | vertices_ = make_unique<S2Point[]>(num_vertices_); |
174 | 0 | std::copy(vertices.begin(), vertices.end(), &vertices_[0]); |
175 | 0 | InitOriginAndBound(); |
176 | 0 | } |
177 | | |
178 | 0 | bool S2Loop::IsValid() const { |
179 | 0 | S2Error error; |
180 | 0 | if (FindValidationError(&error)) { |
181 | 0 | ABSL_LOG_IF(ERROR, absl::GetFlag(FLAGS_s2debug)) << error; |
182 | 0 | return false; |
183 | 0 | } |
184 | 0 | return true; |
185 | 0 | } |
186 | | |
187 | 0 | bool S2Loop::FindValidationError(S2Error* error) const { |
188 | 0 | return (FindValidationErrorNoIndex(error) || |
189 | 0 | s2shapeutil::FindSelfIntersection(index_, error)); |
190 | 0 | } |
191 | | |
192 | 0 | bool S2Loop::FindValidationErrorNoIndex(S2Error* error) const { |
193 | | // subregion_bound_ must be at least as large as bound_. (This is an |
194 | | // internal consistency check rather than a test of client data.) |
195 | 0 | ABSL_DCHECK(subregion_bound_.Contains(bound_)); |
196 | | |
197 | | // All vertices must be unit length. (Unfortunately this check happens too |
198 | | // late in debug mode, because S2Loop construction calls s2pred::Sign which |
199 | | // expects vertices to be unit length. But it is still a useful check in |
200 | | // optimized builds.) |
201 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
202 | 0 | if (!S2::IsUnitLength(vertex(i))) { |
203 | 0 | *error = S2Error(S2Error::NOT_UNIT_LENGTH, |
204 | 0 | absl::StrFormat("Vertex %d is not unit length", i)); |
205 | 0 | return true; |
206 | 0 | } |
207 | 0 | } |
208 | | // Loops must have at least 3 vertices (except for the empty and full loops). |
209 | 0 | if (num_vertices() < 3) { |
210 | 0 | if (is_empty_or_full()) { |
211 | 0 | return false; // Skip remaining tests. |
212 | 0 | } |
213 | 0 | *error = S2Error(S2Error::LOOP_NOT_ENOUGH_VERTICES, |
214 | 0 | "Non-empty, non-full loops must have at least 3 vertices"); |
215 | 0 | return true; |
216 | 0 | } |
217 | | // Loops are not allowed to have any duplicate vertices or edge crossings. |
218 | | // We split this check into two parts. First we check that no edge is |
219 | | // degenerate (identical endpoints). Then we check that there are no |
220 | | // intersections between non-adjacent edges (including at vertices). The |
221 | | // second part needs the S2ShapeIndex, so it does not fall within the scope |
222 | | // of this method. |
223 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
224 | 0 | if (vertex(i) == vertex(i+1)) { |
225 | 0 | *error = S2Error( |
226 | 0 | S2Error::DUPLICATE_VERTICES, |
227 | 0 | absl::StrFormat("Edge %d is degenerate (duplicate vertex)", i)); |
228 | 0 | return true; |
229 | 0 | } |
230 | 0 | if (vertex(i) == -vertex(i + 1)) { |
231 | 0 | *error = S2Error(S2Error::ANTIPODAL_VERTICES, |
232 | 0 | absl::StrFormat("Vertices %d and %d are antipodal", i, |
233 | 0 | (i + 1) % num_vertices())); |
234 | 0 | return true; |
235 | 0 | } |
236 | 0 | } |
237 | 0 | return false; |
238 | 0 | } |
239 | | |
240 | 0 | void S2Loop::InitOriginAndBound() { |
241 | 0 | if (num_vertices() < 3) { |
242 | | // Check for the special empty and full loops (which have one vertex). |
243 | 0 | if (!is_empty_or_full()) { |
244 | 0 | origin_inside_ = false; |
245 | 0 | return; // Bail out without trying to access non-existent vertices. |
246 | 0 | } |
247 | | // If the vertex is in the southern hemisphere then the loop is full, |
248 | | // otherwise it is empty. |
249 | 0 | origin_inside_ = (vertex(0).z() < 0); |
250 | 0 | } else { |
251 | | // The brute force point containment algorithm works by counting edge |
252 | | // crossings starting at a fixed reference point (chosen as S2::Origin() |
253 | | // for historical reasons). Loop initialization would be more efficient |
254 | | // if we used a loop vertex such as vertex(0) as the reference point |
255 | | // instead, however making this change would be a lot of work because |
256 | | // origin_inside_ is currently part of the Encode() format. |
257 | | // |
258 | | // In any case, we initialize origin_inside_ by first guessing that it is |
259 | | // outside, and then seeing whether we get the correct containment result |
260 | | // for vertex 1. If the result is incorrect, the origin must be inside |
261 | | // the loop instead. Note that the S2Loop is not necessarily valid and so |
262 | | // we need to check the requirements of S2::AngleContainsVertex() first. |
263 | 0 | bool v1_inside = vertex(0) != vertex(1) && vertex(2) != vertex(1) && |
264 | 0 | S2::AngleContainsVertex(vertex(0), vertex(1), vertex(2)); |
265 | 0 | origin_inside_ = false; // Initialize before calling Contains(). |
266 | | |
267 | | // Note that Contains(S2Point) only does a bounds check once InitIndex() |
268 | | // has been called, so it doesn't matter that bound_ is undefined here. |
269 | 0 | if (v1_inside != Contains(vertex(1))) { |
270 | 0 | origin_inside_ = true; |
271 | 0 | } |
272 | 0 | } |
273 | | // We *must* call InitBound() before InitIndex(), because InitBound() calls |
274 | | // Contains(S2Point), and Contains(S2Point) does a bounds check whenever the |
275 | | // index is not fresh (i.e., the loop has been added to the index but the |
276 | | // index has not been updated yet). |
277 | | // |
278 | | // TODO(ericv): When fewer S2Loop methods depend on internal bounds checks, |
279 | | // consider computing the bound on demand as well. |
280 | 0 | InitBound(); |
281 | 0 | InitIndex(); |
282 | 0 | } |
283 | | |
284 | 0 | void S2Loop::InitBound() { |
285 | | // Check for the special empty and full loops. |
286 | 0 | if (is_empty_or_full()) { |
287 | 0 | if (is_empty()) { |
288 | 0 | subregion_bound_ = bound_ = S2LatLngRect::Empty(); |
289 | 0 | } else { |
290 | 0 | subregion_bound_ = bound_ = S2LatLngRect::Full(); |
291 | 0 | } |
292 | 0 | return; |
293 | 0 | } |
294 | | |
295 | | // The bounding rectangle of a loop is not necessarily the same as the |
296 | | // bounding rectangle of its vertices. First, the maximal latitude may be |
297 | | // attained along the interior of an edge. Second, the loop may wrap |
298 | | // entirely around the sphere (e.g. a loop that defines two revolutions of a |
299 | | // candy-cane stripe). Third, the loop may include one or both poles. |
300 | | // Note that a small clockwise loop near the equator contains both poles. |
301 | | |
302 | 0 | S2LatLngRectBounder bounder; |
303 | 0 | for (int i = 0; i <= num_vertices(); ++i) { |
304 | 0 | bounder.AddPoint(vertex(i)); |
305 | 0 | } |
306 | 0 | S2LatLngRect b = bounder.GetBound(); |
307 | 0 | if (Contains(S2Point(0, 0, 1))) { |
308 | 0 | b = S2LatLngRect(R1Interval(b.lat().lo(), M_PI_2), S1Interval::Full()); |
309 | 0 | } |
310 | | // If a loop contains the south pole, then either it wraps entirely |
311 | | // around the sphere (full longitude range), or it also contains the |
312 | | // north pole in which case b.lng().is_full() due to the test above. |
313 | | // Either way, we only need to do the south pole containment test if |
314 | | // b.lng().is_full(). |
315 | 0 | if (b.lng().is_full() && Contains(S2Point(0, 0, -1))) { |
316 | 0 | b.mutable_lat()->set_lo(-M_PI_2); |
317 | 0 | } |
318 | 0 | bound_ = b; |
319 | 0 | subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_); |
320 | 0 | } |
321 | | |
322 | 0 | void S2Loop::InitIndex() { |
323 | 0 | index_.Add(make_unique<Shape>(this)); |
324 | 0 | if (absl::GetFlag(FLAGS_s2debug) && s2debug_override_ == S2Debug::ALLOW) { |
325 | | // Note that FLAGS_s2debug is false in optimized builds (by default). |
326 | 0 | ABSL_CHECK(IsValid()); |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | | S2Loop::S2Loop(const S2Cell& cell) |
331 | 0 | : num_vertices_(4), vertices_(new S2Point[num_vertices_]) { |
332 | 0 | for (int i = 0; i < 4; ++i) { |
333 | 0 | vertices_[i] = cell.GetVertex(i); |
334 | 0 | } |
335 | | // We recompute the bounding rectangle ourselves, since S2Cell uses a |
336 | | // different method and we need all the bounds to be consistent. |
337 | 0 | InitOriginAndBound(); |
338 | 0 | } |
339 | | |
340 | 0 | S2Loop::~S2Loop() = default; |
341 | | |
342 | | S2Loop::S2Loop(const S2Loop& src) |
343 | 0 | : depth_(src.depth_), |
344 | 0 | num_vertices_(src.num_vertices_), |
345 | 0 | vertices_(make_unique<S2Point[]>(num_vertices_)), |
346 | 0 | s2debug_override_(src.s2debug_override_), |
347 | 0 | origin_inside_(src.origin_inside_), |
348 | 0 | bound_(src.bound_), |
349 | 0 | subregion_bound_(src.subregion_bound_) { |
350 | 0 | std::copy(&src.vertices_[0], &src.vertices_[num_vertices_], &vertices_[0]); |
351 | 0 | InitIndex(); |
352 | 0 | } |
353 | | |
354 | 0 | S2Loop* S2Loop::Clone() const { |
355 | 0 | return new S2Loop(*this); |
356 | 0 | } |
357 | | |
358 | 0 | int S2Loop::FindVertex(const S2Point& p) const { |
359 | 0 | if (num_vertices() < 10) { |
360 | | // Exhaustive search. Return value must be in the range [1..N]. |
361 | 0 | for (int i = 1; i <= num_vertices(); ++i) { |
362 | 0 | if (vertex(i) == p) return i; |
363 | 0 | } |
364 | 0 | return -1; |
365 | 0 | } |
366 | 0 | MutableS2ShapeIndex::Iterator it(&index_); |
367 | 0 | if (!it.Locate(p)) return -1; |
368 | | |
369 | 0 | const S2ClippedShape& a_clipped = it.cell().clipped(0); |
370 | 0 | for (int i = a_clipped.num_edges() - 1; i >= 0; --i) { |
371 | 0 | int ai = a_clipped.edge(i); |
372 | | // Return value must be in the range [1..N]. |
373 | 0 | if (vertex(ai) == p) return (ai == 0) ? num_vertices() : ai; |
374 | 0 | if (vertex(ai+1) == p) return ai+1; |
375 | 0 | } |
376 | 0 | return -1; |
377 | 0 | } |
378 | | |
379 | 0 | bool S2Loop::IsNormalized() const { |
380 | | // Optimization: if the longitude span is less than 180 degrees, then the |
381 | | // loop covers less than half the sphere and is therefore normalized. |
382 | 0 | if (bound_.lng().GetLength() < M_PI) return true; |
383 | | |
384 | 0 | return S2::IsNormalized(vertices_span()); |
385 | 0 | } |
386 | | |
387 | 0 | void S2Loop::Normalize() { |
388 | 0 | if (!IsNormalized()) Invert(); |
389 | 0 | ABSL_DCHECK(IsNormalized()); |
390 | 0 | } |
391 | | |
392 | 0 | void S2Loop::Invert() { |
393 | 0 | ClearIndex(); |
394 | 0 | if (is_empty_or_full()) { |
395 | 0 | vertices_[0] = is_full() ? kEmptyVertex : kFullVertex; |
396 | 0 | } else { |
397 | 0 | std::reverse(&vertices_[0], &vertices_[num_vertices()]); |
398 | 0 | } |
399 | | // origin_inside_ must be set correctly before building the S2ShapeIndex. |
400 | 0 | origin_inside_ ^= true; |
401 | 0 | if (bound_.lat().lo() > -M_PI_2 && bound_.lat().hi() < M_PI_2) { |
402 | | // The complement of this loop contains both poles. |
403 | 0 | subregion_bound_ = bound_ = S2LatLngRect::Full(); |
404 | 0 | } else { |
405 | 0 | InitBound(); |
406 | 0 | } |
407 | 0 | InitIndex(); |
408 | 0 | } |
409 | | |
410 | 0 | double S2Loop::GetArea() const { |
411 | | // S2Loop has its own convention for empty and full loops. |
412 | 0 | if (is_empty_or_full()) { |
413 | 0 | return contains_origin() ? (4 * M_PI) : 0; |
414 | 0 | } |
415 | 0 | return S2::GetArea(vertices_span()); |
416 | 0 | } |
417 | | |
418 | 0 | S2Point S2Loop::GetCentroid() const { |
419 | | // Empty and full loops are handled correctly. |
420 | 0 | return S2::GetCentroid(vertices_span()); |
421 | 0 | } |
422 | | |
423 | 0 | S2::LoopOrder S2Loop::GetCanonicalLoopOrder() const { |
424 | 0 | return S2::GetCanonicalLoopOrder(vertices_span()); |
425 | 0 | } |
426 | | |
427 | 0 | S1Angle S2Loop::GetDistance(const S2Point& x) const { |
428 | | // Note that S2Loop::Contains(S2Point) is slightly more efficient than the |
429 | | // generic version used by S2ClosestEdgeQuery. |
430 | 0 | if (Contains(x)) return S1Angle::Zero(); |
431 | 0 | return GetDistanceToBoundary(x); |
432 | 0 | } |
433 | | |
434 | 0 | S1Angle S2Loop::GetDistanceToBoundary(const S2Point& x) const { |
435 | 0 | S2ClosestEdgeQuery::Options options; |
436 | 0 | options.set_include_interiors(false); |
437 | 0 | S2ClosestEdgeQuery::PointTarget t(x); |
438 | 0 | return S2ClosestEdgeQuery(&index_, options).GetDistance(&t).ToAngle(); |
439 | 0 | } |
440 | | |
441 | 0 | S2Point S2Loop::Project(const S2Point& x) const { |
442 | 0 | if (Contains(x)) return x; |
443 | 0 | return ProjectToBoundary(x); |
444 | 0 | } |
445 | | |
446 | 0 | S2Point S2Loop::ProjectToBoundary(const S2Point& x) const { |
447 | 0 | S2ClosestEdgeQuery::Options options; |
448 | 0 | options.set_include_interiors(false); |
449 | 0 | S2ClosestEdgeQuery q(&index_, options); |
450 | 0 | S2ClosestEdgeQuery::PointTarget target(x); |
451 | 0 | S2ClosestEdgeQuery::Result edge = q.FindClosestEdge(&target); |
452 | 0 | return q.Project(x, edge); |
453 | 0 | } |
454 | | |
455 | 0 | double S2Loop::GetCurvature() const { |
456 | | // S2Loop has its own convention for empty and full loops. For such loops, |
457 | | // we return the limit value as the area approaches 0 or 4*Pi respectively. |
458 | 0 | if (is_empty_or_full()) { |
459 | 0 | return contains_origin() ? (-2 * M_PI) : (2 * M_PI); |
460 | 0 | } |
461 | 0 | return S2::GetCurvature(vertices_span()); |
462 | 0 | } |
463 | | |
464 | 0 | double S2Loop::GetCurvatureMaxError() const { |
465 | 0 | return S2::GetCurvatureMaxError(vertices_span()); |
466 | 0 | } |
467 | | |
468 | 0 | S2Cap S2Loop::GetCapBound() const { |
469 | 0 | return bound_.GetCapBound(); |
470 | 0 | } |
471 | | |
472 | 0 | void S2Loop::GetCellUnionBound(vector<S2CellId>* cell_ids) const { |
473 | 0 | GetCapBound().GetCellUnionBound(cell_ids); |
474 | 0 | } |
475 | | |
476 | 0 | bool S2Loop::Contains(const S2Cell& target) const { |
477 | 0 | MutableS2ShapeIndex::Iterator it(&index_); |
478 | 0 | S2CellRelation relation = it.Locate(target.id()); |
479 | | |
480 | | // If "target" is disjoint from all index cells, it is not contained. |
481 | | // Similarly, if "target" is subdivided into one or more index cells then it |
482 | | // is not contained, since index cells are subdivided only if they (nearly) |
483 | | // intersect a sufficient number of edges. (But note that if "target" itself |
484 | | // is an index cell then it may be contained, since it could be a cell with |
485 | | // no edges in the loop interior.) |
486 | 0 | if (relation != S2CellRelation::INDEXED) return false; |
487 | | |
488 | | // Otherwise check if any edges intersect "target". |
489 | 0 | if (BoundaryApproxIntersects(it, target)) return false; |
490 | | |
491 | | // Otherwise check if the loop contains the center of "target". |
492 | 0 | return Contains(it, target.GetCenter()); |
493 | 0 | } |
494 | | |
495 | 0 | bool S2Loop::MayIntersect(const S2Cell& target) const { |
496 | 0 | MutableS2ShapeIndex::Iterator it(&index_); |
497 | 0 | S2CellRelation relation = it.Locate(target.id()); |
498 | | |
499 | | // If "target" does not overlap any index cell, there is no intersection. |
500 | 0 | if (relation == S2CellRelation::DISJOINT) return false; |
501 | | |
502 | | // If "target" is subdivided into one or more index cells, there is an |
503 | | // intersection to within the S2ShapeIndex error bound (see Contains). |
504 | 0 | if (relation == S2CellRelation::SUBDIVIDED) return true; |
505 | | |
506 | | // If "target" is an index cell, there is an intersection because index cells |
507 | | // are created only if they have at least one edge or they are entirely |
508 | | // contained by the loop. |
509 | 0 | if (it.id() == target.id()) return true; |
510 | | |
511 | | // Otherwise check if any edges intersect "target". |
512 | 0 | if (BoundaryApproxIntersects(it, target)) return true; |
513 | | |
514 | | // Otherwise check if the loop contains the center of "target". |
515 | 0 | return Contains(it, target.GetCenter()); |
516 | 0 | } |
517 | | |
518 | | bool S2Loop::BoundaryApproxIntersects(const MutableS2ShapeIndex::Iterator& it, |
519 | 0 | const S2Cell& target) const { |
520 | 0 | ABSL_DCHECK(it.id().contains(target.id())); |
521 | 0 | const S2ClippedShape& a_clipped = it.cell().clipped(0); |
522 | 0 | int a_num_edges = a_clipped.num_edges(); |
523 | | |
524 | | // If there are no edges, there is no intersection. |
525 | 0 | if (a_num_edges == 0) return false; |
526 | | |
527 | | // We can save some work if "target" is the index cell itself. |
528 | 0 | if (it.id() == target.id()) return true; |
529 | | |
530 | | // Otherwise check whether any of the edges intersect "target". |
531 | 0 | static const double kMaxError = (S2::kFaceClipErrorUVCoord + |
532 | 0 | S2::kIntersectsRectErrorUVDist); |
533 | 0 | R2Rect bound = target.GetBoundUV().Expanded(kMaxError); |
534 | 0 | for (int i = 0; i < a_num_edges; ++i) { |
535 | 0 | int ai = a_clipped.edge(i); |
536 | 0 | R2Point v0, v1; |
537 | 0 | if (S2::ClipToPaddedFace(vertex(ai), vertex(ai+1), target.face(), |
538 | 0 | kMaxError, &v0, &v1) && |
539 | 0 | S2::IntersectsRect(v0, v1, bound)) { |
540 | 0 | return true; |
541 | 0 | } |
542 | 0 | } |
543 | 0 | return false; |
544 | 0 | } |
545 | | |
546 | 0 | bool S2Loop::Contains(const S2Point& p) const { |
547 | | // NOTE(ericv): A bounds check slows down this function by about 50%. It is |
548 | | // worthwhile only when it might allow us to delay building the index. |
549 | 0 | if (!index_.is_fresh() && !bound_.Contains(p)) return false; |
550 | | |
551 | | // For small loops it is faster to just check all the crossings. We also |
552 | | // use this method during loop initialization because InitOriginAndBound() |
553 | | // calls Contains() before InitIndex(). Otherwise, we keep track of the |
554 | | // number of calls to Contains() and only build the index when enough calls |
555 | | // have been made so that we think it is worth the effort. Note that the |
556 | | // code below is structured so that if many calls are made in parallel only |
557 | | // one thread builds the index, while the rest continue using brute force |
558 | | // until the index is actually available. |
559 | | // |
560 | | // The constants below were tuned using the benchmarks. It turns out that |
561 | | // building the index costs roughly 50x as much as Contains(). (The ratio |
562 | | // increases slowly from 46x with 64 points to 61x with 256k points.) The |
563 | | // textbook approach to this problem would be to wait until the cumulative |
564 | | // time we would have saved with an index approximately equals the cost of |
565 | | // building the index, and then build it. (This gives the optimal |
566 | | // competitive ratio of 2; look up "competitive algorithms" for details.) |
567 | | // We set the limit somewhat lower than this (20 rather than 50) because |
568 | | // building the index may be forced anyway by other API calls, and so we |
569 | | // want to err on the side of building it too early. |
570 | | |
571 | 0 | static const int kMaxBruteForceVertices = 32; |
572 | 0 | static const int kMaxUnindexedContainsCalls = 20; // See notes above. |
573 | 0 | if (index_.num_shape_ids() == 0 || // InitIndex() not called yet |
574 | 0 | num_vertices() <= kMaxBruteForceVertices || |
575 | 0 | (!index_.is_fresh() && |
576 | 0 | ++unindexed_contains_calls_ != kMaxUnindexedContainsCalls)) { |
577 | 0 | return BruteForceContains(p); |
578 | 0 | } |
579 | | // Otherwise we look up the S2ShapeIndex cell containing this point. Note |
580 | | // the index is built automatically the first time an iterator is created. |
581 | 0 | MutableS2ShapeIndex::Iterator it(&index_); |
582 | 0 | if (!it.Locate(p)) return false; |
583 | 0 | return Contains(it, p); |
584 | 0 | } |
585 | | |
586 | 0 | bool S2Loop::BruteForceContains(const S2Point& p) const { |
587 | | // Empty and full loops don't need a special case, but invalid loops with |
588 | | // zero vertices do, so we might as well handle them all at once. |
589 | 0 | if (num_vertices() < 3) return origin_inside_; |
590 | | |
591 | 0 | S2Point origin = S2::Origin(); |
592 | 0 | S2EdgeCrosser crosser(&origin, &p, &vertex(0)); |
593 | 0 | bool inside = origin_inside_; |
594 | 0 | for (int i = 1; i <= num_vertices(); ++i) { |
595 | 0 | inside ^= crosser.EdgeOrVertexCrossing(&vertex(i)); |
596 | 0 | } |
597 | 0 | return inside; |
598 | 0 | } |
599 | | |
600 | | bool S2Loop::Contains(const MutableS2ShapeIndex::Iterator& it, |
601 | 0 | const S2Point& p) const { |
602 | | // Test containment by drawing a line segment from the cell center to the |
603 | | // given point and counting edge crossings. |
604 | 0 | const S2ClippedShape& a_clipped = it.cell().clipped(0); |
605 | 0 | bool inside = a_clipped.contains_center(); |
606 | 0 | int a_num_edges = a_clipped.num_edges(); |
607 | 0 | if (a_num_edges > 0) { |
608 | 0 | S2Point center = it.id().ToPoint(); |
609 | 0 | S2EdgeCrosser crosser(¢er, &p); |
610 | 0 | int ai_prev = -2; |
611 | 0 | for (int i = 0; i < a_num_edges; ++i) { |
612 | 0 | int ai = a_clipped.edge(i); |
613 | 0 | if (ai != ai_prev + 1) crosser.RestartAt(&vertex(ai)); |
614 | 0 | ai_prev = ai; |
615 | 0 | inside ^= crosser.EdgeOrVertexCrossing(&vertex(ai+1)); |
616 | 0 | } |
617 | 0 | } |
618 | 0 | return inside; |
619 | 0 | } |
620 | | |
621 | 0 | void S2Loop::Encode(Encoder* const encoder) const { |
622 | 0 | encoder->Ensure(num_vertices_ * sizeof(vertices_[0]) + 20); // sufficient |
623 | |
|
624 | 0 | encoder->put8(kCurrentLosslessEncodingVersionNumber); |
625 | 0 | encoder->put32(num_vertices_); |
626 | 0 | encoder->putn(vertices_.get(), sizeof(vertices_[0]) * num_vertices_); |
627 | 0 | encoder->put8(origin_inside_); |
628 | 0 | encoder->put32(depth_); |
629 | 0 | ABSL_DCHECK_GE(encoder->avail(), 0); |
630 | |
|
631 | 0 | bound_.Encode(encoder); |
632 | 0 | } |
633 | | |
634 | 0 | bool S2Loop::Decode(Decoder* const decoder) { |
635 | 0 | if (decoder->avail() < sizeof(unsigned char)) return false; |
636 | 0 | unsigned char version = decoder->get8(); |
637 | 0 | switch (version) { |
638 | 0 | case kCurrentLosslessEncodingVersionNumber: |
639 | 0 | return DecodeInternal(decoder); |
640 | 0 | } |
641 | 0 | return false; |
642 | 0 | } |
643 | | |
644 | 0 | bool S2Loop::DecodeInternal(Decoder* const decoder) { |
645 | | // Perform all checks before modifying vertex state. Empty loops are |
646 | | // explicitly allowed here: a newly created loop has zero vertices |
647 | | // and such loops encode and decode properly. |
648 | 0 | if (decoder->avail() < sizeof(uint32_t)) return false; |
649 | 0 | const uint32_t num_vertices = decoder->get32(); |
650 | 0 | if (num_vertices > static_cast<uint32_t>(absl::GetFlag( |
651 | 0 | FLAGS_s2polygon_decode_max_num_vertices))) { |
652 | 0 | return false; |
653 | 0 | } |
654 | 0 | if (decoder->avail() < (num_vertices * sizeof(vertices_[0]) + |
655 | 0 | sizeof(uint8_t) + sizeof(uint32_t))) { |
656 | 0 | return false; |
657 | 0 | } |
658 | 0 | ClearIndex(); |
659 | 0 | num_vertices_ = num_vertices; |
660 | |
|
661 | 0 | vertices_ = make_unique<S2Point[]>(num_vertices_); |
662 | 0 | decoder->getn(vertices_.get(), num_vertices_ * sizeof(vertices_[0])); |
663 | 0 | origin_inside_ = decoder->get8(); |
664 | 0 | depth_ = decoder->get32(); |
665 | 0 | if (!bound_.Decode(decoder)) return false; |
666 | 0 | subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_); |
667 | | |
668 | | // An initialized loop will have some non-zero count of vertices. A default |
669 | | // (uninitialized) has zero vertices. This code supports encoding and |
670 | | // decoding of uninitialized loops, but we only want to call InitIndex for |
671 | | // initialized loops. Otherwise we defer InitIndex until the call to Init(). |
672 | 0 | if (num_vertices > 0) { |
673 | 0 | InitIndex(); |
674 | 0 | } |
675 | |
|
676 | 0 | return true; |
677 | 0 | } |
678 | | |
679 | | // LoopRelation is an abstract class that defines a relationship between two |
680 | | // loops (Contains, Intersects, or CompareBoundary). |
681 | | class LoopRelation { |
682 | | public: |
683 | 0 | LoopRelation() = default; |
684 | 0 | virtual ~LoopRelation() = default; |
685 | | |
686 | | // Optionally, a_target() and b_target() can specify an early-exit condition |
687 | | // for the loop relation. If any point P is found such that |
688 | | // |
689 | | // A.Contains(P) == a_crossing_target() && |
690 | | // B.Contains(P) == b_crossing_target() |
691 | | // |
692 | | // then the loop relation is assumed to be the same as if a pair of crossing |
693 | | // edges were found. For example, the Contains() relation has |
694 | | // |
695 | | // a_crossing_target() == 0 |
696 | | // b_crossing_target() == 1 |
697 | | // |
698 | | // because if A.Contains(P) == 0 (false) and B.Contains(P) == 1 (true) for |
699 | | // any point P, then it is equivalent to finding an edge crossing (i.e., |
700 | | // since Contains() returns false in both cases). |
701 | | // |
702 | | // Loop relations that do not have an early-exit condition of this form |
703 | | // should return -1 for both crossing targets. |
704 | | virtual int a_crossing_target() const = 0; |
705 | | virtual int b_crossing_target() const = 0; |
706 | | |
707 | | // Given a vertex "ab1" that is shared between the two loops, return true if |
708 | | // the two associated wedges (a0, ab1, a2) and (b0, ab1, b2) are equivalent |
709 | | // to an edge crossing. The loop relation is also allowed to maintain its |
710 | | // own internal state, and can return true if it observes any sequence of |
711 | | // wedges that are equivalent to an edge crossing. |
712 | | virtual bool WedgesCross(const S2Point& a0, const S2Point& ab1, |
713 | | const S2Point& a2, const S2Point& b0, |
714 | | const S2Point& b2) = 0; |
715 | | }; |
716 | | |
717 | | // RangeIterator is a wrapper over MutableS2ShapeIndex::Iterator with extra |
718 | | // methods that are useful for merging the contents of two or more |
719 | | // S2ShapeIndexes. |
720 | | class RangeIterator { |
721 | | public: |
722 | | // Construct a new RangeIterator positioned at the first cell of the index. |
723 | | explicit RangeIterator(const MutableS2ShapeIndex* index) |
724 | 0 | : it_(index, S2ShapeIndex::BEGIN) { |
725 | 0 | Refresh(); |
726 | 0 | } |
727 | | |
728 | | // The current S2CellId and cell contents. |
729 | 0 | S2CellId id() const { return it_.id(); } |
730 | 0 | const S2ShapeIndexCell& cell() const { return it_.cell(); } |
731 | | |
732 | | // The min and max leaf cell ids covered by the current cell. If Done() is |
733 | | // true, these methods return a value larger than any valid cell id. |
734 | 0 | S2CellId range_min() const { return range_min_; } |
735 | 0 | S2CellId range_max() const { return range_max_; } |
736 | | |
737 | | // Various other convenience methods for the current cell. |
738 | 0 | const S2ClippedShape& clipped() const { return cell().clipped(0); } |
739 | | |
740 | 0 | int num_edges() const { return clipped().num_edges(); } |
741 | 0 | bool contains_center() const { return clipped().contains_center(); } |
742 | | |
743 | 0 | void Next() { it_.Next(); Refresh(); } |
744 | 0 | bool Done() { return it_.done(); } |
745 | | |
746 | | // Position the iterator at the first cell that overlaps or follows |
747 | | // "target", i.e. such that range_max() >= target.range_min(). |
748 | 0 | void SeekTo(const RangeIterator& target) { |
749 | 0 | it_.Seek(target.range_min()); |
750 | | // If the current cell does not overlap "target", it is possible that the |
751 | | // previous cell is the one we are looking for. This can only happen when |
752 | | // the previous cell contains "target" but has a smaller S2CellId. |
753 | 0 | if (it_.done() || it_.id().range_min() > target.range_max()) { |
754 | 0 | if (it_.Prev() && it_.id().range_max() < target.id()) it_.Next(); |
755 | 0 | } |
756 | 0 | Refresh(); |
757 | 0 | } |
758 | | |
759 | | // Position the iterator at the first cell that follows "target", i.e. the |
760 | | // first cell such that range_min() > target.range_max(). |
761 | 0 | void SeekBeyond(const RangeIterator& target) { |
762 | 0 | it_.Seek(target.range_max().next()); |
763 | 0 | if (!it_.done() && it_.id().range_min() <= target.range_max()) { |
764 | 0 | it_.Next(); |
765 | 0 | } |
766 | 0 | Refresh(); |
767 | 0 | } |
768 | | |
769 | | private: |
770 | | // Updates internal state after the iterator has been repositioned. |
771 | 0 | void Refresh() { |
772 | 0 | range_min_ = id().range_min(); |
773 | 0 | range_max_ = id().range_max(); |
774 | 0 | } |
775 | | |
776 | | MutableS2ShapeIndex::Iterator it_; |
777 | | S2CellId range_min_, range_max_; |
778 | | }; |
779 | | |
780 | | // LoopCrosser is a helper class for determining whether two loops cross. |
781 | | // It is instantiated twice for each pair of loops to be tested, once for the |
782 | | // pair (A,B) and once for the pair (B,A), in order to be able to process |
783 | | // edges in either loop nesting order. |
784 | | class LoopCrosser { |
785 | | public: |
786 | | // If "swapped" is true, the loops A and B have been swapped. This affects |
787 | | // how arguments are passed to the given loop relation, since for example |
788 | | // A.Contains(B) is not the same as B.Contains(A). |
789 | | LoopCrosser(const S2Loop& a, const S2Loop& b, |
790 | | LoopRelation* relation, bool swapped) |
791 | 0 | : a_(a), b_(b), relation_(relation), swapped_(swapped), |
792 | 0 | a_crossing_target_(relation->a_crossing_target()), |
793 | 0 | b_crossing_target_(relation->b_crossing_target()), |
794 | 0 | b_query_(&b.index_) { |
795 | 0 | using std::swap; |
796 | 0 | if (swapped) swap(a_crossing_target_, b_crossing_target_); |
797 | 0 | } |
798 | | |
799 | | // Return the crossing targets for the loop relation, taking into account |
800 | | // whether the loops have been swapped. |
801 | 0 | int a_crossing_target() const { return a_crossing_target_; } |
802 | 0 | int b_crossing_target() const { return b_crossing_target_; } |
803 | | |
804 | | // Given two iterators positioned such that ai->id().Contains(bi->id()), |
805 | | // return true if there is a crossing relationship anywhere within ai->id(). |
806 | | // Specifically, this method returns true if there is an edge crossing, a |
807 | | // wedge crossing, or a point P that matches both "crossing targets". |
808 | | // Advances both iterators past ai->id(). |
809 | | bool HasCrossingRelation(RangeIterator* ai, RangeIterator* bi); |
810 | | |
811 | | // Given two index cells, return true if there are any edge crossings or |
812 | | // wedge crossings within those cells. |
813 | | bool CellCrossesCell(const S2ClippedShape& a_clipped, |
814 | | const S2ClippedShape& b_clipped); |
815 | | |
816 | | private: |
817 | | // Given two iterators positioned such that ai->id().Contains(bi->id()), |
818 | | // return true if there is an edge crossing or wedge crossing anywhere |
819 | | // within ai->id(). Advances "bi" (only) past ai->id(). |
820 | | bool HasCrossing(RangeIterator* ai, RangeIterator* bi); |
821 | | |
822 | | // Given an index cell of A, return true if there are any edge or wedge |
823 | | // crossings with any index cell of B contained within "b_id". |
824 | | bool CellCrossesAnySubcell(const S2ClippedShape& a_clipped, S2CellId b_id); |
825 | | |
826 | | // Prepare to check the given edge of loop A for crossings. |
827 | | void StartEdge(int aj); |
828 | | |
829 | | // Check the current edge of loop A for crossings with all edges of the |
830 | | // given index cell of loop B. |
831 | | bool EdgeCrossesCell(const S2ClippedShape& b_clipped); |
832 | | |
833 | | const S2Loop& a_; |
834 | | const S2Loop& b_; |
835 | | LoopRelation* const relation_; |
836 | | const bool swapped_; |
837 | | int a_crossing_target_, b_crossing_target_; |
838 | | |
839 | | // State maintained by StartEdge() and EdgeCrossesCell(). |
840 | | S2EdgeCrosser crosser_; |
841 | | int aj_, bj_prev_; |
842 | | |
843 | | // Temporary data declared here to avoid repeated memory allocations. |
844 | | S2CrossingEdgeQuery b_query_; |
845 | | vector<const S2ShapeIndexCell*> b_cells_; |
846 | | }; |
847 | | |
848 | 0 | inline void LoopCrosser::StartEdge(int aj) { |
849 | | // Start testing the given edge of A for crossings. |
850 | 0 | crosser_.Init(&a_.vertex(aj), &a_.vertex(aj+1)); |
851 | 0 | aj_ = aj; |
852 | 0 | bj_prev_ = -2; |
853 | 0 | } |
854 | | |
855 | 0 | inline bool LoopCrosser::EdgeCrossesCell(const S2ClippedShape& b_clipped) { |
856 | | // Test the current edge of A against all edges of "b_clipped". |
857 | 0 | int b_num_edges = b_clipped.num_edges(); |
858 | 0 | for (int j = 0; j < b_num_edges; ++j) { |
859 | 0 | int bj = b_clipped.edge(j); |
860 | 0 | if (bj != bj_prev_ + 1) crosser_.RestartAt(&b_.vertex(bj)); |
861 | 0 | bj_prev_ = bj; |
862 | 0 | int crossing = crosser_.CrossingSign(&b_.vertex(bj + 1)); |
863 | 0 | if (crossing < 0) continue; |
864 | 0 | if (crossing > 0) return true; |
865 | | // We only need to check each shared vertex once, so we only |
866 | | // consider the case where a_vertex(aj_+1) == b_.vertex(bj+1). |
867 | 0 | if (a_.vertex(aj_+1) == b_.vertex(bj+1)) { |
868 | 0 | if (swapped_ ? |
869 | 0 | relation_->WedgesCross( |
870 | 0 | b_.vertex(bj), b_.vertex(bj+1), b_.vertex(bj+2), |
871 | 0 | a_.vertex(aj_), a_.vertex(aj_+2)) : |
872 | 0 | relation_->WedgesCross( |
873 | 0 | a_.vertex(aj_), a_.vertex(aj_+1), a_.vertex(aj_+2), |
874 | 0 | b_.vertex(bj), b_.vertex(bj+2))) { |
875 | 0 | return true; |
876 | 0 | } |
877 | 0 | } |
878 | 0 | } |
879 | 0 | return false; |
880 | 0 | } |
881 | | |
882 | | bool LoopCrosser::CellCrossesCell(const S2ClippedShape& a_clipped, |
883 | 0 | const S2ClippedShape& b_clipped) { |
884 | | // Test all edges of "a_clipped" against all edges of "b_clipped". |
885 | 0 | int a_num_edges = a_clipped.num_edges(); |
886 | 0 | for (int i = 0; i < a_num_edges; ++i) { |
887 | 0 | StartEdge(a_clipped.edge(i)); |
888 | 0 | if (EdgeCrossesCell(b_clipped)) return true; |
889 | 0 | } |
890 | 0 | return false; |
891 | 0 | } |
892 | | |
893 | | bool LoopCrosser::CellCrossesAnySubcell(const S2ClippedShape& a_clipped, |
894 | 0 | S2CellId b_id) { |
895 | | // Test all edges of "a_clipped" against all edges of B. The relevant B |
896 | | // edges are guaranteed to be children of "b_id", which lets us find the |
897 | | // correct index cells more efficiently. |
898 | 0 | S2PaddedCell b_root(b_id, 0); |
899 | 0 | int a_num_edges = a_clipped.num_edges(); |
900 | 0 | for (int i = 0; i < a_num_edges; ++i) { |
901 | 0 | int aj = a_clipped.edge(i); |
902 | | // Use an S2CrossingEdgeQuery starting at "b_root" to find the index cells |
903 | | // of B that might contain crossing edges. |
904 | 0 | b_query_.GetCells(a_.vertex(aj), a_.vertex(aj+1), b_root, &b_cells_); |
905 | 0 | if (b_cells_.empty()) continue; |
906 | 0 | StartEdge(aj); |
907 | 0 | for (const S2ShapeIndexCell* b_cell : b_cells_) { |
908 | 0 | if (EdgeCrossesCell(b_cell->clipped(0))) return true; |
909 | 0 | } |
910 | 0 | } |
911 | 0 | return false; |
912 | 0 | } |
913 | | |
914 | 0 | bool LoopCrosser::HasCrossing(RangeIterator* ai, RangeIterator* bi) { |
915 | 0 | ABSL_DCHECK(ai->id().contains(bi->id())); |
916 | | // If ai->id() intersects many edges of B, then it is faster to use |
917 | | // S2CrossingEdgeQuery to narrow down the candidates. But if it intersects |
918 | | // only a few edges, it is faster to check all the crossings directly. |
919 | | // We handle this by advancing "bi" and keeping track of how many edges we |
920 | | // would need to test. |
921 | |
|
922 | 0 | static const int kEdgeQueryMinEdges = 20; // Tuned using benchmarks. |
923 | 0 | int total_edges = 0; |
924 | 0 | b_cells_.clear(); |
925 | 0 | do { |
926 | 0 | if (bi->num_edges() > 0) { |
927 | 0 | total_edges += bi->num_edges(); |
928 | 0 | if (total_edges >= kEdgeQueryMinEdges) { |
929 | | // There are too many edges to test them directly, so use |
930 | | // S2CrossingEdgeQuery. |
931 | 0 | if (CellCrossesAnySubcell(ai->clipped(), ai->id())) return true; |
932 | 0 | bi->SeekBeyond(*ai); |
933 | 0 | return false; |
934 | 0 | } |
935 | 0 | b_cells_.push_back(&bi->cell()); |
936 | 0 | } |
937 | 0 | bi->Next(); |
938 | 0 | } while (bi->id() <= ai->range_max()); |
939 | | |
940 | | // Test all the edge crossings directly. |
941 | 0 | for (const S2ShapeIndexCell* b_cell : b_cells_) { |
942 | 0 | if (CellCrossesCell(ai->clipped(), b_cell->clipped(0))) { |
943 | 0 | return true; |
944 | 0 | } |
945 | 0 | } |
946 | 0 | return false; |
947 | 0 | } |
948 | | |
949 | 0 | bool LoopCrosser::HasCrossingRelation(RangeIterator* ai, RangeIterator* bi) { |
950 | 0 | ABSL_DCHECK(ai->id().contains(bi->id())); |
951 | 0 | if (ai->num_edges() == 0) { |
952 | 0 | if (ai->contains_center() == a_crossing_target_) { |
953 | | // All points within ai->id() satisfy the crossing target for A, so it's |
954 | | // worth iterating through the cells of B to see whether any cell |
955 | | // centers also satisfy the crossing target for B. |
956 | 0 | do { |
957 | 0 | if (bi->contains_center() == b_crossing_target_) return true; |
958 | 0 | bi->Next(); |
959 | 0 | } while (bi->id() <= ai->range_max()); |
960 | 0 | } else { |
961 | | // The crossing target for A is not satisfied, so we skip over the cells |
962 | | // of B using binary search. |
963 | 0 | bi->SeekBeyond(*ai); |
964 | 0 | } |
965 | 0 | } else { |
966 | | // The current cell of A has at least one edge, so check for crossings. |
967 | 0 | if (HasCrossing(ai, bi)) return true; |
968 | 0 | } |
969 | 0 | ai->Next(); |
970 | 0 | return false; |
971 | 0 | } |
972 | | |
973 | | /*static*/ bool S2Loop::HasCrossingRelation(const S2Loop& a, const S2Loop& b, |
974 | 0 | LoopRelation* relation) { |
975 | | // We look for S2CellId ranges where the indexes of A and B overlap, and |
976 | | // then test those edges for crossings. |
977 | 0 | RangeIterator ai(&a.index_), bi(&b.index_); |
978 | 0 | LoopCrosser ab(a, b, relation, false); // Tests edges of A against B |
979 | 0 | LoopCrosser ba(b, a, relation, true); // Tests edges of B against A |
980 | 0 | while (!ai.Done() || !bi.Done()) { |
981 | 0 | if (ai.range_max() < bi.range_min()) { |
982 | | // The A and B cells don't overlap, and A precedes B. |
983 | 0 | ai.SeekTo(bi); |
984 | 0 | } else if (bi.range_max() < ai.range_min()) { |
985 | | // The A and B cells don't overlap, and B precedes A. |
986 | 0 | bi.SeekTo(ai); |
987 | 0 | } else { |
988 | | // One cell contains the other. Determine which cell is larger. |
989 | 0 | int64_t ab_relation = ai.id().lsb() - bi.id().lsb(); |
990 | 0 | if (ab_relation > 0) { |
991 | | // A's index cell is larger. |
992 | 0 | if (ab.HasCrossingRelation(&ai, &bi)) return true; |
993 | 0 | } else if (ab_relation < 0) { |
994 | | // B's index cell is larger. |
995 | 0 | if (ba.HasCrossingRelation(&bi, &ai)) return true; |
996 | 0 | } else { |
997 | | // The A and B cells are the same. Since the two cells have the same |
998 | | // center point P, check whether P satisfies the crossing targets. |
999 | 0 | if (ai.contains_center() == ab.a_crossing_target() && |
1000 | 0 | bi.contains_center() == ab.b_crossing_target()) { |
1001 | 0 | return true; |
1002 | 0 | } |
1003 | | // Otherwise test all the edge crossings directly. |
1004 | 0 | if (ai.num_edges() > 0 && bi.num_edges() > 0 && |
1005 | 0 | ab.CellCrossesCell(ai.clipped(), bi.clipped())) { |
1006 | 0 | return true; |
1007 | 0 | } |
1008 | 0 | ai.Next(); |
1009 | 0 | bi.Next(); |
1010 | 0 | } |
1011 | 0 | } |
1012 | 0 | } |
1013 | 0 | return false; |
1014 | 0 | } |
1015 | | |
1016 | | // Loop relation for Contains(). |
1017 | | class ContainsRelation : public LoopRelation { |
1018 | | public: |
1019 | 0 | ContainsRelation() : found_shared_vertex_(false) {} |
1020 | 0 | bool found_shared_vertex() const { return found_shared_vertex_; } |
1021 | | |
1022 | | // If A.Contains(P) == false && B.Contains(P) == true, it is equivalent to |
1023 | | // having an edge crossing (i.e., Contains returns false). |
1024 | 0 | int a_crossing_target() const override { return false; } |
1025 | 0 | int b_crossing_target() const override { return true; } |
1026 | | |
1027 | | bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2, |
1028 | 0 | const S2Point& b0, const S2Point& b2) override { |
1029 | 0 | found_shared_vertex_ = true; |
1030 | 0 | return !S2::WedgeContains(a0, ab1, a2, b0, b2); |
1031 | 0 | } |
1032 | | |
1033 | | private: |
1034 | | bool found_shared_vertex_; |
1035 | | }; |
1036 | | |
1037 | 0 | bool S2Loop::Contains(const S2Loop& b) const { |
1038 | | // For this loop A to contains the given loop B, all of the following must |
1039 | | // be true: |
1040 | | // |
1041 | | // (1) There are no edge crossings between A and B except at vertices. |
1042 | | // |
1043 | | // (2) At every vertex that is shared between A and B, the local edge |
1044 | | // ordering implies that A contains B. |
1045 | | // |
1046 | | // (3) If there are no shared vertices, then A must contain a vertex of B |
1047 | | // and B must not contain a vertex of A. (An arbitrary vertex may be |
1048 | | // chosen in each case.) |
1049 | | // |
1050 | | // The second part of (3) is necessary to detect the case of two loops whose |
1051 | | // union is the entire sphere, i.e. two loops that contains each other's |
1052 | | // boundaries but not each other's interiors. |
1053 | 0 | if (!subregion_bound_.Contains(b.bound_)) return false; |
1054 | | |
1055 | | // Special cases to handle either loop being empty or full. |
1056 | 0 | if (is_empty_or_full() || b.is_empty_or_full()) { |
1057 | 0 | return is_full() || b.is_empty(); |
1058 | 0 | } |
1059 | | |
1060 | | // Check whether there are any edge crossings, and also check the loop |
1061 | | // relationship at any shared vertices. |
1062 | 0 | ContainsRelation relation; |
1063 | 0 | if (HasCrossingRelation(*this, b, &relation)) return false; |
1064 | | |
1065 | | // There are no crossings, and if there are any shared vertices then A |
1066 | | // contains B locally at each shared vertex. |
1067 | 0 | if (relation.found_shared_vertex()) return true; |
1068 | | |
1069 | | // Since there are no edge intersections or shared vertices, we just need to |
1070 | | // test condition (3) above. We can skip this test if we discovered that A |
1071 | | // contains at least one point of B while checking for edge crossings. |
1072 | 0 | if (!Contains(b.vertex(0))) return false; |
1073 | | |
1074 | | // We still need to check whether (A union B) is the entire sphere. |
1075 | | // Normally this check is very cheap due to the bounding box precondition. |
1076 | 0 | if ((b.subregion_bound_.Contains(bound_) || |
1077 | 0 | b.bound_.Union(bound_).is_full()) && |
1078 | 0 | b.Contains(vertex(0))) { |
1079 | 0 | return false; |
1080 | 0 | } |
1081 | 0 | return true; |
1082 | 0 | } |
1083 | | |
1084 | | // Loop relation for Intersects(). |
1085 | | class IntersectsRelation : public LoopRelation { |
1086 | | public: |
1087 | 0 | IntersectsRelation() : found_shared_vertex_(false) {} |
1088 | 0 | bool found_shared_vertex() const { return found_shared_vertex_; } |
1089 | | |
1090 | | // If A.Contains(P) == true && B.Contains(P) == true, it is equivalent to |
1091 | | // having an edge crossing (i.e., Intersects returns true). |
1092 | 0 | int a_crossing_target() const override { return true; } |
1093 | 0 | int b_crossing_target() const override { return true; } |
1094 | | |
1095 | | bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2, |
1096 | 0 | const S2Point& b0, const S2Point& b2) override { |
1097 | 0 | found_shared_vertex_ = true; |
1098 | 0 | return S2::WedgeIntersects(a0, ab1, a2, b0, b2); |
1099 | 0 | } |
1100 | | |
1101 | | private: |
1102 | | bool found_shared_vertex_; |
1103 | | }; |
1104 | | |
1105 | 0 | bool S2Loop::Intersects(const S2Loop& b) const { |
1106 | | // a->Intersects(b) if and only if !a->Complement()->Contains(b). |
1107 | | // This code is similar to Contains(), but is optimized for the case |
1108 | | // where both loops enclose less than half of the sphere. |
1109 | 0 | if (!bound_.Intersects(b.bound_)) return false; |
1110 | | |
1111 | | // Check whether there are any edge crossings, and also check the loop |
1112 | | // relationship at any shared vertices. |
1113 | 0 | IntersectsRelation relation; |
1114 | 0 | if (HasCrossingRelation(*this, b, &relation)) return true; |
1115 | 0 | if (relation.found_shared_vertex()) return false; |
1116 | | |
1117 | | // Since there are no edge intersections or shared vertices, the loops |
1118 | | // intersect only if A contains B, B contains A, or the two loops contain |
1119 | | // each other's boundaries. These checks are usually cheap because of the |
1120 | | // bounding box preconditions. Note that neither loop is empty (because of |
1121 | | // the bounding box check above), so it is safe to access vertex(0). |
1122 | | |
1123 | | // Check whether A contains B, or A and B contain each other's boundaries. |
1124 | | // (Note that A contains all the vertices of B in either case.) |
1125 | 0 | if (subregion_bound_.Contains(b.bound_) || bound_.Union(b.bound_).is_full()) { |
1126 | 0 | if (Contains(b.vertex(0))) return true; |
1127 | 0 | } |
1128 | | // Check whether B contains A. |
1129 | 0 | if (b.subregion_bound_.Contains(bound_)) { |
1130 | 0 | if (b.Contains(vertex(0))) return true; |
1131 | 0 | } |
1132 | 0 | return false; |
1133 | 0 | } |
1134 | | |
1135 | | // Returns true if the wedge (a0, ab1, a2) contains the "semiwedge" defined as |
1136 | | // any non-empty open set of rays immediately CCW from the edge (ab1, b2). If |
1137 | | // "reverse_b" is true, then substitute "clockwise" for "CCW"; this simulates |
1138 | | // what would happen if the direction of loop B was reversed. |
1139 | | inline static bool WedgeContainsSemiwedge(const S2Point& a0, const S2Point& ab1, |
1140 | | const S2Point& a2, const S2Point& b2, |
1141 | 0 | bool reverse_b) { |
1142 | 0 | if (b2 == a0 || b2 == a2) { |
1143 | | // We have a shared or reversed edge. |
1144 | 0 | return (b2 == a0) == reverse_b; |
1145 | 0 | } else { |
1146 | 0 | return s2pred::OrderedCCW(a0, a2, b2, ab1); |
1147 | 0 | } |
1148 | 0 | } |
1149 | | |
1150 | | // Loop relation for CompareBoundary(). |
1151 | | class CompareBoundaryRelation : public LoopRelation { |
1152 | | public: |
1153 | | explicit CompareBoundaryRelation(bool reverse_b): |
1154 | 0 | reverse_b_(reverse_b), found_shared_vertex_(false), |
1155 | 0 | contains_edge_(false), excludes_edge_(false) { |
1156 | 0 | } |
1157 | 0 | bool found_shared_vertex() const { return found_shared_vertex_; } |
1158 | 0 | bool contains_edge() const { return contains_edge_; } |
1159 | | |
1160 | | // The CompareBoundary relation does not have a useful early-exit condition, |
1161 | | // so we return -1 for both crossing targets. |
1162 | | // |
1163 | | // Aside: A possible early exit condition could be based on the following. |
1164 | | // If A contains a point of both B and ~B, then A intersects Boundary(B). |
1165 | | // If ~A contains a point of both B and ~B, then ~A intersects Boundary(B). |
1166 | | // So if the intersections of {A, ~A} with {B, ~B} are all non-empty, |
1167 | | // the return value is 0, i.e., Boundary(A) intersects Boundary(B). |
1168 | | // Unfortunately it isn't worth detecting this situation because by the |
1169 | | // time we have seen a point in all four intersection regions, we are also |
1170 | | // guaranteed to have seen at least one pair of crossing edges. |
1171 | 0 | int a_crossing_target() const override { return -1; } |
1172 | 0 | int b_crossing_target() const override { return -1; } |
1173 | | |
1174 | | bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2, |
1175 | 0 | const S2Point& b0, const S2Point& b2) override { |
1176 | | // Because we don't care about the interior of B, only its boundary, it is |
1177 | | // sufficient to check whether A contains the semiwedge (ab1, b2). |
1178 | 0 | found_shared_vertex_ = true; |
1179 | 0 | if (WedgeContainsSemiwedge(a0, ab1, a2, b2, reverse_b_)) { |
1180 | 0 | contains_edge_ = true; |
1181 | 0 | } else { |
1182 | 0 | excludes_edge_ = true; |
1183 | 0 | } |
1184 | 0 | return contains_edge_ & excludes_edge_; |
1185 | 0 | } |
1186 | | |
1187 | | protected: |
1188 | | const bool reverse_b_; // True if loop B should be reversed. |
1189 | | bool found_shared_vertex_; // True if any wedge was processed. |
1190 | | bool contains_edge_; // True if any edge of B is contained by A. |
1191 | | bool excludes_edge_; // True if any edge of B is excluded by A. |
1192 | | }; |
1193 | | |
1194 | 0 | int S2Loop::CompareBoundary(const S2Loop& b) const { |
1195 | 0 | ABSL_DCHECK(!is_empty() && !b.is_empty()); |
1196 | 0 | ABSL_DCHECK(!b.is_full() || !b.is_hole()); |
1197 | | |
1198 | | // The bounds must intersect for containment or crossing. |
1199 | 0 | if (!bound_.Intersects(b.bound_)) return -1; |
1200 | | |
1201 | | // Full loops are handled as though the loop surrounded the entire sphere. |
1202 | 0 | if (is_full()) return 1; |
1203 | 0 | if (b.is_full()) return -1; |
1204 | | |
1205 | | // Check whether there are any edge crossings, and also check the loop |
1206 | | // relationship at any shared vertices. |
1207 | 0 | CompareBoundaryRelation relation(b.is_hole()); |
1208 | 0 | if (HasCrossingRelation(*this, b, &relation)) return 0; |
1209 | 0 | if (relation.found_shared_vertex()) { |
1210 | 0 | return relation.contains_edge() ? 1 : -1; |
1211 | 0 | } |
1212 | | |
1213 | | // There are no edge intersections or shared vertices, so we can check |
1214 | | // whether A contains an arbitrary vertex of B. |
1215 | 0 | return Contains(b.vertex(0)) ? 1 : -1; |
1216 | 0 | } |
1217 | | |
1218 | 0 | bool S2Loop::ContainsNested(const S2Loop& b) const { |
1219 | 0 | if (!subregion_bound_.Contains(b.bound_)) return false; |
1220 | | |
1221 | | // Special cases to handle either loop being empty or full. Also bail out |
1222 | | // when B has no vertices to avoid heap overflow on the vertex(1) call |
1223 | | // below. (This method is called during polygon initialization before the |
1224 | | // client has an opportunity to call IsValid().) |
1225 | 0 | if (is_empty_or_full() || b.num_vertices() < 2) { |
1226 | 0 | return is_full() || b.is_empty(); |
1227 | 0 | } |
1228 | | |
1229 | | // We are given that A and B do not share any edges, and that either one |
1230 | | // loop contains the other or they do not intersect. |
1231 | 0 | int m = FindVertex(b.vertex(1)); |
1232 | 0 | if (m < 0) { |
1233 | | // Since b.vertex(1) is not shared, we can check whether A contains it. |
1234 | 0 | return Contains(b.vertex(1)); |
1235 | 0 | } |
1236 | | // Check whether the edge order around b.vertex(1) is compatible with |
1237 | | // A containing B. |
1238 | 0 | return S2::WedgeContains(vertex(m - 1), vertex(m), vertex(m + 1), b.vertex(0), |
1239 | 0 | b.vertex(2)); |
1240 | 0 | } |
1241 | | |
1242 | 0 | bool S2Loop::Equals(const S2Loop& b) const { |
1243 | 0 | if (num_vertices() != b.num_vertices()) return false; |
1244 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
1245 | 0 | if (vertex(i) != b.vertex(i)) return false; |
1246 | 0 | } |
1247 | 0 | return true; |
1248 | 0 | } |
1249 | | |
1250 | 0 | bool S2Loop::BoundaryEquals(const S2Loop& b) const { |
1251 | 0 | if (num_vertices() != b.num_vertices()) return false; |
1252 | | |
1253 | | // Special case to handle empty or full loops. Since they have the same |
1254 | | // number of vertices, if one loop is empty/full then so is the other. |
1255 | 0 | if (is_empty_or_full()) return is_empty() == b.is_empty(); |
1256 | | |
1257 | 0 | for (int offset = 0; offset < num_vertices(); ++offset) { |
1258 | 0 | if (vertex(offset) == b.vertex(0)) { |
1259 | | // There is at most one starting offset since loop vertices are unique. |
1260 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
1261 | 0 | if (vertex(i + offset) != b.vertex(i)) return false; |
1262 | 0 | } |
1263 | 0 | return true; |
1264 | 0 | } |
1265 | 0 | } |
1266 | 0 | return false; |
1267 | 0 | } |
1268 | | |
1269 | 0 | bool S2Loop::BoundaryApproxEquals(const S2Loop& b, S1Angle max_error) const { |
1270 | 0 | if (num_vertices() != b.num_vertices()) return false; |
1271 | | |
1272 | | // Special case to handle empty or full loops. Since they have the same |
1273 | | // number of vertices, if one loop is empty/full then so is the other. |
1274 | 0 | if (is_empty_or_full()) return is_empty() == b.is_empty(); |
1275 | | |
1276 | 0 | for (int offset = 0; offset < num_vertices(); ++offset) { |
1277 | 0 | if (S2::ApproxEquals(vertex(offset), b.vertex(0), max_error)) { |
1278 | 0 | bool success = true; |
1279 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
1280 | 0 | if (!S2::ApproxEquals(vertex(i + offset), b.vertex(i), max_error)) { |
1281 | 0 | success = false; |
1282 | 0 | break; |
1283 | 0 | } |
1284 | 0 | } |
1285 | 0 | if (success) return true; |
1286 | | // Otherwise continue looping. There may be more than one candidate |
1287 | | // starting offset since vertices are only matched approximately. |
1288 | 0 | } |
1289 | 0 | } |
1290 | 0 | return false; |
1291 | 0 | } |
1292 | | |
1293 | | static bool MatchBoundaries(const S2Loop& a, const S2Loop& b, int a_offset, |
1294 | 0 | S1Angle max_error) { |
1295 | | // The state consists of a pair (i,j). A state transition consists of |
1296 | | // incrementing either "i" or "j". "i" can be incremented only if |
1297 | | // a(i+1+a_offset) is near the edge from b(j) to b(j+1), and a similar rule |
1298 | | // applies to "j". The function returns true iff we can proceed all the way |
1299 | | // around both loops in this way. |
1300 | | // |
1301 | | // Note that when "i" and "j" can both be incremented, sometimes only one |
1302 | | // choice leads to a solution. We handle this using a stack and |
1303 | | // backtracking. We also keep track of which states have already been |
1304 | | // explored to avoid duplicating work. |
1305 | |
|
1306 | 0 | vector<pair<int, int>> pending; |
1307 | 0 | flat_hash_set<pair<int, int>> done; |
1308 | 0 | pending.push_back(std::make_pair(0, 0)); |
1309 | 0 | while (!pending.empty()) { |
1310 | 0 | int i = pending.back().first; |
1311 | 0 | int j = pending.back().second; |
1312 | 0 | pending.pop_back(); |
1313 | 0 | if (i == a.num_vertices() && j == b.num_vertices()) { |
1314 | 0 | return true; |
1315 | 0 | } |
1316 | 0 | done.insert(std::make_pair(i, j)); |
1317 | | |
1318 | | // If (i == na && offset == na-1) where na == a->num_vertices(), then |
1319 | | // then (i+1+offset) overflows the [0, 2*na-1] range allowed by vertex(). |
1320 | | // So we reduce the range if necessary. |
1321 | 0 | int io = i + a_offset; |
1322 | 0 | if (io >= a.num_vertices()) io -= a.num_vertices(); |
1323 | |
|
1324 | 0 | if (i < a.num_vertices() && done.count(std::make_pair(i + 1, j)) == 0 && |
1325 | 0 | S2::GetDistance(a.vertex(io + 1), b.vertex(j), |
1326 | 0 | b.vertex(j + 1)) <= max_error) { |
1327 | 0 | pending.push_back(std::make_pair(i + 1, j)); |
1328 | 0 | } |
1329 | 0 | if (j < b.num_vertices() && done.count(std::make_pair(i, j + 1)) == 0 && |
1330 | 0 | S2::GetDistance(b.vertex(j + 1), a.vertex(io), |
1331 | 0 | a.vertex(io + 1)) <= max_error) { |
1332 | 0 | pending.push_back(std::make_pair(i, j + 1)); |
1333 | 0 | } |
1334 | 0 | } |
1335 | 0 | return false; |
1336 | 0 | } |
1337 | | |
1338 | 0 | bool S2Loop::BoundaryNear(const S2Loop& b, S1Angle max_error) const { |
1339 | | // Special case to handle empty or full loops. |
1340 | 0 | if (is_empty_or_full() || b.is_empty_or_full()) { |
1341 | 0 | return (is_empty() && b.is_empty()) || (is_full() && b.is_full()); |
1342 | 0 | } |
1343 | | |
1344 | 0 | for (int a_offset = 0; a_offset < num_vertices(); ++a_offset) { |
1345 | 0 | if (MatchBoundaries(*this, b, a_offset, max_error)) return true; |
1346 | 0 | } |
1347 | 0 | return false; |
1348 | 0 | } |
1349 | | |
1350 | 0 | void S2Loop::GetXYZFaceSiTiVertices(S2XYZFaceSiTi* vertices) const { |
1351 | 0 | for (int i = 0; i < num_vertices(); ++i) { |
1352 | 0 | vertices[i].xyz = vertex(i); |
1353 | 0 | vertices[i].cell_level = S2::XYZtoFaceSiTi(vertices[i].xyz, |
1354 | 0 | &vertices[i].face, &vertices[i].si, &vertices[i].ti); |
1355 | 0 | } |
1356 | 0 | } |
1357 | | |
1358 | | void S2Loop::EncodeCompressed(Encoder* encoder, const S2XYZFaceSiTi* vertices, |
1359 | 0 | int snap_level) const { |
1360 | | // Ensure enough for the data we write before S2EncodePointsCompressed. |
1361 | | // S2EncodePointsCompressed ensures its space. |
1362 | 0 | encoder->Ensure(Encoder::kVarintMax32); |
1363 | 0 | encoder->put_varint32(num_vertices_); |
1364 | |
|
1365 | 0 | S2EncodePointsCompressed(MakeSpan(vertices, num_vertices_), |
1366 | 0 | snap_level, encoder); |
1367 | |
|
1368 | 0 | std::bitset<kNumProperties> properties = GetCompressedEncodingProperties(); |
1369 | | |
1370 | | // Ensure enough only for what we write. Let the bound ensure its own |
1371 | | // space. |
1372 | 0 | encoder->Ensure(2 * Encoder::kVarintMax32); |
1373 | 0 | encoder->put_varint32(properties.to_ulong()); |
1374 | 0 | encoder->put_varint32(depth_); |
1375 | 0 | if (properties.test(kBoundEncoded)) { |
1376 | 0 | bound_.Encode(encoder); |
1377 | 0 | } |
1378 | 0 | ABSL_DCHECK_GE(encoder->avail(), 0); |
1379 | 0 | } |
1380 | | |
1381 | 0 | bool S2Loop::DecodeCompressed(Decoder* decoder, int snap_level) { |
1382 | | // get_varint32 takes a uint32_t*, but num_vertices_ is signed. |
1383 | | // Decode to a temporary variable to avoid reinterpret_cast. |
1384 | 0 | uint32_t unsigned_num_vertices; |
1385 | 0 | if (!decoder->get_varint32(&unsigned_num_vertices)) { |
1386 | 0 | return false; |
1387 | 0 | } |
1388 | 0 | if (unsigned_num_vertices == 0 || |
1389 | 0 | unsigned_num_vertices > static_cast<uint32_t>(absl::GetFlag( |
1390 | 0 | FLAGS_s2polygon_decode_max_num_vertices))) { |
1391 | 0 | return false; |
1392 | 0 | } |
1393 | 0 | ClearIndex(); |
1394 | 0 | num_vertices_ = unsigned_num_vertices; |
1395 | 0 | vertices_ = make_unique<S2Point[]>(num_vertices_); |
1396 | |
|
1397 | 0 | if (!S2DecodePointsCompressed(decoder, snap_level, |
1398 | 0 | MakeSpan(vertices_.get(), num_vertices_))) { |
1399 | 0 | return false; |
1400 | 0 | } |
1401 | 0 | uint32_t properties_uint32; |
1402 | 0 | if (!decoder->get_varint32(&properties_uint32)) { |
1403 | 0 | return false; |
1404 | 0 | } |
1405 | 0 | const std::bitset<kNumProperties> properties(properties_uint32); |
1406 | 0 | origin_inside_ = properties.test(kOriginInside); |
1407 | |
|
1408 | 0 | uint32_t unsigned_depth; |
1409 | 0 | if (!decoder->get_varint32(&unsigned_depth)) { |
1410 | 0 | return false; |
1411 | 0 | } |
1412 | 0 | depth_ = unsigned_depth; |
1413 | |
|
1414 | 0 | if (properties.test(kBoundEncoded)) { |
1415 | 0 | if (!bound_.Decode(decoder)) { |
1416 | 0 | return false; |
1417 | 0 | } |
1418 | 0 | subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_); |
1419 | 0 | } else { |
1420 | 0 | InitBound(); |
1421 | 0 | } |
1422 | 0 | InitIndex(); |
1423 | 0 | return true; |
1424 | 0 | } |
1425 | | |
1426 | 0 | std::bitset<kNumProperties> S2Loop::GetCompressedEncodingProperties() const { |
1427 | 0 | std::bitset<kNumProperties> properties; |
1428 | 0 | if (origin_inside_) { |
1429 | 0 | properties.set(kOriginInside); |
1430 | 0 | } |
1431 | | |
1432 | | // Write whether there is a bound so we can change the threshold later. |
1433 | | // Recomputing the bound multiplies the decode time taken per vertex |
1434 | | // by a factor of about 3.5. Without recomputing the bound, decode |
1435 | | // takes approximately 125 ns / vertex. A loop with 63 vertices |
1436 | | // encoded without the bound will take ~30us to decode, which is |
1437 | | // acceptable. At ~3.5 bytes / vertex without the bound, adding |
1438 | | // the bound will increase the size by <15%, which is also acceptable. |
1439 | 0 | static const int kMinVerticesForBound = 64; |
1440 | 0 | if (num_vertices_ >= kMinVerticesForBound) { |
1441 | 0 | properties.set(kBoundEncoded); |
1442 | 0 | } |
1443 | 0 | return properties; |
1444 | 0 | } |
1445 | | |
1446 | | /* static */ |
1447 | | unique_ptr<S2Loop> S2Loop::MakeRegularLoop(const S2Point& center, |
1448 | 0 | S1Angle radius, int num_vertices) { |
1449 | 0 | return MakeRegularLoop(S2::GetFrame(center), radius, num_vertices); |
1450 | 0 | } |
1451 | | |
1452 | | /* static */ |
1453 | | unique_ptr<S2Loop> S2Loop::MakeRegularLoop(const Matrix3x3_d& frame, |
1454 | 0 | S1Angle radius, int num_vertices) { |
1455 | | // We construct the loop in the given frame coordinates, with the center at |
1456 | | // (0, 0, 1). For a loop of radius "r", the loop vertices have the form |
1457 | | // (x, y, z) where x^2 + y^2 = sin(r) and z = cos(r). The distance on the |
1458 | | // sphere (arc length) from each vertex to the center is acos(cos(r)) = r. |
1459 | 0 | const S1Angle::SinCosPair r_and_z = radius.SinCos(); |
1460 | 0 | const double r = r_and_z.sin; |
1461 | 0 | const double z = r_and_z.cos; |
1462 | 0 | const double radian_step = 2 * M_PI / num_vertices; |
1463 | 0 | vector<S2Point> vertices; |
1464 | 0 | vertices.reserve(num_vertices); |
1465 | 0 | for (int i = 0; i < num_vertices; ++i) { |
1466 | 0 | const S1Angle angle = S1Angle::Radians(i * radian_step); |
1467 | 0 | const S1Angle::SinCosPair a = angle.SinCos(); |
1468 | 0 | const S2Point p(r * a.cos, r * a.sin, z); |
1469 | 0 | vertices.push_back(S2::FromFrame(frame, p).Normalize()); |
1470 | 0 | } |
1471 | 0 | return make_unique<S2Loop>(vertices); |
1472 | 0 | } |
1473 | | |
1474 | 0 | size_t S2Loop::SpaceUsed() const { |
1475 | 0 | size_t size = sizeof(*this); |
1476 | 0 | size += num_vertices() * sizeof(S2Point); |
1477 | | // index_ itself is already included in sizeof(*this). |
1478 | 0 | size += index_.SpaceUsed() - sizeof(index_); |
1479 | 0 | return size; |
1480 | 0 | } |
1481 | | |
1482 | 0 | int S2Loop::Shape::num_chains() const { |
1483 | 0 | return loop_->is_empty() ? 0 : 1; |
1484 | 0 | } |
1485 | | |
1486 | 0 | S2Shape::Chain S2Loop::Shape::chain(int i) const { |
1487 | 0 | ABSL_DCHECK_EQ(i, 0); |
1488 | 0 | return Chain(0, Shape::num_edges()); // Avoid virtual call. |
1489 | 0 | } |