Code

Merge GSoC2009 Connectors into trunk
[inkscape.git] / src / libavoid / shape.cpp
1 /*
2  * vim: ts=4 sw=4 et tw=0 wm=0
3  *
4  * libavoid - Fast, Incremental, Object-avoiding Line Router
5  *
6  * Copyright (C) 2004-2008  Monash University
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  * See the file LICENSE.LGPL distributed with the library.
13  *
14  * Licensees holding a valid commercial license may use this file in
15  * accordance with the commercial license agreement provided with the 
16  * library.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
21  *
22  * Author(s):   Michael Wybrow <mjwybrow@users.sourceforge.net>
23 */
26 #include "libavoid/shape.h"
27 #include "libavoid/graph.h"  // For alertConns
28 #include "libavoid/vertices.h"
29 #include "libavoid/router.h"
30 #include "libavoid/debug.h"
31 #include "libavoid/assertions.h"
34 namespace Avoid {
37 ShapeRef::ShapeRef(Router *router, Polygon& ply, const unsigned int id)
38     : _router(router)
39     , _poly(ply)
40     , _active(false)
41     , _inMoveList(false)
42     , _firstVert(NULL)
43     , _lastVert(NULL)
44 {
45     _id = router->assignId(id);
47     bool isShape = true;
48     VertID i = VertID(_id, isShape, 0);
49     
50     const bool addToRouterNow = false;
51     VertInf *last = NULL;
52     VertInf *node = NULL;
53     for (size_t pt_i = 0; pt_i < _poly.size(); ++pt_i)
54     {
55         node = new VertInf(_router, i, _poly.ps[pt_i], addToRouterNow);
57         if (!_firstVert)
58         {
59             _firstVert = node;
60         }
61         else
62         {
63             node->shPrev = last;
64             last->shNext = node;
65             //node->lstPrev = last;
66             //last->lstNext = node;
67         }
68         
69         last = node;
70         i++;
71     }
72     _lastVert = node;
73     
74     _lastVert->shNext = _firstVert;
75     _firstVert->shPrev = _lastVert;
76 }
79 ShapeRef::~ShapeRef()
80 {
81     COLA_ASSERT(!_router->shapeInQueuedActionList(this));
83     if (_active)
84     {
85         // Destroying a shape without calling removeShape(), so do it now.
86         _router->removeShape(this);
87         _router->processTransaction();
88     }
90     COLA_ASSERT(_firstVert != NULL);
91     
92     VertInf *it = _firstVert;
93     do
94     {
95         VertInf *tmp = it;
96         it = it->shNext;
98         delete tmp;
99     }
100     while (it != _firstVert);
101     _firstVert = _lastVert = NULL;
105 void ShapeRef::setNewPoly(const Polygon& poly)
107     COLA_ASSERT(_firstVert != NULL);
108     COLA_ASSERT(_poly.size() == poly.size());
109     
110     VertInf *curr = _firstVert;
111     for (size_t pt_i = 0; pt_i < _poly.size(); ++pt_i)
112     {
113         COLA_ASSERT(curr->visListSize == 0);
114         COLA_ASSERT(curr->invisListSize == 0);
116         // Reset with the new polygon point.
117         curr->Reset(poly.ps[pt_i]);
118         curr->pathNext = NULL;
119         
120         curr = curr->shNext;
121     }
122     COLA_ASSERT(curr == _firstVert);
123         
124     _poly = poly;
128 void ShapeRef::makeActive(void)
130     COLA_ASSERT(!_active);
131     
132     // Add to shapeRefs list.
133     _pos = _router->shapeRefs.insert(_router->shapeRefs.begin(), this);
135     // Add points to vertex list.
136     VertInf *it = _firstVert;
137     do
138     {
139         VertInf *tmp = it;
140         it = it->shNext;
142         _router->vertices.addVertex(tmp);
143     }
144     while (it != _firstVert);
145     
146     _active = true;
150 void ShapeRef::makeInactive(void)
152     COLA_ASSERT(_active);
153     
154     // Remove from shapeRefs list.
155     _router->shapeRefs.erase(_pos);
157     // Remove points from vertex list.
158     VertInf *it = _firstVert;
159     do
160     {
161         VertInf *tmp = it;
162         it = it->shNext;
164         _router->vertices.removeVertex(tmp);
165     }
166     while (it != _firstVert);
167     
168     _active = false;
172 bool ShapeRef::isActive(void) const
174     return _active;
178 VertInf *ShapeRef::firstVert(void)
180     return _firstVert;
184 VertInf *ShapeRef::lastVert(void)
186     return _lastVert;
190 unsigned int ShapeRef::id(void) const
192     return _id;
196 const Polygon& ShapeRef::polygon(void) const
198     return _poly;
202 Router *ShapeRef::router(void) const
204     return _router;
208 void ShapeRef::boundingBox(BBox& bbox)
210     COLA_ASSERT(!_poly.empty());
212     bbox.a = bbox.b = _poly.ps[0];
213     Point& a = bbox.a;
214     Point& b = bbox.b;
216     for (size_t i = 1; i < _poly.size(); ++i)
217     {
218         const Point& p = _poly.ps[i];
220         a.x = std::min(p.x, a.x);
221         a.y = std::min(p.y, a.y);
222         b.x = std::max(p.x, b.x);
223         b.y = std::max(p.y, b.y);
224     }
228 void ShapeRef::removeFromGraph(void)
230     for (VertInf *iter = firstVert(); iter != lastVert()->lstNext; )
231     {
232         VertInf *tmp = iter;
233         iter = iter->lstNext;
234         
235         // For each vertex.
236         EdgeInfList& visList = tmp->visList;
237         EdgeInfList::const_iterator finish = visList.end();
238         EdgeInfList::const_iterator edge;
239         while ((edge = visList.begin()) != finish)
240         {
241             // Remove each visibility edge
242             (*edge)->alertConns();
243             delete (*edge);
244         }
246         EdgeInfList& invisList = tmp->invisList;
247         finish = invisList.end();
248         while ((edge = invisList.begin()) != finish)
249         {
250             // Remove each invisibility edge
251             delete (*edge);
252         }
254         EdgeInfList& orthogList = tmp->orthogVisList;
255         finish = orthogList.end();
256         while ((edge = orthogList.begin()) != finish)
257         {
258             // Remove each orthogonal visibility edge
259             (*edge)->alertConns();
260             delete (*edge);
261         }
262     }
266 void ShapeRef::markForMove(void)
268     if (!_inMoveList)
269     {
270         _inMoveList = true;
271     }
272     else
273     {
274         db_printf("WARNING: two moves queued for same shape prior to rerouting."
275                 "\n         This is not safe.\n");
276     }
280 void ShapeRef::clearMoveMark(void)
282     _inMoveList = false;
286 VertInf *ShapeRef::getPointVertex(const Point& point)
288     VertInf *curr = _firstVert;
289     do
290     {
291         if (curr->point == point)
292         {
293             return curr;
294         }
295         curr = curr->shNext;
296     }
297     while (curr != _firstVert);
299     return NULL;