From: Nicklas Avén Date: Tue, 14 Jul 2015 15:54:36 +0000 (+0000) Subject: Fix handling of mixed dimmentionality to 3d measuring functions #2034 X-Git-Tag: 2.2.0rc1~253 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=09434ed3af509bf840b30de5f09d3850fe1e4de6;p=postgis Fix handling of mixed dimmentionality to 3d measuring functions #2034 git-svn-id: http://svn.osgeo.org/postgis/trunk@13802 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 9677f706c..54a88a9d5 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -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); diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 514288450..b0c3814ef 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -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; diff --git a/liblwgeom/measures.h b/liblwgeom/measures.h index fa7e340d2..515172776 100644 --- a/liblwgeom/measures.h +++ b/liblwgeom/measures.h @@ -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); diff --git a/liblwgeom/measures3d.c b/liblwgeom/measures3d.c index f7b022a73..6878e7475 100644 --- a/liblwgeom/measures3d.c +++ b/liblwgeom/measures3d.c @@ -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; diff --git a/liblwgeom/measures3d.h b/liblwgeom/measures3d.h index d7ed0e234..3fe19a19f 100644 --- a/liblwgeom/measures3d.h +++ b/liblwgeom/measures3d.h @@ -11,7 +11,7 @@ #ifndef _MEASURES3D_H #define _MEASURES3D_H 1 - +#include #include "measures.h" #define DOT(u,v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z) diff --git a/regress/measures.sql b/regress/measures.sql index 25b37ce7d..4cb9efca2 100644 --- a/regress/measures.sql +++ b/regress/measures.sql @@ -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'); diff --git a/regress/measures_expected b/regress/measures_expected index c156ac0ed..352a8f7d2 100644 --- a/regress/measures_expected +++ b/regress/measures_expected @@ -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