libstp
Robotics library for Botball
Loading...
Searching...
No Matches
WorldMap.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <filesystem>
7#include <stdexcept>
8#include <string>
9#include <vector>
10
11namespace libstp::map
12{
15 class FtmapParseError : public std::runtime_error
16 {
17 public:
18 using std::runtime_error::runtime_error;
19 };
20
25 struct MapLayer
26 {
27 std::string id;
28 std::string name;
29 float zCm{0.0f};
30 std::vector<MapSegment> segments;
31 };
32
35 {
36 float startX{0.0f};
37 float startY{0.0f};
38 float endX{0.0f};
39 float endY{0.0f};
40 };
41
49 {
50 std::string id;
51 std::string name;
52 std::string fromLayer;
53 std::string toLayer;
56 bool bidirectional{true};
57 float widthCm{0.0f};
58 };
59
74 {
75 public:
76 WorldMap() = default;
77
78 // ───────────── Bounds + segment access ─────────────
79 float tableWidthCm() const noexcept { return m_tableWidthCm; }
80 float tableHeightCm() const noexcept { return m_tableHeightCm; }
81 const std::vector<MapSegment>& segments() const noexcept { return m_segments; }
82
83 // ───────────── Multi-layer (v2) access ─────────────
84 // v1 maps load as a single "ground" layer; v2 maps load all authored
85 // layers. `segments()` and the no-arg queries always operate on the
86 // ground/active layer (m_segments) so the particle filter and every
87 // pre-v2 caller keep working unchanged. SimWorld uses the layer-indexed
88 // overloads with the plane the robot is currently on.
89
90 std::size_t layerCount() const noexcept { return m_layers.size(); }
91 const std::vector<MapLayer>& layers() const noexcept { return m_layers; }
92 const std::vector<MapTransition>& transitions() const noexcept { return m_transitions; }
93
95 int layerIndex(const std::string& id) const noexcept;
96
99 const std::vector<MapSegment>& layerSegments(std::size_t idx) const noexcept;
100
104 bool isOnLine(float xCm, float yCm, std::size_t layerIdx) const;
105 bool isOnWall(float xCm, float yCm, std::size_t layerIdx) const;
106
108 std::vector<MapSegment> lines() const;
109
114 std::vector<MapSegment> walls() const;
115
116 // ───────────── Point queries ─────────────
117
121 bool isOnBlackLine(float xCm, float yCm) const;
122
127 bool isOnLine(float xCm, float yCm) const;
128
133 bool isOnWall(float xCm, float yCm) const;
134
138 float distanceToNearestLine(float xCm, float yCm) const;
139
144 float distanceToNearestWall(float xCm, float yCm) const;
145
146 // ───────────── Sensor projection ─────────────
147
155 float robotYCm,
156 float robotHeadingRad,
157 const SensorOffset& sensor) const;
158
160 bool sensorIsOnLine(float robotXCm,
161 float robotYCm,
162 float robotHeadingRad,
163 const SensorOffset& sensor) const;
164
166 bool sensorIsOnWall(float robotXCm,
167 float robotYCm,
168 float robotHeadingRad,
169 const SensorOffset& sensor) const;
170
171 // ───────────── Loading ─────────────
172
176 void loadFtmap(const std::filesystem::path& path);
177
182 void parseFtmap(const std::string& content);
183
184 // ───────────── Programmatic construction ─────────────
185 void setTable(float widthCm, float heightCm) noexcept
186 {
187 m_tableWidthCm = widthCm;
188 m_tableHeightCm = heightCm;
189 }
190 void addSegment(const MapSegment& seg) { m_segments.push_back(seg); }
191 void clear() noexcept
192 {
193 m_segments.clear();
194 m_layers.clear();
195 m_transitions.clear();
196 m_tableWidthCm = 0.0f;
197 m_tableHeightCm = 0.0f;
198 }
199
200 private:
201 float m_tableWidthCm{0.0f};
202 float m_tableHeightCm{0.0f};
203 // Ground/active layer segments — backs segments() and the no-arg
204 // queries. Mirrors m_layers[ground] so legacy callers are unaffected.
205 std::vector<MapSegment> m_segments;
206 std::vector<MapLayer> m_layers;
207 std::vector<MapTransition> m_transitions;
208 };
209}
float tableHeightCm() const noexcept
Definition WorldMap.hpp:80
const std::vector< MapSegment > & layerSegments(std::size_t idx) const noexcept
const std::vector< MapSegment > & segments() const noexcept
Definition WorldMap.hpp:81
void parseFtmap(const std::string &content)
float distanceToNearestLine(float xCm, float yCm) const
bool sensorIsOnWall(float robotXCm, float robotYCm, float robotHeadingRad, const SensorOffset &sensor) const
Convenience: sensorFieldPosition + isOnWall.
float tableWidthCm() const noexcept
Definition WorldMap.hpp:79
void clear() noexcept
Definition WorldMap.hpp:191
bool isOnLine(float xCm, float yCm, std::size_t layerIdx) const
std::size_t layerCount() const noexcept
Definition WorldMap.hpp:90
std::vector< MapSegment > lines() const
Subset of segments() with Kind::Line.
const std::vector< MapTransition > & transitions() const noexcept
Definition WorldMap.hpp:92
bool isOnLine(float xCm, float yCm) const
bool sensorIsOnLine(float robotXCm, float robotYCm, float robotHeadingRad, const SensorOffset &sensor) const
Convenience: sensorFieldPosition + isOnLine.
float distanceToNearestWall(float xCm, float yCm) const
bool isOnWall(float xCm, float yCm) const
Point2D sensorFieldPosition(float robotXCm, float robotYCm, float robotHeadingRad, const SensorOffset &sensor) const
bool isOnBlackLine(float xCm, float yCm) const
void setTable(float widthCm, float heightCm) noexcept
Definition WorldMap.hpp:185
const std::vector< MapLayer > & layers() const noexcept
Definition WorldMap.hpp:91
int layerIndex(const std::string &id) const noexcept
Index of the layer with the given id, or -1 when absent.
void loadFtmap(const std::filesystem::path &path)
bool isOnWall(float xCm, float yCm, std::size_t layerIdx) const
void addSegment(const MapSegment &seg)
Definition WorldMap.hpp:190
std::vector< MapSegment > walls() const
std::vector< MapSegment > segments
Definition WorldMap.hpp:30
Edge geometry of a transition portal on one layer (cm, bottom-up frame).
Definition WorldMap.hpp:35