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
20namespace math
21{
22 /**
23 * @class PathException
24 * @brief Exception class for handling path-related errors.
25 */
26 class PathException final : public std::runtime_error
27 {
28 public:
29 /**
30 * @brief Constructor for PathException.
31 *
32 * @param description A detailed description of the error.
33 */
34 explicit PathException(const std::string& description) :
35 std::runtime_error("Error While Executing Path Code: " + description)
36 {
37 }
38 };
39}
40
41/**
42 * @brief Concept for types that can be interpolated.
43 *
44 * @tparam T The type to be checked for interpolation.
45 * @param a The first value to be interpolated.
46 * @param b The second value to be interpolated.
47 * @param t The interpolation factor.
48 */
49template <typename T>
50concept Interpolatable = requires(T a, T b, RealType t) {
51 { a - b } -> std::same_as<T>;
52 { a* t } -> std::same_as<T>;
53 { a + b } -> std::same_as<T>;
54 { a.t } -> std::convertible_to<RealType>;
55};
56
57/**
58 * @brief Interpolates a static position from a list of coordinates.
59 *
60 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
61 * @param coord The output coordinate to be set.
62 * @param coords A vector of coordinates from which the first will be selected.
63 * @throws PathException if the list of coordinates is empty.
64 */
65template <Interpolatable T>
66void getPositionStatic(T& coord, const std::vector<T>& coords)
67{
68 if (coords.empty())
69 {
70 throw math::PathException("coord list empty during GetPositionStatic");
71 }
72 coord = coords[0];
73}
74
75/**
76 * @brief Performs linear interpolation between coordinate points.
77 *
78 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
79 * @param t The interpolation factor (usually time) to determine the position.
80 * @param coord The output coordinate that will be interpolated.
81 * @param coords A vector of coordinates to interpolate between.
82 * @throws PathException if the list of coordinates is empty.
83 */
84template <Interpolatable T>
85void getPositionLinear(RealType t, T& coord, const std::vector<T>& coords)
86{
87 if (coords.empty())
88 {
89 throw math::PathException("coord list empty during GetPositionLinear");
90 }
91
92 auto xrp = std::ranges::upper_bound(coords, t, {}, &T::t);
93
94 if (xrp == coords.begin())
95 {
96 coord = *xrp;
97 }
98 else if (xrp == coords.end())
99 {
100 coord = *(xrp - 1);
101 }
102 else
103 {
104 auto xri = std::distance(coords.begin(), xrp);
105 auto xli = xri - 1;
106
107 const RealType iw = coords[xri].t - coords[xli].t;
108 const RealType rw = (coords[xri].t - t) / iw;
109 const RealType lw = 1 - rw;
110
111 coord = coords[xri] * lw + coords[xli] * rw;
112 }
113 coord.t = t;
114}
115
116/**
117 * @brief Performs cubic spline interpolation between coordinate points.
118 * The method used for calculating the spline is from "Numerical Recipes in C."
119 *
120 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
121 * @param t The interpolation factor (usually time) to determine the position.
122 * @param coord The output coordinate that will be interpolated.
123 * @param coords A vector of coordinates to interpolate between.
124 * @param dd A vector of second derivatives used in the cubic interpolation.
125 * @throws PathException if the list of coordinates is empty.
126 */
127template <Interpolatable T>
128void getPositionCubic(RealType t, T& coord, const std::vector<T>& coords, const std::vector<T>& dd)
129{
130 if (coords.empty())
131 {
132 throw math::PathException("coord list empty during GetPositionCubic");
133 }
134
135 auto xrp = std::ranges::upper_bound(coords, t, {}, &T::t);
136
137 if (xrp == coords.begin())
138 {
139 coord = *xrp;
140 }
141 else if (xrp == coords.end())
142 {
143 coord = *(xrp - 1);
144 }
145 else
146 {
147 auto xri = std::distance(coords.begin(), xrp);
148 auto xli = xri - 1;
149
150 const RealType xrd = coords[xri].t - t;
151 const RealType xld = t - coords[xli].t;
152 const RealType iw = coords[xri].t - coords[xli].t;
153 const RealType iws = iw * iw / 6.0;
154 const RealType a = xrd / iw;
155 const RealType b = xld / iw;
156 const RealType c = (a * a * a - a) * iws;
157 const RealType d = (b * b * b - b) * iws;
158
159 coord = coords[xli] * a + coords[xri] * b + dd[xli] * c + dd[xri] * d;
160 }
161 coord.t = t;
162}
163
164/**
165 * @brief Finalizes cubic spline interpolation by calculating second derivatives.
166 *
167 * @tparam T The type of the coordinate, which must satisfy the Interpolatable concept.
168 * @param coords A vector of coordinates for which second derivatives will be calculated.
169 * @param dd The output vector that will store the calculated second derivatives.
170 * @throws PathException if there are fewer than two points for interpolation.
171 */
172template <Interpolatable T>
173void finalizeCubic(const std::vector<T>& coords, std::vector<T>& dd)
174{
175 const int size = static_cast<int>(coords.size());
176 if (size < 2)
177 {
178 throw math::PathException("Not enough points for cubic interpolation");
179 }
180
181 std::vector<T> tmp(size);
182 dd.resize(size);
183
184 dd.front() = 0;
185 dd.back() = 0;
186
187 for (int i = 1; i < size - 1; ++i)
188 {
189 const T yrd = coords[i + 1] - coords[i];
190 const T yld = coords[i] - coords[i - 1];
191 const RealType xrd = coords[i + 1].t - coords[i].t;
192 const RealType xld = coords[i].t - coords[i - 1].t;
193 const RealType iw = coords[i + 1].t - coords[i - 1].t;
194 const RealType si = xld / iw;
195 const T p = dd[i - 1] * si + 2.0;
196 dd[i] = (si - 1.0) / p;
197 tmp[i] = ((yrd / xrd - yld / xld) * 6.0 / iw - tmp[i - 1] * si) / p;
198 }
199
200 for (int i = size - 2; i >= 0; --i)
201 {
202 dd[i] = dd[i] * dd[i + 1] + tmp[i];
203 }
204}
Exception class for handling path-related errors.
Definition path_utils.h:27
PathException(const std::string &description)
Constructor for PathException.
Definition path_utils.h:34
Concept for types that can be interpolated.
Definition path_utils.h:50
double RealType
Type for real numbers.
Definition config.h:27
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:85
void getPositionStatic(T &coord, const std::vector< T > &coords)
Interpolates a static position from a list of coordinates.
Definition path_utils.h:66
void finalizeCubic(const std::vector< T > &coords, std::vector< T > &dd)
Finalizes cubic spline interpolation by calculating second derivatives.
Definition path_utils.h:173
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:128