]> granicus.if.org Git - postgis/commitdiff
Conformance changes.
authorDavid Blasby <dblasby@gmail.com>
Fri, 8 Aug 2003 18:19:20 +0000 (18:19 +0000)
committerDavid Blasby <dblasby@gmail.com>
Fri, 8 Aug 2003 18:19:20 +0000 (18:19 +0000)
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(<linestring>,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

12 files changed:
Attic/postgis_sql_common.sql.in
Makefile
doc/postgis.xml
examples/ogc_test_suite/2_queries.sql
postgis.h
postgis_debug.c
postgis_fn.c
postgis_geos.c
postgis_geos_wrapper.cpp
postgis_gist_71.c
postgis_gist_72.c
postgis_inout.c

index 32d4352b7f8246122012f70445fe5ea72bdca741..28f3e87d9fce3b0239b0822865304aa42b450656 100644 (file)
 --  
 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -- $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(<linestring>,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(<WKB>,[<SRID>]).
@@ -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'
index 33ab7f5d4834237afe9cb9cea33ea0afa60a8a10..5ef8279e2947130aeb7df2e65a3ce3464af48667 100644 (file)
--- 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
index 7390f63f8bf1a61999e42d847cda6e96335a9dc5..1464d4179b9635241473d1af91cf5286908039ad 100644 (file)
@@ -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.
                                                </para> 
+                                               <para>OGC SPEC s2.1.1.1 - also see asBinary(<geometry>,'XDR') and asBinary(<geometry>,'NDR')
                                        </listitem> 
                                </varlistentry> 
                                <varlistentry> 
                                        <term>Dimension(geometry)</term> 
                                        <listitem> 
-                                               <para>Returns '2' if the geometry is two dimensional and '3' if the
-                                                 geometry is three dimensional.
+                                               <para>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.
                                                </para> 
+                                               <programlisting>select dimension('GEOMETRYCOLLECTION(LINESTRING(1 1,0 0),POINT(0 0)'); 
+dimension 
+-----------
+1</programlisting>
                                        </listitem> 
                                </varlistentry> 
+                               <varlistentry> 
+                               <term>isEmpty(geometry)</term> 
+                               <listitem> 
+                                       <para>
+                                               Returns 1 (TRUE) if this Geometry is the empty geometry . If true, then this
+Geometry represents the empty point set - i.e. GEOMETRYCOLLECTION(EMPTY).
+                                       </para> 
+                                       <para>OGC SPEC s2.1.1.1 </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>isSimple(geometry)</term> 
+                               <listitem> 
+                                       <para>
+                                               Returns 1 (TRUE) if this Geometry has no anomalous geometric points, such as self
+                                               intersection or self tangency. 
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       
+                                       <para>OGC SPEC s2.1.1.1  </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>boundary(geometry)</term> 
+                               <listitem> 
+                                       <para>
+                                               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.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>OGC SPEC s2.1.1.1  </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>equals(geometry)</term> 
+                               <listitem> 
+                                       <para>
+                                               Returns 1 (TRUE) if this Geometry is \91spatially equal\92 to
+anotherGeometry.  Use this for a 'better' answer than '='.  equals ('LINESTRING(0 0, 10 10)','LINESTRING(0 0, 5 5, 10 10)') is true.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>OGC SPEC s2.1.1.1  </para>
+                               </listitem> 
+                               </varlistentry> 
+                       
+                               <varlistentry> 
+                               <term>disjoint(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry is \91spatially disjoint\92 from anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 //s2.1.13.3 - a.Relate(b, \91FF*FF****\92) </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>intersects(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry  \91spatially intersects\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 //s2.1.13.3 - Intersects(g1, g2 ) --> Not (Disjoint(g1, g2 )) </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>touches(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry  \91spatially touches\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>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  </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>crosses(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry  \91spatially crosses\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3 - a.Relate(b, \91T*T******\92)  </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>within(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry is \91spatially within\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3 - a.Relate(b, \91T*F**F***\92) </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>overlaps(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry is \91spatially overlapping\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3 </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>contains(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry is \91spatially contains\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3  - same as within(geometry,geometry)</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>intersects(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para>Returns 1 (TRUE) if this Geometry is \91spatially intersects\92  anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3  - NOT disjoint(geometry,geometry)</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>relate(geometry,geometry, intersectionPatternMatrix)</term> 
+                               <listitem> 
+                                       <para>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.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para> NOTE: this is the "allowable" version that returns a boolean, not an integer.
+                                       <para>OGC SPEC s2.1.1.1 // s2.1.13.3 </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>relate(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para> returns the DE-9IM (dimensionally extended nine-intersection matrix)
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>not in OGC spec, but implied.  see s2.1.13.2 </para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>buffer(geometry,double)</term> 
+                               <listitem> 
+                                       <para> 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.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>convexhull(geometry)</term> 
+                               <listitem> 
+                                       <para> Returns a geometry that represents the convex hull of this Geometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>intersection(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para> Returns a geometry that represents the point set
+intersection of this Geometry with anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>geomunion(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para> Returns a geometry that represents the point set union of
+this Geometry with anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>NOTE: this is renamed from "union" because union is an SQL reserved word</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>difference(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para> Returns a geometry that represents the point set
+difference of this Geometry with anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
+                               <varlistentry> 
+                               <term>difference(geometry,geometry)</term> 
+                               <listitem> 
+                                       <para> Returns a geometry that represents the point set
+symmetric difference of this Geometry with anotherGeometry.
+                                       </para> 
+                                       <para>Performed by the GEOS module</para>
+                                       <para>Do not call with a GeometryCollection as an argument</para>
+                                       <para>OGC SPEC s2.1.1.1</para>
+                               </listitem> 
+                               </varlistentry> 
                                <varlistentry> 
                                        <term>Envelope(geometry)</term> 
                                        <listitem> 
                                                <para>Returns a POLYGON representing the bounding box of the
                                                  geometry.
                                                </para> 
+                                               <para> 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)).  </para><para>NOTE:PostGIS will add a Zmin/Zmax coordinate as well.</para>
                                        </listitem> 
                                </varlistentry> 
                                <varlistentry> 
                                        <term>GeometryType(geometry)</term> 
                                        <listitem> 
                                                <para>Returns the type of the geometry as a string. Eg: 'LINESTRING',
-                                                 'POLYGON', 'MULTIPOINT', etc.
+                                                 'POLYGON', 'MULTIPOINT', etc. 
                                                </para> 
+                                               <para>
+                                               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.
+                                               </para>
                                        </listitem> 
                                </varlistentry> 
                                <varlistentry> 
@@ -1803,10 +2039,21 @@ if( geom.getType() = Geometry.POLYGON )
                                                </para>
                                        </listitem>
                                </varlistentry> 
+                               <varlistentry>
+                               <term>IsRing(geometry)</term>
+                               <listitem>
+                                       <para>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).
+                                       
+                                       </para>
+                                       <para>performed by GEOS</para>
+                                       <para> OGC spec 2.1.5.1</para>
+                               </listitem>
+                               </varlistentry> 
                                <varlistentry> 
                                        <term>NumGeometries(geometry)</term> 
                                        <listitem> 
-                                               <para>If geometry is a GEOMETRYCOLLECTION return the number of
+                                               <para>If geometry is a GEOMETRYCOLLECTION (or MULTI*) return the number of
                                                  geometries, otherwise return NULL.
                                                </para> 
                                        </listitem> 
@@ -1818,6 +2065,7 @@ if( geom.getType() = Geometry.POLYGON )
                                                  GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING or
                                                  MULTIPOLYGON. Otherwise, return NULL.
                                                </para> 
+                                               <para>0 is 1st geometry</para>
                                        </listitem> 
                                </varlistentry>
                                <varlistentry>
@@ -1834,6 +2082,7 @@ if( geom.getType() = Geometry.POLYGON )
                                                <para>Return the Well-Known Text representation of the
                                                  geometry. For example: POLYGON(0 0,0 1,1 1,1 0,0 0)
                                                </para>
+                                               <para>OGC SPEC s2.1.1.1</para>
                                        </listitem>
                                </varlistentry>
                                <varlistentry>
@@ -1842,6 +2091,7 @@ if( geom.getType() = Geometry.POLYGON )
                                                <para>Returns the integer SRID number of the spatial
                                                  reference system of the geometry.
                                                </para>
+                                               <para>OGC SPEC s2.1.1.1</para>
                                        </listitem>
                                </varlistentry>
                                <varlistentry>
@@ -1962,6 +2212,14 @@ if( geom.getType() = Geometry.POLYGON )
                                                </para> 
                                        </listitem> 
                                </varlistentry> 
+                               <varlistentry> 
+                               <term>area(geometry)</term> 
+                               <listitem> 
+                                       <para>Returns the area of the geometry if it is a polygon or
+                                         multi-polygon. (same as area2(<polygon|multipolygon>)
+                                       </para> 
+                               </listitem> 
+                               </varlistentry> 
                                <varlistentry> 
                                        <term>asbinary(geometry,'NDR')</term> 
                                        <listitem> 
@@ -1971,6 +2229,13 @@ if( geom.getType() = Geometry.POLYGON )
                                                </para> 
                                        </listitem> 
                                </varlistentry> 
+                               <varlistentry> 
+                               <term>isvalid(geometry)</term> 
+                               <listitem> 
+                                       <para>returns true if this geometry is valid.
+                                       </para> 
+                               </listitem> 
+                               </varlistentry> 
                                <varlistentry> 
                                        <term>asbinary(geometry,'XDR')</term> 
                                        <listitem> 
@@ -1980,6 +2245,213 @@ if( geom.getType() = Geometry.POLYGON )
                                                </para> 
                                        </listitem> 
                                </varlistentry> 
+                               <varlistentry> 
+                               <term>GeomFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>GeometryFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PointFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a Point</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>LineFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a Line</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>LinestringFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a Line</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               
+                               <varlistentry> 
+                               <term>PolyFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a Polygon</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PolygonFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a Polygon</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MPointFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a MULTIPOINT</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MLineFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a MULTILINESTRING</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MPolyFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a MULTIPOLYGON</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>GeomCollFromText(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKT with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> Throws an error if the WKT is not a GEOMETRYCOLLECTION</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>GeomFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>GeometryFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PointFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a POINT </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>LineFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a LINESTRING </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>LinestringFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para>  from the conformance suite</para>
+                                       <para> throws an error if WKB is not a LINESTRING </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PolyFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a POLYGON </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PolygonFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> from the conformance suite</para>
+                                       <para> throws an error if WKB is not a POLYGON </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MPointFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a MULTIPOINT </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MLineFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a MULTILINESTRING </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>MPolyFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a MULTIPOLYGON </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>GeomCollFromWKB(text,[<srid>])</term> 
+                               <listitem> 
+                                       <para>Makes a Geometry from WKB with the given SRID.  If SRID is not give, it defaults to -1.</para> 
+                                       <para> OGC SPEC 3.2.6.2  - option SRID is from the conformance suite</para>
+                                       <para> throws an error if WKB is not a GEOMETRYCOLLECTION </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               <varlistentry> 
+                               <term>PointOnSurface(geometry)</term> 
+                               <listitem> 
+                                       <para>Return a Point guaranteed to lie on the surface</para> 
+                                       <para>Implemented using GEOS</para>
+                                       <para> OGC SPEC 3.2.14.2 and 3.2.18.2 - </para>
+                               </listitem> 
+                               </varlistentry> 
+                               
+                               
                                <varlistentry> 
                                        <term>box3d(geometry)</term> 
                                        <listitem> 
@@ -2052,6 +2524,14 @@ if( geom.getType() = Geometry.POLYGON )
                                                  linestring or multi-linestring.</para> 
                                        </listitem> 
                                </varlistentry> 
+                               <varlistentry> 
+                               <term>length(geometry)</term> 
+                               <listitem> 
+                                       <para>The length of this Curve in its associated spatial reference.</para> 
+                                         <para>synonym for length2d()</para>
+                                         <para>OGC SPEC 2.1.5.1 </para>
+                               </listitem> 
+                               </varlistentry> 
                                <varlistentry> 
                                        <term>length3d(geometry)</term> 
                                        <listitem> 
index 9b28947637adf08b00b3d337719a71cded0d270d..8d457792544c417fde7dd074259533435472c351 100644 (file)
@@ -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        
index 742201fb47f3d91d38a48784fd82b570c86a50e2..3f5d58bfd39792d811928446c56aa774d43d5d87 100644 (file)
--- a/postgis.h
+++ b/postgis.h
  *
  **********************************************************************
  * $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(<linestring>,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(<WKB>,[<SRID>]).
@@ -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.
index 84755af3cdb55f58ddff7c2250e6828dff78ec76..2b402bcbf082629993c076b7c899a29da7a3b670 100644 (file)
@@ -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(<linestring>,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)
 // #define DEBUG_GIST
 //#define DEBUG_GIST2
 
-void print_box2d(BOX *box);
-
-
-void dump_bytes( char *a, int numb)
-{
-       int     t;
 
-       for (t=0; t<numb; t++)
-       {
-               printf("        + Byte #%i has value %i (%x)\n",t,a[t],a[t]);
-       }
-}
 
 
-//debug function - whats really in that BOX3D?
-void print_box(BOX3D *box)
-{
-       printf("box is at %p\n",box);
-       if (box == NULL)
-       {
-               printf ("       + BOX IS NULL\n");
-               return;
-       }
-       printf("        + LLB = [%g,%g,%g]\n", box->LLB.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;t<numb_sub;t++)
-       {
-                       if (first_one)
-                       {
-                               first_one = FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
+       colname  =       trigdata->tg_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; t<n1; t++)
-               {
-                       if (first_one)
-                       {
-                               first_one = FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                       if (is3d)
-                       {
-                               memcpy(&x, &wkb[9+t*24],8);
-                               memcpy(&y, &wkb[9+t*24+8],8);
-                               memcpy(&z, &wkb[9+t*24+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);
-                       }
-                       else
-                       {
-                               memcpy(&x, &wkb[9+t*16],8);
-                               memcpy(&y, &wkb[9+t*16+8],8);
-                               if (flipbytes)
-                               {
-                                       flip_endian_double( (char *) & x) ;
-                                       flip_endian_double( (char *) & y) ;
-                               }
-                               printf("%g %g",x,y);
-                       }
-               }
-
-
-               printf(")\n");
-               if (is3d)
-                       *size = 9 + n1*24;
-               else
-                       *size = 9 + n1*16;
-               return;
-       }
-       if (type == 3)
-       {
-               *size = 9;
-               printf("POLYGON(");
-               memcpy(&n1, &wkb[5],4);
-               if (flipbytes)
-                       flip_endian_int32( (char *) & n1) ;
-               //printf("  --- has %i rings\n",n1);
-               *size += 4*n1;
-               offset= 9;
-               first_one = TRUE;
-               for (u=0; u<n1; u++)
-               {
-                       memcpy(&n2, &wkb[offset],4);
-                       if (flipbytes)
-                               flip_endian_int32( (char *) & n2) ;
-               //      printf(" ring %i: has %i points\n",u,n2);
 
+               sprintf(query,"SELECT * FROM temp_lock_have_table  WHERE xideq(transid , getTransactionID() ) AND lockcode =%s",lockcode);
+               elog(NOTICE,"about to execute :%s", query);
 
-                       if (first_one)
-                       {
-                               first_one = FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                       printf("(");
+       SPIcode = SPI_exec(query,0);
+       if (SPIcode !=SPI_OK_SELECT )
+               elog(ERROR,"couldnt execute to test for lock aquire:%s",query);
 
-                       first_one2 = TRUE;
-                       for (v=0; v< n2; v++)
-                       {
-                       if (first_one2)
-                       {
-                               first_one2 = FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                               if (is3d)
-                               {
-                                       memcpy(&x, &wkb[offset + 4+ v*24],8);
-                                       memcpy(&y, &wkb[offset + 4+ v*24 + 8],8);
-                                       memcpy(&z, &wkb[offset + 4+ v*24 + 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);
-
-                               }
-                               else
-                               {
-                                       memcpy(&x, &wkb[offset +4 +v*16],8);
-                                       memcpy(&y, &wkb[offset +4 +v*16 + 8],8);
-                                       if (flipbytes)
-                                       {
-                                               flip_endian_double( (char *) & x) ;
-                                               flip_endian_double( (char *) & y) ;
-                                       }
-                                       printf("%g %g",x,y);
-
-                               }
-                       }
-                       if (is3d)
-                       {
-                               offset +=4 +24*n2;
-                               *size += n2*24;
-                       }
-                       else
-                       {
-                               offset += 4+ 16*n2;
-                               *size += n2*16;
-                       }
-                       printf(")");
-               }
-
-               printf(")\n");
-
-               return;
-
-       }
-       if (type == 4)
+       if (SPI_processed >0)
        {
-               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; t<n1; t++)
-               {
-                       if (first_one)
-                       {
-                               first_one= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                       if (is3d)
-                       {
-                               memcpy(&x, &wkb[9+t*29+5],8);
-                               memcpy(&y, &wkb[9+t*29+8+5],8);
-                               memcpy(&z, &wkb[9+t*29+16+5],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);
-                       }
-                       else
-                       {
-                               memcpy(&x, &wkb[9+t*21+5],8);
-                               memcpy(&y, &wkb[9+t*21+8+5],8);
-                               if (flipbytes)
-                               {
-                                       flip_endian_double( (char *) & x) ;
-                                       flip_endian_double( (char *) & y) ;
-                               }
-                               printf("%g %g",x,y);
-                       }
-               }
-               printf (")\n");
-               return;
+               elog(NOTICE,"I own the lock - I can modify the row");
+               SPI_finish();
+               return PointerGetDatum(rettuple);
        }
-       if (type == 5)
-       {
-               *size = 9;
-               printf("MULTILINESTRING(");
-               memcpy(&n2,&wkb[5],4);
-               if (flipbytes)
-                       flip_endian_int32( (char *) & n2) ;
-       //      printf(" -- has %i sub-lines\n",n2);
-               *size += 9 *n2;
-               offset =9;
-               first_one2 = TRUE;
-               for (u=0; u<n2; u++)
-               {
-                       if (first_one2)
-                       {
-                               first_one2= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-               printf("(");
-               memcpy(&n1, &wkb[5 +offset],4);
-               if (flipbytes)
-                       flip_endian_int32( (char *) & n1) ;
-       //      printf("  --- has %i sub points\n",n1);
-               first_one = TRUE;
-               for (t=0; t<n1; t++)
-               {
-                       if (first_one)
-                       {
-                               first_one= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-
-                       if (is3d)
-                       {
-                               memcpy(&x, &wkb[offset+9+t*24],8);
-                               memcpy(&y, &wkb[offset+9+t*24+8],8);
-                               memcpy(&z, &wkb[offset+9+t*24+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);
-                       }
-                       else
-                       {
-                               memcpy(&x, &wkb[offset+9+t*16],8);
-                               memcpy(&y, &wkb[offset+9+t*16+8],8);
-                               if (flipbytes)
-                               {
-                                       flip_endian_double( (char *) & x) ;
-                                       flip_endian_double( (char *) & y) ;
-                               }
-                               printf("%g %g",x,y);
-                       }
-               }
-               printf(")");
-               if (is3d)
-               {
-                       *size += (24*n1);
-                       offset += 9 + (24*n1);
-               }
-               else
-               {
-                       *size += (16*n1);
-                       offset += 9 + (16*n1);
-               }
-               }
-               printf(")\n");
-               return;
 
+               elog(NOTICE,"I do not own the lock - I cannot modify the row");
+               //PG_RETURN_NULL();
+               SPI_finish();
+               return NULL;
        }
-       if (type == 6)
+       else
        {
-               *size = 9;
-               printf("MULTIPOLYGON(");
-               memcpy(&n3,&wkb[5],4);
-               if (flipbytes)
-                       flip_endian_int32( (char *) & n3) ;
-               //printf(" -- has %i sub-poly\n",n3);
-               *size += 9*n3;
-               offset1 =9;//where polygon starts
-               first_one3= TRUE;
-       for (t=0;t<n3; t++)  //for each polygon
-       {
-                       if (first_one3)
-                       {
-                               first_one3= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-               printf("(");
-               //printf("polygon #%i\n",t);
-               total_points = 0;
-               memcpy(&n1,&wkb[offset1+5],4); //# rings
-               *size += 4*n1;
-               if (flipbytes)
-                       flip_endian_int32( (char *) & n1) ;
-               //printf("This polygon has %i rings\n",n1);
-               offset = offset1+9; //where linear rings are
-               first_one = TRUE;
-               for (u=0; u<n1; u++) //for each ring
-               {
-                       if (first_one)
-                       {
-                               first_one= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                       printf("(");
-                       memcpy(&n2, &wkb[offset],4);
-                       if (flipbytes)
-                               flip_endian_int32( (char *) & n2) ; //pts in linear ring
-               //      printf(" ring %i: has %i points\n",u,n2);
-                       total_points += n2;
-                       first_one2 = TRUE;
-                       for (v=0; v< n2; v++)   //for each point
-                       {
-                       if (first_one2)
-                       {
-                               first_one2= FALSE;
-                       }
-                       else
-                       {
-                               printf(",");
-                       }
-                               if (is3d)
-                               {
-                                       memcpy(&x, &wkb[offset + 4+ v*24],8);
-                                       memcpy(&y, &wkb[offset + 4+ v*24 + 8],8);
-                                       memcpy(&z, &wkb[offset + 4+ v*24 + 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);
-                               }
-                               else
-                               {
-                                       memcpy(&x, &wkb[offset +4 +v*16],8);
-                                       memcpy(&y, &wkb[offset +4 +v*16 + 8],8);
-                                       if (flipbytes)
-                                       {
-                                               flip_endian_double( (char *) & x) ;
-                                               flip_endian_double( (char *) & y) ;
-                                       }
-                                       printf("%g %g",x,y);
-                               }
-                       }
-                       if (is3d)
-                       {
-                               *size += 24*n2;
-                               offset += 4+ 24*n2;
-                       }
-                       else
-                       {
-                               *size += 16*n2;
-                               offset += 4+ 16*n2;
-                       }
-                       printf(")");
-               }
-               printf(")");
-               if (is3d)
-                       offset1 +=9 +24*total_points +4*n1;
-               else
-                       offset1 += 9+ 16*total_points +4*n1;
-       }
-       printf(")\n");
-       return;
+               elog(NOTICE,"there is NOT a lock on this row!");
+               SPI_finish();
+               return PointerGetDatum(rettuple);
        }
-       if (type == 7)
-       {
-               decode_wkb_collection(wkb, size);
-       }
-}
 
+}
 
-char *print_geometry(GEOMETRY *geom)
-{
-       char    *text;
 
-       text = (char *) DatumGetPointer(DirectFunctionCall1(geometry_out,PointerGetDatum(geom) ) ) ;
+extern Datum getTransactionID(PG_FUNCTION_ARGS);
 
-       printf( "%s", text);
-       return text;
-}
+PG_FUNCTION_INFO_V1(getTransactionID);
 
-void print_point_debug(POINT3D *p)
+Datum getTransactionID(PG_FUNCTION_ARGS)
 {
-       printf("[%g %g %g]\n",p->x,p->y,p->z);
+    TransactionId xid = GetCurrentTransactionId();
+    PG_RETURN_DATUM( TransactionIdGetDatum(xid) );
 }
 
 
+
index b59bdc7962d01ca8828befdb9c0391fa7d16fa9b..99954c0f0f9f70e869f61d5d836999eedd2451cc 100644 (file)
@@ -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(<linestring>,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.
 #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(<linestring>, 0) is the 1st point, and pointN(<linestring>, 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(<linestring>, 1) is the 1st point, and pointN(<linestring>, 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; i<line->npoints;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; i<line->npoints;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; i<poly1->npoints[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; i<poly1->npoints[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 <intersect
                                ++cn;   // a valid crossing of y=P.y right of P.x
-       }       
+       }
     }
     return (cn&1);    // 0 if even (out), and 1 if odd (in)
 
@@ -424,15 +441,15 @@ int PIP( POINT3D *P, POINT3D *V, int n )
 //this one is easy - is the point inside a box?
 bool point_truely_inside(POINT3D       *point, BOX3D   *box)
 {
-       return ( 
-                       (point->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;t<geom->nobjs;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 
-               0<r<1 P is interior to AB 
+               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
+               0<r<1 P is interior to AB
        */
 
        r = ( (p->x-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;t<geom1->nobjs;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;v<num_points-1;v++)
                {
-                       tot_x  += pts[v].x;     
+                       tot_x  += pts[v].x;
                        tot_y  += pts[v].y;
-                       tot_z  += pts[v].z;             
+                       tot_z  += pts[v].z;
                }
        }
        cent = palloc(sizeof(POINT3D));
@@ -2224,7 +2287,7 @@ Datum centroid(PG_FUNCTION_ARGS)
         result = (
                                make_oneobj_geometry(sizeof(POINT3D),
                                                         (char *) cent,
-                                                          POINTTYPE,  geom1->is3d, 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;r<p->nrings;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; i<geom2->nobjs; 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;
+               }
+
+       }
+}
+
index 4af704394f41c76e3972ce69993684be3a71bc20..8717efb3ab656393394f45b579841289a0ad878b 100644 (file)
  *
  **********************************************************************
  * $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(<linestring>,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(<WKB>,[<SRID>]).
@@ -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;t<ngeoms;t++)
                {
@@ -1140,7 +1228,9 @@ GEOMETRY *GEOS2POSTGIS(Geometry *g,char want3d)
                ngeoms =        GEOSGetNumGeometries(g);
                if (ngeoms ==0)
                {
-                       return NULL;
+                       result =  makeNullGeometry(GEOSGetSRID(g));
+                       result->type = MULTIPOLYGONTYPE;
+                       return result;
                }
                for (t=0;t<ngeoms;t++)
                {
@@ -1174,7 +1264,8 @@ GEOMETRY *GEOS2POSTGIS(Geometry *g,char want3d)
 
                if (ngeoms ==0)
                {
-                       return NULL;
+                       result =  makeNullGeometry(GEOSGetSRID(g));
+                       return result;
                }
                if (ngeoms == 1)
                {
@@ -1250,13 +1341,16 @@ Geometry *POSTGIS2GEOS(GEOMETRY *g)
                                                        break;
                case MULTIPOLYGONTYPE:
                                                                        //make an array of POLYGON3Ds
-                                                       polys = (POLYGON3D**) palloc(sizeof (POLYGON3D*) * g->nobjs);
+                                                       polys = NULL;
+                                                       if (g->nobjs >0)
+                                                               polys = (POLYGON3D**) palloc(sizeof (POLYGON3D*) * g->nobjs);
                                                        for (t=0;t<g->nobjs;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;t<g->nobjs;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;t<g->nobjs;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;t<g->nobjs;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
 
index bf92dedb0e39c3b5199a2698f18bb757d98484fc..3e2a36dd0df9b93e04ca8332c2ca8e612b8dfd6a 100644 (file)
@@ -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;t<numPoints;t++)
                {
                        c =cl->getAt(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)
 }
 
 
+
index 30794c77aada785df86ef5f155b0da21d645e78a..ae9da4ae5e6efacf4e8203df6cec988b6276c13f 100644 (file)
@@ -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(<linestring>,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 <sys/param.h>       // 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;
 
index 53b13cf35d74dd6e1f7b0acefcbacfbe0412095a..09dbed2b9133c25063d8b6362c898a9c10684d3b 100644 (file)
@@ -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(<linestring>,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
 
index 07acc72cbdf06a4afdca121f7f02421749181d75..5afc319ef201b2a9c49276ae3f45704748d87cf0 100644 (file)
  *
  **********************************************************************
  * $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(<linestring>,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(<WKB>,[<SRID>]).
@@ -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; t<geom->nobjs; 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;t<geom->nobjs; 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;t<geom->nobjs; 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;
+}