From 85ff82755b05c76594da5c2e32f9268f2d855a7c Mon Sep 17 00:00:00 2001 From: David Blasby Date: Fri, 8 Aug 2003 18:19:20 +0000 Subject: [PATCH] Conformance changes. Removed junk from postgis_debug.c and added the first run of the long transaction locking support. (this will change - dont use it) conformance tests were corrected some dos cr/lf removed empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) pointN(,1) now returns the first point (used to return 2nd) git-svn-id: http://svn.osgeo.org/postgis/trunk@288 b70326c6-7e19-0410-871a-916f4a2858ee --- Attic/postgis_sql_common.sql.in | 155 +++++- Makefile | 2 +- doc/postgis.xml | 488 ++++++++++++++++++- examples/ogc_test_suite/2_queries.sql | 6 +- postgis.h | 27 +- postgis_debug.c | 652 ++++---------------------- postgis_fn.c | 580 ++++++++++++++--------- postgis_geos.c | 335 ++++++++----- postgis_geos_wrapper.cpp | 88 +++- postgis_gist_71.c | 101 ++-- postgis_gist_72.c | 58 ++- postgis_inout.c | 120 ++++- 12 files changed, 1612 insertions(+), 1000 deletions(-) diff --git a/Attic/postgis_sql_common.sql.in b/Attic/postgis_sql_common.sql.in index 32d4352b7..28f3e87d9 100644 --- a/Attic/postgis_sql_common.sql.in +++ b/Attic/postgis_sql_common.sql.in @@ -12,6 +12,15 @@ -- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- $Log$ +-- Revision 1.14 2003/08/08 18:19:20 dblasby +-- Conformance changes. +-- Removed junk from postgis_debug.c and added the first run of the long +-- transaction locking support. (this will change - dont use it) +-- conformance tests were corrected +-- some dos cr/lf removed +-- empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) +-- pointN(,1) now returns the first point (used to return 2nd) +-- -- Revision 1.13 2003/08/06 19:31:18 dblasby -- Added the WKB parser. Added all the functions like -- PolyFromWKB(,[]). @@ -461,6 +470,17 @@ CREATE FUNCTION LineFromWKB(wkb) AS '@MODULE_FILENAME@','LinefromWKB_SRID' LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION LinestringFromWKB(wkb,int) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','LinefromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION LinestringFromWKB(wkb) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','LinefromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + CREATE FUNCTION PolyFromWKB(wkb,int) RETURNS GEOMETRY AS '@MODULE_FILENAME@','PolyfromWKB_SRID' @@ -470,6 +490,17 @@ CREATE FUNCTION PolyFromWKB(wkb) RETURNS GEOMETRY AS '@MODULE_FILENAME@','PolyfromWKB_SRID' LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION PolygonFromWKB(wkb,int) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','PolyfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION PolygonFromWKB(wkb) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','PolyfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + CREATE FUNCTION MPointFromWKB(wkb,int) RETURNS GEOMETRY @@ -480,6 +511,28 @@ CREATE FUNCTION MPointFromWKB(wkb) RETURNS GEOMETRY AS '@MODULE_FILENAME@','MPointfromWKB_SRID' LANGUAGE 'C' WITH (iscachable,isstrict); + + +CREATE FUNCTION MultiPointFromWKB(wkb,int) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MPointfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION MultiPointFromWKB(wkb) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MPointfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION MultiLineFromWKB(wkb,int) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MLinefromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION MultiLineFromWKB(wkb) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MLinefromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + CREATE FUNCTION MLineFromWKB(wkb,int) RETURNS GEOMETRY @@ -501,6 +554,18 @@ CREATE FUNCTION MPolyFromWKB(wkb) AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' LANGUAGE 'C' WITH (iscachable,isstrict); +CREATE FUNCTION MultiPolyFromWKB(wkb,int) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + +CREATE FUNCTION MultiPolyFromWKB(wkb) + RETURNS GEOMETRY + AS '@MODULE_FILENAME@','MPolyfromWKB_SRID' + LANGUAGE 'C' WITH (iscachable,isstrict); + + + CREATE FUNCTION GeomCollFromWKB(wkb,int) RETURNS GEOMETRY AS '@MODULE_FILENAME@','GCfromWKB_SRID' @@ -536,10 +601,6 @@ CREATE FUNCTION mem_size(geometry) AS '@MODULE_FILENAME@' LANGUAGE 'C' WITH (isstrict); -CREATE FUNCTION numb_sub_objs(geometry) - RETURNS int4 - AS '@MODULE_FILENAME@' - LANGUAGE 'C' WITH (isstrict); CREATE FUNCTION summary(geometry) RETURNS text @@ -672,6 +733,16 @@ CREATE FUNCTION polyfromtext(geometry,int4) AS '@MODULE_FILENAME@','geometry_from_text_poly' LANGUAGE 'C' WITH (isstrict,iscachable); +CREATE FUNCTION polygonfromtext(geometry,int4) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_poly' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION polygonfromtext(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_poly' + LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION mpolyfromtext(geometry,int4) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_mpoly' @@ -682,11 +753,22 @@ CREATE FUNCTION linefromtext(geometry,int4) AS '@MODULE_FILENAME@','geometry_from_text_line' LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION mlinefromtext(geometry,int4) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_mline' LANGUAGE 'C' WITH (isstrict,iscachable); +CREATE FUNCTION multilinestringfromtext(geometry,int4) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mline' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION multilinestringfromtext(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mline' + LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION pointfromtext(geometry,int4) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_point' @@ -697,6 +779,16 @@ CREATE FUNCTION mpointfromtext(geometry,int4) AS '@MODULE_FILENAME@','geometry_from_text_mpoint' LANGUAGE 'C' WITH (isstrict,iscachable); +CREATE FUNCTION multipointfromtext(geometry,int4) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mpoint' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION multipointfromtext(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mpoint' + LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION geomcollfromtext(geometry,int4) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_gc' @@ -704,7 +796,7 @@ CREATE FUNCTION geomcollfromtext(geometry,int4) CREATE FUNCTION setSRID(geometry,int4) RETURNS geometry - AS '@MODULE_FILENAME@','geometry_from_text_gc' + AS '@MODULE_FILENAME@','geometry_from_text' LANGUAGE 'C' WITH (isstrict,iscachable); CREATE FUNCTION polyfromtext(geometry) @@ -712,15 +804,36 @@ CREATE FUNCTION polyfromtext(geometry) AS '@MODULE_FILENAME@','geometry_from_text_poly' LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION mpolyfromtext(geometry) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_mpoly' LANGUAGE 'C' WITH (isstrict,iscachable); +CREATE FUNCTION multipolygonfromtext(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mpoly' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION multipolygonfromtext(geometry,int) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_mpoly' + LANGUAGE 'C' WITH (isstrict,iscachable); + CREATE FUNCTION linefromtext(geometry) RETURNS geometry AS '@MODULE_FILENAME@','geometry_from_text_line' LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION linestringfromtext(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_line' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION linestringfromtext(geometry,int) + RETURNS geometry + AS '@MODULE_FILENAME@','geometry_from_text_line' + LANGUAGE 'C' WITH (isstrict,iscachable); CREATE FUNCTION mlinefromtext(geometry) RETURNS geometry @@ -743,7 +856,21 @@ CREATE FUNCTION geomcollfromtext(geometry) LANGUAGE 'C' WITH (isstrict,iscachable); +CREATE FUNCTION isempty(geometry) + RETURNS int + AS '@MODULE_FILENAME@','isempty' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION issimple(geometry) + RETURNS boolean + AS '@MODULE_FILENAME@','issimple' + LANGUAGE 'C' WITH (isstrict,iscachable); + +CREATE FUNCTION equals(geometry,geometry) + RETURNS boolean + AS '@MODULE_FILENAME@','geomequals' + LANGUAGE 'C' WITH (isstrict,iscachable); -- @@ -828,6 +955,17 @@ CREATE FUNCTION centroid(geometry) RETURNS geometry AS '@MODULE_FILENAME@' LANGUAGE 'C' WITH (isstrict); + +CREATE FUNCTION isring(geometry) + RETURNS boolean + AS '@MODULE_FILENAME@' + LANGUAGE 'C' WITH (isstrict); + +CREATE FUNCTION pointonsurface(geometry) + RETURNS geometry + AS '@MODULE_FILENAME@' + LANGUAGE 'C' WITH (isstrict); + -- -- BBox operations @@ -1086,6 +1224,13 @@ CREATE FUNCTION buffer(geometry,float8) AS '@MODULE_FILENAME@','symdifference' LANGUAGE 'C' WITH (isstrict); + + CREATE FUNCTION symmetricdifference(geometry,geometry) + RETURNS geometry + AS '@MODULE_FILENAME@','symdifference' + LANGUAGE 'C' WITH (isstrict); + + CREATE FUNCTION GeomUnion(geometry,geometry) RETURNS geometry AS '@MODULE_FILENAME@','geomunion' diff --git a/Makefile b/Makefile index 33ab7f5d4..5ef8279e2 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ GEOS_DIR=/usr/local # GEOMETRY_COLUMNS, so see the list archives for info or # install a fresh database using postgis.sql # -USE_STATS=0 +USE_STATS=1 #--------------------------------------------------------------- subdir=contrib/postgis diff --git a/doc/postgis.xml b/doc/postgis.xml index 7390f63f8..1464d4179 100644 --- a/doc/postgis.xml +++ b/doc/postgis.xml @@ -1705,30 +1705,266 @@ if( geom.getType() = Geometry.POLYGON ) running. This is useful in binary cursors to pull data out of the database without converting it to a string representation. + OGC SPEC s2.1.1.1 - also see asBinary(,'XDR') and asBinary(,'NDR') Dimension(geometry) - Returns '2' if the geometry is two dimensional and '3' if the - geometry is three dimensional. + The inherent dimension of this Geometry object, which must be less than or equal +to the coordinate dimension. OGC SPEC s2.1.1.1 - returns 0 for points, 1 for lines, 2 for polygons, and the largest dimension of the components of a GEOMETRYCOLLECTION. + select dimension('GEOMETRYCOLLECTION(LINESTRING(1 1,0 0),POINT(0 0)'); +dimension +----------- +1 + + isEmpty(geometry) + + + Returns 1 (TRUE) if this Geometry is the empty geometry . If true, then this +Geometry represents the empty point set - i.e. GEOMETRYCOLLECTION(EMPTY). + + OGC SPEC s2.1.1.1 + + + + isSimple(geometry) + + + Returns 1 (TRUE) if this Geometry has no anomalous geometric points, such as self + intersection or self tangency. + + Performed by the GEOS module + + OGC SPEC s2.1.1.1 + + + + boundary(geometry) + + + Returns the closure of the combinatorial boundary of this Geometry. The + combinatorial boundary is defined as described in section 3.12.3.2 of the OGC SPEC. Because the result of this function + is a closure, and hence topologically closed, the resulting boundary can be represented using +representational geometry primitives as discussed in the OGC SPEC, section 3.12.2. + + Performed by the GEOS module + OGC SPEC s2.1.1.1 + + + + equals(geometry) + + + Returns 1 (TRUE) if this Geometry is ‘spatially equal’ to +anotherGeometry. Use this for a 'better' answer than '='. equals ('LINESTRING(0 0, 10 10)','LINESTRING(0 0, 5 5, 10 10)') is true. + + Performed by the GEOS module + OGC SPEC s2.1.1.1 + + + + + disjoint(geometry,geometry) + + Returns 1 (TRUE) if this Geometry is ‘spatially disjoint’ from anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 //s2.1.13.3 - a.Relate(b, ‘FF*FF****’) + + + + intersects(geometry,geometry) + + Returns 1 (TRUE) if this Geometry ‘spatially intersects’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 //s2.1.13.3 - Intersects(g1, g2 ) --> Not (Disjoint(g1, g2 )) + + + + touches(geometry,geometry) + + Returns 1 (TRUE) if this Geometry ‘spatially touches’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3- a.Touches(b) -> (I(a) intersection I(b) = {empty set} ) and (a intersection b) not empty + + + + crosses(geometry,geometry) + + Returns 1 (TRUE) if this Geometry ‘spatially crosses’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 - a.Relate(b, ‘T*T******’) + + + + within(geometry,geometry) + + Returns 1 (TRUE) if this Geometry is ‘spatially within’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 - a.Relate(b, ‘T*F**F***’) + + + + overlaps(geometry,geometry) + + Returns 1 (TRUE) if this Geometry is ‘spatially overlapping’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 + + + + contains(geometry,geometry) + + Returns 1 (TRUE) if this Geometry is ‘spatially contains’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 - same as within(geometry,geometry) + + + + intersects(geometry,geometry) + + Returns 1 (TRUE) if this Geometry is ‘spatially intersects’ anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 - NOT disjoint(geometry,geometry) + + + + relate(geometry,geometry, intersectionPatternMatrix) + + Returns 1 (TRUE) if this +Geometry is spatially related to anotherGeometry, by testing for intersections between the Interior, +Boundary and Exterior of the two geometries as specified by the values in the intersectionPatternMatrix. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is the "allowable" version that returns a boolean, not an integer. + OGC SPEC s2.1.1.1 // s2.1.13.3 + + + + relate(geometry,geometry) + + returns the DE-9IM (dimensionally extended nine-intersection matrix) + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + not in OGC spec, but implied. see s2.1.13.2 + + + + buffer(geometry,double) + + Returns a geometry that represents all points whose distance from +this Geometry is less than or equal to distance. Calculations are in the Spatial Reference System of this +Geometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + OGC SPEC s2.1.1.1 + + + + convexhull(geometry) + + Returns a geometry that represents the convex hull of this Geometry. + + Performed by the GEOS module + OGC SPEC s2.1.1.1 + + + + intersection(geometry,geometry) + + Returns a geometry that represents the point set +intersection of this Geometry with anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + OGC SPEC s2.1.1.1 + + + + geomunion(geometry,geometry) + + Returns a geometry that represents the point set union of +this Geometry with anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + NOTE: this is renamed from "union" because union is an SQL reserved word + OGC SPEC s2.1.1.1 + + + + difference(geometry,geometry) + + Returns a geometry that represents the point set +difference of this Geometry with anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + OGC SPEC s2.1.1.1 + + + + difference(geometry,geometry) + + Returns a geometry that represents the point set +symmetric difference of this Geometry with anotherGeometry. + + Performed by the GEOS module + Do not call with a GeometryCollection as an argument + OGC SPEC s2.1.1.1 + + Envelope(geometry) Returns a POLYGON representing the bounding box of the geometry. + OGC SPEC s2.1.1.1 - The minimum bounding box for this Geometry, returned as a Geometry. The +polygon is defined by the corner points of the bounding box ((MINX, MINY), (MAXX, MINY), (MAXX, +MAXY), (MINX, MAXY), (MINX, MINY)). NOTE:PostGIS will add a Zmin/Zmax coordinate as well. GeometryType(geometry) Returns the type of the geometry as a string. Eg: 'LINESTRING', - 'POLYGON', 'MULTIPOINT', etc. + 'POLYGON', 'MULTIPOINT', etc. + + OGC SPEC s2.1.1.1 - Returns the name of the instantiable subtype of Geometry of which this +Geometry instance is a member. The name of the instantiable subtype of Geometry is returned as a string. + @@ -1803,10 +2039,21 @@ if( geom.getType() = Geometry.POLYGON ) + + IsRing(geometry) + + Returns 1 (TRUE) if this Curve is closed (StartPoint ( ) = EndPoint ( )) and this Curve +is simple (does not pass through the same point more than once). + + + performed by GEOS + OGC spec 2.1.5.1 + + NumGeometries(geometry) - If geometry is a GEOMETRYCOLLECTION return the number of + If geometry is a GEOMETRYCOLLECTION (or MULTI*) return the number of geometries, otherwise return NULL. @@ -1818,6 +2065,7 @@ if( geom.getType() = Geometry.POLYGON ) GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING or MULTIPOLYGON. Otherwise, return NULL. + 0 is 1st geometry @@ -1834,6 +2082,7 @@ if( geom.getType() = Geometry.POLYGON ) Return the Well-Known Text representation of the geometry. For example: POLYGON(0 0,0 1,1 1,1 0,0 0) + OGC SPEC s2.1.1.1 @@ -1842,6 +2091,7 @@ if( geom.getType() = Geometry.POLYGON ) Returns the integer SRID number of the spatial reference system of the geometry. + OGC SPEC s2.1.1.1 @@ -1962,6 +2212,14 @@ if( geom.getType() = Geometry.POLYGON ) + + area(geometry) + + Returns the area of the geometry if it is a polygon or + multi-polygon. (same as area2() + + + asbinary(geometry,'NDR') @@ -1971,6 +2229,13 @@ if( geom.getType() = Geometry.POLYGON ) + + isvalid(geometry) + + returns true if this geometry is valid. + + + asbinary(geometry,'XDR') @@ -1980,6 +2245,213 @@ if( geom.getType() = Geometry.POLYGON ) + + GeomFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + + + + + + GeometryFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + + + + + + PointFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a Point + + + + + LineFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a Line + + + + + LinestringFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + from the conformance suite + Throws an error if the WKT is not a Line + + + + + + PolyFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a Polygon + + + + + PolygonFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + from the conformance suite + Throws an error if the WKT is not a Polygon + + + + + MPointFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a MULTIPOINT + + + + + MLineFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a MULTILINESTRING + + + + + MPolyFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a MULTIPOLYGON + + + + + GeomCollFromText(text,[]) + + Makes a Geometry from WKT with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + Throws an error if the WKT is not a GEOMETRYCOLLECTION + + + + + GeomFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + + + + + GeometryFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + + + + + PointFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a POINT + + + + + LineFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a LINESTRING + + + + + LinestringFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + from the conformance suite + throws an error if WKB is not a LINESTRING + + + + + PolyFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a POLYGON + + + + + PolygonFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + from the conformance suite + throws an error if WKB is not a POLYGON + + + + + MPointFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a MULTIPOINT + + + + + MLineFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a MULTILINESTRING + + + + + MPolyFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a MULTIPOLYGON + + + + + GeomCollFromWKB(text,[]) + + Makes a Geometry from WKB with the given SRID. If SRID is not give, it defaults to -1. + OGC SPEC 3.2.6.2 - option SRID is from the conformance suite + throws an error if WKB is not a GEOMETRYCOLLECTION + + + + + PointOnSurface(geometry) + + Return a Point guaranteed to lie on the surface + Implemented using GEOS + OGC SPEC 3.2.14.2 and 3.2.18.2 - + + + + box3d(geometry) @@ -2052,6 +2524,14 @@ if( geom.getType() = Geometry.POLYGON ) linestring or multi-linestring. + + length(geometry) + + The length of this Curve in its associated spatial reference. + synonym for length2d() + OGC SPEC 2.1.5.1 + + length3d(geometry) diff --git a/examples/ogc_test_suite/2_queries.sql b/examples/ogc_test_suite/2_queries.sql index 9b2894763..8d4577925 100644 --- a/examples/ogc_test_suite/2_queries.sql +++ b/examples/ogc_test_suite/2_queries.sql @@ -931,9 +931,9 @@ WHERE named_places.name = 'Ashton' AND forests.name = 'Green Forest'; -- --================================ -- -SELECT Union(shore, boundary) +SELECT GeomUnion(shore, boundary) FROM lakes, named_places -WHERE lakes.name = 'Blue Lake' AND named_places.name = 'Ashton'; +WHERE lakes.name = 'Blue Lake' AND named_places.name = 'Goose Island'; -- --================================ -- Conformance Item T50 @@ -948,7 +948,7 @@ WHERE lakes.name = 'Blue Lake' AND named_places.name = 'Ashton'; -- SELECT SymmetricDifference(shore, boundary) FROM lakes, named_places -WHERE lakes.name = 'Blue Lake' OR named_places.name = 'Ashton'; +WHERE lakes.name = 'Blue Lake' AND named_places.name = 'Goose Island'; -- --================================ -- Conformance Item T51 diff --git a/postgis.h b/postgis.h index 742201fb4..3f5d58bfd 100644 --- a/postgis.h +++ b/postgis.h @@ -11,6 +11,15 @@ * ********************************************************************** * $Log$ + * Revision 1.33 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.32 2003/08/06 19:31:18 dblasby * Added the WKB parser. Added all the functions like * PolyFromWKB(,[]). @@ -308,8 +317,7 @@ POLYGON3D *make_polygon(int nrings, int *pts_per_ring, POINT3D *pts, int npoints void set_point( POINT3D *pt,double x, double y, double z); GEOMETRY *make_oneobj_geometry(int sub_obj_size, char *sub_obj, int type, bool is3d, int SRID,double scale, double offx,double offy); -void print_box(BOX3D *box); -void print_box_oneline(BOX3D *box); + void print_point(char *result, POINT3D *pt,bool is3d); void print_many_points(char *result, POINT3D *pt ,int npoints, bool is3d); void swap(double *d1, double *d2); @@ -362,7 +370,7 @@ void translate_points(POINT3D *pt, int npoints,double x_off, double y_off, doubl int size_subobject (char *sub_obj, int type); GEOMETRY *add_to_geometry(GEOMETRY *geom,int sub_obj_size, char *sub_obj, int type); LINE3D *make_line(int npoints, POINT3D *pts, int *size); -char *print_geometry(GEOMETRY *geom); + void swap_char(char *a, char*b); void flip_endian_double(char *dd); @@ -379,9 +387,7 @@ char *wkb_multipoint(POINT3D *pt,int32 numb_points,int32 *size, bool flipbytes, char *to_wkb_collection(GEOMETRY *geom, bool flip_endian, int32 *size); char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size); -void decode_wkb_collection(char *wkb,int *size); -void decode_wkb(char *wkb, int *size); -void dump_bytes( char *a, int numb); + double deltaLongitude(double azimuth, double sigma, double tsm,SPHEROID *sphere); double bigA(double u2); @@ -410,7 +416,7 @@ POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *n Datum optimistic_overlap(PG_FUNCTION_ARGS); -void print_point_debug(POINT3D *p); + unsigned char parse_hex(char *str); void deparse_hex(unsigned char str, unsigned char *result); @@ -425,6 +431,11 @@ GEOMETRY *WKBtoGeometry(char *WKB, int length, int *bytes_read); POINT3D *wkb_linearring(char *WKB,char is3d, char flip_endian, int *numbPoints, int *bytes,int bytes_in_stream); +GEOMETRY *makeNullGeometry(int SRID); + +void compressType(GEOMETRY *g); + + //exposed to psql Datum box3d_in(PG_FUNCTION_ARGS); @@ -469,7 +480,6 @@ Datum geometry_eq(PG_FUNCTION_ARGS); Datum npoints(PG_FUNCTION_ARGS); Datum nrings(PG_FUNCTION_ARGS); Datum mem_size(PG_FUNCTION_ARGS); -Datum numb_sub_objs(PG_FUNCTION_ARGS); Datum summary(PG_FUNCTION_ARGS); Datum translate(PG_FUNCTION_ARGS); @@ -590,6 +600,7 @@ Datum geometry_from_text_mpoint(PG_FUNCTION_ARGS); Datum geometry_from_text_line(PG_FUNCTION_ARGS); Datum geometry_from_text_mline(PG_FUNCTION_ARGS); Datum geometry_from_text_gc(PG_FUNCTION_ARGS); +Datum isempty(PG_FUNCTION_ARGS); /*-------------------------------------------------------------------- * Useful floating point utilities and constants. diff --git a/postgis_debug.c b/postgis_debug.c index 84755af3c..2b402bcbf 100644 --- a/postgis_debug.c +++ b/postgis_debug.c @@ -8,9 +8,18 @@ * * This is free software; you can redistribute and/or modify it under * the terms of hte GNU General Public Licence. See the COPYING file. - * + * ********************************************************************** * $Log$ + * Revision 1.11 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.10 2003/07/25 17:08:37 pramsey * Moved Cygwin endian define out of source files into postgis.h common * header file. @@ -41,6 +50,9 @@ #include "postgis.h" #include "utils/elog.h" +#include "executor/spi.h" +#include "commands/trigger.h" + #define SHOW_DIGS_DOUBLE 15 #define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) @@ -49,50 +61,9 @@ // #define DEBUG_GIST //#define DEBUG_GIST2 -void print_box2d(BOX *box); - - -void dump_bytes( char *a, int numb) -{ - int t; - for (t=0; tLLB.x, box->LLB.y,box->LLB.z); - printf(" + URT = [%g,%g,%g]\n", box->URT.x, box->URT.y,box->URT.z); -} - -void print_box2d(BOX *box) -{ - printf (" BOX[%g %g , %g %g] ",box->low.x, box->low.y, box->high.x, box->high.y); -} - -//debug function - whats really in that BOX3D? -void print_box_oneline(BOX3D *box) -{ - printf(" (%p) {",box); - if (box == NULL) - { - printf ("BOX IS NULL}"); - return; - } - printf("[%g,%g,%g] ", box->LLB.x, box->LLB.y,box->LLB.z); - printf("[%g,%g,%g]}", box->URT.x, box->URT.y,box->URT.z); -} //find the size of geometry PG_FUNCTION_INFO_V1(mem_size); @@ -103,14 +74,7 @@ Datum mem_size(PG_FUNCTION_ARGS) PG_RETURN_INT32(geom1->size); } -//find the size of geometry -PG_FUNCTION_INFO_V1(numb_sub_objs); -Datum numb_sub_objs(PG_FUNCTION_ARGS) -{ - GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - PG_RETURN_INT32(geom1->nobjs); -} //get summary info on a GEOMETRY PG_FUNCTION_INFO_V1(summary); @@ -186,552 +150,126 @@ Datum summary(PG_FUNCTION_ARGS) -// DO NOT USE THESE decoding function (except for debugging purposes) -// The code is NOT maintained and is thrown together -// unsupported debugging function. -// given a wkb input thats a geometrycollection, returns its size and prints out -// its contents -// -// Its really messy - dont even think about using this for anything -// -// you shouldnt call this function; just call decode_wkb() and it will -// call this function -// -void decode_wkb_collection(char *wkb,int *size) -{ - int offset =0; - bool flipbytes; - int total_size=0,sub_size; - int numb_sub,t; - bool first_one = TRUE; +extern Datum lockcheck(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(lockcheck); - if (wkb[0] ==0 ) //big endian - { - if (BYTE_ORDER == LITTLE_ENDIAN) - flipbytes= 1; - else - flipbytes= 0; - } - else //little +Datum lockcheck (PG_FUNCTION_ARGS) +{ + TriggerData *trigdata = (TriggerData *) fcinfo->context; + char *colname ; + char *locktablename ; + int id; + HeapTuple rettuple; + TupleDesc tupdesc; + int SPIcode; + char *relname; + bool isnull; + char query[1024]; + + elog(NOTICE,"in lockcheck()"); + + /* Make sure trigdata is pointing at what I expect */ + if (!CALLED_AS_TRIGGER(fcinfo)) + elog(ERROR, "lockcheck: not fired by trigger manager"); + + rettuple = trigdata->tg_newtuple; + tupdesc = trigdata->tg_relation->rd_att; + + /* Connect to SPI manager */ + SPIcode = SPI_connect(); + + if (SPIcode != SPI_OK_CONNECT) { - if (BYTE_ORDER == LITTLE_ENDIAN) - flipbytes= 0; - else - flipbytes= 1; + elog(ERROR,"lockcheck: couldnt open a connection to SPI"); + PG_RETURN_NULL() ; } - memcpy(&numb_sub, wkb+5,4); - if (flipbytes) - flip_endian_int32( (char *) & numb_sub) ; + relname = SPI_getrelname(trigdata->tg_relation); - printf("GEOMETRYCOLLECTION(\n"); - offset = 9; - for (t=0;ttg_trigger->tgargs[0]; - printf(" "); - decode_wkb( wkb + offset, &sub_size); - total_size += sub_size; - offset += sub_size; - } - *size = total_size +9 ; - printf(")\n"); - return; -} + locktablename = trigdata->tg_trigger->tgargs[1]; -// unsupported debugging function. -// given a wkb input, returns its size and prints out -// its contents -// -// Its really messy - dont even think about using this for anything -// -//dump wkb to screen (for debugging) -// assume endian is constant though out structure -void decode_wkb(char *wkb, int *size) -{ - - bool flipbytes; - uint32 type; - uint32 n1,n2,n3,t,u,v; - bool is3d; - bool first_one,first_one2,first_one3; + elog(NOTICE,"trigger was executed on the relation: '%s', with attribute named '%s', with locktable named '%s'", relname,colname,locktablename); - int offset,offset1; - double x,y,z; - int total_points; + //get the value + id = (int) DatumGetInt32( SPI_getbinval(rettuple, tupdesc, SPI_fnumber(tupdesc,colname), &isnull) ); + sprintf(query,"SELECT lock_key FROM %s WHERE expires >= now() AND id = %i", locktablename,id); + elog(NOTICE,"about to execute :%s", query); + SPIcode = SPI_exec(query,0); + if (SPIcode !=SPI_OK_SELECT ) + elog(ERROR,"couldnt execute to test for lock :%s",query); - //printf("decoding wkb\n"); - - if (wkb[0] ==0 ) //big endian - { - if (BYTE_ORDER == LITTLE_ENDIAN) - flipbytes= 1; - else - flipbytes= 0; - } - else //little + if (SPI_processed >0) { - if (BYTE_ORDER == LITTLE_ENDIAN) - flipbytes= 0; - else - flipbytes= 1; - } - - //printf(" + flipbytes = %i\n", flipbytes); + // there is a lock - check to see if I have rights to it! - //printf("info about wkb:\n"); - memcpy(&type, wkb+1,4); - if (flipbytes) - flip_endian_int32( (char *) & type) ; + TupleDesc tupdesc = SPI_tuptable->tupdesc; + SPITupleTable *tuptable = SPI_tuptable; + HeapTuple tuple = tuptable->vals[0]; + char *lockcode = SPI_getvalue(tuple, tupdesc, 1); - is3d = 0; + elog(NOTICE,"there is a lock on this row!"); - if (type > 1000 ) - { - is3d = 1; - type = type - 32768; - } - //printf(" Type = %i (is3d = %i)\n", type, is3d); - if (type == 1) //POINT() - { - printf("POINT("); - if (is3d) + // check to see if temp_lock_have_table table exists (it might not exist if they own no locks + sprintf(query,"SELECT * FROM pg_class WHERE relname = 'temp_lock_have_table'"); + SPIcode = SPI_exec(query,0); + if (SPIcode !=SPI_OK_SELECT ) + elog(ERROR,"couldnt execute to test for lockkey temp table :%s",query); + if (SPI_processed ==0) { - memcpy(&x, &wkb[5], 8); - memcpy(&y, &wkb[5+8], 8); - memcpy(&z, &wkb[5+16], 8); - if (flipbytes) - { - flip_endian_double( (char *) & x) ; - flip_endian_double( (char *) & y) ; - flip_endian_double( (char *) & z) ; - } - printf("%g %g %g)",x,y,z ); + elog(NOTICE,"I do not own any locks (no lock table) - I cannot modify the row"); + //PG_RETURN_NULL(); + SPI_finish(); + return NULL; } - else - { - memcpy(&x, &wkb[5], 8); - memcpy(&y, &wkb[5+8], 8); - if (flipbytes) - { - flip_endian_double( (char *) & x) ; - flip_endian_double( (char *) & y) ; - } - printf("%g %g)", x,y); - } - printf("\n"); - if (is3d) - *size = 29; - else - *size = 21; - return; - } - if (type == 2) - { - printf("LINESTRING("); - memcpy(&n1, &wkb[5],4); - if (flipbytes) - flip_endian_int32( (char *) & n1) ; - // printf(" --- has %i sub points\n",n1); - first_one = TRUE; - for (t=0; t0) { - printf("MULTIPOINT("); - memcpy(&n1,&wkb[5],4); - if (flipbytes) - flip_endian_int32( (char *) & n1) ; - // printf(" -- has %i points\n",n1); - if (is3d) - *size = 9 + n1*29; - else - *size = 9 + n1*21; - first_one = TRUE; - for (t=0; tx,p->y,p->z); + TransactionId xid = GetCurrentTransactionId(); + PG_RETURN_DATUM( TransactionIdGetDatum(xid) ); } + diff --git a/postgis_fn.c b/postgis_fn.c index b59bdc796..99954c0f0 100644 --- a/postgis_fn.c +++ b/postgis_fn.c @@ -8,9 +8,18 @@ * * This is free software; you can redistribute and/or modify it under * the terms of hte GNU General Public Licence. See the COPYING file. - * + * ********************************************************************** * $Log$ + * Revision 1.24 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.23 2003/07/25 17:08:37 pramsey * Moved Cygwin endian define out of source files into postgis.h common * header file. @@ -39,6 +48,14 @@ #include "postgis.h" #include "utils/elog.h" +#define NfunctionFirstPoint 1 + +// if you use #define NfunctionFirstPoint 0, you get 0-based indexing (this is what programmers want):: +// pointN(, 0) is the 1st point, and pointN(, 1) is the second point. + +// if you use #define NfunctionFirstPoint 1, you get 1-based indexing (which seems to be what the spec wants):: +// pointN(, 1) is the 1st point, and pointN(, 2) is the second point. + #define SHOW_DIGS_DOUBLE 15 #define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1) @@ -69,7 +86,7 @@ double line_length2d(LINE3D *line) for (i=1; inpoints;i++) { to = &line->points[i]; - + dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + ( (frm->y - to->y)*(frm->y - to->y) ) ); @@ -92,9 +109,9 @@ double line_length3d(LINE3D *line) for (i=1; inpoints;i++) { to = &line->points[i]; - + dist += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ((frm->y - to->y)*(frm->y - to->y) ) + + ((frm->y - to->y)*(frm->y - to->y) ) + ((frm->z - to->z)*(frm->z - to->z) ) ); frm = to; @@ -108,7 +125,7 @@ double line_length3d(LINE3D *line) // length3d(line) = length of line // length3d(polygon) = 0 -- could make sense to return sum(ring perimeter) // uses euclidian 3d length - + PG_FUNCTION_INFO_V1(length3d); Datum length3d(PG_FUNCTION_ARGS) { @@ -126,7 +143,7 @@ Datum length3d(PG_FUNCTION_ARGS) for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == LINETYPE) //LINESTRING { @@ -142,7 +159,7 @@ Datum length3d(PG_FUNCTION_ARGS) // length3d(line) = length of line // length3d(polygon) = 0 -- could make sense to return sum(ring perimeter) // uses euclidian 2d length - + PG_FUNCTION_INFO_V1(length2d); Datum length2d(PG_FUNCTION_ARGS) { @@ -160,7 +177,7 @@ Datum length2d(PG_FUNCTION_ARGS) for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == LINETYPE) //LINESTRING { @@ -185,28 +202,28 @@ double polygon_area2d_old(POLYGON3D *poly1) pts1 = (POINT3D *) MAXALIGN(pts1); //elog(NOTICE,"in polygon_area2d_old"); - + pt_offset = 0; //index to first point in ring for (ring = 0; ring < poly1->nrings; ring++) { ringarea = 0.0; - - for (i=0;i<(poly1->npoints[ring]-1);i++) - { + + for (i=0;i<(poly1->npoints[ring]-1);i++) + { // j = (i+1) % (poly1->npoints[ring]); j = i+1; - ringarea += pts1[pt_offset+ i].x * pts1[pt_offset+j].y - pts1[pt_offset+ i].y * pts1[pt_offset+j].x; - } + ringarea += pts1[pt_offset+ i].x * pts1[pt_offset+j].y - pts1[pt_offset+ i].y * pts1[pt_offset+j].x; + } - ringarea /= 2.0; + ringarea /= 2.0; //elog(NOTICE," ring 1 has area %lf",ringarea); ringarea = fabs(ringarea ); if (ring != 0) //outer ringarea = -1.0*ringarea ; // its a hole - + poly_area += ringarea; - pt_offset += poly1->npoints[ring]; + pt_offset += poly1->npoints[ring]; } return poly_area; @@ -234,7 +251,7 @@ Datum area2d(PG_FUNCTION_ARGS) for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POLYGONTYPE) //POLYGON { @@ -255,31 +272,31 @@ double polygon_perimeter3d(POLYGON3D *poly1) pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); pts1 = (POINT3D *) MAXALIGN(pts1); - - + + pt_offset = 0; //index to first point in ring for (ring = 0; ring < poly1->nrings; ring++) { ring_perimeter = 0.0; - + frm = &pts1[pt_offset]; for (i=1; inpoints[ring];i++) { to = &pts1[pt_offset+ i]; - + ring_perimeter += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + - ((frm->y - to->y)*(frm->y - to->y) ) + + ((frm->y - to->y)*(frm->y - to->y) ) + ((frm->z - to->z)*(frm->z - to->z) ) ); frm = to; } - + poly_perimeter += ring_perimeter; - pt_offset += poly1->npoints[ring]; + pt_offset += poly1->npoints[ring]; } return poly_perimeter; @@ -297,28 +314,28 @@ double polygon_perimeter2d(POLYGON3D *poly1) pts1 = (POINT3D *) ( (char *)&(poly1->npoints[poly1->nrings] ) ); pts1 = (POINT3D *) MAXALIGN(pts1); - + pt_offset = 0; //index to first point in ring for (ring = 0; ring < poly1->nrings; ring++) { ring_perimeter = 0.0; - + frm = &pts1[pt_offset]; for (i=1; inpoints[ring];i++) { to = &pts1[pt_offset+ i]; - + ring_perimeter += sqrt( ( (frm->x - to->x)*(frm->x - to->x) ) + ((frm->y - to->y)*(frm->y - to->y) ) ); frm = to; } - + poly_perimeter += ring_perimeter; - pt_offset += poly1->npoints[ring]; + pt_offset += poly1->npoints[ring]; } return poly_perimeter; @@ -344,7 +361,7 @@ Datum perimeter3d(PG_FUNCTION_ARGS) for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POLYGONTYPE) //POLYGON { @@ -372,7 +389,7 @@ Datum perimeter2d(PG_FUNCTION_ARGS) for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POLYGONTYPE) //POLYGON { @@ -389,7 +406,7 @@ Datum perimeter2d(PG_FUNCTION_ARGS) // V[] = vertex points of a polygon V[n+1] with V[n]=V[0] // returns: 0 = outside, 1 = inside // -// Our polygons have first and last point the same, +// Our polygons have first and last point the same, // int PIP( POINT3D *P, POINT3D *V, int n ) @@ -401,17 +418,17 @@ int PIP( POINT3D *P, POINT3D *V, int n ) // loop through all edges of the polygon - for (i=0; i< (n-1) ; i++) + for (i=0; i< (n-1) ; i++) { // edge from V[i] to V[i+1] if (((V[i].y <= P->y) && (V[i+1].y > P->y)) // an upward crossing || ((V[i].y > P->y) && (V[i+1].y <= P->y))) // a downward crossing - { + { vt = (double)(P->y - V[i].y) / (V[i+1].y - V[i].y); if (P->x < V[i].x + vt * (V[i+1].x - V[i].x)) // P.x x >= box->LLB.x) && (point->x <= box->URT.x) && - (point->y >= box->LLB.y) && (point->y <= box->URT.y) + return ( + (point->x >= box->LLB.x) && (point->x <= box->URT.x) && + (point->y >= box->LLB.y) && (point->y <= box->URT.y) ); } // see if a linestring is inside a box - check to see if each its line -// segments are inside the box +// segments are inside the box // NOTE: all this is happening in 2d - third dimention is ignored // //use a modified CohenSutherland line clipping algoritm @@ -484,7 +501,7 @@ int compute_outcode( POINT3D *p, BOX3D *box) return (Code+1); } - return (Code); + return (Code); } @@ -497,7 +514,7 @@ bool lineseg_inside_box( POINT3D *P1, POINT3D *P2, BOX3D *box) outcode_p1 = compute_outcode(P1, box); if (outcode_p1 ==0) return TRUE; - + outcode_p2 = compute_outcode(P2, box); if (outcode_p2 ==0) return TRUE; @@ -521,17 +538,17 @@ bool lineseg_inside_box( POINT3D *P1, POINT3D *P2, BOX3D *box) // from comp.graphics.algo's faq: /* - (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) + (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) r = ------------------------------------ - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) + (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) + (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------------- - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) + (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) */ // if 0<= r&s <=1 then intersection exists - + Ax = P1->x; Ay = P1->y; Bx = P2->x; By = P2->y; @@ -587,7 +604,7 @@ bool lineseg_inside_box( POINT3D *P1, POINT3D *P2, BOX3D *box) //otherwise we did not intersect the box return FALSE; - + } @@ -605,8 +622,8 @@ bool linestring_inside_box(POINT3D *pts, int npoints, BOX3D *box) for (i=1; i< npoints;i++) { to = &pts[i]; - - if (lineseg_inside_box( frm, to, box)) + + if (lineseg_inside_box( frm, to, box)) return TRUE; frm = to; @@ -633,13 +650,13 @@ bool polygon_truely_inside(POLYGON3D *poly, BOX3D *box) POINT3D test_point; int32 ring; int point_offset; - + pts1 = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); pts1 = (POINT3D *) MAXALIGN(pts1); //step 1 (and 2) - outer_ring_inside = linestring_inside_box(pts1, poly->npoints[0], box); + outer_ring_inside = linestring_inside_box(pts1, poly->npoints[0], box); if (outer_ring_inside) return TRUE; @@ -647,8 +664,8 @@ bool polygon_truely_inside(POLYGON3D *poly, BOX3D *box) test_point.x = box->LLB.x; test_point.y = box->LLB.y; //.z unimportant - - outer_ring_surrounds = PIP(&test_point, pts1,poly->npoints[0] ); + + outer_ring_surrounds = PIP(&test_point, pts1,poly->npoints[0] ); if (!(outer_ring_surrounds)) return FALSE; // disjoing @@ -671,7 +688,7 @@ bool polygon_truely_inside(POLYGON3D *poly, BOX3D *box) } point_offset += poly->npoints[ring]; } - + return TRUE; } @@ -713,11 +730,11 @@ Datum truly_inside(PG_FUNCTION_ARGS) offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POINTTYPE) //point @@ -761,11 +778,11 @@ Datum npoints(PG_FUNCTION_ARGS) offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POINTTYPE) //point @@ -805,17 +822,17 @@ Datum nrings(PG_FUNCTION_ARGS) offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type1= geom1->objType[j]; if (type1 == POLYGONTYPE) //POLYGON { poly = (POLYGON3D *) o1; - numb_rings += poly->nrings; + numb_rings += poly->nrings; } } @@ -874,11 +891,11 @@ Datum translate(PG_FUNCTION_ARGS) offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom1->nobjs; j++) //for each object in geom1 { - o1 = (char *) geom1 +offsets1[j] ; + o1 = (char *) geom1 +offsets1[j] ; type= geom1->objType[j]; if (type == POINTTYPE) //point @@ -933,7 +950,7 @@ Datum force_2d(PG_FUNCTION_ARGS) result = (GEOMETRY *) palloc(geom->size); memcpy(result,geom, geom->size); - + result->is3d = FALSE; PG_RETURN_POINTER(result); } @@ -976,7 +993,7 @@ Datum combine_bbox(PG_FUNCTION_ARGS) { geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); - box = (BOX3D *) palloc(sizeof(BOX3D)); + box = (BOX3D *) palloc(sizeof(BOX3D)); memcpy(box, &(geom->bvol), sizeof(BOX3D) ); PG_RETURN_POINTER(box); // combine_bbox(null, geometry) => geometry->bvol @@ -984,9 +1001,9 @@ Datum combine_bbox(PG_FUNCTION_ARGS) if (geom_ptr == NULL) { - box = (BOX3D *) palloc(sizeof(BOX3D)); + box = (BOX3D *) palloc(sizeof(BOX3D)); memcpy(box, (char *) PG_GETARG_DATUM(0) , sizeof(BOX3D) ); - + PG_RETURN_POINTER( box ); // combine_bbox(BOX3D, null) => BOX3D } @@ -1029,11 +1046,53 @@ PG_FUNCTION_INFO_V1(dimension); Datum dimension(PG_FUNCTION_ARGS) { GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + int t; + int result,dim,type; - if (geom->is3d) - PG_RETURN_INT32(3); - else + + if ((geom->type == COLLECTIONTYPE) && (geom->nobjs ==0)) + PG_RETURN_INT32(-1); + + if (geom->type == POINTTYPE) + PG_RETURN_INT32(0); + + if (geom->type == LINETYPE) + PG_RETURN_INT32(1); + + if (geom->type == POLYGONTYPE) + PG_RETURN_INT32(2); + + + if (geom->type == MULTIPOINTTYPE) + PG_RETURN_INT32(0); + + if (geom->type == MULTILINETYPE) + PG_RETURN_INT32(1); + + if (geom->type == MULTIPOLYGONTYPE) PG_RETURN_INT32(2); + + result = -1; + dim =0; + //its a collection -look for the largest one + for (t=0;tnobjs;t++) + { + type= geom->objType[t]; + + if (type == POINTTYPE) + dim=0; + + if (type == LINETYPE) + dim=1; + + if (type == POLYGONTYPE) + dim=2; + + if (dim>result) + result = dim; + + } + PG_RETURN_INT32(result); } //returns a string representation of this geometry's type @@ -1044,7 +1103,7 @@ Datum geometrytype(PG_FUNCTION_ARGS) char *text_ob = palloc(20+4); char *result = text_ob+4; int32 size; - + memset(result,0,20); @@ -1072,7 +1131,7 @@ Datum geometrytype(PG_FUNCTION_ARGS) size = strlen(result) +4 ; memcpy(text_ob, &size,4); // size of string - + PG_RETURN_POINTER(text_ob); @@ -1093,7 +1152,7 @@ Datum envelope(PG_FUNCTION_ARGS) POINT3D pts[5]; //5 points around box int pts_per_ring[1]; int poly_size; - + //use LLB's z value (we're going to set is3d to false) set_point( &pts[0], geom->bvol.LLB.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); @@ -1101,7 +1160,7 @@ Datum envelope(PG_FUNCTION_ARGS) set_point( &pts[2], geom->bvol.URT.x , geom->bvol.URT.y , geom->bvol.LLB.z ); set_point( &pts[3], geom->bvol.LLB.x , geom->bvol.URT.y , geom->bvol.LLB.z ); set_point( &pts[4], geom->bvol.LLB.x , geom->bvol.LLB.y , geom->bvol.LLB.z ); - + pts_per_ring[0] = 5; //ring has 5 points //make a polygon @@ -1109,11 +1168,11 @@ Datum envelope(PG_FUNCTION_ARGS) result = make_oneobj_geometry(poly_size, (char *)poly, POLYGONTYPE, FALSE,geom->SRID, geom->scale, geom->offsetX, geom->offsetY); - PG_RETURN_POINTER(result); + PG_RETURN_POINTER(result); } -//X(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its X value. +//X(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its X value. //Return NULL if there is no POINT(..) in GEOMETRY PG_FUNCTION_INFO_V1(x_point); Datum x_point(PG_FUNCTION_ARGS) @@ -1122,15 +1181,15 @@ Datum x_point(PG_FUNCTION_ARGS) char *o; int type1,j; int32 *offsets1; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POINTTYPE) //point @@ -1139,10 +1198,10 @@ Datum x_point(PG_FUNCTION_ARGS) } } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } -//Y(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Y value. +//Y(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Y value. //Return NULL if there is no POINT(..) in GEOMETRY PG_FUNCTION_INFO_V1(y_point); Datum y_point(PG_FUNCTION_ARGS) @@ -1151,15 +1210,15 @@ Datum y_point(PG_FUNCTION_ARGS) char *o; int type1,j; int32 *offsets1; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POINTTYPE) //point @@ -1168,10 +1227,10 @@ Datum y_point(PG_FUNCTION_ARGS) } } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } -//Z(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Z value. +//Z(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its Z value. //Return NULL if there is no POINT(..) in GEOMETRY PG_FUNCTION_INFO_V1(z_point); Datum z_point(PG_FUNCTION_ARGS) @@ -1180,15 +1239,15 @@ Datum z_point(PG_FUNCTION_ARGS) char *o; int type1,j; int32 *offsets1; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POINTTYPE) //point @@ -1197,7 +1256,7 @@ Datum z_point(PG_FUNCTION_ARGS) } } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } //numpoints(GEOMETRY) -- find the first linestring in GEOMETRY, return @@ -1210,12 +1269,12 @@ Datum numpoints_linestring(PG_FUNCTION_ARGS) char *o; int type1,j; int32 *offsets1; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == LINETYPE) //linestring @@ -1224,7 +1283,7 @@ Datum numpoints_linestring(PG_FUNCTION_ARGS) } } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } //pointn(GEOMETRY,INTEGER) -- find the first linestring in GEOMETRY, @@ -1236,18 +1295,20 @@ PG_FUNCTION_INFO_V1(pointn_linestring); Datum pointn_linestring(PG_FUNCTION_ARGS) { GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); + int32 wanted_index =PG_GETARG_INT32(1); char *o; int type1,j; int32 *offsets1; LINE3D *line; - + + wanted_index -= NfunctionFirstPoint; + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == LINETYPE) //linestring @@ -1257,19 +1318,19 @@ Datum pointn_linestring(PG_FUNCTION_ARGS) PG_RETURN_NULL(); //index out of range //get the point, make a new geometry PG_RETURN_POINTER( - make_oneobj_geometry(sizeof(POINT3D), + make_oneobj_geometry(sizeof(POINT3D), (char *)&line->points[wanted_index], - POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) ); } } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } // exteriorRing(GEOMETRY) -- find the first polygon in GEOMETRY, return //its exterior ring (as a linestring). Return NULL if there is no -//POLYGON(..) in GEOMETRY. +//POLYGON(..) in GEOMETRY. PG_FUNCTION_INFO_V1(exteriorring_polygon); Datum exteriorring_polygon(PG_FUNCTION_ARGS) @@ -1284,12 +1345,12 @@ Datum exteriorring_polygon(PG_FUNCTION_ARGS) POINT3D *pts; int size_line; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POLYGONTYPE) //polygon object @@ -1304,7 +1365,7 @@ Datum exteriorring_polygon(PG_FUNCTION_ARGS) PG_RETURN_POINTER( make_oneobj_geometry(size_line, (char *) line, - LINETYPE, geom->is3d,geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + LINETYPE, geom->is3d,geom->SRID, geom->scale, geom->offsetX, geom->offsetY) ); } @@ -1327,12 +1388,12 @@ Datum numinteriorrings_polygon(PG_FUNCTION_ARGS) POLYGON3D *poly; - + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POLYGONTYPE) //polygon object @@ -1353,7 +1414,7 @@ PG_FUNCTION_INFO_V1(interiorringn_polygon); Datum interiorringn_polygon(PG_FUNCTION_ARGS) { GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); + int32 wanted_index =PG_GETARG_INT32(1); char *o; int type1,j,t,point_offset; int32 *offsets1; @@ -1362,12 +1423,14 @@ Datum interiorringn_polygon(PG_FUNCTION_ARGS) POINT3D *pts; int size_line; - + + wanted_index -= NfunctionFirstPoint; + offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; for (j=0; j< geom->nobjs; j++) //for each object in geom1 { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POLYGONTYPE) //polygon object @@ -1377,7 +1440,7 @@ Datum interiorringn_polygon(PG_FUNCTION_ARGS) if ( (wanted_index<0) || (wanted_index> (poly->nrings-2) ) ) PG_RETURN_NULL(); //index out of range - + pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); pts = (POINT3D *) MAXALIGN(pts); @@ -1385,7 +1448,7 @@ Datum interiorringn_polygon(PG_FUNCTION_ARGS) point_offset=0; for (t=0; t< (wanted_index+1); t++) { - point_offset += poly->npoints[t]; + point_offset += poly->npoints[t]; } line = make_line(poly->npoints[wanted_index+1], &pts[point_offset], &size_line); @@ -1394,8 +1457,8 @@ Datum interiorringn_polygon(PG_FUNCTION_ARGS) PG_RETURN_POINTER( make_oneobj_geometry(size_line, (char *) line, - LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) - ); + LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + ); } } PG_RETURN_NULL(); @@ -1411,14 +1474,14 @@ Datum numgeometries_collection(PG_FUNCTION_ARGS) { GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - if ( (geom->type == COLLECTIONTYPE) || - (geom->type == MULTIPOINTTYPE) || - (geom->type == MULTILINETYPE) || + if ( (geom->type == COLLECTIONTYPE) || + (geom->type == MULTIPOINTTYPE) || + (geom->type == MULTILINETYPE) || (geom->type == MULTIPOLYGONTYPE) ) PG_RETURN_INT32( geom->nobjs ) ; else - PG_RETURN_NULL(); + PG_RETURN_NULL(); } @@ -1434,35 +1497,35 @@ PG_FUNCTION_INFO_V1(geometryn_collection); Datum geometryn_collection(PG_FUNCTION_ARGS) { GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - int32 wanted_index =PG_GETARG_INT32(1); + int32 wanted_index =PG_GETARG_INT32(1); int type; int32 *offsets1; char *o; - + wanted_index -= NfunctionFirstPoint; offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - if (!(( (geom->type == COLLECTIONTYPE) || - (geom->type == MULTIPOINTTYPE) || - (geom->type == MULTILINETYPE) || + if (!(( (geom->type == COLLECTIONTYPE) || + (geom->type == MULTIPOINTTYPE) || + (geom->type == MULTILINETYPE) || (geom->type == MULTIPOLYGONTYPE) ))) - PG_RETURN_NULL(); + PG_RETURN_NULL(); if ( (wanted_index <0) || (wanted_index > (geom->nobjs-1) ) ) PG_RETURN_NULL(); //bad index type = geom->objType[wanted_index]; - o = (char *) geom +offsets1[wanted_index] ; - + o = (char *) geom +offsets1[wanted_index] ; + if (type == POINTTYPE) { PG_RETURN_POINTER( make_oneobj_geometry(sizeof(POINT3D), o, - POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + POINTTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) ); } if (type == LINETYPE) @@ -1470,7 +1533,7 @@ Datum geometryn_collection(PG_FUNCTION_ARGS) PG_RETURN_POINTER( make_oneobj_geometry( size_subobject (o, LINETYPE), o, - LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + LINETYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) ); } if (type == POLYGONTYPE) @@ -1478,11 +1541,11 @@ Datum geometryn_collection(PG_FUNCTION_ARGS) PG_RETURN_POINTER( make_oneobj_geometry( size_subobject (o, POLYGONTYPE), o, - POLYGONTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) + POLYGONTYPE, geom->is3d, geom->SRID, geom->scale, geom->offsetX, geom->offsetY) ); } - PG_RETURN_NULL(); + PG_RETURN_NULL(); } @@ -1496,7 +1559,7 @@ Datum force_collection(PG_FUNCTION_ARGS) result = (GEOMETRY *) palloc(geom->size); memcpy(result,geom, geom->size); - + result->type = COLLECTIONTYPE; PG_RETURN_POINTER(result); @@ -1523,11 +1586,11 @@ Datum point_inside_circle(PG_FUNCTION_ARGS) offsets1 = (int32 *) ( ((char *) &(geom->objType[0] ))+ sizeof(int32) * geom->nobjs ) ; - //now have to do a scan of each object + //now have to do a scan of each object for (j=0; j< geom->nobjs; j++) //for each object in geom { - o = (char *) geom +offsets1[j] ; + o = (char *) geom +offsets1[j] ; type1= geom->objType[j]; if (type1 == POINTTYPE) //point @@ -1541,7 +1604,7 @@ Datum point_inside_circle(PG_FUNCTION_ARGS) } } - PG_RETURN_BOOL(FALSE); + PG_RETURN_BOOL(FALSE); } @@ -1557,15 +1620,15 @@ double distance_pt_seg(POINT3D *p, POINT3D *A, POINT3D *B) //otherwise, we use comp.graphics.algorithms Frequently Asked Questions method - /*(1) AC dot AB + /*(1) AC dot AB r = --------- - ||AB||^2 + ||AB||^2 r has the following meaning: - r=0 P = A - r=1 P = B - r<0 P is on the backward extension of AB - r>1 P is on the forward extension of AB - 01 P is on the forward extension of AB + 0x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) ); @@ -1574,19 +1637,19 @@ double distance_pt_seg(POINT3D *p, POINT3D *A, POINT3D *B) return (distance_pt_pt(p,A)); if (r>1) return(distance_pt_pt(p,B)); - + /*(2) - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - s = ----------------------------- - L^2 - - Then the distance from C to P = |s|*L. + (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) + s = ----------------------------- + L^2 + + Then the distance from C to P = |s|*L. */ s = ((A->y-p->y)*(B->x-A->x)- (A->x-p->x)*(B->y-A->y) )/ ((B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) ); - + return abs(s) * sqrt(((B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y) )); } @@ -1614,23 +1677,23 @@ double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D) // AB and CD are line segments /* from comp.graphics.algo - Solving the above for r and s yields - (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) - r = ----------------------------- (eqn 1) + Solving the above for r and s yields + (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy) + r = ----------------------------- (eqn 1) (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) - s = ----------------------------- (eqn 2) - (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) - Let P be the position vector of the intersection point, then - P=A+r(B-A) or - Px=Ax+r(Bx-Ax) - Py=Ay+r(By-Ay) - By examining the values of r & s, you can also determine some other limiting conditions: - If 0<=r<=1 & 0<=s<=1, intersection exists - r<0 or r>1 or s<0 or s>1 line segments do not intersect - If the denominator in eqn 1 is zero, AB & CD are parallel - If the numerator in eqn 1 is also zero, AB & CD are collinear. + (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) + s = ----------------------------- (eqn 2) + (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx) + Let P be the position vector of the intersection point, then + P=A+r(B-A) or + Px=Ax+r(Bx-Ax) + Py=Ay+r(By-Ay) + By examining the values of r & s, you can also determine some other limiting conditions: + If 0<=r<=1 & 0<=s<=1, intersection exists + r<0 or r>1 or s<0 or s>1 line segments do not intersect + If the denominator in eqn 1 is zero, AB & CD are parallel + If the numerator in eqn 1 is also zero, AB & CD are collinear. */ r_top = (A->y-C->y)*(D->x-C->x) - (A->x-C->x)*(D->y-C->y) ; @@ -1641,9 +1704,9 @@ double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D) if ( (r_bot==0) || (s_bot == 0) ) { - return ( - min(distance_pt_seg(A,C,D), - min(distance_pt_seg(B,C,D), + return ( + min(distance_pt_seg(A,C,D), + min(distance_pt_seg(B,C,D), min(distance_pt_seg(C,A,B), distance_pt_seg(D,A,B) ) ) ) ); @@ -1654,22 +1717,22 @@ double distance_seg_seg(POINT3D *A, POINT3D *B, POINT3D *C, POINT3D *D) if ((r<0) || (r>1) || (s<0) || (s>1) ) { //no intersection - return ( - min(distance_pt_seg(A,C,D), - min(distance_pt_seg(B,C,D), + return ( + min(distance_pt_seg(A,C,D), + min(distance_pt_seg(B,C,D), min(distance_pt_seg(C,A,B), distance_pt_seg(D,A,B) ) ) ) ); - + } - else + else return -0; //intersection exists - + } -//trivial +//trivial double distance_pt_pt(POINT3D *p1, POINT3D *p2) { //print_point_debug(p1); @@ -1727,11 +1790,11 @@ double distance_line_line(LINE3D *l1, LINE3D *l2) end = &(l1->points[t]); start2 = &(l2->points[0]); - + for (u=1; u< l2->npoints; u++) //for each segment in L2 { end2 = &(l2->points[u]); - + dist_this = distance_seg_seg(start,end,start2,end2); //printf("line_line; seg %i * seg %i, dist = %g\n",t,u,dist_this); @@ -1785,10 +1848,10 @@ double distance_pt_poly(POINT3D *p1, POLYGON3D *poly2) line = make_line (poly2->npoints[t] , &pts[offset] , &junk); result = distance_pt_line(p1, line); pfree(line); - return result; + return result; } offset += poly2->npoints[t]; - } + } return 0; //its inside the polygon } @@ -1802,12 +1865,12 @@ double distance_pt_poly(POINT3D *p1, POLYGON3D *poly2) return result; } - + } // brute force. Test l1 against each ring. If there's an intersection then return 0 (crosses boundary) -// otherwise, test to see if a point inside outer rings of polygon, but not in inner rings. +// otherwise, test to see if a point inside outer rings of polygon, but not in inner rings. // if so, return 0 (line inside polygon) // otherwise return min distance to a ring (could be outside polygon or inside a hole) double distance_line_poly(LINE3D *l1, POLYGON3D *poly2) @@ -1855,11 +1918,11 @@ double distance_line_poly(LINE3D *l1, POLYGON3D *poly2) if ( PIP( &l1->points[0], &pts[offset], poly2->npoints[t] ) ) { //its inside a hole, then the actual distance is the min ring distance -//printf("line_poly; inside inner ring %i\n",t); +//printf("line_poly; inside inner ring %i\n",t); return min_dist; } offset += poly2->npoints[t]; - } + } // not in hole, there for inside the polygon return 0; } @@ -1868,7 +1931,7 @@ double distance_line_poly(LINE3D *l1, POLYGON3D *poly2) //not in the outside ring, so min distance to a ring is the actual min distance return min_dist; } - + } // true if point is in poly (and not in its holes) @@ -1877,7 +1940,7 @@ bool point_in_poly(POINT3D *p, POLYGON3D *poly) int t; POINT3D *pts1; int offset; - + pts1 = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); pts1 = (POINT3D *) MAXALIGN(pts1); @@ -1898,7 +1961,7 @@ bool point_in_poly(POINT3D *p, POLYGON3D *poly) return FALSE; //not in outer ring } -// brute force. +// brute force. // test to see if any rings intersect. if yes, dist =0 // test to see if one inside the other and if they are inside holes. // find min distance ring-to-ring @@ -1971,7 +2034,7 @@ Datum distance(PG_FUNCTION_ARGS) int g1_i, g2_i; double dist,this_dist = 0; bool dist_set = FALSE; //true once dist makes sense. - int32 *offsets1,*offsets2; + int32 *offsets1,*offsets2; int type1,type2; char *o1,*o2; @@ -1991,11 +2054,11 @@ Datum distance(PG_FUNCTION_ARGS) for (g1_i=0; g1_i < geom1->nobjs; g1_i++) { - o1 = (char *) geom1 +offsets1[g1_i] ; + o1 = (char *) geom1 +offsets1[g1_i] ; type1= geom1->objType[g1_i]; for (g2_i=0; g2_i < geom2->nobjs; g2_i++) { - o2 = (char *) geom2 +offsets2[g2_i] ; + o2 = (char *) geom2 +offsets2[g2_i] ; type2= geom2->objType[g2_i]; if ( (type1 == POINTTYPE) && (type2 == POINTTYPE) ) @@ -2027,7 +2090,7 @@ Datum distance(PG_FUNCTION_ARGS) if ( (type1 == LINETYPE) && (type2 == POINTTYPE) ) { this_dist = distance_pt_line( (POINT3D *)o2, (LINE3D *)o1 ); - } + } if ( (type1 == POLYGONTYPE) && (type2 == POINTTYPE) ) { this_dist = distance_pt_poly( (POINT3D *)o2, (POLYGON3D *)o1 ); @@ -2047,7 +2110,7 @@ Datum distance(PG_FUNCTION_ARGS) dist_set = TRUE; } - if (dist <= 0.0) + if (dist <= 0.0) PG_RETURN_FLOAT8( (double) 0.0); // no need to look for things closer } } @@ -2075,7 +2138,7 @@ Datum expand_bbox(PG_FUNCTION_ARGS) result->URT.x = bbox->URT.x + d; result->URT.y = bbox->URT.y + d; result->URT.z = bbox->URT.z + d; - + PG_RETURN_POINTER(result); } @@ -2099,12 +2162,12 @@ Datum startpoint(PG_FUNCTION_ARGS) line = (LINE3D *) ( (char *) geom1 +offsets1[0]); - pt = &line->points[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) + POINTTYPE, geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) ); } @@ -2130,18 +2193,18 @@ Datum endpoint(PG_FUNCTION_ARGS) line = (LINE3D *) ( (char *) geom1 +offsets1[0]); - pt = &line->points[line->npoints-1]; - + 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) + POINTTYPE, geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) ); } -//isclosed(geometry) :- if geometry is a linestring then returns +//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. @@ -2166,11 +2229,11 @@ Datum isclosed(PG_FUNCTION_ARGS) for (t=0; t< geom1->nobjs; t++) { line = (LINE3D *) ( (char *) geom1 +offsets1[t]); - pt1 = &line->points[0]; - pt2 = &line->points[line->npoints-1]; - + 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(FALSE); } PG_RETURN_BOOL(TRUE); } @@ -2186,7 +2249,7 @@ Datum centroid(PG_FUNCTION_ARGS) 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 ) ; @@ -2194,13 +2257,13 @@ Datum centroid(PG_FUNCTION_ARGS) if (!((geom1->type == POLYGONTYPE) || (geom1->type == MULTIPOLYGONTYPE) )) PG_RETURN_NULL(); - //find the centroid + //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]); + poly = (POLYGON3D *) ( (char *) geom1 +offsets1[t]); pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) ); pts = (POINT3D *) MAXALIGN(pts); num_points =poly->npoints[0]; @@ -2214,9 +2277,9 @@ Datum centroid(PG_FUNCTION_ARGS) num_points_tot += num_points-1; //last point = 1st point for (v=0;vis3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) + POINTTYPE, geom1->is3d, geom1->SRID, geom1->scale, geom1->offsetX, geom1->offsetY) ); pfree(cent); PG_RETURN_POINTER(result); @@ -2233,10 +2296,10 @@ Datum centroid(PG_FUNCTION_ARGS) // max_distance(geom,geom) (both geoms must be linestrings) //find max distance between l1 and l2 -// method: for each point in l1, find distance to l2. +// method: for each point in l1, find distance to l2. // return max distance // -// note: max_distance(l1,l2) != max_distance(l2,l1) +// note: max_distance(l1,l2) != max_distance(l2,l1) // returns double PG_FUNCTION_INFO_V1(max_distance); @@ -2248,9 +2311,9 @@ Datum max_distance(PG_FUNCTION_ARGS) LINE3D *l1,*l2; int32 *offsets1,*offsets2; - + int t; - POINT3D *pt; + POINT3D *pt; double result,dist; @@ -2324,15 +2387,15 @@ Datum optimistic_overlap(PG_FUNCTION_ARGS) //bbox check memcpy(&g1_bvol, &geom1->bvol, sizeof(BOX3D) ); - + g1_bvol.LLB.x = g1_bvol.LLB.x - dist; g1_bvol.LLB.y = g1_bvol.LLB.y - dist; - + g1_bvol.URT.x = g1_bvol.URT.x + dist; g1_bvol.URT.y = g1_bvol.URT.y + dist; - + //xmin = LLB.x, xmax = URT.x - + if ( (g1_bvol.LLB.x > geom2->bvol.URT.x) || (g1_bvol.URT.x < geom2->bvol.LLB.x) || @@ -2353,7 +2416,7 @@ Datum optimistic_overlap(PG_FUNCTION_ARGS) //returns a list of points for a single polygon // foreach segment // (1st and last points will be unaltered, but -// there will be more points inbetween if segment length is +// there will be more points inbetween if segment length is POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *num_points_out) { double seg_distance; @@ -2361,10 +2424,10 @@ POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *n POINT3D *result,*r; bool keep_going; POINT3D *last_point, *next_point; - + //initial storage - max_points = 1000; + max_points = 1000; offset_new=0; //start at beginning of points list result = (POINT3D *) palloc (sizeof(POINT3D) * max_points); @@ -2377,12 +2440,12 @@ POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *n keep_going = 1; while(keep_going) { - next_point = &points[offset_old]; + next_point = &points[offset_old]; //distance last->next > dist seg_distance = sqrt( - (next_point->x-last_point->x)*(next_point->x-last_point->x) + - (next_point->y-last_point->y)*(next_point->y-last_point->y) ); + (next_point->x-last_point->x)*(next_point->x-last_point->x) + + (next_point->y-last_point->y)*(next_point->y-last_point->y) ); if (offset_new >= max_points) { //need to add new points to result @@ -2392,12 +2455,12 @@ POINT3D *segmentize_ring(POINT3D *points, double dist, int num_points_in, int *n max_points *=2; pfree(r); } - + if (seg_distance > dist) { //add a point at the distance location // and set last_point to this loc - + result[offset_new].x = last_point->x + (next_point->x-last_point->x)/seg_distance * dist; result[offset_new].y = last_point->y + (next_point->y-last_point->y)/seg_distance * dist; last_point = &result[offset_new]; @@ -2471,18 +2534,18 @@ Datum segmentize(PG_FUNCTION_ARGS) for (r=0;rnrings;r++) //foreach ring in the polygon { polypts = segmentize_ring(p_points, maxdist, p->npoints[r], &num_polypts); - if ( (all_num_polypts + num_polypts) < all_num_polypts_max ) + if ( (all_num_polypts + num_polypts) < all_num_polypts_max ) { //just add memcpy( &all_polypts[all_num_polypts], polypts, sizeof(POINT3D) *num_polypts ); all_num_polypts += num_polypts; } - else + else { //need more space new_size = all_num_polypts_max + num_polypts + 1000; rr = (POINT3D*) palloc(sizeof(POINT3D) * new_size); - memcpy(rr,all_polypts, sizeof(POINT3D) *all_num_polypts); + memcpy(rr,all_polypts, sizeof(POINT3D) *all_num_polypts); memcpy(&rr[all_num_polypts], polypts , sizeof(POINT3D) *num_polypts); pfree(all_polypts); all_polypts = rr; @@ -2492,7 +2555,7 @@ Datum segmentize(PG_FUNCTION_ARGS) pfree(polypts); p_npoints_ring[r] = num_polypts; } //for each ring - + poly = make_polygon(p->nrings, p_npoints_ring, all_polypts, all_num_polypts, &poly_size); if (first_one) @@ -2512,7 +2575,7 @@ Datum segmentize(PG_FUNCTION_ARGS) result = result2; pfree(poly); pfree(all_polypts); - } + } } // foreach polygon PG_RETURN_POINTER(result); @@ -2523,7 +2586,7 @@ Datum segmentize(PG_FUNCTION_ARGS) // all the sub_objects from both of the argument geometries // returned geometry is the simplest possible, based on the types -// of the colelct objects +// of the colelct objects // ie. if all are of either X or multiX, then a multiX is returned // bboxonly types are treated as null geometries (no sub_objects) PG_FUNCTION_INFO_V1( collector ); @@ -2561,14 +2624,31 @@ Datum collector( PG_FUNCTION_ARGS ) 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(); } + + if (geom1->nobjs ==0) + { + geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + result = (GEOMETRY *)palloc( geom2->size ); + memcpy( result, geom2, geom2->size ); + PG_RETURN_POINTER(result); + } + if (geom2->nobjs ==0) + { + geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + result = (GEOMETRY *)palloc( geom1->size ); + memcpy( result, geom1, geom1->size ); + PG_RETURN_POINTER(result); + } + result = (GEOMETRY *)palloc( geom1->size ); memcpy( result, geom1, geom1->size ); - + offsets2 = (int32 *)( ((char *)&(geom2->objType[0])) + sizeof( int32 ) * geom2->nobjs ) ; for (i=0; inobjs; i++) @@ -2577,7 +2657,7 @@ Datum collector( PG_FUNCTION_ARGS ) { size = geom2->size - offsets2[i]; } - else + else { size = offsets2[i+1] - offsets2[i]; } @@ -2651,3 +2731,41 @@ Datum box3dtobox(PG_FUNCTION_ARGS) PG_RETURN_POINTER(out); } + +PG_FUNCTION_INFO_V1(isempty); +Datum isempty(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom1= (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + + if (geom1->nobjs ==0) + PG_RETURN_INT32(1); + PG_RETURN_INT32(0); +} + + +// converts multi* types with 1 element to the single-element version. +// ie. MULTIPOINT(0 0) --> POINT(0 0) +void compressType(GEOMETRY *g) +{ + if (g->nobjs ==1) + { + if (g->type == MULTIPOINTTYPE) + { + g->type = POINTTYPE; + return; + } + if (g->type == MULTILINETYPE) + { + g->type = LINETYPE; + return; + } + if (g->type == MULTIPOLYGONTYPE) + { + g->type = POLYGONTYPE; + return; + } + + } +} + diff --git a/postgis_geos.c b/postgis_geos.c index 4af704394..8717efb3a 100644 --- a/postgis_geos.c +++ b/postgis_geos.c @@ -10,6 +10,15 @@ * ********************************************************************** * $Log$ + * Revision 1.8 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.7 2003/08/06 19:31:18 dblasby * Added the WKB parser. Added all the functions like * PolyFromWKB(,[]). @@ -115,8 +124,12 @@ extern Geometry *GEOSDifference(Geometry *g1,Geometry *g2); extern Geometry *GEOSBoundary(Geometry *g1); extern Geometry *GEOSSymDifference(Geometry *g1,Geometry *g2); extern Geometry *GEOSUnion(Geometry *g1,Geometry *g2); +extern char GEOSequals(Geometry *g1, Geometry*g2); +extern char GEOSisSimple(Geometry *g1); +extern char GEOSisRing(Geometry *g1); +extern Geometry *GEOSpointonSurface(Geometry *g1); Datum relate_full(PG_FUNCTION_ARGS); @@ -139,6 +152,14 @@ Datum boundary(PG_FUNCTION_ARGS); Datum symdifference(PG_FUNCTION_ARGS); Datum geomunion(PG_FUNCTION_ARGS); + +Datum issimple(PG_FUNCTION_ARGS); +Datum isring(PG_FUNCTION_ARGS); +Datum geomequals(PG_FUNCTION_ARGS); +Datum pointonsurface(PG_FUNCTION_ARGS); + + + Geometry *POSTGIS2GEOS(GEOMETRY *g); void errorIfGeometryCollection(GEOMETRY *g1, GEOMETRY *g2); GEOMETRY *GEOS2POSTGIS(Geometry *g, char want3d ); @@ -161,7 +182,6 @@ Datum geomunion(PG_FUNCTION_ARGS) Geometry *g1,*g2,*g3; GEOMETRY *result; - char empty; initGEOS(MAXIMUM_ALIGNOF); @@ -178,20 +198,6 @@ Datum geomunion(PG_FUNCTION_ARGS) } - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS union() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } - // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); @@ -210,6 +216,8 @@ Datum geomunion(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -223,7 +231,6 @@ Datum symdifference(PG_FUNCTION_ARGS) Geometry *g1,*g2,*g3; GEOMETRY *result; - char empty; initGEOS(MAXIMUM_ALIGNOF); @@ -239,21 +246,6 @@ Datum symdifference(PG_FUNCTION_ARGS) PG_RETURN_NULL(); //never get here } - - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS symdifference() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } - // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); @@ -272,6 +264,8 @@ Datum symdifference(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -283,8 +277,6 @@ Datum boundary(PG_FUNCTION_ARGS) Geometry *g1,*g3; GEOMETRY *result; - char empty; - initGEOS(MAXIMUM_ALIGNOF); g1 = POSTGIS2GEOS(geom1 ); @@ -297,20 +289,6 @@ Datum boundary(PG_FUNCTION_ARGS) PG_RETURN_NULL(); //never get here } - - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS bounary() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } - // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; result = GEOS2POSTGIS(g3, geom1->is3d); @@ -328,6 +306,8 @@ Datum boundary(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g1); GEOSdeleteGeometry(g3); + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -335,7 +315,6 @@ PG_FUNCTION_INFO_V1(convexhull); Datum convexhull(PG_FUNCTION_ARGS) { GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); - char empty; Geometry *g1,*g3; GEOMETRY *result; @@ -352,18 +331,6 @@ Datum convexhull(PG_FUNCTION_ARGS) PG_RETURN_NULL(); //never get here } - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS convexhull() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; @@ -378,6 +345,9 @@ Datum convexhull(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g1); GEOSdeleteGeometry(g3); + + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -387,7 +357,6 @@ Datum buffer(PG_FUNCTION_ARGS) { GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); double size = PG_GETARG_FLOAT8(1); - char empty; Geometry *g1,*g3; GEOMETRY *result; @@ -404,18 +373,6 @@ Datum buffer(PG_FUNCTION_ARGS) PG_RETURN_NULL(); //never get here } - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS buffer() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; @@ -430,6 +387,8 @@ Datum buffer(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g1); GEOSdeleteGeometry(g3); + + compressType(result); // convert multi* to single item if appropriate PG_RETURN_POINTER(result); } @@ -456,7 +415,6 @@ Datum intersection(PG_FUNCTION_ARGS) Geometry *g1,*g2,*g3; GEOMETRY *result; - char empty; initGEOS(MAXIMUM_ALIGNOF); @@ -473,19 +431,7 @@ Datum intersection(PG_FUNCTION_ARGS) } - empty = GEOSisEmpty(g3); - if (empty ==2) - { - GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); - GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS Intersection() threw an error (couldnt test empty on result)!"); - PG_RETURN_NULL(); //never get here - } - if (empty) - { - PG_RETURN_NULL(); - } + // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; @@ -505,6 +451,8 @@ Datum intersection(PG_FUNCTION_ARGS) GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -517,7 +465,6 @@ Datum difference(PG_FUNCTION_ARGS) Geometry *g1,*g2,*g3; GEOMETRY *result; - char empty; initGEOS(MAXIMUM_ALIGNOF); @@ -534,38 +481,75 @@ Datum difference(PG_FUNCTION_ARGS) } - empty = GEOSisEmpty(g3); - if (empty ==2) + + +// elog(NOTICE,"result: %s", GEOSasText(g3) ) ; + + result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); + if (result == NULL) { GEOSdeleteGeometry(g1); GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS difference() threw an error (couldnt test empty on result)!"); + elog(ERROR,"GEOS difference() threw an error (result postgis geometry formation)!"); PG_RETURN_NULL(); //never get here } - if (empty) + + + + GEOSdeleteGeometry(g1); + GEOSdeleteGeometry(g2); + GEOSdeleteGeometry(g3); + + + compressType(result); // convert multi* to single item if appropriate + + PG_RETURN_POINTER(result); +} + + +//select pointonsurface('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'); +PG_FUNCTION_INFO_V1(pointonsurface); +Datum pointonsurface(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + Geometry *g1,*g3; + GEOMETRY *result; + + initGEOS(MAXIMUM_ALIGNOF); + + g1 = POSTGIS2GEOS(geom1 ); + g3 = GEOSpointonSurface(g1); + + if (g3 == NULL) { - PG_RETURN_NULL(); + elog(ERROR,"GEOS pointonsurface() threw an error!"); + GEOSdeleteGeometry(g1); + PG_RETURN_NULL(); //never get here } + + + // elog(NOTICE,"result: %s", GEOSasText(g3) ) ; - result = GEOS2POSTGIS(g3, geom1->is3d || geom2->is3d); + result = GEOS2POSTGIS(g3, geom1->is3d); if (result == NULL) { GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); - elog(ERROR,"GEOS difference() threw an error (result postgis geometry formation)!"); + elog(ERROR,"GEOS pointonsurface() threw an error (result postgis geometry formation)!"); PG_RETURN_NULL(); //never get here } GEOSdeleteGeometry(g1); - GEOSdeleteGeometry(g2); GEOSdeleteGeometry(g3); + compressType(result); // convert multi* to single item if appropriate + PG_RETURN_POINTER(result); } @@ -941,6 +925,106 @@ if ((g1==NULL) || (g2 == NULL)) PG_RETURN_POINTER(result); } +//============================== + +PG_FUNCTION_INFO_V1(geomequals); +Datum geomequals(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); + + + Geometry *g1,*g2; + bool result; + + errorIfGeometryCollection(geom1,geom2); + initGEOS(MAXIMUM_ALIGNOF); + + g1 = POSTGIS2GEOS(geom1 ); + g2 = POSTGIS2GEOS(geom2 ); + + + result = GEOSequals(g1,g2); + GEOSdeleteGeometry(g1); + GEOSdeleteGeometry(g2); + + if (result == 2) + { + elog(ERROR,"GEOS equals() threw an error!"); + PG_RETURN_NULL(); //never get here + } + + PG_RETURN_BOOL(result); +} + +PG_FUNCTION_INFO_V1(issimple); +Datum issimple(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + Geometry *g1; + int result; + + if (geom->nobjs == 0) + PG_RETURN_BOOL(true); + + initGEOS(MAXIMUM_ALIGNOF); + + //elog(NOTICE,"GEOS init()"); + + g1 = POSTGIS2GEOS(geom ); + + result = GEOSisSimple(g1); + GEOSdeleteGeometry(g1); + + + if (result == 2) + { + elog(ERROR,"GEOS issimple() threw an error!"); + PG_RETURN_NULL(); //never get here + } + + PG_RETURN_BOOL(result); +} + +PG_FUNCTION_INFO_V1(isring); +Datum isring(PG_FUNCTION_ARGS) +{ + GEOMETRY *geom = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); + + Geometry *g1; + int result; + + if (geom->type != LINETYPE) + { + elog(ERROR,"isring() should only be called on a LINE"); + } + + if (geom->nobjs == 0) + PG_RETURN_BOOL(false); + + initGEOS(MAXIMUM_ALIGNOF); + + //elog(NOTICE,"GEOS init()"); + + g1 = POSTGIS2GEOS(geom ); + + result = GEOSisRing(g1); + GEOSdeleteGeometry(g1); + + + if (result == 2) + { + elog(ERROR,"GEOS isring() threw an error!"); + PG_RETURN_NULL(); //never get here + } + + PG_RETURN_BOOL(result); +} + + + +//=================================================== POLYGON3D *PolyFromGeometry(Geometry *g, int *size) { @@ -1068,7 +1152,9 @@ GEOMETRY *GEOS2POSTGIS(Geometry *g,char want3d) ngeoms = GEOSGetNumGeometries(g); if (ngeoms ==0) { - return NULL; + result = makeNullGeometry(GEOSGetSRID(g)); + result->type = MULTIPOINTTYPE; + return result; } pts = GEOSGetCoordinates(g); @@ -1103,7 +1189,9 @@ GEOMETRY *GEOS2POSTGIS(Geometry *g,char want3d) ngeoms = GEOSGetNumGeometries(g); if (ngeoms ==0) { - return NULL; + result = makeNullGeometry(GEOSGetSRID(g)); + result->type = MULTILINETYPE; + return result; } for (t=0;ttype = MULTIPOLYGONTYPE; + return result; } for (t=0;tnobjs); + polys = NULL; + if (g->nobjs >0) + polys = (POLYGON3D**) palloc(sizeof (POLYGON3D*) * g->nobjs); for (t=0;tnobjs;t++) { polys[t] = (POLYGON3D*) ((char *) g +offsets1[t]) ; } geos= PostGIS2GEOS_multipolygon(polys, g->nobjs, g->SRID,g->is3d); - pfree(polys); + if (polys != NULL) + pfree(polys); if (geos == NULL) { elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); @@ -1265,7 +1359,9 @@ Geometry *POSTGIS2GEOS(GEOMETRY *g) break; case MULTILINETYPE: //make an array of POLYGON3Ds - lines = (LINE3D**) palloc(sizeof (LINE3D*) * g->nobjs); + lines = NULL; + if (g->nobjs >0) + lines = (LINE3D**) palloc(sizeof (LINE3D*) * g->nobjs); for (t=0;tnobjs;t++) { lines[t] = (LINE3D*) ((char *) g +offsets1[t]) ; @@ -1280,7 +1376,9 @@ Geometry *POSTGIS2GEOS(GEOMETRY *g) break; case MULTIPOINTTYPE: //make an array of POINT3Ds - points = (POINT3D**) palloc(sizeof (POINT3D*) * g->nobjs); + points = NULL; + if (g->nobjs >0) + points = (POINT3D**) palloc(sizeof (POINT3D*) * g->nobjs); for (t=0;tnobjs;t++) { points[t] = (POINT3D*) ((char *) g +offsets1[t]) ; @@ -1303,7 +1401,9 @@ Geometry *POSTGIS2GEOS(GEOMETRY *g) break; case COLLECTIONTYPE: //make an array of GEOS Geometrys - geoms = (Geometry**) palloc(sizeof (Geometry*) * g->nobjs); + geoms = NULL; + if (g->nobjs >0) + geoms = (Geometry**) palloc(sizeof (Geometry*) * g->nobjs); for (t=0;tnobjs;t++) { obj = ((char *) g +offsets1[t]); @@ -1343,7 +1443,8 @@ Geometry *POSTGIS2GEOS(GEOMETRY *g) } } geos= PostGIS2GEOS_collection(geoms,g->nobjs,g->SRID,g->is3d); - pfree(geoms); + if (geoms != NULL) + pfree(geoms); if (geos == NULL) { elog(ERROR,"Couldnt convert the postgis geometry to GEOS!"); @@ -1503,5 +1604,25 @@ Datum isvalid(PG_FUNCTION_ARGS) PG_RETURN_NULL(); // never get here } +PG_FUNCTION_INFO_V1(issimple); +Datum issimple(PG_FUNCTION_ARGS) +{ + elog(ERROR,"issimple:: operation not implemented - compile PostGIS with GEOS support"); + PG_RETURN_NULL(); // never get here +} +PG_FUNCTION_INFO_V1(geomequals); +Datum geomequals(PG_FUNCTION_ARGS) +{ + elog(ERROR,"geomequals:: operation not implemented - compile PostGIS with GEOS support"); + PG_RETURN_NULL(); // never get here +} +PG_FUNCTION_INFO_V1(isring); +Datum isring(PG_FUNCTION_ARGS) +{ + elog(ERROR,"isring:: operation not implemented - compile PostGIS with GEOS support"); + PG_RETURN_NULL(); // never get here +} + + #endif diff --git a/postgis_geos_wrapper.cpp b/postgis_geos_wrapper.cpp index bf92dedb0..3e2a36dd0 100644 --- a/postgis_geos_wrapper.cpp +++ b/postgis_geos_wrapper.cpp @@ -113,6 +113,14 @@ extern "C" int GEOSGetNumInteriorRings(Geometry *g1); extern "C" int GEOSGetSRID(Geometry *g1); extern "C" int GEOSGetNumGeometries(Geometry *g1); +extern "C" char GEOSisSimple(Geometry *g1); +extern "C" char GEOSequals(Geometry *g1, Geometry*g2); + +extern "C" char GEOSisRing(Geometry *g1); + +extern "C" Geometry *GEOSpointonSurface(Geometry *g1); + + //########################################################### @@ -163,7 +171,7 @@ Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is for (t =0; t< ngeoms; t++) { - subGeos->push_back(geoms[t]); + subGeos->push_back(geoms[t]); } g = geomFactory->buildGeometry(subGeos); if (g==NULL) @@ -184,7 +192,7 @@ Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d) Coordinate *c; if (is3d) - c = new Coordinate(point->x, point->y); + c = new Coordinate(point->x, point->y); else c = new Coordinate(point->x, point->y, point->z); Geometry *g = geomFactory->createPoint(*c); @@ -255,7 +263,7 @@ Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, b for (t =0; t< npolys; t++) { - subPolys->push_back(PostGIS2GEOS_polygon(polygons[t], SRID,is3d )); + subPolys->push_back(PostGIS2GEOS_polygon(polygons[t], SRID,is3d )); } g = geomFactory->createMultiPolygon(subPolys); if (g== NULL) @@ -280,7 +288,7 @@ Geometry *PostGIS2GEOS_multilinestring(LINE3D **lines,int nlines, int SRID, bool for (t =0; t< nlines; t++) { - subLines->push_back(PostGIS2GEOS_linestring(lines[t], SRID,is3d )); + subLines->push_back(PostGIS2GEOS_linestring(lines[t], SRID,is3d )); } g = geomFactory->createMultiLineString(subLines); if (g==NULL) @@ -304,7 +312,7 @@ Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool i for (t =0; t< npoints; t++) { - subPoints->push_back(PostGIS2GEOS_point(points[t], SRID,is3d )); + subPoints->push_back(PostGIS2GEOS_point(points[t], SRID,is3d )); } g = geomFactory->createMultiPoint(subPoints); if (g==NULL) @@ -337,7 +345,7 @@ Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d) pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] ) ); pts = (POINT3D *) MAXALIGN(pts); - + // make outerRing cl = new BasicCoordinateList(polygon->npoints[0]); if (is3d) @@ -479,7 +487,7 @@ char GEOSrelateWithin(Geometry *g1, Geometry*g2) } } -// call g1->contains(g2) +// call g1->contains(g2) // returns 0 = false // 1 = true // 2 = error was trapped @@ -578,6 +586,21 @@ char GEOSisvalid(Geometry *g1) // general purpose //----------------------------------------------------------------- +char GEOSequals(Geometry *g1, Geometry*g2) +{ + try { + bool result; + result = g1->equals(g2); + return result; + } + catch (...) + { + return 2; + } +} + + + char *GEOSasText(Geometry *g1) { try @@ -608,6 +631,33 @@ char GEOSisEmpty(Geometry *g1) } } +char GEOSisSimple(Geometry *g1) +{ + try + { + return g1->isSimple(); + } + catch (...) + { + return 2; + } +} + +char GEOSisRing(Geometry *g1) +{ + try + { + return (( (LinearRing*)g1)->isRing()); + } + catch (...) + { + return 2; + } +} + + + + char *GEOSGeometryType(Geometry *g1) { try @@ -725,7 +775,18 @@ Geometry *GEOSUnion(Geometry *g1,Geometry *g2) } - +Geometry *GEOSpointonSurface(Geometry *g1) +{ + try + { + Geometry *g3 = g1->getInteriorPoint(); + return g3; + } + catch (...) + { + return NULL; + } +} @@ -772,7 +833,7 @@ POINT3D *GEOSGetCoordinate(Geometry *g1) try{ POINT3D *result = (POINT3D*) malloc (sizeof(POINT3D)); Coordinate *c =g1->getCoordinate(); - + result->x = c->x; result->y = c->y; result->z = c->z; @@ -782,7 +843,7 @@ POINT3D *GEOSGetCoordinate(Geometry *g1) { return NULL; } - + } @@ -801,12 +862,12 @@ POINT3D *GEOSGetCoordinates(Geometry *g1) for (t=0;tgetAt(t); - + result[t].x = c.x; result[t].y = c.y; result[t].z = c.z; } - + return result; } catch(...) @@ -842,7 +903,7 @@ int GEOSGetNumInteriorRings(Geometry *g1) } -//only call on GCs +//only call on GCs (or multi*) int GEOSGetNumGeometries(Geometry *g1) { try{ @@ -909,3 +970,4 @@ int GEOSGetSRID(Geometry *g1) } + diff --git a/postgis_gist_71.c b/postgis_gist_71.c index 30794c77a..ae9da4ae5 100644 --- a/postgis_gist_71.c +++ b/postgis_gist_71.c @@ -8,9 +8,18 @@ * * This is free software; you can redistribute and/or modify it under * the terms of hte GNU General Public Licence. See the COPYING file. - * + * ********************************************************************** * $Log$ + * Revision 1.3 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.2 2003/07/01 18:30:55 pramsey * Added CVS revision headers. * @@ -35,7 +44,7 @@ #include "utils/elog.h" //Norman Vine found this problem for compiling under cygwin -// it defines BYTE_ORDER and LITTLE_ENDIAN +// it defines BYTE_ORDER and LITTLE_ENDIAN #ifdef __CYGWIN__ #include // FOR ENDIAN DEFINES @@ -116,12 +125,20 @@ GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS) #endif in = (GEOMETRY*)PG_DETOAST_DATUM(PointerGetDatum(entry->pred)); + + if (in->nobjs ==0) // this is the EMPTY geometry + { + //elog(NOTICE,"found an empty geometry"); + // dont bother adding this to the index + PG_RETURN_POINTER(entry); + } + r = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); r->size = sizeof(GEOMETRYKEY); r->SRID = in->SRID; thebox = convert_box3d_to_box(&in->bvol); memcpy( (void*)&(r->key), (void*)thebox, sizeof(BOX) ); - if ( (char*)in != entry->pred ) + if ( (char*)in != entry->pred ) { pfree( in ); pfree(thebox); @@ -133,7 +150,7 @@ GISTENTRY *ggeometry_compress(PG_FUNCTION_ARGS) } else { gistentryinit(*retval, NULL, entry->rel, entry->page, entry->offset, 0,FALSE); - } + } } else { retval = entry; } @@ -167,7 +184,7 @@ bool ggeometry_consistent(PG_FUNCTION_ARGS) PG_RETURN_BOOL(FALSE); } - PG_RETURN_BOOL(rtree_internal_consistent((BOX*)&( ((GEOMETRYKEY *)(entry->pred))->key ), + PG_RETURN_BOOL(rtree_internal_consistent((BOX*)&( ((GEOMETRYKEY *)(entry->pred))->key ), thebox, strategy)); } @@ -181,7 +198,7 @@ GEOMETRYKEY *ggeometry_union(PG_FUNCTION_ARGS) printf("GIST: ggeometry_union called\n"); #endif - result = (GEOMETRYKEY*) + result = (GEOMETRYKEY*) rtree_union( (bytea*) PG_GETARG_POINTER(0), (int*) PG_GETARG_POINTER(1), @@ -241,11 +258,11 @@ bool *ggeometry_same(PG_FUNCTION_ARGS) if ( b1 && b2 ) - *result = DatumGetBool( DirectFunctionCall2( box_same, - PointerGetDatum(&(b1->key)), + *result = DatumGetBool( DirectFunctionCall2( box_same, + PointerGetDatum(&(b1->key)), PointerGetDatum(&(b2->key))) ); else - *result = ( b1==NULL && b2==NULL ) ? TRUE : FALSE; + *result = ( b1==NULL && b2==NULL ) ? TRUE : FALSE; return(result); } @@ -264,16 +281,16 @@ Datum ggeometry_inter(PG_FUNCTION_ARGS) { rt_box_inter, PointerGetDatum( &(b1->key) ), PointerGetDatum( &(b2->key) )) ); - + if (interd) { GEOMETRYKEY *tmp = (GEOMETRYKEY*)palloc( sizeof(GEOMETRYKEY) ); tmp->size = sizeof(GEOMETRYKEY); - + memcpy( (void*)&(tmp->key), (void*)interd, sizeof(BOX) ); tmp->SRID = b1->SRID; pfree( interd ); PG_RETURN_POINTER( tmp ); - } else + } else PG_RETURN_POINTER( NULL ); } @@ -297,7 +314,7 @@ char *ggeometry_binary_union(char *r1, char *r2, int *sizep) } else { *sizep = 0; retval = NULL; - } + } } else { BOX *key = (BOX*)DatumGetPointer( DirectFunctionCall2( rt_box_union, @@ -338,7 +355,7 @@ char *rtree_union(bytea *entryvec, int *sizep, BINARY_UNION bu) printf("GIST: rtree_union called\n"); #endif - numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); + numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); tmp = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[0]).pred; out = NULL; @@ -364,9 +381,9 @@ float *rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, B #endif - + ud = (*bu)( origentry->pred, newentry->pred, &sizep ); - tmp1 = (*sb)( ud ); + tmp1 = (*sb)( ud ); if (ud) pfree(ud); *result = tmp1 - (*sb)( origentry->pred ); @@ -375,7 +392,7 @@ float *rtree_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, B /* ** The GiST PickSplit method -** We use Guttman's poly time split algorithm +** We use Guttman's poly time split algorithm */ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BINARY_UNION bu, RDF interop, SIZE_BOX sb) { @@ -402,17 +419,17 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); - + firsttime = true; waste = 0.0; - + for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) { datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) { datum_beta = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[j].pred); - + /* compute the wasted space by unioning these guys */ - /* size_waste = size_union - size_inter; */ + /* size_waste = size_union - size_inter; */ union_d = (*bu)( datum_alpha, datum_beta, &sizep ); if ( union_d ) { size_union = (*sb)(union_d); @@ -428,18 +445,18 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI if ( inter_d ) { size_inter = (*sb)(inter_d); pfree(inter_d); - } else + } else size_inter = 0.0; } else size_inter = 0.0; size_waste = size_union - size_inter; - + /* * are these a more promising split that what we've * already seen? */ - + if (size_waste > waste || firsttime) { waste = size_waste; seed_1 = i; @@ -448,25 +465,25 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI } } } - + left = v->spl_left; v->spl_nleft = 0; right = v->spl_right; v->spl_nright = 0; - + if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ) { datum_l = (char*) palloc( keylen ); memcpy( (void*)datum_l, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred ), keylen ); - } else - datum_l = NULL; - size_l = (*sb)( datum_l ); + } else + datum_l = NULL; + size_l = (*sb)( datum_l ); if ( ((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ) { datum_r = (char*) palloc( keylen ); memcpy( (void*)datum_r, (void*)(((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred ), keylen ); - } else - datum_r = NULL; - size_r = (*sb)( datum_r ); - + } else + datum_r = NULL; + size_r = (*sb)( datum_r ); + /* * Now split up the regions between the two seeds. An important * property of this split algorithm is that the split vector v @@ -478,17 +495,17 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI * This is handled at the very end, when we have placed all the * existing tuples and i == maxoff + 1. */ - + maxoff = OffsetNumberNext(maxoff); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - + /* * If we've already decided where to place this item, just * put it on the right list. Otherwise, we need to figure * out which page needs the least enlargement in order to * store the item. */ - + if (i == seed_1) { *left++ = i; v->spl_nleft++; @@ -498,14 +515,14 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI v->spl_nright++; continue; } - - /* okay, which page needs least enlargement? */ + + /* okay, which page needs least enlargement? */ datum_alpha = (char *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); union_dl = (*bu)( datum_l, datum_alpha, &sizep ); union_dr = (*bu)( datum_r, datum_alpha, &sizep ); - size_alpha = (*sb)( union_dl ); - size_beta = (*sb)( union_dr ); - + size_alpha = (*sb)( union_dl ); + size_beta = (*sb)( union_dr ); + /* pick which page to add it to */ if (size_alpha - size_l < size_beta - size_r) { pfree(datum_l); @@ -524,7 +541,7 @@ GIST_SPLITVEC *rtree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, int keylen, BI } } *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ - + v->spl_ldatum = datum_l; v->spl_rdatum = datum_r; diff --git a/postgis_gist_72.c b/postgis_gist_72.c index 53b13cf35..09dbed2b9 100644 --- a/postgis_gist_72.c +++ b/postgis_gist_72.c @@ -8,9 +8,18 @@ * * This is free software; you can redistribute and/or modify it under * the terms of hte GNU General Public Licence. See the COPYING file. - * + * ********************************************************************** * $Log$ + * Revision 1.6 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.5 2003/07/01 18:30:55 pramsey * Added CVS revision headers. * @@ -93,31 +102,46 @@ Datum ggeometry_compress(PG_FUNCTION_ARGS) if ( entry->leafkey) { retval = palloc(sizeof(GISTENTRY)); - if ( DatumGetPointer(entry->key) != NULL ) { + if ( DatumGetPointer(entry->key) != NULL ) + { GEOMETRY *in; BOX *r; #ifdef DEBUG_GIST - printf("GIST: ggeometry_compress called on geometry\n"); + elog(NOTICE,"GIST: ggeometry_compress called on geometry\n"); fflush( stdout ); #endif in = (GEOMETRY*)PG_DETOAST_DATUM( entry->key ); - r = convert_box3d_to_box(&in->bvol); - if ( in != (GEOMETRY*)DatumGetPointer(entry->key) ) + + if (in->nobjs ==0) // this is the EMPTY geometry { - pfree( in ); + //elog(NOTICE,"found an empty geometry"); + // dont bother adding this to the index + PG_RETURN_POINTER(entry); } + else + { + r = convert_box3d_to_box(&in->bvol); + if ( in != (GEOMETRY*)DatumGetPointer(entry->key) ) + { + pfree( in ); + } - gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, - entry->offset, sizeof(BOX), FALSE); + gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, + entry->offset, sizeof(BOX), FALSE); + } - } else { + } + else + { gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, 0,FALSE); } - } else { + } + else + { retval = entry; } PG_RETURN_POINTER(retval); @@ -137,7 +161,7 @@ Datum ggeometry_consistent(PG_FUNCTION_ARGS) */ #ifdef DEBUG_GIST - printf("GIST: ggeometry_consistent called\n"); + elog(NOTICE,"GIST: ggeometry_consistent called\n"); fflush( stdout ); #endif @@ -159,7 +183,7 @@ bool rtree_internal_consistent(BOX *key, bool retval; #ifdef DEBUG_GIST - printf("GIST: rtree_internal_consist called\n"); + elog(NOTICE,"GIST: rtree_internal_consist called\n"); fflush( stdout ); #endif @@ -209,7 +233,7 @@ Datum gbox_union(PG_FUNCTION_ARGS) *pageunion; #ifdef DEBUG_GIST - printf("GIST: gbox_union called\n"); + elog(NOTICE,"GIST: gbox_union called\n"); fflush( stdout ); #endif @@ -249,7 +273,7 @@ Datum gbox_penalty(PG_FUNCTION_ARGS) float tmp1; #ifdef DEBUG_GIST - printf("GIST: gbox_penalty called\n"); + elog(NOTICE,"GIST: gbox_penalty called\n"); fflush( stdout ); #endif @@ -310,7 +334,7 @@ gbox_picksplit(PG_FUNCTION_ARGS) int nbytes; #ifdef DEBUG_GIST - printf("GIST: gbox_picksplit called\n"); + elog(NOTICE,"GIST: gbox_picksplit called\n"); fflush( stdout ); #endif @@ -511,7 +535,7 @@ Datum gbox_same(PG_FUNCTION_ARGS) bool *result = (bool *) PG_GETARG_POINTER(2); #ifdef DEBUG_GIST - printf("GIST: gbox_same called\n"); + elog(NOTICE,"GIST: gbox_same called\n"); fflush( stdout ); #endif @@ -527,7 +551,7 @@ size_box(Datum box) { #ifdef DEBUG_GIST - printf("GIST: size_box called\n"); + elog(NOTICE,"GIST: size_box called\n"); fflush( stdout ); #endif diff --git a/postgis_inout.c b/postgis_inout.c index 07acc72cb..5afc319ef 100644 --- a/postgis_inout.c +++ b/postgis_inout.c @@ -11,6 +11,15 @@ * ********************************************************************** * $Log$ + * Revision 1.25 2003/08/08 18:19:20 dblasby + * Conformance changes. + * Removed junk from postgis_debug.c and added the first run of the long + * transaction locking support. (this will change - dont use it) + * conformance tests were corrected + * some dos cr/lf removed + * empty geometries i.e. GEOMETRYCOLLECT(EMPTY) added (with indexing support) + * pointN(,1) now returns the first point (used to return 2nd) + * * Revision 1.24 2003/08/06 19:31:18 dblasby * Added the WKB parser. Added all the functions like * PolyFromWKB(,[]). @@ -1476,6 +1485,8 @@ Datum geometry_in(PG_FUNCTION_ARGS) //printf("str=%s\n",str); + + //trim white while (isspace((unsigned char) *str)) str++; @@ -1501,6 +1512,19 @@ Datum geometry_in(PG_FUNCTION_ARGS) str++; } + + if (strstr(str,"EMPTY")) + { + GEOMETRY *result=makeNullGeometry( SRID); + if (strstr(str,"MULTIPOLYGON")) + result->type = MULTIPOLYGONTYPE; + if (strstr(str,"MULTILINESTRING")) + result->type = MULTILINETYPE; + if (strstr(str,"MULTIPOINT")) + result->type = MULTIPOINTTYPE; + PG_RETURN_POINTER( result ); + } + if (strstr(str,"BOX3D") != NULL ) // bbox only { @@ -1810,6 +1834,23 @@ char *geometry_to_text(GEOMETRY *geometry) int mem_size,npts; + if (geometry->nobjs == 0) + { + //empty geometry + result = (char*) palloc(30); + + sprintf(result,"GEOMETRYCOLLECTION(EMPTY)"); + + if (geometry->type == MULTILINETYPE) + sprintf(result,"MULTILINESTRING(EMPTY)"); + if (geometry->type == MULTIPOINTTYPE) + sprintf(result,"MULTIPOINT(EMPTY)"); + if (geometry->type == MULTIPOLYGONTYPE) + sprintf(result,"MULTIPOLYGON(EMPTY)"); + return result; + } + + //printf("in geom_out(%p)\n",geometry); size = 30; //just enough to put in object type @@ -2020,6 +2061,9 @@ Datum get_bbox_of_geometry(PG_FUNCTION_ARGS) BOX3D *result; + if (geom->nobjs == 0) + PG_RETURN_NULL(); + //make a copy of it result = palloc ( sizeof(BOX3D) ); @@ -2641,12 +2685,15 @@ char *to_wkb_collection(GEOMETRY *geom, bool flip_endian, int32 *end_size) // we make a list of smaller wkb chunks in sub_result[] // and that wkb chunk's size in sizes[] - - sub_result = palloc( sizeof(char *) * geom->nobjs); - sizes = palloc( sizeof(int) * geom->nobjs); + sub_result = NULL; + if (geom->nobjs >0) + sub_result = palloc( sizeof(char *) * geom->nobjs); + sizes = NULL; + if (geom->nobjs >0) + sizes = palloc( sizeof(int) * geom->nobjs); - for (t=0; t<=geom->nobjs; t++) //for each part of the collections, do the work in another function + for (t=0; tnobjs; t++) //for each part of the collections, do the work in another function { type = geom->objType[t]; @@ -2709,8 +2756,10 @@ char *to_wkb_collection(GEOMETRY *geom, bool flip_endian, int32 *end_size) } //free temp structures - pfree( sub_result); - pfree( sizes); + if (sub_result != NULL) + pfree( sub_result); + if (sizes != NULL) + pfree( sizes); //total size of the wkb *end_size = total_size+9; @@ -2799,7 +2848,9 @@ char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size) if (geom->type == MULTILINETYPE) { //make a list of lines - linelist = palloc( sizeof(LINE3D *) * geom->nobjs); + linelist = NULL; + if (geom->nobjs >0) + linelist = palloc( sizeof(LINE3D *) * geom->nobjs); for (t=0;tnobjs; t++) { linelist[t] = (LINE3D *) ((char *) geom +offsets1[t] ) ; @@ -2819,7 +2870,9 @@ char *to_wkb_sub(GEOMETRY *geom, bool flip_endian, int32 *wkb_size) if (geom->type == MULTIPOLYGONTYPE) { //make a list of polygons - polylist = palloc( sizeof(POLYGON3D *) * geom->nobjs); + polylist = NULL; + if (geom->nobjs >0) + polylist = palloc( sizeof(POLYGON3D *) * geom->nobjs); for (t=0;tnobjs; t++) { polylist[t] = (POLYGON3D *) ((char *) geom +offsets1[t] ) ; @@ -4193,7 +4246,11 @@ switch (wkbType) WKB+=4; (*bytes_read)+=4; if (ngeoms ==0) - return NULL; + { + GEOMETRY *result= makeNullGeometry(-1); + result->type = MULTIPOINTTYPE; + return result; + } mybytes_read = *bytes_read; so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); @@ -4240,7 +4297,11 @@ switch (wkbType) WKB+=4; (*bytes_read)+=4; if (ngeoms ==0) - return NULL; + { + GEOMETRY *result= makeNullGeometry(-1); + result->type = MULTILINETYPE; + return result; + } mybytes_read = *bytes_read; so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); @@ -4287,7 +4348,11 @@ switch (wkbType) WKB+=4; (*bytes_read)+=4; if (ngeoms ==0) - return NULL; + { + GEOMETRY *result= makeNullGeometry(-1); + result->type = MULTIPOLYGONTYPE; + return result; + } mybytes_read = *bytes_read; so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); @@ -4334,7 +4399,10 @@ switch (wkbType) WKB+=4; (*bytes_read)+=4; if (ngeoms ==0) - return NULL; + { + GEOMETRY *result= makeNullGeometry(-1); + return result; + } mybytes_read = *bytes_read; so_far = WKBtoGeometry(WKB, length - mybytes_read, &other_bytes_read); @@ -4623,3 +4691,31 @@ Datum geometry_from_text_gc(PG_FUNCTION_ARGS) } PG_RETURN_POINTER(geom); } + + +//returns a GEOMETRYCOLLECTION(EMPTY) +// bbox of this object is BOX3D(0 0 0, 0 0 0) +// but should be treated as NULL +GEOMETRY *makeNullGeometry(int SRID) +{ + int size = sizeof(GEOMETRY); + GEOMETRY *result = palloc(size); + + + memset(result,0, size ); // init to 0s + + result->size = size; + result->nobjs = 0; + result->type = COLLECTIONTYPE; + result->is3d = false; + + + result->SRID = SRID; + result->scale = 1.0; + result->offsetX = 0; + result->offsetY = 0; + + memset(&result->bvol,0, sizeof(BOX3D) ); //make bbox :: BOX3D(0 0 0, 0 0 0) + + return result; +} -- 2.40.0