diff --git a/.gitignore b/.gitignore
index d71adf6e..3fba0510 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ Makefile
*/*/Makefile
pgsql/pointcloud.control
pgsql/pointcloud--*
+pgsql_postgis/pointcloud_postgis--*.sql
+pgsql_postgis/pointcloud_postgis.control
diff --git a/README.md b/README.md
index 795bea5c..1df4448e 100644
--- a/README.md
+++ b/README.md
@@ -276,12 +276,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
@@ -519,6 +519,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 5da8161e..b065a0d8 100644
--- a/lib/cunit/cu_pc_patch.c
+++ b/lib/cunit/cu_pc_patch.c
@@ -454,8 +454,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);
@@ -474,6 +477,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));
@@ -497,6 +501,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_geometry_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);
@@ -505,7 +521,6 @@ test_patch_wkb()
pc_patch_free(pa4);
pc_patch_free((PCPATCH*)pu1);
pc_patch_free((PCPATCH*)pu2);
- pcfree(wkb1);
}
diff --git a/lib/cunit/cu_pc_schema.c b/lib/cunit/cu_pc_schema.c
index c09b7e17..5bbf077c 100644
--- a/lib/cunit/cu_pc_schema.c
+++ b/lib/cunit/cu_pc_schema.c
@@ -205,9 +205,9 @@ test_schema_clone(void)
pc_schema_free(clone);
/* See https://github.com/pgpointcloud/pointcloud/issues/66 */
- xmlstr = "1";
+ xmlstr = "1";
i = pc_schema_from_xml(xmlstr, &myschema);
- CU_ASSERT_EQUAL(i, PC_SUCCESS);
+ CU_ASSERT_EQUAL(i, PC_SUCCESS);
clone = pc_schema_clone(myschema);
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
CU_ASSERT_EQUAL(clone->dims[0]->name, NULL);
diff --git a/lib/pc_api.h b/lib/pc_api.h
index a8647912..7291a223 100644
--- a/lib/pc_api.h
+++ b/lib/pc_api.h
@@ -150,8 +150,19 @@ typedef struct
double xmax;
double ymin;
double ymax;
+ double zmin;
+ double zmax;
+ double mmin;
+ double mmax;
} PCBOUNDS;
+typedef struct
+{
+ double xmin, ymin, zmin;
+ double xmax, ymax, zmax;
+ int32_t srid;
+} PCBOX3D;
+
/* Used for generic patch statistics */
typedef struct
{
@@ -437,6 +448,12 @@ int pc_patch_compute_extent(PCPATCH *patch);
/** True/false if bounds intersect */
int pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2);
+/** Return the bounds as an OGC WKB geometry */
+uint8_t *pc_bounds_to_geometry_wkb(const PCBOUNDS *bounds, uint32_t srid, size_t *wkbsize);
+
+/** Return the bounds as a BOX3D */
+PCBOX3D *pc_bounds_to_box3d(const PCBOUNDS *bounds, uint32_t srid);
+
/** 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_api_internal.h b/lib/pc_api_internal.h
index be7d2a32..0e7e4d91 100644
--- a/lib/pc_api_internal.h
+++ b/lib/pc_api_internal.h
@@ -269,11 +269,13 @@ void pc_bytes_to_ptr(uint8_t *buf, PCBYTES pcb, int n);
*/
/** Initialize with very large mins and very small maxes */
-void pc_bounds_init(PCBOUNDS *b);
+void pc_bounds_init(PCBOUNDS *b, const PCSCHEMA *schema);
/** Copy a bounds */
PCSTATS* pc_stats_clone(const PCSTATS *stats);
/** Expand extents of b1 to encompass b2 */
void pc_bounds_merge(PCBOUNDS *b1, const PCBOUNDS *b2);
+/** Expand extents of b to encompass p */
+void pc_bounds_expand(PCBOUNDS *b, const PCPOINT *p);
/****************************************************************************
* BITMAPS
diff --git a/lib/pc_filter.c b/lib/pc_filter.c
index 7255b1e5..fc1fe965 100644
--- a/lib/pc_filter.c
+++ b/lib/pc_filter.c
@@ -165,7 +165,7 @@ pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map)
stats.max = pc_value_scale_offset(stats.max, dim);
stats.sum = pc_value_scale_offset(stats.sum, dim);
- /* Save the X/Y stats for use in bounds later */
+ /* Save the XYZM stats for use in bounds later */
if ( i == pdl->schema->x_position )
{
fpdl->bounds.xmin = stats.min;
@@ -176,6 +176,16 @@ pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map)
fpdl->bounds.ymin = stats.min;
fpdl->bounds.ymax = stats.max;
}
+ else if ( i == pdl->schema->z_position )
+ {
+ fpdl->bounds.zmin = stats.min;
+ fpdl->bounds.zmax = stats.max;
+ }
+ else if ( i == pdl->schema->m_position )
+ {
+ fpdl->bounds.mmin = stats.min;
+ fpdl->bounds.mmax = stats.max;
+ }
pc_point_set_double_by_index(&(fpdl->stats->min), i, stats.min);
pc_point_set_double_by_index(&(fpdl->stats->max), i, stats.max);
diff --git a/lib/pc_patch_dimensional.c b/lib/pc_patch_dimensional.c
index 840f44b1..8416e6f5 100644
--- a/lib/pc_patch_dimensional.c
+++ b/lib/pc_patch_dimensional.c
@@ -21,7 +21,7 @@ typedef struct
int8_t readonly;
const PCSCHEMA *schema;
uint32_t npoints;
- double xmin, xmax, ymin, ymax;
+ double xmin, xmax, ymin, ymax, zmin, zmax, mmin, mmax;
PCSTATS *stats;
PCBYTES *bytes;
} PCPATCH_DIMENSIONAL;
@@ -179,30 +179,54 @@ pc_patch_dimensional_free(PCPATCH_DIMENSIONAL *pdl)
int
pc_patch_dimensional_compute_extent(PCPATCH_DIMENSIONAL *pdl)
{
- double xmin, xmax, ymin, ymax, xavg, yavg;
+ double min, max, avg;
int rv;
PCBYTES *pcb;
assert(pdl);
assert(pdl->schema);
+ pc_bounds_init(&(pdl->bounds), pdl->schema);
+
/* Get x extremes */
- pcb = &(pdl->bytes[pdl->schema->x_position]);
- rv = pc_bytes_minmax(pcb, &xmin, &xmax, &xavg);
- if ( PC_FAILURE == rv ) return PC_FAILURE;
- xmin = pc_value_scale_offset(xmin, pdl->schema->dims[pdl->schema->x_position]);
- xmax = pc_value_scale_offset(xmax, pdl->schema->dims[pdl->schema->x_position]);
- pdl->bounds.xmin = xmin;
- pdl->bounds.xmax = xmax;
+ if(pdl->schema->x_position!=-1)
+ {
+ pcb = &(pdl->bytes[pdl->schema->x_position]);
+ rv = pc_bytes_minmax(pcb, &min, &max, &avg);
+ if ( PC_FAILURE == rv ) return PC_FAILURE;
+ pdl->bounds.xmin = pc_value_scale_offset(min, pdl->schema->dims[pdl->schema->x_position]);
+ pdl->bounds.xmax = pc_value_scale_offset(max, pdl->schema->dims[pdl->schema->x_position]);
+ }
/* Get y extremes */
- pcb = &(pdl->bytes[pdl->schema->y_position]);
- rv = pc_bytes_minmax(pcb, &ymin, &ymax, &yavg);
- if ( PC_FAILURE == rv ) return PC_FAILURE;
- ymin = pc_value_scale_offset(ymin, pdl->schema->dims[pdl->schema->y_position]);
- ymax = pc_value_scale_offset(ymax, pdl->schema->dims[pdl->schema->y_position]);
- pdl->bounds.ymin = ymin;
- pdl->bounds.ymax = ymax;
+ if(pdl->schema->y_position!=-1)
+ {
+ pcb = &(pdl->bytes[pdl->schema->y_position]);
+ rv = pc_bytes_minmax(pcb, &min, &max, &avg);
+ if ( PC_FAILURE == rv ) return PC_FAILURE;
+ pdl->bounds.ymin = pc_value_scale_offset(min, pdl->schema->dims[pdl->schema->y_position]);
+ pdl->bounds.ymax = pc_value_scale_offset(max, pdl->schema->dims[pdl->schema->y_position]);
+ }
+
+ /* Get z extremes */
+ if(pdl->schema->z_position!=-1)
+ {
+ pcb = &(pdl->bytes[pdl->schema->z_position]);
+ rv = pc_bytes_minmax(pcb, &min, &max, &avg);
+ if ( PC_FAILURE == rv ) return PC_FAILURE;
+ pdl->bounds.zmin = pc_value_scale_offset(min, pdl->schema->dims[pdl->schema->z_position]);
+ pdl->bounds.zmax = pc_value_scale_offset(max, pdl->schema->dims[pdl->schema->z_position]);
+ }
+
+ /* Get m extremes */
+ if(pdl->schema->m_position!=-1)
+ {
+ pcb = &(pdl->bytes[pdl->schema->m_position]);
+ rv = pc_bytes_minmax(pcb, &min, &max, &avg);
+ if ( PC_FAILURE == rv ) return PC_FAILURE;
+ pdl->bounds.mmin = pc_value_scale_offset(min, pdl->schema->dims[pdl->schema->m_position]);
+ pdl->bounds.mmax = pc_value_scale_offset(max, pdl->schema->dims[pdl->schema->m_position]);
+ }
return PC_SUCCESS;
}
diff --git a/lib/pc_patch_ght.c b/lib/pc_patch_ght.c
index 679af86b..4c514350 100644
--- a/lib/pc_patch_ght.c
+++ b/lib/pc_patch_ght.c
@@ -402,6 +402,12 @@ pc_patch_ght_compute_extent(PCPATCH_GHT *patch)
patch->bounds.ymin = area.y.min;
patch->bounds.ymax = area.y.max;
+ // provide a conservative non-discriminative bounding box
+ patch->bounds.zmin = -DBLMAX;
+ patch->bounds.zmax = DBLMAX;
+ patch->bounds.mmin = -DBLMAX;
+ patch->bounds.mmax = DBLMAX;
+
// ght_tree_free(tree);
return PC_SUCCESS;
diff --git a/lib/pc_patch_uncompressed.c b/lib/pc_patch_uncompressed.c
index 810f6e36..3fe147c8 100644
--- a/lib/pc_patch_uncompressed.c
+++ b/lib/pc_patch_uncompressed.c
@@ -180,7 +180,7 @@ pc_patch_uncompressed_make(const PCSCHEMA *s, uint32_t maxpoints)
{
pch->data = pcalloc(datasize);
}
- pc_bounds_init(&(pch->bounds));
+ pc_bounds_init(&(pch->bounds), s);
return pch;
}
@@ -190,24 +190,17 @@ pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch)
{
int i;
PCPOINT *pt = pc_point_from_data(patch->schema, patch->data);
- PCBOUNDS b;
- double x, y;
+ double v;
/* Calculate bounds */
- pc_bounds_init(&b);
+ pc_bounds_init(&(patch->bounds), patch->schema);
for ( i = 0; i < patch->npoints; i++ )
{
/* Just push the data buffer forward by one point at a time */
pt->data = patch->data + i * patch->schema->size;
- x = pc_point_get_x(pt);
- y = pc_point_get_y(pt);
- if ( b.xmin > x ) b.xmin = x;
- if ( b.ymin > y ) b.ymin = y;
- if ( b.xmax < x ) b.xmax = x;
- if ( b.ymax < y ) b.ymax = y;
+ pc_bounds_expand(&(patch->bounds),pt);
}
- patch->bounds = b;
pcfree(pt);
return PC_SUCCESS;
}
@@ -282,7 +275,7 @@ pc_patch_uncompressed_from_pointlist(const PCPOINTLIST *pl)
ptr = pch->data;
/* Initialize bounds */
- pc_bounds_init(&(pch->bounds));
+ pc_bounds_init(&(pch->bounds), s);
/* Set up basic info */
pch->readonly = PC_FALSE;
@@ -418,12 +411,7 @@ pc_patch_uncompressed_add_point(PCPATCH_UNCOMPRESSED *c, const PCPOINT *p)
c->npoints += 1;
/* Update bounding box */
- x = pc_point_get_x(p);
- y = pc_point_get_y(p);
- if ( c->bounds.xmin > x ) c->bounds.xmin = x;
- if ( c->bounds.ymin > y ) c->bounds.ymin = y;
- if ( c->bounds.xmax < x ) c->bounds.xmax = x;
- if ( c->bounds.ymax < y ) c->bounds.ymax = y;
+ pc_bounds_expand(&(c->bounds),p);
return PC_SUCCESS;
}
diff --git a/lib/pc_point.c b/lib/pc_point.c
index 35d539a4..56547450 100644
--- a/lib/pc_point.c
+++ b/lib/pc_point.c
@@ -329,6 +329,9 @@ pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize)
uint32_t srid = pt->schema->srid;
double x, y, z, m;
+ if (pt->schema->x_position < 0 || pt->schema->y_position < 0 )
+ return NULL;
+
if ( srid != 0 )
{
wkbtype |= srid_mask;
@@ -379,7 +382,7 @@ pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize)
if ( pt->schema->m_position > -1 )
{
- m = pc_point_get_z(pt);
+ m = pc_point_get_m(pt);
memcpy(ptr, &m, 8); /* M */
ptr += 8;
}
diff --git a/lib/pc_util.c b/lib/pc_util.c
index fbe724df..370fde55 100644
--- a/lib/pc_util.c
+++ b/lib/pc_util.c
@@ -241,7 +241,11 @@ pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2)
if ( b1->xmin > b2->xmax ||
b1->xmax < b2->xmin ||
b1->ymin > b2->ymax ||
- b1->ymax < b2->ymin )
+ b1->ymax < b2->ymin ||
+ b1->zmin > b2->zmax ||
+ b1->zmax < b2->zmin ||
+ b1->mmin > b2->mmax ||
+ b1->mmax < b2->mmin )
{
return PC_FALSE;
}
@@ -249,17 +253,173 @@ pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2)
}
void
-pc_bounds_init(PCBOUNDS *b)
+pc_bounds_init(PCBOUNDS *b, const PCSCHEMA *schema)
{
- b->xmin = b->ymin = DBL_MAX;
- b->xmax = b->ymax = -1*DBL_MAX;
+ b->xmin = (schema->x_position == -1) ? -DBL_MAX : DBL_MAX;
+ b->ymin = (schema->y_position == -1) ? -DBL_MAX : DBL_MAX;
+ b->zmin = (schema->z_position == -1) ? -DBL_MAX : DBL_MAX;
+ b->mmin = (schema->m_position == -1) ? -DBL_MAX : DBL_MAX;
+
+ b->xmax = -b->xmin;
+ b->ymax = -b->ymin;
+ b->zmax = -b->zmin;
+ b->mmax = -b->mmin;
}
void pc_bounds_merge(PCBOUNDS *b1, const PCBOUNDS *b2)
{
if ( b2->xmin < b1->xmin ) b1->xmin = b2->xmin;
if ( b2->ymin < b1->ymin ) b1->ymin = b2->ymin;
+ if ( b2->zmin < b1->zmin ) b1->zmin = b2->zmin;
+ if ( b2->mmin < b1->mmin ) b1->mmin = b2->mmin;
if ( b2->xmax > b1->xmax ) b1->xmax = b2->xmax;
if ( b2->ymax > b1->ymax ) b1->ymax = b2->ymax;
+ if ( b2->zmax > b1->zmax ) b1->zmax = b2->zmax;
+ if ( b2->mmax > b1->mmax ) b1->mmax = b2->mmax;
+}
+
+void pc_bounds_expand(PCBOUNDS *b, const PCPOINT *p)
+{
+ double v;
+
+ if(p->schema->x_position > -1)
+ {
+ v = pc_point_get_x(p);
+ if ( b->xmin > v ) b->xmin = v;
+ if ( b->xmax < v ) b->xmax = v;
+ }
+
+ if(p->schema->y_position > -1)
+ {
+ v = pc_point_get_y(p);
+ if ( b->ymin > v ) b->ymin = v;
+ if ( b->ymax < v ) b->ymax = v;
+ }
+
+ if(p->schema->z_position > -1)
+ {
+ v = pc_point_get_z(p);
+ if ( b->zmin > v ) b->zmin = v;
+ if ( b->zmax < v ) b->zmax = v;
+ }
+
+ if(p->schema->m_position > -1)
+ {
+ v = pc_point_get_m(p);
+ if ( b->mmin > v ) b->mmin = v;
+ if ( b->mmax < v ) b->mmax = v;
+ }
+}
+
+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_geometry_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;
}
+PCBOX3D *
+pc_bounds_to_box3d(const PCBOUNDS *bounds, uint32_t srid)
+{
+ PCBOX3D *box = (PCBOX3D *) pcalloc(sizeof(PCBOX3D));
+ box->xmin = bounds->xmin;
+ box->ymin = bounds->ymin;
+ box->zmin = bounds->zmin;
+ box->xmax = bounds->xmax;
+ box->ymax = bounds->ymax;
+ box->zmax = bounds->zmax;
+ box->srid = srid;
+ return box;
+}
diff --git a/pgsql/CMakeLists.txt b/pgsql/CMakeLists.txt
index ffe2e2a7..0eff01c2 100644
--- a/pgsql/CMakeLists.txt
+++ b/pgsql/CMakeLists.txt
@@ -10,7 +10,7 @@ set ( PC_HEADERS
pc_pgsql.h
)
-set ( PC_INSTALL_EXENSIONS
+set ( PC_INSTALL_EXTENSIONS
"${PROJECT_BINARY_DIR}/pgsql/pointcloud--${POINTCLOUD_VERSION}.sql"
"${PROJECT_BINARY_DIR}/pgsql/pointcloud.control"
)
@@ -64,7 +64,7 @@ install (
)
install (
- FILES ${PC_INSTALL_EXENSIONS}
+ FILES ${PC_INSTALL_EXTENSIONS}
DESTINATION "${PGSQL_SHAREDIR}/extension"
)
diff --git a/pgsql/META.json b/pgsql/META.json
index f0d1b224..cf3ece5d 100644
--- a/pgsql/META.json
+++ b/pgsql/META.json
@@ -9,7 +9,7 @@
"provides": {
"pointcloud": {
"abstract": "LIDAR point and patch types and functions",
- "version": "1.0.0",
+ "version": "1.1.0",
"file": "",
"docfile": ""
}
@@ -32,7 +32,7 @@
}
},
"meta-spec": {
- "version": "1.0.0",
+ "version": "1.1.0",
"url": "http://pgxn.org/meta/spec.txt"
},
"tags": [
diff --git a/pgsql/Makefile b/pgsql/Makefile
index eba5329e..a9d32ae5 100644
--- a/pgsql/Makefile
+++ b/pgsql/Makefile
@@ -56,4 +56,4 @@ $(EXTENSION)--%--$(EXTVERSION).sql: $(EXTENSION)--$(EXTVERSION).sql ../util/proc
cat $< | ../util/proc_upgrade.pl > $@
$(EXTENSION)--%--$(EXTVERSION)next.sql: $(EXTENSION)--$(EXTVERSION)next--$(EXTVERSION).sql
- ln -f $< $@
+ cp $< $@
diff --git a/pgsql/expected/pointcloud-ght.out b/pgsql/expected/pointcloud-ght.out
index 06ea485b..172adcc4 100644
--- a/pgsql/expected/pointcloud-ght.out
+++ b/pgsql/expected/pointcloud-ght.out
@@ -62,7 +62,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_ght;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_ght;
sum
-----
- 582
+ 710
(1 row)
SELECT Sum(PC_PatchMax(pa,'x')) FROM pa_test_ght;
@@ -98,7 +98,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_ght;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_ght;
sum
-------
- 38681
+ 38809
(1 row)
SELECT Max(PC_PatchMax(pa,'x')) FROM pa_test_ght;
diff --git a/pgsql/expected/pointcloud-laz.out b/pgsql/expected/pointcloud-laz.out
index ccc9bece..46d35fb2 100644
--- a/pgsql/expected/pointcloud-laz.out
+++ b/pgsql/expected/pointcloud-laz.out
@@ -96,7 +96,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_laz;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_laz;
sum
-----
- 487
+ 615
(1 row)
SELECT Sum(PC_PatchMax(pa,'x')) FROM pa_test_laz;
@@ -192,7 +192,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_laz;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_laz;
sum
------
- 1499
+ 1659
(1 row)
SELECT Max(PC_PatchMax(pa,'x')) FROM pa_test_laz;
diff --git a/pgsql/expected/pointcloud.out b/pgsql/expected/pointcloud.out
index 4fa56e28..53c4621f 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
@@ -334,7 +334,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_dim;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_dim;
sum
-----
- 684
+ 812
(1 row)
SELECT Sum(PC_PatchMax(pa,'x')) FROM pa_test_dim;
@@ -370,7 +370,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_dim;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_dim;
sum
------
- 8733
+ 8893
(1 row)
SELECT Max(PC_PatchMax(pa,'x')) FROM pa_test_dim;
diff --git a/pgsql/pc_inout.c b/pgsql/pc_inout.c
index 7a25cc6a..810e7aee 100644
--- a/pgsql/pc_inout.c
+++ b/pgsql/pc_inout.c
@@ -32,6 +32,7 @@ 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_box3d(PG_FUNCTION_ARGS);
static void
@@ -293,8 +294,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,17 +304,26 @@ 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_geometry_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);
}
+PG_FUNCTION_INFO_V1(pcpatch_box3d);
+Datum pcpatch_box3d(PG_FUNCTION_ARGS)
+{
+ SERIALIZED_PATCH *serpatch = PG_GETHEADER_SERPATCH_P(0);
+ PCSCHEMA *schema = pc_schema_from_pcid(serpatch->pcid, fcinfo);
+ PCBOX3D *box = pc_bounds_to_box3d(&serpatch->bounds, schema->srid);
+ PG_RETURN_POINTER(box);
+}
+
PG_FUNCTION_INFO_V1(pc_typmod_in);
Datum pc_typmod_in(PG_FUNCTION_ARGS)
{
diff --git a/pgsql/pc_pgsql.c b/pgsql/pc_pgsql.c
index eb25c00e..6a190545 100644
--- a/pgsql/pc_pgsql.c
+++ b/pgsql/pc_pgsql.c
@@ -995,104 +995,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;
-}
-
-/* 0 = xdr | big endian */
-/* 1 = ndr | little endian */
-static char
-machine_endian(void)
-{
- static int check_int = 1; /* dont modify this!!! */
- return *((char *) &check_int);
-}
-
-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;
-}
diff --git a/pgsql/pointcloud.sql.in b/pgsql/pointcloud.sql.in
index f3b333b1..c2b2a05a 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 a0669abc..32050043 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/CMakeLists.txt b/pgsql_postgis/CMakeLists.txt
index 6796ca4f..68dd877c 100644
--- a/pgsql_postgis/CMakeLists.txt
+++ b/pgsql_postgis/CMakeLists.txt
@@ -1,11 +1,21 @@
-set ( PCPG_INSTALL_EXENSIONS
- pointcloud_postgis--1.0.sql
- pointcloud_postgis.control
+configure_file(
+ pointcloud_postgis.sql.in
+ "${PROJECT_BINARY_DIR}/pgsql/pointcloud_postgis--${POINTCLOUD_VERSION}.sql"
)
-
+
+configure_file(
+ pointcloud_postgis.control.in
+ "${PROJECT_BINARY_DIR}/pgsql/pointcloud_postgis.control"
+ )
+
+set ( PCPG_INSTALL_EXTENSIONS
+ "${PROJECT_BINARY_DIR}/pgsql/pointcloud_postgis--${POINTCLOUD_VERSION}.sql"
+ "${PROJECT_BINARY_DIR}/pgsql/pointcloud_postgis.control"
+ )
+
install (
- FILES ${PCPG_INSTALL_EXENSIONS}
+ FILES ${PCPG_INSTALL_EXTENSIONS}
DESTINATION "${PGSQL_SHAREDIR}/extension"
)
diff --git a/pgsql_postgis/META.json b/pgsql_postgis/META.json
index 2154860e..1ca73d1d 100644
--- a/pgsql_postgis/META.json
+++ b/pgsql_postgis/META.json
@@ -2,7 +2,7 @@
"name": "pointcloud_postgis",
"abstract": "PostGIS integration functions for Pointcloud",
"description": "Provides GIS overlay and vector/raster hooks for point clou data.",
- "version": "1.0.0",
+ "version": "1.1.0",
"release_status": "unstable",
"maintainer": "Paul Ramsey",
"license": "bsd",
@@ -18,7 +18,7 @@
"runtime": {
"requires": {
"postgis": "2.0.0",
- "pointcloud": "1.0.0"
+ "pointcloud": "1.1.0"
}
}
},
@@ -34,7 +34,7 @@
}
},
"meta-spec": {
- "version": "1.0.0",
+ "version": "1.1.0",
"url": "http://pgxn.org/meta/spec.txt"
},
"tags": [
diff --git a/pgsql_postgis/Makefile b/pgsql_postgis/Makefile
index 8f17bf99..5d51208b 100644
--- a/pgsql_postgis/Makefile
+++ b/pgsql_postgis/Makefile
@@ -4,8 +4,11 @@ include ../config.mk
#MODULE_big = pointcloud_postgis
#OBJS =
+SED = sed
EXTENSION = pointcloud_postgis
-DATA = $(EXTENSION)--1.0.sql
+EXTVERSION=$(shell cat ../Version.config)
+EXTVERSION_MAJOR=$(shell cut -d. -f1,2 ../Version.config)
+DATA = $(EXTENSION)--$(EXTVERSION).sql
#REGRESS = pointcloud
@@ -15,3 +18,15 @@ DATA = $(EXTENSION)--1.0.sql
# We are going to use PGXS for sure
include $(PGXS)
+
+$(EXTENSION).control: $(EXTENSION).control.in Makefile
+ $(SED) -e 's/@POINTCLOUD_VERSION@/$(EXTVERSION)/' \
+ -e 's/@POINTCLOUD_VERSION_MAJOR@/$(EXTVERSION_MAJOR)/' $< > $@
+ @cp $(EXTENSION).sql.in $(EXTENSION)--$(EXTVERSION).sql
+
+$(EXTENSION)--$(EXTVERSION).sql: $(EXTENSION).sql.in Makefile
+ $(SED) -e 's/@POINTCLOUD_VERSION@/$(EXTVERSION)/' $< > $@
+
+clean:
+ @rm -f $(EXTENSION)--$(EXTVERSION).sql
+ @rm -f $(EXTENSION).control
diff --git a/pgsql_postgis/pointcloud_postgis.control b/pgsql_postgis/pointcloud_postgis.control.in
similarity index 63%
rename from pgsql_postgis/pointcloud_postgis.control
rename to pgsql_postgis/pointcloud_postgis.control.in
index 01431da0..925afc07 100644
--- a/pgsql_postgis/pointcloud_postgis.control
+++ b/pgsql_postgis/pointcloud_postgis.control.in
@@ -1,6 +1,7 @@
# pointcloud postgis integration extension
comment = 'integration for pointcloud LIDAR data and PostGIS geometry data'
-default_version = '1.0'
+default_version = '@POINTCLOUD_VERSION@'
+module_pathname = '$libdir/pointcloud-@POINTCLOUD_VERSION_MAJOR@'
relocatable = true
superuser = false
requires = 'postgis, pointcloud'
diff --git a/pgsql_postgis/pointcloud_postgis--1.0.sql b/pgsql_postgis/pointcloud_postgis.sql.in
similarity index 59%
rename from pgsql_postgis/pointcloud_postgis--1.0.sql
rename to pgsql_postgis/pointcloud_postgis.sql.in
index 1e6367c7..bb09a933 100644
--- a/pgsql_postgis/pointcloud_postgis--1.0.sql
+++ b/pgsql_postgis/pointcloud_postgis.sql.in
@@ -5,10 +5,10 @@ CREATE OR REPLACE FUNCTION PC_Intersection(pcpatch, geometry)
RETURNS pcpatch AS
$$
WITH
- pts AS (SELECT PC_Explode($1) AS pt),
- pgpts AS (SELECT ST_GeomFromEWKB(PC_AsBinary(pt)) AS pgpt, pt FROM pts),
- ipts AS (SELECT pt FROM pgpts WHERE ST_Intersects(pgpt, $2)),
- ipch AS (SELECT PC_Patch(pt) AS pch FROM ipts)
+ pts AS (SELECT PC_Explode($1) AS pt),
+ pgpts AS (SELECT ST_GeomFromEWKB(PC_AsBinary(pt)) AS pgpt, pt FROM pts),
+ ipts AS (SELECT pt FROM pgpts WHERE ST_Intersects(pgpt, $2)),
+ ipch AS (SELECT PC_Patch(pt) AS pch FROM ipts)
SELECT pch FROM ipch;
$$
LANGUAGE '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';
@@ -55,3 +55,13 @@ CREATE OR REPLACE FUNCTION PC_Intersects(geometry, pcpatch)
$$
LANGUAGE 'sql';
+-----------------------------------------------------------------------------
+-- Cast a pcpatch as a box3d
+--
+CREATE OR REPLACE FUNCTION Box3D(p pcpatch)
+ RETURNS BOX3D AS 'MODULE_PATHNAME', 'pcpatch_box3d'
+ LANGUAGE 'c' IMMUTABLE STRICT;
+
+CREATE CAST (pcpatch AS BOX3D) WITH FUNCTION Box3D(pcpatch);
+
+