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); }