Apollo 10.0
自动驾驶开放平台
line_segment2d.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <algorithm>
20#include <cmath>
21#include <utility>
22
23#include "absl/strings/str_cat.h"
24#include "cyber/common/log.h"
25
27
28namespace apollo {
29namespace common {
30namespace math {
31namespace {
32
33bool IsWithin(double val, double bound1, double bound2) {
34 if (bound1 > bound2) {
35 std::swap(bound1, bound2);
36 }
37 return val >= bound1 - kMathEpsilon && val <= bound2 + kMathEpsilon;
38}
39
40} // namespace
41
42LineSegment2d::LineSegment2d() { unit_direction_ = Vec2d(1, 0); }
43
44LineSegment2d::LineSegment2d(const Vec2d &start, const Vec2d &end)
45 : start_(start), end_(end) {
46 const double dx = end_.x() - start_.x();
47 const double dy = end_.y() - start_.y();
48 length_ = hypot(dx, dy);
49 unit_direction_ =
50 (length_ <= kMathEpsilon ? Vec2d(0, 0)
51 : Vec2d(dx / length_, dy / length_));
52 heading_ = unit_direction_.Angle();
53}
54
55Vec2d LineSegment2d::rotate(const double angle) {
56 Vec2d diff_vec = end_ - start_;
57 diff_vec.SelfRotate(angle);
58 return start_ + diff_vec;
59}
60
61double LineSegment2d::length() const { return length_; }
62
63double LineSegment2d::length_sqr() const { return length_ * length_; }
64
65double LineSegment2d::DistanceTo(const Vec2d &point) const {
66 if (length_ <= kMathEpsilon) {
67 return point.DistanceTo(start_);
68 }
69 const double x0 = point.x() - start_.x();
70 const double y0 = point.y() - start_.y();
71 const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
72 if (proj <= 0.0) {
73 return hypot(x0, y0);
74 }
75 if (proj >= length_) {
76 return point.DistanceTo(end_);
77 }
78 return std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
79}
80
81double LineSegment2d::DistanceTo(const Vec2d &point,
82 Vec2d *const nearest_pt) const {
83 CHECK_NOTNULL(nearest_pt);
84 if (length_ <= kMathEpsilon) {
85 *nearest_pt = start_;
86 return point.DistanceTo(start_);
87 }
88 const double x0 = point.x() - start_.x();
89 const double y0 = point.y() - start_.y();
90 const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
91 if (proj < 0.0) {
92 *nearest_pt = start_;
93 return hypot(x0, y0);
94 }
95 if (proj > length_) {
96 *nearest_pt = end_;
97 return point.DistanceTo(end_);
98 }
99 *nearest_pt = start_ + unit_direction_ * proj;
100 return std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
101}
102
103double LineSegment2d::DistanceSquareTo(const Vec2d &point) const {
104 if (length_ <= kMathEpsilon) {
105 return point.DistanceSquareTo(start_);
106 }
107 const double x0 = point.x() - start_.x();
108 const double y0 = point.y() - start_.y();
109 const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
110 if (proj <= 0.0) {
111 return Square(x0) + Square(y0);
112 }
113 if (proj >= length_) {
114 return point.DistanceSquareTo(end_);
115 }
116 return Square(x0 * unit_direction_.y() - y0 * unit_direction_.x());
117}
118
120 Vec2d *const nearest_pt) const {
121 CHECK_NOTNULL(nearest_pt);
122 if (length_ <= kMathEpsilon) {
123 *nearest_pt = start_;
124 return point.DistanceSquareTo(start_);
125 }
126 const double x0 = point.x() - start_.x();
127 const double y0 = point.y() - start_.y();
128 const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
129 if (proj <= 0.0) {
130 *nearest_pt = start_;
131 return Square(x0) + Square(y0);
132 }
133 if (proj >= length_) {
134 *nearest_pt = end_;
135 return point.DistanceSquareTo(end_);
136 }
137 *nearest_pt = start_ + unit_direction_ * proj;
138 return Square(x0 * unit_direction_.y() - y0 * unit_direction_.x());
139}
140
141bool LineSegment2d::IsPointIn(const Vec2d &point) const {
142 if (length_ <= kMathEpsilon) {
143 return std::abs(point.x() - start_.x()) <= kMathEpsilon &&
144 std::abs(point.y() - start_.y()) <= kMathEpsilon;
145 }
146 const double prod = CrossProd(point, start_, end_);
147 if (std::abs(prod) > kMathEpsilon) {
148 return false;
149 }
150 return IsWithin(point.x(), start_.x(), end_.x()) &&
151 IsWithin(point.y(), start_.y(), end_.y());
152}
153
154double LineSegment2d::ProjectOntoUnit(const Vec2d &point) const {
155 return unit_direction_.InnerProd(point - start_);
156}
157
158double LineSegment2d::ProductOntoUnit(const Vec2d &point) const {
159 return unit_direction_.CrossProd(point - start_);
160}
161
162bool LineSegment2d::HasIntersect(const LineSegment2d &other_segment) const {
163 Vec2d point;
164 return GetIntersect(other_segment, &point);
165}
166
168 Vec2d *const point) const {
169 CHECK_NOTNULL(point);
170 if (IsPointIn(other_segment.start())) {
171 *point = other_segment.start();
172 return true;
173 }
174 if (IsPointIn(other_segment.end())) {
175 *point = other_segment.end();
176 return true;
177 }
178 if (other_segment.IsPointIn(start_)) {
179 *point = start_;
180 return true;
181 }
182 if (other_segment.IsPointIn(end_)) {
183 *point = end_;
184 return true;
185 }
186 if (length_ <= kMathEpsilon || other_segment.length() <= kMathEpsilon) {
187 return false;
188 }
189 const double cc1 = CrossProd(start_, end_, other_segment.start());
190 const double cc2 = CrossProd(start_, end_, other_segment.end());
191 if (cc1 * cc2 >= -kMathEpsilon) {
192 return false;
193 }
194 const double cc3 =
195 CrossProd(other_segment.start(), other_segment.end(), start_);
196 const double cc4 =
197 CrossProd(other_segment.start(), other_segment.end(), end_);
198 if (cc3 * cc4 >= -kMathEpsilon) {
199 return false;
200 }
201 const double ratio = cc4 / (cc4 - cc3);
202 *point = Vec2d(start_.x() * ratio + end_.x() * (1.0 - ratio),
203 start_.y() * ratio + end_.y() * (1.0 - ratio));
204 return true;
205}
206
207// return distance with perpendicular foot point.
209 Vec2d *const foot_point) const {
210 CHECK_NOTNULL(foot_point);
211 if (length_ <= kMathEpsilon) {
212 *foot_point = start_;
213 return point.DistanceTo(start_);
214 }
215 const double x0 = point.x() - start_.x();
216 const double y0 = point.y() - start_.y();
217 const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
218 *foot_point = start_ + unit_direction_ * proj;
219 return std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
220}
221
222std::string LineSegment2d::DebugString() const {
223 return absl::StrCat("segment2d ( start = ", start_.DebugString(),
224 " end = ", end_.DebugString(), " )");
225}
226
227} // namespace math
228} // namespace common
229} // namespace apollo
double DistanceSquareTo(const Vec2d &point) const
Compute the square of the shortest distance from a point on the line segment to a point in 2-D.
bool HasIntersect(const LineSegment2d &other_segment) const
Check if the line segment has an intersect with another line segment in 2-D.
const Vec2d & end() const
Get the end point.
double GetPerpendicularFoot(const Vec2d &point, Vec2d *const foot_point) const
Compute perpendicular foot of a point in 2-D on the straight line expanded from the line segment.
double ProjectOntoUnit(const Vec2d &point) const
Compute the projection of a vector onto the line segment.
double ProductOntoUnit(const Vec2d &point) const
Compute the cross product of a vector onto the line segment.
Vec2d rotate(const double angle)
Get a new line-segment with the same start point, but rotated counterclock-wise by the given amount.
double length() const
Get the length of the line segment.
bool GetIntersect(const LineSegment2d &other_segment, Vec2d *const point) const
Compute the intersect with another line segment in 2-D if any.
double DistanceTo(const Vec2d &point) const
Compute the shortest distance from a point on the line segment to a point in 2-D.
const Vec2d & start() const
Get the start point.
double length_sqr() const
Get the square of length of the line segment.
std::string DebugString() const
Get the debug string including the essential information.
bool IsPointIn(const Vec2d &point) const
Check if a point is within the line segment.
Implements a class of 2-dimensional vectors.
Definition vec2d.h:42
void SelfRotate(const double angle)
rotate the vector itself by angle.
Definition vec2d.cc:70
double DistanceSquareTo(const Vec2d &other) const
Returns the squared distance to the given vector
Definition vec2d.cc:51
double InnerProd(const Vec2d &other) const
Returns the inner product between these two Vec2d.
Definition vec2d.cc:61
std::string DebugString() const
Returns a human-readable string representing this object
Definition vec2d.cc:125
double y() const
Getter for y component
Definition vec2d.h:57
double Angle() const
Gets the angle between the vector and the positive x semi-axis
Definition vec2d.cc:37
double DistanceTo(const Vec2d &other) const
Returns the distance to the given vector
Definition vec2d.cc:47
double x() const
Getter for x component
Definition vec2d.h:54
double CrossProd(const Vec2d &other) const
Returns the "cross" product between these two Vec2d (non-standard).
Definition vec2d.cc:57
Define the LineSegment2d class.
Math-related util functions.
constexpr double kMathEpsilon
Definition vec2d.h:35
double CrossProd(const Vec2d &start_point, const Vec2d &end_point_1, const Vec2d &end_point_2)
Cross product between two 2-D vectors from the common start point, and end at two other points.
Definition math_utils.cc:28
T Square(const T value)
Compute squared value.
Definition math_utils.h:141
class register implement
Definition arena_queue.h:37