Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
vector_object_shapes.cpp
1 // Copyright (c) 2023 Samsung R&D Institute Russia
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 #include "nav2_map_server/vector_object_shapes.hpp"
16 
17 #include <uuid/uuid.h>
18 #include <algorithm>
19 #include <cmath>
20 #include <exception>
21 #include <limits>
22 #include <stdexcept>
23 #include <utility>
24 #include <vector>
25 
26 #include "geometry_msgs/msg/pose_stamped.hpp"
27 
28 #include "nav2_util/occ_grid_utils.hpp"
29 #include "nav2_util/occ_grid_values.hpp"
30 #include "nav2_util/geometry_utils.hpp"
31 #include "nav2_util/raytrace_line_2d.hpp"
32 #include "nav2_util/robot_utils.hpp"
33 #include "nav2_ros_common/tf2_factories.hpp"
34 
35 namespace nav2_map_server
36 {
37 
38 // ---------- Shape ----------
39 
40 Shape::Shape(const nav2::LifecycleNode::WeakPtr & node)
41 : type_(UNKNOWN), node_(node)
42 {}
43 
45 {}
46 
47 ShapeType Shape::getType()
48 {
49  return type_;
50 }
51 
53  nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
54 {
55  double wx1, wy1, wx2, wy2;
56  unsigned int mx1, my1, mx2, my2;
57  getBoundaries(wx1, wy1, wx2, wy2);
58  if (
59  !nav2_util::worldToMap(map, wx1, wy1, mx1, my1) ||
60  !nav2_util::worldToMap(map, wx2, wy2, mx2, my2))
61  {
62  return false;
63  }
64 
65  const double origin_x = map->info.origin.position.x;
66  const double resolution = map->info.resolution;
67  const int8_t value = getValue();
68  std::vector<std::pair<double, double>> spans;
69  for (unsigned int my = my1; my <= my2; my++) {
70  double row_x, row_y;
71  nav2_util::mapToWorld(map, mx1, my, row_x, row_y);
72  const auto inside = [&](unsigned int mx) {
73  double wx, wy;
74  nav2_util::mapToWorld(map, mx, my, wx, wy);
75  return isPointInside(wx, wy);
76  };
77  getRowSpans(row_y, spans);
78  int8_t * row = map->data.data() + static_cast<size_t>(my) * map->info.width;
79  for (const auto & [x_begin, x_end] : spans) {
80  // First and last cell whose center is in [x_begin, x_end)
81  const auto center_x = [&](int64_t mx) {
82  double wx, wy;
83  nav2_util::mapToWorld(map, static_cast<unsigned int>(mx), my, wx, wy);
84  return wx;
85  };
86  int64_t lo = static_cast<int64_t>(std::clamp(
87  std::ceil((x_begin - origin_x) / resolution - 0.5),
88  static_cast<double>(mx1), static_cast<double>(mx2)));
89  int64_t hi = static_cast<int64_t>(std::clamp(
90  std::floor((x_end - origin_x) / resolution - 0.5),
91  static_cast<double>(mx1), static_cast<double>(mx2)));
92  // ceil/floor may be off by one when a center lies exactly on the boundary
93  while (lo > mx1 && center_x(lo - 1) >= x_begin) {
94  lo--;
95  }
96  while (lo <= mx2 && center_x(lo) < x_begin) {
97  lo++;
98  }
99  while (hi < mx2 && center_x(hi + 1) < x_end) {
100  hi++;
101  }
102  while (hi >= mx1 && center_x(hi) >= x_end) {
103  hi--;
104  }
105  // Spans may be slightly too wide (circles): trim with the exact test
106  while (lo <= hi && !inside(static_cast<unsigned int>(lo))) {
107  lo++;
108  }
109  while (hi >= lo && !inside(static_cast<unsigned int>(hi))) {
110  hi--;
111  }
112  if (lo <= hi) {
113  processRun(row + lo, static_cast<size_t>(hi - lo + 1), value, overlay_type);
114  }
115  }
116  }
117  return true;
118 }
119 
121  int8_t * cells, const size_t count, const int8_t shape_val,
122  const OverlayType overlay_type)
123 {
124  switch (overlay_type) {
125  case OverlayType::OVERLAY_SEQ:
126  std::fill_n(cells, count, shape_val);
127  return;
128  case OverlayType::OVERLAY_MAX:
129  for (size_t i = 0; i < count; i++) {
130  cells[i] = std::max(cells[i], shape_val);
131  }
132  return;
133  case OverlayType::OVERLAY_MIN:
134  if (shape_val == nav2_util::OCC_GRID_UNKNOWN) {
135  return;
136  }
137  for (size_t i = 0; i < count; i++) {
138  if (cells[i] == nav2_util::OCC_GRID_UNKNOWN || shape_val < cells[i]) {
139  cells[i] = shape_val;
140  }
141  }
142  return;
143  default:
144  throw std::runtime_error{"Unknown overlay type"};
145  }
146 }
147 
148 bool Shape::obtainShapeUUID(const std::string & shape_name, unsigned char * out_uuid)
149 {
150  auto node = node_.lock();
151  if (!node) {
152  throw std::runtime_error{"Failed to lock node"};
153  }
154 
155  try {
156  // Try to get shape UUID from ROS-parameters
157  std::string uuid_str = nav2::declare_or_get_parameter<std::string>(
158  node, shape_name + ".uuid");
159  if (uuid_parse(uuid_str.c_str(), out_uuid) != 0) {
160  RCLCPP_ERROR(
161  node->get_logger(),
162  "[%s] Can not parse UUID string for shape: %s",
163  shape_name.c_str(), uuid_str.c_str());
164  return false;
165  }
166  } catch (const std::exception &) {
167  // If no UUID was specified, generate a new one
168  uuid_generate(out_uuid);
169 
170  char uuid_str[37];
171  uuid_unparse(out_uuid, uuid_str);
172  RCLCPP_INFO(
173  node->get_logger(),
174  "[%s] No UUID is specified for shape. Generating a new one: %s",
175  shape_name.c_str(), uuid_str);
176  }
177 
178  return true;
179 }
180 
181 // ---------- Polygon ----------
182 
183 Polygon::Polygon(
184  const nav2::LifecycleNode::WeakPtr & node)
185 : Shape::Shape(node)
186 {
187  type_ = POLYGON;
188 }
189 
190 int8_t Polygon::getValue() const
191 {
192  return params_->value;
193 }
194 
195 std::string Polygon::getFrameID() const
196 {
197  return params_->header.frame_id;
198 }
199 
200 std::string Polygon::getUUID() const
201 {
202  return unparseUUID(params_->uuid.uuid.data());
203 }
204 
205 bool Polygon::isUUID(const unsigned char * uuid) const
206 {
207  return uuid_compare(params_->uuid.uuid.data(), uuid) == 0;
208 }
209 
210 bool Polygon::isFill() const
211 {
212  return params_->closed;
213 }
214 
215 bool Polygon::obtainParams(const std::string & shape_name)
216 {
217  auto node = node_.lock();
218  if (!node) {
219  throw std::runtime_error{"Failed to lock node"};
220  }
221 
222  if (!params_) {
223  params_ = std::make_shared<nav2_msgs::msg::PolygonObject>();
224  }
225  if (!polygon_) {
226  polygon_ = std::make_shared<geometry_msgs::msg::Polygon>();
227  }
228 
229  params_->header.frame_id = nav2::declare_or_get_parameter(
230  node, shape_name + ".frame_id", std::string{"map"});
231  params_->value = nav2::declare_or_get_parameter(
232  node, shape_name + ".value", static_cast<int>(nav2_util::OCC_GRID_OCCUPIED));
233  params_->closed = nav2::declare_or_get_parameter(
234  node, shape_name + ".closed", true);
235 
236  std::vector<double> poly_row;
237  try {
238  poly_row = nav2::declare_or_get_parameter<std::vector<double>>(
239  node, shape_name + ".points");
240  } catch (const std::exception & ex) {
241  RCLCPP_ERROR(
242  node->get_logger(),
243  "[%s] Error while getting polygon parameters: %s",
244  shape_name.c_str(), ex.what());
245  return false;
246  }
247  // Check for points format correctness
248  if (poly_row.size() < 6 || poly_row.size() % 2 != 0) {
249  RCLCPP_ERROR(
250  node->get_logger(),
251  "[%s] Polygon has incorrect points description",
252  shape_name.c_str());
253  return false;
254  }
255 
256  // Obtain polygon vertices
257  geometry_msgs::msg::Point32 point;
258  bool first = true;
259  for (double val : poly_row) {
260  if (first) {
261  point.x = val;
262  } else {
263  point.y = val;
264  params_->points.push_back(point);
265  }
266  first = !first;
267  }
268 
269  // Filling the polygon_ with obtained points in map's frame
270  polygon_->points = params_->points;
271 
272  // Getting shape UUID
273  return obtainShapeUUID(shape_name, params_->uuid.uuid.data());
274 }
275 
276 nav2_msgs::msg::PolygonObject::SharedPtr Polygon::getParams() const
277 {
278  return params_;
279 }
280 
281 bool Polygon::setParams(const nav2_msgs::msg::PolygonObject::SharedPtr params)
282 {
283  params_ = params;
284 
285  if (!polygon_) {
286  polygon_ = std::make_shared<geometry_msgs::msg::Polygon>();
287  }
288  polygon_->points = params_->points;
289 
290  // If no UUID was specified, generate a new one
291  if (uuid_is_null(params_->uuid.uuid.data())) {
292  uuid_generate(params_->uuid.uuid.data());
293  }
294 
295  return checkConsistency();
296 }
297 
299  const std::string & to_frame,
300  const nav2::TransformBuffer::SharedPtr tf_buffer,
301  const double transform_tolerance)
302 {
303  geometry_msgs::msg::PoseStamped from_pose, to_pose;
304  from_pose.header = params_->header;
305  for (unsigned int i = 0; i < params_->points.size(); i++) {
306  from_pose.pose.position.x = params_->points[i].x;
307  from_pose.pose.position.y = params_->points[i].y;
308  from_pose.pose.position.z = params_->points[i].z;
309  if (
310  nav2_util::transformPoseInTargetFrame(
311  from_pose, to_pose, *tf_buffer, to_frame, transform_tolerance))
312  {
313  polygon_->points[i].x = to_pose.pose.position.x;
314  polygon_->points[i].y = to_pose.pose.position.y;
315  polygon_->points[i].z = to_pose.pose.position.z;
316  } else {
317  return false;
318  }
319  }
320 
321  return true;
322 }
323 
324 void Polygon::getBoundaries(double & min_x, double & min_y, double & max_x, double & max_y)
325 {
326  min_x = std::numeric_limits<double>::max();
327  min_y = std::numeric_limits<double>::max();
328  max_x = std::numeric_limits<double>::lowest();
329  max_y = std::numeric_limits<double>::lowest();
330 
331  for (auto point : polygon_->points) {
332  min_x = std::min(min_x, static_cast<double>(point.x));
333  min_y = std::min(min_y, static_cast<double>(point.y));
334  max_x = std::max(max_x, static_cast<double>(point.x));
335  max_y = std::max(max_y, static_cast<double>(point.y));
336  }
337 }
338 
339 bool Polygon::isPointInside(const double px, const double py) const
340 {
341  return nav2_util::geometry_utils::isPointInsidePolygon(px, py, polygon_->points);
342 }
343 
345  const double py, std::vector<std::pair<double, double>> & spans) const
346 {
347  // Same edge rule and intersection formula as isPointInsidePolygon()
348  const auto & points = polygon_->points;
349  std::vector<double> crossings;
350  int i = points.size() - 1;
351  for (int j = 0; j < static_cast<int>(points.size()); j++) {
352  if ((py <= points[i].y) == (py > points[j].y)) {
353  crossings.push_back(
354  points[i].x + (py - points[i].y) * (points[j].x - points[i].x) /
355  (points[j].y - points[i].y));
356  }
357  i = j;
358  }
359  std::sort(crossings.begin(), crossings.end());
360 
361  spans.clear();
362  const size_t count = crossings.size();
363  if (count % 2 == 1) {
364  spans.emplace_back(std::numeric_limits<double>::lowest(), crossings[0]);
365  }
366  for (size_t k = 1; k < count; k++) {
367  if ((count - k) % 2 == 1) {
368  spans.emplace_back(crossings[k - 1], crossings[k]);
369  }
370  }
371 }
372 
374  nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
375 {
376  unsigned int mx0, my0, mx1, my1;
377 
378  auto node = node_.lock();
379  if (!node) {
380  throw std::runtime_error{"Failed to lock node"};
381  }
382 
383  if (!nav2_util::worldToMap(map, polygon_->points[0].x, polygon_->points[0].y, mx1, my1)) {
384  RCLCPP_ERROR(
385  node->get_logger(),
386  "[UUID: %s] Can not convert (%f, %f) point to map",
387  getUUID().c_str(), polygon_->points[0].x, polygon_->points[0].y);
388  return;
389  }
390 
391  MapAction ma(map, params_->value, overlay_type);
392  for (unsigned int i = 1; i < polygon_->points.size(); i++) {
393  mx0 = mx1;
394  my0 = my1;
395  if (!nav2_util::worldToMap(map, polygon_->points[i].x, polygon_->points[i].y, mx1, my1)) {
396  RCLCPP_ERROR(
397  node->get_logger(),
398  "[UUID: %s] Can not convert (%f, %f) point to map",
399  getUUID().c_str(), polygon_->points[i].x, polygon_->points[i].y);
400  return;
401  }
402  nav2_util::raytraceLine(ma, mx0, my0, mx1, my1, map->info.width);
403  }
404 }
405 
407 {
408  if (params_->points.size() < 3) {
409  auto node = node_.lock();
410  if (!node) {
411  throw std::runtime_error{"Failed to lock node"};
412  }
413 
414  RCLCPP_ERROR(
415  node->get_logger(),
416  "[UUID: %s] Polygon has incorrect number of vertices: %li",
417  getUUID().c_str(), params_->points.size());
418  return false;
419  }
420 
421  return true;
422 }
423 
424 // ---------- Circle ----------
425 
426 Circle::Circle(
427  const nav2::LifecycleNode::WeakPtr & node)
428 : Shape::Shape(node)
429 {
430  type_ = CIRCLE;
431 }
432 
433 int8_t Circle::getValue() const
434 {
435  return params_->value;
436 }
437 
438 std::string Circle::getFrameID() const
439 {
440  return params_->header.frame_id;
441 }
442 
443 std::string Circle::getUUID() const
444 {
445  return unparseUUID(params_->uuid.uuid.data());
446 }
447 
448 bool Circle::isUUID(const unsigned char * uuid) const
449 {
450  return uuid_compare(params_->uuid.uuid.data(), uuid) == 0;
451 }
452 
453 bool Circle::isFill() const
454 {
455  return params_->fill;
456 }
457 
458 bool Circle::obtainParams(const std::string & shape_name)
459 {
460  auto node = node_.lock();
461  if (!node) {
462  throw std::runtime_error{"Failed to lock node"};
463  }
464 
465  if (!params_) {
466  params_ = std::make_shared<nav2_msgs::msg::CircleObject>();
467  }
468  if (!center_) {
469  center_ = std::make_shared<geometry_msgs::msg::Point32>();
470  }
471 
472  params_->header.frame_id = nav2::declare_or_get_parameter(
473  node, shape_name + ".frame_id", std::string{"map"});
474  params_->value = nav2::declare_or_get_parameter(
475  node, shape_name + ".value", static_cast<int>(nav2_util::OCC_GRID_OCCUPIED));
476  params_->fill = nav2::declare_or_get_parameter(
477  node, shape_name + ".fill", true);
478 
479  std::vector<double> center_row;
480  try {
481  center_row = nav2::declare_or_get_parameter<std::vector<double>>(
482  node, shape_name + ".center");
483  params_->radius = nav2::declare_or_get_parameter<double>(
484  node, shape_name + ".radius");
485  if (params_->radius < 0) {
486  RCLCPP_ERROR(
487  node->get_logger(),
488  "[%s] Circle has incorrect radius less than zero",
489  shape_name.c_str());
490  return false;
491  }
492  } catch (const std::exception & ex) {
493  RCLCPP_ERROR(
494  node->get_logger(),
495  "[%s] Error while getting circle parameters: %s",
496  shape_name.c_str(), ex.what());
497  return false;
498  }
499  // Check for points format correctness
500  if (center_row.size() != 2) {
501  RCLCPP_ERROR(
502  node->get_logger(),
503  "[%s] Circle has incorrect center description",
504  shape_name.c_str());
505  return false;
506  }
507 
508  // Obtain circle center
509  params_->center.x = center_row[0];
510  params_->center.y = center_row[1];
511  // Setting the center_ with obtained circle center in map's frame
512  *center_ = params_->center;
513 
514  // Getting shape UUID
515  return obtainShapeUUID(shape_name, params_->uuid.uuid.data());
516 }
517 
518 nav2_msgs::msg::CircleObject::SharedPtr Circle::getParams() const
519 {
520  return params_;
521 }
522 
523 bool Circle::setParams(const nav2_msgs::msg::CircleObject::SharedPtr params)
524 {
525  params_ = params;
526 
527  if (!center_) {
528  center_ = std::make_shared<geometry_msgs::msg::Point32>();
529  }
530  *center_ = params_->center;
531 
532  // If no UUID was specified, generate a new one
533  if (uuid_is_null(params_->uuid.uuid.data())) {
534  uuid_generate(params_->uuid.uuid.data());
535  }
536 
537  return checkConsistency();
538 }
539 
541  const std::string & to_frame,
542  const nav2::TransformBuffer::SharedPtr tf_buffer,
543  const double transform_tolerance)
544 {
545  geometry_msgs::msg::PoseStamped from_pose, to_pose;
546  from_pose.header = params_->header;
547  from_pose.pose.position.x = params_->center.x;
548  from_pose.pose.position.y = params_->center.y;
549  from_pose.pose.position.z = params_->center.z;
550  if (
551  nav2_util::transformPoseInTargetFrame(
552  from_pose, to_pose, *tf_buffer, to_frame, transform_tolerance))
553  {
554  center_->x = to_pose.pose.position.x;
555  center_->y = to_pose.pose.position.y;
556  center_->z = to_pose.pose.position.z;
557  } else {
558  return false;
559  }
560 
561  return true;
562 }
563 
564 void Circle::getBoundaries(double & min_x, double & min_y, double & max_x, double & max_y)
565 {
566  min_x = center_->x - params_->radius;
567  min_y = center_->y - params_->radius;
568  max_x = center_->x + params_->radius;
569  max_y = center_->y + params_->radius;
570 }
571 
572 bool Circle::isPointInside(const double px, const double py) const
573 {
574  return ( (px - center_->x) * (px - center_->x) + (py - center_->y) * (py - center_->y) ) <=
575  params_->radius * params_->radius;
576 }
577 
579  const double py, std::vector<std::pair<double, double>> & spans) const
580 {
581  spans.clear();
582  const double dy = py - center_->y;
583  const double half_chord_sq = params_->radius * params_->radius - dy * dy;
584  if (half_chord_sq < 0.0) {
585  return;
586  }
587  const double half_chord = std::sqrt(half_chord_sq);
588  // Pad against rounding, putFill() trims the ends
589  const double padding = std::max(1.0, static_cast<double>(params_->radius)) * 1e-9;
590  spans.emplace_back(center_->x - half_chord - padding, center_->x + half_chord + padding);
591 }
592 
594  nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
595 {
596  unsigned int mcx, mcy;
597  if (!centerToMap(map, mcx, mcy)) {
598  return;
599  }
600 
601  // Implementation of the circle generation algorithm, based on the following work:
602  // Berthold K.P. Horn "Circle generators for display devices"
603  // Computer Graphics and Image Processing 5.2 (1976): 280-288.
604 
605  // Inputs initialization
606  const int r = static_cast<int>(std::round(params_->radius / map->info.resolution));
607  int x = r;
608  int y = 1;
609 
610  // Error initialization
611  int s = -r;
612 
613  // Calculation algorithm
614  while (x > y) { // Calculating only first circle octant
615  // Put 8 points in each octant reflecting symmetrically
616  putPoint(mcx + x, mcy + y, map, overlay_type);
617  putPoint(mcx + y, mcy + x, map, overlay_type);
618  putPoint(mcx - x + 1, mcy + y, map, overlay_type);
619  putPoint(mcx + y, mcy - x + 1, map, overlay_type);
620  putPoint(mcx - x + 1, mcy - y + 1, map, overlay_type);
621  putPoint(mcx - y + 1, mcy - x + 1, map, overlay_type);
622  putPoint(mcx + x, mcy - y + 1, map, overlay_type);
623  putPoint(mcx - y + 1, mcy + x, map, overlay_type);
624 
625  s = s + 2 * y + 1;
626  y++;
627  if (s > 0) {
628  s = s - 2 * x + 2;
629  x--;
630  }
631  }
632 
633  // Corner case for x == y: do not put end points twice
634  if (x == y) {
635  putPoint(mcx + x, mcy + y, map, overlay_type);
636  putPoint(mcx - x + 1, mcy + y, map, overlay_type);
637  putPoint(mcx - x + 1, mcy - y + 1, map, overlay_type);
638  putPoint(mcx + x, mcy - y + 1, map, overlay_type);
639  }
640 }
641 
643 {
644  if (params_->radius < 0.0) {
645  auto node = node_.lock();
646  if (!node) {
647  throw std::runtime_error{"Failed to lock node"};
648  }
649 
650  RCLCPP_ERROR(
651  node->get_logger(),
652  "[UUID: %s] Circle has incorrect radius less than zero",
653  getUUID().c_str());
654  return false;
655  }
656  return true;
657 }
658 
660  nav_msgs::msg::OccupancyGrid::ConstSharedPtr map,
661  unsigned int & mcx, unsigned int & mcy)
662 {
663  auto node = node_.lock();
664  if (!node) {
665  throw std::runtime_error{"Failed to lock node"};
666  }
667 
668  // Get center of circle in map coordinates
669  if (center_->x < map->info.origin.position.x || center_->y < map->info.origin.position.y) {
670  RCLCPP_ERROR(
671  node->get_logger(),
672  "[UUID: %s] Can not convert (%f, %f) circle center to map",
673  getUUID().c_str(), center_->x, center_->y);
674  return false;
675  }
676  // We need the circle center to be always shifted one cell less its logical center
677  // and to avoid any FP-accuracy losing on small values, so we are using another
678  // than nav2_util::worldToMap() approach
679  mcx = static_cast<unsigned int>(
680  std::round((center_->x - map->info.origin.position.x) / map->info.resolution)) - 1;
681  mcy = static_cast<unsigned int>(
682  std::round((center_->y - map->info.origin.position.y) / map->info.resolution)) - 1;
683  if (mcx >= map->info.width || mcy >= map->info.height) {
684  RCLCPP_ERROR(
685  node->get_logger(),
686  "[UUID: %s] Can not convert (%f, %f) point to map",
687  getUUID().c_str(), center_->x, center_->y);
688  return false;
689  }
690 
691  return true;
692 }
693 
694 inline void Circle::putPoint(
695  unsigned int mx, unsigned int my,
696  nav_msgs::msg::OccupancyGrid::SharedPtr map,
697  const OverlayType overlay_type)
698 {
699  processCell(map, my * map->info.width + mx, params_->value, overlay_type);
700 }
701 
702 } // namespace nav2_map_server
bool isUUID(const unsigned char *uuid) const
Checks whether the shape is equal to a given UUID.
int8_t getValue() const
Gets the value of the shape.
bool toFrame(const std::string &to_frame, const nav2::TransformBuffer::SharedPtr tf_buffer, const double transform_tolerance)
Transforms shape coordinates to a new frame.
void putPoint(unsigned int mx, unsigned int my, nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
Put Circle's point on map.
bool isPointInside(const double px, const double py) const
Is the point inside the shape.
std::string getUUID() const
Gets UUID of the shape.
void getBoundaries(double &min_x, double &min_y, double &max_x, double &max_y)
Gets shape box-boundaries.
std::string getFrameID() const
Gets frame ID of the shape.
bool centerToMap(nav_msgs::msg::OccupancyGrid::ConstSharedPtr map, unsigned int &mcx, unsigned int &mcy)
Converts circle center to map coordinates considering FP-accuracy losing on small values when using c...
bool isFill() const
Whether the shape to be filled or only its borders to be put on map.
void getRowSpans(const double py, std::vector< std::pair< double, double >> &spans) const
Gets X-interval covered by the circle on the horizontal line y = py.
nav2_msgs::msg::CircleObject::SharedPtr params_
Input circle parameters (could be in any frame)
bool setParams(const nav2_msgs::msg::CircleObject::SharedPtr params)
Tries to update Circle parameters.
void putBorders(nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
Puts shape borders on map.
nav2_msgs::msg::CircleObject::SharedPtr getParams() const
Gets Circle parameters.
bool checkConsistency()
Checks that shape is consistent for further operation.
geometry_msgs::msg::Point32::SharedPtr center_
Circle center in the map's frame.
bool obtainParams(const std::string &shape_name)
Supporting routine obtaining ROS-parameters for the given vector object.
Functor class used in raytraceLine algorithm.
std::string getUUID() const
Gets UUID of the shape.
void getRowSpans(const double py, std::vector< std::pair< double, double >> &spans) const
Gets X-intervals covered by the polygon on the horizontal line y = py.
void getBoundaries(double &min_x, double &min_y, double &max_x, double &max_y)
Gets shape box-boundaries.
void putBorders(nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
Puts shape borders on map.
bool toFrame(const std::string &to_frame, const nav2::TransformBuffer::SharedPtr tf_buffer, const double transform_tolerance)
Transforms shape coordinates to a new frame.
bool isUUID(const unsigned char *uuid) const
Checks whether the shape is equal to a given UUID.
nav2_msgs::msg::PolygonObject::SharedPtr getParams() const
Gets Polygon parameters.
int8_t getValue() const
Gets the value of the shape.
bool setParams(const nav2_msgs::msg::PolygonObject::SharedPtr params)
Tries to update Polygon parameters.
std::string getFrameID() const
Gets frame ID of the shape.
nav2_msgs::msg::PolygonObject::SharedPtr params_
Input polygon parameters (could be in any frame)
bool checkConsistency()
Checks that shape is consistent for further operation.
bool isPointInside(const double px, const double py) const
Is the point inside the shape.
bool isFill() const
Whether the shape to be filled or only its borders to be put on map.
bool obtainParams(const std::string &shape_name)
Supporting routine obtaining ROS-parameters for the given vector object.
geometry_msgs::msg::Polygon::SharedPtr polygon_
Polygon in the map's frame.
Basic class, other vector objects to be inherited from.
bool obtainShapeUUID(const std::string &shape_name, unsigned char *out_uuid)
Supporting routine obtaining shape UUID from ROS-parameters for the given shape object.
virtual void getBoundaries(double &min_x, double &min_y, double &max_x, double &max_y)=0
Gets shape box-boundaries. Empty virtual method intended to be used in child implementations.
virtual bool isPointInside(const double px, const double py) const =0
Is the point inside the shape. Empty virtual method intended to be used in child implementations.
ShapeType type_
Type of shape.
ShapeType getType()
Returns type of the shape.
nav2::LifecycleNode::WeakPtr node_
VectorObjectServer node.
virtual void getRowSpans(const double py, std::vector< std::pair< double, double >> &spans) const =0
Gets X-intervals covered by the shape on the horizontal line y = py. Intervals may be slightly wider ...
virtual ~Shape()
Shape destructor.
Shape(const nav2::LifecycleNode::WeakPtr &node)
Shape basic class constructor.
bool putFill(nav_msgs::msg::OccupancyGrid::SharedPtr map, const OverlayType overlay_type)
Puts filled shape on map.
static void processRun(int8_t *cells, const size_t count, const int8_t shape_val, const OverlayType overlay_type)
Updates a run of consecutive cells with given shape value according to the overlay type.
virtual int8_t getValue() const =0
Gets the value of the shape. Empty virtual method intended to be used in child implementations.