diff options
| author | Jabier Arraiza <jabier.arraiza@marker.es> | 2017-11-28 21:47:59 +0000 |
|---|---|---|
| committer | Jabier Arraiza <jabier.arraiza@marker.es> | 2017-11-28 21:47:59 +0000 |
| commit | d383c6fe801cf851bffb7927d508b5251e19522c (patch) | |
| tree | 698edd9475bd9e6b8cecbb26179a3755c5de5514 /src/live_effects | |
| parent | Working on continuous paths (diff) | |
| download | inkscape-d383c6fe801cf851bffb7927d508b5251e19522c.tar.gz inkscape-d383c6fe801cf851bffb7927d508b5251e19522c.zip | |
Working on BSPline interpolator
Diffstat (limited to 'src/live_effects')
| -rw-r--r-- | src/live_effects/lpe-interpolate_points.cpp | 3 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke-interpolators.h | 37 | ||||
| -rw-r--r-- | src/live_effects/lpe-powerstroke.cpp | 123 |
3 files changed, 133 insertions, 30 deletions
diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp index 7d4c88dc1..c745921c2 100644 --- a/src/live_effects/lpe-interpolate_points.cpp +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -25,7 +25,8 @@ static const Util::EnumData<unsigned> InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, - {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"}, + {Geom::Interpolate::INTERP_BSPLINE , N_("BSpline"), "BSpline"} }; static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index e3ab37e27..651eba057 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -15,7 +15,7 @@ #include <2geom/path.h> #include <2geom/bezier-utils.h> #include <2geom/sbasis-to-bezier.h> - +#include <math.h> #include "live_effects/spiro.h" @@ -27,6 +27,7 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, + INTERP_BSPLINE, INTERP_SPIRO, INTERP_CUBICBEZIER_SMOOTH, INTERP_CENTRIPETAL_CATMULLROM @@ -65,6 +66,38 @@ private: Linear& operator=(const Linear&); }; +class BSpline : public Interpolator { +public: + BSpline() {}; + virtual ~BSpline() {}; + + virtual Path interpolateToPath(std::vector<Point> const &points) const { + Path path; + path.start( points.at(0) ); + for (unsigned int i = 1 ; i < points.size(); ++i) { + Geom::Point pointA = points.at(i-1); + Geom::Point pointB = points.at(i); + Geom::Ray ray(pointA, pointB); + double angle = ray.angle(); + if (angle == 0) { + continue; + } + std::cout << angle << "angle" << std::endl; + double k1 = (Geom::distance(pointA, pointB)*std::sin(angle))/2.0; + std::cout << k1 << "k1" << std::endl; + std::cout << std::sin(angle) << "std::sin(angle)" << std::endl; + Geom::Point handle_1 = Geom::Point::polar(angle, k1) + pointA; + Geom::Point handle_2 = Geom::Point::polar(angle, k1 * 2) + pointA; + path.appendNew<CubicBezier>(handle_1, handle_2, pointB); + } + return path; + }; + +private: + BSpline(const BSpline&); + BSpline& operator=(const BSpline&); +}; + // this class is terrible class CubicBezierFit : public Interpolator { public: @@ -302,6 +335,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierSmooth(); case INTERP_CENTRIPETAL_CATMULLROM: return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); + case INTERP_BSPLINE: + return new Geom::Interpolate::BSpline(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index e9943af4c..2b8ca85c7 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -123,7 +123,8 @@ static const Util::EnumData<unsigned> InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, - {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM, N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"}, + {Geom::Interpolate::INTERP_BSPLINE , N_("BSpline"), "BSpline"} }; static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); @@ -626,12 +627,23 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) if (Geom::Interpolate::CubicBezierSmooth *smooth = dynamic_cast<Geom::Interpolate::CubicBezierSmooth*>(interpolator)) { smooth->setBeta(interpolator_beta); } + bool is_bspline = false; + if (Geom::Interpolate::BSpline *bspline = dynamic_cast<Geom::Interpolate::BSpline*>(interpolator)) { + is_bspline = true; + } Geom::Path strokepath = interpolator->interpolateToPath(ts); - delete interpolator; + std::vector<Geom::Point> mirrorts; + for(auto point:ts) { + Geom::Point p = Geom::Point(point[Geom::X],point[Geom::Y]*-1); + mirrorts.push_back(p); + } + Geom::Path strokepath_mirror = interpolator->interpolateToPath(mirrorts); // apply the inverse knot-xcoord scaling that was applied before the interpolation strokepath *= Scale(1/xcoord_scaling, 1); - + strokepath_mirror *= Scale(1/xcoord_scaling, 1); + Geom::Path fixed_path = strokepath; + Geom::Path fixed_mirrorpath = strokepath_mirror; D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); Piecewise<SBasis> x = Piecewise<SBasis>(patternd2[0]); Piecewise<SBasis> y = Piecewise<SBasis>(patternd2[1]); @@ -643,12 +655,67 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) x = portion(x, rtsmin.at(0), rtsmax.at(0)); y = portion(y, rtsmin.at(0), rtsmax.at(0)); } + if (!is_bspline) { - LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); - 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)); - Geom::Path fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); - Geom::Path fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); + LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); + 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)); + fixed_path = path_from_piecewise_fix_cusps( pwd2_out, y, jointype, miter_limit, LPE_CONVERSION_TOLERANCE); + fixed_mirrorpath = path_from_piecewise_fix_cusps( mirrorpath, reverse(y), jointype, miter_limit, LPE_CONVERSION_TOLERANCE); + } else { + std::vector<Geom::Point> ts_pos; + for(auto point:ts) { + if (point[Geom::X] > pwd2_in.size() || point[Geom::X] < 0) { + g_warning("Broken powerstroke point at %f, I won't try to add that", point[Geom::X]); + continue; + } + point = pwd2_in.valueAt(point[Geom::X]) + (point[Geom::Y] * scale_width) * n.valueAt(point[Geom::X]); + ts_pos.push_back(point); + } + strokepath = interpolator->interpolateToPath(ts_pos); + std::vector<Geom::Point> ts_pos_mirror; + for(auto point:ts) { + point = Geom::Point(point[Geom::X],point[Geom::Y]*-1); + if (point[Geom::X] > pwd2_in.size() || point[Geom::X] < 0) { + g_warning("Broken powerstroke point at %f, I won't try to add that", point[Geom::X]); + continue; + } + point = pwd2_in.valueAt(point[Geom::X]) + (point[Geom::Y] * scale_width) * n.valueAt(point[Geom::X]); + ts_pos_mirror.push_back(point); + } + strokepath_mirror = interpolator->interpolateToPath(ts_pos_mirror); +// Geom::Path fixed_path; +// fixed_path.start(strokepath.initialPoint()); +// for (Geom::Path::const_iterator curve = strokepath->begin(); curve != strokepath->end(); ++curve) { +// Geom::Point pointA = curve.initialPoint(); +// Geom::Point pointB = curve.finalPoint(); +// double angle = pointA.angle()-pointB.angle(); +// if (angle==0) { +// continue; +// } +// double k1 = (Geom::distance(pointA, pointB)/cos(angle)/5.0) * 2; +// Geom::Point handle_1 = Geom::Point::polar(angle, k1) + pointA; +// Geom::Point handle_2 = Geom::Point::polar(angle, k1 * 2) + pointA; +// fixed_path..appendNew<CubicBezier>(handle_1, handle_2, pointB); +// } +// +// Geom::Path fixed_mirrorpath; +// fixed_mirrorpath.start(strokepath_mirror.initialPoint()); +// for (Geom::Path::const_iterator curve = strokepath_mirror->begin(); curve != strokepath_mirror->end(); ++curve) { +// Geom::Point pointA = curve.initialPoint(); +// Geom::Point pointB = curve.finalPoint(); +// double angle = pointA.angle()-pointB.angle(); +// if (angle==0) { +// continue; +// } +// double k1 = (Geom::distance(pointA, pointB)/cos(angle)/5.0) * 2; +// Geom::Point handle_1 = Geom::Point::polar(angle, k1) + pointA; +// Geom::Point handle_2 = Geom::Point::polar(angle, k1 * 2) + pointA; +// fixed_mirrorpath..appendNew<CubicBezier>(handle_1, handle_2, pointB); +// } + + } + delete interpolator; if (pathv[0].closed()) { fixed_path.close(true); path_out.push_back(fixed_path); @@ -663,31 +730,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; } } @@ -700,31 +767,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; } } |
