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