1 /*
2 ===============================================================================
3
4 FILE: lasutility.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-2017, 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 LICENSE.txt file for more information.
21
22 This software is distributed WITHOUT ANY WARRANTY and without even the
23 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24
25 CHANGE HISTORY:
26
27 see corresponding header file
28
29 ===============================================================================
30 */
31 #include "lasutility.hpp"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
LASinventory()37 LASinventory::LASinventory()
38 {
39 U32 i;
40 extended_number_of_point_records = 0;
41 for (i = 0; i < 16; i++) extended_number_of_points_by_return[i] = 0;
42 max_X = min_X = 0;
43 max_Y = min_Y = 0;
44 max_Z = min_Z = 0;
45 first = TRUE;
46 }
47
init(const LASheader * header)48 BOOL LASinventory::init(const LASheader* header)
49 {
50 if (header)
51 {
52 U32 i;
53 extended_number_of_point_records = (header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records);
54 extended_number_of_points_by_return[0] = 0;
55 for (i = 0; i < 5; i++) extended_number_of_points_by_return[i+1] = (header->number_of_points_by_return[i] ? header->number_of_points_by_return[i] : header->extended_number_of_points_by_return[i]);
56 for (i = 5; i < 15; i++) extended_number_of_points_by_return[i+1] = header->extended_number_of_points_by_return[i];
57 max_X = header->get_X(header->max_x);
58 min_X = header->get_X(header->min_x);
59 max_Y = header->get_Y(header->max_y);
60 min_Y = header->get_Y(header->min_y);
61 max_Z = header->get_Z(header->max_z);
62 min_Z = header->get_Z(header->min_z);
63 first = FALSE;
64 return TRUE;
65 }
66 return FALSE;
67 }
68
add(const LASpoint * point)69 BOOL LASinventory::add(const LASpoint* point)
70 {
71 extended_number_of_point_records++;
72 if (point->extended_point_type)
73 {
74 extended_number_of_points_by_return[point->extended_return_number]++;
75 }
76 else
77 {
78 extended_number_of_points_by_return[point->return_number]++;
79 }
80 if (first)
81 {
82 min_X = max_X = point->get_X();
83 min_Y = max_Y = point->get_Y();
84 min_Z = max_Z = point->get_Z();
85 first = FALSE;
86 }
87 else
88 {
89 if (point->get_X() < min_X) min_X = point->get_X();
90 else if (point->get_X() > max_X) max_X = point->get_X();
91 if (point->get_Y() < min_Y) min_Y = point->get_Y();
92 else if (point->get_Y() > max_Y) max_Y = point->get_Y();
93 if (point->get_Z() < min_Z) min_Z = point->get_Z();
94 else if (point->get_Z() > max_Z) max_Z = point->get_Z();
95 }
96 return TRUE;
97 }
98
update_header(LASheader * header) const99 BOOL LASinventory::update_header(LASheader* header) const
100 {
101 if (header)
102 {
103 int i;
104 if (extended_number_of_point_records > U32_MAX)
105 {
106 if (header->version_minor >= 4)
107 {
108 header->number_of_point_records = 0;
109 }
110 else
111 {
112 return FALSE;
113 }
114 }
115 else
116 {
117 header->number_of_point_records = (U32)extended_number_of_point_records;
118 }
119 for (i = 0; i < 5; i++)
120 {
121 if (extended_number_of_points_by_return[i+1] > U32_MAX)
122 {
123 if (header->version_minor >= 4)
124 {
125 header->number_of_points_by_return[i] = 0;
126 }
127 else
128 {
129 return FALSE;
130 }
131 }
132 else
133 {
134 header->number_of_points_by_return[i] = (U32)extended_number_of_points_by_return[i+1];
135 }
136 }
137 header->max_x = header->get_x(max_X);
138 header->min_x = header->get_x(min_X);
139 header->max_y = header->get_y(max_Y);
140 header->min_y = header->get_y(min_Y);
141 header->max_z = header->get_z(max_Z);
142 header->min_z = header->get_z(min_Z);
143 header->extended_number_of_point_records = extended_number_of_point_records;
144 for (i = 0; i < 15; i++)
145 {
146 header->extended_number_of_points_by_return[i] = extended_number_of_points_by_return[i+1];
147 }
148 return TRUE;
149 }
150 else
151 {
152 return FALSE;
153 }
154 }
155
LASsummary()156 LASsummary::LASsummary()
157 {
158 U32 i;
159 number_of_point_records = 0;
160 for (i = 0; i < 16; i++) number_of_points_by_return[i] = 0;
161 for (i = 0; i < 16; i++) number_of_returns[i] = 0;
162 for (i = 0; i < 32; i++) classification[i] = 0;
163 for (i = 0; i < 256; i++) extended_classification[i] = 0;
164 for (i = 0; i < 3; i++)
165 {
166 xyz_fluff_10[i] = 0;
167 xyz_fluff_100[i] = 0;
168 xyz_fluff_1000[i] = 0;
169 xyz_fluff_10000[i] = 0;
170 }
171 classification_synthetic = 0;
172 classification_keypoint = 0;
173 classification_withheld = 0;
174 classification_extended_overlap = 0;
175 first = TRUE;
176 }
177
add(const LASpoint * point)178 BOOL LASsummary::add(const LASpoint* point)
179 {
180 number_of_point_records++;
181 if (point->extended_point_type)
182 {
183 number_of_points_by_return[point->get_extended_return_number()]++;
184 number_of_returns[point->get_extended_number_of_returns()]++;
185 if (point->get_extended_classification() > 31)
186 {
187 extended_classification[point->get_extended_classification()]++;
188 }
189 else
190 {
191 classification[point->get_classification()]++;
192 }
193 if (point->get_extended_overlap_flag()) classification_extended_overlap++;
194 }
195 else
196 {
197 number_of_points_by_return[point->get_return_number()]++;
198 classification[point->get_classification()]++;
199 number_of_returns[point->get_number_of_returns()]++;
200 }
201 if (point->get_synthetic_flag()) classification_synthetic++;
202 if (point->get_keypoint_flag()) classification_keypoint++;
203 if (point->get_withheld_flag()) classification_withheld++;
204 if (first)
205 {
206 // initialize min and max
207 min = *point;
208 max = *point;
209 // initialize fluff detection
210 xyz_low_digits_10[0] = (U16)(point->get_X()%10);
211 xyz_low_digits_10[1] = (U16)(point->get_Y()%10);
212 xyz_low_digits_10[2] = (U16)(point->get_Z()%10);
213 xyz_low_digits_100[0] = (U16)(point->get_X()%100);
214 xyz_low_digits_100[1] = (U16)(point->get_Y()%100);
215 xyz_low_digits_100[2] = (U16)(point->get_Z()%100);
216 xyz_low_digits_1000[0] = (U16)(point->get_X()%1000);
217 xyz_low_digits_1000[1] = (U16)(point->get_Y()%1000);
218 xyz_low_digits_1000[2] = (U16)(point->get_Z()%1000);
219 xyz_low_digits_10000[0] = (U16)(point->get_X()%10000);
220 xyz_low_digits_10000[1] = (U16)(point->get_Y()%10000);
221 xyz_low_digits_10000[2] = (U16)(point->get_Z()%10000);
222 first = FALSE;
223 }
224 else
225 {
226 if (point->get_X() < min.get_X()) min.set_X(point->get_X());
227 else if (point->get_X() > max.get_X()) max.set_X(point->get_X());
228 if (point->get_Y() < min.get_Y()) min.set_Y(point->get_Y());
229 else if (point->get_Y() > max.get_Y()) max.set_Y(point->get_Y());
230 if (point->get_Z() < min.get_Z()) min.set_Z(point->get_Z());
231 else if (point->get_Z() > max.get_Z()) max.set_Z(point->get_Z());
232 if (point->intensity < min.intensity) min.intensity = point->intensity;
233 else if (point->intensity > max.intensity) max.intensity = point->intensity;
234 if (point->edge_of_flight_line < min.edge_of_flight_line) min.edge_of_flight_line = point->edge_of_flight_line;
235 else if (point->edge_of_flight_line > max.edge_of_flight_line) max.edge_of_flight_line = point->edge_of_flight_line;
236 if (point->scan_direction_flag < min.scan_direction_flag) min.scan_direction_flag = point->scan_direction_flag;
237 else if (point->scan_direction_flag > max.scan_direction_flag) max.scan_direction_flag = point->scan_direction_flag;
238 if (point->number_of_returns < min.number_of_returns) min.number_of_returns = point->number_of_returns;
239 else if (point->number_of_returns > max.number_of_returns) max.number_of_returns = point->number_of_returns;
240 if (point->return_number < min.return_number) min.return_number = point->return_number;
241 else if (point->return_number > max.return_number) max.return_number = point->return_number;
242 if (point->classification < min.classification) min.classification = point->classification;
243 else if (point->classification > max.classification) max.classification = point->classification;
244 if (point->scan_angle_rank < min.scan_angle_rank) min.scan_angle_rank = point->scan_angle_rank;
245 else if (point->scan_angle_rank > max.scan_angle_rank) max.scan_angle_rank = point->scan_angle_rank;
246 if (point->user_data < min.user_data) min.user_data = point->user_data;
247 else if (point->user_data > max.user_data) max.user_data = point->user_data;
248 if (point->point_source_ID < min.point_source_ID) min.point_source_ID = point->point_source_ID;
249 else if (point->point_source_ID > max.point_source_ID) max.point_source_ID = point->point_source_ID;
250 if (point->have_gps_time)
251 {
252 if (point->gps_time < min.gps_time) min.gps_time = point->gps_time;
253 else if (point->gps_time > max.gps_time) max.gps_time = point->gps_time;
254 }
255 if (point->have_rgb)
256 {
257 if (point->rgb[0] < min.rgb[0]) min.rgb[0] = point->rgb[0];
258 else if (point->rgb[0] > max.rgb[0]) max.rgb[0] = point->rgb[0];
259 if (point->rgb[1] < min.rgb[1]) min.rgb[1] = point->rgb[1];
260 else if (point->rgb[1] > max.rgb[1]) max.rgb[1] = point->rgb[1];
261 if (point->rgb[2] < min.rgb[2]) min.rgb[2] = point->rgb[2];
262 else if (point->rgb[2] > max.rgb[2]) max.rgb[2] = point->rgb[2];
263 }
264 if (point->extended_point_type)
265 {
266 if (point->extended_classification < min.extended_classification) min.extended_classification = point->extended_classification;
267 else if (point->extended_classification > max.extended_classification) max.extended_classification = point->extended_classification;
268 if (point->extended_return_number < min.extended_return_number) min.extended_return_number = point->extended_return_number;
269 else if (point->extended_return_number > max.extended_return_number) max.extended_return_number = point->extended_return_number;
270 if (point->extended_number_of_returns < min.extended_number_of_returns) min.extended_number_of_returns = point->extended_number_of_returns;
271 else if (point->extended_number_of_returns > max.extended_number_of_returns) max.extended_number_of_returns = point->extended_number_of_returns;
272 if (point->extended_scan_angle < min.extended_scan_angle) min.extended_scan_angle = point->extended_scan_angle;
273 else if (point->extended_scan_angle > max.extended_scan_angle) max.extended_scan_angle = point->extended_scan_angle;
274 if (point->extended_scanner_channel < min.extended_scanner_channel) min.extended_scanner_channel = point->extended_scanner_channel;
275 else if (point->extended_scanner_channel > max.extended_scanner_channel) max.extended_scanner_channel = point->extended_scanner_channel;
276 if (point->have_nir)
277 {
278 if (point->rgb[3] < min.rgb[3]) min.rgb[3] = point->rgb[3];
279 else if (point->rgb[3] > max.rgb[3]) max.rgb[3] = point->rgb[3];
280 }
281 }
282 if (point->have_wavepacket)
283 {
284 if (point->wavepacket.getIndex() < min.wavepacket.getIndex()) min.wavepacket.setIndex(point->wavepacket.getIndex());
285 else if (point->wavepacket.getIndex() > max.wavepacket.getIndex()) max.wavepacket.setIndex(point->wavepacket.getIndex());
286 if (point->wavepacket.getOffset() < min.wavepacket.getOffset()) min.wavepacket.setOffset(point->wavepacket.getOffset());
287 else if (point->wavepacket.getOffset() > max.wavepacket.getOffset()) max.wavepacket.setOffset(point->wavepacket.getOffset());
288 if (point->wavepacket.getSize() < min.wavepacket.getSize()) min.wavepacket.setSize(point->wavepacket.getSize());
289 else if (point->wavepacket.getSize() > max.wavepacket.getSize()) max.wavepacket.setSize(point->wavepacket.getSize());
290 if (point->wavepacket.getLocation() < min.wavepacket.getLocation()) min.wavepacket.setLocation(point->wavepacket.getLocation());
291 else if (point->wavepacket.getLocation() > max.wavepacket.getLocation()) max.wavepacket.setLocation(point->wavepacket.getLocation());
292 if (point->wavepacket.getXt() < min.wavepacket.getXt()) min.wavepacket.setXt(point->wavepacket.getXt());
293 else if (point->wavepacket.getXt() > max.wavepacket.getXt()) max.wavepacket.setXt(point->wavepacket.getXt());
294 if (point->wavepacket.getYt() < min.wavepacket.getYt()) min.wavepacket.setYt(point->wavepacket.getYt());
295 else if (point->wavepacket.getYt() > max.wavepacket.getYt()) max.wavepacket.setYt(point->wavepacket.getYt());
296 if (point->wavepacket.getZt() < min.wavepacket.getZt()) min.wavepacket.setZt(point->wavepacket.getZt());
297 else if (point->wavepacket.getZt() > max.wavepacket.getZt()) max.wavepacket.setZt(point->wavepacket.getZt());
298 }
299 }
300 if (((U16)(point->get_X()%10)) == xyz_low_digits_10[0])
301 {
302 xyz_fluff_10[0]++;
303 if (((U16)(point->get_X()%100)) == xyz_low_digits_100[0])
304 {
305 xyz_fluff_100[0]++;
306 if (((U16)(point->get_X()%1000)) == xyz_low_digits_1000[0])
307 {
308 xyz_fluff_1000[0]++;
309 if (((U16)(point->get_X()%10000)) == xyz_low_digits_10000[0])
310 {
311 xyz_fluff_10000[0]++;
312 }
313 }
314 }
315 }
316 if (((U16)(point->get_Y()%10)) == xyz_low_digits_10[1])
317 {
318 xyz_fluff_10[1]++;
319 if (((U16)(point->get_Y()%100)) == xyz_low_digits_100[1])
320 {
321 xyz_fluff_100[1]++;
322 if (((U16)(point->get_Y()%1000)) == xyz_low_digits_1000[1])
323 {
324 xyz_fluff_1000[1]++;
325 if (((U16)(point->get_Y()%10000)) == xyz_low_digits_10000[1])
326 {
327 xyz_fluff_10000[1]++;
328 }
329 }
330 }
331 }
332 if (((U16)(point->get_Z()%10)) == xyz_low_digits_10[2])
333 {
334 xyz_fluff_10[2]++;
335 if (((U16)(point->get_Z()%100)) == xyz_low_digits_100[2])
336 {
337 xyz_fluff_100[2]++;
338 if (((U16)(point->get_Z()%1000)) == xyz_low_digits_1000[2])
339 {
340 xyz_fluff_1000[2]++;
341 if (((U16)(point->get_Z()%10000)) == xyz_low_digits_10000[2])
342 {
343 xyz_fluff_10000[2]++;
344 }
345 }
346 }
347 }
348 return TRUE;
349 }
350
get_step() const351 F64 LASbin::get_step() const
352 {
353 return step;
354 }
355
LASbin(F64 step,F64 clamp_min,F64 clamp_max)356 LASbin::LASbin(F64 step, F64 clamp_min, F64 clamp_max)
357 {
358 total = 0;
359 count = 0;
360 this->step = step;
361 this->one_over_step = 1.0/step;
362 this->clamp_min = clamp_min;
363 this->clamp_max = clamp_max;
364 first = TRUE;
365 size_pos = 0;
366 size_neg = 0;
367 bins_pos = 0;
368 bins_neg = 0;
369 values_pos = 0;
370 values_neg = 0;
371 }
372
~LASbin()373 LASbin::~LASbin()
374 {
375 if (bins_pos) free(bins_pos);
376 if (bins_neg) free(bins_neg);
377 if (values_pos) free(values_pos);
378 if (values_neg) free(values_neg);
379 }
380
add(I32 item)381 void LASbin::add(I32 item)
382 {
383 if (item > clamp_max)
384 {
385 item = (I32)clamp_max;
386 }
387 else if (item < clamp_min)
388 {
389 item = (I32)clamp_min;
390 }
391 total += item;
392 count++;
393 I32 bin = I32_FLOOR(one_over_step*item);
394 add_to_bin(bin);
395 }
396
add(F64 item)397 void LASbin::add(F64 item)
398 {
399 if (item > clamp_max)
400 {
401 item = clamp_max;
402 }
403 else if (item < clamp_min)
404 {
405 item = clamp_min;
406 }
407 total += item;
408 count++;
409 I32 bin = I32_FLOOR(one_over_step*item);
410 add_to_bin(bin);
411 }
412
add(I64 item)413 void LASbin::add(I64 item)
414 {
415 if (item > clamp_max)
416 {
417 item = (I64)clamp_max;
418 }
419 else if (item < clamp_min)
420 {
421 item = (I64)clamp_min;
422 }
423 total += item;
424 count++;
425 I32 bin = I32_FLOOR(one_over_step*item);
426 add_to_bin(bin);
427 }
428
add_to_bin(I32 bin)429 void LASbin::add_to_bin(I32 bin)
430 {
431 if (first)
432 {
433 anker = bin;
434 first = FALSE;
435 }
436 bin = bin - anker;
437 if (bin >= 0)
438 {
439 if (bin >= size_pos)
440 {
441 I32 i;
442 if (size_pos == 0)
443 {
444 size_pos = bin + 1024;
445 bins_pos = (U32*)malloc(sizeof(U32)*size_pos);
446 if (bins_pos == 0)
447 {
448 fprintf(stderr, "ERROR: allocating %u pos bins\012", size_pos);
449 exit(1);
450 }
451 for (i = 0; i < size_pos; i++) bins_pos[i] = 0;
452 }
453 else
454 {
455 I32 new_size = bin + 1024;
456 bins_pos = (U32*)realloc(bins_pos, sizeof(U32)*new_size);
457 if (bins_pos == 0)
458 {
459 fprintf(stderr, "ERROR: reallocating %u pos bins\012", new_size);
460 exit(1);
461 }
462 for (i = size_pos; i < new_size; i++) bins_pos[i] = 0;
463 size_pos = new_size;
464 }
465 }
466 bins_pos[bin]++;
467 }
468 else
469 {
470 bin = -(bin+1);
471 if (bin >= size_neg)
472 {
473 I32 i;
474 if (size_neg == 0)
475 {
476 size_neg = bin + 1024;
477 bins_neg = (U32*)malloc(sizeof(U32)*size_neg);
478 if (bins_neg == 0)
479 {
480 fprintf(stderr, "ERROR: allocating %u neg bins\012", size_neg);
481 exit(1);
482 }
483 for (i = 0; i < size_neg; i++) bins_neg[i] = 0;
484 }
485 else
486 {
487 I32 new_size = bin + 1024;
488 bins_neg = (U32*)realloc(bins_neg, sizeof(U32)*new_size);
489 if (bins_neg == 0)
490 {
491 fprintf(stderr, "ERROR: reallocating %u neg bins\012", new_size);
492 exit(1);
493 }
494 for (i = size_neg; i < new_size; i++) bins_neg[i] = 0;
495 size_neg = new_size;
496 }
497 }
498 bins_neg[bin]++;
499 }
500 }
501
add(I32 item,I32 value)502 void LASbin::add(I32 item, I32 value)
503 {
504 total += item;
505 count++;
506 I32 bin = I32_FLOOR(one_over_step*item);
507 if (first)
508 {
509 anker = bin;
510 first = FALSE;
511 }
512 bin = bin - anker;
513 if (bin >= 0)
514 {
515 if (bin >= size_pos)
516 {
517 I32 i;
518 if (size_pos == 0)
519 {
520 size_pos = 1024;
521 bins_pos = (U32*)malloc(sizeof(U32)*size_pos);
522 values_pos = (F64*)malloc(sizeof(F64)*size_pos);
523 if (bins_pos == 0)
524 {
525 fprintf(stderr, "ERROR: allocating %u pos bins\012", size_pos);
526 exit(1);
527 }
528 if (values_pos == 0)
529 {
530 fprintf(stderr, "ERROR: allocating %u pos values\012", size_pos);
531 exit(1);
532 }
533 for (i = 0; i < size_pos; i++) { bins_pos[i] = 0; values_pos[i] = 0; }
534 }
535 else
536 {
537 I32 new_size = bin + 1024;
538 bins_pos = (U32*)realloc(bins_pos, sizeof(U32)*new_size);
539 values_pos = (F64*)realloc(values_pos, sizeof(F64)*new_size);
540 if (bins_pos == 0)
541 {
542 fprintf(stderr, "ERROR: reallocating %u pos bins\012", new_size);
543 exit(1);
544 }
545 if (values_pos == 0)
546 {
547 fprintf(stderr, "ERROR: reallocating %u pos values\012", new_size);
548 exit(1);
549 }
550 for (i = size_pos; i < new_size; i++) { bins_pos[i] = 0; values_pos[i] = 0; }
551 size_pos = new_size;
552 }
553 }
554 bins_pos[bin]++;
555 values_pos[bin] += value;
556 }
557 else
558 {
559 bin = -(bin+1);
560 if (bin >= size_neg)
561 {
562 I32 i;
563 if (size_neg == 0)
564 {
565 size_neg = 1024;
566 bins_neg = (U32*)malloc(sizeof(U32)*size_neg);
567 values_neg = (F64*)malloc(sizeof(F64)*size_neg);
568 if (bins_neg == 0)
569 {
570 fprintf(stderr, "ERROR: allocating %u neg bins\012", size_neg);
571 exit(1);
572 }
573 if (values_neg == 0)
574 {
575 fprintf(stderr, "ERROR: allocating %u neg values\012", size_neg);
576 exit(1);
577 }
578 for (i = 0; i < size_neg; i++) { bins_neg[i] = 0; values_neg[i] = 0; }
579 }
580 else
581 {
582 I32 new_size = bin + 1024;
583 bins_neg = (U32*)realloc(bins_neg, sizeof(U32)*new_size);
584 values_neg = (F64*)realloc(values_neg, sizeof(F64)*new_size);
585 if (bins_neg == 0)
586 {
587 fprintf(stderr, "ERROR: reallocating %u neg bins\012", new_size);
588 exit(1);
589 }
590 if (values_neg == 0)
591 {
592 fprintf(stderr, "ERROR: reallocating %u neg values\012", new_size);
593 exit(1);
594 }
595 for (i = size_neg; i < new_size; i++) { bins_neg[i] = 0; values_neg[i] = 0; }
596 size_neg = new_size;
597 }
598 }
599 bins_neg[bin]++;
600 values_neg[bin] += value;
601 }
602 }
603
add(F64 item,F64 value)604 void LASbin::add(F64 item, F64 value)
605 {
606 total += item;
607 count++;
608 I32 bin = I32_FLOOR(one_over_step*item);
609 if (first)
610 {
611 anker = bin;
612 first = FALSE;
613 }
614 bin = bin - anker;
615 if (bin >= 0)
616 {
617 if (bin >= size_pos)
618 {
619 I32 i;
620 if (size_pos == 0)
621 {
622 size_pos = 1024;
623 bins_pos = (U32*)malloc(sizeof(U32)*size_pos);
624 values_pos = (F64*)malloc(sizeof(F64)*size_pos);
625 if (bins_pos == 0)
626 {
627 fprintf(stderr, "ERROR: allocating %u pos bins\012", size_pos);
628 exit(1);
629 }
630 if (values_pos == 0)
631 {
632 fprintf(stderr, "ERROR: allocating %u pos values\012", size_pos);
633 exit(1);
634 }
635 for (i = 0; i < size_pos; i++) { bins_pos[i] = 0; values_pos[i] = 0; }
636 }
637 else
638 {
639 I32 new_size = bin + 1024;
640 bins_pos = (U32*)realloc(bins_pos, sizeof(U32)*new_size);
641 values_pos = (F64*)realloc(values_pos, sizeof(F64)*new_size);
642 if (bins_pos == 0)
643 {
644 fprintf(stderr, "ERROR: reallocating %u pos bins\012", new_size);
645 exit(1);
646 }
647 if (values_pos == 0)
648 {
649 fprintf(stderr, "ERROR: reallocating %u pos values\012", new_size);
650 exit(1);
651 }
652 for (i = size_pos; i < new_size; i++) { bins_pos[i] = 0; values_pos[i] = 0; }
653 size_pos = new_size;
654 }
655 }
656 bins_pos[bin]++;
657 values_pos[bin] += value;
658 }
659 else
660 {
661 bin = -(bin+1);
662 if (bin >= size_neg)
663 {
664 I32 i;
665 if (size_neg == 0)
666 {
667 size_neg = 1024;
668 bins_neg = (U32*)malloc(sizeof(U32)*size_neg);
669 values_neg = (F64*)malloc(sizeof(F64)*size_neg);
670 if (bins_neg == 0)
671 {
672 fprintf(stderr, "ERROR: allocating %u neg bins\012", size_neg);
673 exit(1);
674 }
675 if (values_neg == 0)
676 {
677 fprintf(stderr, "ERROR: allocating %u neg values\012", size_neg);
678 exit(1);
679 }
680 for (i = 0; i < size_neg; i++) { bins_neg[i] = 0; values_neg[i] = 0; }
681 }
682 else
683 {
684 I32 new_size = bin + 1024;
685 bins_neg = (U32*)realloc(bins_neg, sizeof(U32)*new_size);
686 values_neg = (F64*)realloc(values_neg, sizeof(F64)*new_size);
687 if (bins_neg == 0)
688 {
689 fprintf(stderr, "ERROR: reallocating %u neg bins\012", new_size);
690 exit(1);
691 }
692 if (values_neg == 0)
693 {
694 fprintf(stderr, "ERROR: reallocating %u neg values\012", new_size);
695 exit(1);
696 }
697 for (i = size_neg; i < new_size; i++) { bins_neg[i] = 0; values_neg[i] = 0; }
698 size_neg = new_size;
699 }
700 }
701 bins_neg[bin]++;
702 values_neg[bin] += value;
703 }
704 }
705
lidardouble2string(CHAR * string,F64 value)706 static void lidardouble2string(CHAR* string, F64 value)
707 {
708 int len;
709 len = sprintf(string, "%.15f", value) - 1;
710 while (string[len] == '0') len--;
711 if (string[len] != '.') len++;
712 string[len] = '\0';
713 }
714
lidardouble2string(CHAR * string,F64 value,F64 precision)715 static void lidardouble2string(CHAR* string, F64 value, F64 precision)
716 {
717 if (precision == 0.1 || precision == 0.2 || precision == 0.3 || precision == 0.4 || precision == 0.5)
718 sprintf(string, "%.1f", value);
719 else if (precision == 0.01 || precision == 0.02 || precision == 0.03 || precision == 0.04 || precision == 0.05 || precision == 0.25)
720 sprintf(string, "%.2f", value);
721 else if (precision == 0.001 || precision == 0.002 || precision == 0.003 || precision == 0.004 || precision == 0.005 || precision == 0.025 || precision == 0.125)
722 sprintf(string, "%.3f", value);
723 else if (precision == 0.0001 || precision == 0.0002 || precision == 0.0005 || precision == 0.0025 || precision == 0.0125)
724 sprintf(string, "%.4f", value);
725 else if (precision == 0.00001 || precision == 0.00002 || precision == 0.00005 || precision == 0.00025 || precision == 0.00125)
726 sprintf(string, "%.5f", value);
727 else if (precision == 0.000001 || precision == 0.000002 || precision == 0.000005 || precision == 0.000025 || precision == 0.000125)
728 sprintf(string, "%.6f", value);
729 else if (precision == 0.0000001)
730 sprintf(string, "%.7f", value);
731 else if (precision == 0.00000001)
732 sprintf(string, "%.8f", value);
733 else if (precision == 0.000000001)
734 sprintf(string, "%.9f", value);
735 else
736 lidardouble2string(string, value);
737 }
738
report(FILE * file,const CHAR * name,const CHAR * name_avg) const739 void LASbin::report(FILE* file, const CHAR* name, const CHAR* name_avg) const
740 {
741 I32 i, bin;
742 if (name)
743 {
744 if (values_pos)
745 {
746 if (name_avg)
747 fprintf(file, "%s histogram of %s averages with bin size %lf\012", name, name_avg, step);
748 else
749 fprintf(file, "%s histogram of averages with bin size %lf\012", name, step);
750 }
751 else
752 fprintf(file, "%s histogram with bin size %lf\012", name, step);
753 }
754 CHAR temp1[64];
755 CHAR temp2[64];
756 if (size_neg)
757 {
758 for (i = size_neg-1; i >= 0; i--)
759 {
760 if (bins_neg[i])
761 {
762 bin = -(i+1) + anker;
763 if (step == 1)
764 {
765 if (values_neg)
766 fprintf(file, " bin %d has average %g (of %d)\012", bin, values_neg[i]/bins_neg[i], bins_neg[i]);
767 else
768 fprintf(file, " bin %d has %d\012", bin, bins_neg[i]);
769 }
770 else
771 {
772 lidardouble2string(temp1, ((F64)bin)*step, step);
773 lidardouble2string(temp2, ((F64)bin+1)*step, step);
774 if (values_neg)
775 fprintf(file, " bin [%s,%s) has average %g (of %d)\012", temp1, temp2, values_neg[i]/bins_neg[i], bins_neg[i]);
776 else
777 fprintf(file, " bin [%s,%s) has %d\012", temp1, temp2, bins_neg[i]);
778 }
779 }
780 }
781 }
782 if (size_pos)
783 {
784 for (i = 0; i < size_pos; i++)
785 {
786 if (bins_pos[i])
787 {
788 bin = i + anker;
789 if (step == 1)
790 {
791 if (values_pos)
792 fprintf(file, " bin %d has average %g (of %d)\012", bin, values_pos[i]/bins_pos[i], bins_pos[i]);
793 else
794 fprintf(file, " bin %d has %d\012", bin, bins_pos[i]);
795 }
796 else
797 {
798 lidardouble2string(temp1, ((F64)bin)*step, step);
799 lidardouble2string(temp2, ((F64)bin+1)*step, step);
800 if (values_pos)
801 fprintf(file, " bin [%s,%s) average has %g (of %d)\012", temp1, temp2, values_pos[i]/bins_pos[i], bins_pos[i]);
802 else
803 fprintf(file, " bin [%s,%s) has %d\012", temp1, temp2, bins_pos[i]);
804 }
805 }
806 }
807 }
808 if (count)
809 {
810 lidardouble2string(temp1, total/count, step);
811 #ifdef _WIN32
812 if (name)
813 fprintf(file, " average %s %s for %I64d element(s)\012", name, temp1, count);
814 else
815 fprintf(file, " average %s for %I64d element(s)\012", temp1, count);
816 #else
817 if (name)
818 fprintf(file, " average %s %s for %lld element(s)\012", name, temp1, count);
819 else
820 fprintf(file, " average %s for %lld element(s)\012", temp1, count);
821 #endif
822 }
823 }
824
reset()825 void LASbin::reset()
826 {
827 first = TRUE;
828 count = 0;
829 total = 0.0;
830 if (size_pos)
831 {
832 memset(bins_pos, 0, sizeof(U32)*size_pos);
833 if (values_pos)
834 {
835 memset(values_pos, 0, sizeof(F64)*size_pos);
836 }
837 }
838 if (size_neg)
839 {
840 memset(bins_neg, 0, sizeof(U32)*size_neg);
841 if (values_neg)
842 {
843 memset(values_neg, 0, sizeof(F64)*size_neg);
844 }
845 }
846 }
847
LAShistogram()848 LAShistogram::LAShistogram()
849 {
850 is_active = FALSE;
851 // counter bins
852 x_bin = 0;
853 y_bin = 0;
854 z_bin = 0;
855 X_bin = 0;
856 Y_bin = 0;
857 Z_bin = 0;
858 intensity_bin = 0;
859 classification_bin = 0;
860 scan_angle_bin = 0;
861 extended_scan_angle_bin = 0;
862 return_number_bin = 0;
863 number_of_returns_bin = 0;
864 user_data_bin = 0;
865 point_source_id_bin = 0;
866 gps_time_bin = 0;
867 scanner_channel_bin = 0;
868 R_bin = 0;
869 G_bin = 0;
870 B_bin = 0;
871 I_bin = 0;
872 attribute0_bin = 0;
873 attribute1_bin = 0;
874 attribute2_bin = 0;
875 attribute3_bin = 0;
876 attribute4_bin = 0;
877 wavepacket_index_bin = 0;
878 wavepacket_offset_bin = 0;
879 wavepacket_size_bin = 0;
880 wavepacket_location_bin = 0;
881 // averages bins
882 classification_bin_intensity = 0;
883 classification_bin_scan_angle = 0;
884 scan_angle_bin_z = 0;
885 scan_angle_bin_intensity = 0;
886 scan_angle_bin_number_of_returns = 0;
887 return_map_bin_intensity = 0;
888 }
889
~LAShistogram()890 LAShistogram::~LAShistogram()
891 {
892 // counter bins
893 if (x_bin) delete x_bin;
894 if (y_bin) delete y_bin;
895 if (z_bin) delete z_bin;
896 if (X_bin) delete X_bin;
897 if (Y_bin) delete Y_bin;
898 if (Z_bin) delete Z_bin;
899 if (intensity_bin) delete intensity_bin;
900 if (classification_bin) delete classification_bin;
901 if (scan_angle_bin) delete scan_angle_bin;
902 if (extended_scan_angle_bin) delete extended_scan_angle_bin;
903 if (return_number_bin) delete return_number_bin;
904 if (number_of_returns_bin) delete number_of_returns_bin;
905 if (user_data_bin) delete user_data_bin;
906 if (point_source_id_bin) delete point_source_id_bin;
907 if (gps_time_bin) delete gps_time_bin;
908 if (scanner_channel_bin) delete scanner_channel_bin;
909 if (R_bin) delete R_bin;
910 if (G_bin) delete G_bin;
911 if (B_bin) delete B_bin;
912 if (I_bin) delete I_bin;
913 if (attribute0_bin) delete attribute0_bin;
914 if (attribute1_bin) delete attribute1_bin;
915 if (attribute2_bin) delete attribute2_bin;
916 if (attribute3_bin) delete attribute3_bin;
917 if (attribute4_bin) delete attribute4_bin;
918 if (wavepacket_index_bin) delete wavepacket_index_bin;
919 if (wavepacket_offset_bin) delete wavepacket_offset_bin;
920 if (wavepacket_size_bin) delete wavepacket_size_bin;
921 if (wavepacket_location_bin) delete wavepacket_location_bin;
922 // averages bins
923 if (classification_bin_intensity) delete classification_bin_intensity;
924 if (classification_bin_scan_angle) delete classification_bin_scan_angle;
925 if (scan_angle_bin_z) delete scan_angle_bin_z;
926 if (scan_angle_bin_intensity) delete scan_angle_bin_intensity;
927 if (scan_angle_bin_number_of_returns) delete scan_angle_bin_number_of_returns;
928 if (return_map_bin_intensity) delete return_map_bin_intensity;
929 }
930
parse(int argc,char * argv[])931 BOOL LAShistogram::parse(int argc, char* argv[])
932 {
933 int i;
934 for (i = 1; i < argc; i++)
935 {
936 if (argv[i][0] == '\0')
937 {
938 continue;
939 }
940 else if (strcmp(argv[i],"-h") == 0 || strcmp(argv[i],"-help") == 0)
941 {
942 return TRUE;
943 }
944 else if (strcmp(argv[i],"-histo") == 0)
945 {
946 if ((i+2) >= argc)
947 {
948 fprintf(stderr,"ERROR: '%s' needs 2 arguments: name step\n", argv[i]);
949 return FALSE;
950 }
951 F64 step = 0.0;
952 if (sscanf(argv[i+2], "%lf", &step) != 1)
953 {
954 fprintf(stderr,"ERROR: '%s' needs 2 arguments: name step but '%s' is no valid step\n", argv[i], argv[i+2]);
955 return FALSE;
956 }
957 if (!histo(argv[i+1], step)) return FALSE;
958 *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; i+=2;
959 }
960 else if (strcmp(argv[i],"-histo_avg") == 0)
961 {
962 if ((i+3) >= argc)
963 {
964 fprintf(stderr,"ERROR: '%s' needs 3 arguments: name step name_avg\n", argv[i]);
965 return FALSE;
966 }
967 F64 step = 0.0;
968 if (sscanf(argv[i+2], "%lf", &step) != 1)
969 {
970 fprintf(stderr,"ERROR: '%s' needs 3 arguments: name step name_avg but '%s' is no valid step\n", argv[i], argv[i+2]);
971 return FALSE;
972 }
973 if (!histo_avg(argv[i+1], step, argv[i+3])) return FALSE;
974 *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3;
975 }
976 }
977 return TRUE;
978 }
979
unparse(CHAR * string) const980 I32 LAShistogram::unparse(CHAR* string) const
981 {
982 I32 n = 0;
983 if (x_bin) n += sprintf(&string[n], "-histo x %lf ", x_bin->get_step());
984 if (y_bin) n += sprintf(&string[n], "-histo y %lf ", y_bin->get_step());
985 if (z_bin) n += sprintf(&string[n], "-histo z %lf ", z_bin->get_step());
986 if (X_bin) n += sprintf(&string[n], "-histo X %lf ", X_bin->get_step());
987 if (Y_bin) n += sprintf(&string[n], "-histo Y %lf ", Y_bin->get_step());
988 if (Z_bin) n += sprintf(&string[n], "-histo Z %lf ", Z_bin->get_step());
989 if (intensity_bin) n += sprintf(&string[n], "-histo intensity %lf ", intensity_bin->get_step());
990 if (classification_bin) n += sprintf(&string[n], "-histo classification %lf ", classification_bin->get_step());
991 if (scan_angle_bin) n += sprintf(&string[n], "-histo scan_angle %lf ", scan_angle_bin->get_step());
992 if (extended_scan_angle_bin) n += sprintf(&string[n], "-histo extended_scan_angle %lf ", extended_scan_angle_bin->get_step());
993 if (return_number_bin) n += sprintf(&string[n], "-histo return_number %lf ", return_number_bin->get_step());
994 if (number_of_returns_bin) n += sprintf(&string[n], "-histo number_of_returns %lf ", number_of_returns_bin->get_step());
995 if (user_data_bin) n += sprintf(&string[n], "-histo user_data %lf ", user_data_bin->get_step());
996 if (point_source_id_bin) n += sprintf(&string[n], "-histo point_source %lf ", point_source_id_bin->get_step());
997 if (gps_time_bin) n += sprintf(&string[n], "-histo gps_time %lf ", gps_time_bin->get_step());
998 if (scanner_channel_bin) n += sprintf(&string[n], "-histo scanner_channel %lf ", scanner_channel_bin->get_step());
999 if (R_bin) n += sprintf(&string[n], "-histo R %lf ", R_bin->get_step());
1000 if (G_bin) n += sprintf(&string[n], "-histo G %lf ", G_bin->get_step());
1001 if (B_bin) n += sprintf(&string[n], "-histo B %lf ", B_bin->get_step());
1002 if (I_bin) n += sprintf(&string[n], "-histo I %lf ", I_bin->get_step());
1003 if (attribute0_bin) n += sprintf(&string[n], "-histo 0 %lf ", attribute0_bin->get_step());
1004 if (attribute1_bin) n += sprintf(&string[n], "-histo 1 %lf ", attribute1_bin->get_step());
1005 if (attribute2_bin) n += sprintf(&string[n], "-histo 2 %lf ", attribute2_bin->get_step());
1006 if (attribute3_bin) n += sprintf(&string[n], "-histo 3 %lf ", attribute3_bin->get_step());
1007 if (attribute4_bin) n += sprintf(&string[n], "-histo 4 %lf ", attribute4_bin->get_step());
1008 if (wavepacket_index_bin) n += sprintf(&string[n], "-histo wavepacket_index %lf ", wavepacket_index_bin->get_step());
1009 if (wavepacket_offset_bin) n += sprintf(&string[n], "-histo wavepacket_offset %lf ", wavepacket_offset_bin->get_step());
1010 if (wavepacket_size_bin) n += sprintf(&string[n], "-histo wavepacket_size %lf ", wavepacket_size_bin->get_step());
1011 if (wavepacket_location_bin) n += sprintf(&string[n], "-histo wavepacket_location %lf ", wavepacket_location_bin->get_step());
1012 return n;
1013 }
1014
histo(const CHAR * name,F64 step)1015 BOOL LAShistogram::histo(const CHAR* name, F64 step)
1016 {
1017 if (strcmp(name, "x") == 0)
1018 x_bin = new LASbin(step);
1019 else if (strcmp(name, "y") == 0)
1020 y_bin = new LASbin(step);
1021 else if (strcmp(name, "z") == 0)
1022 z_bin = new LASbin(step);
1023 else if (strcmp(name, "X") == 0)
1024 X_bin = new LASbin(step);
1025 else if (strcmp(name, "Y") == 0)
1026 Y_bin = new LASbin(step);
1027 else if (strcmp(name, "Z") == 0)
1028 Z_bin = new LASbin(step);
1029 else if (strcmp(name, "intensity") == 0)
1030 intensity_bin = new LASbin(step);
1031 else if (strcmp(name, "classification") == 0)
1032 classification_bin = new LASbin(step);
1033 else if (strstr(name, "extended_scan_angle") != 0)
1034 extended_scan_angle_bin = new LASbin(step);
1035 else if (strstr(name, "scan_angle") != 0)
1036 scan_angle_bin = new LASbin(step);
1037 else if (strstr(name, "return_number") != 0)
1038 return_number_bin = new LASbin(step);
1039 else if (strstr(name, "number_of_returns") != 0)
1040 number_of_returns_bin = new LASbin(step);
1041 else if (strstr(name, "user_data") != 0)
1042 user_data_bin = new LASbin(step);
1043 else if (strstr(name, "point_source") != 0)
1044 point_source_id_bin = new LASbin(step);
1045 else if (strstr(name, "gps_time") != 0)
1046 gps_time_bin = new LASbin(step);
1047 else if (strstr(name, "scanner_channel") != 0)
1048 scanner_channel_bin = new LASbin(step);
1049 else if (strcmp(name, "R") == 0)
1050 R_bin = new LASbin(step);
1051 else if (strcmp(name, "G") == 0)
1052 G_bin = new LASbin(step);
1053 else if (strcmp(name, "B") == 0)
1054 B_bin = new LASbin(step);
1055 else if (strcmp(name, "I") == 0)
1056 I_bin = new LASbin(step);
1057 else if (strcmp(name, "0") == 0 || strcmp(name, "attribute0") == 0)
1058 attribute0_bin = new LASbin(step);
1059 else if (strcmp(name, "1") == 0 || strcmp(name, "attribute1") == 0)
1060 attribute1_bin = new LASbin(step);
1061 else if (strcmp(name, "2") == 0 || strcmp(name, "attribute2") == 0)
1062 attribute2_bin = new LASbin(step);
1063 else if (strcmp(name, "3") == 0 || strcmp(name, "attribute3") == 0)
1064 attribute3_bin = new LASbin(step);
1065 else if (strcmp(name, "4") == 0 || strcmp(name, "attribute4") == 0)
1066 attribute4_bin = new LASbin(step);
1067 else if (strstr(name, "wavepacket_index") != 0)
1068 wavepacket_index_bin = new LASbin(step);
1069 else if (strstr(name, "wavepacket_offset") != 0)
1070 wavepacket_offset_bin = new LASbin(step);
1071 else if (strstr(name, "wavepacket_size") != 0)
1072 wavepacket_size_bin = new LASbin(step);
1073 else if (strstr(name, "wavepacket_location") != 0)
1074 wavepacket_location_bin = new LASbin(step);
1075 else
1076 {
1077 fprintf(stderr,"ERROR: histogram of '%s' not implemented\n", name);
1078 return FALSE;
1079 }
1080 is_active = TRUE;
1081 return TRUE;
1082 }
1083
histo_avg(const CHAR * name,F64 step,const CHAR * name_avg)1084 BOOL LAShistogram::histo_avg(const CHAR* name, F64 step, const CHAR* name_avg)
1085 {
1086 if (strcmp(name, "classification") == 0)
1087 {
1088 if (strcmp(name_avg, "intensity") == 0)
1089 classification_bin_intensity = new LASbin(step);
1090 else if (strstr(name_avg, "scan_angle") != 0)
1091 classification_bin_scan_angle = new LASbin(step);
1092 else
1093 {
1094 fprintf(stderr,"ERROR: histogram of '%s' with '%s' averages not implemented\n", name, name_avg);
1095 return FALSE;
1096 }
1097 }
1098 else if (strcmp(name, "scan_angle") == 0)
1099 {
1100 if (strcmp(name_avg, "z") == 0)
1101 scan_angle_bin_z = new LASbin(step);
1102 else if (strcmp(name_avg, "number_of_returns") == 0)
1103 scan_angle_bin_number_of_returns = new LASbin(step);
1104 else if (strcmp(name_avg, "intensity") == 0)
1105 scan_angle_bin_intensity = new LASbin(step);
1106 else
1107 {
1108 fprintf(stderr,"ERROR: histogram of '%s' with '%s' averages not implemented\n", name, name_avg);
1109 return FALSE;
1110 }
1111 }
1112 else if (strcmp(name, "return_map") == 0)
1113 {
1114 if (strcmp(name_avg, "intensity") == 0)
1115 return_map_bin_intensity = new LASbin(1);
1116 else
1117 {
1118 fprintf(stderr,"ERROR: histogram of '%s' with '%s' averages not implemented\n", name, name_avg);
1119 return FALSE;
1120 }
1121 }
1122 else
1123 {
1124 fprintf(stderr,"ERROR: histogram of '%s' not implemented\n", name);
1125 return FALSE;
1126 }
1127 is_active = TRUE;
1128 return TRUE;
1129 }
1130
add(const LASpoint * point)1131 void LAShistogram::add(const LASpoint* point)
1132 {
1133 // counter bins
1134 if (x_bin) x_bin->add(point->get_x());
1135 if (y_bin) y_bin->add(point->get_y());
1136 if (z_bin) z_bin->add(point->get_z());
1137 if (X_bin) X_bin->add(point->get_X());
1138 if (Y_bin) Y_bin->add(point->get_Y());
1139 if (Z_bin) Z_bin->add(point->get_Z());
1140 if (intensity_bin) intensity_bin->add(point->get_intensity());
1141 if (classification_bin) classification_bin->add(point->get_classification());
1142 if (scan_angle_bin)
1143 {
1144 scan_angle_bin->add(point->get_scan_angle());
1145 }
1146 if (extended_scan_angle_bin)
1147 {
1148 extended_scan_angle_bin->add(point->extended_scan_angle);
1149 }
1150 if (return_number_bin) return_number_bin->add(point->get_return_number());
1151 if (number_of_returns_bin) number_of_returns_bin->add(point->get_number_of_returns());
1152 if (user_data_bin) user_data_bin->add(point->get_user_data());
1153 if (point_source_id_bin) point_source_id_bin->add(point->get_point_source_ID());
1154 if (gps_time_bin) gps_time_bin->add(point->get_gps_time());
1155 if (scanner_channel_bin) scanner_channel_bin->add(point->get_extended_scanner_channel());
1156 if (R_bin) R_bin->add(point->rgb[0]);
1157 if (G_bin) G_bin->add(point->rgb[1]);
1158 if (B_bin) B_bin->add(point->rgb[2]);
1159 if (I_bin) I_bin->add(point->rgb[3]);
1160 if (attribute0_bin) attribute0_bin->add(point->get_attribute_as_float(0));
1161 if (attribute1_bin) attribute1_bin->add(point->get_attribute_as_float(1));
1162 if (attribute2_bin) attribute2_bin->add(point->get_attribute_as_float(2));
1163 if (attribute3_bin) attribute3_bin->add(point->get_attribute_as_float(3));
1164 if (attribute4_bin) attribute4_bin->add(point->get_attribute_as_float(4));
1165 if (wavepacket_index_bin) wavepacket_index_bin->add(point->wavepacket.getIndex());
1166 if (wavepacket_offset_bin) wavepacket_offset_bin->add((I64)point->wavepacket.getOffset());
1167 if (wavepacket_size_bin) wavepacket_size_bin->add((I32)point->wavepacket.getSize());
1168 if (wavepacket_location_bin) wavepacket_location_bin->add(point->wavepacket.getLocation());
1169 // averages bins
1170 if (classification_bin_intensity) classification_bin_intensity->add(point->get_classification(), point->get_intensity());
1171 if (classification_bin_scan_angle)
1172 {
1173 classification_bin_scan_angle->add((F64)point->get_classification(), (F64)point->get_scan_angle());
1174 }
1175 if (scan_angle_bin_z)
1176 {
1177 scan_angle_bin_z->add((F64)point->get_scan_angle(), (F64)point->get_Z());
1178 }
1179 if (scan_angle_bin_number_of_returns)
1180 {
1181 scan_angle_bin_number_of_returns->add((F64)point->get_scan_angle(), (F64)point->get_extended_number_of_returns());
1182 }
1183 if (scan_angle_bin_intensity)
1184 {
1185 scan_angle_bin_intensity->add((F64)point->get_scan_angle(), (F64)point->get_intensity());
1186 }
1187 if (return_map_bin_intensity)
1188 {
1189 int n = point->number_of_returns;
1190 int r = point->return_number;
1191 return_map_bin_intensity->add((n == 1 ? 0 : (n == 2 ? r : (n == 3 ? r+2 : (n == 4 ? r+5 : (n == 5 ? r+9 : 15))))), point->intensity);
1192 }
1193 }
1194
report(FILE * file) const1195 void LAShistogram::report(FILE* file) const
1196 {
1197 // counter bins
1198 if (x_bin) x_bin->report(file, "x coordinate");
1199 if (y_bin) y_bin->report(file, "y coordinate");
1200 if (z_bin) z_bin->report(file, "z coordinate");
1201 if (X_bin) X_bin->report(file, "raw integer X coordinate");
1202 if (Y_bin) Y_bin->report(file, "raw integer Y coordinate");
1203 if (Z_bin) Z_bin->report(file, "raw integer Z coordinate");
1204 if (intensity_bin) intensity_bin->report(file, "intensity");
1205 if (classification_bin) classification_bin->report(file, "classification");
1206 if (scan_angle_bin) scan_angle_bin->report(file, "scan angle");
1207 if (extended_scan_angle_bin) extended_scan_angle_bin->report(file, "extended scan angle");
1208 if (return_number_bin) return_number_bin->report(file, "return_number");
1209 if (number_of_returns_bin) number_of_returns_bin->report(file, "number_of_returns");
1210 if (user_data_bin) user_data_bin->report(file, "user data");
1211 if (point_source_id_bin) point_source_id_bin->report(file, "point source id");
1212 if (gps_time_bin) gps_time_bin->report(file, "gps_time");
1213 if (scanner_channel_bin) scanner_channel_bin->report(file, "scanner channel");
1214 if (R_bin) R_bin->report(file, "color R channel");
1215 if (G_bin) G_bin->report(file, "color G channel");
1216 if (B_bin) B_bin->report(file, "color B channel");
1217 if (I_bin) I_bin->report(file, "color I channel");
1218 if (attribute0_bin) attribute0_bin->report(file, "attribute 0");
1219 if (attribute1_bin) attribute1_bin->report(file, "attribute 1");
1220 if (attribute2_bin) attribute2_bin->report(file, "attribute 2");
1221 if (attribute3_bin) attribute3_bin->report(file, "attribute 3");
1222 if (attribute4_bin) attribute4_bin->report(file, "attribute 4");
1223 if (wavepacket_index_bin) wavepacket_index_bin->report(file, "wavepacket_index");
1224 if (wavepacket_offset_bin) wavepacket_offset_bin->report(file, "wavepacket_offset");
1225 if (wavepacket_size_bin) wavepacket_size_bin->report(file, "wavepacket_size");
1226 if (wavepacket_location_bin) wavepacket_location_bin->report(file, "wavepacket_location");
1227 // averages bins
1228 if (classification_bin_intensity) classification_bin_intensity->report(file, "classification", "intensity");
1229 if (classification_bin_scan_angle) classification_bin_scan_angle->report(file, "classification", "scan_angle");
1230 if (scan_angle_bin_z) scan_angle_bin_z->report(file, "scan angle", "z coordinate");
1231 if (scan_angle_bin_number_of_returns) scan_angle_bin_number_of_returns->report(file, "scan_angle", "number_of_returns");
1232 if (scan_angle_bin_intensity) scan_angle_bin_intensity->report(file, "scan angle", "intensity");
1233 if (return_map_bin_intensity) return_map_bin_intensity->report(file, "return map", "intensity");
1234 }
1235
reset()1236 void LAShistogram::reset()
1237 {
1238 // reset counter bins
1239 if (x_bin) x_bin->reset();
1240 if (y_bin) y_bin->reset();
1241 if (z_bin) z_bin->reset();
1242 if (X_bin) X_bin->reset();
1243 if (Y_bin) Y_bin->reset();
1244 if (Z_bin) Z_bin->reset();
1245 if (intensity_bin) intensity_bin->reset();
1246 if (classification_bin) classification_bin->reset();
1247 if (scan_angle_bin) scan_angle_bin->reset();
1248 if (extended_scan_angle_bin) extended_scan_angle_bin->reset();
1249 if (return_number_bin) return_number_bin->reset();
1250 if (number_of_returns_bin) number_of_returns_bin->reset();
1251 if (user_data_bin) user_data_bin->reset();
1252 if (point_source_id_bin) point_source_id_bin->reset();
1253 if (gps_time_bin) gps_time_bin->reset();
1254 if (scanner_channel_bin) scanner_channel_bin->reset();
1255 if (R_bin) R_bin->reset();
1256 if (G_bin) G_bin->reset();
1257 if (B_bin) B_bin->reset();
1258 if (I_bin) I_bin->reset();
1259 if (attribute0_bin) attribute0_bin->reset();
1260 if (attribute1_bin) attribute1_bin->reset();
1261 if (attribute2_bin) attribute2_bin->reset();
1262 if (attribute3_bin) attribute3_bin->reset();
1263 if (attribute4_bin) attribute4_bin->reset();
1264 if (wavepacket_index_bin) wavepacket_index_bin->reset();
1265 if (wavepacket_offset_bin) wavepacket_offset_bin->reset();
1266 if (wavepacket_size_bin) wavepacket_size_bin->reset();
1267 if (wavepacket_location_bin) wavepacket_location_bin->reset();
1268 // averages bins
1269 if (classification_bin_intensity) classification_bin_intensity->reset();
1270 if (classification_bin_scan_angle) classification_bin_scan_angle->reset();
1271 if (scan_angle_bin_z) scan_angle_bin_z->reset();
1272 if (scan_angle_bin_intensity) scan_angle_bin_intensity->reset();
1273 if (scan_angle_bin_number_of_returns) scan_angle_bin_number_of_returns->reset();
1274 if (return_map_bin_intensity) return_map_bin_intensity->reset();
1275 }
1276
add(const LASpoint * point)1277 BOOL LASoccupancyGrid::add(const LASpoint* point)
1278 {
1279 I32 pos_x, pos_y;
1280 if (grid_spacing < 0)
1281 {
1282 grid_spacing = -grid_spacing;
1283 pos_x = I32_FLOOR(point->get_x() / grid_spacing);
1284 pos_y = I32_FLOOR(point->get_y() / grid_spacing);
1285 anker = pos_y;
1286 min_x = max_x = pos_x;
1287 min_y = max_y = pos_y;
1288 }
1289 else
1290 {
1291 pos_x = I32_FLOOR(point->get_x() / grid_spacing);
1292 pos_y = I32_FLOOR(point->get_y() / grid_spacing);
1293 if (pos_x < min_x) min_x = pos_x; else if (pos_x > max_x) max_x = pos_x;
1294 if (pos_y < min_y) min_y = pos_y; else if (pos_y > max_y) max_y = pos_y;
1295 }
1296 return add_internal(pos_x, pos_y);
1297 }
1298
add(I32 pos_x,I32 pos_y)1299 BOOL LASoccupancyGrid::add(I32 pos_x, I32 pos_y)
1300 {
1301 if (grid_spacing < 0)
1302 {
1303 grid_spacing = -grid_spacing;
1304 anker = pos_y;
1305 min_x = max_x = pos_x;
1306 min_y = max_y = pos_y;
1307 }
1308 else
1309 {
1310 if (pos_x < min_x) min_x = pos_x; else if (pos_x > max_x) max_x = pos_x;
1311 if (pos_y < min_y) min_y = pos_y; else if (pos_y > max_y) max_y = pos_y;
1312 }
1313 return add_internal(pos_x, pos_y);
1314 }
1315
add_internal(I32 pos_x,I32 pos_y)1316 BOOL LASoccupancyGrid::add_internal(I32 pos_x, I32 pos_y)
1317 {
1318 pos_y = pos_y - anker;
1319 BOOL no_x_anker = FALSE;
1320 U32* array_size;
1321 I32** ankers;
1322 U32*** array;
1323 U16** array_sizes;
1324 if (pos_y < 0)
1325 {
1326 pos_y = -pos_y - 1;
1327 ankers = &minus_ankers;
1328 if ((U32)pos_y < minus_plus_size && minus_plus_sizes[pos_y])
1329 {
1330 pos_x -= minus_ankers[pos_y];
1331 if (pos_x < 0)
1332 {
1333 pos_x = -pos_x - 1;
1334 array_size = &minus_minus_size;
1335 array = &minus_minus;
1336 array_sizes = &minus_minus_sizes;
1337 }
1338 else
1339 {
1340 array_size = &minus_plus_size;
1341 array = &minus_plus;
1342 array_sizes = &minus_plus_sizes;
1343 }
1344 }
1345 else
1346 {
1347 no_x_anker = TRUE;
1348 array_size = &minus_plus_size;
1349 array = &minus_plus;
1350 array_sizes = &minus_plus_sizes;
1351 }
1352 }
1353 else
1354 {
1355 ankers = &plus_ankers;
1356 if ((U32)pos_y < plus_plus_size && plus_plus_sizes[pos_y])
1357 {
1358 pos_x -= plus_ankers[pos_y];
1359 if (pos_x < 0)
1360 {
1361 pos_x = -pos_x - 1;
1362 array_size = &plus_minus_size;
1363 array = &plus_minus;
1364 array_sizes = &plus_minus_sizes;
1365 }
1366 else
1367 {
1368 array_size = &plus_plus_size;
1369 array = &plus_plus;
1370 array_sizes = &plus_plus_sizes;
1371 }
1372 }
1373 else
1374 {
1375 no_x_anker = TRUE;
1376 array_size = &plus_plus_size;
1377 array = &plus_plus;
1378 array_sizes = &plus_plus_sizes;
1379 }
1380 }
1381 // maybe grow banded grid in y direction
1382 if ((U32)pos_y >= *array_size)
1383 {
1384 U32 array_size_new = ((pos_y/1024)+1)*1024;
1385 if (*array_size)
1386 {
1387 if (array == &minus_plus || array == &plus_plus) *ankers = (I32*)realloc(*ankers, array_size_new*sizeof(I32));
1388 *array = (U32**)realloc(*array, array_size_new*sizeof(U32*));
1389 *array_sizes = (U16*)realloc(*array_sizes, array_size_new*sizeof(U16));
1390 }
1391 else
1392 {
1393 if (array == &minus_plus || array == &plus_plus) *ankers = (I32*)malloc(array_size_new*sizeof(I32));
1394 *array = (U32**)malloc(array_size_new*sizeof(U32*));
1395 *array_sizes = (U16*)malloc(array_size_new*sizeof(U16));
1396 }
1397 for (U32 i = *array_size; i < array_size_new; i++)
1398 {
1399 (*array)[i] = 0;
1400 (*array_sizes)[i] = 0;
1401 }
1402 *array_size = array_size_new;
1403 }
1404 // is this the first x anker for this y pos?
1405 if (no_x_anker)
1406 {
1407 (*ankers)[pos_y] = pos_x;
1408 pos_x = 0;
1409 }
1410 // maybe grow banded grid in x direction
1411 U32 pos_x_pos = pos_x/32;
1412 if (pos_x_pos >= (*array_sizes)[pos_y])
1413 {
1414 U32 array_sizes_new = ((pos_x_pos/256)+1)*256;
1415 if ((*array_sizes)[pos_y])
1416 {
1417 (*array)[pos_y] = (U32*)realloc((*array)[pos_y], array_sizes_new*sizeof(U32));
1418 }
1419 else
1420 {
1421 (*array)[pos_y] = (U32*)malloc(array_sizes_new*sizeof(U32));
1422 }
1423 for (U16 i = (*array_sizes)[pos_y]; i < array_sizes_new; i++)
1424 {
1425 (*array)[pos_y][i] = 0;
1426 }
1427 (*array_sizes)[pos_y] = array_sizes_new;
1428 }
1429 U32 pos_x_bit = 1 << (pos_x%32);
1430 if ((*array)[pos_y][pos_x_pos] & pos_x_bit) return FALSE;
1431 (*array)[pos_y][pos_x_pos] |= pos_x_bit;
1432 num_occupied++;
1433 return TRUE;
1434 }
1435
occupied(const LASpoint * point) const1436 BOOL LASoccupancyGrid::occupied(const LASpoint* point) const
1437 {
1438 I32 pos_x = I32_FLOOR(point->get_x() / grid_spacing);
1439 I32 pos_y = I32_FLOOR(point->get_y() / grid_spacing);
1440 return occupied(pos_x, pos_y);
1441 }
1442
occupied(I32 pos_x,I32 pos_y) const1443 BOOL LASoccupancyGrid::occupied(I32 pos_x, I32 pos_y) const
1444 {
1445 if (grid_spacing < 0)
1446 {
1447 return FALSE;
1448 }
1449 pos_y = pos_y - anker;
1450 U32 array_size;
1451 const U32* const * array;
1452 const U16* array_sizes;
1453 if (pos_y < 0)
1454 {
1455 pos_y = -pos_y - 1;
1456 if ((U32)pos_y < minus_plus_size && minus_plus_sizes[pos_y])
1457 {
1458 pos_x -= minus_ankers[pos_y];
1459 if (pos_x < 0)
1460 {
1461 pos_x = -pos_x - 1;
1462 array_size = minus_minus_size;
1463 array = minus_minus;
1464 array_sizes = minus_minus_sizes;
1465 }
1466 else
1467 {
1468 array_size = minus_plus_size;
1469 array = minus_plus;
1470 array_sizes = minus_plus_sizes;
1471 }
1472 }
1473 else
1474 {
1475 return FALSE;
1476 }
1477 }
1478 else
1479 {
1480 if ((U32)pos_y < plus_plus_size && plus_plus_sizes[pos_y])
1481 {
1482 pos_x -= plus_ankers[pos_y];
1483 if (pos_x < 0)
1484 {
1485 pos_x = -pos_x - 1;
1486 array_size = plus_minus_size;
1487 array = plus_minus;
1488 array_sizes = plus_minus_sizes;
1489 }
1490 else
1491 {
1492 array_size = plus_plus_size;
1493 array = plus_plus;
1494 array_sizes = plus_plus_sizes;
1495 }
1496 }
1497 else
1498 {
1499 return FALSE;
1500 }
1501 }
1502 // maybe out of bounds in y direction
1503 if ((U32)pos_y >= array_size)
1504 {
1505 return FALSE;
1506 }
1507 // maybe out of bounds in x direction
1508 U32 pos_x_pos = pos_x/32;
1509 if (pos_x_pos >= array_sizes[pos_y])
1510 {
1511 return FALSE;
1512 }
1513 U32 pos_x_bit = 1 << (pos_x%32);
1514 if (array[pos_y][pos_x_pos] & pos_x_bit) return TRUE;
1515 return FALSE;
1516 }
1517
active() const1518 BOOL LASoccupancyGrid::active() const
1519 {
1520 if (grid_spacing < 0) return FALSE;
1521 return TRUE;
1522 }
1523
reset()1524 void LASoccupancyGrid::reset()
1525 {
1526 min_x = min_y = max_x = max_y = 0;
1527 if (grid_spacing > 0) grid_spacing = -grid_spacing;
1528 if (minus_minus_size)
1529 {
1530 for (U32 i = 0; i < minus_minus_size; i++) if (minus_minus[i]) free(minus_minus[i]);
1531 free(minus_minus);
1532 minus_minus = 0;
1533 free(minus_minus_sizes);
1534 minus_minus_sizes = 0;
1535 minus_minus_size = 0;
1536 }
1537 if (minus_plus_size)
1538 {
1539 free(minus_ankers);
1540 minus_ankers = 0;
1541 for (U32 i = 0; i < minus_plus_size; i++) if (minus_plus[i]) free(minus_plus[i]);
1542 free(minus_plus);
1543 minus_plus = 0;
1544 free(minus_plus_sizes);
1545 minus_plus_sizes = 0;
1546 minus_plus_size = 0;
1547 }
1548 if (plus_minus_size)
1549 {
1550 for (U32 i = 0; i < plus_minus_size; i++) if (plus_minus[i]) free(plus_minus[i]);
1551 free(plus_minus);
1552 plus_minus = 0;
1553 free(plus_minus_sizes);
1554 plus_minus_sizes = 0;
1555 plus_minus_size = 0;
1556 }
1557 if (plus_plus_size)
1558 {
1559 free(plus_ankers);
1560 plus_ankers = 0;
1561 for (U32 i = 0; i < plus_plus_size; i++) if (plus_plus[i]) free(plus_plus[i]);
1562 free(plus_plus);
1563 plus_plus = 0;
1564 free(plus_plus_sizes);
1565 plus_plus_sizes = 0;
1566 plus_plus_size = 0;
1567 }
1568 num_occupied = 0;
1569 }
1570
write_asc_grid(const CHAR * file_name) const1571 BOOL LASoccupancyGrid::write_asc_grid(const CHAR* file_name) const
1572 {
1573 FILE* file = fopen(file_name, "w");
1574 if (file == 0) return FALSE;
1575 fprintf(file, "ncols %d\012", max_x-min_x+1);
1576 fprintf(file, "nrows %d\012", max_y-min_y+1);
1577 fprintf(file, "xllcorner %f\012", grid_spacing*min_x);
1578 fprintf(file, "yllcorner %f\012", grid_spacing*min_y);
1579 fprintf(file, "cellsize %lf\012", grid_spacing);
1580 fprintf(file, "NODATA_value %d\012", 0);
1581 fprintf(file, "\012");
1582 I32 pos_x, pos_y;
1583 for (pos_y = min_y; pos_y <= max_y; pos_y++)
1584 {
1585 for (pos_x = min_x; pos_x <= max_x; pos_x++)
1586 {
1587 if (occupied(pos_x, pos_y))
1588 {
1589 fprintf(file, "1 ");
1590 }
1591 else
1592 {
1593 fprintf(file, "0 ");
1594 }
1595 }
1596 fprintf(file, "\012");
1597 }
1598 fclose(file);
1599 return TRUE;
1600 }
1601
LASoccupancyGrid(F32 grid_spacing)1602 LASoccupancyGrid::LASoccupancyGrid(F32 grid_spacing)
1603 {
1604 min_x = min_y = max_x = max_y = 0;
1605 this->grid_spacing = -grid_spacing;
1606 minus_ankers = 0;
1607 minus_minus_size = 0;
1608 minus_minus = 0;
1609 minus_minus_sizes = 0;
1610 minus_plus_size = 0;
1611 minus_plus = 0;
1612 minus_plus_sizes = 0;
1613 plus_ankers = 0;
1614 plus_minus_size = 0;
1615 plus_minus = 0;
1616 plus_minus_sizes = 0;
1617 plus_plus_size = 0;
1618 plus_plus = 0;
1619 plus_plus_sizes = 0;
1620 num_occupied = 0;
1621 }
1622
~LASoccupancyGrid()1623 LASoccupancyGrid::~LASoccupancyGrid()
1624 {
1625 reset();
1626 }
1627
1628