]> granicus.if.org Git - postgis/commitdiff
Added the collect(geometry) function which is an aggregate function that
authorChris Hodgson <chodgson@refractions.net>
Fri, 22 Mar 2002 18:42:56 +0000 (18:42 +0000)
committerChris Hodgson <chodgson@refractions.net>
Fri, 22 Mar 2002 18:42:56 +0000 (18:42 +0000)
takes a group of geometries and turns them into a geometry collection. For
example, "select collect(roadsgeom) from roadstable group by roadname"
would return one geometrycollection for each unique road name.

git-svn-id: http://svn.osgeo.org/postgis/trunk@130 b70326c6-7e19-0410-871a-916f4a2858ee

postgis.h
postgis.sql.in
postgis_fn.c
postgis_inout.c

index 6244242a839d207f309cc079cc84106d7e584b6a..7c94c108c64872b51d1303f3785366439dd61712 100644 (file)
--- a/postgis.h
+++ b/postgis.h
@@ -490,6 +490,7 @@ Datum box3d_zmax(PG_FUNCTION_ARGS);
 Datum transform_geom(PG_FUNCTION_ARGS);
 
 Datum max_distance(PG_FUNCTION_ARGS);
+Datum collector(PG_FUNCTION_ARGS);
 
 
 //for GIST index
index 87b9503c9489d067d3d46f05dbe4008e23b4e1b6..f1d9c63f6c28329197a8efdd40af14c905b733c6 100644 (file)
@@ -678,6 +678,17 @@ CREATE AGGREGATE extent(
        stype = BOX3D
 );
 
+CREATE FUNCTION collector(GEOMETRY,GEOMETRY)
+   RETURNS GEOMETRY
+   AS '@MODULE_FILENAME@'
+            LANGUAGE 'c';
+
+CREATE AGGREGATE collect(
+       sfunc = collector,
+       basetype = GEOMETRY,
+       stype = GEOMETRY
+);
+
 
 
 -------  OPERATOR functions
index 2eac977d27c13d0e7983a4797b01d29a44784bd3..ff9fdcb289e0364ca1c6c5bbc26849206fb15b6a 100644 (file)
@@ -2395,20 +2395,21 @@ POINT3D *segmentize_ring(POINT3D        *points, double dist, int num_points_in, int *n
 PG_FUNCTION_INFO_V1(segmentize);
 Datum segmentize(PG_FUNCTION_ARGS)
 {
-               GEOMETRY                      *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
-               GEOMETRY                        *result,*result2;
+               GEOMETRY                *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               GEOMETRY                *result,*result2;
                double                  maxdist = PG_GETARG_FLOAT8(1);
-               int32                           *offsets1,*p_npoints_ring;
+               int32                   *offsets1,*p_npoints_ring;
                int                             g1_i,r;
-               POLYGON3D                       *p,*poly;
+               POLYGON3D               *p,*poly;
                POINT3D                 *polypts;
                int                             num_polypts;
                POINT3D                 *all_polypts;
                int                             all_num_polypts,all_num_polypts_max;
                POINT3D                 *p_points,*rr;
                int                             new_size;
-               bool                            first_one;
+               bool                    first_one;
                int                             poly_size;
+               BOX3D                   *bbox;
 
        first_one = 1;
 
@@ -2474,12 +2475,92 @@ Datum segmentize(PG_FUNCTION_ARGS)
                else
                {
                        result2 = add_to_geometry(result,poly_size, (char *) poly, POLYGONTYPE);
+                       bbox = bbox_of_geometry( result2 ); // make bounding box
+                       memcpy( &result2->bvol, bbox, sizeof(BOX3D) ); // copy bounding box
+                       pfree(bbox); // free bounding box
                        pfree(result);
                        result = result2;
                        pfree(poly);
                        pfree(all_polypts);
                }       
 
-       }//foreach polygon
+       } // foreach polygon
        PG_RETURN_POINTER(result);
