Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
lpe-powerstroke-interpolators.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
5/* Authors:
6 * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
7 *
8 * Copyright (C) 2010-2011 Authors
9 *
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#ifndef INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H
14#define INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H
15
16#include <2geom/path.h>
17#include <2geom/bezier-utils.h>
19
20#include "live_effects/spiro.h"
21
22
24namespace Geom {
25namespace Interpolate {
26
35
37public:
38 Interpolator() = default;;
39 virtual ~Interpolator() = default;;
40
42
43 virtual Geom::Path interpolateToPath(std::vector<Point> const &points) const = 0;
44
45private:
46 Interpolator(const Interpolator&) = delete;
48};
49
50class Linear : public Interpolator {
51public:
52 Linear() = default;;
53 ~Linear() override = default;;
54
55 Path interpolateToPath(std::vector<Point> const &points) const override {
56 Path path;
57 path.start( points.at(0) );
58 for (unsigned int i = 1 ; i < points.size(); ++i) {
59 path.appendNew<Geom::LineSegment>(points.at(i));
60 }
61 return path;
62 };
63
64private:
65 Linear(const Linear&) = delete;
66 Linear& operator=(const Linear&) = delete;
67};
68
69// this class is terrible
71public:
72 CubicBezierFit() = default;;
73 ~CubicBezierFit() override = default;;
74
75 Path interpolateToPath(std::vector<Point> const &points) const override {
76 unsigned int n_points = points.size();
77 // worst case gives us 2 segment per point
78 int max_segs = 8*n_points;
79 Geom::Point * b = g_new(Geom::Point, max_segs);
80 Geom::Point * points_array = g_new(Geom::Point, 4*n_points);
81 for (unsigned i = 0; i < n_points; ++i) {
82 points_array[i] = points.at(i);
83 }
84
85 double tolerance_sq = 0; // this value is just a random guess
86
87 int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points,
88 tolerance_sq, max_segs);
89
90 Geom::Path fit;
91 if ( n_segs > 0)
92 {
93 fit.start(b[0]);
94 for (int c = 0; c < n_segs; c++) {
95 fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]);
96 }
97 }
98 g_free(b);
99 g_free(points_array);
100 return fit;
101 };
102
103private:
106};
107
110public:
111 CubicBezierJohan(double beta = 0.2) {
112 _beta = beta;
113 };
114 ~CubicBezierJohan() override = default;;
115
116 Path interpolateToPath(std::vector<Point> const &points) const override {
117 Path fit;
118 fit.start(points.at(0));
119 for (unsigned int i = 1; i < points.size(); ++i) {
120 Point p0 = points.at(i-1);
121 Point p1 = points.at(i);
122 Point dx = Point(p1[X] - p0[X], 0);
123 fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1);
124 }
125 return fit;
126 };
127
128 void setBeta(double beta) {
129 _beta = beta;
130 }
131
132 double _beta;
133
134private:
137};
138
141public:
142 CubicBezierSmooth(double beta = 0.2) {
143 _beta = beta;
144 };
145 ~CubicBezierSmooth() override = default;;
146
147 Path interpolateToPath(std::vector<Point> const &points) const override {
148 Path fit;
149 fit.start(points.at(0));
150 unsigned int num_points = points.size();
151 for (unsigned int i = 1; i < num_points; ++i) {
152 Point p0 = points.at(i-1);
153 Point p1 = points.at(i);
154 Point dx = Point(p1[X] - p0[X], 0);
155 if (i == 1) {
156 fit.appendNew<CubicBezier>(p0, p1-0.75*dx, p1);
157 } else if (i == points.size() - 1) {
158 fit.appendNew<CubicBezier>(p0+0.75*dx, p1, p1);
159 } else {
160 fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1);
161 }
162 }
163 return fit;
164 };
165
166 void setBeta(double beta) {
167 _beta = beta;
168 }
169
170 double _beta;
171
172private:
175};
176
178public:
179 SpiroInterpolator() = default;;
180 ~SpiroInterpolator() override = default;;
181
182 Path interpolateToPath(std::vector<Point> const &points) const override {
183 Coord scale_y = 100.;
184
185 guint len = points.size();
186 Spiro::spiro_cp *controlpoints = g_new (Spiro::spiro_cp, len);
187 for (unsigned int i = 0; i < len; ++i) {
188 controlpoints[i].x = points[i][X];
189 controlpoints[i].y = points[i][Y] / scale_y;
190 controlpoints[i].ty = 'c';
191 }
192 controlpoints[0].ty = '{';
193 controlpoints[1].ty = 'v';
194 controlpoints[len-2].ty = 'v';
195 controlpoints[len-1].ty = '}';
196
197 auto fit = Spiro::spiro_run(controlpoints, len);
198
199 fit *= Scale(1,scale_y);
200 g_free(controlpoints);
201 return fit;
202 };
203
204private:
207};
208
209// Quick mockup for testing the behavior for powerstroke controlpoint interpolation
211public:
214
215 Path interpolateToPath(std::vector<Point> const &points) const override {
216 unsigned int n_points = points.size();
217
218 Geom::Path fit(points.front());
219
220 if (n_points < 3) return fit; // TODO special cases for 0,1 and 2 input points
221
222 // return n_points-1 cubic segments
223
224 // duplicate first point
225 fit.append(calc_bezier(points[0],points[0],points[1],points[2]));
226
227 for (std::size_t i = 0; i < n_points-2; ++i) {
228 Point p0 = points[i];
229 Point p1 = points[i+1];
230 Point p2 = points[i+2];
231 Point p3 = (i < n_points-3) ? points[i+3] : points[i+2];
232
233 fit.append(calc_bezier(p0, p1, p2, p3));
234 }
235
236 return fit;
237 };
238
239private:
241 // create interpolating bezier between p1 and p2
242
243 // Part of the code comes from StackOverflow user eriatarka84
244 // http://stackoverflow.com/a/23980479/2929337
245
246 // calculate time coords (deltas) of points
247 // the factor 0.25 can be generalized for other Catmull-Rom interpolation types
248 // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves",
249 // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
250 double dt0 = powf(distanceSq(p0, p1), 0.25);
251 double dt1 = powf(distanceSq(p1, p2), 0.25);
252 double dt2 = powf(distanceSq(p2, p3), 0.25);
253
254
255 // safety check for repeated points
256 double eps = Geom::EPSILON;
257 if (dt1 < eps)
258 dt1 = 1.0;
259 if (dt0 < eps)
260 dt0 = dt1;
261 if (dt2 < eps)
262 dt2 = dt1;
263
264 // compute tangents when parameterized in [t1,t2]
265 Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1;
266 Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2;
267 // rescale tangents for parametrization in [0,1]
268 tan1 *= dt1;
269 tan2 *= dt1;
270
271 // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it)
272 // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2)
273 // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2
274 // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1
275 // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2
276
277 Point b0 = p1;
278 Point b1 = p1 + tan1 / 3;
279 Point b2 = p2 - tan2 / 3;
280 Point b3 = p2;
281
282 return CubicBezier(b0, b1, b2, b3);
283 }
284
287};
288
289
290inline Interpolator*
309
310} //namespace Interpolate
311} //namespace Geom
312
313#endif
314
315/*
316 Local Variables:
317 mode:c++
318 c-file-style:"stroustrup"
319 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
320 indent-tabs-mode:nil
321 fill-column:99
322 End:
323*/
324// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Path - a sequence of contiguous curves.
Bezier fitting algorithms.
CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator &)=delete
CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const
CentripetalCatmullRomInterpolator & operator=(const CentripetalCatmullRomInterpolator &)=delete
Path interpolateToPath(std::vector< Point > const &points) const override
CubicBezierFit & operator=(const CubicBezierFit &)=delete
CubicBezierFit(const CubicBezierFit &)=delete
~CubicBezierFit() override=default
Path interpolateToPath(std::vector< Point > const &points) const override
CubicBezierJohan & operator=(const CubicBezierJohan &)=delete
Path interpolateToPath(std::vector< Point > const &points) const override
CubicBezierJohan(const CubicBezierJohan &)=delete
~CubicBezierJohan() override=default
Path interpolateToPath(std::vector< Point > const &points) const override
CubicBezierSmooth & operator=(const CubicBezierSmooth &)=delete
CubicBezierSmooth(const CubicBezierSmooth &)=delete
virtual ~Interpolator()=default
Interpolator(const Interpolator &)=delete
virtual Geom::Path interpolateToPath(std::vector< Point > const &points) const =0
Interpolator & operator=(const Interpolator &)=delete
static Interpolator * create(InterpolatorType type)
~Linear() override=default
Linear & operator=(const Linear &)=delete
Linear(const Linear &)=delete
Path interpolateToPath(std::vector< Point > const &points) const override
SpiroInterpolator & operator=(const SpiroInterpolator &)=delete
SpiroInterpolator(const SpiroInterpolator &)=delete
Path interpolateToPath(std::vector< Point > const &points) const override
Sequence of contiguous curves, aka spline.
Definition path.h:353
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
size_type size() const
Natural size of the path.
Definition path.h:490
void appendNew(Args &&... args)
Append a new curve to the path.
Definition path.h:804
void start(Point const &p)
Definition path.cpp:426
Two-dimensional point that doubles as a vector.
Definition point.h:66
Scaling from the origin.
Definition transforms.h:150
double c[8][4]
BezierCurveN< 3 > CubicBezier
Cubic (order 3) Bezier curve.
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
constexpr Coord EPSILON
Default "acceptably small" value.
Definition coord.h:84
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Various utility functions.
Definition affine.h:22
Coord distanceSq(Point const &p, Rect const &rect)
Definition rect.cpp:158
int bezier_fit_cubic_r(Point bezier[], Point const data[], int len, double error, unsigned max_beziers)
Fit a multi-segment Bezier curve to a set of digitized points, with possible weedout of identical poi...
D2< Piecewise< SBasis > > tan2(SBasis const &angle, double tol=.01, unsigned order=3)
Geom::Path spiro_run(const spiro_cp *src, int src_len)
Definition spiro.cpp:23
auto len
Definition safe-printf.h:21
Conversion between SBasis and Bezier basis polynomials.
C implementation of third-order polynomial spirals.
double y
Definition spiro.h:22
double x
Definition spiro.h:21
std::unique_ptr< Toolbar >(* create)()
Definition toolbars.cpp:56