4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen/** @file
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen * Interpolators for lists of points.
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen */
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen/* Authors:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen *
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen * Copyright (C) 2010-2011 Authors
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen *
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen * Released under GNU GPL, read the file 'COPYING' for more information
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen */
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#ifndef INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#define INKSCAPE_LPE_POWERSTROKE_INTERPOLATORS_H
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#include <2geom/path.h>
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#include <2geom/bezier-utils.h>
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#include <2geom/sbasis-to-bezier.h>
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#include "live_effects/spiro.h"
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen/// @TODO Move this to 2geom?
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelennamespace Geom {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelennamespace Interpolate {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenenum InterpolatorType {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen INTERP_LINEAR,
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen INTERP_CUBICBEZIER,
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen INTERP_CUBICBEZIER_JOHAN,
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White INTERP_SPIRO,
0ed512dfeb94b481858723f9ba692fd4682f9012Liam P. White INTERP_CUBICBEZIER_SMOOTH,
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen INTERP_CENTRIPETAL_CATMULLROM
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenclass Interpolator {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenpublic:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Interpolator() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual ~Interpolator() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen static Interpolator* create(InterpolatorType type);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual Geom::Path interpolateToPath(std::vector<Point> const &points) const = 0;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenprivate:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Interpolator(const Interpolator&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Interpolator& operator=(const Interpolator&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenclass Linear : public Interpolator {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenpublic:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Linear() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual ~Linear() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual Path interpolateToPath(std::vector<Point> const &points) const {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Path path;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen path.start( points.at(0) );
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (unsigned int i = 1 ; i < points.size(); ++i) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen path.appendNew<Geom::LineSegment>(points.at(i));
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return path;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen };
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenprivate:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Linear(const Linear&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Linear& operator=(const Linear&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen// this class is terrible
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenclass CubicBezierFit : public Interpolator {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenpublic:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierFit() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual ~CubicBezierFit() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual Path interpolateToPath(std::vector<Point> const &points) const {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen unsigned int n_points = points.size();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen // worst case gives us 2 segment per point
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen int max_segs = 8*n_points;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Geom::Point * b = g_new(Geom::Point, max_segs);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Geom::Point * points_array = g_new(Geom::Point, 4*n_points);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (unsigned i = 0; i < n_points; ++i) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen points_array[i] = points.at(i);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen double tolerance_sq = 0; // this value is just a random guess
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen int const n_segs = Geom::bezier_fit_cubic_r(b, points_array, n_points,
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen tolerance_sq, max_segs);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Geom::Path fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen if ( n_segs > 0)
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fit.start(b[0]);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (int c = 0; c < n_segs; c++) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fit.appendNew<Geom::CubicBezier>(b[4*c+1], b[4*c+2], b[4*c+3]);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen g_free(b);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen g_free(points_array);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen };
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenprivate:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierFit(const CubicBezierFit&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierFit& operator=(const CubicBezierFit&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen/// @todo invent name for this class
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenclass CubicBezierJohan : public Interpolator {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenpublic:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierJohan(double beta = 0.2) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen _beta = beta;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen };
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual ~CubicBezierJohan() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual Path interpolateToPath(std::vector<Point> const &points) const {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Path fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fit.start(points.at(0));
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (unsigned int i = 1; i < points.size(); ++i) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Point p0 = points.at(i-1);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Point p1 = points.at(i);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Point dx = Point(p1[X] - p0[X], 0);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen };
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
ea7d8c8f5752fe8fe4f814fc01baf6f250825817Johan Engelen void setBeta(double beta) {
ea7d8c8f5752fe8fe4f814fc01baf6f250825817Johan Engelen _beta = beta;
ea7d8c8f5752fe8fe4f814fc01baf6f250825817Johan Engelen }
ea7d8c8f5752fe8fe4f814fc01baf6f250825817Johan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen double _beta;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenprivate:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierJohan(const CubicBezierJohan&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen CubicBezierJohan& operator=(const CubicBezierJohan&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White/// @todo invent name for this class
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. Whiteclass CubicBezierSmooth : public Interpolator {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. Whitepublic:
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White CubicBezierSmooth(double beta = 0.2) {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White _beta = beta;
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White };
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White virtual ~CubicBezierSmooth() {};
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White virtual Path interpolateToPath(std::vector<Point> const &points) const {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White Path fit;
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White fit.start(points.at(0));
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White unsigned int num_points = points.size();
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White for (unsigned int i = 1; i < num_points; ++i) {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White Point p0 = points.at(i-1);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White Point p1 = points.at(i);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White Point dx = Point(p1[X] - p0[X], 0);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White if (i == 1) {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White fit.appendNew<CubicBezier>(p0, p1-0.75*dx, p1);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White } else if (i == points.size() - 1) {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White fit.appendNew<CubicBezier>(p0+0.75*dx, p1, p1);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White } else {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White fit.appendNew<CubicBezier>(p0+_beta*dx, p1-_beta*dx, p1);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White }
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White }
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White return fit;
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White };
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White void setBeta(double beta) {
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White _beta = beta;
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White }
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White double _beta;
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. Whiteprivate:
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White CubicBezierSmooth(const CubicBezierSmooth&);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White CubicBezierSmooth& operator=(const CubicBezierSmooth&);
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenclass SpiroInterpolator : public Interpolator {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenpublic:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen SpiroInterpolator() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual ~SpiroInterpolator() {};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen virtual Path interpolateToPath(std::vector<Point> const &points) const {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Path fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Coord scale_y = 100.;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen guint len = points.size();
b49365c42b99e3cc135dcde0077aad31d930f6c1Johan B. C. Engelen Spiro::spiro_cp *controlpoints = g_new (Spiro::spiro_cp, len);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen for (unsigned int i = 0; i < len; ++i) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[i].x = points[i][X];
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[i].y = points[i][Y] / scale_y;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[i].ty = 'c';
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[0].ty = '{';
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[1].ty = 'v';
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[len-2].ty = 'v';
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen controlpoints[len-1].ty = '}';
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
b49365c42b99e3cc135dcde0077aad31d930f6c1Johan B. C. Engelen Spiro::spiro_run(controlpoints, len, fit);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fit *= Scale(1,scale_y);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return fit;
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen };
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelenprivate:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen SpiroInterpolator(const SpiroInterpolator&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen SpiroInterpolator& operator=(const SpiroInterpolator&);
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen};
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen// Quick mockup for testing the behavior for powerstroke controlpoint interpolation
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelenclass CentripetalCatmullRomInterpolator : public Interpolator {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelenpublic:
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen CentripetalCatmullRomInterpolator() {};
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen virtual ~CentripetalCatmullRomInterpolator() {};
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen virtual Path interpolateToPath(std::vector<Point> const &points) const {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen unsigned int n_points = points.size();
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Geom::Path fit(points.front());
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (n_points < 3) return fit; // TODO special cases for 0,1 and 2 input points
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // return n_points-1 cubic segments
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // duplicate first point
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen fit.append(calc_bezier(points[0],points[0],points[1],points[2]));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen for (std::size_t i = 0; i < n_points-2; ++i) {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point p0 = points[i];
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point p1 = points[i+1];
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point p2 = points[i+2];
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point p3 = (i < n_points-3) ? points[i+3] : points[i+2];
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen fit.append(calc_bezier(p0, p1, p2, p3));
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen }
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen return fit;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen };
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelenprivate:
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const {
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // create interpolating bezier between p1 and p2
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen // Part of the code comes from StackOverflow user eriatarka84
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen // http://stackoverflow.com/a/23980479/2929337
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // calculate time coords (deltas) of points
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen // the factor 0.25 can be generalized for other Catmull-Rom interpolation types
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves",
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen double dt0 = powf(distanceSq(p0, p1), 0.25);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen double dt1 = powf(distanceSq(p1, p2), 0.25);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen double dt2 = powf(distanceSq(p2, p3), 0.25);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
26467da82c920aae52b2c00844c12f9ea236b480Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // safety check for repeated points
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen double eps = Geom::EPSILON;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (dt1 < eps)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen dt1 = 1.0;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (dt0 < eps)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen dt0 = dt1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen if (dt2 < eps)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen dt2 = dt1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // compute tangents when parameterized in [t1,t2]
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // rescale tangents for parametrization in [0,1]
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen tan1 *= dt1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen tan2 *= dt1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // 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)
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point b0 = p1;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point b1 = p1 + tan1 / 3;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point b2 = p2 - tan2 / 3;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen Point b3 = p2;
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen return CubicBezier(b0, b1, b2, b3);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen }
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&);
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen};
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engeleninline Interpolator*
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan EngelenInterpolator::create(InterpolatorType type) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen switch (type) {
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen case INTERP_LINEAR:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return new Geom::Interpolate::Linear();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen case INTERP_CUBICBEZIER:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return new Geom::Interpolate::CubicBezierFit();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen case INTERP_CUBICBEZIER_JOHAN:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return new Geom::Interpolate::CubicBezierJohan();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen case INTERP_SPIRO:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return new Geom::Interpolate::SpiroInterpolator();
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White case INTERP_CUBICBEZIER_SMOOTH:
8ba84881e79b6175868d04179ca86f4823a69ec0Liam P. White return new Geom::Interpolate::CubicBezierSmooth();
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen case INTERP_CENTRIPETAL_CATMULLROM:
742a1b08138aef8fc3c19730ae48e5477ee43fc5Johan B. C. Engelen return new Geom::Interpolate::CentripetalCatmullRomInterpolator();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen default:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen return new Geom::Interpolate::Linear();
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen }
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen}
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen} //namespace Interpolate
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen} //namespace Geom
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen#endif
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen/*
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen Local Variables:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen mode:c++
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen c-file-style:"stroustrup"
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen indent-tabs-mode:nil
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen fill-column:99
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen End:
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen*/
4fd537e3c7f3fb1b0013f94688e95b0c3ef6649cJohan Engelen// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :