int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); int i; #ifdef COMPILE_WITH_GUI bool gui = false; #endif bool verbose = false; bool keep_lastiling = false; U32 chopchop = 0; bool projection_was_set = false; double start_time = 0; LASreadOpener lasreadopener; GeoProjectionConverter geoprojectionconverter; LASwriteOpener laswriteopener; if (argc == 1) { #ifdef COMPILE_WITH_GUI return lasmerge_gui(argc, argv, 0); #else fprintf(stderr,"%s is better run in the command line\n", argv[0]); char file_name[256]; fprintf(stderr,"enter input file 1: "); fgets(file_name, 256, stdin); file_name[strlen(file_name)-1] = '\0'; lasreadopener.add_file_name(file_name); fprintf(stderr,"enter input file 2: "); fgets(file_name, 256, stdin); file_name[strlen(file_name)-1] = '\0'; lasreadopener.add_file_name(file_name); fprintf(stderr,"enter output file: "); fgets(file_name, 256, stdin); file_name[strlen(file_name)-1] = '\0'; laswriteopener.set_file_name(file_name); #endif } else { for (i = 1; i < argc; i++) { if (argv[i][0] == '�') argv[i][0] = '-'; } if (!geoprojectionconverter.parse(argc, argv)) byebye(true); if (!lasreadopener.parse(argc, argv)) byebye(true); if (lasreadopener.get_file_name_number()<2) { fprintf(stderr,"Must specify more than one input file.\n"); byebye(true); // only support merging more than one file } if (!laswriteopener.parse(argc, argv)) byebye(true); } for (i = 1; i < argc; i++) { if (argv[i][0] == '\0') { continue; } else if (strcmp(argv[i],"-h") == 0 || strcmp(argv[i],"-help") == 0) { fprintf(stderr, "LAStools (by [email protected]) version %d\n", LAS_TOOLS_VERSION); usage(); } else if (strcmp(argv[i],"-v") == 0 || strcmp(argv[i],"-verbose") == 0) { verbose = true; } else if (strcmp(argv[i],"-version") == 0) { fprintf(stderr, "LAStools (by [email protected]) version %d\n", LAS_TOOLS_VERSION); byebye(); } else if (strcmp(argv[i],"-gui") == 0) { #ifdef COMPILE_WITH_GUI gui = true; #else fprintf(stderr, "WARNING: not compiled with GUI support. ignoring '-gui' ...\n"); #endif } else if (strcmp(argv[i],"-split") == 0) { if ((i+1) >= argc) { fprintf(stderr,"ERROR: '%s' needs 1 argument: size\n", argv[i]); byebye(true); } i++; chopchop = atoi(argv[i]); } else if (strcmp(argv[i],"-keep_lastiling") == 0) { keep_lastiling = true; } else if ((argv[i][0] != '-') && (lasreadopener.get_file_name_number() == 0)) { lasreadopener.add_file_name(argv[i]); argv[i][0] = '\0'; } else { fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]); byebye(true); } } #ifdef COMPILE_WITH_GUI if (gui) { return lasmerge_gui(argc, argv, &lasreadopener); } #endif // read all the input files merged lasreadopener.set_merged(TRUE); // maybe we want to keep the lastiling if (keep_lastiling) { lasreadopener.set_keep_lastiling(TRUE); } // we need to precompute the bounding box lasreadopener.set_populate_header(TRUE); // check input and output if (!lasreadopener.active()) { fprintf(stderr, "ERROR: no input specified\n"); byebye(true, argc==1); } if (!laswriteopener.active()) { fprintf(stderr, "ERROR: no output specified\n"); byebye(true, argc==1); } // make sure we do not corrupt the input file if (lasreadopener.get_file_name() && laswriteopener.get_file_name() && (strcmp(lasreadopener.get_file_name(), laswriteopener.get_file_name()) == 0)) { fprintf(stderr, "ERROR: input and output file name are identical\n"); usage(true); } // check if projection info was set in the command line int number_of_keys; GeoProjectionGeoKeys* geo_keys = 0; int num_geo_double_params; double* geo_double_params = 0; if (geoprojectionconverter.has_projection()) { projection_was_set = geoprojectionconverter.get_geo_keys_from_projection(number_of_keys, &geo_keys, num_geo_double_params, &geo_double_params); } if (verbose) start_time = taketime(); LASreader* lasreader = lasreadopener.open(); lasreader->populate_rank_points(); LASreaderMerged *lasreadermerged = (LASreaderMerged *)lasreader; I32 process_count = lasreadermerged->get_process_count(); dbg(3, "rank %i, lasreadermerged->npoints %lli", lasreadermerged->get_rank(), lasreadermerged->npoints); for (i=0; i<process_count; i++) { dbg(3, "rank %i, rank_begin_point %lli", lasreadermerged->get_rank(), lasreadermerged->get_rank_begin_index()[i]); for(int j=lasreadermerged->get_file_name_start(); j< lasreadermerged->get_file_name_number(); j++) { dbg(3, "rank %i, number %i name %s count %lli, begin", lasreadermerged->get_rank(), j, lasreadermerged->get_file_names()[j], lasreadermerged->get_file_point_counts()[j]); } } dbg(3,"type of reader returned: class %s and declared name %s", typeid(*lasreader).name(), quote(*lasreader)); if (lasreader == 0) { fprintf(stderr, "ERROR: could not open lasreader\n"); byebye(true, argc==1); } #ifdef _WIN32 if (verbose) { fprintf(stderr,"merging headers took %g sec. there are %I64d points in total.\n", taketime()-start_time, lasreader->npoints); start_time = taketime(); } #else if (verbose) { fprintf(stderr,"merging headers took %g sec. there are %lld points in total.\n", taketime()-start_time, lasreader->npoints); start_time = taketime(); } #endif // prepare the header for the surviving points strncpy(lasreader->header.system_identifier, "LAStools (c) by rapidlasso GmbH", 32); lasreader->header.system_identifier[31] = '\0'; char temp[64]; sprintf(temp, "lasmerge (version %d)", LAS_TOOLS_VERSION); strncpy(lasreader->header.generating_software, temp, 32); lasreader->header.generating_software[31] = '\0'; if (projection_was_set) { lasreader->header.set_geo_keys(number_of_keys, (LASvlr_key_entry*)geo_keys); free(geo_keys); if (geo_double_params) { lasreader->header.set_geo_double_params(num_geo_double_params, geo_double_params); free(geo_double_params); } else { lasreader->header.del_geo_double_params(); } lasreader->header.del_geo_ascii_params(); } if (chopchop) { I32 file_number = 0; LASwriter* laswriter = 0; // loop over the points while (lasreader->read_point()) { if (laswriter == 0) { // open the next writer laswriteopener.make_file_name(0, file_number); file_number++; laswriter = laswriteopener.open(&lasreader->header); } laswriter->write_point(&lasreader->point); laswriter->update_inventory(&lasreader->point); if (laswriter->p_count == chopchop) { // close the current writer laswriter->update_header(&lasreader->header, TRUE); laswriter->close(); if (verbose) { fprintf(stderr,"splitting file '%s' took %g sec.\n", laswriteopener.get_file_name(), taketime()-start_time); start_time = taketime(); } delete laswriter; laswriter = 0; } } if (laswriter && laswriter->p_count) { // close the current writer laswriter->update_header(&lasreader->header, TRUE); laswriter->close(); if (verbose) { fprintf(stderr,"splitting file '%s' took %g sec.\n", laswriteopener.get_file_name(), taketime()-start_time); start_time = taketime(); } delete laswriter; laswriter = 0; } } else { // wait for all processes to open their input files MPI_Barrier(MPI_COMM_WORLD); // all processes open a writer LASwriter* laswriter = laswriteopener.open (&lasreader->header); // set the write file pointer... no filter support, assumes all input file's points are written to output file //ByteStreamOutFileLE *bs = (ByteStreamOutFileLE*) laswriter->get_stream (); <-- this is the ByteStreamOut type for las files ByteStreamOut *bs = laswriter->get_stream (); I64 begin_index = (lasreadermerged->get_rank_begin_index())[lasreadermerged->get_rank ()]; bs->seek (lasreader->header.point_data_record_length * begin_index + lasreader->header.offset_to_point_data); if (laswriter == 0) { fprintf (stderr, "ERROR: could not open laswriter\n"); byebye (true, argc == 1); } // wait for all processes to open the output file and set their write file pointers. MPI_Barrier(MPI_COMM_WORLD); // loop over the points while (lasreader->read_point()) { laswriter->write_point(&lasreader->point); laswriter->update_inventory(&lasreader->point); } int rank = lasreadermerged->get_rank(); if(rank!=0) { laswriter->close(FALSE); } MPI_Barrier(MPI_COMM_WORLD); // not needed since reduce causes barrier, used for testing // this whole MPI_Reduce section is not technically needed since we don't yet support point filtering, // It was implemented now to ensure that it will work when point filtering of input files is supported MPI_Reduce(&(laswriter->inventory.extended_number_of_point_records), &extended_number_of_point_records, 1, MPI_LONG_LONG_INT, MPI_SUM, 0, MPI_COMM_WORLD); int i; for(i=0; i<16; i++) { MPI_Reduce(&(laswriter->inventory.extended_number_of_points_by_return[i]), &extended_number_of_points_by_return[i], 1, MPI_LONG_LONG_INT, MPI_SUM, 0, MPI_COMM_WORLD); } MPI_Reduce(&(laswriter->inventory.max_X), &max_X, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); MPI_Reduce(&(laswriter->inventory.min_X), &min_X, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD); MPI_Reduce(&(laswriter->inventory.max_Y), &max_Y, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); MPI_Reduce(&(laswriter->inventory.min_Y), &min_Y, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD); MPI_Reduce(&(laswriter->inventory.max_Z), &max_Z, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); MPI_Reduce(&(laswriter->inventory.min_Z), &min_Z, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD); if(rank==0) { dbg(3, "extended_number_of_point_records %lli", extended_number_of_point_records); laswriter->inventory.extended_number_of_point_records = extended_number_of_point_records; for(i=0; i<16; i++) { laswriter->inventory.extended_number_of_points_by_return[i] = extended_number_of_points_by_return[i]; } laswriter->inventory.max_X = max_X; laswriter->inventory.min_X = min_X; laswriter->inventory.max_Y = max_Y; laswriter->inventory.min_Y = min_Y; laswriter->inventory.max_Z = max_Z; laswriter->inventory.min_Z = min_Z; } dbg(3, "rank %i, point data record length %i", lasreadermerged->get_rank(), lasreader->header.point_data_record_length); // close the writer if(rank==0) { // update header should only be called with TRUE when using the MPI_Reduce calls above, // lasreadopener.open(), called above, generates a correct header for the output file, provided no points are filtered during the read laswriter->update_header(&lasreader->header, TRUE); laswriter->close(FALSE); } if (verbose) fprintf(stderr,"merging files took %g sec.\n", taketime()-start_time); delete laswriter; } MPI_Finalize(); lasreader->close(); delete lasreader; byebye(false, argc==1); return 0; }
BOOL LASindex::append(const char* file_name) const { #ifdef LASZIPDLL_EXPORTS return FALSE; #else LASreadOpener lasreadopener; if (file_name == 0) return FALSE; // open reader LASreader* lasreader = lasreadopener.open(file_name); if (lasreader == 0) return FALSE; if (lasreader->header.laszip == 0) return FALSE; // close reader lasreader->close(); FILE* file = fopen(file_name, "rb"); ByteStreamIn* bytestreamin = 0; if (IS_LITTLE_ENDIAN()) bytestreamin = new ByteStreamInFileLE(file); else bytestreamin = new ByteStreamInFileBE(file); // maybe write LASindex EVLR start position into LASzip VLR I64 offset_laz_vlr = -1; // where to write LASindex EVLR that will contain the LAX file I64 number_of_special_evlrs = lasreader->header.laszip->number_of_special_evlrs; I64 offset_to_special_evlrs = lasreader->header.laszip->offset_to_special_evlrs; if ((number_of_special_evlrs == -1) && (offset_to_special_evlrs == -1)) { bytestreamin->seekEnd(); number_of_special_evlrs = 1; offset_to_special_evlrs = bytestreamin->tell(); // find LASzip VLR I64 total = lasreader->header.header_size + 2; U32 number_of_variable_length_records = lasreader->header.number_of_variable_length_records + 1 + (lasreader->header.vlr_lastiling != 0) + (lasreader->header.vlr_lasoriginal != 0); for (U32 u = 0; u < number_of_variable_length_records; u++) { bytestreamin->seek(total); CHAR user_id[16]; try { bytestreamin->getBytes((U8*)user_id, 16); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].user_id\n", u); return FALSE; } if (strcmp(user_id, "laszip encoded") == 0) { offset_laz_vlr = bytestreamin->tell() - 18; break; } U16 record_id; try { bytestreamin->get16bitsLE((U8*)&record_id); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].record_id\n", u); return FALSE; } U16 record_length_after_header; try { bytestreamin->get16bitsLE((U8*)&record_length_after_header); } catch(...) { fprintf(stderr,"ERROR: reading header.vlrs[%d].record_length_after_header\n", u); return FALSE; } total += (54 + record_length_after_header); } if (number_of_special_evlrs == -1) return FALSE; } delete bytestreamin; fclose(file); ByteStreamOut* bytestreamout; file = fopen(file_name, "rb+"); if (IS_LITTLE_ENDIAN()) bytestreamout = new ByteStreamOutFileLE(file); else bytestreamout = new ByteStreamOutFileBE(file); bytestreamout->seek(offset_to_special_evlrs); LASevlr lax_evlr; sprintf(lax_evlr.user_id, "LAStools"); lax_evlr.record_id = 30; sprintf(lax_evlr.description, "LAX spatial indexing (LASindex)"); bytestreamout->put16bitsLE((U8*)&(lax_evlr.reserved)); bytestreamout->putBytes((U8*)lax_evlr.user_id, 16); bytestreamout->put16bitsLE((U8*)&(lax_evlr.record_id)); bytestreamout->put64bitsLE((U8*)&(lax_evlr.record_length_after_header)); bytestreamout->putBytes((U8*)lax_evlr.description, 32); if (!write(bytestreamout)) { fprintf(stderr,"ERROR (LASindex): cannot append LAX to '%s'\n", file_name); delete bytestreamout; fclose(file); delete lasreader; return FALSE; } // update LASindex EVLR lax_evlr.record_length_after_header = bytestreamout->tell() - offset_to_special_evlrs - 60; bytestreamout->seek(offset_to_special_evlrs + 20); bytestreamout->put64bitsLE((U8*)&(lax_evlr.record_length_after_header)); // maybe update LASzip VLR if (number_of_special_evlrs != -1) { bytestreamout->seek(offset_laz_vlr + 54 + 16); bytestreamout->put64bitsLE((U8*)&number_of_special_evlrs); bytestreamout->put64bitsLE((U8*)&offset_to_special_evlrs); } // close writer bytestreamout->seekEnd(); delete bytestreamout; fclose(file); // delete reader delete lasreader; return TRUE; #endif }