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