2
2
* vim: ts=4 sw=4 et tw=0 wm=0
4
4
* libavoid - Fast, Incremental, Object-avoiding Line Router
5
* Copyright (C) 2004-2006 Michael Wybrow <mjwybrow@users.sourceforge.net>
6
* Copyright (C) 2004-2009 Monash University
7
8
* This library is free software; you can redistribute it and/or
8
9
* modify it under the terms of the GNU Lesser General Public
9
10
* License as published by the Free Software Foundation; either
10
11
* version 2.1 of the License, or (at your option) any later version.
12
* See the file LICENSE.LGPL distributed with the library.
14
* Licensees holding a valid commercial license may use this file in
15
* accordance with the commercial license agreement provided with the
12
18
* This library is distributed in the hope that it will be useful,
13
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22
* Author(s): Michael Wybrow <mjwybrow@users.sourceforge.net>
24
29
#include "libavoid/shape.h"
25
30
#include "libavoid/router.h"
26
31
#include "libavoid/visibility.h"
27
32
#include "libavoid/connector.h"
28
#include "libavoid/polyutil.h"
29
33
#include "libavoid/debug.h"
30
#include "libavoid/region.h"
33
//#define ORTHOGONAL_ROUTING
34
#include "libavoid/orthogonal.h"
35
#include "libavoid/assertions.h"
38
static const unsigned int infoAdd = 1;
39
static const unsigned int infoDel = 2;
40
static const unsigned int infoMov = 3;
47
typedef std::list<std::pair<unsigned int, ConnEnd> > ConnUpdateList;
45
MoveInfo(ShapeRef *s, Polygn *p, bool fM)
47
, newPoly(copyPoly(*p))
51
ActionInfo(ActionType t, ShapeRef *s, const Polygon& p, bool fM)
57
COLA_ASSERT(type == ShapeMove);
59
ActionInfo(ActionType t, ShapeRef *s)
63
COLA_ASSERT(type != ConnChange);
65
ActionInfo(ActionType t, ConnRef *c)
69
COLA_ASSERT(type == ConnChange);
74
ShapeRef *shape(void) const
76
COLA_ASSERT((type == ShapeMove) || (type == ShapeAdd) ||
77
(type == ShapeRemove));
78
return (static_cast<ShapeRef *> (objPtr));
80
ConnRef *conn(void) const
82
COLA_ASSERT(type == ConnChange);
83
return (static_cast<ConnRef *> (objPtr));
85
bool operator==(const ActionInfo& rhs) const
87
return (type == rhs.type) && (objPtr == rhs.objPtr);
89
bool operator<(const ActionInfo& rhs) const
93
return type < rhs.type;
95
return objPtr < rhs.objPtr;
101
ConnUpdateList conns;
63
, SimpleRouting(false)
66
, crossing_penalty(200)
68
, UseAStarSearch(true)
70
, SelectiveReroute(true)
71
, IncludeEndpoints(true)
72
, UseLeesAlgorithm(false)
73
, InvisibilityGrph(true)
74
, ConsolidateMoves(true)
75
, PartialFeedback(false)
105
Router::Router(const unsigned int flags)
106
: visOrthogGraph(true),
108
SimpleRouting(false),
109
ClusteredRouting(true),
110
// Poly-line algorithm options:
112
UseLeesAlgorithm(true),
113
InvisibilityGrph(true),
114
// General algorithm options:
115
SelectiveReroute(true),
116
PartialFeedback(false),
117
RubberBandRouting(false),
123
_largestAssignedId(0),
124
_consolidateActions(true),
125
_orthogonalNudgeDistance(4.0),
127
_polyLineRouting(false),
128
_orthogonalRouting(false),
129
_staticGraphInvalidated(true),
130
_inCrossingPenaltyReroutingStage(false)
132
// At least one of the Routing modes must be set.
133
COLA_ASSERT(flags & (PolyLineRouting | OrthogonalRouting));
135
if (flags & PolyLineRouting)
137
_polyLineRouting = true;
139
if (flags & OrthogonalRouting)
141
_orthogonalRouting = true;
144
for (size_t p = 0; p < lastPenaltyMarker; ++p)
146
_routingPenalties[p] = 0.0;
148
_routingPenalties[clusterCrossingPenalty] = 4000;
154
// Delete remaining connectors.
155
ConnRefList::iterator conn = connRefs.begin();
156
while (conn != connRefs.end())
158
db_printf("Deleting connector %u in ~Router()\n", (*conn)->id());
160
conn = connRefs.begin();
163
// Remove remaining shapes.
164
ShapeRefList::iterator shape = shapeRefs.begin();
165
while (shape != shapeRefs.end())
167
ShapeRef *shapePtr = *shape;
168
db_printf("Deleting shape %u in ~Router()\n", shapePtr->id());
169
if (shapePtr->isActive())
171
shapePtr->removeFromGraph();
172
shapePtr->makeInactive();
175
shape = shapeRefs.begin();
178
// Cleanup orphaned orthogonal graph vertices.
179
destroyOrthogonalVisGraph();
181
COLA_ASSERT(connRefs.size() == 0);
182
COLA_ASSERT(shapeRefs.size() == 0);
183
COLA_ASSERT(visGraph.size() == 0);
184
COLA_ASSERT(invisGraph.size() == 0);
188
void Router::modifyConnector(ConnRef *conn, const unsigned int type,
189
const ConnEnd& connEnd)
191
ActionInfo modInfo(ConnChange, conn);
193
ActionInfoList::iterator found =
194
find(actionList.begin(), actionList.end(), modInfo);
195
if (found == actionList.end())
197
modInfo.conns.push_back(std::make_pair(type, connEnd));
198
actionList.push_back(modInfo);
202
found->conns.push_back(std::make_pair(type, connEnd));
205
if (!_consolidateActions)
207
processTransaction();
212
void Router::modifyConnector(ConnRef *conn)
214
ActionInfo modInfo(ConnChange, conn);
216
ActionInfoList::iterator found =
217
find(actionList.begin(), actionList.end(), modInfo);
218
if (found == actionList.end())
220
actionList.push_back(modInfo);
223
if (!_consolidateActions)
225
processTransaction();
230
void Router::removeQueuedConnectorActions(ConnRef *conn)
232
ActionInfo modInfo(ConnChange, conn);
234
ActionInfoList::iterator found =
235
find(actionList.begin(), actionList.end(), modInfo);
236
if (found != actionList.end())
238
actionList.erase(found);
86
243
void Router::addShape(ShapeRef *shape)
88
unsigned int pid = shape->id();
89
Polygn poly = shape->poly();
91
adjustContainsWithAdd(poly, pid);
93
// o Check all visibility edges to see if this one shape
95
newBlockingShape(&poly, pid);
97
#ifdef ORTHOGONAL_ROUTING
98
Region::addShape(shape);
101
// o Calculate visibility for the new vertices.
102
if (UseLeesAlgorithm)
104
shapeVisSweep(shape);
110
callbackAllInvalidConnectors();
114
void Router::delShape(ShapeRef *shape)
116
unsigned int pid = shape->id();
118
// Delete items that are queued in the movList.
119
for (MoveInfoList::iterator it = moveList.begin(); it != moveList.end(); )
121
if ((*it)->shape->id() == pid)
123
MoveInfoList::iterator doomed = it;
125
moveList.erase(doomed);
133
// o Remove entries related to this shape's vertices
134
shape->removeFromGraph();
136
if (SelectiveReroute)
138
markConnectors(shape);
141
adjustContainsWithDel(pid);
143
#ifdef ORTHOGONAL_ROUTING
144
Region::removeShape(shape);
149
// o Check all edges that were blocked by this shape.
150
if (InvisibilityGrph)
152
checkAllBlockedEdges(pid);
156
// check all edges not in graph
157
checkAllMissingEdges();
159
callbackAllInvalidConnectors();
163
void Router::moveShape(ShapeRef *shape, Polygn *newPoly, const bool first_move)
245
// There shouldn't be remove events or move events for the same shape
246
// already in the action list.
247
// XXX: Possibly we could handle this by ordering them intelligently.
248
COLA_ASSERT(find(actionList.begin(), actionList.end(),
249
ActionInfo(ShapeRemove, shape)) == actionList.end());
250
COLA_ASSERT(find(actionList.begin(), actionList.end(),
251
ActionInfo(ShapeMove, shape)) == actionList.end());
253
ActionInfo addInfo(ShapeAdd, shape);
255
ActionInfoList::iterator found =
256
find(actionList.begin(), actionList.end(), addInfo);
257
if (found == actionList.end())
259
actionList.push_back(addInfo);
262
if (!_consolidateActions)
264
processTransaction();
269
void Router::removeShape(ShapeRef *shape)
271
// There shouldn't be add events events for the same shape already
272
// in the action list.
273
// XXX: Possibly we could handle this by ordering them intelligently.
274
COLA_ASSERT(find(actionList.begin(), actionList.end(),
275
ActionInfo(ShapeAdd, shape)) == actionList.end());
277
// Delete any ShapeMove entries for this shape in the action list.
278
ActionInfoList::iterator found = find(actionList.begin(),
279
actionList.end(), ActionInfo(ShapeMove, shape));
280
if (found != actionList.end())
282
actionList.erase(found);
285
// Add the ShapeRemove entry.
286
ActionInfo remInfo(ShapeRemove, shape);
287
found = find(actionList.begin(), actionList.end(), remInfo);
288
if (found == actionList.end())
290
actionList.push_back(remInfo);
293
if (!_consolidateActions)
295
processTransaction();
300
void Router::moveShape(ShapeRef *shape, const double xDiff, const double yDiff)
302
Polygon newPoly = shape->polygon();
303
newPoly.translate(xDiff, yDiff);
305
moveShape(shape, newPoly);
309
void Router::moveShape(ShapeRef *shape, const Polygon& newPoly,
310
const bool first_move)
312
// There shouldn't be remove events or add events for the same shape
313
// already in the action list.
314
// XXX: Possibly we could handle this by ordering them intelligently.
315
COLA_ASSERT(find(actionList.begin(), actionList.end(),
316
ActionInfo(ShapeRemove, shape)) == actionList.end());
318
if (find(actionList.begin(), actionList.end(),
319
ActionInfo(ShapeAdd, shape)) != actionList.end())
321
// The Add is enough, no need for the Move action too.
325
ActionInfo moveInfo(ShapeMove, shape, newPoly, first_move);
165
326
// Sanely cope with the case where the user requests moving the same
166
327
// shape multiple times before rerouting connectors.
167
bool alreadyThere = false;
168
unsigned int id = shape->id();
169
MoveInfoList::iterator finish = moveList.end();
170
for (MoveInfoList::iterator it = moveList.begin(); it != finish; ++it)
172
if ((*it)->shape->id() == id)
177
"warning: multiple moves requested for shape %d.\n",
180
// Just update the MoveInfo with the second polygon, but
181
// leave the firstMove setting alone.
182
(*it)->newPoly = copyPoly(*newPoly);
189
MoveInfo *moveInfo = new MoveInfo(shape, newPoly, first_move);
190
moveList.push_back(moveInfo);
193
if (!ConsolidateMoves)
200
void Router::processMoves(void)
202
// If SimpleRouting, then don't update yet.
203
if (moveList.empty() || SimpleRouting)
208
MoveInfoList::iterator curr;
209
MoveInfoList::iterator finish = moveList.end();
210
for (curr = moveList.begin(); curr != finish; ++curr)
212
MoveInfo *moveInf = *curr;
213
ShapeRef *shape = moveInf->shape;
214
Polygn *newPoly = &(moveInf->newPoly);
215
bool first_move = moveInf->firstMove;
328
ActionInfoList::iterator found =
329
find(actionList.begin(), actionList.end(), moveInfo);
331
if (found != actionList.end())
335
db_printf("warning: multiple moves requested for shape %d "
336
"within a single transaction.\n", (int) shape->id());
338
// Just update the ActionInfo with the second polygon, but
339
// leave the firstMove setting alone.
340
found->newPoly = newPoly;
344
actionList.push_back(moveInfo);
347
if (!_consolidateActions)
349
processTransaction();
354
void Router::setStaticGraphInvalidated(const bool invalidated)
356
_staticGraphInvalidated = invalidated;
360
void Router::destroyOrthogonalVisGraph(void)
362
// Remove orthogonal visibility graph edges.
363
visOrthogGraph.clear();
365
// Remove the now orphaned vertices.
366
VertInf *curr = vertices.shapesBegin();
369
if (curr->orphaned() && (curr->id == dummyOrthogID))
371
VertInf *following = vertices.removeVertex(curr);
376
curr = curr->lstNext;
381
void Router::regenerateStaticBuiltGraph(void)
383
// Here we do talks involved in updating the static-built visibility
384
// graph (if necessary) before we do any routing.
385
if (_staticGraphInvalidated)
387
if (_orthogonalRouting)
389
destroyOrthogonalVisGraph();
391
timers.Register(tmOrthogGraph, timerStart);
392
// Regenerate a new visibility graph.
393
generateStaticOrthogonalVisGraph(this);
397
_staticGraphInvalidated = false;
402
bool Router::shapeInQueuedActionList(ShapeRef *shape) const
404
bool foundAdd = find(actionList.begin(), actionList.end(),
405
ActionInfo(ShapeAdd, shape)) != actionList.end();
406
bool foundRem = find(actionList.begin(), actionList.end(),
407
ActionInfo(ShapeRemove, shape)) != actionList.end();
408
bool foundMove = find(actionList.begin(), actionList.end(),
409
ActionInfo(ShapeMove, shape)) != actionList.end();
411
return (foundAdd || foundRem || foundMove);
415
bool Router::transactionUse(void) const
417
return _consolidateActions;
421
void Router::setTransactionUse(const bool transactions)
423
_consolidateActions = transactions;
427
bool Router::processTransaction(void)
429
bool notPartialTime = !(PartialFeedback && PartialTime);
430
bool seenShapeMovesOrDeletes = false;
432
// If SimpleRouting, then don't update here.
433
if (actionList.empty() || SimpleRouting)
439
ActionInfoList::iterator curr;
440
ActionInfoList::iterator finish = actionList.end();
441
for (curr = actionList.begin(); curr != finish; ++curr)
443
ActionInfo& actInf = *curr;
444
if (!((actInf.type == ShapeRemove) || (actInf.type == ShapeMove)))
446
// Not a move or remove action, so don't do anything.
449
seenShapeMovesOrDeletes = true;
451
ShapeRef *shape = actInf.shape();
452
bool isMove = (actInf.type == ShapeMove);
453
bool first_move = actInf.firstMove;
217
455
unsigned int pid = shape->id();
218
bool notPartialTime = !(PartialFeedback && PartialTime);
220
457
// o Remove entries related to this shape's vertices
221
458
shape->removeFromGraph();
223
if (SelectiveReroute && (notPartialTime || first_move))
460
if (SelectiveReroute && (!isMove || notPartialTime || first_move))
225
462
markConnectors(shape);
228
465
adjustContainsWithDel(pid);
230
#ifdef ORTHOGONAL_ROUTING
231
Region::removeShape(shape);
234
shape->setNewPoly(*newPoly);
236
adjustContainsWithAdd(*newPoly, pid);
238
467
// Ignore this shape for visibility.
239
468
// XXX: We don't really need to do this if we're not using Partial
240
469
// Feedback. Without this the blocked edges still route
241
470
// around the shape until it leaves the connector.
242
471
shape->makeInactive();
246
if (InvisibilityGrph)
248
for (curr = moveList.begin(); curr != finish; ++curr)
250
MoveInfo *moveInf = *curr;
251
ShapeRef *shape = moveInf->shape;
252
unsigned int pid = shape->id();
254
// o Check all edges that were blocked by this shape.
255
checkAllBlockedEdges(pid);
260
// check all edges not in graph
261
checkAllMissingEdges();
264
while ( ! moveList.empty() )
266
MoveInfo *moveInf = moveList.front();
267
ShapeRef *shape = moveInf->shape;
268
Polygn *newPoly = &(moveInf->newPoly);
474
if (seenShapeMovesOrDeletes && _polyLineRouting)
476
if (InvisibilityGrph)
478
for (curr = actionList.begin(); curr != finish; ++curr)
480
ActionInfo& actInf = *curr;
481
if (!((actInf.type == ShapeRemove) ||
482
(actInf.type == ShapeMove)))
484
// Not a move or remove action, so don't do anything.
488
// o Check all edges that were blocked by this shape.
489
checkAllBlockedEdges(actInf.shape()->id());
494
// check all edges not in graph
495
checkAllMissingEdges();
499
for (curr = actionList.begin(); curr != finish; ++curr)
501
ActionInfo& actInf = *curr;
502
if (!((actInf.type == ShapeAdd) || (actInf.type == ShapeMove)))
504
// Not a move or add action, so don't do anything.
508
ShapeRef *shape = actInf.shape();
509
Polygon& newPoly = actInf.newPoly;
510
bool isMove = (actInf.type == ShapeMove);
270
512
unsigned int pid = shape->id();
271
bool notPartialTime = !(PartialFeedback && PartialTime);
273
514
// Restore this shape for visibility.
274
515
shape->makeActive();
276
#ifdef ORTHOGONAL_ROUTING
277
Region::addShape(shape);
280
// o Check all visibility edges to see if this one shape
284
newBlockingShape(newPoly, pid);
287
// o Calculate visibility for the new vertices.
288
if (UseLeesAlgorithm)
290
shapeVisSweep(shape);
297
moveList.pop_front();
300
callbackAllInvalidConnectors();
519
shape->setNewPoly(newPoly);
521
const Polygon& shapePoly = shape->polygon();
523
adjustContainsWithAdd(shapePoly, pid);
525
if (_polyLineRouting)
527
// o Check all visibility edges to see if this one shape
529
if (!isMove || notPartialTime)
531
newBlockingShape(shapePoly, pid);
534
// o Calculate visibility for the new vertices.
535
if (UseLeesAlgorithm)
537
shapeVisSweep(shape);
546
// Update connector endpoints.
547
for (curr = actionList.begin(); curr != finish; ++curr)
549
ActionInfo& actInf = *curr;
550
if (actInf.type != ConnChange)
554
for (ConnUpdateList::iterator conn = actInf.conns.begin();
555
conn != actInf.conns.end(); ++conn)
557
actInf.conn()->updateEndPoint(conn->first, conn->second);
560
// Clear the actionList.
563
_staticGraphInvalidated = true;
564
rerouteAndCallbackConnectors();
570
void Router::addCluster(ClusterRef *cluster)
572
cluster->makeActive();
574
unsigned int pid = cluster->id();
575
ReferencingPolygon& poly = cluster->polygon();
577
adjustClustersWithAdd(poly, pid);
581
void Router::delCluster(ClusterRef *cluster)
583
cluster->makeInactive();
585
unsigned int pid = cluster->id();
587
adjustClustersWithDel(pid);
591
void Router::setOrthogonalNudgeDistance(const double dist)
593
COLA_ASSERT(dist >= 0);
594
_orthogonalNudgeDistance = dist;
598
double Router::orthogonalNudgeDistance(void) const
600
return _orthogonalNudgeDistance;
604
unsigned int Router::assignId(const unsigned int suggestedId)
606
// If the suggestedId is zero, then we assign the object the next
607
// smallest unassigned ID, otherwise we trust the ID given is unique.
608
unsigned int assignedId = (suggestedId == 0) ?
609
(_largestAssignedId + 1) : suggestedId;
611
// Have the router record if this ID is larger than the _largestAssignedId.
612
_largestAssignedId = std::max(_largestAssignedId, assignedId);
614
// If assertions are enabled, then we check that this ID really is unique.
615
COLA_ASSERT(idIsUnique(assignedId));
621
// Returns whether the given ID is unique among all objects known by the
622
// router. Outputs a warning if the ID is found ore than once.
623
// It is expected this is only going to be called from assertions while
624
// debugging, so efficiency is not an issue and we just iterate over all
626
bool Router::idIsUnique(const unsigned int id) const
628
unsigned int count = 0;
631
for (ShapeRefList::const_iterator i = shapeRefs.begin();
632
i != shapeRefs.end(); ++i)
634
if ((*i)->id() == id)
640
// Examine connectors.
641
for (ConnRefList::const_iterator i = connRefs.begin();
642
i != connRefs.end(); ++i)
644
if ((*i)->id() == id)
651
for (ClusterRefList::const_iterator i = clusterRefs.begin();
652
i != clusterRefs.end(); ++i)
654
if ((*i)->id() == id)
662
db_printf("Warning:\tlibavoid object ID %d not unique.\n", id);
787
1392
fprintf(fp, "checkVisEdge tally: %d\n", st_checked_edges);
788
1393
fprintf(fp, "----------------------\n");
790
fprintf(fp, "ADDS: "); timers.Print(tmAdd);
791
fprintf(fp, "DELS: "); timers.Print(tmDel);
792
fprintf(fp, "MOVS: "); timers.Print(tmMov);
793
fprintf(fp, "***S: "); timers.Print(tmSev);
794
fprintf(fp, "PTHS: "); timers.Print(tmPth);
1395
fprintf(fp, "ADDS: "); timers.Print(tmAdd, fp);
1396
fprintf(fp, "DELS: "); timers.Print(tmDel, fp);
1397
fprintf(fp, "MOVS: "); timers.Print(tmMov, fp);
1398
fprintf(fp, "***S: "); timers.Print(tmSev, fp);
1399
fprintf(fp, "PTHS: "); timers.Print(tmPth, fp);
1400
fprintf(fp, "OrthogGraph: "); timers.Print(tmOrthogGraph, fp);
1401
fprintf(fp, "OrthogRoute: "); timers.Print(tmOrthogRoute, fp);
1402
fprintf(fp, "OrthogCentre: "); timers.Print(tmOrthogCentre, fp);
1403
fprintf(fp, "OrthogNudge: "); timers.Print(tmOrthogNudge, fp);
795
1404
fprintf(fp, "\n");
1409
static const double LIMIT = 100000000;
1411
static void reduceRange(double& val)
1413
val = std::min(val, LIMIT);
1414
val = std::max(val, -LIMIT);
1418
//=============================================================================
1419
// The following methods are for testing and debugging.
1422
bool Router::existsOrthogonalPathOverlap(void)
1424
ConnRefList::iterator fin = connRefs.end();
1425
for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i)
1427
Avoid::Polygon iRoute = (*i)->displayRoute();
1428
ConnRefList::iterator j = i;
1429
for (++j; j != fin; ++j)
1431
// Determine if this pair overlap
1432
Avoid::Polygon jRoute = (*j)->displayRoute();
1433
CrossingsInfoPair crossingInfo = std::make_pair(0, 0);
1434
for (size_t jInd = 1; jInd < jRoute.size(); ++jInd)
1436
const bool finalSegment = ((jInd + 1) == jRoute.size());
1437
CrossingsInfoPair crossingInfo = countRealCrossings(
1438
iRoute, true, jRoute, jInd, true,
1439
finalSegment, NULL, NULL, *i, *j);
1441
if ((crossingInfo.second & CROSSING_SHARES_PATH) &&
1442
(crossingInfo.second & CROSSING_SHARES_FIXED_SEGMENT) &&
1443
!(crossingInfo.second & CROSSING_SHARES_PATH_AT_END))
1445
// We looking for fixedSharedPaths and there is a
1456
bool Router::existsOrthogonalTouchingCorners(void)
1458
ConnRefList::iterator fin = connRefs.end();
1459
for (ConnRefList::iterator i = connRefs.begin(); i != fin; ++i)
1461
Avoid::Polygon iRoute = (*i)->displayRoute();
1462
ConnRefList::iterator j = i;
1463
for (++j; j != fin; ++j)
1465
// Determine if this pair overlap
1466
Avoid::Polygon jRoute = (*j)->displayRoute();
1467
CrossingsInfoPair crossingInfo = std::make_pair(0, 0);
1468
for (size_t jInd = 1; jInd < jRoute.size(); ++jInd)
1470
const bool finalSegment = ((jInd + 1) == jRoute.size());
1471
CrossingsInfoPair crossingInfo = countRealCrossings(
1472
iRoute, true, jRoute, jInd, true,
1473
finalSegment, NULL, NULL, *i, *j);
1475
if (crossingInfo.second & CROSSING_TOUCHES)
1486
void Router::outputInstanceToSVG(std::string instanceName)
1488
std::string filename;
1489
if (!instanceName.empty())
1491
filename = instanceName;
1495
filename = "libavoid-debug";
1498
FILE *fp = fopen(filename.c_str(), "w");
1505
double minX = LIMIT;
1506
double minY = LIMIT;
1507
double maxX = -LIMIT;
1508
double maxY = -LIMIT;
1510
VertInf *curr = vertices.connsBegin();
1513
Point p = curr->point;
1520
minX = std::min(minX, p.x);
1524
maxX = std::max(maxX, p.x);
1528
minY = std::min(minY, p.y);
1532
maxY = std::max(maxY, p.y);
1534
curr = curr->lstNext;
1541
fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1542
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);
1544
// Output source code to generate this instance of the router.
1545
fprintf(fp, "<!-- Source code to generate this instance:\n");
1546
fprintf(fp, "#include \"libavoid/libavoid.h\"\n");
1547
fprintf(fp, "using namespace Avoid;\n");
1548
fprintf(fp, "int main(void) {\n");
1549
fprintf(fp, " Router *router = new Router(\n");
1550
fprintf(fp, " PolyLineRouting | OrthogonalRouting);\n");
1551
for (size_t p = 0; p < lastPenaltyMarker; ++p)
1553
fprintf(fp, " router->setRoutingPenalty((PenaltyType)%lu, %g);\n",
1554
static_cast<long unsigned int>(p), _routingPenalties[p]);
1556
fprintf(fp, " router->setOrthogonalNudgeDistance(%g);\n\n",
1557
orthogonalNudgeDistance());
1558
ShapeRefList::iterator shRefIt = shapeRefs.begin();
1559
while (shRefIt != shapeRefs.end())
1561
ShapeRef *shRef = *shRefIt;
1562
fprintf(fp, " Polygon poly%u(%lu);\n",
1563
shRef->id(), static_cast<long unsigned int>(shRef->polygon().size()));
1564
for (size_t i = 0; i < shRef->polygon().size(); ++i)
1566
fprintf(fp, " poly%u.ps[%lu] = Point(%g, %g);\n",
1567
shRef->id(), static_cast<long unsigned int>(i), shRef->polygon().at(i).x,
1568
shRef->polygon().at(i).y);
1570
fprintf(fp, " ShapeRef *shapeRef%u = new ShapeRef(router, poly%u, "
1571
"%u);\n", shRef->id(), shRef->id(), shRef->id());
1572
fprintf(fp, " router->addShape(shapeRef%u);\n\n", shRef->id());
1575
ConnRefList::reverse_iterator revConnRefIt = connRefs.rbegin();
1576
while (revConnRefIt != connRefs.rend())
1578
ConnRef *connRef = *revConnRefIt;
1579
fprintf(fp, " ConnRef *connRef%u = new ConnRef(router, %u);\n",
1580
connRef->id(), connRef->id());
1583
fprintf(fp, " ConnEnd srcPt%u(Point(%g, %g), %u);\n",
1584
connRef->id(), connRef->src()->point.x,
1585
connRef->src()->point.y, connRef->src()->visDirections);
1586
fprintf(fp, " connRef%u->setSourceEndpoint(srcPt%u);\n",
1587
connRef->id(), connRef->id());
1591
fprintf(fp, " ConnEnd dstPt%u(Point(%g, %g), %u);\n",
1592
connRef->id(), connRef->dst()->point.x,
1593
connRef->dst()->point.y, connRef->dst()->visDirections);
1594
fprintf(fp, " connRef%u->setDestEndpoint(dstPt%u);\n",
1595
connRef->id(), connRef->id());
1597
fprintf(fp, " connRef%u->setRoutingType((ConnType)%u);\n\n",
1598
connRef->id(), connRef->routingType());
1601
fprintf(fp, " router->processTransaction();\n");
1602
fprintf(fp, " router->outputInstanceToSVG();\n");
1603
fprintf(fp, " delete router;\n");
1604
fprintf(fp, " return 0;\n");
1605
fprintf(fp, "};\n");
1606
fprintf(fp, "-->\n");
1609
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1610
"inkscape:label=\"ShapesPoly\">\n");
1611
shRefIt = shapeRefs.begin();
1612
while (shRefIt != shapeRefs.end())
1614
ShapeRef *shRef = *shRefIt;
1616
fprintf(fp, "<path id=\"poly-%u\" style=\"stroke-width: 1px; "
1617
"stroke: black; fill: blue; fill-opacity: 0.3;\" d=\"",
1619
for (size_t i = 0; i < shRef->polygon().size(); ++i)
1621
fprintf(fp, "%c %g,%g ", ((i == 0) ? 'M' : 'L'),
1622
shRef->polygon().at(i).x, shRef->polygon().at(i).y);
1624
fprintf(fp, "Z\" />\n");
1627
fprintf(fp, "</g>\n");
1629
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1630
"style=\"display: none;\" "
1631
"inkscape:label=\"ShapesRect\">\n");
1632
shRefIt = shapeRefs.begin();
1633
while (shRefIt != shapeRefs.end())
1635
ShapeRef *shRef = *shRefIt;
1636
double minX, minY, maxX, maxY;
1637
shRef->polygon().getBoundingRect(&minX, &minY, &maxX, &maxY);
1639
fprintf(fp, "<rect id=\"rect-%u\" x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
1640
"style=\"stroke-width: 1px; stroke: black; fill: blue; fill-opacity: 0.3;\" />\n",
1641
shRef->id(), minX, minY, maxX - minX, maxY - minY);
1644
fprintf(fp, "</g>\n");
1647
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1648
"inkscape:label=\"VisGraph\""
1650
EdgeInf *finish = NULL;
1651
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1652
"style=\"display: none;\" "
1653
"inkscape:label=\"VisGraph-shape\""
1655
finish = visGraph.end();
1656
for (EdgeInf *t = visGraph.begin(); t != finish; t = t->lstNext)
1658
std::pair<VertID, VertID> ids = t->ids();
1659
bool isShape = (ids.first.isShape) && (ids.second.isShape);
1664
std::pair<Point, Point> ptpair = t->points();
1665
Point p1 = ptpair.first;
1666
Point p2 = ptpair.second;
1673
fprintf(fp, "<path d=\"M %g,%g L %g,%g\" "
1674
"style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n",
1675
p1.x, p1.y, p2.x, p2.y,
1676
(!(ids.first.isShape) || !(ids.second.isShape)) ? "green" :
1679
fprintf(fp, "</g>\n");
1681
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1682
"style=\"display: none;\" "
1683
"inkscape:label=\"VisGraph-conn\""
1685
finish = visGraph.end();
1686
for (EdgeInf *t = visGraph.begin(); t != finish; t = t->lstNext)
1688
std::pair<VertID, VertID> ids = t->ids();
1689
bool isShape = (ids.first.isShape) && (ids.second.isShape);
1694
std::pair<Point, Point> ptpair = t->points();
1695
Point p1 = ptpair.first;
1696
Point p2 = ptpair.second;
1703
fprintf(fp, "<path d=\"M %g,%g L %g,%g\" "
1704
"style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n",
1705
p1.x, p1.y, p2.x, p2.y,
1706
(!(ids.first.isShape) || !(ids.second.isShape)) ? "green" :
1709
fprintf(fp, "</g>\n");
1710
fprintf(fp, "</g>\n");
1712
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1713
"style=\"display: none;\" "
1714
"inkscape:label=\"OrthogVisGraph\">\n");
1715
finish = visOrthogGraph.end();
1716
for (EdgeInf *t = visOrthogGraph.begin(); t != finish; t = t->lstNext)
1718
std::pair<Point, Point> ptpair = t->points();
1719
Point p1 = ptpair.first;
1720
Point p2 = ptpair.second;
1727
std::pair<VertID, VertID> ids = t->ids();
1729
fprintf(fp, "<path d=\"M %g,%g L %g,%g\" "
1730
"style=\"fill: none; stroke: %s; stroke-width: 1px;\" />\n",
1731
p1.x, p1.y, p2.x, p2.y,
1732
(!(ids.first.isShape) || !(ids.second.isShape)) ? "green" :
1735
fprintf(fp, "</g>\n");
1737
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1738
"style=\"display: none;\" "
1739
"inkscape:label=\"RawConnectors\""
1741
ConnRefList::iterator connRefIt = connRefs.begin();
1742
while (connRefIt != connRefs.end())
1744
ConnRef *connRef = *connRefIt;
1746
PolyLine route = connRef->route();
1749
fprintf(fp, "<path id=\"raw-%u\" d=\"M %g,%g ", connRef->id(),
1750
route.ps[0].x, route.ps[0].y);
1751
for (size_t i = 1; i < route.size(); ++i)
1753
fprintf(fp, "L %g,%g ", route.ps[i].x, route.ps[i].y);
1756
if (connRef->src() && connRef->dst())
1758
fprintf(fp, "debug=\"src: %d dst: %d\" ",
1759
connRef->src()->visDirections,
1760
connRef->dst()->visDirections);
1762
fprintf(fp, "style=\"fill: none; stroke: black; "
1763
"stroke-width: 1px;\" />\n");
1768
fprintf(fp, "</g>\n");
1770
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1771
"style=\"display: none;\" "
1772
"inkscape:label=\"CurvedDisplayConnectors\""
1774
connRefIt = connRefs.begin();
1775
while (connRefIt != connRefs.end())
1777
ConnRef *connRef = *connRefIt;
1779
PolyLine route = connRef->displayRoute().curvedPolyline(8);
1782
fprintf(fp, "<path id=\"curved-%u\" d=\"M %g,%g ", connRef->id(),
1783
route.ps[0].x, route.ps[0].y);
1784
for (size_t i = 1; i < route.size(); ++i)
1786
if (route.ts[i] == 'C')
1788
fprintf(fp, "%c %g,%g %g,%g %g,%g", route.ts[i],
1789
route.ps[i].x, route.ps[i].y,
1790
route.ps[i+1].x, route.ps[i+1].y,
1791
route.ps[i+2].x, route.ps[i+2].y);
1796
fprintf(fp, "%c %g,%g ", route.ts[i],
1797
route.ps[i].x, route.ps[i].y);
1801
if (connRef->src() && connRef->dst())
1803
fprintf(fp, "debug=\"src: %d dst: %d\" ",
1804
connRef->src()->visDirections,
1805
connRef->dst()->visDirections);
1807
fprintf(fp, "style=\"fill: none; stroke: black; "
1808
"stroke-width: 1px;\" />\n");
1813
fprintf(fp, "</g>\n");
1816
fprintf(fp, "<g inkscape:groupmode=\"layer\" "
1817
"inkscape:label=\"DisplayConnectors\""
1819
connRefIt = connRefs.begin();
1820
while (connRefIt != connRefs.end())
1822
ConnRef *connRef = *connRefIt;
1824
PolyLine route = connRef->displayRoute();
1827
fprintf(fp, "<path id=\"disp-%u\" d=\"M %g,%g ", connRef->id(),
1828
route.ps[0].x, route.ps[0].y);
1829
for (size_t i = 1; i < route.size(); ++i)
1831
fprintf(fp, "L %g,%g ", route.ps[i].x, route.ps[i].y);
1834
if (connRef->src() && connRef->dst())
1836
fprintf(fp, "debug=\"src: %d dst: %d\" ",
1837
connRef->src()->visDirections,
1838
connRef->dst()->visDirections);
1840
fprintf(fp, "style=\"fill: none; stroke: black; "
1841
"stroke-width: 1px;\" />\n");
1846
fprintf(fp, "</g>\n");
1849
fprintf(fp, "</svg>\n");