/* * vim: ts=4 sw=4 et tw=0 wm=0 * * libavoid - Fast, Incremental, Object-avoiding Line Router * * 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. * * Author(s): Michael Wybrow */ //! @file shape.h //! @brief Contains the interface for the ConnRef class. #ifndef AVOID_CONNECTOR_H #define AVOID_CONNECTOR_H #include #include #include "libavoid/vertices.h" #include "libavoid/geometry.h" #include "libavoid/shape.h" namespace Avoid { class Router; class ConnRef; typedef std::list 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); //! @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: //! @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(); //! @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 setEndPointId(const unsigned int type, const unsigned int id); unsigned int getSrcShapeId(void); unsigned int getDstShapeId(void); void makeActive(void); void makeInactive(void); VertInf *start(void); void removeFromGraph(void); bool isInitialised(void); void makePathInvalid(void); 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 PointRepSet; typedef std::list 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 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 PtOrderMap; typedef std::set 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 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); } #endif