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

Fixed Collect function, now does what it's supposed to do. Missing the step 
where the input and group BATs are sorted, right now only works if the input is 
already sorted.


diffs (truncated from 415 to 300 lines):

diff --git a/geom/monetdb5/geom.c b/geom/monetdb5/geom.c
--- a/geom/monetdb5/geom.c
+++ b/geom/monetdb5/geom.c
@@ -531,11 +531,13 @@ static double geoDistancePointLineIntern
 static double geoDistancePointLine(GeoPoint point, GeoLines lines)
 {
        double distance, min_distance = INT_MAX;
+       fflush(stdout);
        for (int i = 0; i < lines.segmentCount; i++)
        {
                distance = geoDistancePointLineInternal(point, 
lines.segments[i]);
                if (distance < min_distance)
                        min_distance = distance;
+                       
        }
        return min_distance;
 }
@@ -762,6 +764,7 @@ static double geoDistanceInternal(GEOSGe
                        distance = geoDistanceSingle(geo1, geo2);
                        if (distance < min_distance)
                                min_distance = distance;
+                               
                }
        }
        return min_distance;
@@ -849,14 +852,44 @@ static bool geoPointEquals(GeoPoint poin
        return (pointA.lat == pointB.lat) && (pointA.lon = pointB.lon);
 }
 
+//POSTgis Calculate Perpendicular of Point
+/*
+normal_cart = cross_product(line->start, line->end)
+point_cart = geo2cart(p)
+dot = dot_product(normal,pt)
+
+vector_scale(&n, dot_product(&p, &n));
+vector_difference(&p, &n, &k);
+normalize(&k);
+cart2geog(&k, &gk);
+edge_contains_point(e, &gk)
+*/
+
+//POSTgis Calculate Point in Edge
+/*
+e -> edge // p -> point
+geog2cart(&(e->start), &vs);
+geog2cart(&(e->end), &ve);
+if ( vs.x == -1.0 * ve.x && vs.y == -1.0 * ve.y && vs.z == -1.0 * ve.z )
+       return LW_TRUE;
+geog2cart(p, &vp);
+vector_sum(&vs, &ve, &vcp);
+normalize(&vcp);
+vs_dot_vcp = dot_product(&vs, &vcp);
+
+POINT ON PLANE (Plane defined by Edge)
+normal_cart = cross_product(line->start, line->end)
+point_cart = geo2cart(p)
+dot = dot_product(normal,pt)
+return dot == 0
+*/
+
+//TODO If a line covers a point, it must have 0 distance to one of the 
segments (is this true?)
 #if 0
