|
| 1 | +#include "occupancy_grid.hpp" |
| 2 | +#include <algorithm> |
| 3 | +#include <iostream> |
| 4 | +#include <cmath> |
| 5 | + |
| 6 | + |
| 7 | +// Log-odds constants |
| 8 | +constexpr float LOG_ODDS_OCCUPIED = 0.85f; |
| 9 | +constexpr float LOG_ODDS_FREE = -0.4f; |
| 10 | +constexpr float LOG_ODDS_MIN = -5.0f; |
| 11 | +constexpr float LOG_ODDS_MAX = 5.0f; |
| 12 | + |
| 13 | +OccupancyGrid::OccupancyGrid(const std::array<size_t, 3>& dimensions, |
| 14 | + double resolution, const Vector3d& origin) |
| 15 | + :grid_dimensions(dimensions), voxel_resolution(resolution), grid_origin(origin) { |
| 16 | + |
| 17 | + size_t total_cells = grid_dimensions[0] * grid_dimensions[1] * grid_dimensions[2]; |
| 18 | + grid_data.resize(total_cells,0.0f); |
| 19 | + |
| 20 | + std::cout << "OccupancyGrid3D initialized:" << std::endl; |
| 21 | + std::cout << " Dimensions: " << grid_dimensions[0] << "×" << grid_dimensions[1] << "×" << grid_dimensions[2] << std::endl; |
| 22 | + std::cout << " Resolution: " << voxel_resolution << "m" << std::endl; |
| 23 | + std::cout << " Origin: " << grid_origin.transpose() << std::endl; |
| 24 | + std::cout << " Total voxels: " << total_cells << std::endl; |
| 25 | + |
| 26 | +} |
| 27 | + |
| 28 | +// converts world coordinates to grid coordinates, assuming grid origin starts in bottom left corner of the map. |
| 29 | +Vector3i OccupancyGrid::world_to_grid(const Vector3d& world_coord) const { |
| 30 | + Vector3d diff = world_coord - grid_origin; |
| 31 | + return Vector3i( |
| 32 | + static_cast<int>(std::floor(diff.x()/voxel_resolution)), |
| 33 | + static_cast<int>(std::floor(diff.y()/voxel_resolution)), |
| 34 | + static_cast<int>(std::floor(diff.z()/voxel_resolution)) |
| 35 | + ); |
| 36 | +} |
| 37 | + |
| 38 | +// converts grid coordinates to world coordinates |
| 39 | +Vector3d OccupancyGrid::grid_to_world(const Vector3i& grid_index) const { |
| 40 | + return grid_origin + Vector3d((grid_index.x() + 0.5) * voxel_resolution, |
| 41 | + (grid_index.y() + 0.5) * voxel_resolution, |
| 42 | + (grid_index.z() + 0.5) * voxel_resolution); |
| 43 | +} |
| 44 | + |
| 45 | +// check if the index is valid and within the grid dimensions |
| 46 | +bool OccupancyGrid::is_InBounds(const Vector3i& idx) const { |
| 47 | + return idx.x() >= 0 && idx.x() < static_cast<int>(grid_dimensions[0]) && |
| 48 | + idx.y() >= 0 && idx.y() < static_cast<int>(grid_dimensions[1]) && |
| 49 | + idx.z() >= 0 && idx.z() < static_cast<int>(grid_dimensions[2]); |
| 50 | +} |
| 51 | + |
| 52 | +//converts 3d grid coordinates to 1d index. |
| 53 | +size_t OccupancyGrid::to_LinearIndex(const Vector3i& idx) const { |
| 54 | + return static_cast<size_t>(idx.z()) * grid_dimensions[0] * grid_dimensions[1] + |
| 55 | + static_cast<size_t>(idx.y()) * grid_dimensions[0] + |
| 56 | + static_cast<size_t>(idx.x()); |
| 57 | +} |
| 58 | + |
| 59 | +// updates occupancy |
| 60 | +void OccupancyGrid::update_occupied(const Vector3i& idx) { |
| 61 | + if(!is_InBounds(idx)) return; |
| 62 | + size_t index = to_LinearIndex(idx); |
| 63 | + grid_data[index] = std::clamp(grid_data[index]+ LOG_ODDS_OCCUPIED, |
| 64 | + LOG_ODDS_MIN, LOG_ODDS_MAX); |
| 65 | +} |
| 66 | + |
| 67 | +// updates occupancy |
| 68 | +void OccupancyGrid::update_free(const Vector3i& idx) { |
| 69 | + if(!is_InBounds(idx)) return; |
| 70 | + size_t index = to_LinearIndex(idx); |
| 71 | + grid_data[index] = std::clamp(grid_data[index]+ LOG_ODDS_FREE, |
| 72 | + LOG_ODDS_MIN, LOG_ODDS_MAX); |
| 73 | +} |
| 74 | + |
| 75 | +// Simple getOccupancy for testing |
| 76 | +float OccupancyGrid::getOccupancy(const Vector3i& grid_index) const { |
| 77 | + if (!is_InBounds(grid_index)) return 0.0f; |
| 78 | + return grid_data[to_LinearIndex(grid_index)]; |
| 79 | +} |
| 80 | + |
| 81 | +// PLACEHOLDER FUNCTIONS - IMPLEMENT |
| 82 | +std::vector<Vector3i> OccupancyGrid::draw_bresenham3d_line(const Vector3i& start, const Vector3i& end) const { |
| 83 | + // TODO: Implement 3D Bresenham algorithm |
| 84 | + // PRIORITY: CRITICAL - Core mapping algorithm |
| 85 | + std::vector<Vector3i> voxels; |
| 86 | + voxels.push_back(start); |
| 87 | + voxels.push_back(end); // Temporary placeholder |
| 88 | + return voxels; |
| 89 | +} |
| 90 | + |
| 91 | +void OccupancyGrid::rayTrace(const Vector3d& start, const Vector3d& end) { |
| 92 | + // TODO: Implement ray tracing |
| 93 | + // PRIORITY: CRITICAL - Main occupancy update method |
| 94 | + Vector3i start_grid = world_to_grid(start); |
| 95 | + Vector3i end_grid = world_to_grid(end); |
| 96 | + |
| 97 | + if (is_InBounds(start_grid) && is_InBounds(end_grid)) { |
| 98 | + update_occupied(end_grid); // Temporary: just mark endpoint |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +Vector3dVector OccupancyGrid::getOccupiedVoxels(float threshold) const { |
| 103 | + // TODO: Implement visualization extraction |
| 104 | + // PRIORITY: HIGH - Needed for final visualization |
| 105 | + Vector3dVector occupied_points; |
| 106 | + return occupied_points; |
| 107 | +} |
0 commit comments