PostGIS  3.7.0dev-r@@SVN_REVISION@@
measures3d.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2011 Nicklas Avén
22  * Copyright 2019 Darafei Praliaskouski
23  *
24  **********************************************************************/
25 
26 #include <string.h>
27 #include <stdlib.h>
28 
29 #include "measures3d.h"
30 #include "lwrandom.h"
31 #include "lwgeom_log.h"
32 
33 static inline int
35 {
36  v->x = p2->x - p1->x;
37  v->y = p2->y - p1->y;
38  v->z = p2->z - p1->z;
39 
40  return (!FP_IS_ZERO(v->x) || !FP_IS_ZERO(v->y) || !FP_IS_ZERO(v->z));
41 }
42 
43 static inline int
44 get_3dcross_product(const VECTOR3D *v1, const VECTOR3D *v2, VECTOR3D *v)
45 {
46  v->x = (v1->y * v2->z) - (v1->z * v2->y);
47  v->y = (v1->z * v2->x) - (v1->x * v2->z);
48  v->z = (v1->x * v2->y) - (v1->y * v2->x);
49 
50  return (!FP_IS_ZERO(v->x) || !FP_IS_ZERO(v->y) || !FP_IS_ZERO(v->z));
51 }
52 
56 static double
58 {
59  /*In our plane definition we have a point on the plane and a normal vector (pl.pv), perpendicular to the plane
60  this vector will be parallel to the line between our inputted point above the plane and the point we are
61  searching for on the plane. So, we already have a direction from p to find p0, but we don't know the distance.
62  */
63 
64  VECTOR3D v1;
65  double f;
66 
67  if (!get_3dvector_from_points(&(pl->pop), p, &v1))
68  return 0.0;
69 
70  f = DOT(pl->pv, v1);
71  if (FP_IS_ZERO(f))
72  {
73  /* Point is in the plane */
74  *p0 = *p;
75  return 0;
76  }
77 
78  f = -f / DOT(pl->pv, pl->pv);
79 
80  p0->x = p->x + pl->pv.x * f;
81  p0->y = p->y + pl->pv.y * f;
82  p0->z = p->z + pl->pv.z * f;
83 
84  return f;
85 }
86 
92 static LWGEOM *
93 create_v_line(const LWGEOM *lwgeom, double x, double y, int32_t srid)
94 {
95 
96  LWPOINT *lwpoints[2];
97  GBOX gbox;
98  int rv = lwgeom_calculate_gbox(lwgeom, &gbox);
99 
100  if (rv == LW_FAILURE)
101  return NULL;
102 
103  lwpoints[0] = lwpoint_make3dz(srid, x, y, gbox.zmin);
104  lwpoints[1] = lwpoint_make3dz(srid, x, y, gbox.zmax);
105 
106  return (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);
107 }
108 
109 LWGEOM *
110 lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
111 {
112  return lw_dist3d_distanceline(lw1, lw2, lw1->srid, DIST_MIN);
113 }
114 
115 LWGEOM *
117 {
118  return lw_dist3d_distanceline(lw1, lw2, lw1->srid, DIST_MAX);
119 }
120 
121 LWGEOM *
122 lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
123 {
124  return lw_dist3d_distancepoint(lw1, lw2, lw1->srid, DIST_MIN);
125 }
126 
130 LWGEOM *
131 lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
132 {
133  LWDEBUG(2, "lw_dist3d_distanceline is called");
134  double x1, x2, y1, y2, z1, z2, x, y;
135  double initdistance = (mode == DIST_MIN ? DBL_MAX : -1.0);
136  DISTPTS3D thedl;
137  LWPOINT *lwpoints[2];
138  LWGEOM *result;
139 
140  thedl.mode = mode;
141  thedl.distance = initdistance;
142  thedl.tolerance = 0.0;
143 
144  /* Check if we really have 3D geometries
145  * If not, send it to 2D-calculations which will give the same result
146  * as an infinite z-value at one or two of the geometries */
147  if (!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
148  {
149 
150  lwnotice(
151  "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
152 
153  if (!lwgeom_has_z(lw1) && !lwgeom_has_z(lw2))
154  return lw_dist2d_distanceline(lw1, lw2, srid, mode);
155 
156  DISTPTS thedl2d;
157  thedl2d.mode = mode;
158  thedl2d.distance = initdistance;
159  thedl2d.tolerance = 0.0;
160  if (!lw_dist2d_comp(lw1, lw2, &thedl2d))
161  {
162  /* should never get here. all cases ought to be error handled earlier */
163  lwerror("Some unspecified error.");
165  }
166  LWGEOM *vertical_line;
167  if (!lwgeom_has_z(lw1))
168  {
169  x = thedl2d.p1.x;
170  y = thedl2d.p1.y;
171 
172  vertical_line = create_v_line(lw2, x, y, srid);
173  if (!lw_dist3d_recursive(vertical_line, lw2, &thedl))
174  {
175  /* should never get here. all cases ought to be error handled earlier */
176  lwfree(vertical_line);
177  lwerror("Some unspecified error.");
179  }
180  lwfree(vertical_line);
181  }
182  if (!lwgeom_has_z(lw2))
183  {
184  x = thedl2d.p2.x;
185  y = thedl2d.p2.y;
186 
187  vertical_line = create_v_line(lw1, x, y, srid);
188  if (!lw_dist3d_recursive(lw1, vertical_line, &thedl))
189  {
190  /* should never get here. all cases ought to be error handled earlier */
191  lwfree(vertical_line);
192  lwerror("Some unspecified error.");
193  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
194  }
195  lwfree(vertical_line);
196  }
197  }
198  else
199  {
200  if (!lw_dist3d_recursive(lw1, lw2, &thedl))
201  {
202  /* should never get here. all cases ought to be error handled earlier */
203  lwerror("Some unspecified error.");
205  }
206  }
207  /*if thedl.distance is unchanged there where only empty geometries input*/
208  if (thedl.distance == initdistance)
209  {
210  LWDEBUG(3, "didn't find geometries to measure between, returning null");
212  }
213  else
214  {
215  x1 = thedl.p1.x;
216  y1 = thedl.p1.y;
217  z1 = thedl.p1.z;
218  x2 = thedl.p2.x;
219  y2 = thedl.p2.y;
220  z2 = thedl.p2.z;
221 
222  lwpoints[0] = lwpoint_make3dz(srid, x1, y1, z1);
223  lwpoints[1] = lwpoint_make3dz(srid, x2, y2, z2);
224 
225  result = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);
226  }
227 
228  return result;
229 }
230 
234 LWGEOM *
235 lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
236 {
237 
238  double x, y, z;
239  DISTPTS3D thedl;
240  double initdistance = DBL_MAX;
241  LWGEOM *result;
242 
243  thedl.mode = mode;
244  thedl.distance = initdistance;
245  thedl.tolerance = 0;
246 
247  LWDEBUG(2, "lw_dist3d_distancepoint is called");
248 
249  /* Check if we really have 3D geometries
250  * If not, send it to 2D-calculations which will give the same result
251  * as an infinite z-value at one or two of the geometries
252  */
253  if (!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
254  {
255  lwnotice(
256  "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
257 
258  if (!lwgeom_has_z(lw1) && !lwgeom_has_z(lw2))
259  return lw_dist2d_distancepoint(lw1, lw2, srid, mode);
260 
261  DISTPTS thedl2d;
262  thedl2d.mode = mode;
263  thedl2d.distance = initdistance;
264  thedl2d.tolerance = 0.0;
265  if (!lw_dist2d_comp(lw1, lw2, &thedl2d))
266  {
267  /* should never get here. all cases ought to be error handled earlier */
268  lwerror("Some unspecified error.");
269  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
270  }
271 
272  LWGEOM *vertical_line;
273  if (!lwgeom_has_z(lw1))
274  {
275  x = thedl2d.p1.x;
276  y = thedl2d.p1.y;
277 
278  vertical_line = create_v_line(lw2, x, y, srid);
279  if (!lw_dist3d_recursive(vertical_line, lw2, &thedl))
280  {
281  /* should never get here. all cases ought to be error handled earlier */
282  lwfree(vertical_line);
283  lwerror("Some unspecified error.");
284  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
285  }
286  lwfree(vertical_line);
287  }
288 
289  if (!lwgeom_has_z(lw2))
290  {
291  x = thedl2d.p2.x;
292  y = thedl2d.p2.y;
293 
294  vertical_line = create_v_line(lw1, x, y, srid);
295  if (!lw_dist3d_recursive(lw1, vertical_line, &thedl))
296  {
297  /* should never get here. all cases ought to be error handled earlier */
298  lwfree(vertical_line);
299  lwerror("Some unspecified error.");
301  }
302  lwfree(vertical_line);
303  }
304  }
305  else
306  {
307  if (!lw_dist3d_recursive(lw1, lw2, &thedl))
308  {
309  /* should never get here. all cases ought to be error handled earlier */
310  lwerror("Some unspecified error.");
312  }
313  }
314  if (thedl.distance == initdistance)
315  {
316  LWDEBUG(3, "didn't find geometries to measure between, returning null");
318  }
319  else
320  {
321  x = thedl.p1.x;
322  y = thedl.p1.y;
323  z = thedl.p1.z;
324  result = (LWGEOM *)lwpoint_make3dz(srid, x, y, z);
325  }
326 
327  return result;
328 }
329 
333 double
334 lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
335 {
336  return lwgeom_maxdistance3d_tolerance(lw1, lw2, 0.0);
337 }
338 
343 double
344 lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
345 {
346  if (!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
347  {
348  lwnotice(
349  "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
350  return lwgeom_maxdistance2d_tolerance(lw1, lw2, tolerance);
351  }
352  DISTPTS3D thedl;
353  LWDEBUG(2, "lwgeom_maxdistance3d_tolerance is called");
354  thedl.mode = DIST_MAX;
355  thedl.distance = -1;
356  thedl.tolerance = tolerance;
357  if (lw_dist3d_recursive(lw1, lw2, &thedl))
358  return thedl.distance;
359 
360  /* should never get here. all cases ought to be error handled earlier */
361  lwerror("Some unspecified error.");
362  return -1;
363 }
364 
368 double
369 lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
370 {
371  return lwgeom_mindistance3d_tolerance(lw1, lw2, 0.0);
372 }
373 
374 static inline int
375 gbox_contains_3d(const GBOX *g1, const GBOX *g2)
376 {
377  return (g2->xmin >= g1->xmin) && (g2->xmax <= g1->xmax) && (g2->ymin >= g1->ymin) && (g2->ymax <= g1->ymax) &&
378  (g2->zmin >= g1->zmin) && (g2->zmax <= g1->zmax);
379 }
380 
381 static inline int
383 {
384  const GBOX *b1;
385  const GBOX *b2;
386 
387  /* If solid isn't solid it can't contain anything */
388  if (!FLAGS_GET_SOLID(solid->flags))
389  return LW_FALSE;
390 
391  b1 = lwgeom_get_bbox(solid);
392  b2 = lwgeom_get_bbox(g);
393 
394  /* If box won't contain box, shape won't contain shape */
395  if (!gbox_contains_3d(b1, b2))
396  return LW_FALSE;
397  else /* Raycast upwards in Z */
398  {
399  POINT4D pt;
400  /* We'll skew copies if we're not lucky */
401  LWGEOM *solid_copy = lwgeom_clone_deep(solid);
402  LWGEOM *g_copy = lwgeom_clone_deep(g);
403 
404  while (LW_TRUE)
405  {
406  uint8_t is_boundary = LW_FALSE;
407  uint8_t is_inside = LW_FALSE;
408 
409  /* take first point */
410  if (!lwgeom_startpoint(g_copy, &pt))
411  return LW_FALSE;
412 
413  /* get part of solid that is upwards */
414  LWCOLLECTION *c = lwgeom_clip_to_ordinate_range(solid_copy, 'Z', pt.z, DBL_MAX, 0);
415 
416  for (uint32_t i = 0; i < c->ngeoms; i++)
417  {
418  if (c->geoms[i]->type == POLYGONTYPE)
419  {
420  /* 3D raycast along Z is 2D point in polygon */
421  int t = lwpoly_contains_point((LWPOLY *)c->geoms[i], (POINT2D *)&pt);
422 
423  if (t == LW_INSIDE)
424  is_inside = !is_inside;
425  else if (t == LW_BOUNDARY)
426  {
427  is_boundary = LW_TRUE;
428  break;
429  }
430  }
431  else if (c->geoms[i]->type == TRIANGLETYPE)
432  {
433  /* 3D raycast along Z is 2D point in polygon */
434  LWTRIANGLE *tri = (LWTRIANGLE *)c->geoms[i];
435  int t = ptarray_contains_point(tri->points, (POINT2D *)&pt);
436 
437  if (t == LW_INSIDE)
438  is_inside = !is_inside;
439  else if (t == LW_BOUNDARY)
440  {
441  is_boundary = LW_TRUE;
442  break;
443  }
444  }
445  }
446 
448  lwgeom_free(solid_copy);
449  lwgeom_free(g_copy);
450 
451  if (is_boundary)
452  {
453  /* randomly skew a bit and restart*/
454  double cx = lwrandom_uniform() - 0.5;
455  double cy = lwrandom_uniform() - 0.5;
456  AFFINE aff = {1, 0, cx, 0, 1, cy, 0, 0, 1, 0, 0, 0};
457 
458  solid_copy = lwgeom_clone_deep(solid);
459  lwgeom_affine(solid_copy, &aff);
460 
461  g_copy = lwgeom_clone_deep(g);
462  lwgeom_affine(g_copy, &aff);
463 
464  continue;
465  }
466  return is_inside;
467  }
468  }
469 }
470 
475 double
476 lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
477 {
478  assert(tolerance >= 0);
479  if (!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
480  {
481  lwnotice(
482  "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
483 
484  return lwgeom_mindistance2d_tolerance(lw1, lw2, tolerance);
485  }
486  DISTPTS3D thedl;
487  thedl.mode = DIST_MIN;
488  thedl.distance = DBL_MAX;
489  thedl.tolerance = tolerance;
490 
491  if (lw_dist3d_recursive(lw1, lw2, &thedl))
492  {
493  if (thedl.distance <= tolerance)
494  return thedl.distance;
496  return 0;
497 
498  return thedl.distance;
499  }
500 
501  /* should never get here. all cases ought to be error handled earlier */
502  lwerror("Some unspecified error.");
503  return DBL_MAX;
504 }
505 
506 /*------------------------------------------------------------------------------------------------------------
507 End of Initializing functions
508 --------------------------------------------------------------------------------------------------------------*/
509 
510 /*------------------------------------------------------------------------------------------------------------
511 Preprocessing functions
512 Functions preparing geometries for distance-calculations
513 --------------------------------------------------------------------------------------------------------------*/
514 
518 int
519 lw_dist3d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS3D *dl)
520 {
521  int i, j;
522  int n1 = 1;
523  int n2 = 1;
524  LWGEOM *g1 = NULL;
525  LWGEOM *g2 = NULL;
526  LWCOLLECTION *c1 = NULL;
527  LWCOLLECTION *c2 = NULL;
528 
529  LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type);
530 
531  if (lwgeom_is_collection(lwg1))
532  {
533  LWDEBUG(3, "First geometry is collection");
534  c1 = lwgeom_as_lwcollection(lwg1);
535  n1 = c1->ngeoms;
536  }
537  if (lwgeom_is_collection(lwg2))
538  {
539  LWDEBUG(3, "Second geometry is collection");
540  c2 = lwgeom_as_lwcollection(lwg2);
541  n2 = c2->ngeoms;
542  }
543 
544  for (i = 0; i < n1; i++)
545  {
546  if (lwgeom_is_collection(lwg1))
547  g1 = c1->geoms[i];
548  else
549  g1 = (LWGEOM *)lwg1;
550 
551  if (lwgeom_is_empty(g1))
552  continue;
553 
554  if (lwgeom_is_collection(g1))
555  {
556  LWDEBUG(3, "Found collection inside first geometry collection, recursing");
557  if (!lw_dist3d_recursive(g1, lwg2, dl))
558  return LW_FALSE;
559  continue;
560  }
561  for (j = 0; j < n2; j++)
562  {
563  if (lwgeom_is_collection(lwg2))
564  g2 = c2->geoms[j];
565  else
566  g2 = (LWGEOM *)lwg2;
567 
568  if (lwgeom_is_empty(g2))
569  continue;
570 
571  if (lwgeom_is_collection(g2))
572  {
573  LWDEBUG(3, "Found collection inside second geometry collection, recursing");
574  if (!lw_dist3d_recursive(g1, g2, dl))
575  return LW_FALSE;
576  continue;
577  }
578 
579  /*If one of geometries is empty, return. True here only means continue searching. False would
580  * have stopped the process*/
581  if (lwgeom_is_empty(g1) || lwgeom_is_empty(g2))
582  return LW_TRUE;
583 
584  if (!lw_dist3d_distribute_bruteforce(g1, g2, dl))
585  return LW_FALSE;
586  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
587  return LW_TRUE; /*just a check if the answer is already given*/
588  }
589  }
590  return LW_TRUE;
591 }
592 
597 int
599 {
600  int t1 = lwg1->type;
601  int t2 = lwg2->type;
602 
603  LWDEBUGF(2, "lw_dist3d_distribute_bruteforce is called with typ1=%d, type2=%d", lwg1->type, lwg2->type);
604 
605  if (t1 == POINTTYPE)
606  {
607  if (t2 == POINTTYPE)
608  {
609  dl->twisted = 1;
610  return lw_dist3d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
611  }
612  else if (t2 == LINETYPE)
613  {
614  dl->twisted = 1;
615  return lw_dist3d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
616  }
617  else if (t2 == POLYGONTYPE)
618  {
619  dl->twisted = 1;
620  return lw_dist3d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2, dl);
621  }
622  else if (t2 == TRIANGLETYPE)
623  {
624  dl->twisted = 1;
625  return lw_dist3d_point_tri((LWPOINT *)lwg1, (LWTRIANGLE *)lwg2, dl);
626  }
627  else
628  {
629  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
630  return LW_FALSE;
631  }
632  }
633  else if (t1 == LINETYPE)
634  {
635  if (t2 == POINTTYPE)
636  {
637  dl->twisted = -1;
638  return lw_dist3d_point_line((LWPOINT *)lwg2, (LWLINE *)lwg1, dl);
639  }
640  else if (t2 == LINETYPE)
641  {
642  dl->twisted = 1;
643  return lw_dist3d_line_line((LWLINE *)lwg1, (LWLINE *)lwg2, dl);
644  }
645  else if (t2 == POLYGONTYPE)
646  {
647  dl->twisted = 1;
648  return lw_dist3d_line_poly((LWLINE *)lwg1, (LWPOLY *)lwg2, dl);
649  }
650  else if (t2 == TRIANGLETYPE)
651  {
652  dl->twisted = 1;
653  return lw_dist3d_line_tri((LWLINE *)lwg1, (LWTRIANGLE *)lwg2, dl);
654  }
655  else
656  {
657  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
658  return LW_FALSE;
659  }
660  }
661  else if (t1 == POLYGONTYPE)
662  {
663  if (t2 == POLYGONTYPE)
664  {
665  dl->twisted = 1;
666  return lw_dist3d_poly_poly((LWPOLY *)lwg1, (LWPOLY *)lwg2, dl);
667  }
668  else if (t2 == POINTTYPE)
669  {
670  dl->twisted = -1;
671  return lw_dist3d_point_poly((LWPOINT *)lwg2, (LWPOLY *)lwg1, dl);
672  }
673  else if (t2 == LINETYPE)
674  {
675  dl->twisted = -1;
676  return lw_dist3d_line_poly((LWLINE *)lwg2, (LWPOLY *)lwg1, dl);
677  }
678  else if (t2 == TRIANGLETYPE)
679  {
680  dl->twisted = 1;
681  return lw_dist3d_poly_tri((LWPOLY *)lwg1, (LWTRIANGLE *)lwg2, dl);
682  }
683  else
684  {
685  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
686  return LW_FALSE;
687  }
688  }
689  else if (t1 == TRIANGLETYPE)
690  {
691  if (t2 == POLYGONTYPE)
692  {
693  dl->twisted = -1;
694  return lw_dist3d_poly_tri((LWPOLY *)lwg2, (LWTRIANGLE *)lwg1, dl);
695  }
696  else if (t2 == POINTTYPE)
697  {
698  dl->twisted = -1;
699  return lw_dist3d_point_tri((LWPOINT *)lwg2, (LWTRIANGLE *)lwg1, dl);
700  }
701  else if (t2 == LINETYPE)
702  {
703  dl->twisted = -1;
704  return lw_dist3d_line_tri((LWLINE *)lwg2, (LWTRIANGLE *)lwg1, dl);
705  }
706  else if (t2 == TRIANGLETYPE)
707  {
708  dl->twisted = 1;
709  return lw_dist3d_tri_tri((LWTRIANGLE *)lwg1, (LWTRIANGLE *)lwg2, dl);
710  }
711  else
712  {
713  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t2));
714  return LW_FALSE;
715  }
716  }
717 
718  else
719  {
720  lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(t1));
721  return LW_FALSE;
722  }
723 }
724 
725 /*------------------------------------------------------------------------------------------------------------
726 End of Preprocessing functions
727 --------------------------------------------------------------------------------------------------------------*/
728 
729 /*------------------------------------------------------------------------------------------------------------
730 Brute force functions
731 So far the only way to do 3D-calculations
732 --------------------------------------------------------------------------------------------------------------*/
733 
738 int
739 lw_dist3d_point_point(const LWPOINT *point1, const LWPOINT *point2, DISTPTS3D *dl)
740 {
741  POINT3DZ p1;
742  POINT3DZ p2;
743  LWDEBUG(2, "lw_dist3d_point_point is called");
744 
745  getPoint3dz_p(point1->point, 0, &p1);
746  getPoint3dz_p(point2->point, 0, &p2);
747 
748  return lw_dist3d_pt_pt(&p1, &p2, dl);
749 }
754 int
755 lw_dist3d_point_line(const LWPOINT *point, const LWLINE *line, DISTPTS3D *dl)
756 {
757  POINT3DZ p;
758  POINTARRAY *pa = line->points;
759  LWDEBUG(2, "lw_dist3d_point_line is called");
760 
761  getPoint3dz_p(point->point, 0, &p);
762  return lw_dist3d_pt_ptarray(&p, pa, dl);
763 }
764 
777 int
778 lw_dist3d_point_poly(const LWPOINT *point, const LWPOLY *poly, DISTPTS3D *dl)
779 {
780  POINT3DZ p, projp; /*projp is "point projected on plane"*/
781  PLANE3D plane;
782  LWDEBUG(2, "lw_dist3d_point_poly is called");
783  getPoint3dz_p(point->point, 0, &p);
784 
785  /* If we are looking for max distance, longestline or dfullywithin */
786  if (dl->mode == DIST_MAX)
787  return lw_dist3d_pt_ptarray(&p, poly->rings[0], dl);
788 
789  /* Find the plane of the polygon, the "holes" have to be on the same plane. so we only care about the boundary */
790  if (!define_plane(poly->rings[0], &plane))
791  {
792  /* Polygon does not define a plane: Return distance point -> line */
793  return lw_dist3d_pt_ptarray(&p, poly->rings[0], dl);
794  }
795 
796  /* Get our point projected on the plane of the polygon */
797  project_point_on_plane(&p, &plane, &projp);
798 
799  return lw_dist3d_pt_poly(&p, poly, &plane, &projp, dl);
800 }
801 
802 /* point to triangle calculation */
803 int
804 lw_dist3d_point_tri(const LWPOINT *point, const LWTRIANGLE *tri, DISTPTS3D *dl)
805 {
806  POINT3DZ p, projp; /*projp is "point projected on plane"*/
807  PLANE3D plane;
808  getPoint3dz_p(point->point, 0, &p);
809 
810  /* If we are looking for max distance, longestline or dfullywithin */
811  if (dl->mode == DIST_MAX)
812  return lw_dist3d_pt_ptarray(&p, tri->points, dl);
813 
814  /* If triangle does not define a plane, treat it as a line */
815  if (!define_plane(tri->points, &plane))
816  return lw_dist3d_pt_ptarray(&p, tri->points, dl);
817 
818  /* Get our point projected on the plane of triangle */
819  project_point_on_plane(&p, &plane, &projp);
820 
821  return lw_dist3d_pt_tri(&p, tri, &plane, &projp, dl);
822 }
823 
825 int
826 lw_dist3d_line_line(const LWLINE *line1, const LWLINE *line2, DISTPTS3D *dl)
827 {
828  POINTARRAY *pa1 = line1->points;
829  POINTARRAY *pa2 = line2->points;
830  LWDEBUG(2, "lw_dist3d_line_line is called");
831 
832  return lw_dist3d_ptarray_ptarray(pa1, pa2, dl);
833 }
834 
836 int
837 lw_dist3d_line_poly(const LWLINE *line, const LWPOLY *poly, DISTPTS3D *dl)
838 {
839  PLANE3D plane;
840  LWDEBUG(2, "lw_dist3d_line_poly is called");
841 
842  if (dl->mode == DIST_MAX)
843  return lw_dist3d_ptarray_ptarray(line->points, poly->rings[0], dl);
844 
845  /* if polygon does not define a plane: Return distance line to line */
846  if (!define_plane(poly->rings[0], &plane))
847  return lw_dist3d_ptarray_ptarray(line->points, poly->rings[0], dl);
848 
849  return lw_dist3d_ptarray_poly(line->points, poly, &plane, dl);
850 }
851 
853 int
854 lw_dist3d_line_tri(const LWLINE *line, const LWTRIANGLE *tri, DISTPTS3D *dl)
855 {
856  PLANE3D plane;
857 
858  if (dl->mode == DIST_MAX)
859  return lw_dist3d_ptarray_ptarray(line->points, tri->points, dl);
860 
861  /* if triangle does not define a plane: Return distance line to line */
862  if (!define_plane(tri->points, &plane))
863  return lw_dist3d_ptarray_ptarray(line->points, tri->points, dl);
864 
865  return lw_dist3d_ptarray_tri(line->points, tri, &plane, dl);
866 }
867 
869 int
870 lw_dist3d_poly_poly(const LWPOLY *poly1, const LWPOLY *poly2, DISTPTS3D *dl)
871 {
872  PLANE3D plane1, plane2;
873  int planedef1, planedef2;
874  LWDEBUG(2, "lw_dist3d_poly_poly is called");
875  if (dl->mode == DIST_MAX)
876  return lw_dist3d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
877 
878  planedef1 = define_plane(poly1->rings[0], &plane1);
879  planedef2 = define_plane(poly2->rings[0], &plane2);
880 
881  if (!planedef1 || !planedef2)
882  {
883  /* Neither polygon define a plane: Return distance line to line */
884  if (!planedef1 && !planedef2)
885  return lw_dist3d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
886 
887  /* Only poly2 defines a plane: Return distance from line (poly1) to poly2 */
888  else if (!planedef1)
889  return lw_dist3d_ptarray_poly(poly1->rings[0], poly2, &plane2, dl);
890 
891  /* Only poly1 defines a plane: Return distance from line (poly2) to poly1 */
892  else
893  return lw_dist3d_ptarray_poly(poly2->rings[0], poly1, &plane1, dl);
894  }
895 
896  /* What we do here is to compare the boundary of one polygon with the other polygon
897  and then take the second boundary comparing with the first polygon */
898  dl->twisted = 1;
899  if (!lw_dist3d_ptarray_poly(poly1->rings[0], poly2, &plane2, dl))
900  return LW_FALSE;
901  if (dl->distance < dl->tolerance) /* Just check if the answer already is given*/
902  return LW_TRUE;
903 
904  dl->twisted = -1; /* because we switch the order of geometries we switch "twisted" to -1 which will give the
905  right order of points in shortest line. */
906  return lw_dist3d_ptarray_poly(poly2->rings[0], poly1, &plane1, dl);
907 }
908 
910 int
911 lw_dist3d_poly_tri(const LWPOLY *poly, const LWTRIANGLE *tri, DISTPTS3D *dl)
912 {
913  PLANE3D plane1, plane2;
914  int planedef1, planedef2;
915 
916  if (dl->mode == DIST_MAX)
917  return lw_dist3d_ptarray_ptarray(poly->rings[0], tri->points, dl);
918 
919  planedef1 = define_plane(poly->rings[0], &plane1);
920  planedef2 = define_plane(tri->points, &plane2);
921 
922  if (!planedef1 || !planedef2)
923  {
924  /* Neither define a plane: Return distance line to line */
925  if (!planedef1 && !planedef2)
926  return lw_dist3d_ptarray_ptarray(poly->rings[0], tri->points, dl);
927 
928  /* Only tri defines a plane: Return distance from line (poly) to tri */
929  else if (!planedef1)
930  return lw_dist3d_ptarray_tri(poly->rings[0], tri, &plane2, dl);
931 
932  /* Only poly defines a plane: Return distance from line (tri) to poly */
933  else
934  return lw_dist3d_ptarray_poly(tri->points, poly, &plane1, dl);
935  }
936 
937  /* What we do here is to compare the boundary of one polygon with the other polygon
938  and then take the second boundary comparing with the first polygon */
939  dl->twisted = 1;
940  if (!lw_dist3d_ptarray_tri(poly->rings[0], tri, &plane2, dl))
941  return LW_FALSE;
942  if (dl->distance < dl->tolerance) /* Just check if the answer already is given*/
943  return LW_TRUE;
944 
945  dl->twisted = -1; /* because we switch the order of geometries we switch "twisted" to -1 which will give the
946  right order of points in shortest line. */
947  return lw_dist3d_ptarray_poly(tri->points, poly, &plane1, dl);
948 }
949 
951 int
952 lw_dist3d_tri_tri(const LWTRIANGLE *tri1, const LWTRIANGLE *tri2, DISTPTS3D *dl)
953 {
954  PLANE3D plane1, plane2;
955  int planedef1, planedef2;
956 
957  if (dl->mode == DIST_MAX)
958  return lw_dist3d_ptarray_ptarray(tri1->points, tri2->points, dl);
959 
960  planedef1 = define_plane(tri1->points, &plane1);
961  planedef2 = define_plane(tri2->points, &plane2);
962 
963  if (!planedef1 || !planedef2)
964  {
965  /* Neither define a plane: Return distance line to line */
966  if (!planedef1 && !planedef2)
967  return lw_dist3d_ptarray_ptarray(tri1->points, tri2->points, dl);
968 
969  /* Only tri defines a plane: Return distance from line (tri1) to tri2 */
970  else if (!planedef1)
971  return lw_dist3d_ptarray_tri(tri1->points, tri2, &plane2, dl);
972 
973  /* Only poly defines a plane: Return distance from line (tri2) to tri1 */
974  else
975  return lw_dist3d_ptarray_tri(tri2->points, tri1, &plane1, dl);
976  }
977 
978  /* What we do here is to compare the boundary of one polygon with the other polygon
979  and then take the second boundary comparing with the first polygon */
980  dl->twisted = 1;
981  if (!lw_dist3d_ptarray_tri(tri1->points, tri2, &plane2, dl))
982  return LW_FALSE;
983  if (dl->distance < dl->tolerance) /* Just check if the answer already is given*/
984  return LW_TRUE;
985 
986  dl->twisted = -1; /* because we switch the order of geometries we switch "twisted" to -1 which will give the
987  right order of points in shortest line. */
988  return lw_dist3d_ptarray_tri(tri2->points, tri1, &plane1, dl);
989 }
990 
995 int
997 {
998  uint32_t t;
999  POINT3DZ start, end;
1000  int twist = dl->twisted;
1001  if (!pa)
1002  return LW_FALSE;
1003 
1004  getPoint3dz_p(pa, 0, &start);
1005 
1006  for (t = 1; t < pa->npoints; t++)
1007  {
1008  dl->twisted = twist;
1009  getPoint3dz_p(pa, t, &end);
1010  if (!lw_dist3d_pt_seg(p, &start, &end, dl))
1011  return LW_FALSE;
1012 
1013  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1014  return LW_TRUE; /*just a check if the answer is already given*/
1015  start = end;
1016  }
1017 
1018  return LW_TRUE;
1019 }
1020 
1025 int
1026 lw_dist3d_pt_seg(const POINT3DZ *p, const POINT3DZ *A, const POINT3DZ *B, DISTPTS3D *dl)
1027 {
1028  POINT3DZ c;
1029  double r;
1030  /*if start==end, then use pt distance */
1031  if ((A->x == B->x) && (A->y == B->y) && (A->z == B->z))
1032  {
1033  return lw_dist3d_pt_pt(p, A, dl);
1034  }
1035 
1036  r = ((p->x - A->x) * (B->x - A->x) + (p->y - A->y) * (B->y - A->y) + (p->z - A->z) * (B->z - A->z)) /
1037  ((B->x - A->x) * (B->x - A->x) + (B->y - A->y) * (B->y - A->y) + (B->z - A->z) * (B->z - A->z));
1038 
1039  /*This is for finding the 3Dmaxdistance.
1040  the maxdistance have to be between two vertices,
1041  compared to mindistance which can be between
1042  two vertices vertex.*/
1043  if (dl->mode == DIST_MAX)
1044  {
1045  if (r >= 0.5)
1046  return lw_dist3d_pt_pt(p, A, dl);
1047  if (r < 0.5)
1048  return lw_dist3d_pt_pt(p, B, dl);
1049  }
1050 
1051  if (r <= 0) /*If the first vertex A is closest to the point p*/
1052  return lw_dist3d_pt_pt(p, A, dl);
1053  if (r >= 1) /*If the second vertex B is closest to the point p*/
1054  return lw_dist3d_pt_pt(p, B, dl);
1055 
1056  /*else if the point p is closer to some point between a and b
1057  then we find that point and send it to lw_dist3d_pt_pt*/
1058  c.x = A->x + r * (B->x - A->x);
1059  c.y = A->y + r * (B->y - A->y);
1060  c.z = A->z + r * (B->z - A->z);
1061 
1062  return lw_dist3d_pt_pt(p, &c, dl);
1063 }
1064 
1065 double
1066 distance3d_pt_pt(const POINT3D *p1, const POINT3D *p2)
1067 {
1068  double dx = p2->x - p1->x;
1069  double dy = p2->y - p1->y;
1070  double dz = p2->z - p1->z;
1071  return sqrt(dx * dx + dy * dy + dz * dz);
1072 }
1073 
1081 int
1082 lw_dist3d_pt_pt(const POINT3DZ *thep1, const POINT3DZ *thep2, DISTPTS3D *dl)
1083 {
1084  double dx = thep2->x - thep1->x;
1085  double dy = thep2->y - thep1->y;
1086  double dz = thep2->z - thep1->z;
1087  double dist = sqrt(dx * dx + dy * dy + dz * dz);
1088  LWDEBUGF(2,
1089  "lw_dist3d_pt_pt called (with points: p1.x=%f, p1.y=%f,p1.z=%f,p2.x=%f, p2.y=%f,p2.z=%f)",
1090  thep1->x,
1091  thep1->y,
1092  thep1->z,
1093  thep2->x,
1094  thep2->y,
1095  thep2->z);
1096 
1097  if (((dl->distance - dist) * (dl->mode)) >
1098  0) /*multiplication with mode to handle mindistance (mode=1) and maxdistance (mode = (-1)*/
1099  {
1100  dl->distance = dist;
1101 
1102  if (dl->twisted > 0) /*To get the points in right order. twisted is updated between 1 and (-1) every
1103  time the order is changed earlier in the chain*/
1104  {
1105  dl->p1 = *thep1;
1106  dl->p2 = *thep2;
1107  }
1108  else
1109  {
1110  dl->p1 = *thep2;
1111  dl->p2 = *thep1;
1112  }
1113  }
1114  return LW_TRUE;
1115 }
1116 
1121 int
1123 {
1124  uint32_t t, u;
1125  POINT3DZ start, end;
1126  POINT3DZ start2, end2;
1127  int twist = dl->twisted;
1128  LWDEBUGF(2, "lw_dist3d_ptarray_ptarray called (points: %d-%d)", l1->npoints, l2->npoints);
1129 
1130  if (dl->mode == DIST_MAX) /*If we are searching for maxdistance we go straight to point-point calculation since
1131  the maxdistance have to be between two vertices*/
1132  {
1133  for (t = 0; t < l1->npoints; t++) /*for each segment in L1 */
1134  {
1135  getPoint3dz_p(l1, t, &start);
1136  for (u = 0; u < l2->npoints; u++) /*for each segment in L2 */
1137  {
1138  getPoint3dz_p(l2, u, &start2);
1139  lw_dist3d_pt_pt(&start, &start2, dl);
1140  }
1141  }
1142  }
1143  else
1144  {
1145  getPoint3dz_p(l1, 0, &start);
1146  for (t = 1; t < l1->npoints; t++) /*for each segment in L1 */
1147  {
1148  getPoint3dz_p(l1, t, &end);
1149  getPoint3dz_p(l2, 0, &start2);
1150  for (u = 1; u < l2->npoints; u++) /*for each segment in L2 */
1151  {
1152  getPoint3dz_p(l2, u, &end2);
1153  dl->twisted = twist;
1154  lw_dist3d_seg_seg(&start, &end, &start2, &end2, dl);
1155  LWDEBUGF(
1156  4, "mindist_ptarray_ptarray; seg %i * seg %i, dist = %g\n", t, u, dl->distance);
1157  LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f", t, u, dl->distance, dl->tolerance);
1158  if (dl->distance <= dl->tolerance && dl->mode == DIST_MIN)
1159  return LW_TRUE; /*just a check if the answer is already given*/
1160  start2 = end2;
1161  }
1162  start = end;
1163  }
1164  }
1165  return LW_TRUE;
1166 }
1167 
1172 int
1173 lw_dist3d_seg_seg(const POINT3DZ *s1p1, const POINT3DZ *s1p2, const POINT3DZ *s2p1, const POINT3DZ *s2p2, DISTPTS3D *dl)
1174 {
1175  VECTOR3D v1, v2, vl;
1176  double s1k, s2k; /*two variables representing where on Line 1 (s1k) and where on Line 2 (s2k) a connecting line
1177  between the two lines is perpendicular to both lines*/
1178  POINT3DZ p1, p2;
1179  double a, b, c, d, e, D;
1180 
1181  /*s1p1 and s1p2 are the same point */
1182  if (p3dz_same(s1p1, s1p2))
1183  {
1184  return lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl);
1185  }
1186  /*s2p1 and s2p2 are the same point */
1187  if (p3dz_same(s2p1, s2p2))
1188  {
1189  dl->twisted = ((dl->twisted) * (-1));
1190  return lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl);
1191  }
1192  /*s2p1 and s1p1 are the same point */
1193  if (p3dz_same(s2p1, s1p1))
1194  {
1195  dl->distance = 0.0;
1196  dl->p1 = dl->p2 = *s2p1;
1197  return LW_TRUE;
1198  }
1199  /*
1200  Here we use algorithm from softsurfer.com
1201  that can be found here
1202  http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
1203  */
1204 
1205  if (!get_3dvector_from_points(s1p1, s1p2, &v1))
1206  return LW_FALSE;
1207 
1208  if (!get_3dvector_from_points(s2p1, s2p2, &v2))
1209  return LW_FALSE;
1210 
1211  if (!get_3dvector_from_points(s2p1, s1p1, &vl))
1212  return LW_FALSE;
1213 
1214  a = DOT(v1, v1);
1215  b = DOT(v1, v2);
1216  c = DOT(v2, v2);
1217  d = DOT(v1, vl);
1218  e = DOT(v2, vl);
1219  D = a * c - b * b;
1220 
1221  if (D < 0.000000001)
1222  { /* the lines are almost parallel*/
1223  s1k =
1224  0.0; /*If the lines are parallel we try by using the startpoint of first segment. If that gives a
1225  projected point on the second line outside segment 2 it will be found that s2k is >1 or <0.*/
1226  if (b > c) /* use the largest denominator*/
1227  s2k = d / b;
1228  else
1229  s2k = e / c;
1230  }
1231  else
1232  {
1233  s1k = (b * e - c * d) / D;
1234  s2k = (a * e - b * d) / D;
1235  }
1236 
1237  /* Now we check if the projected closest point on the infinite lines is outside our segments. If so the
1238  * combinations with start and end points will be tested*/
1239 
1240  if (s1k <= 0.0 || s1k >= 1.0 || s2k <= 0.0 || s2k >= 1.0)
1241  {
1242  if (s1k <= 0.0)
1243  {
1244  if (!lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl))
1245  return LW_FALSE;
1246  }
1247  if (s1k >= 1.0)
1248  {
1249  if (!lw_dist3d_pt_seg(s1p2, s2p1, s2p2, dl))
1250  return LW_FALSE;
1251  }
1252  if (s2k <= 0.0)
1253  {
1254  dl->twisted = ((dl->twisted) * (-1));
1255  if (!lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl))
1256  return LW_FALSE;
1257  }
1258  if (s2k >= 1.0)
1259  {
1260  dl->twisted = ((dl->twisted) * (-1));
1261  if (!lw_dist3d_pt_seg(s2p2, s1p1, s1p2, dl))
1262  return LW_FALSE;
1263  }
1264  }
1265  else
1266  { /*Find the closest point on the edges of both segments*/
1267  p1.x = s1p1->x + s1k * (s1p2->x - s1p1->x);
1268  p1.y = s1p1->y + s1k * (s1p2->y - s1p1->y);
1269  p1.z = s1p1->z + s1k * (s1p2->z - s1p1->z);
1270 
1271  p2.x = s2p1->x + s2k * (s2p2->x - s2p1->x);
1272  p2.y = s2p1->y + s2k * (s2p2->y - s2p1->y);
1273  p2.z = s2p1->z + s2k * (s2p2->z - s2p1->z);
1274 
1275  if (!lw_dist3d_pt_pt(&p1, &p2, dl)) /* Send the closest points to point-point calculation*/
1276  {
1277  return LW_FALSE;
1278  }
1279  }
1280  return LW_TRUE;
1281 }
1282 
1290 int
1291 lw_dist3d_pt_poly(const POINT3DZ *p, const LWPOLY *poly, PLANE3D *plane, POINT3DZ *projp, DISTPTS3D *dl)
1292 {
1293  uint32_t i;
1294 
1295  if (pt_in_ring_3d(projp, poly->rings[0], plane))
1296  {
1297  for (i = 1; i < poly->nrings; i++)
1298  {
1299  /* Inside a hole. Distance = pt -> ring */
1300  if (pt_in_ring_3d(projp, poly->rings[i], plane))
1301  return lw_dist3d_pt_ptarray(p, poly->rings[i], dl);
1302  }
1303 
1304  /* if the projected point is inside the polygon the shortest distance is between that point and the
1305  * input point */
1306  return lw_dist3d_pt_pt(p, projp, dl);
1307  }
1308  else
1309  /* if the projected point is outside the polygon we search for the closest distance against the boundary
1310  * instead */
1311  return lw_dist3d_pt_ptarray(p, poly->rings[0], dl);
1312 
1313  return LW_TRUE;
1314 }
1315 
1316 int
1317 lw_dist3d_pt_tri(const POINT3DZ *p, const LWTRIANGLE *tri, PLANE3D *plane, POINT3DZ *projp, DISTPTS3D *dl)
1318 {
1319  if (pt_in_ring_3d(projp, tri->points, plane))
1320  /* if the projected point is inside the polygon the shortest distance is between that point and the
1321  * input point */
1322  return lw_dist3d_pt_pt(p, projp, dl);
1323  else
1324  /* if the projected point is outside the polygon we search for the closest distance against the boundary
1325  * instead */
1326  return lw_dist3d_pt_ptarray(p, tri->points, dl);
1327 
1328  return LW_TRUE;
1329 }
1330 
1332 int
1333 lw_dist3d_ptarray_poly(const POINTARRAY *pa, const LWPOLY *poly, PLANE3D *plane, DISTPTS3D *dl)
1334 {
1335  uint32_t i, j, k;
1336  double f, s1, s2;
1337  VECTOR3D projp1_projp2;
1338  POINT3DZ p1, p2, projp1, projp2, intersectionp;
1339 
1340  getPoint3dz_p(pa, 0, &p1);
1341 
1342  /* the sign of s1 tells us on which side of the plane the point is. */
1343  s1 = project_point_on_plane(&p1, plane, &projp1);
1344  lw_dist3d_pt_poly(&p1, poly, plane, &projp1, dl);
1345  if ((s1 == 0.0) && (dl->distance < dl->tolerance))
1346  return LW_TRUE;
1347 
1348  for (i = 1; i < pa->npoints; i++)
1349  {
1350  int intersects;
1351  getPoint3dz_p(pa, i, &p2);
1352  s2 = project_point_on_plane(&p2, plane, &projp2);
1353  lw_dist3d_pt_poly(&p2, poly, plane, &projp2, dl);
1354  if ((s2 == 0.0) && (dl->distance < dl->tolerance))
1355  return LW_TRUE;
1356 
1357  /* If s1 and s2 has different signs that means they are on different sides of the plane of the polygon.
1358  * That means that the edge between the points crosses the plane and might intersect with the polygon */
1359  if ((s1 * s2) < 0)
1360  {
1361  /* The size of s1 and s2 is the distance from the point to the plane. */
1362  f = fabs(s1) / (fabs(s1) + fabs(s2));
1363  get_3dvector_from_points(&projp1, &projp2, &projp1_projp2);
1364 
1365  /* Get the point where the line segment crosses the plane */
1366  intersectionp.x = projp1.x + f * projp1_projp2.x;
1367  intersectionp.y = projp1.y + f * projp1_projp2.y;
1368  intersectionp.z = projp1.z + f * projp1_projp2.z;
1369 
1370  /* We set intersects to true until the opposite is proved */
1371  intersects = LW_TRUE;
1372 
1373  if (pt_in_ring_3d(&intersectionp, poly->rings[0], plane)) /*Inside outer ring*/
1374  {
1375  for (k = 1; k < poly->nrings; k++)
1376  {
1377  /* Inside a hole, so no intersection with the polygon*/
1378  if (pt_in_ring_3d(&intersectionp, poly->rings[k], plane))
1379  {
1380  intersects = LW_FALSE;
1381  break;
1382  }
1383  }
1384  if (intersects)
1385  {
1386  dl->distance = 0.0;
1387  dl->p1.x = intersectionp.x;
1388  dl->p1.y = intersectionp.y;
1389  dl->p1.z = intersectionp.z;
1390 
1391  dl->p2.x = intersectionp.x;
1392  dl->p2.y = intersectionp.y;
1393  dl->p2.z = intersectionp.z;
1394  return LW_TRUE;
1395  }
1396  }
1397  }
1398 
1399  projp1 = projp2;
1400  s1 = s2;
1401  p1 = p2;
1402  }
1403 
1404  /* check our pointarray against boundary and inner boundaries of the polygon */
1405  for (j = 0; j < poly->nrings; j++)
1406  lw_dist3d_ptarray_ptarray(pa, poly->rings[j], dl);
1407 
1408  return LW_TRUE;
1409 }
1410 
1412 int
1413 lw_dist3d_ptarray_tri(const POINTARRAY *pa, const LWTRIANGLE *tri, PLANE3D *plane, DISTPTS3D *dl)
1414 {
1415  uint32_t i;
1416  double f, s1, s2;
1417  VECTOR3D projp1_projp2;
1418  POINT3DZ p1, p2, projp1, projp2, intersectionp;
1419 
1420  getPoint3dz_p(pa, 0, &p1);
1421 
1422  /* the sign of s1 tells us on which side of the plane the point is. */
1423  s1 = project_point_on_plane(&p1, plane, &projp1);
1424  lw_dist3d_pt_tri(&p1, tri, plane, &projp1, dl);
1425  if ((s1 == 0.0) && (dl->distance < dl->tolerance))
1426  return LW_TRUE;
1427 
1428  for (i = 1; i < pa->npoints; i++)
1429  {
1430  int intersects;
1431  getPoint3dz_p(pa, i, &p2);
1432  s2 = project_point_on_plane(&p2, plane, &projp2);
1433  lw_dist3d_pt_tri(&p2, tri, plane, &projp2, dl);
1434  if ((s2 == 0.0) && (dl->distance < dl->tolerance))
1435  return LW_TRUE;
1436 
1437  /* If s1 and s2 has different signs that means they are on different sides of the plane of the triangle.
1438  * That means that the edge between the points crosses the plane and might intersect with the triangle
1439  */
1440  if ((s1 * s2) < 0)
1441  {
1442  /* The size of s1 and s2 is the distance from the point to the plane. */
1443  f = fabs(s1) / (fabs(s1) + fabs(s2));
1444  get_3dvector_from_points(&projp1, &projp2, &projp1_projp2);
1445 
1446  /* Get the point where the line segment crosses the plane */
1447  intersectionp.x = projp1.x + f * projp1_projp2.x;
1448  intersectionp.y = projp1.y + f * projp1_projp2.y;
1449  intersectionp.z = projp1.z + f * projp1_projp2.z;
1450 
1451  /* We set intersects to true until the opposite is proved */
1452  intersects = LW_TRUE;
1453 
1454  if (pt_in_ring_3d(&intersectionp, tri->points, plane)) /*Inside outer ring*/
1455  {
1456  if (intersects)
1457  {
1458  dl->distance = 0.0;
1459  dl->p1.x = intersectionp.x;
1460  dl->p1.y = intersectionp.y;
1461  dl->p1.z = intersectionp.z;
1462 
1463  dl->p2.x = intersectionp.x;
1464  dl->p2.y = intersectionp.y;
1465  dl->p2.z = intersectionp.z;
1466  return LW_TRUE;
1467  }
1468  }
1469  }
1470 
1471  projp1 = projp2;
1472  s1 = s2;
1473  p1 = p2;
1474  }
1475 
1476  /* check our pointarray against triangle contour */
1477  lw_dist3d_ptarray_ptarray(pa, tri->points, dl);
1478  return LW_TRUE;
1479 }
1480 
1481 /* Here we define the plane of a polygon (boundary pointarray of a polygon)
1482  * the plane is stored as a point in plane (plane.pop) and a normal vector (plane.pv)
1483  *
1484  * We are calculating the average point and using it to break the polygon into
1485  * POL_BREAKS (3) parts. Then we calculate the normal of those 3 vectors and
1486  * use its average to define the normal of the plane.This is done to minimize
1487  * the error introduced by FP precision
1488  * We use [3] breaks to contemplate the special case of 3d triangles
1489  */
1490 int
1492 {
1493  const uint32_t POL_BREAKS = 3;
1494 
1495  assert(pa);
1496  assert(pa->npoints > 3);
1497  if (!pa)
1498  return LW_FALSE;
1499 
1500  uint32_t unique_points = pa->npoints - 1;
1501  uint32_t i;
1502 
1503  if (pa->npoints < 3)
1504  return LW_FALSE;
1505 
1506  /* Calculate the average point */
1507  pl->pop.x = 0.0;
1508  pl->pop.y = 0.0;
1509  pl->pop.z = 0.0;
1510  for (i = 0; i < unique_points; i++)
1511  {
1512  POINT3DZ p;
1513  getPoint3dz_p(pa, i, &p);
1514  pl->pop.x += p.x;
1515  pl->pop.y += p.y;
1516  pl->pop.z += p.z;
1517  }
1518 
1519  pl->pop.x /= unique_points;
1520  pl->pop.y /= unique_points;
1521  pl->pop.z /= unique_points;
1522 
1523  pl->pv.x = 0.0;
1524  pl->pv.y = 0.0;
1525  pl->pv.z = 0.0;
1526  for (i = 0; i < POL_BREAKS; i++)
1527  {
1528  POINT3DZ point1, point2;
1529  VECTOR3D v1, v2, vp;
1530  uint32_t n1, n2;
1531  n1 = i * unique_points / POL_BREAKS;
1532  n2 = n1 + unique_points / POL_BREAKS; /* May overflow back to the first / last point */
1533 
1534  if (n1 == n2)
1535  continue;
1536 
1537  getPoint3dz_p(pa, n1, &point1);
1538  if (!get_3dvector_from_points(&pl->pop, &point1, &v1))
1539  continue;
1540 
1541  getPoint3dz_p(pa, n2, &point2);
1542  if (!get_3dvector_from_points(&pl->pop, &point2, &v2))
1543  continue;
1544 
1545  if (get_3dcross_product(&v1, &v2, &vp))
1546  {
1547  /* If the cross product isn't zero these 3 points aren't collinear
1548  * We divide by its lengthsq to normalize the additions */
1549  double vl = vp.x * vp.x + vp.y * vp.y + vp.z * vp.z;
1550  pl->pv.x += vp.x / vl;
1551  pl->pv.y += vp.y / vl;
1552  pl->pv.z += vp.z / vl;
1553  }
1554  }
1555 
1556  return (!FP_IS_ZERO(pl->pv.x) || !FP_IS_ZERO(pl->pv.y) || !FP_IS_ZERO(pl->pv.z));
1557 }
1558 
1559 
1572 int
1573 pt_in_ring_3d(const POINT3DZ *p, const POINTARRAY *ring, PLANE3D *plane)
1574 {
1575 
1576  uint32_t cn = 0; /* the crossing number counter */
1577  uint32_t i;
1578  POINT3DZ v1, v2;
1579 
1580  POINT3DZ first, last;
1581 
1582  getPoint3dz_p(ring, 0, &first);
1583  getPoint3dz_p(ring, ring->npoints - 1, &last);
1584  if (memcmp(&first, &last, sizeof(POINT3DZ)))
1585  {
1586  lwerror("pt_in_ring_3d: V[n] != V[0] (%g %g %g!= %g %g %g)",
1587  first.x,
1588  first.y,
1589  first.z,
1590  last.x,
1591  last.y,
1592  last.z);
1593  return LW_FALSE;
1594  }
1595 
1596  LWDEBUGF(2, "pt_in_ring_3d called with point: %g %g %g", p->x, p->y, p->z);
1597  /* printPA(ring); */
1598 
1599  /* loop through all edges of the polygon */
1600  getPoint3dz_p(ring, 0, &v1);
1601 
1602  if (fabs(plane->pv.z) >= fabs(plane->pv.x) &&
1603  fabs(plane->pv.z) >= fabs(plane->pv.y)) /*If the z vector of the normal vector to the plane is larger than x
1604  and y vector we project the ring to the xy-plane*/
1605  {
1606  for (i = 0; i < ring->npoints - 1; i++)
1607  {
1608  double vt;
1609  getPoint3dz_p(ring, i + 1, &v2);
1610 
1611  /* edge from vertex i to vertex i+1 */
1612  if (
1613  /* an upward crossing */
1614  ((v1.y <= p->y) && (v2.y > p->y))
1615  /* a downward crossing */
1616  || ((v1.y > p->y) && (v2.y <= p->y)))
1617  {
1618 
1619  vt = (double)(p->y - v1.y) / (v2.y - v1.y);
1620 
1621  /* P.x <intersect */
1622  if (p->x < v1.x + vt * (v2.x - v1.x))
1623  {
1624  /* a valid crossing of y=p.y right of p.x */
1625  ++cn;
1626  }
1627  }
1628  v1 = v2;
1629  }
1630  }
1631  else if (fabs(plane->pv.y) >= fabs(plane->pv.x) &&
1632  fabs(plane->pv.y) >= fabs(plane->pv.z)) /*If the y vector of the normal vector to the plane is larger
1633  than x and z vector we project the ring to the xz-plane*/
1634  {
1635  for (i = 0; i < ring->npoints - 1; i++)
1636  {
1637  double vt;
1638  getPoint3dz_p(ring, i + 1, &v2);
1639 
1640  /* edge from vertex i to vertex i+1 */
1641  if (
1642  /* an upward crossing */
1643  ((v1.z <= p->z) && (v2.z > p->z))
1644  /* a downward crossing */
1645  || ((v1.z > p->z) && (v2.z <= p->z)))
1646  {
1647 
1648  vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1649 
1650  /* P.x <intersect */
1651  if (p->x < v1.x + vt * (v2.x - v1.x))
1652  {
1653  /* a valid crossing of y=p.y right of p.x */
1654  ++cn;
1655  }
1656  }
1657  v1 = v2;
1658  }
1659  }
1660  else /*Hopefully we only have the cases where x part of the normal vector is largest left*/
1661  {
1662  for (i = 0; i < ring->npoints - 1; i++)
1663  {
1664  double vt;
1665  getPoint3dz_p(ring, i + 1, &v2);
1666 
1667  /* edge from vertex i to vertex i+1 */
1668  if (
1669  /* an upward crossing */
1670  ((v1.z <= p->z) && (v2.z > p->z))
1671  /* a downward crossing */
1672  || ((v1.z > p->z) && (v2.z <= p->z)))
1673  {
1674 
1675  vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1676 
1677  /* P.x <intersect */
1678  if (p->y < v1.y + vt * (v2.y - v1.y))
1679  {
1680  /* a valid crossing of y=p.y right of p.x */
1681  ++cn;
1682  }
1683  }
1684  v1 = v2;
1685  }
1686  }
1687  LWDEBUGF(3, "pt_in_ring_3d returning %d", cn & 1);
1688 
1689  return (cn & 1); /* 0 if even (out), and 1 if odd (in) */
1690 }
1691 
1692 /*------------------------------------------------------------------------------------------------------------
1693 End of Brute force functions
1694 --------------------------------------------------------------------------------------------------------------*/
char * r
Definition: cu_in_wkt.c:24
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
#define LW_FALSE
Definition: liblwgeom.h:94
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition: lwgeom.c:2221
LWLINE * lwline_from_ptarray(int32_t srid, uint32_t npoints, LWPOINT **points)
Definition: lwline.c:228
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
#define LINETYPE
Definition: liblwgeom.h:103
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition: lwgeom.c:529
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
int getPoint3dz_p(const POINTARRAY *pa, uint32_t n, POINT3DZ *point)
Definition: lwgeom_api.c:215
void lwfree(void *mem)
Definition: lwutil.c:248
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition: measures.c:210
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition: lwgeom.c:1097
#define POLYGONTYPE
Definition: liblwgeom.h:104
LWPOINT * lwpoint_make3dz(int32_t srid, double x, double y, double z)
Definition: lwpoint.c:173
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:2083
LWCOLLECTION * lwgeom_clip_to_ordinate_range(const LWGEOM *lwin, char ordinate, double from, double to, double offset)
Given a geometry clip based on the from/to range of one of its ordinates (x, y, z,...
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:357
#define FLAGS_GET_SOLID(flags)
Definition: liblwgeom.h:170
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:743
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition: lwgeom.c:755
#define TRIANGLETYPE
Definition: liblwgeom.h:115
double lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfullywithin calculations.
Definition: measures.c:180
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
int p3dz_same(const POINT3DZ *p1, const POINT3DZ *p2)
Definition: lwalgorithm.c:49
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return LW_INSIDE if the point is inside the POINTARRAY, LW_OUTSIDE if it is outside,...
Definition: ptarray.c:751
int lwpoly_contains_point(const LWPOLY *poly, const POINT2D *pt)
Definition: lwpoly.c:532
#define FP_IS_ZERO(A)
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:199
double lwrandom_uniform(void)
Definition: lwrandom.c:94
int pt_in_ring_3d(const POINT3DZ *p, const POINTARRAY *ring, PLANE3D *plane)
pt_in_ring_3d(): crossing number test for a point in a polygon input: p = a point,...
Definition: measures3d.c:1573
int lw_dist3d_line_line(const LWLINE *line1, const LWLINE *line2, DISTPTS3D *dl)
line to line calculation
Definition: measures3d.c:826
static LWGEOM * create_v_line(const LWGEOM *lwgeom, double x, double y, int32_t srid)
This function is used to create a vertical line used for cases where one if the geometries lacks z-va...
Definition: measures3d.c:93
int lw_dist3d_tri_tri(const LWTRIANGLE *tri1, const LWTRIANGLE *tri2, DISTPTS3D *dl)
triangle to triangle calculation
Definition: measures3d.c:952
double lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfullywithin calculations.
Definition: measures3d.c:344
int lw_dist3d_pt_pt(const POINT3DZ *thep1, const POINT3DZ *thep2, DISTPTS3D *dl)
Compares incoming points and stores the points closest to each other or most far away from each other...
Definition: measures3d.c:1082
int lw_dist3d_seg_seg(const POINT3DZ *s1p1, const POINT3DZ *s1p2, const POINT3DZ *s2p1, const POINT3DZ *s2p2, DISTPTS3D *dl)
Finds the two closest points on two linesegments.
Definition: measures3d.c:1173
int lw_dist3d_line_tri(const LWLINE *line, const LWTRIANGLE *tri, DISTPTS3D *dl)
line to triangle calculation
Definition: measures3d.c:854
static int get_3dcross_product(const VECTOR3D *v1, const VECTOR3D *v2, VECTOR3D *v)
Definition: measures3d.c:44
int lw_dist3d_point_poly(const LWPOINT *point, const LWPOLY *poly, DISTPTS3D *dl)
Computes point to polygon distance For mindistance that means: 1) find the plane of the polygon 2) pr...
Definition: measures3d.c:778
LWGEOM * lwgeom_furthest_line_3d(LWGEOM *lw1, LWGEOM *lw2)
Definition: measures3d.c:116
static int lwgeom_solid_contains_lwgeom(const LWGEOM *solid, const LWGEOM *g)
Definition: measures3d.c:382
LWGEOM * lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures3d.c:122
static int get_3dvector_from_points(const POINT3DZ *p1, const POINT3DZ *p2, VECTOR3D *v)
Definition: measures3d.c:34
int lw_dist3d_pt_seg(const POINT3DZ *p, const POINT3DZ *A, const POINT3DZ *B, DISTPTS3D *dl)
If searching for min distance, this one finds the closest point on segment A-B from p.
Definition: measures3d.c:1026
int lw_dist3d_distribute_bruteforce(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS3D *dl)
This function distributes the brute-force for 3D so far the only type, tasks depending on type.
Definition: measures3d.c:598
int lw_dist3d_line_poly(const LWLINE *line, const LWPOLY *poly, DISTPTS3D *dl)
line to polygon calculation
Definition: measures3d.c:837
static double project_point_on_plane(const POINT3DZ *p, PLANE3D *pl, POINT3DZ *p0)
Finds a point on a plane from where the original point is perpendicular to the plane.
Definition: measures3d.c:57
int lw_dist3d_pt_ptarray(const POINT3DZ *p, const POINTARRAY *pa, DISTPTS3D *dl)
search all the segments of pointarray to see which one is closest to p Returns distance between point...
Definition: measures3d.c:996
int lw_dist3d_ptarray_ptarray(const POINTARRAY *l1, const POINTARRAY *l2, DISTPTS3D *dl)
Finds all combinations of segments between two pointarrays.
Definition: measures3d.c:1122
double distance3d_pt_pt(const POINT3D *p1, const POINT3D *p2)
Definition: measures3d.c:1066
int lw_dist3d_pt_poly(const POINT3DZ *p, const LWPOLY *poly, PLANE3D *plane, POINT3DZ *projp, DISTPTS3D *dl)
Checking if the point projected on the plane of the polygon actually is inside that polygon.
Definition: measures3d.c:1291
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition: measures3d.c:476
int define_plane(const POINTARRAY *pa, PLANE3D *pl)
Definition: measures3d.c:1491
int lw_dist3d_ptarray_poly(const POINTARRAY *pa, const LWPOLY *poly, PLANE3D *plane, DISTPTS3D *dl)
Computes pointarray to polygon distance.
Definition: measures3d.c:1333
int lw_dist3d_point_tri(const LWPOINT *point, const LWTRIANGLE *tri, DISTPTS3D *dl)
Definition: measures3d.c:804
int lw_dist3d_pt_tri(const POINT3DZ *p, const LWTRIANGLE *tri, PLANE3D *plane, POINT3DZ *projp, DISTPTS3D *dl)
Definition: measures3d.c:1317
LWGEOM * lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing 3dclosestpoint calculations.
Definition: measures3d.c:235
int lw_dist3d_point_point(const LWPOINT *point1, const LWPOINT *point2, DISTPTS3D *dl)
point to point calculation
Definition: measures3d.c:739
static int gbox_contains_3d(const GBOX *g1, const GBOX *g2)
Definition: measures3d.c:375
LWGEOM * lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing 3dshortestline and 3dlongestline calculations.
Definition: measures3d.c:131
int lw_dist3d_point_line(const LWPOINT *point, const LWLINE *line, DISTPTS3D *dl)
point to line calculation
Definition: measures3d.c:755
double lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d max distance calculation.
Definition: measures3d.c:334
int lw_dist3d_poly_tri(const LWPOLY *poly, const LWTRIANGLE *tri, DISTPTS3D *dl)
polygon to triangle calculation
Definition: measures3d.c:911
int lw_dist3d_poly_poly(const LWPOLY *poly1, const LWPOLY *poly2, DISTPTS3D *dl)
polygon to polygon calculation
Definition: measures3d.c:870
int lw_dist3d_ptarray_tri(const POINTARRAY *pa, const LWTRIANGLE *tri, PLANE3D *plane, DISTPTS3D *dl)
Computes pointarray to triangle distance.
Definition: measures3d.c:1413
int lw_dist3d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS3D *dl)
This is a recursive function delivering every possible combination of subgeometries.
Definition: measures3d.c:519
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures3d.c:110
double lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d min distance calculation.
Definition: measures3d.c:369
#define DOT(u, v)
Definition: measures3d.h:31
LWGEOM * lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing shortestline and longestline calculations.
Definition: measures.c:84
int lw_dist2d_comp(const LWGEOM *lw1, const LWGEOM *lw2, DISTPTS *dl)
This function just deserializes geometries Bboxes is not checked here since it is the subgeometries b...
Definition: measures.c:239
LWGEOM * lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int32_t srid, int mode)
Function initializing closestpoint calculations.
Definition: measures.c:131
#define DIST_MIN
Definition: measures.h:44
#define DIST_MAX
Definition: measures.h:43
POINT3DZ p2
Definition: measures3d.h:42
int twisted
Definition: measures3d.h:45
POINT3DZ p1
Definition: measures3d.h:41
double distance
Definition: measures3d.h:40
int mode
Definition: measures3d.h:43
double tolerance
Definition: measures3d.h:47
Structure used in distance-calculations.
Definition: measures3d.h:39
POINT2D p1
Definition: measures.h:52
POINT2D p2
Definition: measures.h:53
double tolerance
Definition: measures.h:56
int mode
Definition: measures.h:54
double distance
Definition: measures.h:51
Structure used in distance-calculations.
Definition: measures.h:50
double ymax
Definition: liblwgeom.h:357
double zmax
Definition: liblwgeom.h:359
double xmax
Definition: liblwgeom.h:355
double zmin
Definition: liblwgeom.h:358
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
uint8_t type
Definition: liblwgeom.h:462
int32_t srid
Definition: liblwgeom.h:460
lwflags_t flags
Definition: liblwgeom.h:461
POINTARRAY * points
Definition: liblwgeom.h:483
POINTARRAY * point
Definition: liblwgeom.h:471
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
POINTARRAY * points
Definition: liblwgeom.h:495
POINT3DZ pop
Definition: measures3d.h:57
VECTOR3D pv
Definition: measures3d.h:58
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
double z
Definition: liblwgeom.h:396
double x
Definition: liblwgeom.h:396
double y
Definition: liblwgeom.h:396
double z
Definition: liblwgeom.h:402
double x
Definition: liblwgeom.h:402
double y
Definition: liblwgeom.h:402
double z
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427
double z
Definition: measures3d.h:52
double x
Definition: measures3d.h:52
double y
Definition: measures3d.h:52