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 34 : class PositionVectorTest : public testing::Test {
58 : protected :
59 : PositionVector* vectorPolygon;
60 : PositionVector* vectorLine;
61 : PositionVector* vectorTrianglePositiveCoords;
62 : PositionVector* vectorTriangleNegativeCoords;
63 : PositionVector* vectorRectangleOriginAlignedCorners;
64 :
65 34 : virtual void SetUp() {
66 34 : vectorPolygon = new PositionVector();
67 34 : vectorPolygon->push_back(Position(0, 0));
68 34 : vectorPolygon->push_back(Position(0, 2));
69 34 : vectorPolygon->push_back(Position(2, 4));
70 34 : vectorPolygon->push_back(Position(4, 2));
71 34 : vectorPolygon->push_back(Position(4, 0));
72 :
73 34 : vectorLine = new PositionVector();
74 34 : vectorLine->push_back(Position(0, 0));
75 34 : vectorLine->push_back(Position(2, 2));
76 :
77 34 : vectorTrianglePositiveCoords = new PositionVector();
78 34 : vectorTrianglePositiveCoords->push_back(Position(1, 1));
79 34 : vectorTrianglePositiveCoords->push_back(Position(3, 0));
80 34 : vectorTrianglePositiveCoords->push_back(Position(2, 3));
81 :
82 34 : vectorTriangleNegativeCoords = new PositionVector();
83 34 : vectorTriangleNegativeCoords->push_back(Position(2, -1));
84 34 : vectorTriangleNegativeCoords->push_back(Position(1, -1));
85 34 : vectorTriangleNegativeCoords->push_back(Position(2, -3));
86 :
87 34 : vectorRectangleOriginAlignedCorners = new PositionVector();
88 34 : vectorRectangleOriginAlignedCorners->push_back(Position(1, 1));
89 34 : vectorRectangleOriginAlignedCorners->push_back(Position(3, 1));
90 34 : vectorRectangleOriginAlignedCorners->push_back(Position(3, 3));
91 34 : vectorRectangleOriginAlignedCorners->push_back(Position(1, 3));
92 34 : }
93 :
94 34 : virtual void TearDown() {
95 34 : delete vectorPolygon;
96 34 : delete vectorLine;
97 34 : delete vectorTrianglePositiveCoords;
98 34 : delete vectorTriangleNegativeCoords;
99 34 : delete vectorRectangleOriginAlignedCorners;
100 34 : }
101 :
102 : };
103 :
104 : /* Test the method 'around'*/
105 2 : TEST_F(PositionVectorTest, test_method_around) {
106 :
107 2 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1)));
108 2 : EXPECT_TRUE(vectorPolygon->around(Position(1, 2)));
109 2 : EXPECT_FALSE(vectorPolygon->around(Position(4, 4)));
110 2 : EXPECT_FALSE(vectorPolygon->around(Position(0, 0)));
111 :
112 2 : EXPECT_FALSE(vectorLine->around(Position(1, 1)));
113 2 : EXPECT_FALSE(vectorLine->around(Position(0, 2)));
114 :
115 : // with positive offset
116 2 : EXPECT_TRUE(vectorPolygon->around(Position(4, 2), 1));
117 2 : EXPECT_FALSE(vectorPolygon->around(Position(5, 2), 1));
118 : // what was true remains true
119 2 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1), POSITION_EPS));
120 2 : EXPECT_TRUE(vectorPolygon->around(Position(1, 2), POSITION_EPS));
121 :
122 : // with negative offset
123 2 : EXPECT_FALSE(vectorPolygon->around(Position(4, 2), -POSITION_EPS));
124 2 : EXPECT_TRUE(vectorPolygon->around(Position(1, 1), -1));
125 2 : EXPECT_FALSE(vectorPolygon->around(Position(0.5, 0.5), -1));
126 2 : }
127 :
128 : /* Test the method 'area'*/
129 2 : TEST_F(PositionVectorTest, test_method_area) {
130 2 : PositionVector square;
131 2 : square.push_back(Position(0, 0));
132 2 : square.push_back(Position(1, 0));
133 2 : square.push_back(Position(1, 1));
134 2 : square.push_back(Position(0, 1)); // open
135 2 : EXPECT_DOUBLE_EQ(square.area(), 1);
136 2 : square.push_back(Position(0, 0)); // closed
137 2 : EXPECT_DOUBLE_EQ(square.area(), 1);
138 2 : }
139 :
140 : /* Test the method 'scaleRelative'.*/
141 2 : TEST_F(PositionVectorTest, test_method_scaleRelative) {
142 2 : PositionVector square;
143 2 : square.push_back(Position(0, 0));
144 2 : square.push_back(Position(1, 0));
145 2 : square.push_back(Position(1, 1));
146 2 : square.push_back(Position(0, 1));
147 2 : square.push_back(Position(0, 0));
148 2 : EXPECT_DOUBLE_EQ(square.area(), 1);
149 2 : square.scaleRelative(3);
150 2 : EXPECT_DOUBLE_EQ(square.area(), 9);
151 :
152 4 : PositionVector expected;
153 2 : expected.push_back(Position(-1, -1));
154 2 : expected.push_back(Position(2, -1));
155 2 : expected.push_back(Position(2, 2));
156 2 : expected.push_back(Position(-1, 2));
157 2 : expected.push_back(Position(-1, -1));
158 :
159 4 : EXPECT_EQ(expected.getCentroid(), square.getCentroid());
160 12 : for (int i = 0; i < (int)square.size(); i++) {
161 10 : EXPECT_DOUBLE_EQ(expected[i].x(), square[i].x());
162 10 : EXPECT_DOUBLE_EQ(expected[i].y(), square[i].y());
163 : }
164 2 : }
165 :
166 : /* Test the method 'getCentroid'.*/
167 2 : TEST_F(PositionVectorTest, test_method_getCentroid) {
168 2 : PositionVector square;
169 2 : square.push_back(Position(0, 0));
170 2 : square.push_back(Position(1, 0));
171 2 : square.push_back(Position(1, 1));
172 2 : square.push_back(Position(0, 1));
173 4 : EXPECT_EQ(Position(0.5, 0.5), square.getCentroid());
174 :
175 2 : Position pos2 = vectorLine->getCentroid();
176 2 : EXPECT_DOUBLE_EQ(1, pos2.x());
177 2 : EXPECT_DOUBLE_EQ(1, pos2.y());
178 2 : }
179 :
180 : /* Test the method 'getPolygonCenter'.*/
181 2 : TEST_F(PositionVectorTest, test_method_getPolygonCenter) {
182 2 : Position pos = vectorPolygon->getPolygonCenter();
183 2 : EXPECT_DOUBLE_EQ(2, pos.x());
184 2 : EXPECT_DOUBLE_EQ(1.6, pos.y());
185 2 : Position pos2 = vectorLine->getPolygonCenter();
186 2 : }
187 :
188 :
189 : /* Test the method 'getBoxBoundary'*/
190 2 : TEST_F(PositionVectorTest, test_method_getBoxBoundary) {
191 2 : Boundary bound = vectorPolygon->getBoxBoundary();
192 2 : EXPECT_DOUBLE_EQ(bound.xmax(), 4);
193 2 : EXPECT_DOUBLE_EQ(bound.xmin(), 0);
194 2 : EXPECT_DOUBLE_EQ(bound.ymax(), 4);
195 2 : EXPECT_DOUBLE_EQ(bound.ymin(), 0);
196 2 : }
197 :
198 : /* Test the method 'splitAt'*/
199 2 : TEST_F(PositionVectorTest, test_method_splitAt) {
200 2 : PositionVector vec;
201 2 : vec.push_back(Position(0, 0));
202 2 : vec.push_back(Position(2, 0));
203 2 : vec.push_back(Position(5, 0));
204 : double smallDiff = POSITION_EPS / 2;
205 2 : std::pair<PositionVector, PositionVector> result;
206 : // split in first segment
207 4 : result = vec.splitAt(1);
208 2 : EXPECT_EQ(2, (int)result.first.size());
209 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
210 2 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
211 2 : EXPECT_EQ(3, (int)result.second.size());
212 2 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
213 2 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
214 2 : EXPECT_DOUBLE_EQ(5., result.second[2].x());
215 : // split in second segment
216 4 : result = vec.splitAt(4);
217 2 : EXPECT_EQ(3, (int)result.first.size());
218 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
219 2 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
220 2 : EXPECT_DOUBLE_EQ(4., result.first[2].x());
221 2 : EXPECT_EQ(2, (int)result.second.size());
222 2 : EXPECT_DOUBLE_EQ(4., result.second[0].x());
223 2 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
224 : // split close before inner point
225 4 : result = vec.splitAt(2 - smallDiff);
226 2 : EXPECT_EQ(2, (int)result.first.size());
227 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
228 2 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
229 2 : EXPECT_EQ(2, (int)result.second.size());
230 2 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
231 2 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
232 : // split close after inner point
233 4 : result = vec.splitAt(2 + smallDiff);
234 2 : EXPECT_EQ(2, (int)result.first.size());
235 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
236 2 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
237 2 : EXPECT_EQ(2, (int)result.second.size());
238 2 : EXPECT_DOUBLE_EQ(2., result.second[0].x());
239 2 : EXPECT_DOUBLE_EQ(5., result.second[1].x());
240 :
241 : // catch a bug
242 2 : vec.push_back(Position(6, 0));
243 2 : vec.push_back(Position(8, 0));
244 : // split at inner point
245 4 : result = vec.splitAt(5);
246 2 : EXPECT_EQ(3, (int)result.first.size());
247 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
248 2 : EXPECT_DOUBLE_EQ(2., result.first[1].x());
249 2 : EXPECT_DOUBLE_EQ(5., result.first[2].x());
250 2 : EXPECT_EQ(3, (int)result.second.size());
251 2 : EXPECT_DOUBLE_EQ(5., result.second[0].x());
252 2 : EXPECT_DOUBLE_EQ(6., result.second[1].x());
253 2 : EXPECT_DOUBLE_EQ(8., result.second[2].x());
254 :
255 : // split short vector
256 2 : PositionVector vec2;
257 2 : vec2.push_back(Position(0, 0));
258 2 : vec2.push_back(Position(2, 0));
259 4 : result = vec2.splitAt(1);
260 2 : EXPECT_EQ(2, (int)result.first.size());
261 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
262 2 : EXPECT_DOUBLE_EQ(1., result.first[1].x());
263 2 : EXPECT_EQ(2, (int)result.second.size());
264 2 : EXPECT_DOUBLE_EQ(1., result.second[0].x());
265 2 : EXPECT_DOUBLE_EQ(2., result.second[1].x());
266 :
267 : // split very short vector
268 4 : PositionVector vec3;
269 2 : vec3.push_back(Position(0, 0));
270 2 : vec3.push_back(Position(POSITION_EPS, 0));
271 : // supress expected warning
272 2 : MsgHandler::getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
273 2 : result = vec3.splitAt(smallDiff);
274 4 : MsgHandler::getWarningInstance()->addRetriever(&OutputDevice::getDevice("stderr"));
275 :
276 2 : EXPECT_EQ(2, (int)result.first.size());
277 2 : EXPECT_DOUBLE_EQ(0., result.first[0].x());
278 2 : EXPECT_DOUBLE_EQ(smallDiff, result.first[1].x());
279 2 : EXPECT_EQ(2, (int)result.second.size());
280 2 : EXPECT_DOUBLE_EQ(smallDiff, result.second[0].x());
281 2 : EXPECT_DOUBLE_EQ(POSITION_EPS, result.second[1].x());
282 2 : }
283 :
284 :
285 : /* Test the method 'intersectsAtLengths2D'*/
286 2 : TEST_F(PositionVectorTest, test_method_intersectsAtLengths2D) {
287 2 : PositionVector vec1;
288 2 : vec1.push_back(Position(0, 0, 42));
289 2 : vec1.push_back(Position(100, 0, 0));
290 :
291 2 : PositionVector vec2;
292 2 : vec2.push_back(Position(0, 0, 0));
293 2 : vec2.push_back(Position(3, 1, 0));
294 4 : EXPECT_DOUBLE_EQ(0, vec1.intersectsAtLengths2D(vec2)[0]);
295 2 : }
296 :
297 :
298 : /* Test the method 'nearest_offset_to_point2D'*/
299 2 : TEST_F(PositionVectorTest, test_method_nearest_offset_to_point2D) {
300 2 : PositionVector vec1;
301 2 : vec1.push_back(Position(0, 1, 0));
302 2 : vec1.push_back(Position(0, 0, 0));
303 2 : vec1.push_back(Position(1, 0, 0));
304 :
305 2 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), false));
306 2 : EXPECT_DOUBLE_EQ(1, vec1.nearest_offset_to_point2D(Position(-1, -1), true));
307 2 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(2, 1), false));
308 2 : EXPECT_DOUBLE_EQ(0, vec1.nearest_offset_to_point2D(Position(2, 1), true));
309 2 : EXPECT_DOUBLE_EQ(2, vec1.nearest_offset_to_point2D(Position(3, 2), false));
310 2 : EXPECT_DOUBLE_EQ(-1, vec1.nearest_offset_to_point2D(Position(3, 2), true));
311 2 : }
312 :
313 :
314 2 : TEST_F(PositionVectorTest, test_method_extrapolate2D) {
315 2 : PositionVector vec1;
316 2 : vec1.push_back(Position(0, 1, 0));
317 2 : vec1.push_back(Position(0, 0, 0));
318 2 : vec1.push_back(Position(1, 0, 0));
319 2 : vec1.extrapolate2D(1);
320 4 : EXPECT_EQ(Position(0, 2, 0), vec1[0]);
321 4 : EXPECT_EQ(Position(0, 0, 0), vec1[1]);
322 4 : EXPECT_EQ(Position(2, 0, 0), vec1[2]);
323 :
324 4 : PositionVector vec2;
325 2 : vec2.push_back(Position(0, 1, 0));
326 2 : vec2.push_back(Position(0, 0, 1));
327 0 : vec2.push_back(Position(1, 0, 0));
328 2 : 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 4 : PositionVector vec3;
334 2 : vec3.push_back(Position(-.5, 1));
335 2 : vec3.push_back(Position(-.5, -.5));
336 2 : vec3.push_back(Position(1, -.5));
337 2 : vec3.extrapolate2D(.5);
338 4 : EXPECT_EQ(Position(-.5, 1.5), vec3[0]);
339 4 : EXPECT_EQ(Position(-.5, -.5), vec3[1]);
340 4 : EXPECT_EQ(Position(1.5, -.5), vec3[2]);
341 :
342 2 : }
343 :
344 :
345 : /* Test the method 'move2side'*/
346 2 : TEST_F(PositionVectorTest, test_method_move2side) {
347 2 : PositionVector vec1;
348 2 : vec1.push_back(Position(0, 1, 0));
349 2 : vec1.push_back(Position(0, 0, 0));
350 2 : vec1.push_back(Position(1, 0, 0));
351 2 : vec1.move2side(.5);
352 4 : EXPECT_EQ(Position(-.5, 1), vec1[0]);
353 4 : EXPECT_EQ(Position(-.5, -.5), vec1[1]);
354 4 : EXPECT_EQ(Position(1, -.5), vec1[2]);
355 2 : vec1.move2side(-1);
356 4 : EXPECT_EQ(Position(.5, 1), vec1[0]);
357 4 : EXPECT_EQ(Position(.5, .5), vec1[1]);
358 4 : EXPECT_EQ(Position(1, .5), vec1[2]);
359 :
360 : // parallel case
361 4 : PositionVector vec2;
362 2 : vec2.push_back(Position(0, 0, 0));
363 2 : vec2.push_back(Position(1, 0, 0));
364 2 : vec2.push_back(Position(3, 0, 0));
365 2 : vec2.move2side(.5);
366 4 : EXPECT_EQ(Position(0, -.5), vec2[0]);
367 4 : EXPECT_EQ(Position(1, -.5), vec2[1]);
368 4 : EXPECT_EQ(Position(3, -.5), vec2[2]);
369 2 : vec2.move2side(-1);
370 4 : EXPECT_EQ(Position(0, .5), vec2[0]);
371 4 : EXPECT_EQ(Position(1, .5), vec2[1]);
372 4 : EXPECT_EQ(Position(3, .5), vec2[2]);
373 :
374 : // counterparallel case
375 : {
376 2 : PositionVector vec3;
377 2 : vec3.push_back(Position(0, 0, 0));
378 2 : vec3.push_back(Position(3, 0, 0));
379 2 : vec3.push_back(Position(1, 0, 0));
380 2 : vec3.move2side(.5);
381 : // clipping removal eliminates the middle point
382 4 : EXPECT_EQ(Position(0, -.5), vec3[0]);
383 4 : EXPECT_EQ(Position(1, -.5), vec3[1]);
384 2 : }
385 : // bad input: subsequent identical points
386 : {
387 2 : PositionVector vec4;
388 2 : vec4.push_back(Position(0, 0, 0));
389 2 : vec4.push_back(Position(0, 0, 0));
390 2 : vec4.push_back(Position(1, 0, 0));
391 2 : vec4.move2side(-2);
392 2 : EXPECT_EQ(2, (int)vec4.size());
393 4 : EXPECT_EQ(Position(0, 2), vec4[0]);
394 4 : EXPECT_EQ(Position(1, 2), vec4[1]);
395 2 : }
396 2 : }
397 :
398 : /* Test the method 'transformToVectorCoordinates'*/
399 2 : TEST_F(PositionVectorTest, test_method_transformToVectorCoordinates) {
400 : {
401 2 : PositionVector vec1;
402 2 : vec1.push_back(Position(1, 0));
403 2 : vec1.push_back(Position(10, 0));
404 2 : vec1.push_back(Position(10, 5));
405 2 : 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 4 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
417 4 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(left));
418 4 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(right));
419 4 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(left2));
420 4 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(right2));
421 4 : EXPECT_EQ(Position(9, 5), vec1.transformToVectorCoordinates(cornerRight));
422 4 : EXPECT_EQ(Position(14, -5), vec1.transformToVectorCoordinates(cornerLeft));
423 :
424 4 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
425 4 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
426 4 : EXPECT_EQ(Position(-1, 1), vec1.transformToVectorCoordinates(before, true));
427 4 : EXPECT_EQ(Position(28, -4), vec1.transformToVectorCoordinates(beyond, true));
428 2 : }
429 :
430 : {
431 2 : PositionVector vec1; // the same tests as before, mirrored on x-axis
432 2 : vec1.push_back(Position(1, 0));
433 2 : vec1.push_back(Position(10, 0));
434 2 : vec1.push_back(Position(10, -5));
435 2 : 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 4 : EXPECT_EQ(Position(3, 0), vec1.transformToVectorCoordinates(on));
447 4 : EXPECT_EQ(Position(3, 1), vec1.transformToVectorCoordinates(left));
448 4 : EXPECT_EQ(Position(3, -1), vec1.transformToVectorCoordinates(right));
449 4 : EXPECT_EQ(Position(3, 2), vec1.transformToVectorCoordinates(left2));
450 4 : EXPECT_EQ(Position(3, -2), vec1.transformToVectorCoordinates(right2));
451 4 : EXPECT_EQ(Position(9, -5), vec1.transformToVectorCoordinates(cornerRight));
452 4 : EXPECT_EQ(Position(14, 5), vec1.transformToVectorCoordinates(cornerLeft));
453 :
454 4 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(before));
455 4 : EXPECT_EQ(Position::INVALID, vec1.transformToVectorCoordinates(beyond));
456 4 : EXPECT_EQ(Position(-1, -1), vec1.transformToVectorCoordinates(before, true));
457 4 : EXPECT_EQ(Position(28, 4), vec1.transformToVectorCoordinates(beyond, true));
458 2 : }
459 2 : }
460 :
461 :
462 : /* Test the method 'distance'*/
463 2 : TEST_F(PositionVectorTest, test_method_distance) {
464 : {
465 2 : PositionVector vec1;
466 2 : vec1.push_back(Position(1, 0));
467 2 : vec1.push_back(Position(10, 0));
468 2 : vec1.push_back(Position(10, 5));
469 2 : 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 2 : EXPECT_EQ(0, vec1.distance2D(on));
481 2 : EXPECT_EQ(1, vec1.distance2D(left));
482 2 : EXPECT_EQ(1, vec1.distance2D(right));
483 2 : EXPECT_EQ(2, vec1.distance2D(left2));
484 2 : EXPECT_EQ(2, vec1.distance2D(right2));
485 2 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
486 2 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
487 :
488 2 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
489 2 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
490 2 : EXPECT_EQ(5, vec1.distance2D(before));
491 2 : EXPECT_EQ(5, vec1.distance2D(beyond));
492 2 : }
493 :
494 : {
495 2 : PositionVector vec1; // the same tests as before, mirrored on x-axis
496 2 : vec1.push_back(Position(1, 0));
497 2 : vec1.push_back(Position(10, 0));
498 2 : vec1.push_back(Position(10, -5));
499 2 : 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 2 : EXPECT_EQ(0, vec1.distance2D(on));
511 2 : EXPECT_EQ(1, vec1.distance2D(left));
512 2 : EXPECT_EQ(1, vec1.distance2D(right));
513 2 : EXPECT_EQ(2, vec1.distance2D(left2));
514 2 : EXPECT_EQ(2, vec1.distance2D(right2));
515 2 : EXPECT_EQ(5, vec1.distance2D(cornerRight));
516 2 : EXPECT_EQ(5, vec1.distance2D(cornerLeft));
517 :
518 2 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(before, true));
519 2 : EXPECT_EQ(GeomHelper::INVALID_OFFSET, vec1.distance2D(beyond, true));
520 2 : EXPECT_EQ(5, vec1.distance2D(before));
521 2 : EXPECT_EQ(5, vec1.distance2D(beyond));
522 2 : }
523 2 : }
524 :
525 :
526 : /* Test the method 'distance'*/
527 2 : TEST_F(PositionVectorTest, test_method_distances) {
528 : {
529 2 : PositionVector vec1;
530 2 : vec1.push_back(Position(0, 0));
531 2 : vec1.push_back(Position(10, 0));
532 :
533 2 : PositionVector vec2;
534 2 : vec2.push_back(Position(1, 0));
535 2 : vec2.push_back(Position(5, 2));
536 2 : vec2.push_back(Position(10, 0));
537 2 : vec2.push_back(Position(14, 3));
538 :
539 2 : PositionVector vec3;
540 :
541 : std::vector<double> res1;
542 2 : res1.push_back(1);
543 2 : res1.push_back(0);
544 2 : res1.push_back(0);
545 2 : res1.push_back(2);
546 2 : res1.push_back(0);
547 2 : res1.push_back(5);
548 34 : EXPECT_DOUBLEVEC_EQUAL(res1, vec1.distances(vec2));
549 :
550 :
551 : std::vector<double> res2;
552 : //invalid: res1.push_back(1);
553 2 : res2.push_back(0);
554 2 : res2.push_back(0);
555 2 : res2.push_back(2);
556 2 : res2.push_back(0);
557 : //invalid: res2.push_back(5);
558 26 : EXPECT_DOUBLEVEC_EQUAL(res2, vec1.distances(vec2, true));
559 :
560 :
561 : std::vector<double> res3;
562 2 : res3.push_back(std::numeric_limits<double>::max());
563 2 : res3.push_back(std::numeric_limits<double>::max());
564 18 : EXPECT_DOUBLEVEC_EQUAL(res3, vec1.distances(vec3));
565 2 : }
566 :
567 2 : }
568 :
569 :
570 : /* Test the method 'overlapsWith'*/
571 2 : TEST_F(PositionVectorTest, test_method_overlapsWith) {
572 2 : PositionVector vec1;
573 2 : vec1.push_back(Position(1, 2));
574 2 : vec1.push_back(Position(3, 2));
575 2 : vec1.push_back(Position(3, 6));
576 2 : vec1.push_back(Position(1, 6));
577 :
578 2 : PositionVector vec2;
579 2 : vec2.push_back(Position(10, 17));
580 2 : vec2.push_back(Position(13, 17));
581 2 : vec2.push_back(Position(13, 16));
582 2 : vec2.push_back(Position(10, 16));
583 :
584 2 : PositionVector vec3;
585 2 : vec3.push_back(Position(-1, -7));
586 2 : vec3.push_back(Position(2, -7));
587 2 : vec3.push_back(Position(2, 4));
588 2 : vec3.push_back(Position(-1, 4));
589 :
590 2 : PositionVector vec4;
591 2 : vec4.push_back(Position(0, 3));
592 2 : vec4.push_back(Position(4, 3));
593 2 : vec4.push_back(Position(4, 5));
594 2 : vec4.push_back(Position(0, 5));
595 :
596 2 : PositionVector vec5;
597 2 : vec5.push_back(Position(4, 2));
598 2 : vec5.push_back(Position(5, 2));
599 2 : vec5.push_back(Position(5, 7));
600 2 : vec5.push_back(Position(4, 7));
601 :
602 2 : PositionVector vec6;
603 2 : vec6.push_back(Position(4, 0));
604 2 : vec6.push_back(Position(4, 8));
605 2 : vec6.push_back(Position(-4, 8));
606 :
607 2 : PositionVector empty;
608 :
609 2 : EXPECT_TRUE(vec1.overlapsWith(vec1));
610 2 : EXPECT_FALSE(vec1.overlapsWith(vec2));
611 2 : EXPECT_TRUE(vec1.overlapsWith(vec3));
612 2 : EXPECT_TRUE(vec1.overlapsWith(vec4));
613 2 : EXPECT_FALSE(vec1.overlapsWith(vec5, 0));
614 2 : EXPECT_TRUE(vec1.overlapsWith(vec6)); // overlapsWith implicitly closes the shape of vec6
615 2 : EXPECT_TRUE(vec6.overlapsWith(vec1)); // overlapsWith implicitly closes the shape of vec6
616 : // growth is from centroid and thus different from Boundary behavior
617 2 : EXPECT_FALSE(vec1.overlapsWith(vec5, 1));
618 2 : EXPECT_TRUE(vec1.overlapsWith(vec5, 3));
619 2 : EXPECT_TRUE(vec1.overlapsWith(vec5, 6));
620 2 : EXPECT_FALSE(vec1.overlapsWith(empty));
621 2 : }
622 :
623 :
624 : /* Test the method 'sortAsPolyCWByAngle'*/
625 2 : TEST_F(PositionVectorTest, test_method_sortAsPolyCWByAngle) {
626 2 : PositionVector vectorTrianglePositiveCoordsClockwiseOrdered;
627 2 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(2, 3));
628 2 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(3, 0));
629 2 : vectorTrianglePositiveCoordsClockwiseOrdered.push_back(Position(1, 1));
630 2 : vectorTrianglePositiveCoords->sortAsPolyCWByAngle();
631 24 : EXPECT_POSITIONVEC_EQUAL((*vectorTrianglePositiveCoords), vectorTrianglePositiveCoordsClockwiseOrdered);
632 :
633 4 : PositionVector vectorTriangleNegativeCoordsClockwiseOrdered;
634 2 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(1, -1));
635 2 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -1));
636 2 : vectorTriangleNegativeCoordsClockwiseOrdered.push_back(Position(2, -3));
637 2 : vectorTriangleNegativeCoords->sortAsPolyCWByAngle();
638 24 : EXPECT_POSITIONVEC_EQUAL((*vectorTriangleNegativeCoords), vectorTriangleNegativeCoordsClockwiseOrdered);
639 :
640 4 : PositionVector vectorRectangleOriginAlignedCornersClockwiseOrdered;
641 2 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 3));
642 2 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 3));
643 2 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(3, 1));
644 2 : vectorRectangleOriginAlignedCornersClockwiseOrdered.push_back(Position(1, 1));
645 2 : vectorRectangleOriginAlignedCorners->sortAsPolyCWByAngle();
646 30 : EXPECT_POSITIONVEC_EQUAL((*vectorRectangleOriginAlignedCorners), vectorRectangleOriginAlignedCornersClockwiseOrdered);
647 2 : }
648 :
649 :
650 : /* Test the method 'isClockwiseOriented'*/
651 2 : TEST_F(PositionVectorTest, test_method_isClockwiseOriented) {
652 2 : EXPECT_FALSE(vectorTrianglePositiveCoords->isClockwiseOriented());
653 2 : EXPECT_FALSE(vectorTriangleNegativeCoords->isClockwiseOriented());
654 2 : EXPECT_FALSE(vectorRectangleOriginAlignedCorners->isClockwiseOriented());
655 2 : }
|