curvedraw
changeset 12:84a647283237
added all the extra functionality to the curve class
first pass at a project-to-curve function (needs more work)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 20 Dec 2015 07:21:32 +0200 |
parents | 099fd7adb900 |
children | 4da693339d99 |
files | src/app.cc src/curve.cc src/curve.h src/curvefile.cc |
diffstat | 4 files changed, 378 insertions(+), 98 deletions(-) [+] |
line diff
1.1 --- a/src/app.cc Sat Dec 19 22:39:18 2015 +0200 1.2 +++ b/src/app.cc Sun Dec 20 07:21:32 2015 +0200 1.3 @@ -30,6 +30,8 @@ 1.4 static float grid_size = 1.0; 1.5 static SnapMode snap_mode; 1.6 1.7 +static bool show_bounds; 1.8 + 1.9 static std::vector<Curve*> curves; 1.10 static Curve *sel_curve; // selected curve being edited 1.11 static Curve *new_curve; // new curve being entered 1.12 @@ -38,9 +40,7 @@ 1.13 1.14 static Label *weight_label; // floating label for the cp weight 1.15 1.16 -#ifdef DRAW_MOUSE_POINTER 1.17 static Vector2 mouse_pointer; 1.18 -#endif 1.19 1.20 1.21 bool app_init(int argc, char **argv) 1.22 @@ -151,6 +151,20 @@ 1.23 int numpt = curve->size(); 1.24 int segm = numpt * 16; 1.25 1.26 + if(show_bounds) { 1.27 + Vector3 bmin, bmax; 1.28 + curve->get_bbox(&bmin, &bmax); 1.29 + 1.30 + glLineWidth(1.0); 1.31 + glColor3f(0, 1, 0); 1.32 + glBegin(GL_LINE_LOOP); 1.33 + glVertex2f(bmin.x, bmin.y); 1.34 + glVertex2f(bmax.x, bmin.y); 1.35 + glVertex2f(bmax.x, bmax.y); 1.36 + glVertex2f(bmin.x, bmax.y); 1.37 + glEnd(); 1.38 + } 1.39 + 1.40 glLineWidth(curve == hover_curve ? 4.0 : 2.0); 1.41 if(curve == sel_curve) { 1.42 glColor3f(0.3, 0.4, 1.0); 1.43 @@ -162,7 +176,7 @@ 1.44 glBegin(GL_LINE_STRIP); 1.45 for(int i=0; i<segm; i++) { 1.46 float t = (float)i / (float)(segm - 1); 1.47 - Vector2 v = curve->interpolate(t); 1.48 + Vector3 v = curve->interpolate(t); 1.49 glVertex2f(v.x, v.y); 1.50 } 1.51 glEnd(); 1.52 @@ -183,10 +197,23 @@ 1.53 glColor3f(0.2, 1.0, 0.2); 1.54 } 1.55 } 1.56 - Vector2 pt = curve->get_point(i); 1.57 + Vector2 pt = curve->get_point2(i); 1.58 glVertex2f(pt.x, pt.y); 1.59 } 1.60 glEnd(); 1.61 + 1.62 + // draw the projected mouse point on the selected curve 1.63 + /* 1.64 + if(curve == sel_curve) { 1.65 + Vector3 pp = curve->proj_point(Vector3(mouse_pointer.x, mouse_pointer.y, 0.0)); 1.66 + 1.67 + glPointSize(5.0); 1.68 + glBegin(GL_POINTS); 1.69 + glColor3f(1, 0.8, 0.2); 1.70 + glVertex2f(pp.x, pp.y); 1.71 + glEnd(); 1.72 + } 1.73 + */ 1.74 glPointSize(1.0); 1.75 } 1.76 1.77 @@ -218,38 +245,29 @@ 1.78 } 1.79 break; 1.80 1.81 - case 'l': 1.82 - case 'L': 1.83 + case '1': 1.84 + case '2': 1.85 + case '3': 1.86 if(sel_curve) { 1.87 - sel_curve->set_type(CURVE_LINEAR); 1.88 + sel_curve->set_type((CurveType)((int)CURVE_LINEAR + key - '1')); 1.89 post_redisplay(); 1.90 } 1.91 if(new_curve) { 1.92 - new_curve->set_type(CURVE_LINEAR); 1.93 + new_curve->set_type((CurveType)((int)CURVE_LINEAR + key - '1')); 1.94 post_redisplay(); 1.95 } 1.96 break; 1.97 1.98 case 'b': 1.99 case 'B': 1.100 - if(sel_curve) { 1.101 - sel_curve->set_type(CURVE_BSPLINE); 1.102 - post_redisplay(); 1.103 - } 1.104 - if(new_curve) { 1.105 - new_curve->set_type(CURVE_BSPLINE); 1.106 - post_redisplay(); 1.107 - } 1.108 + show_bounds = !show_bounds; 1.109 + post_redisplay(); 1.110 break; 1.111 1.112 - case 'h': 1.113 - case 'H': 1.114 + case 'n': 1.115 + case 'N': 1.116 if(sel_curve) { 1.117 - sel_curve->set_type(CURVE_HERMITE); 1.118 - post_redisplay(); 1.119 - } 1.120 - if(new_curve) { 1.121 - new_curve->set_type(CURVE_HERMITE); 1.122 + sel_curve->normalize(); 1.123 post_redisplay(); 1.124 } 1.125 break; 1.126 @@ -263,14 +281,19 @@ 1.127 printf("exported %d curves\n", (int)curves.size()); 1.128 break; 1.129 1.130 - case 'i': 1.131 - case 'I': 1.132 + case 'l': 1.133 + case 'L': 1.134 { 1.135 std::list<Curve*> clist = load_curves("test.curves"); 1.136 if(clist.empty()) { 1.137 fprintf(stderr, "failed to import curves\n"); 1.138 } 1.139 1.140 + for(size_t i=0; i<curves.size(); i++) { 1.141 + delete curves[i]; 1.142 + } 1.143 + curves.clear(); 1.144 + 1.145 int num = 0; 1.146 std::list<Curve*>::iterator it = clist.begin(); 1.147 while(it != clist.end()) { 1.148 @@ -279,6 +302,7 @@ 1.149 } 1.150 printf("imported %d curves\n", num); 1.151 } 1.152 + post_redisplay(); 1.153 break; 1.154 } 1.155 } 1.156 @@ -402,10 +426,8 @@ 1.157 if(!dx && !dy) return; 1.158 1.159 Vector2 uv = pixel_to_uv(x, y); 1.160 -#ifdef DRAW_MOUSE_POINTER 1.161 mouse_pointer = uv; 1.162 post_redisplay(); 1.163 -#endif 1.164 1.165 /* when entering a new curve, have the last (extra) point following 1.166 * the mouse until it's entered by a click (see on_click).
2.1 --- a/src/curve.cc Sat Dec 19 22:39:18 2015 +0200 2.2 +++ b/src/curve.cc Sun Dec 20 07:21:32 2015 +0200 2.3 @@ -1,10 +1,39 @@ 2.4 #include <float.h> 2.5 +#include <assert.h> 2.6 #include <algorithm> 2.7 #include "curve.h" 2.8 2.9 Curve::Curve(CurveType type) 2.10 { 2.11 this->type = type; 2.12 + bbvalid = true; 2.13 +} 2.14 + 2.15 +Curve::Curve(const Vector4 *cp, int numcp, CurveType type) 2.16 + : Curve(type) 2.17 +{ 2.18 + this->cp.resize(numcp); 2.19 + for(int i=0; i<numcp; i++) { 2.20 + this->cp[i] = cp[i]; 2.21 + } 2.22 +} 2.23 + 2.24 +Curve::Curve(const Vector3 *cp, int numcp, CurveType type) 2.25 + : Curve(type) 2.26 +{ 2.27 + this->cp.resize(numcp); 2.28 + for(int i=0; i<numcp; i++) { 2.29 + this->cp[i] = Vector4(cp[i].x, cp[i].y, cp[i].z, 1.0f); 2.30 + } 2.31 +} 2.32 + 2.33 +Curve::Curve(const Vector2 *cp, int numcp, CurveType type) 2.34 + : Curve(type) 2.35 +{ 2.36 + this->cp.resize(numcp); 2.37 + for(int i=0; i<numcp; i++) { 2.38 + this->cp[i] = Vector4(cp[i].x, cp[i].y, 0.0f, 1.0f); 2.39 + } 2.40 } 2.41 2.42 void Curve::set_type(CurveType type) 2.43 @@ -17,9 +46,20 @@ 2.44 return type; 2.45 } 2.46 2.47 +void Curve::add_point(const Vector4 &p) 2.48 +{ 2.49 + cp.push_back(p); 2.50 + inval_bounds(); 2.51 +} 2.52 + 2.53 +void Curve::add_point(const Vector3 &p, float weight) 2.54 +{ 2.55 + add_point(Vector4(p.x, p.y, p.z, weight)); 2.56 +} 2.57 + 2.58 void Curve::add_point(const Vector2 &p, float weight) 2.59 { 2.60 - cp.push_back(Vector3(p.x, p.y, weight)); 2.61 + add_point(Vector4(p.x, p.y, 0.0f, weight)); 2.62 } 2.63 2.64 bool Curve::remove_point(int idx) 2.65 @@ -28,23 +68,14 @@ 2.66 return false; 2.67 } 2.68 cp.erase(cp.begin() + idx); 2.69 + inval_bounds(); 2.70 return true; 2.71 } 2.72 2.73 -int Curve::nearest_point(const Vector2 &p) 2.74 +void Curve::clear() 2.75 { 2.76 - int res = -1; 2.77 - float bestsq = FLT_MAX; 2.78 - 2.79 - for(size_t i=0; i<cp.size(); i++) { 2.80 - float d = (get_point(i) - p).length_sq(); 2.81 - if(d < bestsq) { 2.82 - bestsq = d; 2.83 - res = i; 2.84 - } 2.85 - } 2.86 - 2.87 - return res; 2.88 + cp.clear(); 2.89 + inval_bounds(); 2.90 } 2.91 2.92 bool Curve::empty() const 2.93 @@ -57,29 +88,45 @@ 2.94 return (int)cp.size(); 2.95 } 2.96 2.97 -Vector3 &Curve::operator [](int idx) 2.98 +Vector4 &Curve::operator [](int idx) 2.99 +{ 2.100 + inval_bounds(); 2.101 + return cp[idx]; 2.102 +} 2.103 + 2.104 +const Vector4 &Curve::operator [](int idx) const 2.105 { 2.106 return cp[idx]; 2.107 } 2.108 2.109 -const Vector3 &Curve::operator [](int idx) const 2.110 +const Vector4 &Curve::get_point(int idx) const 2.111 { 2.112 return cp[idx]; 2.113 } 2.114 2.115 -const Vector3 &Curve::get_homo_point(int idx) const 2.116 +Vector3 Curve::get_point3(int idx) const 2.117 { 2.118 - return cp[idx]; 2.119 + return Vector3(cp[idx].x, cp[idx].y, cp[idx].z); 2.120 } 2.121 2.122 -Vector2 Curve::get_point(int idx) const 2.123 +Vector2 Curve::get_point2(int idx) const 2.124 { 2.125 return Vector2(cp[idx].x, cp[idx].y); 2.126 } 2.127 2.128 float Curve::get_weight(int idx) const 2.129 { 2.130 - return cp[idx].z; 2.131 + return cp[idx].w; 2.132 +} 2.133 + 2.134 +bool Curve::set_point(int idx, const Vector3 &p, float weight) 2.135 +{ 2.136 + if(idx < 0 || idx >= (int)cp.size()) { 2.137 + return false; 2.138 + } 2.139 + cp[idx] = Vector4(p.x, p.y, p.z, weight); 2.140 + inval_bounds(); 2.141 + return true; 2.142 } 2.143 2.144 bool Curve::set_point(int idx, const Vector2 &p, float weight) 2.145 @@ -87,7 +134,8 @@ 2.146 if(idx < 0 || idx >= (int)cp.size()) { 2.147 return false; 2.148 } 2.149 - cp[idx] = Vector3(p.x, p.y, weight); 2.150 + cp[idx] = Vector4(p.x, p.y, 0.0, weight); 2.151 + inval_bounds(); 2.152 return true; 2.153 } 2.154 2.155 @@ -96,7 +144,17 @@ 2.156 if(idx < 0 || idx >= (int)cp.size()) { 2.157 return false; 2.158 } 2.159 - cp[idx].z = weight; 2.160 + cp[idx].w = weight; 2.161 + return true; 2.162 +} 2.163 + 2.164 +bool Curve::move_point(int idx, const Vector3 &p) 2.165 +{ 2.166 + if(idx < 0 || idx >= (int)cp.size()) { 2.167 + return false; 2.168 + } 2.169 + cp[idx] = Vector4(p.x, p.y, p.z, cp[idx].w); 2.170 + inval_bounds(); 2.171 return true; 2.172 } 2.173 2.174 @@ -105,22 +163,207 @@ 2.175 if(idx < 0 || idx >= (int)cp.size()) { 2.176 return false; 2.177 } 2.178 - cp[idx] = Vector3(p.x, p.y, cp[idx].z); 2.179 + cp[idx] = Vector4(p.x, p.y, 0.0f, cp[idx].w); 2.180 + inval_bounds(); 2.181 return true; 2.182 } 2.183 2.184 -Vector2 Curve::interpolate(float t, CurveType type) const 2.185 + 2.186 +int Curve::nearest_point(const Vector3 &p) const 2.187 { 2.188 - if(cp.empty()) { 2.189 - return Vector2(0, 0); 2.190 + int res = -1; 2.191 + float bestsq = FLT_MAX; 2.192 + 2.193 + for(size_t i=0; i<cp.size(); i++) { 2.194 + float d = (get_point3(i) - p).length_sq(); 2.195 + if(d < bestsq) { 2.196 + bestsq = d; 2.197 + res = i; 2.198 + } 2.199 + } 2.200 + return res; 2.201 +} 2.202 + 2.203 +int Curve::nearest_point(const Vector2 &p) const 2.204 +{ 2.205 + int res = -1; 2.206 + float bestsq = FLT_MAX; 2.207 + 2.208 + for(size_t i=0; i<cp.size(); i++) { 2.209 + float d = (get_point2(i) - p).length_sq(); 2.210 + if(d < bestsq) { 2.211 + bestsq = d; 2.212 + res = i; 2.213 + } 2.214 + } 2.215 + return res; 2.216 +} 2.217 + 2.218 + 2.219 +void Curve::inval_bounds() const 2.220 +{ 2.221 + bbvalid = false; 2.222 +} 2.223 + 2.224 +void Curve::calc_bounds() const 2.225 +{ 2.226 + calc_bbox(&bbmin, &bbmax); 2.227 + bbvalid = true; 2.228 +} 2.229 + 2.230 +void Curve::get_bbox(Vector3 *bbmin, Vector3 *bbmax) const 2.231 +{ 2.232 + if(!bbvalid) { 2.233 + calc_bounds(); 2.234 + } 2.235 + *bbmin = this->bbmin; 2.236 + *bbmax = this->bbmax; 2.237 +} 2.238 + 2.239 +void Curve::calc_bbox(Vector3 *bbmin, Vector3 *bbmax) const 2.240 +{ 2.241 + if(empty()) { 2.242 + *bbmin = *bbmax = Vector3(0, 0, 0); 2.243 + return; 2.244 + } 2.245 + 2.246 + Vector3 bmin = cp[0]; 2.247 + Vector3 bmax = bmin; 2.248 + for(size_t i=1; i<cp.size(); i++) { 2.249 + const Vector4 &v = cp[i]; 2.250 + for(int j=0; j<3; j++) { 2.251 + if(v[j] < bmin[j]) bmin[j] = v[j]; 2.252 + if(v[j] > bmax[j]) bmax[j] = v[j]; 2.253 + } 2.254 + } 2.255 + *bbmin = bmin; 2.256 + *bbmax = bmax; 2.257 +} 2.258 + 2.259 +void Curve::normalize() 2.260 +{ 2.261 + if(!bbvalid) { 2.262 + calc_bounds(); 2.263 + } 2.264 + 2.265 + Vector3 bsize = bbmax - bbmin; 2.266 + Vector3 boffs = (bbmin + bbmax) * 0.5; 2.267 + 2.268 + Vector3 bscale; 2.269 + bscale.x = bsize.x == 0.0f ? 1.0f : 1.0f / bsize.x; 2.270 + bscale.y = bsize.y == 0.0f ? 1.0f : 1.0f / bsize.y; 2.271 + bscale.z = bsize.z == 0.0f ? 1.0f : 1.0f / bsize.z; 2.272 + 2.273 + for(size_t i=0; i<cp.size(); i++) { 2.274 + cp[i].x = (cp[i].x - boffs.x) * bscale.x; 2.275 + cp[i].y = (cp[i].y - boffs.y) * bscale.y; 2.276 + cp[i].z = (cp[i].z - boffs.z) * bscale.z; 2.277 + } 2.278 + inval_bounds(); 2.279 +} 2.280 + 2.281 +/* Projection to the curve is not correct, but should be good enough for 2.282 + * most purposes. 2.283 + * 2.284 + * First we find the nearest segment (pair of control points), and then 2.285 + * we subdivide between them to find the nearest interpolated point in that 2.286 + * segment. 2.287 + * The incorrect assumption here is that the nearest segment as defined by 2.288 + * the distance of its control points to p, will contain the nearest point 2.289 + * on the curve. This only holds for polylines, and *possibly* bsplines, but 2.290 + * certainly not hermite splines. 2.291 + */ 2.292 +Vector3 Curve::proj_point(const Vector3 &p) const 2.293 +{ 2.294 + // TODO fix: select nearest segment based on point-line distance, not distance from the CPs 2.295 + int num_cp = size(); 2.296 + if(num_cp <= 0) return p; 2.297 + if(num_cp == 1) return cp[0]; 2.298 + 2.299 + int idx0 = nearest_point(p); 2.300 + int next_idx = idx0 + 1; 2.301 + int prev_idx = idx0 - 1; 2.302 + 2.303 + float next_distsq = next_idx >= num_cp ? FLT_MAX : (get_point3(next_idx) - p).length_sq(); 2.304 + float prev_distsq = prev_idx < 0 ? FLT_MAX : (get_point3(prev_idx) - p).length_sq(); 2.305 + int idx1 = next_distsq < prev_distsq ? next_idx : prev_idx; 2.306 + assert(idx1 >= 0 && idx1 < num_cp - 1); 2.307 + if(idx0 > idx1) std::swap(idx0, idx1); 2.308 + 2.309 + float t0 = 0.0f, t1 = 1.0f; 2.310 + Vector3 pp0 = interpolate_segment(idx0, idx1, 0.0f); 2.311 + Vector3 pp1 = interpolate_segment(idx0, idx1, 1.0f); 2.312 + float dist0 = (pp0 - p).length_sq(); 2.313 + float dist1 = (pp1 - p).length_sq(); 2.314 + Vector3 pp; 2.315 + 2.316 + for(int i=0; i<32; i++) { // max iterations 2.317 + float t = (t0 + t1) / 2.0; 2.318 + pp = interpolate_segment(idx0, idx1, t); 2.319 + float dist = (pp - p).length_sq(); 2.320 + 2.321 + // mid point more distant than both control points, nearest cp is closest 2.322 + if(dist > dist0 && dist > dist1) { 2.323 + pp = dist0 < dist1 ? pp0 : pp1; 2.324 + break; 2.325 + } 2.326 + 2.327 + if(dist0 < dist1) { 2.328 + t1 = t; 2.329 + dist1 = dist; 2.330 + pp1 = pp; 2.331 + } else { 2.332 + t0 = t; 2.333 + dist0 = dist; 2.334 + pp0 = pp; 2.335 + } 2.336 + 2.337 + if(fabs(dist0 - dist1) < 1e-4) { 2.338 + break; 2.339 + } 2.340 + } 2.341 + return pp; 2.342 +} 2.343 + 2.344 +Vector3 Curve::interpolate_segment(int a, int b, float t) const 2.345 +{ 2.346 + int num_cp = size(); 2.347 + 2.348 + if(t < 0.0) t = 0.0; 2.349 + if(t > 1.0) t = 1.0; 2.350 + 2.351 + Vector4 res; 2.352 + if(type == CURVE_LINEAR || num_cp == 2) { 2.353 + res = lerp(cp[a], cp[b], t); 2.354 + } else { 2.355 + int prev = a <= 0 ? a : a - 1; 2.356 + int next = b >= num_cp - 1 ? b : b + 1; 2.357 + 2.358 + if(type == CURVE_HERMITE) { 2.359 + res = catmull_rom_spline(cp[prev], cp[a], cp[b], cp[next], t); 2.360 + } else { 2.361 + res = bspline(cp[prev], cp[a], cp[b], cp[next], t); 2.362 + if(res.w != 0.0f) { 2.363 + res.x /= res.w; 2.364 + res.y /= res.w; 2.365 + } 2.366 + } 2.367 + } 2.368 + 2.369 + return Vector3(res.x, res.y, res.z); 2.370 +} 2.371 + 2.372 +Vector3 Curve::interpolate(float t) const 2.373 +{ 2.374 + if(empty()) { 2.375 + return Vector3(0, 0, 0); 2.376 } 2.377 2.378 int num_cp = (int)cp.size(); 2.379 if(num_cp == 1) { 2.380 - return Vector2(cp[0].x, cp[0].y); 2.381 + return Vector3(cp[0].x, cp[0].y, cp[0].z); 2.382 } 2.383 2.384 - Vector3 res; 2.385 int idx0 = std::min((int)floor(t * (num_cp - 1)), num_cp - 2); 2.386 int idx1 = idx0 + 1; 2.387 2.388 @@ -129,35 +372,17 @@ 2.389 float t1 = (float)idx1 * dt; 2.390 2.391 t = (t - t0) / (t1 - t0); 2.392 - if(t < 0.0) t = 0.0; 2.393 - if(t > 1.0) t = 1.0; 2.394 2.395 - if(type == CURVE_LINEAR || num_cp <= 2) { 2.396 - res = lerp(cp[idx0], cp[idx1], t); 2.397 - } else { 2.398 - int idx_prev = idx0 <= 0 ? idx0 : idx0 - 1; 2.399 - int idx_next = idx1 >= num_cp - 1 ? idx1 : idx1 + 1; 2.400 + return interpolate_segment(idx0, idx1, t); 2.401 +} 2.402 2.403 - if(type == CURVE_HERMITE) { 2.404 - res = catmull_rom_spline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t); 2.405 - } else { 2.406 - res = bspline(cp[idx_prev], cp[idx0], cp[idx1], cp[idx_next], t); 2.407 - if(res.z != 0.0f) { 2.408 - res.x /= res.z; 2.409 - res.y /= res.z; 2.410 - } 2.411 - } 2.412 - } 2.413 - 2.414 +Vector2 Curve::interpolate2(float t) const 2.415 +{ 2.416 + Vector3 res = interpolate(t); 2.417 return Vector2(res.x, res.y); 2.418 } 2.419 2.420 -Vector2 Curve::interpolate(float t) const 2.421 -{ 2.422 - return interpolate(t, type); 2.423 -} 2.424 - 2.425 -Vector2 Curve::operator ()(float t) const 2.426 +Vector3 Curve::operator ()(float t) const 2.427 { 2.428 return interpolate(t); 2.429 }
3.1 --- a/src/curve.h Sat Dec 19 22:39:18 2015 +0200 3.2 +++ b/src/curve.h Sun Dec 20 07:21:32 2015 +0200 3.3 @@ -12,37 +12,72 @@ 3.4 3.5 class Curve { 3.6 private: 3.7 - std::vector<Vector3> cp; 3.8 + std::vector<Vector4> cp; 3.9 CurveType type; 3.10 3.11 + // bounding box 3.12 + mutable Vector3 bbmin, bbmax; 3.13 + mutable bool bbvalid; 3.14 + 3.15 + void calc_bounds() const; 3.16 + void inval_bounds() const; 3.17 + 3.18 public: 3.19 Curve(CurveType type = CURVE_HERMITE); 3.20 + Curve(const Vector4 *cp, int numcp, CurveType type = CURVE_HERMITE); // homogenous 3.21 + Curve(const Vector3 *cp, int numcp, CurveType type = CURVE_HERMITE); // 3D points, w=1 3.22 + Curve(const Vector2 *cp, int numcp, CurveType type = CURVE_HERMITE); // 2D points, z=0, w=1 3.23 3.24 void set_type(CurveType type); 3.25 CurveType get_type() const; 3.26 3.27 + void add_point(const Vector4 &p); 3.28 + void add_point(const Vector3 &p, float weight = 1.0f); 3.29 void add_point(const Vector2 &p, float weight = 1.0f); 3.30 bool remove_point(int idx); 3.31 3.32 - int nearest_point(const Vector2 &p); 3.33 + void clear(); // remove all control points 3.34 + bool empty() const; // true if 0 control points 3.35 + int size() const; // returns number of control points 3.36 + // access operators for control points 3.37 + Vector4 &operator [](int idx); 3.38 + const Vector4 &operator [](int idx) const; 3.39 + const Vector4 &get_point(int idx) const; 3.40 3.41 - bool empty() const; 3.42 - int size() const; 3.43 - Vector3 &operator [](int idx); 3.44 - const Vector3 &operator [](int idx) const; 3.45 - 3.46 - const Vector3 &get_homo_point(int idx) const; // homogeneous point 3.47 - Vector2 get_point(int idx) const; 3.48 + Vector3 get_point3(int idx) const; 3.49 + Vector2 get_point2(int idx) const; 3.50 float get_weight(int idx) const; 3.51 3.52 + bool set_point(int idx, const Vector3 &p, float weight = 1.0f); 3.53 bool set_point(int idx, const Vector2 &p, float weight = 1.0f); 3.54 bool set_weight(int idx, float weight); 3.55 // move point without changing its weight 3.56 + bool move_point(int idx, const Vector3 &p); 3.57 bool move_point(int idx, const Vector2 &p); 3.58 + 3.59 + int nearest_point(const Vector3 &p) const; 3.60 + // nearest control point on the 2D plane z=0 3.61 + int nearest_point(const Vector2 &p) const; 3.62 3.63 - Vector2 interpolate(float t, CurveType type) const; 3.64 - Vector2 interpolate(float t) const; 3.65 - Vector2 operator ()(float t) const; 3.66 + /* get_bbox returns the axis-aligned bounding box of the curve's 3.67 + * control points. 3.68 + * NOTE: hermite curves can go outside of the bounding box of their control points 3.69 + * NOTE: lazy calculation of bounds is performed, use calc_bbox in multithreaded programs 3.70 + */ 3.71 + void get_bbox(Vector3 *bbmin, Vector3 *bbmax) const; 3.72 + void calc_bbox(Vector3 *bbmin, Vector3 *bbmax) const; 3.73 + // normalize the curve's bounds to coincide with the unit cube 3.74 + void normalize(); 3.75 + 3.76 + // project a point to the curve (nearest point on the curve) 3.77 + Vector3 proj_point(const Vector3 &p) const; 3.78 + // equivalent to (proj_point(p) - p).length(); 3.79 + float distance(const Vector3 &p) const; 3.80 + 3.81 + Vector3 interpolate_segment(int a, int b, float t) const; 3.82 + Vector3 interpolate(float t) const; 3.83 + Vector2 interpolate2(float t) const; 3.84 + Vector3 operator ()(float t) const; 3.85 }; 3.86 3.87 #endif // CURVE_H_
4.1 --- a/src/curvefile.cc Sat Dec 19 22:39:18 2015 +0200 4.2 +++ b/src/curvefile.cc Sun Dec 20 07:21:32 2015 +0200 4.3 @@ -46,8 +46,8 @@ 4.4 fprintf(fp, " type %s\n", curve_type_str(curve->get_type())); 4.5 fprintf(fp, " cpcount %d\n", curve->size()); 4.6 for(int i=0; i<curve->size(); i++) { 4.7 - Vector3 cp = curve->get_homo_point(i); 4.8 - fprintf(fp, " cp %g %g %g\n", cp.x, cp.y, cp.z); 4.9 + Vector4 cp = curve->get_point(i); 4.10 + fprintf(fp, " cp %g %g %g %g\n", cp.x, cp.y, cp.z, cp.w); 4.11 } 4.12 fprintf(fp, "}\n"); 4.13 return true; 4.14 @@ -83,8 +83,6 @@ 4.15 } 4.16 s.push_back(c); 4.17 } 4.18 - 4.19 - printf("TOKEN: \"%s\"\n", s.c_str()); 4.20 return s; 4.21 } 4.22 4.23 @@ -159,13 +157,13 @@ 4.24 if(tok != "cp") { 4.25 goto err; 4.26 } 4.27 - Vector3 cp; 4.28 - for(int i=0; i<3; i++) { 4.29 + Vector4 cp; 4.30 + for(int i=0; i<4; i++) { 4.31 if(!expect_float(fp, &cp[i])) { 4.32 goto err; 4.33 } 4.34 } 4.35 - curve->add_point(Vector2(cp.x, cp.y), cp.z); 4.36 + curve->add_point(Vector3(cp.x, cp.y, cp.z), cp.w); 4.37 } 4.38 } 4.39