1 /*
2 ===============================================================================
3 
4   FILE:  laspoint.hpp
5 
6   CONTENTS:
7 
8     This class describes an LAS point and offers helper functions to access,
9     convert, and set the default (and any additional) point attributes.
10 
11   PROGRAMMERS:
12 
13     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
14 
15   COPYRIGHT:
16 
17     (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality
18 
19     This is free software; you can redistribute and/or modify it under the
20     terms of the GNU Lesser General Licence as published by the Free Software
21     Foundation. See the LICENSE.txt file for more information.
22 
23     This software is distributed WITHOUT ANY WARRANTY and without even the
24     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 
26   CHANGE HISTORY:
27 
28     10 May 2019 -- checking for overflows in X, Y, Z of I32 of fixed-point LAS
29     15 June 2018 -- fix in flag copy from legacy (0-5) to extended (6-10) type
30     10 March 2017 -- fix in copy_to() and copy_from() new LAS 1.4 point types
31     10 October 2016 -- small fixes for NIR and extended scanner channel
32     19 July 2015 -- created after FOSS4GE in the train back from Lake Como
33 
34 ===============================================================================
35 */
36 #ifndef LAS_POINT_HPP
37 #define LAS_POINT_HPP
38 
39 #include "lasquantizer.hpp"
40 #include "lasattributer.hpp"
41 
42 class LASwavepacket
43 {
44 public:
LASwavepacket()45   LASwavepacket() {zero();};
zero()46   void zero() {memset(data, 0, 29);};
getIndex() const47   inline U8 getIndex() const {return data[0];};
getOffset() const48   inline U64 getOffset() const {return ((U64*)&(data[1]))[0];};
getSize() const49   inline U32 getSize() const {return ((U32*)&(data[9]))[0];};
getLocation() const50   inline F32 getLocation() const {return ((F32*)&(data[13]))[0];};
getXt() const51   inline F32 getXt() const {return ((F32*)&(data[17]))[0];};
getYt() const52   inline F32 getYt() const {return ((F32*)&(data[21]))[0];};
getZt() const53   inline F32 getZt() const {return ((F32*)&(data[25]))[0];};
setIndex(U8 index)54   inline void setIndex(U8 index) {data[0] = index;};
setOffset(U64 offset)55   inline void setOffset(U64 offset) {((U64*)&(data[1]))[0] = offset;};
setSize(U32 size)56   inline void setSize(U32 size) {((U32*)&(data[9]))[0] = size;};
setLocation(F32 location)57   inline void setLocation(F32 location) { ((F32*)&(data[13]))[0] = location;};
setXt(F32 xt)58   inline void setXt(F32 xt) {((F32*)&(data[17]))[0] = xt;};
setYt(F32 yt)59   inline void setYt(F32 yt) {((F32*)&(data[21]))[0] = yt;};
setZt(F32 zt)60   inline void setZt(F32 zt) {((F32*)&(data[25]))[0] = zt;};
flipDirection()61   inline void flipDirection() {((F32*)&(data[17]))[0] *= -1; ((F32*)&(data[21]))[0] *= -1; ((F32*)&(data[25]))[0] *= -1;};
62 private:
63   U8 data[29];
64 };
65 
66 class LASpoint
67 {
68 public:
69 
70 // these fields contain the data that describe each point
71 
72   I32 X;
73   I32 Y;
74   I32 Z;
75   U16 intensity;
76   U8 return_number : 3;
77   U8 number_of_returns : 3;
78   U8 scan_direction_flag : 1;
79   U8 edge_of_flight_line : 1;
80   U8 classification : 5;
81   U8 synthetic_flag : 1;
82   U8 keypoint_flag  : 1;
83   U8 withheld_flag  : 1;
84   I8 scan_angle_rank;
85   U8 user_data;
86   U16 point_source_ID;
87 
88   // LAS 1.4 only
89   I16 extended_scan_angle;
90   U8 extended_point_type : 2;
91   U8 extended_scanner_channel : 2;
92   U8 extended_classification_flags : 4;
93   U8 extended_classification;
94   U8 extended_return_number : 4;
95   U8 extended_number_of_returns : 4;
96 
97   // LASlib internal use only
98   U8 deleted_flag;
99 
100   // for 8 byte alignment of the GPS time
101   U8 dummy[2];
102 
103   // compressed LASzip 1.4 points only
104   BOOL gps_time_change;
105 
106   F64 gps_time;
107   U16 rgb[4];
108   LASwavepacket wavepacket;
109 
110   U8* extra_bytes;
111 
112 // for converting between x,y,z integers and scaled/translated coordinates
113 
114   const LASquantizer* quantizer;
115   F64 coordinates[3];
116 
117 // for attributed access to the extra bytes
118 
119   const LASattributer* attributer;
120 
121 // this field provides generic access to the point data
122 
123   U8** point;
124 
125 // these fields describe the point format LAS specific
126 
127   BOOL have_gps_time;
128   BOOL have_rgb;
129   BOOL have_nir;
130   BOOL have_wavepacket;
131   I32 extra_bytes_number;
132   U32 total_point_size;
133 
134 // these fields describe the point format terms of generic items
135 
136   U16 num_items;
137   LASitem* items;
138 
139 // copy functions
140 
LASpoint(const LASpoint & other)141   LASpoint(const LASpoint & other)
142   {
143     *this = other;
144   }
145 
operator =(const LASpoint & other)146   LASpoint & operator=(const LASpoint & other)
147   {
148     X = other.X;
149     Y = other.Y;
150     Z = other.Z;
151     intensity = other.intensity;
152     return_number = other.return_number;
153     number_of_returns = other.number_of_returns;
154     scan_direction_flag = other.scan_direction_flag;
155     edge_of_flight_line = other.edge_of_flight_line;
156     classification = other.classification;
157     synthetic_flag = other.synthetic_flag;
158     keypoint_flag = other.keypoint_flag;
159     withheld_flag = other.withheld_flag;
160     scan_angle_rank = other.scan_angle_rank;
161     user_data = other.user_data;
162     point_source_ID = other.point_source_ID;
163     deleted_flag = other.deleted_flag;
164 
165     if (other.have_gps_time)
166     {
167       gps_time = other.gps_time;
168     }
169     if (other.have_rgb)
170     {
171       rgb[0] = other.rgb[0];
172       rgb[1] = other.rgb[1];
173       rgb[2] = other.rgb[2];
174       if (other.have_nir)
175       {
176         rgb[3] = other.rgb[3];
177       }
178     }
179     if (other.have_wavepacket)
180     {
181       wavepacket = other.wavepacket;
182     }
183     if (other.extra_bytes && extra_bytes)
184     {
185       memcpy(extra_bytes, other.extra_bytes, extra_bytes_number);
186     }
187     if (other.extended_point_type)
188     {
189       extended_classification = other.extended_classification;
190       extended_classification_flags = other.extended_classification_flags;
191       extended_number_of_returns = other.extended_number_of_returns;
192       extended_return_number = other.extended_return_number;
193       extended_scan_angle = other.extended_scan_angle;
194       extended_scanner_channel = other.extended_scanner_channel;
195     }
196     else if (extended_point_type)
197     {
198       extended_classification = other.classification;
199       extended_classification_flags = ((other.withheld_flag) << 2) | ((other.keypoint_flag) << 1) | (other.synthetic_flag);
200       extended_number_of_returns = other.number_of_returns;
201       extended_return_number = other.return_number;
202       extended_scan_angle = I16_QUANTIZE(((F32)other.scan_angle_rank)/0.006);
203       extended_scanner_channel = other.extended_scanner_channel;
204     }
205 
206     return *this;
207   };
208 
copy_to(U8 * buffer) const209   void copy_to(U8* buffer) const
210   {
211     if (extended_point_type)
212     {
213       memcpy(buffer, &X, 14);
214       buffer[14] = ((U8*)&X)[24]; // extended return number and number of returns
215       buffer[15] = (((U8*)&X)[14] & 0xC0) | (extended_scanner_channel << 4) | (extended_classification_flags & 0x08) | ((((U8*)&X)[15]) >> 5);
216       buffer[16] = ((U8*)&X)[23]; // extended classification
217       buffer[17] = ((U8*)&X)[17]; // user data
218       ((I16*)buffer)[9] = ((I16*)&X)[10]; // extended scan angle
219       ((U16*)buffer)[10] = ((U16*)&X)[9]; // point source ID
220       memcpy(buffer+22, &gps_time, 8);
221     }
222     else
223     {
224       memcpy(buffer, &X, 20);
225     }
226     U32 i;
227     U32 b = items[0].size;
228     for (i = 1; i < num_items; i++)
229     {
230       memcpy(&buffer[b], point[i], items[i].size);
231       b += items[i].size;
232     }
233   };
234 
copy_from(const U8 * buffer)235   void copy_from(const U8* buffer)
236   {
237     if (extended_point_type)
238     {
239       memcpy(&X, buffer, 14);
240       ((U8*)&X)[24] = buffer[14]; // extended return number and number of returns
241       extended_classification_flags = buffer[15] & 0x0F;
242       ((U8*)&X)[15] = (buffer[15] & 0x07) << 5; // legacy classification flags
243       extended_scanner_channel = (buffer[15] >> 4) & 0x03;
244       scan_direction_flag = (buffer[15] >> 6) & 0x01;
245       edge_of_flight_line = (buffer[15] >> 7) & 0x01;
246       ((U8*)&X)[23] = buffer[16]; // extended classification
247       if (extended_classification < 32) classification = extended_classification;
248       ((U8*)&X)[17] = buffer[17]; // user data
249       ((I16*)&X)[10] = ((I16*)buffer)[9]; // extended scan angle
250       ((U16*)&X)[9] = ((U16*)buffer)[10]; // point source ID
251       memcpy(&gps_time, buffer+22, 8);
252     }
253     else
254     {
255       memcpy(&X, buffer, 20);
256     }
257     U32 i;
258     U32 b = items[0].size;
259     for (i = 1; i < num_items; i++)
260     {
261       memcpy(point[i], &buffer[b], items[i].size);
262       b += items[i].size;
263     }
264   };
265 
266 // these functions set the desired point format (and maybe add on attributes in extra bytes)
267 
init(const LASquantizer * quantizer,const U8 point_type,const U16 point_size,const LASattributer * attributer=0)268   BOOL init(const LASquantizer* quantizer, const U8 point_type, const U16 point_size, const LASattributer* attributer=0)
269   {
270     // clean the point
271 
272     clean();
273 
274     // switch over the point types we know
275 
276     if (!LASzip().setup(&num_items, &items, point_type, point_size, LASZIP_COMPRESSOR_NONE))
277     {
278       fprintf(stderr,"ERROR: unknown point type %d with point size %d\n", (I32)point_type, (I32)point_size);
279       return FALSE;
280     }
281 
282     // create point's item pointers
283 
284     point = new U8*[num_items];
285 
286     U16 i;
287     for (i = 0; i < num_items; i++)
288     {
289       total_point_size += items[i].size;
290       switch (items[i].type)
291       {
292       case LASitem::POINT14:
293         have_gps_time = TRUE;
294         extended_point_type = 1;
295       case LASitem::POINT10:
296         this->point[i] = (U8*)&(this->X);
297         break;
298       case LASitem::GPSTIME11:
299         have_gps_time = TRUE;
300         this->point[i] = (U8*)&(this->gps_time);
301         break;
302       case LASitem::RGBNIR14:
303         have_nir = TRUE;
304       case LASitem::RGB12:
305       case LASitem::RGB14:
306         have_rgb = TRUE;
307         this->point[i] = (U8*)(this->rgb);
308         break;
309       case LASitem::WAVEPACKET13:
310       case LASitem::WAVEPACKET14:
311         have_wavepacket = TRUE;
312         this->point[i] = (U8*)&(this->wavepacket);
313         break;
314       case LASitem::BYTE:
315       case LASitem::BYTE14:
316         extra_bytes_number = items[i].size;
317         extra_bytes = new U8[extra_bytes_number];
318         this->point[i] = extra_bytes;
319         break;
320       default:
321         return FALSE;
322       }
323     }
324     this->quantizer = quantizer;
325     this->attributer = attributer;
326     return TRUE;
327   };
328 
init(const LASquantizer * quantizer,const U32 num_items,const LASitem * items,const LASattributer * attributer=0)329   BOOL init(const LASquantizer* quantizer, const U32 num_items, const LASitem* items, const LASattributer* attributer=0)
330   {
331     U32 i;
332 
333     // clean the point
334 
335     clean();
336 
337     // create item description
338 
339     this->num_items = num_items;
340     if (this->items) delete [] this->items;
341     this->items = new LASitem[num_items];
342     if (this->point) delete [] this->point;
343     this->point = new U8*[num_items];
344 
345     for (i = 0; i < num_items; i++)
346     {
347       this->items[i] = items[i];
348       total_point_size += items[i].size;
349       switch (items[i].type)
350       {
351       case LASitem::POINT14:
352         have_gps_time = TRUE;
353         extended_point_type = 1;
354       case LASitem::POINT10:
355         this->point[i] = (U8*)&(this->X);
356         break;
357       case LASitem::GPSTIME11:
358         have_gps_time = TRUE;
359         this->point[i] = (U8*)&(this->gps_time);
360         break;
361       case LASitem::RGBNIR14:
362         have_nir = TRUE;
363       case LASitem::RGB12:
364       case LASitem::RGB14:
365         have_rgb = TRUE;
366         this->point[i] = (U8*)(this->rgb);
367         break;
368       case LASitem::WAVEPACKET13:
369       case LASitem::WAVEPACKET14:
370         have_wavepacket = TRUE;
371         this->point[i] = (U8*)&(this->wavepacket);
372         break;
373       case LASitem::BYTE:
374       case LASitem::BYTE14:
375         extra_bytes_number = items[i].size;
376         extra_bytes = new U8[extra_bytes_number];
377         this->point[i] = extra_bytes;
378         break;
379       default:
380         return FALSE;
381       }
382     }
383     this->quantizer = quantizer;
384     this->attributer = attributer;
385     return TRUE;
386   };
387 
inside_rectangle(const F64 r_min_x,const F64 r_min_y,const F64 r_max_x,const F64 r_max_y) const388   BOOL inside_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y) const
389   {
390     F64 xy;
391     xy = get_x();
392     if (xy < r_min_x || xy >= r_max_x) return FALSE;
393     xy = get_y();
394     if (xy < r_min_y || xy >= r_max_y) return FALSE;
395     return TRUE;
396   }
397 
inside_tile(const F32 ll_x,const F32 ll_y,const F32 ur_x,const F32 ur_y) const398   BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 ur_x, const F32 ur_y) const
399   {
400     F64 xy;
401     xy = get_x();
402     if (xy < ll_x || xy >= ur_x) return FALSE;
403     xy = get_y();
404     if (xy < ll_y || xy >= ur_y) return FALSE;
405     return TRUE;
406   }
407 
inside_circle(const F64 center_x,const F64 center_y,F64 squared_radius) const408   BOOL inside_circle(const F64 center_x, const F64 center_y, F64 squared_radius) const
409   {
410     F64 dx = center_x - get_x();
411     F64 dy = center_y - get_y();
412     return ((dx*dx+dy*dy) < squared_radius);
413   }
414 
inside_box(const F64 min_x,const F64 min_y,const F64 min_z,const F64 max_x,const F64 max_y,const F64 max_z) const415   BOOL inside_box(const F64 min_x, const F64 min_y, const F64 min_z, const F64 max_x, const F64 max_y, const F64 max_z) const
416   {
417     F64 xyz;
418     xyz = get_x();
419     if (xyz < min_x || xyz >= max_x) return FALSE;
420     xyz = get_y();
421     if (xyz < min_y || xyz >= max_y) return FALSE;
422     xyz = get_z();
423     if (xyz < min_z || xyz >= max_z) return FALSE;
424     return TRUE;
425   }
426 
inside_bounding_box(const F64 min_x,const F64 min_y,const F64 min_z,const F64 max_x,const F64 max_y,const F64 max_z) const427   BOOL inside_bounding_box(const F64 min_x, const F64 min_y, const F64 min_z, const F64 max_x, const F64 max_y, const F64 max_z) const
428   {
429     F64 xyz;
430     xyz = get_x();
431     if (xyz < min_x || xyz > max_x) return FALSE;
432     xyz = get_y();
433     if (xyz < min_y || xyz > max_y) return FALSE;
434     xyz = get_z();
435     if (xyz < min_z || xyz > max_z) return FALSE;
436     return TRUE;
437   }
438 
is_zero() const439   BOOL is_zero() const
440   {
441     if (((U32*)&(this->X))[0] || ((U32*)&(this->X))[1] || ((U32*)&(this->X))[2] || ((U32*)&(this->X))[3] || ((U32*)&(this->X))[4])
442     {
443       return FALSE;
444     }
445     if (have_gps_time)
446     {
447       if (this->gps_time)
448       {
449         return FALSE;
450       }
451     }
452     if (have_rgb)
453     {
454       if (this->rgb[0] || this->rgb[1] || this->rgb[2])
455       {
456         return FALSE;
457       }
458       if (have_nir)
459       {
460         if (this->rgb[3])
461         {
462           return FALSE;
463         }
464       }
465     }
466     return TRUE;
467   }
468 
zero()469   void zero()
470   {
471     X = 0;
472     Y = 0;
473     Z = 0;
474     intensity = 0;
475     return_number = 1;
476     number_of_returns = 1;
477     scan_direction_flag = 0;
478     edge_of_flight_line = 0;
479     classification = 0;
480     synthetic_flag = 0;
481     keypoint_flag = 0;
482     withheld_flag = 0;
483     scan_angle_rank = 0;
484     user_data = 0;
485     point_source_ID = 0;
486 
487     // LAS 1.4 only
488     extended_scan_angle = 0;
489     extended_scanner_channel = 0;
490     extended_classification_flags = 0;
491     extended_classification = 0;
492     extended_return_number = 1;
493     extended_number_of_returns = 1;
494 
495     // LASlib only
496     deleted_flag = 0;
497 
498     gps_time = 0.0;
499     rgb[0] = rgb[1] = rgb[2] = rgb[3] = 0;
500     wavepacket.zero();
501   };
502 
clean()503   void clean()
504   {
505     zero();
506 
507     if (extra_bytes)
508     {
509       delete [] extra_bytes;
510       extra_bytes = 0;
511     };
512 
513     if (point) delete [] point;
514     point = 0;
515 
516     have_gps_time = FALSE;
517     have_rgb = FALSE;
518     have_wavepacket = FALSE;
519     have_nir = FALSE;
520     extra_bytes_number = 0;
521     total_point_size = 0;
522 
523     num_items = 0;
524     if (items) delete [] items;
525     items = 0;
526 
527     // LAS 1.4 only
528     extended_point_type = 0;
529   };
530 
LASpoint()531   LASpoint()
532   {
533     extra_bytes = 0;
534     point = 0;
535     items = 0;
536     clean();
537   };
538 
is_first() const539   inline BOOL is_first() const { return get_return_number() <= 1; };
is_intermediate() const540   inline BOOL is_intermediate() const { return (!is_first() && !is_last()); };
is_last() const541   inline BOOL is_last() const { return get_return_number() >= get_number_of_returns(); };
is_single() const542   inline BOOL is_single() const { return get_number_of_returns() <= 1; };
543 
is_first_of_many() const544   inline BOOL is_first_of_many() const { return !is_single() && is_first(); };
is_last_of_many() const545   inline BOOL is_last_of_many() const { return !is_single() && is_last(); };
546 
get_X() const547   inline I32 get_X() const { return X; };
get_Y() const548   inline I32 get_Y() const { return Y; };
get_Z() const549   inline I32 get_Z() const { return Z; };
get_intensity() const550   inline U16 get_intensity() const { return intensity; };
get_return_number() const551   inline U8 get_return_number() const { return return_number; };
get_number_of_returns() const552   inline U8 get_number_of_returns() const { return number_of_returns; };
get_scan_direction_flag() const553   inline U8 get_scan_direction_flag() const { return scan_direction_flag; };
get_edge_of_flight_line() const554   inline U8 get_edge_of_flight_line() const { return edge_of_flight_line; };
get_classification() const555   inline U8 get_classification() const { return classification; };
get_synthetic_flag() const556   inline U8 get_synthetic_flag() const { return synthetic_flag; };
get_keypoint_flag() const557   inline U8 get_keypoint_flag() const { return keypoint_flag; };
get_withheld_flag() const558   inline U8 get_withheld_flag() const { return withheld_flag; };
get_scan_angle_rank() const559   inline I8 get_scan_angle_rank() const { return scan_angle_rank; };
get_user_data() const560   inline U8 get_user_data() const { return user_data; };
get_point_source_ID() const561   inline U16 get_point_source_ID() const { return point_source_ID; };
get_deleted_flag() const562   inline U8 get_deleted_flag() const { return deleted_flag; };
get_gps_time() const563   inline F64 get_gps_time() const { return gps_time; };
get_RGB() const564   inline const U16* get_RGB() const { return rgb; };
get_RGBI() const565   inline const U16* get_RGBI() const { return rgb; };
get_RGBI(const U32 band) const566   inline U16 get_RGBI(const U32 band) const { return rgb[band]; };
get_R() const567   inline U16 get_R() const { return rgb[0]; };
get_G() const568   inline U16 get_G() const { return rgb[1]; };
get_B() const569   inline U16 get_B() const { return rgb[2]; };
get_I() const570   inline U16 get_I() const { return rgb[3]; };
get_NIR() const571   inline U16 get_NIR() const { return rgb[3]; };
572 
set_X(const I32 X)573   inline void set_X(const I32 X) { this->X = X; };
set_Y(const I32 Y)574   inline void set_Y(const I32 Y) { this->Y = Y; };
set_Z(const I32 Z)575   inline void set_Z(const I32 Z) { this->Z = Z; };
set_intensity(const U16 intensity)576   inline void set_intensity(const U16 intensity) { this->intensity = intensity; };
set_return_number(const U8 return_number)577   inline void set_return_number(const U8 return_number) { this->return_number = (return_number > 7 ? 7 : return_number); };
set_number_of_returns(const U8 number_of_returns)578   inline void set_number_of_returns(const U8 number_of_returns) { this->number_of_returns = (number_of_returns > 7 ? 7 : number_of_returns); };
set_scan_direction_flag(const U8 scan_direction_flag)579   inline void set_scan_direction_flag(const U8 scan_direction_flag) { this->scan_direction_flag = scan_direction_flag; };
set_edge_of_flight_line(const U8 edge_of_flight_line)580   inline void set_edge_of_flight_line(const U8 edge_of_flight_line) { this->edge_of_flight_line = edge_of_flight_line; };
set_classification(U8 classification)581   inline void set_classification(U8 classification) { if (classification < 32) { this->classification = classification; this->extended_classification = classification; } };
set_synthetic_flag(U8 synthetic_flag)582   inline void set_synthetic_flag(U8 synthetic_flag) { if (synthetic_flag) { this->synthetic_flag = 1; this->extended_classification_flags |= 0x01; } else { this->synthetic_flag = 0; this->extended_classification_flags &= 0x0E; } };
set_keypoint_flag(U8 keypoint_flag)583   inline void set_keypoint_flag(U8 keypoint_flag) { if (keypoint_flag) { this->keypoint_flag = 1; this->extended_classification_flags |= 0x02; } else { this->keypoint_flag = 0; this->extended_classification_flags &= 0x0D; } };
set_withheld_flag(U8 withheld_flag)584   inline void set_withheld_flag(U8 withheld_flag) { if (withheld_flag) { this->withheld_flag = 1; this->extended_classification_flags |= 0x04; } else { this->withheld_flag = 0; this->extended_classification_flags &= 0x0B; } };
set_scan_angle_rank(I8 scan_angle_rank)585   inline void set_scan_angle_rank(I8 scan_angle_rank) { this->scan_angle_rank = scan_angle_rank; };
set_user_data(U8 user_data)586   inline void set_user_data(U8 user_data) { this->user_data = user_data; };
set_point_source_ID(U16 point_source_ID)587   inline void set_point_source_ID(U16 point_source_ID) { this->point_source_ID = point_source_ID; };
set_deleted_flag(U8 deleted_flag)588   inline void set_deleted_flag(U8 deleted_flag) { this->deleted_flag = deleted_flag; };
set_gps_time(const F64 gps_time)589   inline void set_gps_time(const F64 gps_time) { this->gps_time = gps_time; };
set_RGB(const U16 * rgb)590   inline void set_RGB(const U16* rgb) { memcpy(this->rgb, rgb, sizeof(U16) * 3); };
set_RGBI(const U16 * rgb)591   inline void set_RGBI(const U16* rgb) { memcpy(this->rgb, rgb, sizeof(U16) * 4); };
set_RGBI(const U32 band,const U16 value)592   inline void set_RGBI(const U32 band, const U16 value) { rgb[band] = value; };
set_R(const U16 R)593   inline void set_R(const U16 R) { this->rgb[0] = R; };
set_G(const U16 G)594   inline void set_G(const U16 G) { this->rgb[1] = G; };
set_B(const U16 B)595   inline void set_B(const U16 B) { this->rgb[2] = B; };
set_I(const U16 I)596   inline void set_I(const U16 I) { this->rgb[3] = I; };
set_NIR(const U16 NIR)597   inline void set_NIR(const U16 NIR) { this->rgb[3] = NIR; };
598 
get_x() const599   inline F64 get_x() const { return quantizer->get_x(X); };
get_y() const600   inline F64 get_y() const { return quantizer->get_y(Y); };
get_z() const601   inline F64 get_z() const { return quantizer->get_z(Z); };
602 
set_x(const F64 x)603   inline BOOL set_x(const F64 x) { I64 X = quantizer->get_X(x); this->X = (I32)(X); return I32_FITS_IN_RANGE(X); };
set_y(const F64 y)604   inline BOOL set_y(const F64 y) { I64 Y = quantizer->get_Y(y); this->Y = (I32)(Y); return I32_FITS_IN_RANGE(Y); };
set_z(const F64 z)605   inline BOOL set_z(const F64 z) { I64 Z = quantizer->get_Z(z); this->Z = (I32)(Z); return I32_FITS_IN_RANGE(Z); };
606 
is_extended_point_type() const607   inline BOOL is_extended_point_type() const { return extended_point_type; };
608 
get_extended_classification() const609   inline U8 get_extended_classification() const { return extended_classification; };
get_extended_return_number() const610   inline U8 get_extended_return_number() const { return extended_return_number; };
get_extended_number_of_returns() const611   inline U8 get_extended_number_of_returns() const { return extended_number_of_returns; };
get_extended_scan_angle() const612   inline I16 get_extended_scan_angle() const { return extended_scan_angle; };
get_extended_overlap_flag() const613   inline U8 get_extended_overlap_flag() const { return (extended_classification_flags >> 3); };
get_extended_scanner_channel() const614   inline U8 get_extended_scanner_channel() const { return extended_scanner_channel; };
615 
set_extended_classification(U8 extended_classification)616   inline void set_extended_classification(U8 extended_classification) { this->extended_classification = extended_classification; if (extended_classification > 31) this->classification = 0; else this->classification = extended_classification; };
set_extended_return_number(U8 extended_return_number)617   inline void set_extended_return_number(U8 extended_return_number) { this->extended_return_number = extended_return_number; };
set_extended_number_of_returns(U8 extended_number_of_returns)618   inline void set_extended_number_of_returns(U8 extended_number_of_returns) { this->extended_number_of_returns = extended_number_of_returns; };
set_extended_scan_angle(I16 extended_scan_angle)619   inline void set_extended_scan_angle(I16 extended_scan_angle) { this->extended_scan_angle = extended_scan_angle; };
set_extended_overlap_flag(U8 extended_overlap_flag)620   inline void set_extended_overlap_flag(U8 extended_overlap_flag) { this->extended_classification_flags = (extended_overlap_flag << 3) | (this->extended_classification_flags & 7); };
set_extended_scanner_channel(U8 extended_scanner_channel)621   inline void set_extended_scanner_channel(U8 extended_scanner_channel) { this->extended_scanner_channel = extended_scanner_channel; };
622 
get_scan_angle() const623   inline F32 get_scan_angle() const { if (extended_point_type) return 0.006f*extended_scan_angle; else return (F32)scan_angle_rank; };
get_abs_scan_angle() const624   inline F32 get_abs_scan_angle() const { if (extended_point_type) return (extended_scan_angle < 0 ? -0.006f*extended_scan_angle : 0.006f*extended_scan_angle) ; else return (scan_angle_rank < 0 ? (F32)-scan_angle_rank : (F32)scan_angle_rank); };
625 
set_scan_angle(F32 scan_angle)626   inline void set_scan_angle(F32 scan_angle) { if (extended_point_type) set_extended_scan_angle(I16_QUANTIZE(scan_angle/0.006f)); else set_scan_angle_rank(I8_QUANTIZE(scan_angle)); };
627 
compute_coordinates()628   inline void compute_coordinates()
629   {
630     coordinates[0] = get_x();
631     coordinates[1] = get_y();
632     coordinates[2] = get_z();
633   };
634 
compute_XYZ()635   inline BOOL compute_XYZ()
636   {
637     BOOL retX = set_x(coordinates[0]);
638     BOOL retY = set_y(coordinates[1]);
639     BOOL retZ = set_z(coordinates[2]);
640     return (retX && retY && retZ);
641   };
642 
compute_XYZ(const LASquantizer * quantizer)643   inline BOOL compute_XYZ(const LASquantizer* quantizer)
644   {
645     I64 X = quantizer->get_X(coordinates[0]);
646     I64 Y = quantizer->get_Y(coordinates[1]);
647     I64 Z = quantizer->get_Z(coordinates[2]);
648     this->X = (I32)(X);
649     this->Y = (I32)(Y);
650     this->Z = (I32)(Z);
651     return (I32_FITS_IN_RANGE(X) && I32_FITS_IN_RANGE(Y) && I32_FITS_IN_RANGE(Z));
652   };
653 
654   // generic functions for attributes in extra bytes
655 
has_attribute(U32 index) const656   inline BOOL has_attribute(U32 index) const
657   {
658     if (attributer)
659     {
660       if (((I32)index) < attributer->number_attributes)
661       {
662         return TRUE;
663       }
664     }
665     return FALSE;
666   };
667 
get_attribute(U32 index,U8 * data) const668   inline BOOL get_attribute(U32 index, U8* data) const
669   {
670     if (has_attribute(index))
671     {
672       memcpy(data, extra_bytes + attributer->attribute_starts[index], attributer->attribute_sizes[index]);
673       return TRUE;
674     }
675     return FALSE;
676   };
677 
set_attribute(U32 index,const U8 * data)678   inline BOOL set_attribute(U32 index, const U8* data)
679   {
680     if (has_attribute(index))
681     {
682       memcpy(extra_bytes + attributer->attribute_starts[index], data, attributer->attribute_sizes[index]);
683       return TRUE;
684     }
685     return FALSE;
686   };
687 
get_attribute_name(U32 index) const688   inline const CHAR* get_attribute_name(U32 index) const
689   {
690     if (has_attribute(index))
691     {
692       return attributer->attributes[index].name;
693     }
694     return 0;
695   };
696 
get_attribute_as_float(U32 index) const697   inline F64 get_attribute_as_float(U32 index) const
698   {
699     if (has_attribute(index))
700     {
701       return attributer->attributes[index].get_value_as_float(extra_bytes + attributer->attribute_starts[index]);
702     }
703     return 0.0;
704   };
705 
set_attribute_as_float(U32 index,F64 value) const706   inline void set_attribute_as_float(U32 index, F64 value) const
707   {
708     if (has_attribute(index))
709     {
710       attributer->attributes[index].set_value_as_float(extra_bytes + attributer->attribute_starts[index], value);
711     }
712   };
713 
714   // typed and offset functions for attributes in extra bytes (more efficient)
715 
get_attribute(I32 start,U8 & data) const716   inline void get_attribute(I32 start, U8 &data) const { data = extra_bytes[start]; };
set_attribute(I32 start,U8 data)717   inline void set_attribute(I32 start, U8 data) { extra_bytes[start] = data; };
get_attribute(I32 start,I8 & data) const718   inline void get_attribute(I32 start, I8 &data) const { data = (I8)(extra_bytes[start]); };
set_attribute(I32 start,I8 data)719   inline void set_attribute(I32 start, I8 data) { extra_bytes[start] = data; };
get_attribute(I32 start,U16 & data) const720   inline void get_attribute(I32 start, U16 &data) const { data = *((U16*)(extra_bytes + start)); };
set_attribute(I32 start,U16 data)721   inline void set_attribute(I32 start, U16 data) { *((U16*)(extra_bytes + start)) = data; };
get_attribute(I32 start,I16 & data) const722   inline void get_attribute(I32 start, I16 &data) const { data = *((I16*)(extra_bytes + start)); };
set_attribute(I32 start,I16 data)723   inline void set_attribute(I32 start, I16 data) { *((I16*)(extra_bytes + start)) = data; };
get_attribute(I32 start,U32 & data) const724   inline void get_attribute(I32 start, U32 &data) const { data = *((U32*)(extra_bytes + start)); };
set_attribute(I32 start,U32 data)725   inline void set_attribute(I32 start, U32 data) { *((U32*)(extra_bytes + start)) = data; };
get_attribute(I32 start,I32 & data) const726   inline void get_attribute(I32 start, I32 &data) const { data = *((I32*)(extra_bytes + start)); };
set_attribute(I32 start,I32 data)727   inline void set_attribute(I32 start, I32 data) { *((I32*)(extra_bytes + start)) = data; };
get_attribute(I32 start,U64 & data) const728   inline void get_attribute(I32 start, U64 &data) const { data = *((U64*)(extra_bytes + start)); };
set_attribute(I32 start,U64 data)729   inline void set_attribute(I32 start, U64 data) { *((U64*)(extra_bytes + start)) = data; };
get_attribute(I32 start,I64 & data) const730   inline void get_attribute(I32 start, I64 &data) const { data = *((I64*)(extra_bytes + start)); };
set_attribute(I32 start,I64 data)731   inline void set_attribute(I32 start, I64 data) { *((I64*)(extra_bytes + start)) = data; };
get_attribute(I32 start,F32 & data) const732   inline void get_attribute(I32 start, F32 &data) const { data = *((F32*)(extra_bytes + start)); };
set_attribute(I32 start,F32 data)733   inline void set_attribute(I32 start, F32 data) { *((F32*)(extra_bytes + start)) = data; };
get_attribute(I32 start,F64 & data) const734   inline void get_attribute(I32 start, F64 &data) const { data = *((F64*)(extra_bytes + start)); };
set_attribute(I32 start,F64 data)735   inline void set_attribute(I32 start, F64 data) { *((F64*)(extra_bytes + start)) = data; };
736 
~LASpoint()737   ~LASpoint()
738   {
739     clean();
740   };
741 };
742 
743 #endif
744