27#define _USE_MATH_DEFINES
62 ANode(VertInf *vinf,
int time)
86 : m_available_nodes(),
87 m_available_array_size(0),
88 m_available_array_index(0),
89 m_available_node_index(0)
95 for (
size_t i = 0; i < m_available_nodes.size(); ++i)
97 delete[] m_available_nodes[i];
102 ANode *newANode(
const ANode& node,
const bool addToPending =
true)
104 const size_t blockSize = 5000;
105 if ((m_available_array_index + 1 > m_available_array_size) ||
106 (m_available_node_index >= blockSize))
108 m_available_nodes.push_back(
new ANode[blockSize]);
109 ++m_available_array_size;
110 m_available_node_index = 0;
111 m_available_array_index = m_available_array_size - 1;
114 ANode *nodes = m_available_nodes[m_available_array_index];
115 ANode *newNode = &(nodes[m_available_node_index++]);
119 node.inf->aStarPendingNodes.push_back(newNode);
123 void search(ConnRef *lineRef, VertInf *src, VertInf *tar,
127 void determineEndPointLocation(
double dist, VertInf *
start,
128 VertInf *target, VertInf *other,
int level);
129 double estimatedCost(ConnRef *lineRef,
const Point *last,
130 const Point& curr)
const;
132 std::vector<ANode *> m_available_nodes;
133 size_t m_available_array_size;
134 size_t m_available_array_index;
135 size_t m_available_node_index;
138 std::vector<VertInf *> m_cost_targets;
139 std::vector<unsigned int> m_cost_targets_directions;
140 std::vector<double> m_cost_targets_displacements;
157bool operator()(
const ANode *a,
const ANode *b)
162 if (fabs(a->f - b->f) > 0.0000001)
166 if (a->timeStamp != b->timeStamp)
173 return a->timeStamp < b->timeStamp;
182 return (l.
x * r.
x) + (l.
y * r.
y);
187 return (l.
x * r.
y) - (l.
y * r.
x);
196 if ((p1.
x == p2.
x && p1.
y == p2.
y) || (p2.
x == p3.
x && p2.
y == p3.
y))
213 VertInf *inf3, ANode *inf1Node)
216 bool simplified =
true;
219 for (ANode *curr = inf1Node; curr !=
nullptr; curr = curr->prevNode)
223 connRoute.
ps.resize(routeSize);
224 int arraySize = routeSize;
225 connRoute.
ps[routeSize - 1] = inf3->
point;
226 connRoute.
ps[routeSize - 2] = inf2->
point;
228 for (ANode *curr = inf1Node; curr !=
nullptr; curr = curr->prevNode)
232 bool isConnectionPin = curr->inf->
id.isConnectionPin();
238 connRoute.
ps[routeSize] = curr->inf->point;
249 if ((curr == inf1Node) ||
250 vecDir(curr->inf->point, connRoute.
ps[routeSize + 1],
251 connRoute.
ps[routeSize + 2]) != 0)
258 connRoute.
ps[routeSize] = curr->inf->point;
264 connRoute.
ps[routeSize + 1] = curr->inf->point;
276 int diff = routeSize + 1;
277 COLA_ASSERT(simplified || (diff == 0));
280 for (
int i = diff; i < arraySize; ++i)
282 connRoute.
ps[i - diff] = connRoute.
ps[i];
284 connRoute.
ps.resize(connRoute.
size() - diff);
296 else if (difference < 0)
309 VertInf *inf3, ANode *inf1Node)
312 VertInf *inf1 = (inf1Node) ? inf1Node->inf :
nullptr;
324 if ((angle_penalty > 0) || (segmt_penalty > 0))
332 if ((rad > 0) && !isOrthogonal)
337 double xval = rad * 10 / M_PI;
338 double yval = xval * log10(xval + 1) / 10.5;
339 result += (angle_penalty * yval);
347 result += (2 * segmt_penalty);
358 const double cluster_crossing_penalty =
362 (cluster_crossing_penalty > 0))
364 if (connRoute.
empty())
369 for (ClusterRefList::const_iterator cl = router->
clusterRefs.begin();
372 Polygon cBoundary = (isOrthogonal) ?
373 (*cl)->rectangularPolygon() : (*cl)->polygon();
374 if (cBoundary.
size() <= 2)
378 COLA_ASSERT(cBoundary.
ps[0] != cBoundary.
ps[cBoundary.
size() - 1]);
379 for (
size_t j = 0; j < cBoundary.
size(); ++j)
383 COLA_ASSERT(isOrthogonal ||
388 Polygon dynamic_conn_route(connRoute);
389 const bool finalSegment = (inf3 == lineRef->
dst());
391 cross.checkForBranchingSegments =
true;
392 cross.countForSegment(connRoute.
size() - 1, finalSegment);
394 result += (cross.crossingCount * cluster_crossing_penalty);
410 bool doesReverse =
false;
441 const double shared_path_penalty =
443 if ((shared_path_penalty > 0) || (crossing_penalty > 0))
445 if (connRoute.
empty())
449 ConnRefList::const_iterator curr, finish = router->
connRefs.end();
450 for (curr = router->
connRefs.begin(); curr != finish; ++curr)
454 if (connRef->
id() == lineRef->
id())
461 Polygon dynamic_route2(route2);
462 Polygon dynamic_conn_route(connRoute);
463 const bool finalSegment = (inf3->
point == lineRef->
dst()->
point);
465 dynamic_conn_route, connRef, lineRef);
466 cross.checkForBranchingSegments =
true;
467 cross.countForSegment(connRoute.
size() - 1, finalSegment);
477 result += shared_path_penalty;
479 result += (cross.crossingCount * crossing_penalty);
492#ifdef ESTIMATED_COST_DEBUG
517 unsigned int count = 0;
564static unsigned int dirRight(
unsigned int direction)
589static unsigned int dirLeft(
unsigned int direction)
647 unsigned int destDir)
661 COLA_ASSERT(currDir != 0);
663 unsigned int reverseDestDir =
dirReverse(destDir);
664 bool currDirPerpendicularToDestDir =
667 if ((currDir == destDir) &&
668 (currToDestDir == currDir))
675 else if (currDirPerpendicularToDestDir &&
676 (currToDestDir == (destDir | currDir)))
688 else if (currDirPerpendicularToDestDir &&
689 (currToDestDir == currDir))
701 else if (currDirPerpendicularToDestDir &&
702 (currToDestDir == destDir))
711 else if ((currDir == destDir) &&
712 (currToDestDir != currDir) &&
713 !(currToDestDir & reverseDestDir))
723 else if (currDir == reverseDestDir &&
724 (currToDestDir != destDir) &&
725 (currToDestDir != currDir))
735 else if (currDirPerpendicularToDestDir &&
736 (currToDestDir != (destDir | currDir)) &&
737 (currToDestDir != currDir))
752 else if ((currDir == reverseDestDir) &&
753 ((currToDestDir == destDir) || (currToDestDir == currDir)))
762 else if ((currDir == destDir) &&
763 (currToDestDir & reverseDestDir))
782 const unsigned int costTarDirs)
799 double xmove = costTarPoint.
x - curr.
x;
800 double ymove = costTarPoint.
y - curr.
y;
805 if ((xmove != 0) && (ymove != 0))
825 bendCount = std::min(bendCount,
830 bendCount = std::min(bendCount,
835 bendCount = std::min(bendCount,
840 bendCount = std::min(bendCount,
845 double penalty = bendCount *
848 return dist + penalty;
854double AStarPathPrivate::estimatedCost(ConnRef *lineRef,
const Point *last,
855 const Point& curr)
const
857 double estimate = DBL_MAX;
858 COLA_ASSERT(m_cost_targets.size() > 0);
862 for (
size_t i = 0; i < m_cost_targets.size(); ++i)
865 curr, m_cost_targets[i], m_cost_targets_directions[i]);
869 iEstimate += m_cost_targets_displacements[i];
871 estimate = std::min(estimate, iEstimate);
877class CmpVisEdgeRotation
880 CmpVisEdgeRotation(
const VertInf* lastPt)
884 bool operator() (
const EdgeInf* u,
const EdgeInf* v)
const
888 if (u->isOrthogonal() &&
v->isOrthogonal())
890 return u->rotationLessThan(_lastPt, v);
895 const VertInf *_lastPt;
900 const std::vector<Point>& points,
const size_t dim)
902 for (
size_t i = 0; i < points.size(); ++i)
904 if (point[dim] == points[i][dim])
913 : m_private(new AStarPathPrivate())
927void AStarPathPrivate::determineEndPointLocation(
double dist,
VertInf *
start,
939 m_cost_targets.push_back(other);
940 m_cost_targets_directions.push_back(thisDirs);
941 m_cost_targets_displacements.push_back(displacement);
943#ifdef ESTIMATED_COST_DEBUG
944 fprintf(stderr,
" - %g %g ", otherPoint.
x, otherPoint.
y);
947 fprintf(stderr,
"far ");
949 fprintf(stderr,
"%s", (level == 1) ?
"--" :
"- ");
951 fprintf(stderr,
"\n");
965void AStarPathPrivate::search(ConnRef *lineRef, VertInf *src, VertInf *tar, VertInf *
start)
971 if (
start ==
nullptr)
977 if (lineRef->router()->debugHandler())
979 lineRef->router()->debugHandler()->beginningSearchWithEndpoints(
start, tar);
990#ifdef ESTIMATED_COST_DEBUG
991 fprintf(stderr,
"== aStar %g %g ==\n", tar->point.x, tar->point.y);
993 if (isOrthogonal && tar->id.isConnPt() && !tar->id.isConnCheckpoint())
997 for (EdgeInfList::const_iterator it = tar->orthogVisList.begin();
998 it != tar->orthogVisList.end(); ++it)
1001 EdgeInf *edge = *it;
1002 VertInf *other = edge->otherVert(tar);
1003 if (other->id.isConnectionPin())
1008 VertInf *replacementTar = other;
1009 for (EdgeInfList::const_iterator it =
1010 replacementTar->orthogVisList.begin();
1011 it != replacementTar->orthogVisList.end(); ++it)
1013 EdgeInf *edge = *it;
1014 VertInf *other = edge->otherVert(replacementTar);
1015 if ((other == tar) ||
1016 (other->point == tar->point))
1024 determineEndPointLocation(
dist,
start, replacementTar,
1031 determineEndPointLocation(
dist,
start, tar, other, 1);
1036 if (m_cost_targets.empty())
1038 m_cost_targets.push_back(tar);
1043 m_cost_targets_displacements.push_back(0.0);
1046#ifdef ESTIMATED_COST_DEBUG
1047 fprintf(stderr,
"------------\n");
1048 for (
size_t i = 0; i < m_cost_targets.size(); ++i)
1050 fprintf(stderr,
"== %g %g - ", m_cost_targets[i]->point.x,
1051 m_cost_targets[i]->point.y);
1053 fprintf(stderr,
"\n");
1064 std::vector<Point> endPoints;
1067 endPoints = lineRef->possibleDstPinPoints();
1069 endPoints.push_back(tar->point);
1072 std::vector<ANode *> PENDING;
1073 PENDING.reserve(1000);
1075 size_t exploredCount = 0;
1077 ANode *bestNode =
nullptr;
1078 bool bNodeFound =
false;
1081 Router *router = lineRef->router();
1082 if (router->RubberBandRouting && (
start != src))
1084 COLA_ASSERT(router->IgnoreRegions ==
true);
1086 const PolyLine& currRoute = lineRef->route();
1087 VertInf *last =
nullptr;
1089 while (last !=
start)
1091 const Point& pnt = currRoute.
at(rIndx);
1093 VertID vID(pnt.id, pnt.vn,
props);
1096 db_printf(
"/// %d %d\n", pnt.id, pnt.vn);
1098 VertInf *curr = router->vertices.getVertexByID(vID);
1099 COLA_ASSERT(curr !=
nullptr);
1101 node = ANode(curr, timestamp++);
1106 node.h = estimatedCost(lineRef,
nullptr,
node.inf->point);
1112 double edgeDist =
dist(bestNode->inf->point, curr->point);
1114 node.g = bestNode->g +
cost(lineRef, edgeDist, bestNode->inf,
1115 node.inf, bestNode->prevNode);
1118 node.h = estimatedCost(lineRef, &(bestNode->inf->point),
1125 node.prevNode = bestNode;
1130 bool addToPending =
false;
1131 bestNode = newANode(node, addToPending);
1132 bestNode->inf->aStarDoneNodes.push_back(bestNode);
1137 ANode * newNode = newANode(node);
1138 PENDING.push_back(newNode);
1147 if (
start->pathNext)
1155 bool addToPending =
false;
1156 bestNode = newANode(ANode(
start->pathNext, timestamp++),
1158 bestNode->inf->aStarDoneNodes.push_back(bestNode);
1163 node = ANode(src, timestamp++);
1165 node.h = estimatedCost(lineRef,
nullptr,
node.inf->point);
1168 node.prevNode = bestNode;
1171 ANode *newNode = newANode(node);
1172 PENDING.push_back(newNode);
1175 tar->pathNext =
nullptr;
1178 using std::make_heap;
using std::push_heap;
using std::pop_heap;
1179 make_heap( PENDING.begin(), PENDING.end(), pendingCmp);
1182 while (!PENDING.empty())
1184 TIMER_VAR_ADD(router, 0, 1);
1188 bestNode = PENDING.front();
1189 VertInf *bestNodeInf = bestNode->inf;
1192 if (router->debugHandler())
1196 ANode *curr = bestNode;
1199 currentSearchPath.ps.push_back(curr->inf->point);
1200 curr = curr->prevNode;
1202 router->debugHandler()->updateCurrentSearchPath(currentSearchPath);
1207 std::list<ANode *>::iterator finishIt =
1208 bestNodeInf->aStarPendingNodes.end();
1209 for (std::list<ANode *>::iterator currInd =
1210 bestNodeInf->aStarPendingNodes.begin(); currInd != finishIt;
1213 if (*currInd == bestNode)
1215 bestNodeInf->aStarPendingNodes.erase(currInd);
1224 pop_heap(PENDING.begin(), PENDING.end(), pendingCmp);
1229 bestNodeInf->aStarDoneNodes.push_back(bestNode);
1232 VertInf *prevInf = (bestNode->prevNode) ? bestNode->prevNode->inf : nullptr;
1235 db_printf(
" %g %g ", bestNodeInf->point.x, bestNodeInf->point.y);
1236 bestNodeInf->id.db_print();
1237 db_printf(
" - g: %3.1f h: %3.1f back: ", bestNode->g, bestNode->h);
1240 db_printf(
" %g %g", prevInf->point.x, prevInf->point.y);
1246 if (bestNodeInf == tar)
1248 TIMER_VAR_ADD(router, 1, PENDING.size());
1251 db_printf(
"LINE %10d Steps: %4d Cost: %g\n", lineRef->id(),
1252 (
int) exploredCount, bestNode->f);
1256 for (ANode *curr = bestNode; curr->prevNode; curr = curr->prevNode)
1259 db_printf(
"[%.12f, %.12f]\n", curr->inf->point.x, curr->inf->point.y);
1261 curr->inf->pathNext = curr->prevNode->inf;
1273 bestNodeInf->visList : bestNodeInf->orthogVisList;
1278 CmpVisEdgeRotation compare(prevInf);
1279 visList.sort(compare);
1281 EdgeInfList::const_iterator finish = visList.end();
1282 for (EdgeInfList::const_iterator edge = visList.begin();
1283 edge != finish; ++edge)
1285 if ((*edge)->isDisabled())
1291 node = ANode((*edge)->otherVert(bestNodeInf), timestamp++);
1295 node.prevNode = bestNode;
1297 VertInf *prevInf = (bestNode->prevNode) ?
1298 bestNode->prevNode->inf : nullptr;
1301 if (prevInf && (prevInf ==
node.inf))
1305 if (
node.inf->id.isConnectionPin() &&
1306 !
node.inf->id.isConnCheckpoint())
1308 if ( !( (bestNodeInf == lineRef->src()) &&
1309 lineRef->src()->id.isDummyPinHelper()
1311 !(
node.inf->hasNeighbour(lineRef->dst(), isOrthogonal) &&
1312 lineRef->dst()->id.isDummyPinHelper())
1321 else if (
node.inf->id.isConnPt())
1323 if ((
node.inf != tar))
1331 if (isOrthogonal && !(*edge)->isDummyConnection())
1341 Point& bestPt = bestNodeInf->point;
1344 bool notInlineX = prevInf && (prevInf->point.x != bestPt.x);
1345 bool notInlineY = prevInf && (prevInf->point.y != bestPt.y);
1346 if ((bestPt.x == nextPt.x) && notInlineX && !notInlineY &&
1347 (bestPt[
YDIM] != src->point[
YDIM]))
1349 if (nextPt.y < bestPt.y)
1351 if (!(bestNodeInf->orthogVisPropFlags &
YL_EDGE) &&
1357 else if (nextPt.y > bestPt.y)
1359 if (!(bestNodeInf->orthogVisPropFlags &
YH_EDGE) &&
1366 if ((bestPt.y == nextPt.y) && notInlineY && !notInlineX &&
1367 (bestPt[
XDIM] != src->point[
XDIM]))
1369 if (nextPt.x < bestPt.x)
1371 if (!(bestNodeInf->orthogVisPropFlags &
XL_EDGE) &&
1377 else if (nextPt.x > bestPt.x)
1379 if (!(bestNodeInf->orthogVisPropFlags &
XH_EDGE) &&
1388 double edgeDist = (*edge)->getDist();
1395 if (!isOrthogonal &&
1396 (!router->RubberBandRouting || (
start == src)) &&
1407 bool atCostTarget =
false;
1408 for (
size_t i = 0; i < m_cost_targets.size(); ++i)
1410 if (bestNode->inf == m_cost_targets[i])
1413 atCostTarget =
true;
1419 (
node.inf->id.isConnectionPin() || (
node.inf == tar)))
1424 node.g = bestNode->g;
1429 if (
node.inf == tar)
1437 node.h = estimatedCost(lineRef, &(bestNodeInf->point),
1441 if (
node.inf->id.isDummyPinHelper())
1445 node.g = bestNode->g;
1450 node.g = bestNode->g +
cost(lineRef, edgeDist, bestNodeInf,
1451 node.inf, bestNode->prevNode);
1461 node.inf->id.db_print();
1469 std::list<ANode *>::const_iterator finish =
node.inf->aStarPendingNodes.
end();
1470 for (std::list<ANode *>::const_iterator currInd =
1471 node.inf->aStarPendingNodes.
begin(); currInd != finish; ++currInd)
1477 if ((
node.inf == ati.inf) &&
1478 ((
node.prevNode == ati.prevNode) ||
1479 (
node.prevNode->inf == ati.prevNode->inf)))
1486 make_heap( PENDING.begin(), PENDING.end(), pendingCmp);
1496 for (std::list<ANode *>::const_iterator currInd =
1498 currInd !=
node.inf->aStarDoneNodes.
end(); ++currInd)
1504 if ((
node.inf == ati.inf) && ati.prevNode &&
1505 ((
node.prevNode == ati.prevNode) ||
1506 (
node.prevNode->inf == ati.prevNode->inf)))
1521 ANode *newNode = newANode(node);
1522 PENDING.push_back(newNode);
1524 push_heap( PENDING.begin(), PENDING.end(), pendingCmp);
1527 using std::cout;
using std::endl;
1529 cout <<
"PENDING: ";
1530 for (
unsigned int i = 0; i < PENDING.size(); i++)
1532 cout << PENDING[i]->g <<
"," << PENDING[i]->h <<
",";
1533 cout << PENDING[i]->inf <<
"," << PENDING[i]->pp <<
" ";
1535 cout << endl << endl;
1542 VertInf *endVert = router->vertices.end();
1543 for (VertInf *k = router->vertices.connsBegin(); k != endVert;
1546 k->aStarDoneNodes.clear();
1547 k->aStarPendingNodes.clear();
pair< double, double > Point
static SPStyleProp const props[]
Lookup dictionary for attributes/properties.
void search(ConnRef *lineRef, VertInf *src, VertInf *tar, VertInf *start)
AStarPathPrivate * m_private
The ConnRef class represents a connector object.
unsigned int id(void) const
Returns the ID of this connector.
VertInf * dst(void) const
ConnType routingType(void) const
Returns the type of routing performed for this connector.
VertInf * src(void) const
PolyLine & displayRoute(void)
Returns a reference to the current display version of the route for the connector.
Router * router(void) const
Returns a pointer to the router scene this connector is in.
The Point class defines a point in the plane.
unsigned int id
The ID associated with this point.
A dynamic Polygon, to which points can be easily added and removed.
size_t size(void) const
Returns the number of points in this polygon.
bool empty(void) const
Returns true if this polygon is empty.
std::vector< Point > ps
A vector of the points that make up the Polygon.
const Point & at(size_t index) const
Returns a specific point in the polygon.
The Router class represents a libavoid router instance.
bool routingOption(const RoutingOption option) const
Returns the current state for a specific routing option.
ClusterRefList clusterRefs
double routingParameter(const RoutingParameter parameter) const
Returns the current value for a particular routing parameter of a given type.
bool isInCrossingPenaltyReroutingStage(void) const
VertInf * getVertexByPos(const Point &p)
iterator end()
Helper to use the standard lib container functions.
iterator begin()
Iterator over children.
Contains the interface for the ConnRef class.
Inkscape::XML::Node * node
libavoid: Object-avoiding orthogonal and polyline connector routing library.
void db_printf(const char *fmt,...)
double manhattanDist(const Point &a, const Point &b)
bool validateBendPoint(VertInf *aInf, VertInf *bInf, VertInf *cInf)
static double cost(ConnRef *lineRef, const double dist, VertInf *inf2, VertInf *inf3, ANode *inf1Node)
static bool pointAlignedWithOneOf(const Point &point, const std::vector< Point > &points, const size_t dim)
static unsigned int dirReverse(unsigned int direction)
static unsigned int dirRight(unsigned int direction)
static const unsigned int YL_EDGE
static const unsigned int CostDirectionW
@ ConnType_Orthogonal
The connector path will be a shortest-path orthogonal poly-line (only vertical and horizontal line se...
@ ConnType_PolyLine
The connector path will be a shortest-path poly-line that routes around obstacles.
static const unsigned int CostDirectionE
static double CrossLength(const Point &l, const Point &r)
const unsigned int CROSSING_SHARES_PATH_AT_END
static const unsigned int XL_EDGE
static void printDirections(FILE *fp, unsigned int directions)
const unsigned int CROSSING_SHARES_PATH
static int dimDirection(double difference)
std::list< EdgeInf * > EdgeInfList
static unsigned int orthogonalDirection(const Point &a, const Point &b)
double euclideanDist(const Point &a, const Point &b)
@ crossingPenalty
This penalty is applied whenever a connector path crosses another connector path.
@ clusterCrossingPenalty
This penalty is applied whenever a connector path crosses a cluster boundary.
@ reverseDirectionPenalty
This penalty is applied whenever a connector path travels in the direction opposite of the destinatio...
@ fixedSharedPathPenalty
This penalty is applied whenever a connector path shares some segments with an immovable portion of a...
@ anglePenalty
This penalty is applied in its full amount to tight acute bends in the connector path.
@ segmentPenalty
This penalty is applied for each segment in the connector path beyond the first.
unsigned short VertIDProps
static const unsigned int CostDirectionN
static int vecDir(const Point &a, const Point &b, const Point &c, const double maybeZero=0.0)
static double angleBetween(const Point &p1, const Point &p2, const Point &p3)
static unsigned int orthogonalDirectionsCount(const unsigned int directions)
static const unsigned int YH_EDGE
const unsigned int CROSSING_SHARES_FIXED_SEGMENT
static double Dot(const Point &l, const Point &r)
@ penaliseOrthogonalSharedPathsAtConnEnds
This option penalises and attempts to reroute orthogonal shared connector paths terminating at a comm...
static const unsigned int CostDirectionS
static unsigned int dirLeft(unsigned int direction)
int bends(const Point &curr, unsigned int currDir, const Point &dest, unsigned int destDir)
static const unsigned int XH_EDGE
static void constructPolygonPath(Polygon &connRoute, VertInf *inf2, VertInf *inf3, ANode *inf1Node)
double dist(const Point &a, const Point &b)
static double estimatedCostSpecific(ConnRef *lineRef, const Point *last, const Point &curr, const VertInf *costTar, const unsigned int costTarDirs)
Polygon PolyLine
A multi-segment line, represented with the Polygon class.
std::shared_ptr< std::string > timestamp()
Contains the interface for the Router class.
Contains the interface for the ClusterRef class.