// This method splits the current edge, adding a node at the given point. // The current edge will connect the source node and the newly created node. // A new edge will connect the new node and the node at the other end of the // original edge. // void HyperEdgeTreeEdge::splitFromNodeAtPoint(HyperEdgeTreeNode *source, const Point& point) { // Make the source the first of the two nodes. if (ends.second == source) { std::swap(ends.second, ends.first); } COLA_ASSERT(ends.first == source); // Remember the other end. HyperEdgeTreeNode *target = ends.second; // Create a new node for the split point at the given position. HyperEdgeTreeNode *split = new HyperEdgeTreeNode(); split->point = point; // Create a new edge between the split point and the other end. new HyperEdgeTreeEdge(split, target, conn); // Disconnect the current edge from the other end and connect it to // the new split point node. target->disconnectEdge(this); ends.second = split; split->edges.push_back(this); }
// This method traverses the hyperedge tree removing zero length edges. // void HyperEdgeTreeNode::removeZeroLengthEdges(HyperEdgeTreeEdge *ignored) { for (std::list<HyperEdgeTreeEdge *>::iterator curr = edges.begin(); curr != edges.end(); ++curr) { HyperEdgeTreeEdge *edge = *curr; if (edge != ignored) { if (edge->zeroLength()) { HyperEdgeTreeNode *other = edge->followFrom(this); HyperEdgeTreeNode *target = NULL; HyperEdgeTreeNode *source = NULL; if (other->junction && ! junction) { target = other; source = this; } else if ( ! other->junction && junction) { target = this; source = other; } else if ( ! other->junction && ! junction) { target = this; source = other; } if (target) { edge->disconnectEdge(); delete edge; target->spliceEdgesFrom(source); delete source; target->removeZeroLengthEdges(ignored); return; } // XXX Deal with merging two junctions? } // Recursive call. edge->removeZeroLengthEdges(this); } } }
void HyperedgeRerouter::performRerouting(void) { COLA_ASSERT(m_router != NULL); m_new_junctions_vector.clear(); m_new_junctions_vector.resize(count()); m_new_connectors_vector.clear(); m_new_connectors_vector.resize(count()); #ifdef HYPEREDGE_DEBUG double minX = LIMIT; double minY = LIMIT; double maxX = -LIMIT; double maxY = -LIMIT; VertInf *curr = m_router->vertices.connsBegin(); while (curr) { Point p = curr->point; reduceRange(p.x); reduceRange(p.y); if (p.x > -LIMIT) { minX = std::min(minX, p.x); } if (p.x < LIMIT) { maxX = std::max(maxX, p.x); } if (p.y > -LIMIT) { minY = std::min(minY, p.y); } if (p.y < LIMIT) { maxY = std::max(maxY, p.y); } curr = curr->lstNext; } minX -= 8; minY -= 8; maxX += 8; maxY += 8; FILE *fp = fopen("hyperedge-debug.svg", "w"); fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); // width=\"100%%\" height=\"100%%\" fprintf(fp, "<svg xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%g %g %g %g\">\n", minX, minY, maxX - minX, maxY - minY); fprintf(fp, "<defs>\n"); fprintf(fp, "<style type=\"text/css\" ><![CDATA[\n"); fprintf(fp, ".shape { stroke-width: 1px; stroke: black; fill: blue; stroke-opacity: 0.50; fill-opacity: 0.50; }\n"); fprintf(fp, ".graph { opacity: 0; fill: none; stroke: red; stroke-width: 1px; }\n"); fprintf(fp, ".forest { fill: none; stroke: purple; stroke-width: 1px; }\n"); fprintf(fp, ".hyperedge { fill: none; stroke-width: 1px; }\n"); fprintf(fp, "]]></style>\n"); fprintf(fp, "</defs>\n"); fprintf(fp, "<g inkscape:groupmode=\"layer\" " "inkscape:label=\"ShapesRect\">\n"); ObstacleList::iterator obstacleIt = m_router->m_obstacles.begin(); while (obstacleIt != m_router->m_obstacles.end()) { Obstacle *obstacle = *obstacleIt; bool isShape = (NULL != dynamic_cast<ShapeRef *> (obstacle)); if ( ! isShape ) { // Don't output obstacles here, for now. ++obstacleIt; continue; } Box bb = obstacle->routingBox(); fprintf(fp, "<rect id=\"rect-%u\" x=\"%g\" y=\"%g\" width=\"%g\" " "height=\"%g\" class=\"shape\" />\n", obstacle->id(), bb.min.x, bb.min.y, bb.max.x - bb.min.x, bb.max.y - bb.min.y); // shapeContainsEndpointVertex(obstacle) ? "style=\"fill: green;\"" : ""); ++obstacleIt; } fprintf(fp, "</g>\n"); fprintf(fp, "<g inkscape:groupmode=\"layer\" " "id=\"graph\" style=\"display: none;\" " "inkscape:label=\"OrthogVisGraph\">\n"); EdgeInf *finish = m_router->visOrthogGraph.end(); for (EdgeInf *t = m_router->visOrthogGraph.begin(); t != finish; t = t->lstNext) { std::pair<Point, Point> ptpair = t->points(); Point p1 = ptpair.first; Point p2 = ptpair.second; reduceRange(p1.x); reduceRange(p1.y); reduceRange(p2.x); reduceRange(p2.y); // std::pair<VertID, VertID> ids = t->ids(); // (ids.first.isConnPt() || ids.second.isConnPt()) ? "style=\"stroke: green\" " : "" fprintf(fp, "<path class=\"graph\" d=\"M %g %g L %g %g\" " "%s />\n", p1.x, p1.y, p2.x, p2.y, "" ); } fprintf(fp, "</g>\n"); #endif // For each hyperedge... const size_t num_hyperedges = count(); for (size_t i = 0; i < num_hyperedges; ++i) { // Execute the MTST method to find good junction positions and an // initial path. A hyperedge tree will be build for the new route. JunctionHyperEdgeTreeNodeMap hyperEdgeTreeJunctions; MinimumTerminalSpanningTree mtst(m_router, m_terminal_vertices_vector[i], &hyperEdgeTreeJunctions); #ifdef HYPEREDGE_DEBUG mtst.setDebuggingOutput(fp, i); #endif // The older MTST construction method (faster, worse results). //mtst.constructSequential(); // The preferred MTST construction method. // Slightly slower, better quality results. mtst.constructInterleaved(); HyperEdgeTreeNode *treeRoot = mtst.rootJunction(); COLA_ASSERT(treeRoot); // Fill in connector information and join them to junctions of endpoints // of original connectors. treeRoot->addConns(NULL, m_router, m_deleted_connectors_vector[i], NULL); // Output the list of new junctions and connectors from hyperedge tree. treeRoot->listJunctionsAndConnectors(NULL, m_new_junctions_vector[i], m_new_connectors_vector[i]); // Write paths from the hyperedge tree back into individual // connector routes. for (size_t pass = 0; pass < 2; ++pass) { treeRoot->writeEdgesToConns(NULL, pass); } // Tell the router that we are deleting the objects used for the // previous path for the hyperedge. for (ConnRefList::iterator curr = m_deleted_connectors_vector[i].begin(); curr != m_deleted_connectors_vector[i].end(); ++curr) { // Clear visibility assigned for connection pins. (*curr)->assignConnectionPinVisibility(false); m_router->deleteConnector(*curr); } for (JunctionRefList::iterator curr = m_deleted_junctions_vector[i].begin(); curr != m_deleted_junctions_vector[i].end(); ++curr) { m_router->deleteJunction(*curr); } } // Clear the input to this class, so that new objects can be registered // for rerouting for the next time that transaction that is processed. m_terminals_vector.clear(); m_root_junction_vector.clear(); // Free temporarily added vertices. for (VertexList::iterator curr = m_added_vertices.begin(); curr != m_added_vertices.end(); ++curr) { (*curr)->removeFromGraph(); m_router->vertices.removeVertex(*curr); delete *curr; } m_added_vertices.clear(); #ifdef HYPEREDGE_DEBUG fprintf(fp, "</svg>\n"); fclose(fp); #endif }
// This method moves the junction at the given node along any shared paths // (so long as this action would not create any additional shared paths), // while also removing and freeing merged edges and nodes in the process. // It returns the new node where the junction is now located. // HyperEdgeTreeNode *HyperEdgeTreeNode::moveJunctionAlongCommonEdge( HyperEdgeTreeNode *self) { COLA_ASSERT(self->junction); HyperEdgeTreeNode *newSelf = NULL; std::vector<HyperEdgeTreeEdge *> commonEdges; std::vector<HyperEdgeTreeEdge *> otherEdges; // Consider each edge from this node in turn. for (std::list<HyperEdgeTreeEdge *>::iterator curr = self->edges.begin(); curr != self->edges.end(); ++curr) { HyperEdgeTreeEdge *currEdge = *curr; HyperEdgeTreeNode *currNode = currEdge->followFrom(self); commonEdges.clear(); otherEdges.clear(); if (currNode->junction) { // Don't shift junctions onto other junctions. continue; } // The current edge is a common edge we are looking to shift along. commonEdges.push_back(currEdge); // Consider each of the other edges. for (std::list<HyperEdgeTreeEdge *>::iterator curr2 = self->edges.begin(); curr2 != self->edges.end(); ++curr2) { if (curr == curr2) { // Except the current (curr) one. continue; } HyperEdgeTreeEdge *otherEdge = *curr2; HyperEdgeTreeNode *otherNode = otherEdge->followFrom(self); if (otherNode->point == currNode->point) { // A common edge can be at the same point, but can't have // a junction at it. if (otherNode->junction) { otherEdges.push_back(otherEdge); } else { commonEdges.push_back(otherEdge); } } else if (pointOnLine(self->point, otherNode->point, currNode->point)) { // A common edge can be a (longer) collinear line, but we // need to split the longer line at the other end of curr. otherEdge->splitFromNodeAtPoint(self, currNode->point); commonEdges.push_back(otherEdge); } else { // If the edge goes in another direction it is not common. otherEdges.push_back(otherEdge); } } if ((commonEdges.size() > 1) && (otherEdges.size() <= 1)) { // One of the common nodes becomes the target node, we move // all connections from the other common nodes to this node. // We also move the junction there and remove it from the // current node. HyperEdgeTreeNode *targetNode = commonEdges[0]->followFrom(self); for (size_t i = 1; i < commonEdges.size(); ++i) { HyperEdgeTreeNode *thisNode = commonEdges[i]->followFrom(self); commonEdges[i]->disconnectEdge(); targetNode->spliceEdgesFrom(thisNode); delete thisNode; delete commonEdges[i]; } targetNode->junction = self->junction; self->junction = NULL; if (otherEdges.empty()) { // Nothing else connected to this node, so remove the node // and the edge to the target node. commonEdges[0]->disconnectEdge(); delete commonEdges[0]; delete self; } else { // We need to mark commonEdges[0] as being from the connector // of the otherEdges[0]. commonEdges[0]->conn = otherEdges[0]->conn; } newSelf = targetNode; break; } } return newSelf; }
void HyperedgeRerouter::performRerouting(void) { COLA_ASSERT(m_router != NULL); m_new_junctions_vector.clear(); m_new_junctions_vector.resize(count()); m_new_connectors_vector.clear(); m_new_connectors_vector.resize(count()); // For each hyperedge... const size_t num_hyperedges = count(); for (size_t i = 0; i < num_hyperedges; ++i) { // Execute the MTST method to find good junction positions and an // initial path. A hyperedge tree will be build for the new route. JunctionHyperEdgeTreeNodeMap hyperEdgeTreeJunctions; MinimumTerminalSpanningTree mtst(m_router, m_terminal_vertices_vector[i], &hyperEdgeTreeJunctions); mtst.execute(); HyperEdgeTreeNode *treeRoot = mtst.rootJunction(); COLA_ASSERT(treeRoot); // Fill in connector information and join them to junctions of endpoints // of original connectors. treeRoot->addConns(NULL, m_router, m_deleted_connectors_vector[i], NULL); // Output the list of new junctions and connectors from hyperedge tree. treeRoot->listJunctionsAndConnectors(NULL, m_new_junctions_vector[i], m_new_connectors_vector[i]); // Write paths from the hyperedge tree back into individual // connector routes. for (size_t pass = 0; pass < 2; ++pass) { treeRoot->writeEdgesToConns(NULL, pass); } // Tell the router that we are deleting the objects used for the // previous path for the hyperedge. for (ConnRefList::iterator curr = m_deleted_connectors_vector[i].begin(); curr != m_deleted_connectors_vector[i].end(); ++curr) { m_router->deleteConnector(*curr); } for (JunctionRefList::iterator curr = m_deleted_junctions_vector[i].begin(); curr != m_deleted_junctions_vector[i].end(); ++curr) { m_router->deleteJunction(*curr); } } // Clear the input to this class, so that new objects can be registered // for rerouting for the next time that transaction that is processed. m_terminals_vector.clear(); m_root_junction_vector.clear(); // Free temporarily added vertices. for (VertexList::iterator curr = m_added_vertices.begin(); curr != m_added_vertices.end(); ++curr) { (*curr)->removeFromGraph(); m_router->vertices.removeVertex(*curr); delete *curr; } m_added_vertices.clear(); }