/** @file * @brief Path handler in node edit mode */ /* Authors: * Lauris Kaplinski * * This code is in public domain */ #ifndef SEEN_SP_NODEPATH_H #define SEEN_SP_NODEPATH_H #include "libnr/nr-path-code.h" #include #include #include #include <2geom/point.h> #include <2geom/matrix.h> #include struct SPCanvasItem; class SPCurve; struct SPItem; class SPObject; class SPDesktop; class SPPath; class SPKnot; class LivePathEffectObject; namespace Inkscape { namespace XML { class Node; } namespace LivePathEffect { class Effect; } } typedef std::map > HelperPathList; /** * Radial objects are represented by an angle and a distance from * 0,0. 0,0 is represented by a == big_num. */ class Radial{ public: /** Radius */ double r; /** Amplitude */ double a; Radial() {} // Radial(Geom::Point const &p); // Convert a point to radial coordinates Radial(Radial &p) : r(p.r),a(p.a) {} // operator Geom::Point() const; /** * Construct Radial from Geom::Point. */ Radial(Geom::Point const &p) { r = Geom::L2(p); if (r > 0) { a = Geom::atan2 (p); } else { a = HUGE_VAL; //undefined } } /** * Cast Radial to cartesian Geom::Point. */ operator Geom::Point() const { if (a == HUGE_VAL) { return Geom::Point(0,0); } else { return r*Geom::Point(cos(a), sin(a)); } } }; class ShapeEditor; namespace Inkscape { namespace NodePath { /** * The entire nodepath, containing multiple subpaths */ class Path; /** * A subpath is a continuous chain of linked nodes */ class SubPath; /** * One side of a node, i.e. prev or next */ class NodeSide; /** * A node on a subpath */ class Node; /** * This is the lowest list item, a simple list of nodes. */ class SubPath { public: /** The parent of this subpath */ Path * nodepath; /** Is this path closed (no endpoints) or not?*/ gboolean closed; /** The nodes in this subpath. */ GList * nodes; /** The first node of the subpath (does not imply open/closed)*/ Node * first; /** The last node of the subpath */ Node * last; }; /** * What kind of node is this? This is the value for the node->type * field. NodeType indicates the degree of continuity required for * the node. I think that the corresponding integer indicates which * derivate is connected. (Thus 2 means that the node is continuous * to the second derivative, i.e. has matching endpoints and tangents) */ typedef enum { /** A normal node */ NODE_NONE, /** This node non-continuously joins two segments.*/ NODE_CUSP, /** This node continuously joins two segments. */ NODE_SMOOTH, /** This node has automatic handles. */ NODE_AUTO, /** This node is symmetric. */ NODE_SYMM } NodeType; /** * A NodeSide is a datarecord which may be on either side (n or p) of a node, * which describes the segment going to the next node. */ class NodeSide{ public: /** Pointer to the next node, */ Node * other; /** Position */ Geom::Point pos; /** Origin (while dragging) in radial notation */ Radial origin_radial; /** Origin (while dragging) in x/y notation */ Geom::Point origin; /** Knots are Inkscape's way of providing draggable points. This * Knot is the point on the curve representing the control point in a * bezier curve.*/ SPKnot * knot; /** What kind of rendering? */ SPCanvasItem * line; }; /** * A node along a NodePath */ class Node { public: /** The parent subpath of this node */ SubPath * subpath; /** Type is selected from NodeType.*/ guint type : 4; /** Code refers to which ArtCode is used to represent the segment * (which segment?).*/ guint code : 4; /** Boolean. Am I currently selected or not? */ guint selected : 1; /** */ Geom::Point pos; /** */ Geom::Point origin; /** Knots are Inkscape's way of providing draggable points. This * Knot is the point on the curve representing the endpoint.*/ SPKnot * knot; /** The NodeSide in the 'next' direction */ NodeSide n; /** The NodeSide in the 'previous' direction */ NodeSide p; /** The pointer to the nodeside which we are dragging out with Shift */ NodeSide *dragging_out; /** Boolean. Am I being dragged? */ guint is_dragging : 1; }; /** * This is a collection of subpaths which contain nodes * * In the following data model. Nodepaths are made up of subpaths which * are comprised of nodes. * * Nodes are linked thus: * \verbatim n other node -----> nodeside ------> node \endverbatim */ class Path { public: /** Constructor should private, people should create new nodepaths using sp_nodepath_new * But for some reason I cannot make sp_nodepath_new a friend :-( */ Path() {}; /** Destructor */ ~Path(); /** Pointer to the current desktop, for reporting purposes */ SPDesktop * desktop; /** The parent path of this nodepath */ SPObject * object; /** The parent livepatheffect of this nodepath, if applicable */ SPItem * item; /** The context which created this nodepath. Important if this nodepath is deleted */ ShapeEditor *shape_editor; /** The subpaths which comprise this NodePath */ GList * subpaths; /** A list of nodes which are currently selected */ GList * selected; /** Transforms (userspace <---> virtual space? someone please describe ) njh: I'd be guessing that these are item <-> desktop transforms.*/ Geom::Matrix i2d, d2i; /** The DOM node which describes this NodePath */ Inkscape::XML::Node *repr; gchar *repr_key; gchar *repr_nodetypes_key; //STL compliant method to get the selected nodes void selection(std::list &l); guint numSelected() {return (selected? g_list_length(selected) : 0);} Geom::Point& singleSelectedCoords() {return (((Node *) selected->data)->pos);} /// draw a "sketch" of the path by using these variables SPCanvasItem *helper_path; SPCurve *curve; bool show_helperpath; guint32 helperpath_rgba; gdouble helperpath_width; // the helperpaths provided by all LPEs (and their paramaters) of the current item HelperPathList helper_path_vec; /// true if we changed repr, to tell this change from an external one such as from undo, simplify, or another desktop unsigned int local_change; /// true if we're showing selected nodes' handles bool show_handles; /// true if the path cannot contain curves, just straight lines bool straight_path; /// active_node points to the node that is currently mouseovered (= NULL if /// there isn't any); we also consider the node mouseovered if it is covered /// by one of its handles and the latter is mouseovered static Node *active_node; /// Location of mouse pointer when we started dragging, needed for snapping Geom::Point drag_origin_mouse; }; } // namespace NodePath } // namespace Inkscape enum { SCULPT_PROFILE_LINEAR, SCULPT_PROFILE_BELL, SCULPT_PROFILE_ELLIPTIC }; // Do function documentation in nodepath.cpp Inkscape::NodePath::Path * sp_nodepath_new (SPDesktop * desktop, SPObject *object, bool show_handles, const char * repr_key = NULL, SPItem *item = NULL); void sp_nodepath_deselect (Inkscape::NodePath::Path *nodepath); void sp_nodepath_select_all (Inkscape::NodePath::Path *nodepath, bool invert); void sp_nodepath_select_all_from_subpath(Inkscape::NodePath::Path *nodepath, bool invert); void sp_nodepath_select_next (Inkscape::NodePath::Path *nodepath); void sp_nodepath_select_prev (Inkscape::NodePath::Path *nodepath); void sp_nodepath_select_rect (Inkscape::NodePath::Path * nodepath, Geom::Rect const &b, gboolean incremental); GList *save_nodepath_selection (Inkscape::NodePath::Path *nodepath); void restore_nodepath_selection (Inkscape::NodePath::Path *nodepath, GList *r); gboolean nodepath_repr_d_changed (Inkscape::NodePath::Path * np, const char *newd); gboolean nodepath_repr_typestr_changed (Inkscape::NodePath::Path * np, const char *newtypestr); gboolean node_key (GdkEvent * event); void sp_nodepath_update_repr(Inkscape::NodePath::Path *np, const gchar *annotation); void sp_nodepath_update_statusbar (Inkscape::NodePath::Path *nodepath); void sp_nodepath_selected_align(Inkscape::NodePath::Path *nodepath, Geom::Dim2 axis); void sp_nodepath_selected_distribute(Inkscape::NodePath::Path *nodepath, Geom::Dim2 axis); void sp_nodepath_select_segment_near_point(Inkscape::NodePath::Path *nodepath, Geom::Point p, bool toggle); void sp_nodepath_add_node_near_point(Inkscape::NodePath::Path *nodepath, Geom::Point p); void sp_nodepath_curve_drag(Inkscape::NodePath::Path *nodepath, int node, double t, Geom::Point delta); Inkscape::NodePath::Node * sp_nodepath_get_node_by_index(Inkscape::NodePath::Path *np, int index); bool sp_node_side_is_line (Inkscape::NodePath::Node *node, Inkscape::NodePath::NodeSide *side); /* possibly private functions */ void sp_node_selected_add_node (Inkscape::NodePath::Path *nodepath); void sp_node_selected_break (Inkscape::NodePath::Path *nodepath); void sp_node_selected_duplicate (Inkscape::NodePath::Path *nodepath); void sp_node_selected_join (Inkscape::NodePath::Path *nodepath); void sp_node_selected_join_segment (Inkscape::NodePath::Path *nodepath); void sp_node_delete_preserve (GList *nodes_to_delete); void sp_node_selected_delete (Inkscape::NodePath::Path *nodepath); void sp_node_selected_delete_segment (Inkscape::NodePath::Path *nodepath); void sp_node_selected_set_type (Inkscape::NodePath::Path *nodepath, Inkscape::NodePath::NodeType type); void sp_node_selected_set_line_type (Inkscape::NodePath::Path *nodepath, NRPathcode code); void sp_node_selected_move (Inkscape::NodePath::Path *nodepath, gdouble dx, gdouble dy); void sp_node_selected_move_screen (SPDesktop *desktop, Inkscape::NodePath::Path *nodepath, gdouble dx, gdouble dy); void sp_node_selected_move_absolute (Inkscape::NodePath::Path *nodepath, Geom::Coord val, Geom::Dim2 axis); Geom::Rect sp_node_selected_bbox (Inkscape::NodePath::Path *nodepath); boost::optional sp_node_selected_common_coord (Inkscape::NodePath::Path *nodepath, Geom::Dim2 axis); void sp_nodepath_show_handles(Inkscape::NodePath::Path *nodepath, bool show); SPCanvasItem *sp_nodepath_generate_helperpath(SPDesktop *desktop, SPCurve *curve, const Geom::Matrix & i2d, guint32 color); SPCanvasItem *sp_nodepath_generate_helperpath(SPDesktop *desktop, SPItem *item); void sp_nodepath_show_helperpath(Inkscape::NodePath::Path *nodepath, bool show); void sp_nodepath_update_helperpaths(Inkscape::NodePath::Path *np); void sp_nodepath_make_straight_path(Inkscape::NodePath::Path *np); void sp_nodepath_selected_nodes_rotate (Inkscape::NodePath::Path * nodepath, gdouble angle, int which, bool screen); void sp_nodepath_selected_nodes_scale (Inkscape::NodePath::Path * nodepath, gdouble grow, int which); void sp_nodepath_selected_nodes_scale_screen (Inkscape::NodePath::Path * nodepath, gdouble grow, int which); void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, Geom::Dim2 axis, boost::optional center); #endif