+}
+
+
+// collector( geom, geom ) returns a geometry which contains
+// all the sub_objects from both of the argument geometries
+
+// returned geometry is always a geomtry collection
+// bboxonly types are treated as null geometries (no sub_objects)
+PG_FUNCTION_INFO_V1( collector );
+Datum collector( PG_FUNCTION_ARGS )
+{
+       Pointer         geom1_ptr = PG_GETARG_POINTER(0);
+       Pointer         geom2_ptr =  PG_GETARG_POINTER(1);
+       GEOMETRY        *geom1, *geom2, *temp, *result;
+       BOX3D           *bbox;
+       int32           i, size, *offsets2;
+
+       // return null if both geoms are null
+       if ( (geom1_ptr == NULL) && (geom2_ptr == NULL) )
+       {
+               PG_RETURN_NULL();
+       }
+
+       // return a copy of the second geom if only first geom is null
+       if (geom1_ptr == NULL)
+       {
+               geom2 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+               result = (GEOMETRY *)palloc( geom2->size );
+               memcpy( result, geom2, geom2->size );
+               result->type = COLLECTIONTYPE;
+               PG_RETURN_POINTER(result);
+       }
+
+       // return a copy of the first geom if only second geom is null
+       if (geom2_ptr == NULL)
+       {
+               geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               result = (GEOMETRY *)palloc( geom1->size );
+               memcpy( result, geom1, geom1->size );
+               result->type = COLLECTIONTYPE;
+               PG_RETURN_POINTER(result);
+       }
+
+       geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       geom2 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+       if ( geom1->SRID != geom2->SRID )
+       {
+               elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
+               PG_RETURN_NULL();
+       }
+       result = (GEOMETRY *)palloc( geom1->size );
+       memcpy( result, geom1, geom1->size );
+       result->type = COLLECTIONTYPE;
+
+       offsets2 = (int32 *)( ((char *)&(geom2->objType[0])) + sizeof( int32 ) * geom2->nobjs ) ;
+
+       for (i=0; i<geom2->nobjs; i++)
+       {
+               if( i == geom2->nobjs-1 )
+               {
+                       size = geom2->size - offsets2[i];
+               }
+               else 
+               {
+                       size = offsets2[i+1] - offsets2[i];
+               }
+               temp = add_to_geometry( result, size, ((char *) geom2 + offsets2[i]), geom2->objType[i] );
+               pfree( result );
+               result = temp;
+       }
+
+       result->is3d = geom1->is3d || geom2->is3d;
+       bbox = bbox_of_geometry( result ); // make bounding box
+       memcpy( &result->bvol, bbox, sizeof(BOX3D) ); // copy bounding box
+       pfree( bbox ); // free bounding box
+
+       PG_RETURN_POINTER( result );
 }
\ No newline at end of file
index 43f504e1005423261488a146bee92d73d771a9a4..f59fd357e4a727515be26e951697c161932f932e 100644 (file)
@@ -2956,7 +2956,6 @@ GEOMETRY  *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int ty
        int             size_obj,next_offset;
        GEOMETRY        *result;
        int32           *old_offsets, *new_offsets;
-       BOX3D           *bbox;
 
        //all the offsets could cause re-alignment problems, so need to deal with each on
        size = geom->size +(4*geom->nobjs +1) /*byte align*/
@@ -2965,7 +2964,10 @@ GEOMETRY *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int ty
        result = (GEOMETRY *) palloc(size);
        result->size = size;
        result->is3d = geom->is3d;
-
+       result->SRID = geom->SRID;
+       result->offsetX = geom->offsetX;
+       result->offsetY = geom->offsetY;
+       result->scale = geom->scale;
 
        //accidently sent in a single-entity type but gave it a multi-entity type
        //  re-type it as single-entity
@@ -3046,11 +3048,6 @@ GEOMETRY *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int ty
        new_offsets[ result->nobjs -1 ] = next_offset;
        memcpy(  ((char *) result)  + new_offsets[result->nobjs-1] ,sub_obj , sub_obj_size);
 
-//printf("calculating bbox\n");
-
-       bbox = bbox_of_geometry(result);
-       memcpy(&result->bvol,bbox, sizeof(BOX3D) ); //make bounding box
-
 //printf("returning\n");
 
        return result;