X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-path.cpp;h=16e3bec400b4442bc9a61e28253ba54dbeae1b2b;hb=90a3966dd44e306d23febc15ebd65cde07d7a4dd;hp=14f04218f5e1476183e1c41dd9bd3485f1780c8e;hpb=e5183c603c61d36c2c145e99693cbc62463122f3;p=inkscape.git diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 14f04218f..16e3bec40 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -21,9 +21,11 @@ #include #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" @@ -53,8 +55,8 @@ 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); @@ -122,14 +124,9 @@ 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 * @@ -150,30 +147,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 const *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_guide_pt_pairs_to_guides(inkscape_active_desktop(), pts); } /** @@ -252,8 +244,8 @@ 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 = SPCurve::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); curve->unref(); @@ -266,8 +258,8 @@ sp_path_set(SPObject *object, unsigned int key, gchar const *value) case SP_ATTR_D: if (!sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(path))) { if (value) { - NArtBpath *bpath = sp_svg_read_path(value); - SPCurve *curve = SPCurve::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); curve->unref(); @@ -303,38 +295,27 @@ 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"); } if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); - 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 = path->original_curve->first_bpath(); - if (abp) { - gchar *str = sp_svg_write_path(abp); - repr->setAttribute("inkscape:original-d", str); - g_free(str); - } else { - repr->setAttribute("inkscape:original-d", ""); - } + 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", NULL); } @@ -342,7 +323,7 @@ sp_path_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) 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; @@ -367,32 +348,25 @@ 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(); } // Transform the original-d path or the (ordinary) path - bool original_path = (bool)path->original_curve; - SPCurve *srccurve = original_path ? path->original_curve : shape->curve; - SPCurve *dstcurve = srccurve->copy(); - if (dstcurve) { - dstcurve->transform(xform); - if (original_path) { - sp_path_set_original_curve(path, dstcurve, TRUE, true); - } else { - sp_shape_set_curve(shape, dstcurve, TRUE); - } - dstcurve->unref(); + if (path->original_curve) { + 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); @@ -406,39 +380,37 @@ 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(SPLPEItem *lpeitem, bool write) { - SPShape *shape = (SPShape *) lpeitem; - SPPath *path = (SPPath *) lpeitem; - if (path->original_curve) { - SPCurve *curve = path->original_curve->copy(); - sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); - sp_shape_set_curve(shape, curve, TRUE); - curve->unref(); - - if (write) { - // could also do SP_OBJECT(shape)->updateRepr(); but only the d attribute needs updating. - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); - if ( shape->curve != NULL ) { - NArtBpath *abp = shape->curve->first_bpath(); - if (abp) { - gchar *str = sp_svg_write_path(abp); + SPShape * const shape = (SPShape *) lpeitem; + SPPath * const path = (SPPath *) lpeitem; + + if (sp_lpe_item_has_path_effect(lpeitem) && sp_lpe_item_path_effects_enabled(lpeitem)) { + if (path->original_curve) { + SPCurve *curve = path->original_curve->copy(); + sp_shape_set_curve_insync(shape, curve, TRUE); + sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); + SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + curve->unref(); + + if (write) { + // could also do SP_OBJECT(shape)->updateRepr(); but only the d attribute needs updating. + Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); + if ( shape->curve != NULL ) { + gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); repr->setAttribute("d", str); g_free(str); } else { - repr->setAttribute("d", ""); + repr->setAttribute("d", NULL); } - } else { - repr->setAttribute("d", NULL); } } - } else { - } + // else: do nothing. } @@ -446,9 +418,9 @@ sp_path_update_patheffect(SPLPEItem *lpeitem, 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) @@ -463,7 +435,7 @@ sp_path_set_original_curve (SPPath *path, SPCurve *curve, unsigned int owner, bo 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); } @@ -507,66 +479,6 @@ sp_path_get_curve_reference (SPPath *path) } } -/* Create a single dot represented by a circle */ -void freehand_create_single_dot(SPEventContext *ec, NR::Point const &pt, char const *tool, guint event_state) { - g_return_if_fail(!strcmp(tool, "tools.freehand.pen") || !strcmp(tool, "tools.freehand.pencil")); - - SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(ec); - Inkscape::XML::Document *xml_doc = sp_document_repr_doc(desktop->doc()); - Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); - repr->setAttribute("sodipodi:type", "arc"); - SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); - Inkscape::GC::release(repr); - - /* apply the tool's current style */ - sp_desktop_apply_style_tool(desktop, repr, tool, false); - - /* find out stroke width (TODO: is there an easier way??) */ - double stroke_width = 3.0; - gchar const *style_str = NULL; - style_str = repr->attribute("style"); - if (style_str) { - SPStyle *style = sp_style_new(SP_ACTIVE_DOCUMENT); - sp_style_merge_from_style_string(style, style_str); - stroke_width = style->stroke_width.computed; - style->stroke_width.computed = 0; - sp_style_unref(style); - } - /* unset stroke and set fill color to former stroke color */ - gchar * str; - str = g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8); - repr->setAttribute("style", str); - g_free(str); - - /* put the circle where the mouse click occurred and set the diameter to the - current stroke width, multiplied by the amount specified in the preferences */ - NR::Matrix const i2d (sp_item_i2d_affine (item)); - NR::Point pp = pt * i2d; - double rad = 0.5 * prefs_get_double_attribute(tool, "dot-size", 3.0); - if (event_state & GDK_MOD1_MASK) { - /* TODO: We vary the dot size between 0.5*rad and 1.5*rad, where rad is the dot size - as specified in prefs. Very simple, but it might be sufficient in practice. If not, - we need to devise something more sophisticated. */ - double s = g_random_double_range(-0.5, 0.5); - rad *= (1 + s); - } - if (event_state & GDK_SHIFT_MASK) { - // double the point size - rad *= 2; - } - - sp_repr_set_svg_double (repr, "sodipodi:cx", pp[NR::X]); - sp_repr_set_svg_double (repr, "sodipodi:cy", pp[NR::Y]); - sp_repr_set_svg_double (repr, "sodipodi:rx", rad * stroke_width); - sp_repr_set_svg_double (repr, "sodipodi:ry", rad * stroke_width); - item->updateRepr(); - - sp_desktop_selection(desktop)->set(item); - - desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Creating single dot")); - sp_document_done(sp_desktop_document(desktop), SP_VERB_NONE, _("Create single dot")); -} - /* Local Variables: mode:c++