Skip to content

Commit 3fe1631

Browse files
authored
Merge branch 'gz-math9' into releases/9.3.0
2 parents 3ec4d31 + 6c2f718 commit 3fe1631

4 files changed

Lines changed: 185 additions & 18 deletions

File tree

include/gz/math/Line2.hh

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace gz::math
4545
/// \param[in] _y1 Y coordinate of the start point.
4646
/// \param[in] _x2 X coordinate of the end point.
4747
/// \param[in] _y2 Y coordinate of the end point.
48-
public: Line2(double _x1, double _y1, double _x2, double _y2)
48+
public: Line2(T _x1, T _y1, T _x2, T _y2)
4949
{
5050
this->Set(_x1, _y1, _x2, _y2);
5151
}
@@ -65,7 +65,7 @@ namespace gz::math
6565
/// \param[in] _y1 Y coordinate of the start point.
6666
/// \param[in] _x2 X coordinate of the end point.
6767
/// \param[in] _y2 Y coordinate of the end point.
68-
public: void Set(double _x1, double _y1, double _x2, double _y2)
68+
public: void Set(T _x1, T _y1, T _x2, T _y2)
6969
{
7070
this->pts[0].Set(_x1, _y1);
7171
this->pts[1].Set(_x2, _y2);
@@ -77,7 +77,7 @@ namespace gz::math
7777
/// (a.start.y - a.end.y) * (b.start.x - b.end.x)
7878
/// \param[in] _line Line for the cross product computation.
7979
/// \return Return the cross product of this line and the given line.
80-
public: double CrossProduct(const Line2<T> &_line) const
80+
public: T CrossProduct(const Line2<T> &_line) const
8181
{
8282
return (this->pts[0].X() - this->pts[1].X()) *
8383
(_line[0].Y() -_line[1].Y()) -
@@ -90,7 +90,7 @@ namespace gz::math
9090
// (_pt.y - a.y) * (b.x - a.x) - (_pt.x - a.x) * (b.y - a.y)
9191
/// \param[in] _pt Point for the cross product computation.
9292
/// \return Return the cross product of this line and the given point.
93-
public: double CrossProduct(const Vector2<T> &_pt) const
93+
public: T CrossProduct(const Vector2<T> &_pt) const
9494
{
9595
return (_pt.Y() - this->pts[0].Y()) *
9696
(this->pts[1].X() - this->pts[0].X()) -
@@ -108,7 +108,7 @@ namespace gz::math
108108
double _epsilon = 1e-6) const
109109
{
110110
return math::equal(this->CrossProduct(_pt),
111-
0., _epsilon);
111+
static_cast<T>(0), static_cast<T>(_epsilon));
112112
}
113113

114114
/// \brief Check if the given line is parallel with this line.
@@ -122,7 +122,7 @@ namespace gz::math
122122
double _epsilon = 1e-6) const
123123
{
124124
return math::equal(this->CrossProduct(_line),
125-
0., _epsilon);
125+
static_cast<T>(0), static_cast<T>(_epsilon));
126126
}
127127

128128
/// \brief Check if the given line is collinear with this line. This
@@ -160,14 +160,15 @@ namespace gz::math
160160
public: bool Within(const math::Vector2<T> &_pt,
161161
double _epsilon = 1e-6) const
162162
{
163+
auto eps = static_cast<T>(_epsilon);
163164
return _pt.X() <= std::max(this->pts[0].X(),
164-
this->pts[1].X()) + _epsilon &&
165+
this->pts[1].X()) + eps &&
165166
_pt.X() >= std::min(this->pts[0].X(),
166-
this->pts[1].X()) - _epsilon &&
167+
this->pts[1].X()) - eps &&
167168
_pt.Y() <= std::max(this->pts[0].Y(),
168-
this->pts[1].Y()) + _epsilon &&
169+
this->pts[1].Y()) + eps &&
169170
_pt.Y() >= std::min(this->pts[0].Y(),
170-
this->pts[1].Y()) - _epsilon;
171+
this->pts[1].Y()) - eps;
171172
}
172173

