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