diff --git a/README.md b/README.md
index 5c6df95a..ca4b5c91 100644
--- a/README.md
+++ b/README.md
@@ -264,12 +264,12 @@ Now that you have created two tables, you'll see entries for them in the `pointc
>
> 1
-**PC_Envelope(p pcpatch)** returns **bytea**
+**PC_Envelope_AsBinary(p pcpatch)** returns **bytea**
> Return the OGC "well-known binary" format for *bounds* of the patch.
> Useful for performing intersection tests with geometries.
>
-> SELECT PC_Envelope(pa) FROM patches LIMIT 1;
+> SELECT PC_Envelope_AsBinary(pa) FROM patches LIMIT 1;
>
> \x0103000000010000000500000090c2f5285cbf5fc0e17a
> 14ae4781464090c2f5285cbf5fc0ec51b81e858b46400ad7
@@ -493,6 +493,11 @@ The `pointcloud_postgis` extension adds functions that allow you to use PostgreS
>
> POINT Z (-127 45 124)
+**PC_Envelope(pcpatch)** returns **geometry**
+**pcpatch::geometry** returns **geometry**
+
+> Get the PcPatch bounds as a PostGIS geometry
+
## Compressions ##
One of the issues with LIDAR data is that there is a lot of it. To deal with data volumes, PostgreSQL Pointcloud allows schemas to declare their preferred compression method in the `` block of the schema document. In the example schema, we declared our compression as follows:
diff --git a/lib/cunit/cu_pc_patch.c b/lib/cunit/cu_pc_patch.c
index a6a8f356..9137a69a 100644
--- a/lib/cunit/cu_pc_patch.c
+++ b/lib/cunit/cu_pc_patch.c
@@ -446,8 +446,11 @@ test_patch_wkb()
PCPOINTLIST *pl1;
PCPATCH_UNCOMPRESSED *pu1, *pu2;
PCPATCH *pa1, *pa2, *pa3, *pa4;
- size_t z1, z2;
- uint8_t *wkb1, *wkb2;
+ size_t z1, z2, z3;
+ uint8_t *wkb1, *wkb2, *wkb3, *hexwkb;
+
+ static char *hexresult_ndr = "01030000000100000005000000000000000000000000000000000000000000000000000000CDCCCCCCCC8C4B40EC51B81E852B4440CDCCCCCCCC8C4B40EC51B81E852B4440000000000000000000000000000000000000000000000000";
+ static char *hexresult_xdr = "00000000030000000100000005000000000000000000000000000000000000000000000000404B8CCCCCCCCCCD40442B851EB851EC404B8CCCCCCCCCCD40442B851EB851EC000000000000000000000000000000000000000000000000";
pl1 = pc_pointlist_make(npts);
@@ -466,6 +469,7 @@ test_patch_wkb()
// str = hexbytes_from_bytes(wkb1, z1);
// printf("str\n%s\n",str);
pa2 = pc_patch_from_wkb(simpleschema, wkb1, z1);
+ pcfree(wkb1);
// printf("pa2\n%s\n",pc_patch_to_string(pa2));
@@ -489,6 +493,18 @@ test_patch_wkb()
CU_ASSERT_EQUAL(pu1->npoints, pu2->npoints);
CU_ASSERT(memcmp(pu1->data, pu2->data, pu1->datasize) == 0);
+ wkb3 = pc_bounds_to_wkb(&pa1->bounds,simpleschema->srid,&z3);
+ hexwkb = hexbytes_from_bytes(wkb3,z3);
+ if ( machine_endian() == PC_NDR )
+ {
+ CU_ASSERT_STRING_EQUAL(hexwkb, hexresult_ndr);
+ }
+ else
+ {
+ CU_ASSERT_STRING_EQUAL(hexwkb, hexresult_xdr);
+ }
+ pcfree(hexwkb);
+ pcfree(wkb3);
pc_pointlist_free(pl1);
pc_patch_free(pa1);
@@ -497,7 +513,6 @@ test_patch_wkb()
pc_patch_free(pa4);
pc_patch_free((PCPATCH*)pu1);
pc_patch_free((PCPATCH*)pu2);
- pcfree(wkb1);
}
diff --git a/lib/pc_api.h b/lib/pc_api.h
index c1b84dce..49543e44 100644
--- a/lib/pc_api.h
+++ b/lib/pc_api.h
@@ -409,6 +409,9 @@ int pc_patch_compute_extent(PCPATCH *patch);
/** True/false if bounds intersect */
int pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2);
+/** Returns the bounds as an OGC WKB polygon */
+uint8_t *pc_bounds_to_wkb(const PCBOUNDS *bounds, uint32_t srid, size_t *wkbsize);
+
/** Subset batch based on less-than condition on dimension */
PCPATCH* pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name, double val);
diff --git a/lib/pc_util.c b/lib/pc_util.c
index a6a2c055..611b9e8b 100644
--- a/lib/pc_util.c
+++ b/lib/pc_util.c
@@ -263,3 +263,102 @@ void pc_bounds_merge(PCBOUNDS *b1, const PCBOUNDS *b2)
if ( b2->ymax > b1->ymax ) b1->ymax = b2->ymax;
}
+
+uint8_t *
+wkb_set_double(uint8_t *wkb, double d)
+{
+ memcpy(wkb, &d, 8);
+ wkb += 8;
+ return wkb;
+}
+
+uint8_t *
+wkb_set_uint32(uint8_t *wkb, uint32_t i)
+{
+ memcpy(wkb, &i, 4);
+ wkb += 4;
+ return wkb;
+}
+
+uint8_t *
+wkb_set_char(uint8_t *wkb, char c)
+{
+ memcpy(wkb, &c, 1);
+ wkb += 1;
+ return wkb;
+}
+
+uint8_t *
+pc_bounds_to_wkb(const PCBOUNDS *bounds, uint32_t srid, size_t *wkbsize)
+{
+ /* Bounds! */
+ double xmin = bounds->xmin;
+ double ymin = bounds->ymin;
+ double xmax = bounds->xmax;
+ double ymax = bounds->ymax;
+
+ static uint32_t srid_mask = 0x20000000;
+ static uint32_t nrings = 1;
+ static uint32_t npoints_by_type[] = { 0, 1, 2, 5 };
+ uint32_t wkbtype = 1 + (xmin!=xmax) + (ymin!=ymax); /* WKB POINT, LINESTRING or POLYGON */
+ uint32_t npoints = npoints_by_type[wkbtype];
+ uint8_t *wkb, *ptr;
+ size_t size = 1 + wkbtype*4 + npoints*2*8; /* endian + type + (nrings?) + (npoints?) + npoints dbl pt */
+
+ if ( srid )
+ {
+ wkbtype |= srid_mask;
+ size += 4;
+ }
+
+ if ( wkbsize ) *wkbsize = size;
+ wkb = pcalloc(size);
+ ptr = wkb;
+
+ ptr = wkb_set_char(ptr, machine_endian()); /* Endian flag */
+
+ ptr = wkb_set_uint32(ptr, wkbtype); /* TYPE = POINT, LINESTRING or POLYGON */
+
+ if ( srid )
+ {
+ ptr = wkb_set_uint32(ptr, srid); /* SRID */
+ }
+
+
+ switch( npoints )
+ {
+ case 5 : ptr = wkb_set_uint32(ptr, nrings); /* NRINGS = 1 */
+ case 2 : ptr = wkb_set_uint32(ptr, npoints); /* NPOINTS = 1, 2 or 5 */
+ }
+
+ /* Point 0 */
+ ptr = wkb_set_double(ptr, xmin);
+ ptr = wkb_set_double(ptr, ymin);
+
+ if(npoints==2) // LINESTRING
+ {
+ /* Point 1 */
+ ptr = wkb_set_double(ptr, xmax);
+ ptr = wkb_set_double(ptr, ymax);
+ }
+ else if(npoints==5) // POLYGON
+ {
+ /* Point 1 */
+ ptr = wkb_set_double(ptr, xmin);
+ ptr = wkb_set_double(ptr, ymax);
+
+ /* Point 2 */
+ ptr = wkb_set_double(ptr, xmax);
+ ptr = wkb_set_double(ptr, ymax);
+
+ /* Point 3 */
+ ptr = wkb_set_double(ptr, xmax);
+ ptr = wkb_set_double(ptr, ymin);
+
+ /* Point 4 */
+ ptr = wkb_set_double(ptr, xmin);
+ ptr = wkb_set_double(ptr, ymin);
+ }
+
+ return wkb;
+}
diff --git a/pgsql/expected/pointcloud.out b/pgsql/expected/pointcloud.out
index bd0a06ce..a77d0a7a 100644
--- a/pgsql/expected/pointcloud.out
+++ b/pgsql/expected/pointcloud.out
@@ -291,10 +291,10 @@ SELECT PC_AsText(pa) FROM pa_test;
{"pcid":1,"pts":[[0.06,0.07,0.05,6],[0.09,0.1,0.05,10]]}
(4 rows)
-SELECT PC_Envelope(pa) from pa_test;
- pc_envelope
+SELECT PC_Envelope_AsBinary(pa) from pa_test;
+ pc_envelope_asbinary
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- \x010300000001000000050000007b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f
+ \x01010000007b14ae47e17a943fb81e85eb51b89e3f
\x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f
\x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f
\x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f
diff --git a/pgsql/pc_inout.c b/pgsql/pc_inout.c
index eeb5ae05..6675a604 100644
--- a/pgsql/pc_inout.c
+++ b/pgsql/pc_inout.c
@@ -31,7 +31,7 @@ Datum pcpoint_from_double_array(PG_FUNCTION_ARGS);
Datum pcpoint_as_text(PG_FUNCTION_ARGS);
Datum pcpatch_as_text(PG_FUNCTION_ARGS);
Datum pcpoint_as_bytea(PG_FUNCTION_ARGS);
-Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS);
+Datum pcpatch_envelope_as_bytea(PG_FUNCTION_ARGS);
static void
@@ -293,8 +293,8 @@ Datum pcpoint_as_bytea(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(wkb);
}
-PG_FUNCTION_INFO_V1(pcpatch_bytea_envelope);
-Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(pcpatch_envelope_as_bytea);
+Datum pcpatch_envelope_as_bytea(PG_FUNCTION_ARGS)
{
uint8 *bytes;
size_t bytes_size;
@@ -303,13 +303,13 @@ Datum pcpatch_bytea_envelope(PG_FUNCTION_ARGS)
SERIALIZED_PATCH *serpatch = PG_GETHEADER_SERPATCH_P(0);
PCSCHEMA *schema = pc_schema_from_pcid(serpatch->pcid, fcinfo);
- bytes = pc_patch_to_geometry_wkb_envelope(serpatch, schema, &bytes_size);
+ bytes = pc_bounds_to_wkb(&serpatch->bounds, schema->srid, &bytes_size);
wkb_size = VARHDRSZ + bytes_size;
wkb = palloc(wkb_size);
memcpy(VARDATA(wkb), bytes, bytes_size);
SET_VARSIZE(wkb, wkb_size);
- pfree(bytes);
+ pcfree(bytes);
PG_RETURN_BYTEA_P(wkb);
}
diff --git a/pgsql/pc_pgsql.c b/pgsql/pc_pgsql.c
index 44a749f0..f6e7d81d 100644
--- a/pgsql/pc_pgsql.c
+++ b/pgsql/pc_pgsql.c
@@ -895,103 +895,3 @@ pc_patch_deserialize(const SERIALIZED_PATCH *serpatch, const PCSCHEMA *schema)
pcerror("%s: unsupported compression type", __func__);
return NULL;
}
-
-
-static uint8_t *
-pc_patch_wkb_set_double(uint8_t *wkb, double d)
-{
- memcpy(wkb, &d, 8);
- wkb += 8;
- return wkb;
-}
-
-static uint8_t *
-pc_patch_wkb_set_int32(uint8_t *wkb, uint32_t i)
-{
- memcpy(wkb, &i, 8);
- wkb += 4;
- return wkb;
-}
-
-static uint8_t *
-pc_patch_wkb_set_char(uint8_t *wkb, char c)
-{
- memcpy(wkb, &c, 1);
- wkb += 1;
- return wkb;
-}
-
-static char
-machine_endian(void)
-{
- static int check_int = 1; /* dont modify this!!! */
- return *((char *) &check_int); /* 0 = big endian | xdr,
- * 1 = little endian | ndr */
-}
-
-uint8_t *
-pc_patch_to_geometry_wkb_envelope(const SERIALIZED_PATCH *pa, const PCSCHEMA *schema, size_t *wkbsize)
-{
- static uint32_t srid_mask = 0x20000000;
- static uint32_t nrings = 1;
- static uint32_t npoints = 5;
- uint32_t wkbtype = 3; /* WKB POLYGON */
- uint8_t *wkb, *ptr;
- int has_srid = false;
- size_t size = 1 + 4 + 4 + 4 + 2*npoints*8; /* endian + type + nrings + npoints + 5 dbl pts */
-
- /* Bounds! */
- double xmin = pa->bounds.xmin;
- double ymin = pa->bounds.ymin;
- double xmax = pa->bounds.xmax;
- double ymax = pa->bounds.ymax;
-
- /* Make sure they're slightly bigger than a point */
- if ( xmin == xmax ) xmax += xmax * 0.0000001;
- if ( ymin == ymax ) ymax += ymax * 0.0000001;
-
- if ( schema->srid > 0 )
- {
- has_srid = true;
- wkbtype |= srid_mask;
- size += 4;
- }
-
- wkb = palloc(size);
- ptr = wkb;
-
- ptr = pc_patch_wkb_set_char(ptr, machine_endian()); /* Endian flag */
-
- ptr = pc_patch_wkb_set_int32(ptr, wkbtype); /* TYPE = Polygon */
-
- if ( has_srid )
- {
- ptr = pc_patch_wkb_set_int32(ptr, schema->srid); /* SRID */
- }
-
- ptr = pc_patch_wkb_set_int32(ptr, nrings); /* NRINGS = 1 */
- ptr = pc_patch_wkb_set_int32(ptr, npoints); /* NPOINTS = 5 */
-
- /* Point 0 */
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.xmin);
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.ymin);
-
- /* Point 1 */
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.xmin);
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.ymax);
-
- /* Point 2 */
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.xmax);
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.ymax);
-
- /* Point 3 */
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.xmax);
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.ymin);
-
- /* Point 4 */
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.xmin);
- ptr = pc_patch_wkb_set_double(ptr, pa->bounds.ymin);
-
- if ( wkbsize ) *wkbsize = size;
- return wkb;
-}
\ No newline at end of file
diff --git a/pgsql/pointcloud.sql.in b/pgsql/pointcloud.sql.in
index b2cc7a82..a4c32260 100644
--- a/pgsql/pointcloud.sql.in
+++ b/pgsql/pointcloud.sql.in
@@ -194,8 +194,8 @@ CREATE OR REPLACE FUNCTION PC_AsText(p pcpatch)
RETURNS text AS 'MODULE_PATHNAME', 'pcpatch_as_text'
LANGUAGE 'c' IMMUTABLE STRICT;
-CREATE OR REPLACE FUNCTION PC_Envelope(p pcpatch)
- RETURNS bytea AS 'MODULE_PATHNAME', 'pcpatch_bytea_envelope'
+CREATE OR REPLACE FUNCTION PC_Envelope_AsBinary(p pcpatch)
+ RETURNS bytea AS 'MODULE_PATHNAME', 'pcpatch_envelope_as_bytea'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_Uncompress(p pcpatch)
diff --git a/pgsql/sql/pointcloud.sql b/pgsql/sql/pointcloud.sql
index 0d295f55..d34d25d0 100644
--- a/pgsql/sql/pointcloud.sql
+++ b/pgsql/sql/pointcloud.sql
@@ -228,7 +228,7 @@ INSERT INTO pa_test (pa) VALUES ('0000000001000000000000000200000006000000070000
SELECT PC_Uncompress(pa) FROM pa_test LIMIT 1;
SELECT PC_AsText(pa) FROM pa_test;
-SELECT PC_Envelope(pa) from pa_test;
+SELECT PC_Envelope_AsBinary(pa) from pa_test;
SELECT PC_AsText(PC_Union(pa)) FROM pa_test;
SELECT sum(PC_NumPoints(pa)) FROM pa_test;
diff --git a/pgsql_postgis/pointcloud_postgis--1.0.sql b/pgsql_postgis/pointcloud_postgis--1.0.sql
index 872d1365..18ac3fa1 100644
--- a/pgsql_postgis/pointcloud_postgis--1.0.sql
+++ b/pgsql_postgis/pointcloud_postgis--1.0.sql
@@ -16,14 +16,14 @@ CREATE OR REPLACE FUNCTION PC_Intersection(pcpatch, geometry)
-----------------------------------------------------------------------------
-- Cast from pcpatch to polygon
--
-CREATE OR REPLACE FUNCTION geometry(pcpatch)
+CREATE OR REPLACE FUNCTION PC_Envelope(pcpatch)
RETURNS geometry AS
$$
- SELECT ST_GeomFromEWKB(PC_Envelope($1))
+ SELECT ST_GeomFromEWKB(PC_Envelope_AsBinary($1))
$$
LANGUAGE 'sql';
-CREATE CAST (pcpatch AS geometry) WITH FUNCTION geometry(pcpatch);
+CREATE CAST (pcpatch AS geometry) WITH FUNCTION PC_Envelope(pcpatch);
-----------------------------------------------------------------------------
-- Cast from pcpoint to point
@@ -44,7 +44,7 @@ CREATE CAST (pcpoint AS geometry) WITH FUNCTION geometry(pcpoint);
CREATE OR REPLACE FUNCTION PC_Intersects(pcpatch, geometry)
RETURNS boolean AS
$$
- SELECT ST_Intersects($2, geometry($1))
+ SELECT ST_Intersects($2, PC_Envelope($1))
$$
LANGUAGE 'sql';