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; 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; x = pc_point_get_x(pt); y = pc_point_get_y(pt); if ( pt->schema->srid > 0 ) { has_srid = PC_TRUE; wkbtype |= srid_mask; size += 4; srid = pt->schema->srid; } if ( pc_point_get_double_by_name(pt, "Z", &z) ) { has_z = PC_TRUE; wkbtype |= z_mask; size += 8; } wkb = pcalloc(size); ptr = wkb; ptr[0] = machine_endian(); /* Endian flag */ ptr += 1; memcpy(ptr, &wkbtype, 4); /* WKB type */ ptr += 4; if ( has_srid ) { memcpy(ptr, &srid, 4); /* SRID */ ptr += 4; } memcpy(ptr, &x, 8); /* X */ ptr += 8; memcpy(ptr, &y, 8); /* Y */ ptr += 8; if ( has_z ) { memcpy(ptr, &z, 8); /* Z */ ptr += 8; } if ( wkbsize ) *wkbsize = size; return wkb; }
uint8_t * pc_patch_uncompressed_to_wkb(const PCPATCH_UNCOMPRESSED *patch, size_t *wkbsize) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT) uint32: npoints uchar[]: data (interpret relative to pcid) */ char endian = machine_endian(); /* endian + pcid + compression + npoints + datasize */ size_t size = 1 + 4 + 4 + 4 + patch->datasize; uint8_t *wkb = pcalloc(size); uint32_t compression = patch->type; uint32_t npoints = patch->npoints; uint32_t pcid = patch->schema->pcid; wkb[0] = endian; /* Write endian flag */ memcpy(wkb + 1, &pcid, 4); /* Write PCID */ memcpy(wkb + 5, &compression, 4); /* Write compression */ memcpy(wkb + 9, &npoints, 4); /* Write npoints */ memcpy(wkb + 13, patch->data, patch->datasize); /* Write data */ if ( wkbsize ) *wkbsize = size; return wkb; }
/* * Write an uncompressed patch out to hex */ static void test_patch_hex_out() { // 00 endian // 00000000 pcid // 00000000 compression // 00000002 npoints // 0000000200000003000000050006 pt1 (XYZi) // 0000000200000003000000050008 pt2 (XYZi) static char *wkt_result = "{\"pcid\":0,\"pts\":[[0.02,0.03,0.05,6],[0.02,0.03,0.05,8]]}"; static char *hexresult_xdr = "0000000000000000000000000200000002000000030000000500060000000200000003000000050008"; static char *hexresult_ndr = "0100000000000000000200000002000000030000000500000006000200000003000000050000000800"; double d0[4] = { 0.02, 0.03, 0.05, 6 }; double d1[4] = { 0.02, 0.03, 0.05, 8 }; PCPOINT *pt0 = pc_point_from_double_array(simpleschema, d0, 4); PCPOINT *pt1 = pc_point_from_double_array(simpleschema, d1, 4); PCPATCH_UNCOMPRESSED *pa; uint8_t *wkb; size_t wkbsize; char *hexwkb; char *wkt; PCPOINTLIST *pl = pc_pointlist_make(2); pc_pointlist_add_point(pl, pt0); pc_pointlist_add_point(pl, pt1); pa = pc_patch_uncompressed_from_pointlist(pl); wkb = pc_patch_uncompressed_to_wkb(pa, &wkbsize); // printf("wkbsize %zu\n", wkbsize); hexwkb = hexbytes_from_bytes(wkb, wkbsize); // printf("hexwkb %s\n", hexwkb); // printf("hexresult_ndr %s\n", hexresult_ndr); // printf("machine_endian %d\n", machine_endian()); if ( machine_endian() == PC_NDR ) { CU_ASSERT_STRING_EQUAL(hexwkb, hexresult_ndr); } else { CU_ASSERT_STRING_EQUAL(hexwkb, hexresult_xdr); } wkt = pc_patch_uncompressed_to_string(pa); // printf("wkt %s\n", wkt); CU_ASSERT_STRING_EQUAL(wkt, wkt_result); pc_patch_free((PCPATCH*)pa); pc_pointlist_free(pl); pcfree(hexwkb); pcfree(wkb); pcfree(wkt); }
PCPATCH * pc_patch_uncompressed_from_wkb(const PCSCHEMA *s, const uint8_t *wkb, size_t wkbsize) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf) uint32: npoints pcpoint[]: data (interpret relative to pcid) */ static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */ PCPATCH_UNCOMPRESSED *patch; uint8_t *data; uint8_t swap_endian = (wkb[0] != machine_endian()); uint32_t npoints; if ( wkb_get_compression(wkb) != PC_NONE ) { pcerror("%s: call with wkb that is not uncompressed", __func__); return NULL; } npoints = wkb_get_npoints(wkb); if ( (wkbsize - hdrsz) != (s->size * npoints) ) { pcerror("%s: wkb size and expected data size do not match", __func__); return NULL; } if ( swap_endian ) { data = uncompressed_bytes_flip_endian(wkb+hdrsz, s, npoints); } else { data = pcalloc(npoints * s->size); memcpy(data, wkb+hdrsz, npoints*s->size); } patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED)); patch->type = PC_NONE; patch->readonly = PC_FALSE; patch->schema = s; patch->npoints = npoints; patch->maxpoints = npoints; patch->datasize = (wkbsize - hdrsz); patch->data = data; patch->stats = NULL; return (PCPATCH*)patch; }
PCPATCH * pc_patch_ght_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize) { #ifndef HAVE_LIBGHT pcerror("%s: libght support is not enabled", __func__); return NULL; #else /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT) uint32: npoints uint32: ghtsize uint8[]: ghtbuffer */ static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */ PCPATCH_GHT *patch; uint8_t swap_endian = (wkb[0] != machine_endian()); uint32_t npoints; size_t ghtsize; const uint8_t *buf; if ( wkb_get_compression(wkb) != PC_GHT ) { pcerror("%s: call with wkb that is not GHT compressed", __func__); return NULL; } npoints = wkb_get_npoints(wkb); patch = pcalloc(sizeof(PCPATCH_GHT)); patch->type = PC_GHT; patch->readonly = PC_FALSE; patch->schema = schema; patch->npoints = npoints; /* Start on the GHT */ buf = wkb+hdrsz; ghtsize = wkb_get_int32(buf, swap_endian); buf += 4; /* Move to start of GHT buffer */ /* Copy in the tree buffer */ patch->ght = pcalloc(ghtsize); patch->ghtsize = ghtsize; memcpy(patch->ght, buf, ghtsize); return (PCPATCH*)patch; #endif }
uint32_t wkb_get_pcid(const uint8_t *wkb) { /* We expect the bytes to be in WKB format for PCPOINT/PCPATCH */ /* byte 0: endian */ /* byte 1-4: pcid */ /* ...data... */ uint32_t pcid; memcpy(&pcid, wkb + 1, 4); if ( wkb[0] != machine_endian() ) { pcid = int32_flip_endian(pcid); } return pcid; }
uint32_t wkb_get_compression(const uint8_t *wkb) { /* We expect the bytes to be in WKB format for PCPATCH */ /* byte 0: endian */ /* byte 1-4: pcid */ /* byte 5-8: compression */ /* ...data... */ uint32_t compression; memcpy(&compression, wkb+1+4, 4); if ( wkb[0] != machine_endian() ) { compression = int32_flip_endian(compression); } return compression; }
uint32_t wkb_get_npoints(const uint8_t *wkb) { /* We expect the bytes to be in WKB format for PCPATCH */ /* byte 0: endian */ /* byte 1-4: pcid */ /* byte 5-8: compression */ /* byte 9-12: npoints */ /* ...data... */ uint32_t npoints; memcpy(&npoints, wkb+1+4+4, 4); if ( wkb[0] != machine_endian() ) { npoints = int32_flip_endian(npoints); } return npoints; }
uint8_t * pc_point_to_wkb(const PCPOINT *pt, size_t *wkbsize) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uchar[]: data (interpret relative to pcid) */ char endian = machine_endian(); size_t size = 1 + 4 + pt->schema->size; uint8_t *wkb = pcalloc(size); wkb[0] = endian; /* Write endian flag */ memcpy(wkb + 1, &(pt->schema->pcid), 4); /* Write PCID */ memcpy(wkb + 5, pt->data, pt->schema->size); /* Write data */ if ( wkbsize ) *wkbsize = size; return wkb; }
PCPATCH * pc_patch_dimensional_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT) uint32: npoints dimensions[]: dims (interpret relative to pcid and compressions) */ static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */ PCPATCH_DIMENSIONAL *patch; uint8_t swap_endian = (wkb[0] != machine_endian()); uint32_t npoints, ndims; const uint8_t *buf; int i; if ( wkb_get_compression(wkb) != PC_DIMENSIONAL ) { pcerror("%s: call with wkb that is not dimensionally compressed", __func__); return NULL; } npoints = wkb_get_npoints(wkb); ndims = schema->ndims; patch = pcalloc(sizeof(PCPATCH_DIMENSIONAL)); patch->type = PC_DIMENSIONAL; patch->readonly = PC_FALSE; patch->schema = schema; patch->npoints = npoints; patch->bytes = pcalloc(ndims*sizeof(PCBYTES)); buf = wkb+hdrsz; for ( i = 0; i < ndims; i++ ) { PCBYTES *pcb = &(patch->bytes[i]); PCDIMENSION *dim = schema->dims[i]; pc_bytes_deserialize(buf, dim, pcb, PC_FALSE /*readonly*/, swap_endian); pcb->npoints = npoints; buf += pc_bytes_serialized_size(pcb); } return (PCPATCH*)patch; }
PCPOINT * pc_point_from_wkb(const PCSCHEMA *schema, uint8_t *wkb, size_t wkblen) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uchar[]: data (interpret relative to pcid) */ const size_t hdrsz = 1+4; /* endian + pcid */ uint8_t wkb_endian; uint32_t pcid; uint8_t *data; PCPOINT *pt; if ( ! wkblen ) { pcerror("pc_point_from_wkb: zero length wkb"); } wkb_endian = wkb[0]; pcid = wkb_get_pcid(wkb); if ( (wkblen-hdrsz) != schema->size ) { pcerror("pc_point_from_wkb: wkb size inconsistent with schema size"); } if ( wkb_endian != machine_endian() ) { /* uncompressed_bytes_flip_endian creates a flipped copy */ data = uncompressed_bytes_flip_endian(wkb+hdrsz, schema, 1); } else { data = pcalloc(schema->size); memcpy(data, wkb+hdrsz, wkblen-hdrsz); } pt = pc_point_from_data(schema, data); pt->readonly = PC_FALSE; return pt; }
uint8_t * pc_patch_dimensional_to_wkb(const PCPATCH_DIMENSIONAL *patch, size_t *wkbsize) { /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT) uint32: npoints dimensions[]: pcbytes (interpret relative to pcid and compressions) */ int ndims = patch->schema->ndims; int i; uint8_t *buf; char endian = machine_endian(); /* endian + pcid + compression + npoints + datasize */ size_t size = 1 + 4 + 4 + 4 + pc_patch_dimensional_serialized_size(patch); uint8_t *wkb = pcalloc(size); uint32_t compression = patch->type; uint32_t npoints = patch->npoints; uint32_t pcid = patch->schema->pcid; wkb[0] = endian; /* Write endian flag */ memcpy(wkb + 1, &pcid, 4); /* Write PCID */ memcpy(wkb + 5, &compression, 4); /* Write compression */ memcpy(wkb + 9, &npoints, 4); /* Write npoints */ buf = wkb + 13; for ( i = 0; i < ndims; i++ ) { size_t bsz; PCBYTES *pcb = &(patch->bytes[i]); // XXX printf("pcb->(size=%d, interp=%d, npoints=%d, compression=%d, readonly=%d)\n",pcb->size, pcb->interpretation, pcb->npoints, pcb->compression, pcb->readonly); pc_bytes_serialize(pcb, buf, &bsz); buf += bsz; } if ( wkbsize ) *wkbsize = size; return wkb; }
uint8_t * pc_patch_ght_to_wkb(const PCPATCH_GHT *patch, size_t *wkbsize) { #ifndef HAVE_LIBGHT pcerror("%s: libght support is not enabled", __func__); return NULL; #else /* byte: endianness (1 = NDR, 0 = XDR) uint32: pcid (key to POINTCLOUD_SCHEMAS) uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT) uint32: npoints uint32: ghtsize uint8[]: ghtbuffer */ uint8_t *buf; char endian = machine_endian(); /* endian + pcid + compression + npoints + ghtsize + ght */ size_t size = 1 + 4 + 4 + 4 + 4 + patch->ghtsize; uint8_t *wkb = pcalloc(size); uint32_t compression = patch->type; uint32_t npoints = patch->npoints; uint32_t pcid = patch->schema->pcid; uint32_t ghtsize = patch->ghtsize; wkb[0] = endian; /* Write endian flag */ memcpy(wkb + 1, &pcid, 4); /* Write PCID */ memcpy(wkb + 5, &compression, 4); /* Write compression */ memcpy(wkb + 9, &npoints, 4); /* Write npoints */ memcpy(wkb + 13, &ghtsize, 4); /* Write ght buffer size */ buf = wkb + 17; memcpy(buf, patch->ght, patch->ghtsize); if ( wkbsize ) *wkbsize = size; return wkb; #endif }
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; }
uint8_t * pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize) { static uint32_t srid_mask = 0x20000000; 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 = pt->schema->srid; double x, y, z, m; int has_x = pc_point_get_x(pt, &x) == PC_SUCCESS; int has_y = pc_point_get_y(pt, &y) == PC_SUCCESS; int has_z = pc_point_get_z(pt, &z) == PC_SUCCESS; int has_m = pc_point_get_m(pt, &m) == PC_SUCCESS; if ( ! ( has_x && has_y ) ) return NULL; if ( srid ) { wkbtype |= srid_mask; size += 4; } if ( has_z ) { wkbtype |= z_mask; size += 8; } if ( has_m ) { wkbtype |= m_mask; size += 8; } wkb = pcalloc(size); ptr = wkb; ptr[0] = machine_endian(); /* Endian flag */ ptr += 1; memcpy(ptr, &wkbtype, 4); /* WKB type */ ptr += 4; if ( srid != 0 ) { memcpy(ptr, &srid, 4); /* SRID */ ptr += 4; } memcpy(ptr, &x, 8); /* X */ ptr += 8; memcpy(ptr, &y, 8); /* Y */ ptr += 8; if ( has_z ) { memcpy(ptr, &z, 8); /* Z */ ptr += 8; } if ( has_m ) { memcpy(ptr, &m, 8); /* M */ ptr += 8; } if ( wkbsize ) *wkbsize = size; return wkb; }