Code

add SPCurve::get_segment_count
[inkscape.git] / src / nodepath.cpp
index ffbec8a8b945bb4baabeaa0f95653bc30c3cc1d0..b712539ab767f78f872a3fb550c54095ae7f1f9f 100644 (file)
@@ -51,6 +51,7 @@
 #include <cstring>
 #include <string>
 #include "live_effects/lpeobject.h"
+#include "live_effects/effect.h"
 #include "live_effects/parameter/parameter.h"
 #include "util/mathfns.h"
 #include "display/snap-indicator.h"
@@ -94,7 +95,7 @@ static GMemChunk *nodechunk = NULL;
 
 /* Creation from object */
 
-static NArtBpath *subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath *b, gchar const *t);
+static NArtBpath const * subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath const *b, gchar const *t);
 static gchar *parse_nodetypes(gchar const *types, gint length);
 
 /* Object updating */
@@ -151,6 +152,20 @@ static void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve)
 // active_node indicates mouseover node
 Inkscape::NodePath::Node * Inkscape::NodePath::Path::active_node = NULL;
 
+static void sp_nodepath_draw_helper_curve(Inkscape::NodePath::Path *np, SPDesktop *desktop) {
+    // Draw helper curve
+    if (np->show_helperpath) {
+        SPCurve *helper_curve = np->curve->copy();
+        helper_curve->transform(np->i2d );
+        np->helper_path = sp_canvas_bpath_new(sp_desktop_controls(desktop), helper_curve);
+        sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(np->helper_path), np->helperpath_rgba, np->helperpath_width, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+        sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(np->helper_path), 0, SP_WIND_RULE_NONZERO);
+        sp_canvas_item_move_to_z(np->helper_path, 0);
+        sp_canvas_item_show(np->helper_path);
+        helper_curve->unref();
+    }
+}
+
 /**
  * \brief Creates new nodepath from item
  */
@@ -180,8 +195,8 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     if (curve == NULL)
         return NULL;
 
-    NArtBpath *bpath = curve->first_bpath();
-    gint length = curve->_end;
+    NArtBpath const *bpath = curve->get_bpath();
+    gint length = curve->get_length();
     if (length == 0) {
         curve->unref();
         return NULL; // prevent crash for one-node paths
@@ -207,7 +222,13 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     np->helperpath_rgba = prefs_get_int_attribute("tools.nodes", "highlight_color", 0xff0000ff);
     np->helperpath_width = 1.0;
     np->curve = curve->copy();
-    np->show_helperpath = prefs_get_int_attribute ("tools.nodes", "show_helperpath",  0) == 1;
+    np->show_helperpath = (prefs_get_int_attribute ("tools.nodes", "show_helperpath",  0) == 1);
+    if (SP_IS_LPE_ITEM(object)) {
+        Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(object));
+        if (lpe && lpe->isVisible() && lpe->showOrigPath()) {
+            np->show_helperpath = true;
+        }            
+    }
     np->straight_path = false;
     if (IS_LIVEPATHEFFECT(object) && item) {
         np->item = item;
@@ -220,7 +241,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     // to a change in repr by regenerating nodepath     --bb
     sp_object_read_attr(SP_OBJECT(np->item), "transform");
 
-    np->i2d  = sp_item_i2d_affine(np->item);
+    np->i2d  = from_2geom(sp_item_i2d_affine(np->item));
     np->d2i  = np->i2d.inverse();
 
     np->repr = repr;
@@ -236,9 +257,9 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
         if ( sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(np->object)) ) {
             np->repr_key = g_strdup("inkscape:original-d");
 
-            LivePathEffectObject *lpeobj = sp_lpe_item_get_livepatheffectobject(SP_LPE_ITEM(np->object));
-            if (lpeobj && lpeobj->lpe) {
-                lpeobj->lpe->setup_nodepath(np);
+            Inkscape::LivePathEffect::Effect* lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(np->object));
+            if (lpe) {
+                lpe->setup_nodepath(np);
             }
         } else {
             np->repr_key = g_strdup("d");
@@ -249,7 +270,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     gchar *typestr = parse_nodetypes(nodetypes, length);
 
     // create the subpath(s) from the bpath
-    NArtBpath *b = bpath;
+    NArtBpath const *b = bpath;
     while (b->code != NR_END) {
         b = subpath_from_bpath(np, b, typestr + (b - bpath));
     }
@@ -263,17 +284,7 @@ Inkscape::NodePath::Path *sp_nodepath_new(SPDesktop *desktop, SPObject *object,
     // create the livarot representation from the same item
     sp_nodepath_ensure_livarot_path(np);
 
-    // Draw helper curve
-    if (np->show_helperpath) {
-        SPCurve *helper_curve = np->curve->copy();
-        helper_curve->transform(np->i2d );
-        np->helper_path = sp_canvas_bpath_new(sp_desktop_controls(desktop), helper_curve);
-        sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(np->helper_path), np->helperpath_rgba, np->helperpath_width, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
-        sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(np->helper_path), 0, SP_WIND_RULE_NONZERO);
-        sp_canvas_item_move_to_z(np->helper_path, 0);
-        sp_canvas_item_show(np->helper_path);
-        helper_curve->unref();
-    }
+    sp_nodepath_draw_helper_curve(np, desktop);
 
     return np;
 }
