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 babb6131..a5225160 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_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); @@ -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/cunit/cu_pc_schema.c b/lib/cunit/cu_pc_schema.c index b43e6132..dafe1d0e 100644 --- a/lib/cunit/cu_pc_schema.c +++ b/lib/cunit/cu_pc_schema.c @@ -171,6 +171,8 @@ test_schema_clone(void) CU_ASSERT_EQUAL(clone->srid, schema->srid); CU_ASSERT_EQUAL(clone->x_position, schema->x_position); CU_ASSERT_EQUAL(clone->y_position, schema->y_position); + CU_ASSERT_EQUAL(clone->z_position, schema->z_position); + CU_ASSERT_EQUAL(clone->m_position, schema->m_position); CU_ASSERT_EQUAL(clone->compression, schema->compression); CU_ASSERT(clone->dims != schema->dims); /* deep clone */ CU_ASSERT(clone->namehash != schema->namehash); /* deep clone */ diff --git a/lib/pc_api.h b/lib/pc_api.h index 418bd6da..a3568cc1 100644 --- a/lib/pc_api.h +++ b/lib/pc_api.h @@ -90,6 +90,8 @@ typedef struct uint32_t srid; /* Foreign key reference to SPATIAL_REF_SYS */ int32_t x_position; /* What entry is the x coordinate at? */ int32_t y_position; /* What entry is the y coordinate at? */ + int32_t z_position; /* What entry is the z coordinate at? */ + int32_t m_position; /* What entry is the m coordinate at? */ uint32_t compression; /* Compression type applied to the data */ hashtable *namehash; /* Look-up from dimension name to pointer */ } PCSCHEMA; @@ -148,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 { @@ -281,8 +294,8 @@ uint32_t pc_schema_is_valid(const PCSCHEMA *s); PCSCHEMA* pc_schema_clone(const PCSCHEMA *s); /** Add/overwrite a dimension in a schema */ void pc_schema_set_dimension(PCSCHEMA *s, PCDIMENSION *d); -/** Check/set the x/y position in the dimension list */ -void pc_schema_check_xy(PCSCHEMA *s); +/** Check/set the xyzm positions in the dimension list */ +void pc_schema_check_xyzm(PCSCHEMA *s); /** Get the width in bytes of a single point in the schema */ size_t pc_schema_get_size(const PCSCHEMA *s); @@ -342,12 +355,24 @@ double pc_point_get_x(const PCPOINT *pt); /** Returns Y coordinate */ double pc_point_get_y(const PCPOINT *pt); +/** Returns Z coordinate */ +double pc_point_get_z(const PCPOINT *pt); + +/** Returns M coordinate */ +double pc_point_get_m(const PCPOINT *pt); + /** Set the X coordinate */ double pc_point_set_x(PCPOINT *pt, double val); /** Set the Y coordinate */ double pc_point_set_y(PCPOINT *pt, double val); +/** Set the Z coordinate */ +double pc_point_set_z(PCPOINT *pt, double val); + +/** Set the M coordinate */ +double pc_point_set_m(PCPOINT *pt, double val); + /** Create a new readwrite PCPOINT from a hex byte array */ PCPOINT* pc_point_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize); @@ -421,6 +446,12 @@ 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 geometry */ +uint8_t *pc_bounds_to_geometry_wkb(const PCBOUNDS *bounds, uint32_t srid, size_t *wkbsize); + +/** Returns 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_filter.c b/lib/pc_filter.c index a1be182e..d5e4f56d 100644 --- a/lib/pc_filter.c +++ b/lib/pc_filter.c @@ -146,16 +146,16 @@ pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map) int i = 0; PCPATCH_DIMENSIONAL *fpdl = pc_patch_dimensional_clone(pdl); - fpdl->stats = pc_stats_clone(pdl->stats); + fpdl->stats = pc_stats_clone(pdl->stats); fpdl->npoints = map->nset; for ( i = 0; i < pdl->schema->ndims; i++ ) { PCDIMENSION *dim; - PCDOUBLESTAT stats; - stats.min = FLT_MAX; - stats.max = -1*FLT_MAX; - stats.sum = 0; + PCDOUBLESTAT stats; + stats.min = FLT_MAX; + stats.max = -1*FLT_MAX; + stats.sum = 0; fpdl->bytes[i] = pc_bytes_filter(&(pdl->bytes[i]), map, &stats); @@ -168,18 +168,28 @@ pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map) /* Save the X/Y stats for use in bounds later */ if ( i == pdl->schema->x_position ) { - fpdl->bounds.xmin = stats.min; - fpdl->bounds.xmax = stats.max; - } + fpdl->bounds.xmin = stats.min; + fpdl->bounds.xmax = stats.max; + } else if ( i == pdl->schema->y_position ) { - fpdl->bounds.ymin = stats.min; - fpdl->bounds.ymax = stats.max; - } + 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); - pc_point_set_double_by_index(&(fpdl->stats->avg), i, stats.sum/fpdl->npoints); + pc_point_set_double_by_index(&(fpdl->stats->min), i, stats.min); + pc_point_set_double_by_index(&(fpdl->stats->max), i, stats.max); + pc_point_set_double_by_index(&(fpdl->stats->avg), i, stats.sum/fpdl->npoints); } return fpdl; diff --git a/lib/pc_patch_dimensional.c b/lib/pc_patch_dimensional.c index 4e3e579f..43148341 100644 --- a/lib/pc_patch_dimensional.c +++ b/lib/pc_patch_dimensional.c @@ -17,13 +17,13 @@ /* typedef struct { - int type; + int type; 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; + PCBYTES *bytes; } PCPATCH_DIMENSIONAL; */ @@ -179,7 +179,7 @@ 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; @@ -187,22 +187,44 @@ pc_patch_dimensional_compute_extent(PCPATCH_DIMENSIONAL *pdl) assert(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; } @@ -307,17 +329,17 @@ pc_patch_dimensional_from_pointlist(const PCPOINTLIST *pdl) /** get point n, 0-based, positive */ PCPOINT *pc_patch_dimensional_pointn(const PCPATCH_DIMENSIONAL *pdl, int n) { - assert(pdl); - assert(pdl->schema); - int i; - int ndims = pdl->schema->ndims; - PCPOINT *pt = pc_point_make(pdl->schema); - uint8_t *buf = pt->data; - for ( i = 0; i < ndims; i++ ) - { - PCDIMENSION *dim = pc_schema_get_dimension(pdl->schema, i); - pc_bytes_to_ptr(buf+dim->byteoffset,pdl->bytes[i], n); - } - - return pt; + assert(pdl); + assert(pdl->schema); + int i; + int ndims = pdl->schema->ndims; + PCPOINT *pt = pc_point_make(pdl->schema); + uint8_t *buf = pt->data; + for ( i = 0; i < ndims; i++ ) + { + PCDIMENSION *dim = pc_schema_get_dimension(pdl->schema, i); + pc_bytes_to_ptr(buf+dim->byteoffset,pdl->bytes[i], n); + } + + return pt; } diff --git a/lib/pc_patch_uncompressed.c b/lib/pc_patch_uncompressed.c index 9c437201..040e151b 100644 --- a/lib/pc_patch_uncompressed.c +++ b/lib/pc_patch_uncompressed.c @@ -57,13 +57,13 @@ pc_patch_uncompressed_to_stringbuffer(const PCPATCH_UNCOMPRESSED *patch, stringb char * pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch) { - stringbuffer_t *sb = stringbuffer_create(); - char *str; - if ( PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb) ) - return NULL; - str = stringbuffer_release_string(sb); - stringbuffer_destroy(sb); - return str; + stringbuffer_t *sb = stringbuffer_create(); + char *str; + if ( PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb) ) + return NULL; + str = stringbuffer_release_string(sb); + stringbuffer_destroy(sb); + return str; } uint8_t * @@ -175,10 +175,10 @@ pc_patch_uncompressed_make(const PCSCHEMA *s, uint32_t maxpoints) /* Make our own data area */ datasize = s->size * maxpoints; pch->datasize = datasize; - pch->data = NULL; + pch->data = NULL; if ( datasize ) { - pch->data = pcalloc(datasize); + pch->data = pcalloc(datasize); } pc_bounds_init(&(pch->bounds)); @@ -191,7 +191,7 @@ 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); @@ -199,12 +199,26 @@ pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch) { /* 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; + if ( patch->schema->x_position > -1 ) { + v = pc_point_get_x(pt); + if ( b.xmin > v ) b.xmin = v; + if ( b.xmax < v ) b.xmax = v; + } + if ( patch->schema->y_position > -1 ) { + v = pc_point_get_y(pt); + if ( b.ymin > v ) b.ymin = v; + if ( b.ymax < v ) b.ymax = v; + } + if ( patch->schema->z_position > -1 ) { + v = pc_point_get_z(pt); + if ( b.zmin > v ) b.zmin = v; + if ( b.zmax < v ) b.zmax = v; + } + if ( patch->schema->m_position > -1 ) { + v = pc_point_get_m(pt); + if ( b.mmin > v ) b.mmin = v; + if ( b.mmax < v ) b.mmax = v; + } } patch->bounds = b; @@ -336,7 +350,7 @@ pc_patch_uncompressed_from_dimensional(const PCPATCH_DIMENSIONAL *pdl) patch->npoints = npoints; patch->maxpoints = npoints; patch->bounds = pdl->bounds; - patch->stats = pc_stats_clone(pdl->stats); + patch->stats = pc_stats_clone(pdl->stats); patch->datasize = schema->size * pdl->npoints; patch->data = pcalloc(patch->datasize); buf = patch->data; diff --git a/lib/pc_point.c b/lib/pc_point.c index 043fb334..1c62da52 100644 --- a/lib/pc_point.c +++ b/lib/pc_point.c @@ -154,6 +154,22 @@ pc_point_get_y(const PCPOINT *pt) return d; } +double +pc_point_get_z(const PCPOINT *pt) +{ + double d; + pc_point_get_double_by_index(pt, pt->schema->z_position, &d); + return d; +} + +double +pc_point_get_m(const PCPOINT *pt) +{ + double d; + pc_point_get_double_by_index(pt, pt->schema->m_position, &d); + return d; +} + double pc_point_set_x(PCPOINT *pt, double val) { @@ -166,6 +182,18 @@ pc_point_set_y(PCPOINT *pt, double val) return pc_point_set_double_by_index(pt, pt->schema->y_position, val); } +double +pc_point_set_z(PCPOINT *pt, double val) +{ + return pc_point_set_double_by_index(pt, pt->schema->z_position, val); +} + +double +pc_point_set_m(PCPOINT *pt, double val) +{ + return pc_point_set_double_by_index(pt, pt->schema->m_position, val); +} + char * pc_point_to_string(const PCPOINT *pt) { @@ -293,32 +321,36 @@ uint8_t * pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize) { static uint32_t srid_mask = 0x20000000; - static uint32_t z_mask = 0x80000000; + static uint32_t m_mask = 0x40000000; + static uint32_t z_mask = 0x80000000; uint32_t wkbtype = 1; /* WKB POINT */ size_t size = 1 + 4 + 8 + 8; /* endian + type + dblX, + dblY */ uint8_t *wkb, *ptr; uint32_t srid; - int has_srid = PC_FALSE, has_z = PC_FALSE; - double x, y, z; + double x, y, z, m; - x = pc_point_get_x(pt); - y = pc_point_get_y(pt); + if (pt->schema->x_position < 0 || pt->schema->y_position < 0 ) + return NULL; - if ( pt->schema->srid > 0 ) + if ( pt->schema->z_position > -1 ) { - has_srid = PC_TRUE; - wkbtype |= srid_mask; - size += 4; - srid = pt->schema->srid; + wkbtype |= z_mask; + size += 8; } - if ( pc_point_get_double_by_name(pt, "Z", &z) ) + if ( pt->schema->m_position > -1 ) { - has_z = PC_TRUE; - wkbtype |= z_mask; + wkbtype |= m_mask; size += 8; } + if ( pt->schema->srid != 0 ) + { + wkbtype |= srid_mask; + size += 4; + } + + wkb = pcalloc(size); ptr = wkb; @@ -328,24 +360,35 @@ pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize) memcpy(ptr, &wkbtype, 4); /* WKB type */ ptr += 4; - if ( has_srid ) + if ( pt->schema->srid != 0 ) { + srid = pt->schema->srid; memcpy(ptr, &srid, 4); /* SRID */ ptr += 4; } + x = pc_point_get_x(pt); memcpy(ptr, &x, 8); /* X */ ptr += 8; + y = pc_point_get_y(pt); memcpy(ptr, &y, 8); /* Y */ ptr += 8; - if ( has_z ) + if ( pt->schema->z_position > -1 ) { + z = pc_point_get_z(pt); memcpy(ptr, &z, 8); /* Z */ ptr += 8; } + if ( pt->schema->m_position > -1 ) + { + m = pc_point_get_m(pt); + memcpy(ptr, &m, 8); /* M */ + ptr += 8; + } + if ( wkbsize ) *wkbsize = size; return wkb; } diff --git a/lib/pc_schema.c b/lib/pc_schema.c index 2384f2bc..02352146 100644 --- a/lib/pc_schema.c +++ b/lib/pc_schema.c @@ -198,6 +198,8 @@ pc_schema_new(uint32_t ndims) pcs->ndims = ndims; pcs->x_position = -1; pcs->y_position = -1; + pcs->z_position = -1; + pcs->m_position = -1; return pcs; } @@ -237,6 +239,8 @@ pc_schema_clone(const PCSCHEMA *s) pcs->srid = s->srid; pcs->x_position = s->x_position; pcs->y_position = s->y_position; + pcs->z_position = s->z_position; + pcs->m_position = s->m_position; pcs->compression = s->compression; for ( i = 0; i < pcs->ndims; i++ ) { @@ -326,7 +330,7 @@ pc_schema_to_json(const PCSCHEMA *pcs) return str; } -void pc_schema_check_xy(PCSCHEMA *s) +void pc_schema_check_xyzm(PCSCHEMA *s) { int i; for ( i = 0; i < s->ndims; i++ ) @@ -334,34 +338,49 @@ void pc_schema_check_xy(PCSCHEMA *s) char *dimname = s->dims[i]->name; if ( ! dimname ) continue; if ( strcasecmp(dimname, "X") == 0 || - strcasecmp(dimname, "Longitude") == 0 || - strcasecmp(dimname, "Lon") == 0 ) + strcasecmp(dimname, "Longitude") == 0 || + strcasecmp(dimname, "Lon") == 0 ) { s->x_position = i; continue; } if ( strcasecmp(dimname, "Y") == 0 || - strcasecmp(dimname, "Latitude") == 0 || - strcasecmp(dimname, "Lat") == 0 ) + strcasecmp(dimname, "Latitude") == 0 || + strcasecmp(dimname, "Lat") == 0 ) { s->y_position = i; continue; } + if ( strcasecmp(dimname, "Z") == 0 || + strcasecmp(dimname, "H") == 0 || + strcasecmp(dimname, "Height") == 0 ) + { + s->z_position = i; + continue; + } + if ( strcasecmp(dimname, "M") == 0 || + strcasecmp(dimname, "T") == 0 || + strcasecmp(dimname, "Time") == 0 ) + { + s->m_position = i; + continue; + } } if ( s->x_position < 0 ) { - pcerror("pc_schema_check_xy: invalid x_position '%d'", s->x_position); + pcerror("pc_schema_check_xyzm: invalid x_position '%d'", s->x_position); return; } if ( s->y_position < 0 ) { - pcerror("pc_schema_check_xy: invalid y_position '%d'", s->y_position); + pcerror("pc_schema_check_xyzm: invalid y_position '%d'", s->y_position); return; } } + static char * xml_node_get_content(xmlNodePtr node) { @@ -461,7 +480,6 @@ pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) xmlNodePtr cur = nodes->nodeTab[i]; xmlNodePtr child; PCDIMENSION *d = pc_dimension_new(); - char xydim = 0; /* These are the values of the dimension */ for ( child = cur->children; child; child = child->next ) @@ -471,21 +489,7 @@ pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) char *content = (char*)(child->children->content); char *name = (char*)(child->name); if ( strcmp(name, "name") == 0 ) - { - if ( strcasecmp(content, "X") == 0 || - strcasecmp(content, "Longitude") == 0 || - strcasecmp(content, "Lon") == 0 ) - { - xydim = 'x'; - } - if ( strcasecmp(content, "Y") == 0 || - strcasecmp(content, "Latitude") == 0 || - strcasecmp(content, "Lat") == 0 ) - { - xydim = 'y'; - } d->name = pcstrdup(content); - } else if ( strcmp(name, "description") == 0 ) d->description = pcstrdup(content); else if ( strcmp(name, "size") == 0 ) @@ -520,19 +524,11 @@ pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); - xmlCleanupParser(); + xmlCleanupParser(); pc_schema_free(s); pcwarn("schema dimension at position \"%d\" is declared twice", d->position + 1, ndims); return PC_FAILURE; } - if ( xydim == 'x' ) - { - s->x_position = d->position; - } - if ( xydim == 'y' ) - { - s->y_position = d->position; - } pc_schema_set_dimension(s, d); } else @@ -541,7 +537,7 @@ pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) xmlXPathFreeContext(xpath_ctx); xmlFreeDoc(xml_doc); xmlCleanupParser(); - pc_schema_free(s); + pc_schema_free(s); pcwarn("schema dimension states position \"%d\", but number of XML dimensions is \"%d\"", d->position + 1, ndims); return PC_FAILURE; } @@ -551,7 +547,7 @@ pc_schema_from_xml(const char *xml_str, PCSCHEMA **schema) /* Complete the byte offsets of dimensions from the ordered sizes */ pc_schema_calculate_byteoffsets(s); /* Check X/Y positions */ - pc_schema_check_xy(s); + pc_schema_check_xyzm(s); } xmlXPathFreeObject(xpath_obj); diff --git a/lib/pc_util.c b/lib/pc_util.c index a6a2c055..ba65e9f4 100644 --- a/lib/pc_util.c +++ b/lib/pc_util.c @@ -100,8 +100,8 @@ machine_endian(void) { static int check_int = 1; /* dont modify this!!! */ return *((char *) &check_int); /* 0 = big endian | xdr, - * 1 = little endian | ndr - */ + * 1 = little endian | ndr + */ } int32_t @@ -239,9 +239,13 @@ int 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->xmax < b2->xmin || + b1->ymin > b2->ymax || + b1->ymax < b2->ymin || + b1->zmin > b2->zmax || + b1->zmax < b2->zmin || + b1->mmin > b2->mmax || + b1->mmax < b2->mmin ) { return PC_FALSE; } @@ -251,15 +255,131 @@ pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2) void pc_bounds_init(PCBOUNDS *b) { - b->xmin = b->ymin = DBL_MAX; - b->xmax = b->ymax = -1*DBL_MAX; + b->xmin = b->ymin = b->zmin = b->mmin = DBL_MAX; + b->xmax = b->ymax = b->zmax = b->mmax = -1*DBL_MAX; } 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; } + +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/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 eeb5ae05..035fee0b 100644 --- a/pgsql/pc_inout.c +++ b/pgsql/pc_inout.c @@ -31,7 +31,8 @@ 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); +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,27 @@ 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 2749f6b1..23206c19 100644 --- a/pgsql/pc_pgsql.c +++ b/pgsql/pc_pgsql.c @@ -993,103 +993,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; -} diff --git a/pgsql/pointcloud.sql.in b/pgsql/pointcloud.sql.in index 2208a588..c3e0d582 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/Makefile b/pgsql_postgis/Makefile index 8f17bf99..e3637585 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,10 @@ 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)/' $< > $@ + +$(EXTENSION)--$(EXTVERSION).sql: $(EXTENSION).sql.in Makefile + $(SED) -e 's/@POINTCLOUD_VERSION@/$(EXTVERSION)/' $< > $@ diff --git a/pgsql_postgis/pointcloud_postgis--1.0.sql b/pgsql_postgis/pointcloud_postgis--1.0.sql index 872d1365..7641d70e 100644 --- a/pgsql_postgis/pointcloud_postgis--1.0.sql +++ b/pgsql_postgis/pointcloud_postgis--1.0.sql @@ -10,20 +10,20 @@ CREATE OR REPLACE FUNCTION PC_Intersection(pcpatch, geometry) 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'; ----------------------------------------------------------------------------- -- 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 @@ -32,7 +32,7 @@ CREATE OR REPLACE FUNCTION geometry(pcpoint) RETURNS geometry AS $$ SELECT ST_GeomFromEWKB(PC_AsBinary($1)) - $$ + $$ LANGUAGE 'sql'; CREATE CAST (pcpoint AS geometry) WITH FUNCTION geometry(pcpoint); @@ -44,14 +44,22 @@ 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'; CREATE OR REPLACE FUNCTION PC_Intersects(geometry, pcpatch) RETURNS boolean AS $$ SELECT PC_Intersects($2, $1) - $$ + $$ 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); diff --git a/pgsql_postgis/pointcloud_postgis.control b/pgsql_postgis/pointcloud_postgis.control index 01431da0..d9afe4ce 100644 --- a/pgsql_postgis/pointcloud_postgis.control +++ b/pgsql_postgis/pointcloud_postgis.control @@ -1,6 +1,7 @@ # pointcloud postgis integration extension comment = 'integration for pointcloud LIDAR data and PostGIS geometry data' -default_version = '1.0' +default_version = '1.1.0' +module_pathname = '$libdir/pointcloud-1.1' relocatable = true superuser = false requires = 'postgis, pointcloud' diff --git a/pgsql_postgis/pointcloud_postgis.control.in b/pgsql_postgis/pointcloud_postgis.control.in new file mode 100644 index 00000000..925afc07 --- /dev/null +++ b/pgsql_postgis/pointcloud_postgis.control.in @@ -0,0 +1,7 @@ +# pointcloud postgis integration extension +comment = 'integration for pointcloud LIDAR data and PostGIS geometry data' +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.sql.in b/pgsql_postgis/pointcloud_postgis.sql.in new file mode 100644 index 00000000..d621ea7e --- /dev/null +++ b/pgsql_postgis/pointcloud_postgis.sql.in @@ -0,0 +1,65 @@ +----------------------------------------------------------------------------- +-- Function to overlap polygon on patch +-- +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) + SELECT pch FROM ipch; + $$ + LANGUAGE 'sql'; + +----------------------------------------------------------------------------- +-- Cast from pcpatch to polygon +-- +CREATE OR REPLACE FUNCTION PC_Envelope(pcpatch) + RETURNS geometry AS + $$ + SELECT ST_GeomFromEWKB(PC_Envelope_AsBinary($1)) + $$ + LANGUAGE 'sql'; + +CREATE CAST (pcpatch AS geometry) WITH FUNCTION PC_Envelope(pcpatch); + +----------------------------------------------------------------------------- +-- Cast from pcpoint to point +-- +CREATE OR REPLACE FUNCTION geometry(pcpoint) + RETURNS geometry AS + $$ + SELECT ST_GeomFromEWKB(PC_AsBinary($1)) + $$ + LANGUAGE 'sql'; + +CREATE CAST (pcpoint AS geometry) WITH FUNCTION geometry(pcpoint); + + +----------------------------------------------------------------------------- +-- Function to overlap polygon on patch +-- +CREATE OR REPLACE FUNCTION PC_Intersects(pcpatch, geometry) + RETURNS boolean AS + $$ + SELECT ST_Intersects($2, PC_Envelope($1)) + $$ + LANGUAGE 'sql'; + +CREATE OR REPLACE FUNCTION PC_Intersects(geometry, pcpatch) + RETURNS boolean AS + $$ + SELECT PC_Intersects($2, $1) + $$ + 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);