FUNC: KEEPING FUNCTION: [envelope(geometry)]
FUNC: KEEPING FUNCTION: [equals(geometry, geometry)]
+
FUNC: KEEPING FUNCTION: [expand(geometry, double precision)]
+FUNC: KEEPING FUNCTION: [expand(box3d, double precision)]
+
FUNC: KEEPING FUNCTION: [isempty(geometry)]
FUNC: KEEPING FUNCTION: [segmentize(geometry, double precision)]
FUNC: KEEPING FUNCTION: [unite_garray(geometry[])]
FNCAST: KEEPING FNCAST geometry(chip) (see CAST)
--- BOX3D
-FUNC: KEEPING FUNCTION: [box3d_in(cstring)]
-FUNC: KEEPING FUNCTION: [box3d_out(box3d)]
-TYPE: KEEPING TYPE [box3d]
FUNC: KEEPING FUNCTION: [xmax(box3d)]
FUNC: KEEPING FUNCTION: [xmin(box3d)]
FUNC: KEEPING FUNCTION: [ymax(box3d)]
FUNC: KEEPING FUNCTION: [box3d(geometry)]
FUNC: KEEPING FUNCTION: [box3dtobox(box3d)]
FUNC: KEEPING FUNCTION: [combine_bbox(box3d, geometry)]
-FUNC: KEEPING FUNCTION: [expand(box3d, double precision)]
FUNC: KEEPING FUNCTION: [geometry(box3d)]
override CFLAGS += -DUSE_STATS
endif
-OBJS=lwgeom_pg.o lwgeom_spheroid.o lwgeom_api.o lwgeom_ogc.o lwgeom_functions_analytic.o lwgeom_geos.o lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o lwgeom_box2dfloat4.o lex.yy.o wktparse.tab.o lwgparse.o wktunparse.o $(GEOS_WRAPPER)
+OBJS=lwgeom_pg.o lwgeom_spheroid.o lwgeom_api.o lwgeom_ogc.o lwgeom_functions_analytic.o lwgeom_geos.o lwgeom_inout.o lwgeom_estimate.o lwgeom_functions_basic.o lwgeom_gist.o lwgeom_btree.o lwgeom_transform.o stringBuffer.o lwgeom_box3d.o lwgeom_box2dfloat4.o lex.yy.o wktparse.tab.o lwgparse.o wktunparse.o $(GEOS_WRAPPER)
OTHERS=y.output lex.yy.c wktparse.tab.c wktparse.tab.h lwgeom.sql lwpostgis.sql
extern BOX2DFLOAT4 *box_to_box2df(BOX *box); // postgresql standard type
extern BOX3D box2df_to_box3d(BOX2DFLOAT4 *box);
+extern void box2df_to_box3d_p(BOX2DFLOAT4 *box, BOX3D *box3d);
+
extern BOX box2df_to_box(BOX2DFLOAT4 *box); // postgresql standard type
extern BOX3D *combine_boxes(BOX3D *b1, BOX3D *b2);
extern BOX2DFLOAT4 getbox2d(char *serialized_form);
extern void getbox2d_p(char *serialized_form, BOX2DFLOAT4 *box);
+// Expand given box of 'd' units in all directions
+void expand_box2d(BOX2DFLOAT4 *box, double d);
+void expand_box3d(BOX3D *box, double d);
+
//****************************************************************
// memory management -- these only delete the memory associated
// directly with the structure - NOT the stuff pointing into
Datum box2d_inter(PG_FUNCTION_ARGS);
Datum box2d_union(PG_FUNCTION_ARGS);
-
Datum gist_lwgeom_compress(PG_FUNCTION_ARGS);
Datum gist_lwgeom_consistent(PG_FUNCTION_ARGS);
Datum gist_rtree_decompress(PG_FUNCTION_ARGS);
extern BOX3D *lw_geom_getBB_simple(char *serialized_form);
+extern float nextDown_f(double d);
+extern float nextUp_f(double d);
+extern double nextDown_d(float d);
+extern double nextUp_d(float d);
+
#if ! defined(__MINGW32__)
//forward decs
-extern float nextDown_f(double d);
-extern float nextUp_f(double d);
-extern double nextDown_d(float d);
-extern double nextUp_d(float d);
extern BOX3D *lw_geom_getBB_simple(char *serialized_form);
}
// convert BOX2D to BOX3D
+// zmin and zmax are set to 0.0
BOX3D box2df_to_box3d(BOX2DFLOAT4 *box)
{
BOX3D result;
if (box == NULL)
return result;
- result.xmin = nextDown_d(box->xmin);
- result.ymin = nextDown_d(box->ymin);
+ result.xmin = box->xmin;
+ result.ymin = box->ymin;
- result.xmax = nextUp_d(box->xmax);
- result.ymax = nextUp_d(box->ymax);
+ result.xmax = box->xmax;
+ result.ymax = box->ymax;
+
+ result.zmin = result.zmax = 0.0;
return result;
}
+// convert BOX2D to BOX3D, using pre-allocated BOX3D as output
+// Z values are set to 0.0.
+void box2df_to_box3d_p(BOX2DFLOAT4 *box, BOX3D *out)
+{
+ if (box == NULL) return;
+
+ out->xmin = box->xmin;
+ out->ymin = box->ymin;
+
+ out->xmax = box->xmax;
+ out->ymax = box->ymax;
+
+ out->zmin = out->zmax = 0.0;
+}
+
// convert BOX2D to postgresql BOX
BOX box2df_to_box(BOX2DFLOAT4 *box)
//********************************************************************
// basic polygon manipulation
-// construct a new LWLINE. arrays (points/points per ring) will NOT be copied
+// construct a new LWPOLY. arrays (points/points per ring) will NOT be copied
// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
LWPOLY *lwpoly_construct(int ndims, int SRID, int nrings,POINTARRAY **points)
{
// points copied
char *lwpoly_serialize(LWPOLY *poly)
{
- int size=1; // type byte
- char hasSRID;
- char *result;
- int t,u;
- int total_points = 0;
- int npoints;
- char *loc;
+ int size=1; // type byte
+ char hasSRID;
+ char *result;
+ int t,u;
+ int total_points = 0;
+ int npoints;
+ char *loc;
- hasSRID = (poly->SRID != -1);
+ hasSRID = (poly->SRID != -1);
- if (hasSRID)
- size +=4; //4 byte SRID
+ if (hasSRID)
+ size +=4; //4 byte SRID
- size += 4; // nrings
- size += 4*poly->nrings; //npoints/ring
+ size += 4; // nrings
+ size += 4*poly->nrings; //npoints/ring
- for (t=0;t<poly->nrings;t++)
- {
- total_points += poly->rings[t]->npoints;
- }
- if (poly->ndims == 3)
- size += 24*total_points;
- else if (poly->ndims == 2)
- size += 16*total_points;
- else if (poly->ndims == 4)
- size += 32*total_points;
+ for (t=0;t<poly->nrings;t++)
+ {
+ total_points += poly->rings[t]->npoints;
+ }
+ if (poly->ndims == 3)
+ size += 24*total_points;
+ else if (poly->ndims == 2)
+ size += 16*total_points;
+ else if (poly->ndims == 4)
+ size += 32*total_points;
- result = palloc(size);
+ result = palloc(size);
- result[0] = (unsigned char) lwgeom_makeType(poly->ndims,hasSRID, POLYGONTYPE);
- loc = result+1;
+ result[0] = (unsigned char) lwgeom_makeType(poly->ndims,hasSRID, POLYGONTYPE);
+ loc = result+1;
- if (hasSRID)
- {
- memcpy(loc, &poly->SRID, sizeof(int32));
- loc += 4;
- }
+ if (hasSRID)
+ {
+ memcpy(loc, &poly->SRID, sizeof(int32));
+ loc += 4;
+ }
- memcpy(loc, &poly->nrings, sizeof(int32)); // nrings
- loc+=4;
+ memcpy(loc, &poly->nrings, sizeof(int32)); // nrings
+ loc+=4;
- for (t=0;t<poly->nrings;t++)
+ for (t=0;t<poly->nrings;t++)
+ {
+ POINTARRAY *pa = poly->rings[t];
+ npoints = poly->rings[t]->npoints;
+ memcpy(loc, &npoints, sizeof(int32)); //npoints this ring
+ loc+=4;
+ if (poly->ndims == 3)
{
- POINTARRAY *pa = poly->rings[t];
- npoints = poly->rings[t]->npoints;
- memcpy(loc, &npoints, sizeof(int32)); //npoints this ring
- loc+=4;
- if (poly->ndims == 3)
+ for (u=0;u<npoints;u++)
{
- for (u=0;u<npoints;u++)
- {
- getPoint3d_p(pa, u, loc);
- loc+= 24;
- }
+ getPoint3d_p(pa, u, loc);
+ loc+= 24;
}
- else if (poly->ndims == 2)
+ }
+ else if (poly->ndims == 2)
+ {
+ for (u=0;u<npoints;u++)
{
- for (u=0;u<npoints;u++)
- {
- getPoint2d_p(pa, u, loc);
- loc+= 16;
- }
+ getPoint2d_p(pa, u, loc);
+ loc+= 16;
}
- else if (poly->ndims == 4)
+ }
+ else if (poly->ndims == 4)
+ {
+ for (u=0;u<npoints;u++)
{
- for (u=0;u<npoints;u++)
- {
- getPoint4d_p(pa, u, loc);
- loc+= 32;
- }
+ getPoint4d_p(pa, u, loc);
+ loc+= 32;
}
}
+ }
- return result;
+ return result;
}
// create the serialized form of the polygon writing it into the
// basic implementation of BOX2D
- //forward defs
+//forward defs
Datum BOX2DFLOAT4_in(PG_FUNCTION_ARGS);
Datum BOX2DFLOAT4_out(PG_FUNCTION_ARGS);
Datum LWGEOM_to_BOX2DFLOAT4(PG_FUNCTION_ARGS);
+Datum BOX2DFLOAT4_expand(PG_FUNCTION_ARGS);
+Datum BOX2DFLOAT4_to_BOX3D(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(BOX2DFLOAT4_in);
Datum BOX2DFLOAT4_in(PG_FUNCTION_ARGS)
{
- char *str = PG_GETARG_CSTRING(0);
- int nitems;
- BOX2DFLOAT4 *box = (BOX2DFLOAT4 *) palloc(sizeof(BOX2DFLOAT4));
+ char *str = PG_GETARG_CSTRING(0);
+ int nitems;
+ BOX2DFLOAT4 *box = (BOX2DFLOAT4 *) palloc(sizeof(BOX2DFLOAT4));
//printf( "box3d_in gets '%s'\n",str);
- if (strstr(str,"BOX(") != str )
- {
- pfree(box);
- elog(ERROR,"BOX2DFLOAT4 parser - doesnt start with BOX(");
- PG_RETURN_NULL();
- }
- nitems = sscanf(str,"BOX(%f %f,%f %f)", &box->xmin,&box->ymin,&box->xmax,&box->ymax);
- if (nitems != 4)
- {
- pfree(box);
- elog(ERROR,"BOX2DFLOAT4 parser - couldnt parse. It should look like: BOX(xmin ymin,xmax ymax)");
- PG_RETURN_NULL();
- }
-
- if (box->xmin > box->xmax)
- {
- float tmp = box->xmin;
- box->xmin = box->xmax;
- box->xmax = tmp;
- }
- if (box->ymin > box->ymax)
- {
- float tmp = box->ymin;
- box->ymin = box->ymax;
- box->ymax = tmp;
- }
- PG_RETURN_POINTER(box);
+ if (strstr(str,"BOX(") != str )
+ {
+ pfree(box);
+ elog(ERROR,"BOX2DFLOAT4 parser - doesnt start with BOX(");
+ PG_RETURN_NULL();
+ }
+ nitems = sscanf(str,"BOX(%f %f,%f %f)", &box->xmin,&box->ymin,&box->xmax,&box->ymax);
+ if (nitems != 4)
+ {
+ pfree(box);
+ elog(ERROR,"BOX2DFLOAT4 parser - couldnt parse. It should look like: BOX(xmin ymin,xmax ymax)");
+ PG_RETURN_NULL();
+ }
+
+ if (box->xmin > box->xmax)
+ {
+ float tmp = box->xmin;
+ box->xmin = box->xmax;
+ box->xmax = tmp;
+ }
+ if (box->ymin > box->ymax)
+ {
+ float tmp = box->ymin;
+ box->ymin = box->ymax;
+ box->ymax = tmp;
+ }
+ PG_RETURN_POINTER(box);
}
//writer "BOX(xmin ymin,xmax ymax)"
}
+/* Expand given box of 'd' units in all directions */
+void
+expand_box2d(BOX2DFLOAT4 *box, double d)
+{
+ box->xmin -= d;
+ box->ymin -= d;
+
+ box->xmax += d;
+ box->ymax += d;
+}
+PG_FUNCTION_INFO_V1(BOX2DFLOAT4_expand);
+Datum BOX2DFLOAT4_expand(PG_FUNCTION_ARGS)
+{
+ BOX2DFLOAT4 *box = (BOX2DFLOAT4 *)PG_GETARG_POINTER(0);
+ double d = PG_GETARG_FLOAT8(1);
+ BOX2DFLOAT4 *result = (BOX2DFLOAT4 *)palloc(sizeof(BOX2DFLOAT4));
+ memcpy(result, box, sizeof(BOX2DFLOAT4));
+ expand_box2d(result, d);
+
+ PG_RETURN_POINTER(result);
+}
+
+PG_FUNCTION_INFO_V1(BOX2DFLOAT4_to_BOX3D);
+Datum BOX2DFLOAT4_to_BOX3D(PG_FUNCTION_ARGS)
+{
+ BOX2DFLOAT4 *box = (BOX2DFLOAT4 *)PG_GETARG_POINTER(0);
+ BOX3D *result = palloc(sizeof(BOX3D));
+
+ box2df_to_box3d_p(box, result);
+
+ PG_RETURN_POINTER(result);
+}
--- /dev/null
+/**********************************************************************
+ *
+ * BOX3D IO and conversions
+ *
+ **********************************************************************/
+
+#include "postgres.h"
+
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "fmgr.h"
+#include "utils/elog.h"
+
+#include "lwgeom.h"
+
+
+//#define DEBUG
+// basic implementation of BOX2D
+
+#define SHOW_DIGS_DOUBLE 15
+#define MAX_DIGS_DOUBLE (SHOW_DIGS_DOUBLE + 6 + 1 + 3 +1)
+
+//forward defs
+Datum BOX3D_in(PG_FUNCTION_ARGS);
+Datum BOX3D_out(PG_FUNCTION_ARGS);
+Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS);
+Datum BOX3D_expand(PG_FUNCTION_ARGS);
+Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS);
+
+/*
+ * BOX3D_in - takes a string rep of BOX3D and returns internal rep
+ *
+ * example:
+ * "BOX3D(x1 y1 z1,x2 y2 z2)"
+ * or "BOX3D(x1 y1,x2 y2)" z1 and z2 = 0.0
+ *
+ *
+ */
+
+PG_FUNCTION_INFO_V1(BOX3D_in);
+Datum BOX3D_in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ int nitems;
+ BOX3D *box = (BOX3D *) palloc(sizeof(BOX3D));
+ box->zmin = 0;
+ box->zmax = 0;
+
+
+//printf( "box3d_in gets '%s'\n",str);
+
+ if (strstr(str,"BOX3D(") != str )
+ {
+ pfree(box);
+ elog(ERROR,"BOX3D parser - doesnt start with BOX3D(");
+ PG_RETURN_NULL();
+ }
+
+ nitems = sscanf(str,"BOX3D(%le %le %le,%le %le %le)",
+ &box->xmin, &box->ymin, &box->zmin,
+ &box->xmax, &box->ymax, &box->zmax);
+ if (nitems != 6 )
+ {
+ nitems = sscanf(str,"BOX3D(%le %le,%le %le)",
+ &box->xmin, &box->ymin, &box->xmax, &box->ymax);
+ if (nitems != 4)
+ {
+ pfree(box);
+ elog(ERROR,"BOX3D parser - couldnt parse. It should look like: BOX3D(xmin ymin zmin,xmax ymax zmax) or BOX3D(xmin ymin,xmax ymax)");
+ PG_RETURN_NULL();
+ }
+ }
+
+ if (box->xmin > box->xmax)
+ {
+ float tmp = box->xmin;
+ box->xmin = box->xmax;
+ box->xmax = tmp;
+ }
+ if (box->ymin > box->ymax)
+ {
+ float tmp = box->ymin;
+ box->ymin = box->ymax;
+ box->ymax = tmp;
+ }
+ if (box->zmin > box->zmax)
+ {
+ float tmp = box->zmin;
+ box->zmin = box->zmax;
+ box->zmax = tmp;
+ }
+ PG_RETURN_POINTER(box);
+}
+
+
+/*
+ * Takes an internal rep of a BOX3D and returns a string rep.
+ *
+ * example:
+ * "BOX3D(xmin ymin zmin, xmin ymin zmin)"
+ */
+PG_FUNCTION_INFO_V1(BOX3D_out);
+Datum BOX3D_out(PG_FUNCTION_ARGS)
+{
+ BOX3D *bbox = (BOX3D *) PG_GETARG_POINTER(0);
+ int size;
+ char *result;
+
+ if (bbox == NULL)
+ {
+ result = palloc(5);
+ strcat(result,"NULL");
+ PG_RETURN_CSTRING(result);
+ }
+
+ size = MAX_DIGS_DOUBLE*6+5+2+4+5+1;
+ result = (char *) palloc(size); //double digits+ "BOX3D"+ "()" + commas +null
+ sprintf(result, "BOX3D(%.15g %.15g %.15g,%.15g %.15g %.15g)",
+ bbox->xmin, bbox->ymin, bbox->zmin,
+ bbox->xmax,bbox->ymax,bbox->zmax);
+
+ PG_RETURN_CSTRING(result);
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_to_BOX2DFLOAT4);
+Datum BOX3D_to_BOX2DFLOAT4(PG_FUNCTION_ARGS)
+{
+ BOX3D *in = (BOX3D *)PG_GETARG_POINTER(0);
+ BOX2DFLOAT4 *out = box3d_to_box2df(in);
+ PG_RETURN_POINTER(out);
+}
+
+/* Expand given box of 'd' units in all directions */
+void
+expand_box3d(BOX3D *box, double d)
+{
+ box->xmin -= d;
+ box->ymin -= d;
+ box->zmin -= d;
+
+ box->xmax += d;
+ box->ymax += d;
+ box->zmax += d;
+}
+
+PG_FUNCTION_INFO_V1(BOX3D_expand);
+Datum BOX3D_expand(PG_FUNCTION_ARGS)
+{
+ BOX3D *box = (BOX3D *)PG_GETARG_POINTER(0);
+ double d = PG_GETARG_FLOAT8(1);
+ BOX3D *result = (BOX3D *)palloc(sizeof(BOX3D));
+
+ memcpy(result, box, sizeof(BOX3D));
+ expand_box3d(result, d);
+
+ PG_RETURN_POINTER(result);
+}
+
+//convert a LWGEOM to BOX3D
+PG_FUNCTION_INFO_V1(LWGEOM_to_BOX3D);
+Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
+{
+ LWGEOM *lwgeom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ BOX2DFLOAT4 box;
+ BOX3D *result = palloc(sizeof(BOX3D));
+
+ getbox2d_p(SERIALIZED_FORM(lwgeom), &box);
+ box2df_to_box3d_p(&box, result);
+
+ PG_RETURN_POINTER(result);
+}
Datum LWGEOM_collect(PG_FUNCTION_ARGS);
Datum LWGEOM_accum(PG_FUNCTION_ARGS);
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
+Datum LWGEOM_expand(PG_FUNCTION_ARGS);
// internal
char * lwgeom_summary_recursive(char *serialized, int offset);
PG_RETURN_POINTER( result );
}
+
+// makes a polygon of the expanded features bvol - 1st point = LL 3rd=UR
+// 2d only. (3d might be worth adding).
+// create new geometry of type polygon, 1 ring, 5 points
+PG_FUNCTION_INFO_V1(LWGEOM_expand);
+Datum LWGEOM_expand(PG_FUNCTION_ARGS)
+{
+ LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ double d = PG_GETARG_FLOAT8(1);
+ BOX2DFLOAT4 box;
+ POINT2D *pts = palloc(sizeof(POINT2D)*5);
+ POINTARRAY *pa[1];
+ LWPOLY *poly;
+ int SRID;
+ LWGEOM *result;
+ char *ser;
+
+ // get geometry box and SRID
+ getbox2d_p(SERIALIZED_FORM(geom), &box);
+ SRID = lwgeom_getsrid(SERIALIZED_FORM(geom));
+
+ // expand it
+ expand_box2d(&box, d);
+
+ // Assign coordinates to POINT2D array
+ pts[0].x = box.xmin; pts[0].y = box.ymin;
+ pts[1].x = box.xmin; pts[1].y = box.ymax;
+ pts[2].x = box.xmax; pts[2].y = box.ymax;
+ pts[3].x = box.xmax; pts[3].y = box.ymin;
+ pts[4].x = box.xmin; pts[4].y = box.ymin;
+
+ // Construct point array
+ pa[0] = palloc(sizeof(POINTARRAY));
+ pa[0]->serialized_pointlist = (char *)pts;
+ pa[0]->ndims = 2;
+ pa[0]->npoints = 5;
+
+ // Construct polygon
+ poly = lwpoly_construct(2, SRID, 1, pa);
+
+ // Serialize polygon
+ ser = lwpoly_serialize(poly);
+
+ // Construct LWGEOM
+ result = LWGEOM_construct(ser, SRID, lwgeom_hasBBOX(geom->type));
+
+ PG_RETURN_POINTER(result);
+}
storage = main
);
+
+CREATEFUNCTION geometry(text)
+ RETURNS geometry
+ AS '@MODULE_FILENAME@','parse_WKT_lwgeom'
+ LANGUAGE 'C' WITH (isstrict,iscachable);
+
+-------------------------------------------------------------------
+-- BOX3D TYPE
+-------------------------------------------------------------------
+
+#if USE_VERSION < 73
+# define BOX3D_IN_REP opaque
+# define BOX3D_OUT_REP opaque
+#else
+# define BOX3D_IN_REP box3d
+# define BOX3D_OUT_REP cstring
+#endif
+
+CREATEFUNCTION box3d_in(BOX3D_OUT_REP)
+ RETURNS BOX3D_IN_REP
+ AS '@MODULE_FILENAME@', 'BOX3D_in'
+ LANGUAGE 'C' WITH (isstrict);
+
+CREATEFUNCTION box3d_out(BOX3D_IN_REP)
+ RETURNS BOX3D_OUT_REP
+ AS '@MODULE_FILENAME@', 'BOX3D_out'
+ LANGUAGE 'C' WITH (isstrict);
+
+CREATE TYPE box3d (
+ alignment = double,
+ internallength = 48,
+ input = box3d_in,
+ output = box3d_out
+);
-----------------------------------------------------------------------
--
storage = plain
);
-CREATEFUNCTION box2d(geometry)
- RETURNS box2d
- AS '@MODULE_FILENAME@','LWGEOM_to_BOX2DFLOAT4'
- LANGUAGE 'C' WITH (isstrict,iscachable);
-
-
-
-
-CREATEFUNCTION geometry(text)
- RETURNS geometry
- AS '@MODULE_FILENAME@','parse_WKT_lwgeom'
- LANGUAGE 'C' WITH (isstrict,iscachable);
-
---- BOX2D support functions
finalfunc = collect_garray
);
+CREATEFUNCTION expand(box3d,float8)
+ RETURNS box3d
+ AS '@MODULE_FILENAME@', 'BOX3D_expand'
+ LANGUAGE 'C' WITH (iscachable,isstrict);
+
+CREATEFUNCTION expand(box2d,float8)
+ RETURNS box2d
+ AS '@MODULE_FILENAME@', 'BOX2DFLOAT4_expand'
+ LANGUAGE 'C' WITH (iscachable,isstrict);
+
+CREATEFUNCTION expand(geometry,float8)
+ RETURNS geometry
+ AS '@MODULE_FILENAME@', 'LWGEOM_expand'
+ LANGUAGE 'C' WITH (iscachable,isstrict);
+
------------------------------------------------------------------------
--
END
' LANGUAGE 'plpgsql';
+---------------------------------------------------------------
+-- CASTS
+---------------------------------------------------------------
+
+CREATEFUNCTION box2d(geometry)
+ RETURNS box2d
+ AS '@MODULE_FILENAME@','LWGEOM_to_BOX2DFLOAT4'
+ LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE CAST (geometry as box2d) WITH FUNCTION box2d(geometry) AS IMPLICIT ;
+
+CREATEFUNCTION box3d(geometry)
+ RETURNS box3d
+ AS '@MODULE_FILENAME@','LWGEOM_to_BOX3D'
+ LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE CAST (geometry as box3d) WITH FUNCTION box3d(geometry) AS IMPLICIT ;
+
+CREATEFUNCTION box2d(box3d)
+ RETURNS box2d
+ AS '@MODULE_FILENAME@','BOX3D_to_BOX2DFLOAT4'
+ LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE CAST (box3d as box2d) WITH FUNCTION box2d(box3d) AS IMPLICIT ;
+
+CREATEFUNCTION box3d(box2d)
+ RETURNS box3d
+ AS '@MODULE_FILENAME@','BOX2DFLOAT4_to_BOX3D'
+ LANGUAGE 'C' WITH (isstrict,iscachable);
+
+CREATE CAST (box2d as box3d) WITH FUNCTION box3d(box2d) AS IMPLICIT ;
+
---------------------------------------------------------------
-- END
---------------------------------------------------------------