PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
cu_ptarray.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
7 * Copyright (C) 2008 Paul Ramsey
8 *
9 * This is free software; you can redistribute and/or modify it under
10 * the terms of the GNU General Public Licence. See the COPYING file.
11 *
12 **********************************************************************/
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include "CUnit/Basic.h"
18#include "CUnit/CUnit.h"
19
20#include "liblwgeom_internal.h"
21#include "cu_tester.h"
22
23
24static LWGEOM* lwgeom_from_text(const char *str)
25{
28 return NULL;
29 return r.geom;
30}
31
32static char* lwgeom_to_text(const LWGEOM *geom)
33{
34 return lwgeom_to_wkt(geom, WKT_ISO, 8, NULL);
35}
36
38{
39 LWLINE *line;
40 char *wkt;
41 POINT4D p;
42
43 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1)"));
44 p.x = 1;
45 p.y = 1;
48 ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
49 lwfree(wkt);
50
53 ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
54 lwfree(wkt);
55
56 lwline_free(line);
57}
58
60{
61 LWLINE *line;
62 char *wkt;
63 POINT4D p;
64
65 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
66 p.x = 1;
67 p.y = 1;
68 ptarray_insert_point(line->points, &p, 0);
70 ASSERT_STRING_EQUAL(wkt,"LINESTRING(1 1)");
71 lwfree(wkt);
72
73 p.x = 2;
74 p.y = 20;
75 ptarray_insert_point(line->points, &p, 0);
77 ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,1 1)");
78 lwfree(wkt);
79
80 p.x = 3;
81 p.y = 30;
82 ptarray_insert_point(line->points, &p, 1);
84 ASSERT_STRING_EQUAL(wkt,"LINESTRING(2 20,3 30,1 1)");
85 lwfree(wkt);
86
87 p.x = 4;
88 p.y = 40;
89 ptarray_insert_point(line->points, &p, 0);
91 ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1)");
92 lwfree(wkt);
93
94 p.x = 5;
95 p.y = 50;
96 ptarray_insert_point(line->points, &p, 4);
98 ASSERT_STRING_EQUAL(wkt,"LINESTRING(4 40,2 20,3 30,1 1,5 50)");
99 lwfree(wkt);
100
101 lwline_free(line);
102}
103
105{
106 LWLINE *line1, *line2;
107 int ret;
108 char *wkt;
109
110 /* Empty first line */
111 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
112 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,5 5)"));
113 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
114 CU_ASSERT(ret == LW_SUCCESS);
115 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
116 ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,5 5)");
117 lwfree(wkt);
118 lwline_free(line2);
119 lwline_free(line1);
120
121 /* Empty second line */
122 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 5 5, 6 3)"));
123 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
124 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
125 CU_ASSERT(ret == LW_SUCCESS);
126 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
127 ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,5 5,6 3)");
128 lwfree(wkt);
129 lwline_free(line2);
130 lwline_free(line1);
131
132 /* Both lines empty */
133 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
134 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY"));
135 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
136 CU_ASSERT(ret == LW_SUCCESS);
137 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
138 ASSERT_STRING_EQUAL(wkt, "LINESTRING EMPTY");
139 lwfree(wkt);
140 lwline_free(line2);
141 lwline_free(line1);
142
143 /* Sane sewing */
144 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
145 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5 7,12 43, 42 15)"));
146 ret = ptarray_append_ptarray(line1->points, line2->points, 0);
147 CU_ASSERT(ret == LW_SUCCESS);
148 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
149 ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,12 43,42 15)");
150 lwfree(wkt);
151 lwline_free(line2);
152 lwline_free(line1);
153
154 /* Untolerated sewing */
155 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
156 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)"));
157 ret = ptarray_append_ptarray(line1->points, line2->points, 0);
158 CU_ASSERT(ret == LW_FAILURE);
159 lwline_free(line2);
160 lwline_free(line1);
161
162 /* Tolerated sewing */
163 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)"));
164 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)"));
165 ret = ptarray_append_ptarray(line1->points, line2->points, .7);
166 CU_ASSERT(ret == LW_SUCCESS);
167 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
168 ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,5.5 7,12 43,42 15)");
169 lwfree(wkt);
170 lwline_free(line2);
171 lwline_free(line1);
172
173 /* Check user input trust (creates non-simple line */
174 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)"));
175 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)"));
176 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
177 CU_ASSERT(ret == LW_SUCCESS);
178 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
179 ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,0 0,0 10)");
180 lwfree(wkt);
181 lwline_free(line2);
182 lwline_free(line1);
183
184 /* Mixed dimensionality is not allowed */
185 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10 0, 10 0 0)"));
186 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
187 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
188 CU_ASSERT(ret == LW_FAILURE);
189 lwline_free(line2);
190 lwline_free(line1);
191
192 /* Appending a read-only pointarray is allowed */
193 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)"));
194 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
195 FLAGS_SET_READONLY(line2->points->flags, 1);
196 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
197 CU_ASSERT(ret == LW_SUCCESS);
198 wkt = lwgeom_to_text(lwline_as_lwgeom(line1));
199 ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 10,10 0,11 0)");
200 lwfree(wkt);
201 FLAGS_SET_READONLY(line2->points->flags, 0); /* for lwline_free */
202 lwline_free(line2);
203 lwline_free(line1);
204
205 /* Appending to a read-only pointarray is forbidden */
206 line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 10, 10 0)"));
207 line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 0,11 0)"));
208 FLAGS_SET_READONLY(line1->points->flags, 1);
209 ret = ptarray_append_ptarray(line1->points, line2->points, -1);
210 CU_ASSERT(ret == LW_FAILURE);
211 lwline_free(line2);
212 FLAGS_SET_READONLY(line1->points->flags, 0); /* for lwline_free */
213 lwline_free(line1);
214
215}
216
218{
219 LWLINE *line;
220 double loc, dist;
221 POINT4D p, l;
222
223 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4)"));
224
225 p = getPoint4d(line->points, 0);
226 loc = ptarray_locate_point(line->points, &p, &dist, &l);
227 CU_ASSERT_EQUAL(loc, 0);
228 CU_ASSERT_EQUAL(dist, 0.0);
229
230 p = getPoint4d(line->points, 1);
231 loc = ptarray_locate_point(line->points, &p, &dist, &l);
232 CU_ASSERT_EQUAL(loc, 1);
233 CU_ASSERT_EQUAL(dist, 0.0);
234
235 p.x = 21; p.y = 4;
236 loc = ptarray_locate_point(line->points, &p, &dist, NULL);
237 CU_ASSERT_EQUAL(loc, 1);
238 CU_ASSERT_EQUAL(dist, 1.0);
239
240 p.x = 0; p.y = 2;
241 loc = ptarray_locate_point(line->points, &p, &dist, &l);
242 CU_ASSERT_EQUAL(loc, 0);
243 CU_ASSERT_EQUAL(dist, 1.0);
244
245 lwline_free(line);
246 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,20 0,40 0)"));
247
248 p.x = 20; p.y = 0;
249 loc = ptarray_locate_point(line->points, &p, &dist, &l);
250 CU_ASSERT_EQUAL(loc, 0.5);
251 CU_ASSERT_EQUAL(dist, 0.0);
252
253 lwline_free(line);
254 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-40 0,0 0,20 0,40 0)"));
255
256 p.x = 20; p.y = 0;
257 loc = ptarray_locate_point(line->points, &p, &dist, &l);
258 CU_ASSERT_EQUAL(loc, 0.75);
259 CU_ASSERT_EQUAL(dist, 0.0);
260
261 lwline_free(line);
262 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING M (0 0 0, 10 0 20)"));
263
264 p.x = 5; p.y = 0;
265 loc = ptarray_locate_point(line->points, &p, &dist, &l);
266 CU_ASSERT_EQUAL(loc, 0.5);
267 CU_ASSERT_EQUAL(dist, 0.0);
268 CU_ASSERT_EQUAL(l.m, 10.0);
269
270 lwline_free(line);
271
272}
273
274static void test_ptarray_isccw(void)
275{
276 LWLINE *line;
277 LWPOLY* poly;
278 int ccw;
279
280 /* clockwise rectangle */
281 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,10 10,10 0, 0 0)"));
282 ccw = ptarray_isccw(line->points);
283 CU_ASSERT_EQUAL(ccw, 0);
284 lwline_free(line);
285
286 /* clockwise triangle */
287 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 4,20 3, 0 3)"));
288 ccw = ptarray_isccw(line->points);
289 CU_ASSERT_EQUAL(ccw, 0);
290 lwline_free(line);
291
292 /* counterclockwise triangle */
293 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 3,20 3,20 4, 0 3)"));
294 ccw = ptarray_isccw(line->points);
295 CU_ASSERT_EQUAL(ccw, 1);
296 lwline_free(line);
297
298 /* counterclockwise narrow ring (see ticket #1302) */
299 line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA284137894120A4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA2841C976BE1FA4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
300 ccw = ptarray_isccw(line->points);
301 CU_ASSERT_EQUAL(ccw, 1);
302 lwline_free(line);
303
304 /* clockwise narrow ring (see ticket #1302) */
305 line = lwgeom_as_lwline(lwgeom_from_hexwkb("01020000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
306 ccw = ptarray_isccw(line->points);
307 CU_ASSERT_EQUAL(ccw, 0);
308 lwline_free(line);
309
310 /* Clockwise narrow ring (see ticket #1302) */
311 poly = lwgeom_as_lwpoly(lwgeom_from_hexwkb("0103000000010000000500000000917E9BA468294100917E9B8AEA2841C976BE1FA4682941C976BE9F8AEA2841B39ABE1FA46829415ACCC29F8AEA284137894120A4682941C976BE9F8AEA284100917E9BA468294100917E9B8AEA2841", LW_PARSER_CHECK_NONE));
312 ccw = ptarray_isccw(poly->rings[0]);
313 CU_ASSERT_EQUAL(ccw, 0);
314 lwpoly_free(poly);
315}
316
318{
319 LWLINE *line;
320 double area;
321
322 /* parallelogram */
323 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,1 1, 2 1, 1 0, 0 0)"));
324 area = ptarray_signed_area(line->points);
325 ASSERT_DOUBLE_EQUAL_TOLERANCE(area, 1.0, 0.0000001);
326 lwline_free(line);
327
328 /* square */
329 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 2, 2 2, 2 0, 0 0)"));
330 area = ptarray_signed_area(line->points);
331 ASSERT_DOUBLE_EQUAL_TOLERANCE(area, 4.0, 0.0000001);
332 lwline_free(line);
333
334 /* square backwards */
335 line = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,2 0, 2 2, 0 2, 0 0)"));
336 area = ptarray_signed_area(line->points);
337 //printf("%g\n",area);
338 ASSERT_DOUBLE_EQUAL_TOLERANCE(area, -4.0, 0.0000001);
339 lwline_free(line);
340
341}
342
344{
345/* int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt, int *winding_number) */
346
347 LWLINE *lwline;
348 POINTARRAY *pa;
349 POINT2D pt;
350 int rv;
351
352 lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 1, 1 1, 1 0, 0 0)"));
353 pa = lwline->points;
354
355 /* Point in middle of square */
356 pt.x = 0.5;
357 pt.y = 0.5;
358 rv = ptarray_contains_point(pa, &pt);
359 CU_ASSERT_EQUAL(rv, LW_INSIDE);
360
361 /* Point on left edge of square */
362 pt.x = 0;
363 pt.y = 0.5;
364 rv = ptarray_contains_point(pa, &pt);
365 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
366
367 /* Point on top edge of square */
368 pt.x = 0.5;
369 pt.y = 1;
370 rv = ptarray_contains_point(pa, &pt);
371 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
372
373 /* Point on bottom left corner of square */
374 pt.x = 0;
375 pt.y = 0;
376 rv = ptarray_contains_point(pa, &pt);
377 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
378
379 /* Point on top left corner of square */
380 pt.x = 0;
381 pt.y = 1;
382 rv = ptarray_contains_point(pa, &pt);
383 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
384
385 /* Point outside top left corner of square */
386 pt.x = -0.1;
387 pt.y = 1;
388 rv = ptarray_contains_point(pa, &pt);
389 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
390
391 /* Point outside top left corner of square */
392 pt.x = 0;
393 pt.y = 1.1;
394 rv = ptarray_contains_point(pa, &pt);
395 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
396
397 /* Point outside left side of square */
398 pt.x = -0.2;
399 pt.y = 0.5;
400 rv = ptarray_contains_point(pa, &pt);
401 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
402
403 lwline_free(lwline);
404 lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 1 1, 2 0, 0 0)"));
405 pa = lwline->points;
406
407 /* Point outside grazing top of triangle */
408 pt.x = 0;
409 pt.y = 1;
410 rv = ptarray_contains_point(pa, &pt);
411 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
412
413 lwline_free(lwline);
414 lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 4, 1 4, 2 2, 3 4, 4 4, 4 0, 0 0)"));
415 pa = lwline->points;
416
417 /* Point outside grazing top of triangle */
418 pt.x = 1;
419 pt.y = 2;
420 rv = ptarray_contains_point(pa, &pt);
421 CU_ASSERT_EQUAL(rv, LW_INSIDE);
422
423 /* Point outside grazing top of triangle */
424 pt.x = 3;
425 pt.y = 2;
426 rv = ptarray_contains_point(pa, &pt);
427 CU_ASSERT_EQUAL(rv, LW_INSIDE);
428
429 lwline_free(lwline);
430}
431
433{
434 /* int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt) */
435
436 LWCIRCSTRING *lwcirc;
437 POINTARRAY *pa;
438 POINT2D pt;
439 int rv;
440
441 /*** Collection of semi-circles surrounding unit square ***/
442 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(-1 -1, -2 0, -1 1, 0 2, 1 1, 2 0, 1 -1, 0 -2, -1 -1)"));
443 pa = lwcirc->points;
444
445 /* Point in middle of square */
446 pt.x = 0;
447 pt.y = 0;
448 rv = ptarrayarc_contains_point(pa, &pt);
449 CU_ASSERT_EQUAL(rv, LW_INSIDE);
450
451 /* Point in left lobe */
452 pt.x = -1.1;
453 pt.y = 0.1;
454 rv = ptarrayarc_contains_point(pa, &pt);
455 CU_ASSERT_EQUAL(rv, LW_INSIDE);
456
457 /* Point on boundary of left lobe */
458 pt.x = -1;
459 pt.y = 0;
460 rv = ptarrayarc_contains_point(pa, &pt);
461 CU_ASSERT_EQUAL(rv, LW_INSIDE);
462
463 /* Point on boundary vertex */
464 pt.x = -1;
465 pt.y = 1;
466 rv = ptarrayarc_contains_point(pa, &pt);
467 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
468
469 /* Point outside */
470 pt.x = -1.5;
471 pt.y = 1.5;
472 rv = ptarrayarc_contains_point(pa, &pt);
473 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
474
475 /*** Two-edge ring made up of semi-circles (really, a circle) ***/
476 lwcircstring_free(lwcirc);
477 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(-1 0, 0 1, 1 0, 0 -1, -1 0)"));
478 pa = lwcirc->points;
479
480 /* Point outside */
481 pt.x = -1.5;
482 pt.y = 1.5;
483 rv = ptarrayarc_contains_point(pa, &pt);
484 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
485
486 /* Point more outside */
487 pt.x = 2.5;
488 pt.y = 1.5;
489 rv = ptarrayarc_contains_point(pa, &pt);
490 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
491
492 /* Point more outside */
493 pt.x = 2.5;
494 pt.y = 2.5;
495 rv = ptarrayarc_contains_point(pa, &pt);
496 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
497
498 /* Point inside at middle */
499 pt.x = 0;
500 pt.y = 0;
501 rv = ptarrayarc_contains_point(pa, &pt);
502 CU_ASSERT_EQUAL(rv, LW_INSIDE);
503
504 /* Point inside offset from middle */
505 pt.x = 0.01;
506 pt.y = 0.01;
507 rv = ptarrayarc_contains_point(pa, &pt);
508 CU_ASSERT_EQUAL(rv, LW_INSIDE);
509
510 /* Point on edge vertex */
511 pt.x = 0;
512 pt.y = 1;
513 rv = ptarrayarc_contains_point(pa, &pt);
514 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
515
516 /*** Two-edge ring, closed ***/
517 lwcircstring_free(lwcirc);
518 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(1 6, 6 1, 9 7, 6 10, 1 6)"));
519 pa = lwcirc->points;
520
521 /* Point to left of ring */
522 pt.x = 20;
523 pt.y = 4;
524 rv = ptarrayarc_contains_point(pa, &pt);
525 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
526
527 /*** One-edge ring, closed circle ***/
528 lwcircstring_free(lwcirc);
529 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(-1 0, 1 0, -1 0)"));
530 pa = lwcirc->points;
531
532 /* Point inside */
533 pt.x = 0;
534 pt.y = 0;
535 rv = ptarrayarc_contains_point(pa, &pt);
536 CU_ASSERT_EQUAL(rv, LW_INSIDE);
537
538 /* Point outside */
539 pt.x = 0;
540 pt.y = 2;
541 rv = ptarrayarc_contains_point(pa, &pt);
542 CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
543
544 /* Point on boundary */
545 pt.x = 0;
546 pt.y = 1;
547 rv = ptarrayarc_contains_point(pa, &pt);
548 CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
549
550 /*** Overshort ring ***/
551 lwcircstring_free(lwcirc);
552 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(-1 0, 1 0)"));
553 pa = lwcirc->points;
555 rv = ptarrayarc_contains_point(pa, &pt);
556 //printf("%s\n", cu_error_msg);
557 ASSERT_STRING_EQUAL(cu_error_msg, "ptarrayarc_raycast_intersections called with even number of points");
558
559 /*** Unclosed ring ***/
560 lwcircstring_free(lwcirc);
561 lwcirc = lwgeom_as_lwcircstring(lwgeom_from_text("CIRCULARSTRING(-1 0, 1 0, 2 0)"));
562 pa = lwcirc->points;
564 rv = ptarrayarc_contains_point(pa, &pt);
565 ASSERT_STRING_EQUAL(cu_error_msg, "ptarrayarc_contains_point called on unclosed ring");
566
567 lwcircstring_free(lwcirc);
568}
569
571{
572 LWLINE *line;
573 POINTARRAY *pa;
574 POINT4D factor;
575 const char *wkt;
576 char *wktout;
577
578 wkt = "LINESTRING ZM (0 1 2 3,1 2 3 0,-2 -3 0 -1,-3 0 -1 -2)";
580 pa = line->points;
581
582 factor.x = factor.y = factor.z = factor.m = 1;
583 ptarray_scale(pa, &factor);
584 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
585 ASSERT_STRING_EQUAL(wktout, wkt);
586 lwfree(wktout);
587
588 factor.x = 2;
589 wkt = "LINESTRING ZM (0 1 2 3,2 2 3 0,-4 -3 0 -1,-6 0 -1 -2)";
590 ptarray_scale(pa, &factor);
591 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
592 ASSERT_STRING_EQUAL(wktout, wkt);
593 lwfree(wktout);
594
595 factor.x = 1; factor.y = 3;
596 wkt = "LINESTRING ZM (0 3 2 3,2 6 3 0,-4 -9 0 -1,-6 0 -1 -2)";
597 ptarray_scale(pa, &factor);
598 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
599 ASSERT_STRING_EQUAL(wktout, wkt);
600 lwfree(wktout);
601
602 factor.x = 1; factor.y = 1; factor.z = -2;
603 wkt = "LINESTRING ZM (0 3 -4 3,2 6 -6 0,-4 -9 0 -1,-6 0 2 -2)";
604 ptarray_scale(pa, &factor);
605 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
606 ASSERT_STRING_EQUAL(wktout, wkt);
607 lwfree(wktout);
608
609 factor.x = 1; factor.y = 1; factor.z = 1; factor.m = 2;
610 wkt = "LINESTRING ZM (0 3 -4 6,2 6 -6 0,-4 -9 0 -2,-6 0 2 -4)";
611 ptarray_scale(pa, &factor);
612 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
613 ASSERT_STRING_EQUAL(wktout, wkt);
614 lwfree(wktout);
615
616 lwline_free(line);
617}
618
620{
621 LWLINE *line;
622 POINTARRAY *pa;
623 POINT4D scroll;
624 const char *wkt;
625 char *wktout;
626 int rv;
627
628 wkt = "LINESTRING ZM (1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1)";
630 pa = line->points;
631
632 scroll.x = scroll.y = scroll.z = scroll.m = 2;
633 rv = ptarray_scroll_in_place(pa, &scroll);
634 CU_ASSERT_EQUAL(rv, LW_SUCCESS);
635 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
636 wkt = "LINESTRING ZM (2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1,2 2 2 2)";
637 ASSERT_STRING_EQUAL(wktout, wkt);
638 lwfree(wktout);
639
640 scroll.x = scroll.y = scroll.z = scroll.m = 1;
641 rv = ptarray_scroll_in_place(pa, &scroll);
642 CU_ASSERT_EQUAL(rv, LW_SUCCESS);
643 wktout = lwgeom_to_text(lwline_as_lwgeom(line));
644 wkt = "LINESTRING ZM (1 1 1 1,2 2 2 2,3 3 3 3,4 4 4 4,1 1 1 1)";
645 ASSERT_STRING_EQUAL(wktout, wkt);
646 lwfree(wktout);
647
648 scroll.x = scroll.y = scroll.z = scroll.m = 9;
649 rv = ptarray_scroll_in_place(pa, &scroll);
650 CU_ASSERT_EQUAL(rv, LW_FAILURE);
651 ASSERT_STRING_EQUAL(cu_error_msg, "ptarray_scroll_in_place: input POINTARRAY does not contain the given point");
652
653 lwline_free(line);
654}
655
657{
658 LWLINE *line;
659 POINTARRAY *pa;
660 double dist;
661 POINT2D qp;
662 const char *wkt;
663 int rv;
664
665 wkt = "LINESTRING (0 0 0, 1 0 0, 2 0 0, 3 0 10)";
667 pa = line->points;
668
669 qp.x = qp.y = 0;
670 rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
671 ASSERT_INT_EQUAL(rv, 0);
672 ASSERT_DOUBLE_EQUAL(dist, 0);
673
674 qp.x = qp.y = 1;
675 rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
676 ASSERT_INT_EQUAL(rv, 1);
677 ASSERT_DOUBLE_EQUAL(dist, 1);
678
679 qp.x = 5; qp.y = 0;
680 rv = ptarray_closest_vertex_2d(pa, &qp, &dist);
681 ASSERT_INT_EQUAL(rv, 3);
682 ASSERT_DOUBLE_EQUAL(dist, 2);
683
684
685 lwline_free(line);
686}
687
689{
690 LWLINE *line;
691 POINTARRAY *pa;
692 double dist;
693 POINT2D qp;
694 const char *wkt;
695 int rv;
696
697 wkt = "LINESTRING (0 0 0, 1 0 0, 2 0 0, 3 0 10)";
699 pa = line->points;
700
701 qp.x = qp.y = 0;
702 rv = ptarray_closest_segment_2d(pa, &qp, &dist);
703 ASSERT_INT_EQUAL(rv, 0);
704 ASSERT_DOUBLE_EQUAL(dist, 0);
705
706 qp.x = 1;
707 rv = ptarray_closest_segment_2d(pa, &qp, &dist);
708 ASSERT_INT_EQUAL(rv, 0);
709 ASSERT_DOUBLE_EQUAL(dist, 0);
710
711 qp.y = 1;
712 rv = ptarray_closest_segment_2d(pa, &qp, &dist);
713 ASSERT_INT_EQUAL(rv, 0);
714 ASSERT_DOUBLE_EQUAL(dist, 1);
715
716 qp.x = 5; qp.y = 0;
717 rv = ptarray_closest_segment_2d(pa, &qp, &dist);
718 ASSERT_INT_EQUAL(rv, 2);
719 ASSERT_DOUBLE_EQUAL(dist, 2);
720
721
722 lwline_free(line);
723
724 /* See https://trac.osgeo.org/postgis/ticket/4990 */
725 /* Test modified to give more stable results */
726 wkt = "LINESTRING(4 31,7 31,7 34,4 34,4 31)";
728 pa = line->points;
729 qp.x = 7.1; qp.y = 31.1;
730 rv = ptarray_closest_segment_2d(pa, &qp, &dist);
731 ASSERT_INT_EQUAL(rv, 1);
732 lwline_free(line);
733}
734
736{
737 POINT4D s0, s1, qp, cp;
738
739 s0.x = s0.y = 0; s0.z = 10; s0.m = 20;
740 s1.x = 0; s1.y = 10; s1.z = 0; s1.m = 10;
741
742 /* Closest is bottom point */
743
744 qp.x = -0.1; qp.y = 0;
745 closest_point_on_segment(&qp, &s0, &s1, &cp);
746 ASSERT_DOUBLE_EQUAL(cp.x, 0);
747 ASSERT_DOUBLE_EQUAL(cp.y, 0);
748 ASSERT_DOUBLE_EQUAL(cp.z, 10);
749 ASSERT_DOUBLE_EQUAL(cp.m, 20);
750
751 qp.x = 0.1; qp.y = 0;
752 closest_point_on_segment(&qp, &s0, &s1, &cp);
753 ASSERT_DOUBLE_EQUAL(cp.x, 0);
754 ASSERT_DOUBLE_EQUAL(cp.y, 0);
755 ASSERT_DOUBLE_EQUAL(cp.z, 10);
756 ASSERT_DOUBLE_EQUAL(cp.m, 20);
757
758 qp.x = 0; qp.y = -0.1;
759 closest_point_on_segment(&qp, &s0, &s1, &cp);
760 ASSERT_DOUBLE_EQUAL(cp.x, 0);
761 ASSERT_DOUBLE_EQUAL(cp.y, 0);
762 ASSERT_DOUBLE_EQUAL(cp.z, 10);
763 ASSERT_DOUBLE_EQUAL(cp.m, 20);
764
765 /* Closest is top point */
766
767 qp.x = 0; qp.y = 10.1;
768 closest_point_on_segment(&qp, &s0, &s1, &cp);
769 ASSERT_DOUBLE_EQUAL(cp.x, 0);
770 ASSERT_DOUBLE_EQUAL(cp.y, 10);
771 ASSERT_DOUBLE_EQUAL(cp.z, 0);
772 ASSERT_DOUBLE_EQUAL(cp.m, 10);
773
774 qp.x = 0.1; qp.y = 10;
775 closest_point_on_segment(&qp, &s0, &s1, &cp);
776 ASSERT_DOUBLE_EQUAL(cp.x, 0);
777 ASSERT_DOUBLE_EQUAL(cp.y, 10);
778 ASSERT_DOUBLE_EQUAL(cp.z, 0);
779 ASSERT_DOUBLE_EQUAL(cp.m, 10);
780
781 qp.x = -0.1; qp.y = 10;
782 closest_point_on_segment(&qp, &s0, &s1, &cp);
783 ASSERT_DOUBLE_EQUAL(cp.x, 0);
784 ASSERT_DOUBLE_EQUAL(cp.y, 10);
785 ASSERT_DOUBLE_EQUAL(cp.z, 0);
786 ASSERT_DOUBLE_EQUAL(cp.m, 10);
787
788 /* Closest is mid point */
789
790 qp.x = 0.1; qp.y = 5;
791 closest_point_on_segment(&qp, &s0, &s1, &cp);
792 ASSERT_DOUBLE_EQUAL(cp.x, 0);
793 ASSERT_DOUBLE_EQUAL(cp.y, 5);
794 ASSERT_DOUBLE_EQUAL(cp.z, 5);
795 ASSERT_DOUBLE_EQUAL(cp.m, 15);
796
797 qp.x = -0.1; qp.y = 5;
798 closest_point_on_segment(&qp, &s0, &s1, &cp);
799 ASSERT_DOUBLE_EQUAL(cp.x, 0);
800 ASSERT_DOUBLE_EQUAL(cp.y, 5);
801 ASSERT_DOUBLE_EQUAL(cp.z, 5);
802 ASSERT_DOUBLE_EQUAL(cp.m, 15);
803
804 qp.x = 0.1; qp.y = 2;
805 closest_point_on_segment(&qp, &s0, &s1, &cp);
806 ASSERT_DOUBLE_EQUAL(cp.x, 0);
807 ASSERT_DOUBLE_EQUAL(cp.y, 2);
808 ASSERT_DOUBLE_EQUAL(cp.z, 8);
809 ASSERT_DOUBLE_EQUAL(cp.m, 18);
810
811 qp.x = -0.1; qp.y = 2;
812 closest_point_on_segment(&qp, &s0, &s1, &cp);
813 ASSERT_DOUBLE_EQUAL(cp.x, 0);
814 ASSERT_DOUBLE_EQUAL(cp.y, 2);
815 ASSERT_DOUBLE_EQUAL(cp.z, 8);
816 ASSERT_DOUBLE_EQUAL(cp.m, 18);
817
818 qp.x = 0.1; qp.y = 8;
819 closest_point_on_segment(&qp, &s0, &s1, &cp);
820 ASSERT_DOUBLE_EQUAL(cp.x, 0);
821 ASSERT_DOUBLE_EQUAL(cp.y, 8);
822 ASSERT_DOUBLE_EQUAL_TOLERANCE(cp.z, 2, 1e-5);
823 ASSERT_DOUBLE_EQUAL(cp.m, 12);
824
825 qp.x = -0.1; qp.y = 8;
826 closest_point_on_segment(&qp, &s0, &s1, &cp);
827 ASSERT_DOUBLE_EQUAL(cp.x, 0);
828 ASSERT_DOUBLE_EQUAL(cp.y, 8);
829 ASSERT_DOUBLE_EQUAL_TOLERANCE(cp.z, 2, 1e-5);
830 ASSERT_DOUBLE_EQUAL(cp.m, 12);
831
832
833}
834
835
836/*
837** Used by the test harness to register the tests in this file.
838*/
839void ptarray_suite_setup(void);
char * r
Definition cu_in_wkt.c:24
static void test_ptarrayarc_contains_point()
Definition cu_ptarray.c:432
static void test_ptarray_contains_point()
Definition cu_ptarray.c:343
static void test_ptarray_append_point(void)
Definition cu_ptarray.c:37
static void test_ptarray_locate_point(void)
Definition cu_ptarray.c:217
static void test_ptarray_closest_point_on_segment(void)
Definition cu_ptarray.c:735
static void test_ptarray_signed_area()
Definition cu_ptarray.c:317
static char * lwgeom_to_text(const LWGEOM *geom)
Definition cu_ptarray.c:32
static void test_ptarray_closest_segment_2d()
Definition cu_ptarray.c:688
static void test_ptarray_scroll()
Definition cu_ptarray.c:619
static void test_ptarray_scale()
Definition cu_ptarray.c:570
static LWGEOM * lwgeom_from_text(const char *str)
Definition cu_ptarray.c:24
static void test_ptarray_insert_point(void)
Definition cu_ptarray.c:59
void ptarray_suite_setup(void)
Definition cu_ptarray.c:840
static void test_ptarray_append_ptarray(void)
Definition cu_ptarray.c:104
static void test_ptarray_closest_vertex_2d()
Definition cu_ptarray.c:656
static void test_ptarray_isccw(void)
Definition cu_ptarray.c:274
void cu_error_msg_reset()
char cu_error_msg[MAX_CUNIT_ERROR_LENGTH+1]
#define ASSERT_DOUBLE_EQUAL_TOLERANCE(o, e, t)
#define ASSERT_DOUBLE_EQUAL(o, e)
#define ASSERT_INT_EQUAL(o, e)
#define PG_ADD_TEST(suite, testfunc)
#define ASSERT_STRING_EQUAL(o, e)
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition lwgeom_api.c:107
#define LW_FALSE
Definition liblwgeom.h:94
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition ptarray.c:1452
int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance)
Append a POINTARRAY, pa2 to the end of an existing POINTARRAY, pa1.
Definition ptarray.c:177
#define LW_FAILURE
Definition liblwgeom.h:96
int ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition ptarray.c:1485
#define LW_PARSER_CHECK_NONE
Definition liblwgeom.h:2149
#define LW_SUCCESS
Definition liblwgeom.h:97
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:708
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located)
Definition ptarray.c:1518
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
Definition ptarray.c:85
void lwfree(void *mem)
Definition lwutil.c:248
void lwcircstring_free(LWCIRCSTRING *curve)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition lwgeom.c:216
LWGEOM * lwgeom_from_hexwkb(const char *hexwkb, const char check)
Definition lwin_wkb.c:866
#define WKT_ISO
Definition liblwgeom.h:2219
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition ptarray.c:147
#define FLAGS_SET_READONLY(flags, value)
Definition liblwgeom.h:176
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
void lwline_free(LWLINE *line)
Definition lwline.c:67
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition ptarray.c:1123
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition ptarray.c:1143
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *newbase)
Definition ptarray.c:2337
void ptarray_scale(POINTARRAY *pa, const POINT4D *factor)
WARNING, make sure you send in only 16-member double arrays or obviously things will go pear-shaped f...
Definition ptarray.c:2201
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
The following is based on the "Fast Winding Number Inclusion of a Point in a Polygon" algorithm by Da...
Definition ptarray.c:755
#define LW_OUTSIDE
int ptarray_isccw(const POINTARRAY *pa)
Definition ptarray.c:1182
void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition ptarray.c:1408
#define str(s)
POINTARRAY * points
Definition liblwgeom.h:507
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY ** rings
Definition liblwgeom.h:519
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390
double m
Definition liblwgeom.h:414
double x
Definition liblwgeom.h:414
double z
Definition liblwgeom.h:414
double y
Definition liblwgeom.h:414
lwflags_t flags
Definition liblwgeom.h:431
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM.
Definition liblwgeom.h:2157