PostGIS  3.4.0dev-r@@SVN_REVISION@@
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 
24 static LWGEOM* lwgeom_from_text(const char *str)
25 {
28  return NULL;
29  return r.geom;
30 }
31 
32 static char* lwgeom_to_text(const LWGEOM *geom)
33 {
34  return lwgeom_to_wkt(geom, WKT_ISO, 8, NULL);
35 }
36 
37 static void test_ptarray_append_point(void)
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;
47  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
48  ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
49  lwfree(wkt);
50 
52  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
53  ASSERT_STRING_EQUAL(wkt,"LINESTRING(0 0,1 1,1 1)");
54  lwfree(wkt);
55 
56  lwline_free(line);
57 }
58 
59 static void test_ptarray_insert_point(void)
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);
69  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
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);
76  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
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);
83  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
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);
90  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
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);
97  wkt = lwgeom_to_text(lwline_as_lwgeom(line));
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 
217 static void test_ptarray_locate_point(void)
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 
274 static 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 backwares*/
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  LWLINE *lwline;
437  POINTARRAY *pa;
438  POINT2D pt;
439  int rv;
440 
441  /*** Collection of semi-circles surrounding unit square ***/
442  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 -1, -2 0, -1 1, 0 2, 1 1, 2 0, 1 -1, 0 -2, -1 -1)"));
443  pa = lwline->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  lwline_free(lwline);
477  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0, 0 -1, -1 0)"));
478  pa = lwline->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  lwline_free(lwline);
518  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(1 6, 6 1, 9 7, 6 10, 1 6)"));
519  pa = lwline->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  lwline_free(lwline);
529  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, -1 0)"));
530  pa = lwline->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  lwline_free(lwline);
552  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0)"));
553  pa = lwline->points;
555  rv = ptarrayarc_contains_point(pa, &pt);
556  //printf("%s\n", cu_error_msg);
557  ASSERT_STRING_EQUAL("ptarrayarc_contains_point called with even number of points", cu_error_msg);
558 
559  /*** Unclosed ring ***/
560  lwline_free(lwline);
561  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, 2 0)"));
562  pa = lwline->points;
564  rv = ptarrayarc_contains_point(pa, &pt);
565  ASSERT_STRING_EQUAL("ptarrayarc_contains_point called on unclosed ring", cu_error_msg);
566 
567  lwline_free(lwline);
568 }
569 
570 static void test_ptarray_scale()
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)";
579  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
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 
619 static void test_ptarray_scroll()
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)";
629  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
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)";
666  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
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)";
698  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
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)";
727  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
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 */
839 void ptarray_suite_setup(void);
841 {
842  CU_pSuite suite = CU_add_suite("ptarray", NULL, NULL);
856 }
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 char * lwgeom_to_text(const LWGEOM *geom)
Definition: cu_ptarray.c:32
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 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 void test_ptarray_insert_point(void)
Definition: cu_ptarray.c:59
static LWGEOM * lwgeom_from_text(const char *str)
Definition: cu_ptarray.c:24
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)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:108
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1320
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
LWGEOM * lwgeom_from_hexwkb(const char *hexwkb, const char check)
Definition: lwin_wkb.c:858
#define LW_FAILURE
Definition: liblwgeom.h:96
int ptarray_closest_vertex_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
Definition: ptarray.c:1353
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2114
#define LW_SUCCESS
Definition: liblwgeom.h:97
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:1386
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:242
#define WKT_ISO
Definition: liblwgeom.h:2184
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 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
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
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:852
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:1016
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *newbase)
Definition: ptarray.c:2181
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:2058
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return 1 if the point is inside the POINTARRAY, -1 if it is outside, and 0 if it is on the boundary.
Definition: ptarray.c:753
#define LW_OUTSIDE
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1047
void closest_point_on_segment(const POINT4D *R, const POINT4D *A, const POINT4D *B, POINT4D *ret)
Definition: ptarray.c:1276
#define str(s)
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:2122