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
106 {
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;
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
165 {
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();
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;
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;
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);
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);
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);
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);
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
347 {
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
368 {
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);
405 }
408 #endif