5#include <unordered_map>
6#include <unordered_set>
9#include "TinyRobotics/coordinates/Coordinate.h"
10#include "TinyRobotics/utils/Common.h"
11#include "TinyRobotics/utils/LoggerClass.h"
13namespace tinyrobotics {
15
16
17
18
19
20
21
22template <
typename T = DistanceM>
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63template <
typename T = DistanceM>
73 bool operator==(
const Key& other)
const {
74 return x == other.x && y == other.y && z == other.z;
79 size_t operator()(
const Key& k)
const {
80 return ((std::hash<
int>()(k.x) ^ (std::hash<
int>()(k.y) << 1)) >> 1) ^
81 (std::hash<
int>()(k.z) << 1);
89 PointCloud(T voxalSize,
bool isliveVoxel =
false) {
102 void add(T x, T y, T z = 0.0f) {
104 if (!liveVocelGrid_) points_.push_back(p);
110 void add(
const Point3D<T>* pts, size_t count) {
111 for (size_t i = 0; i < count; ++i) add(pts[i].x, pts[i].y, pts[i].z);
115 void add(
const Coordinate<T>& coord) { add(coord.x, coord.y, coord.z); }
124 size_t size()
const {
return points_.size(); }
127 bool isEmpty()
const {
return points_.empty(); }
133 Bounds
bounds()
const {
return bounds_; }
162 for (
const auto& p : points_) {
163 addVoxel(p.x, p.y, p.z);
165 TRLogger.debug(
"Voxel grid built with voxel size: %f, total voxels: %d",
166 voxelSize_, (
int)voxelGrid_.size());
167 for (
const auto& key : voxelGrid_) {
168 TRLogger.debug(
"Voxel: (%d, %d, %d)", key.x, key.y, key.z);
175
176
177
178
179
180
181
182
183
184
185
186
188 std::vector<Coordinate<T>> neighbors;
189 if (voxelSize_ <= 0.0f)
return neighbors;
190 TRLogger.debug(
"-------------------");
192 "Finding neighbors for: %s with bounding box min:(%f,%f,%f) / "
194 from.toCString(), bounds_.min.x, bounds_.min.y, bounds_.min.z,
195 bounds_.max.x, bounds_.max.y, bounds_.max.z);
198 int x0 =
int(std::floor(from.x / voxelSize_));
199 int y0 =
int(std::floor(from.y / voxelSize_));
200 int z0 =
int(std::floor(from.z / voxelSize_));
204 const int dx[6] = {1, -1, 0, 0, 0, 0};
205 const int dy[6] = {0, 0, 1, -1, 0, 0};
206 const int dz[6] = {0, 0, 0, 0, 1, -1};
207 for (
int i = 0; i < 6; ++i) {
212 T cx = (nx + 0.5f) * voxelSize_;
213 T cy = (ny + 0.5f) * voxelSize_;
214 T cz = (nz + 0.5f) * voxelSize_;
216 if (cx < bounds_.min.x || cx > bounds_.max.x || cy < bounds_.min.y ||
217 cy > bounds_.max.y || cz < bounds_.min.z || cz > bounds_.max.z) {
220 Key nkey{nx, ny, nz};
222 if (voxelGrid_.find(nkey) == voxelGrid_.end()) {
223 neighbors.emplace_back(cx, cy, cz);
228 const int dx[4] = {1, -1, 0, 0};
229 const int dy[4] = {0, 0, 1, -1};
230 for (
int i = 0; i < 4; ++i) {
234 T cx = (nx + 0.5f) * voxelSize_;
235 T cy = (ny + 0.5f) * voxelSize_;
238 if (cx < bounds_.min.x || cx > bounds_.max.x || cy < bounds_.min.y ||
239 cy > bounds_.max.y) {
242 Key nkey{nx, ny, nz};
243 if (voxelGrid_.find(nkey) == voxelGrid_.end()) {
244 neighbors.emplace_back(cx, cy, cz);
248 for (
auto& n : neighbors) {
249 TRLogger.debug(
"Neighbor: %s", n.toCString());
251 TRLogger.debug(
"-------------------");
258 void set3D(
bool is3d) { is_3d = is3d; }
262 void setBounds(
float minX,
float minY,
float minZ,
float maxX,
float maxY,
264 bounds_.min = {minX, minY, minZ};
265 bounds_.max = {maxX, maxY, maxZ};
269 bool isOccupied(
float x,
float y,
float z)
const {
270 if (voxelSize_ <= 0.0f)
return false;
272 Key key{
int(std::floor(x / voxelSize_)),
int(std::floor(y / voxelSize_)),
273 int(std::floor(z / voxelSize_))};
275 return voxelGrid_.find(key) != voxelGrid_.end();
281 if (coord.x < bounds_.min.x || coord.x > bounds_.max.x ||
282 coord.y < bounds_.min.y || coord.y > bounds_.max.y ||
283 coord.z < bounds_.min.z || coord.z > bounds_.max.z) {
296 auto endVoxels() {
return voxelGrid_.end(); }
298 auto beginVoxels()
const {
return voxelGrid_.begin(); }
300 auto endVoxels()
const {
return voxelGrid_.end(); }
304 return serializer.write(*
this, out);
309 return serializer.read(*
this, in);
324 bool liveVocelGrid_ =
false;
327 std::unordered_set<Key, KeyHash, std::equal_to<Key>, PSRAMKeyAllocator>
330 PointCloudSerializer<PointCloud<T>> serializer;
333 bounds_.min = {std::numeric_limits<
float>::max(),
334 std::numeric_limits<
float>::max(),
335 std::numeric_limits<
float>::max()};
337 bounds_.max = {std::numeric_limits<
float>::lowest(),
338 std::numeric_limits<
float>::lowest(),
339 std::numeric_limits<
float>::lowest()};
342 void updateBounds(
const Point3D<T>& p) {
343 if (p.x < bounds_.min.x) bounds_.min.x = p.x;
344 if (p.y < bounds_.min.y) bounds_.min.y = p.y;
345 if (p.z < bounds_.min.z) bounds_.min.z = p.z;
347 if (p.x > bounds_.max.x) bounds_.max.x = p.x;
348 if (p.y > bounds_.max.y) bounds_.max.y = p.y;
349 if (p.z > bounds_.max.z) bounds_.max.z = p.z;
353 void addVoxel(
float x,
float y,
float z) {
354 if (voxelSize_ > 0.0f) {
355 Key key{
int(std::floor(x / voxelSize_)),
int(std::floor(y / voxelSize_)),
356 int(std::floor(z / voxelSize_))};
357 voxelGrid_.insert(key);
359 TRLogger.warn(
"Voxel size must be > 0 to add voxels");
368 T wx = (cx + 0.5f) * voxelSize_;
369 T wy = (cy + 0.5f) * voxelSize_;
A generic 3D coordinate class for robotics, navigation, and spatial calculations.
Definition: Coordinate.h:57
Represents a 3D point cloud for robotics and mapping applications.
Definition: PointCloud.h:64
size_t readFrom(Stream &in)
Read map from input.
Definition: PointCloud.h:308
auto endVoxels() const
Provides sequential (iterator) access to all occupied voxels.
Definition: PointCloud.h:300
size_t size() const
Provide the number of points in the point cloud.
Definition: PointCloud.h:124
std::vector< Coordinate< T > > getNeighbors(Coordinate< T > from) const override
Returns the free (unoccupied) neighboring coordinates of a given point in the voxel grid.
Definition: PointCloud.h:187
size_t writeTo(Print &out)
Write map to output.
Definition: PointCloud.h:303
bool isValid(const Coordinate< T > &coord) const override
Checks if a coordinate is valid (within bounds and not occupied)
Definition: PointCloud.h:279
void setVoxalSize(T size)
Set the size of each voxel in the grid (e.g., 0.1 m for 10cm voxels).
Definition: PointCloud.h:99
void addVoxel(float x, float y, float z)
Adds a point to the voxel grid if voxelSize_ > 0.
Definition: PointCloud.h:353
void setBounds(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Definition: PointCloud.h:262
void add(T x, T y, T z=0.0f)
Add a single point.
Definition: PointCloud.h:102
auto beginVoxels() const
Provides sequential (iterator) access to all occupied voxels.
Definition: PointCloud.h:298
Coordinate< T > toVoxel(int cx, int cy) const
Definition: PointCloud.h:366
auto endVoxels()
Provides sequential (iterator) access to all occupied voxels.
Definition: PointCloud.h:296
bool isOccupied(float x, float y, float z) const
Checks if a given point is occupied based on the voxel grid.
Definition: PointCloud.h:269
Bounds bounds() const
Returns the bounding box of the point cloud, which is defined by the minimum and maximum coordinates ...
Definition: PointCloud.h:133
void add(const Coordinate< T > &coord)
Add from Coordinate.
Definition: PointCloud.h:115
void clear()
Clear all data.
Definition: PointCloud.h:313
void set3D(bool is3d)
Definition: PointCloud.h:258
bool isEmpty() const
Checks if the point cloud is empty (i.e., contains no points).
Definition: PointCloud.h:127
auto beginVoxels()
Provides sequential (iterator) access to all occupied voxels.
Definition: PointCloud.h:294
VectorT & points()
Provides access to the points in the point cloud.
Definition: PointCloud.h:121
const VectorT & points() const
Provides access to the points in the point cloud.
Definition: PointCloud.h:118
void buildVoxelGrid()
Builds a voxel grid for fast occupancy queries: A voxel is a grid cell.
Definition: PointCloud.h:159
void setLiveVoxelGrid(bool live)
Definition: PointCloud.h:97
void add(const Point3D< T > *pts, size_t count)
Add from array.
Definition: PointCloud.h:110
Represents a 3D point with x, y, z coordinates (in meters).
Definition: PointCloud.h:23