From d6978fcea4a2ccd2d9cccefabc6558a74f332a6d Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sat, 2 Apr 2011 00:59:01 +0200 Subject: add curve before LPE to SPShape. this is useful for helperpath display. It was inspired from fixing bug 407008 Fixed bugs: - https://launchpad.net/bugs/407008 (bzr r10142) --- src/sp-ellipse.cpp | 4 ++- src/sp-line.cpp | 3 +++ src/sp-offset.cpp | 2 ++ src/sp-path.cpp | 1 + src/sp-rect.cpp | 5 ++++ src/sp-shape.cpp | 36 ++++++++++++++++++++++++++ src/sp-shape.h | 5 ++++ src/sp-spiral.cpp | 2 ++ src/sp-star.cpp | 2 ++ src/splivarot.cpp | 75 +++++++++++++++++++++++++++++++++++++++--------------- src/splivarot.h | 2 ++ 11 files changed, 115 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 4ebbe6287..cb8c1699b 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -256,9 +256,11 @@ static void sp_genericellipse_set_shape(SPShape *shape) Geom::Affine aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed); curve->transform(aff); - /* Reset the shape'scurve to the "original_curve" + /* Reset the shape's 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)*/ shape->setCurveInsync( curve, TRUE); + shape->setCurveBeforeLPE(curve); + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = curve->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); diff --git a/src/sp-line.cpp b/src/sp-line.cpp index 100eefe87..72fe2cfa2 100644 --- a/src/sp-line.cpp +++ b/src/sp-line.cpp @@ -221,6 +221,9 @@ void SPLine::setShape(SPShape *shape) c->lineto(line->x2.computed, line->y2.computed); shape->setCurveInsync(c, TRUE); // *_insync does not call update, avoiding infinite recursion when set_shape is called by update + shape->setCurveBeforeLPE(c); + + // LPE's cannot be applied to lines. (the result can (generally) not be represented as SPLine) c->unref(); } diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 57c04f31f..3fb9441a3 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -463,6 +463,7 @@ sp_offset_set_shape(SPShape *shape) SPCurve *c = new SPCurve(pv); g_assert(c != NULL); ((SPShape *) offset)->setCurveInsync (c, TRUE); + ((SPShape *) offset)->setCurveBeforeLPE(c); c->unref(); } return; @@ -712,6 +713,7 @@ sp_offset_set_shape(SPShape *shape) SPCurve *c = new SPCurve(pv); g_assert(c != NULL); ((SPShape *) offset)->setCurveInsync (c, TRUE); + ((SPShape *) offset)->setCurveBeforeLPE(c); c->unref(); free (res_d); diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 16e2fcc1b..9a27af2f0 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -425,6 +425,7 @@ g_message("sp_path_update_patheffect"); /* 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)*/ shape->setCurveInsync(curve, TRUE); + shape->setCurveBeforeLPE(path->original_curve); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); if (success && write) { diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index fd44f64df..e8f79e6ed 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -232,6 +232,7 @@ sp_rect_set_shape(SPShape *shape) if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) { SP_SHAPE(rect)->setCurveInsync( NULL, TRUE); + SP_SHAPE(rect)->setCurveBeforeLPE( NULL ); return; } @@ -282,6 +283,10 @@ sp_rect_set_shape(SPShape *shape) c->closepath(); SP_SHAPE(rect)->setCurveInsync( c, TRUE); + SP_SHAPE(rect)->setCurveBeforeLPE( c ); + + // LPE is not applied because result can generally not be represented as SPRect + c->unref(); } diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index e9b0909ed..72559c63f 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -126,6 +126,7 @@ void SPShape::sp_shape_init(SPShape *shape) shape->marker[i] = NULL; } shape->curve = NULL; + shape->curve_before_lpe = NULL; } void SPShape::sp_shape_finalize(GObject *object) @@ -195,6 +196,9 @@ void SPShape::sp_shape_release(SPObject *object) if (shape->curve) { shape->curve = shape->curve->unref(); } + if (shape->curve_before_lpe) { + shape->curve_before_lpe = shape->curve_before_lpe->unref(); + } if (((SPObjectClass *) SPShapeClass::parent_class)->release) { ((SPObjectClass *) SPShapeClass::parent_class)->release (object); @@ -1114,6 +1118,20 @@ void SPShape::setCurve(SPCurve *curve, unsigned int owner) this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } +/** + * Sets curve_before_lpe to refer to the curve. + */ +void +SPShape::setCurveBeforeLPE (SPCurve *curve) +{ + if (this->curve_before_lpe) { + this->curve_before_lpe = this->curve_before_lpe->unref(); + } + if (curve) { + this->curve_before_lpe = curve->ref(); + } +} + /** * Return duplicate of curve (if any exists) or NULL if there is no curve */ @@ -1125,6 +1143,24 @@ SPCurve * SPShape::getCurve() return NULL; } +/** + * Return duplicate of curve *before* LPE (if any exists) or NULL if there is no curve + */ +SPCurve * +SPShape::getCurveBeforeLPE() +{ + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(this))) { + if (this->curve_before_lpe) { + return this->curve_before_lpe->copy(); + } + } else { + if (this->curve) { + return this->curve->copy(); + } + } + return NULL; +} + /** * Same as sp_shape_set_curve but without updating the display */ diff --git a/src/sp-shape.h b/src/sp-shape.h index b29b0c50b..b91850d1f 100644 --- a/src/sp-shape.h +++ b/src/sp-shape.h @@ -44,11 +44,16 @@ public: static GType getType (void); void setShape (); SPCurve * getCurve (); + SPCurve * getCurveBeforeLPE (); void setCurve (SPCurve *curve, unsigned int owner); void setCurveInsync (SPCurve *curve, unsigned int owner); + void setCurveBeforeLPE (SPCurve *curve); int hasMarkers () const; int numberOfMarkers (int type); +protected: + SPCurve *curve_before_lpe; + private: static void sp_shape_init (SPShape *shape); static void sp_shape_finalize (GObject *object); diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index e4bd0fa21..05c6bc9cd 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -427,6 +427,7 @@ sp_spiral_set_shape (SPShape *shape) Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); shape->setCurveInsync( cold, TRUE); + shape->setCurveBeforeLPE( cold ); cold->unref(); } return; @@ -470,6 +471,7 @@ sp_spiral_set_shape (SPShape *shape) /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( c, TRUE); + shape->setCurveBeforeLPE( c ); if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = c->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 200217ba2..92d8cd7a5 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -439,6 +439,7 @@ sp_star_set_shape (SPShape *shape) Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); shape->setCurveInsync( cold, TRUE); + shape->setCurveBeforeLPE(cold); cold->unref(); } return; @@ -509,6 +510,7 @@ sp_star_set_shape (SPShape *shape) /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( c, TRUE); + shape->setCurveBeforeLPE( c ); if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = c->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 9c2fc8ff9..0e27ce26d 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -1804,19 +1804,10 @@ sp_selected_path_simplify_item(SPDesktop *desktop, false); } - - SPCurve *curve = NULL; - - if (SP_IS_SHAPE(item)) { - curve = SP_SHAPE(item)->getCurve(); - if (!curve) - return false; - } - - if (SP_IS_TEXT(item)) { - curve = SP_TEXT(item)->getNormalizedBpath(); - if (!curve) - return false; + // get path to simplify (note that the path *before* LPE calculation is needed) + Path *orig = Path_for_item_before_LPE(item, false); + if (orig == NULL) { + return false; } // correct virtual size by full transform (bug #166937) @@ -1836,14 +1827,6 @@ sp_selected_path_simplify_item(SPDesktop *desktop, gchar *mask = g_strdup(item->getRepr()->attribute("mask")); gchar *clip_path = g_strdup(item->getRepr()->attribute("clip-path")); - Path *orig = Path_for_item(item, false); - if (orig == NULL) { - g_free(style); - curve->unref(); - return false; - } - - curve->unref(); // remember the position of the item gint pos = item->getRepr()->position(); // remember parent @@ -2106,6 +2089,27 @@ Path_for_item(SPItem *item, bool doTransformation, bool transformFull) return dest; } +/** + * Obtains an item's Path before the LPE stack has been applied. + */ +Path * +Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull) +{ + SPCurve *curve = curve_for_item_before_LPE(item); + + if (curve == NULL) + return NULL; + + Geom::PathVector *pathv = pathvector_for_curve(item, curve, doTransformation, transformFull, Geom::identity(), Geom::identity()); + curve->unref(); + + Path *dest = new Path; + dest->LoadPathVector(*pathv); + delete pathv; + + return dest; +} + /* * NOTE: Returns empty pathvector if curve == NULL * TODO: see if calling this method can be optimized. All the pathvector copying might be slow. @@ -2132,6 +2136,10 @@ pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool t return dest; } +/** + * Obtains an item's curve. For SPPath, it is the path *before* LPE. For SPShapes other than path, it is the path *after* LPE. + * So the result is somewhat ill-defined, and probably this method should not be used... See curve_for_item_before_LPE. + */ SPCurve* curve_for_item(SPItem *item) { if (!item) @@ -2157,6 +2165,31 @@ SPCurve* curve_for_item(SPItem *item) return curve; // do not forget to unref the curve at some point! } +/** + * Obtains an item's curve *before* LPE. + * The returned SPCurve should be unreffed by the caller. + */ +SPCurve* curve_for_item_before_LPE(SPItem *item) +{ + if (!item) + return NULL; + + SPCurve *curve = NULL; + if (SP_IS_SHAPE(item)) { + curve = SP_SHAPE(item)->getCurveBeforeLPE(); + } + else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) + { + curve = te_get_layout(item)->convertToCurves(); + } + else if (SP_IS_IMAGE(item)) + { + curve = sp_image_get_curve(SP_IMAGE(item)); + } + + return curve; // do not forget to unref the curve at some point! +} + boost::optional get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg) { //get nearest position on path diff --git a/src/splivarot.h b/src/splivarot.h index ea8183b67..40089ad71 100644 --- a/src/splivarot.h +++ b/src/splivarot.h @@ -49,8 +49,10 @@ Geom::PathVector* item_outline(SPItem const *item); void sp_selected_path_simplify (SPDesktop *desktop); Path *Path_for_item(SPItem *item, bool doTransformation, bool transformFull = true); +Path *Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull = true); Geom::PathVector* pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Affine extraPreAffine, Geom::Affine extraPostAffine); SPCurve *curve_for_item(SPItem *item); +SPCurve *curve_for_item_before_LPE(SPItem *item); boost::optional get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg = 0); Geom::Point get_point_on_Path(Path *path, int piece, double t); -- cgit v1.2.3