diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2016-06-16 20:29:40 +0000 |
|---|---|---|
| committer | jabiertxof <info@marker.es> | 2016-06-16 20:29:40 +0000 |
| commit | 5d388f13644b59e355e0980c74695247b2191562 (patch) | |
| tree | a1c3b13bb56679d508bfd5f65087591e435ff0bb /src | |
| parent | fix a bat file (diff) | |
| download | inkscape-5d388f13644b59e355e0980c74695247b2191562.tar.gz inkscape-5d388f13644b59e355e0980c74695247b2191562.zip | |
Fixes some bugs related to powerstroke 'Powerstroke infinite loop'
Fixed bugs:
- https://launchpad.net/bugs/1535444
- https://launchpad.net/bugs/1236320
- https://launchpad.net/bugs/1586973
(bzr r14991)
Diffstat (limited to 'src')
| -rw-r--r-- | src/2geom/sbasis-geometric.cpp | 9 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 25 | ||||
| -rw-r--r-- | src/ui/tools/freehand-base.cpp | 40 |
3 files changed, 23 insertions, 51 deletions
diff --git a/src/2geom/sbasis-geometric.cpp b/src/2geom/sbasis-geometric.cpp index 8aaa15144..19eccc451 100644 --- a/src/2geom/sbasis-geometric.cpp +++ b/src/2geom/sbasis-geometric.cpp @@ -101,7 +101,7 @@ static SBasis divide_by_t1k(SBasis const &a, int k) { static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1.e-4){ D2<SBasis> M = MM; //TODO: divide by all the s at once!!! - while ((M[0].size()>0||M[1].size()>0) && + while ((M[0].size()>1||M[1].size()>1) && fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO && fabs(M[0].at1())<ZERO && @@ -109,12 +109,12 @@ static D2<SBasis> RescaleForNonVanishingEnds(D2<SBasis> const &MM, double ZERO=1 M[0] = divide_by_sk(M[0],1); M[1] = divide_by_sk(M[1],1); } - while ((M[0].size()>0||M[1].size()>0) && + while ((M[0].size()>1||M[1].size()>1) && fabs(M[0].at0())<ZERO && fabs(M[1].at0())<ZERO){ M[0] = divide_by_t0k(M[0],1); M[1] = divide_by_t0k(M[1],1); } - while ((M[0].size()>0||M[1].size()>0) && + while ((M[0].size()>1||M[1].size()>1) && fabs(M[0].at1())<ZERO && fabs(M[1].at1())<ZERO){ M[0] = divide_by_t1k(M[0],1); M[1] = divide_by_t1k(M[1],1); @@ -227,9 +227,9 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ // -This approach is numerically bad. Find a stable way to rescale V_in to have non vanishing ends. // -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles. D2<SBasis> V = RescaleForNonVanishingEnds(V_in); - if (V[0].isZero(0) && V[1].isZero(0)) return Piecewise<D2<SBasis> >(D2<SBasis>(Linear(1),SBasis())); + SBasis x = V[0], y = V[1]; SBasis r_eqn1, r_eqn2; @@ -242,7 +242,6 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ r_eqn1 = -(a*x+b*y); r_eqn2 = Linear(1.)-(a*a+b*b); - for (unsigned k=1; k<=order; k++){ double r0 = (k<r_eqn1.size())? r_eqn1.at(k).at0() : 0; double r1 = (k<r_eqn1.size())? r_eqn1.at(k).at1() : 0; diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 03102a84a..66c8776b5 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -35,6 +35,7 @@ #include <2geom/ellipse.h> #include <2geom/circle.h> #include <2geom/math-utils.h> +#include "helper/geom.h" #include <math.h> #include "spiro.h" @@ -205,14 +206,13 @@ LPEPowerStroke::~LPEPowerStroke() } - void LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) { - if (SP_IS_SHAPE(lpeitem)) { + if (SP_IS_SHAPE(lpeitem) && offset_points.data().empty()) { SPLPEItem* item = const_cast<SPLPEItem*>(lpeitem); std::vector<Geom::Point> points; - Geom::PathVector const &pathv = SP_SHAPE(lpeitem)->_curve->get_pathvector(); + Geom::PathVector const &pathv = pathv_to_linear_and_cubic_beziers(SP_SHAPE(lpeitem)->_curve->get_pathvector()); double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.; SPCSSAttr *css = sp_repr_css_attr_new (); @@ -565,12 +565,11 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (path_in.empty()) { return path_out; } - - // for now, only regard first subpath and ignore the rest - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[0].toPwSb(); - + Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(path_in); + Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = pathv[0].toPwSb(); Piecewise<D2<SBasis> > der = derivative(pwd2_in); - Piecewise<D2<SBasis> > n = rot90(unitVector(der)); + Piecewise<D2<SBasis> > n = unitVector(der,0.0001); + n = rot90(n); offset_points.set_pwd2(pwd2_in, n); LineCapType end_linecap = static_cast<LineCapType>(end_linecap_type.get_value()); @@ -583,7 +582,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (sort_points) { sort(ts.begin(), ts.end(), compare_offsets); } - if (path_in[0].closed()) { + if (pathv[0].closed()) { // add extra points for interpolation between first and last point Point first_point = ts.front(); Point last_point = ts.back(); @@ -605,7 +604,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) for (std::size_t i = 0, e = ts.size(); i < e; ++i) { ts[i][Geom::X] *= xcoord_scaling; } - // create stroke path where points (x,y) := (t, offset) Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())); if (Geom::Interpolate::CubicBezierJohan *johan = dynamic_cast<Geom::Interpolate::CubicBezierJohan*>(interpolator)) { @@ -631,7 +629,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) x = portion(x, rtsmin.at(0), rtsmax.at(0)); y = portion(y, rtsmin.at(0), rtsmax.at(0)); } - LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x); @@ -639,8 +636,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); - - if (path_in[0].closed()) { + if (pathv[0].closed()) { fixed_path.close(true); path_out.push_back(fixed_path); fixed_mirrorpath.close(true); @@ -684,7 +680,6 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) } fixed_path.append(fixed_mirrorpath); - switch (start_linecap) { case LINECAP_ZERO_WIDTH: // do nothing @@ -720,11 +715,9 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) break; } } - fixed_path.close(true); path_out.push_back(fixed_path); } - return path_out; } diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index c98ecb686..7697cd59c 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -236,38 +236,14 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE(); static_cast<LPEPowerStroke*>(lpe)->offset_points.param_set_and_write_new_value(points); - // find out stroke width (TODO: is there an easier way??) - SPDesktop *desktop = dc->desktop; - Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); - Inkscape::GC::release(repr); - - char const* tool = SP_IS_PEN_CONTEXT(dc) ? "/tools/freehand/pen" : "/tools/freehand/pencil"; - - // apply the tool's current style - sp_desktop_apply_style_tool(desktop, repr, tool, false); - - double stroke_width = 1.0; - char const *style_str = NULL; - style_str = repr->attribute("style"); - if (style_str) { - SPStyle style(SP_ACTIVE_DOCUMENT); - style.mergeString(style_str); - stroke_width = style.stroke_width.computed; - } - - std::ostringstream s; - s.imbue(std::locale::classic()); - s << points[0][Geom::X] << "," << stroke_width / 2.; - // write powerstroke parameters: lpe->getRepr()->setAttribute("start_linecap_type", "zerowidth"); lpe->getRepr()->setAttribute("end_linecap_type", "zerowidth"); - lpe->getRepr()->setAttribute("cusp_linecap_type", "round"); lpe->getRepr()->setAttribute("sort_points", "true"); lpe->getRepr()->setAttribute("interpolator_type", "CubicBezierJohan"); lpe->getRepr()->setAttribute("interpolator_beta", "0.2"); - lpe->getRepr()->setAttribute("offset_points", s.str().c_str()); + lpe->getRepr()->setAttribute("miter_limit", "4"); + lpe->getRepr()->setAttribute("linejoin_type", "extrp_arc"); } static void spdc_apply_bend_shape(gchar const *svgd, FreehandBase *dc, SPItem *item) @@ -341,12 +317,14 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, bool shape_applied = false; SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); const char *cstroke = sp_repr_css_property(css_item, "stroke", "none"); + const char *stroke_width = sp_repr_css_property(css_item, "stroke-width", "0"); + double swidth; + sp_svg_number_read_d(stroke_width, &swidth); static SPItem *bend_item; #define SHAPE_LENGTH 10 #define SHAPE_HEIGHT 10 - if(shape == LAST_APPLIED){ shape = previous_shape_type; @@ -363,7 +341,8 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, { // "triangle in" std::vector<Geom::Point> points(1); - points[0] = Geom::Point(0., SHAPE_HEIGHT/2); + points[0] = Geom::Point(0., swidth/2); + points[0] *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse(); spdc_apply_powerstroke_shape(points, dc, item); shape_applied = true; @@ -374,7 +353,9 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, // "triangle out" guint curve_length = curve->get_segment_count(); std::vector<Geom::Point> points(1); - points[0] = Geom::Point((double)curve_length, SHAPE_HEIGHT/2); + points[0] = Geom::Point(0, swidth/2); + points[0] *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse(); + points[0][Geom::X] = (double)curve_length; spdc_apply_powerstroke_shape(points, dc, item); shape_applied = true; @@ -455,7 +436,6 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, if(previous_shape_type == CLIPBOARD){ if(previous_shape_pathv.size() != 0){ spdc_paste_curve_as_freehand_shape(previous_shape_pathv, dc, item); - shape_applied = true; shape = CLIPBOARD; } else{ |
