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