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