1 /*
2 ===============================================================================
3
4 FILE: laszip_dll.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 15 October 2019 -- support reading from and writing to unicode file names under Windows
28 20 March 2019 -- check consistent legacy and extended classification in laszip_write_point()
29 7 November 2018 -- assure identical legacy and extended flags in laszip_write_point()
30 20 October 2018 -- changed (U8*) to (const U8*) for all out->put___() calls
31 5 October 2018 -- corrected 'is_empty' return value in laszip_inside_rectangle()
32 29 September 2018 -- laszip_prepare_point_for_write() sets extended_point_type
33 19 September 2018 -- removed tuples and triple support from attributes
34 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro
35 6 April 2018 -- added zero() function to laszip_dll struct to fix memory leak
36 30 August 2017 -- completing stream-based writing (with writing LAS header)
37 23 August 2017 -- turn on "native" by default
38 3 August 2017 -- new 'laszip_create_laszip_vlr()' gets VLR as C++ std::vector
39 29 July 2017 -- integrating minimal stream-based reading/writing into branch
40 20 July 2017 -- Andrew Bell adds support for stream-based reading/writing
41 28 May 2017 -- support for "LAS 1.4 selective decompression" added into DLL API
42 25 April 2017 -- adding initial support for new "native LAS 1.4 extension"
43 8 January 2017 -- changed from "laszip_dll.h" to "laszip_api.h" for hobu
44
45 ===============================================================================
46 */
47
48 #define LASZIP_DYN_LINK
49 #define LASZIP_SOURCE
50
51 #include <laszip/laszip_api.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <vector>
56
57 #include "laszip.hpp"
58 #include "lasattributer.hpp"
59 #include "bytestreamout_file.hpp"
60 #include "bytestreamin_file.hpp"
61 #include "bytestreamout_array.hpp"
62 #include "bytestreamin_array.hpp"
63 #include "bytestreamin_istream.hpp"
64 #include "bytestreamout_ostream.hpp"
65 #include "laswritepoint.hpp"
66 #include "lasreadpoint.hpp"
67 #include "lasquadtree.hpp"
68 #include "lasindex.hpp"
69
70 class laszip_dll_inventory
71 {
72 public:
active() const73 BOOL active() const { return (first == FALSE); };
74 U32 number_of_point_records;
75 U32 number_of_points_by_return[16];
76 I32 max_X;
77 I32 min_X;
78 I32 max_Y;
79 I32 min_Y;
80 I32 max_Z;
81 I32 min_Z;
add(const laszip_point_struct * point)82 void add(const laszip_point_struct* point)
83 {
84 number_of_point_records++;
85 if (point->extended_point_type)
86 {
87 number_of_points_by_return[point->extended_return_number]++;
88 }
89 else
90 {
91 number_of_points_by_return[point->return_number]++;
92 }
93 if (first)
94 {
95 min_X = max_X = point->X;
96 min_Y = max_Y = point->Y;
97 min_Z = max_Z = point->Z;
98 first = FALSE;
99 }
100 else
101 {
102 if (point->X < min_X) min_X = point->X;
103 else if (point->X > max_X) max_X = point->X;
104 if (point->Y < min_Y) min_Y = point->Y;
105 else if (point->Y > max_Y) max_Y = point->Y;
106 if (point->Z < min_Z) min_Z = point->Z;
107 else if (point->Z > max_Z) max_Z = point->Z;
108 }
109 }
laszip_dll_inventory()110 laszip_dll_inventory()
111 {
112 U32 i;
113 number_of_point_records = 0;
114 for (i = 0; i < 16; i++) number_of_points_by_return[i] = 0;
115 max_X = min_X = 0;
116 max_Y = min_Y = 0;
117 max_Z = min_Z = 0;
118 first = TRUE;
119 }
120 private:
121 BOOL first;
122 };
123
124 typedef struct laszip_dll {
125 laszip_header_struct header;
126 I64 p_count;
127 I64 npoints;
128 laszip_point_struct point;
129 U8** point_items;
130 FILE* file;
131 ByteStreamIn* streamin;
132 LASreadPoint* reader;
133 ByteStreamOut* streamout;
134 LASwritePoint* writer;
135 LASattributer* attributer;
136 CHAR error[1024];
137 CHAR warning[1024];
138 LASindex* lax_index;
139 F64 lax_r_min_x;
140 F64 lax_r_min_y;
141 F64 lax_r_max_x;
142 F64 lax_r_max_y;
143 CHAR* lax_file_name;
144 BOOL lax_create;
145 BOOL lax_append;
146 BOOL lax_exploit;
147 U32 las14_decompress_selective;
148 BOOL preserve_generating_software;
149 BOOL request_native_extension;
150 BOOL request_compatibility_mode;
151 BOOL compatibility_mode;
152 U32 set_chunk_size;
153 I32 start_scan_angle;
154 I32 start_extended_returns;
155 I32 start_classification;
156 I32 start_flags_and_channel;
157 I32 start_NIR_band;
158 laszip_dll_inventory* inventory;
159 std::vector<void *> buffers;
160
zerolaszip_dll161 void zero()
162 {
163 memset(&header, 0, sizeof(laszip_header_struct));
164 p_count = 0;
165 npoints = 0;
166 memset(&point, 0, sizeof(laszip_point_struct));
167 point_items = NULL;
168 file = NULL;
169 streamin = NULL;
170 reader = NULL;
171 streamout = NULL;
172 writer = NULL;
173 attributer = NULL;
174 memset(error, 0, 1024);
175 memset(warning, 0, 1024);
176 lax_index = NULL;
177 lax_r_min_x = 0.0;
178 lax_r_min_y = 0.0;
179 lax_r_max_x = 0.0;
180 lax_r_max_y = 0.0;
181 lax_file_name = NULL;
182 lax_create = FALSE;
183 lax_append = FALSE;
184 lax_exploit = FALSE;
185 las14_decompress_selective = 0;
186 preserve_generating_software = FALSE;
187 request_native_extension = FALSE;
188 request_compatibility_mode = FALSE;
189 compatibility_mode = FALSE;
190 set_chunk_size = 0;
191 start_scan_angle = 0;
192 start_extended_returns = 0;
193 start_classification = 0;
194 start_flags_and_channel = 0;
195 start_NIR_band = 0;
196 inventory = NULL;
197 };
198 } laszip_dll_struct;
199
200 /*---------------------------------------------------------------------------*/
201 LASZIP_API laszip_I32
laszip_get_version(laszip_U8 * version_major,laszip_U8 * version_minor,laszip_U16 * version_revision,laszip_U32 * version_build)202 laszip_get_version(
203 laszip_U8* version_major
204 , laszip_U8* version_minor
205 , laszip_U16* version_revision
206 , laszip_U32* version_build
207 )
208 {
209 try
210 {
211 *version_major = LASZIP_VERSION_MAJOR;
212 *version_minor = LASZIP_VERSION_MINOR;
213 *version_revision = LASZIP_VERSION_REVISION;
214 *version_build = LASZIP_VERSION_BUILD_DATE;
215 }
216 catch (...)
217 {
218 return 1;
219 }
220
221 return 0;
222 }
223
224 /*---------------------------------------------------------------------------*/
225 LASZIP_API laszip_I32
laszip_get_error(laszip_POINTER pointer,laszip_CHAR ** error)226 laszip_get_error(
227 laszip_POINTER pointer
228 , laszip_CHAR** error
229 )
230 {
231 if (pointer == 0) return 1;
232 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
233
234 try
235 {
236 *error = laszip_dll->error;
237 }
238 catch (...)
239 {
240 sprintf(laszip_dll->error, "internal error in laszip_get_error");
241 return 1;
242 }
243
244 return 0;
245 }
246
247 /*---------------------------------------------------------------------------*/
248 LASZIP_API laszip_I32
laszip_get_warning(laszip_POINTER pointer,laszip_CHAR ** warning)249 laszip_get_warning(
250 laszip_POINTER pointer
251 , laszip_CHAR** warning
252 )
253 {
254 if (pointer == 0) return 1;
255 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
256
257 try
258 {
259 *warning = laszip_dll->warning;
260 }
261 catch (...)
262 {
263 sprintf(laszip_dll->error, "internal error in laszip_get_warning");
264 return 1;
265 }
266
267 return 0;
268 }
269
270 /*---------------------------------------------------------------------------*/
271 LASZIP_API laszip_I32
laszip_create(laszip_POINTER * pointer)272 laszip_create(
273 laszip_POINTER* pointer
274 )
275 {
276 if (pointer == 0) return 1;
277
278 try
279 {
280 laszip_dll_struct* laszip_dll = new laszip_dll_struct;
281 if (laszip_dll == 0)
282 {
283 return 1;
284 }
285
286 // zero every field of the laszip_dll struct
287
288 laszip_dll->zero();
289
290 // create the default
291
292 laszip_clean(laszip_dll);
293
294 *pointer = laszip_dll;
295 }
296 catch (...)
297 {
298 return 1;
299 }
300
301 return 0;
302 }
303
304 /*---------------------------------------------------------------------------*/
305 LASZIP_API laszip_I32
laszip_clean(laszip_POINTER pointer)306 laszip_clean(
307 laszip_POINTER pointer
308 )
309 {
310 if (pointer == 0) return 1;
311 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
312
313 try
314 {
315 if (laszip_dll->reader)
316 {
317 sprintf(laszip_dll->error, "cannot clean while reader is open.");
318 return 1;
319 }
320
321 if (laszip_dll->writer)
322 {
323 sprintf(laszip_dll->error, "cannot clean while writer is open.");
324 return 1;
325 }
326
327 // dealloc everything alloc in the header
328
329 if (laszip_dll->header.user_data_in_header)
330 {
331 delete [] laszip_dll->header.user_data_in_header;
332 laszip_dll->header.user_data_in_header = 0;
333 }
334
335 if (laszip_dll->header.vlrs)
336 {
337 U32 i;
338 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
339 {
340 if (laszip_dll->header.vlrs[i].data)
341 {
342 delete [] laszip_dll->header.vlrs[i].data;
343 }
344 }
345 free(laszip_dll->header.vlrs);
346 laszip_dll->header.vlrs = 0;
347 }
348
349 if (laszip_dll->header.user_data_after_header)
350 {
351 delete [] laszip_dll->header.user_data_after_header;
352 laszip_dll->header.user_data_after_header = 0;
353 }
354
355 // dealloc everything alloc in the point
356
357 if (laszip_dll->point.extra_bytes)
358 {
359 delete [] laszip_dll->point.extra_bytes;
360 laszip_dll->point.extra_bytes = 0;
361 }
362
363 // dealloc point items although close_reader() / close_writer() call should have done this already
364
365 if (laszip_dll->point_items)
366 {
367 delete [] laszip_dll->point_items;
368 laszip_dll->point_items = 0;
369 }
370
371 // close file although close_reader() / close_writer() call should have done this already
372
373 if (laszip_dll->file)
374 {
375 fclose(laszip_dll->file);
376 laszip_dll->file = 0;
377 }
378
379 // dealloc streamin although close_reader() call should have done this already
380
381 if (laszip_dll->streamin)
382 {
383 delete laszip_dll->streamin;
384 laszip_dll->streamin = 0;
385 }
386
387 // dealloc streamout although close_writer() call should have done this already
388
389 if (laszip_dll->streamout)
390 {
391 delete laszip_dll->streamout;
392 laszip_dll->streamout = 0;
393 }
394
395 // dealloc the attributer
396
397 if (laszip_dll->attributer)
398 {
399 delete laszip_dll->attributer;
400 laszip_dll->attributer = 0;
401 }
402
403 // dealloc lax_index although close_reader() / close_writer() call should have done this already
404
405 if (laszip_dll->lax_index)
406 {
407 delete laszip_dll->lax_index;
408 laszip_dll->lax_index = 0;
409 }
410
411 // dealloc lax_file_name although close_writer() call should have done this already
412
413 if (laszip_dll->lax_file_name)
414 {
415 free(laszip_dll->lax_file_name);
416 laszip_dll->lax_file_name = 0;
417 }
418
419 // dealloc the inventory although close_writer() call should have done this already
420
421 if (laszip_dll->inventory == 0)
422 {
423 delete laszip_dll->inventory;
424 laszip_dll->inventory = 0;
425 }
426
427 // dealloc any data fields that were kept around in memory for others
428
429 if (laszip_dll->buffers.size())
430 {
431 for (size_t i = 0; i < laszip_dll->buffers.size(); i++)
432 {
433 free(laszip_dll->buffers[i]);
434 }
435 laszip_dll->buffers.clear();
436 }
437
438 // zero every field of the laszip_dll struct
439
440 laszip_dll->zero();
441
442 // create default header
443
444 sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
445 laszip_dll->header.version_major = 1;
446 laszip_dll->header.version_minor = 2;
447 laszip_dll->header.header_size = 227;
448 laszip_dll->header.offset_to_point_data = 227;
449 laszip_dll->header.point_data_format = 1;
450 laszip_dll->header.point_data_record_length = 28;
451 laszip_dll->header.x_scale_factor = 0.01;
452 laszip_dll->header.y_scale_factor = 0.01;
453 laszip_dll->header.z_scale_factor = 0.01;
454 laszip_dll->set_chunk_size = LASZIP_CHUNK_SIZE_DEFAULT;
455 laszip_dll->request_native_extension = TRUE;
456 laszip_dll->las14_decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL;
457 }
458 catch (...)
459 {
460 sprintf(laszip_dll->error, "internal error in laszip_clean");
461 return 1;
462 }
463
464 return 0;
465 }
466
467 /*---------------------------------------------------------------------------*/
468 LASZIP_API laszip_I32
laszip_destroy(laszip_POINTER pointer)469 laszip_destroy(
470 laszip_POINTER pointer
471 )
472 {
473 if (pointer == 0) return 1;
474 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
475
476 int err = 0;
477
478 try
479 {
480 err = laszip_clean(laszip_dll);
481 delete laszip_dll;
482 }
483 catch (...)
484 {
485 return 1;
486 }
487
488 return err;
489 }
490
491 /*---------------------------------------------------------------------------*/
492 LASZIP_API laszip_I32
laszip_get_header_pointer(laszip_POINTER pointer,laszip_header_struct ** header_pointer)493 laszip_get_header_pointer(
494 laszip_POINTER pointer
495 , laszip_header_struct** header_pointer
496 )
497 {
498 if (pointer == 0) return 1;
499 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
500
501 try
502 {
503 if (header_pointer == 0)
504 {
505 sprintf(laszip_dll->error, "laszip_header_struct pointer 'header_pointer' is zero");
506 return 1;
507 }
508
509 *header_pointer = &laszip_dll->header;
510 }
511 catch (...)
512 {
513 sprintf(laszip_dll->error, "internal error in laszip_get_header_pointer");
514 return 1;
515 }
516
517 laszip_dll->error[0] = '\0';
518 return 0;
519 }
520
521 /*---------------------------------------------------------------------------*/
522 LASZIP_API laszip_I32
laszip_get_point_pointer(laszip_POINTER pointer,laszip_point_struct ** point_pointer)523 laszip_get_point_pointer(
524 laszip_POINTER pointer
525 , laszip_point_struct** point_pointer
526 )
527 {
528 if (pointer == 0) return 1;
529 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
530
531 try
532 {
533 if (point_pointer == 0)
534 {
535 sprintf(laszip_dll->error, "laszip_point_struct pointer 'point_pointer' is zero");
536 return 1;
537 }
538
539 *point_pointer = &laszip_dll->point;
540 }
541 catch (...)
542 {
543 sprintf(laszip_dll->error, "internal error in laszip_get_point_pointer");
544 return 1;
545 }
546
547 laszip_dll->error[0] = '\0';
548 return 0;
549 }
550
551 /*---------------------------------------------------------------------------*/
552 LASZIP_API laszip_I32
laszip_get_point_count(laszip_POINTER pointer,laszip_I64 * count)553 laszip_get_point_count(
554 laszip_POINTER pointer
555 , laszip_I64* count
556 )
557 {
558 if (pointer == 0) return 1;
559 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
560
561 try
562 {
563 if (count == 0)
564 {
565 sprintf(laszip_dll->error, "laszip_I64 pointer 'count' is zero");
566 return 1;
567 }
568
569 if ((laszip_dll->reader == 0) && (laszip_dll->writer == 0))
570 {
571 sprintf(laszip_dll->error, "getting count before reader or writer was opened");
572 return 1;
573 }
574
575 *count = laszip_dll->p_count;
576 }
577 catch (...)
578 {
579 sprintf(laszip_dll->error, "internal error in laszip_get_point_count");
580 return 1;
581 }
582
583 laszip_dll->error[0] = '\0';
584 return 0;
585 }
586
587 /*---------------------------------------------------------------------------*/
588 LASZIP_API laszip_I32
laszip_set_header(laszip_POINTER pointer,const laszip_header_struct * header)589 laszip_set_header(
590 laszip_POINTER pointer
591 , const laszip_header_struct* header
592 )
593 {
594 if (pointer == 0) return 1;
595 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
596
597 try
598 {
599 if (header == 0)
600 {
601 sprintf(laszip_dll->error, "laszip_header_struct pointer 'header' is zero");
602 return 1;
603 }
604
605 if (laszip_dll->reader)
606 {
607 sprintf(laszip_dll->error, "cannot set header after reader was opened");
608 return 1;
609 }
610
611 if (laszip_dll->writer)
612 {
613 sprintf(laszip_dll->error, "cannot set header after writer was opened");
614 return 1;
615 }
616
617 // dealloc the attributer (if needed)
618
619 if (laszip_dll->attributer)
620 {
621 delete laszip_dll->attributer;
622 laszip_dll->attributer = 0;
623 }
624
625 // populate the header
626
627 U32 i;
628
629 laszip_dll->header.file_source_ID = header->file_source_ID;
630 laszip_dll->header.global_encoding = header->global_encoding;
631 laszip_dll->header.project_ID_GUID_data_1 = header->project_ID_GUID_data_1;
632 laszip_dll->header.project_ID_GUID_data_2 = header->project_ID_GUID_data_2;
633 laszip_dll->header.project_ID_GUID_data_3 = header->project_ID_GUID_data_3;
634 memcpy(laszip_dll->header.project_ID_GUID_data_4, header->project_ID_GUID_data_4, 8);
635 laszip_dll->header.version_major = header->version_major;
636 laszip_dll->header.version_minor = header->version_minor;
637 memcpy(laszip_dll->header.system_identifier, header->system_identifier, 32);
638 memcpy(laszip_dll->header.generating_software, header->generating_software, 32);
639 laszip_dll->header.file_creation_day = header->file_creation_day;
640 laszip_dll->header.file_creation_year = header->file_creation_year;
641 laszip_dll->header.header_size = header->header_size;
642 laszip_dll->header.offset_to_point_data = header->offset_to_point_data;
643 laszip_dll->header.number_of_variable_length_records = header->number_of_variable_length_records;
644 laszip_dll->header.point_data_format = header->point_data_format;
645 laszip_dll->header.point_data_record_length = header->point_data_record_length;
646 laszip_dll->header.number_of_point_records = header->number_of_point_records;
647 for (i = 0; i < 5; i++) laszip_dll->header.number_of_points_by_return[i] = header->number_of_points_by_return[i];
648 laszip_dll->header.x_scale_factor = header->x_scale_factor;
649 laszip_dll->header.y_scale_factor = header->y_scale_factor;
650 laszip_dll->header.z_scale_factor = header->z_scale_factor;
651 laszip_dll->header.x_offset = header->x_offset;
652 laszip_dll->header.y_offset = header->y_offset;
653 laszip_dll->header.z_offset = header->z_offset;
654 laszip_dll->header.max_x = header->max_x;
655 laszip_dll->header.min_x = header->min_x;
656 laszip_dll->header.max_y = header->max_y;
657 laszip_dll->header.min_y = header->min_y;
658 laszip_dll->header.max_z = header->max_z;
659 laszip_dll->header.min_z = header->min_z;
660
661 if (laszip_dll->header.version_minor >= 3)
662 {
663 laszip_dll->header.start_of_waveform_data_packet_record = header->start_of_first_extended_variable_length_record;
664 }
665
666 if (laszip_dll->header.version_minor >= 4)
667 {
668 laszip_dll->header.start_of_first_extended_variable_length_record = header->start_of_first_extended_variable_length_record;
669 laszip_dll->header.number_of_extended_variable_length_records = header->number_of_extended_variable_length_records;
670 laszip_dll->header.extended_number_of_point_records = header->extended_number_of_point_records;
671 for (i = 0; i < 15; i++) laszip_dll->header.extended_number_of_points_by_return[i] = header->extended_number_of_points_by_return[i];
672 }
673
674 laszip_dll->header.user_data_in_header_size = header->user_data_in_header_size;
675 if (laszip_dll->header.user_data_in_header)
676 {
677 delete [] laszip_dll->header.user_data_in_header;
678 laszip_dll->header.user_data_in_header = 0;
679 }
680 if (header->user_data_in_header_size)
681 {
682 if (header->user_data_in_header == 0)
683 {
684 sprintf(laszip_dll->error, "header->user_data_in_header_size is %d but header->user_data_in_header is NULL", header->user_data_in_header_size);
685 return 1;
686 }
687 laszip_dll->header.user_data_in_header = new U8[header->user_data_in_header_size];
688 memcpy(laszip_dll->header.user_data_in_header, header->user_data_in_header, header->user_data_in_header_size);
689 }
690
691 if (laszip_dll->header.vlrs)
692 {
693 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
694 {
695 if (laszip_dll->header.vlrs[i].data)
696 {
697 delete [] laszip_dll->header.vlrs[i].data;
698 }
699 }
700 free(laszip_dll->header.vlrs);
701 laszip_dll->header.vlrs = 0;
702 }
703 if (header->number_of_variable_length_records)
704 {
705 laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*header->number_of_variable_length_records);
706 for (i = 0; i < header->number_of_variable_length_records; i++)
707 {
708 laszip_dll->header.vlrs[i].reserved = header->vlrs[i].reserved;
709 memcpy(laszip_dll->header.vlrs[i].user_id, header->vlrs[i].user_id, 16);
710 laszip_dll->header.vlrs[i].record_id = header->vlrs[i].record_id;
711 laszip_dll->header.vlrs[i].record_length_after_header = header->vlrs[i].record_length_after_header;
712 memcpy(laszip_dll->header.vlrs[i].description, header->vlrs[i].description, 32);
713 if (header->vlrs[i].record_length_after_header)
714 {
715 if (header->vlrs[i].data == 0)
716 {
717 sprintf(laszip_dll->error, "header->vlrs[%d].record_length_after_header is %d but header->vlrs[%d].data is NULL", i, header->vlrs[i].record_length_after_header, i);
718 return 1;
719 }
720 laszip_dll->header.vlrs[i].data = new U8[header->vlrs[i].record_length_after_header];
721 memcpy(laszip_dll->header.vlrs[i].data, header->vlrs[i].data, header->vlrs[i].record_length_after_header);
722 }
723 else
724 {
725 laszip_dll->header.vlrs[i].data = 0;
726 }
727
728 // populate the attributer if needed
729
730 if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
731 {
732 if (laszip_dll->attributer == 0)
733 {
734 laszip_dll->attributer = new LASattributer;
735 if (laszip_dll->attributer == 0)
736 {
737 sprintf(laszip_dll->error, "cannot allocate LASattributer");
738 return 1;
739 }
740 }
741 laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data);
742 }
743 }
744 }
745
746 laszip_dll->header.user_data_after_header_size = header->user_data_after_header_size;
747 if (laszip_dll->header.user_data_after_header)
748 {
749 delete [] laszip_dll->header.user_data_after_header;
750 laszip_dll->header.user_data_after_header = 0;
751 }
752 if (header->user_data_after_header_size)
753 {
754 if (header->user_data_after_header == 0)
755 {
756 sprintf(laszip_dll->error, "header->user_data_after_header_size is %d but header->user_data_after_header is NULL", header->user_data_after_header_size);
757 return 1;
758 }
759 laszip_dll->header.user_data_after_header = new U8[header->user_data_after_header_size];
760 memcpy(laszip_dll->header.user_data_after_header, header->user_data_after_header, header->user_data_after_header_size);
761 }
762 }
763 catch (...)
764 {
765 sprintf(laszip_dll->error, "internal error in laszip_set_header");
766 return 1;
767 }
768
769 laszip_dll->error[0] = '\0';
770 return 0;
771 }
772
773 /*---------------------------------------------------------------------------*/
774 LASZIP_API laszip_I32
laszip_set_point_type_and_size(laszip_POINTER pointer,laszip_U8 point_type,laszip_U16 point_size)775 laszip_set_point_type_and_size(
776 laszip_POINTER pointer
777 , laszip_U8 point_type
778 , laszip_U16 point_size
779 )
780 {
781 if (pointer == 0) return 1;
782 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
783
784 try
785 {
786 if (laszip_dll->reader)
787 {
788 sprintf(laszip_dll->error, "cannot set point format and point size after reader was opened");
789 return 1;
790 }
791
792 if (laszip_dll->writer)
793 {
794 sprintf(laszip_dll->error, "cannot set point format and point size after writer was opened");
795 return 1;
796 }
797
798 // check if point type and type are supported
799
800 if (!LASzip().setup(point_type, point_size, LASZIP_COMPRESSOR_NONE))
801 {
802 sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size);
803 return 1;
804 }
805
806 // set point type and point size
807
808 laszip_dll->header.point_data_format = point_type;
809 laszip_dll->header.point_data_record_length = point_size;
810 }
811 catch (...)
812 {
813 sprintf(laszip_dll->error, "internal error in laszip_set_point_type_and_size");
814 return 1;
815 }
816
817 laszip_dll->error[0] = '\0';
818 return 0;
819 }
820
821 /*---------------------------------------------------------------------------*/
822 LASZIP_API laszip_I32
laszip_check_for_integer_overflow(laszip_POINTER pointer)823 laszip_check_for_integer_overflow(
824 laszip_POINTER pointer
825 )
826 {
827 if (pointer == 0) return 1;
828 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
829
830 try
831 {
832 // get a pointer to the header
833
834 laszip_header_struct* header = &(laszip_dll->header);
835
836 // quantize and dequantize the bounding box with current scale_factor and offset
837
838 I32 quant_min_x = I32_QUANTIZE((header->min_x-header->x_offset)/header->x_scale_factor);
839 I32 quant_max_x = I32_QUANTIZE((header->max_x-header->x_offset)/header->x_scale_factor);
840 I32 quant_min_y = I32_QUANTIZE((header->min_y-header->y_offset)/header->y_scale_factor);
841 I32 quant_max_y = I32_QUANTIZE((header->max_y-header->y_offset)/header->y_scale_factor);
842 I32 quant_min_z = I32_QUANTIZE((header->min_z-header->z_offset)/header->z_scale_factor);
843 I32 quant_max_z = I32_QUANTIZE((header->max_z-header->z_offset)/header->z_scale_factor);
844
845 F64 dequant_min_x = header->x_scale_factor*quant_min_x+header->x_offset;
846 F64 dequant_max_x = header->x_scale_factor*quant_max_x+header->x_offset;
847 F64 dequant_min_y = header->y_scale_factor*quant_min_y+header->y_offset;
848 F64 dequant_max_y = header->y_scale_factor*quant_max_y+header->y_offset;
849 F64 dequant_min_z = header->z_scale_factor*quant_min_z+header->z_offset;
850 F64 dequant_max_z = header->z_scale_factor*quant_max_z+header->z_offset;
851
852 // make sure that there is not sign flip (a 32-bit integer overflow) for the bounding box
853
854 if ((header->min_x > 0) != (dequant_min_x > 0))
855 {
856 sprintf(laszip_dll->error, "quantization sign flip for min_x from %g to %g. set scale factor for x coarser than %g\n", header->min_x, dequant_min_x, header->x_scale_factor);
857 return 1;
858 }
859 if ((header->max_x > 0) != (dequant_max_x > 0))
860 {
861 sprintf(laszip_dll->error, "quantization sign flip for max_x from %g to %g. set scale factor for x coarser than %g\n", header->max_x, dequant_max_x, header->x_scale_factor);
862 return 1;
863 }
864 if ((header->min_y > 0) != (dequant_min_y > 0))
865 {
866 sprintf(laszip_dll->error, "quantization sign flip for min_y from %g to %g. set scale factor for y coarser than %g\n", header->min_y, dequant_min_y, header->y_scale_factor);
867 return 1;
868 }
869 if ((header->max_y > 0) != (dequant_max_y > 0))
870 {
871 sprintf(laszip_dll->error, "quantization sign flip for max_y from %g to %g. set scale factor for y coarser than %g\n", header->max_y, dequant_max_y, header->y_scale_factor);
872 return 1;
873 }
874 if ((header->min_z > 0) != (dequant_min_z > 0))
875 {
876 sprintf(laszip_dll->error, "quantization sign flip for min_z from %g to %g. set scale factor for z coarser than %g\n", header->min_z, dequant_min_z, header->z_scale_factor);
877 return 1;
878 }
879 if ((header->max_z > 0) != (dequant_max_z > 0))
880 {
881 sprintf(laszip_dll->error, "quantization sign flip for max_z from %g to %g. set scale factor for z coarser than %g\n", header->max_z, dequant_max_z, header->z_scale_factor);
882 return 1;
883 }
884 }
885 catch (...)
886 {
887 sprintf(laszip_dll->error, "internal error in laszip_auto_offset");
888 return 1;
889 }
890
891 laszip_dll->error[0] = '\0';
892 return 0;
893 }
894
895 /*---------------------------------------------------------------------------*/
896 LASZIP_API laszip_I32
laszip_auto_offset(laszip_POINTER pointer)897 laszip_auto_offset(
898 laszip_POINTER pointer
899 )
900 {
901 if (pointer == 0) return 1;
902 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
903
904 try
905 {
906 if (laszip_dll->reader)
907 {
908 sprintf(laszip_dll->error, "cannot auto offset after reader was opened");
909 return 1;
910 }
911
912 if (laszip_dll->writer)
913 {
914 sprintf(laszip_dll->error, "cannot auto offset after writer was opened");
915 return 1;
916 }
917
918 // get a pointer to the header
919
920 laszip_header_struct* header = &(laszip_dll->header);
921
922 // check scale factor
923
924 F64 x_scale_factor = header->x_scale_factor;
925 F64 y_scale_factor = header->y_scale_factor;
926 F64 z_scale_factor = header->z_scale_factor;
927
928 if ((x_scale_factor <= 0) || !F64_IS_FINITE(x_scale_factor))
929 {
930 sprintf(laszip_dll->error, "invalid x scale_factor %g in header", header->x_scale_factor);
931 return 1;
932 }
933
934 if ((y_scale_factor <= 0) || !F64_IS_FINITE(y_scale_factor))
935 {
936 sprintf(laszip_dll->error, "invalid y scale_factor %g in header", header->y_scale_factor);
937 return 1;
938 }
939
940 if ((z_scale_factor <= 0) || !F64_IS_FINITE(z_scale_factor))
941 {
942 sprintf(laszip_dll->error, "invalid z scale_factor %g in header", header->z_scale_factor);
943 return 1;
944 }
945
946 F64 center_bb_x = (header->min_x + header->max_x) / 2;
947 F64 center_bb_y = (header->min_y + header->max_y) / 2;
948 F64 center_bb_z = (header->min_z + header->max_z) / 2;
949
950 if (!F64_IS_FINITE(center_bb_x))
951 {
952 sprintf(laszip_dll->error, "invalid x coordinate at center of bounding box (min: %g max: %g)", header->min_x, header->max_x);
953 return 1;
954 }
955
956 if (!F64_IS_FINITE(center_bb_y))
957 {
958 sprintf(laszip_dll->error, "invalid y coordinate at center of bounding box (min: %g max: %g)", header->min_y, header->max_y);
959 return 1;
960 }
961
962 if (!F64_IS_FINITE(center_bb_z))
963 {
964 sprintf(laszip_dll->error, "invalid z coordinate at center of bounding box (min: %g max: %g)", header->min_z, header->max_z);
965 return 1;
966 }
967
968 F64 x_offset = header->x_offset;
969 F64 y_offset = header->y_offset;
970 F64 z_offset = header->z_offset;
971
972 header->x_offset = (I64_FLOOR(center_bb_x/x_scale_factor/10000000))*10000000*x_scale_factor;
973 header->y_offset = (I64_FLOOR(center_bb_y/y_scale_factor/10000000))*10000000*y_scale_factor;
974 header->z_offset = (I64_FLOOR(center_bb_z/z_scale_factor/10000000))*10000000*z_scale_factor;
975
976 if (laszip_check_for_integer_overflow(pointer))
977 {
978 header->x_offset = x_offset;
979 header->y_offset = y_offset;
980 header->z_offset = z_offset;
981 return 1;
982 }
983 }
984 catch (...)
985 {
986 sprintf(laszip_dll->error, "internal error in laszip_auto_offset");
987 return 1;
988 }
989
990 laszip_dll->error[0] = '\0';
991 return 0;
992 }
993
994 /*---------------------------------------------------------------------------*/
995 LASZIP_API laszip_I32
laszip_set_point(laszip_POINTER pointer,const laszip_point_struct * point)996 laszip_set_point(
997 laszip_POINTER pointer
998 , const laszip_point_struct* point
999 )
1000 {
1001 if (pointer == 0) return 1;
1002 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1003
1004 try
1005 {
1006 if (point == 0)
1007 {
1008 sprintf(laszip_dll->error, "laszip_point_struct pointer 'point' is zero");
1009 return 1;
1010 }
1011
1012 if (laszip_dll->reader)
1013 {
1014 sprintf(laszip_dll->error, "cannot set point for reader");
1015 return 1;
1016 }
1017
1018 memcpy(&laszip_dll->point, point, ((U8*)&(laszip_dll->point.extra_bytes)) - ((U8*)&(laszip_dll->point.X)));
1019
1020 if (laszip_dll->point.extra_bytes)
1021 {
1022 if (point->extra_bytes)
1023 {
1024 if (laszip_dll->point.num_extra_bytes == point->num_extra_bytes)
1025 {
1026 memcpy(laszip_dll->point.extra_bytes, point->extra_bytes, laszip_dll->point.num_extra_bytes);
1027 }
1028 else
1029 {
1030 sprintf(laszip_dll->error, "target point has %d extra bytes but source point has %d", laszip_dll->point.num_extra_bytes, point->num_extra_bytes);
1031 return 1;
1032 }
1033 }
1034 else if (!laszip_dll->compatibility_mode)
1035 {
1036 sprintf(laszip_dll->error, "target point has extra bytes but source point does not");
1037 return 1;
1038 }
1039 }
1040 /*
1041 else
1042 {
1043 if (point->extra_bytes)
1044 {
1045 sprintf(laszip_dll->error, "source point has extra bytes but target point does not");
1046 return 1;
1047 }
1048 }
1049 */
1050 }
1051 catch (...)
1052 {
1053 sprintf(laszip_dll->error, "internal error in laszip_set_point");
1054 return 1;
1055 }
1056
1057 laszip_dll->error[0] = '\0';
1058 return 0;
1059 }
1060
1061 /*---------------------------------------------------------------------------*/
1062 LASZIP_API laszip_I32
laszip_set_coordinates(laszip_POINTER pointer,const laszip_F64 * coordinates)1063 laszip_set_coordinates(
1064 laszip_POINTER pointer
1065 , const laszip_F64* coordinates
1066 )
1067 {
1068 if (pointer == 0) return 1;
1069 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1070
1071 try
1072 {
1073 if (coordinates == 0)
1074 {
1075 sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero");
1076 return 1;
1077 }
1078
1079 if (laszip_dll->reader)
1080 {
1081 sprintf(laszip_dll->error, "cannot set coordinates for reader");
1082 return 1;
1083 }
1084
1085 // get a pointer to the header
1086
1087 laszip_header_struct* header = &(laszip_dll->header);
1088
1089 // get a pointer to the point
1090
1091 laszip_point_struct* point = &(laszip_dll->point);
1092
1093 // set the coordinates
1094
1095 point->X = I32_QUANTIZE((coordinates[0]-header->x_offset)/header->x_scale_factor);
1096 point->Y = I32_QUANTIZE((coordinates[1]-header->y_offset)/header->y_scale_factor);
1097 point->Z = I32_QUANTIZE((coordinates[2]-header->z_offset)/header->z_scale_factor);
1098 }
1099 catch (...)
1100 {
1101 sprintf(laszip_dll->error, "internal error in laszip_set_coordinates");
1102 return 1;
1103 }
1104
1105 laszip_dll->error[0] = '\0';
1106 return 0;
1107 }
1108
1109 /*---------------------------------------------------------------------------*/
1110 LASZIP_API laszip_I32
laszip_get_coordinates(laszip_POINTER pointer,laszip_F64 * coordinates)1111 laszip_get_coordinates(
1112 laszip_POINTER pointer
1113 , laszip_F64* coordinates
1114 )
1115 {
1116 if (pointer == 0) return 1;
1117 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1118
1119 try
1120 {
1121 if (coordinates == 0)
1122 {
1123 sprintf(laszip_dll->error, "laszip_F64 pointer 'coordinates' is zero");
1124 return 1;
1125 }
1126
1127 // get a pointer to the header
1128
1129 laszip_header_struct* header = &(laszip_dll->header);
1130
1131 // get a pointer to the point
1132
1133 laszip_point_struct* point = &(laszip_dll->point);
1134
1135 // get the coordinates
1136
1137 coordinates[0] = header->x_scale_factor*point->X+header->x_offset;
1138 coordinates[1] = header->y_scale_factor*point->Y+header->y_offset;
1139 coordinates[2] = header->z_scale_factor*point->Z+header->z_offset;
1140 }
1141 catch (...)
1142 {
1143 sprintf(laszip_dll->error, "internal error in laszip_get_coordinates");
1144 return 1;
1145 }
1146
1147 laszip_dll->error[0] = '\0';
1148 return 0;
1149 }
1150
1151 /*---------------------------------------------------------------------------*/
1152 LASZIP_API laszip_I32
laszip_set_geokeys(laszip_POINTER pointer,laszip_U32 number,const laszip_geokey_struct * key_entries)1153 laszip_set_geokeys(
1154 laszip_POINTER pointer
1155 , laszip_U32 number
1156 , const laszip_geokey_struct* key_entries
1157 )
1158 {
1159 if (pointer == 0) return 1;
1160 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1161
1162 try
1163 {
1164 if (number == 0)
1165 {
1166 sprintf(laszip_dll->error, "number of key_entries is zero");
1167 return 1;
1168 }
1169
1170 if (key_entries == 0)
1171 {
1172 sprintf(laszip_dll->error, "laszip_geokey_struct pointer 'key_entries' is zero");
1173 return 1;
1174 }
1175
1176 if (laszip_dll->reader)
1177 {
1178 sprintf(laszip_dll->error, "cannot set geokeys after reader was opened");
1179 return 1;
1180 }
1181
1182 if (laszip_dll->writer)
1183 {
1184 sprintf(laszip_dll->error, "cannot set geokeys after writer was opened");
1185 return 1;
1186 }
1187
1188 // create the geokey directory
1189
1190 laszip_geokey_struct* key_entries_plus_one = new laszip_geokey_struct[number+1];
1191 if (key_entries_plus_one == 0)
1192 {
1193 sprintf(laszip_dll->error, "allocating laszip_geokey_struct[%u] array", number+1);
1194 return 1;
1195 }
1196 key_entries_plus_one[0].key_id = 1; // aka key_directory_version
1197 key_entries_plus_one[0].tiff_tag_location = 1; // aka key_revision
1198 key_entries_plus_one[0].count = 0; // aka minor_revision
1199 key_entries_plus_one[0].value_offset = number; // aka number_of_keys
1200 memcpy(key_entries_plus_one + 1, key_entries, sizeof(laszip_geokey_struct)*number);
1201
1202 // add the VLR
1203
1204 if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34735, (laszip_U16)(8 + number*8), 0, (laszip_U8*)key_entries_plus_one))
1205 {
1206 sprintf(laszip_dll->error, "setting %u geodouble_params", number);
1207 return 1;
1208 }
1209 }
1210 catch (...)
1211 {
1212 sprintf(laszip_dll->error, "internal error in laszip_set_geokey_entries");
1213 return 1;
1214 }
1215
1216 laszip_dll->error[0] = '\0';
1217 return 0;
1218 }
1219
1220 /*---------------------------------------------------------------------------*/
1221 LASZIP_API laszip_I32
laszip_set_geodouble_params(laszip_POINTER pointer,laszip_U32 number,const laszip_F64 * geodouble_params)1222 laszip_set_geodouble_params(
1223 laszip_POINTER pointer
1224 , laszip_U32 number
1225 , const laszip_F64* geodouble_params
1226 )
1227 {
1228 if (pointer == 0) return 1;
1229 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1230
1231 try
1232 {
1233 if (number == 0)
1234 {
1235 sprintf(laszip_dll->error, "number of geodouble_params is zero");
1236 return 1;
1237 }
1238
1239 if (geodouble_params == 0)
1240 {
1241 sprintf(laszip_dll->error, "laszip_F64 pointer 'geodouble_params' is zero");
1242 return 1;
1243 }
1244
1245 if (laszip_dll->reader)
1246 {
1247 sprintf(laszip_dll->error, "cannot set geodouble_params after reader was opened");
1248 return 1;
1249 }
1250
1251 if (laszip_dll->writer)
1252 {
1253 sprintf(laszip_dll->error, "cannot set geodouble_params after writer was opened");
1254 return 1;
1255 }
1256
1257 // add the VLR
1258
1259 if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34736, (laszip_U16)(number*8), 0, (laszip_U8*)geodouble_params))
1260 {
1261 sprintf(laszip_dll->error, "setting %u geodouble_params", number);
1262 return 1;
1263 }
1264 }
1265 catch (...)
1266 {
1267 sprintf(laszip_dll->error, "internal error in laszip_set_geodouble_params");
1268 return 1;
1269 }
1270
1271 laszip_dll->error[0] = '\0';
1272 return 0;
1273 }
1274
1275 /*---------------------------------------------------------------------------*/
1276 LASZIP_API laszip_I32
laszip_set_geoascii_params(laszip_POINTER pointer,laszip_U32 number,const laszip_CHAR * geoascii_params)1277 laszip_set_geoascii_params(
1278 laszip_POINTER pointer
1279 , laszip_U32 number
1280 , const laszip_CHAR* geoascii_params
1281 )
1282 {
1283 if (pointer == 0) return 1;
1284 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1285
1286 try
1287 {
1288 if (number == 0)
1289 {
1290 sprintf(laszip_dll->error, "number of geoascii_params is zero");
1291 return 1;
1292 }
1293
1294 if (geoascii_params == 0)
1295 {
1296 sprintf(laszip_dll->error, "laszip_CHAR pointer 'geoascii_params' is zero");
1297 return 1;
1298 }
1299
1300 if (laszip_dll->reader)
1301 {
1302 sprintf(laszip_dll->error, "cannot set geoascii_params after reader was opened");
1303 return 1;
1304 }
1305
1306 if (laszip_dll->writer)
1307 {
1308 sprintf(laszip_dll->error, "cannot set geoascii_params after writer was opened");
1309 return 1;
1310 }
1311
1312 // add the VLR
1313
1314 if (laszip_add_vlr(laszip_dll, "LASF_Projection", 34737, (laszip_U16)(number), 0, (laszip_U8*)geoascii_params))
1315 {
1316 sprintf(laszip_dll->error, "setting %u geoascii_params", number);
1317 return 1;
1318 }
1319 }
1320 catch (...)
1321 {
1322 sprintf(laszip_dll->error, "internal error in laszip_set_geoascii_params");
1323 return 1;
1324 }
1325
1326 laszip_dll->error[0] = '\0';
1327 return 0;
1328 }
1329
1330 /*---------------------------------------------------------------------------*/
1331 LASZIP_API laszip_I32
laszip_add_attribute(laszip_POINTER pointer,laszip_U32 type,const laszip_CHAR * name,const laszip_CHAR * description,laszip_F64 scale,laszip_F64 offset)1332 laszip_add_attribute(
1333 laszip_POINTER pointer
1334 , laszip_U32 type
1335 , const laszip_CHAR* name
1336 , const laszip_CHAR* description
1337 , laszip_F64 scale
1338 , laszip_F64 offset
1339 )
1340 {
1341 if (pointer == 0) return 1;
1342 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1343
1344 try
1345 {
1346 if (type > LAS_ATTRIBUTE_F64)
1347 {
1348 sprintf(laszip_dll->error, "laszip_U32 'type' is %u but needs to be between %d and %d", type, LAS_ATTRIBUTE_U8, LAS_ATTRIBUTE_F64);
1349 return 1;
1350 }
1351
1352 if (name == 0)
1353 {
1354 sprintf(laszip_dll->error, "laszip_CHAR pointer 'name' is zero");
1355 return 1;
1356 }
1357
1358 if (laszip_dll->reader)
1359 {
1360 sprintf(laszip_dll->error, "cannot add attribute after reader was opened");
1361 return 1;
1362 }
1363
1364 if (laszip_dll->writer)
1365 {
1366 sprintf(laszip_dll->error, "cannot add attribute after writer was opened");
1367 return 1;
1368 }
1369
1370 LASattribute lasattribute(type, name, description);
1371 lasattribute.set_scale(scale);
1372 lasattribute.set_offset(offset);
1373
1374 if (laszip_dll->attributer == 0)
1375 {
1376 laszip_dll->attributer = new LASattributer;
1377 if (laszip_dll->attributer == 0)
1378 {
1379 sprintf(laszip_dll->error, "cannot allocate LASattributer");
1380 return 1;
1381 }
1382 }
1383
1384 if (laszip_dll->attributer->add_attribute(lasattribute) == -1)
1385 {
1386 sprintf(laszip_dll->error, "cannot add attribute '%s' to attributer", name);
1387 return 1;
1388 }
1389
1390 if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes))
1391 {
1392 sprintf(laszip_dll->error, "adding the new extra bytes VLR with the additional attribute '%s'", name);
1393 return 1;
1394 }
1395 }
1396 catch (...)
1397 {
1398 sprintf(laszip_dll->error, "internal error in laszip_add_attribute");
1399 return 1;
1400 }
1401
1402 laszip_dll->error[0] = '\0';
1403 return 0;
1404 }
1405
1406 /*---------------------------------------------------------------------------*/
1407 LASZIP_API laszip_I32
laszip_add_vlr(laszip_POINTER pointer,const laszip_CHAR * user_id,laszip_U16 record_id,laszip_U16 record_length_after_header,const laszip_CHAR * description,const laszip_U8 * data)1408 laszip_add_vlr(
1409 laszip_POINTER pointer
1410 , const laszip_CHAR* user_id
1411 , laszip_U16 record_id
1412 , laszip_U16 record_length_after_header
1413 , const laszip_CHAR* description
1414 , const laszip_U8* data
1415 )
1416 {
1417 if (pointer == 0) return 1;
1418 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1419
1420 try
1421 {
1422 if (user_id == 0)
1423 {
1424 sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero");
1425 return 1;
1426 }
1427
1428 if ((record_length_after_header > 0) && (data == 0))
1429 {
1430 sprintf(laszip_dll->error, "record_length_after_header of VLR is %u but data pointer is zero", (U32)record_length_after_header);
1431 return 1;
1432 }
1433
1434 if (laszip_dll->reader)
1435 {
1436 sprintf(laszip_dll->error, "cannot add vlr after reader was opened");
1437 return 1;
1438 }
1439
1440 if (laszip_dll->writer)
1441 {
1442 sprintf(laszip_dll->error, "cannot add vlr after writer was opened");
1443 return 1;
1444 }
1445
1446 U32 i = 0;
1447
1448 if (laszip_dll->header.vlrs)
1449 {
1450 // overwrite existing VLR ?
1451
1452 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
1453 {
1454 if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id))
1455 {
1456 if (laszip_dll->header.vlrs[i].record_length_after_header)
1457 {
1458 laszip_dll->header.offset_to_point_data -= laszip_dll->header.vlrs[i].record_length_after_header;
1459 laszip_dll->header.vlrs[i].record_length_after_header = 0;
1460 delete [] laszip_dll->header.vlrs[i].data;
1461 laszip_dll->header.vlrs[i].data = 0;
1462 }
1463 break;
1464 }
1465 }
1466
1467 // create new VLR
1468
1469 if (i == laszip_dll->header.number_of_variable_length_records)
1470 {
1471 laszip_dll->header.number_of_variable_length_records++;
1472 laszip_dll->header.offset_to_point_data += 54;
1473 laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records);
1474 if (laszip_dll->header.vlrs == 0)
1475 {
1476 sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records);
1477 return 1;
1478 }
1479 }
1480 }
1481 else
1482 {
1483 laszip_dll->header.number_of_variable_length_records = 1;
1484 laszip_dll->header.offset_to_point_data += 54;
1485 laszip_dll->header.vlrs = (laszip_vlr_struct*)malloc(sizeof(laszip_vlr_struct));
1486 if (laszip_dll->header.vlrs == 0)
1487 {
1488 sprintf(laszip_dll->error, "allocating vlrs[1] array");
1489 return 1;
1490 }
1491 }
1492
1493 // zero the VLR
1494
1495 memset(&(laszip_dll->header.vlrs[i]), 0, sizeof(laszip_vlr_struct));
1496
1497 // copy the VLR
1498
1499 laszip_dll->header.vlrs[i].reserved = 0x0;
1500 strncpy(laszip_dll->header.vlrs[i].user_id, user_id, 16);
1501 laszip_dll->header.vlrs[i].record_id = record_id;
1502 laszip_dll->header.vlrs[i].record_length_after_header = record_length_after_header;
1503 if (description)
1504 {
1505 strncpy(laszip_dll->header.vlrs[i].description, description, 32);
1506 }
1507 else
1508 {
1509 sprintf(laszip_dll->header.vlrs[i].description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
1510 }
1511 if (record_length_after_header)
1512 {
1513 laszip_dll->header.offset_to_point_data += record_length_after_header;
1514 laszip_dll->header.vlrs[i].data = new U8[record_length_after_header];
1515 memcpy(laszip_dll->header.vlrs[i].data, data, record_length_after_header);
1516 }
1517 }
1518 catch (...)
1519 {
1520 sprintf(laszip_dll->error, "internal error in laszip_add_vlr");
1521 return 1;
1522 }
1523
1524 laszip_dll->error[0] = '\0';
1525 return 0;
1526 }
1527
1528 /*---------------------------------------------------------------------------*/
1529 LASZIP_API laszip_I32
laszip_remove_vlr(laszip_POINTER pointer,const laszip_CHAR * user_id,laszip_U16 record_id)1530 laszip_remove_vlr(
1531 laszip_POINTER pointer
1532 , const laszip_CHAR* user_id
1533 , laszip_U16 record_id
1534 )
1535 {
1536 if (pointer == 0) return 1;
1537 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1538
1539 try
1540 {
1541 if (user_id == 0)
1542 {
1543 sprintf(laszip_dll->error, "laszip_CHAR pointer 'user_id' is zero");
1544 return 1;
1545 }
1546
1547 if (laszip_dll->reader)
1548 {
1549 sprintf(laszip_dll->error, "cannot remove vlr after reader was opened");
1550 return 1;
1551 }
1552
1553 if (laszip_dll->writer)
1554 {
1555 sprintf(laszip_dll->error, "cannot remove vlr after writer was opened");
1556 return 1;
1557 }
1558
1559 U32 i = 0;
1560
1561 if (laszip_dll->header.vlrs)
1562 {
1563 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
1564 {
1565 if ((strncmp(laszip_dll->header.vlrs[i].user_id, user_id, 16) == 0) && (laszip_dll->header.vlrs[i].record_id == record_id))
1566 {
1567 if (laszip_dll->header.vlrs[i].record_length_after_header)
1568 {
1569 laszip_dll->header.offset_to_point_data -= (54 + laszip_dll->header.vlrs[i].record_length_after_header);
1570 delete [] laszip_dll->header.vlrs[i].data;
1571 laszip_dll->header.vlrs[i].data = 0;
1572 }
1573 laszip_dll->header.number_of_variable_length_records--;
1574 for (/*i = i*/; i < laszip_dll->header.number_of_variable_length_records; i++)
1575 {
1576 laszip_dll->header.vlrs[i] = laszip_dll->header.vlrs[i+1];
1577 }
1578 if (laszip_dll->header.number_of_variable_length_records)
1579 {
1580 laszip_dll->header.vlrs = (laszip_vlr_struct*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr_struct)*laszip_dll->header.number_of_variable_length_records);
1581 if (laszip_dll->header.vlrs == 0)
1582 {
1583 sprintf(laszip_dll->error, "reallocating vlrs[%u] array", laszip_dll->header.number_of_variable_length_records);
1584 return 1;
1585 }
1586 }
1587 else
1588 {
1589 free(laszip_dll->header.vlrs);
1590 laszip_dll->header.vlrs = 0;
1591 }
1592 i = U32_MAX;
1593 break;
1594 }
1595 }
1596 if (i != U32_MAX)
1597 {
1598 sprintf(laszip_dll->error, "cannot find VLR with user_id '%s' and record_id %d among the %u VLRs in the header", user_id, (I32)record_id, laszip_dll->header.number_of_variable_length_records);
1599 return 1;
1600 }
1601 }
1602 else
1603 {
1604 sprintf(laszip_dll->error, "cannot remove VLR with user_id '%s' and record_id %d because header has no VLRs", user_id, (I32)record_id);
1605 return 1;
1606 }
1607 }
1608 catch (...)
1609 {
1610 sprintf(laszip_dll->error, "internal error in laszip_add_vlr");
1611 return 1;
1612 }
1613
1614 laszip_dll->error[0] = '\0';
1615 return 0;
1616 }
1617
1618 /*---------------------------------------------------------------------------*/
1619 LASZIP_API laszip_I32
laszip_preserve_generating_software(laszip_POINTER pointer,const laszip_BOOL preserve)1620 laszip_preserve_generating_software(
1621 laszip_POINTER pointer
1622 , const laszip_BOOL preserve
1623 )
1624 {
1625 if (pointer == 0) return 1;
1626 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1627
1628 try
1629 {
1630 if (laszip_dll->reader)
1631 {
1632 sprintf(laszip_dll->error, "reader is already open");
1633 return 1;
1634 }
1635
1636 if (laszip_dll->writer)
1637 {
1638 sprintf(laszip_dll->error, "writer is already open");
1639 return 1;
1640 }
1641
1642 laszip_dll->preserve_generating_software = preserve;
1643 }
1644 catch (...)
1645 {
1646 sprintf(laszip_dll->error, "internal error in laszip_preserve_generating_software");
1647 return 1;
1648 }
1649
1650 laszip_dll->error[0] = '\0';
1651 return 0;
1652 }
1653
1654
1655 /*---------------------------------------------------------------------------*/
1656 LASZIP_API laszip_I32
laszip_request_native_extension(laszip_POINTER pointer,const laszip_BOOL request)1657 laszip_request_native_extension(
1658 laszip_POINTER pointer
1659 , const laszip_BOOL request
1660 )
1661 {
1662 if (pointer == 0) return 1;
1663 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1664
1665 try
1666 {
1667 if (laszip_dll->reader)
1668 {
1669 sprintf(laszip_dll->error, "reader is already open");
1670 return 1;
1671 }
1672
1673 if (laszip_dll->writer)
1674 {
1675 sprintf(laszip_dll->error, "writer is already open");
1676 return 1;
1677 }
1678
1679 laszip_dll->request_native_extension = request;
1680
1681 if (request) // only one should be on
1682 {
1683 laszip_dll->request_compatibility_mode = FALSE;
1684 }
1685 }
1686 catch (...)
1687 {
1688 sprintf(laszip_dll->error, "internal error in laszip_request_native_extension");
1689 return 1;
1690 }
1691
1692 laszip_dll->error[0] = '\0';
1693 return 0;
1694 }
1695
1696 /*---------------------------------------------------------------------------*/
1697 LASZIP_API laszip_I32
laszip_request_compatibility_mode(laszip_POINTER pointer,const laszip_BOOL request)1698 laszip_request_compatibility_mode(
1699 laszip_POINTER pointer
1700 , const laszip_BOOL request
1701 )
1702 {
1703 if (pointer == 0) return 1;
1704 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1705
1706 try
1707 {
1708 if (laszip_dll->reader)
1709 {
1710 sprintf(laszip_dll->error, "reader is already open");
1711 return 1;
1712 }
1713
1714 if (laszip_dll->writer)
1715 {
1716 sprintf(laszip_dll->error, "writer is already open");
1717 return 1;
1718 }
1719
1720 laszip_dll->request_compatibility_mode = request;
1721
1722 if (request) // only one should be on
1723 {
1724 laszip_dll->request_native_extension = FALSE;
1725 }
1726 }
1727 catch (...)
1728 {
1729 sprintf(laszip_dll->error, "internal error in laszip_request_compatibility_mode");
1730 return 1;
1731 }
1732
1733 laszip_dll->error[0] = '\0';
1734 return 0;
1735 }
1736
1737 /*---------------------------------------------------------------------------*/
1738 LASZIP_API laszip_I32
laszip_set_chunk_size(laszip_POINTER pointer,const laszip_U32 chunk_size)1739 laszip_set_chunk_size(
1740 laszip_POINTER pointer
1741 , const laszip_U32 chunk_size
1742 )
1743 {
1744 if (pointer == 0) return 1;
1745 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1746
1747 try
1748 {
1749 if (laszip_dll->reader)
1750 {
1751 sprintf(laszip_dll->error, "reader is already open");
1752 return 1;
1753 }
1754
1755 if (laszip_dll->writer)
1756 {
1757 sprintf(laszip_dll->error, "writer is already open");
1758 return 1;
1759 }
1760
1761 laszip_dll->set_chunk_size = chunk_size;
1762 }
1763 catch (...)
1764 {
1765 sprintf(laszip_dll->error, "internal error in laszip_set_chunk_size");
1766 return 1;
1767 }
1768
1769 laszip_dll->error[0] = '\0';
1770 return 0;
1771 }
1772
1773 /*---------------------------------------------------------------------------*/
1774 LASZIP_API laszip_I32
laszip_create_spatial_index(laszip_POINTER pointer,const laszip_BOOL create,const laszip_BOOL append)1775 laszip_create_spatial_index(
1776 laszip_POINTER pointer
1777 , const laszip_BOOL create
1778 , const laszip_BOOL append
1779 )
1780 {
1781 if (pointer == 0) return 1;
1782 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
1783
1784 try
1785 {
1786 if (laszip_dll->reader)
1787 {
1788 sprintf(laszip_dll->error, "reader is already open");
1789 return 1;
1790 }
1791
1792 if (laszip_dll->writer)
1793 {
1794 sprintf(laszip_dll->error, "writer is already open");
1795 return 1;
1796 }
1797
1798 if (append)
1799 {
1800 sprintf(laszip_dll->error, "appending of spatial index not (yet) supported in this version");
1801 return 1;
1802 }
1803
1804 laszip_dll->lax_create = create;
1805 laszip_dll->lax_append = append;
1806 }
1807 catch (...)
1808 {
1809 sprintf(laszip_dll->error, "internal error in laszip_create_spatial_index");
1810 return 1;
1811 }
1812
1813 laszip_dll->error[0] = '\0';
1814 return 0;
1815 }
1816
1817 /*---------------------------------------------------------------------------*/
1818 static I32
laszip_prepare_header_for_write(laszip_dll_struct * laszip_dll)1819 laszip_prepare_header_for_write(
1820 laszip_dll_struct* laszip_dll
1821 )
1822 {
1823 if ((laszip_dll->header.version_major != 1) || (laszip_dll->header.version_minor > 4))
1824 {
1825 sprintf(laszip_dll->error, "unknown LAS version %d.%d", (I32)laszip_dll->header.version_major, (I32)laszip_dll->header.version_minor);
1826 return 1;
1827 }
1828
1829 // check counters
1830 U32 i;
1831
1832 if (laszip_dll->header.point_data_format > 5)
1833 {
1834 // legacy counters are zero for new point types
1835
1836 laszip_dll->header.number_of_point_records = 0;
1837 for (i = 0; i < 5; i++)
1838 {
1839 laszip_dll->header.number_of_points_by_return[i] = 0;
1840 }
1841 }
1842 else if (laszip_dll->header.version_minor > 3)
1843 {
1844 // legacy counters must be zero or consistent for old point types
1845
1846 if (laszip_dll->header.number_of_point_records != laszip_dll->header.extended_number_of_point_records)
1847 {
1848 if (laszip_dll->header.number_of_point_records != 0)
1849 {
1850 #ifdef _WIN32
1851 sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %I64d", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records);
1852 #else
1853 sprintf(laszip_dll->error, "inconsistent number_of_point_records %u and extended_number_of_point_records %llu", laszip_dll->header.number_of_point_records, laszip_dll->header.extended_number_of_point_records);
1854 #endif
1855 return 1;
1856 }
1857 else if (laszip_dll->header.extended_number_of_point_records <= U32_MAX)
1858 {
1859 laszip_dll->header.number_of_point_records = (U32)laszip_dll->header.extended_number_of_point_records;
1860 }
1861 }
1862 for (i = 0; i < 5; i++)
1863 {
1864 if (laszip_dll->header.number_of_points_by_return[i] != laszip_dll->header.extended_number_of_points_by_return[i])
1865 {
1866 if (laszip_dll->header.number_of_points_by_return[i] != 0)
1867 {
1868 #ifdef _WIN32
1869 sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %I64d", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]);
1870 #else
1871 sprintf(laszip_dll->error, "inconsistent number_of_points_by_return[%u] %u and extended_number_of_points_by_return[%u] %llu", i, laszip_dll->header.number_of_points_by_return[i], i, laszip_dll->header.extended_number_of_points_by_return[i]);
1872 #endif
1873 return 1;
1874 }
1875 else if (laszip_dll->header.extended_number_of_points_by_return[i] <= U32_MAX)
1876 {
1877 laszip_dll->header.number_of_points_by_return[i] = (U32)laszip_dll->header.extended_number_of_points_by_return[i];
1878 }
1879 }
1880 }
1881 }
1882
1883 return 0;
1884 }
1885
1886 /*---------------------------------------------------------------------------*/
1887 static I32
laszip_prepare_point_for_write(laszip_dll_struct * laszip_dll,const laszip_BOOL compress)1888 laszip_prepare_point_for_write(
1889 laszip_dll_struct* laszip_dll
1890 , const laszip_BOOL compress
1891 )
1892 {
1893 U32 i;
1894
1895 if (laszip_dll->header.point_data_format > 5)
1896 {
1897 // must be set for the new point types 6 or higher ...
1898
1899 laszip_dll->point.extended_point_type = 1;
1900
1901 if (laszip_dll->request_native_extension)
1902 {
1903 // we are *not* operating in compatibility mode
1904
1905 laszip_dll->compatibility_mode = FALSE;
1906 }
1907 else if (laszip_dll->request_compatibility_mode)
1908 {
1909 // we are *not* using the native extension
1910
1911 laszip_dll->request_native_extension = FALSE;
1912
1913 // make sure there are no more than U32_MAX points
1914
1915 if (laszip_dll->header.extended_number_of_point_records > U32_MAX)
1916 {
1917 #ifdef _WIN32
1918 sprintf(laszip_dll->error, "extended_number_of_point_records of %I64d is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records);
1919 #else
1920 sprintf(laszip_dll->error, "extended_number_of_point_records of %llu is too much for 32-bit counters of compatibility mode", laszip_dll->header.extended_number_of_point_records);
1921 #endif
1922 return 1;
1923 }
1924
1925 // copy 64-bit extended counters back into 32-bit legacy counters
1926
1927 laszip_dll->header.number_of_point_records = (U32)(laszip_dll->header.extended_number_of_point_records);
1928 for (i = 0; i < 5; i++)
1929 {
1930 laszip_dll->header.number_of_points_by_return[i] = (U32)(laszip_dll->header.extended_number_of_points_by_return[i]);
1931 }
1932
1933 // are there any "extra bytes" already ... ?
1934
1935 I32 number_of_existing_extrabytes = 0;
1936
1937 switch (laszip_dll->header.point_data_format)
1938 {
1939 case 6:
1940 number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 30;
1941 break;
1942 case 7:
1943 number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 36;
1944 break;
1945 case 8:
1946 number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 38;
1947 break;
1948 case 9:
1949 number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 59;
1950 break;
1951 case 10:
1952 number_of_existing_extrabytes = laszip_dll->header.point_data_record_length - 67;
1953 break;
1954 default:
1955 sprintf(laszip_dll->error, "unknown point_data_format %d", laszip_dll->header.point_data_format);
1956 return 1;
1957 }
1958
1959 if (number_of_existing_extrabytes < 0)
1960 {
1961 sprintf(laszip_dll->error, "bad point_data_format %d point_data_record_length %d combination", laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length);
1962 return 1;
1963 }
1964
1965 // downgrade to LAS 1.2 or LAS 1.3
1966 if (laszip_dll->header.point_data_format <= 8)
1967 {
1968 laszip_dll->header.version_minor = 2;
1969 // LAS 1.2 header is 148 bytes less than LAS 1.4+ header
1970 laszip_dll->header.header_size -= 148;
1971 laszip_dll->header.offset_to_point_data -= 148;
1972 }
1973 else
1974 {
1975 laszip_dll->header.version_minor = 3;
1976 // LAS 1.3 header is 140 bytes less than LAS 1.4+ header
1977 laszip_dll->header.header_size -= 140;
1978 laszip_dll->header.offset_to_point_data -= 140;
1979 }
1980 // turn off the bit indicating the presence of the OGC WKT
1981 laszip_dll->header.global_encoding &= ~(1<<4);
1982
1983 // old point type is two bytes shorter
1984 laszip_dll->header.point_data_record_length -= 2;
1985 // but we add 5 bytes of attributes
1986 laszip_dll->header.point_data_record_length += 5;
1987
1988 // create 2+2+4+148 bytes payload for compatibility VLR
1989 ByteStreamOutArray* out;
1990 if (IS_LITTLE_ENDIAN())
1991 out = new ByteStreamOutArrayLE();
1992 else
1993 out = new ByteStreamOutArrayBE();
1994 // write control info
1995 U16 laszip_version = (U16)LASZIP_VERSION_BUILD_DATE;
1996 out->put16bitsLE((U8*)&laszip_version);
1997 U16 compatible_version = 3;
1998 out->put16bitsLE((U8*)&compatible_version);
1999 U32 unused = 0;
2000 out->put32bitsLE((U8*)&unused);
2001 // write the 148 bytes of the extended LAS 1.4 header
2002 U64 start_of_waveform_data_packet_record = laszip_dll->header.start_of_waveform_data_packet_record;
2003 if (start_of_waveform_data_packet_record != 0)
2004 {
2005 #ifdef _WIN32
2006 fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %I64d. writing 0 instead.\n", start_of_waveform_data_packet_record);
2007 #else
2008 fprintf(stderr,"WARNING: header->start_of_waveform_data_packet_record is %llu. writing 0 instead.\n", start_of_waveform_data_packet_record);
2009 #endif
2010 start_of_waveform_data_packet_record = 0;
2011 }
2012 out->put64bitsLE((U8*)&start_of_waveform_data_packet_record);
2013 U64 start_of_first_extended_variable_length_record = laszip_dll->header.start_of_first_extended_variable_length_record;
2014 if (start_of_first_extended_variable_length_record != 0)
2015 {
2016 #ifdef _WIN32
2017 fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %I64d. writing 0 instead.\n", start_of_first_extended_variable_length_record);
2018 #else
2019 fprintf(stderr,"WARNING: EVLRs not supported. header->start_of_first_extended_variable_length_record is %llu. writing 0 instead.\n", start_of_first_extended_variable_length_record);
2020 #endif
2021 start_of_first_extended_variable_length_record = 0;
2022 }
2023 out->put64bitsLE((U8*)&start_of_first_extended_variable_length_record);
2024 U32 number_of_extended_variable_length_records = laszip_dll->header.number_of_extended_variable_length_records;
2025 if (number_of_extended_variable_length_records != 0)
2026 {
2027 fprintf(stderr,"WARNING: EVLRs not supported. header->number_of_extended_variable_length_records is %u. writing 0 instead.\n", number_of_extended_variable_length_records);
2028 number_of_extended_variable_length_records = 0;
2029 }
2030 out->put32bitsLE((U8*)&number_of_extended_variable_length_records);
2031 U64 extended_number_of_point_records;
2032 if (laszip_dll->header.number_of_point_records)
2033 extended_number_of_point_records = laszip_dll->header.number_of_point_records;
2034 else
2035 extended_number_of_point_records = laszip_dll->header.extended_number_of_point_records;
2036 out->put64bitsLE((U8*)&extended_number_of_point_records);
2037 U64 extended_number_of_points_by_return;
2038 for (i = 0; i < 15; i++)
2039 {
2040 if ((i < 5) && laszip_dll->header.number_of_points_by_return[i])
2041 extended_number_of_points_by_return = laszip_dll->header.number_of_points_by_return[i];
2042 else
2043 extended_number_of_points_by_return = laszip_dll->header.extended_number_of_points_by_return[i];
2044 out->put64bitsLE((U8*)&extended_number_of_points_by_return);
2045 }
2046
2047 // add the compatibility VLR
2048
2049 if (laszip_add_vlr(laszip_dll, "lascompatible\0\0", 22204, (laszip_U16)(2+2+4+148), 0, (laszip_U8*)out->takeData()))
2050 {
2051 sprintf(laszip_dll->error, "adding the compatibility VLR");
2052 return 1;
2053 }
2054 delete out;
2055
2056 // if needed create an attributer to describe the "extra bytes"
2057
2058 if (laszip_dll->attributer == 0)
2059 {
2060 laszip_dll->attributer = new LASattributer;
2061 if (laszip_dll->attributer == 0)
2062 {
2063 sprintf(laszip_dll->error, "cannot allocate LASattributer");
2064 return 1;
2065 }
2066 }
2067
2068 // were there any pre-existing extra bytes
2069
2070 if (number_of_existing_extrabytes > 0)
2071 {
2072 // make sure the existing "extra bytes" are documented
2073
2074 if (laszip_dll->attributer->get_attributes_size() > number_of_existing_extrabytes)
2075 {
2076 sprintf(laszip_dll->error, "bad \"extra bytes\" VLR describes %d bytes more than points actually have", laszip_dll->attributer->get_attributes_size() - number_of_existing_extrabytes);
2077 return 1;
2078 }
2079 else if (laszip_dll->attributer->get_attributes_size() < number_of_existing_extrabytes)
2080 {
2081 // maybe the existing "extra bytes" are documented in a VLR
2082 if (laszip_dll->header.vlrs)
2083 {
2084 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2085 {
2086 if ((strcmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec") == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
2087 {
2088 laszip_dll->attributer->init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/sizeof(LASattribute), (LASattribute*)laszip_dll->header.vlrs[i].data);
2089 }
2090 }
2091 }
2092
2093 // describe any undocumented "extra bytes" as "unknown" U8 attributes
2094 for (I32 i = (I32)(laszip_dll->attributer->get_attributes_size()); i < number_of_existing_extrabytes; i++)
2095 {
2096 CHAR unknown_name[16];
2097 memset(unknown_name, 0, 16);
2098 sprintf(unknown_name, "unknown %d", i);
2099 LASattribute lasattribute_unknown(LAS_ATTRIBUTE_U8, unknown_name, unknown_name);
2100 if (laszip_dll->attributer->add_attribute(lasattribute_unknown) == -1)
2101 {
2102 sprintf(laszip_dll->error, "cannot add unknown U8 attribute '%s' of %d to attributer", unknown_name, number_of_existing_extrabytes);
2103 return 1;
2104 }
2105 }
2106 }
2107 }
2108
2109 // create the "extra bytes" that store the newer LAS 1.4 point attributes
2110
2111 // scan_angle (difference or remainder) is stored as a I16
2112 LASattribute lasattribute_scan_angle(LAS_ATTRIBUTE_I16, "LAS 1.4 scan angle", "additional attributes");
2113 lasattribute_scan_angle.set_scale(0.006);
2114 I32 index_scan_angle = laszip_dll->attributer->add_attribute(lasattribute_scan_angle);
2115 laszip_dll->start_scan_angle = laszip_dll->attributer->get_attribute_start(index_scan_angle);
2116 // extended returns stored as a U8
2117 LASattribute lasattribute_extended_returns(LAS_ATTRIBUTE_U8, "LAS 1.4 extended returns", "additional attributes");
2118 I32 index_extended_returns = laszip_dll->attributer->add_attribute(lasattribute_extended_returns);
2119 laszip_dll->start_extended_returns = laszip_dll->attributer->get_attribute_start(index_extended_returns);
2120 // classification stored as a U8
2121 LASattribute lasattribute_classification(LAS_ATTRIBUTE_U8, "LAS 1.4 classification", "additional attributes");
2122 I32 index_classification = laszip_dll->attributer->add_attribute(lasattribute_classification);
2123 laszip_dll->start_classification = laszip_dll->attributer->get_attribute_start(index_classification);
2124 // flags and channel stored as a U8
2125 LASattribute lasattribute_flags_and_channel(LAS_ATTRIBUTE_U8, "LAS 1.4 flags and channel", "additional attributes");
2126 I32 index_flags_and_channel = laszip_dll->attributer->add_attribute(lasattribute_flags_and_channel);
2127 laszip_dll->start_flags_and_channel = laszip_dll->attributer->get_attribute_start(index_flags_and_channel);
2128 // maybe store the NIR band as a U16
2129 if (laszip_dll->header.point_data_format == 8 || laszip_dll->header.point_data_format == 10)
2130 {
2131 // the NIR band is stored as a U16
2132 LASattribute lasattribute_NIR_band(LAS_ATTRIBUTE_U16, "LAS 1.4 NIR band", "additional attributes");
2133 I32 index_NIR_band = laszip_dll->attributer->add_attribute(lasattribute_NIR_band);
2134 laszip_dll->start_NIR_band = laszip_dll->attributer->get_attribute_start(index_NIR_band);
2135 }
2136 else
2137 {
2138 laszip_dll->start_NIR_band = -1;
2139 }
2140
2141 // add the extra bytes VLR with the additional attributes
2142
2143 if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(laszip_dll->attributer->number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)laszip_dll->attributer->attributes))
2144 {
2145 sprintf(laszip_dll->error, "adding the extra bytes VLR with the additional attributes");
2146 return 1;
2147 }
2148
2149 // update point type
2150
2151 if (laszip_dll->header.point_data_format == 6)
2152 {
2153 laszip_dll->header.point_data_format = 1;
2154 }
2155 else if (laszip_dll->header.point_data_format <= 8)
2156 {
2157 laszip_dll->header.point_data_format = 3;
2158 }
2159 else // 9->4 and 10->5
2160 {
2161 laszip_dll->header.point_data_format -= 5;
2162 }
2163
2164 // we are operating in compatibility mode
2165 laszip_dll->compatibility_mode = TRUE;
2166 }
2167 else if (compress)
2168 {
2169 sprintf(laszip_dll->error, "LASzip DLL %d.%d r%d (%d) cannot compress point data format %d without requesting 'compatibility mode'", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE, (I32)laszip_dll->header.point_data_format);
2170 return 1;
2171 }
2172 }
2173 else
2174 {
2175 // must *not* be set for the old point type 5 or lower
2176
2177 laszip_dll->point.extended_point_type = 0;
2178
2179 // we are *not* operating in compatibility mode
2180
2181 laszip_dll->compatibility_mode = FALSE;
2182 }
2183
2184 return 0;
2185 }
2186
2187 /*---------------------------------------------------------------------------*/
2188 static I32
laszip_prepare_vlrs_for_write(laszip_dll_struct * laszip_dll)2189 laszip_prepare_vlrs_for_write(
2190 laszip_dll_struct* laszip_dll
2191 )
2192 {
2193 U32 i, vlrs_size = 0;
2194
2195 if (laszip_dll->header.number_of_variable_length_records)
2196 {
2197 if (laszip_dll->header.vlrs == 0)
2198 {
2199 sprintf(laszip_dll->error, "number_of_variable_length_records is %u but vlrs pointer is zero", laszip_dll->header.number_of_variable_length_records);
2200 return 1;
2201 }
2202
2203 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2204 {
2205 vlrs_size += 54;
2206 if (laszip_dll->header.vlrs[i].record_length_after_header)
2207 {
2208 if (laszip_dll->header.vlrs == 0)
2209 {
2210 sprintf(laszip_dll->error, "vlrs[%u].record_length_after_header is %u but vlrs[%u].data pointer is zero", i, laszip_dll->header.vlrs[i].record_length_after_header, i);
2211 return 1;
2212 }
2213 vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header;
2214 }
2215 }
2216 }
2217
2218 if ((vlrs_size + laszip_dll->header.header_size + laszip_dll->header.user_data_after_header_size) != laszip_dll->header.offset_to_point_data)
2219 {
2220 sprintf(laszip_dll->error,"header_size (%u) plus vlrs_size (%u) plus user_data_after_header_size (%u) does not equal offset_to_point_data (%u)", (U32)laszip_dll->header.header_size, vlrs_size, laszip_dll->header.user_data_after_header_size, laszip_dll->header.offset_to_point_data);
2221 return 1;
2222 }
2223
2224 return 0;
2225 }
2226
2227 /*---------------------------------------------------------------------------*/
2228 static U32
laszip_vrl_payload_size(const LASzip * laszip)2229 laszip_vrl_payload_size(
2230 const LASzip* laszip
2231 )
2232 {
2233 return 34 + (6 * laszip->num_items);
2234 }
2235
2236 /*---------------------------------------------------------------------------*/
2237 static I32
write_laszip_vlr_header(laszip_dll_struct * laszip_dll,const LASzip * laszip,ByteStreamOut * out)2238 write_laszip_vlr_header(
2239 laszip_dll_struct* laszip_dll
2240 , const LASzip* laszip
2241 , ByteStreamOut* out
2242 )
2243 {
2244 // write the LASzip VLR header
2245
2246 U16 reserved = 0x0;
2247 try { out->put16bitsLE((U8*)&reserved); } catch(...)
2248 {
2249 sprintf(laszip_dll->error, "writing LASzip VLR header.reserved");
2250 return 1;
2251 }
2252 U8 user_id[16] = "laszip encoded\0";
2253 try { out->putBytes((U8*)user_id, 16); } catch(...)
2254 {
2255 sprintf(laszip_dll->error, "writing LASzip VLR header.user_id");
2256 return 1;
2257 }
2258 U16 record_id = 22204;
2259 try { out->put16bitsLE((U8*)&record_id); } catch(...)
2260 {
2261 sprintf(laszip_dll->error, "writing LASzip VLR header.record_id");
2262 return 1;
2263 }
2264 U16 record_length_after_header = (U16)laszip_vrl_payload_size(laszip);
2265 try { out->put16bitsLE((U8*)&record_length_after_header); } catch(...)
2266 {
2267 sprintf(laszip_dll->error, "writing LASzip VLR header.record_length_after_header");
2268 return 1;
2269 }
2270 CHAR description[32];
2271 memset(description, 0, 32);
2272 sprintf(description, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
2273 try { out->putBytes((U8*)description, 32); } catch(...)
2274 {
2275 sprintf(laszip_dll->error, "writing LASzip VLR header.description");
2276 return 1;
2277 }
2278
2279 return 0;
2280 }
2281
2282 /*---------------------------------------------------------------------------*/
2283 static I32
write_laszip_vlr_payload(laszip_dll_struct * laszip_dll,const LASzip * laszip,ByteStreamOut * out)2284 write_laszip_vlr_payload(
2285 laszip_dll_struct* laszip_dll
2286 , const LASzip* laszip
2287 , ByteStreamOut* out
2288 )
2289 {
2290 // write the LASzip VLR payload
2291
2292 // U16 compressor 2 bytes
2293 // U32 coder 2 bytes
2294 // U8 version_major 1 byte
2295 // U8 version_minor 1 byte
2296 // U16 version_revision 2 bytes
2297 // U32 options 4 bytes
2298 // I32 chunk_size 4 bytes
2299 // I64 number_of_special_evlrs 8 bytes
2300 // I64 offset_to_special_evlrs 8 bytes
2301 // U16 num_items 2 bytes
2302 // U16 type 2 bytes * num_items
2303 // U16 size 2 bytes * num_items
2304 // U16 version 2 bytes * num_items
2305 // which totals 34+6*num_items
2306
2307 try { out->put16bitsLE((const U8*)&(laszip->compressor)); } catch(...)
2308 {
2309 sprintf(laszip_dll->error, "writing compressor %d", (I32)laszip->compressor);
2310 return 1;
2311 }
2312 try { out->put16bitsLE((const U8*)&(laszip->coder)); } catch(...)
2313 {
2314 sprintf(laszip_dll->error, "writing coder %d", (I32)laszip->coder);
2315 return 1;
2316 }
2317 try { out->putBytes((const U8*)&(laszip->version_major), 1); } catch(...)
2318 {
2319 sprintf(laszip_dll->error, "writing version_major %d", (I32)laszip->version_major);
2320 return 1;
2321 }
2322 try { out->putBytes((const U8*)&(laszip->version_minor), 1); } catch(...)
2323 {
2324 sprintf(laszip_dll->error, "writing version_minor %d", (I32)laszip->version_minor);
2325 return 1;
2326 }
2327 try { out->put16bitsLE((const U8*)&(laszip->version_revision)); } catch(...)
2328 {
2329 sprintf(laszip_dll->error, "writing version_revision %d", (I32)laszip->version_revision);
2330 return 1;
2331 }
2332 try { out->put32bitsLE((const U8*)&(laszip->options)); } catch(...)
2333 {
2334 sprintf(laszip_dll->error, "writing options %u", laszip->options);
2335 return 1;
2336 }
2337 try { out->put32bitsLE((const U8*)&(laszip->chunk_size)); } catch(...)
2338 {
2339 sprintf(laszip_dll->error, "writing chunk_size %u", laszip->chunk_size);
2340 return 1;
2341 }
2342 try { out->put64bitsLE((const U8*)&(laszip->number_of_special_evlrs)); } catch(...)
2343 {
2344 sprintf(laszip_dll->error, "writing number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs);
2345 return 1;
2346 }
2347 try { out->put64bitsLE((const U8*)&(laszip->offset_to_special_evlrs)); } catch(...)
2348 {
2349 sprintf(laszip_dll->error, "writing offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs);
2350 return 1;
2351 }
2352 try { out->put16bitsLE((const U8*)&(laszip->num_items)); } catch(...)
2353 {
2354 sprintf(laszip_dll->error, "writing num_items %d", (I32)laszip->num_items);
2355 return 1;
2356 }
2357
2358 U32 j;
2359 for (j = 0; j < laszip->num_items; j++)
2360 {
2361 U16 type = (U16)(laszip->items[j].type);
2362 try { out->put16bitsLE((const U8*)&type); } catch(...)
2363 {
2364 sprintf(laszip_dll->error, "writing type %d of item %d", (I32)laszip->items[j].type, j);
2365 return 1;
2366 }
2367 try { out->put16bitsLE((const U8*)&(laszip->items[j].size)); } catch(...)
2368 {
2369 sprintf(laszip_dll->error, "writing size %d of item %d", (I32)laszip->items[j].size, j);
2370 return 1;
2371 }
2372 try { out->put16bitsLE((const U8*)&(laszip->items[j].version)); } catch(...)
2373 {
2374 sprintf(laszip_dll->error, "writing version %d of item %d", (I32)laszip->items[j].version, j);
2375 return 1;
2376 }
2377 }
2378 return 0;
2379 }
2380
2381 /*---------------------------------------------------------------------------*/
2382 static I32
laszip_write_header(laszip_dll_struct * laszip_dll,const LASzip * laszip,const laszip_BOOL compress)2383 laszip_write_header(
2384 laszip_dll_struct* laszip_dll
2385 , const LASzip* laszip
2386 , const laszip_BOOL compress
2387 )
2388 {
2389 U32 i;
2390
2391 try { laszip_dll->streamout->putBytes((const U8*)"LASF", 4); } catch(...)
2392 {
2393 sprintf(laszip_dll->error, "writing header.file_signature");
2394 return 1;
2395 }
2396 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_source_ID)); } catch(...)
2397 {
2398 sprintf(laszip_dll->error, "writing header.file_source_ID");
2399 return 1;
2400 }
2401 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.global_encoding)); } catch(...)
2402 {
2403 sprintf(laszip_dll->error, "writing header.global_encoding");
2404 return 1;
2405 }
2406 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...)
2407 {
2408 sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_1");
2409 return 1;
2410 }
2411 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...)
2412 {
2413 sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_2");
2414 return 1;
2415 }
2416 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...)
2417 {
2418 sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_3");
2419 return 1;
2420 }
2421 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...)
2422 {
2423 sprintf(laszip_dll->error, "writing header.project_ID_GUID_data_4");
2424 return 1;
2425 }
2426 try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_major), 1); } catch(...)
2427 {
2428 sprintf(laszip_dll->error, "writing header.version_major");
2429 return 1;
2430 }
2431 try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.version_minor), 1); } catch(...)
2432 {
2433 sprintf(laszip_dll->error, "writing header.version_minor");
2434 return 1;
2435 }
2436 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.system_identifier, 32); } catch(...)
2437 {
2438 sprintf(laszip_dll->error, "writing header.system_identifier");
2439 return 1;
2440 }
2441 if (!laszip_dll->preserve_generating_software)
2442 {
2443 memset(laszip_dll->header.generating_software, 0, 32);
2444 sprintf(laszip_dll->header.generating_software, "LASzip DLL %d.%d r%d (%d)", LASZIP_VERSION_MAJOR, LASZIP_VERSION_MINOR, LASZIP_VERSION_REVISION, LASZIP_VERSION_BUILD_DATE);
2445 }
2446 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.generating_software, 32); } catch(...)
2447 {
2448 sprintf(laszip_dll->error, "writing header.generating_software");
2449 return 1;
2450 }
2451 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_day)); } catch(...)
2452 {
2453 sprintf(laszip_dll->error, "writing header.file_creation_day");
2454 return 1;
2455 }
2456 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.file_creation_year)); } catch(...)
2457 {
2458 sprintf(laszip_dll->error, "writing header.file_creation_year");
2459 return 1;
2460 }
2461 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.header_size)); } catch(...)
2462 {
2463 sprintf(laszip_dll->error, "writing header.header_size");
2464 return 1;
2465 }
2466 if (compress)
2467 {
2468 laszip_dll->header.offset_to_point_data += (54 + laszip_vrl_payload_size(laszip));
2469 }
2470 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...)
2471 {
2472 sprintf(laszip_dll->error, "writing header.offset_to_point_data");
2473 return 1;
2474 }
2475 if (compress)
2476 {
2477 laszip_dll->header.offset_to_point_data -= (54 + laszip_vrl_payload_size(laszip));
2478 laszip_dll->header.number_of_variable_length_records += 1;
2479 }
2480 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...)
2481 {
2482 sprintf(laszip_dll->error, "writing header.number_of_variable_length_records");
2483 return 1;
2484 }
2485 if (compress)
2486 {
2487 laszip_dll->header.number_of_variable_length_records -= 1;
2488 laszip_dll->header.point_data_format |= 128;
2489 }
2490 try { laszip_dll->streamout->putBytes((const U8*)&(laszip_dll->header.point_data_format), 1); } catch(...)
2491 {
2492 sprintf(laszip_dll->error, "writing header.point_data_format");
2493 return 1;
2494 }
2495 if (compress)
2496 {
2497 laszip_dll->header.point_data_format &= 127;
2498 }
2499 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.point_data_record_length)); } catch(...)
2500 {
2501 sprintf(laszip_dll->error, "writing header.point_data_record_length");
2502 return 1;
2503 }
2504 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_point_records)); } catch(...)
2505 {
2506 sprintf(laszip_dll->error, "writing header.number_of_point_records");
2507 return 1;
2508 }
2509 for (i = 0; i < 5; i++)
2510 {
2511 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...)
2512 {
2513 sprintf(laszip_dll->error, "writing header.number_of_points_by_return %d", i);
2514 return 1;
2515 }
2516 }
2517 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_scale_factor)); } catch(...)
2518 {
2519 sprintf(laszip_dll->error, "writing header.x_scale_factor");
2520 return 1;
2521 }
2522 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_scale_factor)); } catch(...)
2523 {
2524 sprintf(laszip_dll->error, "writing header.y_scale_factor");
2525 return 1;
2526 }
2527 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_scale_factor)); } catch(...)
2528 {
2529 sprintf(laszip_dll->error, "writing header.z_scale_factor");
2530 return 1;
2531 }
2532 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.x_offset)); } catch(...)
2533 {
2534 sprintf(laszip_dll->error, "writing header.x_offset");
2535 return 1;
2536 }
2537 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.y_offset)); } catch(...)
2538 {
2539 sprintf(laszip_dll->error, "writing header.y_offset");
2540 return 1;
2541 }
2542 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.z_offset)); } catch(...)
2543 {
2544 sprintf(laszip_dll->error, "writing header.z_offset");
2545 return 1;
2546 }
2547 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_x)); } catch(...)
2548 {
2549 sprintf(laszip_dll->error, "writing header.max_x");
2550 return 1;
2551 }
2552 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_x)); } catch(...)
2553 {
2554 sprintf(laszip_dll->error, "writing header.min_x");
2555 return 1;
2556 }
2557 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_y)); } catch(...)
2558 {
2559 sprintf(laszip_dll->error, "writing header.max_y");
2560 return 1;
2561 }
2562 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_y)); } catch(...)
2563 {
2564 sprintf(laszip_dll->error, "writing header.min_y");
2565 return 1;
2566 }
2567 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.max_z)); } catch(...)
2568 {
2569 sprintf(laszip_dll->error, "writing header.max_z");
2570 return 1;
2571 }
2572 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.min_z)); } catch(...)
2573 {
2574 sprintf(laszip_dll->error, "writing header.min_z");
2575 return 1;
2576 }
2577
2578 // special handling for LAS 1.3
2579 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3))
2580 {
2581 if (laszip_dll->header.header_size < 235)
2582 {
2583 sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
2584 return 1;
2585 }
2586 else
2587 {
2588 if (laszip_dll->header.start_of_waveform_data_packet_record != 0)
2589 {
2590 #ifdef _WIN32
2591 sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %I64d. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record);
2592 #else
2593 sprintf(laszip_dll->warning, "header.start_of_waveform_data_packet_record is %llu. writing 0 instead.", laszip_dll->header.start_of_waveform_data_packet_record);
2594 #endif
2595 laszip_dll->header.start_of_waveform_data_packet_record = 0;
2596 }
2597 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...)
2598 {
2599 sprintf(laszip_dll->error, "writing header.start_of_waveform_data_packet_record");
2600 return 1;
2601 }
2602 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235;
2603 }
2604 }
2605 else
2606 {
2607 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227;
2608 }
2609
2610 // special handling for LAS 1.4
2611 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4))
2612 {
2613 if (laszip_dll->header.header_size < 375)
2614 {
2615 sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
2616 return 1;
2617 }
2618 else
2619 {
2620 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...)
2621 {
2622 sprintf(laszip_dll->error, "writing header.start_of_first_extended_variable_length_record");
2623 return 1;
2624 }
2625 try { laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...)
2626 {
2627 sprintf(laszip_dll->error, "writing header.number_of_extended_variable_length_records");
2628 return 1;
2629 }
2630 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...)
2631 {
2632 sprintf(laszip_dll->error, "writing header.extended_number_of_point_records");
2633 return 1;
2634 }
2635 for (i = 0; i < 15; i++)
2636 {
2637 try { laszip_dll->streamout->put64bitsLE((const U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...)
2638 {
2639 sprintf(laszip_dll->error, "writing header.extended_number_of_points_by_return[%d]", i);
2640 return 1;
2641 }
2642 }
2643 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375;
2644 }
2645 }
2646
2647 // write any number of user-defined bytes that might have been added to the header
2648 if (laszip_dll->header.user_data_in_header_size)
2649 {
2650 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...)
2651 {
2652 sprintf(laszip_dll->error, "writing %d bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size);
2653 return 1;
2654 }
2655 }
2656
2657 // write variable length records into the header
2658
2659 if (laszip_dll->header.number_of_variable_length_records)
2660 {
2661 U32 i;
2662
2663 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
2664 {
2665 // write variable length records variable after variable (to avoid alignment issues)
2666
2667 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...)
2668 {
2669 sprintf(laszip_dll->error, "writing header.vlrs[%d].reserved", i);
2670 return 1;
2671 }
2672
2673 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...)
2674 {
2675 sprintf(laszip_dll->error, "writing header.vlrs[%d].user_id", i);
2676 return 1;
2677 }
2678 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...)
2679 {
2680 sprintf(laszip_dll->error, "writing header.vlrs[%d].record_id", i);
2681 return 1;
2682 }
2683 try { laszip_dll->streamout->put16bitsLE((const U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...)
2684 {
2685 sprintf(laszip_dll->error, "writing header.vlrs[%d].record_length_after_header", i);
2686 return 1;
2687 }
2688 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...)
2689 {
2690 sprintf(laszip_dll->error, "writing header.vlrs[%d].description", i);
2691 return 1;
2692 }
2693
2694 // write data following the header of the variable length record
2695
2696 if (laszip_dll->header.vlrs[i].record_length_after_header)
2697 {
2698 try { laszip_dll->streamout->putBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...)
2699 {
2700 sprintf(laszip_dll->error, "writing %d bytes of data into header.vlrs[%d].data", laszip_dll->header.vlrs[i].record_length_after_header, i);
2701 return 1;
2702 }
2703 }
2704 }
2705 }
2706
2707 if (compress)
2708 {
2709 // write the LASzip VLR header
2710
2711 if (write_laszip_vlr_header(laszip_dll, laszip, laszip_dll->streamout))
2712 {
2713 return 1;
2714 }
2715
2716 // write the LASzip VLR payload
2717
2718 if (write_laszip_vlr_payload(laszip_dll, laszip, laszip_dll->streamout))
2719 {
2720 return 1;
2721 }
2722 }
2723
2724 // write any number of user-defined bytes that might have been added after the header
2725
2726 if (laszip_dll->header.user_data_after_header_size)
2727 {
2728 try { laszip_dll->streamout->putBytes((const U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...)
2729 {
2730 sprintf(laszip_dll->error, "writing %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size);
2731 return 1;
2732 }
2733 }
2734
2735 return 0;
2736 }
2737
2738 /*----------------------------------------------------------------------------*/
create_point_writer(laszip_dll_struct * laszip_dll,const LASzip * laszip)2739 laszip_I32 create_point_writer
2740 (
2741 laszip_dll_struct *laszip_dll
2742 , const LASzip *laszip
2743 )
2744 {
2745 // create the point writer
2746 laszip_dll->writer = new LASwritePoint();
2747 if (laszip_dll->writer == 0)
2748 {
2749 sprintf(laszip_dll->error, "could not alloc LASwritePoint");
2750 return 1;
2751 }
2752
2753 if (!laszip_dll->writer->setup(laszip->num_items, laszip->items, laszip))
2754 {
2755 sprintf(laszip_dll->error, "setup of LASwritePoint failed");
2756 return 1;
2757 }
2758
2759 if (!laszip_dll->writer->init(laszip_dll->streamout))
2760 {
2761 sprintf(laszip_dll->error, "init of LASwritePoint failed");
2762 return 1;
2763 }
2764
2765 return 0;
2766 }
2767
2768 /*---------------------------------------------------------------------------*/
2769 static I32
setup_laszip_items(laszip_dll_struct * laszip_dll,LASzip * laszip,laszip_BOOL compress)2770 setup_laszip_items(
2771 laszip_dll_struct* laszip_dll
2772 , LASzip* laszip
2773 , laszip_BOOL compress
2774 )
2775 {
2776 laszip_U8 point_type = laszip_dll->header.point_data_format;
2777 laszip_U16 point_size = laszip_dll->header.point_data_record_length;
2778
2779 if ((point_type > 5) && laszip_dll->request_compatibility_mode)
2780 {
2781 if (!laszip->request_compatibility_mode(1))
2782 {
2783 sprintf(laszip_dll->error, "requesting 'compatibility mode' has failed");
2784 return 1;
2785 }
2786 }
2787
2788 // create point items in the LASzip structure from point format and size
2789
2790 if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_NONE))
2791 {
2792 sprintf(laszip_dll->error, "invalid combination of point_type %d and point_size %d", (I32)point_type, (I32)point_size);
2793 return 1;
2794 }
2795
2796 // compute offsets (or points item pointers) for data transfer from the point items
2797
2798 if (laszip_dll->point_items)
2799 {
2800 delete [] laszip_dll->point_items;
2801 }
2802
2803 laszip_dll->point_items = new U8*[laszip->num_items];
2804
2805 if (laszip_dll->point_items == 0)
2806 {
2807 sprintf(laszip_dll->error, "could not alloc point_items");
2808 return 1;
2809 }
2810
2811 for (size_t i = 0; i < laszip->num_items; i++)
2812 {
2813 switch (laszip->items[i].type)
2814 {
2815 case LASitem::POINT10:
2816 case LASitem::POINT14:
2817 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X);
2818 break;
2819 case LASitem::GPSTIME11:
2820 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time);
2821 break;
2822 case LASitem::RGB12:
2823 case LASitem::RGB14:
2824 case LASitem::RGBNIR14:
2825 laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb;
2826 break;
2827 case LASitem::BYTE:
2828 case LASitem::BYTE14:
2829 laszip_dll->point.num_extra_bytes = laszip->items[i].size;
2830 if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes;
2831 laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes];
2832 laszip_dll->point_items[i] = laszip_dll->point.extra_bytes;
2833 break;
2834 case LASitem::WAVEPACKET13:
2835 case LASitem::WAVEPACKET14:
2836 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet);
2837 break;
2838 default:
2839 sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type);
2840 return 1;
2841 }
2842 }
2843
2844 if (compress)
2845 {
2846 if ((point_type > 5) && laszip_dll->request_native_extension)
2847 {
2848 if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_LAYERED_CHUNKED))
2849 {
2850 sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d using native", (I32)point_type, (I32)point_size);
2851 return 1;
2852 }
2853 }
2854 else
2855 {
2856 if (!laszip->setup(point_type, point_size, LASZIP_COMPRESSOR_DEFAULT))
2857 {
2858 sprintf(laszip_dll->error, "cannot compress point_type %d with point_size %d", (I32)point_type, (I32)point_size);
2859 return 1;
2860 }
2861 }
2862
2863 // request version (old point types only, new point types always use version 3)
2864
2865 laszip->request_version(2);
2866
2867 // maybe we should change the chunk size
2868
2869 if (laszip_dll->set_chunk_size != LASZIP_CHUNK_SIZE_DEFAULT)
2870 {
2871 if (!laszip->set_chunk_size(laszip_dll->set_chunk_size))
2872 {
2873 sprintf(laszip_dll->error, "setting chunk size %d has failed", laszip_dll->set_chunk_size);
2874 return 1;
2875 }
2876 }
2877 }
2878 else
2879 {
2880 laszip->request_version(0);
2881 }
2882 return 0;
2883 }
2884
2885 /*---------------------------------------------------------------------------*/
2886 LASZIP_API laszip_I32
laszip_open_writer(laszip_POINTER pointer,const laszip_CHAR * file_name,laszip_BOOL compress)2887 laszip_open_writer(
2888 laszip_POINTER pointer
2889 , const laszip_CHAR* file_name
2890 , laszip_BOOL compress
2891 )
2892 {
2893 if (pointer == 0) return 1;
2894 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
2895
2896 try
2897 {
2898 if (file_name == 0)
2899 {
2900 sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero");
2901 return 1;
2902 }
2903
2904 if (laszip_dll->reader)
2905 {
2906 sprintf(laszip_dll->error, "reader is already open");
2907 return 1;
2908 }
2909
2910 if (laszip_dll->writer)
2911 {
2912 sprintf(laszip_dll->error, "writer is already open");
2913 return 1;
2914 }
2915
2916 // open the file
2917
2918 #ifdef _MSC_VER
2919 wchar_t* utf16_file_name = UTF8toUTF16(file_name);
2920 laszip_dll->file = _wfopen(utf16_file_name, L"wb");
2921 delete [] utf16_file_name;
2922 #else
2923 laszip_dll->file = fopen(file_name, "wb");
2924 #endif
2925
2926 if (laszip_dll->file == 0)
2927 {
2928 sprintf(laszip_dll->error, "cannot open file '%s'", file_name);
2929 return 1;
2930 }
2931
2932 if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0)
2933 {
2934 sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n");
2935 }
2936
2937 // create the outstream
2938
2939 if (IS_LITTLE_ENDIAN())
2940 laszip_dll->streamout = new ByteStreamOutFileLE(laszip_dll->file);
2941 else
2942 laszip_dll->streamout = new ByteStreamOutFileBE(laszip_dll->file);
2943
2944 if (laszip_dll->streamout == 0)
2945 {
2946 sprintf(laszip_dll->error, "could not alloc ByteStreamOutFile");
2947 return 1;
2948 }
2949
2950 // setup the items that make up the point
2951
2952 LASzip laszip;
2953 if (setup_laszip_items(laszip_dll, &laszip, compress))
2954 {
2955 return 1;
2956 }
2957
2958 // prepare header
2959
2960 if (laszip_prepare_header_for_write(laszip_dll))
2961 {
2962 return 1;
2963 }
2964
2965 // prepare point
2966
2967 if (laszip_prepare_point_for_write(laszip_dll, compress))
2968 {
2969 return 1;
2970 }
2971
2972 // prepare VLRs
2973
2974 if (laszip_prepare_vlrs_for_write(laszip_dll))
2975 {
2976 return 1;
2977 }
2978
2979 // write header variable after variable
2980
2981 if (laszip_write_header(laszip_dll, &laszip, compress))
2982 {
2983 return 1;
2984 }
2985
2986 // create the point writer
2987
2988 if (create_point_writer(laszip_dll, &laszip))
2989 {
2990 return 1;
2991 }
2992
2993 if (laszip_dll->lax_create)
2994 {
2995 // create spatial indexing information using cell_size = 100.0f and threshold = 1000
2996
2997 LASquadtree* lasquadtree = new LASquadtree;
2998 lasquadtree->setup(laszip_dll->header.min_x, laszip_dll->header.max_x, laszip_dll->header.min_y, laszip_dll->header.max_y, 100.0f);
2999
3000 laszip_dll->lax_index = new LASindex;
3001 laszip_dll->lax_index->prepare(lasquadtree, 1000);
3002
3003 // copy the file name for later
3004
3005 laszip_dll->lax_file_name = LASCopyString(file_name);
3006 }
3007
3008 // set the point number and point count
3009
3010 laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
3011 laszip_dll->p_count = 0;
3012 }
3013 catch (...)
3014 {
3015 sprintf(laszip_dll->error, "internal error in laszip_open_writer '%s'", file_name);
3016 return 1;
3017 }
3018
3019 laszip_dll->error[0] = '\0';
3020 return 0;
3021 }
3022
3023 /*---------------------------------------------------------------------------*/
3024 LASZIP_API laszip_I32
laszip_write_point(laszip_POINTER pointer)3025 laszip_write_point(
3026 laszip_POINTER pointer
3027 )
3028 {
3029 if (pointer == 0) return 1;
3030 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3031
3032 try
3033 {
3034 // temporary fix to avoid corrupt LAZ files
3035
3036 if (laszip_dll->point.extended_point_type)
3037 {
3038 // make sure legacy flags and extended flags are identical
3039 if ((laszip_dll->point.extended_classification_flags & 0x7) != ((((U8*)&(laszip_dll->point.intensity))[3]) >> 5))
3040 {
3041 sprintf(laszip_dll->error, "legacy flags and extended flags are not identical");
3042 return 1;
3043 }
3044
3045 // make sure legacy classification is zero or identical to extended classification
3046 if (laszip_dll->point.classification != 0)
3047 {
3048 if (laszip_dll->point.classification != laszip_dll->point.extended_classification)
3049 {
3050 sprintf(laszip_dll->error, "legacy classification %d and extended classification %d are not consistent", laszip_dll->point.classification, laszip_dll->point.extended_classification);
3051 return 1;
3052 }
3053 }
3054 }
3055
3056 // special recoding of points (in compatibility mode only)
3057
3058 if (laszip_dll->compatibility_mode)
3059 {
3060 I32 scan_angle_remainder;
3061 I32 number_of_returns_increment;
3062 I32 return_number_increment;
3063 I32 return_count_difference;
3064 I32 overlap_bit;
3065 I32 scanner_channel;
3066
3067 // distill extended attributes
3068 struct laszip_point* point = &laszip_dll->point;
3069
3070 point->scan_angle_rank = I8_CLAMP(I16_QUANTIZE(0.006f*point->extended_scan_angle));
3071 scan_angle_remainder = point->extended_scan_angle - I16_QUANTIZE(((F32)point->scan_angle_rank)/0.006f);
3072 if (point->extended_number_of_returns <= 7)
3073 {
3074 point->number_of_returns = point->extended_number_of_returns;
3075 if (point->extended_return_number <= 7)
3076 {
3077 point->return_number = point->extended_return_number;
3078 }
3079 else
3080 {
3081 point->return_number = 7;
3082 }
3083 }
3084 else
3085 {
3086 point->number_of_returns = 7;
3087 if (point->extended_return_number <= 4)
3088 {
3089 point->return_number = point->extended_return_number;
3090 }
3091 else
3092 {
3093 return_count_difference = point->extended_number_of_returns - point->extended_return_number;
3094 if (return_count_difference <= 0)
3095 {
3096 point->return_number = 7;
3097 }
3098 else if (return_count_difference >= 3)
3099 {
3100 point->return_number = 4;
3101 }
3102 else
3103 {
3104 point->return_number = 7 - return_count_difference;
3105 }
3106 }
3107 }
3108 return_number_increment = point->extended_return_number - point->return_number;
3109 number_of_returns_increment = point->extended_number_of_returns - point->number_of_returns;
3110 if (point->extended_classification > 31)
3111 {
3112 point->classification = 0;
3113 }
3114 else
3115 {
3116 point->extended_classification = 0;
3117 }
3118 scanner_channel = point->extended_scanner_channel;
3119 overlap_bit = (point->extended_classification_flags >> 3);
3120
3121 // write distilled extended attributes into extra bytes
3122
3123 *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle)) = ((I16)scan_angle_remainder);
3124 point->extra_bytes[laszip_dll->start_extended_returns] = (U8)((return_number_increment << 4) | number_of_returns_increment);
3125 point->extra_bytes[laszip_dll->start_classification] = (U8)(point->extended_classification);
3126 point->extra_bytes[laszip_dll->start_flags_and_channel] = (U8)((scanner_channel << 1) | overlap_bit);
3127 if (laszip_dll->start_NIR_band != -1)
3128 {
3129 *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band)) = point->rgb[3];
3130 }
3131 }
3132
3133 // write the point
3134 if (!laszip_dll->writer->write(laszip_dll->point_items))
3135 {
3136 #ifdef _WIN32
3137 sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
3138 #else
3139 sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
3140 #endif
3141 return 1;
3142 }
3143
3144 laszip_dll->p_count++;
3145 }
3146 catch (...)
3147 {
3148 sprintf(laszip_dll->error, "internal error in laszip_write_point");
3149 return 1;
3150 }
3151
3152 laszip_dll->error[0] = '\0';
3153 return 0;
3154 }
3155
3156 /*---------------------------------------------------------------------------*/
3157 LASZIP_API laszip_I32
laszip_write_indexed_point(laszip_POINTER pointer)3158 laszip_write_indexed_point(
3159 laszip_POINTER pointer
3160 )
3161 {
3162 if (pointer == 0) return 1;
3163 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3164
3165 try
3166 {
3167 // write the point
3168 if (!laszip_dll->writer->write(laszip_dll->point_items))
3169 {
3170 #ifdef _WIN32
3171 sprintf(laszip_dll->error, "writing point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
3172 #else
3173 sprintf(laszip_dll->error, "writing point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
3174 #endif
3175 return 1;
3176 }
3177 // index the point
3178 F64 x = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
3179 F64 y = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
3180 laszip_dll->lax_index->add(x, y, (U32)laszip_dll->p_count);
3181 laszip_dll->p_count++;
3182 }
3183 catch (...)
3184 {
3185 sprintf(laszip_dll->error, "internal error in laszip_write_indexed_point");
3186 return 1;
3187 }
3188
3189 laszip_dll->error[0] = '\0';
3190 return 0;
3191 }
3192
3193 /*---------------------------------------------------------------------------*/
3194 LASZIP_API laszip_I32
laszip_update_inventory(laszip_POINTER pointer)3195 laszip_update_inventory(
3196 laszip_POINTER pointer
3197 )
3198 {
3199 if (pointer == 0) return 1;
3200 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3201
3202 try
3203 {
3204 if (laszip_dll->inventory == 0)
3205 {
3206 laszip_dll->inventory = new laszip_dll_inventory;
3207 }
3208
3209 laszip_dll->inventory->add(&laszip_dll->point);
3210 }
3211 catch (...)
3212 {
3213 sprintf(laszip_dll->error, "internal error in laszip_update_inventory");
3214 return 1;
3215 }
3216
3217 laszip_dll->error[0] = '\0';
3218 return 0;
3219 }
3220
3221 /*---------------------------------------------------------------------------*/
3222 LASZIP_API laszip_I32
laszip_close_writer(laszip_POINTER pointer)3223 laszip_close_writer(
3224 laszip_POINTER pointer
3225 )
3226 {
3227 if (pointer == 0) return 1;
3228 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3229
3230 try
3231 {
3232 if (laszip_dll->writer == 0)
3233 {
3234 sprintf(laszip_dll->error, "closing writer before it was opened");
3235 return 1;
3236 }
3237
3238 if (!laszip_dll->writer->done())
3239 {
3240 sprintf(laszip_dll->error, "done of LASwritePoint failed");
3241 return 1;
3242 }
3243
3244 delete laszip_dll->writer;
3245 laszip_dll->writer = 0;
3246
3247 delete [] laszip_dll->point_items;
3248 laszip_dll->point_items = 0;
3249
3250 // maybe update the header
3251
3252 if (laszip_dll->inventory)
3253 {
3254 if (laszip_dll->header.point_data_format <= 5) // only update legacy counters for old point types
3255 {
3256 laszip_dll->streamout->seek(107);
3257 if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_point_records)))
3258 {
3259 sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_point_records");
3260 return 1;
3261 }
3262 for (I32 i = 0; i < 5; i++)
3263 {
3264 if (!laszip_dll->streamout->put32bitsLE((const U8*)&(laszip_dll->inventory->number_of_points_by_return[i+1])))
3265 {
3266 sprintf(laszip_dll->error, "updating laszip_dll->inventory->number_of_points_by_return[%d]\n", i);
3267 return 1;
3268 }
3269 }
3270 }
3271 laszip_dll->streamout->seek(179);
3272 F64 value;
3273 value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->max_X+laszip_dll->header.x_offset;
3274 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3275 {
3276 sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_X");
3277 return 1;
3278 }
3279 value = laszip_dll->header.x_scale_factor*laszip_dll->inventory->min_X+laszip_dll->header.x_offset;
3280 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3281 {
3282 sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_X");
3283 return 1;
3284 }
3285 value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->max_Y+laszip_dll->header.y_offset;
3286 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3287 {
3288 sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Y");
3289 return 1;
3290 }
3291 value = laszip_dll->header.y_scale_factor*laszip_dll->inventory->min_Y+laszip_dll->header.y_offset;
3292 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3293 {
3294 sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Y");
3295 return 1;
3296 }
3297 value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->max_Z+laszip_dll->header.z_offset;
3298 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3299 {
3300 sprintf(laszip_dll->error, "updating laszip_dll->inventory->max_Z");
3301 return 1;
3302 }
3303 value = laszip_dll->header.z_scale_factor*laszip_dll->inventory->min_Z+laszip_dll->header.z_offset;
3304 if (!laszip_dll->streamout->put64bitsLE((const U8*)&value))
3305 {
3306 sprintf(laszip_dll->error, "updating laszip_dll->inventory->min_Z");
3307 return 1;
3308 }
3309 if (laszip_dll->header.version_minor >= 4) // only update extended counters for LAS 1.4
3310 {
3311 laszip_dll->streamout->seek(247);
3312 I64 number = laszip_dll->inventory->number_of_point_records;
3313 if (!laszip_dll->streamout->put64bitsLE((const U8*)&number))
3314 {
3315 sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_point_records");
3316 return 1;
3317 }
3318 for (I32 i = 0; i < 15; i++)
3319 {
3320 number = laszip_dll->inventory->number_of_points_by_return[i+1];
3321 if (!laszip_dll->streamout->put64bitsLE((const U8*)&number))
3322 {
3323 sprintf(laszip_dll->error, "updating laszip_dll->inventory->extended_number_of_points_by_return[%d]\n", i);
3324 return 1;
3325 }
3326 }
3327 }
3328 laszip_dll->streamout->seekEnd();
3329
3330 delete laszip_dll->inventory;
3331 laszip_dll->inventory = 0;
3332 }
3333
3334 if (laszip_dll->lax_index)
3335 {
3336 laszip_dll->lax_index->complete(100000, -20, FALSE);
3337
3338 if (!laszip_dll->lax_index->write(laszip_dll->lax_file_name))
3339 {
3340 sprintf(laszip_dll->error, "writing LAX file to '%s'", laszip_dll->lax_file_name);
3341 return 1;
3342 }
3343
3344 free(laszip_dll->lax_file_name);
3345 laszip_dll->lax_file_name = 0;
3346
3347 delete laszip_dll->lax_index;
3348 laszip_dll->lax_index = 0;
3349 }
3350
3351 delete laszip_dll->streamout;
3352 laszip_dll->streamout = 0;
3353
3354 if (laszip_dll->file)
3355 {
3356 fclose(laszip_dll->file);
3357 laszip_dll->file = 0;
3358 }
3359 }
3360 catch (...)
3361 {
3362 sprintf(laszip_dll->error, "internal error in laszip_writer_close");
3363 return 1;
3364 }
3365
3366 laszip_dll->error[0] = '\0';
3367 return 0;
3368 }
3369
3370 /*---------------------------------------------------------------------------*/
3371 LASZIP_API laszip_I32
laszip_exploit_spatial_index(laszip_POINTER pointer,const laszip_BOOL exploit)3372 laszip_exploit_spatial_index(
3373 laszip_POINTER pointer
3374 , const laszip_BOOL exploit
3375 )
3376 {
3377 if (pointer == 0) return 1;
3378 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3379
3380 try
3381 {
3382 if (laszip_dll->reader)
3383 {
3384 sprintf(laszip_dll->error, "reader is already open");
3385 return 1;
3386 }
3387
3388 if (laszip_dll->writer)
3389 {
3390 sprintf(laszip_dll->error, "writer is already open");
3391 return 1;
3392 }
3393
3394 laszip_dll->lax_exploit = exploit;
3395 }
3396 catch (...)
3397 {
3398 sprintf(laszip_dll->error, "internal error in laszip_exploit_spatial_index");
3399 return 1;
3400 }
3401
3402 laszip_dll->error[0] = '\0';
3403 return 0;
3404 }
3405
3406 /*---------------------------------------------------------------------------*/
3407 LASZIP_API laszip_I32
laszip_decompress_selective(laszip_POINTER pointer,const laszip_U32 decompress_selective)3408 laszip_decompress_selective(
3409 laszip_POINTER pointer
3410 , const laszip_U32 decompress_selective
3411 )
3412 {
3413 if (pointer == 0) return 1;
3414 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
3415
3416 try
3417 {
3418 if (laszip_dll->reader)
3419 {
3420 sprintf(laszip_dll->error, "reader is already open");
3421 return 1;
3422 }
3423
3424 if (laszip_dll->writer)
3425 {
3426 sprintf(laszip_dll->error, "writer is already open");
3427 return 1;
3428 }
3429
3430 laszip_dll->las14_decompress_selective = decompress_selective;
3431 }
3432 catch (...)
3433 {
3434 sprintf(laszip_dll->error, "internal error in laszip_decompress_selective");
3435 return 1;
3436 }
3437
3438 laszip_dll->error[0] = '\0';
3439 return 0;
3440 }
3441
3442 /*---------------------------------------------------------------------------*/
3443 static I32
laszip_read_header(laszip_dll_struct * laszip_dll,laszip_BOOL * is_compressed)3444 laszip_read_header(
3445 laszip_dll_struct* laszip_dll
3446 , laszip_BOOL* is_compressed
3447 )
3448 {
3449 U32 i;
3450
3451 // read the header variable after variable
3452
3453 CHAR file_signature[5];
3454 try { laszip_dll->streamin->getBytes((U8*)file_signature, 4); } catch(...)
3455 {
3456 sprintf(laszip_dll->error, "reading header.file_signature");
3457 return 1;
3458 }
3459 if (strncmp(file_signature, "LASF", 4) != 0)
3460 {
3461 sprintf(laszip_dll->error, "wrong file_signature. not a LAS/LAZ file.");
3462 return 1;
3463 }
3464 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_source_ID)); } catch(...)
3465 {
3466 sprintf(laszip_dll->error, "reading header.file_source_ID");
3467 return 1;
3468 }
3469 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.global_encoding)); } catch(...)
3470 {
3471 sprintf(laszip_dll->error, "reading header.global_encoding");
3472 return 1;
3473 }
3474 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_1)); } catch(...)
3475 {
3476 sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_1");
3477 return 1;
3478 }
3479 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_2)); } catch(...)
3480 {
3481 sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_2");
3482 return 1;
3483 }
3484 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.project_ID_GUID_data_3)); } catch(...)
3485 {
3486 sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_3");
3487 return 1;
3488 }
3489 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.project_ID_GUID_data_4, 8); } catch(...)
3490 {
3491 sprintf(laszip_dll->error, "reading header.project_ID_GUID_data_4");
3492 return 1;
3493 }
3494 try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_major), 1); } catch(...)
3495 {
3496 sprintf(laszip_dll->error, "reading header.version_major");
3497 return 1;
3498 }
3499 try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.version_minor), 1); } catch(...)
3500 {
3501 sprintf(laszip_dll->error, "reading header.version_minor");
3502 return 1;
3503 }
3504 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.system_identifier, 32); } catch(...)
3505 {
3506 sprintf(laszip_dll->error, "reading header.system_identifier");
3507 return 1;
3508 }
3509 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.generating_software, 32); } catch(...)
3510 {
3511 sprintf(laszip_dll->error, "reading header.generating_software");
3512 return 1;
3513 }
3514 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_day)); } catch(...)
3515 {
3516 sprintf(laszip_dll->error, "reading header.file_creation_day");
3517 return 1;
3518 }
3519 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.file_creation_year)); } catch(...)
3520 {
3521 sprintf(laszip_dll->error, "reading header.file_creation_year");
3522 return 1;
3523 }
3524 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.header_size)); } catch(...)
3525 {
3526 sprintf(laszip_dll->error, "reading header.header_size");
3527 return 1;
3528 }
3529 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.offset_to_point_data)); } catch(...)
3530 {
3531 sprintf(laszip_dll->error, "reading header.offset_to_point_data");
3532 return 1;
3533 }
3534 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_variable_length_records)); } catch(...)
3535 {
3536 sprintf(laszip_dll->error, "reading header.number_of_variable_length_records");
3537 return 1;
3538 }
3539 try { laszip_dll->streamin->getBytes((U8*)&(laszip_dll->header.point_data_format), 1); } catch(...)
3540 {
3541 sprintf(laszip_dll->error, "reading header.point_data_format");
3542 return 1;
3543 }
3544 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.point_data_record_length)); } catch(...)
3545 {
3546 sprintf(laszip_dll->error, "reading header.point_data_record_length");
3547 return 1;
3548 }
3549 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_point_records)); } catch(...)
3550 {
3551 sprintf(laszip_dll->error, "reading header.number_of_point_records");
3552 return 1;
3553 }
3554 for (i = 0; i < 5; i++)
3555 {
3556 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_points_by_return[i])); } catch(...)
3557 {
3558 sprintf(laszip_dll->error, "reading header.number_of_points_by_return %d", i);
3559 return 1;
3560 }
3561 }
3562 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_scale_factor)); } catch(...)
3563 {
3564 sprintf(laszip_dll->error, "reading header.x_scale_factor");
3565 return 1;
3566 }
3567 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_scale_factor)); } catch(...)
3568 {
3569 sprintf(laszip_dll->error, "reading header.y_scale_factor");
3570 return 1;
3571 }
3572 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_scale_factor)); } catch(...)
3573 {
3574 sprintf(laszip_dll->error, "reading header.z_scale_factor");
3575 return 1;
3576 }
3577 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.x_offset)); } catch(...)
3578 {
3579 sprintf(laszip_dll->error, "reading header.x_offset");
3580 return 1;
3581 }
3582 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.y_offset)); } catch(...)
3583 {
3584 sprintf(laszip_dll->error, "reading header.y_offset");
3585 return 1;
3586 }
3587 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.z_offset)); } catch(...)
3588 {
3589 sprintf(laszip_dll->error, "reading header.z_offset");
3590 return 1;
3591 }
3592 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_x)); } catch(...)
3593 {
3594 sprintf(laszip_dll->error, "reading header.max_x");
3595 return 1;
3596 }
3597 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_x)); } catch(...)
3598 {
3599 sprintf(laszip_dll->error, "reading header.min_x");
3600 return 1;
3601 }
3602 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_y)); } catch(...)
3603 {
3604 sprintf(laszip_dll->error, "reading header.max_y");
3605 return 1;
3606 }
3607 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_y)); } catch(...)
3608 {
3609 sprintf(laszip_dll->error, "reading header.min_y");
3610 return 1;
3611 }
3612 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.max_z)); } catch(...)
3613 {
3614 sprintf(laszip_dll->error, "reading header.max_z");
3615 return 1;
3616 }
3617 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.min_z)); } catch(...)
3618 {
3619 sprintf(laszip_dll->error, "reading header.min_z");
3620 return 1;
3621 }
3622
3623 // special handling for LAS 1.3
3624 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 3))
3625 {
3626 if (laszip_dll->header.header_size < 235)
3627 {
3628 sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 235 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
3629 return 1;
3630 }
3631 else
3632 {
3633 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_waveform_data_packet_record)); } catch(...)
3634 {
3635 sprintf(laszip_dll->error, "reading header.start_of_waveform_data_packet_record");
3636 return 1;
3637 }
3638 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 235;
3639 }
3640 }
3641 else
3642 {
3643 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 227;
3644 }
3645
3646 // special handling for LAS 1.4
3647 if ((laszip_dll->header.version_major == 1) && (laszip_dll->header.version_minor >= 4))
3648 {
3649 if (laszip_dll->header.header_size < 375)
3650 {
3651 sprintf(laszip_dll->error, "for LAS 1.%d header_size should at least be 375 but it is only %d", laszip_dll->header.version_minor, laszip_dll->header.header_size);
3652 return 1;
3653 }
3654 else
3655 {
3656 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.start_of_first_extended_variable_length_record)); } catch(...)
3657 {
3658 sprintf(laszip_dll->error, "reading header.start_of_first_extended_variable_length_record");
3659 return 1;
3660 }
3661 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip_dll->header.number_of_extended_variable_length_records)); } catch(...)
3662 {
3663 sprintf(laszip_dll->error, "reading header.number_of_extended_variable_length_records");
3664 return 1;
3665 }
3666 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_point_records)); } catch(...)
3667 {
3668 sprintf(laszip_dll->error, "reading header.extended_number_of_point_records");
3669 return 1;
3670 }
3671 for (i = 0; i < 15; i++)
3672 {
3673 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip_dll->header.extended_number_of_points_by_return[i])); } catch(...)
3674 {
3675 sprintf(laszip_dll->error, "reading header.extended_number_of_points_by_return[%d]", i);
3676 return 1;
3677 }
3678 }
3679 laszip_dll->header.user_data_in_header_size = laszip_dll->header.header_size - 375;
3680 }
3681 }
3682
3683 // load any number of user-defined bytes that might have been added to the header
3684 if (laszip_dll->header.user_data_in_header_size)
3685 {
3686 if (laszip_dll->header.user_data_in_header)
3687 {
3688 delete [] laszip_dll->header.user_data_in_header;
3689 }
3690 laszip_dll->header.user_data_in_header = new U8[laszip_dll->header.user_data_in_header_size];
3691
3692 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_in_header, laszip_dll->header.user_data_in_header_size); } catch(...)
3693 {
3694 sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_in_header", laszip_dll->header.user_data_in_header_size);
3695 return 1;
3696 }
3697 }
3698
3699 // read variable length records into the header
3700
3701 U32 vlrs_size = 0;
3702 LASzip* laszip = 0;
3703
3704 if (laszip_dll->header.number_of_variable_length_records)
3705 {
3706 U32 i;
3707
3708 laszip_dll->header.vlrs = (laszip_vlr*)malloc(sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records);
3709
3710 if (laszip_dll->header.vlrs == 0)
3711 {
3712 sprintf(laszip_dll->error, "allocating %u VLRs", laszip_dll->header.number_of_variable_length_records);
3713 return 1;
3714 }
3715
3716 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
3717 {
3718 // make sure there are enough bytes left to read a variable length record before the point block starts
3719
3720 if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < 54)
3721 {
3722 sprintf(laszip_dll->warning, "only %d bytes until point block after reading %d of %d vlrs. skipping remaining vlrs ...", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, i, laszip_dll->header.number_of_variable_length_records);
3723 laszip_dll->header.number_of_variable_length_records = i;
3724 break;
3725 }
3726
3727 // read variable length records variable after variable (to avoid alignment issues)
3728
3729 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].reserved)); } catch(...)
3730 {
3731 sprintf(laszip_dll->error, "reading header.vlrs[%u].reserved", i);
3732 return 1;
3733 }
3734
3735 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].user_id, 16); } catch(...)
3736 {
3737 sprintf(laszip_dll->error, "reading header.vlrs[%u].user_id", i);
3738 return 1;
3739 }
3740 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_id)); } catch(...)
3741 {
3742 sprintf(laszip_dll->error, "reading header.vlrs[%u].record_id", i);
3743 return 1;
3744 }
3745 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip_dll->header.vlrs[i].record_length_after_header)); } catch(...)
3746 {
3747 sprintf(laszip_dll->error, "reading header.vlrs[%u].record_length_after_header", i);
3748 return 1;
3749 }
3750 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.vlrs[i].description, 32); } catch(...)
3751 {
3752 sprintf(laszip_dll->error, "reading header.vlrs[%u].description", i);
3753 return 1;
3754 }
3755
3756 // keep track on the number of bytes we have read so far
3757
3758 vlrs_size += 54;
3759
3760 // check variable length record contents
3761
3762 if ((laszip_dll->header.vlrs[i].reserved != 0xAABB) && (laszip_dll->header.vlrs[i].reserved != 0x0))
3763 {
3764 sprintf(laszip_dll->warning,"wrong header.vlrs[%d].reserved: %d != 0xAABB and %d != 0x0", i, laszip_dll->header.vlrs[i].reserved, laszip_dll->header.vlrs[i].reserved);
3765 }
3766
3767 // make sure there are enough bytes left to read the data of the variable length record before the point block starts
3768
3769 if (((int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size) < laszip_dll->header.vlrs[i].record_length_after_header)
3770 {
3771 sprintf(laszip_dll->warning, "only %d bytes until point block when trying to read %d bytes into header.vlrs[%d].data", (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size, laszip_dll->header.vlrs[i].record_length_after_header, i);
3772 laszip_dll->header.vlrs[i].record_length_after_header = (int)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size;
3773 }
3774
3775 // load data following the header of the variable length record
3776
3777 if (laszip_dll->header.vlrs[i].record_length_after_header)
3778 {
3779 if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
3780 {
3781 if (laszip)
3782 {
3783 delete laszip;
3784 }
3785
3786 laszip = new LASzip();
3787
3788 if (laszip == 0)
3789 {
3790 sprintf(laszip_dll->error, "could not alloc LASzip");
3791 return 1;
3792 }
3793
3794 // read the LASzip VLR payload
3795
3796 // U16 compressor 2 bytes
3797 // U32 coder 2 bytes
3798 // U8 version_major 1 byte
3799 // U8 version_minor 1 byte
3800 // U16 version_revision 2 bytes
3801 // U32 options 4 bytes
3802 // I32 chunk_size 4 bytes
3803 // I64 number_of_special_evlrs 8 bytes
3804 // I64 offset_to_special_evlrs 8 bytes
3805 // U16 num_items 2 bytes
3806 // U16 type 2 bytes * num_items
3807 // U16 size 2 bytes * num_items
3808 // U16 version 2 bytes * num_items
3809 // which totals 34+6*num_items
3810
3811 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->compressor)); } catch(...)
3812 {
3813 sprintf(laszip_dll->error, "reading compressor %d", (I32)laszip->compressor);
3814 return 1;
3815 }
3816 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->coder)); } catch(...)
3817 {
3818 sprintf(laszip_dll->error, "reading coder %d", (I32)laszip->coder);
3819 return 1;
3820 }
3821 try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_major), 1); } catch(...)
3822 {
3823 sprintf(laszip_dll->error, "reading version_major %d", (I32)laszip->version_major);
3824 return 1;
3825 }
3826 try { laszip_dll->streamin->getBytes((U8*)&(laszip->version_minor), 1); } catch(...)
3827 {
3828 sprintf(laszip_dll->error, "reading version_minor %d", (I32)laszip->version_minor);
3829 return 1;
3830 }
3831 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->version_revision)); } catch(...)
3832 {
3833 sprintf(laszip_dll->error, "reading version_revision %d", (I32)laszip->version_revision);
3834 return 1;
3835 }
3836 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->options)); } catch(...)
3837 {
3838 sprintf(laszip_dll->error, "reading options %u", laszip->options);
3839 return 1;
3840 }
3841 try { laszip_dll->streamin->get32bitsLE((U8*)&(laszip->chunk_size)); } catch(...)
3842 {
3843 sprintf(laszip_dll->error, "reading chunk_size %u", laszip->chunk_size);
3844 return 1;
3845 }
3846 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->number_of_special_evlrs)); } catch(...)
3847 {
3848 sprintf(laszip_dll->error, "reading number_of_special_evlrs %d", (I32)laszip->number_of_special_evlrs);
3849 return 1;
3850 }
3851 try { laszip_dll->streamin->get64bitsLE((U8*)&(laszip->offset_to_special_evlrs)); } catch(...)
3852 {
3853 sprintf(laszip_dll->error, "reading offset_to_special_evlrs %d", (I32)laszip->offset_to_special_evlrs);
3854 return 1;
3855 }
3856 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->num_items)); } catch(...)
3857 {
3858 sprintf(laszip_dll->error, "reading num_items %d", (I32)laszip->num_items);
3859 return 1;
3860 }
3861 laszip->items = new LASitem[laszip->num_items];
3862 U32 j;
3863 for (j = 0; j < laszip->num_items; j++)
3864 {
3865 U16 type;
3866 try { laszip_dll->streamin->get16bitsLE((U8*)&type); } catch(...)
3867 {
3868 sprintf(laszip_dll->error, "reading type of item %u", j);
3869 return 1;
3870 }
3871 laszip->items[j].type = (LASitem::Type)type;
3872 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].size)); } catch(...)
3873 {
3874 sprintf(laszip_dll->error, "reading size of item %u", j);
3875 return 1;
3876 }
3877 try { laszip_dll->streamin->get16bitsLE((U8*)&(laszip->items[j].version)); } catch(...)
3878 {
3879 sprintf(laszip_dll->error, "reading version of item %u", j);
3880 return 1;
3881 }
3882 }
3883 }
3884 else
3885 {
3886 laszip_dll->header.vlrs[i].data = new U8[laszip_dll->header.vlrs[i].record_length_after_header];
3887
3888 try { laszip_dll->streamin->getBytes(laszip_dll->header.vlrs[i].data, laszip_dll->header.vlrs[i].record_length_after_header); } catch(...)
3889 {
3890 sprintf(laszip_dll->error, "reading %d bytes of data into header.vlrs[%u].data", (I32)laszip_dll->header.vlrs[i].record_length_after_header, i);
3891 return 1;
3892 }
3893 }
3894 }
3895 else
3896 {
3897 laszip_dll->header.vlrs[i].data = 0;
3898 }
3899
3900 // keep track on the number of bytes we have read so far
3901
3902 vlrs_size += laszip_dll->header.vlrs[i].record_length_after_header;
3903
3904 // special handling for LASzip VLR
3905
3906 if ((strcmp(laszip_dll->header.vlrs[i].user_id, "laszip encoded") == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
3907 {
3908 // we take our the VLR for LASzip away
3909 laszip_dll->header.offset_to_point_data -= (54+laszip_dll->header.vlrs[i].record_length_after_header);
3910 vlrs_size -= (54+laszip_dll->header.vlrs[i].record_length_after_header);
3911 i--;
3912 laszip_dll->header.number_of_variable_length_records--;
3913 // free or resize the VLR array
3914 if (laszip_dll->header.number_of_variable_length_records == 0)
3915 {
3916 free(laszip_dll->header.vlrs);
3917 laszip_dll->header.vlrs = 0;
3918 }
3919 else
3920 {
3921 laszip_dll->header.vlrs = (laszip_vlr*)realloc(laszip_dll->header.vlrs, sizeof(laszip_vlr)*laszip_dll->header.number_of_variable_length_records);
3922 }
3923 }
3924 }
3925 }
3926
3927 // load any number of user-defined bytes that might have been added after the header
3928
3929 laszip_dll->header.user_data_after_header_size = (I32)laszip_dll->header.offset_to_point_data - vlrs_size - laszip_dll->header.header_size;
3930 if (laszip_dll->header.user_data_after_header_size)
3931 {
3932 if (laszip_dll->header.user_data_after_header)
3933 {
3934 delete [] laszip_dll->header.user_data_after_header;
3935 }
3936 laszip_dll->header.user_data_after_header = new U8[laszip_dll->header.user_data_after_header_size];
3937
3938 try { laszip_dll->streamin->getBytes((U8*)laszip_dll->header.user_data_after_header, laszip_dll->header.user_data_after_header_size); } catch(...)
3939 {
3940 sprintf(laszip_dll->error, "reading %u bytes of data into header.user_data_after_header", laszip_dll->header.user_data_after_header_size);
3941 return 1;
3942 }
3943 }
3944
3945 // remove extra bits in point data type
3946
3947 if ((laszip_dll->header.point_data_format & 128) || (laszip_dll->header.point_data_format & 64))
3948 {
3949 if (!laszip)
3950 {
3951 sprintf(laszip_dll->error, "this file was compressed with an experimental version of LASzip. contact 'martin.isenburg@rapidlasso.com' for assistance");
3952 return 1;
3953 }
3954 laszip_dll->header.point_data_format &= 127;
3955 }
3956
3957 // check if file is compressed
3958
3959 if (laszip)
3960 {
3961 // yes. check the compressor state
3962 *is_compressed = 1;
3963 if (!laszip->check(laszip_dll->header.point_data_record_length))
3964 {
3965 sprintf(laszip_dll->error, "%s upgrade to the latest release of LASzip or contact 'martin.isenburg@rapidlasso.com' for assistance", laszip->get_error());
3966 return 1;
3967 }
3968 }
3969 else
3970 {
3971 // no. setup an un-compressed read
3972 *is_compressed = 0;
3973 laszip = new LASzip;
3974 if (laszip == 0)
3975 {
3976 sprintf(laszip_dll->error, "could not alloc LASzip");
3977 return 1;
3978 }
3979 if (!laszip->setup(laszip_dll->header.point_data_format, laszip_dll->header.point_data_record_length, LASZIP_COMPRESSOR_NONE))
3980 {
3981 sprintf(laszip_dll->error, "invalid combination of point_data_format %d and point_data_record_length %d", (I32)laszip_dll->header.point_data_format, (I32)laszip_dll->header.point_data_record_length);
3982 return 1;
3983 }
3984 }
3985
3986 // create point's item pointers
3987
3988 if (laszip_dll->point_items)
3989 {
3990 delete [] laszip_dll->point_items;
3991 }
3992
3993 laszip_dll->point_items = new U8*[laszip->num_items];
3994
3995 if (laszip_dll->point_items == 0)
3996 {
3997 sprintf(laszip_dll->error, "could not alloc point_items");
3998 return 1;
3999 }
4000
4001 for (i = 0; i < laszip->num_items; i++)
4002 {
4003 switch (laszip->items[i].type)
4004 {
4005 case LASitem::POINT10:
4006 case LASitem::POINT14:
4007 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.X);
4008 break;
4009 case LASitem::GPSTIME11:
4010 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.gps_time);
4011 break;
4012 case LASitem::RGB12:
4013 case LASitem::RGB14:
4014 case LASitem::RGBNIR14:
4015 laszip_dll->point_items[i] = (U8*)laszip_dll->point.rgb;
4016 break;
4017 case LASitem::BYTE:
4018 case LASitem::BYTE14:
4019 laszip_dll->point.num_extra_bytes = laszip->items[i].size;
4020 if (laszip_dll->point.extra_bytes) delete [] laszip_dll->point.extra_bytes;
4021 laszip_dll->point.extra_bytes = new U8[laszip_dll->point.num_extra_bytes];
4022 laszip_dll->point_items[i] = laszip_dll->point.extra_bytes;
4023 break;
4024 case LASitem::WAVEPACKET13:
4025 case LASitem::WAVEPACKET14:
4026 laszip_dll->point_items[i] = (U8*)&(laszip_dll->point.wave_packet);
4027 break;
4028 default:
4029 sprintf(laszip_dll->error, "unknown LASitem type %d", (I32)laszip->items[i].type);
4030 return 1;
4031 }
4032 }
4033
4034 // did the user request to recode the compatibility mode points?
4035
4036 laszip_dll->compatibility_mode = FALSE;
4037
4038 if (laszip_dll->request_compatibility_mode && (laszip_dll->header.version_minor < 4))
4039 {
4040 // does this file contain compatibility mode recoded LAS 1.4 content
4041
4042 struct laszip_vlr* compatibility_VLR = 0;
4043
4044 if (laszip_dll->header.point_data_format == 1 || laszip_dll->header.point_data_format == 3 || laszip_dll->header.point_data_format == 4 || laszip_dll->header.point_data_format == 5)
4045 {
4046 // if we find the compatibility VLR
4047
4048 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4049 {
4050 if ((strncmp(laszip_dll->header.vlrs[i].user_id, "lascompatible\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 22204))
4051 {
4052 if (laszip_dll->header.vlrs[i].record_length_after_header == 2+2+4+148)
4053 {
4054 compatibility_VLR = &(laszip_dll->header.vlrs[i]);
4055 break;
4056 }
4057 }
4058 }
4059
4060 if (compatibility_VLR)
4061 {
4062 // and we also find the extra bytes VLR with the right attributes
4063
4064 LASattributer attributer;
4065 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4066 {
4067 if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Spec\0\0\0\0\0\0", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 4))
4068 {
4069 attributer.init_attributes(laszip_dll->header.vlrs[i].record_length_after_header/192, (LASattribute*)laszip_dll->header.vlrs[i].data);
4070 laszip_dll->start_scan_angle = attributer.get_attribute_start("LAS 1.4 scan angle");
4071 laszip_dll->start_extended_returns = attributer.get_attribute_start("LAS 1.4 extended returns");
4072 laszip_dll->start_classification = attributer.get_attribute_start("LAS 1.4 classification");
4073 laszip_dll->start_flags_and_channel = attributer.get_attribute_start("LAS 1.4 flags and channel");
4074 laszip_dll->start_NIR_band = attributer.get_attribute_start("LAS 1.4 NIR band");
4075 break;
4076 }
4077 }
4078
4079 // can we do it ... ?
4080
4081 if ((laszip_dll->start_scan_angle != -1) && (laszip_dll->start_extended_returns != -1) && (laszip_dll->start_classification != -1) && (laszip_dll->start_flags_and_channel != -1))
4082 {
4083 // yes ... so let's fix the header (using the content from the compatibility VLR)
4084
4085 ByteStreamInArray* in;
4086 if (IS_LITTLE_ENDIAN())
4087 in = new ByteStreamInArrayLE(compatibility_VLR->data, compatibility_VLR->record_length_after_header);
4088 else
4089 in = new ByteStreamInArrayBE(compatibility_VLR->data, compatibility_VLR->record_length_after_header);
4090 // read control info
4091 U16 laszip_version;
4092 in->get16bitsLE((U8*)&laszip_version);
4093 U16 compatible_version;
4094 in->get16bitsLE((U8*)&compatible_version);
4095 U32 unused;
4096 in->get32bitsLE((U8*)&unused);
4097 // read the 148 bytes of the extended LAS 1.4 header
4098 U64 start_of_waveform_data_packet_record;
4099 in->get64bitsLE((U8*)&start_of_waveform_data_packet_record);
4100 if (start_of_waveform_data_packet_record != 0)
4101 {
4102 #ifdef _WIN32
4103 fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %I64d. reading 0 instead.\n", start_of_waveform_data_packet_record);
4104 #else
4105 fprintf(stderr,"WARNING: start_of_waveform_data_packet_record is %llu. reading 0 instead.\n", start_of_waveform_data_packet_record);
4106 #endif
4107 }
4108 laszip_dll->header.start_of_waveform_data_packet_record = 0;
4109 U64 start_of_first_extended_variable_length_record;
4110 in->get64bitsLE((U8*)&start_of_first_extended_variable_length_record);
4111 if (start_of_first_extended_variable_length_record != 0)
4112 {
4113 #ifdef _WIN32
4114 fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %I64d. reading 0 instead.\n", start_of_first_extended_variable_length_record);
4115 #else
4116 fprintf(stderr,"WARNING: EVLRs not supported. start_of_first_extended_variable_length_record is %llu. reading 0 instead.\n", start_of_first_extended_variable_length_record);
4117 #endif
4118 }
4119 laszip_dll->header.start_of_first_extended_variable_length_record = 0;
4120 U32 number_of_extended_variable_length_records ;
4121 in->get32bitsLE((U8*)&number_of_extended_variable_length_records);
4122 if (number_of_extended_variable_length_records != 0)
4123 {
4124 fprintf(stderr,"WARNING: EVLRs not supported. number_of_extended_variable_length_records is %u. reading 0 instead.\n", number_of_extended_variable_length_records);
4125 }
4126 laszip_dll->header.number_of_extended_variable_length_records = 0;
4127 U64 extended_number_of_point_records = 0;
4128 in->get64bitsLE((U8*)&extended_number_of_point_records);
4129 if (laszip_dll->header.number_of_point_records != 0 && ((U64)(laszip_dll->header.number_of_point_records)) != extended_number_of_point_records)
4130 {
4131 #ifdef _WIN32
4132 fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %I64u.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records);
4133 #else
4134 fprintf(stderr,"WARNING: number_of_point_records is %u. but extended_number_of_point_records is %llu.\n", laszip_dll->header.number_of_point_records, extended_number_of_point_records);
4135 #endif
4136 }
4137 laszip_dll->header.extended_number_of_point_records = extended_number_of_point_records;
4138 U64 extended_number_of_points_by_return;
4139 for (U32 r = 0; r < 15; r++)
4140 {
4141 in->get64bitsLE((U8*)&extended_number_of_points_by_return);
4142 if ((r < 5) && laszip_dll->header.number_of_points_by_return[r] != 0 && ((U64)(laszip_dll->header.number_of_points_by_return[r])) != extended_number_of_points_by_return)
4143 {
4144 #ifdef _WIN32
4145 fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %I64u.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return);
4146 #else
4147 fprintf(stderr,"WARNING: number_of_points_by_return[%u] is %u. but extended_number_of_points_by_return[%u] is %llu.\n", r, laszip_dll->header.number_of_points_by_return[r], r, extended_number_of_points_by_return);
4148 #endif
4149 }
4150 laszip_dll->header.extended_number_of_points_by_return[r] = extended_number_of_points_by_return;
4151 }
4152 delete in;
4153
4154 // remove the compatibility VLR
4155
4156 if (laszip_remove_vlr(laszip_dll, "lascompatible\0\0", 22204))
4157 {
4158 sprintf(laszip_dll->error, "removing the compatibility VLR");
4159 return 1;
4160 }
4161
4162 // remove the LAS 1.4 attributes from the "extra bytes" description
4163
4164 if (laszip_dll->start_NIR_band != -1) attributer.remove_attribute("LAS 1.4 NIR band");
4165 attributer.remove_attribute("LAS 1.4 flags and channel");
4166 attributer.remove_attribute("LAS 1.4 classification");
4167 attributer.remove_attribute("LAS 1.4 extended returns");
4168 attributer.remove_attribute("LAS 1.4 scan angle");
4169
4170 // either rewrite or remove the "extra bytes" VLR
4171
4172 if (attributer.number_attributes)
4173 {
4174 if (laszip_add_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4, (laszip_U16)(attributer.number_attributes*sizeof(LASattribute)), 0, (laszip_U8*)attributer.attributes))
4175 {
4176 sprintf(laszip_dll->error, "rewriting the extra bytes VLR without 'LAS 1.4 compatibility mode' attributes");
4177 return 1;
4178 }
4179 }
4180 else
4181 {
4182 if (laszip_remove_vlr(laszip_dll, "LASF_Spec\0\0\0\0\0\0", 4))
4183 {
4184 sprintf(laszip_dll->error, "removing the LAS 1.4 attribute VLR");
4185 return 1;
4186 }
4187 }
4188
4189 // upgrade to LAS 1.4
4190 if (laszip_dll->header.version_minor < 3)
4191 {
4192 // LAS 1.2 header is 148 bytes less than LAS 1.4+ header
4193 laszip_dll->header.header_size += 148;
4194 laszip_dll->header.offset_to_point_data += 148;
4195 }
4196 else
4197 {
4198 // LAS 1.3 header is 140 bytes less than LAS 1.4+ header
4199 laszip_dll->header.header_size += 140;
4200 laszip_dll->header.offset_to_point_data += 140;
4201 }
4202 laszip_dll->header.version_minor = 4;
4203
4204 // maybe turn on the bit indicating the presence of the OGC WKT
4205 for (i = 0; i < laszip_dll->header.number_of_variable_length_records; i++)
4206 {
4207 if ((strncmp(laszip_dll->header.vlrs[i].user_id, "LASF_Projection", 16) == 0) && (laszip_dll->header.vlrs[i].record_id == 2112))
4208 {
4209 laszip_dll->header.global_encoding |= (1<<4);
4210 break;
4211 }
4212 }
4213
4214 // update point type and size
4215
4216 laszip_dll->point.extended_point_type = 1;
4217
4218 if (laszip_dll->header.point_data_format == 1)
4219 {
4220 laszip_dll->header.point_data_format = 6;
4221 laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes
4222 }
4223 else if (laszip_dll->header.point_data_format == 3)
4224 {
4225 if (laszip_dll->start_NIR_band == -1)
4226 {
4227 laszip_dll->header.point_data_format = 7;
4228 laszip_dll->header.point_data_record_length += (2 - 5); // record is 2 bytes larger but minus 5 extra bytes
4229 }
4230 else
4231 {
4232 laszip_dll->header.point_data_format = 8;
4233 laszip_dll->header.point_data_record_length += (4 - 7); // record is 4 bytes larger but minus 7 extra bytes
4234 }
4235 }
4236 else
4237 {
4238 if (laszip_dll->start_NIR_band == -1)
4239 {
4240 laszip_dll->header.point_data_format = 9;
4241 laszip_dll->header.point_data_record_length += (2 - 5);
4242 }
4243 else
4244 {
4245 laszip_dll->header.point_data_format = 10;
4246 laszip_dll->header.point_data_record_length += (4 - 7);
4247 }
4248 }
4249
4250 // we are operating in compatibility mode
4251
4252 laszip_dll->compatibility_mode = TRUE;
4253 }
4254 }
4255 }
4256 }
4257 else if (laszip_dll->header.point_data_format > 5)
4258 {
4259 laszip_dll->point.extended_point_type = 1;
4260 }
4261
4262 // create the point reader
4263
4264 laszip_dll->reader = new LASreadPoint(laszip_dll->las14_decompress_selective);
4265 if (laszip_dll->reader == 0)
4266 {
4267 sprintf(laszip_dll->error, "could not alloc LASreadPoint");
4268 return 1;
4269 }
4270
4271 if (!laszip_dll->reader->setup(laszip->num_items, laszip->items, laszip))
4272 {
4273 sprintf(laszip_dll->error, "setup of LASreadPoint failed");
4274 return 1;
4275 }
4276
4277 if (!laszip_dll->reader->init(laszip_dll->streamin))
4278 {
4279 sprintf(laszip_dll->error, "init of LASreadPoint failed");
4280 return 1;
4281 }
4282
4283 delete laszip;
4284
4285 // set the point number and point count
4286
4287 laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
4288 laszip_dll->p_count = 0;
4289
4290 laszip_dll->error[0] = '\0';
4291 return 0;
4292 }
4293
4294 /*---------------------------------------------------------------------------*/
4295 LASZIP_API laszip_I32
laszip_open_reader(laszip_POINTER pointer,const laszip_CHAR * file_name,laszip_BOOL * is_compressed)4296 laszip_open_reader(
4297 laszip_POINTER pointer
4298 , const laszip_CHAR* file_name
4299 , laszip_BOOL* is_compressed
4300 )
4301 {
4302 if (pointer == 0) return 1;
4303 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4304
4305 try
4306 {
4307 if (file_name == 0)
4308 {
4309 sprintf(laszip_dll->error, "laszip_CHAR pointer 'file_name' is zero");
4310 return 1;
4311 }
4312
4313 if (is_compressed == 0)
4314 {
4315 sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero");
4316 return 1;
4317 }
4318
4319 if (laszip_dll->writer)
4320 {
4321 sprintf(laszip_dll->error, "writer is already open");
4322 return 1;
4323 }
4324
4325 if (laszip_dll->reader)
4326 {
4327 sprintf(laszip_dll->error, "reader is already open");
4328 return 1;
4329 }
4330
4331 // open the file
4332
4333 #ifdef _MSC_VER
4334 wchar_t* utf16_file_name = UTF8toUTF16(file_name);
4335 laszip_dll->file = _wfopen(utf16_file_name, L"rb");
4336 delete [] utf16_file_name;
4337 #else
4338 laszip_dll->file = fopen(file_name, "rb");
4339 #endif
4340
4341 if (laszip_dll->file == 0)
4342 {
4343 sprintf(laszip_dll->error, "cannot open file '%s'", file_name);
4344 return 1;
4345 }
4346
4347 if (setvbuf(laszip_dll->file, NULL, _IOFBF, 262144) != 0)
4348 {
4349 sprintf(laszip_dll->warning, "setvbuf() failed with buffer size 262144\n");
4350 }
4351
4352 if (IS_LITTLE_ENDIAN())
4353 laszip_dll->streamin = new ByteStreamInFileLE(laszip_dll->file);
4354 else
4355 laszip_dll->streamin = new ByteStreamInFileBE(laszip_dll->file);
4356
4357 if (laszip_dll->streamin == 0)
4358 {
4359 sprintf(laszip_dll->error, "could not alloc ByteStreamInFile");
4360 return 1;
4361 }
4362
4363 // read the header variable after variable
4364
4365 if (laszip_read_header(laszip_dll, is_compressed))
4366 {
4367 return 1;
4368 }
4369
4370 // should we try to exploit existing spatial indexing information
4371
4372 if (laszip_dll->lax_exploit)
4373 {
4374 laszip_dll->lax_index = new LASindex();
4375
4376 if (!laszip_dll->lax_index->read(file_name))
4377 {
4378 delete laszip_dll->lax_index;
4379 laszip_dll->lax_index = 0;
4380 }
4381 }
4382 }
4383 catch (...)
4384 {
4385 sprintf(laszip_dll->error, "internal error in laszip_open_reader");
4386 return 1;
4387 }
4388
4389 laszip_dll->error[0] = '\0';
4390 return 0;
4391 }
4392
4393 /*---------------------------------------------------------------------------*/
4394 LASZIP_API laszip_I32
laszip_has_spatial_index(laszip_POINTER pointer,laszip_BOOL * is_indexed,laszip_BOOL * is_appended)4395 laszip_has_spatial_index(
4396 laszip_POINTER pointer
4397 , laszip_BOOL* is_indexed
4398 , laszip_BOOL* is_appended
4399 )
4400 {
4401 if (pointer == 0) return 1;
4402 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4403
4404 try
4405 {
4406 if (is_indexed == 0)
4407 {
4408 sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_indexed' is zero");
4409 return 1;
4410 }
4411
4412 if (laszip_dll->reader == 0)
4413 {
4414 sprintf(laszip_dll->error, "reader is not open");
4415 return 1;
4416 }
4417
4418 if (laszip_dll->writer)
4419 {
4420 sprintf(laszip_dll->error, "writer is already open");
4421 return 1;
4422 }
4423
4424 if (laszip_dll->lax_exploit == 0)
4425 {
4426 sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader");
4427 return 1;
4428 }
4429
4430 // check if reader found spatial indexing information when opening file
4431
4432 if (laszip_dll->lax_index)
4433 {
4434 *is_indexed = 1;
4435 }
4436 else
4437 {
4438 *is_indexed = 0;
4439 }
4440
4441 // optional: inform whether spatial index is appended to LAZ file or in separate LAX file
4442
4443 if (is_appended)
4444 {
4445 *is_appended = 0;
4446 }
4447
4448 }
4449 catch (...)
4450 {
4451 sprintf(laszip_dll->error, "internal error in laszip_have_spatial_index");
4452 return 1;
4453 }
4454
4455 laszip_dll->error[0] = '\0';
4456 return 0;
4457 }
4458
4459 /*---------------------------------------------------------------------------*/
4460 LASZIP_API laszip_I32
laszip_inside_rectangle(laszip_POINTER pointer,const laszip_F64 r_min_x,const laszip_F64 r_min_y,const laszip_F64 r_max_x,const laszip_F64 r_max_y,laszip_BOOL * is_empty)4461 laszip_inside_rectangle(
4462 laszip_POINTER pointer
4463 , const laszip_F64 r_min_x
4464 , const laszip_F64 r_min_y
4465 , const laszip_F64 r_max_x
4466 , const laszip_F64 r_max_y
4467 , laszip_BOOL* is_empty
4468 )
4469 {
4470 if (pointer == 0) return 1;
4471 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4472
4473 try
4474 {
4475 if (laszip_dll->reader == 0)
4476 {
4477 sprintf(laszip_dll->error, "reader is not open");
4478 return 1;
4479 }
4480
4481 if (is_empty == 0)
4482 {
4483 sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_empty' is zero");
4484 return 1;
4485 }
4486
4487 if (laszip_dll->lax_exploit == FALSE)
4488 {
4489 sprintf(laszip_dll->error, "exploiting of spatial indexing not enabled before opening reader");
4490 return 1;
4491 }
4492
4493 laszip_dll->lax_r_min_x = r_min_x;
4494 laszip_dll->lax_r_min_y = r_min_y;
4495 laszip_dll->lax_r_max_x = r_max_x;
4496 laszip_dll->lax_r_max_y = r_max_y;
4497
4498 if (laszip_dll->lax_index)
4499 {
4500 if (laszip_dll->lax_index->intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y))
4501 {
4502 *is_empty = 0;
4503 }
4504 else
4505 {
4506 // no overlap between spatial indexing cells and query reactangle
4507 *is_empty = 1;
4508 }
4509 }
4510 else
4511 {
4512 if ((laszip_dll->header.min_x > r_max_x) || (laszip_dll->header.min_y > r_max_y) || (laszip_dll->header.max_x < r_min_x) || (laszip_dll->header.max_y < r_min_y))
4513 {
4514 // no overlap between header bouding box and query reactangle
4515 *is_empty = 1;
4516 }
4517 else
4518 {
4519 *is_empty = 0;
4520 }
4521 }
4522 }
4523 catch (...)
4524 {
4525 sprintf(laszip_dll->error, "internal error in laszip_inside_rectangle");
4526 return 1;
4527 }
4528
4529 laszip_dll->error[0] = '\0';
4530 return 0;
4531 }
4532
4533 /*---------------------------------------------------------------------------*/
4534 LASZIP_API laszip_I32
laszip_seek_point(laszip_POINTER pointer,laszip_I64 index)4535 laszip_seek_point(
4536 laszip_POINTER pointer
4537 , laszip_I64 index
4538 )
4539 {
4540 if (pointer == 0) return 1;
4541 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4542
4543 try
4544 {
4545 // seek to the point
4546 if (!laszip_dll->reader->seek((U32)laszip_dll->p_count, (U32)index))
4547 {
4548 #ifdef _WIN32
4549 sprintf(laszip_dll->error, "seeking from index %I64d to index %I64d for file with %I64d points", laszip_dll->p_count, index, laszip_dll->npoints);
4550 #else
4551 sprintf(laszip_dll->error, "seeking from index %lld to index %lld for file with %lld points", laszip_dll->p_count, index, laszip_dll->npoints);
4552 #endif
4553 return 1;
4554 }
4555 laszip_dll->p_count = index;
4556 }
4557 catch (...)
4558 {
4559 sprintf(laszip_dll->error, "internal error in laszip_seek_point");
4560 return 1;
4561 }
4562
4563 laszip_dll->error[0] = '\0';
4564 return 0;
4565 }
4566
4567 /*---------------------------------------------------------------------------*/
4568 LASZIP_API laszip_I32
laszip_read_point(laszip_POINTER pointer)4569 laszip_read_point(
4570 laszip_POINTER pointer
4571 )
4572 {
4573 if (pointer == 0) return 1;
4574 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4575
4576 try
4577 {
4578 // read the point
4579 if (!laszip_dll->reader->read(laszip_dll->point_items))
4580 {
4581 #ifdef _WIN32
4582 sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
4583 #else
4584 sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
4585 #endif
4586 return 1;
4587 }
4588
4589 // special recoding of points (in compatibility mode only)
4590
4591 if (laszip_dll->compatibility_mode)
4592 {
4593 I16 scan_angle_remainder;
4594 U8 extended_returns;
4595 U8 classification;
4596 U8 flags_and_channel;
4597 I32 return_number_increment;
4598 I32 number_of_returns_increment;
4599 I32 overlap_bit;
4600 I32 scanner_channel;
4601
4602 // instill extended attributes
4603 struct laszip_point* point = &laszip_dll->point;
4604
4605 // get extended attributes from extra bytes
4606 scan_angle_remainder = *((I16*)(point->extra_bytes + laszip_dll->start_scan_angle));
4607 extended_returns = point->extra_bytes[laszip_dll->start_extended_returns];
4608 classification = point->extra_bytes[laszip_dll->start_classification];
4609 flags_and_channel = point->extra_bytes[laszip_dll->start_flags_and_channel];
4610 if (laszip_dll->start_NIR_band != -1)
4611 {
4612 point->rgb[3] = *((U16*)(point->extra_bytes + laszip_dll->start_NIR_band));
4613 }
4614
4615 // decompose into individual attributes
4616 return_number_increment = (extended_returns >> 4) & 0x0F;
4617 number_of_returns_increment = extended_returns & 0x0F;
4618 scanner_channel = (flags_and_channel >> 1) & 0x03;
4619 overlap_bit = flags_and_channel & 0x01;
4620
4621 // instill into point
4622 point->extended_scan_angle = scan_angle_remainder + I16_QUANTIZE(((F32)point->scan_angle_rank) / 0.006f);
4623 point->extended_return_number = return_number_increment + point->return_number;
4624 point->extended_number_of_returns = number_of_returns_increment + point->number_of_returns;
4625 point->extended_classification = classification + point->classification;
4626 point->extended_scanner_channel = scanner_channel;
4627 point->extended_classification_flags = (overlap_bit << 3) | ((point->withheld_flag) << 2) | ((point->keypoint_flag) << 1) | (point->synthetic_flag);
4628 }
4629
4630 laszip_dll->p_count++;
4631 }
4632 catch (...)
4633 {
4634 sprintf(laszip_dll->error, "internal error in laszip_read_point");
4635 return 1;
4636 }
4637
4638 laszip_dll->error[0] = '\0';
4639 return 0;
4640 }
4641
4642 /*---------------------------------------------------------------------------*/
4643 LASZIP_API laszip_I32
laszip_read_inside_point(laszip_POINTER pointer,laszip_BOOL * is_done)4644 laszip_read_inside_point(
4645 laszip_POINTER pointer
4646 , laszip_BOOL* is_done
4647 )
4648 {
4649 if (pointer == 0) return 1;
4650 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4651
4652 try
4653 {
4654 laszip_F64 xy;
4655
4656 *is_done = 1;
4657
4658 if (laszip_dll->lax_index)
4659 {
4660 while (laszip_dll->lax_index->seek_next(laszip_dll->reader, laszip_dll->p_count))
4661 {
4662 if (laszip_dll->reader->read(laszip_dll->point_items))
4663 {
4664 laszip_dll->p_count++;
4665 xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
4666 if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue;
4667 xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
4668 if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue;
4669 *is_done = 0;
4670 break;
4671 }
4672 }
4673 }
4674 else
4675 {
4676 while (laszip_dll->reader->read(laszip_dll->point_items))
4677 {
4678 laszip_dll->p_count++;
4679 xy = laszip_dll->header.x_scale_factor*laszip_dll->point.X+laszip_dll->header.x_offset;
4680 if (xy < laszip_dll->lax_r_min_x || xy >= laszip_dll->lax_r_max_x) continue;
4681 xy = laszip_dll->header.y_scale_factor*laszip_dll->point.Y+laszip_dll->header.y_offset;
4682 if (xy < laszip_dll->lax_r_min_y || xy >= laszip_dll->lax_r_max_y) continue;
4683 *is_done = 0;
4684 break;
4685 }
4686
4687 if (*is_done)
4688 {
4689 if (laszip_dll->p_count < laszip_dll->npoints)
4690 {
4691 #ifdef _WIN32
4692 sprintf(laszip_dll->error, "reading point %I64d of %I64d total points", laszip_dll->p_count, laszip_dll->npoints);
4693 #else
4694 sprintf(laszip_dll->error, "reading point %lld of %lld total points", laszip_dll->p_count, laszip_dll->npoints);
4695 #endif
4696 return 1;
4697 }
4698 }
4699 }
4700 }
4701 catch (...)
4702 {
4703 sprintf(laszip_dll->error, "internal error in laszip_read_inside_point");
4704 return 1;
4705 }
4706
4707 laszip_dll->error[0] = '\0';
4708 return 0;
4709 }
4710
4711 /*---------------------------------------------------------------------------*/
4712 LASZIP_API laszip_I32
laszip_close_reader(laszip_POINTER pointer)4713 laszip_close_reader(
4714 laszip_POINTER pointer
4715 )
4716 {
4717 if (pointer == 0) return 1;
4718 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4719 try
4720 {
4721 if (laszip_dll->reader == 0)
4722 {
4723 sprintf(laszip_dll->error, "closing reader before it was opened");
4724 return 1;
4725 }
4726
4727 if (!laszip_dll->reader->done())
4728 {
4729 sprintf(laszip_dll->error, "done of LASreadPoint failed");
4730 return 1;
4731 }
4732
4733 delete laszip_dll->reader;
4734 laszip_dll->reader = 0;
4735
4736 delete [] laszip_dll->point_items;
4737 laszip_dll->point_items = 0;
4738
4739 delete laszip_dll->streamin;
4740 laszip_dll->streamin = 0;
4741
4742 if (laszip_dll->lax_index)
4743 {
4744 delete laszip_dll->lax_index;
4745 laszip_dll->lax_index = 0;
4746 }
4747
4748 if (laszip_dll->file)
4749 {
4750 fclose(laszip_dll->file);
4751 laszip_dll->file = 0;
4752 }
4753 }
4754 catch (...)
4755 {
4756 sprintf(laszip_dll->error, "internal error in laszip_close_reader");
4757 return 1;
4758 }
4759
4760 laszip_dll->error[0] = '\0';
4761 return 0;
4762 }
4763
4764 #ifdef __cplusplus
4765
4766 /*---------------------------------------------------------------------------*/
4767 LASZIP_API laszip_I32
laszip_open_reader_stream(laszip_POINTER pointer,istream & stream,laszip_BOOL * is_compressed)4768 laszip_open_reader_stream(
4769 laszip_POINTER pointer
4770 , istream& stream
4771 , laszip_BOOL* is_compressed
4772 )
4773 {
4774 if (pointer == 0) return 1;
4775 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4776
4777 try
4778 {
4779 if (is_compressed == 0)
4780 {
4781 sprintf(laszip_dll->error, "laszip_BOOL pointer 'is_compressed' is zero");
4782 return 1;
4783 }
4784
4785 if (laszip_dll->writer)
4786 {
4787 sprintf(laszip_dll->error, "writer is already open");
4788 return 1;
4789 }
4790
4791 if (laszip_dll->reader)
4792 {
4793 sprintf(laszip_dll->error, "reader is already open");
4794 return 1;
4795 }
4796
4797 // open the file
4798
4799 if (IS_LITTLE_ENDIAN())
4800 laszip_dll->streamin = new ByteStreamInIstreamLE(stream);
4801 else
4802 laszip_dll->streamin = new ByteStreamInIstreamBE(stream);
4803
4804 if (laszip_dll->streamin == 0)
4805 {
4806 sprintf(laszip_dll->error, "could not alloc ByteStreamInIstream");
4807 return 1;
4808 }
4809
4810 return laszip_read_header(laszip_dll, is_compressed);
4811 }
4812 catch (...)
4813 {
4814 sprintf(laszip_dll->error, "internal error in laszip_open_reader");
4815 return 1;
4816 }
4817 }
4818
4819 /*---------------------------------------------------------------------------*/
4820 // The stream writer also supports software that writes the LAS header on its
4821 // own simply by setting the BOOL 'do_not_write_header' to TRUE. This function
4822 // should then be called just prior to writing points as data is then written
4823 // to the current stream position
4824 LASZIP_API laszip_I32
laszip_open_writer_stream(laszip_POINTER pointer,ostream & stream,laszip_BOOL compress,laszip_BOOL do_not_write_header)4825 laszip_open_writer_stream(
4826 laszip_POINTER pointer
4827 , ostream& stream
4828 , laszip_BOOL compress
4829 , laszip_BOOL do_not_write_header
4830 )
4831 {
4832 if (pointer == 0) return 1;
4833 laszip_dll_struct* laszip_dll = (laszip_dll_struct*)pointer;
4834
4835 try
4836 {
4837 if (laszip_dll->writer)
4838 {
4839 sprintf(laszip_dll->error, "writer is already open");
4840 return 1;
4841 }
4842
4843 if (laszip_dll->reader)
4844 {
4845 sprintf(laszip_dll->error, "reader is already open");
4846 return 1;
4847 }
4848
4849 // create the outstream
4850
4851 if (IS_LITTLE_ENDIAN())
4852 laszip_dll->streamout = new ByteStreamOutOstreamLE(stream);
4853 else
4854 laszip_dll->streamout = new ByteStreamOutOstreamBE(stream);
4855
4856 if (laszip_dll->streamout == 0)
4857 {
4858 sprintf(laszip_dll->error, "could not alloc ByteStreamOutOstream");
4859 return 1;
4860 }
4861
4862 // setup the items that make up the point
4863
4864 LASzip laszip;
4865 if (setup_laszip_items(laszip_dll, &laszip, compress))
4866 {
4867 return 1;
4868 }
4869
4870 // this supports software that writes the LAS header on its own
4871
4872 if (do_not_write_header == FALSE)
4873 {
4874 // prepare header
4875
4876 if (laszip_prepare_header_for_write(laszip_dll))
4877 {
4878 return 1;
4879 }
4880
4881 // prepare point
4882
4883 if (laszip_prepare_point_for_write(laszip_dll, compress))
4884 {
4885 return 1;
4886 }
4887
4888 // prepare VLRs
4889
4890 if (laszip_prepare_vlrs_for_write(laszip_dll))
4891 {
4892 return 1;
4893 }
4894
4895 // write header variable after variable
4896
4897 if (laszip_write_header(laszip_dll, &laszip, compress))
4898 {
4899 return 1;
4900 }
4901 }
4902
4903 // create the point writer
4904
4905 if (create_point_writer(laszip_dll, &laszip))
4906 {
4907 return 1;
4908 }
4909
4910 // set the point number and point count
4911
4912 laszip_dll->npoints = (laszip_dll->header.number_of_point_records ? laszip_dll->header.number_of_point_records : laszip_dll->header.extended_number_of_point_records);
4913 laszip_dll->p_count = 0;
4914 }
4915 catch (...)
4916 {
4917 sprintf(laszip_dll->error, "internal error in laszip_open_writer_stream.");
4918 return 1;
4919 }
4920 laszip_dll->error[0] = '\0';
4921 return 0;
4922 }
4923
4924 /*---------------------------------------------------------------------------*/
4925 // creates complete LASzip VLR for currently selected point type and compression
4926 // The VLR data is valid until the laszip_dll pointer is destroyed.
4927 LASZIP_API laszip_I32
laszip_create_laszip_vlr(laszip_POINTER pointer,laszip_U8 ** vlr,laszip_U32 * vlr_size)4928 laszip_create_laszip_vlr(
4929 laszip_POINTER pointer
4930 , laszip_U8** vlr
4931 , laszip_U32* vlr_size
4932 )
4933 {
4934 if (pointer == 0) return 1;
4935 laszip_dll_struct *laszip_dll = (laszip_dll_struct *)pointer;
4936
4937 LASzip laszip;
4938 if (setup_laszip_items(laszip_dll, &laszip, TRUE))
4939 {
4940 return 1;
4941 }
4942
4943 ByteStreamOutArray* out = 0;
4944
4945 if (IS_LITTLE_ENDIAN())
4946 out = new ByteStreamOutArrayLE();
4947 else
4948 out = new ByteStreamOutArrayBE();
4949
4950 if (out == 0)
4951 {
4952 sprintf(laszip_dll->error, "could not alloc ByteStreamOutArray");
4953 return 1;
4954 }
4955
4956 if (write_laszip_vlr_header(laszip_dll, &laszip, out))
4957 {
4958 return 1;
4959 }
4960
4961 if (write_laszip_vlr_payload(laszip_dll, &laszip, out))
4962 {
4963 return 1;
4964 }
4965
4966 *vlr = (laszip_U8*)malloc(out->getSize());
4967 *vlr_size = (U32)out->getSize();
4968 laszip_dll->buffers.push_back(*vlr);
4969 memcpy(*vlr, out->getData(), out->getSize());
4970
4971 delete out;
4972
4973 laszip_dll->error[0] = '\0';
4974 return 0;
4975 }
4976
4977 #endif // __cplusplus
4978