[geos-devel] Exception Issues

David Blasby dblasby at refractions.net
Tue May 27 16:27:24 EDT 2003


Norman,

You've got some good ideas here, I thought I'd try to summarize what 
I've done so far so you dont re-invent the wheel.

<spew mode>


================================
Here's a test C++ program.  It tries to relate "LINESTRING(0 0,0 0)" to 
itself.  This is an invalid geometry and causes an exception which is 
caught.  It catches an 'anonymous - "catch (...)"' exception.  The 
output is:

in try block
about to cause an exception
anonymous exeception

NOTE: this program is linked to both libc and libc++.

int main(int argC, char* argV[])
{

     WKTReader *r = new WKTReader();
     GeometryFactory *geomFactory;
     Geometry *g1, *g2,*g3, *g4 ;

     geomFactory= new GeometryFactory( new PrecisionModel(), -1);

     try{
         cout << "in try block " <<endl;

         g1 = r->read("LINESTRING(0 0,0 0)");
         g2 = r->read("LINESTRING(0 0,0 0)");


         cout << "about to cause an exception" << endl;
         IntersectionMatrix *im = g1->relate(g2);
         cout << "finished relate"<< endl;

     }
     catch (exception e)
     {
         cout << "caught exception"<<endl;
         cout << e.what() << endl;
     }
     catch (char *s)
     {
       cout << "caught string exception:"<<s<<endl;
     }
     catch (...)
     {
         cout << "anonymous exeception"<< endl;
     }
}

=========================================
I thought that I might be able to catch exceptions if I modified the 
GEOS source code.  I did an experiment like this:

Added a function to the GEOS geometry.cpp like this:

void throwError()
{
    cout << "about to throw an error" << endl;

    try {
   	 throw "weee an error\n";
    }
    catch (...)
    {
        cout <<"caught an error"<<endl;
    }
}

Amazingly, when I call this GEOS frunction from postgis, IT CATCHES THE 
ERROR!!

I was very happy with this and wrote GeometryCAPI (see attached) that 
would wrap all the important GEOS functions.  Unfortunately, this didnt
work.  The throwError() function doesnt actually involve a 
stack-unwinding, so the exceptionhandling works.  If you add these 2 
functions to GEOS Geometry.cpp:

void throwError2()
{
    cout << "in throwError2() - about to call throwError3()" << endl;

    try {
   	 throwError3();
    }
    catch (...)
    {
        cout <<"throwError2():caught an error"<<endl;
    }
}

void throwError3()
{
	throw "throwError3 error";
}

This doesnt work - when you call throwError2(), a stack unwinding takes 
place and a SIGABRT is caused.  Double-plus-ungood.

===================================

Next we tried compiling postgresql and postgis with the -fexceptions 
option.  This didnt have any any effect - SIBABRT is still sent during a 
stack-unwind.

===================================

My current working version (NOT commited to CVS) uses the GeometryCAPI 
method of calling GEOS.

To use my version:
1. Get the most recent GEOS - if it has util/GeometryCAPI.cpp great!  If 
not, you'll have to add it (attached).
2. replace the postgis_geos.c and postgis_geos_wrapper.cpp  in your 
postgis installation.

Basically, when postgis want to do a relate, it calls 
postgis_geos_wrapper.cpp::GEOSrelate(Geometry *g1, Geometry*g2).  This 
calls GeometryCAPI::relate(Geometry *g1, Geometry*g2).  This calls the
actual GEOS relate function.  All exception should be caught in the GEOS 
c++ code before it gets near postgis or postgresql.


The postgis_geos_wrapper.cpp::GEOSrelate(Geometry *g1, Geometry*g2) is 
very simple.  NOTE: this should never encounter an exception from 
GeometryCAPI - the try block here is just redunant.

char *GEOSrelate(Geometry *g1, Geometry*g2)
{
         try {
                 char *result = geometryCAPI->relate(g1,g2);

                 return result;
         }
         catch (...)
         {
                 return NULL;
         }
}

GeometryCAPI::relate(Geometry *g1, Geometry*g2) is also simple - it 
tries to catch errors thrown by GEOS.  It also prints out a little bit 
of debugging.

//callers responsiblity to free the char* this returns
char *GeometryCAPI::relate(Geometry *g1, Geometry*g2)
{
     try {
cout << "In GeometryCAPI::relate and about to g1->relate(g2) " << endl;

         IntersectionMatrix *im = g1->relate(g2);
cout << "past relate" << endl;

         string s;
         char *result;
         if (im == NULL)
                 return NULL;

         s= im->toString();
         result = (char*) malloc( s.length() + 1);
         strcpy(result, s.c_str() );
         return result;
     }
     catch (...)
     {

cout << "caught error in GeometryCAPI::relate" << endl;
         return NULL;
     }
}


The actual postgis function is a little more complex - but its mostly 
just debugging code.  It never gets past the "GEOSrelate(g1, g2);" line.

