curvedraw

view src/curve.cc @ 2:ce7aa9a0594c

improved curve editing
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 17 Dec 2015 05:13:25 +0200
parents 8e524989c904
children 2b7ae76c173f
line source
1 #include <float.h>
2 #include "curve.h"
4 Curve::Curve(CurveType type)
5 {
6 this->type = type;
7 }
9 void Curve::set_type(CurveType type)
10 {
11 this->type = type;
12 }
14 CurveType Curve::get_type() const
15 {
16 return type;
17 }
19 void Curve::add_point(const Vector2 &p, float weight)
20 {
21 cp.push_back(Vector3(p.x, p.y, weight));
22 }
24 bool Curve::remove_point(int idx)
25 {
26 if(idx < 0 || idx >= (int)cp.size()) {
27 return false;
28 }
29 cp.erase(cp.begin() + idx);
30 return true;
31 }
33 int Curve::nearest_point(const Vector2 &p)
34 {
35 int res = -1;
36 float bestsq = FLT_MAX;
38 for(size_t i=0; i<cp.size(); i++) {
39 float d = (get_point(i) - p).length_sq();
40 if(d < bestsq) {
41 bestsq = d;
42 res = i;
43 }
44 }
46 return res;
47 }
49 bool Curve::empty() const
50 {
51 return cp.empty();
52 }
54 int Curve::size() const
55 {
56 return (int)cp.size();
57 }
59 Vector3 &Curve::operator [](int idx)
60 {
61 return cp[idx];
62 }
64 const Vector3 &Curve::operator [](int idx) const
65 {
66 return cp[idx];
67 }
69 const Vector3 &Curve::get_homo_point(int idx) const
70 {
71 return cp[idx];
72 }
74 Vector2 Curve::get_point(int idx) const
75 {
76 return Vector2(cp[idx].x, cp[idx].y);
77 }
79 float Curve::get_weight(int idx) const
80 {
81 return cp[idx].z;
82 }
84 bool Curve::set_point(int idx, const Vector2 &p, float weight)
85 {
86 if(idx < 0 || idx >= (int)cp.size()) {
87 return false;
88 }
89 cp[idx] = Vector3(p.x, p.y, weight);
90 return true;
91 }
93 bool Curve::set_weight(int idx, float weight)
94 {
95 if(idx < 0 || idx >= (int)cp.size()) {
96 return false;
97 }
98 cp[idx].z = weight;
99 return true;
100 }
102 bool Curve::move_point(int idx, const Vector2 &p)
103 {
104 if(idx < 0 || idx >= (int)cp.size()) {
105 return false;
106 }
107 cp[idx] = Vector3(p.x, p.y, cp[idx].z);
108 return true;
109 }
111 Vector2 Curve::interpolate(float t, CurveType type) const
112 {
113 if(cp.empty()) {
114 return Vector2(0, 0);
115 }
117 int num_cp = (int)cp.size();
118 if(num_cp == 1) {
119 return Vector2(cp[0].x, cp[0].y);
120 }
122 Vector3 res;
123 int idx0 = std::min((int)floor(t * (num_cp - 1)), num_cp - 2);
124 int idx1 = idx0 + 1;
126 float dt = 1.0 / (float)(num_cp - 1);
127 float t0 = (float)idx0 * dt;
128 float t1 = (float)idx1 * dt;
130 t = (t - t0) / (t1 - t0);
131 if(t < 0.0) t = 0.0;
132 if(t > 1.0) t = 1.0;
134 if(type == CURVE_LINEAR || num_cp <= 2) {
135 res = lerp(cp[idx0], cp[idx1], t);
136 } else {
137 int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1;
138 int idx_next = idx1 >= num_cp - 1 ? idx1 : idx1 + 1;
140 if(type == CURVE_HERMITE) {
141 res = catmull_rom_spline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t);
142 } else {
143 res = bspline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t);
144 if(res.z != 0.0f) {
145 res.x /= res.z;
146 res.y /= res.z;
147 }
148 }
149 }
151 return Vector2(res.x, res.y);
152 }
154 Vector2 Curve::interpolate(float t) const
155 {
156 return interpolate(t, type);
157 }
159 Vector2 Curve::operator ()(float t) const
160 {
161 return interpolate(t);
162 }