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 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
44#include <math.h>
45
51static double hermite_h00(double s) {
52 return 2.0 * s * s * s - 3.0 * s * s + 1.0;
53}
54
60static double hermite_h10(double s) {
61 return s * s * s - 2.0 * s * s + s;
62}
63
69static double hermite_h01(double s) {
70 return -2.0 * s * s * s + 3.0 * s * s;
71}
72
78static double hermite_h11(double s) {
79 return s * s * s - s * s;
80}
81
87static double hermite_dh00(double s) {
88 return 6.0 * s * s - 6.0 * s;
89}
90
96static double hermite_dh10(double s) {
97 return 3.0 * s * s - 4.0 * s + 1.0;
98}
99
105static double hermite_dh01(double s) {
106 return -6.0 * s * s + 6.0 * s;
107}
108
114static double hermite_dh11(double s) {
115 return 3.0 * s * s - 2.0 * s;
116}
117
123static double hermite_d2h00(double s) {
124 return 12.0 * s - 6.0;
125}
126
132static double hermite_d2h10(double s) {
133 return 6.0 * s - 4.0;
134}
135
141static double hermite_d2h01(double s) {
142 return -12.0 * s + 6.0;
143}
144
150static double hermite_d2h11(double s) {
151 return 6.0 * s - 2.0;
152}
153
160 for (int i = 0; i < traj->nb_components; i++) {
161 traj->m0[i] = traj->start.speed[i] * traj->duration;
162 traj->m1[i] = traj->end.speed[i] * traj->duration;
163 traj->m0_orient[i] = traj->start.angular_speed[i] * traj->duration;
164 traj->m1_orient[i] = traj->end.angular_speed[i] * traj->duration;
165 }
166}
167
175static void trajectory_load_segment(TRAJECTORY* traj, double time_val) {
176 if (traj->nb_points < 2) return;
177
178 int seg = traj->current_segment;
179 if (seg < 0) seg = 0;
180
181 /* search forward from current segment */
182 while (seg < traj->nb_points - 2 &&
183 time_val >= traj->points[seg + 1].time_val) {
184 seg++;
185 }
186 /* search backward if needed */
187 while (seg > 0 && time_val < traj->points[seg].time_val) {
188 seg--;
189 }
190
191 if (seg != traj->current_segment) {
192 traj->current_segment = seg;
193 memcpy(&traj->start, &traj->points[seg].state, sizeof(PHYSICS));
194 memcpy(&traj->end, &traj->points[seg + 1].state, sizeof(PHYSICS));
195 traj->start_time = traj->points[seg].time_val;
196 traj->end_time = traj->points[seg + 1].time_val;
197 traj->duration = traj->end_time - traj->start_time;
199 }
200}
201
207TRAJECTORY* trajectory_new(int nb_components) {
208 if (nb_components != TRAJECTORY_2D && nb_components != TRAJECTORY_3D) {
209 n_log(LOG_ERR, "nb_components must be TRAJECTORY_2D (2) or TRAJECTORY_3D (3), got %d", nb_components);
210 return NULL;
211 }
212
213 TRAJECTORY* traj = NULL;
214 Malloc(traj, TRAJECTORY, 1);
215 __n_assert(traj, return NULL);
216
217 traj->nb_components = nb_components;
218 traj->mode = TRAJECTORY_BEFORE;
219 traj->start_time = 0.0;
220 traj->end_time = 0.0;
221 traj->duration = 0.0;
222 traj->current_time = 0.0;
223 traj->points = NULL;
224 traj->nb_points = 0;
225 traj->nb_points_allocated = 0;
226 traj->current_segment = -1;
227
228 return traj;
229} /* trajectory_new() */
230
236 __n_assert(traj, return);
237 Free((*traj)->points);
238 Free((*traj));
239} /* trajectory_delete() */
240
248int trajectory_set_start(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
249 __n_assert(traj, return FALSE);
250 __n_assert(state, return FALSE);
251
252 memcpy(&traj->start, state, sizeof(PHYSICS));
253 traj->start_time = time_val;
254 traj->duration = traj->end_time - traj->start_time;
255
256 if (traj->duration > 0.0) {
258 }
259
260 return TRUE;
261} /* trajectory_set_start() */
262
271int trajectory_set_end(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
272 __n_assert(traj, return FALSE);
273 __n_assert(state, return FALSE);
274
275 memcpy(&traj->end, state, sizeof(PHYSICS));
276 traj->end_time = time_val;
277 traj->duration = traj->end_time - traj->start_time;
278
279 if (traj->duration <= 0.0) {
280 n_log(LOG_ERR, "end_time (%g) must be greater than start_time (%g)", time_val, traj->start_time);
281 return FALSE;
282 }
283
285
286 return TRUE;
287} /* trajectory_set_end() */
288
299int trajectory_update(TRAJECTORY* traj, const PHYSICS* new_end, double time_val) {
300 __n_assert(traj, return FALSE);
301 __n_assert(new_end, return FALSE);
302
303 if (time_val <= traj->end_time) {
304 n_log(LOG_ERR, "new time (%g) must be greater than current end_time (%g)", time_val, traj->end_time);
305 return FALSE;
306 }
307
308 /* shift: old end becomes new start */
309 memcpy(&traj->start, &traj->end, sizeof(PHYSICS));
310 traj->start_time = traj->end_time;
311
312 /* set new end */
313 memcpy(&traj->end, new_end, sizeof(PHYSICS));
314 traj->end_time = time_val;
315 traj->duration = traj->end_time - traj->start_time;
316
318
319 return TRUE;
320} /* trajectory_update() */
321
330int trajectory_compute(TRAJECTORY* traj, double time_val) {
331 __n_assert(traj, return FALSE);
332
333 trajectory_load_segment(traj, time_val);
334 traj->current_time = time_val;
335 int nc = traj->nb_components;
336
337 if (traj->duration <= 0.0) {
338 /* no valid interval: just copy start state */
339 memcpy(&traj->current, &traj->start, sizeof(PHYSICS));
340 traj->mode = TRAJECTORY_BEFORE;
341 return TRUE;
342 }
343
344 if (time_val < traj->start_time) {
345 /* before start: quadratic extrapolation backward from start state */
346 traj->mode = TRAJECTORY_BEFORE;
347 double dt = time_val - traj->start_time; /* negative */
348 for (int i = 0; i < nc; i++) {
349 traj->current.position[i] = traj->start.position[i] + traj->start.speed[i] * dt + 0.5 * traj->start.acceleration[i] * dt * dt;
350 traj->current.speed[i] = traj->start.speed[i] + traj->start.acceleration[i] * dt;
351 traj->current.acceleration[i] = traj->start.acceleration[i];
352 traj->current.orientation[i] = traj->start.orientation[i] + traj->start.angular_speed[i] * dt + 0.5 * traj->start.angular_acceleration[i] * dt * dt;
353 traj->current.angular_speed[i] = traj->start.angular_speed[i] + traj->start.angular_acceleration[i] * dt;
355 }
356 } else if (time_val > traj->end_time) {
357 /* after end: quadratic extrapolation forward from end state */
358 traj->mode = TRAJECTORY_EXTRAP;
359 double dt = time_val - traj->end_time;
360 for (int i = 0; i < nc; i++) {
361 traj->current.position[i] = traj->end.position[i] + traj->end.speed[i] * dt + 0.5 * traj->end.acceleration[i] * dt * dt;
362 traj->current.speed[i] = traj->end.speed[i] + traj->end.acceleration[i] * dt;
363 traj->current.acceleration[i] = traj->end.acceleration[i];
364 traj->current.orientation[i] = traj->end.orientation[i] + traj->end.angular_speed[i] * dt + 0.5 * traj->end.angular_acceleration[i] * dt * dt;
365 traj->current.angular_speed[i] = traj->end.angular_speed[i] + traj->end.angular_acceleration[i] * dt;
367 }
368 } else {
369 /* within interval: cubic Hermite spline interpolation */
370 traj->mode = TRAJECTORY_INTERP;
371 double s = (time_val - traj->start_time) / traj->duration;
372
373 /* Hermite basis function values */
374 double h00 = hermite_h00(s);
375 double h10 = hermite_h10(s);
376 double h01 = hermite_h01(s);
377 double h11 = hermite_h11(s);
378
379 /* first derivatives for velocity */
380 double dh00 = hermite_dh00(s);
381 double dh10 = hermite_dh10(s);
382 double dh01 = hermite_dh01(s);
383 double dh11 = hermite_dh11(s);
384
385 /* second derivatives for acceleration */
386 double d2h00 = hermite_d2h00(s);
387 double d2h10 = hermite_d2h10(s);
388 double d2h01 = hermite_d2h01(s);
389 double d2h11 = hermite_d2h11(s);
390
391 double inv_dur = 1.0 / traj->duration;
392 double inv_dur2 = inv_dur * inv_dur;
393
394 for (int i = 0; i < nc; i++) {
395 /* position: P(s) = h00*P0 + h10*M0 + h01*P1 + h11*M1 */
396 traj->current.position[i] = h00 * traj->start.position[i] + h10 * traj->m0[i] + h01 * traj->end.position[i] + h11 * traj->m1[i];
397
398 /* velocity: V(t) = P'(s) / duration */
399 traj->current.speed[i] = (dh00 * traj->start.position[i] + dh10 * traj->m0[i] + dh01 * traj->end.position[i] + dh11 * traj->m1[i]) * inv_dur;
400
401 /* acceleration: A(t) = P''(s) / duration^2 */
402 traj->current.acceleration[i] = (d2h00 * traj->start.position[i] + d2h10 * traj->m0[i] + d2h01 * traj->end.position[i] + d2h11 * traj->m1[i]) * inv_dur2;
403
404 /* orientation: same Hermite approach */
405 traj->current.orientation[i] = h00 * traj->start.orientation[i] + h10 * traj->m0_orient[i] + h01 * traj->end.orientation[i] + h11 * traj->m1_orient[i];
406
407 /* angular speed: derivative of orientation spline / duration */
408 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;
409
410 /* angular acceleration: second derivative / duration^2 */
411 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;
412 }
413 }
414
415 /* zero out unused components for safety */
416 for (int i = nc; i < 3; i++) {
417 traj->current.position[i] = 0.0;
418 traj->current.speed[i] = 0.0;
419 traj->current.acceleration[i] = 0.0;
420 traj->current.orientation[i] = 0.0;
421 traj->current.angular_speed[i] = 0.0;
422 traj->current.angular_acceleration[i] = 0.0;
423 }
424
425 return TRUE;
426} /* trajectory_compute() */
427
436int trajectory_get_position(TRAJECTORY* traj, double time_val, VECTOR3D out) {
437 __n_assert(traj, return FALSE);
438 __n_assert(out, return FALSE);
439
440 trajectory_load_segment(traj, time_val);
441 int nc = traj->nb_components;
442
443 if (traj->duration <= 0.0) {
444 for (int i = 0; i < nc; i++) out[i] = traj->start.position[i];
445 for (int i = nc; i < 3; i++) out[i] = 0.0;
446 return TRUE;
447 }
448
449 if (time_val < traj->start_time) {
450 double dt = time_val - traj->start_time;
451 for (int i = 0; i < nc; i++) {
452 out[i] = traj->start.position[i] + traj->start.speed[i] * dt + 0.5 * traj->start.acceleration[i] * dt * dt;
453 }
454 } else if (time_val > traj->end_time) {
455 double dt = time_val - traj->end_time;
456 for (int i = 0; i < nc; i++) {
457 out[i] = traj->end.position[i] + traj->end.speed[i] * dt + 0.5 * traj->end.acceleration[i] * dt * dt;
458 }
459 } else {
460 double s = (time_val - traj->start_time) / traj->duration;
461 double h00 = hermite_h00(s);
462 double h10 = hermite_h10(s);
463 double h01 = hermite_h01(s);
464 double h11 = hermite_h11(s);
465 for (int i = 0; i < nc; i++) {
466 out[i] = h00 * traj->start.position[i] + h10 * traj->m0[i] + h01 * traj->end.position[i] + h11 * traj->m1[i];
467 }
468 }
469
470 for (int i = nc; i < 3; i++) out[i] = 0.0;
471 return TRUE;
472} /* trajectory_get_position() */
473
481int trajectory_get_speed(TRAJECTORY* traj, double time_val, VECTOR3D out) {
482 __n_assert(traj, return FALSE);
483 __n_assert(out, return FALSE);
484
485 trajectory_load_segment(traj, time_val);
486 int nc = traj->nb_components;
487
488 if (traj->duration <= 0.0) {
489 for (int i = 0; i < nc; i++) out[i] = traj->start.speed[i];
490 for (int i = nc; i < 3; i++) out[i] = 0.0;
491 return TRUE;
492 }
493
494 if (time_val < traj->start_time) {
495 double dt = time_val - traj->start_time;
496 for (int i = 0; i < nc; i++) {
497 out[i] = traj->start.speed[i] + traj->start.acceleration[i] * dt;
498 }
499 } else if (time_val > traj->end_time) {
500 double dt = time_val - traj->end_time;
501 for (int i = 0; i < nc; i++) {
502 out[i] = traj->end.speed[i] + traj->end.acceleration[i] * dt;
503 }
504 } else {
505 double s = (time_val - traj->start_time) / traj->duration;
506 double inv_dur = 1.0 / traj->duration;
507 double dh00 = hermite_dh00(s);
508 double dh10 = hermite_dh10(s);
509 double dh01 = hermite_dh01(s);
510 double dh11 = hermite_dh11(s);
511 for (int i = 0; i < nc; i++) {
512 out[i] = (dh00 * traj->start.position[i] + dh10 * traj->m0[i] + dh01 * traj->end.position[i] + dh11 * traj->m1[i]) * inv_dur;
513 }
514 }
515
516 for (int i = nc; i < 3; i++) out[i] = 0.0;
517 return TRUE;
518} /* trajectory_get_speed() */
519
527int trajectory_get_acceleration(TRAJECTORY* traj, double time_val, VECTOR3D out) {
528 __n_assert(traj, return FALSE);
529 __n_assert(out, return FALSE);
530
531 trajectory_load_segment(traj, time_val);
532 int nc = traj->nb_components;
533
534 if (traj->duration <= 0.0) {
535 for (int i = 0; i < nc; i++) out[i] = traj->start.acceleration[i];
536 for (int i = nc; i < 3; i++) out[i] = 0.0;
537 return TRUE;
538 }
539
540 if (time_val < traj->start_time || time_val > traj->end_time) {
541 /* extrapolation: constant acceleration from nearest endpoint */
542 PHYSICS* ref = (time_val < traj->start_time) ? &traj->start : &traj->end;
543 for (int i = 0; i < nc; i++) {
544 out[i] = ref->acceleration[i];
545 }
546 } else {
547 double s = (time_val - traj->start_time) / traj->duration;
548 double inv_dur2 = 1.0 / (traj->duration * traj->duration);
549 double d2h00 = hermite_d2h00(s);
550 double d2h10 = hermite_d2h10(s);
551 double d2h01 = hermite_d2h01(s);
552 double d2h11 = hermite_d2h11(s);
553 for (int i = 0; i < nc; i++) {
554 out[i] = (d2h00 * traj->start.position[i] + d2h10 * traj->m0[i] + d2h01 * traj->end.position[i] + d2h11 * traj->m1[i]) * inv_dur2;
555 }
556 }
557
558 for (int i = nc; i < 3; i++) out[i] = 0.0;
559 return TRUE;
560} /* trajectory_get_acceleration() */
561
569int trajectory_get_orientation(TRAJECTORY* traj, double time_val, VECTOR3D out) {
570 __n_assert(traj, return FALSE);
571 __n_assert(out, return FALSE);
572
573 trajectory_load_segment(traj, time_val);
574 int nc = traj->nb_components;
575
576 if (traj->duration <= 0.0) {
577 for (int i = 0; i < nc; i++) out[i] = traj->start.orientation[i];
578 for (int i = nc; i < 3; i++) out[i] = 0.0;
579 return TRUE;
580 }
581
582 if (time_val < traj->start_time) {
583 double dt = time_val - traj->start_time;
584 for (int i = 0; i < nc; i++) {
585 out[i] = traj->start.orientation[i] + traj->start.angular_speed[i] * dt + 0.5 * traj->start.angular_acceleration[i] * dt * dt;
586 }
587 } else if (time_val > traj->end_time) {
588 double dt = time_val - traj->end_time;
589 for (int i = 0; i < nc; i++) {
590 out[i] = traj->end.orientation[i] + traj->end.angular_speed[i] * dt + 0.5 * traj->end.angular_acceleration[i] * dt * dt;
591 }
592 } else {
593 double s = (time_val - traj->start_time) / traj->duration;
594 double h00 = hermite_h00(s);
595 double h10 = hermite_h10(s);
596 double h01 = hermite_h01(s);
597 double h11 = hermite_h11(s);
598 for (int i = 0; i < nc; i++) {
599 out[i] = h00 * traj->start.orientation[i] + h10 * traj->m0_orient[i] + h01 * traj->end.orientation[i] + h11 * traj->m1_orient[i];
600 }
601 }
602
603 for (int i = nc; i < 3; i++) out[i] = 0.0;
604 return TRUE;
605} /* trajectory_get_orientation() */
606
617int trajectory_add_point(TRAJECTORY* traj, const PHYSICS* state, double time_val) {
618 __n_assert(traj, return FALSE);
619 __n_assert(state, return FALSE);
620
621 /* enforce chronological order */
622 if (traj->nb_points > 0 && time_val <= traj->points[traj->nb_points - 1].time_val) {
623 n_log(LOG_ERR, "time_val (%g) must be greater than last point time (%g)",
624 time_val, traj->points[traj->nb_points - 1].time_val);
625 return FALSE;
626 }
627
628 /* grow array if needed */
629 if (traj->nb_points >= traj->nb_points_allocated) {
630 int new_size = (traj->nb_points_allocated == 0) ? 8 : traj->nb_points_allocated * 2;
631 __n_assert(new_size > 0, return FALSE);
632 if (!Realloc(traj->points, TRAJECTORY_POINT, (size_t)new_size)) {
633 return FALSE;
634 }
635 traj->nb_points_allocated = new_size;
636 }
637
638 memcpy(&traj->points[traj->nb_points].state, state, sizeof(PHYSICS));
639 traj->points[traj->nb_points].time_val = time_val;
640 traj->nb_points++;
641
642 /* when we reach 2 points, load the first segment */
643 if (traj->nb_points == 2) {
644 traj->current_segment = -1; /* force reload */
646 }
647
648 return TRUE;
649} /* trajectory_add_point() */
650
658 __n_assert(traj, return FALSE);
659
660 traj->nb_points = 0;
661 traj->current_segment = -1;
662 memset(&traj->start, 0, sizeof(PHYSICS));
663 memset(&traj->end, 0, sizeof(PHYSICS));
664 traj->start_time = 0.0;
665 traj->end_time = 0.0;
666 traj->duration = 0.0;
667
668 return TRUE;
669} /* trajectory_clear_points() */
670
680double trajectory_distance(TRAJECTORY* traj, double time_a, double time_b, int steps) {
681 __n_assert(traj, return -1.0);
682
683 if (steps < 1) steps = 1;
684
685 double dist = 0.0;
686 double dt = (time_b - time_a) / (double)steps;
687 VECTOR3D prev, curr;
688 /* nb_components is constrained to TRAJECTORY_2D (2) or TRAJECTORY_3D (3)
689 * at construction time. Clamp to the VECTOR3D extent so the static
690 * analyzer can see the bound and the per-component loop below stays
691 * safely inside the [0,3) array range. */
692 int nc = traj->nb_components;
693 if (nc < 2) nc = 2;
694 if (nc > 3) nc = 3;
695
696 trajectory_get_position(traj, time_a, prev);
697
698 for (int step = 1; step <= steps; step++) {
699 double t = time_a + dt * (double)step;
700 trajectory_get_position(traj, t, curr);
701
702 double seg = 0.0;
703 for (int i = 0; i < nc; i++) {
704 double d = curr[i] - prev[i];
705 seg += d * d;
706 }
707 dist += sqrt(seg);
708
709 for (int i = 0; i < nc; i++) prev[i] = curr[i];
710 }
711
712 return dist;
713} /* trajectory_distance() */
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define Realloc(__ptr, __struct, __size)
Realloc Handler to get errors.
Definition n_common.h:231
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_ERR
error conditions
Definition n_log.h:76
VECTOR3D speed
vx,vy,vz actual speed
Definition n_3d.h:76
VECTOR3D orientation
ax,ay,az actual rotation position
Definition n_3d.h:80
VECTOR3D position
x,y,z actual position
Definition n_3d.h:74
VECTOR3D acceleration
ax,ay,az actual acceleration
Definition n_3d.h:78
VECTOR3D angular_acceleration
rax,ray,raz actual angular acceleration
Definition n_3d.h:84
VECTOR3D angular_speed
rvx,rvy,rvz actual angular speed
Definition n_3d.h:82
double VECTOR3D[3]
struct of a point
Definition n_3d.h:59
structure of the physics of an object
Definition n_3d.h:70
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.