1 /***************************************************************************
2 *
3 * Project: libLAS -- C/C++ read/write library for LAS LIDAR data
4 * Purpose: LAS translation to PostgreSQL binary format with optional configuration
5 * Author: Oscar Martinez Rubi o.rubi@esciencecenter.nl
6 ***************************************************************************
7 * This tool has been developed by the Netherlands eScience Center
8 * (https://www.esciencecenter.nl/)
9 *
10 * Copyright (c) 2016, Oscar Martinez Rubi o.rubi@esciencecenter.nl
11 *
12 * See LICENSE.txt in this source distribution for more information.
13 **************************************************************************/
14
15 #include <time.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <stdint.h>
21 #include <limits.h>
22 #include <inttypes.h>
23 #if defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
24
25 # include <endian.h>
26
27 #elif defined(__APPLE__)
28
29 # include <libkern/OSByteOrder.h>
30
31 # define htobe16(x) OSSwapHostToBigInt16(x)
32 # define htole16(x) OSSwapHostToLittleInt16(x)
33 # define be16toh(x) OSSwapBigToHostInt16(x)
34 # define le16toh(x) OSSwapLittleToHostInt16(x)
35
36 # define htobe32(x) OSSwapHostToBigInt32(x)
37 # define htole32(x) OSSwapHostToLittleInt32(x)
38 # define be32toh(x) OSSwapBigToHostInt32(x)
39 # define le32toh(x) OSSwapLittleToHostInt32(x)
40
41 # define htobe64(x) OSSwapHostToBigInt64(x)
42 # define htole64(x) OSSwapHostToLittleInt64(x)
43 # define be64toh(x) OSSwapBigToHostInt64(x)
44 # define le64toh(x) OSSwapLittleToHostInt64(x)
45
46 # define __BYTE_ORDER BYTE_ORDER
47 # define __BIG_ENDIAN BIG_ENDIAN
48 # define __LITTLE_ENDIAN LITTLE_ENDIAN
49 # define __PDP_ENDIAN PDP_ENDIAN
50
51 #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
52
53 # include <sys/endian.h>
54
55 #elif defined(__NetBSD__)
56
57 # include <sys/endian.h>
58
59 # define be16toh(x) betoh16(x)
60 # define le16toh(x) letoh16(x)
61
62 # define be32toh(x) betoh32(x)
63 # define le32toh(x) letoh32(x)
64
65 # define be64toh(x) betoh64(x)
66 # define le64toh(x) letoh64(x)
67
68 #elif defined(__WINDOWS__)
69
70 # include <winsock2.h>
71 # include <sys/param.h>
72
73 # if BYTE_ORDER == LITTLE_ENDIAN
74
75 # define htobe16(x) htons(x)
76 # define htole16(x) (x)
77 # define be16toh(x) ntohs(x)
78 # define le16toh(x) (x)
79
80 # define htobe32(x) htonl(x)
81 # define htole32(x) (x)
82 # define be32toh(x) ntohl(x)
83 # define le32toh(x) (x)
84
85 # define htobe64(x) htonll(x)
86 # define htole64(x) (x)
87 # define be64toh(x) ntohll(x)
88 # define le64toh(x) (x)
89
90 # elif BYTE_ORDER == BIG_ENDIAN
91
92 /* that would be xbox 360 */
93 # define htobe16(x) (x)
94 # define htole16(x) __builtin_bswap16(x)
95 # define be16toh(x) (x)
96 # define le16toh(x) __builtin_bswap16(x)
97
98 # define htobe32(x) (x)
99 # define htole32(x) __builtin_bswap32(x)
100 # define be32toh(x) (x)
101 # define le32toh(x) __builtin_bswap32(x)
102
103 # define htobe64(x) (x)
104 # define htole64(x) __builtin_bswap64(x)
105 # define be64toh(x) (x)
106 # define le64toh(x) __builtin_bswap64(x)
107
108 # else
109
110 # error byte order not supported
111
112 # endif
113
114 # define __BYTE_ORDER BYTE_ORDER
115 # define __BIG_ENDIAN BIG_ENDIAN
116 # define __LITTLE_ENDIAN LITTLE_ENDIAN
117 # define __PDP_ENDIAN PDP_ENDIAN
118
119 #else
120
121 # error platform not supported
122
123 #endif
124
125 #include <math.h>
126
127 #include "liblas.h"
128
129 #ifndef _BSD_SOURCE
130 #define _BSD_SOURCE
131 #endif
132
133 #define combine(a,b,c) ( (a) = ((unsigned long long)(b) << 32) | (c) )
134
135 unsigned int unity = 1;
136 #define is_littleEndian() (*(unsigned char *)&unity) // will return 1 if little endian, otherwise 0
137
138 #define TOLERANCE 0.0000001
139 #define MAX_INT_31 2147483648.0
140
141 #define VERSION "1.1"
142
143
144 struct postHeader {
145 char *s;
146 uint32_t i1;
147 uint32_t i2;
148 };
149
150 struct postRow {
151 uint16_t h;
152 uint32_t varSize;
153 uint32_t vardSize;
154 };
155
156 void print_header(FILE *file, LASHeaderH header, const char* file_name);
157
usage()158 void usage()
159 {
160 fprintf(stderr,"----------------------------------------------------------\n");
161 fprintf(stderr," las2pg (version %s) usage:\n", VERSION);
162 fprintf(stderr,"----------------------------------------------------------\n");
163 fprintf(stderr,"\n");
164
165 fprintf(stderr,"Convert a las/laz file into PostgreSQL binary dump format, outputs <input_file>:\n");
166 fprintf(stderr," las2pg -i <input_file>.las\n");
167 fprintf(stderr,"\n");
168
169 fprintf(stderr,"Convert a las/laz file into PostgreSQL binary dump format, outputs <output_name>:\n");
170 fprintf(stderr," las2pg -i <input_file>.las -o <output_name>\n");
171 fprintf(stderr,"Use flag --stdout to write to standard output (recommended use together with a pipe, see below).\n");
172 fprintf(stderr,"\n\n");
173
174 fprintf(stderr,"----------------------------------------------------------\n");
175 fprintf(stderr," The '--parse txyzia' flag specifies what exactly to\n");
176 fprintf(stderr," write for each row (default is --parse xyz). For example, 'txyzia'\n");
177 fprintf(stderr," means that the first field of each row will be the\n");
178 fprintf(stderr," gpstime, the next three fields will be the x, y, and\n");
179 fprintf(stderr," z coordinates, the next field will be the intensity\n");
180 fprintf(stderr," and the next field will be the scan angle.\n");
181 fprintf(stderr," The supported entries are:\n");
182 fprintf(stderr," t - gpstime as double\n");
183 fprintf(stderr," x - x coordinate as double\n");
184 fprintf(stderr," y - y coordinate as double\n");
185 fprintf(stderr," z - z coordinate as double\n");
186 fprintf(stderr," a - scan angle as integer\n");
187 fprintf(stderr," i - intensity as integer\n");
188 fprintf(stderr," n - number of returns for given pulse as integer\n");
189 fprintf(stderr," r - number of this return as integer\n");
190 fprintf(stderr," c - classification number as integer\n");
191 fprintf(stderr," u - user data as integer\n");
192 fprintf(stderr," p - point source ID as integer\n");
193 fprintf(stderr," e - edge of flight line as integer\n");
194 fprintf(stderr," d - direction of scan flag as integer\n");
195 fprintf(stderr," R - red channel of RGB color as integer\n");
196 fprintf(stderr," G - green channel of RGB color as integer\n");
197 fprintf(stderr," B - blue channel of RGB color as integer\n");
198 fprintf(stderr," M - vertex index number as integer\n");
199 fprintf(stderr," k - Morton 2D code using X and Y (unscaled and no offset) as bigint\n\n");
200
201 fprintf(stderr," The moffset flag (for example '--moffset 8600000,40000000') specifies a global offset to subtract to X and Y \n");
202 fprintf(stderr," to be used when computing the Morton 2D code. Values must be unscaled \n\n");
203
204 fprintf(stderr," The check flag (for example '--check 0.01,0.01') checks suitability to compute Morton 2D codes \n");
205 fprintf(stderr," It checks specified scale matches the one in input file. \n");
206 fprintf(stderr," If moffset is provided it also checks that obtained Morton 2D codes \n");
207 fprintf(stderr," will be consistent, i.e. global X,Y within [0,2^31] \n\n");
208
209 fprintf(stderr,"----------------------------------------------------------\n");
210
211 fprintf(stderr," The intended use of this tool is by using the --stdout flag and a pipe to avoid storing intermediate files. Example: \n");
212 fprintf(stderr," las2pg 1.2-with-color.laz --parse xyzRGBi --stdout | psql -c \"copy flat from stdin with binary\" \n");
213 fprintf(stderr," This obviously require a table called flat to be created in a PostgreSQL DB beforehand. The table must have \n");
214 fprintf(stderr," the columns in the same order as specified by the --parse option, and the column types must be the ones specified above. Example: \n");
215 fprintf(stderr," psql -c \"create table flat (x double precision, y double precision, z double precision, r integer, g integer, b integer, i integer)\" \n\n");
216 }
217
218
bigEndian_double(double a)219 uint64_t bigEndian_double(double a)
220 {
221 uint64_t b;
222 unsigned char *src = (unsigned char *)&a,
223 *dst = (unsigned char *)&b;
224
225 if (is_littleEndian())
226 {
227 dst[0] = src[7];
228 dst[1] = src[6];
229 dst[2] = src[5];
230 dst[3] = src[4];
231 dst[4] = src[3];
232 dst[5] = src[2];
233 dst[6] = src[1];
234 dst[7] = src[0];
235 }
236 else
237 b = *(uint64_t *)&a;
238
239 return b;
240 }
241
S64(const char * s)242 int64_t S64(const char *s) {
243 int64_t i;
244 char c ;
245 int scanned = sscanf(s, "%" SCNd64 "%c", &i, &c);
246 if (scanned == 1) return i;
247 fprintf(stderr, "ERROR: parsing string to int64_t.\n");
248 exit(1);
249 }
250
Expand1(uint32_t a)251 static uint64_t Expand1(uint32_t a)
252 {
253 uint64_t b = a & 0x7fffffff; // b = ---- ---- ---- ---- ---- ---- ---- ---- 0edc ba98 7654 3210 fedc ba98 7654 3210
254 b = (b ^ (b << 16)) & 0x0000ffff0000ffff; // b = ---- ---- ---- ---- 0edc ba98 7654 3210 ---- ---- ---- ---- fedc ba98 7654 3210
255 b = (b ^ (b << 8)) & 0x00ff00ff00ff00ff; // b = ---- ---- 0edc ba98 ---- ---- 7654 3210 ---- ---- fedc ba98 ---- ---- 7654 3210
256 b = (b ^ (b << 4)) & 0x0f0f0f0f0f0f0f0f; // b = ---- 0edc ---- ba98 ---- 7654 ---- 3210 ---- fedc ---- ba98 ---- 7654 ---- 3210
257 b = (b ^ (b << 2)) & 0x3333333333333333; // b = --0e --dc --ba --98 --76 --54 --32 --10 --fe --dc --ba --98 --76 --54 --32 --10
258 b = (b ^ (b << 1)) & 0x5555555555555555; // b = -0-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0 -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
259 return b;
260 }
261
EncodeMorton2D(uint32_t x,uint32_t y)262 static uint64_t EncodeMorton2D(uint32_t x, uint32_t y)
263 {
264 return (Expand1(x) << 1) + Expand1(y);
265 }
266
main(int argc,char * argv[])267 int main(int argc, char *argv[])
268 {
269 int i;
270 int j;
271 char* buffer;
272 int use_stdout = FALSE;
273 int skip_invalid = FALSE;
274 int num_entries = 0;
275
276 int verbose = FALSE;
277 char* file_name_in = 0;
278 char* file_name_out = 0;
279 char separator_sign = ' ';
280 char* parse_string = "xyz";
281
282 int64_t global_offset_x = 0;
283 int64_t global_offset_y = 0;
284 int check = FALSE;
285 double scale_x;
286 double scale_y;
287
288 LASReaderH reader = NULL;
289 LASHeaderH header = NULL;
290 LASPointH p = NULL;
291 FILE* file_out;
292 int len;
293
294 unsigned int index = 0;
295 if (argc == 1) {
296 usage();
297 exit(0);
298 }
299
300 for (i = 1; i < argc; i++)
301 {
302 if ( strcmp(argv[i],"-h") == 0 ||
303 strcmp(argv[i],"-help") == 0 ||
304 strcmp(argv[i],"--help") == 0
305 )
306 {
307 usage();
308 exit(0);
309 }
310 else if ( strcmp(argv[i],"-v") == 0 ||
311 strcmp(argv[i],"--verbose") == 0
312 )
313 {
314 verbose = TRUE;
315 }
316 else if ( strcmp(argv[i],"-s") == 0 ||
317 strcmp(argv[i],"--skip_invalid") == 0
318 )
319 {
320 skip_invalid = TRUE;
321 }
322 else if ( strcmp(argv[i], "--parse") == 0 ||
323 strcmp(argv[i], "-parse") == 0
324 )
325 {
326 i++;
327 parse_string = argv[i];
328 }
329 else if ( strcmp(argv[i], "--moffset") == 0 ||
330 strcmp(argv[i], "-moffset") == 0
331 )
332 {
333 i++;
334 buffer = strtok (argv[i], ",");
335 j = 0;
336 while (buffer) {
337 if (j == 0) {
338 global_offset_x = S64(buffer);
339 }
340 else if (j == 1) {
341 global_offset_y = S64(buffer);
342 }
343 j++;
344 buffer = strtok (NULL, ",");
345 while (buffer && *buffer == '\040')
346 buffer++;
347 }
348 if (j != 2){
349 fprintf(stderr, "Only two int64_t are required in moffset option!\n");
350 exit(1);
351 }
352
353 }
354 else if ( strcmp(argv[i], "--check") == 0 ||
355 strcmp(argv[i], "-check") == 0
356 )
357 {
358 i++;
359 check = TRUE;
360 buffer = strtok (argv[i], ",");
361 j = 0;
362 while (buffer) {
363 if (j == 0) {
364 sscanf(buffer, "%lf", &scale_x);
365 }
366 else if (j == 1) {
367 sscanf(buffer, "%lf", &scale_y);
368 }
369 j++;
370 buffer = strtok (NULL, ",");
371 while (buffer && *buffer == '\040')
372 buffer++;
373 }
374 if (j != 2){
375 fprintf(stderr, "Only two doubles are required in moffset option!\n");
376 exit(1);
377 }
378 }
379 else if ( strcmp(argv[i], "--stdout") == 0
380 )
381 {
382 use_stdout = TRUE;
383 }
384 else if ( strcmp(argv[i],"--input") == 0 ||
385 strcmp(argv[i],"-input") == 0 ||
386 strcmp(argv[i],"-i") == 0 ||
387 strcmp(argv[i],"-in") == 0
388 )
389 {
390 i++;
391 file_name_in = argv[i];
392 }
393 else if ( strcmp(argv[i],"--output") == 0 ||
394 strcmp(argv[i],"--out") == 0 ||
395 strcmp(argv[i],"-out") == 0 ||
396 strcmp(argv[i],"-o") == 0
397 )
398 {
399 i++;
400 file_name_out = argv[i];
401 }
402 else if (file_name_in == 0 && file_name_out == 0)
403 {
404 file_name_in = argv[i];
405 }
406 else if (file_name_in && file_name_out == 0)
407 {
408 file_name_out = argv[i];
409 }
410 else
411 {
412 fprintf(stderr, "ERROR: unknown argument '%s'\n",argv[i]);
413 usage();
414 exit(1);
415 }
416 } /* end looping through argc/argv */
417 num_entries = strlen(parse_string);
418
419 if (use_stdout == TRUE && file_name_out){
420 LASError_Print("If an output file is specified, --stdout must not be used!");
421 exit(1);
422 }
423
424 reader = LASReader_Create(file_name_in);
425 if (!reader) {
426 LASError_Print("Unable to read file");
427 exit(1);
428 }
429
430 header = LASReader_GetHeader(reader);
431 if (!header) {
432 LASError_Print("Unable to fetch header for file");
433 exit(1);
434 }
435
436 if (use_stdout)
437 {
438 file_out = stdout;
439 }
440 else
441 {
442 if (file_name_out == NULL)
443 {
444 if (file_name_in == NULL)
445 {
446 LASError_Print("No input filename was specified");
447 usage();
448 exit(1);
449 }
450
451 len = (int)strlen(file_name_in);
452 file_name_out = LASCopyString(file_name_in);
453 if (file_name_out[len-3] == '.' && file_name_out[len-2] == 'g' && file_name_out[len-1] == 'z')
454 {
455 len = len - 4;
456 }
457 while (len > 0 && file_name_out[len] != '.')
458 {
459 len--;
460 }
461 file_name_out[len] = '\0';
462 }
463 file_out = fopen(file_name_out, "wb");
464 }
465
466 if (file_out == 0)
467 {
468 LASError_Print("Could not open file for write");
469 usage();
470 exit(1);
471 }
472
473 if (verbose)
474 {
475 print_header(stderr, header, file_name_in);
476 }
477
478 // Compute factors to add to X and Y and check sanity of generated codes
479 double file_scale_x = LASHeader_GetScaleX(header);
480 double file_scale_y = LASHeader_GetScaleY(header);
481
482 if (check)
483 {
484 // Check specified scales are like in the LAS file
485 if (fabs(scale_x - file_scale_x) > TOLERANCE){
486 fprintf(stderr, "ERROR: x scale in input file (%lf) does not match specified x scale (%lf)\n",file_scale_x, scale_x);
487 exit(1);
488 }
489 if (fabs(scale_y - file_scale_y) > TOLERANCE){
490 fprintf(stderr, "ERROR: y scale in input file (%lf) does not match specified y scale (%lf)\n",file_scale_y, scale_y);
491 exit(1);
492 }
493 /* Check that the extent of the file (taking into account the global offset)
494 * is within 0,2^31 */
495 double check_min_x = 1.0 + LASHeader_GetMinX(header) - (((double) global_offset_x) * scale_x);
496 if (check_min_x < TOLERANCE) {
497 fprintf(stderr, "ERROR: Specied X global offset is too large. (MinX - (GlobalX*ScaleX)) < 0\n");
498 exit(1);
499 }
500 double check_min_y = 1.0 + LASHeader_GetMinY(header) - (((double) global_offset_y) * scale_y);
501 if (check_min_y < TOLERANCE) {
502 fprintf(stderr, "ERROR: Specied Y global offset is too large. (MinY - (GlobalY*ScaleY)) < 0\n");
503 exit(1);
504 }
505 double check_max_x = LASHeader_GetMaxX(header) - (((double) global_offset_x) * scale_x);
506 if (check_max_x > (MAX_INT_31 * scale_x)) {
507 fprintf(stderr, "ERROR: Specied X global offset is too small. (MaxX - (GlobalX*ScaleX)) > (2^31)*ScaleX\n");
508 exit(1);
509 }
510 double check_max_y = LASHeader_GetMaxY(header) - (((double) global_offset_y) * scale_y);
511 if (check_max_y > (MAX_INT_31 * scale_y)) {
512 fprintf(stderr, "ERROR: Specied Y global offset is too small. (MaxY - (GlobalY*ScaleY)) > (2^31)*ScaleY\n");
513 exit(1);
514 }
515 }
516
517
518 /*Write Postgres header*/
519 struct postHeader pgHeader;
520 pgHeader.s = "PGCOPY\n\377\r\n\0";
521 int i1T = 0, i2T = 0;
522 pgHeader.i1 = htonl(i1T);
523 pgHeader.i2 = htonl(i2T);
524 fwrite(pgHeader.s, 11, 1, file_out);
525 fwrite(&pgHeader.i1, sizeof(uint32_t), 1, file_out);
526 fwrite(&pgHeader.i2, sizeof(uint32_t), 1, file_out);
527
528 /* declaration for morton*/
529 uint32_t rawx = 0;
530 uint32_t rawy = 0;
531 uint64_t mortonkey = 0;
532
533 /* scaled offsets to add for the morton encoding */
534 int64_t factorX = ((int64_t) (LASHeader_GetOffsetX(header) / file_scale_x)) - global_offset_x;
535 int64_t factorY = ((int64_t) (LASHeader_GetOffsetY(header) / file_scale_y)) - global_offset_y;
536
537 p = LASReader_GetNextPoint(reader);
538 while (p)
539 {
540 if (skip_invalid && !LASPoint_IsValid(p)) {
541 if (verbose) {
542 LASError_Print("Skipping writing invalid point...");
543 }
544 p = LASReader_GetNextPoint(reader);
545 index -=1;
546 continue;
547 }
548 struct postRow pgRow;
549 uint32_t size;
550 uint16_t hT = num_entries;
551 pgRow.h = htons(hT);
552 fwrite(& pgRow.h, 2, 1, file_out);
553 size = sizeof(double);
554 pgRow.vardSize = htonl(size);
555 size = sizeof(uint32_t);
556 pgRow.varSize = htonl(size);
557
558 i = 0;
559 for (;;)
560 {
561 LASColorH color = LASPoint_GetColor(p);
562 double vard;
563 int var;
564 unsigned long long int vardL, varL;
565
566 switch (parse_string[i])
567 {
568 /* // the morton code on xy */
569 case 'k':
570 rawx = (uint32_t) (((int64_t) LASPoint_GetRawX(p)) + factorX);
571 rawy = (uint32_t) (((int64_t) LASPoint_GetRawY(p)) + factorY);
572 mortonkey = EncodeMorton2D(rawx,rawy);
573 varL = htobe64(mortonkey);
574 fwrite(&pgRow.vardSize, sizeof(uint32_t), 1, file_out);
575 fwrite(&varL, sizeof(uint64_t), 1, file_out);
576 break;
577 /* // the x coordinate */
578 case 'x':
579 vard = LASPoint_GetX(p);
580 fwrite(&pgRow.vardSize, sizeof(uint32_t), 1, file_out);
581 vardL = bigEndian_double(vard);
582 fwrite(&vardL, sizeof(double), 1, file_out);
583 break;
584 /* // the y coordinate */
585 case 'y':
586 vard = LASPoint_GetY(p);
587 fwrite(&pgRow.vardSize, sizeof(uint32_t), 1, file_out);
588 vardL = bigEndian_double(vard);
589 fwrite(&vardL, sizeof(double), 1, file_out);
590 break;
591 /* // the z coordinate */
592 case 'z':
593 vard = LASPoint_GetZ(p);
594 fwrite(&pgRow.vardSize, sizeof(uint32_t), 1, file_out);
595 vardL = bigEndian_double(vard);
596 fwrite(&vardL, sizeof(double), 1, file_out);
597 break;
598 /* // the gps-time */
599 case 't':
600 vard = LASPoint_GetTime(p);
601 fwrite(&pgRow.vardSize, sizeof(uint32_t), 1, file_out);
602 vardL = bigEndian_double(vard);
603 fwrite(&vardL, sizeof(double), 1, file_out);
604 break;
605 /* // the intensity */
606 case 'i':
607 var = LASPoint_GetIntensity(p);
608 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
609 varL = htonl(var);
610 fwrite(&varL, sizeof(uint32_t), 1, file_out);
611 break;
612 /* the scan angle */
613 case 'a':
614 var = LASPoint_GetScanAngleRank(p);
615 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
616 varL = htonl(var);
617 fwrite(&varL, sizeof(uint32_t), 1, file_out);
618 break;
619 /* the number of the return */
620 case 'r':
621 var = LASPoint_GetReturnNumber(p);
622 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
623 varL = htonl(var);
624 fwrite(&varL, sizeof(uint32_t), 1, file_out);
625 break;
626 /* the classification */
627 case 'c':
628 var = LASPoint_GetClassification(p);
629 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
630 varL = htonl(var);
631 fwrite(&varL, sizeof(uint32_t), 1, file_out);
632 break;
633 /* the user data */
634 case 'u':
635 var = LASPoint_GetUserData(p);
636 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
637 varL = htonl(var);
638 fwrite(&varL, sizeof(uint32_t), 1, file_out);
639 break;
640 /* the number of returns of given pulse */
641 case 'n':
642 var = LASPoint_GetNumberOfReturns(p);
643 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
644 varL = htonl(var);
645 fwrite(&varL, sizeof(uint32_t), 1, file_out);
646 break;
647 /* the red channel color */
648 case 'R':
649 var = LASColor_GetRed(color);
650 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
651 varL = htonl(var);
652 fwrite(&varL, sizeof(uint32_t), 1, file_out);
653 break;
654 /* the green channel color */
655 case 'G':
656 var = LASColor_GetGreen(color);
657 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
658 varL = htonl(var);
659 fwrite(&varL, sizeof(uint32_t), 1, file_out);
660 break;
661 /* the blue channel color */
662 case 'B':
663 var = LASColor_GetBlue(color);
664 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
665 varL = htonl(var);
666 fwrite(&varL, sizeof(uint32_t), 1, file_out);
667 break;
668 case 'M':
669 var = index;
670 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
671 varL = htonl(var);
672 fwrite(&varL, sizeof(uint32_t), 1, file_out);
673 break;
674 case 'p':
675 var = LASPoint_GetPointSourceId(p);
676 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
677 varL = htonl(var);
678 fwrite(&varL, sizeof(uint32_t), 1, file_out);
679 break;
680 /* the edge of flight line flag */
681 case 'e':
682 var = LASPoint_GetFlightLineEdge(p);
683 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
684 varL = htonl(var);
685 fwrite(&varL, sizeof(uint32_t), 1, file_out);
686 break;
687 /* the direction of scan flag */
688 case 'd':
689 var = LASPoint_GetScanDirection(p);
690 fwrite(&pgRow.varSize, sizeof(uint32_t), 1, file_out);
691 varL = htonl(var);
692 fwrite(&varL, sizeof(uint32_t), 1, file_out);
693 break;
694 }
695 i++;
696 if (!parse_string[i])
697 {
698 break;
699 }
700 LASColor_Destroy(color);
701 }
702 p = LASReader_GetNextPoint(reader);
703 index +=1;
704 }
705 short endT = -1;
706 short end = htons(endT);
707 fwrite(&end, sizeof(end), 1, file_out);
708
709 fflush(file_out);
710 fclose(file_out);
711
712 LASReader_Destroy(reader);
713 LASHeader_Destroy(header);
714 return 0;
715 }
716