Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_trajectory.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
43#include <math.h>
44
50static double hermite_h00(double s) {
51 return 2.0 * s * s * s - 3.0 * s * s + 1.0;
52}
53
59static double hermite_h10(double s) {
60 return s * s * s - 2.0 * s * s + s;
61}
62
68static double hermite_h01(double s) {
69 return -2.0 * s * s * s + 3.0 * s * s;
70}
71
77static double hermite_h11(double s) {
78 return s * s * s - s * s;
79}
80
86static double hermite_dh00(double s) {
87 return 6.0 * s * s - 6.0 * s;
88}
89
95static double hermite_dh10(double s) {
96 return 3.0 * s * s - 4.0 * s + 1.0;
97}
98
104static double hermite_dh01(double s) {
105 return -6.0 * s * s + 6.0 * s;
106}
107
113static double hermite_dh11(double s) {
114 return 3.0 * s * s - 2.0 * s;
115}
116
122static double hermite_d2h00(double s) {
123 return 12.0 * s - 6.0;
124}
125
131static double hermite_d2h10(double s) {
132 return 6.0 * s - 4.0;
133}
134
140static double hermite_d2h01(double s) {
141 return -12.0 * s + 6.0;
142}
143
149static double hermite_d2h11(double s) {
150 return 6.0 * s - 2.0;
151}
152
159 for (int i = 0; i < traj->nb_components; i++) {
160 traj->m0[i] = traj->start.speed[i] * traj->duration;
161 traj->m1[i] = traj->end.speed[i] * traj->duration;
162 traj->m0_orient[i] = traj->start.angular_speed[i] * traj->duration;
163 traj->m1_orient[i] = traj->end.angular_speed[i] * traj->duration;
164 }
165}
166
174static void trajectory_load_segment(TRAJECTORY* traj, double time_val) {
175 if (traj->nb_points < 2) return;
176
177 int seg = traj->current_segment;
178 if (seg < 0) seg = 0;
179
180 /* search forward from current segment */
181 while (seg < traj->nb_points - 2 &&
182 time_val >= traj->points[seg + 1].time_val) {
183 seg++;
184 }
185 /* search backward if needed */
186 while (seg > 0 && time_val < traj->points[seg].time_val) {
187 seg--;
188 }
189
190 if (seg != traj->current_segment) {
191 traj->current_segment = seg;
192 memcpy(&traj->start, &traj->points[seg].state, sizeof(PHYSICS));
193 memcpy(&traj->end, &traj->points[seg + 1].state, sizeof(PHYSICS));
194 traj->start_time = traj->points[seg].time_val;
195 traj->end_time = traj->points[seg + 1].time_val;
196 traj->duration = traj->end_time - traj->start_time;
198 }
199}
200
206TRAJECTORY* trajectory_new(int nb_components) {
207 if (nb_components != TRAJECTORY_2D && nb_components != TRAJECTORY_3D) {
208 n_log(LOG_ERR, "nb_components must be TRAJECTORY_2D (2) or TRAJECTORY_3D (3), got %d", nb_components);
209 return NULL;
210 }
211
212 TRAJECTORY* traj = NULL;
213 Malloc(traj, TRAJECTORY, 1);
214 __n_assert(traj, return NULL);
215
216 traj->nb_components = nb_components;
217 traj->mode = TRAJECTORY_BEFORE;
218 traj->start_time = 0.0;
219 traj->end_time = 0.0;
220 traj->duration = 0.0;
221 traj->current_time = 0.0;
222 traj->points = NULL;
223 traj->nb_points = 0;
224 traj->nb_points_allocated = 0;
225 traj->current_segment = -1;
226
227 return traj;
228} /* trajectory_new() */
229
235 __n_assert(traj, return);
236 Free((*traj)->points);
237 Free((*traj));
238} /* trajectory_delete() */
239
247int trajectory_set_start(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
248 __n_assert(traj, return FALSE);
249 __n_assert(state, return FALSE);
250
251 memcpy(&traj->start, state, sizeof(PHYSICS));
252 traj->start_time = time_val;
253 traj->duration = traj->end_time - traj->start_time;
254
255 if (traj->duration > 0.0) {
257 }
258
259 return TRUE;
260} /* trajectory_set_start() */
261
270int trajectory_set_end(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
271 __n_assert(traj, return FALSE);
272 __n_assert(state, return FALSE);
273
274 memcpy(&traj->end, state, sizeof(PHYSICS));
275 traj->end_time = time_val;
276 traj->duration = traj->end_time - traj->start_time;
277
278 if (traj->duration <= 0.0) {
279 n_log(LOG_ERR, "end_time (%g) must be greater than start_time (%g)", time_val, traj->start_time);
280 return FALSE;
281 }
282
284
285 return TRUE;
286} /* trajectory_set_end() */
287
298int trajectory_update(TRAJECTORY* traj, const PHYSICS* new_end, double time_val) {
299 __n_assert(traj, return FALSE);
300 __n_assert(new_end, return FALSE);
301
302 if (time_val <= traj->end_time) {
303 n_log(LOG_ERR, "new time (%g) must be greater than current end_time (%g)", time_val, traj->end_time);
304 return FALSE;
305 }
306
307 /* shift: old end becomes new start */
308 memcpy(&traj->start, &traj->end, sizeof(PHYSICS));
309 traj->start_time = traj->end_time;
310
311 /* set new end */
312 memcpy(&traj->end, new_end, sizeof(PHYSICS));
313 traj->end_time = time_val;
314 traj->duration = traj->end_time - traj->start_time;
315
317
318 return TRUE;
319} /* trajectory_update() */
320
329int trajectory_compute(TRAJECTORY* traj, double time_val) {
330 __n_assert(traj, return FALSE);
331
332 trajectory_load_segment(traj, time_val);
333 traj->current_time = time_val;
334 int nc = traj->nb_components;
335
336 if (traj->duration <= 0.0) {
337 /* no valid interval: just copy start state */
338 memcpy(&traj->current, &traj->start, sizeof(PHYSICS));
339 traj->mode = TRAJECTORY_BEFORE;
340 return TRUE;
341 }
342
343 if (time_val < traj->start_time) {
344 /* before start: quadratic extrapolation backward from start state */
345 traj->mode = TRAJECTORY_BEFORE;
346 double dt = time_val - traj->start_time; /* negative */
347 for (int i = 0; i < nc; i++) {
348 traj->current.position[i] = traj->start.position[i] + traj->start.speed[i] * dt + 0.5 * traj->start.acceleration[i] * dt * dt;
349 traj->current.speed[i] = traj->start.speed[i] + traj->start.acceleration[i] * dt;
350 traj->current.acceleration[i] = traj->start.acceleration[i];
351 traj->current.orientation[i] = traj->start.orientation[i] + traj->start.angular_speed[i] * dt + 0.5 * traj->start.angular_acceleration[i] * dt * dt;
352 traj->current.angular_speed[i] = traj->start.angular_speed[i] + traj->start.angular_acceleration[i] * dt;
354 }
355 } else if (time_val > traj->end_time) {
356 /* after end: quadratic extrapolation forward from end state */
357 traj->mode = TRAJECTORY_EXTRAP;
358 double dt = time_val - traj->end_time;
359 for (int i = 0; i < nc; i++) {
360 traj->current.position[i] = traj->end.position[i] + traj->end.speed[i] * dt + 0.5 * traj->end.acceleration[i] * dt * dt;
361 traj->current.speed[i] = traj->end.speed[i] + traj->end.acceleration[i] * dt;
362 traj->current.acceleration[i] = traj->end.acceleration[i];
363 traj->current.orientation[i] = traj->end.orientation[i] + traj->end.angular_speed[i] * dt + 0.5 * traj->end.angular_acceleration[i] * dt * dt;
364 traj->current.angular_speed[i] = traj->end.angular_speed[i] + traj->end.angular_acceleration[i] * dt;
366 }
367 } else {
368 /* within interval: cubic Hermite spline interpolation */
369 traj->mode = TRAJECTORY_INTERP;
370 double s = (time_val - traj->start_time) / traj->duration;
371
372 /* Hermite basis function values */
373 double h00 = hermite_h00(s);
374 double h10 = hermite_h10(s);
375 double h01 = hermite_h01(s);
376 double h11 = hermite_h11(s);
377
378 /* first derivatives for velocity */
379 double dh00 = hermite_dh00(s);
380 double dh10 = hermite_dh10(s);
381 double dh01 = hermite_dh01(s);
382 double dh11 = hermite_dh11(s);
383
384 /* second derivatives for acceleration */
385 double d2h00 = hermite_d2h00(s);
386 double d2h10 = hermite_d2h10(s);
387 double d2h01 = hermite_d2h01(s);
388 double d2h11 = hermite_d2h11(s);
389
390 double inv_dur = 1.0 / traj->duration;
391 double inv_dur2 = inv_dur * inv_dur;
392
393 for (int i = 0; i < nc; i++) {
394 /* position: P(s) = h00*P0 + h10*M0 + h01*P1 + h11*M1 */
395 traj->current.position[i] = h00 * traj->start.position[i] + h10 * traj->m0[i] + h01 * traj->end.position[i] + h11 * traj->m1[i];
396
397 /* velocity: V(t) = P'(s) / duration */
398 traj->current.speed[i] = (dh00 * traj->start.position[i] + dh10 * traj->m0[i] + dh01 * traj->end.position[i] + dh11 * traj->m1[i]) * inv_dur;
399
400 /* acceleration: A(t) = P''(s) / duration^2 */
401 traj->current.acceleration[i] = (d2h00 * traj->start.position[i] + d2h10 * traj->m0[i] + d2h01 * traj->end.position[i] + d2h11 * traj->m1[i]) * inv_dur2;
402
403 /* orientation: same Hermite approach */
404 traj->current.orientation[i] = h00 * traj->start.orientation[i] + h10 * traj->m0_orient[i] + h01 * traj->end.orientation[i] + h11 * traj->m1_orient[i];
405
406 /* angular speed: derivative of orientation spline / duration */
407 traj->current.angular_speed[i] = (dh00 * traj->start.orientation[i] + dh10 * traj->m0_orient[i] + dh01 * traj->end.orientation[i] + dh11 * traj->m1_orient[i]) * inv_dur;
408
409 /* angular acceleration: second derivative / duration^2 */
410 traj->current.angular_acceleration[i] = (d2h00 * traj->start.orientation[i] + d2h10 * traj->m0_orient[i] + d2h01 * traj->end.orientation[i] + d2h11 * traj->m1_orient[i]) * inv_dur2;
411 }
412 }
413
414 /* zero out unused components for safety */
415 for (int i = nc; i < 3; i++) {
416 traj->current.position[i] = 0.0;
417 traj->current.speed[i] = 0.0;
418 traj->current.acceleration[i] = 0.0;
419 traj->current.orientation[i] = 0.0;
420 traj->current.angular_speed[i] = 0.0;
421 traj->current.angular_acceleration[i] = 0.0;
422 }
423
424 return TRUE;
425} /* trajectory_compute() */
426
435int trajectory_get_position(TRAJECTORY* traj, double time_val, VECTOR3D out) {
436 __n_assert(traj, return FALSE);
437 __n_assert(out, return FALSE);
438
439 trajectory_load_segment(traj, time_val);
440 int nc = traj->nb_components;
441
442 if (traj->duration <= 0.0) {
443 for (int i = 0; i < nc; i++) out[i] = traj->start.position[i];
444 for (int i = nc; i < 3; i++) out[i] = 0.0;
445 return TRUE;
446 }
447
448 if (time_val < traj->start_time) {
449 double dt = time_val - traj->start_time;
450 for (int i = 0; i < nc; i++) {
451 out[i] = traj->start.position[i] + traj->start.speed[i] * dt + 0.5 * traj->start.acceleration[i] * dt * dt;
452 }
453 } else if (time_val > traj->end_time) {
454 double dt = time_val - traj->end_time;
455 for (int i = 0; i < nc; i++) {
456 out[i] = traj->end.position[i] + traj->end.speed[i] * dt + 0.5 * traj->end.acceleration[i] * dt * dt;
457 }
458 } else {
459 double s = (time_val - traj->start_time) / traj->duration;
460 double h00 = hermite_h00(s);
461 double h10 = hermite_h10(s);
462 double h01 = hermite_h01(s);
463 double h11 = hermite_h11(s);
464 for (int i = 0; i < nc; i++) {
465 out[i] = h00 * traj->start.position[i] + h10 * traj->m0[i] + h01 * traj->end.position[i] + h11 * traj->m1[i];
466 }
467 }
468
469 for (int i = nc; i < 3; i++) out[i] = 0.0;
470 return TRUE;
471} /* trajectory_get_position() */
472
480int trajectory_get_speed(TRAJECTORY* traj, double time_val, VECTOR3D out) {
481 __n_assert(traj, return FALSE);
482 __n_assert(out, return FALSE);
483
484 trajectory_load_segment(traj, time_val);
485 int nc = traj->nb_components;
486
487 if (traj->duration <= 0.0) {
488 for (int i = 0; i < nc; i++) out[i] = traj->start.speed[i];
489 for (int i = nc; i < 3; i++) out[i] = 0.0;
490 return TRUE;
491 }
492
493 if (time_val < traj->start_time) {
494 double dt = time_val - traj->start_time;
495 for (int i = 0; i < nc; i++) {
496 out[i] = traj->start.speed[i] + traj->start.acceleration[i] * dt;
497 }
498 } else if (time_val > traj->end_time) {
499 double dt = time_val - traj->end_time;
500 for (int i = 0; i < nc; i++) {
501 out[i] = traj->end.speed[i] + traj->end.acceleration[i] * dt;
502 }
503 } else {
504 double s = (time_val - traj->start_time) / traj->duration;
505 double inv_dur = 1.0 / traj->duration;
506 double dh00 = hermite_dh00(s);
507 double dh10 = hermite_dh10(s);
508 double dh01 = hermite_dh01(s);
509 double dh11 = hermite_dh11(s);
510 for (int i = 0; i < nc; i++) {
511 out[i] = (dh00 * traj->start.position[i] + dh10 * traj->m0[i] + dh01 * traj->end.position[i] + dh11 * traj->m1[i]) * inv_dur;
512 }
513 }
514
515 for (int i = nc; i < 3; i++) out[i] = 0.0;
516 return TRUE;
517} /* trajectory_get_speed() */
518
526int trajectory_get_acceleration(TRAJECTORY* traj, double time_val, VECTOR3D out) {
527 __n_assert(traj, return FALSE);
528 __n_assert(out, return FALSE);
529
530 trajectory_load_segment(traj, time_val);
531 int nc = traj->nb_components;
532
533 if (traj->duration <= 0.0) {
534 for (int i = 0; i < nc; i++) out[i] = traj->start.acceleration[i];
535 for (int i = nc; i < 3; i++) out[i] = 0.0;
536 return TRUE;
537 }
538
539 if (time_val < traj->start_time || time_val > traj->end_time) {
540 /* extrapolation: constant acceleration from nearest endpoint */
541 PHYSICS* ref = (time_val < traj->start_time) ? &traj->start : &traj->end;
542 for (int i = 0; i < nc; i++) {
543 out[i] = ref->acceleration[i];
544 }
545 } else {
546 double s = (time_val - traj->start_time) / traj->duration;
547 double inv_dur2 = 1.0 / (traj->duration * traj->duration);
548 double d2h00 = hermite_d2h00(s);
549 double d2h10 = hermite_d2h10(s);
550 double d2h01 = hermite_d2h01(s);
551 double d2h11 = hermite_d2h11(s);
552 for (int i = 0; i < nc; i++) {
553 out[i] = (d2h00 * traj->start.position[i] + d2h10 * traj->m0[i] + d2h01 * traj->end.position[i] + d2h11 * traj->m1[i]) * inv_dur2;
554 }
555 }
556
557 for (int i = nc; i < 3; i++) out[i] = 0.0;
558 return TRUE;
559} /* trajectory_get_acceleration() */
560
568int trajectory_get_orientation(TRAJECTORY* traj, double time_val, VECTOR3D out) {
569 __n_assert(traj, return FALSE);
570 __n_assert(out, return FALSE);
571
572 trajectory_load_segment(traj, time_val);
573 int nc = traj->nb_components;
574
575 if (traj->duration <= 0.0) {
576 for (int i = 0; i < nc; i++) out[i] = traj->start.orientation[i];
577 for (int i = nc; i < 3; i++) out[i] = 0.0;
578 return TRUE;
579 }
580
581 if (time_val < traj->start_time) {
582 double dt = time_val - traj->start_time;
583 for (int i = 0; i < nc; i++) {
584 out[i] = traj->start.orientation[i] + traj->start.angular_speed[i] * dt + 0.5 * traj->start.angular_acceleration[i] * dt * dt;
585 }
586 } else if (time_val > traj->end_time) {
587 double dt = time_val - traj->end_time;
588 for (int i = 0; i < nc; i++) {
589 out[i] = traj->end.orientation[i] + traj->end.angular_speed[i] * dt + 0.5 * traj->end.angular_acceleration[i] * dt * dt;
590 }
591 } else {
592 double s = (time_val - traj->start_time) / traj->duration;
593 double h00 = hermite_h00(s);
594 double h10 = hermite_h10(s);
595 double h01 = hermite_h01(s);
596 double h11 = hermite_h11(s);
597 for (int i = 0; i < nc; i++) {
598 out[i] = h00 * traj->start.orientation[i] + h10 * traj->m0_orient[i] + h01 * traj->end.orientation[i] + h11 * traj->m1_orient[i];
599 }
600 }
601
602 for (int i = nc; i < 3; i++) out[i] = 0.0;
603 return TRUE;
604} /* trajectory_get_orientation() */
605
616int trajectory_add_point(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
617 __n_assert(traj, return FALSE);
618 __n_assert(state, return FALSE);
619
620 /* enforce chronological order */
621 if (traj->nb_points > 0 && time_val <= traj->points[traj->nb_points - 1].time_val) {
622 n_log(LOG_ERR, "time_val (%g) must be greater than last point time (%g)",
623 time_val, traj->points[traj->nb_points - 1].time_val);
624 return FALSE;
625 }
626
627 /* grow array if needed */
628 if (traj->nb_points >= traj->nb_points_allocated) {
629 int new_size = (traj->nb_points_allocated == 0) ? 8 : traj->nb_points_allocated * 2;
630 if (!Realloc(traj->points, TRAJECTORY_POINT, (size_t)new_size)) {
631 return FALSE;
632 }
633 traj->nb_points_allocated = new_size;
634 }
635
636 memcpy(&traj->points[traj->nb_points].state, state, sizeof(PHYSICS));
637 traj->points[traj->nb_points].time_val = time_val;
638 traj->nb_points++;
639
640 /* when we reach 2 points, load the first segment */
641 if (traj->nb_points == 2) {
642 traj->current_segment = -1; /* force reload */
644 }
645
646 return TRUE;
647} /* trajectory_add_point() */
648
656 __n_assert(traj, return FALSE);
657
658 traj->nb_points = 0;
659 traj->current_segment = -1;
660 memset(&traj->start, 0, sizeof(PHYSICS));
661 memset(&traj->end, 0, sizeof(PHYSICS));
662 traj->start_time = 0.0;
663 traj->end_time = 0.0;
664 traj->duration = 0.0;
665
666 return TRUE;
667} /* trajectory_clear_points() */
668
678double trajectory_distance(TRAJECTORY* traj, double time_a, double time_b, int steps) {
679 __n_assert(traj, return -1.0);
680
681 if (steps < 1) steps = 1;
682
683 double dist = 0.0;
684 double dt = (time_b - time_a) / (double)steps;
685 VECTOR3D prev, curr;
686 int nc = traj->nb_components;
687
688 trajectory_get_position(traj, time_a, prev);
689
690 for (int step = 1; step <= steps; step++) {
691 double t = time_a + dt * (double)step;
692 trajectory_get_position(traj, t, curr);
693
694 double seg = 0.0;
695 for (int i = 0; i < nc; i++) {
696 double d = curr[i] - prev[i];
697 seg += d * d;
698 }
699 dist += sqrt(seg);
700
701 for (int i = 0; i < 3; i++) prev[i] = curr[i];
702 }
703
704 return dist;
705} /* trajectory_distance() */
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define Realloc(__ptr, __struct, __size)
Realloc Handler to get errors.
Definition n_common.h:230
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:262
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_ERR
error conditions
Definition n_log.h:75
VECTOR3D speed
vx,vy,vz actual speed
Definition n_3d.h:75
VECTOR3D orientation
ax,ay,az actual rotation position
Definition n_3d.h:79
VECTOR3D position
x,y,z actual position
Definition n_3d.h:73
VECTOR3D acceleration
ax,ay,az actual acceleration
Definition n_3d.h:77
VECTOR3D angular_acceleration
rax,ray,raz actual angular acceleration
Definition n_3d.h:83
VECTOR3D angular_speed
rvx,rvy,rvz actual angular speed
Definition n_3d.h:81
double VECTOR3D[3]
struct of a point
Definition n_3d.h:58
structure of the physics of an object
Definition n_3d.h:69
VECTOR3D m0_orient
Hermite tangent at start for orientation (start.angular_speed * duration)
PHYSICS current
current computed state at current_time
VECTOR3D m0
Hermite tangent at start for position (start.speed * duration)
VECTOR3D m1_orient
Hermite tangent at end for orientation (end.angular_speed * duration)
int nb_points_allocated
allocated capacity of the points array
int nb_points
number of waypoints in the points array
double current_time
last computed time
PHYSICS end
state at trajectory end (terminal known state)
double time_val
timestamp of this waypoint
double duration
duration = end_time - start_time
TRAJECTORY_POINT * points
array of waypoints for multi-point paths (NULL if single segment)
int current_segment
index of the currently loaded segment (points[i] -> points[i+1]), -1 if none
PHYSICS state
physics state (position, speed, etc.) at this waypoint
int mode
current computation mode: TRAJECTORY_INTERP, TRAJECTORY_EXTRAP, or TRAJECTORY_BEFORE
VECTOR3D m1
Hermite tangent at end for position (end.speed * duration)
PHYSICS start
state at trajectory start (initial known state)
int nb_components
number of components to process: TRAJECTORY_2D (2) or TRAJECTORY_3D (3)
double start_time
timestamp of start state
double end_time
timestamp of end state
int trajectory_get_position(TRAJECTORY *traj, double time_val, VECTOR3D out)
Compute position at a given time.
TRAJECTORY * trajectory_new(int nb_components)
Allocate and initialize a new TRAJECTORY.
int trajectory_set_start(TRAJECTORY *traj, const PHYSICS *state, double time_val)
Set the initial (start) state and time of the trajectory.
int trajectory_add_point(TRAJECTORY *traj, const PHYSICS *state, double time_val)
Add a waypoint to the multi-point trajectory path.
#define TRAJECTORY_EXTRAP
trajectory is extrapolating beyond the end state using quadratic motion
void trajectory_delete(TRAJECTORY **traj)
Free a TRAJECTORY and set the pointer to NULL.
int trajectory_get_orientation(TRAJECTORY *traj, double time_val, VECTOR3D out)
Compute orientation at a given time.
#define TRAJECTORY_3D
use 3 components (x,y,z) for trajectory computation
#define TRAJECTORY_BEFORE
trajectory is extrapolating before the start state using quadratic motion
#define TRAJECTORY_2D
use 2 components (x,y) for trajectory computation
int trajectory_get_acceleration(TRAJECTORY *traj, double time_val, VECTOR3D out)
Compute acceleration at a given time.
#define TRAJECTORY_INTERP
trajectory is interpolating along the cubic Hermite spline between start and end
int trajectory_compute(TRAJECTORY *traj, double time_val)
Compute the full state (position, speed, acceleration, orientation, angular_speed) at a given time us...
int trajectory_set_end(TRAJECTORY *traj, const PHYSICS *state, double time_val)
Set the terminal (end) state and time of the trajectory.
int trajectory_get_speed(TRAJECTORY *traj, double time_val, VECTOR3D out)
Compute velocity at a given time.
int trajectory_clear_points(TRAJECTORY *traj)
Clear all waypoints from the multi-point path.
int trajectory_update(TRAJECTORY *traj, const PHYSICS *new_end, double time_val)
Update the trajectory with a new end state (dead reckoning shift).
double trajectory_distance(TRAJECTORY *traj, double time_a, double time_b, int steps)
Compute the approximate arc length (distance traveled) along the trajectory between two times,...
structure holding all data for trajectory interpolation / extrapolation
a single waypoint in a multi-point trajectory path
static double hermite_d2h01(double s)
Second derivative of h01: d2h01/ds2 = -12s + 6.
static double hermite_h00(double s)
Hermite basis function h00: weights the start position.
static double hermite_dh00(double s)
First derivative of h00: dh00/ds = 6s^2 - 6s.
static double hermite_h10(double s)
Hermite basis function h10: weights the start tangent.
static double hermite_h11(double s)
Hermite basis function h11: weights the end tangent.
static double hermite_d2h00(double s)
Second derivative of h00: d2h00/ds2 = 12s - 6.
static void trajectory_compute_tangents(TRAJECTORY *traj)
Recompute the Hermite tangent vectors from current start/end states.
static double hermite_dh11(double s)
First derivative of h11: dh11/ds = 3s^2 - 2s.
static double hermite_d2h10(double s)
Second derivative of h10: d2h10/ds2 = 6s - 4.
static double hermite_dh10(double s)
First derivative of h10: dh10/ds = 3s^2 - 4s + 1.
static double hermite_h01(double s)
Hermite basis function h01: weights the end position.
static double hermite_d2h11(double s)
Second derivative of h11: d2h11/ds2 = 6s - 2.
static void trajectory_load_segment(TRAJECTORY *traj, double time_val)
Load the correct spline segment for a given time when using multi-point paths.
static double hermite_dh01(double s)
First derivative of h01: dh01/ds = -6s^2 + 6s.
Trajectory interpolation and dead reckoning for 2D/3D networked simulations.