@@ -330,8 +341,8 @@ void sp_nodepath_ensure_livarot_path(Inkscape::NodePath::Path *np)
 {
     if (np && np->livarot_path == NULL) {
         SPCurve *curve = create_curve(np);
-        NArtBpath const *bpath = SP_CURVE_BPATH(curve);
-        np->livarot_path = bpath_to_Path(bpath);
+        np->livarot_path = new Path;
+        np->livarot_path->LoadPathVector(curve->get_pathvector());
 
         if (np->livarot_path)
             np->livarot_path->ConvertWithBackData(0.01);
@@ -443,7 +454,7 @@ static void sp_nodepath_cleanup(Inkscape::NodePath::Path *nodepath)
  * \param t The node type.
  * \todo Fixme: t should be a proper type, rather than gchar
  */
-static NArtBpath *subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath *b, gchar const *t)
+static NArtBpath const * subpath_from_bpath(Inkscape::NodePath::Path *np, NArtBpath const *b, gchar const *t)
 {
     NR::Point ppos, pos, npos;
 
@@ -559,7 +570,7 @@ static void update_repr_internal(Inkscape::NodePath::Path *np)
     np->curve = create_curve(np);
 
     gchar *typestr = create_typestr(np);
-    gchar *svgpath = sp_svg_write_path(SP_CURVE_BPATH(np->curve));
+    gchar *svgpath = sp_svg_write_path(np->curve->get_pathvector());
 
     // determine if path has an effect applied and write to correct "d" attribute.
     if (repr->attribute(np->repr_key) == NULL || strcmp(svgpath, repr->attribute(np->repr_key))) { // d changed
@@ -636,7 +647,7 @@ static void stamp_repr(Inkscape::NodePath::Path *np)
     SPCurve *curve = create_curve(np);
     gchar *typestr = create_typestr(np);
 
-    gchar *svgpath = sp_svg_write_path(SP_CURVE_BPATH(curve));
+    gchar *svgpath = sp_svg_write_path(curve->get_pathvector());
 
     new_repr->setAttribute(np->repr_key, svgpath);
     new_repr->setAttribute(np->repr_nodetypes_key, typestr);
@@ -1202,13 +1213,13 @@ void sp_node_moveto(Inkscape::NodePath::Node *node, NR::Point p)
  * Call sp_node_moveto() for node selection and handle possible snapping.
  */
 static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath, NR::Coord dx, NR::Coord dy,
-                                            bool const snap = true)
+                                            bool const snap, bool constrained = false, 
+                                            Inkscape::Snapper::ConstraintLine const &constraint = NR::Point())
 {
     NR::Coord best = NR_HUGE;
     NR::Point delta(dx, dy);
     NR::Point best_pt = delta;
     Inkscape::SnappedPoint best_abs;
-
     
     if (snap) {    
         /* When dragging a (selected) node, it should only snap to other nodes (i.e. unselected nodes), and
@@ -1231,8 +1242,15 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
         
         for (GList *l = nodepath->selected; l != NULL; l = l->next) {
             Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data;
-            m.setup(nodepath->desktop, SP_PATH(n->subpath->nodepath->item), &unselected_nodes);
-            Inkscape::SnappedPoint s = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, n->pos + delta);            
+            m.setup(NULL, SP_PATH(n->subpath->nodepath->item), &unselected_nodes);
+            Inkscape::SnappedPoint s;
+            if (constrained) {
+                Inkscape::Snapper::ConstraintLine dedicated_constraint = constraint;
+                dedicated_constraint.setPoint(n->pos);
+                s = m.constrainedSnap(Inkscape::Snapper::SNAPPOINT_NODE, n->pos + delta, dedicated_constraint);
+            } else {
+                s = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, n->pos + delta);
+            }            
             if (s.getSnapped() && (s.getDistance() < best)) {
                 best = s.getDistance();
                 best_abs = s;
@@ -1242,6 +1260,8 @@ static void sp_nodepath_selected_nodes_move(Inkscape::NodePath::Path *nodepath,
                         
         if (best_abs.getSnapped()) {
             nodepath->desktop->snapindicator->set_new_snappoint(best_abs);
+        } else {
+            nodepath->desktop->snapindicator->remove_snappoint();    
         }
     }
 
@@ -3392,11 +3412,11 @@ node_request(SPKnot */*knot*/, NR::Point *p, guint state, gpointer data)
     NR::Point c;
     NR::Point pr;
 
-   Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) data;
+    Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) data;
 
     n->subpath->nodepath->desktop->snapindicator->remove_snappoint();
 
