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 }
int main (int argc, char **argv) { Las2GhtConfig config; Las2GhtState state; GhtTreePtr tree; int num_points; /* Set up to use the GHT system memory management / logging */ ght_init(); /* We can't do anything if we don't have GDAL/GeoTIFF support in libLAS */ if ( ! (LAS_IsGDALEnabled() && LAS_IsLibGeoTIFFEnabled()) ) { ght_error("%s: requires LibLAS built with GDAL and GeoTIFF support", EXENAME); return 1; } /* Ensure state is clean */ memset(&state, 0, sizeof(Las2GhtState)); /* If no options are specified, display l2g_usage */ if (argc <= 1) { l2g_usage(); return 1; } /* Parse command line options and set configuration */ if ( ! l2g_getopts(argc, argv, &config) ) { l2g_usage(); return 1; } /* Hard code resolution for now */ config.resolution = GHT_MAX_HASH_LENGTH; config.maxpoints = 2000000; /* Temporary info printout */ l2g_config_printf(&config); /* Input file exists? */ if ( ! l2g_fexists(config.lasfile) ) { ght_error("%s: LAS file '%s' does not exist\n", EXENAME, config.lasfile); return 1; } /* Output file is writeable? */ if ( ! l2g_writable(config.ghtfile) ) { ght_error("%s: GHT file '%s' is not writable\n", EXENAME, config.ghtfile); return 1; } /* Can we open the LAS file? */ state.reader = LASReader_Create(config.lasfile); if ( ! state.reader ) { ght_error("%s: unable to open LAS file '%s'\n", EXENAME, config.lasfile); return 1; } ght_info("Opened LAS file '%s' for reading", config.lasfile); /* Get the header */ state.header = LASReader_GetHeader(state.reader); if ( ! state.header) { l2g_state_free(&state); ght_error("%s: unable to read LAS header in '%s'\n", EXENAME, config.lasfile); return 1; } /* Schema is needed to create nodes/attributes */ if ( GHT_OK != l2g_build_schema(&config, &state) ) { l2g_state_free(&state); ght_error("%s: unable to build schema!", EXENAME); return 1; } /* Project info is needed to get points into lat/lon space */ if ( GHT_OK != l2g_read_projection(&config, &state) ) { l2g_state_free(&state); ght_error("%s: unable to build projection information", EXENAME); return 1; } // char *xmlstr; // size_t xmlsize; // ght_schema_to_xml_str(schema, &xmlstr, &xmlsize); // printf("\n%s\n\n", xmlstr); /* Break the problem into chunks. We might get a really really */ /* big LAS file, and we don't want to blow out memory, so we need to */ /* do this a few million records at a file */ do { num_points = l2g_build_tree(&config, &state, &tree); if ( num_points ) { GhtErr err; ght_tree_compact_attributes(tree); err = l2g_save_tree(&config, &state, tree); ght_tree_free(tree); if ( err != GHT_OK ) return 1; } } while ( num_points > 0 ); l2g_state_free(&state); l2g_config_free(&config); ght_info("conversion complete"); return 0; }