PostGIS  2.5.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 {
27  if( LW_FAILURE == lwgeom_parse_wkt(&r, (char*)str, LW_PARSER_CHECK_NONE) )
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  CU_ASSERT_DOUBLE_EQUAL(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  CU_ASSERT_DOUBLE_EQUAL(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  CU_ASSERT_DOUBLE_EQUAL(area, -4.0, 0.0000001);
339  lwline_free(line);
340 
341 }
342 
344 {
345  LWGEOM *in, *out;
346  char *str;
347 
348  /* It would be nice if this example returned two arcs (it's the intersection of two circles)
349  but it looks like the intersection itself is too sloppy in generating the derived point
350  to accurately reconstruct the circles.
351  in = lwgeom_from_text("POLYGON((0.5 0,0.471177920604846 -0.292635483024192,0.38581929876693 -0.574025148547634,0.247204418453818 -0.833355349529403,0.0606601717798223 -1.06066017177982,-5.44089437167602e-17 -1.11044268820754,-0.0606601717798188 -1.06066017177982,-0.247204418453816 -0.833355349529406,-0.385819298766929 -0.574025148547639,-0.471177920604845 -0.292635483024197,-0.5 -4.84663372329776e-15,-0.471177920604847 0.292635483024187,-0.385819298766932 0.57402514854763,-0.247204418453821 0.833355349529398,-0.0606601717798256 1.06066017177982,3.45538806345173e-16 1.11044268820754,0.0606601717798183 1.06066017177982,0.247204418453816 0.833355349529407,0.385819298766929 0.574025148547638,0.471177920604845 0.292635483024196,0.5 0))");
352  out = lwgeom_unstroke(in);
353  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
354  printf("%s\n", str);
355  ASSERT_STRING_EQUAL(str, "CIRCULARSTRING(-1 0,0 1,0 -1)");
356  lwgeom_free(in);
357  lwgeom_free(out);
358  lwfree(str);
359  */
360 
361  in = lwgeom_from_text("CIRCULARSTRING(-1 0,0 1,0 -1)");
362  out = lwgeom_stroke(in,8);
363  lwgeom_free(in);
364  in = out;
365  out = lwgeom_unstroke(in);
366  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
367  // printf("%s\n", str);
368  ASSERT_STRING_EQUAL(str, "CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1)");
369  lwgeom_free(in);
370  lwgeom_free(out);
371  lwfree(str);
372 
373  in = lwgeom_from_text("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,-1 -1))");
374  out = lwgeom_stroke(in,8);
375  lwgeom_free(in);
376  in = out;
377  out = lwgeom_unstroke(in);
378  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
379  // printf("%s\n", str);
380  ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE(CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 -1),(0 -1,-1 -1))");
381  lwgeom_free(in);
382  lwgeom_free(out);
383  lwfree(str);
384 
385  in = lwgeom_from_text("COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0 1,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 -2,-1 -3,1 -3),(1 -3,5 5))");
386  out = lwgeom_stroke(in,8);
387  lwgeom_free(in);
388  in = out;
389  out = lwgeom_unstroke(in);
390  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
391  // printf("%s\n", str);
393  str,
394  "COMPOUNDCURVE((-3 -3,-1 0),CIRCULARSTRING(-1 0,0.70710678 "
395  "0.70710678,0 -1),(0 -1,0 -1.5,0 -2),CIRCULARSTRING(0 "
396  "-2,-0.70710678 -3.70710678,1 -3),(1 -3,5 5))");
397  lwgeom_free(in);
398  lwgeom_free(out);
399  lwfree(str);
400 
401  in = lwgeom_from_text("COMPOUNDCURVE(CIRCULARSTRING(-1 0,0 1,0 -1),CIRCULARSTRING(0 -1,-1 -2,1 -2))");
402  out = lwgeom_stroke(in,8);
403  lwgeom_free(in);
404  in = out;
405  out = lwgeom_unstroke(in);
406  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
407  // printf("%s\n", str);
409  str,
410  "COMPOUNDCURVE(CIRCULARSTRING(-1 0,0.70710678 0.70710678,0 "
411  "-1),CIRCULARSTRING(0 -1,-0.70710678 -2.70710678,1 -2))");
412  lwgeom_free(in);
413  lwgeom_free(out);
414  lwfree(str);
415 
416  in = lwgeom_from_text("COMPOUNDCURVE((0 0, 1 1), CIRCULARSTRING(1 1, 2 2, 3 1), (3 1, 4 4))");
417  out = lwgeom_stroke(in,8);
418  lwgeom_free(in);
419  in = out;
420  out = lwgeom_unstroke(in);
421  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
422  ASSERT_STRING_EQUAL(str, "COMPOUNDCURVE((0 0,1 1),CIRCULARSTRING(1 1,2 2,3 1),(3 1,4 4))");
423  lwgeom_free(in);
424  lwgeom_free(out);
425  // printf("%s\n", str);
426  lwfree(str);
427 
428  // See http://trac.osgeo.org/postgis/ticket/2425
429  // and http://trac.osgeo.org/postgis/ticket/2420
430  in = lwgeom_from_text("LINESTRING(0 0,10 0,10 10,0 10,0 0)");
431  out = lwgeom_unstroke(in);
432  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
433  ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,10 0,10 10,0 10,0 0)");
434  lwgeom_free(in);
435  lwgeom_free(out);
436  lwfree(str);
437 
438  in = lwgeom_from_text("LINESTRING(10 10,0 10,0 0,10 0)");
439  out = lwgeom_unstroke(in);
440  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
441  ASSERT_STRING_EQUAL(str, "LINESTRING(10 10,0 10,0 0,10 0)");
442  // printf("%s\n", str);
443  lwgeom_free(in);
444  lwgeom_free(out);
445  lwfree(str);
446 
447  in = lwgeom_from_text("LINESTRING(0 0,10 0,10 10,0 10)");
448  out = lwgeom_unstroke(in);
449  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
450  ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,10 0,10 10,0 10)");
451  // printf("%s\n", str);
452  lwgeom_free(in);
453  lwgeom_free(out);
454  lwfree(str);
455 
456  // See http://trac.osgeo.org/postgis/ticket/2412
457  in = lwgeom_from_text("LINESTRING(0 0, 1 1)");
458  out = lwgeom_unstroke(in);
459  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
460  // printf("%s\n", str);
461  ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,1 1)");
462  lwgeom_free(in);
463  lwgeom_free(out);
464  lwfree(str);
465 
466 }
467 
469 {
470 /* int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt, int *winding_number) */
471 
472  LWLINE *lwline;
473  POINTARRAY *pa;
474  POINT2D pt;
475  int rv;
476 
477  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 1, 1 1, 1 0, 0 0)"));
478  pa = lwline->points;
479 
480  /* Point in middle of square */
481  pt.x = 0.5;
482  pt.y = 0.5;
483  rv = ptarray_contains_point(pa, &pt);
484  CU_ASSERT_EQUAL(rv, LW_INSIDE);
485 
486  /* Point on left edge of square */
487  pt.x = 0;
488  pt.y = 0.5;
489  rv = ptarray_contains_point(pa, &pt);
490  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
491 
492  /* Point on top edge of square */
493  pt.x = 0.5;
494  pt.y = 1;
495  rv = ptarray_contains_point(pa, &pt);
496  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
497 
498  /* Point on bottom left corner of square */
499  pt.x = 0;
500  pt.y = 0;
501  rv = ptarray_contains_point(pa, &pt);
502  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
503 
504  /* Point on top left corner of square */
505  pt.x = 0;
506  pt.y = 1;
507  rv = ptarray_contains_point(pa, &pt);
508  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
509 
510  /* Point outside top left corner of square */
511  pt.x = -0.1;
512  pt.y = 1;
513  rv = ptarray_contains_point(pa, &pt);
514  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
515 
516  /* Point outside top left corner of square */
517  pt.x = 0;
518  pt.y = 1.1;
519  rv = ptarray_contains_point(pa, &pt);
520  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
521 
522  /* Point outside left side of square */
523  pt.x = -0.2;
524  pt.y = 0.5;
525  rv = ptarray_contains_point(pa, &pt);
526  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
527 
528  lwline_free(lwline);
529  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 1 1, 2 0, 0 0)"));
530  pa = lwline->points;
531 
532  /* Point outside grazing top of triangle */
533  pt.x = 0;
534  pt.y = 1;
535  rv = ptarray_contains_point(pa, &pt);
536  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
537 
538  lwline_free(lwline);
539  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 0 4, 1 4, 2 2, 3 4, 4 4, 4 0, 0 0)"));
540  pa = lwline->points;
541 
542  /* Point outside grazing top of triangle */
543  pt.x = 1;
544  pt.y = 2;
545  rv = ptarray_contains_point(pa, &pt);
546  CU_ASSERT_EQUAL(rv, LW_INSIDE);
547 
548  /* Point outside grazing top of triangle */
549  pt.x = 3;
550  pt.y = 2;
551  rv = ptarray_contains_point(pa, &pt);
552  CU_ASSERT_EQUAL(rv, LW_INSIDE);
553 
554  lwline_free(lwline);
555 }
556 
558 {
559  /* int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt) */
560 
561  LWLINE *lwline;
562  POINTARRAY *pa;
563  POINT2D pt;
564  int rv;
565 
566  /*** Collection of semi-circles surrounding unit square ***/
567  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)"));
568  pa = lwline->points;
569 
570  /* Point in middle of square */
571  pt.x = 0;
572  pt.y = 0;
573  rv = ptarrayarc_contains_point(pa, &pt);
574  CU_ASSERT_EQUAL(rv, LW_INSIDE);
575 
576  /* Point in left lobe */
577  pt.x = -1.1;
578  pt.y = 0.1;
579  rv = ptarrayarc_contains_point(pa, &pt);
580  CU_ASSERT_EQUAL(rv, LW_INSIDE);
581 
582  /* Point on boundary of left lobe */
583  pt.x = -1;
584  pt.y = 0;
585  rv = ptarrayarc_contains_point(pa, &pt);
586  CU_ASSERT_EQUAL(rv, LW_INSIDE);
587 
588  /* Point on boundary vertex */
589  pt.x = -1;
590  pt.y = 1;
591  rv = ptarrayarc_contains_point(pa, &pt);
592  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
593 
594  /* Point outside */
595  pt.x = -1.5;
596  pt.y = 1.5;
597  rv = ptarrayarc_contains_point(pa, &pt);
598  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
599 
600  /*** Two-edge ring made up of semi-circles (really, a circle) ***/
601  lwline_free(lwline);
602  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0, 0 -1, -1 0)"));
603  pa = lwline->points;
604 
605  /* Point outside */
606  pt.x = -1.5;
607  pt.y = 1.5;
608  rv = ptarrayarc_contains_point(pa, &pt);
609  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
610 
611  /* Point more outside */
612  pt.x = 2.5;
613  pt.y = 1.5;
614  rv = ptarrayarc_contains_point(pa, &pt);
615  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
616 
617  /* Point more outside */
618  pt.x = 2.5;
619  pt.y = 2.5;
620  rv = ptarrayarc_contains_point(pa, &pt);
621  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
622 
623  /* Point inside at middle */
624  pt.x = 0;
625  pt.y = 0;
626  rv = ptarrayarc_contains_point(pa, &pt);
627  CU_ASSERT_EQUAL(rv, LW_INSIDE);
628 
629  /* Point inside offset from middle */
630  pt.x = 0.01;
631  pt.y = 0.01;
632  rv = ptarrayarc_contains_point(pa, &pt);
633  CU_ASSERT_EQUAL(rv, LW_INSIDE);
634 
635  /* Point on edge vertex */
636  pt.x = 0;
637  pt.y = 1;
638  rv = ptarrayarc_contains_point(pa, &pt);
639  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
640 
641  /*** Two-edge ring, closed ***/
642  lwline_free(lwline);
643  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(1 6, 6 1, 9 7, 6 10, 1 6)"));
644  pa = lwline->points;
645 
646  /* Point to left of ring */
647  pt.x = 20;
648  pt.y = 4;
649  rv = ptarrayarc_contains_point(pa, &pt);
650  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
651 
652  /*** One-edge ring, closed circle ***/
653  lwline_free(lwline);
654  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, -1 0)"));
655  pa = lwline->points;
656 
657  /* Point inside */
658  pt.x = 0;
659  pt.y = 0;
660  rv = ptarrayarc_contains_point(pa, &pt);
661  CU_ASSERT_EQUAL(rv, LW_INSIDE);
662 
663  /* Point outside */
664  pt.x = 0;
665  pt.y = 2;
666  rv = ptarrayarc_contains_point(pa, &pt);
667  CU_ASSERT_EQUAL(rv, LW_OUTSIDE);
668 
669  /* Point on boundary */
670  pt.x = 0;
671  pt.y = 1;
672  rv = ptarrayarc_contains_point(pa, &pt);
673  CU_ASSERT_EQUAL(rv, LW_BOUNDARY);
674 
675  /*** Overshort ring ***/
676  lwline_free(lwline);
677  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0)"));
678  pa = lwline->points;
680  rv = ptarrayarc_contains_point(pa, &pt);
681  //printf("%s\n", cu_error_msg);
682  ASSERT_STRING_EQUAL("ptarrayarc_contains_point called with even number of points", cu_error_msg);
683 
684  /*** Unclosed ring ***/
685  lwline_free(lwline);
686  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 1 0, 2 0)"));
687  pa = lwline->points;
689  rv = ptarrayarc_contains_point(pa, &pt);
690  ASSERT_STRING_EQUAL("ptarrayarc_contains_point called on unclosed ring", cu_error_msg);
691 
692  lwline_free(lwline);
693 }
694 
695 static void test_ptarray_scale()
696 {
697  LWLINE *line;
698  POINTARRAY *pa;
699  POINT4D factor;
700  const char *wkt;
701  char *wktout;
702 
703  wkt = "LINESTRING ZM (0 1 2 3,1 2 3 0,-2 -3 0 -1,-3 0 -1 -2)";
704  line = lwgeom_as_lwline(lwgeom_from_text(wkt));
705  pa = line->points;
706 
707  factor.x = factor.y = factor.z = factor.m = 1;
708  ptarray_scale(pa, &factor);
709  wktout = lwgeom_to_text(lwline_as_lwgeom(line));
710  ASSERT_STRING_EQUAL(wktout, wkt);
711  lwfree(wktout);
712 
713  factor.x = 2;
714  wkt = "LINESTRING ZM (0 1 2 3,2 2 3 0,-4 -3 0 -1,-6 0 -1 -2)";
715  ptarray_scale(pa, &factor);
716  wktout = lwgeom_to_text(lwline_as_lwgeom(line));
717  ASSERT_STRING_EQUAL(wktout, wkt);
718  lwfree(wktout);
719 
720  factor.x = 1; factor.y = 3;
721  wkt = "LINESTRING ZM (0 3 2 3,2 6 3 0,-4 -9 0 -1,-6 0 -1 -2)";
722  ptarray_scale(pa, &factor);
723  wktout = lwgeom_to_text(lwline_as_lwgeom(line));
724  ASSERT_STRING_EQUAL(wktout, wkt);
725  lwfree(wktout);
726 
727  factor.x = 1; factor.y = 1; factor.z = -2;
728  wkt = "LINESTRING ZM (0 3 -4 3,2 6 -6 0,-4 -9 0 -1,-6 0 2 -2)";
729  ptarray_scale(pa, &factor);
730  wktout = lwgeom_to_text(lwline_as_lwgeom(line));
731  ASSERT_STRING_EQUAL(wktout, wkt);
732  lwfree(wktout);
733 
734  factor.x = 1; factor.y = 1; factor.z = 1; factor.m = 2;
735  wkt = "LINESTRING ZM (0 3 -4 6,2 6 -6 0,-4 -9 0 -2,-6 0 2 -4)";
736  ptarray_scale(pa, &factor);
737  wktout = lwgeom_to_text(lwline_as_lwgeom(line));
738  ASSERT_STRING_EQUAL(wktout, wkt);
739  lwfree(wktout);
740 
741  lwline_free(line);
742 }
743 
744 
745 /*
746 ** Used by the test harness to register the tests in this file.
747 */
748 void ptarray_suite_setup(void);
750 {
751  CU_pSuite suite = CU_add_suite("ptarray", NULL, NULL);
762 }
double x
Definition: liblwgeom.h:351
LWGEOM * lwgeom_stroke(const LWGEOM *geom, uint32_t perQuad)
Definition: lwstroke.c:714
double m
Definition: liblwgeom.h:351
int ptarray_isccw(const POINTARRAY *pa)
Definition: ptarray.c:1021
char * r
Definition: cu_in_wkt.c:24
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:675
static void test_ptarray_scale()
Definition: cu_ptarray.c:695
void lwfree(void *mem)
Definition: lwutil.c:244
void ptarray_scale(POINTARRAY *pa, const POINT4D *factor)
Scale a pointarray.
Definition: ptarray.c:1840
#define ASSERT_STRING_EQUAL(o, e)
Datum area(PG_FUNCTION_ARGS)
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1137
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition: ptarray.c:826
#define LW_SUCCESS
Definition: liblwgeom.h:79
void lwline_free(LWLINE *line)
Definition: lwline.c:76
static void test_ptarray_isccw(void)
Definition: cu_ptarray.c:274
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:205
static void test_ptarray_append_ptarray(void)
Definition: cu_ptarray.c:104
void ptarray_suite_setup(void)
Definition: cu_ptarray.c:749
double ptarray_signed_area(const POINTARRAY *pa)
Returns the area in cartesian units.
Definition: ptarray.c:990
static void test_ptarray_insert_point(void)
Definition: cu_ptarray.c:59
#define LW_FAILURE
Definition: liblwgeom.h:78
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:1998
double x
Definition: liblwgeom.h:327
double ptarray_locate_point(const POINTARRAY *pa, const POINT4D *pt, double *dist, POINT4D *p_located)
Definition: ptarray.c:1298
static LWGEOM * lwgeom_from_text(const char *str)
Definition: cu_ptarray.c:24
#define WKT_ISO
Definition: liblwgeom.h:2068
POINT4D getPoint4d(const POINTARRAY *pa, uint32_t n)
Definition: lwgeom_api.c:96
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:329
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, then a duplicate point will not be added.
Definition: ptarray.c:156
#define LW_FALSE
Definition: liblwgeom.h:76
uint8_t flags
Definition: liblwgeom.h:368
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:173
void cu_error_msg_reset()
static char * lwgeom_to_text(const LWGEOM *geom)
Definition: cu_ptarray.c:32
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:75
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM...
Definition: liblwgeom.h:2005
#define PG_ADD_TEST(suite, testfunc)
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:187
POINTARRAY ** rings
Definition: liblwgeom.h:456
#define LW_INSIDE
Constants for point-in-polygon return values.
static void test_ptarray_unstroke()
Definition: cu_ptarray.c:343
double y
Definition: liblwgeom.h:327
static void test_ptarray_locate_point(void)
Definition: cu_ptarray.c:217
double z
Definition: liblwgeom.h:351
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:169
LWGEOM * lwgeom_from_hexwkb(const char *hexwkb, const char check)
Definition: lwin_wkb.c:789
static void test_ptarrayarc_contains_point()
Definition: cu_ptarray.c:557
#define LW_BOUNDARY
static void test_ptarray_contains_point()
Definition: cu_ptarray.c:468
int ptarray_insert_point(POINTARRAY *pa, const POINT4D *p, uint32_t where)
Insert a point into an existing POINTARRAY.
Definition: ptarray.c:96
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:727
#define LW_OUTSIDE
double y
Definition: liblwgeom.h:351
LWGEOM * lwgeom_unstroke(const LWGEOM *geom)
Definition: lwstroke.c:1086
char cu_error_msg[MAX_CUNIT_ERROR_LENGTH+1]
static void test_ptarray_append_point(void)
Definition: cu_ptarray.c:37
static void test_ptarray_signed_area()
Definition: cu_ptarray.c:317
#define FLAGS_SET_READONLY(flags, value)
Definition: liblwgeom.h:149
POINTARRAY * points
Definition: liblwgeom.h:421