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 {
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 }
111 }
114 void ConnRef::setType(unsigned int type)
115 {
116 _type = type;
117 }
120 void ConnRef::updateEndPoint(const unsigned int type, const Point& point)
121 {
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 }
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 }
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 }
163 altered = _dstVert;
164 partner = _srcVert;
165 }
167 bool knownNew = false;
168 vertexVisibility(altered, partner, knownNew, true);
169 }
172 void ConnRef::setEndPointId(const unsigned int type, const unsigned int id)
173 {
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 }
182 }
185 void ConnRef::makeActive(void)
186 {
187 assert(!_active);
189 // Add to connRefs list.
190 _pos = _router->connRefs.insert(_router->connRefs.begin(), this);
191 _active = true;
192 }
195 void ConnRef::makeInactive(void)
196 {
197 assert(_active);
199 // Remove from connRefs list.
200 _router->connRefs.erase(_pos);
201 _active = false;
202 }
205 void ConnRef::freeRoute(void)
206 {
207 if (_route.ps)
208 {
209 _route.pn = 0;
210 std::free(_route.ps);
211 _route.ps = NULL;
212 }
213 }
216 PolyLine& ConnRef::route(void)
217 {
218 return _route;
219 }
222 void ConnRef::calcRouteDist(void)
223 {
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 }
229 }
232 bool ConnRef::needsReroute(void)
233 {
234 return (_false_path || _needs_reroute_flag);
235 }
238 void ConnRef::moveRoute(const int& diff_x, const int& diff_y)
239 {
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 }
245 }
248 void ConnRef::lateSetup(const Point& src, const Point& dst)
249 {
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;
259 }
262 VertInf *ConnRef::src(void)
263 {
264 return _srcVert;
265 }
268 VertInf *ConnRef::dst(void)
269 {
270 return _dstVert;
271 }
274 bool ConnRef::isInitialised(void)
275 {
276 return _initialised;
277 }
280 void ConnRef::unInitialise(void)
281 {
282 _router->vertices.removeVertex(_srcVert);
283 _router->vertices.removeVertex(_dstVert);
284 makeInactive();
285 _initialised = false;
286 }
289 void ConnRef::removeFromGraph(void)
290 {
291 for (VertInf *iter = _srcVert; iter != NULL; )
292 {
293 VertInf *tmp = iter;
294 iter = (iter == _srcVert) ? _dstVert : NULL;
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 }
314 }
317 void ConnRef::setCallback(void (*cb)(void *), void *ptr)
318 {
319 _callback = cb;
320 _connector = ptr;
321 }
324 void ConnRef::handleInvalid(void)
325 {
326 if (_false_path || _needs_reroute_flag) {
327 if (_callback) {
328 _callback(_connector);
329 }
330 }
331 }
334 void ConnRef::makePathInvalid(void)
335 {
336 _needs_reroute_flag = true;
337 }
340 Router *ConnRef::router(void)
341 {
342 return _router;
343 }
346 int ConnRef::generatePath(Point p0, Point p1)
347 {
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);
363 // Update as they have just been set by lateSetup.
364 src = _srcVert;
365 tar = _dstVert;
367 bool knownNew = true;
368 vertexVisibility(src, tar, knownNew);
369 vertexVisibility(tar, src, knownNew);
370 }
372 bool *flag = &(_needs_reroute_flag);
374 makePath(this, flag);
376 bool result = true;
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;
429 return (int) result;
430 }
433 //============================================================================
435 }