Code

Fixing scrollbar size for embeded color swatches.
[inkscape.git] / src / libavoid / graph.cpp
1 /*
2  * vim: ts=4 sw=4 et tw=0 wm=0
3  *
4  * libavoid - Fast, Incremental, Object-avoiding Line Router
5  * Copyright (C) 2004-2006  Michael Wybrow <mjwybrow@users.sourceforge.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * 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.
16  *
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  *
21 */
23 #include "libavoid/debug.h"
24 #include "libavoid/graph.h"
25 #include "libavoid/connector.h"
26 #include "libavoid/geometry.h"
27 #include "libavoid/polyutil.h"
28 #include "libavoid/timer.h"
29 #include "libavoid/vertices.h"
30 #include "libavoid/router.h"
32 #include <math.h>
34 namespace Avoid {
37 EdgeInf::EdgeInf(VertInf *v1, VertInf *v2)
38     : lstPrev(NULL)
39     , lstNext(NULL)
40     , _router(NULL)
41     , _added(false)
42     , _visible(false)
43     , _v1(v1)
44     , _v2(v2)
45     , _dist(-1)
46 {
47     // Not passed NULL values.
48     assert(v1 && v2);
50     // We are in the same instance
51     assert(_v1->_router == _v2->_router);
52     _router = _v1->_router;
54     _blockers.clear();
55     _conns.clear();
56 }
59 EdgeInf::~EdgeInf()
60 {
61     if (_added)
62     {
63         makeInactive();
64     }
65 }
68 void EdgeInf::makeActive(void)
69 {
70     assert(_added == false);
72     if (_visible)
73     {
74         _router->visGraph.addEdge(this);
75         _pos1 = _v1->visList.insert(_v1->visList.begin(), this);
76         _v1->visListSize++;
77         _pos2 = _v2->visList.insert(_v2->visList.begin(), this);
78         _v2->visListSize++;
79     }
80     else // if (invisible)
81     {
82         _router->invisGraph.addEdge(this);
83         _pos1 = _v1->invisList.insert(_v1->invisList.begin(), this);
84         _v1->invisListSize++;
85         _pos2 = _v2->invisList.insert(_v2->invisList.begin(), this);
86         _v2->invisListSize++;
87     }
88     _added = true;
89 }
92 void EdgeInf::makeInactive(void)
93 {
94     assert(_added == true);
96     if (_visible)
97     {
98         _router->visGraph.removeEdge(this);
99         _v1->visList.erase(_pos1);
100         _v1->visListSize--;
101         _v2->visList.erase(_pos2);
102         _v2->visListSize--;
103     }
104     else // if (invisible)
105     {
106         _router->invisGraph.removeEdge(this);
107         _v1->invisList.erase(_pos1);
108         _v1->invisListSize--;
109         _v2->invisList.erase(_pos2);
110         _v2->invisListSize--;
111     }
112     _blockers.clear();
113     _conns.clear();
114     _added = false;
118 double EdgeInf::getDist(void)
120     return _dist;
124 void EdgeInf::setDist(double dist)
126     //assert(dist != 0);
128     if (_added && !_visible)
129     {
130         makeInactive();
131     }
132     if (!_added)
133     {
134         _visible = true;
135         makeActive();
136     }
137     _dist = dist;
138     _blockers.clear();
142 void EdgeInf::alertConns(void)
144     for (FlagList::iterator i = _conns.begin(); i != _conns.end(); ++i)
145     {
146         *(*i) = true;
147     }
148     _conns.clear();
152 void EdgeInf::addConn(bool *flag)
154     _conns.push_back(flag);
158 void EdgeInf::addCycleBlocker(void)
160     // Needs to be in invisibility graph.
161     addBlocker(-1);
165 void EdgeInf::addBlocker(int b)
167     assert(_router->InvisibilityGrph);
169     if (_added && _visible)
170     {
171         makeInactive();
172     }
173     if (!_added)
174     {
175         _visible = false;
176         makeActive();
177     }
178     _dist = 0;
179     _blockers.clear();
180     _blockers.push_back(b);
184 bool EdgeInf::hasBlocker(int b)
186     assert(_router->InvisibilityGrph);
188     ShapeList::iterator finish = _blockers.end();
189     for (ShapeList::iterator it = _blockers.begin(); it != finish; ++it)
190     {
191         if ((*it) == -1)
192         {
193             alertConns();
194             return true;
195         }
196         else if ((*it) == b)
197         {
198             return true;
199         }
200     }
201     return false;
205 pair<VertID, VertID> EdgeInf::ids(void)
207     return std::make_pair(_v1->id, _v2->id);
211 pair<Point, Point> EdgeInf::points(void)
213     return std::make_pair(_v1->point, _v2->point);
217 void EdgeInf::db_print(void)
219     db_printf("Edge(");
220     _v1->id.db_print();
221     db_printf(",");
222     _v2->id.db_print();
223     db_printf(")\n");
227 void EdgeInf::checkVis(void)
229     if (_added && !_visible)
230     {
231         db_printf("\tChecking visibility for existing invisibility edge..."
232                 "\n\t\t");
233         db_print();
234     }
235     else if (_added && _visible)
236     {
237         db_printf("\tChecking visibility for existing visibility edge..."
238                 "\n\t\t");
239         db_print();
240     }
242     int blocker = 0;
243     bool cone1 = true;
244     bool cone2 = true;
246     VertInf *i = _v1;
247     VertInf *j = _v2;
248     const VertID& iID = i->id;
249     const VertID& jID = j->id;
250     const Point& iPoint = i->point;
251     const Point& jPoint = j->point;
253     _router->st_checked_edges++;
255     if (iID.isShape)
256     {
257         cone1 = inValidRegion(_router->IgnoreRegions, i->shPrev->point,
258                 iPoint, i->shNext->point, jPoint);
259     }
260     else
261     {
262         ShapeSet& ss = _router->contains[iID];
264         if ((jID.isShape) && (ss.find(jID.objID) != ss.end()))
265         {
266             db_printf("1: Edge of bounding shape\n");
267             // Don't even check this edge, it should be zero,
268             // since a point in a shape can't see it's corners
269             cone1 = false;
270         }
271     }
273     if (cone1)
274     {
275         // If outside the first cone, don't even bother checking.
276         if (jID.isShape)
277         {
278             cone2 = inValidRegion(_router->IgnoreRegions, j->shPrev->point,
279                     jPoint, j->shNext->point, iPoint);
280         }
281         else
282         {
283             ShapeSet& ss = _router->contains[jID];
285             if ((iID.isShape) && (ss.find(iID.objID) != ss.end()))
286             {
287                 db_printf("2: Edge of bounding shape\n");
288                 // Don't even check this edge, it should be zero,
289                 // since a point in a shape can't see it's corners
290                 cone2 = false;
291             }
292         }
293     }
295     if (cone1 && cone2 && ((blocker = firstBlocker()) == 0))
296     {
298         // if i and j see each other, add edge
299         db_printf("\tSetting visibility edge... \n\t\t");
300         db_print();
302         double d = dist(iPoint, jPoint);
304         setDist(d);
306     }
307     else if (_router->InvisibilityGrph)
308     {
309 #if 0
310         db_printf("%d, %d, %d\n", cone1, cone2, blocker);
311         db_printf("\t(%d, %d)--(%d, %d)\n", (int) iInfo.point.x,
312                 (int) iInfo.point.y, (int) jInfo.point.x,
313                 (int) jInfo.point.y);
314 #endif
316         // if i and j can't see each other, add blank edge
317         db_printf("\tSetting invisibility edge... \n\t\t");
318         db_print();
319         addBlocker(blocker);
320     }
324 int EdgeInf::firstBlocker(void)
326     ShapeSet ss = ShapeSet();
328     Point& pti = _v1->point;
329     Point& ptj = _v2->point;
330     VertID& iID = _v1->id;
331     VertID& jID = _v2->id;
333     ContainsMap &contains = _router->contains;
334     if (!(iID.isShape))
335     {
336         ss.insert(contains[iID].begin(), contains[iID].end());
337     }
338     if (!(jID.isShape))
339     {
340         ss.insert(contains[jID].begin(), contains[jID].end());
341     }
343     VertInf *last = _router->vertices.end();
344     for (VertInf *k = _router->vertices.shapesBegin(); k != last; )
345     {
346         VertID kID = k->id;
347         if ((ss.find(kID.objID) != ss.end()))
348         {
349             unsigned int shapeID = kID.objID;
350             db_printf("Endpoint is inside shape %u so ignore shape edges.\n",
351                     kID.objID);
352             // One of the endpoints is inside this shape so ignore it.
353             while ((k != last) && (k->id.objID == shapeID))
354             {
355                 // And skip the other vertices from this shape.
356                 k = k->lstNext;
357             }
358             continue;
359         }
360         Point& kPoint = k->point;
361         Point& kPrevPoint = k->shPrev->point;
363         if (segmentIntersect(pti, ptj, kPrevPoint, kPoint))
364         {
365             ss.clear();
366             return kID.objID;
367         }
368         k = k->lstNext;
369     }
370     ss.clear();
371     return 0;
375 bool EdgeInf::isBetween(VertInf *i, VertInf *j)
377     if ( ((i == _v1) && (j == _v2)) ||
378          ((i == _v2) && (j == _v1)) )
379     {
380         return true;
381     }
382     return false;
386 VertInf *EdgeInf::otherVert(VertInf *vert)
388     assert((vert == _v1) || (vert == _v2));
390     if (vert == _v1)
391     {
392         return _v2;
393     }
394     return _v1;
398 EdgeInf *EdgeInf::checkEdgeVisibility(VertInf *i, VertInf *j, bool knownNew)
400     Router *router = i->_router;
401     EdgeInf *edge = NULL;
403     if (knownNew)
404     {
405         assert(existingEdge(i, j) == NULL);
406         edge = new EdgeInf(i, j);
407     }
408     else
409     {
410         edge = existingEdge(i, j);
411         if (edge == NULL)
412         {
413             edge = new EdgeInf(i, j);
414         }
415     }
416     edge->checkVis();
417     if (!(edge->_added) && !(router->InvisibilityGrph))
418     {
419         delete edge;
420         edge = NULL;
421     }
423     return edge;
427 EdgeInf *EdgeInf::existingEdge(VertInf *i, VertInf *j)
429     VertInf *selected = NULL;
431     if (i->visListSize <= j->visListSize)
432     {
433         selected = i;
434     }
435     else
436     {
437         selected = j;
438     }
440     EdgeInfList& visList = selected->visList;
441     EdgeInfList::iterator finish = visList.end();
442     for (EdgeInfList::iterator edge = visList.begin(); edge != finish;
443             ++edge)
444     {
445         if ((*edge)->isBetween(i, j))
446         {
447             return (*edge);
448         }
449     }
451     if (i->invisListSize <= j->invisListSize)
452     {
453         selected = i;
454     }
455     else
456     {
457         selected = j;
458     }
460     EdgeInfList& invisList = selected->invisList;
461     finish = invisList.end();
462     for (EdgeInfList::iterator edge = invisList.begin(); edge != finish;
463             ++edge)
464     {
465         if ((*edge)->isBetween(i, j))
466         {
467             return (*edge);
468         }
469     }
471     return NULL;
475 //===========================================================================
478 EdgeList::EdgeList()
479     : _firstEdge(NULL)
480     , _lastEdge(NULL)
481     , _count(0)
486 void EdgeList::addEdge(EdgeInf *edge)
488     if (_firstEdge == NULL)
489     {
490         assert(_lastEdge == NULL);
492         _lastEdge = edge;
493         _firstEdge = edge;
495         edge->lstPrev = NULL;
496         edge->lstNext = NULL;
497     }
498     else
499     {
500         assert(_lastEdge != NULL);
502         _lastEdge->lstNext = edge;
503         edge->lstPrev = _lastEdge;
505         _lastEdge = edge;
507         edge->lstNext = NULL;
508     }
509     _count++;
513 void EdgeList::removeEdge(EdgeInf *edge)
515     if (edge->lstPrev)
516     {
517         edge->lstPrev->lstNext = edge->lstNext;
518     }
519     if (edge->lstNext)
520     {
521         edge->lstNext->lstPrev = edge->lstPrev;
522     }
523     if (edge == _lastEdge)
524     {
525         _lastEdge = edge->lstPrev;
526         if (edge == _firstEdge)
527         {
528             _firstEdge = NULL;
529         }
530     }
531     else if (edge == _firstEdge)
532     {
533         _firstEdge = edge->lstNext;
534     }
537     edge->lstPrev = NULL;
538     edge->lstNext = NULL;
540     _count--;
544 EdgeInf *EdgeList::begin(void)
546     return _firstEdge;
550 EdgeInf *EdgeList::end(void)
552     return NULL;