PG_FUNCTION_INFO_V1(relate_full);
Datum relate_full(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;
     char    *relate_str;
     int len;
     char *result;

elog(NOTICE,"in relate_full()");

     errorIfGeometryCollection(geom1,geom2);


     initGEOS(MAXIMUM_ALIGNOF);

elog(NOTICE,"GEOS init()");

     g1 =    POSTGIS2GEOS(geom1 );
     g2 =    POSTGIS2GEOS(geom2 );

elog(NOTICE,"constructed geometries ");


if ((g1==NULL) || (g2 == NULL))
     elog(NOTICE,"g1 or g2 are null");

elog(NOTICE,GEOSasText(g1));
elog(NOTICE,GEOSasText(g2));

elog(NOTICE,"valid g1 = %i", GEOSisvalid(g1));
elog(NOTICE,"valid g2 = %i",GEOSisvalid(g2));

elog(NOTICE,"about to relate()");
        relate_str = GEOSrelate(g1, g2);

elog(NOTICE,"finished relate()");

     GEOSdeleteGeometry(g1);
     GEOSdeleteGeometry(g2);



     if (relate_str == NULL)
     {
         //free(relate_str);
         elog(ERROR,"GEOS relate() threw an error!");
         PG_RETURN_NULL(); //never get here
     }


     len = strlen(relate_str) + 4;

     result= palloc(len);
     *((int *) result) = len;

     memcpy(result +4, relate_str, len-4);

     free(relate_str);


     PG_RETURN_POINTER(result);
}


If look at the postgresql console while executing a simple query like:

select relate('LINESTRING(0 0,0 0)'::geometry,'LINESTRING(0 0,0 
0)'::geometry);

You'll see something like:

[postgres at hydra init.d]$ /opt/pgsql73/bin/postmaster -i -D 
/raid/pgdata/pgsql_devel_73
LOG:  database system was shut down at 2003-05-27 13:12:41 PDT
LOG:  checkpoint record is at 0/E955D68
LOG:  redo record is at 0/E955D68; undo record is at 0/0; shutdown TRUE
LOG:  next transaction id: 6708; next oid: 577113
LOG:  database system is ready
NOTICE:  in relate_full()
NOTICE:  GEOS init()
NOTICE:  constructed geometries
NOTICE:  LINESTRING (0.0000000000000000 0.0000000000000000, 
0.0000000000000000 0.0000000000000000)
NOTICE:  LINESTRING (0.0000000000000000 0.0000000000000000, 
0.0000000000000000 0.0000000000000000)
NOTICE:  valid g1 = 0
NOTICE:  valid g2 = 0
NOTICE:  about to relate()
In GeometryCAPI::relate and about to g1->relate(g2)
LOG:  server process (pid 11062) was terminated by signal 6


Signal 6 is SIGABRT.

===================================

</spew>

attached: GeometryCAPI.h     (inside GEOS)
           GeometryCAPI.cpp   (inside GEOS)
           postgis_geos_wrapper.cpp  (inside postgis)
           postgis_geos.c            (inside postgis)


What we havent tried:

1. linking postgresql to libc++.  This should work, but we dont want to 
have a special 'postgis' version of postgresql hanging around.
2. removing exceptions from GEOS.  This could be quite a bit of work
3. Try a newer compiler/libc
4. see if this problem occurs on other platforms.



-------------------------------------------------------
nhv at cape.com wrote:

> Our problem is that we were AFAICT never trying to catch any 
> exceptions other then those defined by GEOS hence when a
> standard exception was thrown it was never caught and therefore
> the underlying C++ standard terminate() handler was called when
> a standard exception was raised.

Yes - we are trying to catch all exceptions using the "catch (...)" 
symantic.  I think the real problem is that the default exception 
handler is supposed to pop the exception up the call stack, but the 
exception handler that is in libc doesnt know how to do that and will 
immediately SIGABRT.

> At a minimum this would consist of
> 1) A common PostGIS data set
> 2) The PostGIS GEOS enabled SQL query that causes the behaviour
>      on this data set

select relate('LINESTRING(0 0,0 0)'::geometry,'LINESTRING(0 0,0 
0)'::geometry);

If you can catch this, we should be off to the races.


Any thoughts?

dave




-------------- next part --------------
#include "geom.h"
#include "stdio.h"
#include "GeometryCAPI.h"


//---------------------------------------------------------------------------
// constructors

GeometryCAPI::GeometryCAPI(void)
{
	factory = new GeometryFactory( new PrecisionModel(), -1); // NOTE: SRID will have to be changed after geometry creation
	SRID = -1;
}

GeometryCAPI::GeometryCAPI(PrecisionModel *pm)
{
	factory = new GeometryFactory( pm, -1); // NOTE: SRID will have to be changed after geometry creation
	SRID = -1;
}

GeometryCAPI::GeometryCAPI(PrecisionModel *pm,int srid)
{
	factory = new GeometryFactory( pm, SRID); // NOTE: SRID will have to be changed after geometry creation
	SRID = srid;
}



