Changeset: add78eb3398e for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/add78eb3398e
Modified Files:
        geom/monetdb5/geom.c
        geom/monetdb5/geom.h
        geom/monetdb5/geom_atoms.c
        geom/monetdb5/geom_atoms.h
        geom/sql/40_geom.sql
Branch: geo-update
Log Message:

Adds implementation of ST_DWithin2 based on MBR distance


diffs (248 lines):

diff --git a/geom/monetdb5/geom.c b/geom/monetdb5/geom.c
--- a/geom/monetdb5/geom.c
+++ b/geom/monetdb5/geom.c
@@ -22,16 +22,16 @@
  **/
 
 /**
-* Collect (Group By implementation) 
-* 
+* Collect (Group By implementation)
+*
 **/
 //Gets the type of collection a single geometry should belong to
 static int
 GEOSGeom_getCollectionType (int GEOSGeom_type) {
-       
+
        //TODO Remove
        (void) geodeticEdgeBoundingBox;
-       
+
        //Single geometries get collected into a Multi* geometry
        if (GEOSGeom_type == GEOS_POINT)
                return GEOS_MULTIPOINT;
@@ -47,7 +47,7 @@ GEOSGeom_getCollectionType (int GEOSGeom
 /* Group By operation. Joins geometries together in the same group into a 
MultiGeometry */
 //TODO Check if the SRID is consistent within a group (right now we only use 
the first SRID)
 //TODO The number of candidates is getting wrong here
-str 
+str
 wkbCollectAggrSubGroupedCand(bat *outid, const bat *bid, const bat *gid, const 
bat *eid, const bat *sid, const bit *skip_nils)
 {
        BAT *b = NULL, *g = NULL, *s = NULL, *out = NULL;
@@ -72,7 +72,7 @@ wkbCollectAggrSubGroupedCand(bat *outid,
        (void)eid;
 
        //Get the BAT descriptors for the value, group and candidate bats
-       if ((b = BATdescriptor(*bid)) == NULL || 
+       if ((b = BATdescriptor(*bid)) == NULL ||
                (gid && !is_bat_nil(*gid) && (g = BATdescriptor(*gid)) == NULL) 
||
                (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == 
NULL)) {
                msg = createException(MAL, "geom.Collect", 
RUNTIME_OBJECT_MISSING);
@@ -83,7 +83,7 @@ wkbCollectAggrSubGroupedCand(bat *outid,
                msg = createException(MAL, "geom.Collect", "BAT sort failed.");
                goto free;
        }
-       
+
        //Project new order onto input bat IF the sortedorder isn't dense (in 
which case, the original input order is correct)
        if (!BATtdense(sortedorder)) {
                sortedinput = BATproject(sortedorder,b);
@@ -92,7 +92,7 @@ wkbCollectAggrSubGroupedCand(bat *outid,
                b = sortedinput;
                g = sortedgroups;
                BBPunfix(sortedorder->batCacheid);
-               
+
        }
        else {
                BBPunfix(sortedgroups->batCacheid);
@@ -131,7 +131,7 @@ wkbCollectAggrSubGroupedCand(bat *outid,
        if (g && !BATtdense(g))
                gids = (const oid *)Tloc(g, 0);
        bi = bat_iterator(b);
-       
+
        for (BUN i = 0; i < ncand; i++) {
                oid o = canditer_next(&ci);
                BUN p = o - b->hseqbase;
@@ -222,7 +222,7 @@ free:
        return msg;
 }
 
-str 
+str
 wkbCollectAggrSubGrouped(bat *out, const bat *bid, const bat *gid, const bat 
*eid, const bit *skip_nils)
 {
        return wkbCollectAggrSubGroupedCand(out, bid, gid, eid, NULL, 
skip_nils);
@@ -271,7 +271,7 @@ wkbCollectAggr (wkb **out, const bat *bi
                msg = createException(MAL, "geom.ConvexHull", SQLSTATE(38000) 
"Geos operation geos2wkb failed");
 
     // Cleanup
-    // Data ownership has been transfered from unionGroup elements to 
+    // Data ownership has been transfered from unionGroup elements to
     // collection. Check libgeos GEOSGeom_createCollection() for more.
     bat_iterator_end(&bi);
     GEOSGeom_destroy(collection);
@@ -4508,6 +4508,59 @@ wkbDWithin(bit *out, wkb **geomWKB_a, wk
        return MAL_SUCCEED;
 }
 
+str
+wkbDWithinMbr(bit *out, wkb **a, wkb **b, mbr **mbr_a, mbr **mbr_b, dbl 
*distance)
+{
+       double actualDistance, bboxDistance;
+       double halfd_a, halfd_b; // halfed diagonals of the a and b bounding 
boxes
+       double ambiguous_zone_min, ambiguous_zone_max; // see comments
+       str err;
+
+       if (is_wkb_nil(*a) || is_wkb_nil(*b) || is_dbl_nil(*distance)) {
+               *out = bit_nil;
+               return MAL_SUCCEED;
+       }
+
+       // if there are no mbr(s) fallback to wkbDWithin
+       if (is_mbr_nil(*mbr_a) || is_mbr_nil(*mbr_b))
+               return wkbDWithin(out, a, b, distance);
+
+       // first calculate the distance of the bounding boxes (mbrs)
+       if ((err = mbrDistance(&bboxDistance, mbr_a, mbr_b)) != MAL_SUCCEED)
+               return err;
+
+       if ((err = mbrDiagonal(&halfd_a, mbr_a)) != MAL_SUCCEED)
+               return err;
+       halfd_a *= .5;
+
+       if ((err = mbrDiagonal(&halfd_b, mbr_b)) != MAL_SUCCEED)
+               return err;
+       halfd_b *= .5;
+
+       // Every bounding box can be inscribed in a circle. When calculating 
the distance
+       // between two mbrs we do so by their centroids which are actually the 
origins of
+       // their circumscribed circles. Then, independently of the bounded 
geometry, we can
+       // find two rough distance limits which are giving us a zone outside of 
which the
+       // questions 'distance within' can be answered only by the bounding box 
geometry.
+       // If the 'distance within' check is done over distance value in this 
zone then we
+       // actually need to perform the underlying geometry distance 
calculation.
+       ambiguous_zone_max = bboxDistance;
+       ambiguous_zone_min = bboxDistance - halfd_a - halfd_b;
+
+       if (*distance < ambiguous_zone_min) {
+               *out = false;
+       } else if (*distance > ambiguous_zone_max) {
+               *out = true;
+       } else {
+               // if we are not sure still calculate the actual distance of 
the geometries
+               if ((err = wkbDistance(&actualDistance, a, b)) != MAL_SUCCEED)
+                       return err;
+               *out = (actualDistance <= *distance);
+       }
+
+       return MAL_SUCCEED;
+}
+
 /*returns the n-th geometry in a multi-geometry */
 str
 wkbGeometryN(wkb **out, wkb **geom, const int *geometryNum)
@@ -5286,13 +5339,13 @@ static mel_atom geom_init_atoms[] = {
  { .name="wkba", .tostr=wkbaTOSTR, .fromstr=wkbaFROMSTR, .null=wkbaNULL, 
.hash=wkbaHASH, .cmp=wkbaCOMP, .read=wkbaREAD, .write=wkbaWRITE, .put=wkbaPUT, 
.del=wkbaDEL, .length=wkbaLENGTH, .heap=wkbaHEAP, },  { .cmp=NULL }
 };
 static mel_func geom_init_funcs[] = {
- //TODO Fill in descriptions 
+ //TODO Fill in descriptions
  command("geom", "CoversGeographic", wkbCoversGeographic, false, "TODO", 
args(1, 3, arg("", bit), arg("a", wkb), arg("b", wkb))),
 
  command("geom", "DistanceGeographic", wkbDistanceGeographic, false, "TODO", 
args(1, 3, arg("", dbl), arg("a", wkb), arg("b", wkb))),
  command("batgeom", "DistanceGeographic", wkbDistanceGeographic_bat, false, 
"TODO", args(1, 3, batarg("", dbl), batarg("a", wkb), batarg("b", wkb))),
  command("batgeom", "DistanceGeographic", wkbDistanceGeographic_bat_cand, 
false, "TODO", args(1, 5, batarg("", dbl), batarg("a", wkb), batarg("b", wkb), 
batarg("s1", oid), batarg("s2", oid))),
-  
+
  //Filter functions
  command("geom", "DWithinGeographic", wkbDWithinGeographic, false, "TODO", 
args(1, 4, arg("", bit), arg("a", wkb), arg("b", wkb), arg("d", dbl))),
  command("geom", "DWithinGeographicselect", wkbDWithinGeographicSelect, false, 
"TODO", args(1, 6, batarg("", oid), batarg("b", wkb), batarg("s", oid), 
arg("c", wkb), arg("d", dbl),arg("anti",bit))),
@@ -5304,12 +5357,12 @@ static mel_func geom_init_funcs[] = {
  command("aggr", "Collect", wkbCollectAggr, false, "TODO", args(1, 2, arg("", 
wkb), batarg("val", wkb))),
  command("aggr", "subCollect", wkbCollectAggrSubGrouped, false, "TODO", 
args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", 
oid), arg("skip_nils", bit))),
  command("aggr", "subCollect", wkbCollectAggrSubGroupedCand, false, "TODO", 
args(1, 6, batarg("", wkb), batarg("val", wkb), batarg("g", oid), 
batargany("e", 1), batarg("g", oid), arg("skip_nils", bit))),
- 
+
  //TODO: See if we can remove (used in SQL level on 39_spatial_ref_sys.sql)
  command("geom", "hasZ", geoHasZ, false, "returns 1 if the geometry has z 
coordinate", args(1,2, arg("",int),arg("flags",int))),
  command("geom", "hasM", geoHasM, false, "returns 1 if the geometry has m 
coordinate", args(1,2, arg("",int),arg("flags",int))),
  command("geom", "getType", geoGetType, false, "returns the str representation 
of the geometry type", args(1,3, 
arg("",str),arg("flags",int),arg("format",int))),
- 
+
  command("geom", "MLineStringToPolygon", wkbMLineStringToPolygon, false, 
"Creates polygons using the MultiLineString provided as WKT. Depending on the 
flag creates one (flag=0) or multiple (flag=1) polygons", args(1,4, 
arg("",wkb),arg("wkt",str),arg("srid",int),arg("flag",int))),
  command("geom", "AsBinary", wkbAsBinary, false, "Returns the wkb 
representation into HEX format", args(1,2, arg("",str),arg("w",wkb))),
  command("geom", "FromBinary", wkbFromBinary, false, "Creates a wkb using the 
HEX representation", args(1,2, arg("",wkb),arg("w",str))),
@@ -5363,6 +5416,7 @@ static mel_func geom_init_funcs[] = {
  command("geom", "Covers", wkbCovers, false, "Returns TRUE if no point of 
geometry B is outside geometry A", args(1,3, 
arg("",bit),arg("a",wkb),arg("b",wkb))),
  command("geom", "CoveredBy", wkbCoveredBy, false, "Returns TRUE if no point 
of geometry A is outside geometry B", args(1,3, 
arg("",bit),arg("a",wkb),arg("b",wkb))),
  command("geom", "DWithin", wkbDWithin, false, "Returns true if the two 
geometries are within the specifies distance from each other", args(1,4, 
arg("",bit),arg("a",wkb),arg("b",wkb),arg("dst",dbl))),
+ command("geom", "DWithin2", wkbDWithinMbr, false, "" /* <<< desc TODO */, 
args(1,6, 
arg("",bit),arg("a",wkb),arg("b",wkb),arg("a_mbr",mbr),arg("b_mbr",mbr),arg("dst",dbl))),
  command("geom", "GeometryN", wkbGeometryN, false, "Returns the 1-based Nth 
geometry if the geometry is a GEOMETRYCOLLECTION, (MULTI)POINT, 
(MULTI)LINESTRING, MULTICURVE or (MULTI)POLYGON. Otherwise, return NULL", 
args(1,3, arg("",wkb),arg("g",wkb),arg("n",int))),
  command("geom", "NumGeometries", wkbNumGeometries, false, "Returns the number 
of geometries", args(1,2, arg("",int),arg("g",wkb))),
  command("geom", "Transform", wkbTransform, false, "Transforms a geometry from 
one srid to another", args(1,6, 
arg("",wkb),arg("g",wkb),arg("srid_src",int),arg("srid_dst",int),arg("proj_src",str),arg("proj_dest",str))),
diff --git a/geom/monetdb5/geom.h b/geom/monetdb5/geom.h
--- a/geom/monetdb5/geom.h
+++ b/geom/monetdb5/geom.h
@@ -102,6 +102,7 @@ geom_export str wkbRelate(bit*, wkb**, w
 geom_export str wkbCovers(bit *out, wkb **geomWKB_a, wkb **geomWKB_b);
 geom_export str wkbCoveredBy(bit *out, wkb **geomWKB_a, wkb **geomWKB_b);
 geom_export str wkbDWithin(bit*, wkb**, wkb**, dbl*);
+geom_export str wkbDWithinMbr(bit*, wkb**, wkb**, mbr**, mbr**, dbl*);
 
 //LocateAlong
 //LocateBetween
diff --git a/geom/monetdb5/geom_atoms.c b/geom/monetdb5/geom_atoms.c
--- a/geom/monetdb5/geom_atoms.c
+++ b/geom/monetdb5/geom_atoms.c
@@ -879,6 +879,24 @@ mbrEqual_wkb(bit *out, wkb **geom1WKB, w
        return mbrrelation_wkb(out, geom1WKB, geom2WKB, mbrEqual);
 }
 
+str
+mbrDiagonal(dbl *out, mbr **b)
+{
+       double side_a = .0, side_b = .0;
+
+       if (is_mbr_nil(*b)) {
+               *out = dbl_nil;
+               return MAL_SUCCEED;
+       }
+
+       side_a = (*b)->xmax - (*b)->xmin;
+       side_b = (*b)->ymax - (*b)->ymin;
+
+       *out = sqrt(pow(side_a, 2.0) + pow(side_b, 2.0));
+
+       return MAL_SUCCEED;
+}
+
 /* returns the Euclidean distance of the centroids of the boxes */
 str
 mbrDistance(dbl *out, mbr **b1, mbr **b2)
diff --git a/geom/monetdb5/geom_atoms.h b/geom/monetdb5/geom_atoms.h
--- a/geom/monetdb5/geom_atoms.h
+++ b/geom/monetdb5/geom_atoms.h
@@ -64,6 +64,7 @@ geom_export str mbrContained(bit *out, m
 geom_export str mbrContained_wkb(bit *out, wkb **geom1WKB, wkb **geom2WKB);
 geom_export str mbrEqual(bit *out, mbr **b1, mbr **b2);
 geom_export str mbrEqual_wkb(bit *out, wkb **geom1WKB, wkb **geom2WKB);
+geom_export str mbrDiagonal(dbl *out, mbr **b);
 geom_export str mbrDistance(dbl *out, mbr **b1, mbr **b2);
 geom_export str mbrDistance_wkb(dbl *out, wkb **geom1WKB, wkb **geom2WKB);
 geom_export str wkbCoordinateFromWKB(dbl*, wkb**, int*);
diff --git a/geom/sql/40_geom.sql b/geom/sql/40_geom.sql
--- a/geom/sql/40_geom.sql
+++ b/geom/sql/40_geom.sql
@@ -514,6 +514,8 @@ GRANT EXECUTE ON FUNCTION ST_CoveredBy(G
 --CREATE FUNCTION ST_Distance(geog1 Geometry, geog2 Geometry, use_spheroid 
boolean) RETURNS double EXTERNAL NAME geom."Distance"
 CREATE FUNCTION ST_DWithin(geom1 Geometry, geom2 Geometry, dst double) RETURNS 
boolean EXTERNAL NAME geom."DWithin";
 GRANT EXECUTE ON FUNCTION ST_DWithin(Geometry, Geometry, double) TO PUBLIC;
+CREATE FUNCTION ST_DWithin2(geom1 Geometry, geom2 Geometry, bbox1 mbr, bbox2 
mbr, dst double) RETURNS boolean EXTERNAL NAME geom."DWithin2";
+GRANT EXECUTE ON FUNCTION ST_DWithin2(Geometry, Geometry, mbr, mbr, double) TO 
PUBLIC;
 --CREATE FUNCTION ST_HausdorffDistance RETURNS EXTERNAL NAME
 --CREATE FUNCTION ST_MaxDistance RETURNS EXTERNAL NAME
 --CREATE FUNCTION ST_Distance_Sphere RETURNS EXTERNAL NAME
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to