Code

Merge GSoC2009 Connectors into trunk
[inkscape.git] / src / libavoid / connector.h
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-2009  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 */
25 //! @file    shape.h
26 //! @brief   Contains the interface for the ConnRef class.
29 #ifndef AVOID_CONNECTOR_H
30 #define AVOID_CONNECTOR_H
32 #include <list>
33 #include <vector>
35 #include "libavoid/vertices.h"
36 #include "libavoid/geometry.h"
37 #include "libavoid/shape.h"
40 namespace Avoid {
42 class Router;
43 class ConnRef;
44 typedef std::list<ConnRef *> ConnRefList;
47 //! @brief  Describes the type of routing that is performed for each 
48 //!         connector.
49 enum ConnType {
50     ConnType_None       = 0,
51     //! @brief  The connector path will be a shortest-path poly-line that
52     //!         routes around obstacles.
53     ConnType_PolyLine   = 1,
54     //! @brief  The connector path will be a shortest-path orthogonal 
55     //!         poly-line (only vertical and horizontal line segments) that
56     //!         routes around obstacles.
57     ConnType_Orthogonal = 2
58 };
60 //! @brief  Flags that can be passed to the ConnEnd constructor to specify
61 //!         which sides of a shape this point should have visibility to if
62 //!         it is located within the shape's area.
63 //!
64 //! Like SVG, libavoid considers the Y-axis to point downwards, that is, 
65 //! like screen coordinates the coordinates increase from left-to-right and 
66 //! also from top-to-bottom.
67 //!
68 enum ConnDirFlag {
69     ConnDirNone  = 0,
70     //! @brief  This option specifies the point should be given visibility 
71     //!         to the top of the shape that it is located within.
72     ConnDirUp    = 1,
73     //! @brief  This option specifies the point should be given visibility 
74     //!         to the bottom of the shape that it is located within.
75     ConnDirDown  = 2,
76     //! @brief  This option specifies the point should be given visibility 
77     //!         to the left side of the shape that it is located within.
78     ConnDirLeft  = 4,
79     //! @brief  This option specifies the point should be given visibility 
80     //!         to the right side of the shape that it is located within.
81     ConnDirRight = 8,
82     //! @brief  This option, provided for convenience, specifies the point 
83     //!         should be given visibility to all four sides of the shape 
84     //!         that it is located within.
85     ConnDirAll   = 15
86 };
87 //! @brief  One or more Avoid::ConnDirFlag options.
88 //!
89 typedef unsigned int ConnDirFlags;
92 static const double ATTACH_POS_TOP = 0;
93 static const double ATTACH_POS_CENTER = 0.5;
94 static const double ATTACH_POS_BOTTOM = 1;
95 static const double ATTACH_POS_LEFT = ATTACH_POS_TOP;
96 static const double ATTACH_POS_RIGHT = ATTACH_POS_BOTTOM;
99 //! @brief  The ConnEnd class represents different possible endpoints for 
100 //!         connectors.
101 //!
102 //! Currently this class just allows free-floating endpoints, but in future
103 //! will be capable of representing attachments to connection points on shapes.
104 //! 
105 class ConnEnd 
107     public:
108         //! @brief Constructs a ConnEnd from a free-floating point.
109         //!
110         //! @param[in]  point  The position of the connector endpoint.
111         //!
112         ConnEnd(const Point& point);
114         //! @brief Constructs a ConnEnd from a free-floating point as well
115         //!        as a set of flags specifying visibility for this point 
116         //!        if it is located inside a shape.
117         //!
118         //! @param[in]  point    The position of the connector endpoint.
119         //! @param[in]  visDirs  One or more Avoid::ConnDirFlag options 
120         //!                      specifying the directions that this point 
121         //!                      should be given visibility if it is inside 
122         //!                      a shape.
123         //!
124         ConnEnd(const Point& point, const ConnDirFlags visDirs);
126         ConnEnd(ShapeRef *shapeRef, const double x_pos, const double y_pos,
127                 const double insideOffset = 0.0,
128                 const ConnDirFlags visDirs = ConnDirNone);
130         //! @brief Returns the position of this connector endpoint
131         //!
132         //! @return The position of this connector endpoint.
133         const Point point(void) const;
135         ConnDirFlags directions(void) const;
136     private:
137         Point _point;
138         ConnDirFlags _directions;
139         
140         // For referencing ConnEnds
141         ShapeRef *_shapeRef;
142         double _xPosition;
143         double _yPosition;
144         double _insideOffset;
145 };
148 //! @brief   The ConnRef class represents a connector object.
149 //!
150 //! Connectors are a (possible multi-segment) line between two points.
151 //! They are routed intelligently so as not to overlap any of the shape
152 //! objects in the Router scene.
153 //! 
154 //! Routing penalties can be applied, resulting in more aesthetically pleasing
155 //! connector paths with fewer segments or less severe bend-points.
156 //!
157 //! You can set a function to be called when the connector has been rerouted
158 //! and needs to be redrawn.  Alternatively, you can query the connector's
159 //! needsRepaint() function to determine this manually.
160 //!
161 //! Usually, it is expected that you would create a ConnRef for each connector 
162 //! in your diagram and keep that reference in your own connector class.
163 //!
164 class ConnRef
166     public:
167         //! @brief Constructs a connector with no endpoints specified.
168         //!
169         //! @param[in]  router  The router scene to place the connector into.
170         //! @param[in]  id      A unique positive integer ID for the connector.  
171         //!
172         //! If an ID is not specified, then one will be assigned to the shape.
173         //! If assigning an ID yourself, note that it should be a unique 
174         //! positive integer.  Also, IDs are given to all objects in a scene,
175         //! so the same ID cannot be given to a shape and a connector for 
176         //! example.
177         //!
178         ConnRef(Router *router, const unsigned int id = 0);
179         //! @brief Constructs a connector with endpoints specified.
180         //!
181         //! @param[in]  router  The router scene to place the connector into.
182         //! @param[in]  id      A unique positive integer ID for the connector.
183         //! @param[in]  src     The source endpoint of the connector.
184         //! @param[in]  dst     The destination endpoint of the connector.
185         //!
186         //! If an ID is not specified, then one will be assigned to the shape.
187         //! If assigning an ID yourself, note that it should be a unique 
188         //! positive integer.  Also, IDs are given to all objects in a scene,
189         //! so the same ID cannot be given to a shape and a connector for 
190         //! example.
191         //!
192         ConnRef(Router *router, const ConnEnd& src, const ConnEnd& dst,
193                 const unsigned int id = 0);
194         //! @brief  Destuctor.
195         ~ConnRef();
196         
197         //! @brief  Sets both new source and destination endpoints for this 
198         //!         connector.
199         //!
200         //! @param[in]  srcPoint  New source endpoint for the connector.
201         //! @param[in]  dstPoint  New destination endpoint for the connector.
202         void setEndpoints(const ConnEnd& srcPoint, const ConnEnd& dstPoint);
203         //! @brief  Sets just a new source endpoint for this connector.
204         //!
205         //! @param[in]  srcPoint  New source endpoint for the connector.
206         void setSourceEndpoint(const ConnEnd& srcPoint);
207         //! @brief  Sets just a new destination endpoint for this connector.
208         //!
209         //! @param[in]  dstPoint  New destination endpoint for the connector.
210         void setDestEndpoint(const ConnEnd& dstPoint);
211         //! @brief   Returns the ID of this connector.
212         //! @returns The ID of the connector. 
213         unsigned int id(void) const;
214         //! @brief   Returns a pointer to the router scene this connector is in.
215         //! @returns A pointer to the router scene for this connector.
216         Router *router(void) const;
218         //! @brief   Returns an indication of whether this connector has a 
219         //!          new route and thus needs to be repainted.
220         //!
221         //! If the connector has been rerouted and need repainting, the  
222         //! route() method can be called to get a reference to the new route.
223         //!
224         //! @returns Returns true if the connector requires repainting, or 
225         //!          false if it does not.
226         bool needsRepaint(void) const;
227         
228         //! @brief   Returns a reference to the current route for the connector.
229         //!
230         //! This is a "raw" version of the route, where each line segment in
231         //! the route may be made up of multiple collinear line segments.  It
232         //! will also not have post-processing (like curved corners) applied
233         //! to it.  The simplified route for display can be obtained by calling
234         //! displayRoute().
235         //!
236         //! @returns The PolyLine route for the connector.
237         //! @note    You can obtain a modified version of this poly-line 
238         //!          route with curved corners added by calling 
239         //!          PolyLine::curvedPolyline().
240         const PolyLine& route(void) const;
241         
242         //! @brief   Returns a reference to the current display version of the
243         //!          route for the connector.
244         //! 
245         //! The display version of a route has been simplified to collapse all
246         //! collinear line segments into single segments.  It may also have 
247         //! post-processing applied to the route, such as curved corners or
248         //! nudging.
249         //! 
250         //! @returns The PolyLine display route for the connector.
251         PolyLine& displayRoute(void);
252         
253         //! @brief   Sets a callback function that will called to indicate that
254         //!          the connector needs rerouting.
255         //!
256         //! The cb function will be called when shapes are added to, removed 
257         //! from or moved about on the page.  The pointer ptr will be passed 
258         //! as an argument to the callback function.
259         //!
260         //! @param[in]  cb   A pointer to the callback function.
261         //! @param[in]  ptr  A generic pointer that will be passed to the 
262         //!                  callback function.
263         void setCallback(void (*cb)(void *), void *ptr);
264         //! @brief   Returns the type of routing performed for this connector.
265         //! @return  The type of routing performed.
266         //!
267         ConnType routingType(void) const;
268         //! @brief       Sets the type of routing to be performed for this 
269         //!              connector.
270         //! 
271         //! If a call to this method changes the current type of routing 
272         //! being used for the connector, then it will get rerouted during
273         //! the next processTransaction() call, or immediately if 
274         //! transactions are not being used.
275         //!
276         //! @param type  The type of routing to be performed.
277         //!
278         void setRoutingType(ConnType type);
280        
282         // @brief   Returns the source endpoint vertex in the visibility graph.
283         // @returns The source endpoint vertex.
284         VertInf *src(void);
285         // @brief   Returns the destination endpoint vertex in the 
286         //          visibility graph.
287         // @returns The destination endpoint vertex.
288         VertInf *dst(void);
289         
291         void set_route(const PolyLine& route);
292         void calcRouteDist(void);
293         void setEndPointId(const unsigned int type, const unsigned int id);
294         unsigned int getSrcShapeId(void);
295         unsigned int getDstShapeId(void);
296         void makeActive(void);
297         void makeInactive(void);
298         VertInf *start(void);
299         void removeFromGraph(void);
300         bool isInitialised(void);
301         void makePathInvalid(void);
302         void setHateCrossings(bool value);
303         bool doesHateCrossings(void);
304         void setEndpoint(const unsigned int type, const ConnEnd& connEnd);
305         bool setEndpoint(const unsigned int type, const VertID& pointID, 
306                 Point *pointSuggestion = NULL);
307     
308     private:
309         friend class Router;
311         PolyLine& routeRef(void);
312         void freeRoutes(void);
313         void performCallback(void);
314         bool generatePath(void);
315         bool generatePath(Point p0, Point p1);
316         void unInitialise(void);
317         void updateEndPoint(const unsigned int type, const ConnEnd& connEnd);
318         void common_updateEndPoint(const unsigned int type, const ConnEnd& connEnd);
319         Router *_router;
320         unsigned int _id;
321         ConnType _type;
322         unsigned int _srcId, _dstId;
323         bool _orthogonal;
324         bool _needs_reroute_flag;
325         bool _false_path;
326         bool _needs_repaint;
327         bool _active;
328         PolyLine _route;
329         Polygon _display_route;
330         double _route_dist;
331         ConnRefList::iterator _pos;
332         VertInf *_srcVert;
333         VertInf *_dstVert;
334         VertInf *_startVert;
335         bool _initialised;
336         void (*_callback)(void *);
337         void *_connector;
338         bool _hateCrossings;
339 };
342 class PointRep;
343 typedef std::set<PointRep *> PointRepSet;
344 typedef std::list<PointRep *> PointRepList;
346 class PointRep
348     public:
349         PointRep(Point *p, const ConnRef *c)
350             : point(p),
351               conn(c)
353         {
354         }
355         bool follow_inner(PointRep *target);
357         Point *point;
358         const ConnRef *conn;
359         // inner_set: Set of pointers to the PointReps 'inner' of 
360         // this one, at this corner.
361         PointRepSet inner_set;
362 };
365 typedef std::pair<Point *, ConnRef *> PtConnPtrPair;
367 class PtOrder
369     public:
370         PtOrder()
371         {
372         }
373         ~PtOrder();
374         bool addPoints(const int dim, PtConnPtrPair innerArg, 
375                 PtConnPtrPair outerArg, bool swapped);
376         void sort(const int dim);
377         int positionFor(const ConnRef *conn, const size_t dim) const;
379         // One for each dimension.
380         PointRepList connList[2];
381 };
383 typedef std::map<Avoid::Point,PtOrder> PtOrderMap;
384 typedef std::set<Avoid::Point> PointSet;
387 const unsigned int CROSSING_NONE = 0;
388 const unsigned int CROSSING_TOUCHES = 1;
389 const unsigned int CROSSING_SHARES_PATH = 2;
390 const unsigned int CROSSING_SHARES_PATH_AT_END = 4;
391 const unsigned int CROSSING_SHARES_FIXED_SEGMENT = 8;
394 typedef std::pair<int, unsigned int> CrossingsInfoPair;
396 extern CrossingsInfoPair countRealCrossings( Avoid::Polygon& poly, 
397         bool polyIsConn, Avoid::Polygon& conn, size_t cIndex, 
398         bool checkForBranchingSegments, const bool finalSegment = false, 
399         PointSet *crossingPoints = NULL, PtOrderMap *pointOrders = NULL, 
400         ConnRef *polyConnRef = NULL, ConnRef *connConnRef = NULL);
401 extern void splitBranchingSegments(Avoid::Polygon& poly, bool polyIsConn,
402         Avoid::Polygon& conn, const double tolerance = 0);
403 extern bool validateBendPoint(VertInf *aInf, VertInf *bInf, VertInf *cInf);
408 #endif