1 /*
2 * vim: ts=4 sw=4 et tw=0 wm=0
3 *
4 * libavoid - Fast, Incremental, Object-avoiding Line Router
5 *
6 * Copyright (C) 2011-2014 Monash University
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 * See the file LICENSE.LGPL distributed with the library.
13 *
14 * Licensees holding a valid commercial license may use this file in
15 * accordance with the commercial license agreement provided with the
16 * library.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 *
22 * Author(s): Michael Wybrow
23 */
24
25 #include <algorithm>
26
27 #include "libavoid/hyperedgetree.h"
28 #include "libavoid/geometry.h"
29 #include "libavoid/connector.h"
30 #include "libavoid/router.h"
31 #include "libavoid/connend.h"
32 #include "libavoid/assertions.h"
33 #include "libavoid/junction.h"
34 #include "libavoid/debughandler.h"
35
36 namespace Avoid {
37
38
39 // Constructs a new hyperedge tree node.
40 //
HyperedgeTreeNode()41 HyperedgeTreeNode::HyperedgeTreeNode()
42 : junction(nullptr),
43 shiftSegmentNodeSet(nullptr),
44 finalVertex(nullptr),
45 isConnectorSource(false),
46 isPinDummyEndpoint(false),
47 visited(false)
48 {
49 }
50
~HyperedgeTreeNode()51 HyperedgeTreeNode::~HyperedgeTreeNode()
52 {
53 if (shiftSegmentNodeSet)
54 {
55 shiftSegmentNodeSet->erase(this);
56 shiftSegmentNodeSet = nullptr;
57 }
58 }
59
60
61 // This method traverses the hyperedge tree and outputs each of the edges
62 // and junction positions as SVG objects to the file fp.
63 //
outputEdgesExcept(FILE * fp,HyperedgeTreeEdge * ignored)64 void HyperedgeTreeNode::outputEdgesExcept(FILE *fp, HyperedgeTreeEdge *ignored)
65 {
66 if (junction)
67 {
68 fprintf(fp, "<circle cx=\"%g\" cy=\"%g\" r=\"6\" "
69 "style=\"fill: green; stroke: none;\" />\n", point.x, point.y);
70 }
71 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
72 curr != edges.end(); ++curr)
73 {
74 if (*curr != ignored)
75 {
76 (*curr)->outputNodesExcept(fp, this);
77 }
78 }
79 }
80
81
82 // This method traverses the hyperedge tree and removes from treeRoots any
83 // junction nodes (other than this one).
84
removeOtherJunctionsFrom(HyperedgeTreeEdge * ignored,JunctionSet & treeRoots)85 bool HyperedgeTreeNode::removeOtherJunctionsFrom(HyperedgeTreeEdge *ignored,
86 JunctionSet& treeRoots)
87 {
88 bool containsCycle = false;
89 if (visited)
90 {
91 // We've encountered this node before, so there must be cycles in
92 // the hyperedge. Don't recurse any further.
93 containsCycle = true;
94 return containsCycle;
95 }
96
97 if (junction && (ignored != nullptr))
98 {
99 // Remove junctions other than the first (when ignored == nullptr).
100 treeRoots.erase(junction);
101 }
102 visited = true;
103 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
104 curr != edges.end(); ++curr)
105 {
106 if (*curr != ignored)
107 {
108 containsCycle |= (*curr)->removeOtherJunctionsFrom(this, treeRoots);
109 }
110 }
111 return containsCycle;
112 }
113
114
115 // This method traverses the hyperedge tree and writes each of the paths
116 // back to the individual connectors as routes.
117 //
writeEdgesToConns(HyperedgeTreeEdge * ignored,size_t pass)118 void HyperedgeTreeNode::writeEdgesToConns(HyperedgeTreeEdge *ignored,
119 size_t pass)
120 {
121 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
122 curr != edges.end(); ++curr)
123 {
124 if (*curr != ignored)
125 {
126 (*curr)->writeEdgesToConns(this, pass);
127 }
128 }
129 }
130
131 // This method traverses the hyperedge tree and creates connectors for each
132 // segment bridging junction and/or terminals. It also sets the
133 // appropriate ConnEnds for each connector.
134 //
addConns(HyperedgeTreeEdge * ignored,Router * router,ConnRefList & oldConns,ConnRef * conn)135 void HyperedgeTreeNode::addConns(HyperedgeTreeEdge *ignored, Router *router,
136 ConnRefList& oldConns, ConnRef *conn)
137 {
138 // If no connector is set, then we must be starting off at a junction.
139 COLA_ASSERT(conn || junction);
140
141 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
142 curr != edges.end(); ++curr)
143 {
144 if (*curr != ignored)
145 {
146 // If we're not at a junction, then use the connector value being
147 // passed in to the method.
148
149 if (junction)
150 {
151 // If we're at a junction, then we are effectively starting
152 // our traversal along a connector, so create this new connector
153 // and set it's start ConnEnd to be this junction.
154 conn = new ConnRef(router);
155 router->removeObjectFromQueuedActions(conn);
156 conn->makeActive();
157 conn->m_initialised = true;
158 ConnEnd connend(junction);
159 conn->updateEndPoint(VertID::src, connend);
160 }
161
162 // Set the connector for this edge.
163 (*curr)->conn = conn;
164
165 // Continue recursive traversal.
166 (*curr)->addConns(this, router, oldConns);
167 }
168 }
169 }
170
travellingForwardOnConnector(ConnRef * conn,JunctionRef * junction)171 static bool travellingForwardOnConnector(ConnRef *conn, JunctionRef *junction)
172 {
173 std::pair<ConnEnd, ConnEnd> connEnds = conn->endpointConnEnds();
174
175 if (connEnds.first.junction() == junction)
176 {
177 return true;
178 }
179 if (connEnds.second.junction() == junction)
180 {
181 return false;
182 }
183 if (connEnds.first.type() != ConnEndJunction &&
184 connEnds.first.type() != ConnEndEmpty)
185 {
186 return false;
187 }
188 if (connEnds.second.type() != ConnEndJunction &&
189 connEnds.second.type() != ConnEndEmpty)
190 {
191 return true;
192 }
193 return true;
194 }
195
196 // This method traverses the hyperedge tree and rewrites connector ends
197 // that may have changed junctions due to major hyperedge improvement.
198 //
updateConnEnds(HyperedgeTreeEdge * ignored,bool forward,ConnRefList & changedConns)199 void HyperedgeTreeNode::updateConnEnds(HyperedgeTreeEdge *ignored,
200 bool forward, ConnRefList& changedConns)
201 {
202 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
203 curr != edges.end(); ++curr)
204 {
205 HyperedgeTreeEdge *edge = *curr;
206 if (edge != ignored)
207 {
208 if (junction)
209 {
210 // If we're at a junction, then we are effectively starting
211 // our traversal along a connector, so create this new connector
212 // and set it's start ConnEnd to be this junction.
213 forward = travellingForwardOnConnector(edge->conn, junction);
214
215 std::pair<ConnEnd, ConnEnd> existingEnds =
216 edge->conn->endpointConnEnds();
217 ConnEnd existingEnd = (forward) ?
218 existingEnds.first : existingEnds.second;
219 if (existingEnd.junction() != junction)
220 {
221 #ifdef MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG
222 fprintf(stderr, "HyperedgeImprover: changed %s of "
223 "connector %u (from junction %u to %u)\n",
224 (forward) ? "src" : "tar", edge->conn->id(),
225 existingEnd.junction()->id(), junction->id());
226 #endif
227 unsigned short end = (forward) ? VertID::src : VertID::tar;
228 ConnEnd connend(junction);
229 edge->conn->updateEndPoint(end, connend);
230 changedConns.push_back(edge->conn);
231 }
232 }
233
234 // Continue recursive traversal.
235 edge->updateConnEnds(this, forward, changedConns);
236 }
237 }
238 }
239
240
241 // This method traverses the hyperedge tree and returns a list of the junctions
242 // and connectors that make up the hyperedge.
243 //
listJunctionsAndConnectors(HyperedgeTreeEdge * ignored,JunctionRefList & junctions,ConnRefList & connectors)244 void HyperedgeTreeNode::listJunctionsAndConnectors(HyperedgeTreeEdge *ignored,
245 JunctionRefList& junctions, ConnRefList& connectors)
246 {
247 if (junction)
248 {
249 junctions.push_back(junction);
250 }
251
252 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
253 curr != edges.end(); ++curr)
254 {
255 if (*curr != ignored)
256 {
257 (*curr)->listJunctionsAndConnectors(this, junctions, connectors);
258 }
259 }
260 }
261
262
validateHyperedge(const HyperedgeTreeEdge * ignored,const size_t dist) const263 void HyperedgeTreeNode::validateHyperedge(const HyperedgeTreeEdge *ignored,
264 const size_t dist) const
265 {
266 size_t newDist = dist;
267 #ifdef MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG
268 if (junction)
269 {
270 if (newDist == 0)
271 {
272 fprintf(stderr,"\nHyperedge topology:\n");
273 }
274 else
275 {
276 ++newDist;
277 }
278 for (size_t d = 0; d < newDist; ++d)
279 {
280 fprintf(stderr," ");
281 }
282 fprintf(stderr, "j(%d)\n", junction->id());
283 ++newDist;
284 }
285 else if (edges.size() == 1)
286 {
287 ++newDist;
288 for (size_t d = 0; d < newDist; ++d)
289 {
290 fprintf(stderr, " ");
291 }
292 fprintf(stderr, "t()\n");
293 ++newDist;
294 }
295 #endif
296 for (std::list<HyperedgeTreeEdge *>::const_iterator curr = edges.begin();
297 curr != edges.end(); ++curr)
298 {
299 HyperedgeTreeEdge *edge = *curr;
300 std::pair<ConnEnd, ConnEnd> connEnds = edge->conn->endpointConnEnds();
301
302 if (junction)
303 {
304 COLA_ASSERT((connEnds.first.junction() == junction) ||
305 (connEnds.second.junction() == junction));
306 COLA_ASSERT(connEnds.first.junction() != connEnds.second.junction());
307 }
308 else if (edges.size() == 1)
309 {
310 COLA_ASSERT(!connEnds.first.junction() ||
311 !connEnds.second.junction());
312 }
313
314 if (edge != ignored)
315 {
316 edge->validateHyperedge(this, newDist);
317 }
318 }
319 }
320
321
322 // This method traverses the hyperedge tree, clearing up the objects and
323 // memory used to store the tree.
324 //
deleteEdgesExcept(HyperedgeTreeEdge * ignored)325 void HyperedgeTreeNode::deleteEdgesExcept(HyperedgeTreeEdge *ignored)
326 {
327 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
328 curr != edges.end(); ++curr)
329 {
330 if (*curr != ignored)
331 {
332 (*curr)->deleteNodesExcept(this);
333 delete *curr;
334 }
335 }
336 edges.clear();
337 }
338
339
340 // This method disconnects a specific hyperedge tree edge from the given node.
341 //
disconnectEdge(HyperedgeTreeEdge * edge)342 void HyperedgeTreeNode::disconnectEdge(HyperedgeTreeEdge *edge)
343 {
344 for (std::list<HyperedgeTreeEdge *>::iterator curr = edges.begin();
345 curr != edges.end(); )
346 {
347 if (*curr == edge)
348 {
349 curr = edges.erase(curr);
350 }
351 else
352 {
353 ++curr;
354 }
355 }
356
357 }
358
359
360 // This method moves all edges attached to oldNode to instead be attached to
361 // the given hyperedge tree node.
362 //
spliceEdgesFrom(HyperedgeTreeNode * oldNode)363 void HyperedgeTreeNode::spliceEdgesFrom(HyperedgeTreeNode *oldNode)
364 {
365 COLA_ASSERT(oldNode != this);
366 for (std::list<HyperedgeTreeEdge *>::iterator curr = oldNode->edges.begin();
367 curr != oldNode->edges.end(); curr = oldNode->edges.begin())
368 {
369 (*curr)->replaceNode(oldNode, this);
370 }
371 }
372
373
isImmovable(void) const374 bool HyperedgeTreeNode::isImmovable(void) const
375 {
376 if ((edges.size() == 1) || (junction && junction->positionFixed()))
377 {
378 return true;
379 }
380 for (std::list<HyperedgeTreeEdge *>::const_iterator curr = edges.begin();
381 curr != edges.end(); ++curr)
382 {
383 if ((*curr)->hasFixedRoute)
384 {
385 return true;
386 }
387 }
388 return false;
389 }
390
391 // Constructs a new hyperedge tree edge, given two endpoint nodes.
392 //
HyperedgeTreeEdge(HyperedgeTreeNode * node1,HyperedgeTreeNode * node2,ConnRef * conn)393 HyperedgeTreeEdge::HyperedgeTreeEdge(HyperedgeTreeNode *node1,
394 HyperedgeTreeNode *node2, ConnRef *conn)
395 : conn(conn),
396 hasFixedRoute(false)
397 {
398 if (conn)
399 {
400 hasFixedRoute = conn->hasFixedRoute();
401 }
402 ends = std::make_pair(node1, node2);
403 node1->edges.push_back(this);
404 node2->edges.push_back(this);
405 }
406
407
408 // Given one endpoint of the hyperedge tree edge, returns the other endpoint.
409 //
followFrom(HyperedgeTreeNode * from) const410 HyperedgeTreeNode *HyperedgeTreeEdge::followFrom(HyperedgeTreeNode *from) const
411 {
412 return (ends.first == from) ? ends.second : ends.first;
413 }
414
415
416 // Returns true if the length of this edge is zero, i.e., the endpoints are
417 // located at the same position.
418 //
zeroLength(void) const419 bool HyperedgeTreeEdge::zeroLength(void) const
420 {
421 return (ends.first->point == ends.second->point);
422 }
423
424
425 // This method traverses the hyperedge tree and outputs each of the edges
426 // and junction positions as SVG objects to the file fp.
427 //
outputNodesExcept(FILE * fp,HyperedgeTreeNode * ignored)428 void HyperedgeTreeEdge::outputNodesExcept(FILE *fp, HyperedgeTreeNode *ignored)
429 {
430 fprintf(fp, "<path d=\"M %g %g L %g %g\" "
431 "style=\"fill: none; stroke: %s; stroke-width: 2px; "
432 "stroke-opacity: 0.5;\" />\n",
433 ends.first->point.x, ends.first->point.y,
434 ends.second->point.x, ends.second->point.y, "purple");
435 if (ends.first != ignored)
436 {
437 ends.first->outputEdgesExcept(fp, this);
438 }
439
440 if (ends.second != ignored)
441 {
442 ends.second->outputEdgesExcept(fp, this);
443 }
444 }
445
446
447 // This method returns true if the edge is in the dimension given, i.e.,
448 // either horizontal or vertical.
449 //
hasOrientation(const size_t dimension) const450 bool HyperedgeTreeEdge::hasOrientation(const size_t dimension) const
451 {
452 return (ends.first->point[dimension] == ends.second->point[dimension]);
453 }
454
455
456 // This method updates any of the given hyperedge tree edge's endpoints that
457 // are attached to oldNode to instead be attached to newNode.
458 //
replaceNode(HyperedgeTreeNode * oldNode,HyperedgeTreeNode * newNode)459 void HyperedgeTreeEdge::replaceNode(HyperedgeTreeNode *oldNode,
460 HyperedgeTreeNode *newNode)
461 {
462 if (ends.first == oldNode)
463 {
464 oldNode->disconnectEdge(this);
465 newNode->edges.push_back(this);
466 ends.first = newNode;
467 }
468 else if (ends.second == oldNode)
469 {
470 oldNode->disconnectEdge(this);
471 newNode->edges.push_back(this);
472 ends.second = newNode;
473 }
474 }
475
476
477 // This method traverses the hyperedge tree and writes each of the paths
478 // back to the individual connectors as routes.
479 //
writeEdgesToConns(HyperedgeTreeNode * ignored,size_t pass)480 void HyperedgeTreeEdge::writeEdgesToConns(HyperedgeTreeNode *ignored,
481 size_t pass)
482 {
483 COLA_ASSERT(ignored != nullptr);
484 COLA_ASSERT(ends.first != nullptr);
485 COLA_ASSERT(ends.second != nullptr);
486
487 HyperedgeTreeNode *prevNode =
488 (ignored == ends.first) ? ends.first : ends.second;
489 HyperedgeTreeNode *nextNode =
490 (ignored == ends.first) ? ends.second : ends.first;
491
492 if (pass == 0)
493 {
494 conn->m_display_route.clear();
495 }
496 else if (pass == 1)
497 {
498 if (conn->m_display_route.empty())
499 {
500 //printf("[%u] - %g %g\n", conn->id(), prevNode->point.x, prevNode->point.y);
501 conn->m_display_route.ps.push_back(prevNode->point);
502 }
503 //printf("[%u] + %g %g\n", conn->id(), nextNode->point.x, nextNode->point.y);
504 conn->m_display_route.ps.push_back(nextNode->point);
505
506 size_t nextNodeEdges = nextNode->edges.size();
507 if (nextNodeEdges != 2)
508 {
509 // We have finished writing a connector. If the node has just
510 // two edges then it is an intermediate node on a connector.
511 bool shouldReverse = false;
512 if (nextNodeEdges == 1)
513 {
514 // This connector led to a terminal.
515 if (nextNode->isConnectorSource)
516 {
517 shouldReverse = true;
518 }
519
520 if (nextNode->isPinDummyEndpoint)
521 {
522 // If may be that the hyperedge has an extra segment or
523 // two leading to the centre dummy pin used for connection
524 // pin routing. If so, remove these points from the
525 // resulting route.
526 conn->m_display_route.ps.pop_back();
527 if (prevNode->point == nextNode->point)
528 {
529 // Duplicated dummy point. Remove second one.
530 conn->m_display_route.ps.pop_back();
531 }
532 }
533 }
534 else // if (nextNodeEdges > 2)
535 {
536 // This connector was between two junctions.
537 COLA_ASSERT(conn->m_dst_connend);
538 JunctionRef *correctEndJunction =
539 conn->m_dst_connend->junction();
540 if (nextNode->junction != correctEndJunction)
541 {
542 shouldReverse = true;
543 }
544 }
545
546 if (shouldReverse == true)
547 {
548 // Reverse the written connector route.
549 std::reverse(conn->m_display_route.ps.begin(),
550 conn->m_display_route.ps.end());
551 }
552 }
553
554 #ifdef DEBUGHANDLER
555 if (conn->router()->debugHandler())
556 {
557 conn->router()->debugHandler()->updateConnectorRoute(
558 conn, -1, -1);
559 }
560 #endif
561 }
562
563 nextNode->writeEdgesToConns(this, pass);
564 }
565
566 // This method traverses the hyperedge tree and creates connectors for each
567 // segment bridging junction and/or terminals. It also sets the
568 // appropriate ConnEnds for each connector.
569 //
addConns(HyperedgeTreeNode * ignored,Router * router,ConnRefList & oldConns)570 void HyperedgeTreeEdge::addConns(HyperedgeTreeNode *ignored, Router *router,
571 ConnRefList& oldConns)
572 {
573 COLA_ASSERT(conn != nullptr);
574 HyperedgeTreeNode *endNode = nullptr;
575 if (ends.first && (ends.first != ignored))
576 {
577 endNode = ends.first;
578 ends.first->addConns(this, router, oldConns, conn);
579 }
580
581 if (ends.second && (ends.second != ignored))
582 {
583 endNode = ends.second;
584 ends.second->addConns(this, router, oldConns, conn);
585 }
586
587 if (endNode->finalVertex)
588 {
589 // We have reached a terminal of the hyperedge, so set a ConnEnd for
590 // the original connector endpoint
591 ConnEnd connend;
592 bool result = false;
593 // Find the ConnEnd from the list of original connectors.
594 for (ConnRefList::iterator curr = oldConns.begin();
595 curr != oldConns.end(); ++curr)
596 {
597 result |= (*curr)->getConnEndForEndpointVertex(
598 endNode->finalVertex, connend);
599 if (result)
600 {
601 break;
602 }
603 }
604 if (result)
605 {
606 // XXX: Create new conn here.
607 conn->updateEndPoint(VertID::tar, connend);
608 }
609 }
610 else if (endNode->junction)
611 {
612 // Or, set a ConnEnd connecting to the junction we have reached.
613 ConnEnd connend(endNode->junction);
614 conn->updateEndPoint(VertID::tar, connend);
615 }
616 }
617
618
619 // This method traverses the hyperedge tree and rewrites connector ends
620 // that may have changed junctions due to major hyperedge improvement.
621 //
updateConnEnds(HyperedgeTreeNode * ignored,bool forward,ConnRefList & changedConns)622 void HyperedgeTreeEdge::updateConnEnds(HyperedgeTreeNode *ignored,
623 bool forward, ConnRefList& changedConns)
624 {
625 HyperedgeTreeNode *endNode = nullptr;
626 if (ends.first && (ends.first != ignored))
627 {
628 endNode = ends.first;
629 ends.first->updateConnEnds(this, forward, changedConns);
630 }
631
632 if (ends.second && (ends.second != ignored))
633 {
634 endNode = ends.second;
635 ends.second->updateConnEnds(this, forward, changedConns);
636 }
637
638 if (endNode->junction)
639 {
640 // We've reached a junction at the end of this connector, and it's
641 // not an endpoint of the hyperedge. So the connector ConnEnd to
642 // connect to the junction we have reached.
643 std::pair<ConnEnd, ConnEnd> existingEnds = conn->endpointConnEnds();
644 ConnEnd existingEnd = (forward) ?
645 existingEnds.second : existingEnds.first;
646 if (existingEnd.junction() != endNode->junction)
647 {
648 #ifdef MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG
649 fprintf(stderr, "HyperedgeImprover: changed %s of "
650 "connector %u (from junction %u to %u)\n",
651 (forward) ? "tar" : "src", conn->id(),
652 existingEnd.junction()->id(), endNode->junction->id());
653 #endif
654 ConnEnd connend(endNode->junction);
655 unsigned short end = (forward) ? VertID::tar : VertID::src;
656 conn->updateEndPoint(end, connend);
657
658 // Record that this connector was changed (so long as it wasn't
659 // already recorded).
660 if (changedConns.empty() || (changedConns.back() != conn))
661 {
662 changedConns.push_back(conn);
663 }
664 }
665 }
666 }
667
668 // This method traverses the hyperedge tree and returns a list of the junctions
669 // and connectors that make up the hyperedge.
670 //
listJunctionsAndConnectors(HyperedgeTreeNode * ignored,JunctionRefList & junctions,ConnRefList & connectors)671 void HyperedgeTreeEdge::listJunctionsAndConnectors(HyperedgeTreeNode *ignored,
672 JunctionRefList& junctions, ConnRefList& connectors)
673 {
674 ConnRefList::iterator foundPosition =
675 std::find(connectors.begin(), connectors.end(), conn);
676 if (foundPosition == connectors.end())
677 {
678 // Add connector if it isn't already in the list.
679 connectors.push_back(conn);
680 }
681
682 if (ends.first != ignored)
683 {
684 ends.first->listJunctionsAndConnectors(this, junctions, connectors);
685 }
686 else if (ends.second != ignored)
687 {
688 ends.second->listJunctionsAndConnectors(this, junctions, connectors);
689 }
690 }
691
692
validateHyperedge(const HyperedgeTreeNode * ignored,const size_t dist) const693 void HyperedgeTreeEdge::validateHyperedge(
694 const HyperedgeTreeNode *ignored, const size_t dist) const
695 {
696 #ifdef MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG
697 for (size_t d = 0; d < dist; ++d)
698 {
699 fprintf(stderr, " ");
700 }
701 fprintf(stderr, "-(%d)\n", conn->id());
702 #endif
703 if (ends.first != ignored)
704 {
705 ends.first->validateHyperedge(this, dist);
706 }
707 else if (ends.second != ignored)
708 {
709 ends.second->validateHyperedge(this, dist);
710 }
711 }
712
713
714 // This method splits the current edge, adding a node at the given point.
715 // The current edge will connect the source node and the newly created node.
716 // A new edge will connect the new node and the node at the other end of the
717 // original edge.
718 //
splitFromNodeAtPoint(HyperedgeTreeNode * source,const Point & point)719 void HyperedgeTreeEdge::splitFromNodeAtPoint(HyperedgeTreeNode *source,
720 const Point& point)
721 {
722 // Make the source the first of the two nodes.
723 if (ends.second == source)
724 {
725 std::swap(ends.second, ends.first);
726 }
727 COLA_ASSERT(ends.first == source);
728
729 // Remember the other end.
730 HyperedgeTreeNode *target = ends.second;
731
732 // Create a new node for the split point at the given position.
733 HyperedgeTreeNode *split = new HyperedgeTreeNode();
734 split->point = point;
735
736 // Create a new edge between the split point and the other end.
737 new HyperedgeTreeEdge(split, target, conn);
738
739 // Disconnect the current edge from the other end and connect it to
740 // the new split point node.
741 target->disconnectEdge(this);
742 ends.second = split;
743 split->edges.push_back(this);
744 }
745
746
747 // This method disconnects the hyperedge tree edge nodes that it's attached to.
748 //
disconnectEdge(void)749 void HyperedgeTreeEdge::disconnectEdge(void)
750 {
751 COLA_ASSERT(ends.first != nullptr);
752 COLA_ASSERT(ends.second != nullptr);
753
754 ends.first->disconnectEdge(this);
755 ends.second->disconnectEdge(this);
756 ends.first = nullptr;
757 ends.second = nullptr;
758 }
759
760
761 // This method traverses the hyperedge tree and removes from treeRoots any
762 // junction nodes.
763 //
removeOtherJunctionsFrom(HyperedgeTreeNode * ignored,JunctionSet & treeRoots)764 bool HyperedgeTreeEdge::removeOtherJunctionsFrom(HyperedgeTreeNode *ignored,
765 JunctionSet& treeRoots)
766 {
767 bool containsCycle = false;
768 if (ends.first && (ends.first != ignored))
769 {
770 containsCycle |= ends.first->removeOtherJunctionsFrom(this, treeRoots);
771 }
772
773 if (ends.second && (ends.second != ignored))
774 {
775 containsCycle |= ends.second->removeOtherJunctionsFrom(this, treeRoots);
776 }
777 return containsCycle;
778 }
779
780
781 // This method traverses the hyperedge tree, clearing up the objects and
782 // memory used to store the tree.
783 //
deleteNodesExcept(HyperedgeTreeNode * ignored)784 void HyperedgeTreeEdge::deleteNodesExcept(HyperedgeTreeNode *ignored)
785 {
786 if (ends.first && (ends.first != ignored))
787 {
788 ends.first->deleteEdgesExcept(this);
789 delete ends.first;
790 }
791 ends.first = nullptr;
792
793 if (ends.second && (ends.second != ignored))
794 {
795 ends.second->deleteEdgesExcept(this);
796 delete ends.second;
797 }
798 ends.second = nullptr;
799 }
800
801
CmpNodesInDim(const size_t dim)802 CmpNodesInDim::CmpNodesInDim(const size_t dim)
803 : m_dimension(dim)
804 {
805 }
806
807
808 // Nodes in set are ordered by position along a line in a certain dimension,
809 // and then by Node pointer since multiple may exist at a particular position.
operator ()(const HyperedgeTreeNode * lhs,const HyperedgeTreeNode * rhs) const810 bool CmpNodesInDim::operator()(const HyperedgeTreeNode *lhs,
811 const HyperedgeTreeNode *rhs) const
812 {
813 if (lhs->point[m_dimension] != rhs->point[m_dimension])
814 {
815 return lhs->point[m_dimension] < rhs->point[m_dimension];
816 }
817 return lhs < rhs;
818 }
819
820 }
821
822