diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2014-10-18 14:46:03 +0000 |
|---|---|---|
| committer | Johan B. C. Engelen <j.b.c.engelen@alumnus.utwente.nl> | 2014-10-18 14:46:03 +0000 |
| commit | fa5fb39f8c780f78da13545ece947f167d4324b2 (patch) | |
| tree | 468c1a2524c5da41b907b873a40c48cc379fa867 /src | |
| parent | Update to trunk r13621 (diff) | |
| download | inkscape-fa5fb39f8c780f78da13545ece947f167d4324b2.tar.gz inkscape-fa5fb39f8c780f78da13545ece947f167d4324b2.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 r13341.1.279)
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 58d733b53..03a10807a 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -659,6 +659,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)) { @@ -670,6 +679,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]); |
