1 // Copyright 2005 Google Inc. All Rights Reserved.
2
3 #include <algorithm>
4 using std::min;
5 using std::max;
6 using std::swap;
7 using std::reverse;
8
9 #include "base/definer.h"
10 #include "s2.h"
11 #include "hash.h"
12
13 #include <set>
14 using std::set;
15 using std::multiset;
16
17 #include <vector>
18 using std::vector;
19
20 #include "s2polygon.h"
21
22 #include "base/port.h" // for HASH_NAMESPACE_DECLARATION_START
23 #include "util/coding/coder.h"
24 #include "s2edgeindex.h"
25 #include "s2cap.h"
26 #include "s2cell.h"
27 #include "s2cellunion.h"
28 #include "s2latlngrect.h"
29 #include "s2polygonbuilder.h"
30 #include "s2polyline.h"
31
32 #include "mongo/util/mongoutils/str.h"
33 using mongoutils::str::stream;
34
35 static const unsigned char kCurrentEncodingVersionNumber = 1;
36
37 typedef pair<S2Point, S2Point> S2Edge;
38
S2Polygon()39 S2Polygon::S2Polygon()
40 : loops_(),
41 bound_(S2LatLngRect::Empty()),
42 owns_loops_(true),
43 has_holes_(false),
44 num_vertices_(0) {
45 }
46
S2Polygon(vector<S2Loop * > * loops)47 S2Polygon::S2Polygon(vector<S2Loop*>* loops)
48 : bound_(S2LatLngRect::Empty()),
49 owns_loops_(true) {
50 Init(loops);
51 }
52
S2Polygon(S2Cell const & cell)53 S2Polygon::S2Polygon(S2Cell const& cell)
54 : bound_(S2LatLngRect::Empty()),
55 owns_loops_(true),
56 has_holes_(false),
57 num_vertices_(4) {
58 S2Loop* loop = new S2Loop(cell);
59 bound_ = loop->GetRectBound();
60 loops_.push_back(loop);
61 }
62
S2Polygon(S2Loop * loop)63 S2Polygon::S2Polygon(S2Loop* loop)
64 : bound_(loop->GetRectBound()),
65 owns_loops_(false),
66 has_holes_(false),
67 num_vertices_(loop->num_vertices()) {
68 loops_.push_back(loop);
69 }
70
Copy(S2Polygon const * src)71 void S2Polygon::Copy(S2Polygon const* src) {
72 DCHECK_EQ(0, num_loops());
73 for (int i = 0; i < src->num_loops(); ++i) {
74 loops_.push_back(src->loop(i)->Clone());
75 }
76 bound_ = src->bound_;
77 owns_loops_ = true;
78 has_holes_ = src->has_holes_;
79 num_vertices_ = src->num_vertices();
80 }
81
Clone() const82 S2Polygon* S2Polygon::Clone() const {
83 S2Polygon* result = new S2Polygon;
84 result->Copy(this);
85 return result;
86 }
87
Release(vector<S2Loop * > * loops)88 void S2Polygon::Release(vector<S2Loop*>* loops) {
89 if (loops != NULL) {
90 loops->insert(loops->end(), loops_.begin(), loops_.end());
91 }
92 loops_.clear();
93 bound_ = S2LatLngRect::Empty();
94 has_holes_ = false;
95 }
96
DeleteLoopsInVector(vector<S2Loop * > * loops)97 static void DeleteLoopsInVector(vector<S2Loop*>* loops) {
98 for (size_t i = 0; i < loops->size(); ++i) {
99 delete loops->at(i);
100 }
101 loops->clear();
102 }
103
~S2Polygon()104 S2Polygon::~S2Polygon() {
105 if (owns_loops_) DeleteLoopsInVector(&loops_);
106 }
107
108 typedef pair<S2Point, S2Point> S2PointPair;
109
110 HASH_NAMESPACE_START
111 template<> class hash<S2PointPair> {
112 public:
operator ()(S2PointPair const & p) const113 size_t operator()(S2PointPair const& p) const {
114 hash<S2Point> h;
115 return h(p.first) + (h(p.second) << 1);
116 }
117 };
118 HASH_NAMESPACE_END
119
IsValid(const vector<S2Loop * > & loops,string * err)120 bool S2Polygon::IsValid(const vector<S2Loop*>& loops, string* err) {
121 // If a loop contains an edge AB, then no other loop may contain AB or BA.
122 if (loops.size() > 1) {
123 hash_map<S2PointPair, pair<int, int> > edges;
124 for (size_t i = 0; i < loops.size(); ++i) {
125 S2Loop* lp = loops[i];
126 for (int j = 0; j < lp->num_vertices(); ++j) {
127 S2PointPair key = make_pair(lp->vertex(j), lp->vertex(j + 1));
128 if (edges.insert(make_pair(key, make_pair(i, j))).second) {
129 key = make_pair(lp->vertex(j + 1), lp->vertex(j));
130 if (edges.insert(make_pair(key, make_pair(i, j))).second)
131 continue;
132 }
133 pair<int, int> other = edges[key];
134 VLOG(2) << "Duplicate edge: loop " << i << ", edge " << j
135 << " and loop " << other.first << ", edge " << other.second;
136 if (err) {
137 *err = stream() << "Duplicate edge: loop " << i << ", edge " << j
138 << " and loop " << other.first << ", edge " << other.second;
139 }
140 return false;
141 }
142 }
143 }
144
145 // Verify that no loop covers more than half of the sphere, and that no
146 // two loops cross.
147 for (size_t i = 0; i < loops.size(); ++i) {
148 if (!loops[i]->IsNormalized()) {
149 VLOG(2) << "Loop " << i << " encloses more than half the sphere";
150 if (err) *err = stream() << "Loop " << i << " encloses more than half the sphere";
151 return false;
152 }
153 for (size_t j = i + 1; j < loops.size(); ++j) {
154 // This test not only checks for edge crossings, it also detects
155 // cases where the two boundaries cross at a shared vertex.
156 if (loops[i]->ContainsOrCrosses(loops[j]) < 0) {
157 VLOG(2) << "Loop " << i << " crosses loop " << j;
158 if (err) *err = stream() << "Loop " << i << " crosses loop " << j;
159 return false;
160 }
161 }
162 }
163
164 return true;
165 }
166
IsValid(string * err) const167 bool S2Polygon::IsValid(string* err) const {
168 for (int i = 0; i < num_loops(); ++i) {
169 if (!loop(i)->IsValid(err)) {
170 return false;
171 }
172 }
173 return IsValid(loops_, err);
174 }
175
IsValid(bool check_loops,int max_adjacent) const176 bool S2Polygon::IsValid(bool check_loops, int max_adjacent) const {
177 return IsValid();
178 }
179
InsertLoop(S2Loop * new_loop,S2Loop * parent,LoopMap * loop_map)180 void S2Polygon::InsertLoop(S2Loop* new_loop, S2Loop* parent,
181 LoopMap* loop_map) {
182 vector<S2Loop*>* children = &(*loop_map)[parent];
183 for (size_t i = 0; i < children->size(); ++i) {
184 S2Loop* child = (*children)[i];
185 if (child->ContainsNested(new_loop)) {
186 InsertLoop(new_loop, child, loop_map);
187 return;
188 }
189 }
190 // No loop may contain the complement of another loop. (Handling this case
191 // is significantly more complicated.)
192 DCHECK(parent == NULL || !new_loop->ContainsNested(parent));
193
194 // Some of the children of the parent loop may now be children of
195 // the new loop.
196 vector<S2Loop*>* new_children = &(*loop_map)[new_loop];
197 for (size_t i = 0; i < children->size();) {
198 S2Loop* child = (*children)[i];
199 if (new_loop->ContainsNested(child)) {
200 new_children->push_back(child);
201 children->erase(children->begin() + i);
202 } else {
203 ++i;
204 }
205 }
206 children->push_back(new_loop);
207 }
208
InitLoop(S2Loop * loop,int depth,LoopMap * loop_map)209 void S2Polygon::InitLoop(S2Loop* loop, int depth, LoopMap* loop_map) {
210 if (loop) {
211 loop->set_depth(depth);
212 loops_.push_back(loop);
213 }
214 vector<S2Loop*> const& children = (*loop_map)[loop];
215 for (size_t i = 0; i < children.size(); ++i) {
216 InitLoop(children[i], depth + 1, loop_map);
217 }
218 }
219
ContainsChild(S2Loop * a,S2Loop * b,LoopMap const & loop_map)220 bool S2Polygon::ContainsChild(S2Loop* a, S2Loop* b, LoopMap const& loop_map) {
221 // This function is just used to verify that the loop map was
222 // constructed correctly.
223
224 if (a == b) return true;
225 vector<S2Loop*> const& children = loop_map.find(a)->second;
226 for (size_t i = 0; i < children.size(); ++i) {
227 if (ContainsChild(children[i], b, loop_map)) return true;
228 }
229 return false;
230 }
231
Init(vector<S2Loop * > * loops)232 void S2Polygon::Init(vector<S2Loop*>* loops) {
233 if (S2::debug) {
234 CHECK(IsValid(*loops));
235 }
236 DCHECK(loops_.empty());
237 loops_.swap(*loops);
238
239 num_vertices_ = 0;
240 for (int i = 0; i < num_loops(); ++i) {
241 num_vertices_ += loop(i)->num_vertices();
242 }
243
244 LoopMap loop_map;
245 for (int i = 0; i < num_loops(); ++i) {
246 InsertLoop(loop(i), NULL, &loop_map);
247 }
248 // Reorder the loops in depth-first traversal order.
249 loops_.clear();
250 InitLoop(NULL, -1, &loop_map);
251
252 if (S2::debug) {
253 // Check that the LoopMap is correct (this is fairly cheap).
254 for (int i = 0; i < num_loops(); ++i) {
255 for (int j = 0; j < num_loops(); ++j) {
256 if (i == j) continue;
257 CHECK_EQ(ContainsChild(loop(i), loop(j), loop_map),
258 loop(i)->ContainsNested(loop(j)));
259 }
260 }
261 }
262
263 // Compute the bounding rectangle of the entire polygon.
264 has_holes_ = false;
265 bound_ = S2LatLngRect::Empty();
266 for (int i = 0; i < num_loops(); ++i) {
267 if (loop(i)->sign() < 0) {
268 has_holes_ = true;
269 } else {
270 bound_ = bound_.Union(loop(i)->GetRectBound());
271 }
272 }
273 }
274
GetParent(int k) const275 int S2Polygon::GetParent(int k) const {
276 int depth = loop(k)->depth();
277 if (depth == 0) return -1; // Optimization.
278 while (--k >= 0 && loop(k)->depth() >= depth) continue;
279 return k;
280 }
281
GetLastDescendant(int k) const282 int S2Polygon::GetLastDescendant(int k) const {
283 if (k < 0) return num_loops() - 1;
284 int depth = loop(k)->depth();
285 while (++k < num_loops() && loop(k)->depth() > depth) continue;
286 return k - 1;
287 }
288
GetArea() const289 double S2Polygon::GetArea() const {
290 double area = 0;
291 for (int i = 0; i < num_loops(); ++i) {
292 area += loop(i)->sign() * loop(i)->GetArea();
293 }
294 return area;
295 }
296
GetCentroid() const297 S2Point S2Polygon::GetCentroid() const {
298 S2Point centroid;
299 for (int i = 0; i < num_loops(); ++i) {
300 centroid += loop(i)->sign() * loop(i)->GetCentroid();
301 }
302 return centroid;
303 }
304
ContainsOrCrosses(S2Loop const * b) const305 int S2Polygon::ContainsOrCrosses(S2Loop const* b) const {
306 bool inside = false;
307 for (int i = 0; i < num_loops(); ++i) {
308 int result = loop(i)->ContainsOrCrosses(b);
309 if (result < 0) return -1; // The loop boundaries intersect.
310 if (result > 0) inside ^= true;
311 }
312 return static_cast<int>(inside); // True if loop B is contained by the
313 // polygon.
314 }
315
AnyLoopContains(S2Loop const * b) const316 bool S2Polygon::AnyLoopContains(S2Loop const* b) const {
317 // Return true if any loop contains the given loop.
318 for (int i = 0; i < num_loops(); ++i) {
319 if (loop(i)->Contains(b)) return true;
320 }
321 return false;
322 }
323
ContainsAllShells(S2Polygon const * b) const324 bool S2Polygon::ContainsAllShells(S2Polygon const* b) const {
325 // Return true if this polygon (A) contains all the shells of B.
326 for (int j = 0; j < b->num_loops(); ++j) {
327 if (b->loop(j)->sign() < 0) continue;
328 if (ContainsOrCrosses(b->loop(j)) <= 0) {
329 // Shell of B is not contained by A, or the boundaries intersect.
330 return false;
331 }
332 }
333 return true;
334 }
335
ExcludesAllHoles(S2Polygon const * b) const336 bool S2Polygon::ExcludesAllHoles(S2Polygon const* b) const {
337 // Return true if this polygon (A) excludes (i.e. does not intersect)
338 // all holes of B.
339 for (int j = 0; j < b->num_loops(); ++j) {
340 if (b->loop(j)->sign() > 0) continue;
341 if (ContainsOrCrosses(b->loop(j)) != 0) {
342 // Hole of B is contained by A, or the boundaries intersect.
343 return false;
344 }
345 }
346 return true;
347 }
348
IntersectsAnyShell(S2Polygon const * b) const349 bool S2Polygon::IntersectsAnyShell(S2Polygon const* b) const {
350 // Return true if this polygon (A) intersects any shell of B.
351 for (int j = 0; j < b->num_loops(); ++j) {
352 if (b->loop(j)->sign() < 0) continue;
353 if (IntersectsShell(b->loop(j)) != 0)
354 return true;
355 }
356 return false;
357 }
358
IntersectsShell(S2Loop const * b) const359 bool S2Polygon::IntersectsShell(S2Loop const* b) const {
360 bool inside = false;
361 for (int i = 0; i < num_loops(); ++i) {
362 if (loop(i)->Contains(b)) {
363 inside ^= true;
364 } else if (!b->Contains(loop(i)) && loop(i)->Intersects(b)) {
365 // We definitely have an intersection if the loops intersect AND one
366 // is not properly contained in the other. If A (this) is properly
367 // contained in a loop of B, we don't know yet if it may be actually
368 // inside a hole within B.
369 return true;
370 }
371 }
372 return inside;
373 }
374
Contains(S2Polygon const * b) const375 bool S2Polygon::Contains(S2Polygon const* b) const {
376 // If both polygons have one loop, use the more efficient S2Loop method.
377 // Note that S2Loop::Contains does its own bounding rectangle check.
378 if (num_loops() == 1 && b->num_loops() == 1) {
379 return loop(0)->Contains(b->loop(0));
380 }
381
382 // Otherwise if neither polygon has holes, we can still use the more
383 // efficient S2Loop::Contains method (rather than ContainsOrCrosses),
384 // but it's worthwhile to do our own bounds check first.
385 if (!bound_.Contains(b->bound_)) {
386 // If the union of the bounding boxes spans the full longitude range,
387 // it is still possible that polygon A contains B. (This is only
388 // possible if at least one polygon has multiple shells.)
389 if (!bound_.lng().Union(b->bound_.lng()).is_full()) return false;
390 }
391 if (!has_holes_ && !b->has_holes_) {
392 for (int j = 0; j < b->num_loops(); ++j) {
393 if (!AnyLoopContains(b->loop(j))) return false;
394 }
395 return true;
396 }
397
398 // This could be implemented more efficiently for polygons with lots of
399 // holes by keeping a copy of the LoopMap computed during initialization.
400 // However, in practice most polygons are one loop, and multiloop polygons
401 // tend to consist of many shells rather than holes. In any case, the real
402 // way to get more efficiency is to implement a sub-quadratic algorithm
403 // such as building a trapezoidal map.
404
405 // Every shell of B must be contained by an odd number of loops of A,
406 // and every hole of A must be contained by an even number of loops of B.
407 return ContainsAllShells(b) && b->ExcludesAllHoles(this);
408 }
409
Intersects(S2Polygon const * b) const410 bool S2Polygon::Intersects(S2Polygon const* b) const {
411 // A.Intersects(B) if and only if !Complement(A).Contains(B). However,
412 // implementing a Complement() operation is trickier than it sounds,
413 // and in any case it's more efficient to test for intersection directly.
414
415 // If both polygons have one loop, use the more efficient S2Loop method.
416 // Note that S2Loop::Intersects does its own bounding rectangle check.
417 if (num_loops() == 1 && b->num_loops() == 1) {
418 return loop(0)->Intersects(b->loop(0));
419 }
420
421 // Otherwise if neither polygon has holes, we can still use the more
422 // efficient S2Loop::Intersects method. The polygons intersect if and
423 // only if some pair of loop regions intersect.
424 if (!bound_.Intersects(b->bound_)) return false;
425 if (!has_holes_ && !b->has_holes_) {
426 for (int i = 0; i < num_loops(); ++i) {
427 for (int j = 0; j < b->num_loops(); ++j) {
428 if (loop(i)->Intersects(b->loop(j))) return true;
429 }
430 }
431 return false;
432 }
433
434 // Otherwise if any shell of B is contained by an odd number of loops of A,
435 // or any shell of A is contained by an odd number of loops of B, or there is
436 // an intersection without containment, then there is an intersection.
437 return IntersectsAnyShell(b) || b->IntersectsAnyShell(this);
438 }
439
GetCapBound() const440 S2Cap S2Polygon::GetCapBound() const {
441 return bound_.GetCapBound();
442 }
443
Contains(S2Cell const & cell) const444 bool S2Polygon::Contains(S2Cell const& cell) const {
445 if (num_loops() == 1) {
446 return loop(0)->Contains(cell);
447 }
448
449 // We can't check bound_.Contains(cell.GetRectBound()) because S2Cell's
450 // GetRectBound() calculation is not precise.
451 if (!bound_.Contains(cell.GetCenter())) return false;
452
453 S2Loop cell_loop(cell);
454 S2Polygon cell_poly(&cell_loop);
455 bool contains = Contains(&cell_poly);
456 if (contains) {
457 DCHECK(Contains(cell.GetCenter()));
458 }
459 return contains;
460 }
461
ApproxContains(S2Polygon const * b,S1Angle vertex_merge_radius) const462 bool S2Polygon::ApproxContains(S2Polygon const* b,
463 S1Angle vertex_merge_radius) const {
464 S2Polygon difference;
465 difference.InitToDifferenceSloppy(b, this, vertex_merge_radius);
466 return difference.num_loops() == 0;
467 }
468
MayIntersect(S2Cell const & cell) const469 bool S2Polygon::MayIntersect(S2Cell const& cell) const {
470 if (num_loops() == 1) {
471 return loop(0)->MayIntersect(cell);
472 }
473 if (!bound_.Intersects(cell.GetRectBound())) return false;
474
475 S2Loop cell_loop(cell);
476 S2Polygon cell_poly(&cell_loop);
477 bool intersects = Intersects(&cell_poly);
478 if (!intersects) {
479 DCHECK(!Contains(cell.GetCenter()));
480 }
481 return intersects;
482 }
483
VirtualContainsPoint(S2Point const & p) const484 bool S2Polygon::VirtualContainsPoint(S2Point const& p) const {
485 return Contains(p); // The same as Contains() below, just virtual.
486 }
487
Contains(S2Point const & p) const488 bool S2Polygon::Contains(S2Point const& p) const {
489 if (num_loops() == 1) {
490 return loop(0)->Contains(p); // Optimization.
491 }
492 if (!bound_.Contains(p)) return false;
493 bool inside = false;
494 for (int i = 0; i < num_loops(); ++i) {
495 inside ^= loop(i)->Contains(p);
496 if (inside && !has_holes_) break; // Shells are disjoint.
497 }
498 return inside;
499 }
500
Encode(Encoder * const encoder) const501 void S2Polygon::Encode(Encoder* const encoder) const {
502 encoder->Ensure(10); // Sufficient
503 encoder->put8(kCurrentEncodingVersionNumber);
504 encoder->put8(owns_loops_);
505 encoder->put8(has_holes_);
506 encoder->put32(loops_.size());
507 DCHECK_GE(encoder->avail(), 0);
508
509 for (int i = 0; i < num_loops(); ++i) {
510 loop(i)->Encode(encoder);
511 }
512 bound_.Encode(encoder);
513 }
514
Decode(Decoder * const decoder)515 bool S2Polygon::Decode(Decoder* const decoder) {
516 return DecodeInternal(decoder, false);
517 }
518
DecodeWithinScope(Decoder * const decoder)519 bool S2Polygon::DecodeWithinScope(Decoder* const decoder) {
520 return DecodeInternal(decoder, true);
521 }
522
DecodeInternal(Decoder * const decoder,bool within_scope)523 bool S2Polygon::DecodeInternal(Decoder* const decoder, bool within_scope) {
524 unsigned char version = decoder->get8();
525 if (version > kCurrentEncodingVersionNumber) return false;
526
527 if (owns_loops_) DeleteLoopsInVector(&loops_);
528
529 owns_loops_ = decoder->get8();
530 has_holes_ = decoder->get8();
531 int num_loops = decoder->get32();
532 loops_.clear();
533 loops_.reserve(num_loops);
534 num_vertices_ = 0;
535 for (int i = 0; i < num_loops; ++i) {
536 loops_.push_back(new S2Loop);
537 if (within_scope) {
538 if (!loops_.back()->DecodeWithinScope(decoder)) return false;
539 } else {
540 if (!loops_.back()->Decode(decoder)) return false;
541 }
542 num_vertices_ += loops_.back()->num_vertices();
543 }
544 if (!bound_.Decode(decoder)) return false;
545
546 DCHECK(IsValid(loops_));
547
548 return decoder->avail() >= 0;
549 }
550
551 // Indexing structure to efficiently ClipEdge() of a polygon. This is
552 // an abstract class because we need to use if for both polygons (for
553 // InitToIntersection() and friends) and for sets of vectors of points
554 // (for InitToSimplified()).
555 //
556 // Usage -- in your subclass:
557 // - Call AddLoop() for each of your loops -- and keep them accessible in
558 // your subclass.
559 // - Overwrite EdgeFromTo(), calling DecodeIndex() and accessing your
560 // underlying data with the resulting two indices.
561 class S2LoopSequenceIndex: public S2EdgeIndex {
562 public:
S2LoopSequenceIndex()563 S2LoopSequenceIndex(): num_edges_(0), num_loops_(0) {}
~S2LoopSequenceIndex()564 ~S2LoopSequenceIndex() {}
565
AddLoop(int num_vertices)566 void AddLoop(int num_vertices) {
567 int vertices_so_far = num_edges_;
568 loop_to_first_index_.push_back(vertices_so_far);
569 index_to_loop_.resize(vertices_so_far + num_vertices);
570 for (int i = 0; i < num_vertices; ++i) {
571 index_to_loop_[vertices_so_far] = num_loops_;
572 vertices_so_far++;
573 }
574 num_edges_ += num_vertices;
575 num_loops_++;
576 }
577
DecodeIndex(int index,int * loop_index,int * vertex_in_loop) const578 inline void DecodeIndex(int index,
579 int* loop_index, int* vertex_in_loop) const {
580 *loop_index = index_to_loop_[index];
581 *vertex_in_loop = index - loop_to_first_index_[*loop_index];
582 }
583
584 // It is faster to return both vertices at once. It makes a difference
585 // for small polygons.
586 virtual void EdgeFromTo(int index,
587 S2Point const* * from, S2Point const* * to) const = 0;
588
num_edges() const589 int num_edges() const { return num_edges_; }
590
edge_from(int index) const591 virtual S2Point const* edge_from(int index) const {
592 S2Point const* from;
593 S2Point const* to;
594 EdgeFromTo(index, &from, &to);
595 return from;
596 }
597
edge_to(int index) const598 virtual S2Point const* edge_to(int index) const {
599 S2Point const* from;
600 S2Point const* to;
601 EdgeFromTo(index, &from, &to);
602 return to;
603 }
604
605 protected:
606 // Map from the unidimensional edge index to the loop this edge
607 // belongs to.
608 vector<int> index_to_loop_;
609
610 // Reverse of index_to_loop_: maps a loop index to the
611 // unidimensional index of the first edge in the loop.
612 vector<int> loop_to_first_index_;
613
614 // Total number of edges.
615 int num_edges_;
616
617 // Total number of loops.
618 int num_loops_;
619 };
620
621 // Indexing structure for an S2Polygon.
622 class S2PolygonIndex: public S2LoopSequenceIndex {
623 public:
S2PolygonIndex(S2Polygon const * poly,bool reverse)624 S2PolygonIndex(S2Polygon const* poly, bool reverse):
625 poly_(poly),
626 reverse_(reverse) {
627 for (int iloop = 0; iloop < poly_->num_loops(); ++iloop) {
628 AddLoop(poly_->loop(iloop)->num_vertices());
629 }
630 }
631
~S2PolygonIndex()632 virtual ~S2PolygonIndex() {}
633
EdgeFromTo(int index,S2Point const ** from,S2Point const ** to) const634 virtual void EdgeFromTo(int index,
635 S2Point const* * from, S2Point const* * to) const {
636 int loop_index;
637 int vertex_in_loop;
638 DecodeIndex(index, &loop_index, &vertex_in_loop);
639 S2Loop const* loop(poly_->loop(loop_index));
640 int from_index, to_index;
641 if (loop->is_hole() ^ reverse_) {
642 from_index = loop->num_vertices() - 1 - vertex_in_loop;
643 to_index = 2 * loop->num_vertices() - 2 - vertex_in_loop;
644 } else {
645 from_index = vertex_in_loop;
646 to_index = vertex_in_loop + 1;
647 }
648 *from = &(loop->vertex(from_index));
649 *to = &(loop->vertex(to_index));
650 }
651
652 private:
653 S2Polygon const* poly_;
654 bool reverse_;
655 };
656
657 // Indexing structure for a sequence of loops (not in the sense of S2:
658 // the loops can self-intersect). Each loop is given in a vector<S2Point>
659 // where, as in S2Loop, the last vertex is implicitely joined to the first.
660 // Add each loop individually with AddVector(). The caller owns
661 // the vector<S2Point>'s.
662 class S2LoopsAsVectorsIndex: public S2LoopSequenceIndex {
663 public:
S2LoopsAsVectorsIndex()664 S2LoopsAsVectorsIndex() {}
~S2LoopsAsVectorsIndex()665 ~S2LoopsAsVectorsIndex() {}
666
AddVector(vector<S2Point> const * v)667 void AddVector(vector<S2Point> const* v) {
668 loops_.push_back(v);
669 AddLoop(v->size());
670 }
671
EdgeFromTo(int index,S2Point const ** from,S2Point const ** to) const672 virtual void EdgeFromTo(int index,
673 S2Point const* *from, S2Point const* *to) const {
674 int loop_index;
675 int vertex_in_loop;
676 DecodeIndex(index, &loop_index, &vertex_in_loop);
677 vector<S2Point> const* loop = loops_[loop_index];
678 *from = &loop->at(vertex_in_loop);
679 *to = &loop->at((size_t)vertex_in_loop == loop->size() - 1
680 ? 0
681 : vertex_in_loop + 1);
682 }
683
684 private:
685 vector< vector<S2Point> const* > loops_;
686 };
687
688 typedef vector<pair<double, S2Point> > IntersectionSet;
689
AddIntersection(S2Point const & a0,S2Point const & a1,S2Point const & b0,S2Point const & b1,bool add_shared_edges,int crossing,IntersectionSet * intersections)690 static void AddIntersection(S2Point const& a0, S2Point const& a1,
691 S2Point const& b0, S2Point const& b1,
692 bool add_shared_edges, int crossing,
693 IntersectionSet* intersections) {
694 if (crossing > 0) {
695 // There is a proper edge crossing.
696 S2Point x = S2EdgeUtil::GetIntersection(a0, a1, b0, b1);
697 double t = S2EdgeUtil::GetDistanceFraction(x, a0, a1);
698 intersections->push_back(make_pair(t, x));
699
700 } else if (S2EdgeUtil::VertexCrossing(a0, a1, b0, b1)) {
701 // There is a crossing at one of the vertices. The basic rule is simple:
702 // if a0 equals one of the "b" vertices, the crossing occurs at t=0;
703 // otherwise, it occurs at t=1.
704 //
705 // This has the effect that when two symmetric edges are
706 // encountered (an edge an its reverse), neither one is included
707 // in the output. When two duplicate edges are encountered, both
708 // are included in the output. The "add_shared_edges" flag allows
709 // one of these two copies to be removed by changing its
710 // intersection parameter from 0 to 1.
711
712 double t = (a0 == b0 || a0 == b1) ? 0 : 1;
713 if (!add_shared_edges && a1 == b1) t = 1;
714 intersections->push_back(make_pair(t, t == 0 ? a0 : a1));
715 }
716 }
717
ClipEdge(S2Point const & a0,S2Point const & a1,S2LoopSequenceIndex * b_index,bool add_shared_edges,IntersectionSet * intersections)718 static void ClipEdge(S2Point const& a0, S2Point const& a1,
719 S2LoopSequenceIndex* b_index,
720 bool add_shared_edges, IntersectionSet* intersections) {
721 // Find all points where the polygon B intersects the edge (a0,a1),
722 // and add the corresponding parameter values (in the range [0,1]) to
723 // "intersections".
724 S2LoopSequenceIndex::Iterator it(b_index);
725 it.GetCandidates(a0, a1);
726 S2EdgeUtil::EdgeCrosser crosser(&a0, &a1, &a0);
727 S2Point const* from;
728 S2Point const* to = NULL;
729 for (; !it.Done(); it.Next()) {
730 S2Point const* const previous_to = to;
731 b_index->EdgeFromTo(it.Index(), &from, &to);
732 if (previous_to != from) crosser.RestartAt(from);
733 int crossing = crosser.RobustCrossing(to);
734 if (crossing < 0) continue;
735 AddIntersection(a0, a1, *from, *to,
736 add_shared_edges, crossing, intersections);
737 }
738 }
739
740
ClipBoundary(S2Polygon const * a,bool reverse_a,S2Polygon const * b,bool reverse_b,bool invert_b,bool add_shared_edges,S2PolygonBuilder * builder)741 static void ClipBoundary(S2Polygon const* a, bool reverse_a,
742 S2Polygon const* b, bool reverse_b, bool invert_b,
743 bool add_shared_edges, S2PolygonBuilder* builder) {
744 // Clip the boundary of A to the interior of B, and add the resulting edges
745 // to "builder". Shells are directed CCW and holes are directed clockwise,
746 // unless "reverse_a" or "reverse_b" is true in which case these directions
747 // in the corresponding polygon are reversed. If "invert_b" is true, the
748 // boundary of A is clipped to the exterior rather than the interior of B.
749 // If "add_shared_edges" is true, then the output will include any edges
750 // that are shared between A and B (both edges must be in the same direction
751 // after any edge reversals are taken into account).
752
753 S2PolygonIndex b_index(b, reverse_b);
754 b_index.PredictAdditionalCalls(a->num_vertices());
755
756 IntersectionSet intersections;
757 for (int i = 0; i < a->num_loops(); ++i) {
758 S2Loop* a_loop = a->loop(i);
759 int n = a_loop->num_vertices();
760 int dir = (a_loop->is_hole() ^ reverse_a) ? -1 : 1;
761 bool inside = b->Contains(a_loop->vertex(0)) ^ invert_b;
762 for (int j = (dir > 0) ? 0 : n; n > 0; --n, j += dir) {
763 S2Point const& a0 = a_loop->vertex(j);
764 S2Point const& a1 = a_loop->vertex(j + dir);
765 intersections.clear();
766 ClipEdge(a0, a1, &b_index, add_shared_edges, &intersections);
767
768 if (inside) intersections.push_back(make_pair(0, a0));
769 inside = (intersections.size() & 1);
770 DCHECK_EQ((b->Contains(a1) ^ invert_b), inside);
771 if (inside) intersections.push_back(make_pair(1, a1));
772 sort(intersections.begin(), intersections.end());
773 for (size_t k = 0; k < intersections.size(); k += 2) {
774 if (intersections[k] == intersections[k+1]) continue;
775 builder->AddEdge(intersections[k].second, intersections[k+1].second);
776 }
777 }
778 }
779 }
780
InitToIntersection(S2Polygon const * a,S2Polygon const * b)781 void S2Polygon::InitToIntersection(S2Polygon const* a, S2Polygon const* b) {
782 InitToIntersectionSloppy(a, b, S2EdgeUtil::kIntersectionTolerance);
783 }
784
InitToIntersectionSloppy(S2Polygon const * a,S2Polygon const * b,S1Angle vertex_merge_radius)785 void S2Polygon::InitToIntersectionSloppy(S2Polygon const* a, S2Polygon const* b,
786 S1Angle vertex_merge_radius) {
787 DCHECK_EQ(0, num_loops());
788 if (!a->bound_.Intersects(b->bound_)) return;
789
790 // We want the boundary of A clipped to the interior of B,
791 // plus the boundary of B clipped to the interior of A,
792 // plus one copy of any directed edges that are in both boundaries.
793
794 S2PolygonBuilderOptions options(S2PolygonBuilderOptions::DIRECTED_XOR());
795 options.set_vertex_merge_radius(vertex_merge_radius);
796 S2PolygonBuilder builder(options);
797 ClipBoundary(a, false, b, false, false, true, &builder);
798 ClipBoundary(b, false, a, false, false, false, &builder);
799 if (!builder.AssemblePolygon(this, NULL)) {
800 S2LOG(DFATAL) << "Bad directed edges in InitToIntersection";
801 }
802 }
803
InitToUnion(S2Polygon const * a,S2Polygon const * b)804 void S2Polygon::InitToUnion(S2Polygon const* a, S2Polygon const* b) {
805 InitToUnionSloppy(a, b, S2EdgeUtil::kIntersectionTolerance);
806 }
807
InitToUnionSloppy(S2Polygon const * a,S2Polygon const * b,S1Angle vertex_merge_radius)808 void S2Polygon::InitToUnionSloppy(S2Polygon const* a, S2Polygon const* b,
809 S1Angle vertex_merge_radius) {
810 DCHECK_EQ(0, num_loops());
811
812 // We want the boundary of A clipped to the exterior of B,
813 // plus the boundary of B clipped to the exterior of A,
814 // plus one copy of any directed edges that are in both boundaries.
815
816 S2PolygonBuilderOptions options(S2PolygonBuilderOptions::DIRECTED_XOR());
817 options.set_vertex_merge_radius(vertex_merge_radius);
818 S2PolygonBuilder builder(options);
819 ClipBoundary(a, false, b, false, true, true, &builder);
820 ClipBoundary(b, false, a, false, true, false, &builder);
821 if (!builder.AssemblePolygon(this, NULL)) {
822 S2LOG(DFATAL) << "Bad directed edges";
823 }
824 }
825
InitToDifference(S2Polygon const * a,S2Polygon const * b)826 void S2Polygon::InitToDifference(S2Polygon const* a, S2Polygon const* b) {
827 InitToDifferenceSloppy(a, b, S2EdgeUtil::kIntersectionTolerance);
828 }
829
InitToDifferenceSloppy(S2Polygon const * a,S2Polygon const * b,S1Angle vertex_merge_radius)830 void S2Polygon::InitToDifferenceSloppy(S2Polygon const* a, S2Polygon const* b,
831 S1Angle vertex_merge_radius) {
832 DCHECK_EQ(0, num_loops());
833
834 // We want the boundary of A clipped to the exterior of B,
835 // plus the reversed boundary of B clipped to the interior of A,
836 // plus one copy of any edge in A that is also a reverse edge in B.
837
838 S2PolygonBuilderOptions options(S2PolygonBuilderOptions::DIRECTED_XOR());
839 options.set_vertex_merge_radius(vertex_merge_radius);
840 S2PolygonBuilder builder(options);
841 ClipBoundary(a, false, b, true, true, true, &builder);
842 ClipBoundary(b, true, a, false, false, false, &builder);
843 if (!builder.AssemblePolygon(this, NULL)) {
844 S2LOG(DFATAL) << "Bad directed edges in InitToDifference";
845 }
846 }
847
848 // Takes a loop and simplifies it. This may return a self-intersecting
849 // polyline. Always keeps the first vertex from the loop.
SimplifyLoopAsPolyline(S2Loop const * loop,S1Angle tolerance)850 vector<S2Point>* SimplifyLoopAsPolyline(S2Loop const* loop, S1Angle tolerance) {
851 vector<S2Point> points(loop->num_vertices() + 1);
852 // Add the first vertex at the beginning and at the end.
853 for (int i = 0; i <= loop->num_vertices(); ++i) {
854 points[i] = loop->vertex(i);
855 }
856 S2Polyline line(points);
857 vector<int> indices;
858 line.SubsampleVertices(tolerance, &indices);
859 if (indices.size() <= 2) return NULL;
860 // Add them all except the last: it is the same as the first.
861 vector<S2Point>* simplified_line = new vector<S2Point>(indices.size() - 1);
862 VLOG(4) << "Now simplified to: ";
863 for (size_t i = 0; i + 1 < indices.size(); ++i) {
864 (*simplified_line)[i] = line.vertex(indices[i]);
865 VLOG(4) << S2LatLng(line.vertex(indices[i]));
866 }
867 return simplified_line;
868 }
869
870 // Takes a set of possibly intersecting edges, stored in an
871 // S2EdgeIndex. Breaks the edges into small pieces so that there is
872 // no intersection anymore, and adds all these edges to the builder.
BreakEdgesAndAddToBuilder(S2LoopsAsVectorsIndex * edge_index,S2PolygonBuilder * builder)873 void BreakEdgesAndAddToBuilder(S2LoopsAsVectorsIndex* edge_index,
874 S2PolygonBuilder* builder) {
875 // If there are self intersections, we add the pieces separately.
876 for (int i = 0; i < edge_index->num_edges(); ++i) {
877 S2Point const* from;
878 S2Point const* to;
879 edge_index->EdgeFromTo(i, &from, &to);
880
881 IntersectionSet intersections;
882 intersections.push_back(make_pair(0, *from));
883 // add_shared_edges can be false or true: it makes no difference
884 // due to the way we call ClipEdge.
885 ClipEdge(*from, *to, edge_index, false, &intersections);
886 intersections.push_back(make_pair(1, *to));
887 sort(intersections.begin(), intersections.end());
888 for (size_t k = 0; k + 1 < intersections.size(); ++k) {
889 if (intersections[k] == intersections[k+1]) continue;
890 builder->AddEdge(intersections[k].second, intersections[k+1].second);
891 }
892 }
893 }
894
895 // Simplifies the polygon. The algorithm is straightforward and naive:
896 // 1. Simplify each loop by removing points while staying in the
897 // tolerance zone. This uses S2Polyline::SubsampleVertices(),
898 // which is not guaranteed to be optimal in terms of number of
899 // points.
900 // 2. Break any edge in pieces such that no piece intersects any
901 // other.
902 // 3. Use the polygon builder to regenerate the full polygon.
InitToSimplified(S2Polygon const * a,S1Angle tolerance)903 void S2Polygon::InitToSimplified(S2Polygon const* a, S1Angle tolerance) {
904 S2PolygonBuilderOptions builder_options =
905 S2PolygonBuilderOptions::UNDIRECTED_XOR();
906 builder_options.set_validate(false);
907 // Ideally, we would want to set the vertex_merge_radius of the
908 // builder roughly to tolerance (and in fact forego the edge
909 // splitting step). Alas, if we do that, we are liable to the
910 // 'chain effect', where vertices are merged with closeby vertices
911 // and so on, so that a vertex can move by an arbitrary distance.
912 // So we remain conservative:
913 builder_options.set_vertex_merge_radius(tolerance * 0.10);
914 S2PolygonBuilder builder(builder_options);
915
916 // Simplify each loop separately and add to the edge index
917 S2LoopsAsVectorsIndex index;
918 vector<vector<S2Point>*> simplified_loops;
919 for (int i = 0; i < a->num_loops(); ++i) {
920 vector<S2Point>* simpler = SimplifyLoopAsPolyline(a->loop(i), tolerance);
921 if (NULL == simpler) continue;
922 simplified_loops.push_back(simpler);
923 index.AddVector(simpler);
924 }
925 if (0 != index.num_edges()) {
926 BreakEdgesAndAddToBuilder(&index, &builder);
927
928 if (!builder.AssemblePolygon(this, NULL)) {
929 S2LOG(DFATAL) << "Bad edges in InitToSimplified.";
930 }
931 }
932
933 for (size_t i = 0; i < simplified_loops.size(); ++i) {
934 delete simplified_loops[i];
935 }
936 simplified_loops.clear();
937 }
938
InternalClipPolyline(bool invert,S2Polyline const * a,vector<S2Polyline * > * out,S1Angle merge_radius) const939 void S2Polygon::InternalClipPolyline(bool invert,
940 S2Polyline const* a,
941 vector<S2Polyline*> *out,
942 S1Angle merge_radius) const {
943 // Clip the polyline A to the interior of this polygon.
944 // The resulting polyline(s) will be appended to 'out'.
945 // If invert is true, we clip A to the exterior of this polygon instead.
946 // Vertices will be dropped such that adjacent vertices will not
947 // be closer than 'merge_radius'.
948 //
949 // We do the intersection/subtraction by walking the polyline edges.
950 // For each edge, we compute all intersections with the polygon boundary
951 // and sort them in increasing order of distance along that edge.
952 // We then divide the intersection points into pairs, and output a
953 // clipped polyline segment for each one.
954 // We keep track of whether we're inside or outside of the polygon at
955 // all times to decide which segments to output.
956
957 CHECK(out->empty());
958
959 IntersectionSet intersections;
960 vector<S2Point> vertices;
961 S2PolygonIndex poly_index(this, false);
962 int n = a->num_vertices();
963 bool inside = Contains(a->vertex(0)) ^ invert;
964 for (int j = 0; j < n-1; j++) {
965 S2Point const& a0 = a->vertex(j);
966 S2Point const& a1 = a->vertex(j + 1);
967 ClipEdge(a0, a1, &poly_index, true, &intersections);
968 if (inside) intersections.push_back(make_pair(0, a0));
969 inside = (intersections.size() & 1);
970 DCHECK_EQ((Contains(a1) ^ invert), inside);
971 if (inside) intersections.push_back(make_pair(1, a1));
972 sort(intersections.begin(), intersections.end());
973 // At this point we have a sorted array of vertex pairs representing
974 // the edge(s) obtained after clipping (a0,a1) against the polygon.
975 for (size_t k = 0; k < intersections.size(); k += 2) {
976 if (intersections[k] == intersections[k+1]) continue;
977 S2Point const& v0 = intersections[k].second;
978 S2Point const& v1 = intersections[k+1].second;
979
980 // If the gap from the previous vertex to this one is large
981 // enough, start a new polyline.
982 if (!vertices.empty() &&
983 vertices.back().Angle(v0) > merge_radius.radians()) {
984 out->push_back(new S2Polyline(vertices));
985 vertices.clear();
986 }
987 // Append this segment to the current polyline, ignoring any
988 // vertices that are too close to the previous vertex.
989 if (vertices.empty()) vertices.push_back(v0);
990 if (vertices.back().Angle(v1) > merge_radius.radians()) {
991 vertices.push_back(v1);
992 }
993 }
994 intersections.clear();
995 }
996 if (!vertices.empty()) {
997 out->push_back(new S2Polyline(vertices));
998 }
999 }
1000
IntersectWithPolyline(S2Polyline const * a,vector<S2Polyline * > * out) const1001 void S2Polygon::IntersectWithPolyline(
1002 S2Polyline const* a,
1003 vector<S2Polyline*> *out) const {
1004 IntersectWithPolylineSloppy(a, out, S2EdgeUtil::kIntersectionTolerance);
1005 }
1006
IntersectWithPolylineSloppy(S2Polyline const * a,vector<S2Polyline * > * out,S1Angle vertex_merge_radius) const1007 void S2Polygon::IntersectWithPolylineSloppy(
1008 S2Polyline const* a,
1009 vector<S2Polyline*> *out,
1010 S1Angle vertex_merge_radius) const {
1011 InternalClipPolyline(false, a, out, vertex_merge_radius);
1012 }
1013
SubtractFromPolyline(S2Polyline const * a,vector<S2Polyline * > * out) const1014 void S2Polygon::SubtractFromPolyline(S2Polyline const* a,
1015 vector<S2Polyline*> *out) const {
1016 SubtractFromPolylineSloppy(a, out, S2EdgeUtil::kIntersectionTolerance);
1017 }
1018
SubtractFromPolylineSloppy(S2Polyline const * a,vector<S2Polyline * > * out,S1Angle vertex_merge_radius) const1019 void S2Polygon::SubtractFromPolylineSloppy(
1020 S2Polyline const* a,
1021 vector<S2Polyline*> *out,
1022 S1Angle vertex_merge_radius) const {
1023 InternalClipPolyline(true, a, out, vertex_merge_radius);
1024 }
1025
1026
DestructiveUnion(vector<S2Polygon * > * polygons)1027 S2Polygon* S2Polygon::DestructiveUnion(vector<S2Polygon*>* polygons) {
1028 return DestructiveUnionSloppy(polygons, S2EdgeUtil::kIntersectionTolerance);
1029 }
1030
DestructiveUnionSloppy(vector<S2Polygon * > * polygons,S1Angle vertex_merge_radius)1031 S2Polygon* S2Polygon::DestructiveUnionSloppy(vector<S2Polygon*>* polygons,
1032 S1Angle vertex_merge_radius) {
1033 // Effectively create a priority queue of polygons in order of number of
1034 // vertices. Repeatedly union the two smallest polygons and add the result
1035 // to the queue until we have a single polygon to return.
1036 typedef multimap<int, S2Polygon*> QueueType;
1037 QueueType queue; // Map from # of vertices to polygon.
1038 for (size_t i = 0; i < polygons->size(); ++i)
1039 queue.insert(make_pair((*polygons)[i]->num_vertices(), (*polygons)[i]));
1040 polygons->clear();
1041
1042 while (queue.size() > 1) {
1043 // Pop two simplest polygons from queue.
1044 QueueType::iterator smallest_it = queue.begin();
1045 int a_size = smallest_it->first;
1046 S2Polygon* a_polygon = smallest_it->second;
1047 queue.erase(smallest_it);
1048 smallest_it = queue.begin();
1049 int b_size = smallest_it->first;
1050 S2Polygon* b_polygon = smallest_it->second;
1051 queue.erase(smallest_it);
1052
1053 // Union and add result back to queue.
1054 S2Polygon* union_polygon = new S2Polygon();
1055 union_polygon->InitToUnionSloppy(a_polygon, b_polygon, vertex_merge_radius);
1056 delete a_polygon;
1057 delete b_polygon;
1058 queue.insert(make_pair(a_size + b_size, union_polygon));
1059 // We assume that the number of vertices in the union polygon is the
1060 // sum of the number of vertices in the original polygons, which is not
1061 // always true, but will almost always be a decent approximation, and
1062 // faster than recomputing.
1063 }
1064
1065 if (queue.empty())
1066 return new S2Polygon();
1067 else
1068 return queue.begin()->second;
1069 }
1070
InitToCellUnionBorder(S2CellUnion const & cells)1071 void S2Polygon::InitToCellUnionBorder(S2CellUnion const& cells) {
1072 // Use a polygon builder to union the cells in the union. Due to rounding
1073 // errors, we can't do an exact union - when a small cell is adjacent to a
1074 // larger cell, the shared edges can fail to line up exactly. Two cell edges
1075 // cannot come closer then kMinWidth, so if we have the polygon builder merge
1076 // edges within half that distance, we should always merge shared edges
1077 // without merging different edges.
1078 S2PolygonBuilderOptions options(S2PolygonBuilderOptions::DIRECTED_XOR());
1079 double min_cell_angle = S2::kMinWidth.GetValue(S2CellId::kMaxLevel);
1080 options.set_vertex_merge_radius(S1Angle::Radians(min_cell_angle / 2));
1081 S2PolygonBuilder builder(options);
1082 for (int i = 0; i < cells.num_cells(); ++i) {
1083 S2Loop cell_loop(S2Cell(cells.cell_id(i)));
1084 builder.AddLoop(&cell_loop);
1085 }
1086 if (!builder.AssemblePolygon(this, NULL)) {
1087 S2LOG(DFATAL) << "AssemblePolygon failed in InitToCellUnionBorder";
1088 }
1089 }
1090
IsNormalized(string * err) const1091 bool S2Polygon::IsNormalized(string* err) const {
1092 set<S2Point> vertices;
1093 S2Loop* last_parent = NULL;
1094 for (int i = 0; i < num_loops(); ++i) {
1095 S2Loop* child = loop(i);
1096 if (child->depth() == 0) continue;
1097 S2Loop* parent = loop(GetParent(i));
1098 if (parent != last_parent) {
1099 vertices.clear();
1100 for (int j = 0; j < parent->num_vertices(); ++j) {
1101 vertices.insert(parent->vertex(j));
1102 }
1103 last_parent = parent;
1104 }
1105 int count = 0;
1106 for (int j = 0; j < child->num_vertices(); ++j) {
1107 if (vertices.count(child->vertex(j)) > 0) ++count;
1108 }
1109 if (count > 1) {
1110 if (err) {
1111 *err = stream() << "Loop " << i << " shares more than one vertex"
1112 << " with its parent loop " << GetParent(i);
1113 }
1114 return false;
1115 }
1116 }
1117 return true;
1118 }
1119
BoundaryEquals(S2Polygon const * b) const1120 bool S2Polygon::BoundaryEquals(S2Polygon const* b) const {
1121 if (num_loops() != b->num_loops()) return false;
1122
1123 for (int i = 0; i < num_loops(); ++i) {
1124 S2Loop* a_loop = loop(i);
1125 bool success = false;
1126 for (int j = 0; j < num_loops(); ++j) {
1127 S2Loop* b_loop = b->loop(j);
1128 if ((b_loop->depth() == a_loop->depth()) &&
1129 b_loop->BoundaryEquals(a_loop)) {
1130 success = true;
1131 break;
1132 }
1133 }
1134 if (!success) return false;
1135 }
1136 return true;
1137 }
1138
BoundaryApproxEquals(S2Polygon const * b,double max_error) const1139 bool S2Polygon::BoundaryApproxEquals(S2Polygon const* b,
1140 double max_error) const {
1141 if (num_loops() != b->num_loops()) return false;
1142
1143 // For now, we assume that there is at most one candidate match for each
1144 // loop. (So far this method is just used for testing.)
1145
1146 for (int i = 0; i < num_loops(); ++i) {
1147 S2Loop* a_loop = loop(i);
1148 bool success = false;
1149 for (int j = 0; j < num_loops(); ++j) {
1150 S2Loop* b_loop = b->loop(j);
1151 if (b_loop->depth() == a_loop->depth() &&
1152 b_loop->BoundaryApproxEquals(a_loop, max_error)) {
1153 success = true;
1154 break;
1155 }
1156 }
1157 if (!success) return false;
1158 }
1159 return true;
1160 }
1161
BoundaryNear(S2Polygon const * b,double max_error) const1162 bool S2Polygon::BoundaryNear(S2Polygon const* b, double max_error) const {
1163 if (num_loops() != b->num_loops()) return false;
1164
1165 // For now, we assume that there is at most one candidate match for each
1166 // loop. (So far this method is just used for testing.)
1167
1168 for (int i = 0; i < num_loops(); ++i) {
1169 S2Loop* a_loop = loop(i);
1170 bool success = false;
1171 for (int j = 0; j < num_loops(); ++j) {
1172 S2Loop* b_loop = b->loop(j);
1173 if (b_loop->depth() == a_loop->depth() &&
1174 b_loop->BoundaryNear(a_loop, max_error)) {
1175 success = true;
1176 break;
1177 }
1178 }
1179 if (!success) return false;
1180 }
1181 return true;
1182 }
1183
Project(S2Point const & point) const1184 S2Point S2Polygon::Project(S2Point const& point) const {
1185 DCHECK(!loops_.empty());
1186
1187 if (Contains(point)) {
1188 return point;
1189 }
1190
1191 S1Angle min_distance = S1Angle::Radians(10);
1192 int min_loop_index = 0;
1193 int min_vertex_index = 0;
1194
1195 for (int l = 0; l < num_loops(); ++l) {
1196 S2Loop *a_loop = loop(l);
1197 for (int v = 0; v < a_loop->num_vertices(); ++v) {
1198 S1Angle distance_to_segment =
1199 S2EdgeUtil::GetDistance(point,
1200 a_loop->vertex(v),
1201 a_loop->vertex(v + 1));
1202 if (distance_to_segment < min_distance) {
1203 min_distance = distance_to_segment;
1204 min_loop_index = l;
1205 min_vertex_index = v;
1206 }
1207 }
1208 }
1209
1210 S2Point closest_point = S2EdgeUtil::GetClosestPoint(
1211 point,
1212 loop(min_loop_index)->vertex(min_vertex_index),
1213 loop(min_loop_index)->vertex(min_vertex_index + 1));
1214
1215 return closest_point;
1216 }
1217