PCPATCH_DIMENSIONAL * pc_patch_dimensional_compress(const PCPATCH_DIMENSIONAL *pdl, PCDIMSTATS *pds_in) { int i; int ndims = pdl->schema->ndims; PCPATCH_DIMENSIONAL *pdl_compressed; PCDIMSTATS *pds = pds_in; assert(pdl); assert(pdl->schema); if ( ! pds ) pds = pc_dimstats_make(pdl->schema); /* Still sampling, update stats */ if ( pds->total_points < PCDIMSTATS_MIN_SAMPLE ) pc_dimstats_update(pds, pdl); pdl_compressed = pcalloc(sizeof(PCPATCH_DIMENSIONAL)); memcpy(pdl_compressed, pdl, sizeof(PCPATCH_DIMENSIONAL)); pdl_compressed->bytes = pcalloc(ndims*sizeof(PCBYTES)); pdl_compressed->stats = pc_stats_clone(pdl->stats); /* Compress each dimension as dictated by stats */ for ( i = 0; i < ndims; i++ ) { pdl_compressed->bytes[i] = pc_bytes_encode(pdl->bytes[i], pds->stats[i].recommended_compression); } if ( pds != pds_in ) pc_dimstats_free(pds); return pdl_compressed; }
PCPATCH_UNCOMPRESSED * pc_patch_uncompressed_from_dimensional(const PCPATCH_DIMENSIONAL *pdl) { int i, j, npoints; PCPATCH_UNCOMPRESSED *patch; PCPATCH_DIMENSIONAL *pdl_uncompressed; const PCSCHEMA *schema; uint8_t *buf; npoints = pdl->npoints; schema = pdl->schema; patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED)); patch->type = PC_NONE; patch->readonly = PC_FALSE; patch->schema = schema; patch->npoints = npoints; patch->maxpoints = npoints; patch->bounds = pdl->bounds; patch->stats = pc_stats_clone(pdl->stats); patch->datasize = schema->size * pdl->npoints; patch->data = pcalloc(patch->datasize); buf = patch->data; /* Can only read from uncompressed dimensions */ pdl_uncompressed = pc_patch_dimensional_decompress(pdl); for ( i = 0; i < npoints; i++ ) { for ( j = 0; j < schema->ndims; j++ ) { PCDIMENSION *dim = pc_schema_get_dimension(schema, j); uint8_t *in = pdl_uncompressed->bytes[j].bytes + dim->size * i; uint8_t *out = buf + dim->byteoffset; memcpy(out, in, dim->size); } buf += schema->size; } pc_patch_dimensional_free(pdl_uncompressed); return patch; }
PCPATCH_DIMENSIONAL * pc_patch_dimensional_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa) { PCPATCH_DIMENSIONAL *pdl; const PCSCHEMA *schema; int i, j, ndims, npoints; assert(pa); npoints = pa->npoints; schema = pa->schema; ndims = schema->ndims; /* Cannot handle empty patches */ if ( npoints == 0 ) return NULL; /* Initialize dimensional */ pdl = pcalloc(sizeof(PCPATCH_DIMENSIONAL)); pdl->type = PC_DIMENSIONAL; pdl->readonly = PC_FALSE; pdl->schema = schema; pdl->npoints = npoints; pdl->bounds = pa->bounds; pdl->stats = pc_stats_clone(pa->stats); pdl->bytes = pcalloc(ndims * sizeof(PCBYTES)); for ( i = 0; i < ndims; i++ ) { PCDIMENSION *dim = pc_schema_get_dimension(schema, i); pdl->bytes[i] = pc_bytes_make(dim, npoints); for ( j = 0; j < npoints; j++ ) { uint8_t *to = pdl->bytes[i].bytes + dim->size * j; uint8_t *from = pa->data + schema->size * j + dim->byteoffset; memcpy(to, from, dim->size); } } return pdl; }
static PCPATCH_DIMENSIONAL * 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->npoints = map->nset; for ( i = 0; i < pdl->schema->ndims; i++ ) { PCDOUBLESTAT stats; stats.min = FLT_MAX; stats.max = FLT_MIN; stats.sum = 0; fpdl->bytes[i] = pc_bytes_filter(&(pdl->bytes[i]), map, &stats); /* 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; } else if ( i == pdl->schema->y_position ) { fpdl->bounds.ymin = stats.min; fpdl->bounds.ymax = 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); } return fpdl; }
PCPATCH_GHT * pc_patch_ght_filter(const PCPATCH_GHT *patch, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2) { #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 */ GhtTreePtr tree; GhtTreePtr tree_filtered; GhtErr err; GhtWriterPtr writer; GhtArea area; const char *dimname; const PCDIMENSION *dim; PCPATCH_GHT *paght; int npoints; /* Echo null back */ if ( ! patch ) return NULL; /* Get a tree */ tree = ght_tree_from_pc_patch(patch); if ( ! tree ) pcerror("%s: call to ght_tree_from_pc_patch failed", __func__); /* Get dimname */ dim = pc_schema_get_dimension(patch->schema, dimnum); if ( ! dim ) pcerror("%s: invalid dimension number (%d)", __func__, dimnum); dimname = dim->name; switch ( filter ) { case PC_GT: err = ght_tree_filter_greater_than(tree, dimname, val1 > val2 ? val1 : val2, &tree_filtered); break; case PC_LT: err = ght_tree_filter_less_than(tree, dimname, val1 < val2 ? val1 : val2, &tree_filtered); break; case PC_EQUAL: err = ght_tree_filter_equal(tree, dimname, val1, &tree_filtered); break; case PC_BETWEEN: err = ght_tree_filter_between(tree, dimname, val1, val2, &tree_filtered); break; default: pcerror("%s: invalid filter type (%d)", __func__, filter); return NULL; } /* ght_tree_filter_* returns a tree with NULL tree element and npoints == 0 */ /* for empty filter results (everything got filtered away) */ if ( err != GHT_OK || ! tree_filtered ) pcerror("%s: ght_tree_filter failed", __func__); /* Read numpoints left in patch */ ght_tree_get_numpoints(tree_filtered, &(npoints)); /* Allocate a fresh GHT patch for output */ paght = pcalloc(sizeof(PCPATCH_GHT)); paght->type = PC_GHT; paght->readonly = PC_FALSE; paght->schema = patch->schema; paght->npoints = npoints; /* No points, not much to do... */ if ( ! npoints ) { paght->ghtsize = 0; paght->ght = NULL; } else { /* Calculate bounds and save */ if ( GHT_OK != ght_tree_get_extent(tree_filtered, &area) ) pcerror("%s: ght_tree_get_extent failed", __func__); paght->bounds.xmin = area.x.min; paght->bounds.xmax = area.x.max; paght->bounds.ymin = area.y.min; paght->bounds.ymax = area.y.max; /* TODO: Replace this; need to update stats too */ paght->stats = pc_stats_clone(patch->stats); /* Convert the tree to a memory buffer */ ght_writer_new_mem(&writer); ght_tree_write(tree_filtered, writer); ght_writer_get_size(writer, &(paght->ghtsize)); paght->ght = pcalloc(paght->ghtsize); ght_writer_get_bytes(writer, paght->ght); ght_writer_free(writer); } // ght_tree_free(tree_filtered); // ght_tree_free(tree); return paght; #endif }
PCPATCH_UNCOMPRESSED * pc_patch_uncompressed_from_ght(const PCPATCH_GHT *paght) { #ifndef HAVE_LIBGHT pcerror("%s: libght support is not enabled", __func__); return NULL; #else int i, npoints; PCPATCH_UNCOMPRESSED *patch; PCPOINT point; const PCSCHEMA *schema; GhtNodeListPtr nodelist; GhtCoordinate coord; GhtNodePtr node; GhtTreePtr tree; GhtAttributePtr attr; /* Build a structured tree from the tree serialization */ if ( ! paght || ! paght->ght ) return NULL; tree = ght_tree_from_pc_patch(paght); if ( ! tree ) return NULL; /* Convert tree to nodelist */ ght_nodelist_new(paght->npoints, &nodelist); ght_tree_to_nodelist(tree, nodelist); /* Allocate uncompressed patch */ ght_nodelist_get_num_nodes(nodelist, &npoints); schema = paght->schema; patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED)); patch->type = PC_NONE; patch->readonly = PC_FALSE; patch->schema = schema; patch->npoints = npoints; patch->bounds = paght->bounds; patch->stats = pc_stats_clone(paght->stats); patch->maxpoints = npoints; patch->datasize = schema->size * npoints; patch->data = pcalloc(patch->datasize); /* Set up utility point */ point.schema = schema; point.readonly = PC_FALSE; point.data = patch->data; /* Process each point... */ for ( i = 0; i < npoints; i++ ) { double val; /* Read and set X and Y */ ght_nodelist_get_node(nodelist, i, &node); ght_node_get_coordinate(node, &coord); pc_point_set_x(&point, coord.x); pc_point_set_y(&point, coord.y); /* Read and set all the attributes */ ght_node_get_attributes(node, &attr); while ( attr ) { GhtDimensionPtr dim; const char *name; ght_attribute_get_value(attr, &val); ght_attribute_get_dimension(attr, &dim); ght_dimension_get_name(dim, &name); pc_point_set_double_by_name(&point, name, val); ght_attribute_get_next(attr, &attr); } point.data += schema->size; } /* Done w/ nodelist and tree */ ght_nodelist_free_deep(nodelist); // ght_tree_free(tree); /* Done */ return patch; #endif }
PCPATCH_GHT * pc_patch_ght_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa) { #ifndef HAVE_LIBGHT pcerror("%s: libght support is not enabled", __func__); return NULL; #else int i, j; int pointcount = 0; GhtSchemaPtr schema; GhtTreePtr tree; GhtCoordinate coord; GhtNodePtr node; PCPOINT pt; PCDIMENSION *xdim, *ydim; PCPATCH_GHT *paght = NULL; size_t pt_size = pa->schema->size; /* Cannot handle empty patches */ if ( ! pa || ! pa->npoints ) return NULL; pt.schema = pa->schema; pt.readonly = PC_TRUE; xdim = pa->schema->dims[pa->schema->x_position]; ydim = pa->schema->dims[pa->schema->y_position]; schema = ght_schema_from_pc_schema(pa->schema); if ( ght_tree_new(schema, &tree) != GHT_OK ) { pcerror("ght_tree_new failed"); return NULL; } /* Build up the tree from the points. */ for ( i = 0; i < pa->npoints; i++ ) { pt.data = pa->data + pt_size * i; pc_point_get_double(&pt, xdim, &(coord.x)); pc_point_get_double(&pt, ydim, &(coord.y)); /* Build a node from the x/y information */ /* TODO, make resolution configurable from the schema */ if ( ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node) == GHT_OK ) { unsigned int num_dims; ght_schema_get_num_dimensions(schema, &num_dims); /* Add attributes to the node */ for ( j = 0; j < num_dims; j++ ) { PCDIMENSION *dim; GhtDimensionPtr ghtdim; GhtAttributePtr attr; double val; /* Don't add X or Y as attributes, they are already embodied in the hash */ if ( j == pa->schema->x_position || j == pa->schema->y_position ) continue; dim = pc_schema_get_dimension(pa->schema, j); pc_point_get_double(&pt, dim, &val); ght_schema_get_dimension_by_index(schema, j, &ghtdim); ght_attribute_new_from_double(ghtdim, val, &attr); ght_node_add_attribute(node, attr); } /* Add the node to the tree */ /* TODO, make duplicate handling configurable from the schema */ if ( ght_tree_insert_node(tree, node) == GHT_OK ) { pointcount++; } else { // ght_tree_free(tree); pcerror("ght_tree_insert_node failed"); return NULL; } } else { ght_tree_free(tree); pcerror("ght_node_new_from_coordinate failed"); return NULL; } } /* Compact the tree */ if ( ght_tree_compact_attributes(tree) == GHT_OK ) { GhtWriterPtr writer; paght = pcalloc(sizeof(PCPATCH_GHT)); paght->type = PC_GHT; paght->readonly = PC_FALSE; paght->schema = pa->schema; paght->npoints = pointcount; paght->bounds = pa->bounds; paght->stats = pc_stats_clone(pa->stats); /* Convert the tree to a memory buffer */ ght_writer_new_mem(&writer); ght_tree_write(tree, writer); ght_writer_get_size(writer, &(paght->ghtsize)); paght->ght = pcalloc(paght->ghtsize); ght_writer_get_bytes(writer, paght->ght); ght_writer_free(writer); } // Let the hierarchical memory manager clean up the tree // ght_tree_free(tree); return paght; #endif }