1 /******************************************************************************
2  * Copyright (c) 2015, Hobu Inc.
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following
8  * conditions are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided
15  *       with the distribution.
16  *     * Neither the name of the Martin Isenburg or Iowa Department
17  *       of Natural Resources nor the names of its contributors may be
18  *       used to endorse or promote products derived from this software
19  *       without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32  * OF SUCH DAMAGE.
33  ****************************************************************************/
34 
35 #include "LasUtils.hpp"
36 
37 #include <pdal/util/Extractor.hpp>
38 #include <pdal/util/Inserter.hpp>
39 #include <pdal/util/Utils.hpp>
40 
41 #include <string>
42 
43 namespace pdal
44 {
45 
46 namespace
47 {
48     using DT = Dimension::Type;
49     const Dimension::Type lastypes[] = {
50         DT::None, DT::Unsigned8, DT::Signed8, DT::Unsigned16, DT::Signed16,
51         DT::Unsigned32, DT::Signed32, DT::Unsigned64, DT::Signed64,
52         DT::Float, DT::Double
53     };
54 }
55 
lasType()56 uint8_t ExtraBytesIf::lasType()
57 {
58     uint8_t lastype = 0;
59 
60     for (size_t i = 0; i < sizeof(lastypes) / sizeof(lastypes[0]); ++i)
61         if (m_type == lastypes[i])
62         {
63             lastype = i;
64             break;
65         }
66     if (m_fieldCnt == 0 || lastype == 0)
67         return 0;
68     return 10 * (m_fieldCnt - 1) + lastype;
69 }
70 
71 
setType(uint8_t lastype)72 void ExtraBytesIf::setType(uint8_t lastype)
73 {
74     m_fieldCnt = 1;
75     while (lastype > 10)
76     {
77         m_fieldCnt++;
78         lastype -= 10;
79     }
80 
81     m_type = lastypes[lastype];
82     if (m_type == Dimension::Type::None)
83         m_fieldCnt = 0;
84 }
85 
86 
appendTo(std::vector<uint8_t> & ebBytes)87 void ExtraBytesIf::appendTo(std::vector<uint8_t>& ebBytes)
88 {
89     size_t offset = ebBytes.size();
90     ebBytes.resize(ebBytes.size() + sizeof(ExtraBytesSpec));
91     LeInserter inserter(ebBytes.data() + offset, sizeof(ExtraBytesSpec));
92 
93     uint8_t lastype = lasType();
94     uint8_t options = lastype ? 0 : m_size;
95 
96     inserter << (uint16_t)0 << lastype << options;
97     inserter.put(m_name, 32);
98     inserter << (uint32_t)0;  // Reserved.
99     for (size_t i = 0; i < 3; ++i)
100         inserter << (uint64_t)0;  // No data field.
101     for (size_t i = 0; i < 3; ++i)
102         inserter << (double)0.0; // Min.
103     for (size_t i = 0; i < 3; ++i)
104         inserter << (double)0.0; // Max.
105     for (size_t i = 0; i < 3; ++i)
106         inserter << m_scale[i];
107     for (size_t i = 0; i < 3; ++i)
108         inserter << m_offset[i];
109     inserter.put(m_description, 32);
110 }
111 
112 
readFrom(const char * buf)113 void ExtraBytesIf::readFrom(const char *buf)
114 {
115     LeExtractor extractor(buf, sizeof(ExtraBytesSpec));
116     uint16_t dummy16;
117     uint32_t dummy32;
118     uint64_t dummy64;
119     double dummyd;
120     uint8_t options;
121     uint8_t type;
122 
123     uint8_t SCALE_MASK = 1 << 3;
124     uint8_t OFFSET_MASK = 1 << 4;
125 
126     extractor >> dummy16 >> type >> options;
127     extractor.get(m_name, 32);
128     extractor >> dummy32;
129     for (size_t i = 0; i < 3; ++i)
130         extractor >> dummy64;  // No data field.
131     for (size_t i = 0; i < 3; ++i)
132         extractor >> dummyd;  // Min.
133     for (size_t i = 0; i < 3; ++i)
134         extractor >> dummyd;  // Max.
135     for (size_t i = 0; i < 3; ++i)
136         extractor >> m_scale[i];
137     for (size_t i = 0; i < 3; ++i)
138         extractor >> m_offset[i];
139     extractor.get(m_description, 32);
140 
141     setType(type);
142     if (m_type == Dimension::Type::None)
143         m_size = options;
144     if (!(options & SCALE_MASK))
145         for (size_t i = 0; i < 3; ++i)
146             m_scale[i] = 1.0;
147     if (!(options & OFFSET_MASK))
148         for (size_t i = 0; i < 3; ++i)
149             m_offset[i] = 0.0;
150 }
151 
152 
toExtraDims()153 std::vector<ExtraDim> ExtraBytesIf::toExtraDims()
154 {
155     std::vector<ExtraDim> eds;
156 
157     if (m_type == Dimension::Type::None)
158     {
159         ExtraDim ed(m_name, m_size);
160         eds.push_back(ed);
161     }
162     else if (m_fieldCnt == 1)
163     {
164         ExtraDim ed(m_name, m_type, m_scale[0], m_offset[0]);
165         eds.push_back(ed);
166     }
167     else
168     {
169         for (size_t i = 0; i < m_fieldCnt; ++i)
170         {
171             ExtraDim ed(m_name + std::to_string(i), m_type, m_scale[i], m_offset[i]);
172             eds.push_back(ed);
173         }
174     }
175     return eds;
176 }
177 
178 namespace LasUtils
179 {
180 
parseIgnoreVLRs(const StringList & ignored)181 std::vector<IgnoreVLR> parseIgnoreVLRs(const StringList& ignored)
182 {
183     std::vector<IgnoreVLR> ignoredVLRs;
184     for (auto& v: ignored)
185     {
186 
187         StringList s = Utils::split2(v, '/');
188         if (s.size() == 2)
189         {
190             Utils::trim(s[0]);
191             Utils::trim(s[1]);
192             int i = std::stoi(s[1]);
193             uint16_t id = (uint16_t)i;
194             IgnoreVLR v;
195             v.m_userId = s[0];
196             v.m_recordId = id;
197             ignoredVLRs.push_back(v);
198         } else if (s.size() == 1)
199         {
200             Utils::trim(s[0]);
201             IgnoreVLR v;
202             v.m_userId = s[0];
203             v.m_recordId = 0;
204             ignoredVLRs.push_back(v);
205         } else
206         {
207             throw error("Invalid VLR user_id/record_id specified");
208         }
209     }
210     return ignoredVLRs;
211 
212 }
parse(const StringList & dimString,bool allOk)213 std::vector<ExtraDim> parse(const StringList& dimString, bool allOk)
214 {
215     std::vector<ExtraDim> extraDims;
216     bool all = false;
217 
218     for (auto& dim : dimString)
219     {
220         if (dim == "all")
221         {
222             // We only accept all for LasWriter.
223             if (!allOk)
224                 throw error("Invalid extra dimension specified: '" + dim +
225                     "'.  Need <dimension>=<type>.  See documentation "
226                     " for details.");
227             all = true;
228             continue;
229         }
230 
231         StringList s = Utils::split2(dim, '=');
232         if (s.size() != 2)
233             throw error("Invalid extra dimension specified: '" + dim +
234                 "'.  Need <dimension>=<type>.  See documentation "
235                 " for details.");
236         Utils::trim(s[0]);
237         Utils::trim(s[1]);
238         Dimension::Type type = Dimension::type(s[1]);
239         if (type == Dimension::Type::None)
240             throw error("Invalid extra dimension type specified: '" + dim +
241                 "'.  Need <dimension>=<type>.  See documentation "
242                 " for details.");
243         ExtraDim ed(s[0], type);
244         extraDims.push_back(ed);
245     }
246 
247     if (all)
248     {
249         if (extraDims.size())
250             throw error("Can't specify specific extra dimensions with "
251                 "special 'all' keyword.");
252         extraDims.push_back(ExtraDim("all", Dimension::Type::None));
253     }
254 
255     return extraDims;
256 }
257 
258 } // namespace LasUtils
259 
260 } // namespace pdal
261