index 1fd4255a8a6726550bd99aee289bf190d78fd4e1..8f7499a2934838709479ec325a87d5a18713761c 100644 (file)
--- a/src/libavoid/connector.h
+++ b/src/libavoid/connector.h
* vim: ts=4 sw=4 et tw=0 wm=0
*
* libavoid - Fast, Incremental, Object-avoiding Line Router
- * Copyright (C) 2004-2005 Michael Wybrow <mjwybrow@users.sourceforge.net>
+ *
+ * Copyright (C) 2004-2009 Monash University
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
+ * See the file LICENSE.LGPL distributed with the library.
+ *
+ * Licensees holding a valid commercial license may use this file in
+ * accordance with the commercial license agreement provided with the
+ * library.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Author(s): Michael Wybrow <mjwybrow@users.sourceforge.net>
*/
+//! @file shape.h
+//! @brief Contains the interface for the ConnRef class.
+
+
#ifndef AVOID_CONNECTOR_H
#define AVOID_CONNECTOR_H
+#include <list>
+#include <vector>
+
+#include "libavoid/vertices.h"
#include "libavoid/geometry.h"
#include "libavoid/shape.h"
-#include <list>
namespace Avoid {
+class Router;
class ConnRef;
-
typedef std::list<ConnRef *> ConnRefList;
-typedef std::list<unsigned int> IntList;
+//! @brief Describes the type of routing that is performed for each
+//! connector.
+enum ConnType {
+ ConnType_None = 0,
+ //! @brief The connector path will be a shortest-path poly-line that
+ //! routes around obstacles.
+ ConnType_PolyLine = 1,
+ //! @brief The connector path will be a shortest-path orthogonal
+ //! poly-line (only vertical and horizontal line segments) that
+ //! routes around obstacles.
+ ConnType_Orthogonal = 2
+};
+
+//! @brief Flags that can be passed to the ConnEnd constructor to specify
+//! which sides of a shape this point should have visibility to if
+//! it is located within the shape's area.
+//!
+//! Like SVG, libavoid considers the Y-axis to point downwards, that is,
+//! like screen coordinates the coordinates increase from left-to-right and
+//! also from top-to-bottom.
+//!
+enum ConnDirFlag {
+ ConnDirNone = 0,
+ //! @brief This option specifies the point should be given visibility
+ //! to the top of the shape that it is located within.
+ ConnDirUp = 1,
+ //! @brief This option specifies the point should be given visibility
+ //! to the bottom of the shape that it is located within.
+ ConnDirDown = 2,
+ //! @brief This option specifies the point should be given visibility
+ //! to the left side of the shape that it is located within.
+ ConnDirLeft = 4,
+ //! @brief This option specifies the point should be given visibility
+ //! to the right side of the shape that it is located within.
+ ConnDirRight = 8,
+ //! @brief This option, provided for convenience, specifies the point
+ //! should be given visibility to all four sides of the shape
+ //! that it is located within.
+ ConnDirAll = 15
+};
+//! @brief One or more Avoid::ConnDirFlag options.
+//!
+typedef unsigned int ConnDirFlags;
+
+
+static const double ATTACH_POS_TOP = 0;
+static const double ATTACH_POS_CENTER = 0.5;
+static const double ATTACH_POS_BOTTOM = 1;
+static const double ATTACH_POS_LEFT = ATTACH_POS_TOP;
+static const double ATTACH_POS_RIGHT = ATTACH_POS_BOTTOM;
+
+
+//! @brief The ConnEnd class represents different possible endpoints for
+//! connectors.
+//!
+//! Currently this class just allows free-floating endpoints, but in future
+//! will be capable of representing attachments to connection points on shapes.
+//!
+class ConnEnd
+{
+ public:
+ //! @brief Constructs a ConnEnd from a free-floating point.
+ //!
+ //! @param[in] point The position of the connector endpoint.
+ //!
+ ConnEnd(const Point& point);
+
+ //! @brief Constructs a ConnEnd from a free-floating point as well
+ //! as a set of flags specifying visibility for this point
+ //! if it is located inside a shape.
+ //!
+ //! @param[in] point The position of the connector endpoint.
+ //! @param[in] visDirs One or more Avoid::ConnDirFlag options
+ //! specifying the directions that this point
+ //! should be given visibility if it is inside
+ //! a shape.
+ //!
+ ConnEnd(const Point& point, const ConnDirFlags visDirs);
+
+ ConnEnd(ShapeRef *shapeRef, const double x_pos, const double y_pos,
+ const double insideOffset = 0.0,
+ const ConnDirFlags visDirs = ConnDirNone);
+
+ //! @brief Returns the position of this connector endpoint
+ //!
+ //! @return The position of this connector endpoint.
+ const Point point(void) const;
+
+ ConnDirFlags directions(void) const;
+ private:
+ Point _point;
+ ConnDirFlags _directions;
+
+ // For referencing ConnEnds
+ ShapeRef *_shapeRef;
+ double _xPosition;
+ double _yPosition;
+ double _insideOffset;
+};
+
+
+//! @brief The ConnRef class represents a connector object.
+//!
+//! Connectors are a (possible multi-segment) line between two points.
+//! They are routed intelligently so as not to overlap any of the shape
+//! objects in the Router scene.
+//!
+//! Routing penalties can be applied, resulting in more aesthetically pleasing
+//! connector paths with fewer segments or less severe bend-points.
+//!
+//! You can set a function to be called when the connector has been rerouted
+//! and needs to be redrawn. Alternatively, you can query the connector's
+//! needsRepaint() function to determine this manually.
+//!
+//! Usually, it is expected that you would create a ConnRef for each connector
+//! in your diagram and keep that reference in your own connector class.
+//!
class ConnRef
{
public:
- ConnRef(const unsigned int id);
- ConnRef(const unsigned int id, const Point& src, const Point& dst);
+ //! @brief Constructs a connector with no endpoints specified.
+ //!
+ //! @param[in] router The router scene to place the connector into.
+ //! @param[in] id A unique positive integer ID for the connector.
+ //!
+ //! If an ID is not specified, then one will be assigned to the shape.
+ //! If assigning an ID yourself, note that it should be a unique
+ //! positive integer. Also, IDs are given to all objects in a scene,
+ //! so the same ID cannot be given to a shape and a connector for
+ //! example.
+ //!
+ ConnRef(Router *router, const unsigned int id = 0);
+ //! @brief Constructs a connector with endpoints specified.
+ //!
+ //! @param[in] router The router scene to place the connector into.
+ //! @param[in] id A unique positive integer ID for the connector.
+ //! @param[in] src The source endpoint of the connector.
+ //! @param[in] dst The destination endpoint of the connector.
+ //!
+ //! If an ID is not specified, then one will be assigned to the shape.
+ //! If assigning an ID yourself, note that it should be a unique
+ //! positive integer. Also, IDs are given to all objects in a scene,
+ //! so the same ID cannot be given to a shape and a connector for
+ //! example.
+ //!
+ ConnRef(Router *router, const ConnEnd& src, const ConnEnd& dst,
+ const unsigned int id = 0);
+ //! @brief Destuctor.
~ConnRef();
- PolyLine& route(void);
- bool needsReroute(void);
- void moveRoute(const int& diff_x, const int& diff_y);
- void freeRoute(void);
+ //! @brief Sets both new source and destination endpoints for this
+ //! connector.
+ //!
+ //! @param[in] srcPoint New source endpoint for the connector.
+ //! @param[in] dstPoint New destination endpoint for the connector.
+ void setEndpoints(const ConnEnd& srcPoint, const ConnEnd& dstPoint);
+ //! @brief Sets just a new source endpoint for this connector.
+ //!
+ //! @param[in] srcPoint New source endpoint for the connector.
+ void setSourceEndpoint(const ConnEnd& srcPoint);
+ //! @brief Sets just a new destination endpoint for this connector.
+ //!
+ //! @param[in] dstPoint New destination endpoint for the connector.
+ void setDestEndpoint(const ConnEnd& dstPoint);
+ //! @brief Returns the ID of this connector.
+ //! @returns The ID of the connector.
+ unsigned int id(void) const;
+ //! @brief Returns a pointer to the router scene this connector is in.
+ //! @returns A pointer to the router scene for this connector.
+ Router *router(void) const;
+
+ //! @brief Returns an indication of whether this connector has a
+ //! new route and thus needs to be repainted.
+ //!
+ //! If the connector has been rerouted and need repainting, the
+ //! route() method can be called to get a reference to the new route.
+ //!
+ //! @returns Returns true if the connector requires repainting, or
+ //! false if it does not.
+ bool needsRepaint(void) const;
+
+ //! @brief Returns a reference to the current route for the connector.
+ //!
+ //! This is a "raw" version of the route, where each line segment in
+ //! the route may be made up of multiple collinear line segments. It
+ //! will also not have post-processing (like curved corners) applied
+ //! to it. The simplified route for display can be obtained by calling
+ //! displayRoute().
+ //!
+ //! @returns The PolyLine route for the connector.
+ //! @note You can obtain a modified version of this poly-line
+ //! route with curved corners added by calling
+ //! PolyLine::curvedPolyline().
+ const PolyLine& route(void) const;
+
+ //! @brief Returns a reference to the current display version of the
+ //! route for the connector.
+ //!
+ //! The display version of a route has been simplified to collapse all
+ //! collinear line segments into single segments. It may also have
+ //! post-processing applied to the route, such as curved corners or
+ //! nudging.
+ //!
+ //! @returns The PolyLine display route for the connector.
+ PolyLine& displayRoute(void);
+
+ //! @brief Sets a callback function that will called to indicate that
+ //! the connector needs rerouting.
+ //!
+ //! The cb function will be called when shapes are added to, removed
+ //! from or moved about on the page. The pointer ptr will be passed
+ //! as an argument to the callback function.
+ //!
+ //! @param[in] cb A pointer to the callback function.
+ //! @param[in] ptr A generic pointer that will be passed to the
+ //! callback function.
+ void setCallback(void (*cb)(void *), void *ptr);
+ //! @brief Returns the type of routing performed for this connector.
+ //! @return The type of routing performed.
+ //!
+ ConnType routingType(void) const;
+ //! @brief Sets the type of routing to be performed for this
+ //! connector.
+ //!
+ //! If a call to this method changes the current type of routing
+ //! being used for the connector, then it will get rerouted during
+ //! the next processTransaction() call, or immediately if
+ //! transactions are not being used.
+ //!
+ //! @param type The type of routing to be performed.
+ //!
+ void setRoutingType(ConnType type);
+
+
+
+ // @brief Returns the source endpoint vertex in the visibility graph.
+ // @returns The source endpoint vertex.
+ VertInf *src(void);
+ // @brief Returns the destination endpoint vertex in the
+ // visibility graph.
+ // @returns The destination endpoint vertex.
+ VertInf *dst(void);
+
+
+ void set_route(const PolyLine& route);
void calcRouteDist(void);
- void updateEndPoint(const unsigned int type, const Point& point);
void setEndPointId(const unsigned int type, const unsigned int id);
+ unsigned int getSrcShapeId(void);
+ unsigned int getDstShapeId(void);
void makeActive(void);
void makeInactive(void);
- void lateSetup(const Point& src, const Point& dst);
- VertInf *src(void);
- VertInf *dst(void);
+ VertInf *start(void);
void removeFromGraph(void);
bool isInitialised(void);
- void unInitialise(void);
- void setCallback(void (*cb)(void *), void *ptr);
- void handleInvalid(void);
- int generatePath(Point p0, Point p1);
void makePathInvalid(void);
-
- friend void markConnectors(ShapeRef *shape);
- friend void attachedToShape(IntList &conns,
- const unsigned int shapeId, const unsigned int type);
-
- static const unsigned int runningTo;
- static const unsigned int runningFrom;
- static const unsigned int runningToAndFrom;
-
+ void setHateCrossings(bool value);
+ bool doesHateCrossings(void);
+ void setEndpoint(const unsigned int type, const ConnEnd& connEnd);
+ bool setEndpoint(const unsigned int type, const VertID& pointID,
+ Point *pointSuggestion = NULL);
+
private:
+ friend class Router;
+
+ PolyLine& routeRef(void);
+ void freeRoutes(void);
+ void performCallback(void);
+ bool generatePath(void);
+ bool generatePath(Point p0, Point p1);
+ void unInitialise(void);
+ void updateEndPoint(const unsigned int type, const ConnEnd& connEnd);
+ void common_updateEndPoint(const unsigned int type, const ConnEnd& connEnd);
+ Router *_router;
unsigned int _id;
+ ConnType _type;
unsigned int _srcId, _dstId;
+ bool _orthogonal;
bool _needs_reroute_flag;
bool _false_path;
+ bool _needs_repaint;
bool _active;
PolyLine _route;
+ Polygon _display_route;
double _route_dist;
ConnRefList::iterator _pos;
VertInf *_srcVert;
VertInf *_dstVert;
+ VertInf *_startVert;
bool _initialised;
void (*_callback)(void *);
void *_connector;
+ bool _hateCrossings;
+};
+
+
+class PointRep;
+typedef std::set<PointRep *> PointRepSet;
+typedef std::list<PointRep *> PointRepList;
+
+class PointRep
+{
+ public:
+ PointRep(Point *p, const ConnRef *c)
+ : point(p),
+ conn(c)
+
+ {
+ }
+ bool follow_inner(PointRep *target);
+
+ Point *point;
+ const ConnRef *conn;
+ // inner_set: Set of pointers to the PointReps 'inner' of
+ // this one, at this corner.
+ PointRepSet inner_set;
+};
+
+
+typedef std::pair<Point *, ConnRef *> PtConnPtrPair;
+
+class PtOrder
+{
+ public:
+ PtOrder()
+ {
+ }
+ ~PtOrder();
+ bool addPoints(const int dim, PtConnPtrPair innerArg,
+ PtConnPtrPair outerArg, bool swapped);
+ void sort(const int dim);
+ int positionFor(const ConnRef *conn, const size_t dim) const;
+
+ // One for each dimension.
+ PointRepList connList[2];
};
+typedef std::map<Avoid::Point,PtOrder> PtOrderMap;
+typedef std::set<Avoid::Point> PointSet;
+
+
+const unsigned int CROSSING_NONE = 0;
+const unsigned int CROSSING_TOUCHES = 1;
+const unsigned int CROSSING_SHARES_PATH = 2;
+const unsigned int CROSSING_SHARES_PATH_AT_END = 4;
+const unsigned int CROSSING_SHARES_FIXED_SEGMENT = 8;
+
-extern ConnRefList connRefs;
+typedef std::pair<int, unsigned int> CrossingsInfoPair;
-extern void callbackAllInvalidConnectors(void);
-extern void attachedToShape(IntList &conns, const unsigned int shapeId,
- const unsigned int type);
+extern CrossingsInfoPair countRealCrossings( Avoid::Polygon& poly,
+ bool polyIsConn, Avoid::Polygon& conn, size_t cIndex,
+ bool checkForBranchingSegments, const bool finalSegment = false,
+ PointSet *crossingPoints = NULL, PtOrderMap *pointOrders = NULL,
+ ConnRef *polyConnRef = NULL, ConnRef *connConnRef = NULL);
+extern void splitBranchingSegments(Avoid::Polygon& poly, bool polyIsConn,
+ Avoid::Polygon& conn, const double tolerance = 0);
+extern bool validateBendPoint(VertInf *aInf, VertInf *bInf, VertInf *cInf);
}