Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 : }
187 :
188 :
189 : /* Test the method 'getBoxBoundary'*/
190 1 : TEST_F(PositionVectorTest, test_method_getBoxBoundary) {
191 1 : Boundary bound = vectorPolygon->getBoxBoundary();
192 1 : EXPECT_DOUBLE_EQ(bound.xmax(), 4);
193 1 : EXPECT_DOUBLE_EQ(bound.xmin(), 0);
194 1 : EXPECT_DOUBLE_EQ(bound.ymax(), 4);
195 1 : EXPECT_DOUBLE_EQ(bound.ymin(), 0);
196 1 : }
197 :
198 : /* Test the method 'splitAt'*/
199 1 : TEST_F(PositionVectorTest, test_method_splitAt) {
200 1 : PositionVector vec;
201 1 : vec.push_back(Position(0, 0));
202 1 : vec.push_back(Position(2, 0));
203 1 : vec.push_back(Position(5, 0));
204 : double smallDiff = POSITION_EPS / 2;
205 1 : std::pair<PositionVector, PositionVector> result;
206 : // split in first segment
207 2 : result = vec.splitAt(1);
208 1 : EXPECT_EQ(2, (int)result.first.size());
209 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
210 1 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
211 1 : EXPECT_EQ(3, (int)result.second.size());
212 1 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
213 1 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
214 1 : EXPECT_DOUBLE_EQ(5., result.second[2].x());
215 : // split in second segment
216 2 : result = vec.splitAt(4);
217 1 : EXPECT_EQ(3, (int)result.first.size());
218 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
219 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
220 1 : EXPECT_DOUBLE_EQ(4., result.first[2].x());
221 1 : EXPECT_EQ(2, (int)result.second.size());
222 1 : EXPECT_DOUBLE_EQ(4., result.second[0].x());
223 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
224 : // split close before inner point
225 2 : result = vec.splitAt(2 - smallDiff);
226 1 : EXPECT_EQ(2, (int)result.first.size());
227 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
228 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
229 1 : EXPECT_EQ(2, (int)result.second.size());
230 1 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
231 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
232 : // split close after inner point
233 2 : result = vec.splitAt(2 + smallDiff);
234 1 : EXPECT_EQ(2, (int)result.first.size());
235 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
236 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
237 1 : EXPECT_EQ(2, (int)result.second.size());
238 1 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
239 1 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
240 :
241 : // catch a bug
242 1 : vec.push_back(Position(6, 0));
243 1 : vec.push_back(Position(8, 0));
244 : // split at inner point
245 2 : result = vec.splitAt(5);
246 1 : EXPECT_EQ(3, (int)result.first.size());
247 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
248 1 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
249 1 : EXPECT_DOUBLE_EQ(5., result.first[2].x());
250 1 : EXPECT_EQ(3, (int)result.second.size());
251 1 : EXPECT_DOUBLE_EQ(5., result.second[0].x());
252 1 : EXPECT_DOUBLE_EQ(6., result.second[1].x());
253 1 : EXPECT_DOUBLE_EQ(8., result.second[2].x());
254 :
255 : // split short vector
256 1 : PositionVector vec2;
257 1 : vec2.push_back(Position(0, 0));
258 1 : vec2.push_back(Position(2, 0));
259 2 : result = vec2.splitAt(1);
260 1 : EXPECT_EQ(2, (int)result.first.size());
261 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
262 1 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
263 1 : EXPECT_EQ(2, (int)result.second.size());
264 1 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
265 1 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
266 :
267 : // split very short vector
268 2 : PositionVector vec3;
269 1 : vec3.push_back(Position(0, 0));
270 1 : vec3.push_back(Position(POSITION_EPS, 0));
271 : // supress expected warning
272 1 : MsgHandler::getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
273 1 : result = vec3.splitAt(smallDiff);
274 2 : MsgHandler::getWarningInstance()->addRetriever(&OutputDevice::getDevice("stderr"));
275 :
276 1 : EXPECT_EQ(2, (int)result.first.size());
277 1 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
278 1 : EXPECT_DOUBLE_EQ(smallDiff, result.first[1].x());
279 1 : EXPECT_EQ(2, (int)result.second.size());
280 1 : EXPECT_DOUBLE_EQ(smallDiff, result.second[0].x());
281 1 : EXPECT_DOUBLE_EQ(POSITION_EPS, result.second[1].x());
282 1 : }
283 :
284 :
285 : /* Test the method 'intersectsAtLengths2D'*/
286 1 : TEST_F(PositionVectorTest, test_method_intersectsAtLengths2D) {
287 1 : PositionVector vec1;
288 1 : vec1.push_back(Position(0, 0, 42));
289 1 : vec1.push_back(Position(100, 0, 0));
290 :
291 1 : PositionVector vec2;
292 1 : vec2.push_back(Position(0, 0, 0));
293 1 : vec2.push_back(Position(3, 1, 0));
294 1 : EXPECT_DOUBLE_EQ(0, vec1.intersectsAtLengths2D(vec2)[0]);
295 1 : }
296 :
297 :
298 : /* Test the method 'nearest_offset_to_point2D'*/
299 1 : TEST_F(PositionVectorTest, test_method_nearest_offset_to_point2D) {
300 1 : PositionVector vec1;
301 1 : vec1.push_back(Position(0, 1, 0));
302 1 : vec1.push_back(Position(0, 0, 0));
303 1 : vec1.push_back(Position(1, 0, 0));
304 :
305 1 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), false));
306 1 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), true));
307 1 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(2, 1), false));
308 1 : EXPECT_DOUBLE_EQ(0, vec1.nearest_offset_to_point2D(Position(2, 1), true));
309 1 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(3, 2), false));
310 1 : EXPECT_DOUBLE_EQ(-1, vec1.nearest_offset_to_point2D(Position(3, 2), true));
311 1 : }
312 :
313 :
314 1 : TEST_F(PositionVectorTest, test_method_extrapolate2D) {
315 1 : PositionVector vec1;
316 1 : vec1.push_back(Position(0, 1, 0));
317 1 : vec1.push_back(Position(0, 0, 0));
318 1 : vec1.push_back(Position(1, 0, 0));
319 1 : vec1.extrapolate2D(1);
320 2 : EXPECT_EQ(Position(0, 2, 0), vec1[0]);
321 2 : EXPECT_EQ(Position(0, 0, 0), vec1[1]);
322 2 : EXPECT_EQ(Position(2, 0, 0), vec1[2]);
323 :
324 2 : PositionVector vec2;
325 1 : vec2.push_back(Position(0, 1, 0));
326 1 : vec2.push_back(Position(0, 0, 1));
327 0 : vec2.push_back(Position(1, 0, 0));
328 1 : vec2.extrapolate2D(1);
329 : // EXPECT_EQ(Position(0,2,0), vec2[0]);
330 : // EXPECT_EQ(Position(0,0,0), vec2[1]);
331 : // EXPECT_EQ(Position(2,0,0), vec2[2]);
332 :
333 2 : PositionVector vec3;
334 1 : vec3.push_back(Position(-.5, 1));
335 1 : vec3.push_back(Position(-.5, -.5));
336 1 : vec3.push_back(Position(1, -.5));
337 1 : vec3.extrapolate2D(.5);
338 2 : EXPECT_EQ(Position(-.5, 1.5), vec3[0]);
339 2 : EXPECT_EQ(Position(-.5, -.5), vec3[1]);
340 2 : EXPECT_EQ(Position(1.5, -.5), vec3[2]);
341 :
342 1 : }
343 :
344 :
345 : /* Test the method 'move2side'*/
346 1 : TEST_F(PositionVectorTest, test_method_move2side) {
347 1 : PositionVector vec1;
348 1 : vec1.push_back(Position(0, 1, 0));
349 1 : vec1.push_back(Position(0, 0, 0));
350 1 : vec1.push_back(Position(1, 0, 0));
351 1 : vec1.move2side(.5);
352 2 : EXPECT_EQ(Position(-.5, 1), vec1[0]);
353 2 : EXPECT_EQ(Position(-.5, -.5), vec1[1]);
354 2 : EXPECT_EQ(Position(1, -.5), vec1[2]);
355 1 : vec1.move2side(-1);
356 2 : EXPECT_EQ(Position(.5, 1), vec1[0]);
357 2 : EXPECT_EQ(Position(.5, .5), vec1[1]);
358 2 : EXPECT_EQ(Position(1, .5), vec1[2]);
359 :
360 : // parallel case
361 2 : PositionVector vec2;
362 1 : vec2.push_back(Position(0, 0, 0));
363 1 : vec2.push_back(Position(1, 0, 0));
364 1 : vec2.push_back(Position(3, 0, 0));
365 1 : vec2.move2side(.5);
366 2 : EXPECT_EQ(Position(0, -.5), vec2[0]);
367 2 : EXPECT_EQ(Position(1, -.5), vec2[1]);
368 2 : EXPECT_EQ(Position(3, -.5), vec2[2]);
369 1 : vec2.move2side(-1);
370 2 : EXPECT_EQ(Position(0, .5), vec2[0]);
371 2 : EXPECT_EQ(Position(1, .5), vec2[1]);
372 2 : EXPECT_EQ(Position(3, .5), vec2[2]);
373 :
374 : // counterparallel case
375 : {
376 1 : PositionVector vec3;
377 1 : vec3.push_back(Position(0, 0, 0));
378 1 : vec3.push_back(Position(3, 0, 0));
379 1 : vec3.push_back(Position(1, 0, 0));
380 1 : vec3.move2side(.5);
381 : // clipping removal eliminates the middle point
382 2 : EXPECT_EQ(Position(0, -.5), vec3[0]);
383 2 : EXPECT_EQ(Position(1, -.5), vec3[1]);
384 1 : }
385 : // bad input: subsequent identical points
386 : {
387 1 : PositionVector vec4;
388 1 : vec4.push_back(Position(0, 0, 0));
389 1 : vec4.push_back(Position(0, 0, 0));
390 1 : vec4.push_back(Position(1, 0, 0));
391 1 : vec4.move2side(-2);
392 1 : EXPECT_EQ(2, (int)vec4.size());
393 2 : EXPECT_EQ(Position(0, 2), vec4[0]);
394 2 : EXPECT_EQ(Position(1, 2), vec4[1]);
395 1 : }
396 1 : }
397 :
398 : /* Test the method 'transformToVectorCoordinates'*/
399 1 : TEST_F(PositionVectorTest, test_method_transformToVectorCoordinates) {
400 : {
401 1 : PositionVector vec1;
402 1 : vec1.push_back(Position(1, 0));
403 1 : vec1.push_back(Position(10, 0));
404 1 : vec1.push_back(Position(10, 5));
405 1 : vec1.push_back(Position(20, 5));
406 : Position on(4, 0);
407 : Position left(4, 1);
408 : Position right(4, -1);
409 : Position left2(4, 2);
410 : Position right2(4, -2);
411 : Position cornerRight(13, -4);
412 : Position cornerLeft(7, 9);
413 : Position before(0, -1);
414 : Position beyond(24, 9);
415 :
416 2 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
417 2 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(left));
418 2 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(right));
419 2 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(left2));
420 2 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(right2));
421 2 : EXPECT_EQ(Position(9, 5), vec1.transformToVectorCoordinates(cornerRight));
422 2 : EXPECT_EQ(Position(14, -5), vec1.transformToVectorCoordinates(cornerLeft));
423 :
424 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
425 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
426 2 : EXPECT_EQ(Position(-1, 1), vec1.transformToVectorCoordinates(before, true));
427 2 : EXPECT_EQ(Position(28, -4), vec1.transformToVectorCoordinates(beyond, true));
428 1 : }
429 :
430 : {
431 1 : PositionVector vec1; // the same tests as before, mirrored on x-axis
432 1 : vec1.push_back(Position(1, 0));
433 1 : vec1.push_back(Position(10, 0));
434 1 : vec1.push_back(Position(10, -5));
435 1 : vec1.push_back(Position(20, -5));
436 : Position on(4, 0);
437 : Position left(4, -1);
438 : Position right(4, 1);
439 : Position left2(4, -2);
440 : Position right2(4, 2);
441 : Position cornerRight(13, 4);
442 : Position cornerLeft(7, -9);
443 : Position before(0, 1);
444 : Position beyond(24, -9);
445 :
446 2 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
447 2 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(left));
448 2 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(right));
449 2 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(left2));
450 2 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(right2));
451 2 : EXPECT_EQ(Position(9, -5), vec1.transformToVectorCoordinates(cornerRight));
452 2 : EXPECT_EQ(Position(14, 5), vec1.transformToVectorCoordinates(cornerLeft));
453 :
454 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
455 2 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
456 2 : EXPECT_EQ(Position(-1, -1), vec1.transformToVectorCoordinates(before, true));
457 2 : EXPECT_EQ(Position(28, 4), vec1.transformToVectorCoordinates(beyond, true));
458 1 : }
459 1 : }
460 :
461 :
462 : /* Test the method 'distance'*/
463 1 : TEST_F(PositionVectorTest, test_method_distance) {
464 : {
465 1 : PositionVector vec1;
466 1 : vec1.push_back(Position(1, 0));
467 1 : vec1.push_back(Position(10, 0));
468 1 : vec1.push_back(Position(10, 5));
469 1 : vec1.push_back(Position(20, 5));
470 : Position on(4, 0);
471 : Position left(4, 1);
472 : Position right(4, -1);
473 : Position left2(4, 2);
474 : Position right2(4, -2);
475 : Position cornerRight(13, -4);
476 : Position cornerLeft(7, 9);
477 : Position before(-3, -3);
478 : Position beyond(24, 8);
479 :
480 1 : EXPECT_EQ(0, vec1.distance2D(on));
481 1 : EXPECT_EQ(1, vec1.distance2D(left));
482 1 : EXPECT_EQ(1, vec1.distance2D(right));
483 1 : EXPECT_EQ(2, vec1.distance2D(left2));
484 1 : EXPECT_EQ(2, vec1.distance2D(right2));
485 1 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
486 1 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
487 :
488 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
489 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
490 1 : EXPECT_EQ(5, vec1.distance2D(before));
491 1 : EXPECT_EQ(5, vec1.distance2D(beyond));
492 1 : }
493 :
494 : {
495 1 : PositionVector vec1; // the same tests as before, mirrored on x-axis
496 1 : vec1.push_back(Position(1, 0));
497 1 : vec1.push_back(Position(10, 0));
498 1 : vec1.push_back(Position(10, -5));
499 1 : vec1.push_back(Position(20, -5));
500 : Position on(4, 0);
501 : Position left(4, -1);
502 : Position right(4, 1);
503 : Position left2(4, -2);
504 : Position right2(4, 2);
505 : Position cornerRight(13, 4);
506 : Position cornerLeft(7, -9);
507 : Position before(-3, 3);
508 : Position beyond(24, -8);
509 :
510 1 : EXPECT_EQ(0, vec1.distance2D(on));
511 1 : EXPECT_EQ(1, vec1.distance2D(left));
512 1 : EXPECT_EQ(1, vec1.distance2D(right));
513 1 : EXPECT_EQ(2, vec1.distance2D(left2));
514 1 : EXPECT_EQ(2, vec1.distance2D(right2));
515 1 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
516 1 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
517 :
518 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
519 1 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
520 1 : EXPECT_EQ(5, vec1.distance2D(before));
521 1 : EXPECT_EQ(5, vec1.distance2D(beyond));
522 1 : }
523 1 : }
524 :
525 :
526 : /* Test the method 'distance'*/
527 1 : TEST_F(PositionVectorTest, test_method_distances) {
528 : {
529 1 : PositionVector vec1;
530 1 : vec1.push_back(Position(0, 0));
531 1 : vec1.push_back(Position(10, 0));
532 :
533 1 : PositionVector vec2;
534 1 : vec2.push_back(Position(1, 0));
535 1 : vec2.push_back(Position(5, 2));
536 1 : vec2.push_back(Position(10, 0));
537 1 : vec2.push_back(Position(14, 3));
538 :
539 1 : PositionVector vec3;
540 :
541 : std::vector<double> res1;
542 1 : res1.push_back(1);
543 1 : res1.push_back(0);
544 1 : res1.push_back(0);
545 1 : res1.push_back(2);
546 1 : res1.push_back(0);
547 1 : res1.push_back(5);
548 9 : EXPECT_DOUBLEVEC_EQUAL(res1, vec1.distances(vec2));
549 :
550 :
551 1 : std::vector<double> res2;
552 : //invalid: res1.push_back(1);
553 1 : res2.push_back(0);
554 1 : res2.push_back(0);
555 1 : res2.push_back(2);
556 1 : res2.push_back(0);
557 : //invalid: res2.push_back(5);
558 7 : EXPECT_DOUBLEVEC_EQUAL(res2, vec1.distances(vec2, true));
559 :
560 :
561 1 : std::vector<double> res3;
562 1 : res3.push_back(std::numeric_limits<double>::max());
563 1 : res3.push_back(std::numeric_limits<double>::max());
564 5 : EXPECT_DOUBLEVEC_EQUAL(res3, vec1.distances(vec3));
565 1 : }
566 :
567 1 : }
568 :
569 :
570 : /* Test the method 'overlapsWith'*/
571 1 : TEST_F(PositionVectorTest, test_method_overlapsWith) {
572 1 : PositionVector vec1;
573 1 : vec1.push_back(Position(1, 2));
574 1 : vec1.push_back(Position(3, 2));
575 1 : vec1.push_back(Position(3, 6));
576 1 : vec1.push_back(Position(1, 6));
577 :
578 1 : PositionVector vec2;
579 1 : vec2.push_back(Position(10, 17));
580 1 : vec2.push_back(Position(13, 17));
581 1 : vec2.push_back(Position(13, 16));
582 1 : vec2.push_back(Position(10, 16));
583 :
584 1 : PositionVector vec3;
585 1 : vec3.push_back(Position(-1, -7));
586 1 : vec3.push_back(Position(2, -7));
587 1 : vec3.push_back(Position(2, 4));
588 1 : vec3.push_back(Position(-1, 4));
589 :
590 1 : PositionVector vec4;
591 1 : vec4.push_back(Position(0, 3));
592 1 : vec4.push_back(Position(4, 3));
593 1 : vec4.push_back(Position(4, 5));
594 1 : vec4.push_back(Position(0, 5));
595 :
596 1 : PositionVector vec5;
597 1 : vec5.push_back(Position(4, 2));
598 1 : vec5.push_back(Position(5, 2));
599 1 : vec5.push_back(Position(5, 7));
600 1 : vec5.push_back(Position(4, 7));
601 :
602 1 : PositionVector vec6;
603 1 : vec6.push_back(Position(4, 0));
604 1 : vec6.push_back(Position(4, 8));
605 1 : vec6.push_back(Position(-4, 8));
606 :
607 1 : PositionVector empty;
608 :
609 1 : EXPECT_TRUE(vec1.overlapsWith(vec1));
610 1 : EXPECT_FALSE(vec1.overlapsWith(vec2));
611 1 : EXPECT_TRUE(vec1.overlapsWith(vec3));
612 1 : EXPECT_TRUE(vec1.overlapsWith(vec4));
613 1 : EXPECT_FALSE(vec1.overlapsWith(vec5, 0));
614 1 : EXPECT_TRUE(vec1.overlapsWith(vec6)); // overlapsWith implicitly closes the shape of vec6
615 1 : EXPECT_TRUE(vec6.overlapsWith(vec1)); // overlapsWith implicitly closes the shape of vec6
616 : // growth is from centroid and thus different from Boundary behavior
617 1 : EXPECT_FALSE(vec1.overlapsWith(vec5, 1));
618 1 : EXPECT_TRUE(vec1.overlapsWith(vec5, 3));
619 1 : EXPECT_TRUE(vec1.overlapsWith(vec5, 6));
620 1 : EXPECT_FALSE(vec1.overlapsWith(empty));
621 1 : }
622 :
623 :
624 : /* Test the method 'sortAsPolyCWByAngle'*/
625 1 : TEST_F(PositionVectorTest, test_method_sortAsPolyCWByAngle) {
626 1 : PositionVector vectorTrianglePositiveCoordsClockwiseOrdered;
627 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(2, 3));
628 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(3, 0));
629 1 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(1, 1));
630 1 : vectorTrianglePositiveCoords->sortAsPolyCWByAngle();
631 12 : EXPECT_POSITIONVEC_EQUAL((*vectorTrianglePositiveCoords), vectorTrianglePositiveCoordsClockwiseOrdered);
632 :
633 2 : PositionVector vectorTriangleNegativeCoordsClockwiseOrdered;
634 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(1, -1));
635 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -1));
636 1 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -3));
637 1 : vectorTriangleNegativeCoords->sortAsPolyCWByAngle();
638 12 : EXPECT_POSITIONVEC_EQUAL((*vectorTriangleNegativeCoords), vectorTriangleNegativeCoordsClockwiseOrdered);
639 :
640 2 : PositionVector vectorRectangleOriginAlignedCornersClockwiseOrdered;
641 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 3));
642 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 3));
643 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 1));
644 1 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 1));
645 1 : vectorRectangleOriginAlignedCorners->sortAsPolyCWByAngle();
646 15 : EXPECT_POSITIONVEC_EQUAL((*vectorRectangleOriginAlignedCorners), vectorRectangleOriginAlignedCornersClockwiseOrdered);
647 1 : }
648 :
649 :
650 : /* Test the method 'isClockwiseOriented'*/
651 1 : TEST_F(PositionVectorTest, test_method_isClockwiseOriented) {
652 1 : EXPECT_FALSE(vectorTrianglePositiveCoords->isClockwiseOriented());
653 1 : EXPECT_FALSE(vectorTriangleNegativeCoords->isClockwiseOriented());
654 1 : EXPECT_FALSE(vectorRectangleOriginAlignedCorners->isClockwiseOriented());
655 1 : }
656 :
657 :
658 : /* Test the method 'simplified'*/
659 2 : TEST_F(PositionVectorTest, test_method_simplified) {
660 1 : const PositionVector vec1(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2)});
661 1 : const PositionVector result = vec1.simplified();
662 1 : EXPECT_EQ(3, (int)result.size());
663 2 : const PositionVector vec2(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2), Position(1, 2)});
664 2 : const PositionVector result2 = vec2.simplified();
665 1 : EXPECT_EQ(4, (int)result2.size());
666 2 : const PositionVector vec3(std::vector<Position> {Position(1, 2), Position(1, 3), Position(1, 4), Position(1, 5)});
667 2 : const PositionVector result3 = vec3.simplified();
668 : // std::cout << result3 << std::endl;
669 1 : EXPECT_EQ(3, (int)result3.size());
670 :
671 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),
672 : Position(2. * NUMERICAL_EPS, 4), Position(3. * NUMERICAL_EPS / 2., 3), Position(NUMERICAL_EPS, 2), Position(NUMERICAL_EPS / 2., 1)
673 2 : });
674 2 : const PositionVector result4 = vec4.simplified();
675 1 : EXPECT_EQ(3, (int)result4.size());
676 1 : }
677 :
678 :
679 : /* Test the method 'simplified2'*/
680 2 : TEST_F(PositionVectorTest, test_method_simplified2) {
681 1 : const PositionVector vec1(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2)});
682 1 : const PositionVector result = vec1.simplified2(true);
683 1 : EXPECT_EQ(2, (int)result.size());
684 2 : const PositionVector vec2(std::vector<Position> {Position(1, 2), Position(1, 2), Position(1, 2), Position(1, 2)});
685 2 : const PositionVector result2 = vec2.simplified2(true);
686 1 : EXPECT_EQ(2, (int)result2.size());
687 2 : const PositionVector vec3(std::vector<Position> {Position(1, 2), Position(1, 3), Position(1, 4), Position(1, 5)});
688 2 : const PositionVector result3 = vec3.simplified2(true);
689 : // std::cout << result3 << std::endl;
690 1 : EXPECT_EQ(2, (int)result3.size());
691 1 : EXPECT_DOUBLE_EQ(2., result3.front().y());
692 1 : EXPECT_DOUBLE_EQ(5., result3.back().y());
693 :
694 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),
695 : Position(2. * NUMERICAL_EPS, 4), Position(3. * NUMERICAL_EPS / 2., 3), Position(NUMERICAL_EPS, 2), Position(NUMERICAL_EPS / 2., 1)
696 2 : });
697 2 : const PositionVector result4 = vec4.simplified2(true);
698 1 : EXPECT_EQ(3, (int)result4.size());
699 1 : EXPECT_DOUBLE_EQ(0., result4.front().y());
700 1 : EXPECT_DOUBLE_EQ(8., result4[1].y());
701 1 : EXPECT_DOUBLE_EQ(4., result4.back().y());
702 1 : }
|