blob: b69f6613cb8fa4e00c6f6d35506b88393618e335 [file] [log] [blame]
#ifndef Y2018_CONTORL_LOOPS_PYTHON_ARM_BOUNDS_H_
#define Y2018_CONTORL_LOOPS_PYTHON_ARM_BOUNDS_H_
#include <CGAL/Bbox_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_2_algorithms.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/squared_distance_2.h>
#include <Eigen/Dense>
// Prototype level code to find the nearest point and distance to a polygon.
namespace y2018 {
namespace control_loops {
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_2 Point;
typedef K::Segment_2 Segment;
typedef CGAL::Bbox_2 Bbox;
typedef CGAL::Polygon_2<K> SimplePolygon;
typedef CGAL::Polygon_with_holes_2<K> Polygon;
typedef K::Line_2 Line;
typedef K::Vector_2 Vector;
// Returns true if the point p3 is to the left of the vector from p1 to p2.
inline bool is_left(Point p1, Point p2, Point p3) {
switch (CGAL::orientation(p1, p2, p3)) {
case CGAL::LEFT_TURN:
case CGAL::COLLINEAR:
return true;
case CGAL::RIGHT_TURN:
return false;
}
}
// Returns true if the segments intersect.
inline bool intersects(Segment s1, Segment s2) {
return CGAL::do_intersect(s1, s2);
}
class BoundsCheck {
public:
BoundsCheck(const std::vector<Point> &points)
: points_(points), grid_(points_, 6) {}
double min_distance(Point point, ::Eigen::Matrix<double, 2, 1> *normal) const;
const std::vector<Point> &points() const { return points_; }
private:
static Bbox ToBbox(const std::vector<Point> &points) {
Bbox out;
out += Segment(points.back(), points.front()).bbox();
for (size_t i = 0; i < points.size() - 1; ++i) {
out += Segment(points[i], points[i + 1]).bbox();
}
return out;
}
static SimplePolygon ToPolygon(Bbox bbox) {
Point points[4]{{bbox.xmin(), bbox.ymin()},
{bbox.xmax(), bbox.ymin()},
{bbox.xmax(), bbox.ymax()},
{bbox.xmin(), bbox.ymax()}};
return SimplePolygon(&points[0], &points[4]);
}
static double min_dist(Point pt, const std::vector<Point> &points,
Segment *best_segment) {
*best_segment = Segment(points.back(), points.front());
double min_dist_sqr = CGAL::squared_distance(pt, *best_segment);
for (size_t i = 0; i < points.size() - 1; ++i) {
Segment s(points[i], points[i + 1]);
double segment_distance = CGAL::squared_distance(pt, s);
if (segment_distance < min_dist_sqr) {
min_dist_sqr = segment_distance;
*best_segment = s;
}
}
return sqrt(min_dist_sqr);
}
static std::vector<Segment> ToSegment(Bbox bbox) {
Point points[4]{{bbox.xmin(), bbox.ymin()},
{bbox.xmax(), bbox.ymin()},
{bbox.xmax(), bbox.ymax()},
{bbox.xmin(), bbox.ymax()}};
return std::vector<Segment>({{points[0], points[1]},
{points[1], points[2]},
{points[2], points[3]},
{points[3], points[0]}});
}
static bool check_inside(Point pt, const std::vector<Point> &points) {
switch (CGAL::bounded_side_2(&points[0], &points[points.size()], pt, K())) {
case CGAL::ON_BOUNDED_SIDE:
case CGAL::ON_BOUNDARY:
return true;
case CGAL::ON_UNBOUNDED_SIDE:
return false;
}
return false;
}
const std::vector<Point> points_;
class GridCell {
public:
GridCell(const std::vector<Point> &points, Bbox bbox) {
bool has_intersect = false;
Point center{(bbox.xmin() + bbox.xmax()) / 2,
(bbox.ymin() + bbox.ymax()) / 2};
// Purposefully overestimate.
double r = bbox.ymax() - bbox.ymin();
Segment best_segment;
double best = min_dist(center, points, &best_segment);
dist_upper_bound_ = best + 2 * r;
dist_lower_bound_ = std::max(best - 2 * r, 0.0);
double sq_upper_bound = dist_upper_bound_ * dist_upper_bound_;
auto try_add_segment = [&](Segment segment) {
for (const auto &bbox_segment : ToSegment(bbox)) {
if (CGAL::do_intersect(bbox_segment, segment)) {
has_intersect = true;
}
}
double dist_sqr = CGAL::squared_distance(center, segment);
if (dist_sqr < sq_upper_bound) {
segments_.push_back(segment);
}
};
try_add_segment(Segment(points.back(), points.front()));
for (size_t i = 0; i < points.size() - 1; ++i) {
try_add_segment(Segment(points[i], points[i + 1]));
}
if (has_intersect) {
is_borderline = true;
} else {
is_inside = check_inside(center, points);
}
}
bool IsInside(Point pt) const {
(void)pt;
return is_inside;
}
bool IsBorderline() const { return is_borderline; }
double DistanceSqr(Point pt, Segment *best_segment) const {
double min_dist_sqr = CGAL::squared_distance(pt, segments_[0]);
*best_segment = segments_[0];
for (size_t i = 1; i < segments_.size(); ++i) {
double new_distance = CGAL::squared_distance(pt, segments_[i]);
if (new_distance < min_dist_sqr) {
min_dist_sqr = new_distance;
*best_segment = segments_[i];
}
}
return min_dist_sqr;
}
double Distance(Point pt, Segment *best_segment) const {
return sqrt(DistanceSqr(pt, best_segment));
}
bool is_inside = false;
bool is_borderline = false;
double dist_upper_bound_;
double dist_lower_bound_;
std::vector<Segment> segments_;
std::vector<std::vector<Point>> polygons_;
};
class GridSystem {
public:
// Precision is really 2**-precision and must be positive.
GridSystem(const std::vector<Point> &points, int precision)
: points_(points), scale_factor_(1 << precision) {
auto bbox = ToBbox(points);
fprintf(stderr, "%g %g, %g %g\n", bbox.xmin(), bbox.ymin(), bbox.xmax(),
bbox.ymax());
x_min_ = static_cast<int>(std::floor(bbox.xmin() * scale_factor_)) - 1;
y_min_ = static_cast<int>(std::floor(bbox.ymin() * scale_factor_)) - 1;
stride_ = static_cast<int>(bbox.xmax() * scale_factor_) + 3 - x_min_;
height_ = static_cast<int>(bbox.ymax() * scale_factor_) + 3 - y_min_;
fprintf(stderr, "num_cells: %d\n", stride_ * height_);
cells_.reserve(stride_ * height_);
for (int y_cell = 0; y_cell < height_; ++y_cell) {
for (int x_cell = 0; x_cell < stride_; ++x_cell) {
cells_.push_back(
GridCell(points, Bbox(static_cast<double>(x_cell + x_min_) /
static_cast<double>(scale_factor_),
static_cast<double>(y_cell + y_min_) /
static_cast<double>(scale_factor_),
static_cast<double>(x_cell + x_min_ + 1) /
static_cast<double>(scale_factor_),
static_cast<double>(y_cell + y_min_ + 1) /
static_cast<double>(scale_factor_))));
}
}
}
const GridCell *GetCell(Point pt) const {
int x_cell =
static_cast<int>(std::floor(pt.x() * scale_factor_)) - x_min_;
int y_cell =
static_cast<int>(std::floor(pt.y() * scale_factor_)) - y_min_;
if (x_cell < 0 || x_cell >= stride_) return nullptr;
if (y_cell < 0 || y_cell >= height_) return nullptr;
return &cells_[stride_ * y_cell + x_cell];
}
const std::vector<Point> &points() const { return points_; }
private:
std::vector<Point> points_;
int scale_factor_;
int x_min_;
int y_min_;
int stride_;
int height_;
std::vector<GridCell> cells_;
};
GridSystem grid_;
};
BoundsCheck MakeClippedArmSpace();
BoundsCheck MakeFullArmSpace();
} // namespace control_loops
} // namespace y2018
#endif // Y2018_CONTORL_LOOPS_PYTHON_ARM_BOUNDS_H_