nodepath.h revision 86b3a7fc48d3fa59eb2e3289e0b8b2b56c7ed270
0N/A#ifndef __SP_NODEPATH_H__
0N/A#define __SP_NODEPATH_H__
0N/A
0N/A/** \file
0N/A * Path handler in node edit mode
0N/A */
0N/A
0N/A/*
0N/A * Authors:
0N/A * Lauris Kaplinski <lauris@kaplinski.com>
0N/A *
0N/A * This code is in public domain
0N/A */
0N/A
0N/A//#include "knot.h"
0N/A//#include "sp-path.h"
0N/A//#include "desktop-handles.h"
0N/A#include "libnr/nr-path-code.h"
0N/A#include <glibmm/ustring.h>
#include <gdk/gdkevents.h>
#include <list>
#include <2geom/forward.h>
#include <boost/optional.hpp>
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<Inkscape::LivePathEffect::Effect *, std::vector<SPCanvasItem *> > 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 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:
/** 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<Node *> &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;
};
} // 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_destroy (Inkscape::NodePath::Path * nodepath);
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<Geom::Coord> 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 SPItem *item, guint32 color);
//SPCanvasItem *sp_nodepath_generate_helperpath(SPDesktop *desktop, SPPath *path);
SPCanvasItem *sp_nodepath_helperpath_from_path(SPDesktop *desktop, SPPath *path);
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<Geom::Point> center);
#endif