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