]> granicus.if.org Git - postgis/commitdiff
Added more openGIS functions:
authorDavid Blasby <dblasby@gmail.com>
Thu, 2 Aug 2001 16:50:24 +0000 (16:50 +0000)
committerDavid Blasby <dblasby@gmail.com>
Thu, 2 Aug 2001 16:50:24 +0000 (16:50 +0000)
Length2d() is renamed length()
perimeter2d() is renamed to perimeter()

numgeometries(geometry) works on MULTI* types
geometryn(geometry) works on MULTI* types

from section 2.1.5.1
--------------------
startpoint(geometry) :- if geometry is a linestring, return the first
point.  Otherwise, return NULL.

endpoint(geometry) :- if geometry is a linestring, return the last
point.  Otherwise, return NULL.

from section 2.1.9.1/3.2.18.2
--------------------

centroid(geometry) :- if geometry is a polygon (or multipolygon), return
the mathematical centroid (no guaranteed to be on polygon), otherwise
return NULL. I define centroid as the average location of all the points
in the polygon (outer ring only).  For multipolygons, average all the
points on all the outer rings.

from section 3.2.12.2/3.2.17.2
---------------------
isclosed(geometry) :- if geometry is a linestring then returns
startpoint == endpoint.  If its not a linestring then return NULL.  If
its a multilinestring, return true only if all the sub-linestrings have
startpoint=endpoint.

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

postgis.h
postgis.sql.in
postgis_fn.c

index 3f9685bee147427670f85ea3f676a2c50b7bfd74..19ed72e7d9595f8ed58d62eb8998ac48ff2ee5da 100644 (file)
--- a/postgis.h
+++ b/postgis.h
@@ -401,6 +401,13 @@ Datum expand_bbox(PG_FUNCTION_ARGS);
 Datum srid_geom(PG_FUNCTION_ARGS);
 Datum geometry_from_text(PG_FUNCTION_ARGS);
 
+Datum startpoint(PG_FUNCTION_ARGS);
+
+Datum endpoint(PG_FUNCTION_ARGS);
+Datum isclosed(PG_FUNCTION_ARGS);
+
+Datum centroid(PG_FUNCTION_ARGS);
+
 //for GIST index
 typedef char* (*BINARY_UNION)(char*, char*, int*);
 typedef float (*SIZE_BOX)(char*);
index f728f7c0ab421329ad8ebf9a203a6066e0a565b2..01819e631f6ae6aed77b5a6b97c4d32e4260ffaf 100644 (file)
@@ -24,7 +24,7 @@ f_table_name    varchar(256) not null,
 f_geometry_column varchar(256) not null,
 coord_dimension  integer NOT NULL,
 srid           integer NOT NULL,
-type           integer NOT NULL,
+type           varchar(30) NOT NULL,
 CONSTRAINT GC_PK primary key ( f_table_catalog,f_table_schema, f_table_name,f_geometry_column)
 ) ;
 
@@ -97,11 +97,12 @@ END;
 -- select DropGeometryColumn('new_test','test_table','mygeom');
 
 
----select AddGeometryColumn('new_test','tt','new_geom2',2,0,3);
----drop function AddGeometryColumn(varchar,varchar,varchar,integer,integer,integer);
+drop function AddGeometryColumn(varchar,varchar,varchar,integer,varchar,integer);
 
 --- AddGeometryColumn(<db name>,<table name>,<column name>, <srid>, <type>,<dim>)
---- only type available is 0 GEOMETRY_GENERIC, so its ignored (for future expansion)
+--- type can be one of GEOMETRY, GEOMETRYCOLLECTION,POINT,MULTIPOINT,POLYGON,
+--- MULTIPOLYGON,LINESTRING, or MULTILINESTRING 
+--- types (except GEOMETRY) are checked for consistency using a CHECK constraint
 --- uses SQL ALTER TABLE command to add the geometry column to the table
 --- added a row to geometry_columns with info (catalog = '', schema = <db name>)
 --- addes a constraint on the table that all the geometries MUST have the same SRID
