int main(void) { Router *router = new Router(OrthogonalRouting); router->setRoutingPenalty((PenaltyType)0, 50); router->setRoutingPenalty((PenaltyType)1, 0); router->setRoutingPenalty((PenaltyType)2, 0); router->setRoutingPenalty((PenaltyType)3, 4000); router->setRoutingPenalty((PenaltyType)4, 105); router->setOrthogonalNudgeDistance(25); Rectangle rect478845150(Point(50695, 51070), Point(50705, 51080)); JunctionRef *junctionRef478845150 = new JunctionRef(router, Point(50700, 51075), 478845150); Rectangle rect92712048(Point(51246, 50475), Point(51304, 50585)); new ShapeRef(router, rect92712048, 92712048); Rectangle rect23127921(Point(50365, 50766), Point(50485, 50834)); new ShapeRef(router, rect23127921, 23127921); Rectangle rect159957148(Point(51740, 50891), Point(51860, 50959)); new ShapeRef(router, rect159957148, 159957148); Rectangle rect1350214(Point(50375, 51015), Point(50625, 51135)); new ShapeRef(router, rect1350214, 1350214); Rectangle rect247197258(Point(50265, 51046), Point(50375, 51104)); new ShapeRef(router, rect247197258, 247197258); Rectangle rect281096654(Point(50700, 50390), Point(51000, 50610)); new ShapeRef(router, rect281096654, 281096654); ConnEnd srcPt342420237(Point(50425, 50800), 15); ConnEnd dstPt342420237(Point(50710, 50450), 4); new ConnRef(router, srcPt342420237, dstPt342420237, 342420237); ConnEnd srcPt352019675(Point(50990, 50500), 8); ConnEnd dstPt352019675(junctionRef478845150); //ConnEnd dstPt352019675(Point(50700, 51075), 15); new ConnRef(router, srcPt352019675, dstPt352019675, 352019675); ConnEnd srcPt42699400(junctionRef478845150); //ConnEnd srcPt42699400(Point(50700, 51075), 15); ConnEnd dstPt42699400(Point(50615, 51075), 8); new ConnRef(router, srcPt42699400, dstPt42699400, 42699400); ConnEnd srcPt94712625(Point(50710, 50550), 4); ConnEnd dstPt94712625(junctionRef478845150); //ConnEnd dstPt94712625(Point(50700, 51075), 15); new ConnRef(router, srcPt94712625, dstPt94712625, 94712625); ConnEnd srcPt92802970(Point(50990, 50450), 8); ConnEnd dstPt92802970(Point(51275, 50485), 1); ConnRef *conn = new ConnRef(router, srcPt92802970, dstPt92802970, 92802970); std::vector<Point> checkpoints; checkpoints.push_back(Point(50000, 50000)); checkpoints.push_back(Point(50200, 50000)); checkpoints.push_back(Point(50200, 50200)); conn->setRoutingCheckpoints(checkpoints); ConnEnd srcPt716502036(Point(50710, 50500), 4); ConnEnd dstPt716502036(Point(51800, 50925), 15); new ConnRef(router, srcPt716502036, dstPt716502036, 716502036); router->processTransaction(); router->outputInstanceToSVG("test-checkpoints01-1"); router->moveJunction(junctionRef478845150, 585, 0); router->processTransaction(); router->outputInstanceToSVG("test-checkpoints01-2"); delete router; return 0; };
void RoutingAdapter::addEdges(const EdgesById &edges, const EdgeConnDirsById *connDirs) { // We take advantage of the ordered nature of the maps. auto it = edges.begin(); if (connDirs != nullptr) { auto jt = connDirs->begin(); // Before falling off the end of either map... while (it != edges.end() && jt != connDirs->end()) { auto p = *it; auto q = *jt; // Record the Edge in the local lookup. this->edges.insert(p); // Get the two IDs. id_type i = p.first, j = q.first; // Advance the connDirs iterator iff its ID lags the edges ID. if (i > j) ++jt; // In all other cases we are able to test whether the current Edge's ID // is in the connDirs map. else { // Allocate a ConnRef and add it to the router. ConnRef *cr = new ConnRef(&router); // Store it in the lookup map by Edge ID. edgeIdToConnRef.insert({i, cr}); // Get the ConnEnds. ConnEndPair ends; if (i==j) { // If the two IDs are equal then this Edge has special connDirs. auto cd = q.second; ends = p.second->makeLibavoidConnEnds(cd.first, cd.second); } else { // Otherwise it does not. ends = p.second->makeLibavoidConnEnds(); } // Set the ends in the ConnRef. cr->setEndpoints(ends.first, ends.second); ++it; } } } // In case we fell off the end of the connDirs map first, then all remaining edges // take the default of ConnDirAll. while (it != edges.end()) { auto p = *it; // Record the Edge in the local lookup. this->edges.insert(p); // Allocate a ConnRef and add it to the router. ConnRef *cr = new ConnRef(&router); // Store it in the lookup map by Edge ID. edgeIdToConnRef.insert({p.first, cr}); // Get the ConnEnds. ConnEndPair ends = p.second->makeLibavoidConnEnds(); // Set the ends in the ConnRef. cr->setEndpoints(ends.first, ends.second); ++it; } }
void buildConnectorRouteCheckpointCache(Router *router) { for (ConnRefList::const_iterator curr = router->connRefs.begin(); curr != router->connRefs.end(); ++curr) { ConnRef *conn = *curr; if (conn->routingType() != ConnType_Orthogonal) { continue; } PolyLine& displayRoute = conn->displayRoute(); std::vector<Point> checkpoints = conn->routingCheckpoints(); // Initialise checkpoint vector and set to false. There will be // one entry for each *segment* in the path, and the value indicates // whether the segment is affected by a checkpoint. displayRoute.segmentHasCheckpoint = std::vector<bool>(displayRoute.size() - 1, false); size_t nCheckpoints = displayRoute.segmentHasCheckpoint.size(); for (size_t cpi = 0; cpi < checkpoints.size(); ++cpi) { for (size_t ind = 0; ind < displayRoute.size(); ++ind) { if (displayRoute.ps[ind].equals(checkpoints[cpi])) { // The checkpoint is at a bendpoint, so mark the edge // before and after and being affected by checkpoints. if (ind > 0) { displayRoute.segmentHasCheckpoint[ind - 1] = true; } if (ind < nCheckpoints) { displayRoute.segmentHasCheckpoint[ind] = true; } } else if ((ind > 0) && pointOnLine(displayRoute.ps[ind - 1], displayRoute.ps[ind], checkpoints[cpi]) ) { // If the checkpoint is on a segment, only that segment is // affected. displayRoute.segmentHasCheckpoint[ind - 1] = true; } } } } }
void buildConnectorRouteCheckpointCache(Router *router) { for (ConnRefList::const_iterator curr = router->connRefs.begin(); curr != router->connRefs.end(); ++curr) { ConnRef *conn = *curr; if (conn->routingType() != ConnType_Orthogonal) { continue; } PolyLine& displayRoute = conn->displayRoute(); std::vector<Checkpoint> checkpoints = conn->routingCheckpoints(); // Initialise checkpoint vector and set to false. There will be // one entry for each *segment* in the path, and the value indicates // whether the segment is affected by a checkpoint. displayRoute.checkpointsOnRoute = std::vector<std::pair<size_t, Point> >(); for (size_t ind = 0; ind < displayRoute.size(); ++ind) { if (ind > 0) { for (size_t cpi = 0; cpi < checkpoints.size(); ++cpi) { if (pointOnLine(displayRoute.ps[ind - 1], displayRoute.ps[ind], checkpoints[cpi].point) ) { // The checkpoint is on a segment. displayRoute.checkpointsOnRoute.push_back( std::make_pair((ind * 2) - 1, checkpoints[cpi].point)); } } } for (size_t cpi = 0; cpi < checkpoints.size(); ++cpi) { if (displayRoute.ps[ind].equals(checkpoints[cpi].point)) { // The checkpoint is at a bendpoint. displayRoute.checkpointsOnRoute.push_back( std::make_pair(ind * 2, checkpoints[cpi].point)); } } } } }
void clearConnectorRouteCheckpointCache(Router *router) { for (ConnRefList::const_iterator curr = router->connRefs.begin(); curr != router->connRefs.end(); ++curr) { ConnRef *conn = *curr; if (conn->routingType() != ConnType_Orthogonal) { continue; } // Clear the cache. PolyLine& displayRoute = conn->displayRoute(); displayRoute.checkpointsOnRoute.clear(); } }
CardinalDir LeaflessOrthoRouter::departureDir(const Edge_SP &e, const Node_SP &u) const { ConnRef *cr = m_ra.edgeIdToConnRef.at(e->id()); PolyLine poly = cr->displayRoute(); vector<Point> pts = poly.ps; Point p0, p1; if (u->id() == e->getSourceEnd()->id()) { // Node u is the source end of Edge e. // So we want the first two points in the route, in order. p0 = pts[0]; p1 = pts[1]; } else { // Node u is the target end of Edge e. // So we want the last two points in the route, in reverse order. size_t L = pts.size(); p0 = pts[L-1]; p1 = pts[L-2]; } return Compass::cardinalDirection(p0, p1); }
int main(void) { Router *router = new Router(OrthogonalRouting); router->setRoutingParameter((RoutingParameter)0, 10); router->setRoutingParameter((RoutingParameter)1, 0); router->setRoutingParameter((RoutingParameter)2, 1000); router->setRoutingParameter((RoutingParameter)3, 4000); router->setRoutingParameter((RoutingParameter)4, 0); router->setRoutingParameter((RoutingParameter)5, 100); router->setRoutingParameter((RoutingParameter)6, 1); router->setRoutingParameter((RoutingParameter)7, 10); router->setRoutingParameter(reverseDirectionPenalty, 500); router->setRoutingOption((RoutingOption)0, false); router->setRoutingOption((RoutingOption)1, true); router->setRoutingOption((RoutingOption)2, false); router->setRoutingOption((RoutingOption)3, false); router->setRoutingOption((RoutingOption)4, true); router->setRoutingOption((RoutingOption)5, true); Polygon polygon; ConnRef *connRef = NULL; ConnEnd srcPt; ConnEnd dstPt; PolyLine newRoute; // shapeRef1 polygon = Polygon(4); polygon.ps[0] = Point(0, 0); polygon.ps[1] = Point(0, 0); polygon.ps[2] = Point(0, 0); polygon.ps[3] = Point(0, 0); new ShapeRef(router, polygon, 1); // shapeRef2 polygon = Polygon(4); polygon.ps[0] = Point(0, 0); polygon.ps[1] = Point(0, 0); polygon.ps[2] = Point(0, 0); polygon.ps[3] = Point(0, 0); new ShapeRef(router, polygon, 2); // shapeRef3 polygon = Polygon(4); polygon.ps[0] = Point(0, 0); polygon.ps[1] = Point(0, 0); polygon.ps[2] = Point(0, 0); polygon.ps[3] = Point(0, 0); new ShapeRef(router, polygon, 3); // shapeRef4 polygon = Polygon(4); polygon.ps[0] = Point(0, 0); polygon.ps[1] = Point(0, 0); polygon.ps[2] = Point(0, 0); polygon.ps[3] = Point(0, 0); new ShapeRef(router, polygon, 4); // shapeRef5 polygon = Polygon(4); polygon.ps[0] = Point(501, 345); polygon.ps[1] = Point(501, 404); polygon.ps[2] = Point(421, 404); polygon.ps[3] = Point(421, 345); ShapeRef *shapeRef5 = new ShapeRef(router, polygon, 5); new ShapeConnectionPin(shapeRef5, 5, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef5, 6, 0, 0.79096, true, 0, (ConnDirFlags) 4); new ShapeConnectionPin(shapeRef5, 7, 0, 0.514124, true, 0, (ConnDirFlags) 4); // shapeRef6 polygon = Polygon(4); polygon.ps[0] = Point(94, 251.5); polygon.ps[1] = Point(94, 315.5); polygon.ps[2] = Point(12, 315.5); polygon.ps[3] = Point(12, 251.5); ShapeRef *shapeRef6 = new ShapeRef(router, polygon, 6); new ShapeConnectionPin(shapeRef6, 8, 1, 0.640625, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef6, 9, 0, 0.640625, true, 0, (ConnDirFlags) 4); // shapeRef7 polygon = Polygon(4); polygon.ps[0] = Point(634.366, 262); polygon.ps[1] = Point(634.366, 305); polygon.ps[2] = Point(416.366, 305); polygon.ps[3] = Point(416.366, 262); ShapeRef *shapeRef7 = new ShapeRef(router, polygon, 7); new ShapeConnectionPin(shapeRef7, 10, 1, 0.709302, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef7, 11, 0, 0.709302, true, 0, (ConnDirFlags) 4); // shapeRef8 polygon = Polygon(4); polygon.ps[0] = Point(324, 147.167); polygon.ps[1] = Point(324, 206.167); polygon.ps[2] = Point(236, 206.167); polygon.ps[3] = Point(236, 147.167); ShapeRef *shapeRef8 = new ShapeRef(router, polygon, 8); new ShapeConnectionPin(shapeRef8, 12, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef8, 13, 0, 0.79096, true, 0, (ConnDirFlags) 4); new ShapeConnectionPin(shapeRef8, 14, 0, 0.514124, true, 0, (ConnDirFlags) 4); // shapeRef9 polygon = Polygon(4); polygon.ps[0] = Point(816, 353.167); polygon.ps[1] = Point(816, 412.167); polygon.ps[2] = Point(735, 412.167); polygon.ps[3] = Point(735, 353.167); ShapeRef *shapeRef9 = new ShapeRef(router, polygon, 9); new ShapeConnectionPin(shapeRef9, 15, 1, 0.514124, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef9, 16, 1, 0.79096, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef9, 17, 0, 0.79096, true, 0, (ConnDirFlags) 4); new ShapeConnectionPin(shapeRef9, 18, 0, 0.514124, true, 0, (ConnDirFlags) 4); // shapeRef10 polygon = Polygon(4); polygon.ps[0] = Point(981, 263.833); polygon.ps[1] = Point(981, 321.833); polygon.ps[2] = Point(828, 321.833); polygon.ps[3] = Point(828, 263.833); ShapeRef *shapeRef10 = new ShapeRef(router, polygon, 10); new ShapeConnectionPin(shapeRef10, 19, 0, 0.655172, true, 0, (ConnDirFlags) 4); // shapeRef11 polygon = Polygon(4); polygon.ps[0] = Point(1011.49, 361.833); polygon.ps[1] = Point(1011.49, 419.833); polygon.ps[2] = Point(834.489, 419.833); polygon.ps[3] = Point(834.489, 361.833); ShapeRef *shapeRef11 = new ShapeRef(router, polygon, 11); new ShapeConnectionPin(shapeRef11, 20, 0, 0.655172, true, 0, (ConnDirFlags) 4); // shapeRef12 polygon = Polygon(4); polygon.ps[0] = Point(511, 155.333); polygon.ps[1] = Point(511, 214.333); polygon.ps[2] = Point(422, 214.333); polygon.ps[3] = Point(422, 155.333); ShapeRef *shapeRef12 = new ShapeRef(router, polygon, 12); new ShapeConnectionPin(shapeRef12, 21, 1, 0.514124, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef12, 22, 1, 0.79096, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef12, 23, 0, 0.79096, true, 0, (ConnDirFlags) 4); new ShapeConnectionPin(shapeRef12, 24, 0, 0.514124, true, 0, (ConnDirFlags) 4); // shapeRef13 polygon = Polygon(4); polygon.ps[0] = Point(690, 66); polygon.ps[1] = Point(690, 124); polygon.ps[2] = Point(523, 124); polygon.ps[3] = Point(523, 66); ShapeRef *shapeRef13 = new ShapeRef(router, polygon, 13); new ShapeConnectionPin(shapeRef13, 25, 0, 0.655172, true, 0, (ConnDirFlags) 4); // shapeRef14 polygon = Polygon(4); polygon.ps[0] = Point(720.212, 164); polygon.ps[1] = Point(720.212, 222); polygon.ps[2] = Point(529.212, 222); polygon.ps[3] = Point(529.212, 164); ShapeRef *shapeRef14 = new ShapeRef(router, polygon, 14); new ShapeConnectionPin(shapeRef14, 26, 0, 0.655172, true, 0, (ConnDirFlags) 4); // shapeRef15 polygon = Polygon(4); polygon.ps[0] = Point(217, 336.833); polygon.ps[1] = Point(217, 395.833); polygon.ps[2] = Point(98, 395.833); polygon.ps[3] = Point(98, 336.833); ShapeRef *shapeRef15 = new ShapeRef(router, polygon, 15); new ShapeConnectionPin(shapeRef15, 27, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef15, 28, 0, 0.652542, true, 0, (ConnDirFlags) 4); // shapeRef16 polygon = Polygon(4); polygon.ps[0] = Point(413, 147.167); polygon.ps[1] = Point(413, 206.167); polygon.ps[2] = Point(336, 206.167); polygon.ps[3] = Point(336, 147.167); ShapeRef *shapeRef16 = new ShapeRef(router, polygon, 16); new ShapeConnectionPin(shapeRef16, 29, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef16, 30, 0, 0.652542, true, 0, (ConnDirFlags) 4); // shapeRef17 polygon = Polygon(4); polygon.ps[0] = Point(306, 336.833); polygon.ps[1] = Point(306, 395.833); polygon.ps[2] = Point(229, 395.833); polygon.ps[3] = Point(229, 336.833); ShapeRef *shapeRef17 = new ShapeRef(router, polygon, 17); new ShapeConnectionPin(shapeRef17, 31, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef17, 32, 0, 0.652542, true, 0, (ConnDirFlags) 4); // shapeRef18 polygon = Polygon(4); polygon.ps[0] = Point(175, 139); polygon.ps[1] = Point(175, 198); polygon.ps[2] = Point(98, 198); polygon.ps[3] = Point(98, 139); ShapeRef *shapeRef18 = new ShapeRef(router, polygon, 18); new ShapeConnectionPin(shapeRef18, 33, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef18, 34, 0, 0.652542, true, 0, (ConnDirFlags) 4); // shapeRef19 polygon = Polygon(4); polygon.ps[0] = Point(409, 399.333); polygon.ps[1] = Point(409, 458.333); polygon.ps[2] = Point(298, 458.333); polygon.ps[3] = Point(298, 399.333); ShapeRef *shapeRef19 = new ShapeRef(router, polygon, 19); new ShapeConnectionPin(shapeRef19, 35, 1, 0.652542, true, 0, (ConnDirFlags) 8); // shapeRef20 polygon = Polygon(4); polygon.ps[0] = Point(224, 40); polygon.ps[1] = Point(224, 99); polygon.ps[2] = Point(106, 99); polygon.ps[3] = Point(106, 40); ShapeRef *shapeRef20 = new ShapeRef(router, polygon, 20); new ShapeConnectionPin(shapeRef20, 36, 1, 0.652542, true, 0, (ConnDirFlags) 8); // shapeRef21 polygon = Polygon(4); polygon.ps[0] = Point(604, 345); polygon.ps[1] = Point(604, 404); polygon.ps[2] = Point(513, 404); polygon.ps[3] = Point(513, 345); ShapeRef *shapeRef21 = new ShapeRef(router, polygon, 21); new ShapeConnectionPin(shapeRef21, 37, 1, 0.652542, true, 0, (ConnDirFlags) 8); new ShapeConnectionPin(shapeRef21, 38, 0, 0.652542, true, 0, (ConnDirFlags) 4); // connRef1 connRef = new ConnRef(router, 1); srcPt = ConnEnd(shapeRef5, 5); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef21, 38); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef2 connRef = new ConnRef(router, 2); srcPt = ConnEnd(shapeRef6, 8); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef18, 34); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef3 connRef = new ConnRef(router, 3); srcPt = ConnEnd(shapeRef6, 8); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef15, 28); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef4 connRef = new ConnRef(router, 4); srcPt = ConnEnd(shapeRef6, 8); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef12, 23); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef5 connRef = new ConnRef(router, 5); srcPt = ConnEnd(shapeRef6, 8); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef7, 11); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef6 connRef = new ConnRef(router, 6); srcPt = ConnEnd(shapeRef7, 10); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef9, 17); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); ConnRef *connector6 = connRef; // connRef7 connRef = new ConnRef(router, 7); srcPt = ConnEnd(shapeRef8, 12); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef16, 30); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef8 connRef = new ConnRef(router, 8); srcPt = ConnEnd(shapeRef9, 15); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef10, 19); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef9 connRef = new ConnRef(router, 9); srcPt = ConnEnd(shapeRef9, 16); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef11, 20); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef10 connRef = new ConnRef(router, 10); srcPt = ConnEnd(shapeRef12, 21); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef13, 25); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef11 connRef = new ConnRef(router, 11); srcPt = ConnEnd(shapeRef12, 22); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef14, 26); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef12 connRef = new ConnRef(router, 12); srcPt = ConnEnd(shapeRef15, 27); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef17, 32); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef13 connRef = new ConnRef(router, 13); srcPt = ConnEnd(shapeRef16, 29); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef12, 24); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef14 connRef = new ConnRef(router, 14); srcPt = ConnEnd(shapeRef17, 31); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef5, 7); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef15 connRef = new ConnRef(router, 15); srcPt = ConnEnd(shapeRef18, 33); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef8, 14); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef16 connRef = new ConnRef(router, 16); srcPt = ConnEnd(shapeRef19, 35); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef5, 7); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef17 connRef = new ConnRef(router, 17); srcPt = ConnEnd(shapeRef20, 36); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef8, 14); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef18 connRef = new ConnRef(router, 18); srcPt = ConnEnd(shapeRef21, 37); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef9, 18); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); router->processTransaction(); // Test that connector 6 has three segments and doesnt loop right // around the shapes on the right due to the crossing penalty. bool suceeds = (connector6->displayRoute().size() == 4); //router->outputDiagram("output/forwardFlowingConnectors01"); delete router; return (suceeds ? 0 : 1); };
void LeaflessOrthoRouter::route(Logger *logger) { // Set up for logging. unsigned ln = logger != nullptr ? logger->nextLoggingIndex : 0; std::function<void(unsigned)> log = [ln, this, logger](unsigned n)->void{ if (logger!=nullptr) { std::string fn = string_format("%02d_%02d_routing_attempt", ln, n); std::string path = logger->writeFullPathForFilename(fn); this->m_ra.router.outputInstanceToSVG(path); } }; /* * We may need to route multiple times to ensure that at least two sides of each node are being used, * but in theory we should never have to route more than 4n+1 times. * * Proof: We always begin with an initial routing. We want to show it could be necessary to re-route * at most 4n times. * * In order to see this, we first argue that the worst-case-scenario for any single node is that it * require four routings. Consider then some node u all of whose edges have been routed to one side, s0. We * then pick some edge e0 incident to u, say that it may not connect to side s0, and we re-route for the first time. * * While unlikely, it could be that, for whatever reason, now all edges incident to node u are routed to some other side, * s1. We then pick some edge e1 (could be the same or different from e0), forbid it from connecting to * side s1, and re-route for a second time. * * Again, for whatever reason, all edges could now connect to one * of the two remaining sides, s2. Continuing in this way, we could be led to re-route a third and a fourth time. But * prior to the fourth re-routing it would be the case that for each side si of node u, there was * some edge ei incident to u that had been forbidden from connecting on side si. Therefore on the fourth * re-routing it would be impossible for all edges to connect on any single side of u. * * So much for the case of a single node. However, in again a highly unlikely worst-case-scenario, it could be * that during the first five routings no other node besides u was a pseudoleaf (had all edges routed to one side), * but after the fifth some other node became a pseudoleaf. In this way we could be led to do four re-routings * for each node in the graph. QED * * In practice, it would probably be very rare for more that two routings to ever be necessary. For this * requires the odd circumstance, considered in the proof, that forbidding one edge from connecting on a * given side somehow results in /all/ edges incident at that node migrating to some other, single side. * * In order that our theory be tested, we use an infinite loop with counter and assertion, instead * of a mere for-loop which would fail silently. */ size_t numRoutings = 0; size_t maxRoutings = 4*m_n + 1; while (true) { m_ra.router.processTransaction(); log(++numRoutings); // As explained in the comments above, at most five routings should ever be needed. COLA_ASSERT(numRoutings <= maxRoutings); // For testing purposes, we may want to record the results of // each routing attempt. if (recordEachAttempt) { m_ra.recordRoutes(true); routingAttemptTglf.push_back(m_graph->writeTglf()); } // Are there any nodes having all of their edges routed // out of just one side? This is what we want to prevent. // Such nodes would become leaves in a planarisation, so we // call them "pseudoleaves". Nodes pseudoLeaves; // For each such Node (if any), there is a sole direction in which // all connectors depart. We keep track of those directions as we work. vector<CardinalDir> soleDepartureDirecs; // Check each Node in the Graph: for (auto p : m_graph->getNodeLookup()) { Node_SP &u = p.second; const EdgesById edgeLookup = u->getEdgeLookup(); // Sanity check, that Node u is not an actual leaf: COLA_ASSERT(edgeLookup.size() > 1); // Determine the departure direction from Node u for its first Edge. auto edge_it = edgeLookup.cbegin(); CardinalDir d0 = departureDir((*edge_it).second, u); // If two or more directions have been used, some edge must depart // in a different direction than this one. (For if all the rest equal // this first one, then all are the same.) bool isPseudoLeaf = true; for (auto jt = ++edge_it; jt != edgeLookup.cend(); ++jt) { CardinalDir d1 = departureDir((*jt).second, u); if (d1 != d0) { isPseudoLeaf = false; break; } } if (isPseudoLeaf) { pseudoLeaves.push_back(u); soleDepartureDirecs.push_back(d0); } } // Are there any pseudoleaves? if (pseudoLeaves.empty()) { // If there are none, then we're done routing, and can break out of the outer while loop. break; } else { // But if there are still pseudoleaves, then we need to work on them. for (size_t i = 0; i < pseudoLeaves.size(); ++i) { // Get the Node and the direction in which all connectors currently depart from it. Node_SP u = pseudoLeaves[i]; CardinalDir d0 = soleDepartureDirecs[i]; // Now among all Edges incident at this Node we must select one that is still // allowed to depart in at least two directions (hence at least one different // from d0), and remove direction d0 from its list of allowed directions. // // If possible, we would like to choose such an Edge e such that if v is the Node // at the other end, then the predominant cardinal direction from Node u to Node v // be different than d0; for such would seem a suitable Edge to depart in a different // direction. However, such an Edge may not exist. In that case, we will just take // any one. Edge_SP candidate; for (auto p : u->getEdgeLookup()) { Edge_SP &e = p.second; // If this Edge is only allowed the one direction, then skip it. if (isSoleDirec(m_allowedConnDirs.at(e->id()).at(u->id()))) continue; // Otherwise mark it as the candidate. candidate = e; // Determine the predominant cardinal direction from Node u to the Node v at // the opposite end of Edge e. Node_SP v = e->getOtherEnd(*u); CardinalDir d1 = Compass::cardinalDirection(u, v); // If this is different from direction d0, then we're happy to accept this candidate. if (d1 != d0) break; } // Start with the directions allowed last time: ConnDirFlags available = m_allowedConnDirs.at(candidate->id()).at(u->id()); // XOR with the connection flag corresponding to cardinal direction d0, // so that this direction is no longer allowed. available ^= Compass::libavoidConnDirs.at(d0); // Record the new value. m_allowedConnDirs[candidate->id()][u->id()] = available; // Set a new ConnEnd. Point p = u->getCentre(); ConnEnd end(p, available); ConnRef *cr = m_ra.edgeIdToConnRef.at(candidate->id()); if (u->id() == candidate->getSourceEnd()->id()) { cr->setSourceEndpoint(end); } else { cr->setDestEndpoint(end); } } } } // Finally, the routing is done and we can set the connector routes in the Edge objects. m_ra.recordRoutes(true); }
int main(void) { Router *router = new Router(OrthogonalRouting); router->setRoutingParameter((RoutingParameter)0, 2); router->setRoutingParameter((RoutingParameter)1, 0); router->setRoutingParameter((RoutingParameter)2, 0); router->setRoutingParameter((RoutingParameter)3, 4000); router->setRoutingParameter((RoutingParameter)4, 9000); router->setRoutingParameter((RoutingParameter)5, 0); router->setRoutingParameter((RoutingParameter)6, 0); router->setRoutingParameter((RoutingParameter)7, 16); router->setRoutingParameter((RoutingParameter)8, 0); router->setRoutingOption((RoutingOption)0, false); router->setRoutingOption((RoutingOption)1, true); router->setRoutingOption((RoutingOption)2, false); router->setRoutingOption((RoutingOption)3, false); router->setRoutingOption((RoutingOption)4, true); router->setRoutingOption((RoutingOption)5, false); router->setRoutingOption((RoutingOption)6, true); Polygon polygon; ConnEnd srcPt; ConnEnd dstPt; ConnEnd heConnPt; PolyLine newRoute; ShapeConnectionPin *connPin = NULL; // shapeRef1 polygon = Polygon(4); polygon.ps[0] = Point(450, 330); polygon.ps[1] = Point(490, 330); polygon.ps[2] = Point(490, 450); polygon.ps[3] = Point(450, 450); ShapeRef *shapeRef1 = new ShapeRef(router, polygon, 1); connPin = new ShapeConnectionPin(shapeRef1, 1, 0, 0.333333, true, 10, (ConnDirFlags) 0); connPin->setExclusive(false); connPin = new ShapeConnectionPin(shapeRef1, 2, 0, 0.666667, true, 10, (ConnDirFlags) 0); connPin->setExclusive(false); connPin = new ShapeConnectionPin(shapeRef1, 3, 1, 0.5, true, 10, (ConnDirFlags) 0); connPin->setExclusive(false); connPin = new ShapeConnectionPin(shapeRef1, 4, 0.5, 0, true, 10, (ConnDirFlags) 0); connPin->setExclusive(false); // shapeRef8 polygon = Polygon(4); polygon.ps[0] = Point(502, 237.5); polygon.ps[1] = Point(502, 262.5); polygon.ps[2] = Point(438, 262.5); polygon.ps[3] = Point(438, 237.5); ShapeRef *shapeRef8 = new ShapeRef(router, polygon, 8); connPin = new ShapeConnectionPin(shapeRef8, 1, 0, 0.5, true, 1, (ConnDirFlags) 0); connPin = new ShapeConnectionPin(shapeRef8, 2, 1, 0.5, true, 1, (ConnDirFlags) 0); connPin = new ShapeConnectionPin(shapeRef8, 3, 0.5, 1, true, 1, (ConnDirFlags) 0); connPin = new ShapeConnectionPin(shapeRef8, 4, 0.5, 0, true, 1, (ConnDirFlags) 0); JunctionRef *junctionRef6 = new JunctionRef(router, Point(470, 300), 6); /* // This may be useful if junction pins are modified. connPin = new ShapeConnectionPin(junctionRef6, 2147483646, (ConnDirFlags) 15); */ // connRef9 ConnRef *connRef9 = new ConnRef(router, 9); srcPt = ConnEnd(junctionRef6); connRef9->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef8, 3); connRef9->setDestEndpoint(dstPt); connRef9->setRoutingType((ConnType)2); #if 1 // connRef10 - WITH BUG ConnRef *connRef10 = new ConnRef(router, 10); srcPt = ConnEnd(junctionRef6); connRef10->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef1, 4); connRef10->setDestEndpoint(dstPt); connRef10->setRoutingType((ConnType)2); #else // connRef10 - WITHOUT BUG ConnRef *connRef10 = new ConnRef(router, 10); srcPt = ConnEnd(shapeRef1, 4); connRef10->setSourceEndpoint(srcPt); dstPt = ConnEnd(junctionRef6); connRef10->setDestEndpoint(dstPt); connRef10->setRoutingType((ConnType)2); #endif // router->deleteConnector(connRef5); router->processTransaction(); ConnRef *mergedConn = junctionRef6->removeJunctionAndMergeConnectors(); router->processTransaction(); router->outputDiagram("output/removeJunctions01"); std::pair<ConnEnd, ConnEnd> ends = mergedConn->endpointConnEnds(); // Expected result: output images should be virtually identical. // Result: An endpoint seems to be disconnected from shapeRef8. bool isConnected = (ends.first.shape() == shapeRef8) || (ends.second.shape() == shapeRef8); delete router; return isConnected ? 0 : 1; };