43 #include <ilqgames/geometry/line_segment2.h> 44 #include <ilqgames/geometry/polyline2.h> 45 #include <ilqgames/utils/types.h> 47 #include <glog/logging.h> 51 Polyline2::Polyline2(
const PointList2& points) : length_(0.0) {
52 CHECK_GT(points.size(), 1);
53 cumulative_lengths_.push_back(length_);
56 for (
size_t ii = 1; ii < points.size(); ii++) {
57 segments_.emplace_back(points[ii - 1], points[ii]);
58 length_ += segments_.back().Length();
59 cumulative_lengths_.push_back(length_);
63 void Polyline2::AddPoint(
const Point2& point) {
64 segments_.emplace_back(segments_.back().SecondPoint(), point);
65 length_ += segments_.back().Length();
68 Point2 Polyline2::PointAt(
float route_pos,
bool* is_vertex,
69 LineSegment2* segment,
bool* is_endpoint)
const {
70 auto upper = std::upper_bound(cumulative_lengths_.begin(),
71 cumulative_lengths_.end(), route_pos);
72 if (upper == cumulative_lengths_.end()) {
73 LOG(WARNING) <<
"Route position " << route_pos
74 <<
" was off the end of the route.";
80 const size_t idx = std::distance(cumulative_lengths_.begin(), upper);
81 if (segment) *segment = segments_[idx];
84 const float remaining = route_pos - cumulative_lengths_[idx];
85 CHECK_GE(remaining, 0.0);
88 *is_vertex = remaining < constants::kSmallNumber ||
89 remaining > segments_[idx].Length();
92 const Point2 return_point =
93 segments_[idx].FirstPoint() + remaining * segments_[idx].UnitDirection();
95 if (idx != 0 && idx != segments_.size() - 1)
98 *is_endpoint = (return_point == segments_.front().FirstPoint()) ||
99 (return_point == segments_.back().SecondPoint());
105 Point2 Polyline2::ClosestPoint(
const Point2& query,
bool* is_vertex,
106 LineSegment2* segment,
107 float* signed_squared_distance,
108 bool* is_endpoint)
const {
110 float closest_signed_squared_distance = constants::kInfinity;
111 Point2 closest_point;
113 float current_signed_squared_distance;
115 int segment_counter = 0;
116 bool is_segment_endpoint;
117 for (
const auto& s : segments_) {
118 const Point2 current_point = s.ClosestPoint(
119 query, &is_segment_endpoint, ¤t_signed_squared_distance);
121 if (std::abs(current_signed_squared_distance) <
122 std::abs(closest_signed_squared_distance)) {
126 if (is_segment_endpoint &&
127 (segment_counter > 0 || current_point == s.SecondPoint()) &&
128 (segment_counter < segments_.size() - 1 ||
129 current_point == s.FirstPoint())) {
130 const LineSegment2 shortcut =
131 (current_point == s.FirstPoint())
132 ? LineSegment2(segments_[segment_counter - 1].FirstPoint(),
134 : LineSegment2(s.FirstPoint(),
135 segments_[segment_counter + 1].SecondPoint());
136 current_signed_squared_distance *=
137 (shortcut.Side(query)) ? sgn(current_signed_squared_distance)
138 : -sgn(current_signed_squared_distance);
141 (current_signed_squared_distance >= 0.0 && shortcut.Side(query)) ||
142 (current_signed_squared_distance <= 0.0 && !shortcut.Side(query)));
145 closest_signed_squared_distance = current_signed_squared_distance;
146 closest_point = current_point;
148 if (is_vertex) *is_vertex = is_segment_endpoint;
149 segment_idx = segment_counter;
156 if (segment) *segment = segments_[segment_idx];
159 if (signed_squared_distance)
160 *signed_squared_distance = closest_signed_squared_distance;
164 auto is_same_point = [](
const Point2& p1,
const Point2& p2) {
165 return (p1 - p2).squaredNorm() < constants::kSmallNumber;
169 is_same_point(closest_point, segments_.front().FirstPoint()) ||
170 is_same_point(closest_point, segments_.back().SecondPoint());
173 return closest_point;