@@ -109,7 +110,7 @@ END;
 --- should also check the precision grid (future expansion)
 ---  also checks to see if the database_name is in the pg_database table
 
-CREATE FUNCTION AddGeometryColumn(varchar,varchar,varchar,integer,integer,integer)
+CREATE FUNCTION AddGeometryColumn(varchar,varchar,varchar,integer,varchar,integer)
        RETURNS text
        AS 
 '
@@ -126,13 +127,16 @@ DECLARE
        db_name_ok   boolean;
 
 BEGIN
-       IF ( (new_dim >3) or (new_dim <0) ) THEN
-               RAISE EXCEPTION ''invalid dimension'';
+
+       IF (not( (new_type =''GEOMETRY'') or (new_type =''GEOMETRYCOLLECTION'')  or (new_type =''POINT'')
+                 or (new_type =''MULTIPOINT'') or      (new_type =''POLYGON'')  or (new_type =''MULTIPOLYGON'')  
+                 or (new_type =''LINESTRING'')  or (new_type =''MULTILINESTRING'')   ) ) THEN          
+               RAISE EXCEPTION ''invalid type name - valid ones are: GEOMETRY, GEOMETRYCOLLECTION,POINT,MULTIPOINT,POLYGON,MULTIPOLYGON,LINESTRING, or MULTILINESTRING  '';
                return ''fail'';
        END IF;
 
-       IF (new_type <> 0) THEN
-               RAISE EXCEPTION ''invalid type'';
+       IF ( (new_dim >3) or (new_dim <0) ) THEN
+               RAISE EXCEPTION ''invalid dimension'';
                return ''fail'';
        END IF;
 
