From: David Blasby Date: Thu, 2 Aug 2001 16:50:24 +0000 (+0000) Subject: Added more openGIS functions: X-Git-Tag: pgis_0_6_0~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=912b0a8b7515acfff7380a5cc24e1e01f5bbeffc;p=postgis Added more openGIS functions: 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 --- diff --git a/postgis.h b/postgis.h index 3f9685bee..19ed72e7d 100644 --- 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*); diff --git a/postgis.sql.in b/postgis.sql.in index f728f7c0a..01819e631 100644 --- a/postgis.sql.in +++ b/postgis.sql.in @@ -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(,,, , ,) ---- 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 = ) --- 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 diff --git a/postgis_fn.c b/postgis_fn.c index 928a5718c..fd4e1fa23 100644 --- a/postgis_fn.c +++ b/postgis_fn.c @@ -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;tnobjs;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;unrings;u++) + // { + // num_points += poly->npoints[u]; + // } + + num_points_tot += num_points-1; //last point = 1st point + for (v=0;vis3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) + ); + pfree(cent); + PG_RETURN_POINTER(result); +} \ No newline at end of file