diff options
Diffstat (limited to 'src/libavoid/router.cpp')
| -rw-r--r-- | src/libavoid/router.cpp | 3131 |
1 files changed, 0 insertions, 3131 deletions
diff --git a/src/libavoid/router.cpp b/src/libavoid/router.cpp deleted file mode 100644 index 84f919f3d..000000000 --- a/src/libavoid/router.cpp +++ /dev/null @@ -1,3131 +0,0 @@ -/* - * vim: ts=4 sw=4 et tw=0 wm=0 - * - * libavoid - Fast, Incremental, Object-avoiding Line Router - * - * Copyright (C) 2004-2014 Monash University - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * See the file LICENSE.LGPL distributed with the library. - * - * Licensees holding a valid commercial license may use this file in - * accordance with the commercial license agreement provided with the - * library. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Author(s): Michael Wybrow -*/ - - -#include <algorithm> -#include <cmath> -#include <cfloat> - -#include "libavoid/shape.h" -#include "libavoid/router.h" -#include "libavoid/visibility.h" -#include "libavoid/connector.h" -#include "libavoid/junction.h" -#include "libavoid/viscluster.h" -#include "libavoid/connend.h" -#include "libavoid/debug.h" -#include "libavoid/orthogonal.h" -#include "libavoid/assertions.h" -#include "libavoid/connectionpin.h" - - -namespace Avoid { - - -Router::Router(const unsigned int flags) - : visOrthogGraph(), - PartialTime(false), - SimpleRouting(false), - ClusteredRouting(true), - // Poly-line algorithm options: - IgnoreRegions(true), - UseLeesAlgorithm(true), - InvisibilityGrph(true), - // General algorithm options: - SelectiveReroute(true), - PartialFeedback(false), - RubberBandRouting(false), - // Instrumentation: - st_checked_edges(0), - m_largest_assigned_id(0), - m_consolidate_actions(true), - m_currently_calling_destructors(false), - m_topology_addon(new TopologyAddonInterface()), - // Mode options: - m_allows_polyline_routing(false), - m_allows_orthogonal_routing(false), - m_static_orthogonal_graph_invalidated(true), - m_in_crossing_rerouting_stage(false), - m_settings_changes(false), - m_debug_handler(NULL) -{ - // At least one of the Routing modes must be set. - COLA_ASSERT(flags & (PolyLineRouting | OrthogonalRouting)); - - if (flags & PolyLineRouting) - { - m_allows_polyline_routing = true; - } - if (flags & OrthogonalRouting) - { - m_allows_orthogonal_routing = true; - } - - for (size_t p = 0; p < lastRoutingParameterMarker; ++p) - { - m_routing_parameters[p] = 0.0; - } - m_routing_parameters[segmentPenalty] = 10; - m_routing_parameters[clusterCrossingPenalty] = 4000; - m_routing_parameters[idealNudgingDistance] = 4.0; - - m_routing_options[nudgeOrthogonalSegmentsConnectedToShapes] = false; - m_routing_options[improveHyperedgeRoutesMovingJunctions] = true; - m_routing_options[penaliseOrthogonalSharedPathsAtConnEnds] = false; - m_routing_options[nudgeOrthogonalTouchingColinearSegments] = false; - m_routing_options[performUnifyingNudgingPreprocessingStep] = true; - m_routing_options[improveHyperedgeRoutesMovingAddingAndDeletingJunctions] = - false; - m_routing_options[nudgeSharedPathsWithCommonEndPoint] = true; - - m_hyperedge_improver.setRouter(this); - m_hyperedge_rerouter.setRouter(this); -} - - -Router::~Router() -{ - m_currently_calling_destructors = true; - - // Delete remaining connectors. - ConnRefList::iterator conn = connRefs.begin(); - while (conn != connRefs.end()) - { - db_printf("Deleting connector %u in ~Router()\n", (*conn)->id()); - delete *conn; - conn = connRefs.begin(); - } - - // Remove remaining obstacles (shapes and junctions). - ObstacleList::iterator obstacle = m_obstacles.begin(); - while (obstacle != m_obstacles.end()) - { - Obstacle *obstaclePtr = *obstacle; - ShapeRef *shape = dynamic_cast<ShapeRef *> (obstaclePtr); - db_printf("Deleting %s %u in ~Router()\n", - (shape) ? "shape" : "junction", obstaclePtr->id()); - if (obstaclePtr->isActive()) - { - obstaclePtr->removeFromGraph(); - obstaclePtr->makeInactive(); - } - delete obstaclePtr; - obstacle = m_obstacles.begin(); - } - m_currently_calling_destructors = false; - - // Cleanup orphaned orthogonal graph vertices. - destroyOrthogonalVisGraph(); - - COLA_ASSERT(m_obstacles.size() == 0); - COLA_ASSERT(connRefs.size() == 0); - COLA_ASSERT(visGraph.size() == 0); - - delete m_topology_addon; -} - -void Router::setDebugHandler(DebugHandler *handler) -{ - m_debug_handler = handler; -} - -DebugHandler *Router::debugHandler(void) const -{ - return m_debug_handler; -} - -ShapeRef *Router::shapeContainingPoint(const Point& point) -{ - // Count points on the border as being inside. - bool countBorder = true; - - // Compute enclosing shapes. - ObstacleList::const_iterator finish = m_obstacles.end(); - for (ObstacleList::const_iterator i = m_obstacles.begin(); i != finish; ++i) - { - ShapeRef *shape = dynamic_cast<ShapeRef *>(*i); - if (shape && inPoly(shape->routingPolygon(), point, countBorder)) - { - return shape; - } - } - return NULL; -} - -void Router::modifyConnector(ConnRef *conn, const unsigned int type, - const ConnEnd& connEnd, bool connPinMoveUpdate) -{ - ActionInfo modInfo(ConnChange, conn); - - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), modInfo); - if (found == actionList.end()) - { - // Matching action not found, so add. - modInfo.conns.push_back(std::make_pair(type, connEnd)); - actionList.push_back(modInfo); - } - else - { - // Update the found action as necessary. - found->addConnEndUpdate(type, connEnd, connPinMoveUpdate); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::modifyConnector(ConnRef *conn) -{ - ActionInfo modInfo(ConnChange, conn); - - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), modInfo); - if (found == actionList.end()) - { - actionList.push_back(modInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::modifyConnectionPin(ShapeConnectionPin *pin) -{ - ActionInfo modInfo(ConnectionPinChange, pin); - - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), modInfo); - if (found == actionList.end()) - { - actionList.push_back(modInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::removeObjectFromQueuedActions(const void *object) -{ - for (ActionInfoList::iterator curr = actionList.begin(); - curr != actionList.end(); ) - { - if (curr->objPtr == object) - { - curr = actionList.erase(curr); - } - else - { - ++curr; - } - } -} - - -void Router::addShape(ShapeRef *shape) -{ - // There shouldn't be remove events or move events for the same shape - // already in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(ShapeRemove, shape)) == actionList.end()); - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(ShapeMove, shape)) == actionList.end()); - - ActionInfo addInfo(ShapeAdd, shape); - - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), addInfo); - if (found == actionList.end()) - { - actionList.push_back(addInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::deleteShape(ShapeRef *shape) -{ - // There shouldn't be add events events for the same shape already - // in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(ShapeAdd, shape)) == actionList.end()); - - // Delete any ShapeMove entries for this shape in the action list. - ActionInfoList::iterator found = find(actionList.begin(), - actionList.end(), ActionInfo(ShapeMove, shape)); - if (found != actionList.end()) - { - actionList.erase(found); - } - - // Add the ShapeRemove entry. - ActionInfo remInfo(ShapeRemove, shape); - found = find(actionList.begin(), actionList.end(), remInfo); - if (found == actionList.end()) - { - actionList.push_back(remInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::deleteConnector(ConnRef *connector) -{ - m_currently_calling_destructors = true; - delete connector; - m_currently_calling_destructors = false; -} - -void Router::moveShape(ShapeRef *shape, const double xDiff, const double yDiff) -{ - ActionInfo moveInfo(ShapeMove, shape, Polygon(), false); - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), moveInfo); - - Polygon newPoly; - if (found != actionList.end()) - { - // The shape already has a queued move, so use that shape position. - newPoly = found->newPoly; - } - else - { - // Just use the existing position. - newPoly = shape->polygon(); - } - newPoly.translate(xDiff, yDiff); - - moveShape(shape, newPoly); -} - - -void Router::markAllObstaclesAsMoved(void) -{ - for (ObstacleList::iterator obstacleIt = m_obstacles.begin(); - obstacleIt != m_obstacles.end(); ++obstacleIt) - { - ShapeRef *shape = dynamic_cast<ShapeRef *> (*obstacleIt); - JunctionRef *junction = dynamic_cast<JunctionRef *> (*obstacleIt); - if (shape) - { - moveShape(shape, 0, 0); - } - else if (junction) - { - moveJunction(junction, 0, 0); - } - } -} - -void Router::moveShape(ShapeRef *shape, const Polygon& newPoly, - const bool first_move) -{ - // There shouldn't be remove events or add events for the same shape - // already in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(ShapeRemove, shape)) == actionList.end()); - - ActionInfoList::iterator found = find(actionList.begin(), - actionList.end(), ActionInfo(ShapeAdd, shape)); - if (found != actionList.end()) - { - // The Add is enough, no need for the Move action too. - // The shape will be added with it's existing polygon, - // so set this to be the newPoly passed for the move. - found->shape()->setNewPoly(newPoly); - return; - } - - ActionInfo moveInfo(ShapeMove, shape, newPoly, first_move); - // Sanely cope with the case where the user requests moving the same - // shape multiple times before rerouting connectors. - found = find(actionList.begin(), actionList.end(), moveInfo); - - if (found != actionList.end()) - { - // Just update the ActionInfo with the second polygon, but - // leave the firstMove setting alone. - found->newPoly = newPoly; - } - else - { - actionList.push_back(moveInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::setStaticGraphInvalidated(const bool invalidated) -{ - m_static_orthogonal_graph_invalidated = invalidated; -} - - -void Router::destroyOrthogonalVisGraph(void) -{ - // Remove orthogonal visibility graph edges. - visOrthogGraph.clear(); - - // Remove the now orphaned vertices. - VertInf *curr = vertices.shapesBegin(); - while (curr) - { - if (curr->orphaned() && (curr->id == dummyOrthogID)) - { - VertInf *following = vertices.removeVertex(curr); - delete curr; - curr = following; - continue; - } - curr = curr->lstNext; - } -} - - -void Router::regenerateStaticBuiltGraph(void) -{ - // Here we do talks involved in updating the static-built visibility - // graph (if necessary) before we do any routing. - if (m_static_orthogonal_graph_invalidated) - { - if (m_allows_orthogonal_routing) - { - destroyOrthogonalVisGraph(); - - TIMER_START(this, tmOrthogGraph); - // Regenerate a new visibility graph. - generateStaticOrthogonalVisGraph(this); - - TIMER_STOP(this); - } - m_static_orthogonal_graph_invalidated = false; - } -} - - -bool Router::transactionUse(void) const -{ - return m_consolidate_actions; -} - - -void Router::setTransactionUse(const bool transactions) -{ - m_consolidate_actions = transactions; -} - - -// Processes the action list. -void Router::processActions(void) -{ - bool notPartialTime = !(PartialFeedback && PartialTime); - bool seenShapeMovesOrDeletes = false; - - m_transaction_start_time = clock(); - m_abort_transaction = false; - - std::list<unsigned int> deletedObstacles; - actionList.sort(); - ActionInfoList::iterator curr; - ActionInfoList::iterator finish = actionList.end(); - for (curr = actionList.begin(); curr != finish; ++curr) - { - ActionInfo& actInf = *curr; - if (!((actInf.type == ShapeRemove) || (actInf.type == ShapeMove) || - (actInf.type == JunctionRemove) || (actInf.type == JunctionMove))) - { - // Not a move or remove action, so don't do anything. - continue; - } - seenShapeMovesOrDeletes = true; - - Obstacle *obstacle = actInf.obstacle(); - ShapeRef *shape = actInf.shape(); - JunctionRef *junction = actInf.junction(); - bool isMove = (actInf.type == ShapeMove) || - (actInf.type == JunctionMove);; - bool first_move = actInf.firstMove; - - unsigned int pid = obstacle->id(); - - // o Remove entries related to this shape's vertices - obstacle->removeFromGraph(); - - if (SelectiveReroute && (!isMove || notPartialTime || first_move)) - { - markPolylineConnectorsNeedingReroutingForDeletedObstacle(obstacle); - } - - adjustContainsWithDel(pid); - - if (isMove) - { - if (shape) - { - shape->moveAttachedConns(actInf.newPoly); - } - else if (junction) - { - junction->moveAttachedConns(actInf.newPosition); - } - } - - // Ignore this shape for visibility. - // XXX: We don't really need to do this if we're not using Partial - // Feedback. Without this the blocked edges still route - // around the shape until it leaves the connector. - obstacle->makeInactive(); - - if (!isMove) - { - // Free deleted obstacle. - m_currently_calling_destructors = true; - deletedObstacles.push_back(obstacle->id()); - delete obstacle; - m_currently_calling_destructors = false; - } - } - - if (seenShapeMovesOrDeletes && m_allows_polyline_routing) - { - if (InvisibilityGrph) - { - // Check edges for obstacles that were moved or removed. - for (curr = actionList.begin(); curr != finish; ++curr) - { - ActionInfo& actInf = *curr; - if ((actInf.type == ShapeMove) || (actInf.type == JunctionMove)) - { - // o Check all edges that were blocked by moved obstacle. - checkAllBlockedEdges(actInf.obstacle()->id()); - } - } - - for (std::list<unsigned int>::iterator it = deletedObstacles.begin(); - it != deletedObstacles.end(); ++it) - { - // o Check all edges that were blocked by deleted obstacle. - checkAllBlockedEdges(*it); - } - } - else - { - // check all edges not in graph - checkAllMissingEdges(); - } - } - - for (curr = actionList.begin(); curr != finish; ++curr) - { - ActionInfo& actInf = *curr; - if (!((actInf.type == ShapeAdd) || (actInf.type == ShapeMove) || - (actInf.type == JunctionAdd) || (actInf.type == JunctionMove))) - { - // Not a move or add action, so don't do anything. - continue; - } - - Obstacle *obstacle = actInf.obstacle(); - ShapeRef *shape = actInf.shape(); - JunctionRef *junction = actInf.junction(); - Polygon& newPoly = actInf.newPoly; - bool isMove = (actInf.type == ShapeMove) || - (actInf.type == JunctionMove); - - unsigned int pid = obstacle->id(); - - // Restore this shape for visibility. - obstacle->makeActive(); - - if (isMove) - { - if (shape) - { - shape->setNewPoly(newPoly); - } - else - { - junction->setPosition(actInf.newPosition); - } - } - const Polygon& shapePoly = obstacle->routingPolygon(); - - adjustContainsWithAdd(shapePoly, pid); - - if (m_allows_polyline_routing) - { - // o Check all visibility edges to see if this one shape - // blocks them. - if (!isMove || notPartialTime) - { - newBlockingShape(shapePoly, pid); - } - - // o Calculate visibility for the new vertices. - if (UseLeesAlgorithm) - { - obstacle->computeVisibilitySweep(); - } - else - { - obstacle->computeVisibilityNaive(); - } - obstacle->updatePinPolyLineVisibility(); - } - } - - // Update connector endpoints. - for (curr = actionList.begin(); curr != finish; ++curr) - { - ActionInfo& actInf = *curr; - if (actInf.type != ConnChange) - { - continue; - } - for (ConnUpdateList::iterator conn = actInf.conns.begin(); - conn != actInf.conns.end(); ++conn) - { - actInf.conn()->updateEndPoint(conn->first, conn->second); - } - } - // Clear the actionList. - actionList.clear(); -} - -bool Router::processTransaction(void) -{ - // If SimpleRouting, then don't update here. - if ((actionList.empty() && (m_hyperedge_rerouter.count() == 0) && - (m_settings_changes == false)) || SimpleRouting) - { - return false; - } - m_settings_changes = false; - - processActions(); - - m_static_orthogonal_graph_invalidated = true; - rerouteAndCallbackConnectors(); - - return true; -} - - -void Router::addJunction(JunctionRef *junction) -{ - // There shouldn't be remove events or move events for the same junction - // already in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(JunctionRemove, junction)) == actionList.end()); - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(JunctionMove, junction)) == actionList.end()); - - ActionInfo addInfo(JunctionAdd, junction); - - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), addInfo); - if (found == actionList.end()) - { - actionList.push_back(addInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::deleteJunction(JunctionRef *junction) -{ - // There shouldn't be add events events for the same junction already - // in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(JunctionAdd, junction)) == actionList.end()); - - // Delete any ShapeMove entries for this shape in the action list. - ActionInfoList::iterator found = find(actionList.begin(), - actionList.end(), ActionInfo(JunctionMove, junction)); - if (found != actionList.end()) - { - actionList.erase(found); - } - - // Add the ShapeRemove entry. - ActionInfo remInfo(JunctionRemove, junction); - found = find(actionList.begin(), actionList.end(), remInfo); - if (found == actionList.end()) - { - actionList.push_back(remInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - - -void Router::moveJunction(JunctionRef *junction, const double xDiff, - const double yDiff) -{ - ActionInfo moveInfo(JunctionMove, junction, Point()); - ActionInfoList::iterator found = - find(actionList.begin(), actionList.end(), moveInfo); - - Point newPosition; - if (found != actionList.end()) - { - // The junction already has a queued move, so use that position. - newPosition = found->newPosition; - } - else - { - // Just use the existing position. - newPosition = junction->position(); - } - newPosition.x += xDiff; - newPosition.y += yDiff; - - moveJunction(junction, newPosition); -} - - -void Router::moveJunction(JunctionRef *junction, const Point& newPosition) -{ - // There shouldn't be remove events or add events for the same junction - // already in the action list. - // XXX: Possibly we could handle this by ordering them intelligently. - COLA_ASSERT(find(actionList.begin(), actionList.end(), - ActionInfo(JunctionRemove, junction)) == actionList.end()); - - ActionInfoList::iterator found = find(actionList.begin(), - actionList.end(), ActionInfo(JunctionAdd, junction)); - if (found != actionList.end()) - { - // The Add is enough, no need for the Move action too. - // The junction will be added with the new position. - found->junction()->setPosition(newPosition); - return; - } - - ActionInfo moveInfo(JunctionMove, junction, newPosition); - // Sanely cope with the case where the user requests moving the same - // shape multiple times before rerouting connectors. - found = find(actionList.begin(), actionList.end(), moveInfo); - - if (found != actionList.end()) - { - // Just update the ActionInfo with the second position. - found->newPosition = newPosition; - } - else - { - actionList.push_back(moveInfo); - } - - if (!m_consolidate_actions) - { - processTransaction(); - } -} - -void Router::addCluster(ClusterRef *cluster) -{ - cluster->makeActive(); - - unsigned int pid = cluster->id(); - ReferencingPolygon& poly = cluster->polygon(); - - adjustClustersWithAdd(poly, pid); -} - - -void Router::deleteCluster(ClusterRef *cluster) -{ - cluster->makeInactive(); - - unsigned int pid = cluster->id(); - - adjustClustersWithDel(pid); -} - - -unsigned int Router::newObjectId(void) const -{ - return m_largest_assigned_id + 1; -} - - -unsigned int Router::assignId(const unsigned int suggestedId) -{ - // If the suggestedId is zero, then we assign the object the next - // smallest unassigned ID, otherwise we trust the ID given is unique. - unsigned int assignedId = (suggestedId == 0) ? newObjectId() : suggestedId; - - // If assertions are enabled, then we check that this ID really is unique. - COLA_ASSERT(objectIdIsUnused(assignedId)); - - // Have the router record if this ID is larger than the largest assigned ID. - m_largest_assigned_id = std::max(m_largest_assigned_id, assignedId); - - return assignedId; -} - - - // Returns whether the given ID is unique among all objects known by the - // router. It is expected this is only going to be called from assertions - // while debugging, so efficiency is not an issue and we just iterate over - // all objects. -bool Router::objectIdIsUnused(const unsigned int id) const -{ - // Examine shapes/junctions. - for (ObstacleList::const_iterator i = m_obstacles.begin(); - i != m_obstacles.end(); ++i) - { - if ((*i)->id() == id) - { - return false; - } - } - - // Examine connectors. - for (ConnRefList::const_iterator i = connRefs.begin(); - i != connRefs.end(); ++i) - { - if ((*i)->id() == id) - { - return false; - } - } - - // Examine clusters. - for (ClusterRefList::const_iterator i = clusterRefs.begin(); - i != clusterRefs.end(); ++i) - { - if ((*i)->id() == id) - { - return false; - } - } - - return true; -} - - -//---------------------------------------------------------------------------- - - // Returns a list of connector Ids of all the connectors of type - // 'type' attached to the shape with the ID 'shapeId'. -void Router::attachedConns(IntList &conns, const unsigned int shapeId, - const unsigned int type) -{ - ConnRefList::const_iterator fin = connRefs.end(); - for (ConnRefList::const_iterator i = connRefs.begin(); i != fin; ++i) - { - std::pair<Obstacle *, Obstacle *> anchors = (*i)->endpointAnchors(); - - if ((type & runningTo) && - (anchors.second && (anchors.second->id() == shapeId))) - { - conns.push_back((*i)->id()); - } - else if ((type & runningFrom) && - (anchors.first && (anchors.first->id() == shapeId))) - { - conns.push_back((*i)->id()); - } - } -} - - - // Returns a list of shape Ids of all the shapes attached to the - // shape with the ID 'shapeId' with connection type 'type'. -void Router::attachedShapes(IntList &shapes, const unsigned int shapeId, - const unsigned int type) -{ - ConnRefList::const_iterator fin = connRefs.end(); - for (ConnRefList::const_iterator i = connRefs.begin(); i != fin; ++i) - { - std::pair<Obstacle *, Obstacle *> anchors = (*i)->endpointAnchors(); - - if ((type & runningTo) && - (anchors.second && (anchors.second->id() == shapeId))) - { - if (anchors.first) - { - // Only if there is a shape attached to the other end. - shapes.push_back(anchors.first->id()); - } - } - else if ((type & runningFrom) && - (anchors.first && (anchors.first->id() == shapeId))) - { - if (anchors.second) - { - // Only if there is a shape attached to the other end. - shapes.push_back(anchors.second->id()); - } - } - } -} - - - // It's intended this function is called after visibility changes - // resulting from shape movement have happened. It will alert - // rerouted connectors (via a callback) that they need to be redrawn. -void Router::rerouteAndCallbackConnectors(void) -{ - ConnRefList reroutedConns; - ConnRefList::const_iterator fin = connRefs.end(); - - this->m_conn_reroute_flags.alertConns(); - - // Updating the orthogonal visibility graph if necessary. - regenerateStaticBuiltGraph(); - - for (ConnRefList::const_iterator i = connRefs.begin(); i != fin; ++i) - { - (*i)->freeActivePins(); - } - - // Calculate and return connectors that are part of hyperedges and will - // be completely rerouted by that code and thus don't need to have routes - // generated here. - ConnRefSet hyperedgeConns = - m_hyperedge_rerouter.calcHyperedgeConnectors(); - - // TODO: It might be worth sorting connectors and routing them from - // smallest to largest estimated cost. This way we likely get - // better exclusive pin assignment during initial routing. - - size_t totalConns = connRefs.size(); - size_t numOfReroutedConns = 0; - for (ConnRefList::const_iterator i = connRefs.begin(); i != fin; ++i) - { - // Progress reporting and continuation check. - performContinuationCheck(TransactionPhaseRouteSearch, - numOfReroutedConns, totalConns); - ++numOfReroutedConns; - - ConnRef *connector = *i; - if (hyperedgeConns.find(connector) != hyperedgeConns.end()) - { - // This will be rerouted by the hyperedge code, so do nothing. - continue; - } - - if (connector->hasFixedRoute()) - { - // We don't reroute connectors with fixed routes. - continue; - } - - TIMER_START(this, tmOrthogRoute); - connector->m_needs_repaint = false; - bool rerouted = connector->generatePath(); - if (rerouted) - { - reroutedConns.push_back(connector); - } - TIMER_STOP(this); - } - - - // Perform any complete hyperedge rerouting that has been requested. - m_hyperedge_rerouter.performRerouting(); - - // Find and reroute crossing connectors if crossing penalties are set. - improveCrossings(); - - bool withMinorImprovements = routingOption( - improveHyperedgeRoutesMovingJunctions); - bool withMajorImprovements = routingOption( - improveHyperedgeRoutesMovingAddingAndDeletingJunctions); - if (withMinorImprovements || withMajorImprovements) - { - m_hyperedge_improver.clear(); - m_hyperedge_improver.execute(withMajorImprovements); - } - - // Perform centring and nudging for orthogonal routes. - improveOrthogonalRoutes(this); - - // Find a list of all the deleted connectors in hyperedges. - HyperedgeNewAndDeletedObjectLists changedHyperedgeObjs = - m_hyperedge_improver.newAndDeletedObjectLists(); - ConnRefList deletedConns = changedHyperedgeObjs.deletedConnectorList; - for (size_t index = 0; index < m_hyperedge_rerouter.count(); ++index) - { - changedHyperedgeObjs = - m_hyperedge_rerouter.newAndDeletedObjectLists(index); - deletedConns.merge(changedHyperedgeObjs.deletedConnectorList); - } - - // Alert connectors that they need redrawing. - fin = reroutedConns.end(); - for (ConnRefList::const_iterator i = reroutedConns.begin(); i != fin; ++i) - { - ConnRef *conn = *i; - - // Skip hyperedge connectors which have been deleted. - ConnRefList::iterator findIt = std::find( - deletedConns.begin(), deletedConns.end(), conn); - if (findIt != deletedConns.end()) - { - // Connector deleted, skip. - continue; - } - - conn->m_needs_repaint = true; - conn->performCallback(); - } - - // Progress reporting. - performContinuationCheck(TransactionPhaseCompleted, 1, 1); -} - -// Type holding a cost estimate and ConnRef. -typedef std::pair<double, ConnRef *> ConnCostRef; - -// A comparison class used to order a set of ConnCostRefs. -class CmpConnCostRef -{ - public: - CmpConnCostRef() - { - } - bool operator() (const ConnCostRef& u, const ConnCostRef& v) const - { - return (u.second->id() < v.second->id()); - } -}; - -typedef std::set<ConnCostRef, CmpConnCostRef> ConnCostRefSet; -typedef std::list<ConnCostRefSet> ConnCostRefSetList; - - -static double cheapEstimatedCost(ConnRef *lineRef) -{ - // We use an estimate of overall connector length, reduced by a count - // of the number of segments. In the case of equal length, This causes - // straight line connectors to be left alone and connectors with more - // complex paths to be rerouted. - bool isPolyLine = (lineRef->routingType() == ConnType_PolyLine); - const PolyLine& route = lineRef->displayRoute(); - double length = 0; - - for (size_t i = 1; i < route.size(); ++i) - { - const Point& a = route.ps[i - 1]; - const Point& b = route.ps[i]; - - double segmentLength = (isPolyLine) ? - euclideanDist(a, b) : manhattanDist(a, b); - length += segmentLength; - } - return length - (route.size() + 1); -} - -// A map of connectors to the set of connectors that cross them. -typedef std::map<ConnRef *, std::set<ConnRef *> > CrossingConnectorsMap; - -// A list of connector crossing maps that don't interact with each other. -typedef std::list<CrossingConnectorsMap> CrossingConnectorsMapList; - -// This class maintains the list of connector crossing maps and provides -// methods for adding crossing connector pairs and getting the minimal sets -// of connectors that can be removed from each group to prevent crossings. -class CrossingConnectorsInfo -{ - public: - - // Add information that a pair of connectors cross. - void addCrossing(ConnRef *conn1, ConnRef *conn2) - { - // Find the existing or new group that this crossing - // should be recorded in. - CrossingConnectorsMapList::iterator it = - groupForCrossingConns(conn1, conn2); - CrossingConnectorsMap& pairsSet = *it; - - // Record the crossing. - pairsSet[conn1].insert(conn2); - pairsSet[conn2].insert(conn1); - } - - // This method builds and returns a list of non-interacting sets of - // connectors (with crossing counts) that need to be removed so there - // are no crossings. These are the connectors we reroute. Where - // these connectors attach to exclusive connection pins, we return - // and thus reroute all connectors attached to the exlcusive pins. We - // do this so we are no so committed to possible bad pin assignemnts. - ConnCostRefSetList crossingSetsListToRemoveCrossingsFromGroups(void) - { - // A list of the minimal sets of connectors that cause crossings - // in all groups of crossingconnectors. - ConnCostRefSetList crossingSetsList; - - // For each group of crossing connectors. - for (CrossingConnectorsMapList::iterator it = pairsSetList.begin(); - it != pairsSetList.end(); ++it) - { - // The minimal set of crossing-causing connectors. - // We will build this. - ConnCostRefSet crossingSet; - - // Set of exclusive pins that the crossing-causing connectors - // attach to. - std::set<ConnectionPinIds> exclusivePins; - - // The group of all crossing pairs. - CrossingConnectorsMap& pairsSet = *it; - - // For each crossing-causing connector. - ConnCostRef crossingCausingConnector; - while ( (crossingCausingConnector = - removeConnectorWithMostCrossings(pairsSet)).second != NULL ) - { - // Add it to our crossing-causing set. - crossingSet.insert(crossingCausingConnector); - - // Determine if it attaches to any exclusive pins and - // record these. - std::pair<ConnEnd, ConnEnd> ends = - crossingCausingConnector.second->endpointConnEnds(); - // Look at one end. - ShapeConnectionPin *pin = ends.first.m_active_pin; - if (pin && pin->isExclusive()) - { - exclusivePins.insert(pin->ids()); - } - // Look at other end. - pin = ends.second.m_active_pin; - if (pin && pin->isExclusive()) - { - exclusivePins.insert(pin->ids()); - } - } - - // For each of the remaining connectors which are not - // crossing-causing, add them to our crossing set if they - // attach to one of the exclusive pin classes which the - // crossing-causing connectors attached to. - for (CrossingConnectorsMap::const_iterator it2 = - pairsSet.begin(); it2 != pairsSet.end(); ++it2) - { - ConnRef *conn = it2->first; - std::pair<ConnEnd, ConnEnd> ends = conn->endpointConnEnds(); - // Look at one end. - ShapeConnectionPin *pin = ends.first.m_active_pin; - if (pin && pin->isExclusive()) - { - if (exclusivePins.count(pin->ids()) > 0) - { - // Attaches to an exclusive pin and it matches - // one attached to by the crossing-causing - // connectors. So add the conn to the - // crossing set and continue.. - crossingSet.insert(std::make_pair(0, conn)); - continue; - } - } - // Look at other end. - pin = ends.second.m_active_pin; - if (pin && pin->isExclusive()) - { - if (exclusivePins.count(pin->ids()) > 0) - { - // Attaches to an exclusive pin and it matches - // one attached to by the crossing-causing - // connectors. So add the conn to the - // crossing set. - crossingSet.insert(std::make_pair(0, conn)); - } - } - } - - if (!crossingSet.empty()) - { - crossingSetsList.push_back(crossingSet); - } - } - return crossingSetsList; - } - - // Returns whether this pair of connector is already known to cross. - bool connsKnownToCross(ConnRef *conn1, ConnRef *conn2) - { - CrossingConnectorsMapList::iterator it1 = groupForConn(conn1); - CrossingConnectorsMapList::iterator it2 = groupForConn(conn2); - - // The connectors cross if - if ((it1 == it2) && (it1 != pairsSetList.end())) - { - // They are in the same group and conn2 is in crossing - // connectors set of conn1. - CrossingConnectorsMap& pairsSet = *it1; - return ((pairsSet.count(conn1) > 0) && - (pairsSet[conn1].count(conn2) > 0)); - } - return false; - } - - private: - - // Given a particular group (pairsSet), removes the connector with - // the most crossings withing the group and returns it along with its - // crossing count. - ConnCostRef removeConnectorWithMostCrossings( - CrossingConnectorsMap& pairsSet) - { - // Tracking of the greatest number of crossings. - ConnRef *candidateConnector = NULL; - size_t candidateCrossingCount = 0; - double candidateEstimatedCost = 0; - - // For each connector in the group... - for (CrossingConnectorsMap::const_iterator it = pairsSet.begin(); - it != pairsSet.end(); ++it) - { - // ... check if it has any crossings. - size_t crossings = it->second.size(); - if (crossings == 0) - { - // If not, skip. - continue; - } - - // It has crossings. Determine if it has the most crossings - // of the connectors we've seen, or if it is tied but has - // a greater estimated cost. If so, it is our new candidate. - double cost = cheapEstimatedCost(it->first); - if ((crossings > candidateCrossingCount) || - ((crossings == candidateCrossingCount) && - (cost > candidateEstimatedCost))) - { - // Update with new candidate. - candidateConnector = it->first; - candidateCrossingCount = crossings; - candidateEstimatedCost = cost; - } - } - - if (candidateConnector == NULL) - { - // If no candidate, return NULL connector. - return std::make_pair(0, (ConnRef *) NULL); - } - - // Remove the candidate from the group. To do this we find the - // set of all connectors it crosses. - std::set<ConnRef *>& connSet = pairsSet[candidateConnector]; - // For each of these - for (std::set<ConnRef *>::const_iterator it = connSet.begin(); - it != connSet.end(); ++it) - { - // we remove the candidate from their crossing lists - pairsSet[*it].erase(candidateConnector); - } - // And then clear the crossing list for the candidate itself. - connSet.clear(); - - // Return the candidate connector and its original crossing count. - return std::make_pair(candidateCrossingCount, candidateConnector); - } - - // Returns the iterator to the group that the given conn is in, - // if it is part of any crossing group. - CrossingConnectorsMapList::iterator groupForConn(ConnRef *conn) - { - // For each group... - for (CrossingConnectorsMapList::iterator it = pairsSetList.begin(); - it != pairsSetList.end(); ++it) - { - // ... check if the connector is in it. - if (it->count(conn) > 0) - { - // If so, return it. - return it; - } - } - // Connector was not in any existing group. - return pairsSetList.end(); - } - - // Given a pair of crossing connectors, returns an iterator to the - // crossing connector group they are part of. If neither are part - // of any group, one is created and returned. If one connector is - // part of an exisitng group, that group is returned. If they are - // part of two different groups, the groups are merged and the - // merged group is returned. - CrossingConnectorsMapList::iterator groupForCrossingConns( - ConnRef *conn1, ConnRef *conn2) - { - CrossingConnectorsMapList::iterator it1 = groupForConn(conn1); - CrossingConnectorsMapList::iterator it2 = groupForConn(conn2); - - // groupIt will be the iterator to the appropriate group. - CrossingConnectorsMapList::iterator groupIt = pairsSetList.end(); - - if ((it1 == pairsSetList.end()) && (it2 == pairsSetList.end())) - { - // Neither are part of a group. Create one. - CrossingConnectorsMap newSet; - groupIt = pairsSetList.insert(pairsSetList.end(), newSet); - } - else if ((it1 != pairsSetList.end()) && (it2 == pairsSetList.end())) - { - // it1 is the appropriate existing group. - groupIt = it1; - } - else if ((it1 == pairsSetList.end()) && (it2 != pairsSetList.end())) - { - // it2 is the appropriate exisitng group. - groupIt = it2; - } - else if (it1 != it2) - { - // There are two different existing groups, so merge them. - COLA_ASSERT(it1 != pairsSetList.end()); - COLA_ASSERT(it2 != pairsSetList.end()); - it1->insert(it2->begin(), it2->end()); - pairsSetList.erase(it2); - groupIt = it1; - } - else - { - // These are already part of the same group. Do nothing. - COLA_ASSERT(it1 == it2); - groupIt = it1; - } - return groupIt; - } - - CrossingConnectorsMapList pairsSetList; -}; - - -void Router::performContinuationCheck(unsigned int phaseNumber, - size_t stepNumber, size_t totalSteps) -{ - // Compute the elapsed time in msec since the beginning of the transaction. - unsigned int elapsedMsec = (unsigned int) - ((clock() - m_transaction_start_time) / - (CLOCKS_PER_SEC / (double) 1000)); - - bool shouldContinue = shouldContinueTransactionWithProgress(elapsedMsec, - phaseNumber, TransactionPhaseCompleted, - stepNumber / (double)totalSteps); - if (shouldContinue == false) - { - // Host program has asked us not to continue the transaction. - m_abort_transaction = true; - } -} - - -bool Router::shouldContinueTransactionWithProgress(unsigned int elapsedTime, - unsigned int phaseNumber, unsigned int totalPhases, - double proportion) -{ - COLA_UNUSED(elapsedTime); - COLA_UNUSED(phaseNumber); - COLA_UNUSED(totalPhases); - COLA_UNUSED(proportion); - -#if 0 - printf("Progress: %8u, phase %u of %u... %.2f%%\n", elapsedTime, - phaseNumber, totalPhases, proportion * 100); -#endif - - // We always continue. Subclasses can override this behaviour. - return true; -} - - -class CmpOrderedConnCostRef -{ - public: - CmpOrderedConnCostRef() - { - } - bool operator() (const ConnCostRef& u, const ConnCostRef& v) const - { - return (u.first < v.first); - } -}; -typedef std::list<ConnCostRef> ConnCostRefList; - - -void Router::improveCrossings(void) -{ - const double crossing_penalty = routingParameter(crossingPenalty); - const double shared_path_penalty = routingParameter(fixedSharedPathPenalty); - if ((crossing_penalty == 0) && (shared_path_penalty == 0)) - { - // No penalties, return. - return; - } - - // Information on crossing connector groups. - CrossingConnectorsInfo crossingConnInfo; - - size_t numOfConns = connRefs.size(); - size_t numOfConnsChecked = 0; - - // Find crossings and reroute connectors. - m_in_crossing_rerouting_stage = true; - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - // Progress reporting and continuation check. - ++numOfConnsChecked; - performContinuationCheck(TransactionPhaseCrossingDetection, - numOfConnsChecked, numOfConns); - if (m_abort_transaction) - { - m_in_crossing_rerouting_stage = false; - return; - } - - Avoid::Polygon& iRoute = (*i)->routeRef(); - if (iRoute.size() == 0) - { - // Rerouted hyperedges will have an empty route. - // We can't reroute these. - continue; - } - ConnRefList::iterator j = i; - for (++j; j != fin; ++j) - { - if (crossingConnInfo.connsKnownToCross(*i, *j)) - { - // We already know both these have crossings. - continue; - } - - // Determine if this pair cross. - Avoid::Polygon& jRoute = (*j)->routeRef(); - ConnectorCrossings cross(iRoute, true, jRoute, *i, *j); - for (size_t jInd = 1; jInd < jRoute.size(); ++jInd) - { - const bool finalSegment = ((jInd + 1) == jRoute.size()); - cross.countForSegment(jInd, finalSegment); - - if ((shared_path_penalty > 0) && - (cross.crossingFlags & CROSSING_SHARES_PATH) && - (cross.crossingFlags & CROSSING_SHARES_FIXED_SEGMENT) && - (m_routing_options[penaliseOrthogonalSharedPathsAtConnEnds] || - !(cross.crossingFlags & CROSSING_SHARES_PATH_AT_END))) - { - // We are penalising fixedSharedPaths and there is a - // fixedSharedPath. - crossingConnInfo.addCrossing(*i, *j); - break; - } - else if ((crossing_penalty > 0) && (cross.crossingCount > 0)) - { - // We are penalising crossings and this is a crossing. - crossingConnInfo.addCrossing(*i, *j); - break; - } - } - } - } - - // Find the list of connector sets that need to be removed to avoid any - // crossings in all crossing groups. This is our candidate set for - // rerouting. Where these connectors connect to exlusive pins, all - // connectors attached to exclusive pins with the same IDs will also - // be rerouted, starting with the shortest. - ConnCostRefSetList crossingConnsGroups = - crossingConnInfo.crossingSetsListToRemoveCrossingsFromGroups(); - - // At this point we have a list containing crossings for rerouting. - // We do this rerouting via two passes, for each group of interacting - // crossing connectors: - // 1) clear existing routes and free pin assignments, and - // 2) compute new routes. - unsigned int numOfConnsToReroute = 1; - unsigned int numOfConnsRerouted = 1; - for (ConnCostRefSetList::iterator setIt = crossingConnsGroups.begin(); - setIt != crossingConnsGroups.end(); ++setIt) - { - // Sort the connectors we will be rerouting from lowest to - // highest cost. - ConnCostRefList orderedConnList(setIt->begin(), setIt->end()); - orderedConnList.sort(CmpOrderedConnCostRef()); - - // Perform rerouting of this set of connectors. - for (int pass = 0; pass < 2; ++pass) - { - for (ConnCostRefList::iterator connIt = orderedConnList.begin(); - connIt != orderedConnList.end(); ++connIt) - { - ConnRef *conn = connIt->second; - if (pass == 0) - { - ++numOfConnsToReroute; - - // Mark the fixed shared path as being invalid. - conn->makePathInvalid(); - - // Free the previous path, so it is not noticed by other - // connectors during rerouting. - conn->freeRoutes(); - - // Free pin assignments. - conn->freeActivePins(); - } - else if (pass == 1) - { - // Progress reporting and continuation check. - performContinuationCheck(TransactionPhaseRerouteSearch, - numOfConnsRerouted, numOfConnsToReroute); - if (m_abort_transaction) - { - m_in_crossing_rerouting_stage = false; - return; - } - ++numOfConnsRerouted; - - // Recompute this path. - conn->generatePath(); - } - } - } - } - m_in_crossing_rerouting_stage = false; -} - - -void Router::newBlockingShape(const Polygon& poly, int pid) -{ - // o Check all visibility edges to see if this one shape - // blocks them. - EdgeInf *finish = visGraph.end(); - for (EdgeInf *iter = visGraph.begin(); iter != finish ; ) - { - EdgeInf *tmp = iter; - iter = iter->lstNext; - - if (tmp->getDist() != 0) - { - std::pair<VertID, VertID> ids(tmp->ids()); - VertID eID1 = ids.first; - VertID eID2 = ids.second; - std::pair<Point, Point> points(tmp->points()); - Point e1 = points.first; - Point e2 = points.second; - bool blocked = false; - - bool countBorder = false; - bool ep_in_poly1 = (eID1.isConnPt()) ? - inPoly(poly, e1, countBorder) : false; - bool ep_in_poly2 = (eID2.isConnPt()) ? - inPoly(poly, e2, countBorder) : false; - if (ep_in_poly1 || ep_in_poly2) - { - // Don't check edges that have a connector endpoint - // and are inside the shape being added. - continue; - } - - bool seenIntersectionAtEndpoint = false; - for (size_t pt_i = 0; pt_i < poly.size(); ++pt_i) - { - size_t pt_n = (pt_i == (poly.size() - 1)) ? 0 : pt_i + 1; - const Point& pi = poly.ps[pt_i]; - const Point& pn = poly.ps[pt_n]; - if (segmentShapeIntersect(e1, e2, pi, pn, - seenIntersectionAtEndpoint)) - { - blocked = true; - break; - } - } - if (blocked) - { - db_printf("\tRemoving newly blocked edge (by shape %3d)" - "... \n\t\t", pid); - tmp->alertConns(); - tmp->db_print(); - if (InvisibilityGrph) - { - tmp->addBlocker(pid); - } - else - { - delete tmp; - } - } - } - } -} - - -void Router::checkAllBlockedEdges(int pid) -{ - COLA_ASSERT(InvisibilityGrph); - - for (EdgeInf *iter = invisGraph.begin(); iter != invisGraph.end() ; ) - { - EdgeInf *tmp = iter; - iter = iter->lstNext; - - if (tmp->blocker() == -1) - { - tmp->alertConns(); - tmp->checkVis(); - } - else if (tmp->blocker() == pid) - { - tmp->checkVis(); - } - } -} - - -void Router::checkAllMissingEdges(void) -{ - COLA_ASSERT(!InvisibilityGrph); - - VertInf *first = vertices.connsBegin(); - - VertInf *pend = vertices.end(); - for (VertInf *i = first; i != pend; i = i->lstNext) - { - VertID iID = i->id; - - // Check remaining, earlier vertices - for (VertInf *j = first ; j != i; j = j->lstNext) - { - VertID jID = j->id; - if (iID.isConnPt() && !iID.isConnectionPin() && - (iID.objID != jID.objID)) - { - // Don't keep visibility between edges of different conns - continue; - } - - // See if the edge is already there? - bool found = (EdgeInf::existingEdge(i, j) != NULL); - - if (!found) - { - // Didn't already exist, check. - bool knownNew = true; - EdgeInf::checkEdgeVisibility(i, j, knownNew); - } - } - } -} - - -void Router::generateContains(VertInf *pt) -{ - contains[pt->id].clear(); - enclosingClusters[pt->id].clear(); - - // Don't count points on the border as being inside. - bool countBorder = false; - - // Compute enclosing shapes. - ObstacleList::const_iterator finish = m_obstacles.end(); - for (ObstacleList::const_iterator i = m_obstacles.begin(); i != finish; ++i) - { - if (inPoly((*i)->routingPolygon(), pt->point, countBorder)) - { - contains[pt->id].insert((*i)->id()); - } - } - - // Computer enclosing Clusters - ClusterRefList::const_iterator clFinish = clusterRefs.end(); - for (ClusterRefList::const_iterator i = clusterRefs.begin(); - i != clFinish; ++i) - { - if (inPolyGen((*i)->polygon(), pt->point)) - { - enclosingClusters[pt->id].insert((*i)->id()); - } - } -} - - -void Router::adjustClustersWithAdd(const PolygonInterface& poly, - const int p_cluster) -{ - for (VertInf *k = vertices.connsBegin(); k != vertices.shapesBegin(); - k = k->lstNext) - { - if (inPolyGen(poly, k->point)) - { - enclosingClusters[k->id].insert(p_cluster); - } - } -} - - -void Router::adjustClustersWithDel(const int p_cluster) -{ - for (ContainsMap::iterator k = enclosingClusters.begin(); - k != enclosingClusters.end(); ++k) - { - (*k).second.erase(p_cluster); - } -} - - -void Router::adjustContainsWithAdd(const Polygon& poly, const int p_shape) -{ - // Don't count points on the border as being inside. - bool countBorder = false; - - for (VertInf *k = vertices.connsBegin(); k != vertices.shapesBegin(); - k = k->lstNext) - { - if (inPoly(poly, k->point, countBorder)) - { - contains[k->id].insert(p_shape); - } - } -} - - -void Router::adjustContainsWithDel(const int p_shape) -{ - for (ContainsMap::iterator k = contains.begin(); k != contains.end(); ++k) - { - (*k).second.erase(p_shape); - } -} - - -#ifdef SELECTIVE_DEBUG -static double AngleAFromThreeSides(const double a, const double b, - const double c) -{ - // returns angle A, the angle opposite from side a, in radians - return acos((pow(b, 2) + pow(c, 2) - pow(a, 2)) / (2 * b * c)); -} -#endif - -// Given an deleted obstacle, uses a simple heauristic to determine polyline -// connectors that may now have a better path through the region occupied by -// the shape and mark them as needing to be rerouted. -// See the "Incremental Connector Routing" paper which explains this code. -// -void Router::markPolylineConnectorsNeedingReroutingForDeletedObstacle( - Obstacle *obstacle) -{ - if (RubberBandRouting) - { - // When rubber-band routing, we do not reroute connectors that - // may have a better route, only invalid connectors. - return; - } - - COLA_ASSERT(SelectiveReroute); - - // For each connector... - ConnRefList::const_iterator end = connRefs.end(); - for (ConnRefList::const_iterator it = connRefs.begin(); it != end; ++it) - { - ConnRef *conn = (*it); - - if (conn->m_route.empty()) - { - // Ignore uninitialised connectors. - continue; - } - else if (conn->m_needs_reroute_flag) - { - // Already marked, so skip. - continue; - } - else if (conn->routingType() != ConnType_PolyLine) - { - // This test only works for polyline connectors, so skip others. - continue; - } - - Point start = conn->m_route.ps[0]; - Point end = conn->m_route.ps[conn->m_route.size() - 1]; - - double conndist = conn->m_route_dist; - - double estdist; - double e1, e2; - - // For each vertex of the obstacle... - VertInf *beginV = obstacle->firstVert(); - VertInf *endV = obstacle->lastVert()->lstNext; - for (VertInf *i = beginV; i != endV; i = i->lstNext) - { - const Point& p1 = i->point; - const Point& p2 = i->shNext->point; - - double offy; - double a; - double b; - double c; - double d; - - double min; - double max; - - if (p1.y == p2.y) - { - // Standard case - offy = p1.y; - a = start.x; - b = start.y - offy; - c = end.x; - d = end.y - offy; - - min = std::min(p1.x, p2.x); - max = std::max(p1.x, p2.x); - } - else if (p1.x == p2.x) - { - // Other Standard case - offy = p1.x; - a = start.y; - b = start.x - offy; - c = end.y; - d = end.x - offy; - - min = std::min(p1.y, p2.y); - max = std::max(p1.y, p2.y); - } - else - { - // Need to do rotation - Point n_p2(p2.x - p1.x, p2.y - p1.y); - Point n_start(start.x - p1.x, start.y - p1.y); - Point n_end(end.x - p1.x, end.y - p1.y); - //db_printf("n_p2: (%.1f, %.1f)\n", n_p2.x, n_p2.y); - //db_printf("n_start: (%.1f, %.1f)\n", n_start.x, n_start.y); - //db_printf("n_end: (%.1f, %.1f)\n", n_end.x, n_end.y); - - double theta = 0 - atan2(n_p2.y, n_p2.x); - //db_printf("theta = %.2f\n", theta * (180 / PI)); - - Point r_p1(0, 0); - Point r_p2 = n_p2; - start = n_start; - end = n_end; - - double cosv = cos(theta); - double sinv = sin(theta); - - r_p2.x = cosv * n_p2.x - sinv * n_p2.y; - r_p2.y = cosv * n_p2.y + sinv * n_p2.x; - start.x = cosv * n_start.x - sinv * n_start.y; - start.y = cosv * n_start.y + sinv * n_start.x; - end.x = cosv * n_end.x - sinv * n_end.y; - end.y = cosv * n_end.y + sinv * n_end.x; - //db_printf("r_p2: (%.1f, %.1f)\n", r_p2.x, r_p2.y); - //db_printf("r_start: (%.1f, %.1f)\n", start.x, start.y); - //db_printf("r_end: (%.1f, %.1f)\n", end.x, end.y); - - // This might be slightly off. - if (fabs(r_p2.y) > 0.0001) - { - db_printf("r_p2.y: %f != 0\n", r_p2.y); - } - r_p2.y = 0; - - offy = r_p1.y; - a = start.x; - b = start.y - offy; - c = end.x; - d = end.y - offy; - - min = std::min(r_p1.x, r_p2.x); - max = std::max(r_p1.x, r_p2.x); - - } - - double x; - if ((b + d) == 0) - { - db_printf("WARNING: (b + d) == 0\n"); - d = d * -1; - } - - if ((b == 0) && (d == 0)) - { - db_printf("WARNING: b == d == 0\n"); - if (((a < min) && (c < min)) || - ((a > max) && (c > max))) - { - // It's going to get adjusted. - x = a; - } - else - { - continue; - } - } - else - { - x = ((b*c) + (a*d)) / (b + d); - } - - //db_printf("%.1f, %.1f, %.1f, %.1f\n", a, b, c, d); - //db_printf("x = %.1f\n", x); - - x = std::max(min, x); - x = std::min(max, x); - - //db_printf("x = %.1f\n", x); - - Point xp; - if (p1.x == p2.x) - { - xp.x = offy; - xp.y = x; - } - else - { - xp.x = x; - xp.y = offy; - } - //db_printf("(%.1f, %.1f)\n", xp.x, xp.y); - - e1 = euclideanDist(start, xp); - e2 = euclideanDist(xp, end); - estdist = e1 + e2; - - - //db_printf("is %.1f < %.1f\n", estdist, conndist); - if (estdist < conndist) - { -#ifdef SELECTIVE_DEBUG - //double angle = AngleAFromThreeSides(dist(start, end), - // e1, e2); - db_printf("[%3d] - Possible better path found (%.1f < %.1f)\n", - conn->_id, estdist, conndist); -#endif - conn->m_needs_reroute_flag = true; - break; - } - - } - } -} - - -ConnType Router::validConnType(const ConnType select) const -{ - if (select != ConnType_None) - { - if ((select == ConnType_Orthogonal) && m_allows_orthogonal_routing) - { - return ConnType_Orthogonal; - } - else if ((select == ConnType_PolyLine) && m_allows_polyline_routing) - { - return ConnType_PolyLine; - } - } - - if (m_allows_polyline_routing) - { - return ConnType_PolyLine; - } - else if (m_allows_orthogonal_routing) - { - return ConnType_Orthogonal; - } - return ConnType_None; -} - - -void Router::setRoutingParameter(const RoutingParameter parameter, - const double value) -{ - COLA_ASSERT(parameter < lastRoutingParameterMarker); - if (value < 0) - { - // Set some sensible parameter value for the parameter being 'active'. - switch (parameter) - { - case segmentPenalty: - m_routing_parameters[parameter] = 50; - break; - case fixedSharedPathPenalty: - m_routing_parameters[parameter] = 110; - break; - case anglePenalty: - m_routing_parameters[parameter] = 50; - break; - case crossingPenalty: - m_routing_parameters[parameter] = 200; - break; - case clusterCrossingPenalty: - m_routing_parameters[parameter] = 4000; - break; - case idealNudgingDistance: - m_routing_parameters[parameter] = 4.0; - break; - case portDirectionPenalty: - m_routing_parameters[parameter] = 100; - break; - default: - m_routing_parameters[parameter] = 50; - break; - } - } - else - { - m_routing_parameters[parameter] = value; - } - m_settings_changes = true; -} - - -double Router::routingParameter(const RoutingParameter parameter) const -{ - COLA_ASSERT(parameter < lastRoutingParameterMarker); - return m_routing_parameters[parameter]; -} - - -void Router::setRoutingOption(const RoutingOption option, const bool value) -{ - COLA_ASSERT(option < lastRoutingOptionMarker); - m_routing_options[option] = value; - m_settings_changes = true; -} - - -bool Router::routingOption(const RoutingOption option) const -{ - COLA_ASSERT(option < lastRoutingOptionMarker); - return m_routing_options[option]; -} - - -void Router::setRoutingPenalty(const RoutingParameter penType, - const double penValue) -{ - setRoutingParameter(penType, penValue); -} - -void Router::registerSettingsChange(void) -{ - m_settings_changes = true; -} - -HyperedgeRerouter *Router::hyperedgeRerouter(void) -{ - return &m_hyperedge_rerouter; -} - - -bool Router::isInCrossingPenaltyReroutingStage(void) const -{ - return m_in_crossing_rerouting_stage; -} - - -void Router::printInfo(void) -{ - FILE *fp = stdout; - fprintf(fp, "\nVisibility Graph info:\n"); - fprintf(fp, "----------------------\n"); - - unsigned int currshape = 0; - int st_shapes = 0; - int st_vertices = 0; - int st_endpoints = 0; - int st_valid_shape_visedges = 0; - int st_valid_endpt_visedges = 0; - int st_orthogonal_visedges = 0; - int st_invalid_visedges = 0; - VertInf *finish = vertices.end(); - for (VertInf *t = vertices.connsBegin(); t != finish; t = t->lstNext) - { - VertID pID = t->id; - - if (!(pID.isConnPt()) && (pID.objID != currshape)) - { - currshape = pID.objID; - st_shapes++; - } - if (!(pID.isConnPt())) - { - st_vertices++; - } - else - { - // The shape 0 ones are temporary and not considered. - st_endpoints++; - } - } - for (EdgeInf *t = visGraph.begin(); t != visGraph.end(); - t = t->lstNext) - { - std::pair<VertID, VertID> idpair = t->ids(); - - if (idpair.first.isConnPt() || idpair.second.isConnPt()) - { - st_valid_endpt_visedges++; - } - else - { - st_valid_shape_visedges++; - } - } - for (EdgeInf *t = invisGraph.begin(); t != invisGraph.end(); - t = t->lstNext) - { - st_invalid_visedges++; - } - for (EdgeInf *t = visOrthogGraph.begin(); t != visOrthogGraph.end(); - t = t->lstNext) - { - st_orthogonal_visedges++; - } - fprintf(fp, "Number of shapes: %d\n", st_shapes); - fprintf(fp, "Number of vertices: %d (%d real, %d endpoints)\n", - st_vertices + st_endpoints, st_vertices, st_endpoints); - fprintf(fp, "Number of orthog_vis_edges: %d\n", st_orthogonal_visedges); - fprintf(fp, "Number of vis_edges: %d (%d valid [%d normal, %d endpt], " - "%d invalid)\n", st_valid_shape_visedges + st_invalid_visedges + - st_valid_endpt_visedges, st_valid_shape_visedges + - st_valid_endpt_visedges, st_valid_shape_visedges, - st_valid_endpt_visedges, st_invalid_visedges); - fprintf(fp, "----------------------\n"); - fprintf(fp, "checkVisEdge tally: %d\n", st_checked_edges); - fprintf(fp, "----------------------\n"); - -#ifdef AVOID_PROFILE - timers.printAll(fp); - timers.reset(); -#endif -} - - -static const double LIMIT = 100000000; - -static void reduceRange(double& val) -{ - val = std::min(val, LIMIT); - val = std::max(val, -LIMIT); -} - - -//============================================================================= -// The following methods are for testing and debugging. - - -bool Router::existsOrthogonalSegmentOverlap(const bool atEnds) -{ - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - Avoid::Polygon iRoute = (*i)->displayRoute(); - ConnRefList::iterator j = i; - for (++j; j != fin; ++j) - { - // Determine if this pair overlap - Avoid::Polygon jRoute = (*j)->displayRoute(); - ConnectorCrossings cross(iRoute, true, jRoute, *i, *j); - cross.checkForBranchingSegments = true; - for (size_t jInd = 1; jInd < jRoute.size(); ++jInd) - { - const bool finalSegment = ((jInd + 1) == jRoute.size()); - cross.countForSegment(jInd, finalSegment); - - if ((cross.crossingFlags & CROSSING_SHARES_PATH) && - (atEnds || - !(cross.crossingFlags & CROSSING_SHARES_PATH_AT_END))) - { - // We are looking for fixedSharedPaths and there is a - // fixedSharedPath. - return true; - } - } - } - } - return false; -} - - -bool Router::existsOrthogonalFixedSegmentOverlap(const bool atEnds) -{ - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - Avoid::Polygon iRoute = (*i)->displayRoute(); - ConnRefList::iterator j = i; - for (++j; j != fin; ++j) - { - // Determine if this pair overlap - Avoid::Polygon jRoute = (*j)->displayRoute(); - ConnectorCrossings cross(iRoute, true, jRoute, *i, *j); - cross.checkForBranchingSegments = true; - for (size_t jInd = 1; jInd < jRoute.size(); ++jInd) - { - const bool finalSegment = ((jInd + 1) == jRoute.size()); - cross.countForSegment(jInd, finalSegment); - - if ((cross.crossingFlags & CROSSING_SHARES_PATH) && - (cross.crossingFlags & CROSSING_SHARES_FIXED_SEGMENT) && - (atEnds || - !(cross.crossingFlags & CROSSING_SHARES_PATH_AT_END))) - { - // We are looking for fixedSharedPaths and there is a - // fixedSharedPath. - return true; - } - } - } - } - return false; -} - - -bool Router::existsOrthogonalTouchingPaths(void) -{ - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - Avoid::Polygon iRoute = (*i)->displayRoute(); - ConnRefList::iterator j = i; - for (++j; j != fin; ++j) - { - // Determine if this pair overlap - Avoid::Polygon jRoute = (*j)->displayRoute(); - ConnectorCrossings cross(iRoute, true, jRoute, *i, *j); - cross.checkForBranchingSegments = true; - for (size_t jInd = 1; jInd < jRoute.size(); ++jInd) - { - const bool finalSegment = ((jInd + 1) == jRoute.size()); - cross.countForSegment(jInd, finalSegment); - - if (cross.crossingFlags & CROSSING_TOUCHES) - { - return true; - } - } - } - } - return false; -} - - -// Counts the number of crossings between all connectors. -// -// If optimisedForConnectorType is set, This will only count crossings -// between orthogonal connectors if they appear at segment endpoints. -// Thus, it can be used on raw connectors but not on simplified orthogonal -// connectors. -// -int Router::existsCrossings(const bool optimisedForConnectorType) -{ - int count = 0; - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - Avoid::Polygon iRoute = (*i)->displayRoute(); - ConnRefList::iterator j = i; - for (++j; j != fin; ++j) - { - // Determine if this pair overlap - Avoid::Polygon jRoute = (*j)->displayRoute(); - ConnRef *iConn = (optimisedForConnectorType) ? *i : NULL; - ConnRef *jConn = (optimisedForConnectorType) ? *j : NULL; - ConnectorCrossings cross(iRoute, true, jRoute, iConn, jConn); - cross.checkForBranchingSegments = true; - for (size_t jInd = 1; jInd < jRoute.size(); ++jInd) - { - const bool finalSegment = ((jInd + 1) == jRoute.size()); - - // Normal crossings aren't counted if we pass the pointers - // for the connectors, so don't pass them. - cross.countForSegment(jInd, finalSegment); - - count += cross.crossingCount; - } - } - } - return count; -} - -// Looks for non-orthogonal segments in orthogonal connectors and -// returns true if it finds any. -bool Router::existsInvalidOrthogonalPaths(void) -{ - // For each connector... - ConnRefList::iterator fin = connRefs.end(); - for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i) - { - // If it is an orthogonal connector... - if ((*i)->routingType() == Avoid::ConnType_Orthogonal) - { - // Check each segment of the path... - Avoid::Polygon iRoute = (*i)->displayRoute(); - for (size_t iInd = 1; iInd < iRoute.size(); ++iInd) - { - // And if it isn't either vertical or horizontal... - if ( (iRoute.at(iInd - 1).x != iRoute.at(iInd).x) && - (iRoute.at(iInd - 1).y != iRoute.at(iInd).y) ) - { - // Then we've found an invalid path. - return true; - } - } - } - } - return false; -} - - -void Router::setTopologyAddon(TopologyAddonInterface *topologyAddon) -{ - COLA_ASSERT(m_topology_addon); - delete m_topology_addon; - if (topologyAddon) - { - m_topology_addon = topologyAddon->clone(); - } - else - { - m_topology_addon = new TopologyAddonInterface(); - } - registerSettingsChange(); -} - -void Router::improveOrthogonalTopology(void) -{ - COLA_ASSERT(m_topology_addon); - m_topology_addon->improveOrthogonalTopology(this); -} - -void Router::outputInstanceToSVG(std::string instanceName) -{ - std::string filename; - if (!instanceName.empty()) - { - filename = instanceName; - } - else - { - filename = "libavoid-debug"; - } - filename += ".svg"; - FILE *fp = fopen(filename.c_str(), "w"); - - if (fp == NULL) - { - return; - } - - double minX = LIMIT; - double minY = LIMIT; - double maxX = -LIMIT; - double maxY = -LIMIT; - - VertInf *curr = 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; - - fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - fprintf(fp, "<svg xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns=\"http://www.w3.org/2000/svg\" width=\"100%%\" height=\"100%%\" viewBox=\"%g %g %g %g\">\n", minX, minY, maxX - minX, maxY - minY); - - // Output source code to generate this instance of the router. - fprintf(fp, "<!-- Source code to generate this instance:\n"); - fprintf(fp, "#include \"libavoid/libavoid.h\"\n"); - if (m_topology_addon->outputCode(NULL)) - { - fprintf(fp, "#include \"libcola/cola.h\"\n"); - fprintf(fp, "#include \"libtopology/orthogonal_topology.h\"\n"); - fprintf(fp, "using namespace cola;\n"); - } - fprintf(fp, "using namespace Avoid;\n"); - fprintf(fp, "int main(void) {\n"); - fprintf(fp, " Router *router = new Router("); - if (m_allows_polyline_routing) - { - fprintf(fp, "PolyLineRouting"); - } - if (m_allows_polyline_routing && m_allows_orthogonal_routing) - { - fprintf(fp, " | "); - } - if (m_allows_orthogonal_routing) - { - fprintf(fp, "OrthogonalRouting"); - } - fprintf(fp, ");\n"); - for (size_t p = 0; p < lastRoutingParameterMarker; ++p) - { - fprintf(fp, " router->setRoutingParameter((RoutingParameter)%lu, %g);\n", - (unsigned long)p, m_routing_parameters[p]); - } - for (size_t p = 0; p < lastRoutingOptionMarker; ++p) - { - fprintf(fp, " router->setRoutingOption((RoutingOption)%lu, %s);\n", - (unsigned long)p, (m_routing_options[p]) ? "true" : "false"); - } - fprintf(fp, " Polygon polygon;\n"); - fprintf(fp, " ConnRef *connRef = NULL;\n"); - fprintf(fp, " ConnEnd srcPt;\n"); - fprintf(fp, " ConnEnd dstPt;\n"); - fprintf(fp, " ConnEnd heConnPt;\n"); - fprintf(fp, " PolyLine newRoute;\n"); - fprintf(fp, " ShapeConnectionPin *connPin = NULL;\n"); - fprintf(fp, "\n"); - ClusterRefList::reverse_iterator revClusterRefIt = clusterRefs.rbegin(); - while (revClusterRefIt != clusterRefs.rend()) - { - ClusterRef *cRef = *revClusterRefIt; - fprintf(fp, " polygon = Polygon(%lu);\n", - (unsigned long)cRef->polygon().size()); - for (size_t i = 0; i <cRef->polygon().size(); ++i) - { - fprintf(fp, " polygon.ps[%lu] = Point(%g, %g);\n", - (unsigned long)i, cRef->polygon().at(i).x, - cRef->polygon().at(i).y); - } - fprintf(fp, " new ClusterRef(router, polygon, %u);\n", cRef->id()); - ++revClusterRefIt; - } - ObstacleList::reverse_iterator revObstacleIt = m_obstacles.rbegin(); - while (revObstacleIt != m_obstacles.rend()) - { - Obstacle *obstacle = *revObstacleIt; - obstacle->outputCode(fp); - ++revObstacleIt; - } - ConnRefList::reverse_iterator revConnRefIt = connRefs.rbegin(); - while (revConnRefIt != connRefs.rend()) - { - ConnRef *connRef = *revConnRefIt; - connRef->outputCode(fp); - ++revConnRefIt; - } - - m_topology_addon->outputCode(fp); - - fprintf(fp, " router->processTransaction();\n"); - fprintf(fp, " router->outputInstanceToSVG();\n"); - - m_topology_addon->outputDeletionCode(fp); - fprintf(fp, " delete router;\n"); - fprintf(fp, " return 0;\n"); - fprintf(fp, "};\n"); - fprintf(fp, "-->\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"Clusters\">\n"); - revClusterRefIt = clusterRefs.rbegin(); - while (revClusterRefIt != clusterRefs.rend()) - { - ClusterRef *cRef = *revClusterRefIt; - fprintf(fp, "<path id=\"cluster-%u\" style=\"stroke-width: 1px; " - "stroke: black; fill: green; opacity: 0.1;\" d=\"", - cRef->id()); - for (size_t i = 0; i < cRef->polygon().size(); ++i) - { - fprintf(fp, "%c %g %g ", ((i == 0) ? 'M' : 'L'), - cRef->polygon().at(i).x, cRef->polygon().at(i).y); - } - fprintf(fp, "Z\" />\n"); - - fprintf(fp, "<path id=\"cluster-%u-rect\" style=\"stroke-width: 1px; " - "stroke: black; fill: green; opacity: 0.1;\" d=\"", - cRef->id()); - for (size_t i = 0; i < cRef->rectangularPolygon().size(); ++i) - { - fprintf(fp, "%c %g %g ", ((i == 0) ? 'M' : 'L'), - cRef->rectangularPolygon().at(i).x, - cRef->rectangularPolygon().at(i).y); - } - fprintf(fp, "Z\" />\n"); - ++revClusterRefIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"ShapePolygons\">\n"); - ObstacleList::iterator obstacleIt = m_obstacles.begin(); - while (obstacleIt != m_obstacles.end()) - { - Obstacle *obstacle = *obstacleIt; - bool isShape = (NULL != dynamic_cast<ShapeRef *> (obstacle)); - - if ( ! isShape ) - { - // Don't output obstacles here, for now. - ++obstacleIt; - continue; - } - - fprintf(fp, "<path id=\"poly-%u\" style=\"stroke-width: 1px; " - "stroke: black; fill: %s; fill-opacity: 0.3;\" d=\"", - obstacle->id(), (isShape) ? "grey" : "red"); - for (size_t i = 0; i < obstacle->polygon().size(); ++i) - { - fprintf(fp, "%c %g %g ", ((i == 0) ? 'M' : 'L'), - obstacle->polygon().at(i).x, obstacle->polygon().at(i).y); - } - fprintf(fp, "Z\" />\n"); - ++obstacleIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"ObstaclePolygons\">\n"); - obstacleIt = m_obstacles.begin(); - while (obstacleIt != m_obstacles.end()) - { - Obstacle *obstacle = *obstacleIt; - bool isShape = (NULL != dynamic_cast<ShapeRef *> (obstacle)); - - if ( ! isShape ) - { - // Don't output obstacles here, for now. - ++obstacleIt; - continue; - } - - Polygon polygon = obstacle->routingPolygon(); - fprintf(fp, "<path id=\"poly-%u\" style=\"stroke-width: 1px; " - "stroke: black; fill: %s; fill-opacity: 0.3;\" d=\"", - obstacle->id(), (isShape) ? "grey" : "red"); - for (size_t i = 0; i < polygon.size(); ++i) - { - fprintf(fp, "%c %g %g ", ((i == 0) ? 'M' : 'L'), - polygon.at(i).x, polygon.at(i).y); - } - fprintf(fp, "Z\" />\n"); - ++obstacleIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"IdealJunctions\">\n"); - for (ObstacleList::iterator obstacleIt = m_obstacles.begin(); - obstacleIt != m_obstacles.end(); ++obstacleIt) - { - JunctionRef *junction = dynamic_cast<JunctionRef *> (*obstacleIt); - if (junction) - { - fprintf(fp, "<circle id=\"idealJunction-%u\" cx=\"%g\" cy=\"%g\" " - "r=\"8\" style=\"stroke: none; fill: %s; " - "fill-opacity: 0.5;\" />\n", junction->id(), - junction->recommendedPosition().x, - junction->recommendedPosition().y, "green"); - } - - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"ObstacleRects\">\n"); - obstacleIt = m_obstacles.begin(); - while (obstacleIt != 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 bBox = obstacle->routingBox(); - - fprintf(fp, "<rect id=\"rect-%u\" x=\"%g\" y=\"%g\" width=\"%g\" " - "height=\"%g\" style=\"stroke-width: 1px; stroke: black; " - "fill: grey; stroke-opacity: 0.1; fill-opacity: 0.1;\" />\n", - obstacle->id(), bBox.min.x, bBox.min.y, - bBox.max.x - bBox.min.x, bBox.max.y - bBox.min.y); - ++obstacleIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"VisGraph\"" - ">\n"); - EdgeInf *finish = NULL; - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"VisGraph-shape\"" - ">\n"); - finish = visGraph.end(); - for (EdgeInf *t = visGraph.begin(); t != finish; t = t->lstNext) - { - std::pair<VertID, VertID> ids = t->ids(); - bool isConn = ids.first.isConnPt() || ids.second.isConnPt(); - if (isConn) - { - continue; - } - 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); - - fprintf(fp, "<path d=\"M %g %g L %g %g\" " - "style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n", - p1.x, p1.y, p2.x, p2.y, - (ids.first.isConnPt() || ids.second.isConnPt()) ? "blue" : - "red"); - } - fprintf(fp, "</g>\n"); - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"VisGraph-conn\"" - ">\n"); - finish = visGraph.end(); - for (EdgeInf *t = visGraph.begin(); t != finish; t = t->lstNext) - { - std::pair<VertID, VertID> ids = t->ids(); - bool isConn = ids.first.isConnPt() || ids.second.isConnPt(); - if (!isConn) - { - continue; - } - 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); - - fprintf(fp, "<path d=\"M %g %g L %g %g\" " - "style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n", - p1.x, p1.y, p2.x, p2.y, - (ids.first.isConnPt() || ids.second.isConnPt()) ? "blue" : - "red"); - } - fprintf(fp, "</g>\n"); - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"OrthogVisGraph\">\n"); - finish = visOrthogGraph.end(); - for (EdgeInf *t = 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(); - - fprintf(fp, "<path d=\"M %g %g L %g %g\" " - "style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n", - p1.x, p1.y, p2.x, p2.y, - (ids.first.isConnPt() || ids.second.isConnPt()) ? "green" : - "red"); - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"RawConnectors\"" - ">\n"); - ConnRefList::iterator connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - PolyLine route = connRef->route(); - if (!route.empty()) - { - fprintf(fp, "<path id=\"raw-%u\" d=\"M %g %g ", connRef->id(), - route.ps[0].x, route.ps[0].y); - for (size_t i = 1; i < route.size(); ++i) - { - fprintf(fp, "L %g %g ", route.ps[i].x, route.ps[i].y); - } - fprintf(fp, "\" "); - if (connRef->src() && connRef->dst()) - { - fprintf(fp, "debug=\"src: %d dst: %d\" ", - connRef->src()->visDirections, - connRef->dst()->visDirections); - } - fprintf(fp, "style=\"fill: none; stroke: black; " - "stroke-width: 1px;\" />\n"); - } - - ++connRefIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "style=\"display: none;\" " - "inkscape:label=\"CurvedDisplayConnectors\"" - ">\n"); - connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - PolyLine route = connRef->displayRoute().curvedPolyline(8); - if (!route.empty()) - { - fprintf(fp, "<path id=\"curved-%u\" d=\"M %g %g ", connRef->id(), - route.ps[0].x, route.ps[0].y); - for (size_t i = 1; i < route.size(); ++i) - { - if (route.ts[i] == 'C') - { - fprintf(fp, "%c %g %g %g %g %g %g", route.ts[i], - route.ps[i].x, route.ps[i].y, - route.ps[i+1].x, route.ps[i+1].y, - route.ps[i+2].x, route.ps[i+2].y); - i += 2; - } - else - { - fprintf(fp, "%c %g %g ", route.ts[i], - route.ps[i].x, route.ps[i].y); - } - } - fprintf(fp, "\" "); - if (connRef->src() && connRef->dst()) - { - fprintf(fp, "debug=\"src: %d dst: %d\" ", - connRef->src()->visDirections, - connRef->dst()->visDirections); - } - fprintf(fp, "style=\"fill: none; stroke: black; " - "stroke-width: 1px;\" />\n"); - } - - ++connRefIt; - } - fprintf(fp, "</g>\n"); - - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"DisplayConnectors\"" - ">\n"); - connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - PolyLine route = connRef->displayRoute(); - if (!route.empty()) - { - fprintf(fp, "<path id=\"disp-%u\" d=\"M %g %g ", connRef->id(), - route.ps[0].x, route.ps[0].y); - for (size_t i = 1; i < route.size(); ++i) - { - fprintf(fp, "L %g %g ", route.ps[i].x, route.ps[i].y); - } - fprintf(fp, "\" "); - if (connRef->src() && connRef->dst()) - { - fprintf(fp, "debug=\"src: %d dst: %d\" ", - connRef->src()->visDirections, - connRef->dst()->visDirections); - } - fprintf(fp, "style=\"fill: none; stroke: black; " - "stroke-width: 1px;\" />\n"); - } - - ++connRefIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"ConnectorCheckpoints\"" - ">\n"); - connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - for (size_t i = 0; i < connRef->m_checkpoints.size(); ++i) - { - fprintf(fp, "<circle id=\"checkpoint-%u-%d\" cx=\"%g\" cy=\"%g\" " - "r=\"8\" style=\"stroke: none; fill: red; " - "fill-opacity: 0.25;\" />\n", connRef->id(), (int) i, - connRef->m_checkpoints[i].point.x, - connRef->m_checkpoints[i].point.y); - } - - ++connRefIt; - } - fprintf(fp, "</g>\n"); - - - fprintf(fp, "</svg>\n"); - fclose(fp); - //printInfo(); -} - -void Router::outputDiagramSVG(std::string instanceName, LineReps *lineReps) -{ - std::string filename; - if (!instanceName.empty()) - { - filename = instanceName; - } - else - { - filename = "libavoid-diagram"; - } - filename += ".svg"; - FILE *fp = fopen(filename.c_str(), "w"); - - if (fp == NULL) - { - return; - } - - double minX = LIMIT; - double minY = LIMIT; - double maxX = -LIMIT; - double maxY = -LIMIT; - - VertInf *curr = 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; - - fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - fprintf(fp, "<svg xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns=\"http://www.w3.org/2000/svg\" width=\"100%%\" height=\"100%%\" viewBox=\"%g %g %g %g\">\n", minX, minY, maxX - minX, maxY - minY); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"ShapesRect\">\n"); - ObstacleList::iterator obstacleIt = m_obstacles.begin(); - while (obstacleIt != m_obstacles.end()) - { - Obstacle *obstacle = *obstacleIt; - bool isShape = (NULL != dynamic_cast<ShapeRef *> (obstacle)); - - if ( ! isShape ) - { - // Don't output non-shape obstacles here, for now. - ++obstacleIt; - continue; - } - - Box bBox = obstacle->polygon().offsetBoundingBox(0.0); - - fprintf(fp, "<rect id=\"rect-%u\" x=\"%g\" y=\"%g\" width=\"%g\" " - "height=\"%g\" style=\"stroke-width: 1px; stroke: black; " - "fill: grey; stroke-opacity: 0.5; fill-opacity: 0.4;\" />\n", - obstacle->id(), bBox.min.x, bBox.min.y, - bBox.max.x - bBox.min.x, bBox.max.y - bBox.min.y); - ++obstacleIt; - } - fprintf(fp, "</g>\n"); - - fprintf(fp, "<g inkscape:groupmode=\"layer\" " - "inkscape:label=\"DisplayConnectors\"" - ">\n"); - ConnRefList::iterator connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - PolyLine route = connRef->displayRoute(); - if (!route.empty()) - { - fprintf(fp, "<path id=\"disp-%u\" d=\"M %g %g ", connRef->id(), - route.ps[0].x, route.ps[0].y); - for (size_t i = 1; i < route.size(); ++i) - { - fprintf(fp, "L %g %g ", route.ps[i].x, route.ps[i].y); - } - fprintf(fp, "\" "); - fprintf(fp, "style=\"fill: none; stroke: black; " - "stroke-width: 1px;\" />\n"); - - /* - for (size_t i = 1; i < route.size(); ++i) - { - if (route.segmentHasCheckpoint[i - 1]) - { - fprintf(fp, "<path d=\"M %g %g ", - route.ps[i - 1].x, route.ps[i - 1].y); - fprintf(fp, "L %g %g\" ", route.ps[i].x, route.ps[i].y); - fprintf(fp, "style=\"fill: none; stroke: red; " - "stroke-width: 1px; stroke-opacity: 1;\" />\n"); - } - } - */ - } - - ++connRefIt; - } - fprintf(fp, "</g>\n"); - - if (lineReps) - { - - for (LineReps::iterator it = lineReps->begin(); it != lineReps->end(); - ++it) - { - fprintf(fp, "<path d=\"M %g %g ", - it->begin.x, it->begin.y); - fprintf(fp, "L %g %g\" ", it->end.x, it->end.y); - fprintf(fp, "style=\"fill: none; stroke: red; " - "stroke-width: 1px; stroke-opacity: 0.7;\" />\n"); - } - } - - fprintf(fp, "</svg>\n"); - fclose(fp); -} - -void Router::outputDiagram(std::string instanceName) -{ - outputDiagramText(instanceName); -#ifdef SVG_OUTPUT - outputInstanceToSVG(instanceName); -#endif -} - -void Router::outputDiagramText(std::string instanceName) -{ - std::string filename; - if (!instanceName.empty()) - { - filename = instanceName; - } - else - { - filename = "libavoid-diagram"; - } - filename += ".txt"; - FILE *fp = fopen(filename.c_str(), "w"); - - if (fp == NULL) - { - return; - } - - ObstacleList::iterator obstacleIt = m_obstacles.begin(); - while (obstacleIt != m_obstacles.end()) - { - Obstacle *obstacle = *obstacleIt; - bool isShape = (NULL != dynamic_cast<ShapeRef *> (obstacle)); - - if ( ! isShape ) - { - // Don't output non-shape obstacles here, for now. - ++obstacleIt; - continue; - } - - Box bBox = obstacle->polygon().offsetBoundingBox(0.0); - - fprintf(fp, "rect\n"); - fprintf(fp, "id=%u\n", obstacle->id()); - fprintf(fp, "x=%g\n", bBox.min.x); - fprintf(fp, "y=%g\n", bBox.min.y); - fprintf(fp, "width=%g\n", bBox.max.x - bBox.min.x); - fprintf(fp, "height=%g\n", bBox.max.y - bBox.min.y); - fprintf(fp, "\n"); - - ++obstacleIt; - } - - ConnRefList::iterator connRefIt = connRefs.begin(); - while (connRefIt != connRefs.end()) - { - ConnRef *connRef = *connRefIt; - - PolyLine route = connRef->displayRoute(); - if (!route.empty()) - { - fprintf(fp, "path\n"); - fprintf(fp, "id=%u\n", connRef->id()); - for (size_t i = 0; i < route.size(); ++i) - { - fprintf(fp, "p%lu: %g %g ", i, route.ps[i].x, route.ps[i].y); - fprintf(fp, "\n"); - } - fprintf(fp, "\n"); - } - - ++connRefIt; - } - - fprintf(fp, "\n"); - - fclose(fp); -} - -HyperedgeNewAndDeletedObjectLists - Router::newAndDeletedObjectListsFromHyperedgeImprovement(void) const -{ - return m_hyperedge_improver.newAndDeletedObjectLists(); -} - - -ConnRerouteFlagDelegate::ConnRerouteFlagDelegate() -{ -} - -ConnRerouteFlagDelegate::~ConnRerouteFlagDelegate() -{ -} - -bool *ConnRerouteFlagDelegate::addConn(ConnRef *conn) -{ - m_mapping.push_back(std::make_pair(conn, false)); - return &(m_mapping.back().second); -} - -void ConnRerouteFlagDelegate::removeConn(ConnRef *conn) -{ - std::list<std::pair<ConnRef *, bool> >::iterator it; - for (it = m_mapping.begin(); it != m_mapping.end(); ++it) - { - if (it->first == conn) - { - it->first = NULL; - } - } -} - - -void ConnRerouteFlagDelegate::alertConns(void) -{ - std::list<std::pair<ConnRef *, bool> >::iterator it; - for (it = m_mapping.begin(); it != m_mapping.end(); ++it) - { - if ((it->first != NULL) && (it->second == true)) - { - it->second = false; - it->first->m_needs_reroute_flag = true; - } - } -} - - -} - |
