1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
// SPDX-License-Identifier: GPL-2.0-or-later
#include <iostream>
#include <vector>
#include "bezier-fit.h"
#include <2geom/bezier-utils.h>
#include <2geom/point.h>
extern "C" {
#include "splinefit.h"
#include "splinefont.h"
}
int bezier_fit(Geom::Point bezier[4], const std::vector<InputPoint>& data) {
if (data.size() <= 2) return 0;
int order2 = false; // not 2nd order, so cubic
// "Fitting cubic Bézier curves"
// https://raphlinus.github.io/curves/2021/03/11/bezier-fitting.html
mergetype mt = mt_levien;
auto len = data.size();
std::vector<FitPoint> fit;
for (int i = 0; i < len; ++i) {
fit.push_back({});
auto& fp = fit.back();
fp.p.x = data[i].x();
fp.p.y = data[i].y();
fp.t = data[i].t;
fp.ut.x = fp.ut.y = 0;
}
// transform data into spline set format
auto input = (SplineSet*)chunkalloc(sizeof(SplineSet));
for (int i = 0; i < len; ++i) {
auto& d = data[i];
auto sp = SplinePointCreate(d.x(), d.y());
if (d.have_slope) {
sp->nextcp.x = d.front.x();
sp->nextcp.y = d.front.y();
sp->nonextcp = false;
sp->prevcp.x = d.back.x();
sp->prevcp.y = d.back.y();
sp->noprevcp = false;
}
if (i == 0) {
input->first = input->last = sp;
}
else {
SplineMake(input->last, sp, order2);
input->last = sp;
}
}
Spline* spline = ApproximateSplineFromPointsSlopes(input->first, input->last, fit.data(), fit.size(), order2, mt);
bool ok = spline != nullptr;
if (!spline) {
std::vector<Geom::Point> inp;
inp.reserve(data.size());
for (auto& pt : data) {
inp.push_back(pt);
}
ok = bezier_fit_cubic(bezier, inp.data(), inp.size(), 0.5) > 0;
}
if (spline) {
bezier[0].x() = spline->from->me.x;
bezier[0].y() = spline->from->me.y;
bezier[1].x() = spline->from->nextcp.x;
bezier[1].y() = spline->from->nextcp.y;
bezier[2].x() = spline->to->prevcp.x;
bezier[2].y() = spline->to->prevcp.y;
bezier[3].x() = spline->to->me.x;
bezier[3].y() = spline->to->me.y;
}
SplinePointListFree(input);
//TODO: verify that all C structs are freed up
// SplineFree(spline);
return ok;
}
|