Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file PositionVectorTest.cpp
15 : /// @author Matthias Heppner
16 : /// @author Michael Behrisch
17 : /// @author Jakob Erdmann
18 : /// @date 2009-10-24
19 : ///
20 : // Tests the class PositionVector
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <gtest/gtest.h>
25 : #include <utils/geom/PositionVector.h>
26 : #include <utils/geom/Boundary.h>
27 : #include <utils/geom/GeomHelper.h>
28 : #include <utils/common/UtilExceptions.h>
29 : #include <utils/common/MsgHandler.h>
30 : #include <utils/iodevices/OutputDevice.h>
31 :
32 :
33 : #define EXPECT_DOUBLEVEC_EQUAL(v1, v2) \
34 : { \
35 : EXPECT_EQ(v1.size(), v2.size()); \
36 : if (v1.size() == v2.size()) { \
37 : for (int i = 0; i < (int)v1.size(); ++i) { \
38 : EXPECT_DOUBLE_EQ(v1[i], v2[i]); \
39 : } \
40 : } \
41 : } \
42 :
43 :
44 : #define EXPECT_POSITIONVEC_EQUAL(v1, v2) \
45 : { \
46 : EXPECT_EQ(v1.size(), v2.size()); \
47 : if (v1.size() == v2.size()) { \
48 : for (int i = 0; i < (int)v1.size(); ++i) { \
49 : EXPECT_DOUBLE_EQ((v1[i].x()), (v2[i].x())); \
50 : EXPECT_DOUBLE_EQ((v1[i].y()), (v2[i].y())); \
51 : EXPECT_DOUBLE_EQ((v1[i].z()), (v2[i].z())); \
52 : } \
53 : } \
54 : } \
55 :
56 :
57 19 : class PositionVectorTest : public testing::Test {
58 : protected :
59 : PositionVector* vectorPolygon;
60 : PositionVector* vectorLine;
61 : PositionVector* vectorTrianglePositiveCoords;
62 : PositionVector* vectorTriangleNegativeCoords;
63 : PositionVector* vectorRectangleOriginAlignedCorners;
64 :
65 19 : virtual void SetUp() {
66 19 : vectorPolygon = new PositionVector();
67 19 : vectorPolygon->push_back(Position(0, 0));
68 19 : vectorPolygon->push_back(Position(0, 2));
69 19 : vectorPolygon->push_back(Position(2, 4));
70 19 : vectorPolygon->push_back(Position(4, 2));
71 19 : vectorPolygon->push_back(Position(4, 0));
72 :
73 19 : vectorLine = new PositionVector();
74 19 : vectorLine->push_back(Position(0, 0));
75 19 : vectorLine->push_back(Position(2, 2));
76 :
77 19 : vectorTrianglePositiveCoords = new PositionVector();
78 19 : vectorTrianglePositiveCoords->push_back(Position(1, 1));
79 19 : vectorTrianglePositiveCoords->push_back(Position(3, 0));
80 19 : vectorTrianglePositiveCoords->push_back(Position(2, 3));
81 :
82 19 : vectorTriangleNegativeCoords = new PositionVector();
83 19 : vectorTriangleNegativeCoords->push_back(Position(2, -1));
84 19 : vectorTriangleNegativeCoords->push_back(Position(1, -1));
85 19 : vectorTriangleNegativeCoords->push_back(Position(2, -3));
86 :
87 19 : vectorRectangleOriginAlignedCorners = new PositionVector();
88 19 : vectorRectangleOriginAlignedCorners->push_back(Position(1, 1));
89 19 : vectorRectangleOriginAlignedCorners->push_back(Position(3, 1));
90 19 : vectorRectangleOriginAlignedCorners->push_back(Position(3, 3));
91 19 : vectorRectangleOriginAlignedCorners->push_back(Position(1, 3));
92 19 : }
93 :
94 19 : virtual void TearDown() {
95 19 : delete vectorPolygon;
96 19 : delete vectorLine;
97 19 : delete vectorTrianglePositiveCoords;
98 19 : delete vectorTriangleNegativeCoords;
99 19 : delete vectorRectangleOriginAlignedCorners;
100 19 : }
101 :
102 : };
103 :
104 : /* Test the method 'around'*/
105 1 : TEST_F(PositionVectorTest, test_method_around) {
106 :
107 1 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1)));
108 1 : EXPECT_TRUE(vectorPolygon->around(Position(1, 2)));
109 1 : EXPECT_FALSE(vectorPolygon->around(Position(4, 4)));
110 1 : EXPECT_FALSE(vectorPolygon->around(Position(0, 0)));
111 :
112 1 : EXPECT_FALSE(vectorLine->around(Position(1, 1)));
113 1 : EXPECT_FALSE(vectorLine->around(Position(0, 2)));
114 :
115 : // with positive offset
116 1 : EXPECT_TRUE(vectorPolygon->around(Position(4, 2), 1));
117 1 : EXPECT_FALSE(vectorPolygon->around(Position(5, 2), 1));
118 : // what was true remains true
119 1 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1), POSITION_EPS));
120 1 : EXPECT_TRUE(vectorPolygon->around(Position(1, 2), POSITION_EPS));
121 :
122 : // with negative offset
123 1 : EXPECT_FALSE(vectorPolygon->around(Position(4, 2), -POSITION_EPS));
124 1 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1), -1));
125 1 : EXPECT_FALSE(vectorPolygon->around(Position(0.5, 0.5), -1));
126 1 : }
127 :
128 : /* Test the method 'area'*/
129 1 : TEST_F(PositionVectorTest, test_method_area) {
130 1 : PositionVector square;
131 1 : square.push_back(Position(0, 0));
132 1 : square.push_back(Position(1, 0));
133 1 : square.push_back(Position(1, 1));
134 1 : square.push_back(Position(0, 1)); // open
135 1 : EXPECT_DOUBLE_EQ(square.area(), 1);
136 1 : square.push_back(Position(0, 0)); // closed
137 1 : EXPECT_DOUBLE_EQ(square.area(), 1);
138 1 : }
139 :
140 : /* Test the method 'scaleRelative'.*/
141 1 : TEST_F(PositionVectorTest, test_method_scaleRelative) {
142 1 : PositionVector square;
143 1 : square.push_back(Position(0, 0));
144 1 : square.push_back(Position(1, 0));
145 1 : square.push_back(Position(1, 1));
146 1 : square.push_back(Position(0, 1));
147 1 : square.push_back(Position(0, 0));
148 1 : EXPECT_DOUBLE_EQ(square.area(), 1);
149 1 : square.scaleRelative(3);
150 1 : EXPECT_DOUBLE_EQ(square.area(), 9);
151 :
152 2 : PositionVector expected;
153 1 : expected.push_back(Position(-1, -1));
154 1 : expected.push_back(Position(2, -1));
155 1 : expected.push_back(Position(2, 2));
156 1 : expected.push_back(Position(-1, 2));
157 1 : expected.push_back(Position(-1, -1));
158 :
159 2 : EXPECT_EQ(expected.getCentroid(), square.getCentroid());
160 6 : for (int i = 0; i < (int)square.size(); i++) {
161 5 : EXPECT_DOUBLE_EQ(expected[i].x(), square[i].x());
162 5 : EXPECT_DOUBLE_EQ(expected[i].y(), square[i].y());
163 : }
164 1 : }
165 :
166 : /* Test the method 'getCentroid'.*/
167 1 : TEST_F(PositionVectorTest, test_method_getCentroid) {
168 1 : PositionVector square;
169 1 : square.push_back(Position(0, 0));
170 1 : square.push_back(Position(1, 0));
171 1 : square.push_back(Position(1, 1));
172 1 : square.push_back(Position(0, 1));
173 2 : EXPECT_EQ(Position(0.5, 0.5), square.getCentroid());
174 :
175 1 : Position pos2 = vectorLine->getCentroid();
176 1 : EXPECT_DOUBLE_EQ(1, pos2.x());
177 1 : EXPECT_DOUBLE_EQ(1, pos2.y());
178 1 : }
179 :
180 : /* Test the method 'getPolygonCenter'.*/
181 1 : TEST_F(PositionVectorTest, test_method_getPolygonCenter) {
182 1 : Position pos = vectorPolygon->getPolygonCenter();
183 1 : EXPECT_DOUBLE_EQ(2, pos.x());
184 1 : EXPECT_DOUBLE_EQ(1.6, pos.y());
185 1 : Position pos2 = vectorLine->getPolygonCenter();
186 1 : EXPECT_DOUBLE_EQ(1, pos2.x());
187 1 : EXPECT_DOUBLE_EQ(1, pos2.y());
188 1 : }
189 :
190 :
191 : /* Test the method 'getBoxBoundary'*/
192 1 : TEST_F(PositionVectorTest, test_method_getBoxBoundary) {
193 1 : Boundary bound = vectorPolygon->getBoxBoundary();
194 1 : EXPECT_DOUBLE_EQ(bound.xmax(), 4);
195 1 : EXPECT_DOUBLE_EQ(bound.xmin(), 0);
196 1 : EXPECT_DOUBLE_EQ(bound.ymax(), 4);
197 1 : EXPECT_DOUBLE_EQ(bound.ymin(), 0);
198 1 : }
199 :
200 : /* Test the method 'splitAt'*/
201 1 : TEST_F(PositionVectorTest, test_method_splitAt) {
202 1 : PositionVector vec;
203 1 : vec.push_back(Position(0, 0));
204 1 : vec.push_back(Position(2, 0));
205 1 : vec.push_back(Position(5, 0));
206 : double smallDiff = POSITION_EPS / 2;
207 1 : std::pair<PositionVector, PositionVector> result;
208 : // split in first segment
209 2 : result = vec.splitAt(1);
210 1 : EXPECT_EQ(2, (int)result.first.size());
211 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
212 1 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
213 1 : EXPECT_EQ(3, (int)result.second.size());
214 1 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
215 1 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
216 1 : EXPECT_DOUBLE_EQ(5., result.second[2].x());
217 : // split in second segment
218 2 : result = vec.splitAt(4);
219 1 : EXPECT_EQ(3, (int)result.first.size());
220 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
221 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
222 1 : EXPECT_DOUBLE_EQ(4., result.first[2].x());
223 1 : EXPECT_EQ(2, (int)result.second.size());
224 1 : EXPECT_DOUBLE_EQ(4., result.second[0].x());
225 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
226 : // split close before inner point
227 2 : result = vec.splitAt(2 - smallDiff);
228 1 : EXPECT_EQ(2, (int)result.first.size());
229 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
230 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
231 1 : EXPECT_EQ(2, (int)result.second.size());
232 1 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
233 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
234 : // split close after inner point
235 2 : result = vec.splitAt(2 + smallDiff);
236 1 : EXPECT_EQ(2, (int)result.first.size());
237 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
238 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
239 1 : EXPECT_EQ(2, (int)result.second.size());
240 1 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
241 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
242 :
243 : // catch a bug
244 1 : vec.push_back(Position(6, 0));
245 1 : vec.push_back(Position(8, 0));
246 : // split at inner point
247 2 : result = vec.splitAt(5);
248 1 : EXPECT_EQ(3, (int)result.first.size());
249 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
250 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
251 1 : EXPECT_DOUBLE_EQ(5., result.first[2].x());
252 1 : EXPECT_EQ(3, (int)result.second.size());
253 1 : EXPECT_DOUBLE_EQ(5., result.second[0].x());
254 1 : EXPECT_DOUBLE_EQ(6., result.second[1].x());
255 1 : EXPECT_DOUBLE_EQ(8., result.second[2].x());
256 :
257 : // split short vector
258 2 : PositionVector vec2;
259 1 : vec2.push_back(Position(0, 0));
260 1 : vec2.push_back(Position(2, 0));
261 2 : result = vec2.splitAt(1);
262 1 : EXPECT_EQ(2, (int)result.first.size());
263 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
264 1 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
265 1 : EXPECT_EQ(2, (int)result.second.size());
266 1 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
267 1 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
268 :
269 : // split very short vector
270 2 : PositionVector vec3;
271 1 : vec3.push_back(Position(0, 0));
272 1 : vec3.push_back(Position(POSITION_EPS, 0));
273 : // supress expected warning
274 1 : MsgHandler::getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
275 1 : result = vec3.splitAt(smallDiff);
276 2 : MsgHandler::getWarningInstance()->addRetriever(&OutputDevice::getDevice("stderr"));
277 :
278 1 : EXPECT_EQ(2, (int)result.first.size());
279 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
280 1 : EXPECT_DOUBLE_EQ(smallDiff, result.first[1].x());
281 1 : EXPECT_EQ(2, (int)result.second.size());
282 1 : EXPECT_DOUBLE_EQ(smallDiff, result.second[0].x());
283 1 : EXPECT_DOUBLE_EQ(POSITION_EPS, result.second[1].x());
284 1 : }
285 :
286 :
287 : /* Test the method 'intersectsAtLengths2D'*/
288 1 : TEST_F(PositionVectorTest, test_method_intersectsAtLengths2D) {
289 1 : PositionVector vec1;
290 1 : vec1.push_back(Position(0, 0, 42));
291 1 : vec1.push_back(Position(100, 0, 0));
292 :
293 1 : PositionVector vec2;
294 1 : vec2.push_back(Position(0, 0, 0));
295 1 : vec2.push_back(Position(3, 1, 0));
296 1 : EXPECT_DOUBLE_EQ(0, vec1.intersectsAtLengths2D(vec2)[0]);
297 1 : }
298 :
299 :
300 : /* Test the method 'nearest_offset_to_point2D'*/
301 1 : TEST_F(PositionVectorTest, test_method_nearest_offset_to_point2D) {
302 1 : PositionVector vec1;
303 1 : vec1.push_back(Position(0, 1, 0));
304 1 : vec1.push_back(Position(0, 0, 0));
305 1 : vec1.push_back(Position(1, 0, 0));
306 :
307 1 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), false));
308 1 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), true));
309 1 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(2, 1), false));
310 1 : EXPECT_DOUBLE_EQ(0, vec1.nearest_offset_to_point2D(Position(2, 1), true));
311 1 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(3, 2), false));
312 1 : EXPECT_DOUBLE_EQ(-1, vec1.nearest_offset_to_point2D(Position(3, 2), true));
313 1 : }
314 :
315 :
316 1 : TEST_F(PositionVectorTest, test_method_extrapolate2D) {
317 1 : PositionVector vec1;
318 1 : vec1.push_back(Position(0, 1, 0));
319 1 : vec1.push_back(Position(0, 0, 0));
320 1 : vec1.push_back(Position(1, 0, 0));
321 1 : vec1.extrapolate2D(1);
322 2 : EXPECT_EQ(Position(0, 2, 0), vec1[0]);
323 2 : EXPECT_EQ(Position(0, 0, 0), vec1[1]);
324 2 : EXPECT_EQ(Position(2, 0, 0), vec1[2]);
325 :
326 2 : PositionVector vec2;
327 1 : vec2.push_back(Position(0, 1, 0));
328 1 : vec2.push_back(Position(0, 0, 1));
329 0 : vec2.push_back(Position(1, 0, 0));
330 1 : vec2.extrapolate2D(1);
331 : // EXPECT_EQ(Position(0,2,0), vec2[0]);
332 : // EXPECT_EQ(Position(0,0,0), vec2[1]);
333 : // EXPECT_EQ(Position(2,0,0), vec2[2]);
334 :
335 2 : PositionVector vec3;
336 1 : vec3.push_back(Position(-.5, 1));
337 1 : vec3.push_back(Position(-.5, -.5));
338 1 : vec3.push_back(Position(1, -.5));
339 1 : vec3.extrapolate2D(.5);
340 2 : EXPECT_EQ(Position(-.5, 1.5), vec3[0]);
341 2 : EXPECT_EQ(Position(-.5, -.5), vec3[1]);
342 2 : EXPECT_EQ(Position(1.5, -.5), vec3[2]);
343 :
344 1 : }
345 :
346 :
347 : /* Test the method 'move2side'*/
348 1 : TEST_F(PositionVectorTest, test_method_move2side) {
349 1 : PositionVector vec1;
350 1 : vec1.push_back(Position(0, 1, 0));
351 1 : vec1.push_back(Position(0, 0, 0));
352 1 : vec1.push_back(Position(1, 0, 0));
353 1 : vec1.move2side(.5);
354 2 : EXPECT_EQ(Position(-.5, 1), vec1[0]);
355 2 : EXPECT_EQ(Position(-.5, -.5), vec1[1]);
356 2 : EXPECT_EQ(Position(1, -.5), vec1[2]);
357 1 : vec1.move2side(-1);
358 2 : EXPECT_EQ(Position(.5, 1), vec1[0]);
359 2 : EXPECT_EQ(Position(.5, .5), vec1[1]);
360 2 : EXPECT_EQ(Position(1, .5), vec1[2]);
361 :
362 : // parallel case
363 2 : PositionVector vec2;
364 1 : vec2.push_back(Position(0, 0, 0));
365 1 : vec2.push_back(Position(1, 0, 0));
366 1 : vec2.push_back(Position(3, 0, 0));
367 1 : vec2.move2side(.5);
368 2 : EXPECT_EQ(Position(0, -.5), vec2[0]);
369 2 : EXPECT_EQ(Position(1, -.5), vec2[1]);
370 2 : EXPECT_EQ(Position(3, -.5), vec2[2]);
371 1 : vec2.move2side(-1);
372 2 : EXPECT_EQ(Position(0, .5), vec2[0]);
373 2 : EXPECT_EQ(Position(1, .5), vec2[1]);
374 2 : EXPECT_EQ(Position(3, .5), vec2[2]);
375 :
376 : // counterparallel case
377 : {
378 1 : PositionVector vec3;
379 1 : vec3.push_back(Position(0, 0, 0));
380 1 : vec3.push_back(Position(3, 0, 0));
381 1 : vec3.push_back(Position(1, 0, 0));
382 1 : vec3.move2side(.5);
383 : // clipping removal eliminates the middle point
384 2 : EXPECT_EQ(Position(0, -.5), vec3[0]);
385 2 : EXPECT_EQ(Position(1, -.5), vec3[1]);
386 1 : }
387 : // bad input: subsequent identical points
388 : {
389 1 : PositionVector vec4;
390 1 : vec4.push_back(Position(0, 0, 0));
391 1 : vec4.push_back(Position(0, 0, 0));
392 1 : vec4.push_back(Position(1, 0, 0));
393 1 : vec4.move2side(-2);
394 1 : EXPECT_EQ(2, (int)vec4.size());
395 2 : EXPECT_EQ(Position(0, 2), vec4[0]);
396 2 : EXPECT_EQ(Position(1, 2), vec4[1]);
397 1 : }
398 1 : }
399 :
400 : /* Test the method 'transformToVectorCoordinates'*/
401 1 : TEST_F(PositionVectorTest, test_method_transformToVectorCoordinates) {
402 : {
403 1 : PositionVector vec1;
404 1 : vec1.push_back(Position(1, 0));
405 1 : vec1.push_back(Position(10, 0));
406 1 : vec1.push_back(Position(10, 5));
407 1 : vec1.push_back(Position(20, 5));
408 : Position on(4, 0);
409 : Position left(4, 1);
410 : Position right(4, -1);
411 : Position left2(4, 2);
412 : Position right2(4, -2);
413 : Position cornerRight(13, -4);
414 : Position cornerLeft(7, 9);
415 : Position before(0, -1);
416 : Position beyond(24, 9);
417 :
418 2 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
419 2 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(left));
420 2 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(right));
421 2 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(left2));
422 2 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(right2));
423 2 : EXPECT_EQ(Position(9, 5), vec1.transformToVectorCoordinates(cornerRight));
424 2 : EXPECT_EQ(Position(14, -5), vec1.transformToVectorCoordinates(cornerLeft));
425 :
426 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
427 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
428 2 : EXPECT_EQ(Position(-1, 1), vec1.transformToVectorCoordinates(before, true));
429 2 : EXPECT_EQ(Position(28, -4), vec1.transformToVectorCoordinates(beyond, true));
430 1 : }
431 :
432 : {
433 1 : PositionVector vec1; // the same tests as before, mirrored on x-axis
434 1 : vec1.push_back(Position(1, 0));
435 1 : vec1.push_back(Position(10, 0));
436 1 : vec1.push_back(Position(10, -5));
437 1 : vec1.push_back(Position(20, -5));
438 : Position on(4, 0);
439 : Position left(4, -1);
440 : Position right(4, 1);
441 : Position left2(4, -2);
442 : Position right2(4, 2);
443 : Position cornerRight(13, 4);
444 : Position cornerLeft(7, -9);
445 : Position before(0, 1);
446 : Position beyond(24, -9);
447 :
448 2 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
449 2 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(left));
450 2 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(right));
451 2 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(left2));
452 2 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(right2));
453 2 : EXPECT_EQ(Position(9, -5), vec1.transformToVectorCoordinates(cornerRight));
454 2 : EXPECT_EQ(Position(14, 5), vec1.transformToVectorCoordinates(cornerLeft));
455 :
456 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
457 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
458 2 : EXPECT_EQ(Position(-1, -1), vec1.transformToVectorCoordinates(before, true));
459 2 : EXPECT_EQ(Position(28, 4), vec1.transformToVectorCoordinates(beyond, true));
460 1 : }
461 1 : }
462 :
463 :
464 : /* Test the method 'distance'*/
465 1 : TEST_F(PositionVectorTest, test_method_distance) {
466 : {
467 1 : PositionVector vec1;
468 1 : vec1.push_back(Position(1, 0));
469 1 : vec1.push_back(Position(10, 0));
470 1 : vec1.push_back(Position(10, 5));
471 1 : vec1.push_back(Position(20, 5));
472 : Position on(4, 0);
473 : Position left(4, 1);
474 : Position right(4, -1);
475 : Position left2(4, 2);
476 : Position right2(4, -2);
477 : Position cornerRight(13, -4);
478 : Position cornerLeft(7, 9);
479 : Position before(-3, -3);
480 : Position beyond(24, 8);
481 :
482 1 : EXPECT_EQ(0, vec1.distance2D(on));
483 1 : EXPECT_EQ(1, vec1.distance2D(left));
484 1 : EXPECT_EQ(1, vec1.distance2D(right));
485 1 : EXPECT_EQ(2, vec1.distance2D(left2));
486 1 : EXPECT_EQ(2, vec1.distance2D(right2));
487 1 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
488 1 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
489 :
490 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
491 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
492 1 : EXPECT_EQ(5, vec1.distance2D(before));
493 1 : EXPECT_EQ(5, vec1.distance2D(beyond));
494 1 : }
495 :
496 : {
497 1 : PositionVector vec1; // the same tests as before, mirrored on x-axis
498 1 : vec1.push_back(Position(1, 0));
499 1 : vec1.push_back(Position(10, 0));
500 1 : vec1.push_back(Position(10, -5));
501 1 : vec1.push_back(Position(20, -5));
502 : Position on(4, 0);
503 : Position left(4, -1);
504 : Position right(4, 1);
505 : Position left2(4, -2);
506 : Position right2(4, 2);
507 : Position cornerRight(13, 4);
508 : Position cornerLeft(7, -9);
509 : Position before(-3, 3);
510 : Position beyond(24, -8);
511 :
512 1 : EXPECT_EQ(0, vec1.distance2D(on));
513 1 : EXPECT_EQ(1, vec1.distance2D(left));
514 1 : EXPECT_EQ(1, vec1.distance2D(right));
515 1 : EXPECT_EQ(2, vec1.distance2D(left2));
516 1 : EXPECT_EQ(2, vec1.distance2D(right2));
517 1 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
518 1 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
519 :
520 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
521 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
522 1 : EXPECT_EQ(5, vec1.distance2D(before));
523 1 : EXPECT_EQ(5, vec1.distance2D(beyond));
524 1 : }
525 1 : }
526 :
527 :
528 : /* Test the method 'distance'*/
529 1 : TEST_F(PositionVectorTest, test_method_distances) {
530 : {
531 1 : PositionVector vec1;
532 1 : vec1.push_back(Position(0, 0));
533 1 : vec1.push_back(Position(10, 0));
534 :
535 1 : PositionVector vec2;
536 1 : vec2.push_back(Position(1, 0));
537 1 : vec2.push_back(Position(5, 2));
538 1 : vec2.push_back(Position(10, 0));
539 1 : vec2.push_back(Position(14, 3));
540 :
541 1 : PositionVector vec3;
542 :
543 : std::vector<double> res1;
544 1 : res1.push_back(1);
545 1 : res1.push_back(0);
546 1 : res1.push_back(0);
547 1 : res1.push_back(2);
548 1 : res1.push_back(0);
549 1 : res1.push_back(5);
550 9 : EXPECT_DOUBLEVEC_EQUAL(res1, vec1.distances(vec2));
551 :
552 :
553 1 : std::vector<double> res2;
554 : //invalid: res1.push_back(1);
555 1 : res2.push_back(0);
556 1 : res2.push_back(0);
557 1 : res2.push_back(2);
558 1 : res2.push_back(0);
559 : //invalid: res2.push_back(5);
560 7 : EXPECT_DOUBLEVEC_EQUAL(res2, vec1.distances(vec2, true));
561 :
562 :
563 1 : std::vector<double> res3;
564 1 : res3.push_back(std::numeric_limits<double>::max());
565 1 : res3.push_back(std::numeric_limits<double>::max());
566 5 : EXPECT_DOUBLEVEC_EQUAL(res3, vec1.distances(vec3));
567 1 : }
568 :
569 1 : }
570 :
571 :
572 : /* Test the method 'overlapsWith'*/
573 1 : TEST_F(PositionVectorTest, test_method_overlapsWith) {
574 1 : PositionVector vec1;
575 1 : vec1.push_back(Position(1, 2));
576 1 : vec1.push_back(Position(3, 2));
577 1 : vec1.push_back(Position(3, 6));
578 1 : vec1.push_back(Position(1, 6));
579 :
580 1 : PositionVector vec2;
581 1 : vec2.push_back(Position(10, 17));
582 1 : vec2.push_back(Position(13, 17));
583 1 : vec2.push_back(Position(13, 16));
584 1 : vec2.push_back(Position(10, 16));
585 :
586 1 : PositionVector vec3;
587 1 : vec3.push_back(Position(-1, -7));
588 1 : vec3.push_back(Position(2, -7));
589 1 : vec3.push_back(Position(2, 4));
590 1 : vec3.push_back(Position(-1, 4));
591 :
592 1 : PositionVector vec4;
593 1 : vec4.push_back(Position(0, 3));
594 1 : vec4.push_back(Position(4, 3));
595 1 : vec4.push_back(Position(4, 5));
596 1 : vec4.push_back(Position(0, 5));
597 :
598 1 : PositionVector vec5;
599 1 : vec5.push_back(Position(4, 2));
600 1 : vec5.push_back(Position(5, 2));
601 1 : vec5.push_back(Position(5, 7));
602 1 : vec5.push_back(Position(4, 7));
603 :
604 1 : PositionVector vec6;
605 1 : vec6.push_back(Position(4, 0));
606 1 : vec6.push_back(Position(4, 8));
607 1 : vec6.push_back(Position(-4, 8));
608 :
609 1 : PositionVector empty;
610 :
611 1 : EXPECT_TRUE(vec1.overlapsWith(vec1));
612 1 : EXPECT_FALSE(vec1.overlapsWith(vec2));
613 1 : EXPECT_TRUE(vec1.overlapsWith(vec3));
614 1 : EXPECT_TRUE(vec1.overlapsWith(vec4));
615 1 : EXPECT_FALSE(vec1.overlapsWith(vec5, 0));
616 1 : EXPECT_TRUE(vec1.overlapsWith(vec6)); // overlapsWith implicitly closes the shape of vec6
617 1 : EXPECT_TRUE(vec6.overlapsWith(vec1)); // overlapsWith implicitly closes the shape of vec6
618 : // growth is from centroid and thus different from Boundary behavior
619 1 : EXPECT_FALSE(vec1.overlapsWith(vec5, 1));
620 1 : EXPECT_TRUE(vec1.overlapsWith(vec5, 3));
621 1 : EXPECT_TRUE(vec1.overlapsWith(vec5, 6));
622 1 : EXPECT_FALSE(vec1.overlapsWith(empty));
623 1 : }
624 :
625 :
626 : /* Test the method 'sortAsPolyCWByAngle'*/
627 1 : TEST_F(PositionVectorTest, test_method_sortAsPolyCWByAngle) {
628 1 : PositionVector vectorTrianglePositiveCoordsClockwiseOrdered;
629 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(2, 3));
630 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(3, 0));
631 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(1, 1));
632 1 : vectorTrianglePositiveCoords->sortAsPolyCWByAngle();
633 12 : EXPECT_POSITIONVEC_EQUAL((*vectorTrianglePositiveCoords), vectorTrianglePositiveCoordsClockwiseOrdered);
634 :
635 2 : PositionVector vectorTriangleNegativeCoordsClockwiseOrdered;
636 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(1, -1));
637 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -1));
638 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -3));
639 1 : vectorTriangleNegativeCoords->sortAsPolyCWByAngle();
640 12 : EXPECT_POSITIONVEC_EQUAL((*vectorTriangleNegativeCoords), vectorTriangleNegativeCoordsClockwiseOrdered);
641 :
642 2 : PositionVector vectorRectangleOriginAlignedCornersClockwiseOrdered;
643 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 3));
644 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 3));
645 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 1));
646 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 1));
647 1 : vectorRectangleOriginAlignedCorners->sortAsPolyCWByAngle();
648 15 : EXPECT_POSITIONVEC_EQUAL((*vectorRectangleOriginAlignedCorners), vectorRectangleOriginAlignedCornersClockwiseOrdered);
649 1 : }
650 :
651 :
652 : /* Test the method 'isClockwiseOriented'*/
653 1 : TEST_F(PositionVectorTest, test_method_isClockwiseOriented) {
654 1 : EXPECT_FALSE(vectorTrianglePositiveCoords->isClockwiseOriented());
655 1 : EXPECT_FALSE(vectorTriangleNegativeCoords->isClockwiseOriented());
656 1 : EXPECT_FALSE(vectorRectangleOriginAlignedCorners->isClockwiseOriented());
657 1 : }
658 :
659 :
660 : /* Test the method 'simplified'*/
661 2 : TEST_F(PositionVectorTest, test_method_simplified) {
662 1 : const PositionVector vec1(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2)});
663 1 : const PositionVector result = vec1.simplified();
664 1 : EXPECT_EQ(3, (int)result.size());
665 2 : const PositionVector vec2(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2), Position(1, 2)});
666 2 : const PositionVector result2 = vec2.simplified();
667 1 : EXPECT_EQ(4, (int)result2.size());
668 2 : const PositionVector vec3(std::vector<Position> {Position(1, 2), Position(1, 3), Position(1, 4), Position(1, 5)});
669 2 : const PositionVector result3 = vec3.simplified();
670 : // std::cout << result3 << std::endl;
671 1 : EXPECT_EQ(3, (int)result3.size());
672 :
673 2 : const PositionVector vec4(std::vector<Position> {Position(0, 0), Position(0, 8), Position(NUMERICAL_EPS / 2., 7), Position(NUMERICAL_EPS, 6), Position(3. * NUMERICAL_EPS / 2., 5),
674 : Position(2. * NUMERICAL_EPS, 4), Position(3. * NUMERICAL_EPS / 2., 3), Position(NUMERICAL_EPS, 2), Position(NUMERICAL_EPS / 2., 1)
675 2 : });
676 2 : const PositionVector result4 = vec4.simplified();
677 1 : EXPECT_EQ(3, (int)result4.size());
678 1 : }
679 :
680 :
681 : /* Test the method 'simplified2'*/
682 2 : TEST_F(PositionVectorTest, test_method_simplified2) {
683 1 : const PositionVector vec1(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2)});
684 1 : const PositionVector result = vec1.simplified2(true);
685 1 : EXPECT_EQ(2, (int)result.size());
686 2 : const PositionVector vec2(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2), Position(1, 2)});
687 2 : const PositionVector result2 = vec2.simplified2(true);
688 1 : EXPECT_EQ(2, (int)result2.size());
689 2 : const PositionVector vec3(std::vector<Position> {Position(1, 2), Position(1, 3), Position(1, 4), Position(1, 5)});
690 2 : const PositionVector result3 = vec3.simplified2(true);
691 : // std::cout << result3 << std::endl;
692 1 : EXPECT_EQ(2, (int)result3.size());
693 1 : EXPECT_DOUBLE_EQ(2., result3.front().y());
694 1 : EXPECT_DOUBLE_EQ(5., result3.back().y());
695 :
696 2 : const PositionVector vec4(std::vector<Position> {Position(0, 0), Position(0, 8), Position(NUMERICAL_EPS / 2., 7), Position(NUMERICAL_EPS, 6), Position(3. * NUMERICAL_EPS / 2., 5),
697 : Position(2. * NUMERICAL_EPS, 4), Position(3. * NUMERICAL_EPS / 2., 3), Position(NUMERICAL_EPS, 2), Position(NUMERICAL_EPS / 2., 1)
698 2 : });
699 2 : const PositionVector result4 = vec4.simplified2(true);
700 1 : EXPECT_EQ(3, (int)result4.size());
701 1 : EXPECT_DOUBLE_EQ(0., result4.front().y());
702 1 : EXPECT_DOUBLE_EQ(8., result4[1].y());
703 1 : EXPECT_DOUBLE_EQ(4., result4.back().y());
704 1 : }
|