From 88e2cc7380b34bbe50e9e3ea3389453d862c35e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Br=C3=A9dif?= Date: Tue, 8 Mar 2016 12:16:29 +0100 Subject: [PATCH 1/3] pc_envelope testing, degenerate cases, pc_envelope_asbinary --- lib/cunit/cu_pc_patch.c | 21 ++++- lib/pc_api.h | 3 + lib/pc_util.c | 99 +++++++++++++++++++++ pgsql/expected/pointcloud.out | 4 +- pgsql/pc_inout.c | 10 +-- pgsql/pc_pgsql.c | 100 ---------------------- pgsql/pointcloud.sql.in | 4 +- pgsql/sql/pointcloud.sql | 2 +- pgsql_postgis/pointcloud_postgis--1.0.sql | 8 +- 9 files changed, 134 insertions(+), 117 deletions(-) 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..3c0c36f0 100644 --- a/pgsql/expected/pointcloud.out +++ b/pgsql/expected/pointcloud.out @@ -291,8 +291,8 @@ 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 \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'; From 27a38a0c1eccf29f5c39e7d7ed728c9eb7dca3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Br=C3=A9dif?= Date: Sat, 12 Mar 2016 09:38:51 +0100 Subject: [PATCH 2/3] Fixing expected PC_enveloppe_asbinary test --- pgsql/expected/pointcloud.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgsql/expected/pointcloud.out b/pgsql/expected/pointcloud.out index 3c0c36f0..a77d0a7a 100644 --- a/pgsql/expected/pointcloud.out +++ b/pgsql/expected/pointcloud.out @@ -294,7 +294,7 @@ SELECT PC_AsText(pa) FROM pa_test; SELECT PC_Envelope_AsBinary(pa) from pa_test; pc_envelope_asbinary ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - \x010300000001000000050000007b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f7b14ae47e17a943fb81e85eb51b89e3f + \x01010000007b14ae47e17a943fb81e85eb51b89e3f \x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f \x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f \x01030000000100000005000000b81e85eb51b8ae3fec51b81e85ebb13fb81e85eb51b8ae3f9a9999999999b93f0ad7a3703d0ab73f9a9999999999b93f0ad7a3703d0ab73fec51b81e85ebb13fb81e85eb51b8ae3fec51b81e85ebb13f From 6aedef75480ae43108080a4d96377fb2c044cfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathieu=20Br=C3=A9dif?= Date: Wed, 9 Mar 2016 16:47:31 +0100 Subject: [PATCH 3/3] readme --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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: