1 /*
2 ===============================================================================
3
4 FILE: laszip.cpp
5
6 CONTENTS:
7
8 see corresponding header file
9
10 PROGRAMMERS:
11
12 martin.isenburg@rapidlasso.com - http://rapidlasso.com
13
14 COPYRIGHT:
15
16 (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality
17
18 This is free software; you can redistribute and/or modify it under the
19 terms of the GNU Lesser General Licence as published by the Free Software
20 Foundation. See the COPYING file for more information.
21
22 This software is distributed WITHOUT ANY WARRANTY and without even the
23 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24
25 CHANGE HISTORY:
26
27 see corresponding header file
28
29 ===============================================================================
30 */
31 #include "laszip.hpp"
32
33 #include "mydefs.hpp"
34
35 #include <assert.h>
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40
LASzip()41 LASzip::LASzip()
42 {
43 compressor = LASZIP_COMPRESSOR_DEFAULT;
44 coder = LASZIP_CODER_ARITHMETIC;
45 version_major = LASZIP_VERSION_MAJOR;
46 version_minor = LASZIP_VERSION_MINOR;
47 version_revision = LASZIP_VERSION_REVISION;
48 options = 0;
49 num_items = 0;
50 chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
51 number_of_special_evlrs = -1;
52 offset_to_special_evlrs = -1;
53 error_string = 0;
54 items = 0;
55 bytes = 0;
56 }
57
~LASzip()58 LASzip::~LASzip()
59 {
60 if (error_string) free(error_string);
61 if (items) delete [] items;
62 if (bytes) delete [] bytes;
63 }
64
65 // the data of the LASzip VLR
66 // U16 compressor 2 bytes
67 // U16 coder 2 bytes
68 // U8 version_major 1 byte
69 // U8 version_minor 1 byte
70 // U16 version_revision 2 bytes
71 // U32 options 4 bytes
72 // U32 chunk_size 4 bytes
73 // I64 num_points 8 bytes
74 // I64 num_bytes 8 bytes
75 // U16 num_items 2 bytes
76 // U16 type 2 bytes * num_items
77 // U16 size 2 bytes * num_items
78 // U16 version 2 bytes * num_items
79 // which totals 34+6*num_items
80
81 // unpack from VLR data
unpack(const U8 * bytes,const I32 num)82 bool LASzip::unpack(const U8* bytes, const I32 num)
83 {
84 // check input
85 if (num < 34) return return_error("too few bytes to unpack");
86 if (((num - 34) % 6) != 0) return return_error("wrong number bytes to unpack");
87 if (((num - 34) / 6) == 0) return return_error("zero items to unpack");
88 num_items = (num - 34) / 6;
89
90 // create item list
91 if (items) delete [] items;
92 items = new LASitem[num_items];
93
94 // do the unpacking
95 U16 i;
96 const U8* b = bytes;
97 compressor = *((U16*)b);
98 b += 2;
99 coder = *((U16*)b);
100 b += 2;
101 version_major = *((U8*)b);
102 b += 1;
103 version_minor = *((U8*)b);
104 b += 1;
105 version_revision = *((U16*)b);
106 b += 2;
107 options = *((U32*)b);
108 b += 4;
109 chunk_size = *((U32*)b);
110 b += 4;
111 number_of_special_evlrs = *((I64*)b);
112 b += 8;
113 offset_to_special_evlrs = *((I64*)b);
114 b += 8;
115 num_items = *((U16*)b);
116 b += 2;
117 for (i = 0; i < num_items; i++)
118 {
119 items[i].type = (LASitem::Type)*((U16*)b);
120 b += 2;
121 items[i].size = *((U16*)b);
122 b += 2;
123 items[i].version = *((U16*)b);
124 b += 2;
125 }
126 assert((bytes + num) == b);
127
128 // check if we support the contents
129
130 for (i = 0; i < num_items; i++)
131 {
132 if (!check_item(&items[i])) return false;
133 }
134 return true;
135 }
136
137 // pack to VLR data
pack(U8 * & bytes,I32 & num)138 bool LASzip::pack(U8*& bytes, I32& num)
139 {
140 // check if we support the contents
141 if (!check()) return false;
142
143 // prepare output
144 num = 34 + 6*num_items;
145 if (this->bytes) delete [] this->bytes;
146 this->bytes = bytes = new U8[num];
147
148 // pack
149 U16 i;
150 U8* b = bytes;
151 *((U16*)b) = compressor;
152 b += 2;
153 *((U16*)b) = coder;
154 b += 2;
155 *((U8*)b) = version_major;
156 b += 1;
157 *((U8*)b) = version_minor;
158 b += 1;
159 *((U16*)b) = version_revision;
160 b += 2;
161 *((U32*)b) = options;
162 b += 4;
163 *((U32*)b) = chunk_size;
164 b += 4;
165 *((I64*)b) = number_of_special_evlrs;
166 b += 8;
167 *((I64*)b) = offset_to_special_evlrs;
168 b += 8;
169 *((U16*)b) = num_items;
170 b += 2;
171 for (i = 0; i < num_items; i++)
172 {
173 *((U16*)b) = (U16)items[i].type;
174 b += 2;
175 *((U16*)b) = items[i].size;
176 b += 2;
177 *((U16*)b) = items[i].version;
178 b += 2;
179 }
180 assert((bytes + num) == b);
181 return true;
182 }
183
get_error() const184 const char* LASzip::get_error() const
185 {
186 return error_string;
187 }
188
return_error(const char * error)189 bool LASzip::return_error(const char* error)
190 {
191
192 #if defined(_MSC_VER) && \
193 (_MSC_FULL_VER >= 150000000)
194 #define CopyString _strdup
195 #else
196 #define CopyString strdup
197 #endif
198 char err[256];
199 sprintf(err, "%s (LASzip v%d.%dr%d)", error, LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION);
200 if (error_string) free(error_string);
201 error_string = CopyString(err);
202 return false;
203 }
204
check_compressor(const U16 compressor)205 bool LASzip::check_compressor(const U16 compressor)
206 {
207 if (compressor < LASZIP_COMPRESSOR_TOTAL_NUMBER_OF) return true;
208 char error[64];
209 sprintf(error, "compressor %d not supported", compressor);
210 return return_error(error);
211 }
212
check_coder(const U16 coder)213 bool LASzip::check_coder(const U16 coder)
214 {
215 if (coder < LASZIP_CODER_TOTAL_NUMBER_OF) return true;
216 char error[64];
217 sprintf(error, "coder %d not supported", coder);
218 return return_error(error);
219 }
220
check_item(const LASitem * item)221 bool LASzip::check_item(const LASitem* item)
222 {
223 switch (item->type)
224 {
225 case LASitem::POINT10:
226 if (item->size != 20) return return_error("POINT10 has size != 20");
227 if (item->version > 2) return return_error("POINT10 has version > 2");
228 break;
229 case LASitem::GPSTIME11:
230 if (item->size != 8) return return_error("GPSTIME11 has size != 8");
231 if (item->version > 2) return return_error("GPSTIME11 has version > 2");
232 break;
233 case LASitem::RGB12:
234 if (item->size != 6) return return_error("RGB12 has size != 6");
235 if (item->version > 2) return return_error("RGB12 has version > 2");
236 break;
237 case LASitem::BYTE:
238 if (item->size < 1) return return_error("BYTE has size < 1");
239 if (item->version > 2) return return_error("BYTE has version > 2");
240 break;
241 case LASitem::POINT14:
242 if (item->size != 30) return return_error("POINT14 has size != 30");
243 if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("POINT14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
244 break;
245 case LASitem::RGB14:
246 if (item->size != 6) return return_error("RGB14 has size != 6");
247 if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGB14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
248 break;
249 case LASitem::RGBNIR14:
250 if (item->size != 8) return return_error("RGBNIR14 has size != 8");
251 if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("RGBNIR14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
252 break;
253 case LASitem::BYTE14:
254 if (item->size < 1) return return_error("BYTE14 has size < 1");
255 if ((item->version != 0) && (item->version != 2) && (item->version != 3) && (item->version != 4)) return return_error("BYTE14 has version != 0 and != 2 and != 3 and != 4"); // version == 2 from lasproto, version == 4 fixes context-switch
256 break;
257 case LASitem::WAVEPACKET13:
258 if (item->size != 29) return return_error("WAVEPACKET13 has size != 29");
259 if (item->version > 1) return return_error("WAVEPACKET13 has version > 1");
260 break;
261 case LASitem::WAVEPACKET14:
262 if (item->size != 29) return return_error("WAVEPACKET14 has size != 29");
263 if ((item->version != 0) && (item->version != 3) && (item->version != 4)) return return_error("WAVEPACKET14 has version != 0 and != 3 and != 4"); // version == 4 fixes context-switch
264 break;
265 default:
266 if (1)
267 {
268 char error[64];
269 sprintf(error, "item unknown (%d,%d,%d)", item->type, item->size, item->version);
270 return return_error(error);
271 }
272 }
273 return true;
274 }
275
check_items(const U16 num_items,const LASitem * items,const U16 point_size)276 bool LASzip::check_items(const U16 num_items, const LASitem* items, const U16 point_size)
277 {
278 if (num_items == 0) return return_error("number of items cannot be zero");
279 if (items == 0) return return_error("items pointer cannot be NULL");
280 U16 i;
281 U16 size = 0;
282 for (i = 0; i < num_items; i++)
283 {
284 if (!check_item(&items[i])) return false;
285 size += items[i].size;
286 }
287 if (point_size && (point_size != size))
288 {
289 CHAR temp[66];
290 sprintf(temp, "point has size of %d but items only add up to %d bytes", point_size, size);
291 return return_error(temp);
292 }
293 return true;
294 }
295
check(const U16 point_size)296 bool LASzip::check(const U16 point_size)
297 {
298 if (!check_compressor(compressor)) return false;
299 if (!check_coder(coder)) return false;
300 if (!check_items(num_items, items, point_size)) return false;
301 return true;
302 }
303
request_compatibility_mode(const U16 requested_compatibility_mode)304 bool LASzip::request_compatibility_mode(const U16 requested_compatibility_mode)
305 {
306 if (num_items != 0) return return_error("request compatibility mode before calling setup()");
307 if (requested_compatibility_mode > 1)
308 {
309 return return_error("compatibility mode larger than 1 not supported");
310 }
311 if (requested_compatibility_mode)
312 {
313 options = options | 0x00000001;
314 }
315 else
316 {
317 options = options & 0xFFFFFFFE;
318 }
319 return true;
320 }
321
setup(const U8 point_type,const U16 point_size,const U16 compressor)322 bool LASzip::setup(const U8 point_type, const U16 point_size, const U16 compressor)
323 {
324 if (!check_compressor(compressor)) return false;
325 this->num_items = 0;
326 if (this->items) delete [] this->items;
327 this->items = 0;
328 if (!setup(&num_items, &items, point_type, point_size, compressor)) return false;
329 if (compressor)
330 {
331 if (items[0].type == LASitem::POINT14)
332 {
333 if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED)
334 {
335 return false;
336 }
337 this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED;
338 }
339 else
340 {
341 if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)
342 {
343 this->compressor = LASZIP_COMPRESSOR_CHUNKED;
344 }
345 else
346 {
347 this->compressor = compressor;
348 }
349 }
350 if (compressor != LASZIP_COMPRESSOR_POINTWISE)
351 {
352 if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
353 }
354 }
355 else
356 {
357 this->compressor = LASZIP_COMPRESSOR_NONE;
358 }
359 return true;
360 }
361
setup(const U16 num_items,const LASitem * items,const U16 compressor)362 bool LASzip::setup(const U16 num_items, const LASitem* items, const U16 compressor)
363 {
364 // check input
365 if (!check_compressor(compressor)) return false;
366 if (!check_items(num_items, items)) return false;
367
368 // setup compressor
369 if (compressor)
370 {
371 if (items[0].type == LASitem::POINT14)
372 {
373 if (compressor != LASZIP_COMPRESSOR_LAYERED_CHUNKED)
374 {
375 return false;
376 }
377 this->compressor = LASZIP_COMPRESSOR_LAYERED_CHUNKED;
378 }
379 else
380 {
381 if (compressor == LASZIP_COMPRESSOR_LAYERED_CHUNKED)
382 {
383 this->compressor = LASZIP_COMPRESSOR_CHUNKED;
384 }
385 else
386 {
387 this->compressor = compressor;
388 }
389 }
390 if (compressor != LASZIP_COMPRESSOR_POINTWISE)
391 {
392 if (chunk_size == 0) chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
393 }
394 }
395 else
396 {
397 this->compressor = LASZIP_COMPRESSOR_NONE;
398 }
399
400 // prepare items
401 this->num_items = 0;
402 if (this->items) delete [] this->items;
403 this->items = 0;
404 this->num_items = num_items;
405 this->items = new LASitem[num_items];
406
407 // setup items
408 U16 i;
409 for (i = 0; i < num_items; i++)
410 {
411 this->items[i] = items[i];
412 }
413
414 return true;
415 }
416
setup(U16 * num_items,LASitem ** items,const U8 point_type,const U16 point_size,const U16 compressor)417 bool LASzip::setup(U16* num_items, LASitem** items, const U8 point_type, const U16 point_size, const U16 compressor)
418 {
419 BOOL compatible = FALSE;
420 BOOL have_point14 = FALSE;
421 BOOL have_gps_time = FALSE;
422 BOOL have_rgb = FALSE;
423 BOOL have_nir = FALSE;
424 BOOL have_wavepacket = FALSE;
425 I32 extra_bytes_number = 0;
426
427 // turns on LAS 1.4 compatibility mode
428
429 if (options & 1) compatible = TRUE;
430
431 // switch over the point types we know
432 switch (point_type)
433 {
434 case 0:
435 extra_bytes_number = (I32)point_size - 20;
436 break;
437 case 1:
438 have_gps_time = TRUE;
439 extra_bytes_number = (I32)point_size - 28;
440 break;
441 case 2:
442 have_rgb = TRUE;
443 extra_bytes_number = (I32)point_size - 26;
444 break;
445 case 3:
446 have_gps_time = TRUE;
447 have_rgb = TRUE;
448 extra_bytes_number = (I32)point_size - 34;
449 break;
450 case 4:
451 have_gps_time = TRUE;
452 have_wavepacket = TRUE;
453 extra_bytes_number = (I32)point_size - 57;
454 break;
455 case 5:
456 have_gps_time = TRUE;
457 have_rgb = TRUE;
458 have_wavepacket = TRUE;
459 extra_bytes_number = (I32)point_size - 63;
460 break;
461 case 6:
462 have_point14 = TRUE;
463 extra_bytes_number = (I32)point_size - 30;
464 break;
465 case 7:
466 have_point14 = TRUE;
467 have_rgb = TRUE;
468 extra_bytes_number = (I32)point_size - 36;
469 break;
470 case 8:
471 have_point14 = TRUE;
472 have_rgb = TRUE;
473 have_nir = TRUE;
474 extra_bytes_number = (I32)point_size - 38;
475 break;
476 case 9:
477 have_point14 = TRUE;
478 have_wavepacket = TRUE;
479 extra_bytes_number = (I32)point_size - 59;
480 break;
481 case 10:
482 have_point14 = TRUE;
483 have_rgb = TRUE;
484 have_nir = TRUE;
485 have_wavepacket = TRUE;
486 extra_bytes_number = (I32)point_size - 67;
487 break;
488 default:
489 if (1)
490 {
491 char error[64];
492 sprintf(error, "point type %d unknown", point_type);
493 return return_error(error);
494 }
495 }
496
497 if (extra_bytes_number < 0)
498 {
499 fprintf(stderr, "WARNING: point size %d too small by %d bytes for point type %d. assuming point_size of %d\n", point_size, -extra_bytes_number, point_type, point_size-extra_bytes_number);
500 extra_bytes_number = 0;
501 }
502
503 // maybe represent new LAS 1.4 as corresponding LAS 1.3 points plus extra bytes for compatibility
504 if (have_point14 && compatible)
505 {
506 // we need 4 extra bytes for the new point attributes
507 extra_bytes_number += 5;
508 // we store the GPS time separately
509 have_gps_time = TRUE;
510 // we do not use the point14 item
511 have_point14 = FALSE;
512 // if we have NIR ...
513 if (have_nir)
514 {
515 // we need another 2 extra bytes
516 extra_bytes_number += 2;
517 // we do not use the NIR item
518 have_nir = FALSE;
519 }
520 }
521
522 // create item description
523
524 (*num_items) = 1 + !!(have_gps_time) + !!(have_rgb) + !!(have_wavepacket) + !!(extra_bytes_number);
525 (*items) = new LASitem[*num_items];
526
527 U16 i = 1;
528 if (have_point14)
529 {
530 (*items)[0].type = LASitem::POINT14;
531 (*items)[0].size = 30;
532 (*items)[0].version = 0;
533 }
534 else
535 {
536 (*items)[0].type = LASitem::POINT10;
537 (*items)[0].size = 20;
538 (*items)[0].version = 0;
539 }
540 if (have_gps_time)
541 {
542 (*items)[i].type = LASitem::GPSTIME11;
543 (*items)[i].size = 8;
544 (*items)[i].version = 0;
545 i++;
546 }
547 if (have_rgb)
548 {
549 if (have_point14)
550 {
551 if (have_nir)
552 {
553 (*items)[i].type = LASitem::RGBNIR14;
554 (*items)[i].size = 8;
555 (*items)[i].version = 0;
556 }
557 else
558 {
559 (*items)[i].type = LASitem::RGB14;
560 (*items)[i].size = 6;
561 (*items)[i].version = 0;
562 }
563 }
564 else
565 {
566 (*items)[i].type = LASitem::RGB12;
567 (*items)[i].size = 6;
568 (*items)[i].version = 0;
569 }
570 i++;
571 }
572 if (have_wavepacket)
573 {
574 if (have_point14)
575 {
576 (*items)[i].type = LASitem::WAVEPACKET14;
577 (*items)[i].size = 29;
578 (*items)[i].version = 0;
579 }
580 else
581 {
582 (*items)[i].type = LASitem::WAVEPACKET13;
583 (*items)[i].size = 29;
584 (*items)[i].version = 0;
585 }
586 i++;
587 }
588 if (extra_bytes_number)
589 {
590 if (have_point14)
591 {
592 (*items)[i].type = LASitem::BYTE14;
593 (*items)[i].size = extra_bytes_number;
594 (*items)[i].version = 0;
595 }
596 else
597 {
598 (*items)[i].type = LASitem::BYTE;
599 (*items)[i].size = extra_bytes_number;
600 (*items)[i].version = 0;
601 }
602 i++;
603 }
604 if (compressor) request_version(2);
605 assert(i == *num_items);
606 return true;
607 }
608
set_chunk_size(const U32 chunk_size)609 bool LASzip::set_chunk_size(const U32 chunk_size)
610 {
611 if (num_items == 0) return return_error("call setup() before setting chunk size");
612 if (this->compressor != LASZIP_COMPRESSOR_POINTWISE)
613 {
614 this->chunk_size = chunk_size;
615 return true;
616 }
617 return false;
618 }
619
request_version(const U16 requested_version)620 bool LASzip::request_version(const U16 requested_version)
621 {
622 if (num_items == 0) return return_error("call setup() before requesting version");
623 if (compressor == LASZIP_COMPRESSOR_NONE)
624 {
625 if (requested_version > 0) return return_error("without compression version is always 0");
626 }
627 else
628 {
629 if (requested_version < 1) return return_error("with compression version is at least 1");
630 if (requested_version > 2) return return_error("version larger than 2 not supported");
631 }
632 U16 i;
633 for (i = 0; i < num_items; i++)
634 {
635 switch (items[i].type)
636 {
637 case LASitem::POINT10:
638 case LASitem::GPSTIME11:
639 case LASitem::RGB12:
640 case LASitem::BYTE:
641 items[i].version = requested_version;
642 break;
643 case LASitem::WAVEPACKET13:
644 items[i].version = 1; // no version 2
645 break;
646 case LASitem::POINT14:
647 case LASitem::RGB14:
648 case LASitem::RGBNIR14:
649 case LASitem::WAVEPACKET14:
650 case LASitem::BYTE14:
651 items[i].version = 3; // no version 1 or 2
652 break;
653 default:
654 return return_error("item type not supported");
655 }
656 }
657 return true;
658 }
659
is_standard(U8 * point_type,U16 * record_length)660 bool LASzip::is_standard(U8* point_type, U16* record_length)
661 {
662 return is_standard(num_items, items, point_type, record_length);
663 }
664
is_standard(const U16 num_items,const LASitem * items,U8 * point_type,U16 * record_length)665 bool LASzip::is_standard(const U16 num_items, const LASitem* items, U8* point_type, U16* record_length)
666 {
667 if (items == 0) return return_error("LASitem array is zero");
668
669 // this is always true
670 if (point_type) *point_type = 127;
671 if (record_length)
672 {
673 U16 i;
674 *record_length = 0;
675 for (i = 0; i < num_items; i++)
676 {
677 *record_length += items[i].size;
678 }
679 }
680
681 // the minimal number of items is 1
682 if (num_items < 1) return return_error("less than one LASitem entries");
683 // the maximal number of items is 5
684 if (num_items > 5) return return_error("more than five LASitem entries");
685
686 if (items[0].is_type(LASitem::POINT10))
687 {
688 // consider all the POINT10 combinations
689 if (num_items == 1)
690 {
691 if (point_type) *point_type = 0;
692 if (record_length) assert(*record_length == 20);
693 return true;
694 }
695 else
696 {
697 if (items[1].is_type(LASitem::GPSTIME11))
698 {
699 if (num_items == 2)
700 {
701 if (point_type) *point_type = 1;
702 if (record_length) assert(*record_length == 28);
703 return true;
704 }
705 else
706 {
707 if (items[2].is_type(LASitem::RGB12))
708 {
709 if (num_items == 3)
710 {
711 if (point_type) *point_type = 3;
712 if (record_length) assert(*record_length == 34);
713 return true;
714 }
715 else
716 {
717 if (items[3].is_type(LASitem::WAVEPACKET13))
718 {
719 if (num_items == 4)
720 {
721 if (point_type) *point_type = 5;
722 if (record_length) assert(*record_length == 63);
723 return true;
724 }
725 else
726 {
727 if (items[4].is_type(LASitem::BYTE))
728 {
729 if (num_items == 5)
730 {
731 if (point_type) *point_type = 5;
732 if (record_length) assert(*record_length == (63 + items[4].size));
733 return true;
734 }
735 }
736 }
737 }
738 else if (items[3].is_type(LASitem::BYTE))
739 {
740 if (num_items == 4)
741 {
742 if (point_type) *point_type = 3;
743 if (record_length) assert(*record_length == (34 + items[3].size));
744 return true;
745 }
746 }
747 }
748 }
749 else if (items[2].is_type(LASitem::WAVEPACKET13))
750 {
751 if (num_items == 3)
752 {
753 if (point_type) *point_type = 4;
754 if (record_length) assert(*record_length == 57);
755 return true;
756 }
757 else
758 {
759 if (items[3].is_type(LASitem::BYTE))
760 {
761 if (num_items == 4)
762 {
763 if (point_type) *point_type = 4;
764 if (record_length) assert(*record_length == (57 + items[3].size));
765 return true;
766 }
767 }
768 }
769 }
770 else if (items[2].is_type(LASitem::BYTE))
771 {
772 if (num_items == 3)
773 {
774 if (point_type) *point_type = 1;
775 if (record_length) assert(*record_length == (28 + items[2].size));
776 return true;
777 }
778 }
779 }
780 }
781 else if (items[1].is_type(LASitem::RGB12))
782 {
783 if (num_items == 2)
784 {
785 if (point_type) *point_type = 2;
786 if (record_length) assert(*record_length == 26);
787 return true;
788 }
789 else
790 {
791 if (items[2].is_type(LASitem::BYTE))
792 {
793 if (num_items == 3)
794 {
795 if (point_type) *point_type = 2;
796 if (record_length) assert(*record_length == (26 + items[2].size));
797 return true;
798 }
799 }
800 }
801 }
802 else if (items[1].is_type(LASitem::BYTE))
803 {
804 if (num_items == 2)
805 {
806 if (point_type) *point_type = 0;
807 if (record_length) assert(*record_length == (20 + items[1].size));
808 return true;
809 }
810 }
811 }
812 }
813 else if (items[0].is_type(LASitem::POINT14))
814 {
815 // consider all the POINT14 combinations
816 if (num_items == 1)
817 {
818 if (point_type) *point_type = 6;
819 if (record_length) assert(*record_length == 30);
820 return true;
821 }
822 else
823 {
824 if (items[1].is_type(LASitem::RGB14))
825 {
826 if (num_items == 2)
827 {
828 if (point_type) *point_type = 7;
829 if (record_length) assert(*record_length == 36);
830 return true;
831 }
832 else
833 {
834 if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
835 {
836 if (num_items == 3)
837 {
838 if (point_type) *point_type = 7;
839 if (record_length) assert(*record_length == (36 + items[2].size));
840 return true;
841 }
842 }
843 }
844 }
845 else if (items[1].is_type(LASitem::RGBNIR14))
846 {
847 if (num_items == 2)
848 {
849 if (point_type) *point_type = 8;
850 if (record_length) assert(*record_length == 38);
851 return true;
852 }
853 else
854 {
855 if (items[2].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14))
856 {
857 if (num_items == 3)
858 {
859 if (point_type) *point_type = 10;
860 if (record_length) assert(*record_length == 67);
861 return true;
862 }
863 else
864 {
865 if (items[3].is_type(LASitem::BYTE) || items[3].is_type(LASitem::BYTE14))
866 {
867 if (num_items == 4)
868 {
869 if (point_type) *point_type = 10;
870 if (record_length) assert(*record_length == (67 + items[3].size));
871 return true;
872 }
873 }
874 }
875 }
876 else if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
877 {
878 if (num_items == 3)
879 {
880 if (point_type) *point_type = 8;
881 if (record_length) assert(*record_length == (38 + items[2].size));
882 return true;
883 }
884 }
885 }
886 }
887 else if (items[1].is_type(LASitem::WAVEPACKET13) || items[1].is_type(LASitem::WAVEPACKET14))
888 {
889 if (num_items == 2)
890 {
891 if (point_type) *point_type = 9;
892 if (record_length) assert(*record_length == 59);
893 return true;
894 }
895 else
896 {
897 if (items[2].is_type(LASitem::BYTE) || items[2].is_type(LASitem::BYTE14))
898 {
899 if (num_items == 3)
900 {
901 if (point_type) *point_type = 9;
902 if (record_length) assert(*record_length == (59 + items[2].size));
903 return true;
904 }
905 }
906 }
907 }
908 else if (items[1].is_type(LASitem::BYTE) || items[1].is_type(LASitem::BYTE14))
909 {
910 if (num_items == 2)
911 {
912 if (point_type) *point_type = 6;
913 if (record_length) assert(*record_length == (30 + items[1].size));
914 return true;
915 }
916 }
917 }
918 }
919 else
920 {
921 return_error("first LASitem is neither POINT10 nor POINT14");
922 }
923 return return_error("LASitem array does not match LAS specification 1.4");
924 }
925
is_type(LASitem::Type t) const926 bool LASitem::is_type(LASitem::Type t) const
927 {
928 if (t != type) return false;
929 switch (t)
930 {
931 case POINT10:
932 if (size != 20) return false;
933 break;
934 case POINT14:
935 if (size != 30) return false;
936 break;
937 case GPSTIME11:
938 if (size != 8) return false;
939 break;
940 case RGB12:
941 if (size != 6) return false;
942 break;
943 case BYTE:
944 if (size < 1) return false;
945 break;
946 case RGB14:
947 if (size != 6) return false;
948 break;
949 case RGBNIR14:
950 if (size != 8) return false;
951 break;
952 case BYTE14:
953 if (size < 1) return false;
954 break;
955 case WAVEPACKET13:
956 if (size != 29) return false;
957 break;
958 case WAVEPACKET14:
959 if (size != 29) return false;
960 break;
961 default:
962 return false;
963 }
964 return true;
965 }
966
get_name() const967 const char* LASitem::get_name() const
968 {
969 switch (type)
970 {
971 case POINT10:
972 return "POINT10";
973 break;
974 case POINT14:
975 return "POINT14";
976 break;
977 case GPSTIME11:
978 return "GPSTIME11";
979 break;
980 case RGB12:
981 return "RGB12";
982 break;
983 case BYTE:
984 return "BYTE";
985 break;
986 case RGB14:
987 return "RGB14";
988 break;
989 case RGBNIR14:
990 return "RGBNIR14";
991 break;
992 case BYTE14:
993 return "BYTE14";
994 break;
995 case WAVEPACKET13:
996 return "WAVEPACKET13";
997 break;
998 case WAVEPACKET14:
999 return "WAVEPACKET14";
1000 break;
1001 default:
1002 break;
1003 }
1004 return 0;
1005 }
1006
1007