PostGIS  2.4.9dev-r@@SVN_REVISION@@
cu_measures.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2015 Sandro Santilli <strk@kbt.io>
7  * Copyright (C) 2009 Paul Ramsey <pramsey@cleverelephant.ca>
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 
19 #include "liblwgeom_internal.h"
20 #include "cu_tester.h"
21 #include "measures.h"
22 #include "measures3d.h"
23 #include "lwtree.h"
24 
25 static LWGEOM* lwgeom_from_text(const char *str)
26 {
28  if( LW_FAILURE == lwgeom_parse_wkt(&r, (char*)str, LW_PARSER_CHECK_NONE) )
29  return NULL;
30  return r.geom;
31 }
32 
33 #define DIST2DTEST(str1, str2, res) \
34  do_test_mindistance_tolerance(str1, str2, res, __LINE__, lwgeom_mindistance2d_tolerance);\
35  do_test_mindistance_tolerance(str2, str1, res, __LINE__, lwgeom_mindistance2d_tolerance)
36 #define DIST3DTEST(str1, str2, res) \
37  do_test_mindistance_tolerance(str1, str2, res, __LINE__, lwgeom_mindistance3d_tolerance)
38 
39 static void
41  char *in2,
42  double expected_res,
43  int line,
44  double (*distancef)(const LWGEOM *, const LWGEOM *, double))
45 {
46  LWGEOM *lw1;
47  LWGEOM *lw2;
48  double distance;
49  char *msg1 = "test_mindistance2d_tolerance failed (got %g expected %g) at line %d\n";
50  char *msg2 = "\n\ndo_test_mindistance2d_tolerance: NULL lwgeom generated from WKT\n %s\n\n";
51 
54 
55  if ( ! lw1 )
56  {
57  printf(msg2, in1);
58  exit(1);
59  }
60  if ( ! lw2 )
61  {
62  printf(msg2, in2);
63  exit(1);
64  }
65 
66  distance = distancef(lw1, lw2, 0.0);
67  lwgeom_free(lw1);
68  lwgeom_free(lw2);
69 
70  if ( fabs(distance - expected_res) > 0.00001 )
71  {
72  printf(msg1, distance, expected_res, line);
73  CU_FAIL();
74  }
75  else
76  {
77  CU_PASS();
78  }
79 
80 }
81 
83 {
84  /*
85  ** Simple case.
86  */
87  DIST2DTEST("POINT(0 0)", "MULTIPOINT(0 1.5,0 2,0 2.5)", 1.5);
88 
89  /*
90  ** Point vs Geometry Collection.
91  */
92  DIST2DTEST("POINT(0 0)", "GEOMETRYCOLLECTION(POINT(3 4))", 5.0);
93 
94  /*
95  ** Point vs Geometry Collection Collection.
96  */
97  DIST2DTEST("POINT(0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4)))", 5.0);
98 
99  /*
100  ** Point vs Geometry Collection Collection Collection.
101  */
102  DIST2DTEST("POINT(0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4))))", 5.0);
103 
104  /*
105  ** Point vs Geometry Collection Collection Collection Multipoint.
106  */
107  DIST2DTEST("POINT(0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(3 4))))", 5.0);
108 
109  /*
110  ** Geometry Collection vs Geometry Collection
111  */
112  DIST2DTEST("GEOMETRYCOLLECTION(POINT(0 0))", "GEOMETRYCOLLECTION(POINT(3 4))", 5.0);
113 
114  /*
115  ** Geometry Collection Collection vs Geometry Collection Collection
116  */
117  DIST2DTEST("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4)))", 5.0);
118 
119  /*
120  ** Geometry Collection Collection Multipoint vs Geometry Collection Collection Multipoint
121  */
122  DIST2DTEST("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(0 0)))", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(3 4)))", 5.0);
123 
124  /*
125  ** Linestring vs its start point
126  */
127  DIST2DTEST("LINESTRING(-2 0, -0.2 0)", "POINT(-2 0)", 0);
128 
129  /*
130  ** Linestring vs its end point
131  */
132  DIST2DTEST("LINESTRING(-0.2 0, -2 0)", "POINT(-2 0)", 0);
133 
134  /*
135  ** Linestring vs its start point (tricky number, see #1459)
136  */
137  DIST2DTEST("LINESTRING(-1e-8 0, -0.2 0)", "POINT(-1e-8 0)", 0);
138 
139  /*
140  ** Linestring vs its end point (tricky number, see #1459)
141  */
142  DIST2DTEST("LINESTRING(-0.2 0, -1e-8 0)", "POINT(-1e-8 0)", 0);
143 
144  /*
145  * Circular string and point
146  */
147  DIST2DTEST("CIRCULARSTRING(-1 0, 0 1, 1 0)", "POINT(0 0)", 1);
148  DIST2DTEST("CIRCULARSTRING(-3 0, -2 0, -1 0, 0 1, 1 0)", "POINT(0 0)", 1);
149 
150  /*
151  * Circular string and Circular string
152  */
153  DIST2DTEST("CIRCULARSTRING(-1 0, 0 1, 1 0)", "CIRCULARSTRING(0 0, 1 -1, 2 0)", 1);
154 
155  /*
156  * CurvePolygon and Point
157  */
158  static char *cs1 = "CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(1 6, 6 1, 9 7),(9 7, 3 13, 1 6)),COMPOUNDCURVE((3 6, 5 4, 7 4, 7 6),CIRCULARSTRING(7 6,5 8,3 6)))";
159  DIST2DTEST(cs1, "POINT(3 14)", 1);
160  DIST2DTEST(cs1, "POINT(3 8)", 0);
161  DIST2DTEST(cs1, "POINT(6 5)", 1);
162  DIST2DTEST(cs1, "POINT(6 4)", 0);
163 
164  /*
165  * CurvePolygon and Linestring
166  */
167  DIST2DTEST(cs1, "LINESTRING(0 0, 50 0)", 0.917484);
168  DIST2DTEST(cs1, "LINESTRING(6 0, 10 7)", 0);
169  DIST2DTEST(cs1, "LINESTRING(4 4, 4 8)", 0);
170  DIST2DTEST(cs1, "LINESTRING(4 7, 5 6, 6 7)", 0.585786);
171  DIST2DTEST(cs1, "LINESTRING(10 0, 10 2, 10 0)", 1.52913);
172 
173  /*
174  * CurvePolygon and Polygon
175  */
176  DIST2DTEST(cs1, "POLYGON((10 4, 10 8, 13 8, 13 4, 10 4))", 0.58415);
177  DIST2DTEST(cs1, "POLYGON((9 4, 9 8, 12 8, 12 4, 9 4))", 0);
178  DIST2DTEST(cs1, "POLYGON((1 4, 1 8, 4 8, 4 4, 1 4))", 0);
179 
180  /*
181  * CurvePolygon and CurvePolygon
182  */
183  DIST2DTEST(cs1, "CURVEPOLYGON(CIRCULARSTRING(-1 4, 0 5, 1 4, 0 3, -1 4))", 0.0475666);
184  DIST2DTEST(cs1, "CURVEPOLYGON(CIRCULARSTRING(1 4, 2 5, 3 4, 2 3, 1 4))", 0.0);
185 
186  /*
187  * MultiSurface and CurvePolygon
188  */
189  static char *cs2 = "MULTISURFACE(POLYGON((0 0,0 4,4 4,4 0,0 0)),CURVEPOLYGON(CIRCULARSTRING(8 2,10 4,12 2,10 0,8 2)))";
190  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(5 2,6 3,7 2,6 1,5 2))", 1);
191  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(4 2,5 3,6 2,5 1,4 2))", 0);
192  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(5 3,6 2,5 1,4 2,5 3))", 0);
193  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(4.5 3,5.5 2,4.5 1,3.5 2,4.5 3))", 0);
194  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(5.5 3,6.5 2,5.5 1,4.5 2,5.5 3))", 0.5);
195  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(10 3,11 2,10 1,9 2,10 3))", 0);
196  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(2 3,3 2,2 1,1 2,2 3))", 0);
197  DIST2DTEST(cs2, "CURVEPOLYGON(CIRCULARSTRING(5 7,6 8,7 7,6 6,5 7))", 2.60555);
198 
199  /*
200  * MultiCurve and Linestring
201  */
202  DIST2DTEST("LINESTRING(0.5 1,0.5 3)", "MULTICURVE(CIRCULARSTRING(2 3,3 2,2 1,1 2,2 3),(0 0, 0 5))", 0.5);
203 
204 }
205 
206 static void
208 {
209  /* 2D [Z=0] should work just the same */
210  DIST3DTEST("POINT(0 0 0)", "MULTIPOINT(0 1.5 0, 0 2 0, 0 2.5 0)", 1.5);
211  DIST3DTEST("POINT(0 0 0)", "MULTIPOINT(0 1.5 0, 0 2 0, 0 2.5 0)", 1.5);
212  DIST3DTEST("POINT(0 0 0)", "GEOMETRYCOLLECTION(POINT(3 4 0))", 5.0);
213  DIST3DTEST("POINT(0 0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4 0)))", 5.0);
214  DIST3DTEST("POINT(0 0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4 0))))", 5.0);
215  DIST3DTEST("POINT(0 0)", "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(3 4))))", 5.0);
216  DIST3DTEST("GEOMETRYCOLLECTION(POINT(0 0 0))", "GEOMETRYCOLLECTION(POINT(3 4 0))", 5.0);
217  DIST3DTEST("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0 0)))",
218  "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(3 4 0)))",
219  5.0);
220  DIST3DTEST("GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(0 0 0)))",
221  "GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(MULTIPOINT(3 4 0)))",
222  5.0);
223  DIST3DTEST("LINESTRING(-2 0 0, -0.2 0 0)", "POINT(-2 0 0)", 0);
224  DIST3DTEST("LINESTRING(-0.2 0 0, -2 0 0)", "POINT(-2 0 0)", 0);
225  DIST3DTEST("LINESTRING(-1e-8 0 0, -0.2 0 0)", "POINT(-1e-8 0 0)", 0);
226  DIST3DTEST("LINESTRING(-0.2 0 0, -1e-8 0 0)", "POINT(-1e-8 0 0)", 0);
227 
228  /* Tests around intersections */
229  DIST3DTEST("LINESTRING(1 0 0 , 2 0 0)", "POLYGON((1 1 0, 2 1 0, 2 2 0, 1 2 0, 1 1 0))", 1.0);
230  DIST3DTEST("LINESTRING(1 1 1 , 2 1 0)", "POLYGON((1 1 0, 2 1 0, 2 2 0, 1 2 0, 1 1 0))", 0.0);
231  DIST3DTEST("LINESTRING(1 1 1 , 2 1 1)", "POLYGON((1 1 0, 2 1 0, 2 2 0, 1 2 0, 1 1 0))", 1.0);
232  /* Line in polygon */
233  DIST3DTEST("LINESTRING(1 1 1 , 2 2 2)", "POLYGON((0 0 0, 2 2 2, 3 3 1, 0 0 0))", 0.0);
234 
235  /* Line has a point in the same plane as the polygon but isn't the closest*/
236  DIST3DTEST("LINESTRING(-10000 -10000 0, 0 0 1)", "POLYGON((0 0 0, 1 0 0, 1 1 0, 0 1 0, 0 0 0))", 1);
237 
238  /* This is an invalid polygon since it defines just a line */
239  DIST3DTEST("LINESTRING(1 1 1 , 2 2 2)", "POLYGON((0 0 0, 2 2 2, 3 3 3, 0 0 0))", 0);
240 }
241 
243 {
244  LWPOLY *poly;
245  POINT2D p;
246  RECT_NODE* tree;
247  int result;
248  int boundary = 0;
249 
250  /* square */
251  poly = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))", LW_PARSER_CHECK_NONE);
252  tree = rect_tree_new(poly->rings[0]);
253 
254  /* inside square */
255  boundary = 0;
256  p.x = 0.5;
257  p.y = 0.5;
258  result = rect_tree_contains_point(tree, &p, &boundary);
259  CU_ASSERT_NOT_EQUAL(result, 0);
260 
261  /* outside square */
262  boundary = 0;
263  p.x = 1.5;
264  p.y = 0.5;
265  result = rect_tree_contains_point(tree, &p, &boundary);
266  CU_ASSERT_EQUAL(result, 0);
267 
268  rect_tree_free(tree);
269  lwpoly_free(poly);
270 
271  /* ziggy zaggy horizontal saw tooth polygon */
272  poly = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 1 3, 2 0, 3 3, 4 0, 4 5, 0 5, 0 0))", LW_PARSER_CHECK_NONE);
273  tree = rect_tree_new(poly->rings[0]);
274 
275  /* not in, left side */
276  boundary = 0;
277  p.x = -0.5;
278  p.y = 0.5;
279  result = rect_tree_contains_point(tree, &p, &boundary);
280  CU_ASSERT_EQUAL(result, 0);
281 
282  /* not in, right side */
283  boundary = 0;
284  p.x = 3.0;
285  p.y = 1.0;
286  result = rect_tree_contains_point(tree, &p, &boundary);
287  CU_ASSERT_EQUAL(result, 0);
288 
289  /* inside */
290  boundary = 0;
291  p.x = 2.0;
292  p.y = 1.0;
293  result = rect_tree_contains_point(tree, &p, &boundary);
294  CU_ASSERT_NOT_EQUAL(result, 0);
295 
296  /* on left border */
297  boundary = 0;
298  p.x = 0.0;
299  p.y = 1.0;
300  result = rect_tree_contains_point(tree, &p, &boundary);
301  CU_ASSERT_EQUAL(boundary, 1);
302 
303  /* on right border */
304  boundary = 0;
305  p.x = 4.0;
306  p.y = 0.0;
307  result = rect_tree_contains_point(tree, &p, &boundary);
308  CU_ASSERT_EQUAL(boundary, 1);
309 
310  /* on tooth concave */
311  boundary = 0;
312  p.x = 3.0;
313  p.y = 3.0;
314  result = rect_tree_contains_point(tree, &p, &boundary);
315  CU_ASSERT_EQUAL(boundary, 1);
316 
317  /* on tooth convex */
318  boundary = 0;
319  p.x = 2.0;
320  p.y = 0.0;
321  result = rect_tree_contains_point(tree, &p, &boundary);
322  CU_ASSERT_EQUAL(boundary, 1);
323 
324  rect_tree_free(tree);
325  lwpoly_free(poly);
326 
327  /* ziggy zaggy vertical saw tooth polygon */
328  poly = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
329  tree = rect_tree_new(poly->rings[0]);
330 
331  /* not in, left side */
332  boundary = 0;
333  p.x = -0.5;
334  p.y = 3.5;
335  result = rect_tree_contains_point(tree, &p, &boundary);
336  CU_ASSERT_EQUAL(result, 0);
337 
338  /* not in, right side */
339  boundary = 0;
340  p.x = 6.0;
341  p.y = 2.2;
342  result = rect_tree_contains_point(tree, &p, &boundary);
343  CU_ASSERT_EQUAL(result, 0);
344 
345  /* inside */
346  boundary = 0;
347  p.x = 3.0;
348  p.y = 2.0;
349  result = rect_tree_contains_point(tree, &p, &boundary);
350  CU_ASSERT_NOT_EQUAL(result, 0);
351 
352  /* on bottom border */
353  boundary = 0;
354  p.x = 1.0;
355  p.y = 0.0;
356  result = rect_tree_contains_point(tree, &p, &boundary);
357  CU_ASSERT_EQUAL(boundary, 1);
358 
359  /* on top border */
360  boundary = 0;
361  p.x = 3.0;
362  p.y = 6.0;
363  result = rect_tree_contains_point(tree, &p, &boundary);
364  CU_ASSERT_EQUAL(boundary, 1);
365 
366  /* on tooth concave */
367  boundary = 0;
368  p.x = 3.0;
369  p.y = 1.0;
370  result = rect_tree_contains_point(tree, &p, &boundary);
371  CU_ASSERT_EQUAL(boundary, 1);
372 
373  /* on tooth convex */
374  boundary = 0;
375  p.x = 0.0;
376  p.y = 2.0;
377  result = rect_tree_contains_point(tree, &p, &boundary);
378  CU_ASSERT_EQUAL(boundary, 1);
379 
380  /* on tooth convex */
381  boundary = 0;
382  p.x = 0.0;
383  p.y = 6.0;
384  result = rect_tree_contains_point(tree, &p, &boundary);
385  CU_ASSERT_EQUAL(boundary, 1);
386 
387  rect_tree_free(tree);
388  lwpoly_free(poly);
389 
390 }
391 
393 {
394  LWPOLY *poly1, *poly2;
395  RECT_NODE *tree1, *tree2;
396  int result;
397 
398  /* total overlap, A == B */
399  poly1 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
400  poly2 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
401  tree1 = rect_tree_new(poly1->rings[0]);
402  tree2 = rect_tree_new(poly2->rings[0]);
403  result = rect_tree_intersects_tree(tree1, tree2);
404  CU_ASSERT_EQUAL(result, LW_TRUE);
405  lwpoly_free(poly1);
406  lwpoly_free(poly2);
407  rect_tree_free(tree1);
408  rect_tree_free(tree2);
409 
410  /* hiding between the tines of the comb */
411  poly1 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
412  poly2 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0.3 0.7, 0.3 0.8, 0.4 0.8, 0.4 0.7, 0.3 0.7))", LW_PARSER_CHECK_NONE);
413  tree1 = rect_tree_new(poly1->rings[0]);
414  tree2 = rect_tree_new(poly2->rings[0]);
415  result = rect_tree_intersects_tree(tree1, tree2);
416  CU_ASSERT_EQUAL(result, LW_FALSE);
417  lwpoly_free(poly1);
418  lwpoly_free(poly2);
419  rect_tree_free(tree1);
420  rect_tree_free(tree2);
421 
422  /* between the tines, but with a corner overlapping */
423  poly1 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
424  poly2 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0.3 0.7, 0.3 0.8, 0.4 0.8, 1.3 0.3, 0.3 0.7))", LW_PARSER_CHECK_NONE);
425  tree1 = rect_tree_new(poly1->rings[0]);
426  tree2 = rect_tree_new(poly2->rings[0]);
427  result = rect_tree_intersects_tree(tree1, tree2);
428  CU_ASSERT_EQUAL(result, LW_TRUE);
429  lwpoly_free(poly1);
430  lwpoly_free(poly2);
431  rect_tree_free(tree1);
432  rect_tree_free(tree2);
433 
434  /* Just touching the top left corner of the comb */
435  poly1 = (LWPOLY*)lwgeom_from_wkt("POLYGON((0 0, 3 1, 0 2, 3 3, 0 4, 3 5, 0 6, 5 6, 5 0, 0 0))", LW_PARSER_CHECK_NONE);
436  poly2 = (LWPOLY*)lwgeom_from_wkt("POLYGON((-1 5, 0 5, 0 7, -1 7, -1 5))", LW_PARSER_CHECK_NONE);
437  tree1 = rect_tree_new(poly1->rings[0]);
438  tree2 = rect_tree_new(poly2->rings[0]);
439  result = rect_tree_intersects_tree(tree1, tree2);
440  CU_ASSERT_EQUAL(result, LW_TRUE);
441  lwpoly_free(poly1);
442  lwpoly_free(poly2);
443  rect_tree_free(tree1);
444  rect_tree_free(tree2);
445 
446 
447 }
448 
449 static void
451 {
452  LWGEOM *linein = lwgeom_from_wkt("LINESTRING(0 0,10 0)", LW_PARSER_CHECK_NONE);
453  LWGEOM *lineout = lwgeom_segmentize2d(linein, 5);
454  char *strout = lwgeom_to_ewkt(lineout);
455  CU_ASSERT_STRING_EQUAL(strout, "LINESTRING(0 0,5 0,10 0)");
456  lwfree(strout);
457  lwgeom_free(linein);
458  lwgeom_free(lineout);
459 
460  /* test interruption */
461 
462  linein = lwgeom_from_wkt("LINESTRING(0 0,10 0)", LW_PARSER_CHECK_NONE);
464  lineout = lwgeom_segmentize2d(linein, 1e-100);
465  CU_ASSERT_EQUAL(lineout, NULL);
466  lwgeom_free(linein);
467 
468  linein = lwgeom_from_wkt("MULTILINESTRING((0 0,10 0),(20 0, 30 0))", LW_PARSER_CHECK_NONE);
470  lineout = lwgeom_segmentize2d(linein, 1e-100);
471  CU_ASSERT_EQUAL(lineout, NULL);
472  lwgeom_free(linein);
473 
474  linein = lwgeom_from_wkt(
475  "MULTIPOLYGON(((0 0,20 0,20 20,0 20,0 0),(2 2,2 4,4 4,4 2,2 2),(6 6,6 8,8 8,8 6,6 6)),((40 0,40 20,60 20,60 0,40 0),(42 2,42 4,44 4,44 2,42 2)))"
478  lineout = lwgeom_segmentize2d(linein, 1e-100);
479  CU_ASSERT_EQUAL(lineout, NULL);
480  lwgeom_free(linein);
481 
482  linein = lwgeom_from_wkt(
483  "GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,20 0,20 20,0 20,0 0),(2 2,2 4,4 4,4 2,2 2),(6 6,6 8,8 8,8 6,6 6)),((40 0,40 20,60 20,60 0,40 0),(42 2,42 4,44 4,44 2,42 2))),MULTILINESTRING((0 0,10 0),(20 0, 30 0)),MULTIPOINT(0 0, 3 4))"
485  CU_ASSERT_FATAL(linein != NULL);
487  lineout = lwgeom_segmentize2d(linein, 1e-100);
488  CU_ASSERT_EQUAL(lineout, NULL);
489  lwgeom_free(linein);
490 
491  linein = lwgeom_from_wkt("LINESTRING(20 0, 30 0)", LW_PARSER_CHECK_NONE);
492  /* NOT INTERRUPTED */
493  lineout = lwgeom_segmentize2d(linein, 5);
494  strout = lwgeom_to_ewkt(lineout);
495  CU_ASSERT_STRING_EQUAL(strout, "LINESTRING(20 0,25 0,30 0)");
496  lwfree(strout);
497  lwgeom_free(linein);
498  lwgeom_free(lineout);
499 }
500 
501 static void
503 {
504  LWGEOM *geom = NULL;
505  LWGEOM *out = NULL;
506  double measure = 105.0;
507  char *str;
508 
509  /* ST_Locatealong(ST_GeomFromText('MULTILINESTRING M ((1 2 3, 5 4 5), (50 50 1, 60 60 200))'), 105) */
510  geom = lwgeom_from_wkt("MULTILINESTRING M ((1 2 3, 5 4 5), (50 50 1, 60 60 200))", LW_PARSER_CHECK_NONE);
511  out = lwgeom_locate_along(geom, measure, 0.0);
512  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
513  lwgeom_free(geom);
514  lwgeom_free(out);
515  CU_ASSERT_STRING_EQUAL("MULTIPOINT M (55.226131 55.226131 105)", str);
516  lwfree(str);
517 
518  /* ST_Locatealong(ST_GeomFromText('MULTILINESTRING M ((1 2 3, 5 4 5), (50 50 1, 60 60 200))'), 105) */
519  geom = lwgeom_from_wkt("MULTILINESTRING M ((1 2 3, 3 4 2, 9 4 3), (1 2 3, 5 4 5), (50 50 1, 60 60 200))", LW_PARSER_CHECK_NONE);
520  out = lwgeom_locate_along(geom, measure, 0.0);
521  str = lwgeom_to_wkt(out, WKT_ISO, 8, NULL);
522  lwgeom_free(geom);
523  lwgeom_free(out);
524  CU_ASSERT_STRING_EQUAL("MULTIPOINT M (55.226131 55.226131 105)", str);
525  lwfree(str);
526 }
527 
528 static void
530 {
531  /* int lw_dist2d_pt_arc(const POINT2D* P, const POINT2D* A1, const POINT2D* A2, const POINT2D* A3, DISTPTS* dl) */
532  DISTPTS dl;
533  POINT2D P, A1, A2, A3;
534  int rv;
535 
536 
537  /* Point within unit semicircle, 0.5 units from arc */
538  A1.x = -1; A1.y = 0;
539  A2.x = 0 ; A2.y = 1;
540  A3.x = 1 ; A3.y = 0;
541  P.x = 0 ; P.y = 0.5;
542 
544  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
545  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
546  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
547 
548  /* Point outside unit semicircle, 0.5 units from arc */
549  P.x = 0 ; P.y = 1.5;
551  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
552  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
553  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
554 
555  /* Point outside unit semicircle, sqrt(2) units from arc end point*/
556  P.x = 0 ; P.y = -1;
558  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
559  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
560  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0), 0.000001);
561 
562  /* Point outside unit semicircle, sqrt(2)-1 units from arc end point*/
563  P.x = 1 ; P.y = 1;
565  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
566  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
567  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0)-1, 0.000001);
568 
569  /* Point on unit semicircle midpoint */
570  P.x = 0 ; P.y = 1;
572  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
573  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
574  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0, 0.000001);
575 
576  /* Point on unit semicircle endpoint */
577  P.x = 1 ; P.y = 0;
579  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
580  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
581  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0, 0.000001);
582 
583  /* Point on semicircle center */
584  P.x = 0 ; P.y = 0;
586  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
587  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
588  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
589 
590  /* Point inside closed circle */
591  P.x = 0 ; P.y = 0.5;
592  A2.x = 1; A2.y = 0;
593  A3 = A1;
595  rv = lw_dist2d_pt_arc(&P, &A1, &A2, &A3, &dl);
596  //printf("distance %g\n", dl.distance);
597  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
598  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
599 }
600 
601 static void
603 {
604  /* int lw_dist2d_seg_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, DISTPTS *dl) */
605 
606  DISTPTS dl;
607  POINT2D A1, A2, B1, B2, B3;
608  int rv;
609 
610  /* Unit semicircle */
611  B1.x = -1; B1.y = 0;
612  B2.x = 0 ; B2.y = 1;
613  B3.x = 1 ; B3.y = 0;
614 
615  /* Edge above the unit semicircle */
617  A1.x = -2; A1.y = 2;
618  A2.x = 2 ; A2.y = 2;
619  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
620  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
621  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
622 
623  /* Edge to the right of the unit semicircle */
625  A1.x = 2; A1.y = -2;
626  A2.x = 2; A2.y = 2;
627  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
628  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
629  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
630 
631  /* Edge to the left of the unit semicircle */
633  A1.x = -2; A1.y = -2;
634  A2.x = -2; A2.y = 2;
635  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
636  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
637  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
638 
639  /* Edge within the unit semicircle */
641  A1.x = 0; A1.y = 0;
642  A2.x = 0; A2.y = 0.5;
643  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
644  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
645  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
646 
647  /* Edge grazing the unit semicircle */
649  A1.x = -2; A1.y = 1;
650  A2.x = 2; A2.y = 1;
651  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
652  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
653  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0., 0.000001);
654 
655  /* Line grazing the unit semicircle, but edge not */
657  A1.x = 1; A1.y = 1;
658  A2.x = 2; A2.y = 1;
659  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
660  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
661  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0)-1, 0.000001);
662 
663  /* Edge intersecting the unit semicircle */
665  A1.x = 0; A1.y = 0;
666  A2.x = 2; A2.y = 2;
667  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
668  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
669  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0, 0.000001);
670 
671  /* Line intersecting the unit semicircle, but edge not */
673  A1.x = -1; A1.y = 1;
674  A2.x = -2; A2.y = 2;
675  rv = lw_dist2d_seg_arc(&A1, &A2, &B1, &B2, &B3, &dl);
676  //printf("distance %g\n", dl.distance);
677  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
678  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0)-1, 0.000001);
679 }
680 
681 static void
683 {
684  /* lw_dist2d_arc_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3,
685  const POINT2D *B1, const POINT2D *B2, const POINT2D *B3,
686  DISTPTS *dl) */
687  DISTPTS dl;
688  POINT2D A1, A2, A3, B1, B2, B3;
689  int rv;
690 
691  /* Ticket #4326 */
693  A1.x = -1.0; A1.y = 4.0;
694  A2.x = 0.0; A2.y = 5.0;
695  A3.x = 1.0; A3.y = 4.0;
696  B1.x = 1.0; B1.y = 6.0;
697  B2.x = 6.0; B2.y = 1.0;
698  B3.x = 9.0; B3.y = 7.0;
699  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
700  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
701  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.0475666, 0.000001);
702 
703  /* Unit semicircle at 0,0 */
704  B1.x = -1; B1.y = 0;
705  B2.x = 0 ; B2.y = 1;
706  B3.x = 1 ; B3.y = 0;
707 
708  /* Arc above the unit semicircle */
710  A1.x = -1; A1.y = 3;
711  A2.x = 0 ; A2.y = 2;
712  A3.x = 1 ; A3.y = 3;
713  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
714  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
715  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
716 
717  /* Arc grazes the unit semicircle */
719  A1.x = -1; A1.y = 2;
720  A2.x = 0 ; A2.y = 1;
721  A3.x = 1 ; A3.y = 2;
722  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
723  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
724  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0, 0.000001);
725 
726  /* Circles intersect, but arcs do not */
728  A1.x = -1; A1.y = 1;
729  A2.x = 0; A2.y = 2;
730  A3.x = 1; A3.y = 1;
731  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
732  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
733  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2)-1, 0.000001);
734 
735  /* Circles and arcs intersect */
737  A1.x = -1; A1.y = 1;
738  A2.x = 0; A2.y = 0;
739  A3.x = 1; A3.y = 1;
740  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
741  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
742  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0, 0.000001);
743 
744  /* Concentric: and fully parallel */
746  A1.x = -2.0; A1.y = 0.0;
747  A2.x = 0.0; A2.y = 2.0;
748  A3.x = 2.0; A3.y = 0.0;
749  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
750  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
751  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
752 
753  /* Concentric: with A fully included in B's range */
755  A1.x = -0.5 / sqrt(2.0); A1.y = 0.5 / sqrt(2.0);
756  A2.x = 0.0; A2.y = 0.5;
757  A3.x = 0.5 / sqrt(2.0); A3.y = 0.5 / sqrt(2.0);
758  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
759  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
760  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
761 
762  /* Concentric: with A partially included in B's range */
764  A1.x = -0.5 / sqrt(2.0); A1.y = -0.5 / sqrt(2.0);
765  A2.x = -0.5; A2.y = 0.0;
766  A3.x = -0.5 / sqrt(2.0); A3.y = 0.5 / sqrt(2.0);
767  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
768  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
769  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
770 
771  /* Concentric: with A and B without parallel segments */
773  A1.x = -0.5 / sqrt(2.0); A1.y = -0.5 / sqrt(2.0);
774  A2.x = 0.0; A2.y = -0.5;
775  A3.x = 0.5 / sqrt(2.0); A3.y = -0.5 / sqrt(2.0);
776  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
777  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
778  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.736813, 0.000001);
779 
780  /* Concentric: Arcs are the same */
782  A1.x = -1.0; A1.y = 0.0;
783  A2.x = 0.0; A2.y = 1.0;
784  A3.x = 1.0; A3.y = 0.0;
785  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
786  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
787  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.0, 0.000001);
788 
789  /* Check different orientations */
790  B1.x = -10.0; B1.y = 0.0;
791  B2.x = 0.0 ; B2.y = 10.0;
792  B3.x = 10.0 ; B3.y = 0.0;
793 
795  A1.x = -22.0; A1.y = 0.0;
796  A2.x = -17.0; A2.y = -5.0;
797  A3.x = -12.0; A3.y = 0.0;
798  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
799  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
800  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 2.0, 0.000001);
801 
803  A1.x = -19.0; A1.y = 0.0;
804  A2.x = -14.0; A2.y = -5.0;
805  A3.x = - 9.0; A3.y = 0.0;
806  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
807  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
808  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
809 
811  A1.x = -9.0; A1.y = 0.0;
812  A2.x = -4.0; A2.y = -5.0;
813  A3.x = 1.0; A3.y = 0.0;
814  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
815  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
816  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
817 
819  A1.x = -1.0; A1.y = 0.0;
820  A2.x = 4.0; A2.y = -5.0;
821  A3.x = 9.0; A3.y = 0.0;
822  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
823  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
824  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
825 
827  A1.x = 1.0; A1.y = 0.0;
828  A2.x = 6.0; A2.y = -5.0;
829  A3.x = 11.0; A3.y = 0.0;
830  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
831  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
832  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
833 
835  A1.x = 11.0; A1.y = 0.0;
836  A2.x = 16.0; A2.y = -5.0;
837  A3.x = 21.0; A3.y = 0.0;
838  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
839  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
840  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
841 
842 
844  A1.x = -15.0; A1.y = -6.0;
845  A2.x = -10.0; A2.y = -1.0;
846  A3.x = - 5.0; A3.y = -6.0;
847  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
848  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
849  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1.0, 0.000001);
850 
852  A1.x = -5.0; A1.y = 0.0;
853  A2.x = 0.0; A2.y = 5.0;
854  A3.x = 5.0; A3.y = 0.0;
855  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
856  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
857  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 5.0, 0.000001);
858 
860  A1.x = -5.0; A1.y = 0.0;
861  A2.x = 0.0; A2.y = -5.0;
862  A3.x = 5.0; A3.y = 0.0;
863  rv = lw_dist2d_arc_arc(&A1, &A2, &A3, &B1, &B2, &B3, &dl);
864  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
865  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 5.0, 0.000001);
866 
867 }
868 
869 static void
871 {
872 /* double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3) */
873 
874  POINT2D A1, A2, A3;
875  double d;
876 
877  /* Unit semicircle at 0,0 */
878  A1.x = -1; A1.y = 0;
879  A2.x = 0 ; A2.y = 1;
880  A3.x = 1 ; A3.y = 0;
881 
882  /* Arc above the unit semicircle */
883  d = lw_arc_length(&A1, &A2, &A3);
884  CU_ASSERT_DOUBLE_EQUAL(d, M_PI, 0.000001);
885  d = lw_arc_length(&A3, &A2, &A1);
886  CU_ASSERT_DOUBLE_EQUAL(d, M_PI, 0.000001);
887 
888  /* Unit semicircle at 0,0 */
889  A1.x = 0; A1.y = 1;
890  A2.x = 1; A2.y = 0;
891  A3.x = 0; A3.y = -1;
892 
893  /* Arc to right of the unit semicircle */
894  d = lw_arc_length(&A1, &A2, &A3);
895  CU_ASSERT_DOUBLE_EQUAL(d, M_PI, 0.000001);
896  d = lw_arc_length(&A3, &A2, &A1);
897  CU_ASSERT_DOUBLE_EQUAL(d, M_PI, 0.000001);
898 
899  /* Unit 3/4 circle at 0,0 */
900  A1.x = -1; A1.y = 0;
901  A2.x = 1; A2.y = 0;
902  A3.x = 0; A3.y = -1;
903 
904  /* Arc to right of the unit semicircle */
905  d = lw_arc_length(&A1, &A2, &A3);
906  CU_ASSERT_DOUBLE_EQUAL(d, 3*M_PI_2, 0.000001);
907  d = lw_arc_length(&A3, &A2, &A1);
908  CU_ASSERT_DOUBLE_EQUAL(d, 3*M_PI_2, 0.000001);
909 }
910 
911 static void
913 {
914  /* lw_dist2d_pt_ptarrayarc(const POINT2D *p, const POINTARRAY *pa, DISTPTS *dl) */
915  DISTPTS dl;
916  int rv;
917  LWLINE *lwline;
918  POINT2D P;
919 
920  /* Unit semi-circle above X axis */
921  lwline = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0)"));
922 
923  /* Point at origin */
924  P.x = P.y = 0;
926  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
927  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
928  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
929 
930  /* Point above arc on Y axis */
931  P.y = 2;
933  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
934  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
935  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
936 
937  /* Point 45 degrees off arc, 2 radii from center */
938  P.y = P.x = 2 * cos(M_PI_4);
940  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
941  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
942  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
943 
944  /* Four unit semi-circles surrounding the 2x2 box around origin */
945  lwline_free(lwline);
946  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)"));
947 
948  /* Point at origin */
949  P.x = P.y = 0;
951  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
952  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
953  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0), 0.000001);
954 
955  /* Point on box edge */
956  P.x = -1; P.y = 0;
958  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
959  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
960  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
961 
962  /* Point within a semicircle lobe */
963  P.x = -1.5; P.y = 0;
965  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
966  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
967  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
968 
969  /* Point outside a semicircle lobe */
970  P.x = -2.5; P.y = 0;
972  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
973  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
974  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
975 
976  /* Point outside a semicircle lobe */
977  P.y = -2.5; P.x = 0;
979  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
980  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
981  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
982 
983  /* Point outside a semicircle lobe */
984  P.y = 2; P.x = 1;
986  rv = lw_dist2d_pt_ptarrayarc(&P, lwline->points, &dl);
987  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
988  CU_ASSERT_DOUBLE_EQUAL(dl.distance, sqrt(2.0)-1.0, 0.000001);
989 
990  /* Clean up */
991  lwline_free(lwline);
992 }
993 
994 static void
996 {
997  /* int lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl) */
998  DISTPTS dl;
999  int rv;
1000  LWLINE *lwline1;
1001  LWLINE *lwline2;
1002 
1003  /* Unit semi-circle above X axis */
1004  lwline1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0)"));
1005 
1006  /* Line above top of semi-circle */
1007  lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2 2, -1 2, 1 2, 2 2)"));
1009  rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl);
1010  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
1011  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
1012 
1013  /* Reversed arguments, should fail */
1016  rv = lw_dist2d_ptarray_ptarrayarc(lwline1->points, lwline2->points, &dl);
1017  //printf("%s\n", cu_error_msg);
1018  CU_ASSERT_EQUAL( rv, LW_FAILURE );
1019  CU_ASSERT_STRING_EQUAL("lw_dist2d_ptarray_ptarrayarc called with non-arc input", cu_error_msg);
1020 
1021  lwline_free(lwline2);
1022 
1023  /* Line along side of semi-circle */
1024  lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2 -3, -2 -2, -2 2, -2 3)"));
1026  rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl);
1027  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
1028  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001);
1029 
1030  /* Four unit semi-circles surrounding the 2x2 box around origin */
1031  lwline_free(lwline1);
1032  lwline_free(lwline2);
1033  lwline1 = 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)"));
1034  lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2.5 -3, -2.5 -2, -2.5 2, -2.5 3)"));
1035  rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl);
1036  CU_ASSERT_EQUAL( rv, LW_SUCCESS );
1037  CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001);
1038 
1039  lwline_free(lwline2);
1040  lwline_free(lwline1);
1041 }
1042 
1043 static void
1045 {
1046  LWGEOM *g1, *g2;
1047  double m, dist;
1048 
1049  /* Invalid input, lack of dimensions */
1050 
1051  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1052  g2 = lwgeom_from_wkt("LINESTRING (0 0 2, 0 0 5)", LW_PARSER_CHECK_NONE);
1053  m = lwgeom_tcpa(g1, g2, NULL);
1054  lwgeom_free(g1);
1055  lwgeom_free(g2);
1056  ASSERT_DOUBLE_EQUAL(m, -1.0);
1057  CU_ASSERT_STRING_EQUAL(
1058  "Both input geometries must have a measure dimension",
1059  cu_error_msg
1060  );
1061 
1062  /* Invalid input, not linestrings */
1063 
1064  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1065  g2 = lwgeom_from_wkt("POINT M (0 0 2)", LW_PARSER_CHECK_NONE);
1066  m = lwgeom_tcpa(g1, g2, NULL);
1067  lwgeom_free(g1);
1068  lwgeom_free(g2);
1069  ASSERT_DOUBLE_EQUAL(m, -1.0);
1070  CU_ASSERT_STRING_EQUAL(
1071  "Both input geometries must be linestrings",
1072  cu_error_msg
1073  );
1074 
1075  /* Invalid input, too short linestring */
1076 
1077  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 10 0 10)", LW_PARSER_CHECK_NONE);
1078  g2 = lwgeom_from_wkt("LINESTRING M(2 0 1)", LW_PARSER_CHECK_NONE);
1079  dist = -77;
1080  m = lwgeom_tcpa(g1, g2, &dist);
1081  lwgeom_free(g1);
1082  lwgeom_free(g2);
1083  ASSERT_DOUBLE_EQUAL(dist, -77.0); /* not touched */
1084  ASSERT_DOUBLE_EQUAL(m, -1.0);
1085  CU_ASSERT_STRING_EQUAL(
1086  "Both input lines must have at least 2 points", /* should be accepted ? */
1087  cu_error_msg
1088  );
1089 
1090  /* Invalid input, empty linestring */
1091 
1092  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 10 0 10)", LW_PARSER_CHECK_NONE);
1093  g2 = lwgeom_from_wkt("LINESTRING M EMPTY", LW_PARSER_CHECK_NONE);
1094  m = lwgeom_tcpa(g1, g2, NULL);
1095  lwgeom_free(g1);
1096  lwgeom_free(g2);
1097  ASSERT_DOUBLE_EQUAL(m, -1.0);
1098  CU_ASSERT_STRING_EQUAL(
1099  "Both input lines must have at least 2 points",
1100  cu_error_msg
1101  );
1102 
1103  /* Timeranges do not overlap */
1104 
1105  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1106  g2 = lwgeom_from_wkt("LINESTRING M(0 0 2, 0 0 5)", LW_PARSER_CHECK_NONE);
1107  m = lwgeom_tcpa(g1, g2, NULL);
1108  lwgeom_free(g1);
1109  lwgeom_free(g2);
1110  ASSERT_DOUBLE_EQUAL(m, -2.0); /* means timeranges do not overlap */
1111 
1112  /* One of the tracks is still, the other passes to that point */
1113 
1114  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1115  g2 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 5)", LW_PARSER_CHECK_NONE);
1116  dist = -1;
1117  m = lwgeom_tcpa(g1, g2, &dist);
1118  ASSERT_DOUBLE_EQUAL(m, 1.0);
1119  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1120  CU_ASSERT( lwgeom_cpa_within(g1, g2, 0.0) == LW_TRUE );
1121  lwgeom_free(g1);
1122  lwgeom_free(g2);
1123 
1124  /* One of the tracks is still, the other passes at 10 meters from point */
1125 
1126  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 5)", LW_PARSER_CHECK_NONE);
1127  g2 = lwgeom_from_wkt("LINESTRING M(-10 10 1, 10 10 5)", LW_PARSER_CHECK_NONE);
1128  dist = -1;
1129  m = lwgeom_tcpa(g1, g2, &dist);
1130  ASSERT_DOUBLE_EQUAL(m, 3.0);
1131  ASSERT_DOUBLE_EQUAL(dist, 10.0);
1132  CU_ASSERT( lwgeom_cpa_within(g1, g2, 11.0) == LW_TRUE );
1133  CU_ASSERT( lwgeom_cpa_within(g1, g2, 10.0) == LW_TRUE );
1134  CU_ASSERT( lwgeom_cpa_within(g1, g2, 9.0) == LW_FALSE );
1135  lwgeom_free(g1);
1136  lwgeom_free(g2);
1137 
1138  /* Equal tracks, 2d */
1139 
1140  g1 = lwgeom_from_wkt("LINESTRING M(0 0 10, 10 0 20)", LW_PARSER_CHECK_NONE);
1141  g2 = lwgeom_from_wkt("LINESTRING M(0 0 10, 10 0 20)", LW_PARSER_CHECK_NONE);
1142  dist = -1;
1143  m = lwgeom_tcpa(g1, g2, &dist);
1144  lwgeom_free(g1);
1145  lwgeom_free(g2);
1146  ASSERT_DOUBLE_EQUAL(m, 10.0);
1147  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1148 
1149  /* Reversed tracks, 2d */
1150 
1151  g1 = lwgeom_from_wkt("LINESTRING M(0 0 10, 10 0 20)", LW_PARSER_CHECK_NONE);
1152  g2 = lwgeom_from_wkt("LINESTRING M(10 0 10, 0 0 20)", LW_PARSER_CHECK_NONE);
1153  dist = -1;
1154  m = lwgeom_tcpa(g1, g2, &dist);
1155  lwgeom_free(g1);
1156  lwgeom_free(g2);
1157  ASSERT_DOUBLE_EQUAL(m, 15.0);
1158  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1159 
1160  /* Parallel tracks, same speed, 2d */
1161 
1162  g1 = lwgeom_from_wkt("LINESTRING M(2 0 10, 12 0 20)", LW_PARSER_CHECK_NONE);
1163  g2 = lwgeom_from_wkt("LINESTRING M(13 0 10, 23 0 20)", LW_PARSER_CHECK_NONE);
1164  dist = -1;
1165  m = lwgeom_tcpa(g1, g2, &dist);
1166  lwgeom_free(g1);
1167  lwgeom_free(g2);
1168  ASSERT_DOUBLE_EQUAL(m, 10.0);
1169  ASSERT_DOUBLE_EQUAL(dist, 11.0);
1170 
1171  /* Parallel tracks, different speed (g2 gets closer as time passes), 2d */
1172 
1173  g1 = lwgeom_from_wkt("LINESTRING M(4 0 10, 10 0 20)", LW_PARSER_CHECK_NONE);
1174  g2 = lwgeom_from_wkt("LINESTRING M(2 0 10, 9 0 20)", LW_PARSER_CHECK_NONE);
1175  dist = -1;
1176  m = lwgeom_tcpa(g1, g2, &dist);
1177  lwgeom_free(g1);
1178  lwgeom_free(g2);
1179  ASSERT_DOUBLE_EQUAL(m, 20.0);
1180  ASSERT_DOUBLE_EQUAL(dist, 1.0);
1181 
1182  /* Parallel tracks, different speed (g2 left behind as time passes), 2d */
1183 
1184  g1 = lwgeom_from_wkt("LINESTRING M(4 0 10, 10 0 20)", LW_PARSER_CHECK_NONE);
1185  g2 = lwgeom_from_wkt("LINESTRING M(2 0 10, 6 0 20)", LW_PARSER_CHECK_NONE);
1186  dist = -1;
1187  m = lwgeom_tcpa(g1, g2, &dist);
1188  lwgeom_free(g1);
1189  lwgeom_free(g2);
1190  ASSERT_DOUBLE_EQUAL(m, 10.0);
1191  ASSERT_DOUBLE_EQUAL(dist, 2.0);
1192 
1193  /* Tracks, colliding, 2d */
1194 
1195  g1 = lwgeom_from_wkt("LINESTRING M(0 0 0, 10 0 10)", LW_PARSER_CHECK_NONE);
1196  g2 = lwgeom_from_wkt("LINESTRING M(5 -8 0, 5 8 10)", LW_PARSER_CHECK_NONE);
1197  dist = -1;
1198  m = lwgeom_tcpa(g1, g2, &dist);
1199  lwgeom_free(g1);
1200  lwgeom_free(g2);
1201  ASSERT_DOUBLE_EQUAL(m, 5.0);
1202  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1203 
1204  /* Tracks crossing, NOT colliding, 2d */
1205 
1206  g1 = lwgeom_from_wkt("LINESTRING M(0 0 0, 10 0 10)", LW_PARSER_CHECK_NONE);
1207  g2 = lwgeom_from_wkt("LINESTRING M(8 -5 0, 8 5 10)", LW_PARSER_CHECK_NONE);
1208  dist = -1;
1209  m = lwgeom_tcpa(g1, g2, &dist);
1210  lwgeom_free(g1);
1211  lwgeom_free(g2);
1212  ASSERT_DOUBLE_EQUAL(m, 6.5);
1213  ASSERT_DOUBLE_EQUAL(rint(dist*100), 212.0);
1214 
1215  /* Same origin, different direction, 2d */
1216 
1217  g1 = lwgeom_from_wkt("LINESTRING M(0 0 1, 10 0 10)", LW_PARSER_CHECK_NONE);
1218  g2 = lwgeom_from_wkt("LINESTRING M(0 0 1, -100 0 10)", LW_PARSER_CHECK_NONE);
1219  dist = -1;
1220  m = lwgeom_tcpa(g1, g2, &dist);
1221  lwgeom_free(g1);
1222  lwgeom_free(g2);
1223  ASSERT_DOUBLE_EQUAL(m, 1.0);
1224  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1225 
1226  /* Same ending, different direction, 2d */
1227 
1228  g1 = lwgeom_from_wkt("LINESTRING M(10 0 1, 0 0 10)", LW_PARSER_CHECK_NONE);
1229  g2 = lwgeom_from_wkt("LINESTRING M(0 -100 1, 0 0 10)", LW_PARSER_CHECK_NONE);
1230  dist = -1;
1231  m = lwgeom_tcpa(g1, g2, &dist);
1232  lwgeom_free(g1);
1233  lwgeom_free(g2);
1234  ASSERT_DOUBLE_EQUAL(m, 10.0);
1235  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1236 
1237  /* Converging tracks, 3d */
1238 
1239  g1 = lwgeom_from_wkt("LINESTRING ZM(0 0 0 10, 10 0 0 20)", LW_PARSER_CHECK_NONE);
1240  g2 = lwgeom_from_wkt("LINESTRING ZM(0 0 8 10, 10 0 5 20)", LW_PARSER_CHECK_NONE);
1241  dist = -1;
1242  m = lwgeom_tcpa(g1, g2, &dist);
1243  lwgeom_free(g1);
1244  lwgeom_free(g2);
1245  ASSERT_DOUBLE_EQUAL(m, 20.0);
1246  ASSERT_DOUBLE_EQUAL(dist, 5.0);
1247 
1248  /* G1 stops at t=1 until t=4 to let G2 pass by, then continues */
1249  /* G2 passes at 1 meter from G1 t=3 */
1250 
1251  g1 = lwgeom_from_wkt("LINESTRING M(0 0 0, 0 1 1, 0 1 4, 0 10 13)", LW_PARSER_CHECK_NONE);
1252  g2 = lwgeom_from_wkt("LINESTRING M(-10 2 0, 0 2 3, 12 2 13)", LW_PARSER_CHECK_NONE);
1253  dist = -1;
1254  m = lwgeom_tcpa(g1, g2, &dist);
1255  lwgeom_free(g1);
1256  lwgeom_free(g2);
1257  ASSERT_DOUBLE_EQUAL(m, 3.0);
1258  ASSERT_DOUBLE_EQUAL(dist, 1.0);
1259 
1260  /* Test for https://trac.osgeo.org/postgis/ticket/3136 */
1261 
1262  g1 = lwgeom_from_wkt("LINESTRING M (0 0 1432291464,2 0 1432291536) ", LW_PARSER_CHECK_NONE);
1263  g2 = lwgeom_from_wkt("LINESTRING M (0 0 1432291464,1 0 1432291466.25,2 0 1432291500)", LW_PARSER_CHECK_NONE);
1264  dist = -1;
1265  m = lwgeom_tcpa(g1, g2, &dist);
1266  lwgeom_free(g1);
1267  lwgeom_free(g2);
1268  ASSERT_DOUBLE_EQUAL(m, 1432291464.0);
1269  ASSERT_DOUBLE_EQUAL(dist, 0.0);
1270 
1271  /* Tracks share a single point in time */
1272 
1273  g1 = lwgeom_from_wkt("LINESTRINGM(0 0 0, 1 0 2)", LW_PARSER_CHECK_NONE);
1274  g2 = lwgeom_from_wkt("LINESTRINGM(0 0 2, 1 0 3)", LW_PARSER_CHECK_NONE);
1275  dist = -1;
1276  m = lwgeom_tcpa(g1, g2, &dist);
1277  lwgeom_free(g1);
1278  lwgeom_free(g2);
1279  ASSERT_DOUBLE_EQUAL(m, 2.0);
1280  ASSERT_DOUBLE_EQUAL(dist, 1.0);
1281 
1282 }
1283 
1284 static void
1286 {
1287  LWGEOM *g;
1288  int ret;
1289 
1290  g = lwgeom_from_wkt("POINT M(0 0 1)", LW_PARSER_CHECK_NONE);
1291  ret = lwgeom_is_trajectory(g);
1292  lwgeom_free(g);
1293  ASSERT_INT_EQUAL(ret, LW_FALSE); /* not a linestring */
1294 
1295  g = lwgeom_from_wkt("LINESTRING Z(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1296  ret = lwgeom_is_trajectory(g);
1297  lwgeom_free(g);
1298  ASSERT_INT_EQUAL(ret, LW_FALSE); /* no measure */
1299 
1300  g = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 1)", LW_PARSER_CHECK_NONE);
1301  ret = lwgeom_is_trajectory(g);
1302  lwgeom_free(g);
1303  ASSERT_INT_EQUAL(ret, LW_FALSE); /* same measure in two points */
1304 
1305  g = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 0)", LW_PARSER_CHECK_NONE);
1306  ret = lwgeom_is_trajectory(g);
1307  lwgeom_free(g);
1308  ASSERT_INT_EQUAL(ret, LW_FALSE); /* backward measure */
1309 
1310  g = lwgeom_from_wkt("LINESTRING M(0 0 1, 1 0 3, 2 2 2)", LW_PARSER_CHECK_NONE);
1311  ret = lwgeom_is_trajectory(g);
1312  lwgeom_free(g);
1313  ASSERT_INT_EQUAL(ret, LW_FALSE); /* backward measure */
1314 
1315  g = lwgeom_from_wkt("LINESTRING M(0 0 1, 0 0 2)", LW_PARSER_CHECK_NONE);
1316  ret = lwgeom_is_trajectory(g);
1317  lwgeom_free(g);
1318  ASSERT_INT_EQUAL(ret, LW_TRUE); /* ok (still) */
1319 
1320  g = lwgeom_from_wkt("LINESTRING M EMPTY", LW_PARSER_CHECK_NONE);
1321  ret = lwgeom_is_trajectory(g);
1322  lwgeom_free(g);
1323  ASSERT_INT_EQUAL(ret, LW_TRUE); /* ok (empty) */
1324 
1325  g = lwgeom_from_wkt("LINESTRING M (0 0 1)", LW_PARSER_CHECK_NONE);
1326  ret = lwgeom_is_trajectory(g);
1327  lwgeom_free(g);
1328  ASSERT_INT_EQUAL(ret, LW_TRUE); /* ok (corner case) */
1329 }
1330 
1331 /*
1332 ** Used by test harness to register the tests in this file.
1333 */
1334 void measures_suite_setup(void);
1336 {
1337  CU_pSuite suite = CU_add_suite("measures", NULL, NULL);
1350  PG_ADD_TEST(suite, test_lwgeom_tcpa);
1352 }
static void test_lw_dist2d_seg_arc(void)
Definition: cu_measures.c:602
#define DIST3DTEST(str1, str2, res)
Definition: cu_measures.c:36
int lwgeom_is_trajectory(const LWGEOM *geom)
Return LW_TRUE or LW_FALSE depending on whether or not a geometry is a linestring with measure value ...
Definition: lwgeom.c:2080
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
Datum boundary(PG_FUNCTION_ARGS)
void lwfree(void *mem)
Definition: lwutil.c:244
char * lwgeom_to_ewkt(const LWGEOM *lwgeom)
Return an alloced string.
Definition: lwgeom.c:518
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
#define LW_SUCCESS
Definition: liblwgeom.h:80
void lwline_free(LWLINE *line)
Definition: lwline.c:76
static void test_mindistance3d_tolerance(void)
Definition: cu_measures.c:207
static LWGEOM * lwgeom_from_text(const char *str)
Definition: cu_measures.c:25
LWGEOM * lwgeom_from_wkt(const char *wkt, const char check)
Definition: lwin_wkt.c:904
void lwgeom_request_interrupt(void)
Request interruption of any running code.
Definition: lwgeom_api.c:698
static void test_lw_dist2d_arc_arc(void)
Definition: cu_measures.c:682
int lw_dist2d_arc_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, DISTPTS *dl)
Definition: measures.c:1493
RECT_NODE * rect_tree_new(const POINTARRAY *pa)
Build a tree of nodes from a point array, one node per edge, and each with an associated measure rang...
Definition: lwtree.c:175
#define LW_FAILURE
Definition: liblwgeom.h:79
static void test_lw_dist2d_pt_arc(void)
Definition: cu_measures.c:529
static void test_lwgeom_segmentize2d(void)
Definition: cu_measures.c:450
static void test_lw_dist2d_pt_ptarrayarc(void)
Definition: cu_measures.c:912
int lwgeom_cpa_within(const LWGEOM *g1, const LWGEOM *g2, double maxdist)
Is the closest point of approach within a distance ?
static void do_test_mindistance_tolerance(char *in1, char *in2, double expected_res, int line, double(*distancef)(const LWGEOM *, const LWGEOM *, double))
Definition: cu_measures.c:40
#define LW_PARSER_CHECK_NONE
Definition: liblwgeom.h:2013
double x
Definition: liblwgeom.h:328
int rect_tree_contains_point(const RECT_NODE *node, const POINT2D *pt, int *on_boundary)
Definition: lwtree.c:58
static void test_lwgeom_tcpa(void)
Definition: cu_measures.c:1044
double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns the length of a circular arc segment.
Definition: lwalgorithm.c:118
#define WKT_ISO
Definition: liblwgeom.h:2083
#define DIST_MIN
Definition: measures.h:44
#define LW_FALSE
Definition: liblwgeom.h:77
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()
#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
int lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl)
Test each segment of pa against each arc of pb for distance.
Definition: measures.c:1183
int lw_dist2d_pt_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, DISTPTS *dl)
Definition: measures.c:1435
#define PG_ADD_TEST(suite, testfunc)
#define ASSERT_INT_EQUAL(o, e)
POINTARRAY ** rings
Definition: liblwgeom.h:457
int lw_dist2d_pt_ptarrayarc(const POINT2D *p, const POINTARRAY *pa, DISTPTS *dl)
Search all the arcs of pointarray to see which one is closest to p1 Returns minimum distance between ...
Definition: measures.c:1079
double y
Definition: liblwgeom.h:328
Datum distance(PG_FUNCTION_ARGS)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:138
static void test_rect_tree_contains_point(void)
Definition: cu_measures.c:242
#define DIST2DTEST(str1, str2, res)
Definition: cu_measures.c:33
void measures_suite_setup(void)
Definition: cu_measures.c:1335
double lwgeom_tcpa(const LWGEOM *g1, const LWGEOM *g2, double *mindist)
Find the time of closest point of approach.
LWGEOM * lwgeom_locate_along(const LWGEOM *lwin, double m, double offset)
Determine the location(s) along a measured line where m occurs and return as a multipoint.
double distance
Definition: measures.h:51
static void test_lwgeom_locate_along(void)
Definition: cu_measures.c:502
LWGEOM * lwgeom_segmentize2d(LWGEOM *line, double dist)
Definition: lwgeom.c:717
int rect_tree_intersects_tree(const RECT_NODE *n1, const RECT_NODE *n2)
Definition: lwtree.c:79
static void test_mindistance2d_tolerance(void)
Definition: cu_measures.c:82
int lw_dist2d_seg_arc(const POINT2D *A1, const POINT2D *A2, const POINT2D *B1, const POINT2D *B2, const POINT2D *B3, DISTPTS *dl)
Calculate the shortest distance between an arc and an edge.
Definition: measures.c:1288
static void test_lw_dist2d_ptarray_ptarrayarc(void)
Definition: cu_measures.c:995
#define ASSERT_DOUBLE_EQUAL(o, e)
void rect_tree_free(RECT_NODE *node)
Recurse from top of node tree and free all children.
Definition: lwtree.c:42
Structure used in distance-calculations.
Definition: measures.h:49
void lw_dist2d_distpts_init(DISTPTS *dl, int mode)
Definition: measures.c:67
char cu_error_msg[MAX_CUNIT_ERROR_LENGTH+1]
static void test_lwgeom_is_trajectory(void)
Definition: cu_measures.c:1285
static void test_rect_tree_intersects_tree(void)
Definition: cu_measures.c:392
static void test_lw_arc_length(void)
Definition: cu_measures.c:870
POINTARRAY * points
Definition: liblwgeom.h:422