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::lateSetup(const Point& src, const Point& dst)
239 {
240 assert(!_initialised);
242 bool isShape = false;
243 _srcVert = new VertInf(_router, VertID(_id, isShape, 1), src);
244 _dstVert = new VertInf(_router, VertID(_id, isShape, 2), dst);
245 _router->vertices.addVertex(_srcVert);
246 _router->vertices.addVertex(_dstVert);
247 makeActive();
248 _initialised = true;
249 }
252 VertInf *ConnRef::src(void)
253 {
254 return _srcVert;
255 }
258 VertInf *ConnRef::dst(void)
259 {
260 return _dstVert;
261 }
264 bool ConnRef::isInitialised(void)
265 {
266 return _initialised;
267 }
270 void ConnRef::unInitialise(void)
271 {
272 _router->vertices.removeVertex(_srcVert);
273 _router->vertices.removeVertex(_dstVert);
274 makeInactive();
275 _initialised = false;
276 }
279 void ConnRef::removeFromGraph(void)
280 {
281 for (VertInf *iter = _srcVert; iter != NULL; )
282 {
283 VertInf *tmp = iter;
284 iter = (iter == _srcVert) ? _dstVert : NULL;
286 // For each vertex.
287 EdgeInfList& visList = tmp->visList;
288 EdgeInfList::iterator finish = visList.end();
289 EdgeInfList::iterator edge;
290 while ((edge = visList.begin()) != finish)
291 {
292 // Remove each visibility edge
293 delete (*edge);
294 }
296 EdgeInfList& invisList = tmp->invisList;
297 finish = invisList.end();
298 while ((edge = invisList.begin()) != finish)
299 {
300 // Remove each invisibility edge
301 delete (*edge);
302 }
303 }
304 }
307 void ConnRef::setCallback(void (*cb)(void *), void *ptr)
308 {
309 _callback = cb;
310 _connector = ptr;
311 }
314 void ConnRef::handleInvalid(void)
315 {
316 if (_false_path || _needs_reroute_flag) {
317 if (_callback) {
318 _callback(_connector);
319 }
320 }
321 }
324 void ConnRef::makePathInvalid(void)
325 {
326 _needs_reroute_flag = true;
327 }
330 Router *ConnRef::router(void)
331 {
332 return _router;
333 }
336 int ConnRef::generatePath(Point p0, Point p1)
337 {
338 if (!_false_path && !_needs_reroute_flag) {
339 // This connector is up to date.
340 return (int) false;
341 }
343 _false_path = false;
344 _needs_reroute_flag = false;
346 VertInf *src = _srcVert;
347 VertInf *tar = _dstVert;
349 if ( !(_router->IncludeEndpoints) )
350 {
351 lateSetup(p0, p1);
353 // Update as they have just been set by lateSetup.
354 src = _srcVert;
355 tar = _dstVert;
357 bool knownNew = true;
358 vertexVisibility(src, tar, knownNew);
359 vertexVisibility(tar, src, knownNew);
360 }
362 bool *flag = &(_needs_reroute_flag);
364 makePath(this, flag);
366 bool result = true;
368 int pathlen = 1;
369 for (VertInf *i = tar; i != src; i = i->pathNext)
370 {
371 pathlen++;
372 if (i == NULL)
373 {
374 db_printf("Warning: Path not found...\n");
375 pathlen = 2;
376 tar->pathNext = src;
377 if (_router->InvisibilityGrph)
378 {
379 // TODO: Could we know this edge already?
380 EdgeInf *edge = EdgeInf::existingEdge(src, tar);
381 assert(edge != NULL);
382 edge->addCycleBlocker();
383 }
384 result = false;
385 break;
386 }
387 if (pathlen > 100)
388 {
389 fprintf(stderr, "ERROR: Should never be here...\n");
390 exit(1);
391 }
392 }
393 Point *path = (Point *) malloc(pathlen * sizeof(Point));
395 int j = pathlen - 1;
396 for (VertInf *i = tar; i != src; i = i->pathNext)
397 {
398 if (_router->InvisibilityGrph)
399 {
400 // TODO: Again, we could know this edge without searching.
401 EdgeInf *edge = EdgeInf::existingEdge(i, i->pathNext);
402 edge->addConn(flag);
403 }
404 else
405 {
406 _false_path = true;
407 }
408 path[j--] = i->point;
409 }
410 path[0] = src->point;
413 // Would clear visibility for endpoints here if required.
415 PolyLine& output_route = route();
416 output_route.pn = pathlen;
417 output_route.ps = path;
419 return (int) result;
420 }
423 //============================================================================
425 }