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