area_occupancy_estimator.h
Go to the documentation of this file.
1 #ifndef __AREA_OCCUPANCY_ESTIMATOR_H
2 #define __AREA_OCCUPANCY_ESTIMATOR_H
3 
4 #include <cassert>
5 #include <vector>
6 #include <type_traits>
7 
9 
18 private: // types
19  enum class IntersLocation : char {
20  Bot = 0, Left = 1, Top = 2, Right = 3
21  };
22 
23  struct Intersection {
24  Intersection(IntersLocation loc, double inters_x, double inters_y) :
25  location(loc), x(inters_x), y(inters_y) {}
26 
28  bool is_horiz() const {
29  return location == IntersLocation::Bot || location == IntersLocation::Top;
30  }
31  double x, y;
32  };
33 
34  using Intersections = std::vector<Intersection>;
35 
36  struct Ray { // in parametric form
37  Ray(double x_s, double x_d, double y_s, double y_d) :
38  x_st(x_s), x_delta(x_d), y_st(y_s), y_delta(y_d) {}
39 
40  double x_st, x_delta;
41  double y_st, y_delta;
42 
43  void intersect_horiz_segm(double st_x, double end_x, double y,
44  IntersLocation loc, Intersections &consumer) {
45  if (EQ_DOUBLE(y_delta, 0))
46  return;
47 
48  double inters_alpha = (y - y_st) / y_delta;
49  double inters_x = x_st + inters_alpha * x_delta;
50  if (inters_x < st_x || end_x < inters_x) // out of segment bounds
51  return;
52 
53  consumer.push_back(Intersection(loc, inters_x, y));
54  }
55 
56  void intersect_vert_segm(double st_y, double end_y, double x,
57  IntersLocation loc, Intersections &consumer) {
58  if (EQ_DOUBLE(x_delta, 0))
59  return;
60 
61  double inters_alpha = (x - x_st) / x_delta;
62  double inters_y = y_st + inters_alpha * y_delta;
63  if (inters_y < st_y || end_y < inters_y) // out of segment bounds
64  return;
65  consumer.push_back(Intersection(loc, x, inters_y));
66  }
67  };
68 
69 public: //methods
70 
75  AreaOccupancyEstimator(double occ, double empty) :
76  CellOccupancyEstimator(occ, empty) {}
77 
81  virtual Occupancy estimate_occupancy(const Beam &beam,
82  const Rectangle &cell_bnds,
83  bool is_occ) override {
84  Intersections intrs = find_intersections(beam, cell_bnds, is_occ);
85  double chunk_area = compute_chunk_area(beam, cell_bnds, is_occ, intrs);
86  return estimate_occupancy(chunk_area, cell_bnds.area(), is_occ);
87  }
88 
89 private: // methods
91  const Rectangle &bnds, bool is_occ) {
92  Intersections intersections;
93  // if the cell is occupied, rotate ray around beam by 90 degrees
94  Ray ray = is_occ ?
95  Ray(beam.x_end, beam.y_st - beam.y_end,
96  beam.y_end, beam.x_end - beam.x_st) :
97  Ray(beam.x_st, beam.x_end - beam.x_st,
98  beam.y_st, beam.y_end - beam.y_st);
99 
100  ray.intersect_horiz_segm(bnds.left, bnds.right, bnds.top,
101  IntersLocation::Top, intersections);
102  ray.intersect_horiz_segm(bnds.left, bnds.right, bnds.bot,
103  IntersLocation::Bot, intersections);
104  ray.intersect_vert_segm(bnds.bot, bnds.top, bnds.left,
105  IntersLocation::Left, intersections);
106  ray.intersect_vert_segm(bnds.bot, bnds.top, bnds.right,
107  IntersLocation::Right, intersections);
108  return intersections;
109  }
110 
111  double compute_chunk_area(const Beam &beam, const Rectangle &bnds,
112  bool is_occ,
113  const std::vector<Intersection> inters) {
114  if (inters.size() == 0) {
115  // TODO: deal with line approx introduced by Bresenham
116  return bnds.area() / 2;
117  }
118 
119  assert(inters.size() == 2 || inters.size() == 4);
120  if (inters.size() == 4) {
121  // TODO: generalize spec. case. Looks like ray is a cells diagonal
122  return (bnds.top - bnds.bot) * (bnds.right - bnds.left) / 2;
123  }
124 
125  double corner_x = 0, corner_y = 0, area = 0;
126  double chunk_is_triangle = inters[0].is_horiz() ^ inters[1].is_horiz();
127  if (chunk_is_triangle) {
128  // determine "base" corner (corner of cell that
129  // is also a corner of the triangle
130  for (auto &inter : inters) {
131  switch (inter.location) {
132  case IntersLocation::Bot: corner_y = bnds.bot; break;
133  case IntersLocation::Top: corner_y = bnds.top; break;
134  case IntersLocation::Left: corner_x = bnds.left; break;
135  case IntersLocation::Right: corner_x = bnds.right; break;
136  }
137  }
138  // calculate triange area
139  area = 0.5;
140  for (auto &inter : inters) {
141  if (inter.is_horiz()) {
142  area *= inter.x - corner_x;
143  } else {
144  area *= inter.y - corner_y;
145  }
146  }
147  } else {
148  // chunk is trapezoid
149  // corner choise doesn't matter, so pick bottom-left one.
150  corner_x = bnds.bot, corner_y = bnds.left;
151  double base_sum = 0;
152  for (auto &inter : inters) {
153  if (inter.is_horiz()) {
154  base_sum += inter.x - corner_x;
155  } else {
156  base_sum += inter.y - corner_y;
157  }
158  }
159  // NOTE: cell is supposed to be a square
160  area = 0.5 * (bnds.top - bnds.bot) * base_sum;
161  }
162  if (is_occ &&
163  are_on_the_same_side(inters[0].x, inters[0].y, inters[1].x, inters[1].y,
164  beam.x_st, beam.y_st, corner_x, corner_y)) {
165  area = bnds.area() - area;
166  }
167  return area;
168  }
169 
170  bool are_on_the_same_side(double line_x1, double line_y1,
171  double line_x2, double line_y2,
172  double x1, double y1, double x2, double y2) {
173  double dx = line_x2 - line_x1, dy = line_y2 - line_y1;
174  return 0 < (dy*y1 - dx*x1 + dy*x1 - dx*y1) *
175  (dy*y2 - dx*x2 + dy*x2 - dx*y2);
176  }
177 
178  Occupancy estimate_occupancy(double chunk_area, double total_area,
179  bool is_occ) {
180  double area_rate = chunk_area / total_area;
181  if (is_occ) {
182  // Far ToDo: think about experiment quality metric for an occupied case.
183  return Occupancy{area_rate, 1.0};
184  } else {
185  if (0.5 < area_rate) {
186  area_rate = 1 - area_rate;
187  }
188  return Occupancy{base_empty_prob(), area_rate};
189  }
190  }
191 };
192 
193 #endif
double top
The top of a rectangle.
double bot
The bottom of a rectangle.
double base_empty_prob()
Returns the probability of being empty.
std::vector< Intersection > Intersections
void intersect_vert_segm(double st_y, double end_y, double x, IntersLocation loc, Intersections &consumer)
double right
The right side of a rectangle.
#define EQ_DOUBLE(a, b)
void intersect_horiz_segm(double st_x, double end_x, double y, IntersLocation loc, Intersections &consumer)
TFSIMD_FORCE_INLINE const tfScalar & y() const
double compute_chunk_area(const Beam &beam, const Rectangle &bnds, bool is_occ, const std::vector< Intersection > inters)
double area() const
double y_end
Coordinates where the beam reaches an obstacle.
Defines interface Cell Occupancy Estimator. There are structures Occupancy and Beam that are used in ...
A strategy that estimates a grid cell&#39;s occupancy based on how a laser beam passes through the cell...
double left
The left side of a rectangle.
TFSIMD_FORCE_INLINE const tfScalar & x() const
Defines an axis-aligned rectangle.
AreaOccupancyEstimator(double occ, double empty)
bool are_on_the_same_side(double line_x1, double line_y1, double line_x2, double line_y2, double x1, double y1, double x2, double y2)
Intersection(IntersLocation loc, double inters_x, double inters_y)
Occupancy estimate_occupancy(double chunk_area, double total_area, bool is_occ)
double y_st
Coordinates of a start of the beam.
virtual Occupancy estimate_occupancy(const Beam &beam, const Rectangle &cell_bnds, bool is_occ) override
Intersections find_intersections(const Beam &beam, const Rectangle &bnds, bool is_occ)
Ray(double x_s, double x_d, double y_s, double y_d)


tiny_slam
Author(s):
autogenerated on Mon Jun 10 2019 15:30:57