]> granicus.if.org Git - postgis/commitdiff
Fix handling of mixed dimmentionality to 3d measuring functions #2034
authorNicklas Avén <nicklas.aven@jordogskog.no>
Tue, 14 Jul 2015 15:54:36 +0000 (15:54 +0000)
committerNicklas Avén <nicklas.aven@jordogskog.no>
Tue, 14 Jul 2015 15:54:36 +0000 (15:54 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@13802 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/liblwgeom.h.in
liblwgeom/measures.c
liblwgeom/measures.h
liblwgeom/measures3d.c
liblwgeom/measures3d.h
regress/measures.sql
regress/measures_expected

index 9677f706c5578045ed6115a1e7641417135e341f..54a88a9d5faad3729f2f37423ef374df08ce7fbd 100644 (file)
@@ -1141,14 +1141,14 @@ extern double  distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2);
 extern double  distance2d_sqr_pt_pt(const POINT2D *p1, const POINT2D *p2);
 extern double  distance2d_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B);
 extern double  distance2d_sqr_pt_seg(const POINT2D *p, const POINT2D *A, const POINT2D *B);
-extern LWGEOM* lwgeom_closest_line(LWGEOM *lw1, LWGEOM *lw2);
-extern LWGEOM* lwgeom_furthest_line(LWGEOM *lw1, LWGEOM *lw2);
-extern LWGEOM* lwgeom_closest_point(LWGEOM *lw1, LWGEOM *lw2);
-extern LWGEOM* lwgeom_furthest_point(LWGEOM *lw1, LWGEOM *lw2);
-extern double  lwgeom_mindistance2d(LWGEOM *lw1, LWGEOM *lw2);
-extern double  lwgeom_mindistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance);
-extern double  lwgeom_maxdistance2d(LWGEOM *lw1, LWGEOM *lw2);
-extern double  lwgeom_maxdistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance);
+extern LWGEOM* lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2);
+extern LWGEOM* lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2);
+extern LWGEOM* lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2);
+extern LWGEOM* lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2);
+extern double  lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2);
+extern double  lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance);
+extern double  lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2);
+extern double  lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance);
 
 /* 3D */
 extern double distance3d_pt_pt(const POINT3D *p1, const POINT3D *p2);
index 5142884509ea9cb0cafc5ea27e207382651ce2df..b0c3814efb4d88bf3fdafa7be85757fb834adc62 100644 (file)
@@ -25,25 +25,25 @@ The functions starting the distance-calculation processses
 --------------------------------------------------------------------------------------------------------------*/
 
 LWGEOM *
-lwgeom_closest_line(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
 {
   return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MIN);
 }
 
 LWGEOM *
