FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
path_utils.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2006-2008 Marc Brooker and Michael Inggs
4// Copyright (c) 2008-present FERS Contributors (see AUTHORS.md).
5//
6// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
7
8/**
9 * @file path_utils.h
10 * @brief Utility functions for path interpolation and exception handling.
11 *
12 * The cubic interpolation functions are based on methods described in "Numerical Recipes
13 * in C, Second Edition" by Press et al., but the code here is distinct from the original.
14 */
15
16#pragma once
17
18#include <algorithm>
19#include <concepts>
20#include <stdexcept>
21#include <vector>
22
23#include "core/config.h"
24
25namespace math
26{
27 /**
28 * @class PathException
29 * @brief Exception class for handling path-related errors.
30 */
31 class PathException final : public std::runtime_error
32 {
33 public:
34 /**
35 * @brief Constructor for PathException.
36 *
37 * @param description A detailed description of the error.
38 */
39 explicit PathException(const std::string& description) :
40 std::runtime_error("Error While Executing Path Code: " + description)
41 {
42 }
43 };
44}
45
46/**
47 * @brief Concept for types that can be interpolated.
48 *
49 * @tparam T The type to be checked for interpolation.
50 * @param a The first value to be interpolated.
51 * @param b The second value to be interpolated.
52 * @param t The interpolation factor.
53 */
54template <typename T>
55concept Interpolatable = requires(T a, T b, RealType t) {
56 { a - b } -> std::same_as<T>;
57 { a * t } -> std::same_as<T>;
58 { a + b } -> std::same_as<T>;
59 { a.t } -> std::convertible_to<RealType>;
60};
61
62/**
63 * @brief Interpolates a static position from a list of coordinates.
64 *
65 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
66 * @param coord The output coordinate to be set.
67 * @param coords A vector of coordinates from which the first will be selected.
68 * @throws PathException if the list of coordinates is empty.
69 */
70template <Interpolatable T>
71void getPositionStatic(T& coord, const std::vector<T>& coords)
72{
73 if (coords.empty())
74 {
75 throw math::PathException("coord list empty during GetPositionStatic");
76 }
77 coord = coords[0];
78}
79
80/**
81 * @brief Performs linear interpolation between coordinate points.
82 *
83 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
84 * @param t The interpolation factor (usually time) to determine the position.
85 * @param coord The output coordinate that will be interpolated.
86 * @param coords A vector of coordinates to interpolate between.
87 * @throws PathException if the list of coordinates is empty.
88 */
89template <Interpolatable T>
90void getPositionLinear(RealType t, T& coord, const std::vector<T>& coords)
91{
92 if (coords.empty())
93 {
94 throw math::PathException("coord list empty during GetPositionLinear");
95 }
96
97 auto xrp = std::ranges::upper_bound(coords, t, {}, &T::t);
98
99 if (xrp == coords.begin())
100 {
101 coord = *xrp;
102 }
103 else if (xrp == coords.end())
104 {
105 coord = *(xrp - 1);
106 }
107 else
108 {
109 using index_type = typename std::vector<T>::size_type;
110 const auto right_index = static_cast<index_type>(xrp - coords.begin());
111 const auto left_index = right_index - 1;
112
113 const RealType iw = coords[right_index].t - coords[left_index].t;
114 const RealType rw = (coords[right_index].t - t) / iw;
115 const RealType lw = 1 - rw;
116
117 coord = coords[right_index] * lw + coords[left_index] * rw;
118 }
119 coord.t = t;
120}
121
122/**
123 * @brief Performs cubic spline interpolation between coordinate points.
124 * The method used for calculating the spline is from "Numerical Recipes in C."
125 *
126 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
127 * @param t The interpolation factor (usually time) to determine the position.
128 * @param coord The output coordinate that will be interpolated.
129 * @param coords A vector of coordinates to interpolate between.
130 * @param dd A vector of second derivatives used in the cubic interpolation.
131 * @throws PathException if the list of coordinates is empty.
132 */
133template <Interpolatable T>
134void getPositionCubic(RealType t, T& coord, const std::vector<T>& coords, const std::vector<T>& dd)
135{
136 if (coords.empty())
137 {
138 throw math::PathException("coord list empty during GetPositionCubic");
139 }
140
141 auto xrp = std::ranges::upper_bound(coords, t, {}, &T::t);
142
143 if (xrp == coords.begin())
144 {
145 coord = *xrp;
146 }
147 else if (xrp == coords.end())
148 {
149 coord = *(xrp - 1);
150 }
151 else
152 {
153 using index_type = typename std::vector<T>::size_type;
154 const auto right_index = static_cast<index_type>(xrp - coords.begin());
155 const auto left_index = right_index - 1;
156
157 const RealType xrd = coords[right_index].t - t;
158 const RealType xld = t - coords[left_index].t;
159 const RealType iw = coords[right_index].t - coords[left_index].t;
160 const RealType iws = iw * iw / 6.0;
161 const RealType a = xrd / iw;
162 const RealType b = xld / iw;
163 const RealType c = (a * a * a - a) * iws;
164 const RealType d = (b * b * b - b) * iws;
165
166 coord = coords[left_index] * a + coords[right_index] * b + dd[left_index] * c + dd[right_index] * d;
167 }
168 coord.t = t;
169}
170
171/**
172 * @brief Finalizes cubic spline interpolation by calculating second derivatives.
173 *
174 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
175 * @param coords A vector of coordinates for which second derivatives will be calculated.
176 * @param dd The output vector that will store the calculated second derivatives.
177 * @throws PathException if there are fewer than two points for interpolation.
178 */
179template <Interpolatable T>
180void finalizeCubic(const std::vector<T>& coords, std::vector<T>& dd)
181{
182 using index_type = typename std::vector<T>::size_type;
183 const index_type size = coords.size();
184 if (size < 2)
185 {
186 throw math::PathException("Not enough points for cubic interpolation");
187 }
188
189 std::vector<T> tmp(size);
190 dd.resize(size);
191
192 dd.front() = 0;
193 dd.back() = 0;
194
195 for (index_type i = 1; i + 1 < size; ++i)
196 {
197 const index_type next_index = i + 1;
198 const index_type prev_index = i - 1;
199
200 const T yrd = coords[next_index] - coords[i];
201 const T yld = coords[i] - coords[prev_index];
202 const RealType xrd = coords[next_index].t - coords[i].t;
203 const RealType xld = coords[i].t - coords[prev_index].t;
204 const RealType iw = coords[next_index].t - coords[prev_index].t;
205
206 if (iw <= EPSILON)
207 {
208 dd[i] = 0.0;
209 tmp[i] = 0.0;
210 continue;
211 }
212
213 const T yrd_xrd = (xrd <= EPSILON) ? (yrd * 0.0) : (yrd / xrd);
214 const T yld_xld = (xld <= EPSILON) ? (yld * 0.0) : (yld / xld);
215
216 const RealType si = xld / iw;
217 const T p = dd[prev_index] * si + 2.0;
218 dd[i] = (si - 1.0) / p;
219 tmp[i] = ((yrd_xrd - yld_xld) * 6.0 / iw - tmp[prev_index] * si) / p;
220 }
221
222 for (index_type i = size - 1; i-- > 0;)
223 {
224 dd[i] = dd[i] * dd[i + 1] + tmp[i];
225 }
226}
Exception class for handling path-related errors.
Definition path_utils.h:32
PathException(const std::string &description)
Constructor for PathException.
Definition path_utils.h:39
Concept for types that can be interpolated.
Definition path_utils.h:55
Global configuration file for the project.
double RealType
Type for real numbers.
Definition config.h:27
constexpr RealType EPSILON
Machine epsilon for real numbers.
Definition config.h:51
Definition coord.h:18
void getPositionLinear(RealType t, T &coord, const std::vector< T > &coords)
Performs linear interpolation between coordinate points.
Definition path_utils.h:90
void getPositionStatic(T &coord, const std::vector< T > &coords)
Interpolates a static position from a list of coordinates.
Definition path_utils.h:71
void finalizeCubic(const std::vector< T > &coords, std::vector< T > &dd)
Finalizes cubic spline interpolation by calculating second derivatives.
Definition path_utils.h:180
void getPositionCubic(RealType t, T &coord, const std::vector< T > &coords, const std::vector< T > &dd)
Performs cubic spline interpolation between coordinate points.
Definition path_utils.h:134