summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohan B. C. Engelen <jbc.engelen@swissonline.ch>2014-10-19 17:22:28 +0000
committerJohan B. C. Engelen <j.b.c.engelen@alumnus.utwente.nl>2014-10-19 17:22:28 +0000
commit6d0d26db12a8103388a0fe796bd8696836b40c25 (patch)
tree9453cc7eff6975383f04580b0f16ee60a5fbf002 /src
parentTypo. Fixing typos in translatable strings. (diff)
downloadinkscape-6d0d26db12a8103388a0fe796bd8696836b40c25.tar.gz
inkscape-6d0d26db12a8103388a0fe796bd8696836b40c25.zip
Fix LPE Powerstroke unintuitive / unstable / scale-dependent behavior
(visible for example with Catmul-Rom interpolation) The instability happens when the width-value of adjacent control knots are the same. It's technical, but here goes quickly. Knots are treated as [offset along path, width] points. The offset along path is the segment number + the location along that segment. The width is (may not be true, but for ease of discussion) in canvas coordinates. This means that the interpolation is performed in a *very* compressed coordinate system, where the x-coords may range from, say, 0 to 5, and the y-coords from 0 to 2000. This is also scale dependent; changing the scale of your path and scaling all widths accordingly will change the look of your path. The fix now does the interpolation in a scaled coordinate system. It stretches the x-coordinates to the arclength of the path. After interpolation, the inverse scaling is applied to the interpolation result. (bzr r13627)
Diffstat (limited to 'src')
-rw-r--r--src/live_effects/lpe-powerstroke.cpp12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index b8657e165..087424c21 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -582,6 +582,15 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in)
ts.push_back( Point( pwd2_in.domain().max(),
(end_linecap==LINECAP_ZERO_WIDTH) ? 0. : ts.back()[Geom::Y]) );
}
+
+ // do the interpolation in a coordinate system that is more alike to the on-canvas knots,
+ // instead of the heavily compressed coordinate system of (segment_no offset, Y) in which the knots are stored
+ double pwd2_in_arclength = length(pwd2_in);
+ double xcoord_scaling = pwd2_in_arclength / ts.back()[Geom::X];
+ 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)) {
@@ -590,6 +599,9 @@ LPEPowerStroke::doEffect_path (std::vector<Geom::Path> const & path_in)
Geom::Path strokepath = interpolator->interpolateToPath(ts);
delete interpolator;
+ // apply the inverse knot-xcoord scaling that was applied before the interpolation
+ strokepath *= Scale(1/xcoord_scaling, 1);
+
D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb());
Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]);
Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]);