Code

Fixing scrollbar size for embeded color swatches.
[inkscape.git] / src / libavoid / connector.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/graph.h"
24 #include "libavoid/connector.h"
25 #include "libavoid/makepath.h"
26 #include "libavoid/visibility.h"
27 #include "libavoid/debug.h"
28 #include "libavoid/router.h"
31 namespace Avoid {
33     
34 ConnRef::ConnRef(Router *router, const unsigned int id)
35     : _router(router)
36     , _id(id)
37     , _type(ConnType_PolyLine)
38     , _srcId(0)
39     , _dstId(0)
40     , _needs_reroute_flag(true)
41     , _false_path(false)
42     , _active(false)
43     , _route_dist(0)
44     , _srcVert(NULL)
45     , _dstVert(NULL)
46     , _initialised(false)
47     , _callback(NULL)
48     , _connector(NULL)
49 {
50     // TODO: Store endpoints and details.
51     _route.pn = 0;
52     _route.ps = NULL;
53 }
56 ConnRef::ConnRef(Router *router, const unsigned int id,
57         const Point& src, const Point& dst)
58     : _router(router)
59     , _id(id)
60     , _type(ConnType_PolyLine)
61     , _srcId(0)
62     , _dstId(0)
63     , _needs_reroute_flag(true)
64     , _false_path(false)
65     , _active(false)
66     , _route_dist(0)
67     , _srcVert(NULL)
68     , _dstVert(NULL)
69     , _initialised(false)
70     , _callback(NULL)
71     , _connector(NULL)
72 {
73     _route.pn = 0;
74     _route.ps = NULL;
76     if (_router->IncludeEndpoints)
77     {
78         bool isShape = false;
79         _srcVert = new VertInf(_router, VertID(id, isShape, 1), src);
80         _dstVert = new VertInf(_router, VertID(id, isShape, 2), dst);
81         _router->vertices.addVertex(_srcVert);
82         _router->vertices.addVertex(_dstVert);
83         makeActive();
84         _initialised = true;
85     }
86 }
89 ConnRef::~ConnRef()
90 {
91     freeRoute();
93     if (_srcVert)
94     {
95         _router->vertices.removeVertex(_srcVert);
96         delete _srcVert;
97         _srcVert = NULL;
98     }
100     if (_dstVert)
101     {
102         _router->vertices.removeVertex(_dstVert);
103         delete _dstVert;
104         _dstVert = NULL;
105     }
107     if (_active)
108     {
109         makeInactive();
110     }
114 void ConnRef::setType(unsigned int type)
116     _type = type;
120 void ConnRef::updateEndPoint(const unsigned int type, const Point& point)
122     assert((type == (unsigned int) VertID::src) ||
123            (type == (unsigned int) VertID::tar));
124     //assert(IncludeEndpoints);
126     if (!_initialised)
127     {
128         makeActive();
129         _initialised = true;
130     }
131     
132     VertInf *altered = NULL;
133     VertInf *partner = NULL;
134     bool isShape = false;
136     if (type == (unsigned int) VertID::src)
137     {
138         if (_srcVert)
139         {
140             _srcVert->Reset(point);
141         }
142         else
143         {
144             _srcVert = new VertInf(_router, VertID(_id, isShape, type), point);
145             _router->vertices.addVertex(_srcVert);
146         }
147         
148         altered = _srcVert;
149         partner = _dstVert;
150     }
151     else // if (type == (unsigned int) VertID::dst)
152     {
153         if (_dstVert)
154         {
155             _dstVert->Reset(point);
156         }
157         else
158         {
159             _dstVert = new VertInf(_router, VertID(_id, isShape, type), point);
160             _router->vertices.addVertex(_dstVert);
161         }
162         
163         altered = _dstVert;
164         partner = _srcVert;
165     }
167     bool knownNew = false;
168     vertexVisibility(altered, partner, knownNew, true);
172 void ConnRef::setEndPointId(const unsigned int type, const unsigned int id)
174     if (type == (unsigned int) VertID::src)
175     {
176         _srcId = id;
177     }
178     else  // if (type == (unsigned int) VertID::dst)
179     {
180         _dstId = id;
181     }
185 void ConnRef::makeActive(void)
187     assert(!_active);
188     
189     // Add to connRefs list.
190     _pos = _router->connRefs.insert(_router->connRefs.begin(), this);
191     _active = true;
195 void ConnRef::makeInactive(void)
197     assert(_active);
198     
199     // Remove from connRefs list.
200     _router->connRefs.erase(_pos);
201     _active = false;
205 void ConnRef::freeRoute(void)
207     if (_route.ps)
208     {
209         _route.pn = 0;
210         std::free(_route.ps);
211         _route.ps = NULL;
212     }
214     
216 PolyLine& ConnRef::route(void)
218     return _route;
222 void ConnRef::calcRouteDist(void)
224     _route_dist = 0;
225     for (int i = 1; i < _route.pn; i++)
226     {
227         _route_dist += dist(_route.ps[i], _route.ps[i - 1]);
228     }
232 bool ConnRef::needsReroute(void)
234     return (_false_path || _needs_reroute_flag);
238 void ConnRef::moveRoute(const int& diff_x, const int& diff_y)
240     for (int i = 0; i < _route.pn; i++)
241     {
242         _route.ps[i].x += diff_x;
243         _route.ps[i].y += diff_y;
244     }
248 void ConnRef::lateSetup(const Point& src, const Point& dst)
250     assert(!_initialised);
252     bool isShape = false;
253     _srcVert = new VertInf(_router, VertID(_id, isShape, 1), src);
254     _dstVert = new VertInf(_router, VertID(_id, isShape, 2), dst);
255     _router->vertices.addVertex(_srcVert);
256     _router->vertices.addVertex(_dstVert);
257     makeActive();
258     _initialised = true;
262 VertInf *ConnRef::src(void)
264     return _srcVert;
267     
268 VertInf *ConnRef::dst(void)
270     return _dstVert;
274 bool ConnRef::isInitialised(void)
276     return _initialised;
280 void ConnRef::unInitialise(void)
282     _router->vertices.removeVertex(_srcVert);
283     _router->vertices.removeVertex(_dstVert);
284     makeInactive();
285     _initialised = false;
289 void ConnRef::removeFromGraph(void)
291     for (VertInf *iter = _srcVert; iter != NULL; )
292     {
293         VertInf *tmp = iter;
294         iter = (iter == _srcVert) ? _dstVert : NULL;
295         
296         // For each vertex.
297         EdgeInfList& visList = tmp->visList;
298         EdgeInfList::iterator finish = visList.end();
299         EdgeInfList::iterator edge;
300         while ((edge = visList.begin()) != finish)
301         {
302             // Remove each visibility edge
303             delete (*edge);
304         }
306         EdgeInfList& invisList = tmp->invisList;
307         finish = invisList.end();
308         while ((edge = invisList.begin()) != finish)
309         {
310             // Remove each invisibility edge
311             delete (*edge);
312         }
313     }
317 void ConnRef::setCallback(void (*cb)(void *), void *ptr)
319     _callback = cb;
320     _connector = ptr;
324 void ConnRef::handleInvalid(void)
326     if (_false_path || _needs_reroute_flag) {
327         if (_callback) {
328             _callback(_connector);
329         }
330     }
334 void ConnRef::makePathInvalid(void)
336     _needs_reroute_flag = true;
340 Router *ConnRef::router(void)
342     return _router;
346 int ConnRef::generatePath(Point p0, Point p1)
348     if (!_false_path && !_needs_reroute_flag) {
349         // This connector is up to date.
350         return (int) false;
351     }
353     _false_path = false;
354     _needs_reroute_flag = false;
356     VertInf *src = _srcVert;
357     VertInf *tar = _dstVert;
359     if ( !(_router->IncludeEndpoints) )
360     {
361         lateSetup(p0, p1);
362         
363         // Update as they have just been set by lateSetup.
364         src = _srcVert;
365         tar = _dstVert;
366    
367         bool knownNew = true;
368         vertexVisibility(src, tar, knownNew);
369         vertexVisibility(tar, src, knownNew);
370     }
372     bool *flag = &(_needs_reroute_flag);
373     
374     makePath(this, flag);
375     
376     bool result = true;
377     
378     int pathlen = 1;
379     for (VertInf *i = tar; i != src; i = i->pathNext)
380     {
381         pathlen++;
382         if (i == NULL)
383         {
384             db_printf("Warning: Path not found...\n");
385             pathlen = 2;
386             tar->pathNext = src;
387             if (_router->InvisibilityGrph)
388             {
389                 // TODO:  Could we know this edge already?
390                 EdgeInf *edge = EdgeInf::existingEdge(src, tar);
391                 assert(edge != NULL);
392                 edge->addCycleBlocker();
393             }
394             result = false;
395             break;
396         }
397         if (pathlen > 100)
398         {
399             fprintf(stderr, "ERROR: Should never be here...\n");
400             exit(1);
401         }
402     }
403     Point *path = (Point *) malloc(pathlen * sizeof(Point));
405     int j = pathlen - 1;
406     for (VertInf *i = tar; i != src; i = i->pathNext)
407     {
408         if (_router->InvisibilityGrph)
409         {
410             // TODO: Again, we could know this edge without searching.
411             EdgeInf *edge = EdgeInf::existingEdge(i, i->pathNext);
412             edge->addConn(flag);
413         }
414         else
415         {
416             _false_path = true;
417         }
418         path[j--] = i->point;
419     }
420     path[0] = src->point;
423     // Would clear visibility for endpoints here if required.
425     PolyLine& output_route = route();
426     output_route.pn = pathlen;
427     output_route.ps = path;
428    
429     return (int) result;
433 //============================================================================