| 68 | /// @details Fully tested. |
| 69 | template <typename GridVisitor> |
| 70 | inline void traverseGridSegmentFloat(const vec2f &start, const vec2f &end, |
| 71 | GridVisitor &visitor) { |
| 72 | int x0 = static_cast<int>(fl::floor(start.x)); |
| 73 | int y0 = static_cast<int>(fl::floor(start.y)); |
| 74 | int x1 = static_cast<int>(fl::floor(end.x)); |
| 75 | int y1 = static_cast<int>(fl::floor(end.y)); |
| 76 | |
| 77 | int stepX = (x1 > x0) ? 1 : (x1 < x0) ? -1 : 0; |
| 78 | int stepY = (y1 > y0) ? 1 : (y1 < y0) ? -1 : 0; |
| 79 | |
| 80 | float dx = end.x - start.x; |
| 81 | float dy = end.y - start.y; |
| 82 | |
| 83 | float tDeltaX = (dx != 0.0f) ? fl::abs(1.0f / dx) : FL_FLT_MAX; |
| 84 | float tDeltaY = (dy != 0.0f) ? fl::abs(1.0f / dy) : FL_FLT_MAX; |
| 85 | |
| 86 | float nextX = (stepX > 0) ? (fl::floor(start.x) + 1) : fl::floor(start.x); |
| 87 | float nextY = (stepY > 0) ? (fl::floor(start.y) + 1) : fl::floor(start.y); |
| 88 | |
| 89 | float tMaxX = (dx != 0.0f) ? fl::abs((nextX - start.x) / dx) : FL_FLT_MAX; |
| 90 | float tMaxY = (dy != 0.0f) ? fl::abs((nextY - start.y) / dy) : FL_FLT_MAX; |
| 91 | |
| 92 | float maxT = 1.0f; |
| 93 | |
| 94 | int currentX = x0; |
| 95 | int currentY = y0; |
| 96 | |
| 97 | while (true) { |
| 98 | visitor.visit(currentX, currentY); |
| 99 | float t = fl::min(tMaxX, tMaxY); |
| 100 | if (t > maxT) |
| 101 | break; |
| 102 | |
| 103 | if (tMaxX < tMaxY) { |
| 104 | tMaxX += tDeltaX; |
| 105 | currentX += stepX; |
| 106 | } else { |
| 107 | tMaxY += tDeltaY; |
| 108 | currentY += stepY; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Ensure the end cell (x1, y1) is visited at least once |
| 113 | if (currentX != x1 || currentY != y1) { |
| 114 | visitor.visit(x1, y1); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | /// @brief Traverse a grid segment using fixed-point 8.8 arithmetic. |
| 119 | /// @tparam GridVisitor |