Code

Merge GSoC2009 Connectors into trunk
[inkscape.git] / src / libavoid / connector.h
index 64afb4dda7f9abe698031613d687ac7522f692d7..8f7499a2934838709479ec325a87d5a18713761c 100644 (file)
  * vim: ts=4 sw=4 et tw=0 wm=0
  *
  * libavoid - Fast, Incremental, Object-avoiding Line Router
- * Copyright (C) 2004-2006  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 "libavoid/router.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;
+
+
+//! @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);
 
-static const int ConnType_PolyLine   = 1;
-static const int ConnType_Orthogonal = 2;
+        //! @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(Router *router, const unsigned int id);
-        ConnRef(Router *router, const unsigned int id,
-                const Point& src, const Point& dst);
-        virtual ~ConnRef();
+        //! @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();
         
-        void setType(unsigned int type);
-        PolyLine& route(void);
-        bool needsReroute(void);
-        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);
-        unsigned int id(void);
-        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);
-        Router *router(void);
         void setHateCrossings(bool value);
         bool doesHateCrossings(void);
-        
-        friend void Router::attachedShapes(IntList &shapes,
-                const unsigned int shapeId, const unsigned int type);
-        friend void Router::attachedConns(IntList &conns,
-                const unsigned int shapeId, const unsigned int type);
-        friend void Router::markConnectors(ShapeRef *shape);
-        
+        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;
-        unsigned int _type;
+        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;
@@ -96,6 +339,69 @@ class ConnRef
 };
 
 
+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;
+
+
+typedef std::pair<int, unsigned int> CrossingsInfoPair;
+
+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);
+
 }