1 /*
2 ===============================================================================
3
4 FILE: lasmerge.cpp
5
6 CONTENTS:
7
8 This tool merges multiple LAS file into a single LAS file and outputs it in
9 the LAS format. As input the user either provides multiple LAS file names or
10 a text file containing a list of LAS file names.
11
12 PROGRAMMERS:
13
14 martin.isenburg@rapidlasso.com - http://rapidlasso.com
15
16 COPYRIGHT:
17
18 (c) 2007-12, martin isenburg, rapidlasso - fast tools to catch reality
19
20 This is free software; you can redistribute and/or modify it under the
21 terms of the GNU Lesser General Licence as published by the Free Software
22 Foundation. See the LICENSE.txt file for more information.
23
24 This software is distributed WITHOUT ANY WARRANTY and without even the
25 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26
27 CHANGE HISTORY:
28
29 20 August 2014 -- new option '-keep_lastiling' to preserve the LAStiling VLR
30 20 August 2014 -- copy VLRs from empty (zero points) LAS/LAZ files to others
31 5 August 2011 -- possible to add/change projection info in command line
32 13 May 2011 -- moved indexing, filtering, transforming into LASreader
33 21 January 2011 -- added LASreadOpener and reading of multiple LAS files
34 7 January 2011 -- added the LASfilter to drop or keep points
35 12 March 2009 -- updated to ask for input if started without arguments
36 07 November 2007 -- created after email from luis.viveros@digimapas.cl
37
38 ===============================================================================
39 */
40
41 #include <time.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "lasreader.hpp"
46 #include "laswriter.hpp"
47 #include "geoprojectionconverter.hpp"
48
usage(bool error=false,bool wait=false)49 void usage(bool error=false, bool wait=false)
50 {
51 fprintf(stderr,"usage:\n");
52 fprintf(stderr,"lasmerge -i *.las -o out.las\n");
53 fprintf(stderr,"lasmerge -lof lasfiles.txt -o out.las\n");
54 fprintf(stderr,"lasmerge -i *.las -o out0000.laz -split 1000000000\n");
55 fprintf(stderr,"lasmerge -i file1.las file2.las file3.las -o out.las\n");
56 fprintf(stderr,"lasmerge -i file1.las file2.las -reoffset 600000 4000000 0 -olas > out.las\n");
57 fprintf(stderr,"lasmerge -lof lasfiles.txt -rescale 0.01 0.01 0.01 -verbose -o out.las\n");
58 fprintf(stderr,"lasmerge -h\n");
59 if (wait)
60 {
61 fprintf(stderr,"<press ENTER>\n");
62 getc(stdin);
63 }
64 exit(error);
65 }
66
byebye(bool error=false,bool wait=false)67 static void byebye(bool error=false, bool wait=false)
68 {
69 if (wait)
70 {
71 fprintf(stderr,"<press ENTER>\n");
72 getc(stdin);
73 }
74 exit(error);
75 }
76
taketime()77 static double taketime()
78 {
79 return (double)(clock())/CLOCKS_PER_SEC;
80 }
81
82 #ifdef COMPILE_WITH_GUI
83 extern int lasmerge_gui(int argc, char *argv[], LASreadOpener* lasreadopener);
84 #endif
85
main(int argc,char * argv[])86 int main(int argc, char *argv[])
87 {
88 int i;
89 #ifdef COMPILE_WITH_GUI
90 bool gui = false;
91 #endif
92 bool verbose = false;
93 bool keep_lastiling = false;
94 U32 chopchop = 0;
95 bool projection_was_set = false;
96 double start_time = 0;
97
98 LASreadOpener lasreadopener;
99 GeoProjectionConverter geoprojectionconverter;
100 LASwriteOpener laswriteopener;
101
102 if (argc == 1)
103 {
104 #ifdef COMPILE_WITH_GUI
105 return lasmerge_gui(argc, argv, 0);
106 #else
107 fprintf(stderr,"%s is better run in the command line\n", argv[0]);
108 char file_name[256];
109 fprintf(stderr,"enter input file 1: "); fgets(file_name, 256, stdin);
110 file_name[strlen(file_name)-1] = '\0';
111 lasreadopener.add_file_name(file_name);
112 fprintf(stderr,"enter input file 2: "); fgets(file_name, 256, stdin);
113 file_name[strlen(file_name)-1] = '\0';
114 lasreadopener.add_file_name(file_name);
115 fprintf(stderr,"enter output file: "); fgets(file_name, 256, stdin);
116 file_name[strlen(file_name)-1] = '\0';
117 laswriteopener.set_file_name(file_name);
118 #endif
119 }
120 else
121 {
122 for (i = 1; i < argc; i++)
123 {
124 if (argv[i][0] == '�') argv[i][0] = '-';
125 }
126 if (!geoprojectionconverter.parse(argc, argv)) byebye(true);
127 if (!lasreadopener.parse(argc, argv)) byebye(true);
128 if (!laswriteopener.parse(argc, argv)) byebye(true);
129 }
130
131 for (i = 1; i < argc; i++)
132 {
133 if (argv[i][0] == '\0')
134 {
135 continue;
136 }
137 else if (strcmp(argv[i],"-h") == 0 || strcmp(argv[i],"-help") == 0)
138 {
139 fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
140 usage();
141 }
142 else if (strcmp(argv[i],"-v") == 0 || strcmp(argv[i],"-verbose") == 0)
143 {
144 verbose = true;
145 }
146 else if (strcmp(argv[i],"-version") == 0)
147 {
148 fprintf(stderr, "LAStools (by martin@rapidlasso.com) version %d\n", LAS_TOOLS_VERSION);
149 byebye();
150 }
151 else if (strcmp(argv[i],"-gui") == 0)
152 {
153 #ifdef COMPILE_WITH_GUI
154 gui = true;
155 #else
156 fprintf(stderr, "WARNING: not compiled with GUI support. ignoring '-gui' ...\n");
157 #endif
158 }
159 else if (strcmp(argv[i],"-split") == 0)
160 {
161 if ((i+1) >= argc)
162 {
163 fprintf(stderr,"ERROR: '%s' needs 1 argument: size\n", argv[i]);
164 byebye(true);
165 }
166 i++;
167 chopchop = atoi(argv[i]);
168 }
169 else if (strcmp(argv[i],"-keep_lastiling") == 0)
170 {
171 keep_lastiling = true;
172 }
173 else if ((argv[i][0] != '-') && (lasreadopener.get_file_name_number() == 0))
174 {
175 lasreadopener.add_file_name(argv[i]);
176 argv[i][0] = '\0';
177 }
178 else
179 {
180 fprintf(stderr, "ERROR: cannot understand argument '%s'\n", argv[i]);
181 byebye(true);
182 }
183 }
184
185 #ifdef COMPILE_WITH_GUI
186 if (gui)
187 {
188 return lasmerge_gui(argc, argv, &lasreadopener);
189 }
190 #endif
191
192 // read all the input files merged
193
194 lasreadopener.set_merged(TRUE);
195
196 // maybe we want to keep the lastiling
197
198 if (keep_lastiling)
199 {
200 lasreadopener.set_keep_lastiling(TRUE);
201 }
202
203 // we need to precompute the bounding box
204
205 lasreadopener.set_populate_header(TRUE);
206
207 // check input and output
208
209 if (!lasreadopener.active())
210 {
211 fprintf(stderr, "ERROR: no input specified\n");
212 byebye(true, argc==1);
213 }
214
215 if (!laswriteopener.active())
216 {
217 fprintf(stderr, "ERROR: no output specified\n");
218 byebye(true, argc==1);
219 }
220
221 // make sure we do not corrupt the input file
222
223 if (lasreadopener.get_file_name() && laswriteopener.get_file_name() && (strcmp(lasreadopener.get_file_name(), laswriteopener.get_file_name()) == 0))
224 {
225 fprintf(stderr, "ERROR: input and output file name are identical\n");
226 usage(true);
227 }
228
229 // check if projection info was set in the command line
230
231 int number_of_keys;
232 GeoProjectionGeoKeys* geo_keys = 0;
233 int num_geo_double_params;
234 double* geo_double_params = 0;
235
236 if (geoprojectionconverter.has_projection())
237 {
238 projection_was_set = geoprojectionconverter.get_geo_keys_from_projection(number_of_keys, &geo_keys, num_geo_double_params, &geo_double_params);
239 }
240
241 if (verbose) start_time = taketime();
242
243 LASreader* lasreader = lasreadopener.open();
244 if (lasreader == 0)
245 {
246 fprintf(stderr, "ERROR: could not open lasreader\n");
247 byebye(true, argc==1);
248 }
249
250 #ifdef _WIN32
251 if (verbose) { fprintf(stderr,"merging headers took %g sec. there are %I64d points in total.\n", taketime()-start_time, lasreader->npoints); start_time = taketime(); }
252 #else
253 if (verbose) { fprintf(stderr,"merging headers took %g sec. there are %lld points in total.\n", taketime()-start_time, lasreader->npoints); start_time = taketime(); }
254 #endif
255
256 // prepare the header for the surviving points
257
258 strncpy(lasreader->header.system_identifier, "LAStools (c) by rapidlasso GmbH", 32);
259 lasreader->header.system_identifier[31] = '\0';
260 char temp[64];
261 sprintf(temp, "lasmerge (version %d)", LAS_TOOLS_VERSION);
262 strncpy(lasreader->header.generating_software, temp, 32);
263 lasreader->header.generating_software[31] = '\0';
264
265 if (projection_was_set)
266 {
267 lasreader->header.set_geo_keys(number_of_keys, (LASvlr_key_entry*)geo_keys);
268 free(geo_keys);
269 if (geo_double_params)
270 {
271 lasreader->header.set_geo_double_params(num_geo_double_params, geo_double_params);
272 free(geo_double_params);
273 }
274 else
275 {
276 lasreader->header.del_geo_double_params();
277 }
278 lasreader->header.del_geo_ascii_params();
279 }
280
281 if (chopchop)
282 {
283 I32 file_number = 0;
284 LASwriter* laswriter = 0;
285 // loop over the points
286 while (lasreader->read_point())
287 {
288 if (laswriter == 0)
289 {
290 // open the next writer
291 laswriteopener.make_file_name(0, file_number);
292 file_number++;
293 laswriter = laswriteopener.open(&lasreader->header);
294 }
295 laswriter->write_point(&lasreader->point);
296 laswriter->update_inventory(&lasreader->point);
297 if (laswriter->p_count == chopchop)
298 {
299 // close the current writer
300 laswriter->update_header(&lasreader->header, TRUE);
301 laswriter->close();
302 if (verbose) { fprintf(stderr,"splitting file '%s' took %g sec.\n", laswriteopener.get_file_name(), taketime()-start_time); start_time = taketime(); }
303 delete laswriter;
304 laswriter = 0;
305 }
306 }
307 if (laswriter && laswriter->p_count)
308 {
309 // close the current writer
310 laswriter->update_header(&lasreader->header, TRUE);
311 laswriter->close();
312 if (verbose) { fprintf(stderr,"splitting file '%s' took %g sec.\n", laswriteopener.get_file_name(), taketime()-start_time); start_time = taketime(); }
313 delete laswriter;
314 laswriter = 0;
315 }
316 }
317 else
318 {
319 if (lasreader->npoints > U32_MAX)
320 {
321 if (lasreader->header.version_minor < 4)
322 {
323 #ifdef _WIN32
324 fprintf(stderr, "ERROR: cannot merge %I64d points into single LAS 1.%d file. maximum is %u\n", lasreader->npoints, lasreader->header.version_minor, U32_MAX);
325 #else
326 fprintf(stderr, "ERROR: cannot merge %lld points into single LAS 1.%d file. maximum is %u\n", lasreader->npoints, lasreader->header.version_minor, U32_MAX);
327 #endif
328 byebye(true, argc==1);
329 }
330 }
331
332 // open the writer
333 LASwriter* laswriter = laswriteopener.open(&lasreader->header);
334 if (laswriter == 0)
335 {
336 fprintf(stderr, "ERROR: could not open laswriter\n");
337 byebye(true, argc==1);
338 }
339 // loop over the points
340 while (lasreader->read_point())
341 {
342 laswriter->write_point(&lasreader->point);
343 laswriter->update_inventory(&lasreader->point);
344 }
345 // close the writer
346 laswriter->update_header(&lasreader->header, TRUE);
347 laswriter->close();
348 if (verbose) fprintf(stderr,"merging files took %g sec.\n", taketime()-start_time);
349 delete laswriter;
350 }
351
352 lasreader->close();
353 delete lasreader;
354
355 byebye(false, argc==1);
356
357 return 0;
358 }
359