X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-path.cpp;h=54d2a201a1480225c438fb778d5ca44d71baa7a1;hb=a401603e1e2635fadeec3b7a3a48de442da93472;hp=a8e3ad6eebf74db53a4a0aacee145a22c2e186d0;hpb=7a8af702272bac1fbba95077d0ddbebfa54f01ca;p=inkscape.git diff --git a/src/sp-path.cpp b/src/sp-path.cpp index a8e3ad6ee..54d2a201a 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -20,10 +20,17 @@ #include +#include "live_effects/effect.h" +#include "live_effects/lpeobject.h" +#include "live_effects/lpeobject-reference.h" +#include "sp-lpe-item.h" + #include -#include -#include #include +#include <2geom/pathvector.h> +#include <2geom/bezier-curve.h> +#include <2geom/hvlinesegment.h> +#include "helper/geom-curves.h" #include "svg/svg.h" #include "xml/repr.h" @@ -33,6 +40,14 @@ #include "sp-guide.h" #include "document.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "desktop-style.h" +#include "event-context.h" +#include "inkscape.h" +#include "style.h" +#include "message-stack.h" +#include "selection.h" #define noPATH_VERBOSE @@ -44,13 +59,13 @@ static void sp_path_release(SPObject *object); static void sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_path_set(SPObject *object, unsigned key, gchar const *value); -static Inkscape::XML::Node *sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); -static NR::Matrix sp_path_set_transform(SPItem *item, NR::Matrix const &xform); +static Inkscape::XML::Node *sp_path_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); +static Geom::Matrix sp_path_set_transform(SPItem *item, Geom::Matrix const &xform); static gchar * sp_path_description(SPItem *item); static void sp_path_convert_to_guides(SPItem *item); static void sp_path_update(SPObject *object, SPCtx *ctx, guint flags); -static void sp_path_update_patheffect(SPShape *shape, bool write); +static void sp_path_update_patheffect(SPLPEItem *lpeitem, bool write); static SPShapeClass *parent_class; @@ -89,7 +104,7 @@ sp_path_class_init(SPPathClass * klass) GObjectClass *gobject_class = (GObjectClass *) klass; SPObjectClass *sp_object_class = (SPObjectClass *) klass; SPItemClass *item_class = (SPItemClass *) klass; - SPShapeClass *shape_class = (SPShapeClass *) klass; + SPLPEItemClass *lpe_item_class = (SPLPEItemClass *) klass; parent_class = (SPShapeClass *)g_type_class_peek_parent(klass); @@ -105,7 +120,7 @@ sp_path_class_init(SPPathClass * klass) item_class->set_transform = sp_path_set_transform; item_class->convert_to_guides = sp_path_convert_to_guides; - shape_class->update_patheffect = sp_path_update_patheffect; + lpe_item_class->update_patheffect = sp_path_update_patheffect; } @@ -113,23 +128,33 @@ gint sp_nodes_in_path(SPPath *path) { SPCurve *curve = SP_SHAPE(path)->curve; - if (!curve) return 0; - gint r = curve->end; - gint i = curve->length - 1; - if (i > r) i = r; // sometimes after switching from node editor length is wrong, e.g. f6 - draw - f2 - tab - f1, this fixes it - for (; i >= 0; i --) - if (SP_CURVE_BPATH(curve)[i].code == NR_MOVETO) - r --; - return r; + if (!curve) + return 0; + return curve->nodes_in_path(); } static gchar * sp_path_description(SPItem * item) { int count = sp_nodes_in_path(SP_PATH(item)); - if (SP_SHAPE(item)->path_effect_href) { - return g_strdup_printf(ngettext("Path (%i node, path effect)", - "Path (%i nodes, path effect)",count), count); + if (SP_IS_LPE_ITEM(item) && sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) { + + Glib::ustring s; + + PathEffectList effect_list = sp_lpe_item_get_effect_list(SP_LPE_ITEM(item)); + for (PathEffectList::iterator it = effect_list.begin(); it != effect_list.end(); it++) + { + LivePathEffectObject *lpeobj = (*it)->lpeobject; + if (!lpeobj || !lpeobj->get_lpe()) + break; + if (s.empty()) + s = lpeobj->get_lpe()->getName(); + else + s = s + ", " + lpeobj->get_lpe()->getName(); + } + + return g_strdup_printf(ngettext("Path (%i node, path effect: %s)", + "Path (%i nodes, path effect: %s)",count), count, s.c_str()); } else { return g_strdup_printf(ngettext("Path (%i node)", "Path (%i nodes)",count), count); @@ -141,32 +166,25 @@ sp_path_convert_to_guides(SPItem *item) { SPPath *path = SP_PATH(item); - SPDocument *doc = SP_OBJECT_DOCUMENT(path); + SPCurve *curve = SP_SHAPE(path)->curve; + if (!curve) return; + std::list > pts; - NR::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(path))); + Geom::Matrix const i2d (sp_item_i2d_affine(SP_ITEM(path))); - SPCurve *curve = SP_SHAPE(path)->curve; - if (!curve) return; - NArtBpath *bpath = SP_CURVE_BPATH(curve); - - NR::Point last_pt; - NR::Point pt; - for (int i = 0; bpath[i].code != NR_END; i++){ - if (bpath[i].code == NR_LINETO) { - /* we only convert straight line segments (converting curve segments would be unintuitive) */ - pt = bpath[i].c(3) * i2d; - pts.push_back(std::make_pair(last_pt.to_2geom(), pt.to_2geom())); + Geom::PathVector const & pv = curve->get_pathvector(); + for(Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { + for(Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_default(); ++cit) { + // only add curves for straight line segments + if( is_straight_curve(*cit) ) + { + pts.push_back(std::make_pair(cit->initialPoint() * i2d, cit->finalPoint() * i2d)); + } } - - /* remember current point for potential reuse in the next step - (e.g., in case this was an NR_MOVETO or NR_MOVETO_OPEN) */ - last_pt = bpath[i].c(3) * i2d; } - sp_guide_pt_pairs_to_guides(doc, pts); - - SP_OBJECT(path)->deleteObject(true); + sp_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts); } /** @@ -225,7 +243,7 @@ sp_path_release(SPObject *object) path->connEndPair.release(); if (path->original_curve) { - path->original_curve = sp_curve_unref (path->original_curve); + path->original_curve = path->original_curve->unref(); } if (((SPObjectClass *) parent_class)->release) { @@ -245,11 +263,11 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value) switch (key) { case SP_ATTR_INKSCAPE_ORIGINAL_D: if (value) { - NArtBpath *bpath = sp_svg_read_path(value); - SPCurve *curve = sp_curve_new_from_bpath(bpath); + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *curve = new SPCurve(pv); if (curve) { sp_path_set_original_curve(path, curve, TRUE, true); - sp_curve_unref(curve); + curve->unref(); } } else { sp_path_set_original_curve(path, NULL, TRUE, true); @@ -257,19 +275,17 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_D: - if (!((SPShape *) path)->path_effect_href) { if (value) { - NArtBpath *bpath = sp_svg_read_path(value); - SPCurve *curve = sp_curve_new_from_bpath(bpath); + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *curve = new SPCurve(pv); if (curve) { sp_shape_set_curve((SPShape *) path, curve, TRUE); - sp_curve_unref(curve); + curve->unref(); } } else { sp_shape_set_curve((SPShape *) path, NULL, TRUE); } object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - } break; case SP_PROP_MARKER: case SP_PROP_MARKER_START: @@ -279,8 +295,11 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_CONNECTOR_TYPE: + case SP_ATTR_CONNECTOR_CURVATURE: case SP_ATTR_CONNECTION_START: case SP_ATTR_CONNECTION_END: + case SP_ATTR_CONNECTION_START_POINT: + case SP_ATTR_CONNECTION_END_POINT: path->connEndPair.setAttr(key, value); break; default: @@ -296,46 +315,40 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value) * Writes the path object into a Inkscape::XML::Node */ static Inkscape::XML::Node * -sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) +sp_path_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { SPShape *shape = (SPShape *) object; if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { - Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object)); repr = xml_doc->createElement("svg:path"); } +#ifdef PATH_VERBOSE +g_message("sp_path_write writes 'd' attribute"); +#endif if ( shape->curve != NULL ) { - NArtBpath *abp = sp_curve_first_bpath(shape->curve); - if (abp) { - gchar *str = sp_svg_write_path(abp); - repr->setAttribute("d", str); - g_free(str); - } else { - repr->setAttribute("d", ""); - } + gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); + repr->setAttribute("d", str); + g_free(str); } else { repr->setAttribute("d", NULL); } - SPPath *path = (SPPath *) object; - if ( path->original_curve != NULL ) { - NArtBpath *abp = sp_curve_first_bpath(path->original_curve); - if (abp) { - gchar *str = sp_svg_write_path(abp); + if (flags & SP_OBJECT_WRITE_EXT) { + SPPath *path = (SPPath *) object; + if ( path->original_curve != NULL ) { + gchar *str = sp_svg_write_path(path->original_curve->get_pathvector()); repr->setAttribute("inkscape:original-d", str); g_free(str); } else { - repr->setAttribute("inkscape:original-d", ""); + repr->setAttribute("inkscape:original-d", NULL); } - } else { - repr->setAttribute("inkscape:original-d", NULL); } SP_PATH(shape)->connEndPair.writeRepr(repr); if (((SPObjectClass *)(parent_class))->write) { - ((SPObjectClass *)(parent_class))->write(object, repr, flags); + ((SPObjectClass *)(parent_class))->write(object, xml_doc, repr, flags); } return repr; @@ -360,38 +373,26 @@ sp_path_update(SPObject *object, SPCtx *ctx, guint flags) /** * Writes the given transform into the repr for the given item. */ -static NR::Matrix -sp_path_set_transform(SPItem *item, NR::Matrix const &xform) +static Geom::Matrix +sp_path_set_transform(SPItem *item, Geom::Matrix const &xform) { SPShape *shape = (SPShape *) item; SPPath *path = (SPPath *) item; if (!shape->curve) { // 0 nodes, nothing to transform - return NR::identity(); + return Geom::identity(); } - if (path->original_curve) { /* Transform the original-d path */ - NRBPath dorigpath, sorigpath; - sorigpath.path = SP_CURVE_BPATH(path->original_curve); - nr_path_duplicate_transform(&dorigpath, &sorigpath, xform); - SPCurve *origcurve = sp_curve_new_from_bpath(dorigpath.path); - if (origcurve) { - sp_path_set_original_curve(path, origcurve, TRUE, true); - sp_curve_unref(origcurve); - } - } else { /* Transform the path */ - NRBPath dpath, spath; - spath.path = SP_CURVE_BPATH(shape->curve); - nr_path_duplicate_transform(&dpath, &spath, xform); - SPCurve *curve = sp_curve_new_from_bpath(dpath.path); - if (curve) { - sp_shape_set_curve(shape, curve, TRUE); - sp_curve_unref(curve); - } + // Transform the original-d path if this is a valid LPE item, other else the (ordinary) path + if (path->original_curve && SP_IS_LPE_ITEM(item) && + sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(item))) { + path->original_curve->transform(xform); + } else { + shape->curve->transform(xform); } // Adjust stroke - sp_item_adjust_stroke(item, NR::expansion(xform)); + sp_item_adjust_stroke(item, xform.descrim()); // Adjust pattern fill sp_item_adjust_pattern(item, xform); @@ -405,37 +406,53 @@ sp_path_set_transform(SPItem *item, NR::Matrix const &xform) item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); // nothing remains - we've written all of the transform, so return identity - return NR::identity(); + return Geom::identity(); } + static void -sp_path_update_patheffect(SPShape *shape, bool write) +sp_path_update_patheffect(SPLPEItem *lpeitem, bool write) { - SPPath *path = (SPPath *) shape; - if (path->original_curve) { - SPCurve *curve = sp_curve_copy (path->original_curve); - sp_shape_perform_path_effect(curve, shape); - sp_shape_set_curve(shape, curve, TRUE); - sp_curve_unref(curve); + SPShape * const shape = (SPShape *) lpeitem; + SPPath * const path = (SPPath *) lpeitem; + Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); - if (write) { +#ifdef PATH_VERBOSE +g_message("sp_path_update_patheffect"); +#endif + + if (path->original_curve && sp_lpe_item_has_path_effect_recursive(lpeitem)) { + SPCurve *curve = path->original_curve->copy(); + /* if a path does not have an lpeitem applied, then reset the curve to the original_curve. + * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ + sp_shape_set_curve_insync(shape, curve, TRUE); + + bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); + if (success && write) { // could also do SP_OBJECT(shape)->updateRepr(); but only the d attribute needs updating. - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); +#ifdef PATH_VERBOSE +g_message("sp_path_update_patheffect writes 'd' attribute"); +#endif if ( shape->curve != NULL ) { - NArtBpath *abp = sp_curve_first_bpath(shape->curve); - if (abp) { - gchar *str = sp_svg_write_path(abp); - repr->setAttribute("d", str); - g_free(str); - } else { - repr->setAttribute("d", ""); - } + gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); + repr->setAttribute("d", str); + g_free(str); } else { repr->setAttribute("d", NULL); } + } else if (!success) { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = repr->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + sp_shape_set_curve(shape, oldcurve, TRUE); + oldcurve->unref(); + } + } } - } else { - + SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + curve->unref(); } } @@ -444,24 +461,24 @@ sp_path_update_patheffect(SPShape *shape, bool write) * Adds a original_curve to the path. If owner is specified, a reference * will be made, otherwise the curve will be copied into the path. * Any existing curve in the path will be unreferenced first. - * This routine triggers reapplication of the an effect is present - * an also triggers a request to update the display. Does not write -* result to XML when write=false. + * This routine triggers reapplication of an effect if present + * and also triggers a request to update the display. Does not write + * result to XML when write=false. */ void sp_path_set_original_curve (SPPath *path, SPCurve *curve, unsigned int owner, bool write) { if (path->original_curve) { - path->original_curve = sp_curve_unref (path->original_curve); + path->original_curve = path->original_curve->unref(); } if (curve) { if (owner) { - path->original_curve = sp_curve_ref (curve); + path->original_curve = curve->ref(); } else { - path->original_curve = sp_curve_copy (curve); + path->original_curve = curve->copy(); } } - sp_path_update_patheffect(path, write); + sp_lpe_item_update_patheffect(path, true, write); SP_OBJECT(path)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } @@ -472,7 +489,7 @@ SPCurve * sp_path_get_original_curve (SPPath *path) { if (path->original_curve) { - return sp_curve_copy (path->original_curve); + return path->original_curve->copy(); } return NULL; } @@ -484,7 +501,8 @@ sp_path_get_original_curve (SPPath *path) SPCurve* sp_path_get_curve_for_edit (SPPath *path) { - if (path->original_curve) { + if (path->original_curve && SP_IS_LPE_ITEM(path) && + sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(path))) { return sp_path_get_original_curve(path); } else { return sp_shape_get_curve( (SPShape *) path ); @@ -498,7 +516,8 @@ sp_path_get_curve_for_edit (SPPath *path) const SPCurve* sp_path_get_curve_reference (SPPath *path) { - if (path->original_curve) { + if (path->original_curve && SP_IS_LPE_ITEM(path) && + sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(path))) { return path->original_curve; } else { return path->curve;