diff options
Diffstat (limited to 'src/live_effects/lpe-powerstroke.cpp')
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 103 |
1 files changed, 64 insertions, 39 deletions
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 51c8451a5..4e937c1e4 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -97,10 +97,13 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0 if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // try second time dM=derivative(dM); } - if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // admit defeat + if ( dM.isZero(tol) || (are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) )) { // admit defeat return Geom::Circle(Geom::Point(0., 0.), 0.); } Piecewise<D2<SBasis> > unitv = unitVector(dM,tol); + if (unitv.empty()) { // admit defeat + return Geom::Circle(Geom::Point(0., 0.), 0.); + } Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv); Piecewise<SBasis> k = cross(derivative(unitv),unitv); k = divide(k,dMlength,tol,3); @@ -322,7 +325,7 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: /* per definition, each discontinuity should be fixed with a join-ending, as defined by linejoin_type */ Geom::PathBuilder pb; - if (B.size() == 0) { + if (B.empty()) { return pb.peek().front(); } @@ -555,7 +558,6 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom:: return pb.peek().front(); } - Geom::PathVector LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) { @@ -567,11 +569,18 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) } Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers(path_in); Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = pathv[0].toPwSb(); + if (pwd2_in.empty()) { + return path_in; + } Piecewise<D2<SBasis> > der = derivative(pwd2_in); - Piecewise<D2<SBasis> > n = unitVector(der,0.0001); - if (!n.size() || !pwd2_in.size() || !n.size()) { + if (der.empty()) { + return path_in; + } + Piecewise<D2<SBasis> > n = unitVector(der,0.00001); + if (n.empty()) { return path_in; } + n = rot90(n); offset_points.set_pwd2(pwd2_in, n); @@ -590,12 +599,33 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (sort_points) { sort(ts.begin(), ts.end(), compare_offsets); } + // 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)) { + johan->setBeta(interpolator_beta); + } + if (Geom::Interpolate::CubicBezierSmooth *smooth = dynamic_cast<Geom::Interpolate::CubicBezierSmooth*>(interpolator)) { + smooth->setBeta(interpolator_beta); + } if (pathv[0].closed()) { - // 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) ); + std::vector<Geom::Point> ts_close; + //we have only one knot or overwrite before + Geom::Point start = Geom::Point( pwd2_in.domain().min(), ts.front()[Geom::Y]); + Geom::Point end = Geom::Point( pwd2_in.domain().max(), ts.front()[Geom::Y]); + if (ts.size() > 1) { + ts_close.push_back(ts[ts.size()-2]); + ts_close.push_back(ts.back()); + ts_close.push_back(ts.front()); + ts_close.push_back(ts[1]); + Geom::Path closepath = interpolator->interpolateToPath(ts_close); + start = closepath.pointAt(Geom::nearest_time(Geom::Point( pwd2_in.domain().min(),0), closepath)); + start[Geom::X] = pwd2_in.domain().min(); + end = start; + end[Geom::X] = pwd2_in.domain().max(); + } + ts.insert(ts.begin(), start ); + ts.push_back( end ); + ts_close.clear(); } else { // add width data for first and last point on the path // depending on cap type, these first and last points have width zero or take the width from the closest width point. @@ -612,14 +642,7 @@ 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)) { - johan->setBeta(interpolator_beta); - } - if (Geom::Interpolate::CubicBezierSmooth *smooth = dynamic_cast<Geom::Interpolate::CubicBezierSmooth*>(interpolator)) { - smooth->setBeta(interpolator_beta); - } + Geom::Path strokepath = interpolator->interpolateToPath(ts); delete interpolator; @@ -639,7 +662,9 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) } LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); - + if (x.empty() || y.empty()) { + return path_in; + } Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x); Piecewise<D2<SBasis> > mirrorpath = reverse( compose(pwd2_in,x) - y*compose(n,x)); @@ -659,31 +684,31 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) case LINECAP_PEAK: { Geom::Point end_deriv = -unitTangentAt( reverse(pwd2_in.segs.back()), 0.); - double radius = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); - Geom::Point midpoint = 0.5*(pwd2_out.lastValue() + mirrorpath.firstValue()) + radius*end_deriv; + double radius = 0.5 * distance(fixed_path.finalPoint(), fixed_mirrorpath.initialPoint()); + Geom::Point midpoint = 0.5*(fixed_path.finalPoint() + fixed_mirrorpath.initialPoint()) + radius*end_deriv; fixed_path.appendNew<LineSegment>(midpoint); - fixed_path.appendNew<LineSegment>(mirrorpath.firstValue()); + fixed_path.appendNew<LineSegment>(fixed_mirrorpath.initialPoint()); break; } case LINECAP_SQUARE: { Geom::Point end_deriv = -unitTangentAt( reverse(pwd2_in.segs.back()), 0.); - double radius = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); - fixed_path.appendNew<LineSegment>( pwd2_out.lastValue() + radius*end_deriv ); - fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() + radius*end_deriv ); - fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() ); + double radius = 0.5 * distance(fixed_path.finalPoint(), fixed_mirrorpath.initialPoint()); + fixed_path.appendNew<LineSegment>( fixed_path.finalPoint() + radius*end_deriv ); + fixed_path.appendNew<LineSegment>( fixed_mirrorpath.initialPoint() + radius*end_deriv ); + fixed_path.appendNew<LineSegment>( fixed_mirrorpath.initialPoint() ); break; } case LINECAP_BUTT: { - fixed_path.appendNew<LineSegment>( mirrorpath.firstValue() ); + fixed_path.appendNew<LineSegment>( fixed_mirrorpath.initialPoint() ); break; } case LINECAP_ROUND: default: { - double radius1 = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); - fixed_path.appendNew<EllipticalArc>( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); + double radius1 = 0.5 * distance(fixed_path.finalPoint(), fixed_mirrorpath.initialPoint()); + fixed_path.appendNew<EllipticalArc>( radius1, radius1, M_PI/2., false, y.lastValue() < 0, fixed_mirrorpath.initialPoint() ); break; } } @@ -696,31 +721,31 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) case LINECAP_PEAK: { Geom::Point start_deriv = unitTangentAt( pwd2_in.segs.front(), 0.); - double radius = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); - Geom::Point midpoint = 0.5*(mirrorpath.lastValue() + pwd2_out.firstValue()) - radius*start_deriv; + double radius = 0.5 * distance(fixed_path.initialPoint(), fixed_mirrorpath.finalPoint()); + Geom::Point midpoint = 0.5*(fixed_mirrorpath.finalPoint() + fixed_path.initialPoint()) - radius*start_deriv; fixed_path.appendNew<LineSegment>( midpoint ); - fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + fixed_path.appendNew<LineSegment>( fixed_path.initialPoint() ); break; } case LINECAP_SQUARE: { Geom::Point start_deriv = unitTangentAt( pwd2_in.segs.front(), 0.); - double radius = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); - fixed_path.appendNew<LineSegment>( mirrorpath.lastValue() - radius*start_deriv ); - fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() - radius*start_deriv ); - fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + double radius = 0.5 * distance(fixed_path.initialPoint(), fixed_mirrorpath.finalPoint()); + fixed_path.appendNew<LineSegment>( fixed_mirrorpath.finalPoint() - radius*start_deriv ); + fixed_path.appendNew<LineSegment>( fixed_path.initialPoint() - radius*start_deriv ); + fixed_path.appendNew<LineSegment>( fixed_path.initialPoint() ); break; } case LINECAP_BUTT: { - fixed_path.appendNew<LineSegment>( pwd2_out.firstValue() ); + fixed_path.appendNew<LineSegment>( fixed_path.initialPoint() ); break; } case LINECAP_ROUND: default: { - double radius2 = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); - fixed_path.appendNew<EllipticalArc>( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); + double radius2 = 0.5 * distance(fixed_path.initialPoint(), fixed_mirrorpath.finalPoint()); + fixed_path.appendNew<EllipticalArc>( radius2, radius2, M_PI/2., false, y.firstValue() < 0, fixed_path.initialPoint() ); break; } } |
