1 /******************************************************************************
2 * $Id$
3 *
4 * Project: libLAS - http://liblas.org - A BSD library for LAS format data.
5 * Purpose: LAS point class
6 * Author: Mateusz Loskot, mateusz@loskot.net
7 *
8 ******************************************************************************
9 * Copyright (c) 2008, Mateusz Loskot
10 *
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following
15 * conditions are met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * * Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided
22 * with the distribution.
23 * * Neither the name of the Martin Isenburg or Iowa Department
24 * of Natural Resources nor the names of its contributors may be
25 * used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
35 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
36 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
39 * OF SUCH DAMAGE.
40 ****************************************************************************/
41
42 #include <liblas/point.hpp>
43 #include <liblas/header.hpp>
44 #include <liblas/schema.hpp>
45 #include <liblas/exception.hpp>
46 #include <liblas/detail/binary.hpp>
47 #include <liblas/detail/pointrecord.hpp>
48 // boost
49 #include <boost/array.hpp>
50 #include <boost/cstdint.hpp>
51 #include <liblas/external/property_tree/ptree.hpp>
52
53 // std
54 #include <cstring>
55 #include <stdexcept>
56 #include <string>
57 #include <vector>
58 #include <iosfwd>
59 #include <algorithm>
60 #include <numeric>
61
62 using namespace boost;
63
64 namespace liblas {
65
Point(Header const * hdr)66 Point::Point(Header const* hdr)
67 :
68 m_header(hdr)
69 , m_default_header(DefaultHeader::get())
70 {
71 m_data.resize(hdr->GetDataRecordLength());
72 m_data.assign(hdr->GetDataRecordLength(), 0);
73 }
74
Point(Point const & other)75 Point::Point(Point const& other)
76 : m_data(other.m_data)
77 , m_header(other.GetHeader())
78 , m_default_header(DefaultHeader::get())
79 {
80 }
81
operator =(Point const & rhs)82 Point& Point::operator=(Point const& rhs)
83 {
84 if (&rhs != this)
85 {
86 m_data = rhs.m_data;
87 m_header = rhs.m_header;
88 }
89 return *this;
90 }
91
SetCoordinates(double const & x,double const & y,double const & z)92 void Point::SetCoordinates(double const& x, double const& y, double const& z)
93 {
94 SetX(x);
95 SetY(y);
96 SetZ(z);
97 }
98
equal(Point const & other) const99 bool Point::equal(Point const& other) const
100 {
101 // TODO - mloskot: Default epsilon is too small.
102 // Is 0.00001 good as tolerance or too wide?
103 //double const epsilon = std::numeric_limits<double>::epsilon();
104 double const epsilon = 0.00001;
105
106 double const dx = GetX() - other.GetX();
107 double const dy = GetY() - other.GetY();
108 double const dz = GetZ() - other.GetZ();
109
110 // TODO: Should we compare other data members, besides the coordinates?
111
112 if ((dx <= epsilon && dx >= -epsilon)
113 && (dy <= epsilon && dy >= -epsilon)
114 && (dz <= epsilon && dz >= -epsilon))
115 {
116 return true;
117 }
118
119 // If we do other members
120 // bool compare_classification(uint8_t cls, uint8_t expected)
121 // {
122 // // 31 is max index in classification lookup table
123 // clsidx = (cls & 31);
124 // assert(clsidx <= 31);
125 // return (clsidx == expected);
126 // }
127
128 return false;
129 }
130
Validate() const131 bool Point::Validate() const
132 {
133 unsigned int flags = 0;
134
135 if (this->GetReturnNumber() > 0x07)
136 flags |= eReturnNumber;
137
138 if (this->GetNumberOfReturns() > 0x07)
139 flags |= eNumberOfReturns;
140
141 if (this->GetScanDirection() > 0x01)
142 flags |= eScanDirection;
143
144 if (this->GetFlightLineEdge() > 0x01)
145 flags |= eFlightLineEdge;
146
147 if (eScanAngleRankMin > this->GetScanAngleRank()
148 || this->GetScanAngleRank() > eScanAngleRankMax)
149 {
150 flags |= eScanAngleRank;
151 }
152
153 if (flags > 0)
154 {
155 throw invalid_point_data("point data members out of range", flags);
156 }
157
158 return true;
159 }
160
IsValid() const161 bool Point::IsValid() const
162 {
163
164 if (eScanAngleRankMin > this->GetScanAngleRank() || this->GetScanAngleRank() > eScanAngleRankMax)
165 return false;
166
167 if (this->GetFlightLineEdge() > 0x01)
168 return false;
169
170 if (this->GetScanDirection() > 0x01)
171 return false;
172
173 if (this->GetNumberOfReturns() > 0x07)
174 return false;
175
176 if (this->GetReturnNumber() > 0x07)
177 return false;
178
179 return true;
180 }
181
SetHeader(Header const * header)182 void Point::SetHeader(Header const* header)
183 {
184
185 if (!header)
186 {
187 throw liblas_error("header reference for SetHeader is void");
188 }
189
190 // If we don't have a header initialized, set the point's to the
191 // one we were given.
192 if (!m_header) m_header = header;
193
194 // This is hopefully faster than copying everything if we don't have
195 // any data set and nothing to worry about.
196 const liblas::Schema* schema;
197 uint16_t wanted_length = header->GetDataRecordLength();
198 schema = &(header->GetSchema());
199 uint32_t sum = std::accumulate(m_data.begin(), m_data.end(), 0);
200
201 if (!sum) {
202 std::vector<uint8_t> data;
203 data.resize(wanted_length);
204 data.assign(wanted_length, 0);
205 m_data = data;
206 m_header = header;
207 return;
208 }
209
210 bool bApplyNewScaling = true;
211
212
213
214 if (detail::compare_distance(header->GetScaleX(), m_header->GetScaleX()) &&
215 detail::compare_distance(header->GetScaleY(), m_header->GetScaleY()) &&
216 detail::compare_distance(header->GetScaleZ(), m_header->GetScaleZ()) &&
217 detail::compare_distance(header->GetOffsetX(), m_header->GetOffsetX()) &&
218 detail::compare_distance(header->GetOffsetY(), m_header->GetOffsetY()) &&
219 detail::compare_distance(header->GetOffsetZ(), m_header->GetOffsetZ()))
220 bApplyNewScaling = false;
221 else
222 bApplyNewScaling = true;
223
224
225
226 if (wanted_length != m_data.size())
227 {
228 // Manually copy everything but the header ptr
229 // We can't just copy the raw data because its
230 // layout is likely changing as a result of the
231 // schema change.
232 Point p(*this);
233 m_header = header;
234
235 std::vector<uint8_t> data;
236 data.resize(wanted_length);
237 data.assign(wanted_length, 0);
238 m_data = data;
239 m_header = header;
240
241 SetX(p.GetX());
242 SetY(p.GetY());
243 SetZ(p.GetZ());
244
245 SetIntensity(p.GetIntensity());
246 SetScanFlags(p.GetScanFlags());
247 SetClassification(p.GetClassification());
248 SetScanAngleRank(p.GetScanAngleRank());
249 SetUserData(p.GetUserData());
250 SetPointSourceID(p.GetPointSourceID());
251
252 boost::optional< Dimension const& > t = schema->GetDimension("Time");
253 if (t)
254 SetTime(p.GetTime());
255
256 boost::optional< Dimension const& > c = schema->GetDimension("Red");
257 if (c)
258 SetColor(p.GetColor());
259
260 // FIXME: copy other custom dimensions here? resetting the
261 // headerptr can be catastrophic in a lot of cases.
262 }
263
264
265 // The header's scale/offset can change the raw storage of xyz.
266 // SetHeader can result in a rescaling of the data.
267 double x;
268 double y;
269 double z;
270
271 if (bApplyNewScaling)
272 {
273 x = GetX();
274 y = GetY();
275 z = GetZ();
276 }
277
278 m_header = header;
279
280 if (bApplyNewScaling)
281 {
282 SetX(x);
283 SetY(y);
284 SetZ(z);
285 }
286
287
288 }
GetHeader() const289 Header const* Point::GetHeader() const
290 {
291 if (m_header) return m_header; else return &m_default_header;
292 }
293
GetPTree() const294 liblas::property_tree::ptree Point::GetPTree() const
295 {
296 using liblas::property_tree::ptree;
297 ptree pt;
298
299 pt.put("x", GetX());
300 pt.put("y", GetY());
301 pt.put("z", GetZ());
302
303 pt.put("rawx", GetRawX());
304 pt.put("rawy", GetRawY());
305 pt.put("rawz", GetRawZ());
306
307 pt.put("time", GetTime());
308 pt.put("intensity", GetIntensity());
309 pt.put("returnnumber", GetReturnNumber());
310 pt.put("numberofreturns", GetNumberOfReturns());
311 pt.put("scandirection", GetScanDirection());
312
313 pt.put("scanangle", GetScanAngleRank());
314 pt.put("flightlineedge", GetFlightLineEdge());
315
316 pt.put("userdata", GetUserData());
317 pt.put("pointsourceid", GetPointSourceID());
318
319 ptree klasses;
320
321 liblas::Classification const& c = GetClassification();
322
323 // I hate you windows
324 #ifdef _MSC_VER
325 #ifdef GetClassName
326 #undef GetClassName
327 #endif
328 #endif
329 std::string name = c.GetClassName();
330
331 klasses.put("name", name);
332 klasses.put("id", c.GetClass());
333 klasses.put("withheld", c.IsWithheld());
334 klasses.put("keypoint", c.IsKeyPoint());
335 klasses.put("synthetic", c.IsSynthetic());
336
337 pt.add_child("classification",klasses);
338
339 ptree colors;
340 liblas::Color const& clr = GetColor();
341
342 colors.put("red", clr.GetRed());
343 colors.put("green", clr.GetGreen());
344 colors.put("blue", clr.GetBlue());
345 pt.add_child("color", colors);
346
347 return pt;
348 }
349
operator <<(std::ostream & os,liblas::Point const & p)350 std::ostream& operator<<(std::ostream& os, liblas::Point const& p)
351 {
352 using liblas::property_tree::ptree;
353 ptree tree = p.GetPTree();
354
355 os << "---------------------------------------------------------" << std::endl;
356
357 os.setf(std::ios_base::fixed, std::ios_base::floatfield);
358 os.precision(6);
359
360 os << " X: \t\t\t" << tree.get<double>("x") << std::endl;
361 os << " Y: \t\t\t" << tree.get<double>("y") << std::endl;
362 os << " Z: \t\t\t" << tree.get<double>("z") << std::endl;
363 os << " Time: \t\t" << tree.get<double>("time") << std::endl;
364 os.unsetf(std::ios_base::fixed);
365 os.unsetf(std::ios_base::floatfield);
366 os << " Return Number: \t" << tree.get<uint32_t>("returnnumber") << std::endl;
367 os << " Return Count: \t" << tree.get<uint32_t>("numberofreturns") << std::endl;
368 os << " Flightline Edge: \t" << tree.get<uint32_t>("flightlineedge") << std::endl;
369 os << " Intensity: \t\t" << tree.get<uint32_t>("intensity") << std::endl;
370 os << " Scan Direction: \t" << tree.get<uint32_t>("scandirection") << std::endl;
371 os << " Scan Angle Rank: \t" << tree.get<int32_t>("scanangle") << std::endl;
372 os << " Classification: \t" << tree.get<std::string>("classification.name") << std::endl;
373 os << " witheld: \t" << tree.get<std::string>("classification.withheld") << std::endl;
374 os << " keypoint: \t" << tree.get<std::string>("classification.keypoint") << std::endl;
375 os << " synthetic: \t" << tree.get<std::string>("classification.synthetic") << std::endl;
376 os << " RGB Color: \t\t" << tree.get<uint32_t>("color.red") << " "
377 << tree.get<uint32_t>("color.green") << " "
378 << tree.get<uint32_t>("color.blue") << std::endl;
379 os << "---------------------------------------------------------" << std::endl;
380
381 return os;
382 }
383
384
GetX() const385 double Point::GetX() const
386 {
387 int32_t v = GetRawX();
388
389 double output = (v * GetHeader()->GetScaleX()) + GetHeader()->GetOffsetX();
390
391 return output;
392 }
393
GetY() const394 double Point::GetY() const
395 {
396 int32_t v = GetRawY();
397
398 double output = (v * GetHeader()->GetScaleY()) + GetHeader()->GetOffsetY();
399 return output;
400 }
401
GetZ() const402 double Point::GetZ() const
403 {
404 int32_t v = GetRawZ();
405
406 double output = 0;
407
408 output = (v * GetHeader()->GetScaleZ()) + GetHeader()->GetOffsetZ();
409
410 return output;
411 }
412
SetX(double const & value)413 void Point::SetX( double const& value )
414 {
415 int32_t v;
416 double scale;
417 double offset;
418
419 scale = GetHeader()->GetScaleX();
420 offset = GetHeader()->GetOffsetX();
421
422 // descale the value given our scale/offset
423 v = static_cast<int32_t>(
424 detail::sround((value - offset) / scale));
425 SetRawX(v);
426 }
427
SetY(double const & value)428 void Point::SetY( double const& value )
429 {
430 int32_t v;
431 double scale;
432 double offset;
433
434 scale = GetHeader()->GetScaleY();
435 offset = GetHeader()->GetOffsetY();
436
437
438 // descale the value given our scale/offset
439 v = static_cast<int32_t>(
440 detail::sround((value - offset) / scale));
441 SetRawY(v);
442 }
443
SetZ(double const & value)444 void Point::SetZ( double const& value )
445 {
446 int32_t v;
447 double scale;
448 double offset;
449
450 scale = GetHeader()->GetScaleZ();
451 offset = GetHeader()->GetOffsetZ();
452
453 // descale the value given our scale/offset
454 v = static_cast<int32_t>(
455 detail::sround((value - offset) / scale));
456 SetRawZ(v);
457 }
458
GetRawX() const459 int32_t Point::GetRawX() const
460 {
461 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("X");
462 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(0);
463 std::vector<uint8_t>::size_type pos = 0;
464
465 #ifdef LIBLAS_ENDIAN_AWARE
466 int32_t output = liblas::detail::bitsToInt<int32_t>(output, m_data, pos);
467 return output;
468 #else
469 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
470 int32_t* output = reinterpret_cast<int32_t*>(data);
471 return *output;
472 #endif
473 }
474
GetRawY() const475 int32_t Point::GetRawY() const
476 {
477 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("Y");
478 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(1);
479 std::vector<uint8_t>::size_type pos = 4;
480
481 #ifdef LIBLAS_ENDIAN_AWARE
482 int32_t output = liblas::detail::bitsToInt<int32_t>(output, m_data, pos);
483 return output;
484 #else
485 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
486 int32_t* output = reinterpret_cast<int32_t*>(data);
487 return *output;
488 #endif
489 }
490
GetRawZ() const491 int32_t Point::GetRawZ() const
492 {
493 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("Z");
494 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(2);
495 std::vector<uint8_t>::size_type pos = 8;
496
497 #ifdef LIBLAS_ENDIAN_AWARE
498 int32_t output = liblas::detail::bitsToInt<int32_t>(output, m_data, pos);
499 return output;
500 #else
501 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
502 int32_t* output = reinterpret_cast<int32_t*>(data);
503 return *output;
504 #endif
505 }
506
SetRawX(int32_t const & value)507 void Point::SetRawX( int32_t const& value)
508 {
509 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("X");
510 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(0);
511 std::vector<uint8_t>::size_type pos = 0;
512 liblas::detail::intToBits<int32_t>(value, m_data, pos);
513 }
514
SetRawY(int32_t const & value)515 void Point::SetRawY( int32_t const& value)
516 {
517 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("Y");
518 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(1);
519 std::vector<uint8_t>::size_type pos = 4;
520 liblas::detail::intToBits<int32_t>(value, m_data, pos);
521 }
522
SetRawZ(int32_t const & value)523 void Point::SetRawZ( int32_t const& value)
524 {
525 // std::vector<uint8_t>::size_type pos = GetDimensionPosition("Z");
526 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(2);
527 std::vector<uint8_t>::size_type pos = 8;
528 liblas::detail::intToBits<int32_t>(value, m_data, pos);
529 }
530
GetIntensity() const531 uint16_t Point::GetIntensity() const
532 {
533 // Intensity's position is always the 4th dimension
534 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(3);
535 std::vector<uint8_t>::size_type pos = 12;
536
537 #ifdef LIBLAS_ENDIAN_AWARE
538 uint16_t output = liblas::detail::bitsToInt<uint16_t>(output, m_data, pos);
539 return output;
540 #else
541 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
542 uint16_t* output = reinterpret_cast<uint16_t*>(data);
543 return *output;
544 #endif
545
546 }
547
548
SetIntensity(uint16_t const & intensity)549 void Point::SetIntensity(uint16_t const& intensity)
550 {
551 // Intensity's position is always the 4th dimension
552 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(3);
553 std::vector<uint8_t>::size_type pos = 12;
554 liblas::detail::intToBits<uint16_t>(intensity,
555 m_data,
556 pos);
557 }
558
GetScanFlags() const559 uint8_t Point::GetScanFlags() const
560 {
561 // Scan Flag's position is always the 5th dimension
562 // (the entire byte composed of "Return Number", "Number of Returns",
563 // "Scan Direction", and "Flightline Edge")
564 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(4);
565 std::vector<uint8_t>::size_type pos = 14;
566 return m_data[pos];
567 }
568
SetScanFlags(uint8_t const & flags)569 void Point::SetScanFlags(uint8_t const& flags)
570 {
571 // Scan Flag's position is always the 5th dimension
572 // (the entire byte composed of "Return Number", "Number of Returns",
573 // "Scan Direction", and "Flightline Edge")
574 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(4);
575 std::vector<uint8_t>::size_type pos = 14;
576 m_data[pos] = flags;
577 }
578
GetReturnNumber() const579 uint16_t Point::GetReturnNumber() const
580 {
581 // "Return Number" is always the 5th dimension
582 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(4);
583 std::vector<uint8_t>::size_type pos = 14;
584
585 uint8_t flags = m_data[pos];
586
587 // Read bits 1,2,3 (first 3 bits)
588 return (flags & 0x07);
589 }
590
SetReturnNumber(uint16_t const & num)591 void Point::SetReturnNumber(uint16_t const& num)
592 {
593 // "Return Number" is always the 5th dimension
594 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(4);
595 std::vector<uint8_t>::size_type pos = 14;
596 uint8_t flags = m_data[pos];
597
598 // Store value in bits 0,1,2
599 uint8_t mask = 0x7 << 0; // 0b00000111
600 flags &= ~mask;
601 flags |= mask & (static_cast<uint8_t>(num) << 0);
602 m_data[pos] = flags;
603 }
604
GetNumberOfReturns() const605 uint16_t Point::GetNumberOfReturns() const
606 {
607 uint8_t flags;
608
609 // "Number of Returns" is always the 6th dimension
610 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(5);
611 std::vector<uint8_t>::size_type pos = 14;
612
613 flags = m_data[pos];
614
615 // Read bits 4,5,6
616 return ((flags >> 3) & 0x07);
617 }
618
SetNumberOfReturns(uint16_t const & num)619 void Point::SetNumberOfReturns(uint16_t const& num)
620 {
621 // "Number of Returns" is always the 6th dimension
622 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(5);
623 std::vector<uint8_t>::size_type pos = 14;
624
625 uint8_t flags = m_data[pos];
626
627 // Store value in bits 3,4,5
628 uint8_t mask = 0x7 << 3; // 0b00111000
629 flags &= ~mask;
630 flags |= mask & (static_cast<uint8_t>(num) << 3);
631 m_data[pos] = flags;
632
633 }
634
SetScanDirection(uint16_t const & dir)635 void Point::SetScanDirection(uint16_t const& dir)
636 {
637 // "Scan Direction" is always the 7th dimension
638 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(6);
639 std::vector<uint8_t>::size_type pos = 14;
640
641 uint8_t flags = m_data[pos];
642
643 // Store value in bits 6
644 uint8_t mask = 0x1 << 6; // 0b01000000
645 flags &= ~mask;
646 flags |= mask & (static_cast<uint8_t>(dir) << 6);
647 m_data[pos] = flags;
648 }
649
GetScanDirection() const650 uint16_t Point::GetScanDirection() const
651 {
652 // "Scan Direction" is always the 7th dimension
653 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(6);
654 std::vector<uint8_t>::size_type pos = 14;
655 uint8_t flags = m_data[pos];
656
657 // Read 6th bit
658 return ((flags >> 6) & 0x01);
659 }
660
SetFlightLineEdge(uint16_t const & edge)661 void Point::SetFlightLineEdge(uint16_t const& edge)
662 {
663 // "Flightline Edge" is always the 8th dimension
664 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(7);
665 std::vector<uint8_t>::size_type pos = 14;
666
667 uint8_t flags = m_data[pos];
668
669 // Store value in bits 7
670 uint8_t mask = 0x1 << 7; // 0b10000000
671 flags &= ~mask;
672 flags |= mask & (static_cast<uint8_t>(edge) << 7);
673 m_data[pos] = flags;
674
675 }
676
GetFlightLineEdge() const677 uint16_t Point::GetFlightLineEdge() const
678 {
679 // "Flightline Edge" is always the 8th dimension
680 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(7);
681 std::vector<uint8_t>::size_type pos = 14;
682
683 uint8_t flags = m_data[pos];
684
685 // Read 8th bit
686 return ((flags >> 7) & 0x01);
687 }
688
689
GetClassification() const690 Classification Point::GetClassification() const
691 {
692 // "Classification" is always the 9th dimension
693 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(8);
694 std::vector<uint8_t>::size_type pos = 15;
695
696 uint8_t kls = m_data[pos];
697 return Classification(kls);
698 }
699
SetClassification(Classification const & cls)700 void Point::SetClassification(Classification const& cls)
701 {
702 // "Classification" is always the 9th dimension
703 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(8);
704 std::vector<uint8_t>::size_type const pos = 15;
705 m_data[pos] = static_cast<uint8_t>(cls.GetFlags().to_ulong());
706 }
707
SetClassification(Classification::bitset_type const & flags)708 void Point::SetClassification(Classification::bitset_type const& flags)
709 {
710 // "Classification" is always the 9th dimension
711 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(8);
712 std::vector<uint8_t>::size_type const pos = 15;
713 m_data[pos] = static_cast<uint8_t>(flags.to_ulong());
714 }
715
SetClassification(uint8_t const & flags)716 void Point::SetClassification(uint8_t const& flags)
717 {
718 // "Classification" is always the 9th dimension
719 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(8);
720 std::vector<uint8_t>::size_type const pos = 15;
721 m_data[pos] = flags;
722 }
723
SetScanAngleRank(int8_t const & rank)724 void Point::SetScanAngleRank(int8_t const& rank)
725 {
726 // "Scan Angle Rank" is always the 10th dimension
727 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(9);
728 std::vector<uint8_t>::size_type pos = 16;
729
730 m_data[pos] = rank;
731
732 }
GetScanAngleRank() const733 int8_t Point::GetScanAngleRank() const
734 {
735 // "Scan Angle Rank" is always the 10th dimension
736 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(9);
737 std::vector<uint8_t>::size_type pos = 16;
738
739 return m_data[pos];
740 }
741
GetUserData() const742 uint8_t Point::GetUserData() const
743 {
744 // "User Data" is always the 11th dimension
745 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(10);
746 std::vector<uint8_t>::size_type pos = 17;
747 return m_data[pos];
748 }
749
SetUserData(uint8_t const & flags)750 void Point::SetUserData(uint8_t const& flags)
751 {
752 // "User Data" is always the 11th dimension
753 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(10);
754 std::vector<uint8_t>::size_type pos = 17;
755 m_data[pos] = flags;
756 }
757
GetPointSourceID() const758 uint16_t Point::GetPointSourceID() const
759 {
760
761 // "Point Source ID" is always the 12th dimension
762 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(11);
763 std::vector<uint8_t>::size_type pos = 18;
764
765 #ifdef LIBLAS_ENDIAN_AWARE
766 uint16_t output = liblas::detail::bitsToInt<uint16_t>(output, m_data, pos);
767 return output;
768 #else
769 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
770 uint16_t* output = reinterpret_cast<uint16_t*>(data);
771 return *output;
772 #endif
773
774 }
775
SetPointSourceID(uint16_t const & id)776 void Point::SetPointSourceID(uint16_t const& id)
777 {
778 // "Point Source ID" is always the 12th dimension
779 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(11);
780 std::vector<uint8_t>::size_type pos = 18;
781 liblas::detail::intToBits<uint16_t>(id, m_data, pos);
782 }
783
SetTime(double const & t)784 void Point::SetTime(double const& t)
785 {
786
787 // "Time" is the 13th dimension if it exists
788 // std::size_t index_pos = 12;
789
790 PointFormatName f = GetHeader()->GetDataFormatId();
791
792 if ( f == ePointFormat0 || f == ePointFormat2 ) {
793 std::ostringstream msg;
794 msg << "Point::SetTime - Unable to set time for ePointFormat0 or ePointFormat2, "
795 << "no Time dimension exists on this format";
796 throw liblas::invalid_format(msg.str());
797 }
798
799 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(index_pos);
800 std::vector<uint8_t>::size_type pos = 20;
801 detail::binary::endian_value<double> value(t);
802 value.store<detail::binary::little_endian_tag>(&m_data[0] + pos);
803 }
804
GetTime() const805 double Point::GetTime() const
806 {
807 PointFormatName f = GetHeader()->GetDataFormatId();
808
809 if (f == ePointFormat0 || f == ePointFormat2)
810 {
811 // std::ostringstream msg;
812 // msg << "Point::GetTime - Unable to get time for ePointFormat0 or ePointFormat2, "
813 // << "no Time dimension exists on this format";
814 // throw std::runtime_error(msg.str());
815 return 0.0;
816 }
817
818 // "Time" is the 13th dimension if it exists
819 // std::size_t const index_pos = 12;
820 // std::vector<uint8_t>::size_type pos = GetDimensionBytePosition(index_pos);
821 std::vector<uint8_t>::size_type pos = 20;
822
823 #ifdef LIBLAS_ENDIAN_AWARE
824 detail::binary::endian_value<double> output;
825 output.load<detail::binary::little_endian_tag>(&m_data[0] + pos);
826 return output;
827 #else
828 uint8_t* data = const_cast<uint8_t*>(&m_data[0] + pos);
829 double* output = reinterpret_cast<double*>(data);
830 return *output;
831 #endif
832
833 }
834
GetColor() const835 Color Point::GetColor() const
836 {
837
838
839 // "Color" starts at the 14th dimension if it exists
840 // std::size_t index_pos = 13;
841
842 Color color;
843 PointFormatName f = GetHeader()->GetDataFormatId();
844
845 if ( f == ePointFormat0 || f == ePointFormat1 ) {
846 return color;
847 }
848
849 assert(!(f == ePointFormat0 || f == ePointFormat1));
850
851
852 std::size_t index_pos = 20;
853
854 if (f == ePointFormat3)
855 index_pos = index_pos + 8; // increment to include position of Time.
856
857
858
859 std::vector<uint8_t>::size_type red_pos = index_pos;
860 std::vector<uint8_t>::size_type green_pos = index_pos + 2;
861 std::vector<uint8_t>::size_type blue_pos = index_pos + 4;
862
863 assert(red_pos <= m_data.size());
864 assert(blue_pos <= m_data.size());
865 assert(green_pos <= m_data.size());
866
867 #ifdef LIBLAS_ENDIAN_AWARE
868 using liblas::detail::bitsToInt;
869 uint16_t red(0);
870 uint16_t green(0);
871 uint16_t blue(0);
872 red = bitsToInt<uint16_t>(red, m_data, red_pos);
873 green = bitsToInt<uint16_t>(green, m_data, green_pos);
874 blue = bitsToInt<uint16_t>(blue, m_data, blue_pos);
875 color[0] = red;
876 color[1] = green;
877 color[2] = blue;
878 #else
879 uint8_t* red_data = const_cast<uint8_t*>(&m_data[0] + red_pos);
880 uint16_t* p_red = reinterpret_cast<uint16_t*>(red_data);
881
882 uint8_t* green_data = const_cast<uint8_t*>(&m_data[0] + green_pos);
883 uint16_t* p_green = reinterpret_cast<uint16_t*>(green_data);
884
885 uint8_t* blue_data = const_cast<uint8_t*>(&m_data[0] + blue_pos);
886 uint16_t* p_blue = reinterpret_cast<uint16_t*>(blue_data);
887
888 color[0] = *p_red;
889 color[1] = *p_green;
890 color[2] = *p_blue;
891 #endif
892
893 return color;
894
895
896 }
897
SetColor(Color const & value)898 void Point::SetColor(Color const& value)
899 {
900
901 // "Color" starts at the 14th dimension if it exists
902 // std::size_t index_pos = 13;
903
904 PointFormatName f = GetHeader()->GetDataFormatId();
905
906 if ( f == ePointFormat0 || f == ePointFormat1 ) {
907 std::ostringstream msg;
908 msg << "Point::SetColor - Unable to set color for ePointFormat0 or ePointFormat1, "
909 << "no Color dimension exists on this format";
910 throw liblas::invalid_format(msg.str());
911 }
912
913 if ( m_data.size() == ePointFormat0 || f == ePointFormat1 ) {
914 std::ostringstream msg;
915 msg << "Point::SetColor - Unable to set color for ePointFormat0 or ePointFormat1, "
916 << "no Color dimension exists on this format";
917 throw liblas::invalid_format(msg.str());
918 }
919
920 using liblas::detail::intToBits;
921
922 std::size_t index_pos = 20;
923
924 if (f == ePointFormat3)
925 index_pos = 28; // increment to include position of Time.
926 if (f == ePointFormat2)
927 index_pos = 20; // increment to include position of Time.
928
929
930 std::vector<uint8_t>::size_type red_pos = index_pos;
931 std::vector<uint8_t>::size_type green_pos = index_pos + 2;
932 std::vector<uint8_t>::size_type blue_pos = index_pos + 4;
933
934 assert(red_pos <= m_data.size());
935 assert(blue_pos <= m_data.size());
936 assert(green_pos <= m_data.size());
937
938 intToBits<uint16_t>(value.GetRed(), m_data, red_pos);
939 intToBits<uint16_t>(value.GetGreen(), m_data, green_pos);
940 intToBits<uint16_t>(value.GetBlue(), m_data, blue_pos);
941 }
942
GetDimensionBytePosition(std::size_t dim_pos) const943 std::vector<uint8_t>::size_type Point::GetDimensionBytePosition(std::size_t dim_pos) const
944 {
945 optional<Dimension const&> d;
946 d = m_header->GetSchema().GetDimension(dim_pos);
947
948 if (!d)
949 {
950 std::ostringstream oss;
951 oss <<"Dimension at position " << dim_pos << " not found";
952 throw liblas_error(oss.str());
953 }
954 return d->GetByteOffset();
955 }
956
GetValue(Dimension const & d) const957 boost::any Point::GetValue(Dimension const& d) const
958 {
959 boost::any output;
960 boost::ignore_unused_variable_warning(d);
961
962 return output;
963 }
964
965 } // namespace liblas
966