TinyRobotics
Loading...
Searching...
No Matches
Coordinate.h
1#pragma once
2#include <cmath>
3#include <functional>
4#include <string>
5
6#include "TinyRobotics/serialize/Serializable.h"
7#include "TinyRobotics/units/Units.h"
8#include "TinyRobotics/utils/Common.h"
9#include "TinyRobotics/utils/Config.h"
10
11namespace tinyrobotics {
12
13/**
14 * @class Coordinate
15 * @ingroup coordinates
16 * @brief A generic 3D coordinate class for robotics, navigation, and spatial
17 * calculations.
18 *
19 * The Coordinate class represents a point in 3D space with x, y, and z values
20 * (in meters by default). It is templated to support different numeric types
21 * (e.g., float, double) for precision or memory needs. This class provides
22 * essential geometric operations for robotics, mapping, and navigation,
23 * including:
24 * - Calculating Euclidean distance to another coordinate (with selectable
25 * units)
26 * - Computing the horizontal bearing (heading) and vertical elevation angle
27 * to another point
28 * - Navigating to a new coordinate given a distance, heading, and altitude
29 * change
30 * - Comparing coordinates for proximity within a specified tolerance
31 * - Basic arithmetic operations (addition, subtraction, assignment)
32 * - Serialization and deserialization to/from string for storage or
33 * communication
34 *
35 * The x, y, and z values are interpreted as meters in a local or global
36 * Cartesian frame.
37 *
38 * @tparam T Numeric type for coordinates (default: float)
39 *
40 * Example usage:
41 * @code
42 * Coordinate<float> a(1.0, 2.0, 0.5);
43 * Coordinate<float> b(2.0, 3.0, 1.0);
44 * float dist = a.distance(b); // Euclidean distance in meters
45 * float bearing = a.bearing(b); // Horizontal angle in degrees
46 * float elev = a.elevation(b); // Vertical angle in degrees
47 * Coordinate<float> c = a.navigate(5.0, 90); // Move 5m east from a
48 * @endcode
49 *
50 * This class is suitable for use in path planning, SLAM, mapping, sensor
51 * fusion, and any application requiring 2D or 3D spatial representation and
52 * geometric calculations.
53 * @ingroup coordinates
54 */
55
56template <typename T = DistanceM>
57class Coordinate : public Serializable {
58 public:
59 using value_type = T;
60 Coordinate() = default;
61 Coordinate(T x, T y, T z = 0) : x(x), y(y), z(z) {}
62 /// Copy constructor
63 Coordinate(const Coordinate& other) : x(other.x), y(other.y), z(other.z) {}
64 /// Construct from Distance objects
66 : x(x.getValue(DistanceUnit::M)),
67 y(y.getValue(DistanceUnit::M)),
69
70 /// X coordinate (meters)
71 T x = 0;
72 /// Y coordinate (meters)
73 T y = 0;
74 /// Z coordinate (meters)
75 T z = 0;
76
77 /// Calculate the Euclidean distance to another coordinate, with optional unit
78 /// conversion
79 DistanceM distance(const Coordinate& other,
80 DistanceUnit unit = DistanceUnit::M) const {
81 auto distM = distanceM(other);
82 Distance dist(distM, DistanceUnit::M);
83 return dist.getValue(unit);
84 }
85
86 /// Calculate the horizontal bearing (heading) in degrees from this coordinate
87 /// to another
88 float bearing(const Coordinate& other,
89 AngleUnit unit = AngleUnit::DEG) const {
90 AngleDeg bearingDegValue = bearingDeg(other);
91 Angle angle(bearingDegValue, AngleUnit::DEG);
92 return angle.getValue(unit);
93 }
94
95 /// Calculate the elevation angle from this coordinate to another
96 float elevation(const Coordinate& other,
97 AngleUnit unit = AngleUnit::DEG) const {
98 AngleDeg angleDeg = elevationDeg(other);
99 Angle angle(angleDeg, AngleUnit::DEG);
100 return angle.getValue(unit);
101 }
102
103 /// Navigate to a new coordinate given a distance, heading, and optional
104 /// altitude change
105 Coordinate navigate(Distance distance, Angle bearing,
106 Distance altDiff = 0) const {
107 AngleDeg bearingDeg = bearing.getValue(AngleUnit::DEG);
108 DistanceM distanceM = distance.getValue(DistanceUnit::M);
109 DistanceM altDiffM = altDiff.getValue(DistanceUnit::M);
110 return navigate(distanceM, bearingDeg, altDiffM);
111 }
112
113 /// Navigate to a new coordinate given a distance, heading, and optional
114 /// altitude change
115 Coordinate navigate(DistanceM distanceM, float headingDegrees,
116 float altDiffM = 0) const {
117 float headingRad = headingDegrees * static_cast<float>(M_PI) / 180.0f;
118 DistanceM newX = x + distanceM * std::cos(headingRad);
119 DistanceM newY = y + distanceM * std::sin(headingRad);
120 return Coordinate(newX, newY, z + altDiffM); // Keep same altitude
121 }
122
123 /// Calculate the altitude difference in meters between this coordinate and
124 /// another
125 DistanceM altitudeDifference(const Coordinate& other) const {
126 return other.z - z;
127 }
128
129 /// Check if this coordinate is within a certain distance of another
130 /// coordinate
131 bool equals(const Coordinate& other, DistanceM limit) const {
132 return distance(other) < limit;
133 }
134
135 /// Compare two GPS coordinates for proximity within specified distance and
136 /// altitude limits
137 bool equalsWithAltitude(const Coordinate& other, DistanceM limit,
138 DistanceM altLimit) const {
139 return distance(other) < limit &&
140 std::fabs(altitudeDifference(other)) < altLimit;
141 }
142
143 /// Calculate new Coordinate by adding offset defined in other to current
144 /// coordinate
145 Coordinate operator+(const Coordinate& other) const {
146 return Coordinate(x + other.x, y + other.y, z + other.z);
147 }
148
149 /// Calculate new coordinate by subtracting offset in other from this one
150 Coordinate operator-(const Coordinate& other) const {
151 return Coordinate(x - other.x, y - other.y, z - other.z);
152 }
153
154 /// Add offset defined in other to current coordinate
155 void operator+=(const Coordinate& other) {
156 x += other.x;
157 y += other.y;
158 z += other.z;
159 }
160
161 /// Subtract offset in other from this one
162 void operator-=(const Coordinate& other) {
163 x -= other.x;
164 y -= other.y;
165 z -= other.z;
166 }
167
168 /// Assign values from another coordinate
169 void operator=(const Coordinate& other) {
170 x = other.x;
171 y = other.y;
172 z = other.z;
173 }
174
175 /// Equality operators for use in std::unordered_map and comparisons
176 bool operator==(const Coordinate<T>& other) const {
177 return x == other.x && y == other.y && z == other.z;
178 }
179
180 bool operator!=(const Coordinate<T>& other) const {
181 return !(*this == other);
182 }
183
184 /// Lexicographical comparison for STL containers (priority_queue, set, etc.)
185 bool operator<(const Coordinate& other) const {
186 if (x != other.x) return x < other.x;
187 if (y != other.y) return y < other.y;
188 return z < other.z;
189 }
190
191 /// Convert coordinate to string representation
192 std::string toString() const {
193 char buf[100];
194 snprintf(buf, sizeof(buf), "%s: %.8f, %.8f, %.2f", getTypeName(), x, y, z);
195 return std::string(buf);
196 }
197
198 /// Parse coordinate from string representation
199 bool fromString(const std::string& str) {
200 if (str.find(getTypeName()) == std::string::npos)
201 return false; // Must start with type name
202 size_t colon = str.find(':');
203 if (colon == std::string::npos) return false;
204 size_t comma1 = str.find(',');
205 if (comma1 == std::string::npos) return false;
206 size_t comma2 = str.find(',', comma1 + 1);
207 x = std::stof(str.substr(colon, comma1));
208 y = std::stof(str.substr(comma1 + 1, comma2 - comma1 - 1));
209 if (comma2 != std::string::npos) {
210 z = std::stof(str.substr(comma2 + 1));
211 } else {
212 z = 0;
213 }
214 return true;
215 }
216
217 /// Set coordinate values from numeric types
218 void setValues(T newX, T newY, T newZ = 0) {
219 x = newX;
220 y = newY;
221 z = newZ;
222 }
223
224 /// Set coordinate values from Distance objects
225 void setValues(Distance newX, Distance newY, Distance newZ = 0) {
226 x = newX.getValue(DistanceUnit::M);
227 y = newY.getValue(DistanceUnit::M);
228 z = newZ.getValue(DistanceUnit::M);
229 }
230
231 /**
232 * @brief Interpolate points between source and target with a defined
233 * resolution.
234 *
235 * @param source The starting coordinate.
236 * @param target The ending coordinate.
237 * @param resolution The distance between interpolated points.
238 * @return std::vector<Coordinate<T>> List of interpolated coordinates
239 * (including source and target).
240 */
242 T resolution) {
243 std::vector<Coordinate<T>> points;
244 T dx = target.x - this->x;
245 T dy = target.y - this->y;
246 T dz = target.z - this->z;
247 T distance = std::sqrt(dx * dx + dy * dy + dz * dz);
248 int steps = std::max(1, static_cast<int>(std::ceil(distance / resolution)));
249 for (int i = 0; i <= steps; ++i) {
250 T t = static_cast<T>(i) / steps;
251 points.emplace_back(this->x + t * dx, this->y + t * dy, this->z + t * dz);
252 }
253 return points;
254 }
255
256 /// Interpolate points between source and target with Distance resolution
259 return interpolateTo(target, resolution.getValue(DistanceUnit::M));
260 }
261
262 /// Get the type name string
263 const char* getTypeName() const { return "Coordinate"; }
264
265 protected:
266 /// Calculate bearing in degrees to another coordinate
267 AngleDeg bearingDeg(const Coordinate& other) const {
268 float dx = other.x - x;
269 float dy = other.y - y;
270 float angle = std::atan2(dy, dx) * 180.0f / static_cast<float>(M_PI);
271 return normalizeAngleDeg(angle); // Degrees
272 }
273
274 // Returns the vertical angle (elevation) in degrees to another coordinate
275
276 /// Calculate elevation angle in degrees to another coordinate
277 AngleDeg elevationDeg(const Coordinate& other) const {
278 float dz = other.z - z;
279 float dxy = std::sqrt((other.x - x) * (other.x - x) +
280 (other.y - y) * (other.y - y));
281 float angle = std::atan2(dz, dxy) * 180.0f / static_cast<float>(M_PI);
282 return normalizeAngleDeg(angle);
283 }
284
285 /// Calculate Euclidean distance in meters to another coordinate
286 DistanceM distanceM(const Coordinate& other) const {
287 auto dx = x - other.x;
288 auto dy = y - other.y;
289 auto dz = z - other.z;
290 return std::sqrt(dx * dx + dy * dy + dz * dz);
291 }
292};
293
294} // namespace tinyrobotics
295
296namespace std {
297template <typename T>
298struct hash<tinyrobotics::Coordinate<T>> {
299 std::size_t operator()(const tinyrobotics::Coordinate<T>& c) const noexcept {
300 std::size_t h1 = std::hash<T>{}(c.x);
301 std::size_t h2 = std::hash<T>{}(c.y);
302 return h1 ^ (h2 << 1);
303 }
304};
305} // namespace std
Represents an angle with unit conversion and wrap-around support.
Definition: Angle.h:42
A generic 3D coordinate class for robotics, navigation, and spatial calculations.
Definition: Coordinate.h:57
Coordinate navigate(DistanceM distanceM, float headingDegrees, float altDiffM=0) const
Definition: Coordinate.h:115
void operator+=(const Coordinate &other)
Add offset defined in other to current coordinate.
Definition: Coordinate.h:155
DistanceM distanceM(const Coordinate &other) const
Calculate Euclidean distance in meters to another coordinate.
Definition: Coordinate.h:286
Coordinate(const Coordinate &other)
Copy constructor.
Definition: Coordinate.h:63
T y
Y coordinate (meters)
Definition: Coordinate.h:73
std::string toString() const
Convert coordinate to string representation.
Definition: Coordinate.h:192
void operator=(const Coordinate &other)
Assign values from another coordinate.
Definition: Coordinate.h:169
Coordinate operator+(const Coordinate &other) const
Definition: Coordinate.h:145
void operator-=(const Coordinate &other)
Subtract offset in other from this one.
Definition: Coordinate.h:162
Coordinate operator-(const Coordinate &other) const
Calculate new coordinate by subtracting offset in other from this one.
Definition: Coordinate.h:150
bool equalsWithAltitude(const Coordinate &other, DistanceM limit, DistanceM altLimit) const
Definition: Coordinate.h:137
DistanceM altitudeDifference(const Coordinate &other) const
Definition: Coordinate.h:125
std::vector< Coordinate< T > > interpolateTo(const Coordinate< T > &target, Distance resolution)
Interpolate points between source and target with Distance resolution.
Definition: Coordinate.h:257
void setValues(T newX, T newY, T newZ=0)
Set coordinate values from numeric types.
Definition: Coordinate.h:218
Coordinate(Distance x, Distance y, Distance z=0)
Construct from Distance objects.
Definition: Coordinate.h:65
bool equals(const Coordinate &other, DistanceM limit) const
Definition: Coordinate.h:131
bool fromString(const std::string &str)
Parse coordinate from string representation.
Definition: Coordinate.h:199
T x
X coordinate (meters)
Definition: Coordinate.h:71
float bearing(const Coordinate &other, AngleUnit unit=AngleUnit::DEG) const
Definition: Coordinate.h:88
T z
Z coordinate (meters)
Definition: Coordinate.h:75
float elevation(const Coordinate &other, AngleUnit unit=AngleUnit::DEG) const
Calculate the elevation angle from this coordinate to another.
Definition: Coordinate.h:96
bool operator==(const Coordinate< T > &other) const
Equality operators for use in std::unordered_map and comparisons.
Definition: Coordinate.h:176
AngleDeg bearingDeg(const Coordinate &other) const
Calculate bearing in degrees to another coordinate.
Definition: Coordinate.h:267
bool operator<(const Coordinate &other) const
Lexicographical comparison for STL containers (priority_queue, set, etc.)
Definition: Coordinate.h:185
std::vector< Coordinate< T > > interpolateTo(const Coordinate< T > &target, T resolution)
Interpolate points between source and target with a defined resolution.
Definition: Coordinate.h:241
Coordinate navigate(Distance distance, Angle bearing, Distance altDiff=0) const
Definition: Coordinate.h:105
void setValues(Distance newX, Distance newY, Distance newZ=0)
Set coordinate values from Distance objects.
Definition: Coordinate.h:225
const char * getTypeName() const
Get the type name string.
Definition: Coordinate.h:263
DistanceM distance(const Coordinate &other, DistanceUnit unit=DistanceUnit::M) const
Definition: Coordinate.h:79
AngleDeg elevationDeg(const Coordinate &other) const
Calculate elevation angle in degrees to another coordinate.
Definition: Coordinate.h:277
Represents a distance measurement with unit conversion support.
Definition: Distance.h:40
This class defines an interface for serializable objects that can be converted to and from a string r...
Definition: Serializable.h:32
DistanceUnit
Supported distance units for conversion and representation.
Definition: Distance.h:10
AngleUnit
Supported angle units for conversion and representation.
Definition: Angle.h:11