1 #ifndef SLAM_CTOR_CORE_GEOMETRY_PRIMITIVES_H 2 #define SLAM_CTOR_CORE_GEOMETRY_PRIMITIVES_H 12 Point2D(
double x_par = 0,
double y_par = 0) :
x(x_par),
y(y_par) {}
15 return std::pow(
x - pt.
x, 2) + std::pow(
y - pt.
y, 2);
33 return stream <<
"(" << pnt.
x <<
", " << pnt.
y <<
")";
52 bool is_point()
const {
return _is_horiz && _is_vert; }
57 explicit operator bool()
const {
return is_valid; }
66 assert(
false &&
"BUG: Contains is undefined for non-axes-aligned segment");
71 return x_projection_contains(p) && y_projection_contains(p);
75 return std::pow(_end.x - _beg.x, 2) + std::pow(_end.y - _beg.y, 2);
95 return stream <<
"[" << s.
beg() <<
"; " << s.
end() <<
"]";
100 Bot = 0, Left = 1, Top = 2, Right = 3
107 return location == Location::Bot || location == Location::Top;
116 Ray(
double x_s,
double x_d,
double y_s,
double y_d) :
117 beg{x_s, y_s}, delta{x_d, y_d} {}
119 explicit Ray(
const Segment2D &s) : beg(s.beg()), delta(s.end() - s.beg()) {}
125 intersect_horiz_segm(s.
beg().
x, s.
end().
x, s.
beg().
y, loc, consumer);
129 intersect_vert_segm(s.
beg().
y, s.
end().
y, s.
beg().
x, loc, consumer);
132 assert(
false &&
"BUG: Unable to intersect non-axes-aligned segment");
141 double inters_alpha = (y - beg.y) / delta.y;
142 double inters_x = beg.x + inters_alpha * delta.x;
143 if (inters_x < st_x || end_x < inters_x)
146 consumer.emplace_back(loc, inters_x, y);
154 double inters_alpha = (x - beg.x) / delta.x;
155 double inters_y = beg.y + inters_alpha * delta.y;
156 if (inters_y < st_y || end_y < inters_y)
159 consumer.emplace_back(loc, x, inters_y);
171 : _bot{b}, _top{t}, _left{l}, _right{r} {
172 assert(_bot <= _top);
173 assert(_left <= _right);
178 double bot()
const {
return _bot; }
179 double top()
const {
return _top; }
180 double left()
const {
return _left; }
181 double right()
const {
return _right; }
185 bool is_square()
const {
return vside_len() == hside_len(); }
186 double side()
const {
return vside_len(); }
187 double area()
const {
return vside_len() * hside_len(); }
189 return {left() + hside_len() / 2, bot() + vside_len() / 2};
192 bool is_line()
const {
return (vside_len() == 0) ^ (hside_len() == 0); }
193 bool is_point()
const {
return (vside_len() == 0) && (hside_len() == 0); }
201 return std::vector<Point2D>{{left(), bot()}, {left(), top()},
202 {right(), bot()}, {right(), top()}};
206 double half_v = vside_len() / 2, half_h = hside_len() / 2;
207 return {new_center.
y - half_v, new_center.
y + half_v,
208 new_center.
x - half_h, new_center.
x + half_h};
213 auto new_hv = vside_len() / (factor * 2),
214 new_hh = hside_len() / (factor * 2);
215 return LVRect{c.y - new_hv, c.y + new_hv,
216 c.x - new_hh, c.x + new_hh};
222 return std::vector<LVRect>{
223 LVRect{bot(), c.y, left(), right()},
224 LVRect{ c.y, top(), left(), right()}
230 return std::vector<LVRect>{
231 LVRect{bot(), top(), left(), c.x},
232 LVRect{bot(), top(), c.x, right()}
238 return std::vector<LVRect>{
239 LVRect{ bot(), c.y, left(), c.x},
240 LVRect{ c.y, top(), left(), c.x},
241 LVRect{ bot(), c.y, c.x, right()},
242 LVRect{ c.y, top(), c.x, right()}
253 return intersect_internal(that,
false);
258 return intersect(that).area() / area();
261 return that.
contains(left(), bot()) ? 1.0 : 0.0;
264 assert(is_point() && that.
is_point() &&
"TODO: support lwr-lines");
265 return *
this == that ? 1.0 : 0.0;
271 bool reversed =
false)
const {
276 unsigned contained_corners_nm = 0;
277 auto cleft = left(), cright = right(), ctop = top(), cbot = bot();
279 #define PROCESS_CORNER(horz_id, vert_id) \ 280 if (contains(that.horz_id(), that.vert_id())) { \ 281 ++contained_corners_nm; \ 282 c##horz_id = that.horz_id(); \ 283 c##vert_id = that.vert_id(); \ 291 #undef PROCESS_CORNER 294 switch (contained_corners_nm) {
303 case 1:
case 2:
case 4:
306 assert(0 &&
"Unexpected inclusions number");
313 double _bot,
_top, _left, _right;
318 stream <<
"LVRectangle [t:" << r.
top() <<
", b:" << r.
bot();
319 return stream <<
", l:" << r.
left() <<
", r:" << r.
right() <<
"]";
324 static constexpr std::size_t BOT_EDGE_IDX = 0;
325 static constexpr std::size_t TOP_EDGE_IDX = 1;
326 static constexpr std::size_t LFT_EDGE_IDX = 2;
327 static constexpr std::size_t RHT_EDGE_IDX = 3;
334 Segment2D{{ left(), bot()}, {right(), bot()}},
335 Segment2D{{ left(), top()}, {right(), top()}},
336 Segment2D{{ left(), bot()}, { left(), top()}},
337 Segment2D{{right(), bot()}, {right(), top()}}
359 for (
auto &e : edges()) {
360 if (!e.contains(p)) {
continue; }
371 std::copy_if(ray_intrs.begin(), ray_intrs.end(), std::back_inserter(inters),
386 if (1 < intersections.size() &&
387 intersections.front() == intersections.back()) {
388 intersections.pop_back();
390 auto new_last = std::unique(intersections.begin(), intersections.end());
391 intersections.erase(new_last, intersections.end());
392 assert(intersections.size() < 3);
393 return intersections;
402 const std::vector<Segment2D> &
edges()
const {
return _edges; }
bool operator==(const LightWeightRectangle &rhs) const
void intersect(const Segment2D &s, Intersection::Location loc, Intersections &consumer) const
bool contains(double x, double y) const
Intersection(Location loc, double x, double y)
#define PROCESS_CORNER(horz_id, vert_id)
auto overlap(const LightWeightRectangle &that) const
auto split4_evenly() const
CONSTEXPR bool are_equal(const T &a, const T &b, const T &eps)
bool contains(const Point2D &p) const
double dist_sq(const Point2D &pt) const
void intersect_vert_segm(double st_y, double end_y, double x, Intersection::Location loc, Intersections &consumer) const
LVRect move_center(const Point2D &new_center) const
Point2D operator-(const Point2D &p) const
auto intersect(const LightWeightRectangle &that) const
bool x_projection_contains(const Point2D &p) const
Point2D(double x_par=0, double y_par=0)
const std::vector< Segment2D > _edges
Segment2D find_containing_edge(const Point2D &p) const
LightWeightRectangle(const Point2D &p)
Segment2D(const Point2D &begin, const Point2D &end)
std::ostream & operator<<(std::ostream &stream, const Point2D &pnt)
Rectangle(double b, double t, double l, double r)
bool contains_intersection(const Point2D &p) const
bool operator==(const Point2D &that) const
auto shrink(double factor) const
Ray(double x_s, double x_d, double y_s, double y_d)
Point2D operator+(const Point2D &p) const
LightWeightRectangle(double b, double t, double l, double r)
void intersect_horiz_segm(double st_x, double end_x, double y, Intersection::Location loc, Intersections &consumer) const
Intersections find_intersections(const Segment2D &s) const
Point2D operator*(double scalar) const
const Point2D & end() const
Intersections find_intersections(const Ray &ray) const
std::vector< Intersection > Intersections
bool are_ordered(double a, double b, double c)
bool contains(const Point2D &p) const
bool y_projection_contains(const Point2D &p) const
const Segment2D & right_edge() const
static Segment2D invalid()
const Segment2D & left_edge() const
const Segment2D & bot_edge() const
const std::vector< Segment2D > & edges() const
const Point2D & beg() const
bool has_on_edge_line(const Segment2D &s) const
const Segment2D & top_edge() const
LightWeightRectangle intersect_internal(const LightWeightRectangle &that, bool reversed=false) const