-//TODO: Can we calculate the perpendicular of the Point in the Line and check 
if it is the same as the point?
-//Probably not, this must be wrong
 static bool geoLineCoversPoint (GeoLines lines, GeoPoint point) {
        GeoPoint perpendicularPoint;
        for (int i = 0; i < lines.segmentCount; i++) {
-               perpendicularPoint = 
calculatePerpendicular(point,lines.segments[i]);
-               if (geoPointEquals(perpendicularPoint,point))
+               if (geoDistancePointLineInternal(point,lines.segments[i]) == 0)
                        return true;
        }
        return false;
@@ -872,6 +905,7 @@ static bool geoLineCoversLine (GeoLines 
 }
 #endif
 
+//TODO Check if this works correctly
 static bool geoCoversSingle(GEOSGeom a, GEOSGeom b)
 {
        int dimA = GEOSGeom_getDimensions(a), dimB = GEOSGeom_getDimensions(b);
@@ -975,23 +1009,76 @@ str wkbCoversGeographic(bit *out, wkb **
        return err;
 }
 
+//TODO I confused the Union with the Collect. The Collect operation keeps the 
input geometries but creates a Collection.
+//The union operation (which is the GEOS function I'm using here) merges the 
input geometries
+//TODO Fix this, possibly by using the GEOSGeom_createCollection() function 
with all the collected geometries 
 /**
-* Union (Group By implementation) 
+* Collect (Group By implementation) 
 * 
 **/
+static str alignedInputWithGroups (BAT *b, BAT *g, BAT *b_ordered) {
+       BAT *sortedgroups, *sortedorder;
+       BATiter bi = bat_iterator(b);
+       str msg = MAL_SUCCEED;
+       //Sort the groups
+       if ((BATsort(&sortedgroups, &sortedorder, NULL, g, NULL, NULL, false, 
false, true)) != GDK_SUCCEED) {
+               msg = createException(MAL, "geom.Collect", "BAT sort failed.");
+       }
+
+       const oid * sortedgroupsids = NULL, *sortedorderids = NULL;
+       oid sortedordercounter;
+
+       if (sortedgroups && !BATtdense(sortedgroups))
+               sortedgroupsids = (const oid *)Tloc(sortedgroups, 0);
+       //TODO Else, if it is a dense BAT
+       
+       if (sortedorder && !BATtdense(sortedorder))
+               sortedorderids = (const oid *)Tloc(sortedorder, 0);
+       else if (BATtdense(sortedorder))
+               sortedordercounter = sortedorder->tseqbase;
+
+       wkb** borderedvalues = NULL;
+       //Project new order onto input bat IF the sortedorder isn't dense -> in 
which case, the original input order is correct
+       if (sortedorderids ) {
+               //TODO Is this how the in-order BAT should be created?
+               if ((b_ordered = COLnew(b->hseqbase, ATOMindex("wkb"), 
BATcount(b), TRANSIENT)) == NULL)
+               {
+                       msg = createException(MAL, "geom.Collect", 
SQLSTATE(HY013) MAL_MALLOC_FAIL);
+               }
+               if ((borderedvalues = GDKzalloc(sizeof(wkb *) * BATcount(b))) 
== NULL)
+               {
+                       msg = createException(MAL, "geom.Collect", 
SQLSTATE(HY013) MAL_MALLOC_FAIL);
+               }
+               for (BUN i = 0; i < BATcount(b); i++) {
+                       oid is = i + sortedorder->hseqbase;
+                       borderedvalues[i] = (wkb*) 
BUNtail(bi,sortedorderids[is]);
+               }
+               if (BUNappendmulti(b_ordered, borderedvalues, BATcount(b), 
false) != GDK_SUCCEED)
+               {
+                       msg = createException(MAL, "geom.Union", 
SQLSTATE(38000) "BUNappend operation failed");
+               }
+       }
+       bat_iterator_end(&bi);
+       return msg;
+}
+
+
 /* Group By operation. Joins geometries together in the same group into a 
MultiGeometry */
-str wkbUnionAggrSubGroupedCand(bat *outid, const bat *bid, const bat *gid, 
const bat *eid, const bat *sid, const bit *skip_nils)
+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, *e = NULL, *s = NULL, *out = NULL;
+       BATiter bi;
+       const oid *gids = NULL;
+       wkb **unions = NULL;
+       GEOSGeom *unionGroup = NULL;
+       
        str msg = MAL_SUCCEED;
+       const char *err;
+
        oid min, max;
        BUN ngrp, ncand;
        struct canditer ci;
-       const char *err;
-       const oid *gids = NULL;
-       BATiter bi;
-       wkb **unions = NULL;
-       GEOSGeom *unionsGEOS = NULL;
+
        (void)skip_nils;
 
        //Get the BAT descriptors for the value bat + the other 3 optional BATs
@@ -1000,91 +1087,98 @@ str wkbUnionAggrSubGroupedCand(bat *outi
                (eid && !is_bat_nil(*eid) && (e = BATdescriptor(*eid)) == NULL) 
||
                (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL))
        {
-               msg = createException(MAL, "geom.Union", 
RUNTIME_OBJECT_MISSING);
+               msg = createException(MAL, "geom.Collect", 
RUNTIME_OBJECT_MISSING);
                return msg;
        }
 
+       //TODO Check this
+       /*BAT *b_ordered = NULL;
+       if((msg = alignedInputWithGroups(b,g,b_ordered)) == MAL_SUCCEED) {
+               b = b_ordered;
+       }*/
+       alignedInputWithGroups(b,g,NULL);
+
        //Fill in the values of the group aggregate operation
        if ((err = BATgroupaggrinit(b, g, e, s, &min, &max, &ngrp, &ci, 
&ncand)) != NULL)
        {
-               msg = createException(MAL, "geom.Union", "%s", err);
+               msg = createException(MAL, "geom.Collect", "%s", err);
                goto free;
        }
 
        if (ngrp == 0)
        {
-               msg = createException(MAL, "geom.Union", "Number of groups is 
equal to 0");
+               msg = createException(MAL, "geom.Collect", "Number of groups is 
equal to 0");
                goto free;
        }
 
        //Create a new BAT column of wkb type, with lenght equal to the number 
of groups
        if ((out = COLnew(min, ATOMindex("wkb"), ngrp, TRANSIENT)) == NULL)
        {
-               msg = createException(MAL, "geom.Union", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
+               msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
                goto free;
        }
 
-       bi = bat_iterator(b);
-
-       //Allocate space for the intermediate unions
+       //All unions for output BAT
        if ((unions = GDKzalloc(sizeof(wkb *) * ngrp)) == NULL)
        {
-               msg = createException(MAL, "geom.Union", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
-               bat_iterator_end(&bi);
+               msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
                goto free;
        }
 
-       if ((unionsGEOS = GDKzalloc(sizeof(GEOSGeom) * ngrp)) == NULL)
-       {
-               msg = createException(MAL, "geom.Union", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
-               bat_iterator_end(&bi);
+       //Intermediate array for all the geometries in a group
+       //TODO Change allocation size
+       if ((unionGroup = GDKzalloc(sizeof(GEOSGeom) * ncand)) == NULL)
+       {
+               msg = createException(MAL, "geom.Collect", SQLSTATE(HY013) 
MAL_MALLOC_FAIL);
                goto free;
        }
 
        if (g && !BATtdense(g))
                gids = (const oid *)Tloc(g, 0);
-
+       bi = bat_iterator(b);
+
+       oid lastGrp = -1;
+       int lastType = -1, geomCount = 0;
        for (BUN i = 0; i < ncand; i++)
        {
                oid o = canditer_next(&ci);
                BUN p = o - b->hseqbase;
-               wkb *inWKB = (wkb *)BUNtvar(bi, p);
                oid grp = gids ? gids[p] : g ? min + (oid)p : 0;
-
-#ifndef NDEBUG
-               /*char *geomSTR;
-               wkbAsText(&geomSTR, &inWKB, NULL);
-               printf("Row %zu: %s\n", i, geomSTR);
-               fflush(stdout);
-               GDKfree(geomSTR);*/
-#endif
-               //Instead of converting back and forth with the wkbUnion() 
func, convert only once from wkb to GEOS
-               if (unionsGEOS[grp] == NULL)
-               {
-                       if (!is_wkb_nil(inWKB))
-                       {
-                               unionsGEOS[grp] = wkb2geos(inWKB);
+               wkb* inWKB = (wkb *)BUNtvar(bi, p);
+               GEOSGeom inGEOM = wkb2geos(inWKB);
+               
+               if (grp != lastGrp) {
+                       if (lastGrp != (oid)-1) {
+                               //Finish the previous group, move on to the 
next one
+                               unions[lastGrp] = 
geos2wkb(GEOSGeom_createCollection(lastType,unionGroup,geomCount));
+                               GDKfree(unionGroup);
+                               //TODO Change allocation size
+                               if ((unionGroup = GDKzalloc(sizeof(GEOSGeom) * 
ncand)) == NULL)
+                               {
+                                       msg = createException(MAL, 
"geom.Collect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
+                                       bat_iterator_end(&bi);
+                                       goto free;
+                               }
+                               geomCount = 0;
                        }
+                       else {
+                               //First group
+                               //Type + 4 equals to a collection of that type 
(Point is 0, MultiPoint is 4)
+                               lastType = GEOSGeomTypeId(inGEOM) + 4;
+                               geomCount = 0;
+                       }
+                       lastGrp = grp;
                }
-               else
-               {
-                       if (!is_wkb_nil(inWKB))
-                       {
-                               GEOSGeom nextUnion = wkb2geos(inWKB);
-                               if (GEOSGetSRID(nextUnion) == 
GEOSGetSRID(unionsGEOS[grp]))
-                               {
-                                       //TODO: This operation is really slow.
-                                       unionsGEOS[grp] = 
GEOSUnion(unionsGEOS[grp], nextUnion);
-                               }
-                       }
+
+               unionGroup[geomCount] = inGEOM;
+               geomCount += 1;
+               if (lastType != GEOS_GEOMETRYCOLLECTION && 
GEOSGeomTypeId(inGEOM) + 4 != lastType) {
+                       lastType = GEOS_GEOMETRYCOLLECTION;
                }
        }
-
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to