Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
distance_transform.hpp
1 // Copyright (c) 2026, Dexory (Tony Najjar)
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef NAV2_COSTMAP_2D__DISTANCE_TRANSFORM_HPP_
16 #define NAV2_COSTMAP_2D__DISTANCE_TRANSFORM_HPP_
17 
18 #include <limits>
19 #include <vector>
20 #ifdef _OPENMP
21 #include <omp.h>
22 #endif
23 #include <Eigen/Core>
24 
25 
26 namespace nav2_costmap_2d
27 {
28 
30 using MatrixXfRM = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
31 
48 {
49 public:
51  static constexpr float DT_INF = std::numeric_limits<float>::max();
52 
66  static void distanceTransform1D(
67  const float * f, float * d, int n,
68  int * v, float * z)
69  {
70  if (!f || !d || !v || !z || n <= 0) {
71  return;
72  }
73 
74  int k = 0;
75  v[0] = 0;
76  z[0] = -DT_INF;
77  z[1] = DT_INF;
78 
79  for (int q = 1; q < n; q++) {
80  // Use integer arithmetic for squared values to avoid precision loss
81  // Only convert to float for the division operation
82  float s = (f[q] - f[v[k]] + static_cast<float>(q * q - v[k] * v[k])) /
83  (2.0f * static_cast<float>(q - v[k]));
84  while (s <= z[k]) {
85  k--;
86  s = (f[q] - f[v[k]] + static_cast<float>(q * q - v[k] * v[k])) /
87  (2.0f * static_cast<float>(q - v[k]));
88  }
89  k++;
90  v[k] = q;
91  z[k] = s;
92  z[k + 1] = DT_INF;
93  }
94 
95  k = 0;
96  for (int q = 0; q < n; q++) {
97  while (z[k + 1] < static_cast<float>(q)) {
98  k++;
99  }
100  const int diff = q - v[k];
101  d[q] = static_cast<float>(diff * diff) + f[v[k]];
102  }
103  }
104 
120  static void distanceTransform2D(MatrixXfRM & img, int height, int width)
121  {
122  // Column pass (parallelizable)
123 #ifdef _OPENMP
124  #pragma omp parallel for schedule(dynamic, 16)
125 #endif
126  for (int x = 0; x < width; x++) {
127  // Thread-local buffers
128  std::vector<float> f(height);
129  std::vector<float> d(height);
130  std::vector<int> v(height);
131  std::vector<float> z(height + 1);
132 
133  // Extract column
134  for (int y = 0; y < height; y++) {
135  f[y] = img(y, x);
136  }
137 
138  // 1D transform
139  distanceTransform1D(f.data(), d.data(), height, v.data(), z.data());
140 
141  // Write back
142  for (int y = 0; y < height; y++) {
143  img(y, x) = d[y];
144  }
145  }
146 
147  // Row pass (parallelizable)
148 #ifdef _OPENMP
149  #pragma omp parallel for schedule(dynamic, 16)
150 #endif
151  for (int y = 0; y < height; y++) {
152  // Thread-local buffers
153  std::vector<float> f(width);
154  std::vector<float> d(width);
155  std::vector<int> v(width);
156  std::vector<float> z(width + 1);
157 
158  // Extract row (already contiguous in row-major)
159  for (int x = 0; x < width; x++) {
160  f[x] = img(y, x);
161  }
162 
163  // 1D transform
164  distanceTransform1D(f.data(), d.data(), width, v.data(), z.data());
165 
166  // Write back
167  for (int x = 0; x < width; x++) {
168  img(y, x) = d[x];
169  }
170  }
171 
172  // Square root to get Euclidean distance (not squared distance)
173  img = img.cwiseSqrt();
174  }
175 };
176 
177 } // namespace nav2_costmap_2d
178 
179 #endif // NAV2_COSTMAP_2D__DISTANCE_TRANSFORM_HPP_
Efficient Euclidean distance transform using the Felzenszwalb-Huttenlocher algorithm.
static constexpr float DT_INF
Infinity constant for distance transform.
static void distanceTransform1D(const float *f, float *d, int n, int *v, float *z)
Perform 1D distance transform using lower envelope of parabolas.
static void distanceTransform2D(MatrixXfRM &img, int height, int width)
Perform 2D Euclidean distance transform using separable passes.
Eigen::Matrix< float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixXfRM
Row-major float matrix type for efficient row-wise access.