// 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);
}
Exemple #2
0
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 DEBUGHANDLER
    if (m_router->debugHandler())
    {
        std::vector<Box> obstacleBoxes;
        ObstacleList::iterator obstacleIt = m_router->m_obstacles.begin();
        while (obstacleIt != m_router->m_obstacles.end())
        {
            Obstacle *obstacle = *obstacleIt;
            JunctionRef *junction = dynamic_cast<JunctionRef *> (obstacle);
            if (junction && ! junction->positionFixed())
            {
                // Junctions that are free to move are not treated as obstacles.
                ++obstacleIt;
                continue;
            }
            Box bbox = obstacle->routingBox();
            obstacleBoxes.push_back(bbox);
            ++obstacleIt;
        }
        m_router->debugHandler()->updateObstacleBoxes(obstacleBoxes);
    }
#endif

    // For each hyperedge...
    const size_t num_hyperedges = count();
    for (size_t i = 0; i < num_hyperedges; ++i)
    {
        if (m_terminal_vertices_vector[i].empty())
        {
            // Invalid hyperedge, ignore.
            continue;
        }

        // Execute the MTST method to find good junction positions and an
        // initial path.  A hyperedge tree will be built for the new route.
        JunctionHyperedgeTreeNodeMap hyperedgeTreeJunctions;
        MinimumTerminalSpanningTree mtst(m_router, 
                m_terminal_vertices_vector[i], &hyperedgeTreeJunctions);

        // 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();
}
// This method traverses the hyperedge tree and writes each of the paths
// back to the individual connectors as routes.
//
void HyperedgeTreeEdge::writeEdgesToConns(HyperedgeTreeNode *ignored,
        size_t pass)
{
    COLA_ASSERT(ignored != NULL);
    COLA_ASSERT(ends.first != NULL);
    COLA_ASSERT(ends.second != NULL);

    HyperedgeTreeNode *prevNode = 
            (ignored == ends.first) ? ends.first : ends.second;
    HyperedgeTreeNode *nextNode = 
            (ignored == ends.first) ? ends.second : ends.first;

    if (pass == 0)
    {
        conn->m_display_route.clear();
    }
    else if (pass == 1)
    {
        if (conn->m_display_route.empty())
        {
            //printf("[%u] - %g %g\n", conn->id(), prevNode->point.x, prevNode->point.y);
            conn->m_display_route.ps.push_back(prevNode->point);
        }
        //printf("[%u] + %g %g\n", conn->id(), nextNode->point.x, nextNode->point.y);
        conn->m_display_route.ps.push_back(nextNode->point);

        size_t nextNodeEdges = nextNode->edges.size();
        if (nextNodeEdges != 2)
        {
            // We have finished writing a connector.  If the node has just
            // two edges then it is an intermediate node on a connector.
            bool shouldReverse = false;
            if (nextNodeEdges == 1)
            {
                // This connector led to a terminal.
                if (nextNode->isConnectorSource)
                {
                    shouldReverse = true;
                }
                
                if (nextNode->isPinDummyEndpoint)
                {
                    // If may be that the hyperedge has an extra segment or
                    // two leading to the centre dummy pin used for connection 
                    // pin routing.  If so, remove these points from the
                    // resulting route.
                    conn->m_display_route.ps.pop_back();
                    if (prevNode->point == nextNode->point)
                    {
                        // Duplicated dummy point.  Remove second one.
                        conn->m_display_route.ps.pop_back();
                    }
                }
            }
            else // if (nextNodeEdges > 2)
            {
                // This connector was between two junctions.
                COLA_ASSERT(conn->m_dst_connend);
                JunctionRef *correctEndJunction = 
                        conn->m_dst_connend->junction();
                if (nextNode->junction != correctEndJunction)
                {
                    shouldReverse = true;
                }
            }

            if (shouldReverse == true)
            {
                // Reverse the written connector route.
                std::reverse(conn->m_display_route.ps.begin(),
                        conn->m_display_route.ps.end());
            }
        }

#ifdef DEBUGHANDLER
        if (conn->router()->debugHandler())
        {
            conn->router()->debugHandler()->updateConnectorRoute(
                    conn, -1, -1);
        }
#endif
    }

    nextNode->writeEdgesToConns(this, pass);
}