-lwgeom_furthest_line(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
 {
   return lw_dist2d_distanceline(lw1, lw2, lw1->srid, DIST_MAX);
 }
 
 LWGEOM *
-lwgeom_closest_point(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
 {
   return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MIN);  
 }
 
 LWGEOM *
-lwgeom_furthest_point(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_furthest_point(const LWGEOM *lw1, const LWGEOM *lw2)
 {
   return lw_dist2d_distancepoint(lw1, lw2, lw1->srid, DIST_MAX);  
 }
@@ -67,7 +67,7 @@ lw_dist2d_distpts_init(DISTPTS *dl, int mode)
 Function initializing shortestline and longestline calculations.
 */
 LWGEOM *
-lw_dist2d_distanceline(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
+lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
 {
        double x1,x2,y1,y2;
 
@@ -114,7 +114,7 @@ lw_dist2d_distanceline(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
 Function initializing closestpoint calculations.
 */
 LWGEOM *
-lw_dist2d_distancepoint(LWGEOM *lw1, LWGEOM *lw2,int srid,int mode)
+lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2,int srid,int mode)
 {
        double x,y;
        DISTPTS thedl;
@@ -152,7 +152,7 @@ lw_dist2d_distancepoint(LWGEOM *lw1, LWGEOM *lw2,int srid,int mode)
 Function initialazing max distance calculation
 */
 double
-lwgeom_maxdistance2d(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
 {
        LWDEBUG(2, "lwgeom_maxdistance2d is called");
 
@@ -164,7 +164,7 @@ Function handling max distance calculations and dfyllywithin calculations.
 The difference is just the tolerance.
 */
 double
-lwgeom_maxdistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
+lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
 {
        /*double thedist;*/
        DISTPTS thedl;
@@ -185,7 +185,7 @@ lwgeom_maxdistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
        Function initialazing min distance calculation
 */
 double
-lwgeom_mindistance2d(LWGEOM *lw1, LWGEOM *lw2)
+lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
 {
        LWDEBUG(2, "lwgeom_mindistance2d is called");
        return lwgeom_mindistance2d_tolerance( lw1, lw2, 0.0 );
@@ -196,7 +196,7 @@ lwgeom_mindistance2d(LWGEOM *lw1, LWGEOM *lw2)
        The difference is just the tolerance.
 */
 double
-lwgeom_mindistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
+lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
 {
        DISTPTS thedl;
        LWDEBUG(2, "lwgeom_mindistance2d_tolerance is called");
@@ -228,7 +228,7 @@ Functions preparing geometries for distance-calculations
        bboxes we will use anyway.
 */
 int
-lw_dist2d_comp(LWGEOM *lw1, LWGEOM *lw2, DISTPTS *dl)
+lw_dist2d_comp(const LWGEOM *lw1,const LWGEOM *lw2, DISTPTS *dl)
 {
        LWDEBUG(2, "lw_dist2d_comp is called");
 
@@ -353,7 +353,7 @@ int lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl)
 
 
 int
-lw_dist2d_distribute_bruteforce(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl)
+lw_dist2d_distribute_bruteforce(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS *dl)
 {
 
        int     t1 = lwg1->type;
index fa7e340d2e94a13526f0f888d9c6a568ae71eee6..515172776f9bdf5e425ca5336b42f8b23d25dadc 100644 (file)
@@ -39,8 +39,8 @@ typedef struct
 /*
 * Preprocessing functions
 */
-int lw_dist2d_comp(LWGEOM *lw1, LWGEOM *lw2, DISTPTS *dl);
-int lw_dist2d_distribute_bruteforce(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl);
+int lw_dist2d_comp(const LWGEOM *lw1, const LWGEOM *lw2, DISTPTS *dl);
+int lw_dist2d_distribute_bruteforce(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl);
 int lw_dist2d_recursive(const LWGEOM *lwg1, const LWGEOM *lwg2, DISTPTS *dl);
 int lw_dist2d_check_overlap(LWGEOM *lwg1, LWGEOM *lwg2);
 int lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl);
@@ -97,7 +97,7 @@ double lw_arc_length(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3);
 /*
 * Geometry returning functions
 */
-LWGEOM* lw_dist2d_distancepoint(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode);
-LWGEOM* lw_dist2d_distanceline(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode);
+LWGEOM* lw_dist2d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode);
+LWGEOM* lw_dist2d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode);
 
 
index f7b022a73a1f8ac146e5b20488e89adbad392a71..6878e7475e71c85f75d1d5ee3cbc8334ab1f5ef4 100644 (file)
@@ -63,6 +63,7 @@ Function initializing 3dshortestline and 3dlongestline calculations.
 LWGEOM *
 lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
 {
+       LWDEBUG(2, "lw_dist3d_distanceline is called");
        double x1,x2,y1,y2, z1, z2;
        double initdistance = ( mode == DIST_MIN ? FLT_MAX : -1.0);
        DISTPTS3D thedl;
@@ -73,14 +74,70 @@ lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
        thedl.distance = initdistance;
        thedl.tolerance = 0.0;
 
-       LWDEBUG(2, "lw_dist3d_distanceline is called");
-       if (!lw_dist3d_recursive(lw1, lw2, &thedl))
+       /*Check if we really have 3D geoemtries*/
+       /*If not, send it to 2D-calculations which will give the same result*/
+       /*as an infinite z-value at one or two of the geometries*/
+       if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
        {
-               /*should never get here. all cases ought to be error handled earlier*/
-               lwerror("Some unspecified error.");
-               result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'");
+               
+               if(!lwgeom_has_z(lw1) && !lwgeom_has_z(lw2))
+                       return lw_dist2d_distanceline(lw1, lw2, srid, mode);    
+               
+               DISTPTS thedl2d;
+               thedl2d.mode = mode;
+               thedl2d.distance = initdistance;
+               thedl2d.tolerance = 0.0;
+               if (!lw_dist2d_comp( lw1,lw2,&thedl2d))
+               {
+                       /*should never get here. all cases ought to be error handled earlier*/
+                       lwerror("Some unspecified error.");
+                       result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               }
+               
+               if(!lwgeom_has_z(lw1))
+               {
+                       LWGEOM *new_lw1;
+                       x1=thedl2d.p1.x;
+                       y1=thedl2d.p1.y;
+                       lwpoints[0] = lwpoint_make3dz(srid, x1, y1, FLT_MIN);
+                       lwpoints[1] = lwpoint_make3dz(srid, x1, y1, FLT_MAX);
+                       
+                       new_lw1 = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);             
+                       if (!lw_dist3d_recursive(new_lw1, lw2, &thedl))
+                       {
+                               /*should never get here. all cases ought to be error handled earlier*/
+                               lwerror("Some unspecified error.");
+                               result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+                       }                       
+               }       
+               if(!lwgeom_has_z(lw2))
+               {
+                       LWGEOM *new_lw2;
+                       x2=thedl2d.p2.x;
+                       y2=thedl2d.p2.y;                        
+                       lwpoints[0] = lwpoint_make3dz(srid, x2, y2, FLT_MIN);
+                       lwpoints[1] = lwpoint_make3dz(srid, x2, y2, FLT_MAX);
+                       
+                       new_lw2 = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);     
+                       if (!lw_dist3d_recursive(lw1, new_lw2, &thedl))
+                       {
+                               /*should never get here. all cases ought to be error handled earlier*/
+                               lwerror("Some unspecified error.");
+                               result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+                       }                                               
+               }                       
+               
+       }
+       else
+       {               
+               if (!lw_dist3d_recursive(lw1, lw2, &thedl))
+               {
+                       /*should never get here. all cases ought to be error handled earlier*/
+                       lwerror("Some unspecified error.");
+                       result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               }
        }
-
        /*if thedl.distance is unchanged there where only empty geometries input*/
        if (thedl.distance == initdistance)
        {
@@ -96,7 +153,6 @@ lw_dist3d_distanceline(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
                y2=thedl.p2.y;
                z2=thedl.p2.z;
 
-
                lwpoints[0] = lwpoint_make3dz(srid, x1, y1, z1);
                lwpoints[1] = lwpoint_make3dz(srid, x2, y2, z2);
 
@@ -112,6 +168,7 @@ Function initializing 3dclosestpoint calculations.
 LWGEOM *
 lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode)
 {
+       
        double x,y,z;
        DISTPTS3D thedl;
        double initdistance = FLT_MAX;
@@ -122,14 +179,59 @@ lw_dist3d_distancepoint(const LWGEOM *lw1, const LWGEOM *lw2, int srid, int mode
        thedl.tolerance = 0;
 
        LWDEBUG(2, "lw_dist3d_distancepoint is called");
+       
+       /*Check if we really have 3D geoemtries*/
+       /*If not, send it to 2D-calculations which will give the same result*/
+       /*as an infinite z-value at one or two of the geometries*/
+       if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
+       {
+               lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'");
+               
+               
+               if(!lwgeom_has_z(lw2))
+                       return lw_dist2d_distancepoint(lw1, lw2, srid, mode);
+                       
+               
+               DISTPTS thedl2d;
+               thedl2d.mode = mode;
+               thedl2d.distance = initdistance;
+               thedl2d.tolerance = 0.0;
+               if (!lw_dist2d_comp( lw1,lw2,&thedl2d))
+               {
+                       /*should never get here. all cases ought to be error handled earlier*/
+                       lwerror("Some unspecified error.");
+                       result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               }
+               
+               if(!lwgeom_has_z(lw1))
+               {
+                       LWPOINT *lwpoints[2];
+                       LWGEOM *new_lw1;
+                       x=thedl2d.p1.x;
+                       y=thedl2d.p1.y;
 
-       if (!lw_dist3d_recursive(lw1, lw2, &thedl))
+                       lwpoints[0] = lwpoint_make3dz(srid, x, y, FLT_MIN);
+                       lwpoints[1] = lwpoint_make3dz(srid, x, y, FLT_MAX);
+                       
+                       new_lw1 = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints);             
+                       if (!lw_dist3d_recursive(new_lw1, lw2, &thedl))
+                       {
+                               /*should never get here. all cases ought to be error handled earlier*/
+                               lwerror("Some unspecified error.");
+                               result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+                       }                       
+               }       
+               
+       }
+       else
        {
-               /*should never get here. all cases ought to be error handled earlier*/
-               lwerror("Some unspecified error.");
-               result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               if (!lw_dist3d_recursive(lw1, lw2, &thedl))
+               {
+                       /*should never get here. all cases ought to be error handled earlier*/
+                       lwerror("Some unspecified error.");
+                       result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0);
+               }
        }
-
        if (thedl.distance == initdistance)
        {
                LWDEBUG(3, "didn't find geometries to measure between, returning null");
@@ -165,6 +267,11 @@ The difference is just the tolerance.
 double
 lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
 {
+       if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
+       {
+               lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'");
+               return lwgeom_maxdistance2d_tolerance(lw1, lw2, tolerance);     
+       }
        /*double thedist;*/
        DISTPTS3D thedl;
        LWDEBUG(2, "lwgeom_maxdistance3d_tolerance is called");
@@ -197,6 +304,11 @@ lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
 double
 lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
 {
+       if(!lwgeom_has_z(lw1) || !lwgeom_has_z(lw2))
+       {
+               lwnotice("One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'");
+               return lwgeom_mindistance2d_tolerance(lw1, lw2, tolerance);     
+       }
        DISTPTS3D thedl;
        LWDEBUG(2, "lwgeom_mindistance3d_tolerance is called");
        thedl.mode = DIST_MIN;
index d7ed0e234130198055f3e001cee352661acc52af..3fe19a19f9c1ecaaf93a87d0a2aafc57018f71de 100644 (file)
@@ -11,7 +11,7 @@
 
 #ifndef _MEASURES3D_H
 #define _MEASURES3D_H 1
-
+#include <float.h>
 #include "measures.h"
 
 #define DOT(u,v)   ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
index 25b37ce7dd70d1b0cf99e160f5abeb54c2a0bcb4..4cb9efca2fd6629a8685670d183aeb735d125558 100644 (file)
@@ -238,6 +238,29 @@ SELECT '3dDistancetest6',
        ST_3DDistance(a,b) FROM (
        SELECT 'LINESTRING(1 1 1 , 2 2 2)'::geometry as a, 'POLYGON((0 0 0, 2 2 2, 3 3 3, 0 0 0))'::geometry as b) as foo;      
 
+
+-- 3D mixed dimmentionality #2034
+--closestpoint with 2d as first point and 3d as second
+select st_astext(st_3dclosestpoint('linestring(0 0,1 1,2 0)'::geometry, 'linestring(0 2 3, 3 2 3)'::geometry));
+
+--closestpoint with 3d as first point and 2d as second
+select st_astext(st_3dclosestpoint('linestring(0 0 1,1 1 2,2 0 3)'::geometry, 'linestring(0 2, 3 2)'::geometry));
+
+--shortestline with 2d as first point and 3d as second
+select st_astext(st_3dshortestline('linestring(0 0,1 1,2 0)'::geometry, 'linestring(0 2 3, 3 2 3)'::geometry));
+
+--shortestline with 3d as first point and 2d as second
+select st_astext(st_3dshortestline('linestring(0 0 1,1 1 2,2 0 3)'::geometry, 'linestring(0 2, 3 2)'::geometry));
+
+--distance with 2d as first point and 3d as second
+select st_3ddistance('linestring(0 0,1 1,2 0)'::geometry, 'linestring(0 2 3, 3 2 3)'::geometry);
+
+--distance with 3d as first point and 2d as second
+select st_3ddistance('linestring(0 0 1,1 1 2,2 0 3)'::geometry, 'linestring(0 2, 3 2)'::geometry);
+
+
+
+
 -- Area of an empty polygon
 select 'emptyPolyArea', st_area('POLYGON EMPTY');
 
index c156ac0edae56f6ff31069619e6ae6953d5ab5ee..352a8f7d2180139660fa1c287d4c560204b9a1c0 100644 (file)
@@ -35,6 +35,18 @@ distancepoly6|0|32.5269119345812|LINESTRING(2 2,2 2)|LINESTRING(2 2,2 2)|LINESTR
 3dDistancetest4|2|10.0498756211209|t|f|LINESTRING(1 1 3,1 1 1)|POINT(1 1 3)|LINESTRING(5 7 8,1 1 1)
 3dDistancetest5|2|10|t|f|LINESTRING(5 0 5,5 2 5)|POINT(5 0 5)|LINESTRING(11 0 5,5 0 13)
 3dDistancetest6|0
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+POINT Z (1 1 3)
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+POINT(1 1)
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+LINESTRING Z (1 1 3,1 2 3)
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+LINESTRING Z (1 1 2,1 2 2)
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+1
+NOTICE:  One or both of the geometries is missing z-value. The unknown z-value will be regarded as 'any value'
+1
 emptyPolyArea|0
 emptyLineArea|0
 emptyPointArea|0