summaryrefslogtreecommitdiffstats
path: root/src/live_effects/lpe-powerstroke.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/live_effects/lpe-powerstroke.cpp')
-rw-r--r--src/live_effects/lpe-powerstroke.cpp103
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;
}
}