/** Function handling 3d min distance calculations and dwithin calculations. The difference is just the tolerance. */ double lwgeom_mindistance3d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance) { DISTPTS3D thedl; LWDEBUG(2, "lwgeom_mindistance3d_tolerance is called"); thedl.mode = DIST_MIN; thedl.distance= MAXFLOAT; thedl.tolerance = tolerance; if (lw_dist3d_recursive(lw1, lw2, &thedl)) { return thedl.distance; } /*should never get here. all cases ought to be error handled earlier*/ lwerror("Some unspecified error."); return MAXFLOAT; }
/** Function initializing 3dshortestline and 3dlongestline calculations. */ LWGEOM * lw_dist3d_distanceline(LWGEOM *lw1, LWGEOM *lw2,int srid,int mode) { double x1,x2,y1,y2, z1, z2; double initdistance = ( mode == DIST_MIN ? MAXFLOAT : -1.0); DISTPTS3D thedl; LWPOINT *lwpoints[2]; LWGEOM *result; thedl.mode = mode; thedl.distance = initdistance; thedl.tolerance = 0.0; LWDEBUG(2, "lw_dist3d_distanceline is called"); 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) { LWDEBUG(3, "didn't find geometries to measure between, returning null"); result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0); } else { x1=thedl.p1.x; y1=thedl.p1.y; z1=thedl.p1.z; x2=thedl.p2.x; y2=thedl.p2.y; z2=thedl.p2.z; lwpoints[0] = lwpoint_make3dz(srid, x1, y1, z1); lwpoints[1] = lwpoint_make3dz(srid, x2, y2, z2); result = (LWGEOM *)lwline_from_lwpointarray(srid, 2, lwpoints); } return result; }
/** Function handling 3d min distance calculations and dwithin calculations. The difference is just the tolerance. */ 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; thedl.distance= FLT_MAX; thedl.tolerance = tolerance; if (lw_dist3d_recursive(lw1, lw2, &thedl)) { return thedl.distance; } /*should never get here. all cases ought to be error handled earlier*/ lwerror("Some unspecified error."); return FLT_MAX; }
/** Function initializing 3dclosestpoint calculations. */ LWGEOM * lw_dist3d_distancepoint(LWGEOM *lw1, LWGEOM *lw2,int srid,int mode) { double x,y,z; DISTPTS3D thedl; double initdistance = MAXFLOAT; LWGEOM *result; thedl.mode = mode; thedl.distance= initdistance; thedl.tolerance = 0; LWDEBUG(2, "lw_dist3d_distancepoint is called"); 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"); result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0); } else { x=thedl.p1.x; y=thedl.p1.y; z=thedl.p1.z; result = (LWGEOM *)lwpoint_make3dz(srid, x, y, z); } return result; }
/** 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, x, y; double initdistance = ( mode == DIST_MIN ? FLT_MAX : -1.0); DISTPTS3D thedl; LWPOINT *lwpoints[2]; LWGEOM *result; thedl.mode = mode; thedl.distance = initdistance; thedl.tolerance = 0.0; /*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(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); } LWGEOM *vertical_line; if(!lwgeom_has_z(lw1)) { x=thedl2d.p1.x; y=thedl2d.p1.y; vertical_line = create_v_line(lw2,x,y,srid); if (!lw_dist3d_recursive(vertical_line, lw2, &thedl)) { /*should never get here. all cases ought to be error handled earlier*/ lwfree(vertical_line); lwerror("Some unspecified error."); result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0); } lwfree(vertical_line); } if(!lwgeom_has_z(lw2)) { x=thedl2d.p2.x; y=thedl2d.p2.y; vertical_line = create_v_line(lw1,x,y,srid); if (!lw_dist3d_recursive(lw1, vertical_line, &thedl)) { /*should never get here. all cases ought to be error handled earlier*/ lwfree(vertical_line); lwerror("Some unspecified error."); return (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0); } lwfree(vertical_line); } } 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) { LWDEBUG(3, "didn't find geometries to measure between, returning null"); result = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, srid, 0, 0); } else { x1=thedl.p1.x; y1=thedl.p1.y; z1=thedl.p1.z; x2=thedl.p2.x; y2=thedl.p2.y; z2=thedl.p2.z; lwpoints[0] = lwpoint_make3dz(srid, x1, y1, z1); lwpoints[1] = lwpoint_make3dz(srid, x2, y2, z2); result = (LWGEOM *)lwline_from_ptarray(srid, 2, lwpoints); } return result; }
/** This is a recursive function delivering every possible combination of subgeometries */ int lw_dist3d_recursive(const LWGEOM *lwg1,const LWGEOM *lwg2, DISTPTS3D *dl) { int i, j; int n1=1; int n2=1; LWGEOM *g1 = NULL; LWGEOM *g2 = NULL; LWCOLLECTION *c1 = NULL; LWCOLLECTION *c2 = NULL; LWDEBUGF(2, "lw_dist3d_recursive is called with type1=%d, type2=%d", lwg1->type, lwg2->type); if (lwgeom_is_collection(lwg1)) { LWDEBUG(3, "First geometry is collection"); c1 = lwgeom_as_lwcollection(lwg1); n1 = c1->ngeoms; } if (lwgeom_is_collection(lwg2)) { LWDEBUG(3, "Second geometry is collection"); c2 = lwgeom_as_lwcollection(lwg2); n2 = c2->ngeoms; } for ( i = 0; i < n1; i++ ) { if (lwgeom_is_collection(lwg1)) { g1 = c1->geoms[i]; } else { g1 = (LWGEOM*)lwg1; } if (lwgeom_is_empty(g1)) return LW_TRUE; if (lwgeom_is_collection(g1)) { LWDEBUG(3, "Found collection inside first geometry collection, recursing"); if (!lw_dist3d_recursive(g1, lwg2, dl)) return LW_FALSE; continue; } for ( j = 0; j < n2; j++ ) { if (lwgeom_is_collection(lwg2)) { g2 = c2->geoms[j]; } else { g2 = (LWGEOM*)lwg2; } if (lwgeom_is_collection(g2)) { LWDEBUG(3, "Found collection inside second geometry collection, recursing"); if (!lw_dist3d_recursive(g1, g2, dl)) return LW_FALSE; continue; } /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/ if (lwgeom_is_empty(g1)||lwgeom_is_empty(g2)) return LW_TRUE; if (!lw_dist3d_distribute_bruteforce(g1, g2, dl)) return LW_FALSE; if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return LW_TRUE; /*just a check if the answer is already given*/ } } return LW_TRUE; }