Changeset: a4e562885d01 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=a4e562885d01
Modified Files:
        geom/monetdb5/geom.c
        geom/monetdb5/geom.h
        geom/monetdb5/geom.mal
Branch: sfcgal
Log Message:

ST_Collect uses Union. Union should be cascaded and not done by adding a geom 
iteratively. For a 3000 points line-string it got 30 times faster


diffs (139 lines):

diff --git a/geom/monetdb5/geom.c b/geom/monetdb5/geom.c
--- a/geom/monetdb5/geom.c
+++ b/geom/monetdb5/geom.c
@@ -4415,6 +4415,112 @@ wkbUnionAggr(wkb **outWKB, bat *inBAT_id
 
 }
 
+static str
+wkbUnaryUnion(wkb **out, wkb **geoms, int num_geoms)
+{
+    int i = 0, j = 0;
+       GEOSGeom outGeometry, *geomGeometries = NULL, geomCollection;
+
+    if ( (geomGeometries = (GEOSGeom*) GDKmalloc(sizeof(GEOSGeom)*num_geoms)) 
== NULL) {
+               *out = NULL;
+        throw(MAL, "GEOSUnaryUnion", "GDKmalloc failed");
+    }
+
+    for (i = 0; i < num_geoms; i++) {
+        if (wkb_isnil(geoms[i])) {
+            if ((*out = wkbNULLcopy()) == NULL)
+                throw(MAL, "GEOSUnaryUnion", MAL_MALLOC_FAIL);
+            return MAL_SUCCEED;
+        }
+
+        geomGeometries[i] = wkb2geos(geoms[i]);
+        if (!geomGeometries[i]) {
+            for (j = 0; j < i; j++)
+                       GEOSGeom_destroy(geomGeometries[j]);
+            GDKfree(geomGeometries);
+            *out = NULL;
+            throw(MAL, "GEOSUnaryUnion", "wkb2geos failed");
+        }
+    }
+
+       if ( (geomCollection = GEOSGeom_createCollection(wkbMultiPoint_mdb - 1, 
geomGeometries, num_geoms)) == NULL ) {
+               *out = NULL;
+        for (i = 0; i < num_geoms; i++)
+            GEOSGeom_destroy(geomGeometries[i]);
+        GDKfree(geomGeometries);
+               throw(MAL, "GEOSUnaryUnion", "GEOSGeom_createCollection 
failed");
+    }
+
+       if (!(outGeometry = GEOSUnaryUnion(geomCollection))) {
+               *out = NULL;
+        GDKfree(geomGeometries);
+               throw(MAL, "GEOSUnaryUnion", "GEOSUnaryUnion failed");
+       }
+
+       GEOSSetSRID(outGeometry, GEOSGetSRID(geomGeometries[0]));
+       *out = geos2wkb(outGeometry);
+    GDKfree(geomGeometries);
+
+       return MAL_SUCCEED;
+}
+
+//Gets a BAT with geometries and returns a single LineString
+str
+wkbUnionCascade(wkb **outWKB, bat *inBAT_id)
+{
+       BAT *inBAT = NULL;
+       BATiter inBAT_iter;
+       BUN i;
+    int j = 0;
+    wkb *geomWKB = wkbNULL(), **geoms = NULL;
+       str err;
+
+       //get the BATs
+       if (!(inBAT = BATdescriptor(*inBAT_id))) {
+               throw(MAL, "geom.Collect", "Problem retrieving BATs");
+       }
+
+    /*TODO: We need a better way to handle the cases where the BAT was 
created, but it has zero elements*/
+    if (!BATcount(inBAT)) {
+               BBPunfix(inBAT->batCacheid);
+               if ((err = wkbUnion(outWKB,&geomWKB, &geomWKB)) != MAL_SUCCEED) 
{
+                       BBPunfix(inBAT->batCacheid);
+                       return err;
+               }
+        return MAL_SUCCEED;
+    }
+       //check if the BATs are dense and aligned
+       if (!BAThdense(inBAT)) {
+               BBPunfix(inBAT->batCacheid);
+               throw(MAL, "geom.Collect", "BATs must have dense heads");
+       }
+       //iterator over the BATs
+       inBAT_iter = bat_iterator(inBAT);
+
+    /*Collect all geoms*/
+    if ( (geoms = (wkb**) GDKmalloc(sizeof(wkb*)*BATcount(inBAT))) == NULL) {
+        BBPunfix(inBAT->batCacheid);
+               throw(MAL, "geom.Collect", "GDKmalloc failed");
+    }
+
+       for (j = 0, i = BUNfirst(inBAT); i < BATcount(inBAT); i++, j++) {
+        geoms[j] = (wkb *) BUNtail(inBAT_iter, i + BUNfirst(inBAT));
+    }
+
+    if ((err = wkbUnaryUnion(outWKB, geoms, j)) != MAL_SUCCEED) {
+        BBPunfix(inBAT->batCacheid);
+        if (geoms)
+            GDKfree(geoms);
+        return err;
+    }
+
+       BBPunfix(inBAT->batCacheid);
+    if (geoms)
+        GDKfree(geoms);
+
+       return MAL_SUCCEED;
+}
+
 str
 wkbDifference(wkb **out, wkb **a, wkb **b)
 {
diff --git a/geom/monetdb5/geom.h b/geom/monetdb5/geom.h
--- a/geom/monetdb5/geom.h
+++ b/geom/monetdb5/geom.h
@@ -211,6 +211,7 @@ geom_export str wkbIntersection_bat(bat 
 geom_export str wkbIntersection_bat_s(bat *outBAT_id, bat *aBAT_id, bat 
*bBAT_id, bat *saBAT_id, bat *sbBAT_id);
 geom_export str wkbUnion(wkb **out, wkb **a, wkb **b);
 geom_export str wkbUnionAggr(wkb** outWKB, bat* inBAT_id);
+geom_export str wkbUnionCascade(wkb** outWKB, bat* inBAT_id);
 geom_export str wkbDifference(wkb **out, wkb **a, wkb **b);
 geom_export str wkbSymDifference(wkb **out, wkb **a, wkb **b);
 geom_export str wkbBuffer(wkb **out, wkb **geom, dbl *distance);
diff --git a/geom/monetdb5/geom.mal b/geom/monetdb5/geom.mal
--- a/geom/monetdb5/geom.mal
+++ b/geom/monetdb5/geom.mal
@@ -288,7 +288,7 @@ command Intersection(a:wkb, b:wkb) :wkb 
 comment "Returns a geometry that represents the point set intersection of the 
Geometries a, b";
 command Union(a:wkb, b:wkb) :wkb address wkbUnion
 comment "Returns a geometry that represents the point set union of the 
Geometries a, b";
-command Union(a:bat[:oid,:wkb]) :wkb address wkbUnionAggr
+command Union(a:bat[:oid,:wkb]) :wkb address wkbUnionCascade
 comment "Gets a BAT with geometries and returns their union"; 
 command Difference(a:wkb, b:wkb) :wkb address wkbDifference
 comment "Returns a geometry that represents that part of geometry A that does 
not intersect with geometry B";
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to