static void test_ght_build_node_with_attributes(void) { GhtAttribute *a; GhtCoordinate coord; GhtNode *node; stringbuffer_t *sb = stringbuffer_create(); /* X, Y */ coord.x = -127; coord.y = 45; ght_node_new_from_coordinate(&coord, 16, &node); /* Z */ ght_attribute_new_from_double(simpleschema->dims[2], 1231.2, &a); ght_node_add_attribute(node, a); /* Intensity */ ght_attribute_new_from_double(simpleschema->dims[3], 3, &a); ght_node_add_attribute(node, a); ght_node_to_string(node, sb, 0); CU_ASSERT_STRING_EQUAL("c0j8n012j80252h0 Z=1231.2:Intensity=3\n", stringbuffer_getstring(sb)); // printf("%s\n", stringbuffer_getstring(sb)); stringbuffer_destroy(sb); ght_node_free(node); }
static GhtErr l2g_build_node(const Las2GhtConfig *config, const Las2GhtState *state, LASPointH laspoint, GhtNodePtr *node) { int i; double z; GhtDimensionPtr ghtdim; GhtAttributePtr attribute; GhtCoordinate coord; GhtErr err; assert(config); assert(state->schema); /* Skip invalid points, if so configured */ if ( config->validpoints && ! LASPoint_IsValid(laspoint) ) return GHT_ERROR; coord.x = LASPoint_GetX(laspoint); coord.y = LASPoint_GetY(laspoint); if ( l2g_coordinate_reproject(state, &coord) != GHT_OK ) return GHT_ERROR; if ( ght_node_new_from_coordinate(&coord, config->resolution, node) != GHT_OK ) return GHT_ERROR; /* We know that 'Z' is always dimension 2 */ z = LASPoint_GetZ(laspoint); GHT_TRY(ght_schema_get_dimension_by_index(state->schema, 2, &ghtdim)); if ( ght_attribute_new_from_double(ghtdim, z, &attribute) != GHT_OK ) return GHT_ERROR; if ( ght_node_add_attribute(*node, attribute) != GHT_OK ) return GHT_ERROR; for ( i = 0; i < config->num_attrs; i++ ) { LasAttribute lasattr = config->attrs[i]; double val = l2g_attribute_value(laspoint, lasattr); /* Magic number 3: X,Y,Z are first three dimensions */ GHT_TRY(ght_schema_get_dimension_by_index(state->schema, 3+i, &ghtdim)); if ( ght_attribute_new_from_double(ghtdim, val, &attribute) != GHT_OK ) return GHT_ERROR; if ( ght_node_add_attribute(*node, attribute) != GHT_OK ) return GHT_ERROR; } return GHT_OK; }
/* * Recursive compaction routine. Pulls attribute up to the highest node such that * all children share the attribute value. */ static GhtErr ght_node_compact_attribute_with_delta(GhtNode *node, const GhtDimension *dim, double delta, GhtAttribute *compacted_attribute) { int i; /* This is an internal node, see if all the children share a value in this dimension */ if ( node->children && node->children->num_nodes > 0 ) { double minval = DBL_MAX; double maxval = -1 * DBL_MAX; double totval = 0.0; int node_count = 0; /* Figure out the range of values for this dimension in child nodes */ for ( i = 0; i < node->children->num_nodes; i++ ) { GhtAttribute attr; GhtErr err; err = ght_node_compact_attribute_with_delta(node->children->nodes[i], dim, delta, &attr); if ( err == GHT_OK ) { double d; GHT_TRY(ght_attribute_get_value(&attr, &d)); (d < minval) ? (minval = d) : 0; (d > maxval) ? (maxval = d) : 0; totval += d; node_count++; } else { continue; } } /* If the range is narrow, and we got values from all our children, compact them */ if ( (maxval-minval) < delta && node_count == node->children->num_nodes ) { double val = (minval+maxval)/2.0; GhtAttribute *myattr; for ( i = 0; i < node->children->num_nodes; i++ ) { ght_node_delete_attribute(node->children->nodes[i], dim); } ght_attribute_new_from_double(dim, val, &myattr); memcpy(compacted_attribute, myattr, sizeof(GhtAttribute)); ght_node_add_attribute(node, myattr); return GHT_OK; } return GHT_ERROR; } /* This is a leaf node, send the attribute value up to the caller */ else { if ( ! node->attributes ) return GHT_ERROR; return ght_attribute_get_by_dimension(node->attributes, dim, compacted_attribute); } }
GhtNodeList * tsv_file_to_node_list(const char *fname, const GhtSchema *schema) { GhtNodeList *nodelist; char *ptr_start, *ptr_end, *tmp; char *filestr = file_to_str(fname); double dblval[16]; /* Only going to handle files 16 columns wide */ int field_num = 0; if ( ! filestr ) return NULL; ght_nodelist_new(16, &nodelist); ptr_start = ptr_end = filestr; while( 1 ) { if ( *ptr_end == '\t' || *ptr_end == '\n' || *ptr_end == '\0' ) { char ptr_tmp = *ptr_end; *ptr_end = '\0'; dblval[field_num] = atof(ptr_start); *ptr_end = ptr_tmp; ptr_start = ptr_end; if ( *ptr_end == '\n' || ! ptr_end ) { int i; GhtCoordinate coord; GhtNode *node; if ( schema->num_dims != field_num + 1 ) return NULL; coord.x = dblval[0]; coord.y = dblval[1]; ght_node_new_from_coordinate(&coord, 16, &node); for ( i = 2; i < schema->num_dims; i++ ) { GhtAttribute *a; ght_attribute_new_from_double(schema->dims[i], dblval[i], &a); ght_node_add_attribute(node, a); } ght_nodelist_add_node(nodelist, node); field_num = 0; } else field_num++; /* All done! */ if ( *ptr_end == '\0' ) break; } ptr_end++; } return nodelist; }
static void test_ght_node_file_serialization(void) { GhtCoordinate coord; GhtNode *node, *root, *noderead; GhtErr err; GhtWriter *writer; GhtReader *reader; stringbuffer_t *sb1; GhtAttribute *attr; const char* testfile = "test.ght"; if ( fexists(testfile) ) remove(testfile); coord.x = -127.4123; coord.y = 49.23141; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node); CU_ASSERT_EQUAL(err, GHT_OK); root = node; coord.x = -127.4122; coord.y = 49.23142; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node); err = ght_attribute_new_from_double(schema->dims[2], 88.88, &attr); err = ght_node_add_attribute(node, attr); err = ght_node_insert_node(root, node, GHT_DUPES_YES); CU_ASSERT_EQUAL(err, GHT_OK); coord.x = -127.4122001; coord.y = 49.23142001; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node); err = ght_attribute_new_from_double(schema->dims[2], 15.23, &attr); err = ght_node_add_attribute(node, attr); err = ght_node_insert_node(root, node, GHT_DUPES_YES); CU_ASSERT_EQUAL(err, GHT_OK); coord.x = -127.4122002; coord.y = 49.23142002; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node); err = ght_attribute_new_from_double(schema->dims[2], 19.23, &attr); err = ght_node_add_attribute(node, attr); err = ght_node_insert_node(root, node, GHT_DUPES_YES); CU_ASSERT_EQUAL(err, GHT_OK); // sb1 = stringbuffer_create(); // err = ght_node_to_string(root, sb1, 0); // printf("\n%s\n", stringbuffer_getstring(sb1)); // stringbuffer_destroy(sb1); err = ght_writer_new_file(testfile, &writer); CU_ASSERT_EQUAL(err, GHT_OK); err = ght_node_write(root, writer); CU_ASSERT_EQUAL(err, GHT_OK); ght_writer_free(writer); err = ght_reader_new_file(testfile, schema, &reader); CU_ASSERT_EQUAL(err, GHT_OK); err = ght_node_read(reader, &noderead); CU_ASSERT_EQUAL(err, GHT_OK); ght_reader_free(reader); remove(testfile); ght_node_free(root); ght_node_free(noderead); }
static void test_ght_node_serialization(void) { GhtCoordinate coord; int x, y; GhtNode *node1, *node2, *node3; GhtErr err; GhtWriter *writer; GhtReader *reader; const uint8_t *bytes; size_t bytes_size; stringbuffer_t *sb1, *sb2; GhtAttribute *attr; char *hex; /* ght_node_new_from_coordinate(const GhtCoordinate *coord, unsigned int resolution, GhtNode **node); */ coord.x = -127.4123; coord.y = 49.23141; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node1); CU_ASSERT_STRING_EQUAL(node1->hash, "c0v2hdm1wpzpy4vtv4"); CU_ASSERT_EQUAL(err, GHT_OK); err = ght_writer_new_mem(&writer); err = ght_node_write(node1, writer); bytes = bytebuffer_getbytes(writer->bytebuffer); bytes_size = bytebuffer_getsize(writer->bytebuffer); err = ght_reader_new_mem(bytes, bytes_size, schema, &reader); err = ght_node_read(reader, &node2); CU_ASSERT_STRING_EQUAL(node1->hash, node2->hash); ght_node_free(node2); /* add a child */ coord.x = -127.4125; coord.y = 49.23144; err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_attribute_new_from_double(schema->dims[3], 88.88, &attr); err = ght_node_add_attribute(node3, attr); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); CU_ASSERT_EQUAL(err, GHT_OK); /* add another (dupe) child */ err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); /* add another (dupe) child with an attribute */ err = ght_node_new_from_coordinate(&coord, GHT_MAX_HASH_LENGTH, &node3); err = ght_attribute_new_from_double(schema->dims[2], 99.99, &attr); err = ght_node_add_attribute(node3, attr); err = ght_node_insert_node(node1, node3, GHT_DUPES_YES); sb1 = stringbuffer_create(); err = ght_node_to_string(node1, sb1, 0); // printf("ORIGINAL\n%s\n", stringbuffer_getstring(sb1)); err = ght_writer_new_mem(&writer); err = ght_node_write(node1, writer); bytes = bytebuffer_getbytes(writer->bytebuffer); bytes_size = bytebuffer_getsize(writer->bytebuffer); err = hexbytes_from_bytes(bytes, bytes_size, &hex); CU_ASSERT_STRING_EQUAL("086330763268646D3100020A77707A7079347674763400000A6374643463637839796201035800020000000001020F27000000", hex); // printf("\n\n%s\n", hex); err = ght_reader_new_mem(bytes, bytes_size, schema, &reader); err = ght_node_read(reader, &node2); sb2 = stringbuffer_create(); err = ght_node_to_string(node2, sb2, 0); // printf("COPY\n%s\n", stringbuffer_getstring(sb2)); CU_ASSERT_STRING_EQUAL(stringbuffer_getstring(sb1), stringbuffer_getstring(sb2)); stringbuffer_destroy(sb2); stringbuffer_destroy(sb1); ght_node_free(node1); ght_node_free(node2); ght_writer_free(writer); ght_reader_free(reader); }
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 }