ray_casting.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2016 The Cartographer Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 namespace cartographer {
20 namespace mapping {
21 namespace {
22 
23 // Factor for subpixel accuracy of start and end point.
24 constexpr int kSubpixelScale = 1000;
25 
26 // We divide each pixel in kSubpixelScale x kSubpixelScale subpixels. 'begin'
27 // and 'end' are coordinates at subpixel precision. We compute all pixels in
28 // which some part of the line segment connecting 'begin' and 'end' lies.
29 void CastRay(const Eigen::Array2i& begin, const Eigen::Array2i& end,
30  const std::vector<uint16>& miss_table,
31  ProbabilityGrid* const probability_grid) {
32  // For simplicity, we order 'begin' and 'end' by their x coordinate.
33  if (begin.x() > end.x()) {
34  CastRay(end, begin, miss_table, probability_grid);
35  return;
36  }
37 
38  CHECK_GE(begin.x(), 0);
39  CHECK_GE(begin.y(), 0);
40  CHECK_GE(end.y(), 0);
41 
42  // Special case: We have to draw a vertical line in full pixels, as 'begin'
43  // and 'end' have the same full pixel x coordinate.
44  if (begin.x() / kSubpixelScale == end.x() / kSubpixelScale) {
45  Eigen::Array2i current(begin.x() / kSubpixelScale,
46  std::min(begin.y(), end.y()) / kSubpixelScale);
47  const int end_y = std::max(begin.y(), end.y()) / kSubpixelScale;
48  for (; current.y() <= end_y; ++current.y()) {
49  probability_grid->ApplyLookupTable(current, miss_table);
50  }
51  return;
52  }
53 
54  const int64 dx = end.x() - begin.x();
55  const int64 dy = end.y() - begin.y();
56  const int64 denominator = 2 * kSubpixelScale * dx;
57 
58  // The current full pixel coordinates. We begin at 'begin'.
59  Eigen::Array2i current = begin / kSubpixelScale;
60 
61  // To represent subpixel centers, we use a factor of 2 * 'kSubpixelScale' in
62  // the denominator.
63  // +-+-+-+ -- 1 = (2 * kSubpixelScale) / (2 * kSubpixelScale)
64  // | | | |
65  // +-+-+-+
66  // | | | |
67  // +-+-+-+ -- top edge of first subpixel = 2 / (2 * kSubpixelScale)
68  // | | | | -- center of first subpixel = 1 / (2 * kSubpixelScale)
69  // +-+-+-+ -- 0 = 0 / (2 * kSubpixelScale)
70 
71  // The center of the subpixel part of 'begin.y()' assuming the
72  // 'denominator', i.e., sub_y / denominator is in (0, 1).
73  int64 sub_y = (2 * (begin.y() % kSubpixelScale) + 1) * dx;
74 
75  // The distance from the from 'begin' to the right pixel border, to be divided
76  // by 2 * 'kSubpixelScale'.
77  const int first_pixel =
78  2 * kSubpixelScale - 2 * (begin.x() % kSubpixelScale) - 1;
79  // The same from the left pixel border to 'end'.
80  const int last_pixel = 2 * (end.x() % kSubpixelScale) + 1;
81 
82  // The full pixel x coordinate of 'end'.
83  const int end_x = std::max(begin.x(), end.x()) / kSubpixelScale;
84 
85  // Move from 'begin' to the next pixel border to the right.
86  sub_y += dy * first_pixel;
87  if (dy > 0) {
88  while (true) {
89  probability_grid->ApplyLookupTable(current, miss_table);
90  while (sub_y > denominator) {
91  sub_y -= denominator;
92  ++current.y();
93  probability_grid->ApplyLookupTable(current, miss_table);
94  }
95  ++current.x();
96  if (sub_y == denominator) {
97  sub_y -= denominator;
98  ++current.y();
99  }
100  if (current.x() == end_x) {
101  break;
102  }
103  // Move from one pixel border to the next.
104  sub_y += dy * 2 * kSubpixelScale;
105  }
106  // Move from the pixel border on the right to 'end'.
107  sub_y += dy * last_pixel;
108  probability_grid->ApplyLookupTable(current, miss_table);
109  while (sub_y > denominator) {
110  sub_y -= denominator;
111  ++current.y();
112  probability_grid->ApplyLookupTable(current, miss_table);
113  }
114  CHECK_NE(sub_y, denominator);
115  CHECK_EQ(current.y(), end.y() / kSubpixelScale);
116  return;
117  }
118 
119  // Same for lines non-ascending in y coordinates.
120  while (true) {
121  probability_grid->ApplyLookupTable(current, miss_table);
122  while (sub_y < 0) {
123  sub_y += denominator;
124  --current.y();
125  probability_grid->ApplyLookupTable(current, miss_table);
126  }
127  ++current.x();
128  if (sub_y == 0) {
129  sub_y += denominator;
130  --current.y();
131  }
132  if (current.x() == end_x) {
133  break;
134  }
135  sub_y += dy * 2 * kSubpixelScale;
136  }
137  sub_y += dy * last_pixel;
138  probability_grid->ApplyLookupTable(current, miss_table);
139  while (sub_y < 0) {
140  sub_y += denominator;
141  --current.y();
142  probability_grid->ApplyLookupTable(current, miss_table);
143  }
144  CHECK_NE(sub_y, 0);
145  CHECK_EQ(current.y(), end.y() / kSubpixelScale);
146 }
147 
148 void GrowAsNeeded(const sensor::RangeData& range_data,
149  ProbabilityGrid* const probability_grid) {
150  Eigen::AlignedBox2f bounding_box(range_data.origin.head<2>());
151  constexpr float kPadding = 1e-6f;
152  for (const Eigen::Vector3f& hit : range_data.returns) {
153  bounding_box.extend(hit.head<2>());
154  }
155  for (const Eigen::Vector3f& miss : range_data.misses) {
156  bounding_box.extend(miss.head<2>());
157  }
158  probability_grid->GrowLimits(bounding_box.min() -
159  kPadding * Eigen::Vector2f::Ones());
160  probability_grid->GrowLimits(bounding_box.max() +
161  kPadding * Eigen::Vector2f::Ones());
162 }
163 
164 } // namespace
165 
166 void CastRays(const sensor::RangeData& range_data,
167  const std::vector<uint16>& hit_table,
168  const std::vector<uint16>& miss_table,
169  const bool insert_free_space,
170  ProbabilityGrid* const probability_grid) {
171  GrowAsNeeded(range_data, probability_grid);
172 
173  const MapLimits& limits = probability_grid->limits();
174  const double superscaled_resolution = limits.resolution() / kSubpixelScale;
175  const MapLimits superscaled_limits(
176  superscaled_resolution, limits.max(),
177  CellLimits(limits.cell_limits().num_x_cells * kSubpixelScale,
178  limits.cell_limits().num_y_cells * kSubpixelScale));
179  const Eigen::Array2i begin =
180  superscaled_limits.GetCellIndex(range_data.origin.head<2>());
181  // Compute and add the end points.
182  std::vector<Eigen::Array2i> ends;
183  ends.reserve(range_data.returns.size());
184  for (const Eigen::Vector3f& hit : range_data.returns) {
185  ends.push_back(superscaled_limits.GetCellIndex(hit.head<2>()));
186  probability_grid->ApplyLookupTable(ends.back() / kSubpixelScale, hit_table);
187  }
188 
189  if (!insert_free_space) {
190  return;
191  }
192 
193  // Now add the misses.
194  for (const Eigen::Array2i& end : ends) {
195  CastRay(begin, end, miss_table, probability_grid);
196  }
197 
198  // Finally, compute and add empty rays based on misses in the range data.
199  for (const Eigen::Vector3f& missing_echo : range_data.misses) {
200  CastRay(begin, superscaled_limits.GetCellIndex(missing_echo.head<2>()),
201  miss_table, probability_grid);
202  }
203 }
204 
205 } // namespace mapping
206 } // namespace cartographer
const Eigen::Vector2d & max() const
Definition: map_limits.h:61
void CastRays(const sensor::RangeData &range_data, const std::vector< uint16 > &hit_table, const std::vector< uint16 > &miss_table, const bool insert_free_space, ProbabilityGrid *const probability_grid)
Definition: ray_casting.cc:166
int64_t int64
Definition: port.h:33
Eigen::Array2i GetCellIndex(const Eigen::Vector2f &point) const
Definition: map_limits.h:69
const MapLimits & limits() const
Definition: grid_2d.h:41
bool ApplyLookupTable(const Eigen::Array2i &cell_index, const std::vector< uint16 > &table)
const CellLimits & cell_limits() const
Definition: map_limits.h:64


cartographer
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:00:58