173174
/// \brief Check if this line intersects the given line segment.
@@ -193,11 +194,11 @@ namespace gz::math
193194
public: bool Intersect(const Line2<T> &_line, math::Vector2<T> &_pt,
194195
double _epsilon = 1e-6) const
195196
{
196-
double d = this->CrossProduct(_line);
197+
T d = this->CrossProduct(_line);
197198

198199
// d is zero if the two line are collinear. Must check special
199200
// cases.
200-
if (math::equal(d, 0.0, _epsilon))
201+
if (math::equal(d, static_cast<T>(0), static_cast<T>(_epsilon)))
201202
{
202203
// Check if _line's starting point is on the line.
203204
if (this->Within(_line[0], _epsilon))
@@ -253,10 +254,7 @@ namespace gz::math
253254
/// \return The length of the line.
254255
public: T Length() const
255256
{
256-
return sqrt((this->pts[0].X() - this->pts[1].X()) *
257-
(this->pts[0].X() - this->pts[1].X()) +
258-
(this->pts[0].Y() - this->pts[1].Y()) *
259-
(this->pts[0].Y() - this->pts[1].Y()));
257+
return static_cast<T>(this->pts[0].Distance(this->pts[1]));
260258
}
261259

262260
/// \brief Get the slope of the line

src/Line2_TEST.cc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,49 @@ TEST(Line2Test, Constructor)
4040
EXPECT_NO_THROW(lineB[2].X());
4141
EXPECT_DOUBLE_EQ(lineB[2].X(), lineB[1].X());
4242
EXPECT_NO_THROW(lineA[0].X());
43+
44+
// Test Set method with Vector2
45+
lineA.Set(math::Vector2d(5, 6), math::Vector2d(7, 8));
46+
EXPECT_EQ(lineA[0], math::Vector2d(5, 6));
47+
EXPECT_EQ(lineA[1], math::Vector2d(7, 8));
48+
}
49+
50+
/////////////////////////////////////////////////
51+
TEST(Line2Test, CrossProduct)
52+
{
53+
math::Line2d lineA(0, 0, 10, 0);
54+
math::Line2d lineB(0, 0, 0, 10);
55+
EXPECT_DOUBLE_EQ(lineA.CrossProduct(lineB), 100.0);
56+
57+
math::Vector2d pt(5, 5);
58+
EXPECT_DOUBLE_EQ(lineA.CrossProduct(pt), 50.0);
59+
}
60+
61+
/////////////////////////////////////////////////
62+
TEST(Line2Test, OnSegmentAndWithin)
63+
{
64+
math::Line2d line(0, 0, 10, 10);
65+
66+
// Point on segment
67+
math::Vector2d pt1(5, 5);
68+
EXPECT_TRUE(line.Within(pt1));
69+
EXPECT_TRUE(line.OnSegment(pt1));
70+
71+
// Point collinear with line, but outside segment bounds
72+
math::Vector2d pt2(15, 15);
73+
EXPECT_FALSE(line.Within(pt2));
74+
EXPECT_FALSE(line.OnSegment(pt2));
75+
76+
// Point within bounding box of segment, but not collinear
77+
math::Vector2d pt3(5, 6);
78+
EXPECT_TRUE(line.Within(pt3));
79+
EXPECT_FALSE(line.OnSegment(pt3));
80+
81+
// Endpoints
82+
EXPECT_TRUE(line.Within(line[0]));
83+
EXPECT_TRUE(line.OnSegment(line[0]));
84+
EXPECT_TRUE(line.Within(line[1]));
85+
EXPECT_TRUE(line.OnSegment(line[1]));
4386
}
4487

4588
/////////////////////////////////////////////////
@@ -83,29 +126,34 @@ TEST(Line2Test, ParallelLine)
83126
// Line is always parallel with itself
84127
math::Line2d line(0, 0, 10, 0);
85128
EXPECT_TRUE(line.Parallel(line, 1e-10));
129+
EXPECT_DOUBLE_EQ(line.CrossProduct(line), 0.0);
86130
}
87131

88132
{
89133
// Degenerate line segment
90134
// Still expect Line is parallel with itself
91135
math::Line2d line(0, 0, 0, 0);
92136
EXPECT_TRUE(line.Parallel(line, 1e-10));
137+
EXPECT_DOUBLE_EQ(line.CrossProduct(line), 0.0);
93138
}
94139

95140
math::Line2d lineA(0, 0, 10, 0);
96141
math::Line2d lineB(0, 0, 10, 0);
97142
EXPECT_TRUE(lineA.Parallel(lineB, 1e-10));
143+
EXPECT_DOUBLE_EQ(lineA.CrossProduct(lineB), 0.0);
98144

99145
lineB.Set(0, 0, 0, 10);
100146
EXPECT_FALSE(lineA.Parallel(lineB));
101147

102148
lineB.Set(0, 10, 10, 10);
103149
EXPECT_TRUE(lineA.Parallel(lineB));
150+
EXPECT_DOUBLE_EQ(lineA.CrossProduct(lineB), 0.0);
104151