//---------------------------------------------------------------------------
// geometryFactory functions

	void GeometryCAPI::setSRID(Geometry *g, int srid)
	{
		try{
			g->setSRID(srid);
		}
		catch (...)
		{
			//do nothing
		}	
	}

	Geometry *GeometryCAPI::makeBox(Envelope* envelope)
	{
		try{
			Geometry *result =factory->toGeometry(envelope, factory->getPrecisionModel() , SRID );
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::buildGeometry(vector<Geometry *> *subGeos)
	{
		try{
			Geometry *result =factory->buildGeometry(subGeos);
			return result;
		}
		catch (...)
		{
			return NULL;
		}

	}

	Geometry *GeometryCAPI::createPoint(Coordinate *c)
	{
		try{
			Geometry *result =factory->createPoint(*c);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::createMultiPolygon(vector<Geometry *> *polys)
	{
		try{
			Geometry *result =factory->createMultiPolygon(polys);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::createMultiLineString(vector<Geometry *> *lines)
	{
		try{
			Geometry *result =factory->createMultiLineString(lines);
			return result;
		}
		catch (...)
		{
			return NULL;
		}

	}

	Geometry *GeometryCAPI::createMultiPoint(vector<Geometry *> *points)
	{
		try{
			Geometry *result =factory->createMultiPoint(points);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::createLinearRing(BasicCoordinateList *pts)
	{
		try{
			Geometry *result =factory->createLinearRing(pts);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::createPolygon(LinearRing *outer, vector<Geometry *> *innerRings)
	{
		try{
			Geometry *result =factory->createPolygon(outer,innerRings);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

	Geometry *GeometryCAPI::createLineString(BasicCoordinateList *pts)
	{
		try{
			Geometry *result =factory->createLineString(pts);
			return result;
		}
		catch (...)
		{
			return NULL;
		}
	}

//---------------------------------------------------------------------------
// relate-type functions
//-----------------------------------------------------------
// relate()-related functions
//  return 0 = false, 1 = true, 2 = error occured
//-----------------------------------------------------------

char GeometryCAPI::disjoint(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->disjoint(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

char GeometryCAPI::touches(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result =  g1->touches(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

char GeometryCAPI::intersects(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->intersects(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

char GeometryCAPI::crosses(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->crosses(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

char GeometryCAPI::within(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->within(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

// call g1->contains(g2) 
// returns 0 = false
//         1 = true
//         2 = error was trapped
char GeometryCAPI::contains(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->contains(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}

char GeometryCAPI::overlaps(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = g1->overlaps(g2);
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}
}


//-------------------------------------------------------------------
// low-level relate functions
//------------------------------------------------------------------

char GeometryCAPI::relatePattern(Geometry *g1, Geometry*g2,char *pat)
{
	try {
		bool result;
		string s = pat;
		result = g1->relate(g2,pat);
		if (result)
				return 1;
		else 
				return 0;
	}
	catch (...)
	{
		return 2;
	}
}


//callers responsiblity to free the char* this returns
char *GeometryCAPI::relate(Geometry *g1, Geometry*g2)
{
	try {
cout << "In GeometryCAPI::relate and about to g1->relate(g2) " << endl;

		IntersectionMatrix *im = g1->relate(g2);
cout << "past relate" << endl;

		string s;
		char *result;
		if (im == NULL)
				return NULL;

		s= im->toString();
		result = (char*) malloc( s.length() + 1);
		strcpy(result, s.c_str() );
		return result;
	}
	catch (...)
	{

cout << "caught error in GeometryCAPI::relate" << endl;
		return NULL;
	}
}



//-----------------------------------------------------------------
// isValid
//-----------------------------------------------------------------


char GeometryCAPI::isValid(Geometry *g1)
{
	try {
		bool result;
		result =g1->isValid();
		if (result)
			return 1;
		else 
			return 0;
	}
	catch (...)
	{
		return 2;
	}

}


//-----------------------------------------------------------------
// general purpose
//-----------------------------------------------------------------


//callers responsibility to free the char* result.
char *GeometryCAPI::asText(Geometry *g1)
{
	try
	{
		string s = g1->toString();


		char *result;
		result = (char*) malloc( s.length() + 1);
		strcpy(result, s.c_str() );
		return result;
	}
	catch (...)
	{
		return NULL;
	}
}

//-------------------------------------------------------------------
// memory management functions
//------------------------------------------------------------------


//BUG:: this leaks memory, but delete kills the PrecisionModel for ALL the geometries
void GeometryCAPI::deleteGeometry(Geometry *a)
{
	try{
//	delete a;
	}
	catch(...)
	{
		// do nothing!
	}
}

void GeometryCAPI::deleteChar(char *a)
{
	try{
		free(a);
	}
	catch(...)
	{
		// do nothing!
	}

}

-------------- next part --------------


// This is just a simple wrapper for basic geometry functions.  See the 
// Geometry type documentation for exact definition for these functions.
//
//
// Because some C programs might have trouble calling C++ (most notably
// postgresql, PERL, PYTHON, JAVA, etc...) when there is triple indirect
// access  (postgresql -> libpostgis -> libgeos).
// A more technical discussion of this bug is at http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=37933 
//  Basically, if libc is loaded before libc++ exception handling might be comprimised.
//  
// This class solves this problem.  It basically wraps try..catch blocks around the obvious
// calls to GEOS functions.
//
// For functions that return a boolean (ie. g->isValid() or g1->disjoint(g2)), these functions
// return:
//     0  -- FALSE
//     1  -- TRUE
//     2  -- ERROR OCCURRED  * usually due to invalid geometry or robustness failure
//
//
//  For functions that return objects (ie. g->asText(), g1->relate(g2)), these functions
//  return either the appropriate object or NULL if an error occurred.
//
//
// Usage:
//  if you want to do 
//     g1->relate(g2);
//
//  then you do:
//		GeometryCAPI *capi = new GeometryCAPI();
//		char result        =  capi->relate(g1,g2);
//      if (result ==2)
//		{
//			//handle error
//		}
//
//
//  GeometryCAPI also handles geometry construction.  When you create a GeometryCAPI,
//  you also make a new GeometryFactory (see GeometryCAPI constructors vis-a-vis GeometryFactory).


class GeometryCAPI
{
public:
			//relate() related functions  - 0=false, 1=true, 2=error
	char disjoint(Geometry *g1, Geometry*g2);
	char touches(Geometry *g1, Geometry*g2);
	char intersects(Geometry *g1, Geometry*g2);
	char crosses(Geometry *g1, Geometry*g2);
	char within(Geometry *g1, Geometry*g2);
	char contains(Geometry *g1, Geometry*g2);
	char overlaps(Geometry *g1, Geometry*g2);
	char relatePattern(Geometry *g1, Geometry*g2,char *pat);

	char isValid(Geometry *g1);


	char *asText(Geometry *g1);


	char *relate(Geometry *g1, Geometry*g2);

		//memory management  ERROR = no action
	void deleteGeometry(Geometry *a);
	void deleteChar(char *a);

		//constructors
	GeometryCAPI();                    //make GeometryFactory( new PrecisionModel(), -1)
	GeometryCAPI(PrecisionModel*);     //make GeometryFactory(<PrecisionModel>, -1)
	GeometryCAPI(PrecisionModel*,int); //make GeometryFactory(<PrecisionModel>, #)


		// geometryFactory-type methods (c.f. GeometryFactory for what these functions do)
		// returns NULL = ERROR occured

	Geometry *makeBox(Envelope*);  // make a polygon representing the envelope
	Geometry *buildGeometry(vector<Geometry *>*); // make a geometrycollection (or multi*)
	Geometry *createPoint(Coordinate *);
	Geometry *createMultiPolygon(vector<Geometry *>*);
	Geometry *createMultiLineString(vector<Geometry *>*);
	Geometry *createMultiPoint(vector<Geometry *>*);
	Geometry *createLinearRing(BasicCoordinateList*);
	Geometry *createPolygon(LinearRing*, vector<Geometry *>*);
	Geometry *createLineString(BasicCoordinateList*);


	void setSRID(Geometry *g1, int SRID); // ERROR = no action

	

private:
	GeometryFactory *factory;
	int   SRID;
};
-------------- next part --------------
//  g++ postgis_GEOSwrapper.cpp -c -I/usr/local/include  -I/usr/local/include/geos -I/usr/local/src/postgresql-7.2.3//src/include


#include <stdio.h>

#include <string>
#include <iostream>
#include <fstream>

//#include "geom.h"
//#include "util.h"
//#include "graph.h"
#include "io.h"
#include "GeometryCAPI.h"
//#include "opRelate.h"



//WARNING THIS *MUST* BE SET CORRECTLY.
int MAXIMUM_ALIGNOF = -999999;    // to be set during initialization - this will be either 4 (intel) or 8 (sparc)

//for getting things to align properly  double are on 8byte align on solaris machines, and 4bytes on intel

#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
#define MAXALIGN(LEN)           TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))

typedef  int int32;

typedef struct
{
	double		x,y,z;  //for lat/long   x=long, y=lat
} POINT3D;

typedef struct
{
	POINT3D		LLB,URT; /* corner POINT3Ds on long diagonal */
} BOX3D;

typedef struct
{
	int32 	npoints; // how many points in the line
	int32 	junk;	   // double-word alignment
	POINT3D  	points[1]; // array of actual points
} LINE3D;


typedef struct
{
	int32 	nrings;	 // how many rings in this polygon
	int32		npoints[1]; //how many points in each ring
	/* could be 4 byes of filler here to make sure points[] is
         double-word aligned*/
	POINT3D  	points[1]; // array of actual points
} POLYGON3D;



//###########################################################

extern "C" char *GEOSrelate(Geometry *g1, Geometry*g2);
extern "C" void initGEOS(int maxalign);


extern "C" void GEOSdeleteChar(char *a);
extern "C" void GEOSdeleteGeometry(Geometry *a);
extern "C" char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat);
extern "C" char GEOSrelateDisjoint(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateTouches(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateIntersects(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateCrosses(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateWithin(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateContains(Geometry *g1, Geometry*g2);
extern "C" char GEOSrelateOverlaps(Geometry *g1, Geometry*g2);


extern "C" Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d);
extern "C" Geometry *PostGIS2GEOS_linestring(LINE3D *line,int SRID, bool is3d);
extern "C" Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d);
extern "C" Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d);
extern "C" Geometry *PostGIS2GEOS_multilinestring(LINE3D **lines,int nlines, int SRID, bool is3d);
extern "C" Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d);

extern "C" Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID);
extern "C" Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d);

extern "C" char GEOSisvalid(Geometry *g1);


extern "C" char *GEOSasText(Geometry *g1);

extern "C" char *throw_exception(Geometry *g);


//###########################################################

GeometryCAPI *geometryCAPI = NULL;

void initGEOS (int maxalign)
{
	if (geometryCAPI == NULL)
	{
		geometryCAPI = new GeometryCAPI( new PrecisionModel(), -1); // NOTE: SRID will have to be changed after geometry creation
		MAXIMUM_ALIGNOF = maxalign;
	}
}

// ------------------------------------------------------------------------------
// geometry constuctors - return NULL if there was an error
//-------------------------------------------------------------------------------

		//note: you lose the 3d from this!
Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID)
{
	try {
		Geometry *g;
		Envelope *envelope = new Envelope(box->LLB.x,box->URT.x ,box->LLB.y,box->URT.y);
		g = geometryCAPI->makeBox(envelope);
		if (g==NULL)
			return NULL;
		geometryCAPI->setSRID(g,SRID);
		delete envelope;
		return g;
	}
	catch (...)
	{
		return NULL;
	}
}

Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d)
{
	try
	{
		Geometry *g;
		int t;
		vector<Geometry *> *subGeos=new vector<Geometry *>;

		for (t =0; t< ngeoms; t++)
		{
			subGeos->push_back(geoms[t]);	
		}
		g = geometryCAPI->buildGeometry(subGeos);
		if (g==NULL)
			return NULL;
		g->setSRID(SRID);
		return g;
	}
	catch (...)
	{
		return NULL;
	}
}

Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d)
{
	try
	{
			Coordinate *c;

			if (is3d)
				c = new Coordinate(point->x, point->y);	
			else
				c = new Coordinate(point->x, point->y, point->z);
			Geometry *g = geometryCAPI->createPoint(c);
			if (g==NULL)
				return NULL;
			g->setSRID(SRID);
			return g;
		}
	catch (...)
	{
		return NULL;
	}
}


Geometry *PostGIS2GEOS_linestring(LINE3D *line,int SRID, bool is3d)
{
	try{

			int t;
			Coordinate c;

			//build coordinatelist & pre-allocate space
			BasicCoordinateList  *coords = new BasicCoordinateList(line->npoints);
			if (is3d)
			{
				for (t=0;t<line->npoints;t++)
				{
					c.x = line->points[t].x;
					c.y = line->points[t].y;
					c.z = line->points[t].z;
					coords->setAt( c ,t);
				}

			}
			else  //make 2d points
			{
				for (t=0;t<line->npoints;t++)
				{
					c.x = line->points[t].x;
					c.y = line->points[t].y;
					c.z = DoubleNotANumber;
					coords->setAt( c ,t);
				}

			}
			Geometry *g = geometryCAPI->createLineString(coords);
			if (g==NULL)
				return NULL;
			g->setSRID(SRID);
			return g;
		}
	catch (...)
	{
		return NULL;
	}
}

	//polygons is an array of pointers to polygons
Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d)
{
	try
	{
			int t;
			vector<Geometry *> *subPolys=new vector<Geometry *>;
			Geometry *g;

			for (t =0; t< npolys; t++)
			{
				subPolys->push_back(PostGIS2GEOS_polygon(polygons[t], SRID,is3d ));	
			}
			g = geometryCAPI->createMultiPolygon(subPolys);
			if (g== NULL)
				return NULL;
			g->setSRID(SRID);
			return g;
		}
	catch (...)
	{
		return NULL;
	}
}

	//lines is an array of pointers to line3d
Geometry *PostGIS2GEOS_multilinestring(LINE3D **lines,int nlines, int SRID, bool is3d)
{
	try
	{
			int t;
			vector<Geometry *> *subLines =new vector<Geometry *>;
			Geometry *g;

			for (t =0; t< nlines; t++)
			{
				subLines->push_back(PostGIS2GEOS_linestring(lines[t], SRID,is3d ));	
			}
			g = geometryCAPI->createMultiLineString(subLines);
			if (g==NULL)
				return NULL;
			g->setSRID(SRID);
			return g;
		}
	catch (...)
	{
		return NULL;
	}
}

Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d)
{
	try
	{
			int t;
			vector<Geometry *> *subPoints =new vector<Geometry *>;
			Geometry *g;

			for (t =0; t< npoints; t++)
			{
				subPoints->push_back(PostGIS2GEOS_point(points[t], SRID,is3d ));	
			}
			g = geometryCAPI->createMultiPoint(subPoints);
			if (g==NULL)
				return NULL;
			g->setSRID(SRID);
			return g;
		}
	catch (...)
	{
		return NULL;
	}

}


Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d)
{
	try
	{
		POINT3D *pts;
		Coordinate c;
		int  ring,t;
		Geometry *g;
		LinearRing *outerRing;
		LinearRing *innerRing;
		BasicCoordinateList *cl;
		int pointOffset =0; // first point that we're looking at.  a POLYGON3D has all its points smooshed together
		vector<Geometry *> *innerRings=new vector<Geometry *>;


		pts = (POINT3D *) ( (char *)&(polygon->npoints[polygon->nrings] )  );
		pts = (POINT3D *) MAXALIGN(pts);
	
			// make outerRing
			cl = new BasicCoordinateList(polygon->npoints[0]);
			if (is3d)
			{
				for(t=0;t<polygon->npoints[0];t++)
				{
						c.x = pts[t].x;
						c.y = pts[t].y;
						c.z = pts[t].z;
						cl->setAt( c ,t);
				}
			}
			else
			{
				for(t=0;t<polygon->npoints[0];t++)
				{
						c.x = pts[t].x;
						c.y = pts[t].y;
						c.z = DoubleNotANumber;
						cl->setAt( c ,t);
				}
			}
			outerRing = (LinearRing*) geometryCAPI->createLinearRing(cl);
			if (outerRing == NULL)
				return NULL;
			outerRing->setSRID(SRID);
			pointOffset = polygon->npoints[0];

		for(ring =1; ring< polygon->nrings; ring++)
		{
			cl = new BasicCoordinateList(polygon->npoints[ring]);
			if (is3d)
			{
				for(t=0;t<polygon->npoints[ring];t++)
				{
						c.x = pts[t+pointOffset].x;
						c.y = pts[t+pointOffset].y;
						c.z = pts[t+pointOffset].z;
						cl->setAt( c ,t);
				}
			}
			else
			{
				for(t=0;t<polygon->npoints[ring];t++)
				{
						c.x = pts[t+pointOffset].x;
						c.y = pts[t+pointOffset].y;
						c.z = DoubleNotANumber;
						cl->setAt( c ,t);
				}
			}
			innerRing = (LinearRing *) geometryCAPI->createLinearRing(cl);
			if (innerRing == NULL)
				return NULL;
			innerRing->setSRID(SRID);
			innerRings->push_back(innerRing);
			pointOffset += polygon->npoints[ring];
		}

		g = geometryCAPI->createPolygon(outerRing, innerRings);
		if (g==NULL)
			return NULL;
		g->setSRID(SRID);
		return g;
		}
	catch (...)
	{
		return NULL;
	}
}

//-----------------------------------------------------------
// relate()-related functions
//  return 0 = false, 1 = true, 2 = error occured
//-----------------------------------------------------------

char GEOSrelateDisjoint(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->disjoint(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char GEOSrelateTouches(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result =  geometryCAPI->touches(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char GEOSrelateIntersects(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->intersects(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char GEOSrelateCrosses(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->crosses(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char GEOSrelateWithin(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->within(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

// call g1->contains(g2) 
// returns 0 = false
//         1 = true
//         2 = error was trapped
char GEOSrelateContains(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->contains(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char GEOSrelateOverlaps(Geometry *g1, Geometry*g2)
{
	try {
		bool result;
		result = geometryCAPI->overlaps(g1,g2);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}


//-------------------------------------------------------------------
// low-level relate functions
//------------------------------------------------------------------

char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat)
{
	try {
		bool result;
		string s = pat;
		result = geometryCAPI->relatePattern(g1,g2,pat);
		return result;
	}
	catch (...)
	{
		return 2;
	}
}

char *GEOSrelate(Geometry *g1, Geometry*g2)
{

	try {

		char *result = geometryCAPI->relate(g1,g2);

		return result;
	}
	catch (...)
	{
		return NULL;
	}
}



//-----------------------------------------------------------------
// isValid
//-----------------------------------------------------------------


char GEOSisvalid(Geometry *g1)
{
	try {
		bool result;
		result =geometryCAPI->isValid(g1);
		return result;
	}
	catch (...)
	{
		return 2;
	}

}


//-----------------------------------------------------------------
// general purpose
//-----------------------------------------------------------------

char *GEOSasText(Geometry *g1)
{
	try
	{
		char * result = geometryCAPI->asText(g1);
		return result;
	}
	catch (...)
	{
		return NULL;
	}
}

//-------------------------------------------------------------------
// memory management functions
//------------------------------------------------------------------


//BUG:: this leaks memory, but delete kills the PrecisionModel for ALL the geometries
void GEOSdeleteGeometry(Geometry *a)
{
	try{
		geometryCAPI->deleteGeometry(a);
	}
	catch(...)
	{
		// do nothing!
	}
}

void GEOSdeleteChar(char *a)
{
	try{
		geometryCAPI->deleteChar(a);
	}
	catch(...)
	{
		// do nothing!
	}

}

-------------- next part --------------


//--------------------------------------------------------------------------
//  
#ifdef USE_GEOS

#include "postgres.h"


#include <math.h>
#include <float.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include "fmgr.h"

#include "postgis.h"
#include "utils/elog.h"

#include "access/gist.h"
#include "access/itup.h"
#include "access/rtree.h"

#include "utils/builtins.h"



typedef  struct Geometry Geometry;


extern const char * createGEOSPoint(POINT3D *pt);
extern void initGEOS(int maxalign);
extern char *GEOSrelate(Geometry *g1, Geometry*g2);
extern char GEOSrelatePattern(Geometry *g1, Geometry*g2,char *pat);
extern  char GEOSrelateDisjoint(Geometry *g1, Geometry*g2);
extern  char GEOSrelateTouches(Geometry *g1, Geometry*g2);
extern  char GEOSrelateIntersects(Geometry *g1, Geometry*g2);
extern  char GEOSrelateCrosses(Geometry *g1, Geometry*g2);
extern  char GEOSrelateWithin(Geometry *g1, Geometry*g2);
extern  char GEOSrelateContains(Geometry *g1, Geometry*g2);
extern  char GEOSrelateOverlaps(Geometry *g1, Geometry*g2);

extern char *GEOSasText(Geometry *g1);


extern void GEOSdeleteChar(char *a);
extern void GEOSdeleteGeometry(Geometry *a);

extern  Geometry *PostGIS2GEOS_point(POINT3D *point,int SRID, bool is3d);
extern  Geometry *PostGIS2GEOS_linestring(LINE3D *line,int SRID, bool is3d);
extern  Geometry *PostGIS2GEOS_polygon(POLYGON3D *polygon,int SRID, bool is3d);
extern  Geometry *PostGIS2GEOS_multipolygon(POLYGON3D **polygons,int npolys, int SRID, bool is3d);
extern Geometry *PostGIS2GEOS_multilinestring(LINE3D **lines,int nlines, int SRID, bool is3d);
extern Geometry *PostGIS2GEOS_multipoint(POINT3D **points,int npoints, int SRID, bool is3d);
extern Geometry *PostGIS2GEOS_box3d(BOX3D *box, int SRID);
extern Geometry *PostGIS2GEOS_collection(Geometry **geoms, int ngeoms,int SRID, bool is3d);

extern char GEOSisvalid(Geometry *g1);



extern char *throw_exception(Geometry *g);



Datum relate_full(PG_FUNCTION_ARGS);
Datum relate_pattern(PG_FUNCTION_ARGS);
Datum disjoint(PG_FUNCTION_ARGS);
Datum touches(PG_FUNCTION_ARGS);
Datum intersects(PG_FUNCTION_ARGS);
Datum crosses(PG_FUNCTION_ARGS);
Datum within(PG_FUNCTION_ARGS);
Datum contains(PG_FUNCTION_ARGS);
Datum overlaps(PG_FUNCTION_ARGS);
Datum isvalid(PG_FUNCTION_ARGS);
 

Geometry *POSTGIS2GEOS(GEOMETRY *g);
void errorIfGeometryCollection(GEOMETRY *g1, GEOMETRY *g2);

// return a GEOS Geometry from a POSTGIS GEOMETRY

 
void errorIfGeometryCollection(GEOMETRY *g1, GEOMETRY *g2)
{
	if (  (g1->type == COLLECTIONTYPE) || (g2->type == COLLECTIONTYPE) )
		elog(ERROR,"Relate Operation called with a GEOMETRYCOLLECTION type.  This is unsupported");
}

PG_FUNCTION_INFO_V1(isvalid);
Datum isvalid(PG_FUNCTION_ARGS) 
{
		GEOMETRY		*geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
		bool result;
		Geometry *g1;

		initGEOS(MAXIMUM_ALIGNOF);

		g1 = 	POSTGIS2GEOS(geom1 );

		result = GEOSisvalid(g1);
		GEOSdeleteGeometry(g1);
	if (result == 2)
	{
		elog(ERROR,"GEOS isvalid() threw an error!");
		PG_RETURN_NULL(); //never get here
	}


	PG_RETURN_BOOL(result);
}


// overlaps(GEOMETRY g1,GEOMETRY g2)
// returns  if GEOS::g1->overlaps(g2) returns true
// throws an error (elog(ERROR,...)) if GEOS throws an error
PG_FUNCTION_INFO_V1(overlaps);
Datum overlaps(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	result = GEOSrelateOverlaps(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS overlaps() threw an error!");
		PG_RETURN_NULL(); //never get here
	}

	PG_RETURN_BOOL(result);
}



PG_FUNCTION_INFO_V1(contains);
Datum contains(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	result = GEOSrelateContains(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS contains() threw an error!");
		PG_RETURN_NULL(); //never get here
	}



	PG_RETURN_BOOL(result);
}


PG_FUNCTION_INFO_V1(within);
Datum within(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);
	result = GEOSrelateWithin(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS within() threw an error!");
		PG_RETURN_NULL(); //never get here
	}



	PG_RETURN_BOOL(result);
}



PG_FUNCTION_INFO_V1(crosses);
Datum crosses(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	result = GEOSrelateCrosses(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS crosses() threw an error!");
		PG_RETURN_NULL(); //never get here
	}



	PG_RETURN_BOOL(result);
}



PG_FUNCTION_INFO_V1(intersects);
Datum intersects(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	result = GEOSrelateIntersects(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS intersects() threw an error!");
		PG_RETURN_NULL(); //never get here
	}



	PG_RETURN_BOOL(result);
}


PG_FUNCTION_INFO_V1(touches);
Datum touches(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 );

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	result = GEOSrelateTouches(g1,g2);
	if (result == 2)
	{
		elog(ERROR,"GEOS touches() threw an error!");
		PG_RETURN_NULL(); //never get here
	}



	PG_RETURN_BOOL(result);
}


PG_FUNCTION_INFO_V1(disjoint);
Datum disjoint(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 = GEOSrelateDisjoint(g1,g2);
	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);

	if (result == 2)
	{
		elog(ERROR,"GEOS disjoin() threw an error!");
		PG_RETURN_NULL(); //never get here
	}

	PG_RETURN_BOOL(result);
}


PG_FUNCTION_INFO_V1(relate_pattern);
Datum relate_pattern(PG_FUNCTION_ARGS)
{
	GEOMETRY		*geom1 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
	GEOMETRY		*geom2 = (GEOMETRY *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
	char *patt;
	bool result;

	Geometry *g1,*g2;


	errorIfGeometryCollection(geom1,geom2);
	initGEOS(MAXIMUM_ALIGNOF);

	g1 = 	POSTGIS2GEOS(geom1 );
	g2 = 	POSTGIS2GEOS(geom2 );


	patt =  DatumGetCString(DirectFunctionCall1(textout,
                        PointerGetDatum(PG_GETARG_DATUM(2))));

	result = GEOSrelatePattern(g1,g2,patt);
	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);
	pfree(patt);

	if (result == 2)
	{
		elog(ERROR,"GEOS relate_pattern() threw an error!");
		PG_RETURN_NULL(); //never get here
	}

	PG_RETURN_BOOL(result);


}



PG_FUNCTION_INFO_V1(relate_full);
Datum relate_full(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;
	char	*relate_str;
	int len;
	char *result;

elog(NOTICE,"in relate_full()");

	errorIfGeometryCollection(geom1,geom2);


	initGEOS(MAXIMUM_ALIGNOF);

elog(NOTICE,"GEOS init()");

	g1 = 	POSTGIS2GEOS(geom1 );
	g2 = 	POSTGIS2GEOS(geom2 );

elog(NOTICE,"constructed geometries ");





if ((g1==NULL) || (g2 == NULL))
	elog(NOTICE,"g1 or g2 are null");

elog(NOTICE,GEOSasText(g1));
elog(NOTICE,GEOSasText(g2));

elog(NOTICE,"valid g1 = %i", GEOSisvalid(g1));
elog(NOTICE,"valid g2 = %i",GEOSisvalid(g2));

elog(NOTICE,"about to relate()");


		relate_str = GEOSrelate(g1, g2);

elog(NOTICE,"finished relate()");

	GEOSdeleteGeometry(g1);
	GEOSdeleteGeometry(g2);



	if (relate_str == NULL)
	{
		//free(relate_str);
		elog(ERROR,"GEOS relate() threw an error!");
		PG_RETURN_NULL(); //never get here
	}


	len = strlen(relate_str) + 4;

	result= palloc(len);
	*((int *) result) = len;

	memcpy(result +4, relate_str, len-4);

	free(relate_str);


	PG_RETURN_POINTER(result);
}


//BBOXONLYTYPE -> returns as a 2d polygon
Geometry *POSTGIS2GEOS(GEOMETRY *g)
{
	POINT3D *pt;
	LINE3D *line;
	POLYGON3D *poly;
	POLYGON3D **polys;
	LINE3D **lines;
	POINT3D **points;
	Geometry **geoms;
	Geometry *geos;
	char     *obj;
	int      obj_type;
	int t;
	Geometry	*result;

	int32 *offsets1 = (int32 *) ( ((char *) &(g->objType[0] ))+ sizeof(int32) * g->nobjs ) ;

	switch(g->type)
	{
		case POINTTYPE:	
							pt = (POINT3D*) ((char *) g +offsets1[0]) ;
							result =  PostGIS2GEOS_point(pt,g->SRID,g->is3d);
							if (result == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return result;
							break;
		case LINETYPE:		
							line = (LINE3D*) ((char *) g +offsets1[0]) ;
							result =  PostGIS2GEOS_linestring(line,g->SRID,g->is3d);
							if (result == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return result;
							break;
		case POLYGONTYPE:   
							poly = (POLYGON3D*) ((char *) g +offsets1[0]) ;
							result =  PostGIS2GEOS_polygon(poly,g->SRID,g->is3d);
							if (result == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return result;
							break;
		case MULTIPOLYGONTYPE:
									//make an array of POLYGON3Ds
							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 (geos == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return geos;
							break;
		case MULTILINETYPE:
								//make an array of POLYGON3Ds
							lines = (LINE3D**) palloc(sizeof (LINE3D*) * g->nobjs);
							for (t=0;t<g->nobjs;t++)
							{
								lines[t] = 	(LINE3D*) ((char *) g +offsets1[t]) ;
							}
							geos= PostGIS2GEOS_multilinestring(lines, g->nobjs, g->SRID,g->is3d);
							pfree(lines);
							if (geos == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return geos;
							break;
		case MULTIPOINTTYPE:
								//make an array of POINT3Ds
							points = (POINT3D**) palloc(sizeof (POINT3D*) * g->nobjs);
							for (t=0;t<g->nobjs;t++)
							{
								points[t] = 	(POINT3D*) ((char *) g +offsets1[t]) ;
							}
							geos= PostGIS2GEOS_multipoint(points, g->nobjs,g->SRID,g->is3d);
							pfree(points);
							if (geos == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return geos;
							break;
		case BBOXONLYTYPE:
							result =   PostGIS2GEOS_box3d(&g->bvol, g->SRID);
							if (result == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return result;
							break;
		case COLLECTIONTYPE:
								//make an array of GEOS Geometrys
							geoms = (Geometry**) palloc(sizeof (Geometry*) * g->nobjs);
							for (t=0;t<g->nobjs;t++)
							{
								obj = ((char *) g +offsets1[t]);
								obj_type =  g->objType[t];
								switch (obj_type)
								{
									case POINTTYPE:
													pt = (POINT3D*) obj ;
													geoms[t] = PostGIS2GEOS_point(pt,g->SRID,g->is3d);
													if (geoms[t] == NULL)
													{
														pfree(geoms);
														elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
														return NULL;
													}
													break;
									case LINETYPE:
													line = (LINE3D*) obj ;
													geoms[t] = PostGIS2GEOS_linestring(line,g->SRID,g->is3d);
													if (geoms[t] == NULL)
													{
														pfree(geoms);
														elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
														return NULL;
													}
													break;
									case POLYGONTYPE:
													poly = (POLYGON3D*) obj ;
													geoms[t] = PostGIS2GEOS_polygon(poly,g->SRID,g->is3d);
													if (geoms[t] == NULL)
													{
														pfree(geoms);
														elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
														return NULL;
													}
													break;
								}
							}
							geos= PostGIS2GEOS_collection(geoms,g->nobjs,g->SRID,g->is3d);
							pfree(geoms);
							if (geos == NULL)
							{
								elog(ERROR,"Couldnt convert the postgis geometry to GEOS!");
							}
							return geos; 
							break;

	}
	return NULL;
}




//----------------------------------------------------------------------------
// NULL implementation here
// ---------------------------------------------------------------------------
#else


#include "postgres.h"


#include <math.h>
#include <float.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include "fmgr.h"


Datum relate_full(PG_FUNCTION_ARGS);
Datum relate_pattern(PG_FUNCTION_ARGS);
Datum disjoint(PG_FUNCTION_ARGS);
Datum touches(PG_FUNCTION_ARGS);
Datum intersects(PG_FUNCTION_ARGS);
Datum crosses(PG_FUNCTION_ARGS);
Datum within(PG_FUNCTION_ARGS);
Datum contains(PG_FUNCTION_ARGS);
Datum overlaps(PG_FUNCTION_ARGS);
Datum isvalid(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(relate_full);
Datum relate_full(PG_FUNCTION_ARGS)
{
	elog(ERROR,"relate_full:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(relate_pattern);
Datum relate_pattern(PG_FUNCTION_ARGS)
{
	elog(ERROR,"relate_pattern:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(disjoint);
Datum disjoint(PG_FUNCTION_ARGS)
{
	elog(ERROR,"disjoint:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(intersects);
Datum intersects(PG_FUNCTION_ARGS)
{
	elog(ERROR,"intersects:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(touches);
Datum touches(PG_FUNCTION_ARGS)
{
	elog(ERROR,"touches:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(crosses);
Datum crosses(PG_FUNCTION_ARGS)
{
	elog(ERROR,"crosses:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(within);
Datum within(PG_FUNCTION_ARGS)
{
	elog(ERROR,"within:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(contains);
Datum contains(PG_FUNCTION_ARGS)
{
	elog(ERROR,"contains:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(overlaps);
Datum overlaps(PG_FUNCTION_ARGS)
{
	elog(ERROR,"overlaps:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}
PG_FUNCTION_INFO_V1(isvalid);
Datum isvalid(PG_FUNCTION_ARGS)
{
	elog(ERROR,"isvalid:: operation not implemented - compile PostGIS with GEOS support");
	PG_RETURN_NULL(); // never get here
}

#endif



More information about the geos-devel mailing list