-   // If either (Shift and some handle retracted), or (we're already dragging out a handle)
+    // If either (Shift and some handle retracted), or (we're already dragging out a handle)
     if ( (!n->subpath->nodepath->straight_path) &&
          ( ((state & GDK_SHIFT_MASK) && ((n->n.other && n->n.pos == n->pos) || (n->p.other && n->p.pos == n->pos)))
            || n->dragging_out ) )
@@ -3540,14 +3560,23 @@ node_request(SPKnot */*knot*/, NR::Point *p, guint state, gpointer data)
             // move the node to the closest point
             sp_nodepath_selected_nodes_move(n->subpath->nodepath,
                                             n->origin[NR::X] + c[NR::X] - n->pos[NR::X],
-                                            n->origin[NR::Y] + c[NR::Y] - n->pos[NR::Y]);
+                                            n->origin[NR::Y] + c[NR::Y] - n->pos[NR::Y], 
+                                            true);
 
         } else {  // constraining to hor/vert
 
             if (fabs((*p)[NR::X] - n->origin[NR::X]) > fabs((*p)[NR::Y] - n->origin[NR::Y])) { // snap to hor
-                sp_nodepath_selected_nodes_move(n->subpath->nodepath, (*p)[NR::X] - n->pos[NR::X], n->origin[NR::Y] - n->pos[NR::Y]);
+                sp_nodepath_selected_nodes_move(n->subpath->nodepath,
+                                                (*p)[NR::X] - n->pos[NR::X], 
+                                                n->origin[NR::Y] - n->pos[NR::Y],
+                                                true, 
+                                                true, Inkscape::Snapper::ConstraintLine(component_vectors[NR::X]));
             } else { // snap to vert
-                sp_nodepath_selected_nodes_move(n->subpath->nodepath, n->origin[NR::X] - n->pos[NR::X], (*p)[NR::Y] - n->pos[NR::Y]);
+                sp_nodepath_selected_nodes_move(n->subpath->nodepath,
+                                                n->origin[NR::X] - n->pos[NR::X],
+                                                (*p)[NR::Y] - n->pos[NR::Y],
+                                                true,
+                                                true, Inkscape::Snapper::ConstraintLine(component_vectors[NR::Y]));
             }
         }
     } else { // move freely
@@ -4677,12 +4706,10 @@ SPCurve* sp_nodepath_object_get_curve(SPObject *object, const gchar *key) {
     } else if ( IS_LIVEPATHEFFECT(object) && key) {
         const gchar *svgd = object->repr->attribute(key);
         if (svgd) {
-            NArtBpath *bpath = sp_svg_read_path(svgd);
-            SPCurve *curve_new = SPCurve::new_from_bpath(bpath);
+            Geom::PathVector pv = sp_svg_read_pathv(svgd);
+            SPCurve *curve_new = new SPCurve(pv);
             if (curve_new) {
                 curve = curve_new; // don't do curve_copy because curve_new is already only created for us!
-            } else {
-                g_free(bpath);
             }
         }
     }
@@ -4703,7 +4730,7 @@ void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve) {
     } else if ( IS_LIVEPATHEFFECT(np->object) ) {
         // FIXME: this writing to string and then reading from string is bound to be slow.
         // create a method to convert from curve directly to 2geom...
-        gchar *svgpath = sp_svg_write_path(SP_CURVE_BPATH(np->curve));
+        gchar *svgpath = sp_svg_write_path( np->curve->get_pathvector() );
         LIVEPATHEFFECT(np->object)->lpe->setParameter(np->repr_key, svgpath);
         g_free(svgpath);
 
@@ -4711,6 +4738,27 @@ void sp_nodepath_set_curve (Inkscape::NodePath::Path *np, SPCurve *curve) {
     }
 }
 
+SPCanvasItem *
+sp_nodepath_generate_helperpath(SPDesktop *desktop, SPCurve *curve, const SPItem *item, guint32 color = 0xff0000ff) {
+    SPCurve *flash_curve = curve->copy();
+    Geom::Matrix i2d = item ? sp_item_i2d_affine(item) : Geom::identity();
+    flash_curve->transform(i2d);
+    SPCanvasItem * canvasitem = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), flash_curve);
+    // would be nice if its color could be XORed or something, now it is invisible for red stroked objects...
+    // unless we also flash the nodes...
+    sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvasitem), color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
+    sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvasitem), 0, SP_WIND_RULE_NONZERO);
+    sp_canvas_item_show(canvasitem);
+    flash_curve->unref();
+    return canvasitem;
+}
+
+SPCanvasItem *
+sp_nodepath_generate_helperpath(SPDesktop *desktop, SPPath *path) {
+    return sp_nodepath_generate_helperpath(desktop, sp_path_get_curve_for_edit(path), SP_ITEM(path),
+                                           prefs_get_int_attribute("tools.nodes", "highlight_color", 0xff0000ff));
+}
+
 void sp_nodepath_show_helperpath(Inkscape::NodePath::Path *np, bool show) {
     np->show_helperpath = show;