@@ -151,18 +155,24 @@ BEGIN
        EXECUTE ''INSERT INTO   geometry_columns VALUES ('' || quote_literal('''') || '','' ||
                         quote_literal(database_name) || '','' || quote_literal(table_name) || '','' ||
                         quote_literal(column_name) || '','' ||
-                        new_dim ||'',''||new_srid||'',''||new_type||'')'';
+                        new_dim ||'',''||new_srid||'',''||quote_literal(new_type)||'')'';
 
 
  
        EXECUTE ''ALTER TABLE '' ||table_name||'' ADD CHECK (SRID('' || column_name ||
                '') = '' || new_srid || '')'' ;
+
+       IF (not(new_type = ''GEOMETRY'')) THEN
+               EXECUTE ''ALTER TABLE '' ||table_name||'' ADD CHECK ( geometrytype(''||column_name||'')=''|| quote_literal(new_type)||'')'';
+       END IF;
+
        return ''Geometry column '' || column_name || '' added to table ''
-                       ||table_name ||'' with a SRID of ''||new_srid;  
+                       ||table_name ||'' with a SRID of ''||new_srid || '' and type ''||new_type;      
 END;
 '
        LANGUAGE 'plpgsql' with (isstrict);
 
+---select AddGeometryColumn('new_test','tt','new_geom3',2,'GEOMETRY',3);
 
 
 
@@ -401,7 +411,7 @@ CREATE FUNCTION length3d(GEOMETRY)
    AS '@MODULE_FILENAME@'
    LANGUAGE 'c' with (isstrict);
 
-CREATE FUNCTION length2d(GEOMETRY)
+CREATE FUNCTION length(GEOMETRY)
    RETURNS FLOAT8
    AS '@MODULE_FILENAME@'
    LANGUAGE 'c' with (isstrict);
@@ -416,7 +426,7 @@ CREATE FUNCTION perimeter3d(GEOMETRY)
    AS '@MODULE_FILENAME@'
    LANGUAGE 'c' with (isstrict);
 
-CREATE FUNCTION perimeter2d(GEOMETRY)
+CREATE FUNCTION perimeter(GEOMETRY)
    RETURNS FLOAT8
    AS '@MODULE_FILENAME@'
    LANGUAGE 'c' with (isstrict);
@@ -431,6 +441,25 @@ CREATE FUNCTION point_inside_circle(GEOMETRY,float8,float8,float8)
    AS '@MODULE_FILENAME@'
    LANGUAGE 'c' with (isstrict);
 
+CREATE FUNCTION startpoint(GEOMETRY)
+   RETURNS GEOMETRY
+   AS '@MODULE_FILENAME@'
+   LANGUAGE 'c' with (isstrict);
+
+CREATE FUNCTION endpoint(GEOMETRY)
+   RETURNS GEOMETRY
+   AS '@MODULE_FILENAME@'
+   LANGUAGE 'c' with (isstrict);
+
+CREATE FUNCTION isclosed(GEOMETRY)
+   RETURNS boolean
+   AS '@MODULE_FILENAME@'
+   LANGUAGE 'c' with (isstrict);
+
+CREATE FUNCTION centroid(GEOMETRY)
+   RETURNS GEOMETRY
+   AS '@MODULE_FILENAME@'
+   LANGUAGE 'c' with (isstrict);
 
 ------- Aggregate
 
index 928a5718c0bf60754d1046c4782dc490bc7749d8..fd4e1fa238f3ca053c2017c385ba310c04444967 100644 (file)
@@ -1374,13 +1374,18 @@ Datum interiorringn_polygon(PG_FUNCTION_ARGS)
 
 //        numgeometries(GEOMETRY) -- if GEOMETRY is a GEOMETRYCOLLECTION, return
 //the number of geometries in it, otherwise return NULL.
+//             if GEOMETRY is a MULTI* type, return the number of sub-types in it.
 
 PG_FUNCTION_INFO_V1(numgeometries_collection);
 Datum numgeometries_collection(PG_FUNCTION_ARGS)
 {
                GEOMETRY                      *geom = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
 
-               if (geom->type == COLLECTIONTYPE)
+               if  ( (geom->type == COLLECTIONTYPE) || 
+                     (geom->type == MULTIPOINTTYPE) || 
+                       (geom->type == MULTILINETYPE) || 
+                       (geom->type == MULTIPOLYGONTYPE)
+                   )
                        PG_RETURN_INT32( geom->nobjs ) ;
                else
                        PG_RETURN_NULL();       
@@ -1392,6 +1397,7 @@ Datum numgeometries_collection(PG_FUNCTION_ARGS)
 //return NULL.   NOTE: MULTIPOINT, MULTILINESTRING,MULTIPOLYGON are
 //converted to sets of POINT,LINESTRING, and POLYGON so the index may
 //change.
+// if GEOMETRY is a MULTI* type, return the Nth sub-geometry
 
 
 PG_FUNCTION_INFO_V1(geometryn_collection);
@@ -1407,9 +1413,14 @@ Datum geometryn_collection(PG_FUNCTION_ARGS)
 
        offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ;
 
-               if (geom->type != COLLECTIONTYPE)
+               if  (!(( (geom->type == COLLECTIONTYPE) || 
+                     (geom->type == MULTIPOINTTYPE) || 
+                       (geom->type == MULTILINETYPE) || 
+                       (geom->type == MULTIPOLYGONTYPE)
+                   )))
                                PG_RETURN_NULL();                       
 
+
                if ( (wanted_index <0) || (wanted_index > (geom->nobjs-1) ) )
                        PG_RETURN_NULL();       //bad index
 
@@ -2032,4 +2043,153 @@ Datum expand_bbox(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(result);
 }
 
+//startpoint(geometry) :- if geometry is a linestring, return the first
+//point.  Otherwise, return NULL.
+
+PG_FUNCTION_INFO_V1(startpoint);
+Datum startpoint(PG_FUNCTION_ARGS)
+{
+               GEOMETRY                      *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               POINT3D                 *pt;
+               LINE3D                  *line;
+               int32                           *offsets1;
+
+       if (geom1->type != LINETYPE)
+               PG_RETURN_NULL();
+
+       offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
+
+
+       line = (LINE3D *) ( (char *) geom1 +offsets1[0]);
+
+       pt = &line->points[0];  
+       
+       PG_RETURN_POINTER(
+                               make_oneobj_geometry(sizeof(POINT3D),
+                                                        (char *) pt,
+                                                          POINTTYPE,  geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) 
+                               );
+}
+
+//endpoint(geometry) :- if geometry is a linestring, return the last
+//point.  Otherwise, return NULL.
+
+PG_FUNCTION_INFO_V1(endpoint);
+Datum endpoint(PG_FUNCTION_ARGS)
+{
+               GEOMETRY                      *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               POINT3D                 *pt;
+               LINE3D                  *line;
+               int32                           *offsets1;
+
+
+
+       if (geom1->type != LINETYPE)
+               PG_RETURN_NULL();
+
+       offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
+
+
+       line = (LINE3D *) ( (char *) geom1 +offsets1[0]);
+
+
+       pt = &line->points[line->npoints-1];  
+       
+       PG_RETURN_POINTER(
+                               make_oneobj_geometry(sizeof(POINT3D),
+                                                        (char *) pt,
+                                                          POINTTYPE,  geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) 
+                               );
+}
+
+
+
+//isclosed(geometry) :- if geometry is a linestring then returns 
+//startpoint == endpoint.  If its not a linestring then return NULL.  If
+//its a multilinestring, return true only if all the sub-linestrings have
+//startpoint=endpoint.
+//calculations always done in 3d (even if you do a force2d)
+
+
+PG_FUNCTION_INFO_V1(isclosed);
+Datum isclosed(PG_FUNCTION_ARGS)
+{
+               GEOMETRY                      *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               POINT3D                 *pt1,*pt2;
+               LINE3D                  *line;
+               int32                           *offsets1;
+               int                             t;
+
+       if  (!((geom1->type == LINETYPE) || (geom1->type == MULTILINETYPE) ))
+               PG_RETURN_NULL();
+
+       offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
+
+
+       for (t=0; t< geom1->nobjs; t++)
+       {
+               line = (LINE3D *) ( (char *) geom1 +offsets1[t]);
+               pt1 = &line->points[0];  
+               pt2 = &line->points[line->npoints-1];  
+               
+               if ( (pt1->x != pt2->x) || (pt1->y != pt2->y) || (pt1->z != pt2->z) )
+                       PG_RETURN_BOOL(FALSE);  
+       }
+       PG_RETURN_BOOL(TRUE);
+}
+
+PG_FUNCTION_INFO_V1(centroid);
+Datum centroid(PG_FUNCTION_ARGS)
+{
+               GEOMETRY                      *geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+               int32                           *offsets1;
+               POINT3D                 *pts,*cent;
+               POLYGON3D                       *poly;
+               int                             t,v;
+               int                             num_points,num_points_tot;
+               double                  tot_x,tot_y,tot_z;
+               GEOMETRY                        *result;
+               
+
+
+       offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
+
+       if  (!((geom1->type == POLYGONTYPE) || (geom1->type == MULTIPOLYGONTYPE) ))
+               PG_RETURN_NULL();
+
+       //find the centroid 
+       num_points_tot = 0;
+               tot_x = 0; tot_y =0; tot_z=0;
+       
+       for (t=0;t<geom1->nobjs;t++)
+       {
+               poly = (POLYGON3D *) ( (char *) geom1 +offsets1[t]);    
+               pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] )  );
+               pts = (POINT3D *) MAXALIGN(pts);
+               num_points =poly->npoints[0];
+
+               // just do the outer ring
+       //      for (u=0;u<poly->nrings;u++)
+       //      {
+       //              num_points += poly->npoints[u];
+       //      }
+
+               num_points_tot += num_points-1; //last point = 1st point
+               for (v=0;v<num_points-1;v++)
+               {
+                       tot_x  += pts[v].x;     
+                       tot_y  += pts[v].y;
+                       tot_z  += pts[v].z;             
+               }
+       }
+       cent = palloc(sizeof(POINT3D));
+       set_point(cent, tot_x/num_points_tot, tot_y/num_points_tot,tot_z/num_points_tot);
+        result = (
+                               make_oneobj_geometry(sizeof(POINT3D),
+                                                        (char *) cent,
+                                                          POINTTYPE,  geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) 
+                               );
+       pfree(cent);
+       PG_RETURN_POINTER(result);
 
+}
\ No newline at end of file