105152
lineB.Set(0, 10, 10, 10.00001);
106153
EXPECT_FALSE(lineA.Parallel(lineB, 1e-10));
107154
EXPECT_FALSE(lineA.Parallel(lineB));
108155
EXPECT_TRUE(lineA.Parallel(lineB, 1e-3));
156+
EXPECT_NEAR(lineA.CrossProduct(lineB), 0.0, 1e-3);
109157
}
110158

111159
/////////////////////////////////////////////////
@@ -234,6 +282,28 @@ TEST(Line2Test, Intersect)
234282
lineB.Set(0, 10, 10, 0);
235283
EXPECT_TRUE(lineA.Intersect(lineB, pt));
236284
EXPECT_EQ(pt, math::Vector2d(5, 5));
285+
286+
// Collinear parallel non-overlapping lines
287+
lineA.Set(0, 0, 10, 0);
288+
lineB.Set(20, 0, 30, 0);
289+
EXPECT_FALSE(lineA.Intersect(lineB, pt));
290+
EXPECT_FALSE(lineA.Intersect(lineB));
291+
292+
// Collinear lines where lineB end point is within lineA but start point isn't
293+
lineA.Set(0, 0, 10, 0);
294+
lineB.Set(-5, 0, 5, 0);
295+
EXPECT_TRUE(lineA.Intersect(lineB, pt));
296+
EXPECT_EQ(pt, math::Vector2d(5, 0));
297+
298+
// Lines whose extensions intersect, but intersection Y is outside bounds
299+
lineA.Set(-10, 0, 10, 0);
300+
lineB.Set(0, 2, 0, 10);
301+
EXPECT_FALSE(lineA.Intersect(lineB, pt));
302+
303+
// Lines whose extensions intersect, but intersection X is outside bounds
304+
lineA.Set(0, -10, 0, 10);
305+
lineB.Set(2, 0, 10, 0);
306+
EXPECT_FALSE(lineA.Intersect(lineB, pt));
237307
}
238308

239309
/////////////////////////////////////////////////
@@ -243,7 +313,9 @@ TEST(Line2Test, Equality)
243313
math::Line2d lineB(1, 2, 2, 2);
244314

245315
EXPECT_TRUE(lineA != lineB);
316+
EXPECT_FALSE(lineA == lineB);
246317
EXPECT_TRUE(lineA == lineA);
318+
EXPECT_FALSE(lineA != lineA);
247319

248320
lineB.Set(1, 1, 2, 1.1);
249321
EXPECT_FALSE(lineA == lineB);
@@ -266,3 +338,18 @@ TEST(Line2Test, OperatorStreamOut)
266338
stream << line;
267339
EXPECT_EQ(stream.str(), "0 1 2 3");
268340
}
341+
342+
/////////////////////////////////////////////////
343+
TEST(Line2Test, TemplateTypes)
344+
{
345+
math::Line2i lineI(0, 0, 10, 10);
346+
EXPECT_EQ(lineI[0], math::Vector2i(0, 0));
347+
EXPECT_EQ(lineI[1], math::Vector2i(10, 10));
348+
EXPECT_EQ(lineI.Length(), 14);
349+
350+
math::Line2f lineF(0.0f, 0.0f, 10.0f, 10.0f);
351+
EXPECT_FLOAT_EQ(lineF[0].X(), 0.0f);
352+
EXPECT_FLOAT_EQ(lineF[1].Y(), 10.0f);
353+
EXPECT_NEAR(lineF.Length(), 14.1421356f, 1e-4f);
354+
}
355+

src/python_pybind11/src/Line2.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ void helpDefineMathLine2(py::module &m, const std::string &typestr)
5656
py::dynamic_attr())
5757
.def(py::init<const gz::math::Vector2<T>&,
5858
const gz::math::Vector2<T>&>())
59-
.def(py::init<double, double, double, double>())
59+
.def(py::init<T, T, T, T>())
6060
.def(py::self != py::self)
6161
.def(py::self == py::self)
6262
.def("set",
6363
py::overload_cast<const gz::math::Vector2<T>&,
6464
const gz::math::Vector2<T>&>(&Class::Set),
6565
"Set the start and end point of the line segment")
6666
.def("set",
67-
py::overload_cast<double, double, double, double>(&Class::Set),
67+
py::overload_cast<T, T, T, T>(&Class::Set),
6868
"Set the start and end point of the line segment")
6969
.def("cross_product",
7070
py::overload_cast<const Class&>(&Class::CrossProduct, py::const_),

0 commit comments

Comments
 (0)