MRPT  1.9.9
geometry_unittest.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2019, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include <gtest/gtest.h>
11 #include <mrpt/math/CPolygon.h>
12 #include <mrpt/math/TLine3D.h>
13 #include <mrpt/math/TObject2D.h>
14 #include <mrpt/math/TObject3D.h>
15 #include <mrpt/math/geometry.h>
16 #include <algorithm>
17 
18 using namespace mrpt;
19 using namespace mrpt::math;
20 using namespace std;
21 
22 TEST(Geometry, Line2DIntersect)
23 {
24  // Two lines that should intersect at (0.5,0.5)
25  const TLine2D l1(TPoint2D(0, 1), TPoint2D(1, 0));
26  const TLine2D l2(TPoint2D(-1, 0.5), TPoint2D(4, 0.5));
27 
28  TObject2D inter;
29  bool do_inter = intersect(l1, l2, inter);
30 
31  EXPECT_TRUE(do_inter);
32  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_POINT);
33 
34  TPoint2D i(0, 0);
35  inter.getPoint(i);
36  EXPECT_NEAR(i.x, 0.5, 1e-9);
37  EXPECT_NEAR(i.y, 0.5, 1e-9);
38 }
39 
40 TEST(Geometry, Line2DAngle)
41 {
42  const TLine2D l1(TPoint2D(0, 0), TPoint2D(1, 0));
43  const TLine2D l2(TPoint2D(-1, -1), TPoint2D(5, 5));
44 
45  // Angles in 2D do have sign:
46  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l1, l2)), +45.0, 1e-5);
47  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l2, l1)), -45.0, 1e-5);
48 
49  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l1, l1)), 0.0, 1e-5);
50  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l2, l2)), 0.0, 1e-5);
51 
52  const TLine2D l3(TPoint2D(1, 0), TPoint2D(0, 0));
53  EXPECT_NEAR(RAD2DEG(std::abs(mrpt::math::getAngle(l1, l3))), 180.0, 1e-5);
54  EXPECT_NEAR(RAD2DEG(std::abs(mrpt::math::getAngle(l3, l1))), 180.0, 1e-5);
55 }
56 
57 TEST(Geometry, Line3DAngle)
58 {
59  const TLine3D l1(TPoint3D(0, 0, 0), TPoint3D(1, 0, 0));
60  const TLine3D l2(TPoint3D(-1, -1, 0), TPoint3D(5, 5, 0));
61 
62  // Angles in 3D don't have sign:
63  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l1, l2)), 45.0, 1e-5);
64  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l2, l1)), 45.0, 1e-5);
65 
66  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l1, l1)), 0.0, 1e-5);
67  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l2, l2)), 0.0, 1e-5);
68 
69  const TLine3D l3(TPoint3D(1, 0, 0), TPoint3D(0, 0, 0));
70  EXPECT_NEAR(RAD2DEG(std::abs(mrpt::math::getAngle(l1, l3))), 180.0, 1e-5);
71  EXPECT_NEAR(RAD2DEG(std::abs(mrpt::math::getAngle(l3, l1))), 180.0, 1e-5);
72 
73  const TLine3D l4(
74  TPoint3D(0, 0, 0), TPoint3D(cos(DEG2RAD(30.0)), sin(DEG2RAD(30.0)), 0));
75  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l1, l4)), 30.0, 1e-5);
76  EXPECT_NEAR(mrpt::RAD2DEG(mrpt::math::getAngle(l4, l1)), 30.0, 1e-5);
77 }
78 
79 TEST(Geometry, Segment2DIntersect)
80 {
81  {
82  // Two segments that should intersect at (0.5,0.5)
83  const TSegment2D s1(TPoint2D(0, 1), TPoint2D(1, 0));
84  const TSegment2D s2(TPoint2D(-1, 0.5), TPoint2D(4, 0.5));
85 
86  TObject2D inter;
87  bool do_inter = intersect(s1, s2, inter);
88 
89  EXPECT_TRUE(do_inter);
90  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_POINT);
91 
92  TPoint2D i(0, 0);
93  inter.getPoint(i);
94  EXPECT_NEAR(i.x, 0.5, 1e-9);
95  EXPECT_NEAR(i.y, 0.5, 1e-9);
96  }
97 
98  {
99  // Two segments that do NOT intersect
100  const TSegment2D s1(TPoint2D(0, 1), TPoint2D(1, 0));
101  const TSegment2D s2(TPoint2D(0.6, 0.5), TPoint2D(4, 0.5));
102 
103  TObject2D inter;
104  bool do_inter = intersect(s1, s2, inter);
105 
106  EXPECT_FALSE(do_inter);
107  }
108  {
109  // Two parallel segments that do NOT intersect: result is a "segment in
110  // the middle".
111  const TSegment2D s1(TPoint2D(-0.05, 0.05), TPoint2D(-0.05, -0.05));
112  const TSegment2D s2(TPoint2D(0, 0.135), TPoint2D(0, -0.0149999));
113 
114  TObject2D inter;
115  bool do_inter = intersect(s1, s2, inter);
116 
117  // EXPECT_TRUE(do_inter && inter.getType()==GEOMETRIC_TYPE_SEGMENT);
118  EXPECT_FALSE(do_inter);
119  }
120 }
121 
122 TEST(Geometry, Intersection3D)
123 {
124  {
125  TPolygon3D p3d({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
126  TSegment3D s3d({
127  {1, 0, 0},
128  {0, 1, 0},
129  });
130 
131  TObject3D inter;
132  EXPECT_TRUE(intersect(p3d, s3d, inter));
133  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_SEGMENT);
134  TSegment3D test;
135  inter.getSegment(test);
136  // Should this be true? EXPECT_EQ(s3d, test);
137  }
138  {
139  TPolygon3D p3d({{1, 0, 0}, {0, 1, 0}, {0, 0, 1}});
140  TSegment3D s3d({
141  {0, 0, 0},
142  {1, 1, 1},
143  });
144 
145  TObject3D inter;
146  EXPECT_TRUE(intersect(p3d, s3d, inter));
147  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_POINT);
148  }
149  {
150  TSegment3D s3d1({
151  {1, 0, 0},
152  {0, 1, 0},
153  });
154  TSegment3D s3d2({
155  {2, -1.0, 0},
156  {0, 1.0, 0},
157  });
158 
159  TObject3D inter;
160  EXPECT_TRUE(intersect(s3d1, s3d2, inter));
161  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_SEGMENT);
162  }
163  {
164  TSegment3D s3d1({
165  {1, 0, 0},
166  {0, 1, 0},
167  });
168  TSegment3D s3d2({
169  {0, 0, 0},
170  {1, 1, 0},
171  });
172 
173  TObject3D inter;
174  EXPECT_TRUE(intersect(s3d1, s3d2, inter));
175  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_POINT);
176 
177  TPoint3D test;
178  TPoint3D expect{0.5, 0.5, 0};
179  inter.getPoint(test);
180  EXPECT_EQ(expect, test);
181  }
182 }
183 
184 TEST(Geometry, IntersectionPlanePlane)
185 {
186  {
187  // Parallel planes
188  TPlane plane1({
189  {1, 0, 0},
190  {0, 1, 0},
191  {0, 0, 1},
192  });
193  TPlane plane2({
194  {2, 0, 0},
195  {0, 2, 0},
196  {0, 0, 2},
197  });
198 
199  TObject3D inter;
200  EXPECT_FALSE(intersect(plane1, plane2, inter));
201  }
202  {
203  // Same plane
204  TPlane plane1({
205  {1, 0, 0},
206  {0, 1, 0},
207  {0, 0, 1},
208  });
209  TPlane plane2({
210  {-1, 1, 1},
211  {1, -1, 1},
212  {1, 1, -1},
213  });
214 
215  TObject3D inter;
216  EXPECT_TRUE(intersect(plane1, plane2, inter));
217  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_PLANE);
218  }
219  {
220  // Intersecting planes
221  TPlane plane1({
222  {1, 0, 0},
223  {0, 1, 0},
224  {0, 0, 1},
225  });
226  TPlane plane2({
227  {1, 0, 0},
228  {0, -1, 0},
229  {0, 0, -1},
230  });
231 
232  TObject3D inter;
233  EXPECT_TRUE(intersect(plane1, plane2, inter));
234  EXPECT_EQ(inter.getType(), GEOMETRIC_TYPE_LINE);
235  }
236 }
237 
238 void myTestPolygonContainsPoint(std::vector<TPoint2D>& vs, bool convex)
239 {
240  const mrpt::math::TPolygon2D poly(vs);
241 
242  EXPECT_EQ(poly.isConvex(), convex);
243 
244  EXPECT_TRUE(poly.contains(TPoint2D(0.0, 0.0)));
245  EXPECT_TRUE(poly.contains(TPoint2D(0.0, 0.9)));
246  EXPECT_TRUE(poly.contains(TPoint2D(-0.9, -0.9)));
247  EXPECT_TRUE(poly.contains(TPoint2D(0.9, -0.9)));
248 
249  EXPECT_FALSE(poly.contains(TPoint2D(-4.0, -5.1)));
250  EXPECT_FALSE(poly.contains(TPoint2D(-5.0, -0.1)));
251  EXPECT_FALSE(poly.contains(TPoint2D(1.1, -6.1)));
252  EXPECT_FALSE(poly.contains(TPoint2D(0, 5.1)));
253  EXPECT_FALSE(poly.contains(TPoint2D(0, -1.1)));
254 }
255 
256 TEST(Geometry, PolygonConvexContainsPoint)
257 {
258  // Test with a polygon in one winding order:
259  std::vector<TPoint2D> vs;
260  vs.emplace_back(-1.0, -1.0);
261  vs.emplace_back(0.0, 1.0);
262  vs.emplace_back(1.0, -1.0);
263  myTestPolygonContainsPoint(vs, true);
264 
265  // and the other:
266  std::reverse(vs.begin(), vs.end());
267  myTestPolygonContainsPoint(vs, true);
268 
269  {
271  p.AddVertex(0, -0.322);
272  p.AddVertex(-0.644, -0.322);
273  p.AddVertex(-0.210377, -0.324673);
274  p.AddVertex(0.433623, -0.324673);
275 
276  EXPECT_FALSE(p.contains(TPoint2D(0.73175, -0.325796)));
277  }
278 }
279 
280 TEST(Geometry, PolygonConcaveContainsPoint)
281 {
282  // Test with a polygon in one winding order:
283  std::vector<TPoint2D> vs;
284  vs.emplace_back(-2.0, 3.0);
285  vs.emplace_back(2.0, 2.0);
286  vs.emplace_back(3.0, -4.0);
287  vs.emplace_back(0.1, -3.0);
288  vs.emplace_back(0.1, -0.1);
289  vs.emplace_back(-0.1, -0.1);
290  vs.emplace_back(-0.1, -3.0);
291  vs.emplace_back(-2.0, -2.0);
292 
293  myTestPolygonContainsPoint(vs, false);
294 
295  // and the other:
296  std::reverse(vs.begin(), vs.end());
297  myTestPolygonContainsPoint(vs, false);
298 }
bool getPoint(TPoint2D &p) const
Gets the content as a point, returning false if the type is inadequate.
Definition: TObject2D.h:109
void myTestPolygonContainsPoint(std::vector< TPoint2D > &vs, bool convex)
double RAD2DEG(const double x)
Radians to degrees.
unsigned char getType() const
Gets content type.
Definition: TObject2D.h:105
double DEG2RAD(const double x)
Degrees to radians.
Standard type for storing any lightweight 2D type.
Definition: TObject2D.h:24
A wrapper of a TPolygon2D class, implementing CSerializable.
Definition: CPolygon.h:19
static constexpr unsigned char GEOMETRIC_TYPE_POINT
Object type identifier for TPoint2D or TPoint3D.
Definition: TPoseOrPoint.h:101
Standard object for storing any 3D lightweight object.
Definition: TObject3D.h:25
STL namespace.
static constexpr unsigned char GEOMETRIC_TYPE_PLANE
Object type identifier for TPlane.
Definition: TPoseOrPoint.h:121
TEST(Geometry, Line2DIntersect)
This base provides a set of functions for maths stuff.
2D segment, consisting of two points.
Definition: TSegment2D.h:20
3D segment, consisting of two points.
Definition: TSegment3D.h:21
3D Plane, represented by its equation
Definition: TPlane.h:22
double getAngle(const TPlane &p1, const TPlane &p2)
Computes the angle between two planes.
Definition: geometry.cpp:866
bool isConvex() const
Checks whether is convex.
bool contains(const TPoint2D &point) const
Check whether a point is inside (or within geometryEpsilon of a polygon edge).
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
static constexpr unsigned char GEOMETRIC_TYPE_SEGMENT
Object type identifier for TSegment2D or TSegment3D.
Definition: TPoseOrPoint.h:106
Lightweight 3D point.
Definition: TPoint3D.h:90
Lightweight 2D point.
Definition: TPoint2D.h:31
GLfloat GLfloat p
Definition: glext.h:6398
bool intersect(const TSegment3D &s1, const TSegment3D &s2, TObject3D &obj)
Gets the intersection between two 3D segments.
Definition: geometry.cpp:638
static constexpr unsigned char GEOMETRIC_TYPE_LINE
Object type identifier for TLine2D or TLine3D.
Definition: TPoseOrPoint.h:111
2D polygon, inheriting from std::vector<TPoint2D>.
Definition: TPolygon2D.h:21
3D polygon, inheriting from std::vector<TPoint3D>
Definition: TPolygon3D.h:18
3D line, represented by a base point and a director vector.
Definition: TLine3D.h:19
2D line without bounds, represented by its equation .
Definition: TLine2D.h:19



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 8fe78517f Sun Jul 14 19:43:28 2019 +0200 at lun oct 28 02:10:00 CET 2019