PostGIS  2.4.9dev-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  *
23  **********************************************************************/
24 
25 
26 /**********************************************************************
27  *
28  * PostGIS - Spatial Types for PostgreSQL
29  * http://postgis.net
30  * Copyright 2011 Nicklas Avén
31  *
32  * This is free software; you can redistribute and/or modify it under
33  * the terms of the GNU General Public Licence. See the COPYING file.
34  *
35  **********************************************************************/
36 
37 #include <string.h>
38 #include <stdlib.h>
39 
40 #include "measures3d.h"
41 #include "lwgeom_log.h"
42 
43 
44 static inline int
46 {
47  v->x=p2->x-p1->x;
48  v->y=p2->y-p1->y;
49  v->z=p2->z-p1->z;
50 
51  return (!FP_IS_ZERO(v->x) || !FP_IS_ZERO(v->y) || !FP_IS_ZERO(v->z));
52 }
53 
54 static inline int
56 {
57  v->x=(v1->y*v2->z)-(v1->z*v2->y);
58  v->y=(v1->z*v2->x)-(v1->x*v2->z);
59  v->z=(v1->x*v2->y)-(v1->y*v2->x);
60 
61  return (!FP_IS_ZERO(v->x) || !FP_IS_ZERO(v->y) || !FP_IS_ZERO(v->z));
62 }
63 
64 
70 static
71 LWGEOM* create_v_line(const LWGEOM *lwgeom,double x, double y, int srid)
72 {
73 
74  LWPOINT *lwpoints[2];
75  GBOX gbox;
76  int rv = lwgeom_calculate_gbox(lwgeom, &gbox);
77 
78  if ( rv == LW_FAILURE )
79  return NULL;
80 
81  lwpoints[0] = lwpoint_make3dz(srid, x, y, gbox.zmin);
82  lwpoints[1] = lwpoint_make3dz(srid, x, y, gbox.zmax);
83 
84  return (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);
85 }
86 
87 LWGEOM *
88 lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
89 {
90  return lw_dist3d_distanceline(lw1, lw2, lw1->srid, DIST_MIN);
91 }
92 
93 LWGEOM *
95 {
96  return lw_dist3d_distanceline(lw1, lw2, lw1->srid, DIST_MAX);
97 }
98 
99 LWGEOM *
100 lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
101 {
102  return lw_dist3d_distancepoint(lw1, lw2, lw1->srid, DIST_MIN);
103 }
104 
105 
109 LWGEOM *
110 lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
111 {
112  LWDEBUG(2, "lw_dist3d_distanceline is called");
113  double x1,x2,y1,y2, z1, z2, x, y;
114  double initdistance = ( mode == DIST_MIN ? FLT_MAX : -1.0);
115  DISTPTS3D thedl;
116  LWPOINT *lwpoints[2];
117  LWGEOM *result;
118 
119  thedl.mode = mode;
120  thedl.distance = initdistance;
121  thedl.tolerance = 0.0;
122 
123  /*Check if we really have 3D geoemtries*/
124  /*If not, send it to 2D-calculations which will give the same result*/
125  /*as an infinite z-value at one or two of the geometries*/
126  if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
127  {
128 
129  lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
130 
131  if(!lwgeom_has_z(lw1) && !lwgeom_has_z(lw2))
132  return lw_dist2d_distanceline(lw1, lw2, srid, mode);
133 
134  DISTPTS thedl2d;
135  thedl2d.mode = mode;
136  thedl2d.distance = initdistance;
137  thedl2d.tolerance = 0.0;
138  if (!lw_dist2d_comp( lw1,lw2,&thedl2d))
139  {
140  /*should never get here. all cases ought to be error handled earlier*/
141  lwerror("Some unspecified error.");
142  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
143  }
144  LWGEOM *vertical_line;
145  if(!lwgeom_has_z(lw1))
146  {
147  x=thedl2d.p1.x;
148  y=thedl2d.p1.y;
149 
150  vertical_line = create_v_line(lw2,x,y,srid);
151  if (!lw_dist3d_recursive(vertical_line, lw2, &thedl))
152  {
153  /*should never get here. all cases ought to be error handled earlier*/
154  lwfree(vertical_line);
155  lwerror("Some unspecified error.");
156  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
157  }
158  lwfree(vertical_line);
159  }
160  if(!lwgeom_has_z(lw2))
161  {
162  x=thedl2d.p2.x;
163  y=thedl2d.p2.y;
164 
165  vertical_line = create_v_line(lw1,x,y,srid);
166  if (!lw_dist3d_recursive(lw1, vertical_line, &thedl))
167  {
168  /*should never get here. all cases ought to be error handled earlier*/
169  lwfree(vertical_line);
170  lwerror("Some unspecified error.");
171  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
172  }
173  lwfree(vertical_line);
174  }
175 
176  }
177  else
178  {
179  if (!lw_dist3d_recursive(lw1, lw2, &thedl))
180  {
181  /*should never get here. all cases ought to be error handled earlier*/
182  lwerror("Some unspecified error.");
183  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
184  }
185  }
186  /*if thedl.distance is unchanged there where only empty geometries input*/
187  if (thedl.distance == initdistance)
188  {
189  LWDEBUG(3, "didn't find geometries to measure between, returning null");
190  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
191  }
192  else
193  {
194  x1=thedl.p1.x;
195  y1=thedl.p1.y;
196  z1=thedl.p1.z;
197  x2=thedl.p2.x;
198  y2=thedl.p2.y;
199  z2=thedl.p2.z;
200 
201  lwpoints[0] = lwpoint_make3dz(srid, x1, y1, z1);
202  lwpoints[1] = lwpoint_make3dz(srid, x2, y2, z2);
203 
204  result = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);
205  }
206 
207  return result;
208 }
209 
213 LWGEOM *
214 lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
215 {
216 
217  double x,y,z;
218  DISTPTS3D thedl;
219  double initdistance = FLT_MAX;
220  LWGEOM *result;
221 
222  thedl.mode = mode;
223  thedl.distance= initdistance;
224  thedl.tolerance = 0;
225 
226  LWDEBUG(2, "lw_dist3d_distancepoint is called");
227 
228  /*Check if we really have 3D geoemtries*/
229  /*If not, send it to 2D-calculations which will give the same result*/
230  /*as an infinite z-value at one or two of the geometries*/
231  if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
232  {
233  lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
234 
235  if(!lwgeom_has_z(lw1) && !lwgeom_has_z(lw2))
236  return lw_dist2d_distancepoint(lw1, lw2, srid, mode);
237 
238 
239  DISTPTS thedl2d;
240  thedl2d.mode = mode;
241  thedl2d.distance = initdistance;
242  thedl2d.tolerance = 0.0;
243  if (!lw_dist2d_comp( lw1,lw2,&thedl2d))
244  {
245  /*should never get here. all cases ought to be error handled earlier*/
246  lwerror("Some unspecified error.");
247  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
248  }
249 
250  LWGEOM *vertical_line;
251  if(!lwgeom_has_z(lw1))
252  {
253  x=thedl2d.p1.x;
254  y=thedl2d.p1.y;
255 
256  vertical_line = create_v_line(lw2,x,y,srid);
257  if (!lw_dist3d_recursive(vertical_line, lw2, &thedl))
258  {
259  /*should never get here. all cases ought to be error handled earlier*/
260  lwfree(vertical_line);
261  lwerror("Some unspecified error.");
262  return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
263  }
264  lwfree(vertical_line);
265  }
266 
267  if(!lwgeom_has_z(lw2))
268  {
269  x=thedl2d.p2.x;
270  y=thedl2d.p2.y;
271 
272  vertical_line = create_v_line(lw1,x,y,srid);
273  if (!lw_dist3d_recursive(lw1, vertical_line, &thedl))
274  {
275  /*should never get here. all cases ought to be error handled earlier*/
276  lwfree(vertical_line);
277  lwerror("Some unspecified error.");
278  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
279  }
280  lwfree(vertical_line);
281  }
282 
283  }
284  else
285  {
286  if (!lw_dist3d_recursive(lw1, lw2, &thedl))
287  {
288  /*should never get here. all cases ought to be error handled earlier*/
289  lwerror("Some unspecified error.");
290  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
291  }
292  }
293  if (thedl.distance == initdistance)
294  {
295  LWDEBUG(3, "didn't find geometries to measure between, returning null");
296  result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
297  }
298  else
299  {
300  x=thedl.p1.x;
301  y=thedl.p1.y;
302  z=thedl.p1.z;
303  result = (LWGEOM *)lwpoint_make3dz(srid, x, y, z);
304  }
305 
306  return result;
307 }
308 
309 
313 double
314 lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
315 {
316  LWDEBUG(2, "lwgeom_maxdistance3d is called");
317 
318  return lwgeom_maxdistance3d_tolerance( lw1, lw2, 0.0 );
319 }
320 
325 double
326 lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
327 {
328  if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
329  {
330  lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
331  return lwgeom_maxdistance2d_tolerance(lw1, lw2, tolerance);
332  }
333  /*double thedist;*/
334  DISTPTS3D thedl;
335  LWDEBUG(2, "lwgeom_maxdistance3d_tolerance is called");
336  thedl.mode = DIST_MAX;
337  thedl.distance= -1;
338  thedl.tolerance = tolerance;
339  if (lw_dist3d_recursive(lw1, lw2, &thedl))
340  {
341  return thedl.distance;
342  }
343  /*should never get here. all cases ought to be error handled earlier*/
344  lwerror("Some unspecified error.");
345  return -1;
346 }
347 
351 double
352 lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
353 {
354  LWDEBUG(2, "lwgeom_mindistance3d is called");
355  return lwgeom_mindistance3d_tolerance( lw1, lw2, 0.0 );
356 }
357 
362 double
363 lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
364 {
365  if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
366  {
367  lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
368 
369  return lwgeom_mindistance2d_tolerance(lw1, lw2, tolerance);
370  }
371  DISTPTS3D thedl;
372  LWDEBUG(2, "lwgeom_mindistance3d_tolerance is called");
373  thedl.mode = DIST_MIN;
374  thedl.distance= FLT_MAX;
375  thedl.tolerance = tolerance;
376  if (lw_dist3d_recursive(lw1, lw2, &thedl))
377  {
378  return thedl.distance;
379  }
380  /*should never get here. all cases ought to be error handled earlier*/
381  lwerror("Some unspecified error.");
382  return FLT_MAX;
383 }
384 
385 
386 /*------------------------------------------------------------------------------------------------------------
387 End of Initializing functions
388 --------------------------------------------------------------------------------------------------------------*/
389 
390 /*------------------------------------------------------------------------------------------------------------
391 Preprocessing functions
392 Functions preparing geometries for distance-calculations
393 --------------------------------------------------------------------------------------------------------------*/
394 
395 
399 int lw_dist3d_recursive(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS3D *dl)
400 {
401  int i, j;
402  int n1=1;
403  int n2=1;
404  LWGEOM *g1 = NULL;
405  LWGEOM *g2 = NULL;
406  LWCOLLECTION *c1 = NULL;
407  LWCOLLECTION *c2 = NULL;
408 
409  LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type);
410 
411  if (lwgeom_is_collection(lwg1))
412  {
413  LWDEBUG(3, "First geometry is collection");
414  c1 = lwgeom_as_lwcollection(lwg1);
415  n1 = c1->ngeoms;
416  }
417  if (lwgeom_is_collection(lwg2))
418  {
419  LWDEBUG(3, "Second geometry is collection");
420  c2 = lwgeom_as_lwcollection(lwg2);
421  n2 = c2->ngeoms;
422  }
423 
424  for ( i = 0; i < n1; i++ )
425  {
426 
427  if (lwgeom_is_collection(lwg1))
428  {
429  g1 = c1->geoms[i];
430  }
431  else
432  {
433  g1 = (LWGEOM*)lwg1;
434  }
435 
436  if (lwgeom_is_empty(g1)) return LW_TRUE;
437 
438  if (lwgeom_is_collection(g1))
439  {
440  LWDEBUG(3, "Found collection inside first geometry collection, recursing");
441  if (!lw_dist3d_recursive(g1, lwg2, dl)) return LW_FALSE;
442  continue;
443  }
444  for ( j = 0; j < n2; j++ )
445  {
446  if (lwgeom_is_collection(lwg2))
447  {
448  g2 = c2->geoms[j];
449  }
450  else
451  {
452  g2 = (LWGEOM*)lwg2;
453  }
454  if (lwgeom_is_collection(g2))
455  {
456  LWDEBUG(3, "Found collection inside second geometry collection, recursing");
457  if (!lw_dist3d_recursive(g1, g2, dl)) return LW_FALSE;
458  continue;
459  }
460 
461 
462  /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/
463  if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE;
464 
465 
466  if (!lw_dist3d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE;
467  if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/
468  }
469  }
470  return LW_TRUE;
471 }
472 
473 
474 
479 int
481 {
482 
483  int t1 = lwg1->type;
484  int t2 = lwg2->type;
485 
486  LWDEBUGF(2, "lw_dist3d_distribute_bruteforce is called with typ1=%d, type2=%d", lwg1->type, lwg2->type);
487 
488  if ( t1 == POINTTYPE )
489  {
490  if ( t2 == POINTTYPE )
491  {
492  dl->twisted=1;
493  return lw_dist3d_point_point((LWPOINT *)lwg1, (LWPOINT *)lwg2, dl);
494  }
495  else if ( t2 == LINETYPE )
496  {
497  dl->twisted=1;
498  return lw_dist3d_point_line((LWPOINT *)lwg1, (LWLINE *)lwg2, dl);
499  }
500  else if ( t2 == POLYGONTYPE )
501  {
502  dl->twisted=1;
503  return lw_dist3d_point_poly((LWPOINT *)lwg1, (LWPOLY *)lwg2,dl);
504  }
505  else
506  {
507  lwerror("Unsupported geometry type: %s", lwtype_name(t2));
508  return LW_FALSE;
509  }
510  }
511  else if ( t1 == LINETYPE )
512  {
513  if ( t2 == POINTTYPE )
514  {
515  dl->twisted=(-1);
516  return lw_dist3d_point_line((LWPOINT *)lwg2,(LWLINE *)lwg1,dl);
517  }
518  else if ( t2 == LINETYPE )
519  {
520  dl->twisted=1;
521  return lw_dist3d_line_line((LWLINE *)lwg1,(LWLINE *)lwg2,dl);
522  }
523  else if ( t2 == POLYGONTYPE )
524  {
525  dl->twisted=1;
526  return lw_dist3d_line_poly((LWLINE *)lwg1,(LWPOLY *)lwg2,dl);
527  }
528  else
529  {
530  lwerror("Unsupported geometry type: %s", lwtype_name(t2));
531  return LW_FALSE;
532  }
533  }
534  else if ( t1 == POLYGONTYPE )
535  {
536  if ( t2 == POLYGONTYPE )
537  {
538  dl->twisted=1;
539  return lw_dist3d_poly_poly((LWPOLY *)lwg1, (LWPOLY *)lwg2,dl);
540  }
541  else if ( t2 == POINTTYPE )
542  {
543  dl->twisted=-1;
544  return lw_dist3d_point_poly((LWPOINT *)lwg2, (LWPOLY *)lwg1,dl);
545  }
546  else if ( t2 == LINETYPE )
547  {
548  dl->twisted=-1;
549  return lw_dist3d_line_poly((LWLINE *)lwg2,(LWPOLY *)lwg1,dl);
550  }
551  else
552  {
553  lwerror("Unsupported geometry type: %s", lwtype_name(t2));
554  return LW_FALSE;
555  }
556  }
557  else
558  {
559  lwerror("Unsupported geometry type: %s", lwtype_name(t1));
560  return LW_FALSE;
561  }
562  /*You shouldn't being able to get here*/
563  lwerror("unspecified error in function lw_dist3d_distribute_bruteforce");
564  return LW_FALSE;
565 }
566 
567 
568 
569 /*------------------------------------------------------------------------------------------------------------
570 End of Preprocessing functions
571 --------------------------------------------------------------------------------------------------------------*/
572 
573 
574 /*------------------------------------------------------------------------------------------------------------
575 Brute force functions
576 So far the only way to do 3D-calculations
577 --------------------------------------------------------------------------------------------------------------*/
578 
583 int
585 {
586  POINT3DZ p1;
587  POINT3DZ p2;
588  LWDEBUG(2, "lw_dist3d_point_point is called");
589 
590  getPoint3dz_p(point1->point, 0, &p1);
591  getPoint3dz_p(point2->point, 0, &p2);
592 
593  return lw_dist3d_pt_pt(&p1, &p2,dl);
594 }
599 int
601 {
602  POINT3DZ p;
603  POINTARRAY *pa = line->points;
604  LWDEBUG(2, "lw_dist3d_point_line is called");
605 
606  getPoint3dz_p(point->point, 0, &p);
607  return lw_dist3d_pt_ptarray(&p, pa, dl);
608 }
609 
621 int
623 {
624  POINT3DZ p, projp;/*projp is "point projected on plane"*/
625  PLANE3D plane;
626  LWDEBUG(2, "lw_dist3d_point_poly is called");
627  getPoint3dz_p(point->point, 0, &p);
628 
629  /*If we are lookig for max distance, longestline or dfullywithin*/
630  if (dl->mode == DIST_MAX)
631  {
632  LWDEBUG(3, "looking for maxdistance");
633  return lw_dist3d_pt_ptarray(&p, poly->rings[0], dl);
634  }
635 
636  /*Find the plane of the polygon, the "holes" have to be on the same plane. so we only care about the boudary*/
637  if(!define_plane(poly->rings[0], &plane))
638  {
639  /* Polygon does not define a plane: Return distance point -> line */
640  return lw_dist3d_pt_ptarray(&p, poly->rings[0], dl);
641  }
642 
643  /*get our point projected on the plane of the polygon*/
644  project_point_on_plane(&p, &plane, &projp);
645 
646  return lw_dist3d_pt_poly(&p, poly,&plane, &projp, dl);
647 }
648 
649 
654 int
656 {
657  POINTARRAY *pa1 = line1->points;
658  POINTARRAY *pa2 = line2->points;
659  LWDEBUG(2, "lw_dist3d_line_line is called");
660 
661  return lw_dist3d_ptarray_ptarray(pa1, pa2, dl);
662 }
663 
669 {
670  PLANE3D plane;
671  LWDEBUG(2, "lw_dist3d_line_poly is called");
672 
673  if (dl->mode == DIST_MAX)
674  {
675  return lw_dist3d_ptarray_ptarray(line->points, poly->rings[0], dl);
676  }
677 
678  if(!define_plane(poly->rings[0], &plane))
679  {
680  /* Polygon does not define a plane: Return distance line to line */
681  return lw_dist3d_ptarray_ptarray(line->points, poly->rings[0], dl);
682  }
683 
684  return lw_dist3d_ptarray_poly(line->points, poly,&plane, dl);
685 }
686 
691 int lw_dist3d_poly_poly(LWPOLY *poly1, LWPOLY *poly2, DISTPTS3D *dl)
692 {
693  PLANE3D plane1, plane2;
694  int planedef1, planedef2;
695  LWDEBUG(2, "lw_dist3d_poly_poly is called");
696  if (dl->mode == DIST_MAX)
697  {
698  return lw_dist3d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
699  }
700 
701  planedef1 = define_plane(poly1->rings[0], &plane1);
702  planedef2 = define_plane(poly2->rings[0], &plane2);
703 
704  if (!planedef1 || !planedef2)
705  {
706  if (!planedef1 && !planedef2)
707  {
708  /* Neither polygon define a plane: Return distance line to line */
709  return lw_dist3d_ptarray_ptarray(poly1->rings[0], poly2->rings[0], dl);
710  }
711 
712  if (!planedef1)
713  {
714  /* Only poly2 defines a plane: Return distance from line (poly1) to poly2 */
715  return lw_dist3d_ptarray_poly(poly1->rings[0], poly2, &plane2, dl);
716  }
717 
718  /* Only poly1 defines a plane: Return distance from line (poly2) to poly1 */
719  return lw_dist3d_ptarray_poly(poly2->rings[0], poly1, &plane1, dl);
720  }
721 
722  /*What we do here is to compare the boundary of one polygon with the other polygon
723  and then take the second boundary comparing with the first polygon*/
724  dl->twisted=1;
725  if (!lw_dist3d_ptarray_poly(poly1->rings[0], poly2, &plane2, dl))
726  return LW_FALSE;
727  if (dl->distance < dl->tolerance) /*Just check if the answer already is given*/
728  return LW_TRUE;
729 
730  dl->twisted=-1; /*because we switch the order of geometries we switch "twisted" to -1 which will give the right order of points in shortest line.*/
731  return lw_dist3d_ptarray_poly(poly2->rings[0], poly1, &plane1, dl);
732 }
733 
739 int
741 {
742  int t;
743  POINT3DZ start, end;
744  int twist = dl->twisted;
745 
746  LWDEBUG(2, "lw_dist3d_pt_ptarray is called");
747 
748  getPoint3dz_p(pa, 0, &start);
749 
750  for (t=1; t<pa->npoints; t++)
751  {
752  dl->twisted=twist;
753  getPoint3dz_p(pa, t, &end);
754  if (!lw_dist3d_pt_seg(p, &start, &end,dl)) return LW_FALSE;
755 
756  if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/
757  start = end;
758  }
759 
760  return LW_TRUE;
761 }
762 
763 
769 int
771 {
772  POINT3DZ c;
773  double r;
774  /*if start==end, then use pt distance */
775  if ( ( A->x == B->x) && (A->y == B->y) && (A->z == B->z) )
776  {
777  return lw_dist3d_pt_pt(p,A,dl);
778  }
779 
780 
781  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) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y)+(B->z-A->z)*(B->z-A->z) );
782 
783  /*This is for finding the 3Dmaxdistance.
784  the maxdistance have to be between two vertexes,
785  compared to mindistance which can be between
786  tvo vertexes vertex.*/
787  if (dl->mode == DIST_MAX)
788  {
789  if (r>=0.5)
790  {
791  return lw_dist3d_pt_pt(p,A,dl);
792  }
793  if (r<0.5)
794  {
795  return lw_dist3d_pt_pt(p,B,dl);
796  }
797  }
798 
799  if (r<0) /*If the first vertex A is closest to the point p*/
800  {
801  return lw_dist3d_pt_pt(p,A,dl);
802  }
803  if (r>1) /*If the second vertex B is closest to the point p*/
804  {
805  return lw_dist3d_pt_pt(p,B,dl);
806  }
807 
808  /*else if the point p is closer to some point between a and b
809  then we find that point and send it to lw_dist3d_pt_pt*/
810  c.x=A->x + r * (B->x-A->x);
811  c.y=A->y + r * (B->y-A->y);
812  c.z=A->z + r * (B->z-A->z);
813 
814  return lw_dist3d_pt_pt(p,&c,dl);
815 }
816 
817 double
819 {
820  double dx = p2->x - p1->x;
821  double dy = p2->y - p1->y;
822  double dz = p2->z - p1->z;
823  return sqrt ( dx*dx + dy*dy + dz*dz);
824 }
825 
826 
834 int
836 {
837  double dx = thep2->x - thep1->x;
838  double dy = thep2->y - thep1->y;
839  double dz = thep2->z - thep1->z;
840  double dist = sqrt ( dx*dx + dy*dy + dz*dz);
841  LWDEBUGF(2, "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)",thep1->x,thep1->y,thep1->z,thep2->x,thep2->y,thep2->z );
842 
843  if (((dl->distance - dist)*(dl->mode))>0) /*multiplication with mode to handle mindistance (mode=1) and maxdistance (mode = (-1)*/
844  {
845  dl->distance = dist;
846 
847  if (dl->twisted>0) /*To get the points in right order. twisted is updated between 1 and (-1) every time the order is changed earlier in the chain*/
848  {
849  dl->p1 = *thep1;
850  dl->p2 = *thep2;
851  }
852  else
853  {
854  dl->p1 = *thep2;
855  dl->p2 = *thep1;
856  }
857  }
858  return LW_TRUE;
859 }
860 
861 
866 int
868 {
869  int t,u;
870  POINT3DZ start, end;
871  POINT3DZ start2, end2;
872  int twist = dl->twisted;
873  LWDEBUGF(2, "lw_dist3d_ptarray_ptarray called (points: %d-%d)",l1->npoints, l2->npoints);
874 
875 
876 
877  if (dl->mode == DIST_MAX)/*If we are searching for maxdistance we go straight to point-point calculation since the maxdistance have to be between two vertexes*/
878  {
879  for (t=0; t<l1->npoints; t++) /*for each segment in L1 */
880  {
881  getPoint3dz_p(l1, t, &start);
882  for (u=0; u<l2->npoints; u++) /*for each segment in L2 */
883  {
884  getPoint3dz_p(l2, u, &start2);
885  lw_dist3d_pt_pt(&start,&start2,dl);
886  LWDEBUGF(4, "maxdist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance);
887  LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f",
888  t, u, dl->distance, dl->tolerance);
889  }
890  }
891  }
892  else
893  {
894  getPoint3dz_p(l1, 0, &start);
895  for (t=1; t<l1->npoints; t++) /*for each segment in L1 */
896  {
897  getPoint3dz_p(l1, t, &end);
898  getPoint3dz_p(l2, 0, &start2);
899  for (u=1; u<l2->npoints; u++) /*for each segment in L2 */
900  {
901  getPoint3dz_p(l2, u, &end2);
902  dl->twisted=twist;
903  lw_dist3d_seg_seg(&start, &end, &start2, &end2,dl);
904  LWDEBUGF(4, "mindist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance);
905  LWDEBUGF(3, " seg%d-seg%d dist: %f, mindist: %f",
906  t, u, dl->distance, dl->tolerance);
907  if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/
908  start2 = end2;
909  }
910  start = end;
911  }
912  }
913  return LW_TRUE;
914 }
915 
920 int
922 {
923  VECTOR3D v1, v2, vl;
924  double s1k, s2k; /*two variables representing where on Line 1 (s1k) and where on Line 2 (s2k) a connecting line between the two lines is perpendicular to both lines*/
925  POINT3DZ p1, p2;
926  double a, b, c, d, e, D;
927 
928  /*s1p1 and s1p2 are the same point */
929  if ( ( s1p1->x == s1p2->x) && (s1p1->y == s1p2->y) && (s1p1->z == s1p2->z) )
930  {
931  return lw_dist3d_pt_seg(s1p1,s2p1,s2p2,dl);
932  }
933  /*s2p1 and s2p2 are the same point */
934  if ( ( s2p1->x == s2p2->x) && (s2p1->y == s2p2->y) && (s2p1->z == s2p2->z) )
935  {
936  dl->twisted= ((dl->twisted) * (-1));
937  return lw_dist3d_pt_seg(s2p1,s1p1,s1p2,dl);
938  }
939 
940 /*
941  Here we use algorithm from softsurfer.com
942  that can be found here
943  http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
944 */
945 
946  if (!get_3dvector_from_points(s1p1, s1p2, &v1))
947  return LW_FALSE;
948 
949  if (!get_3dvector_from_points(s2p1, s2p2, &v2))
950  return LW_FALSE;
951 
952  if (!get_3dvector_from_points(s2p1, s1p1, &vl))
953  return LW_FALSE;
954 
955  a = DOT(v1,v1);
956  b = DOT(v1,v2);
957  c = DOT(v2,v2);
958  d = DOT(v1,vl);
959  e = DOT(v2,vl);
960  D = a*c - b*b;
961 
962 
963  if (D <0.000000001)
964  { /* the lines are almost parallel*/
965  s1k = 0.0; /*If the lines are paralell we try by using the startpoint of first segment. If that gives a projected point on the second line outside segment 2 it wil be found that s2k is >1 or <0.*/
966  if(b>c) /* use the largest denominator*/
967  {
968  s2k=d/b;
969  }
970  else
971  {
972  s2k =e/c;
973  }
974  }
975  else
976  {
977  s1k = (b*e - c*d) / D;
978  s2k = (a*e - b*d) / D;
979  }
980 
981  /* Now we check if the projected closest point on the infinite lines is outside our segments. If so the combinations with start and end points will be tested*/
982  if(s1k<0.0||s1k>1.0||s2k<0.0||s2k>1.0)
983  {
984  if(s1k<0.0)
985  {
986 
987  if (!lw_dist3d_pt_seg(s1p1, s2p1, s2p2, dl))
988  {
989  return LW_FALSE;
990  }
991  }
992  if(s1k>1.0)
993  {
994 
995  if (!lw_dist3d_pt_seg(s1p2, s2p1, s2p2, dl))
996  {
997  return LW_FALSE;
998  }
999  }
1000  if(s2k<0.0)
1001  {
1002  dl->twisted= ((dl->twisted) * (-1));
1003  if (!lw_dist3d_pt_seg(s2p1, s1p1, s1p2, dl))
1004  {
1005  return LW_FALSE;
1006  }
1007  }
1008  if(s2k>1.0)
1009  {
1010  dl->twisted= ((dl->twisted) * (-1));
1011  if (!lw_dist3d_pt_seg(s2p2, s1p1, s1p2, dl))
1012  {
1013  return LW_FALSE;
1014  }
1015  }
1016  }
1017  else
1018  {/*Find the closest point on the edges of both segments*/
1019  p1.x=s1p1->x+s1k*(s1p2->x-s1p1->x);
1020  p1.y=s1p1->y+s1k*(s1p2->y-s1p1->y);
1021  p1.z=s1p1->z+s1k*(s1p2->z-s1p1->z);
1022 
1023  p2.x=s2p1->x+s2k*(s2p2->x-s2p1->x);
1024  p2.y=s2p1->y+s2k*(s2p2->y-s2p1->y);
1025  p2.z=s2p1->z+s2k*(s2p2->z-s2p1->z);
1026 
1027  if (!lw_dist3d_pt_pt(&p1,&p2,dl))/* Send the closest points to point-point calculation*/
1028  {
1029  return LW_FALSE;
1030  }
1031  }
1032  return LW_TRUE;
1033 }
1034 
1042 int
1044 {
1045  int i;
1046 
1047  LWDEBUG(2, "lw_dist3d_point_poly called");
1048 
1049 
1050  if(pt_in_ring_3d(projp, poly->rings[0], plane))
1051  {
1052  for (i=1; i<poly->nrings; i++)
1053  {
1054  /* Inside a hole. Distance = pt -> ring */
1055  if ( pt_in_ring_3d(projp, poly->rings[i], plane ))
1056  {
1057  LWDEBUG(3, " inside an hole");
1058  return lw_dist3d_pt_ptarray(p, poly->rings[i], dl);
1059  }
1060  }
1061 
1062  return lw_dist3d_pt_pt(p,projp,dl);/* If the projected point is inside the polygon the shortest distance is between that point and the inputed point*/
1063  }
1064  else
1065  {
1066  return lw_dist3d_pt_ptarray(p, poly->rings[0], dl); /*If the projected point is outside the polygon we search for the closest distance against the boundarry instead*/
1067  }
1068 
1069  return LW_TRUE;
1070 
1071 }
1072 
1078 {
1079 
1080 
1081  int i,j,k;
1082  double f, s1, s2;
1083  VECTOR3D projp1_projp2;
1084  POINT3DZ p1, p2,projp1, projp2, intersectionp;
1085 
1086  getPoint3dz_p(pa, 0, &p1);
1087 
1089  &p1, plane, &projp1); /*the sign of s1 tells us on which side of the plane the point is. */
1090  lw_dist3d_pt_poly(&p1, poly, plane,&projp1, dl);
1091  if ((s1 == 0.0) && (dl->distance < dl->tolerance))
1092  {
1093  return LW_TRUE;
1094  }
1095 
1096  for (i=1;i<pa->npoints;i++)
1097  {
1098  int intersects;
1099  getPoint3dz_p(pa, i, &p2);
1100  s2=project_point_on_plane(&p2, plane, &projp2);
1101  lw_dist3d_pt_poly(&p2, poly, plane,&projp2, dl);
1102  if ((s2 == 0.0) && (dl->distance < dl->tolerance))
1103  {
1104  return LW_TRUE;
1105  }
1106 
1107  /*If s1and s2 has different signs that means they are on different sides of the plane of the polygon.
1108  That means that the edge between the points crosses the plane and might intersect with the polygon*/
1109  if ((s1 * s2) < 0)
1110  {
1111  f=fabs(s1)/(fabs(s1)+fabs(s2)); /*The size of s1 and s2 is the distance from the point to the plane.*/
1112  get_3dvector_from_points(&projp1, &projp2,&projp1_projp2);
1113 
1114  /*get the point where the line segment crosses the plane*/
1115  intersectionp.x=projp1.x+f*projp1_projp2.x;
1116  intersectionp.y=projp1.y+f*projp1_projp2.y;
1117  intersectionp.z=projp1.z+f*projp1_projp2.z;
1118 
1119  intersects = LW_TRUE; /*We set intersects to true until the opposite is proved*/
1120 
1121  if(pt_in_ring_3d(&intersectionp, poly->rings[0], plane)) /*Inside outer ring*/
1122  {
1123  for (k=1;k<poly->nrings; k++)
1124  {
1125  /* Inside a hole, so no intersection with the polygon*/
1126  if ( pt_in_ring_3d(&intersectionp, poly->rings[k], plane ))
1127  {
1128  intersects=LW_FALSE;
1129  break;
1130  }
1131  }
1132  if(intersects)
1133  {
1134  dl->distance=0.0;
1135  dl->p1.x=intersectionp.x;
1136  dl->p1.y=intersectionp.y;
1137  dl->p1.z=intersectionp.z;
1138 
1139  dl->p2.x=intersectionp.x;
1140  dl->p2.y=intersectionp.y;
1141  dl->p2.z=intersectionp.z;
1142  return LW_TRUE;
1143 
1144  }
1145  }
1146  }
1147 
1148  projp1=projp2;
1149  s1=s2;
1150  p1=p2;
1151  }
1152 
1153  /*check or pointarray against boundary and inner boundaries of the polygon*/
1154  for (j=0;j<poly->nrings;j++)
1155  {
1156  lw_dist3d_ptarray_ptarray(pa, poly->rings[j], dl);
1157  }
1158 
1159 return LW_TRUE;
1160 }
1161 
1162 
1163 /* Here we define the plane of a polygon (boundary pointarray of a polygon)
1164  * the plane is stored as a point in plane (plane.pop) and a normal vector (plane.pv)
1165  *
1166  * We are calculating the average point and using it to break the polygon into
1167  * POL_BREAKS (3) parts. Then we calculate the normal of those 3 vectors and
1168  * use its average to define the normal of the plane.This is done to minimize
1169  * the error introduced by FP precision
1170  * We use [3] breaks to contemplate the special case of 3d triangles
1171  */
1172 int
1174 {
1175  const uint32_t POL_BREAKS = 3;
1176  uint32_t unique_points = pa->npoints - 1;
1177  uint32_t i;
1178 
1179  /* Calculate the average point */
1180  pl->pop.x = 0.0;
1181  pl->pop.y = 0.0;
1182  pl->pop.z = 0.0;
1183  for (i = 0; i < unique_points; i++)
1184  {
1185  POINT3DZ p;
1186  getPoint3dz_p(pa, i, &p);
1187  pl->pop.x += p.x;
1188  pl->pop.y += p.y;
1189  pl->pop.z += p.z;
1190  }
1191 
1192  pl->pop.x /= unique_points;
1193  pl->pop.y /= unique_points;
1194  pl->pop.z /= unique_points;
1195 
1196  pl->pv.x = 0.0;
1197  pl->pv.y = 0.0;
1198  pl->pv.z = 0.0;
1199  for (i = 0; i < POL_BREAKS; i++)
1200  {
1201  POINT3DZ point1, point2;
1202  VECTOR3D v1, v2, vp;
1203  uint32_t n1, n2;
1204  n1 = i * unique_points / POL_BREAKS;
1205  n2 = n1 + unique_points / POL_BREAKS; /* May overflow back to the first / last point */
1206 
1207  if (n1 == n2)
1208  continue;
1209 
1210  getPoint3dz_p(pa, n1, &point1);
1211  if (!get_3dvector_from_points(&pl->pop, &point1, &v1))
1212  continue;
1213 
1214  getPoint3dz_p(pa, n2, &point2);
1215  if (!get_3dvector_from_points(&pl->pop, &point2, &v2))
1216  continue;
1217 
1218  if (get_3dcross_product(&v1, &v2, &vp))
1219  {
1220  /* If the cross product isn't zero these 3 points aren't collinear
1221  * We divide by its lengthsq to normalize the additions */
1222  double vl = vp.x * vp.x + vp.y * vp.y + vp.z * vp.z;
1223  pl->pv.x += vp.x / vl;
1224  pl->pv.y += vp.y / vl;
1225  pl->pv.z += vp.z / vl;
1226  }
1227  }
1228 
1229  return (!FP_IS_ZERO(pl->pv.x) || !FP_IS_ZERO(pl->pv.y) || !FP_IS_ZERO(pl->pv.z));
1230 }
1231 
1236 double
1238 {
1239 /*In our plane definition we have a point on the plane and a normal vektor (pl.pv), perpendicular to the plane
1240 this vector will be paralell to the line between our inputted point above the plane and the point we are searching for on the plane.
1241 So, we already have a direction from p to find p0, but we don't know the distance.
1242 */
1243 
1244  VECTOR3D v1;
1245  double f;
1246 
1247  if (!get_3dvector_from_points(&(pl->pop), p, &v1))
1248  return 0.0;
1249 
1250  f = DOT(pl->pv, v1);
1251  if (FP_IS_ZERO(f))
1252  {
1253  /* Point is in the plane */
1254  *p0 = *p;
1255  return 0;
1256  }
1257 
1258  f = -f / DOT(pl->pv, pl->pv);
1259 
1260  p0->x = p->x + pl->pv.x * f;
1261  p0->y = p->y + pl->pv.y * f;
1262  p0->z = p->z + pl->pv.z * f;
1263 
1264  return f;
1265 }
1266 
1267 
1268 
1269 
1282 int
1283 pt_in_ring_3d(const POINT3DZ *p, const POINTARRAY *ring,PLANE3D *plane)
1284 {
1285 
1286  int cn = 0; /* the crossing number counter */
1287  int i;
1288  POINT3DZ v1, v2;
1289 
1290  POINT3DZ first, last;
1291 
1292  getPoint3dz_p(ring, 0, &first);
1293  getPoint3dz_p(ring, ring->npoints-1, &last);
1294  if ( memcmp(&first, &last, sizeof(POINT3DZ)) )
1295  {
1296  lwerror("pt_in_ring_3d: V[n] != V[0] (%g %g %g!= %g %g %g)",
1297  first.x, first.y, first.z, last.x, last.y, last.z);
1298  return LW_FALSE;
1299  }
1300 
1301  LWDEBUGF(2, "pt_in_ring_3d called with point: %g %g %g", p->x, p->y, p->z);
1302  /* printPA(ring); */
1303 
1304  /* loop through all edges of the polygon */
1305  getPoint3dz_p(ring, 0, &v1);
1306 
1307 
1308  if(fabs(plane->pv.z)>=fabs(plane->pv.x)&&fabs(plane->pv.z)>=fabs(plane->pv.y)) /*If the z vector of the normal vector to the plane is larger than x and y vector we project the ring to the xy-plane*/
1309  {
1310  for (i=0; i<ring->npoints-1; i++)
1311  {
1312  double vt;
1313  getPoint3dz_p(ring, i+1, &v2);
1314 
1315  /* edge from vertex i to vertex i+1 */
1316  if
1317  (
1318  /* an upward crossing */
1319  ((v1.y <= p->y) && (v2.y > p->y))
1320  /* a downward crossing */
1321  || ((v1.y > p->y) && (v2.y <= p->y))
1322  )
1323  {
1324 
1325  vt = (double)(p->y - v1.y) / (v2.y - v1.y);
1326 
1327  /* P.x <intersect */
1328  if (p->x < v1.x + vt * (v2.x - v1.x))
1329  {
1330  /* a valid crossing of y=p.y right of p.x */
1331  ++cn;
1332  }
1333  }
1334  v1 = v2;
1335  }
1336  }
1337  else if(fabs(plane->pv.y)>=fabs(plane->pv.x)&&fabs(plane->pv.y)>=fabs(plane->pv.z)) /*If the y vector of the normal vector to the plane is larger than x and z vector we project the ring to the xz-plane*/
1338  {
1339  for (i=0; i<ring->npoints-1; i++)
1340  {
1341  double vt;
1342  getPoint3dz_p(ring, i+1, &v2);
1343 
1344  /* edge from vertex i to vertex i+1 */
1345  if
1346  (
1347  /* an upward crossing */
1348  ((v1.z <= p->z) && (v2.z > p->z))
1349  /* a downward crossing */
1350  || ((v1.z > p->z) && (v2.z <= p->z))
1351  )
1352  {
1353 
1354  vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1355 
1356  /* P.x <intersect */
1357  if (p->x < v1.x + vt * (v2.x - v1.x))
1358  {
1359  /* a valid crossing of y=p.y right of p.x */
1360  ++cn;
1361  }
1362  }
1363  v1 = v2;
1364  }
1365  }
1366  else /*Hopefully we only have the cases where x part of the normal vector is largest left*/
1367  {
1368  for (i=0; i<ring->npoints-1; i++)
1369  {
1370  double vt;
1371  getPoint3dz_p(ring, i+1, &v2);
1372 
1373  /* edge from vertex i to vertex i+1 */
1374  if
1375  (
1376  /* an upward crossing */
1377  ((v1.z <= p->z) && (v2.z > p->z))
1378  /* a downward crossing */
1379  || ((v1.z > p->z) && (v2.z <= p->z))
1380  )
1381  {
1382 
1383  vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1384 
1385  /* P.x <intersect */
1386  if (p->y < v1.y + vt * (v2.y - v1.y))
1387  {
1388  /* a valid crossing of y=p.y right of p.x */
1389  ++cn;
1390  }
1391  }
1392  v1 = v2;
1393  }
1394  }
1395  LWDEBUGF(3, "pt_in_ring_3d returning %d", cn&1);
1396 
1397  return (cn&1); /* 0 if even (out), and 1 if odd (in) */
1398 }
1399 
1400 
1401 
1402 /*------------------------------------------------------------------------------------------------------------
1403 End of Brute force functions
1404 --------------------------------------------------------------------------------------------------------------*/
1405 
1406 
1407 
#define LINETYPE
Definition: liblwgeom.h:86
double z
Definition: liblwgeom.h:334
double y
Definition: liblwgeom.h:334
double distance
Definition: measures3d.h:41
LWGEOM * lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
Function initializing closestpoint calculations.
Definition: measures.c:131
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:1040
int lw_dist3d_line_poly(LWLINE *line, LWPOLY *poly, DISTPTS3D *dl)
line to polygon calculation
Definition: measures3d.c:668
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:245
double x
Definition: liblwgeom.h:334
char * r
Definition: cu_in_wkt.c:24
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
void lwfree(void *mem)
Definition: lwutil.c:244
double z
Definition: measures3d.h:51
double y
Definition: liblwgeom.h:340
double lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfyllywithin calculations.
Definition: measures.c:181
POINT3DZ p2
Definition: measures3d.h:43
int npoints
Definition: liblwgeom.h:371
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 POLYGONTYPE
Definition: liblwgeom.h:87
int mode
Definition: measures.h:54
LWLINE * lwline_from_ptarray(int srid, uint32_t npoints, LWPOINT **points)
Definition: lwline.c:243
int lw_dist3d_poly_poly(LWPOLY *poly1, LWPOLY *poly2, DISTPTS3D *dl)
polygon to polygon calculation
Definition: measures3d.c:691
double distance3d_pt_pt(const POINT3D *p1, const POINT3D *p2)
Definition: measures3d.c:818
POINT2D * p1
Definition: lwtree.h:33
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
double x
Definition: liblwgeom.h:340
VECTOR3D pv
Definition: measures3d.h:58
POINTARRAY * point
Definition: liblwgeom.h:411
Structure used in distance-calculations.
Definition: measures3d.h:39
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:885
int32_t srid
Definition: liblwgeom.h:399
#define FP_IS_ZERO(A)
int lw_dist3d_seg_seg(POINT3DZ *s1p1, POINT3DZ *s1p2, POINT3DZ *s2p1, POINT3DZ *s2p2, DISTPTS3D *dl)
Finds the two closest points on two linesegments.
Definition: measures3d.c:921
double project_point_on_plane(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:1237
POINT3DZ p1
Definition: measures3d.h:42
double y
Definition: measures3d.h:51
POINT2D * p2
Definition: lwtree.h:34
#define LW_FAILURE
Definition: liblwgeom.h:79
LWGEOM * lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
Function initializing shortestline and longestline calculations.
Definition: measures.c:84
POINT2D p1
Definition: measures.h:52
double z
Definition: liblwgeom.h:340
#define DOT(u, v)
Definition: measures3d.h:31
unsigned int uint32_t
Definition: uthash.h:78
double tolerance
Definition: measures.h:56
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:701
LWGEOM * lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures3d.c:100
double x
Definition: liblwgeom.h:328
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:480
double zmax
Definition: liblwgeom.h:297
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
int lw_dist3d_pt_poly(POINT3DZ *p, 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:1043
#define DIST_MIN
Definition: measures.h:44
int getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *point)
Definition: lwgeom_api.c:214
LWGEOM * lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
Function initializing 3dshortestline and 3dlongestline calculations.
Definition: measures3d.c:110
#define LW_FALSE
Definition: liblwgeom.h:77
int lw_dist3d_point_poly(LWPOINT *point, LWPOLY *poly, DISTPTS3D *dl)
Computes point to polygon distance For mindistance that means: 1)find the plane of the polygon 2)proj...
Definition: measures3d.c:622
Datum intersects(PG_FUNCTION_ARGS)
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
int lw_dist3d_pt_pt(POINT3DZ *thep1, POINT3DZ *thep2, DISTPTS3D *dl)
Compares incomming points and stores the points closest to each other or most far away from each othe...
Definition: measures3d.c:835
LWGEOM ** geoms
Definition: liblwgeom.h:509
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures3d.c:88
LWGEOM * lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
Function initializing 3dclosestpoint calculations.
Definition: measures3d.c:214
int twisted
Definition: measures3d.h:45
POINTARRAY ** rings
Definition: liblwgeom.h:457
LWPOINT * lwpoint_make3dz(int srid, double x, double y, double z)
Definition: lwpoint.c:173
static int get_3dvector_from_points(POINT3DZ *p1, POINT3DZ *p2, VECTOR3D *v)
Definition: measures3d.c:45
POINT2D p2
Definition: measures.h:53
int nrings
Definition: liblwgeom.h:455
int mode
Definition: measures3d.h:44
double y
Definition: liblwgeom.h:328
LWGEOM * lwgeom_furthest_line_3d(LWGEOM *lw1, LWGEOM *lw2)
Definition: measures3d.c:94
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition: measures3d.c:363
POINT3DZ pop
Definition: measures3d.h:57
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:399
double lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfullywithin calculations.
Definition: measures3d.c:326
int lw_dist3d_point_line(LWPOINT *point, LWLINE *line, DISTPTS3D *dl)
point to line calculation
Definition: measures3d.c:600
int define_plane(POINTARRAY *pa, PLANE3D *pl)
Definition: measures3d.c:1173
double tolerance
Definition: measures3d.h:46
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, pa = vertex points of a ring V[n+1] with V[n]=V[0] plane=the plane that the vertex points are lying on returns: 0 = outside, 1 = inside
Definition: measures3d.c:1283
double distance
Definition: measures.h:51
#define DIST_MAX
Definition: measures.h:43
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:192
double zmin
Definition: liblwgeom.h:296
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
int lw_dist3d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS3D *dl)
point to point calculation
Definition: measures3d.c:584
double lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d max distance calculation.
Definition: measures3d.c:314
int lw_dist3d_pt_seg(POINT3DZ *p, POINT3DZ *A, POINT3DZ *B, DISTPTS3D *dl)
If searching for min distance, this one finds the closest point on segment A-B from p...
Definition: measures3d.c:770
uint8_t type
Definition: liblwgeom.h:396
double x
Definition: measures3d.h:51
static LWGEOM * create_v_line(const LWGEOM *lwgeom, double x, double y, int srid)
This function is used to create a vertical line used for cases where one if the geometries lacks z-va...
Definition: measures3d.c:71
double lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d min distance calculation.
Definition: measures3d.c:352
int lw_dist3d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2, DISTPTS3D *dl)
Finds all combinationes of segments between two pointarrays.
Definition: measures3d.c:867
int lw_dist3d_line_line(LWLINE *line1, LWLINE *line2, DISTPTS3D *dl)
line to line calculation
Definition: measures3d.c:655
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1346
Structure used in distance-calculations.
Definition: measures.h:49
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
int lw_dist3d_pt_ptarray(POINT3DZ *p, 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:740
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
int lw_dist3d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly, PLANE3D *plane, DISTPTS3D *dl)
Computes pointarray to polygon distance.
Definition: measures3d.c:1077
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
POINTARRAY * points
Definition: liblwgeom.h:422
static int get_3dcross_product(VECTOR3D *v1, VECTOR3D *v2, VECTOR3D *v)
Definition: measures3d.c:55