1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 // Author: ericv@google.com (Eric Veach)
17
18 #include "s2/s2builder_graph.h"
19
20 #include <algorithm>
21 #include <limits>
22 #include <memory>
23 #include <numeric>
24 #include <vector>
25 #include "s2/base/logging.h"
26 #include "absl/container/btree_map.h"
27 #include "s2/id_set_lexicon.h"
28 #include "s2/s2builder.h"
29 #include "s2/s2error.h"
30 #include "s2/s2predicates.h"
31
32 using std::make_pair;
33 using std::max;
34 using std::min;
35 using std::pair;
36 using std::vector;
37
38 using Graph = S2Builder::Graph;
39 using GraphOptions = S2Builder::GraphOptions;
40 using DegenerateEdges = GraphOptions::DegenerateEdges;
41 using DuplicateEdges = GraphOptions::DuplicateEdges;
42 using SiblingPairs = GraphOptions::SiblingPairs;
43
Graph(const GraphOptions & options,const vector<S2Point> * vertices,const vector<Edge> * edges,const vector<InputEdgeIdSetId> * input_edge_id_set_ids,const IdSetLexicon * input_edge_id_set_lexicon,const vector<LabelSetId> * label_set_ids,const IdSetLexicon * label_set_lexicon,IsFullPolygonPredicate is_full_polygon_predicate)44 Graph::Graph(const GraphOptions& options,
45 const vector<S2Point>* vertices,
46 const vector<Edge>* edges,
47 const vector<InputEdgeIdSetId>* input_edge_id_set_ids,
48 const IdSetLexicon* input_edge_id_set_lexicon,
49 const vector<LabelSetId>* label_set_ids,
50 const IdSetLexicon* label_set_lexicon,
51 IsFullPolygonPredicate is_full_polygon_predicate)
52 : options_(options), num_vertices_(vertices->size()), vertices_(vertices),
53 edges_(edges), input_edge_id_set_ids_(input_edge_id_set_ids),
54 input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
55 label_set_ids_(label_set_ids),
56 label_set_lexicon_(label_set_lexicon),
57 is_full_polygon_predicate_(std::move(is_full_polygon_predicate)) {
58 S2_DCHECK(std::is_sorted(edges->begin(), edges->end()));
59 S2_DCHECK_EQ(edges->size(), input_edge_id_set_ids->size());
60 }
61
GetInEdgeIds() const62 vector<Graph::EdgeId> Graph::GetInEdgeIds() const {
63 vector<EdgeId> in_edge_ids(num_edges());
64 std::iota(in_edge_ids.begin(), in_edge_ids.end(), 0);
65 std::sort(in_edge_ids.begin(), in_edge_ids.end(),
66 [this](EdgeId ai, EdgeId bi) {
67 return StableLessThan(reverse(edge(ai)), reverse(edge(bi)), ai, bi);
68 });
69 return in_edge_ids;
70 }
71
GetSiblingMap() const72 vector<Graph::EdgeId> Graph::GetSiblingMap() const {
73 vector<EdgeId> in_edge_ids = GetInEdgeIds();
74 MakeSiblingMap(&in_edge_ids);
75 return in_edge_ids;
76 }
77
MakeSiblingMap(vector<Graph::EdgeId> * in_edge_ids) const78 void Graph::MakeSiblingMap(vector<Graph::EdgeId>* in_edge_ids) const {
79 S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
80 options_.sibling_pairs() == SiblingPairs::CREATE ||
81 options_.edge_type() == EdgeType::UNDIRECTED);
82 for (EdgeId e = 0; e < num_edges(); ++e) {
83 S2_DCHECK(edge(e) == reverse(edge((*in_edge_ids)[e])));
84 }
85 if (options_.edge_type() == EdgeType::DIRECTED) return;
86 if (options_.degenerate_edges() == DegenerateEdges::DISCARD) return;
87
88 for (EdgeId e = 0; e < num_edges(); ++e) {
89 VertexId v = edge(e).first;
90 if (edge(e).second == v) {
91 S2_DCHECK_LT(e + 1, num_edges());
92 S2_DCHECK_EQ(edge(e + 1).first, v);
93 S2_DCHECK_EQ(edge(e + 1).second, v);
94 S2_DCHECK_EQ((*in_edge_ids)[e], e);
95 S2_DCHECK_EQ((*in_edge_ids)[e + 1], e + 1);
96 (*in_edge_ids)[e] = e + 1;
97 (*in_edge_ids)[e + 1] = e;
98 ++e;
99 }
100 }
101 }
102
Init(const Graph & g)103 void Graph::VertexOutMap::Init(const Graph& g) {
104 edges_ = &g.edges();
105 edge_begins_.reserve(g.num_vertices() + 1);
106 EdgeId e = 0;
107 for (VertexId v = 0; v <= g.num_vertices(); ++v) {
108 while (e < g.num_edges() && g.edge(e).first < v) ++e;
109 edge_begins_.push_back(e);
110 }
111 }
112
Init(const Graph & g)113 void Graph::VertexInMap::Init(const Graph& g) {
114 in_edge_ids_ = g.GetInEdgeIds();
115 in_edge_begins_.reserve(g.num_vertices() + 1);
116 EdgeId e = 0;
117 for (VertexId v = 0; v <= g.num_vertices(); ++v) {
118 while (e < g.num_edges() && g.edge(in_edge_ids_[e]).second < v) ++e;
119 in_edge_begins_.push_back(e);
120 }
121 }
122
Init(const Graph & g,S2Builder::EdgeType edge_type)123 void Graph::LabelFetcher::Init(const Graph& g, S2Builder::EdgeType edge_type) {
124 g_ = &g;
125 edge_type_ = edge_type;
126 if (edge_type == EdgeType::UNDIRECTED) sibling_map_ = g.GetSiblingMap();
127 }
128
Fetch(EdgeId e,vector<S2Builder::Label> * labels)129 void Graph::LabelFetcher::Fetch(EdgeId e, vector<S2Builder::Label>* labels) {
130 labels->clear();
131 for (InputEdgeId input_edge_id : g_->input_edge_ids(e)) {
132 for (Label label : g_->labels(input_edge_id)) {
133 labels->push_back(label);
134 }
135 }
136 if (edge_type_ == EdgeType::UNDIRECTED) {
137 for (InputEdgeId input_edge_id : g_->input_edge_ids(sibling_map_[e])) {
138 for (Label label : g_->labels(input_edge_id)) {
139 labels->push_back(label);
140 }
141 }
142 }
143 if (labels->size() > 1) {
144 std::sort(labels->begin(), labels->end());
145 labels->erase(std::unique(labels->begin(), labels->end()), labels->end());
146 }
147 }
148
min_input_edge_id(EdgeId e) const149 S2Builder::InputEdgeId Graph::min_input_edge_id(EdgeId e) const {
150 IdSetLexicon::IdSet id_set = input_edge_ids(e);
151 return (id_set.size() == 0) ? kNoInputEdgeId : *id_set.begin();
152 }
153
GetMinInputEdgeIds() const154 vector<S2Builder::InputEdgeId> Graph::GetMinInputEdgeIds() const {
155 vector<InputEdgeId> min_input_ids(num_edges());
156 for (EdgeId e = 0; e < num_edges(); ++e) {
157 min_input_ids[e] = min_input_edge_id(e);
158 }
159 return min_input_ids;
160 }
161
GetInputEdgeOrder(const vector<InputEdgeId> & input_ids) const162 vector<Graph::EdgeId> Graph::GetInputEdgeOrder(
163 const vector<InputEdgeId>& input_ids) const {
164 vector<EdgeId> order(input_ids.size());
165 std::iota(order.begin(), order.end(), 0);
166 std::sort(order.begin(), order.end(), [&input_ids](EdgeId a, EdgeId b) {
167 // Comparison function ensures sort is stable.
168 return make_pair(input_ids[a], a) < make_pair(input_ids[b], b);
169 });
170 return order;
171 }
172
173 // A struct for sorting the incoming and outgoing edges around a vertex "v0".
174 struct VertexEdge {
VertexEdgeVertexEdge175 VertexEdge(bool _incoming, Graph::EdgeId _index,
176 Graph::VertexId _endpoint, int32 _rank)
177 : incoming(_incoming), index(_index),
178 endpoint(_endpoint), rank(_rank) {
179 }
180 bool incoming; // Is this an incoming edge to "v0"?
181 Graph::EdgeId index; // Index of this edge in "edges_" or "in_edge_ids"
182 Graph::VertexId endpoint; // The other (not "v0") endpoint of this edge
183 int32 rank; // Secondary key for edges with the same endpoint
184 };
185
186 // Given a set of duplicate outgoing edges (v0, v1) and a set of duplicate
187 // incoming edges (v1, v0), this method assigns each edge an integer "rank" so
188 // that the edges are sorted in a consistent order with respect to their
189 // orderings around "v0" and "v1". Usually there is just one edge, in which
190 // case this is easy. Sometimes there is one edge in each direction, in which
191 // case the outgoing edge is always ordered before the incoming edge.
192 //
193 // In general, we allow any number of duplicate edges in each direction, in
194 // which case outgoing edges are interleaved with incoming edges so as to
195 // create as many degenerate (two-edge) loops as possible. In order to get a
196 // consistent ordering around "v0" and "v1", we move forwards through the list
197 // of outgoing edges and backwards through the list of incoming edges. If
198 // there are more incoming edges, they go at the beginning of the ordering,
199 // while if there are more outgoing edges then they go at the end.
200 //
201 // For example, suppose there are 2 edges "a,b" from "v0" to "v1", and 4 edges
202 // "w,x,y,z" from "v1" to "v0". Using lower/upper case letters to represent
203 // incoming/outgoing edges, the clockwise ordering around v0 would be zyAxBw,
204 // and the clockwise ordering around v1 would be WbXaYZ. (Try making a
205 // diagram with each edge as a separate arc.)
AddVertexEdges(Graph::EdgeId out_begin,Graph::EdgeId out_end,Graph::EdgeId in_begin,Graph::EdgeId in_end,Graph::VertexId v1,vector<VertexEdge> * v0_edges)206 static void AddVertexEdges(Graph::EdgeId out_begin, Graph::EdgeId out_end,
207 Graph::EdgeId in_begin, Graph::EdgeId in_end,
208 Graph::VertexId v1, vector<VertexEdge>* v0_edges) {
209 int rank = 0;
210 // Any extra incoming edges go at the beginning of the ordering.
211 while (in_end - in_begin > out_end - out_begin) {
212 v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
213 }
214 // Next we interleave as many outgoing and incoming edges as possible.
215 while (in_end > in_begin) {
216 v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
217 v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
218 }
219 // Any extra outgoing edges to at the end of the ordering.
220 while (out_end > out_begin) {
221 v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
222 }
223 }
224
GetLeftTurnMap(const vector<EdgeId> & in_edge_ids,vector<EdgeId> * left_turn_map,S2Error * error) const225 bool Graph::GetLeftTurnMap(const vector<EdgeId>& in_edge_ids,
226 vector<EdgeId>* left_turn_map,
227 S2Error* error) const {
228 left_turn_map->assign(num_edges(), -1);
229 if (num_edges() == 0) return true;
230
231 // Declare vectors outside the loop to avoid reallocating them each time.
232 vector<VertexEdge> v0_edges;
233 vector<EdgeId> e_in, e_out;
234
235 // Walk through the two sorted arrays of edges (outgoing and incoming) and
236 // gather all the edges incident to each vertex. Then we sort those edges
237 // and add an entry to the left turn map from each incoming edge to the
238 // immediately following outgoing edge in clockwise order.
239 int out = 0, in = 0;
240 const Edge* out_edge = &edge(out);
241 const Edge* in_edge = &edge(in_edge_ids[in]);
242 Edge sentinel(num_vertices(), num_vertices());
243 Edge min_edge = min(*out_edge, reverse(*in_edge));
244 while (min_edge != sentinel) {
245 // Gather all incoming and outgoing edges around vertex "v0".
246 VertexId v0 = min_edge.first;
247 for (; min_edge.first == v0; min_edge = min(*out_edge, reverse(*in_edge))) {
248 VertexId v1 = min_edge.second;
249 // Count the number of copies of "min_edge" in each direction.
250 int out_begin = out, in_begin = in;
251 while (*out_edge == min_edge) {
252 out_edge = (++out == num_edges()) ? &sentinel : &edge(out);
253 }
254 while (reverse(*in_edge) == min_edge) {
255 in_edge = (++in == num_edges()) ? &sentinel : &edge(in_edge_ids[in]);
256 }
257 if (v0 != v1) {
258 AddVertexEdges(out_begin, out, in_begin, in, v1, &v0_edges);
259 } else {
260 // Each degenerate edge becomes its own loop.
261 for (; in_begin < in; ++in_begin) {
262 (*left_turn_map)[in_begin] = in_begin;
263 }
264 }
265 }
266 if (v0_edges.empty()) continue;
267
268 // Sort the edges in clockwise order around "v0".
269 VertexId min_endpoint = v0_edges.front().endpoint;
270 std::sort(v0_edges.begin() + 1, v0_edges.end(),
271 [v0, min_endpoint, this](const VertexEdge& a,
272 const VertexEdge& b) {
273 if (a.endpoint == b.endpoint) return a.rank < b.rank;
274 if (a.endpoint == min_endpoint) return true;
275 if (b.endpoint == min_endpoint) return false;
276 return !s2pred::OrderedCCW(vertex(a.endpoint), vertex(b.endpoint),
277 vertex(min_endpoint), vertex(v0));
278 });
279 // Match incoming with outgoing edges. We do this by keeping a stack of
280 // unmatched incoming edges. We also keep a stack of outgoing edges with
281 // no previous incoming edge, and match these at the end by wrapping
282 // around circularly to the start of the edge ordering.
283 for (const VertexEdge& e : v0_edges) {
284 if (e.incoming) {
285 e_in.push_back(in_edge_ids[e.index]);
286 } else if (!e_in.empty()) {
287 (*left_turn_map)[e_in.back()] = e.index;
288 e_in.pop_back();
289 } else {
290 e_out.push_back(e.index); // Matched below.
291 }
292 }
293 // Pair up additional edges using the fact that the ordering is circular.
294 std::reverse(e_out.begin(), e_out.end());
295 for (; !e_out.empty() && !e_in.empty(); e_out.pop_back(), e_in.pop_back()) {
296 (*left_turn_map)[e_in.back()] = e_out.back();
297 }
298 // We only need to process unmatched incoming edges, since we are only
299 // responsible for creating left turn map entries for those edges.
300 if (!e_in.empty() && error->ok()) {
301 error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
302 "Given edges do not form loops (indegree != outdegree)");
303 }
304 e_in.clear();
305 e_out.clear();
306 v0_edges.clear();
307 }
308 return error->ok();
309 }
310
CanonicalizeLoopOrder(const vector<InputEdgeId> & min_input_ids,vector<EdgeId> * loop)311 void Graph::CanonicalizeLoopOrder(const vector<InputEdgeId>& min_input_ids,
312 vector<EdgeId>* loop) {
313 if (loop->empty()) return;
314 // Find the position of the element with the highest input edge id. If
315 // there are multiple such elements together (i.e., the edge was split
316 // into several pieces by snapping it to several vertices), then we choose
317 // the last such position in cyclic order (this attempts to preserve the
318 // original loop order even when new vertices are added). For example, if
319 // the input edge id sequence is (7, 7, 4, 5, 6, 7) then we would rotate
320 // it to obtain (4, 5, 6, 7, 7, 7).
321
322 // The reason that we put the highest-numbered edge last, rather than the
323 // lowest-numbered edge first, is that S2Loop::Invert() reverses the loop
324 // edge order *except* for the last edge. For example, the loop ABCD (with
325 // edges AB, BC, CD, DA) becomes DCBA (with edges DC, CB, BA, AD). Note
326 // that the last edge is the same except for its direction (DA vs. AD).
327 // This has the advantage that if an undirected loop is assembled with the
328 // wrong orientation and later inverted (e.g. by S2Polygon::InitOriented),
329 // we still end up preserving the original cyclic vertex order.
330 int pos = 0;
331 bool saw_gap = false;
332 for (int i = 1; i < loop->size(); ++i) {
333 int cmp = min_input_ids[(*loop)[i]] - min_input_ids[(*loop)[pos]];
334 if (cmp < 0) {
335 saw_gap = true;
336 } else if (cmp > 0 || !saw_gap) {
337 pos = i;
338 saw_gap = false;
339 }
340 }
341 if (++pos == loop->size()) pos = 0; // Convert loop end to loop start.
342 std::rotate(loop->begin(), loop->begin() + pos, loop->end());
343 }
344
CanonicalizeVectorOrder(const vector<InputEdgeId> & min_input_ids,vector<vector<EdgeId>> * chains)345 void Graph::CanonicalizeVectorOrder(const vector<InputEdgeId>& min_input_ids,
346 vector<vector<EdgeId>>* chains) {
347 std::sort(chains->begin(), chains->end(),
348 [&min_input_ids](const vector<EdgeId>& a, const vector<EdgeId>& b) {
349 return min_input_ids[a[0]] < min_input_ids[b[0]];
350 });
351 }
352
GetDirectedLoops(LoopType loop_type,vector<EdgeLoop> * loops,S2Error * error) const353 bool Graph::GetDirectedLoops(LoopType loop_type, vector<EdgeLoop>* loops,
354 S2Error* error) const {
355 S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
356 options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
357 S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);
358
359 vector<EdgeId> left_turn_map;
360 if (!GetLeftTurnMap(GetInEdgeIds(), &left_turn_map, error)) return false;
361 vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
362
363 // If we are breaking loops at repeated vertices, we maintain a map from
364 // VertexId to its position in "path".
365 vector<int> path_index;
366 if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
367
368 // Visit edges in arbitrary order, and try to build a loop from each edge.
369 vector<EdgeId> path;
370 for (EdgeId start = 0; start < num_edges(); ++start) {
371 if (left_turn_map[start] < 0) continue;
372
373 // Build a loop by making left turns at each vertex until we return to
374 // "start". We use "left_turn_map" to keep track of which edges have
375 // already been visited by setting its entries to -1 as we go along. If
376 // we are building vertex cycles, then whenever we encounter a vertex that
377 // is already part of the path, we "peel off" a loop by removing those
378 // edges from the path so far.
379 for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
380 path.push_back(e);
381 next = left_turn_map[e];
382 left_turn_map[e] = -1;
383 if (loop_type == LoopType::SIMPLE) {
384 path_index[edge(e).first] = path.size() - 1;
385 int loop_start = path_index[edge(e).second];
386 if (loop_start < 0) continue;
387 // Peel off a loop from the path.
388 vector<EdgeId> loop(path.begin() + loop_start, path.end());
389 path.erase(path.begin() + loop_start, path.end());
390 for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
391 CanonicalizeLoopOrder(min_input_ids, &loop);
392 loops->push_back(std::move(loop));
393 }
394 }
395 if (loop_type == LoopType::SIMPLE) {
396 S2_DCHECK(path.empty()); // Invariant.
397 } else {
398 CanonicalizeLoopOrder(min_input_ids, &path);
399 loops->push_back(std::move(path));
400 path.clear();
401 }
402 }
403 CanonicalizeVectorOrder(min_input_ids, loops);
404 return true;
405 }
406
GetDirectedComponents(DegenerateBoundaries degenerate_boundaries,vector<DirectedComponent> * components,S2Error * error) const407 bool Graph::GetDirectedComponents(
408 DegenerateBoundaries degenerate_boundaries,
409 vector<DirectedComponent>* components, S2Error* error) const {
410 S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
411 (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
412 degenerate_boundaries == DegenerateBoundaries::KEEP));
413 S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
414 options_.sibling_pairs() == SiblingPairs::CREATE);
415 S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED); // Implied by above.
416
417 vector<EdgeId> sibling_map = GetInEdgeIds();
418 vector<EdgeId> left_turn_map;
419 if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
420 MakeSiblingMap(&sibling_map);
421 vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
422 vector<EdgeId> frontier; // Unexplored sibling edges.
423
424 // A map from EdgeId to the position of that edge in "path". Only needed if
425 // degenerate boundaries are being discarded.
426 vector<int> path_index;
427 if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
428 path_index.assign(num_edges(), -1);
429 }
430 for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
431 if (left_turn_map[min_start] < 0) continue; // Already used.
432
433 // Build a connected component by keeping a stack of unexplored siblings
434 // of the edges used so far.
435 DirectedComponent component;
436 frontier.push_back(min_start);
437 while (!frontier.empty()) {
438 EdgeId start = frontier.back();
439 frontier.pop_back();
440 if (left_turn_map[start] < 0) continue; // Already used.
441
442 // Build a path by making left turns at each vertex until we return to
443 // "start". Whenever we encounter an edge that is a sibling of an edge
444 // that is already on the path, we "peel off" a loop consisting of any
445 // edges that were between these two edges.
446 vector<EdgeId> path;
447 for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
448 path.push_back(e);
449 next = left_turn_map[e];
450 left_turn_map[e] = -1;
451 // If the sibling hasn't been visited yet, add it to the frontier.
452 EdgeId sibling = sibling_map[e];
453 if (left_turn_map[sibling] >= 0) {
454 frontier.push_back(sibling);
455 }
456 if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
457 path_index[e] = path.size() - 1;
458 int sibling_index = path_index[sibling];
459 if (sibling_index < 0) continue;
460
461 // Common special case: the edge and its sibling are adjacent, in
462 // which case we can simply remove them from the path and continue.
463 if (sibling_index == path.size() - 2) {
464 path.resize(sibling_index);
465 // We don't need to update "path_index" for these two edges
466 // because both edges of the sibling pair have now been used.
467 continue;
468 }
469 // Peel off a loop from the path.
470 vector<EdgeId> loop(path.begin() + sibling_index + 1, path.end() - 1);
471 path.erase(path.begin() + sibling_index, path.end());
472 // Mark the edges that are no longer part of the path.
473 for (EdgeId e2 : loop) path_index[e2] = -1;
474 CanonicalizeLoopOrder(min_input_ids, &loop);
475 component.push_back(std::move(loop));
476 }
477 }
478 // Mark the edges that are no longer part of the path.
479 if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
480 for (EdgeId e2 : path) path_index[e2] = -1;
481 }
482 CanonicalizeLoopOrder(min_input_ids, &path);
483 component.push_back(std::move(path));
484 }
485 CanonicalizeVectorOrder(min_input_ids, &component);
486 components->push_back(std::move(component));
487 }
488 // Sort the components to correspond to the input edge ordering.
489 std::sort(components->begin(), components->end(),
490 [&min_input_ids](const DirectedComponent& a,
491 const DirectedComponent& b) {
492 return min_input_ids[a[0][0]] < min_input_ids[b[0][0]];
493 });
494 return true;
495 }
496
497 // Encodes the index of one of the two complements of each component
498 // (a.k.a. the "slot", either 0 or 1) as a negative EdgeId.
MarkEdgeUsed(int slot)499 inline static Graph::EdgeId MarkEdgeUsed(int slot) { return -1 - slot; }
500
GetUndirectedComponents(LoopType loop_type,vector<UndirectedComponent> * components,S2Error * error) const501 bool Graph::GetUndirectedComponents(LoopType loop_type,
502 vector<UndirectedComponent>* components,
503 S2Error* error) const {
504 S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
505 options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
506 S2_DCHECK(options_.edge_type() == EdgeType::UNDIRECTED);
507
508 vector<EdgeId> sibling_map = GetInEdgeIds();
509 vector<EdgeId> left_turn_map;
510 if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
511 MakeSiblingMap(&sibling_map);
512 vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
513
514 // A stack of unexplored sibling edges. Each sibling edge has a "slot"
515 // (0 or 1) that indicates which of the two complements it belongs to.
516 vector<pair<EdgeId, int>> frontier;
517
518 // If we are breaking loops at repeated vertices, we maintain a map from
519 // VertexId to its position in "path".
520 vector<int> path_index;
521 if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
522
523 for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
524 if (left_turn_map[min_start] < 0) continue; // Already used.
525
526 // Build a connected component by keeping a stack of unexplored siblings
527 // of the edges used so far.
528 UndirectedComponent component;
529 frontier.push_back(make_pair(min_start, 0));
530 while (!frontier.empty()) {
531 EdgeId start = frontier.back().first;
532 int slot = frontier.back().second;
533 frontier.pop_back();
534 if (left_turn_map[start] < 0) continue; // Already used.
535
536 // Build a path by making left turns at each vertex until we return to
537 // "start". We use "left_turn_map" to keep track of which edges have
538 // already been visited, and which complement they were assigned to, by
539 // setting its entries to negative values as we go along.
540 vector<EdgeId> path;
541 for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
542 path.push_back(e);
543 next = left_turn_map[e];
544 left_turn_map[e] = MarkEdgeUsed(slot);
545 // If the sibling hasn't been visited yet, add it to the frontier.
546 EdgeId sibling = sibling_map[e];
547 if (left_turn_map[sibling] >= 0) {
548 frontier.push_back(make_pair(sibling, 1 - slot));
549 } else if (left_turn_map[sibling] != MarkEdgeUsed(1 - slot)) {
550 // Two siblings edges can only belong the same complement if the
551 // given undirected edges do not form loops.
552 error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
553 "Given undirected edges do not form loops");
554 return false;
555 }
556 if (loop_type == LoopType::SIMPLE) {
557 // Whenever we encounter a vertex that is already part of the path,
558 // we "peel off" a loop by removing those edges from the path.
559 path_index[edge(e).first] = path.size() - 1;
560 int loop_start = path_index[edge(e).second];
561 if (loop_start < 0) continue;
562 vector<EdgeId> loop(path.begin() + loop_start, path.end());
563 path.erase(path.begin() + loop_start, path.end());
564 // Mark the vertices that are no longer part of the path.
565 for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
566 CanonicalizeLoopOrder(min_input_ids, &loop);
567 component[slot].push_back(std::move(loop));
568 }
569 }
570 if (loop_type == LoopType::SIMPLE) {
571 S2_DCHECK(path.empty()); // Invariant.
572 } else {
573 CanonicalizeLoopOrder(min_input_ids, &path);
574 component[slot].push_back(std::move(path));
575 }
576 }
577 CanonicalizeVectorOrder(min_input_ids, &component[0]);
578 CanonicalizeVectorOrder(min_input_ids, &component[1]);
579 // To save some work in S2PolygonLayer, we swap the two loop sets of the
580 // component so that the loop set whose first loop most closely follows
581 // the input edge ordering is first. (If the input was a valid S2Polygon,
582 // then this component will contain normalized loops.)
583 if (min_input_ids[component[0][0][0]] > min_input_ids[component[1][0][0]]) {
584 component[0].swap(component[1]);
585 }
586 components->push_back(std::move(component));
587 }
588 // Sort the components to correspond to the input edge ordering.
589 std::sort(components->begin(), components->end(),
590 [&min_input_ids](const UndirectedComponent& a,
591 const UndirectedComponent& b) {
592 return min_input_ids[a[0][0][0]] < min_input_ids[b[0][0][0]];
593 });
594 return true;
595 }
596
597 class Graph::PolylineBuilder {
598 public:
599 explicit PolylineBuilder(const Graph& g);
600 vector<EdgePolyline> BuildPaths();
601 vector<EdgePolyline> BuildWalks();
602
603 private:
604 bool is_interior(VertexId v);
605 int excess_degree(VertexId v);
606 EdgePolyline BuildPath(EdgeId e);
607 EdgePolyline BuildWalk(VertexId v);
608 void MaximizeWalk(EdgePolyline* polyline);
609
610 const Graph& g_;
611 Graph::VertexInMap in_;
612 Graph::VertexOutMap out_;
613 vector<EdgeId> sibling_map_;
614 vector<InputEdgeId> min_input_ids_;
615 bool directed_;
616 int edges_left_;
617 vector<bool> used_;
618 // A map of (outdegree(v) - indegree(v)) considering used edges only.
619 absl::btree_map<VertexId, int> excess_used_;
620 };
621
GetPolylines(PolylineType polyline_type) const622 vector<Graph::EdgePolyline> Graph::GetPolylines(
623 PolylineType polyline_type) const {
624 S2_DCHECK(options_.sibling_pairs() == SiblingPairs::DISCARD ||
625 options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS ||
626 options_.sibling_pairs() == SiblingPairs::KEEP);
627 PolylineBuilder builder(*this);
628 if (polyline_type == PolylineType::PATH) {
629 return builder.BuildPaths();
630 } else {
631 return builder.BuildWalks();
632 }
633 }
634
PolylineBuilder(const Graph & g)635 Graph::PolylineBuilder::PolylineBuilder(const Graph& g)
636 : g_(g), in_(g), out_(g),
637 min_input_ids_(g.GetMinInputEdgeIds()),
638 directed_(g_.options().edge_type() == EdgeType::DIRECTED),
639 edges_left_(g.num_edges() / (directed_ ? 1 : 2)),
640 used_(g.num_edges(), false) {
641 if (!directed_) {
642 sibling_map_ = in_.in_edge_ids();
643 g.MakeSiblingMap(&sibling_map_);
644 }
645 }
646
is_interior(VertexId v)647 inline bool Graph::PolylineBuilder::is_interior(VertexId v) {
648 if (directed_) {
649 return in_.degree(v) == 1 && out_.degree(v) == 1;
650 } else {
651 return out_.degree(v) == 2;
652 }
653 }
654
excess_degree(VertexId v)655 inline int Graph::PolylineBuilder::excess_degree(VertexId v) {
656 return directed_ ? out_.degree(v) - in_.degree(v) : out_.degree(v) % 2;
657 }
658
BuildPaths()659 vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildPaths() {
660 // First build polylines starting at all the vertices that cannot be in the
661 // polyline interior (i.e., indegree != 1 or outdegree != 1 for directed
662 // edges, or degree != 2 for undirected edges). We consider the possible
663 // starting edges in input edge id order so that we preserve the input path
664 // direction even when undirected edges are used. (Undirected edges are
665 // represented by sibling pairs where only the edge in the input direction
666 // is labeled with an input edge id.)
667 vector<EdgePolyline> polylines;
668 vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
669 for (EdgeId e : edges) {
670 if (!used_[e] && !is_interior(g_.edge(e).first)) {
671 polylines.push_back(BuildPath(e));
672 }
673 }
674 // If there are any edges left, they form non-intersecting loops. We build
675 // each loop and then canonicalize its edge order. We consider candidate
676 // starting edges in input edge id order in order to preserve the input
677 // direction of undirected loops. Even so, we still need to canonicalize
678 // the edge order to ensure that when an input edge is split into an edge
679 // chain, the loop does not start in the middle of such a chain.
680 for (EdgeId e : edges) {
681 if (edges_left_ == 0) break;
682 if (used_[e]) continue;
683 EdgePolyline polyline = BuildPath(e);
684 CanonicalizeLoopOrder(min_input_ids_, &polyline);
685 polylines.push_back(std::move(polyline));
686 }
687 S2_DCHECK_EQ(0, edges_left_);
688
689 // Sort the polylines to correspond to the input order (if possible).
690 CanonicalizeVectorOrder(min_input_ids_, &polylines);
691 return polylines;
692 }
693
BuildPath(EdgeId e)694 Graph::EdgePolyline Graph::PolylineBuilder::BuildPath(EdgeId e) {
695 // We simply follow edges until either we reach a vertex where there is a
696 // choice about which way to go (where is_interior(v) is false), or we
697 // return to the starting vertex (if the polyline is actually a loop).
698 EdgePolyline polyline;
699 VertexId start = g_.edge(e).first;
700 for (;;) {
701 polyline.push_back(e);
702 S2_DCHECK(!used_[e]);
703 used_[e] = true;
704 if (!directed_) used_[sibling_map_[e]] = true;
705 --edges_left_;
706 VertexId v = g_.edge(e).second;
707 if (!is_interior(v) || v == start) break;
708 if (directed_) {
709 S2_DCHECK_EQ(1, out_.degree(v));
710 e = *out_.edge_ids(v).begin();
711 } else {
712 S2_DCHECK_EQ(2, out_.degree(v));
713 for (EdgeId e2 : out_.edge_ids(v)) if (!used_[e2]) e = e2;
714 }
715 }
716 return polyline;
717 }
718
BuildWalks()719 vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildWalks() {
720 // Note that some of this code is worst-case quadratic in the maximum vertex
721 // degree. This could be fixed with a few extra arrays, but it should not
722 // be a problem in practice.
723
724 // First, build polylines from all vertices where outdegree > indegree (or
725 // for undirected edges, vertices whose degree is odd). We consider the
726 // possible starting edges in input edge id order, for idempotency in the
727 // case where multiple input polylines share vertices or edges.
728 vector<EdgePolyline> polylines;
729 vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
730 for (EdgeId e : edges) {
731 if (used_[e]) continue;
732 VertexId v = g_.edge(e).first;
733 int excess = excess_degree(v);
734 if (excess <= 0) continue;
735 excess -= excess_used_[v];
736 if (directed_ ? (excess <= 0) : (excess % 2 == 0)) continue;
737 ++excess_used_[v];
738 polylines.push_back(BuildWalk(v));
739 --excess_used_[g_.edge(polylines.back().back()).second];
740 }
741 // Now all vertices have outdegree == indegree (or even degree if undirected
742 // edges are being used). Therefore all remaining edges can be assembled
743 // into loops. We first try to expand the existing polylines if possible by
744 // adding loops to them.
745 if (edges_left_ > 0) {
746 for (EdgePolyline& polyline : polylines) {
747 MaximizeWalk(&polyline);
748 }
749 }
750 // Finally, if there are still unused edges then we build loops. If the
751 // input is a polyline that forms a loop, then for idempotency we need to
752 // start from the edge with minimum input edge id. If the minimal input
753 // edge was split into several edges, then we start from the first edge of
754 // the chain.
755 for (int i = 0; i < edges.size() && edges_left_ > 0; ++i) {
756 EdgeId e = edges[i];
757 if (used_[e]) continue;
758
759 // Determine whether the origin of this edge is the start of an edge
760 // chain. To do this, we test whether (outdegree - indegree == 1) for the
761 // origin, considering only unused edges with the same minimum input edge
762 // id. (Undirected edges have input edge ids in one direction only.)
763 VertexId v = g_.edge(e).first;
764 InputEdgeId id = min_input_ids_[e];
765 int excess = 0;
766 for (int j = i; j < edges.size() && min_input_ids_[edges[j]] == id; ++j) {
767 EdgeId e2 = edges[j];
768 if (used_[e2]) continue;
769 if (g_.edge(e2).first == v) ++excess;
770 if (g_.edge(e2).second == v) --excess;
771 }
772 // It is also acceptable to start a polyline from any degenerate edge.
773 if (excess == 1 || g_.edge(e).second == v) {
774 EdgePolyline polyline = BuildWalk(v);
775 MaximizeWalk(&polyline);
776 polylines.push_back(std::move(polyline));
777 }
778 }
779 S2_DCHECK_EQ(0, edges_left_);
780
781 // Sort the polylines to correspond to the input order (if possible).
782 CanonicalizeVectorOrder(min_input_ids_, &polylines);
783 return polylines;
784 }
785
BuildWalk(VertexId v)786 Graph::EdgePolyline Graph::PolylineBuilder::BuildWalk(VertexId v) {
787 EdgePolyline polyline;
788 for (;;) {
789 // Follow the edge with the smallest input edge id.
790 EdgeId best_edge = -1;
791 InputEdgeId best_out_id = std::numeric_limits<InputEdgeId>::max();
792 for (EdgeId e : out_.edge_ids(v)) {
793 if (used_[e] || min_input_ids_[e] >= best_out_id) continue;
794 best_out_id = min_input_ids_[e];
795 best_edge = e;
796 }
797 if (best_edge < 0) return polyline;
798 // For idempotency when there are multiple input polylines, we stop the
799 // walk early if "best_edge" might be a continuation of a different
800 // incoming edge.
801 int excess = excess_degree(v) - excess_used_[v];
802 if (directed_ ? (excess < 0) : (excess % 2) == 1) {
803 for (EdgeId e : in_.edge_ids(v)) {
804 if (!used_[e] && min_input_ids_[e] <= best_out_id) {
805 return polyline;
806 }
807 }
808 }
809 polyline.push_back(best_edge);
810 used_[best_edge] = true;
811 if (!directed_) used_[sibling_map_[best_edge]] = true;
812 --edges_left_;
813 v = g_.edge(best_edge).second;
814 }
815 }
816
MaximizeWalk(EdgePolyline * polyline)817 void Graph::PolylineBuilder::MaximizeWalk(EdgePolyline* polyline) {
818 // Examine all vertices of the polyline and check whether there are any
819 // unused outgoing edges. If so, then build a loop starting at that vertex
820 // and insert it into the polyline. (The walk is guaranteed to be a loop
821 // because this method is only called when all vertices have equal numbers
822 // of unused incoming and outgoing edges.)
823 for (int i = 0; i <= polyline->size(); ++i) {
824 VertexId v = (i == 0 ? g_.edge((*polyline)[i]).first
825 : g_.edge((*polyline)[i - 1]).second);
826 for (EdgeId e : out_.edge_ids(v)) {
827 if (!used_[e]) {
828 EdgePolyline loop = BuildWalk(v);
829 S2_DCHECK_EQ(v, g_.edge(loop.back()).second);
830 polyline->insert(polyline->begin() + i, loop.begin(), loop.end());
831 S2_DCHECK(used_[e]); // All outgoing edges from "v" are now used.
832 break;
833 }
834 }
835 }
836 }
837
838 class Graph::EdgeProcessor {
839 public:
840 EdgeProcessor(const GraphOptions& options,
841 vector<Edge>* edges,
842 vector<InputEdgeIdSetId>* input_ids,
843 IdSetLexicon* id_set_lexicon);
844 void Run(S2Error* error);
845
846 private:
847 void AddEdge(const Edge& edge, InputEdgeIdSetId input_edge_id_set_id);
848 void AddEdges(int num_edges, const Edge& edge,
849 InputEdgeIdSetId input_edge_id_set_id);
850 void CopyEdges(int out_begin, int out_end);
851 InputEdgeIdSetId MergeInputIds(int out_begin, int out_end);
852
853 GraphOptions options_;
854 vector<Edge>& edges_;
855 vector<InputEdgeIdSetId>& input_ids_;
856 IdSetLexicon* id_set_lexicon_;
857 vector<EdgeId> out_edges_;
858 vector<EdgeId> in_edges_;
859
860 vector<Edge> new_edges_;
861 vector<InputEdgeIdSetId> new_input_ids_;
862
863 vector<InputEdgeId> tmp_ids_;
864 };
865
ProcessEdges(GraphOptions * options,std::vector<Edge> * edges,std::vector<InputEdgeIdSetId> * input_ids,IdSetLexicon * id_set_lexicon,S2Error * error)866 void Graph::ProcessEdges(
867 GraphOptions* options, std::vector<Edge>* edges,
868 std::vector<InputEdgeIdSetId>* input_ids, IdSetLexicon* id_set_lexicon,
869 S2Error* error) {
870 EdgeProcessor processor(*options, edges, input_ids, id_set_lexicon);
871 processor.Run(error);
872 // Certain values of sibling_pairs() discard half of the edges and change
873 // the edge_type() to DIRECTED (see the description of GraphOptions).
874 if (options->sibling_pairs() == SiblingPairs::REQUIRE ||
875 options->sibling_pairs() == SiblingPairs::CREATE) {
876 options->set_edge_type(EdgeType::DIRECTED);
877 }
878 }
879
EdgeProcessor(const GraphOptions & options,vector<Edge> * edges,vector<InputEdgeIdSetId> * input_ids,IdSetLexicon * id_set_lexicon)880 Graph::EdgeProcessor::EdgeProcessor(const GraphOptions& options,
881 vector<Edge>* edges,
882 vector<InputEdgeIdSetId>* input_ids,
883 IdSetLexicon* id_set_lexicon)
884 : options_(options), edges_(*edges),
885 input_ids_(*input_ids), id_set_lexicon_(id_set_lexicon),
886 out_edges_(edges_.size()), in_edges_(edges_.size()) {
887 // Sort the outgoing and incoming edges in lexigraphic order. We use a
888 // stable sort to ensure that each undirected edge becomes a sibling pair,
889 // even if there are multiple identical input edges.
890 std::iota(out_edges_.begin(), out_edges_.end(), 0);
891 std::sort(out_edges_.begin(), out_edges_.end(), [this](EdgeId a, EdgeId b) {
892 return StableLessThan(edges_[a], edges_[b], a, b);
893 });
894 std::iota(in_edges_.begin(), in_edges_.end(), 0);
895 std::sort(in_edges_.begin(), in_edges_.end(), [this](EdgeId a, EdgeId b) {
896 return StableLessThan(reverse(edges_[a]), reverse(edges_[b]), a, b);
897 });
898 new_edges_.reserve(edges_.size());
899 new_input_ids_.reserve(edges_.size());
900 }
901
AddEdge(const Edge & edge,InputEdgeIdSetId input_edge_id_set_id)902 inline void Graph::EdgeProcessor::AddEdge(
903 const Edge& edge, InputEdgeIdSetId input_edge_id_set_id) {
904 new_edges_.push_back(edge);
905 new_input_ids_.push_back(input_edge_id_set_id);
906 }
907
AddEdges(int num_edges,const Edge & edge,InputEdgeIdSetId input_edge_id_set_id)908 void Graph::EdgeProcessor::AddEdges(int num_edges, const Edge& edge,
909 InputEdgeIdSetId input_edge_id_set_id) {
910 for (int i = 0; i < num_edges; ++i) {
911 AddEdge(edge, input_edge_id_set_id);
912 }
913 }
914
CopyEdges(int out_begin,int out_end)915 void Graph::EdgeProcessor::CopyEdges(int out_begin, int out_end) {
916 for (int i = out_begin; i < out_end; ++i) {
917 AddEdge(edges_[out_edges_[i]], input_ids_[out_edges_[i]]);
918 }
919 }
920
MergeInputIds(int out_begin,int out_end)921 S2Builder::InputEdgeIdSetId Graph::EdgeProcessor::MergeInputIds(
922 int out_begin, int out_end) {
923 if (out_end - out_begin == 1) {
924 return input_ids_[out_edges_[out_begin]];
925 }
926 tmp_ids_.clear();
927 for (int i = out_begin; i < out_end; ++i) {
928 for (auto id : id_set_lexicon_->id_set(input_ids_[out_edges_[i]])) {
929 tmp_ids_.push_back(id);
930 }
931 }
932 return id_set_lexicon_->Add(tmp_ids_);
933 }
934
Run(S2Error * error)935 void Graph::EdgeProcessor::Run(S2Error* error) {
936 int num_edges = edges_.size();
937 if (num_edges == 0) return;
938
939 // Walk through the two sorted arrays performing a merge join. For each
940 // edge, gather all the duplicate copies of the edge in both directions
941 // (outgoing and incoming). Then decide what to do based on "options_" and
942 // how many copies of the edge there are in each direction.
943 int out = 0, in = 0;
944 const Edge* out_edge = &edges_[out_edges_[out]];
945 const Edge* in_edge = &edges_[in_edges_[in]];
946 Edge sentinel(std::numeric_limits<VertexId>::max(),
947 std::numeric_limits<VertexId>::max());
948 for (;;) {
949 Edge edge = min(*out_edge, reverse(*in_edge));
950 if (edge == sentinel) break;
951
952 int out_begin = out, in_begin = in;
953 while (*out_edge == edge) {
954 out_edge = (++out == num_edges) ? &sentinel : &edges_[out_edges_[out]];
955 }
956 while (reverse(*in_edge) == edge) {
957 in_edge = (++in == num_edges) ? &sentinel : &edges_[in_edges_[in]];
958 }
959 int n_out = out - out_begin;
960 int n_in = in - in_begin;
961 if (edge.first == edge.second) {
962 S2_DCHECK_EQ(n_out, n_in);
963 if (options_.degenerate_edges() == DegenerateEdges::DISCARD) {
964 continue;
965 }
966 if (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
967 ((out_begin > 0 &&
968 edges_[out_edges_[out_begin - 1]].first == edge.first) ||
969 (out < num_edges && edges_[out_edges_[out]].first == edge.first) ||
970 (in_begin > 0 &&
971 edges_[in_edges_[in_begin - 1]].second == edge.first) ||
972 (in < num_edges && edges_[in_edges_[in]].second == edge.first))) {
973 continue; // There were non-degenerate incident edges, so discard.
974 }
975 if (options_.edge_type() == EdgeType::UNDIRECTED &&
976 (options_.sibling_pairs() == SiblingPairs::REQUIRE ||
977 options_.sibling_pairs() == SiblingPairs::CREATE)) {
978 // When we have undirected edges and are guaranteed to have siblings,
979 // we cut the number of edges in half (see s2builder.h).
980 S2_DCHECK_EQ(0, n_out & 1); // Number of edges is always even.
981 AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
982 1 : (n_out / 2), edge, MergeInputIds(out_begin, out));
983 } else if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
984 AddEdges(options_.edge_type() == EdgeType::UNDIRECTED ? 2 : 1,
985 edge, MergeInputIds(out_begin, out));
986 } else if (options_.sibling_pairs() == SiblingPairs::DISCARD ||
987 options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
988 // Any SiblingPair option that discards edges causes the labels of all
989 // duplicate edges to be merged together (see s2builder.h).
990 AddEdges(n_out, edge, MergeInputIds(out_begin, out));
991 } else {
992 CopyEdges(out_begin, out);
993 }
994 } else if (options_.sibling_pairs() == SiblingPairs::KEEP) {
995 if (n_out > 1 && options_.duplicate_edges() == DuplicateEdges::MERGE) {
996 AddEdge(edge, MergeInputIds(out_begin, out));
997 } else {
998 CopyEdges(out_begin, out);
999 }
1000 } else if (options_.sibling_pairs() == SiblingPairs::DISCARD) {
1001 if (options_.edge_type() == EdgeType::DIRECTED) {
1002 // If n_out == n_in: balanced sibling pairs
1003 // If n_out < n_in: unbalanced siblings, in the form AB, BA, BA
1004 // If n_out > n_in: unbalanced siblings, in the form AB, AB, BA
1005 if (n_out <= n_in) continue;
1006 // Any option that discards edges causes the labels of all duplicate
1007 // edges to be merged together (see s2builder.h).
1008 AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
1009 1 : (n_out - n_in), edge, MergeInputIds(out_begin, out));
1010 } else {
1011 if ((n_out & 1) == 0) continue;
1012 AddEdge(edge, MergeInputIds(out_begin, out));
1013 }
1014 } else if (options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
1015 if (options_.edge_type() == EdgeType::DIRECTED) {
1016 // See comments above. The only difference is that if there are
1017 // balanced sibling pairs, we want to keep one such pair.
1018 if (n_out < n_in) continue;
1019 AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
1020 1 : max(1, n_out - n_in), edge, MergeInputIds(out_begin, out));
1021 } else {
1022 AddEdges((n_out & 1) ? 1 : 2, edge, MergeInputIds(out_begin, out));
1023 }
1024 } else {
1025 S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
1026 options_.sibling_pairs() == SiblingPairs::CREATE);
1027 if (error->ok() && options_.sibling_pairs() == SiblingPairs::REQUIRE &&
1028 (options_.edge_type() == EdgeType::DIRECTED ? (n_out != n_in)
1029 : ((n_out & 1) != 0))) {
1030 error->Init(S2Error::BUILDER_MISSING_EXPECTED_SIBLING_EDGES,
1031 "Expected all input edges to have siblings, "
1032 "but some were missing");
1033 }
1034 if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
1035 AddEdge(edge, MergeInputIds(out_begin, out));
1036 } else if (options_.edge_type() == EdgeType::UNDIRECTED) {
1037 // Convert graph to use directed edges instead (see documentation of
1038 // REQUIRE/CREATE for undirected edges).
1039 AddEdges((n_out + 1) / 2, edge, MergeInputIds(out_begin, out));
1040 } else {
1041 CopyEdges(out_begin, out);
1042 if (n_in > n_out) {
1043 // Automatically created edges have no input edge ids or labels.
1044 AddEdges(n_in - n_out, edge, IdSetLexicon::EmptySetId());
1045 }
1046 }
1047 }
1048 }
1049 edges_.swap(new_edges_);
1050 edges_.shrink_to_fit();
1051 input_ids_.swap(new_input_ids_);
1052 input_ids_.shrink_to_fit();
1053 }
1054
FilterVertices(const vector<S2Point> & vertices,std::vector<Edge> * edges,vector<VertexId> * tmp)1055 vector<S2Point> Graph::FilterVertices(const vector<S2Point>& vertices,
1056 std::vector<Edge>* edges,
1057 vector<VertexId>* tmp) {
1058 // Gather the vertices that are actually used.
1059 vector<VertexId> used;
1060 used.reserve(2 * edges->size());
1061 for (const Edge& e : *edges) {
1062 used.push_back(e.first);
1063 used.push_back(e.second);
1064 }
1065 // Sort the vertices and find the distinct ones.
1066 std::sort(used.begin(), used.end());
1067 used.erase(std::unique(used.begin(), used.end()), used.end());
1068
1069 // Build the list of new vertices, and generate a map from old vertex id to
1070 // new vertex id.
1071 vector<VertexId>& vmap = *tmp;
1072 vmap.resize(vertices.size());
1073 vector<S2Point> new_vertices(used.size());
1074 for (int i = 0; i < used.size(); ++i) {
1075 new_vertices[i] = vertices[used[i]];
1076 vmap[used[i]] = i;
1077 }
1078 // Update the edges.
1079 for (Edge& e : *edges) {
1080 e.first = vmap[e.first];
1081 e.second = vmap[e.second];
1082 }
1083 return new_vertices;
1084 }
1085