diff options
| author | Johan B. C. Engelen <jbc.engelen@swissonline.ch> | 2010-07-31 00:01:03 +0000 |
|---|---|---|
| committer | Johan Engelen <goejendaagh@zonnet.nl> | 2010-07-31 00:01:03 +0000 |
| commit | 7dba444cb945b48feb3001d4cb1e19650ff01ba1 (patch) | |
| tree | 9356f88f539e3400c93b99c98c2a36be32706c10 /src | |
| parent | powerstroke: redefine meaning of offset point parameter values. now knots mov... (diff) | |
| download | inkscape-7dba444cb945b48feb3001d4cb1e19650ff01ba1.tar.gz inkscape-7dba444cb945b48feb3001d4cb1e19650ff01ba1.zip | |
powerstroke: add code that handles closed paths
(bzr r9673)
Diffstat (limited to 'src')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 93 |
1 files changed, 66 insertions, 27 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 68cdac115..6109ea498 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -169,40 +169,79 @@ LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & offset_points.set_pwd2(pwd2_in); - // perhaps use std::list instead of std::vector? - std::vector<Geom::Point> ts(offset_points.data().size() + 2); - // first and last point coincide with input path (for now at least) - ts.front() = Point(pwd2_in.domain().min(),0); - ts.back() = Point(pwd2_in.domain().max(),0); - for (unsigned int i = 0; i < offset_points.data().size(); ++i) { - ts.at(i+1) = offset_points.data().at(i); - } + Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); + Piecewise<D2<SBasis> > n = rot90(der); + offset_points.set_pwd2_normal(n); - if (sort_points) { - sort(ts.begin(), ts.end(), compare_offsets); + // see if we should treat the path as being closed. + bool closed_path = false; + if ( are_near(pwd2_in.firstValue(), pwd2_in.lastValue()) ) { + closed_path = true; } - // create stroke path where points (x,y) = (t, offset) - Geom::Interpolate::CubicBezierJohan interpolator; - Path strokepath = interpolator.interpolateToPath(ts); - Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); - strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); - strokepath.close(); + Piecewise<D2<SBasis> > output; + if (!closed_path) { + // perhaps use std::list instead of std::vector? + std::vector<Geom::Point> ts(offset_points.data().size() + 2); + // first and last point coincide with input path (for now at least) + ts.front() = Point(pwd2_in.domain().min(),0); + ts.back() = Point(pwd2_in.domain().max(),0); + for (unsigned int i = 0; i < offset_points.data().size(); ++i) { + ts.at(i+1) = offset_points.data().at(i); + } - D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); - Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); - Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + if (sort_points) { + sort(ts.begin(), ts.end(), compare_offsets); + } - Piecewise<D2<SBasis> > der = unitVector(derivative(pwd2_in)); - Piecewise<D2<SBasis> > n = rot90(der); - offset_points.set_pwd2_normal(n); + // create stroke path where points (x,y) := (t, offset) + Geom::Interpolate::CubicBezierJohan interpolator; + Path strokepath = interpolator.interpolateToPath(ts); + Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); + + strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); + strokepath.close(); + + D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); + Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); + Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + + output = compose(pwd2_in,x) + y*compose(n,x); + } else { + // path is closed -// output = pwd2_in + n * offset; -// append_half_circle(output, pwd2_in.lastValue(), n.lastValue() * offset); -// output.continuousConcat(reverse(pwd2_in - n * offset)); -// append_half_circle(output, pwd2_in.firstValue(), -n.firstValue() * offset); + // perhaps use std::list instead of std::vector? + std::vector<Geom::Point> ts = offset_points.data(); + if (sort_points) { + sort(ts.begin(), ts.end(), compare_offsets); + } + // add extra points for interpolation between first and last point + Point first_point = ts.front(); + Point last_point = ts.back(); + ts.insert(ts.begin(), last_point - Point(pwd2_in.domain().extent() ,0)); + ts.push_back( first_point + Point(pwd2_in.domain().extent() ,0) ); + // create stroke path where points (x,y) := (t, offset) + Geom::Interpolate::CubicBezierJohan interpolator; + Path strokepath = interpolator.interpolateToPath(ts); + + // output 2 separate paths + D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); + Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); + Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); + // find time values for which x lies outside path domain + // and only take portion of x and y that lies within those time values + std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); + std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); + if ( !rtsmin.empty() && !rtsmax.empty() ) { + x = portion(x, rtsmin.at(0), rtsmax.at(0)); + y = portion(y, rtsmin.at(0), rtsmax.at(0)); + } + output = compose(pwd2_in,x) + y*compose(n,x); + x = reverse(x); + y = reverse(y); + output.concat(compose(pwd2_in,x) - y*compose(n,x)); + } - Piecewise<D2<SBasis> > output = compose(pwd2_in,x) + y*compose(n,x); return output; } |
