summaryrefslogtreecommitdiffstats
path: root/src/live_effects
diff options
context:
space:
mode:
authorJabier Arraiza <jabier.arraiza@marker.es>2017-11-28 21:47:59 +0000
committerJabier Arraiza <jabier.arraiza@marker.es>2017-11-28 21:47:59 +0000
commitd383c6fe801cf851bffb7927d508b5251e19522c (patch)
tree698edd9475bd9e6b8cecbb26179a3755c5de5514 /src/live_effects
parentWorking on continuous paths (diff)
downloadinkscape-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.cpp3
-rw-r--r--src/live_effects/lpe-powerstroke-interpolators.h37
-rw-r--r--src/live_effects/lpe-powerstroke.cpp123
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;
}
}