Changeset: 8715067844c5 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/8715067844c5 Modified Files: geom/monetdb5/geom.c geom/monetdb5/geom.h geom/sql/40_geom.sql Branch: geo-update Log Message:
First implementation for ST_MakeLine aggregate diffs (240 lines): diff --git a/geom/monetdb5/geom.c b/geom/monetdb5/geom.c --- a/geom/monetdb5/geom.c +++ b/geom/monetdb5/geom.c @@ -191,6 +191,7 @@ wkbCollectAggrSubGroupedCand(bat *outid, GDKfree(unionGroup); if (BUNappendmulti(out, unions, ngrp, false) != GDK_SUCCEED) { + //TODO Free out BAT msg = createException(MAL, "geom.Union", SQLSTATE(38000) "BUNappend operation failed"); bat_iterator_end(&bi); if (unions) { @@ -3325,7 +3326,7 @@ wkbMakeLine(wkb **out, wkb **geom1WKB, w //Gets a BAT with geometries and returns a single LineString str -wkbMakeLineAggr(wkb **outWKB, bat *inBAT_id) +wkbMakeLineAggr(wkb **outWKB, bat *bid) { BAT *inBAT = NULL; BATiter inBAT_iter; @@ -3334,7 +3335,7 @@ wkbMakeLineAggr(wkb **outWKB, bat *inBAT str err; //get the BATs - if ((inBAT = BATdescriptor(*inBAT_id)) == NULL) { + if ((inBAT = BATdescriptor(*bid)) == NULL) { throw(MAL, "geom.MakeLine", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); } @@ -3379,6 +3380,173 @@ wkbMakeLineAggr(wkb **outWKB, bat *inBAT return err; } +static str +wkbMakeLineAggrArray(wkb **outWKB, wkb **inWKB_array, int size) { + str msg = MAL_SUCCEED; + int i; + wkb *aWKB, *bWKB; + + /* TODO: what should be returned if the input is less than + * two rows? --sjoerd */ + if (size == 0) { + if ((*outWKB = wkbNULLcopy()) == NULL) + throw(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL); + return MAL_SUCCEED; + } + aWKB = inWKB_array[0]; + if (size == 1) { + msg = wkbFromWKB(outWKB, &aWKB); + if (msg) { + freeException(msg); + throw(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL); + } + return MAL_SUCCEED; + } + bWKB = inWKB_array[1]; + //create the first line using the first two geometries + msg = wkbMakeLine(outWKB, &aWKB, &bWKB); + + // add one more segment for each following row + for (i = 2; msg == MAL_SUCCEED && i < size; i++) { + aWKB = *outWKB; + bWKB = inWKB_array[i]; + *outWKB = NULL; + + msg = wkbMakeLine(outWKB, &aWKB, &bWKB); + GDKfree(aWKB); + } + return msg; +} + +//TODO Check SRID +//TODO Check if the input geometries are points +str +wkbMakeLineAggrSubGroupedCand(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; + BAT *sortedgroups, *sortedorder, *sortedinput; + BATiter bi; + const oid *gids = NULL; + str msg = MAL_SUCCEED; + + oid min, max; + BUN ngrp; + struct canditer ci; + + oid lastGrp = -1; + wkb **lines = NULL, **lineGroup = NULL; + int position = 0; + + //Not using these variables + (void) skip_nils; + (void) eid; + + //Get the BAT descriptors for the value, group and candidate bats + 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, "aggr.MakeLine", RUNTIME_OBJECT_MISSING); + goto free; + } + + if ((BATsort(&sortedgroups, &sortedorder, NULL, g, NULL, NULL, false, false, true)) != GDK_SUCCEED) { + msg = createException(MAL, "aggr.MakeLine", "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); + BBPunfix(b->batCacheid); + BBPunfix(g->batCacheid); + b = sortedinput; + g = sortedgroups; + BBPunfix(sortedorder->batCacheid); + } + else { + BBPunfix(sortedgroups->batCacheid); + BBPunfix(sortedorder->batCacheid); + } + + //Fill in the values of the group aggregate operation + if ((msg = (str) BATgroupaggrinit(b, g, NULL, s, &min, &max, &ngrp, &ci)) != NULL) { + msg = createException(MAL, "aggr.MakeLine", "%s", msg); + 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, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL); + goto free; + } + + //Create an array of WKB to hold the results of the MakeLine + if ((lines = GDKzalloc(sizeof(wkb *) * ngrp)) == NULL) { + msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL); + BBPunfix(out->batCacheid); + goto free; + } + + //Create an array of WKB to hold the points to be made into a line (for one group at a time) + if ((lineGroup = GDKzalloc(sizeof(wkb*) * ci.ncand)) == NULL) { + msg = createException(MAL, "aggr.MakeLine", SQLSTATE(HY013) MAL_MALLOC_FAIL); + BBPunfix(out->batCacheid); + goto free; + } + + if (g && !BATtdense(g)) + gids = (const oid *)Tloc(g, 0); + bi = bat_iterator(b); + + for (BUN i = 0; i < ci.ncand; i++) { + oid o = canditer_next(&ci); + BUN p = o - b->hseqbase; + oid grp = gids ? gids[p] : g ? min + (oid)p : 0; + wkb *inWKB = (wkb *)BUNtvar(bi, p); + + if (grp != lastGrp) { + if (lastGrp != (oid)-1) { + msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position); + position = 0; + } + lastGrp = grp; + } + lineGroup[position++] = inWKB; + } + msg = wkbMakeLineAggrArray(&lines[lastGrp], lineGroup, position); + + if (BUNappendmulti(out, lines, ngrp, false) != GDK_SUCCEED) { + //TODO Free out BAT + msg = createException(MAL, "geom.Union", SQLSTATE(38000) "BUNappend operation failed"); + bat_iterator_end(&bi); + goto free; + } + + bat_iterator_end(&bi); + + *outid = out->batCacheid; + BBPkeepref(out); + BBPunfix(b->batCacheid); + if (g) + BBPunfix(g->batCacheid); + if (s) + BBPunfix(s->batCacheid); + return MAL_SUCCEED; +free: + if (b) + BBPunfix(b->batCacheid); + if (g) + BBPunfix(g->batCacheid); + if (s) + BBPunfix(s->batCacheid); + return msg; +} + +str +wkbMakeLineAggrSubGrouped (bat *out, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils) { + return wkbMakeLineAggrSubGroupedCand(out,bid,gid,eid,NULL,skip_nils); +} + /* Returns the first or last point of a linestring */ static str wkbBorderPoint(wkb **out, wkb **geom, GEOSGeometry *(*func) (const GEOSGeometry *), const char *name) @@ -5392,7 +5560,9 @@ static mel_func geom_init_funcs[] = { command("geom", "Contains", wkbContains_point_bat, false, "Returns true if the Geometry-BAT a 'spatially contains' Geometry-B b", args(1,4, batarg("",bit),arg("a",wkb),batarg("px",dbl),batarg("py",dbl))), command("geom", "PointsNum", wkbNumPoints, false, "The number of points in the Geometry. If check=1, the geometry should be a linestring", args(1,3, arg("",int),arg("w",wkb),arg("check",int))), command("geom", "MakeLine", wkbMakeLine, false, "Gets two point or linestring geometries and returns a linestring geometry", args(1,3, arg("",wkb),arg("a",wkb),arg("b",wkb))), - command("geom", "MakeLine", wkbMakeLineAggr, false, "Gets a BAT with point or linestring geometries and returns a single linestring geometry", args(1,2, arg("",wkb),batarg("a",wkb))), + command("aggr", "MakeLine", wkbMakeLineAggr, false, "Gets a BAT with point or linestring geometries and returns a single linestring geometry", args(1,2, arg("",wkb),batarg("a",wkb))), + command("aggr", "subMakeLine", wkbMakeLineAggrSubGrouped, false, "TODO", args(1, 5, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batarg("e", oid), arg("skip_nils", bit))), + command("aggr", "subMakeLine", wkbMakeLineAggrSubGroupedCand, false, "TODO", args(1, 6, batarg("", wkb), batarg("val", wkb), batarg("g", oid), batargany("e", 1), batarg("g", oid), arg("skip_nils", bit))), command("geom", "PointOnSurface", wkbPointOnSurface, false, "Returns a point guaranteed to lie on the surface. Similar to postGIS it works for points and lines in addition to surfaces and for 3d geometries.", args(1,2, arg("",wkb),arg("w",wkb))), command("geom", "mbr", wkbMBR, false, "Creates the mbr for the given wkb.", args(1,2, arg("",mbr),arg("",wkb))), command("geom", "MakeBox2D", wkbBox2D, false, "Creates an mbr from the two 2D points", args(1,3, arg("",mbr),arg("",wkb),arg("",wkb))), diff --git a/geom/monetdb5/geom.h b/geom/monetdb5/geom.h --- a/geom/monetdb5/geom.h +++ b/geom/monetdb5/geom.h @@ -128,7 +128,9 @@ geom_export str wkbEnvelope(wkb **out, w geom_export str wkbEnvelopeFromCoordinates(wkb** out, dbl* xmin, dbl* ymin, dbl* xmax, dbl* ymax, int* srid); geom_export str wkbMakePolygon(wkb** out, wkb** external, bat* internalBAT_id, int* srid); geom_export str wkbMakeLine(wkb**, wkb**, wkb**); -geom_export str wkbMakeLineAggr(wkb** outWKB, bat* inBAT_id); +geom_export str wkbMakeLineAggr (wkb **out, bat *bid); +geom_export str wkbMakeLineAggrSubGrouped(bat *out, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils); +geom_export str wkbMakeLineAggrSubGroupedCand(bat* outid, const bat* bid, const bat* gid, const bat* eid, const bat* sid, const bit* skip_nils); geom_export str wkbExteriorRing(wkb**, wkb**); geom_export str wkbInteriorRingN(wkb**, 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 @@ -328,7 +328,7 @@ GRANT EXECUTE ON FUNCTION ST_MakePoint(d CREATE FUNCTION ST_MakePointM(x double, y double, m double) RETURNS Geometry EXTERNAL NAME geom."MakePointM"; GRANT EXECUTE ON FUNCTION ST_MakePointM(double, double, double) TO PUBLIC; --CREATE FUNCTION ST_MakeLine(geometry set geoms)????? -CREATE AGGREGATE ST_MakeLine(geom Geometry) RETURNS Geometry external name geom."MakeLine"; +CREATE AGGREGATE ST_MakeLine(geom Geometry) RETURNS Geometry external name aggr."MakeLine"; CREATE FUNCTION ST_MakeLine(geom1 Geometry, geom2 Geometry) RETURNS Geometry external name geom."MakeLine"; --two single geometries GRANT EXECUTE ON FUNCTION ST_MakeLine(Geometry, Geometry) TO PUBLIC; --CREATE FUNCTION ST_MakeLine(geoms_arr Geometry[]) RETURNS Geometry external name geom."MakeLine"; _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org