Branch data Line data Source code
1 : : /*
2 : : ===============================================================================
3 : :
4 : : FILE: field_point10.hpp
5 : :
6 : : CONTENTS:
7 : :
8 : :
9 : : PROGRAMMERS:
10 : :
11 : : martin.isenburg@rapidlasso.com - http://rapidlasso.com
12 : : uday.karan@gmail.com - Hobu, Inc.
13 : :
14 : : COPYRIGHT:
15 : :
16 : : (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
17 : : (c) 2014, Uday Verma, Hobu, Inc.
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 COPYING 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 : : ===============================================================================
29 : : */
30 : :
31 : : #ifndef __las_hpp__
32 : : #error Cannot directly include this file, this is a part of las.hpp
33 : : #endif
34 : :
35 : : namespace laszip {
36 : : namespace formats {
37 : : namespace detail {
38 : : inline int changed_values(const las::point10& this_val, const las::point10& last, unsigned short last_intensity) {
39 : : // This logic here constructs a 5-bit changed value which is basically a bit map of what has changed
40 : : // since the last point, not considering the x, y and z values
41 : : int bitfields_changed = (
42 : : (last.return_number ^ this_val.return_number) |
43 : : (last.number_of_returns_of_given_pulse ^ this_val.number_of_returns_of_given_pulse) |
44 : : (last.scan_direction_flag ^ this_val.scan_direction_flag) |
45 : : (last.edge_of_flight_line ^ this_val.edge_of_flight_line)) != 0;
46 : :
47 : : // last intensity is not checked with last point, but the passed in
48 : : // last intensity value
49 : : int intensity_changed =
50 : : (last_intensity ^ this_val.intensity) != 0;
51 : :
52 : : int classification_changed =
53 : : (last.classification ^ this_val.classification) != 0;
54 : :
55 : : int scan_angle_rank_changed =
56 : : (last.scan_angle_rank ^ this_val.scan_angle_rank) != 0;
57 : :
58 : : int user_data_changed =
59 : : (last.user_data ^ this_val.user_data) != 0;
60 : :
61 : : int point_source_changed =
62 : : (last.point_source_ID ^ this_val.point_source_ID) != 0;
63 : :
64 : : return
65 : : (bitfields_changed << 5) |
66 : : (intensity_changed << 4) |
67 : : (classification_changed << 3) |
68 : : (scan_angle_rank_changed << 2) |
69 : : (user_data_changed << 1) |
70 : : (point_source_changed);
71 : : }
72 : :
73 : 0 : inline unsigned char bitfields_to_char(const las::point10& p) {
74 : 0 : unsigned char a = p.return_number,
75 : 0 : b = p.number_of_returns_of_given_pulse,
76 : 0 : c = p.scan_direction_flag,
77 : 0 : d = p.edge_of_flight_line;
78 : :
79 : 0 : return
80 : 0 : ((d & 0x1) << 7) |
81 : 0 : ((c & 0x1) << 6) |
82 : 0 : ((b & 0x7) << 3) |
83 : 0 : (a & 0x7);
84 : : }
85 : :
86 : 0 : inline void char_to_bitfields(unsigned char d, las::point10& p) {
87 : 0 : p.return_number = d & 0x7;
88 : 0 : p.number_of_returns_of_given_pulse = (d >> 3) & 0x7;
89 : 0 : p.scan_direction_flag = (d >> 6) & 0x1;
90 : 0 : p.edge_of_flight_line = (d >> 7) & 0x1;
91 : 0 : }
92 : : }
93 : :
94 : : // Teach packers how to pack unpack the point10 struct
95 : : //
96 : : template<>
97 : : struct packers<las::point10> {
98 : 0 : inline static las::point10 unpack(const char *in) {
99 : : // blind casting will cause problems for ARM and Emscripten targets
100 : : //
101 : 0 : las::point10 p;
102 : :
103 : 0 : p.x = packers<int>::unpack(in); in += sizeof(int);
104 : 0 : p.y = packers<int>::unpack(in); in += sizeof(int);
105 : 0 : p.z = packers<int>::unpack(in); in += sizeof(int);
106 : 0 : p.intensity = packers<unsigned short>::unpack(in); in += sizeof(unsigned short);
107 : :
108 : 0 : unsigned char d =
109 : 0 : packers<unsigned char>::unpack(in); in += sizeof(unsigned char);
110 : :
111 : : // unpack read bitfields into p
112 : 0 : detail::char_to_bitfields(d, p);
113 : :
114 : 0 : p.classification =
115 : 0 : packers<unsigned char>::unpack(in); in += sizeof(unsigned char);
116 : :
117 : 0 : p.scan_angle_rank = packers<char>::unpack(in); in += sizeof(char);
118 : 0 : p.user_data = packers<char>::unpack(in); in += sizeof(char);
119 : 0 : p.point_source_ID =
120 : 0 : packers<unsigned short>::unpack(in);
121 : :
122 : 0 : return p;
123 : : }
124 : :
125 : 0 : inline static void pack(const las::point10& p, char *buffer) {
126 : 0 : packers<int>::pack(p.x, buffer); buffer += sizeof(int);
127 : 0 : packers<int>::pack(p.y, buffer); buffer += sizeof(int);
128 : 0 : packers<int>::pack(p.z, buffer); buffer += sizeof(int);
129 : :
130 : 0 : packers<unsigned short>::pack(p.intensity, buffer); buffer += sizeof(unsigned short);
131 : :
132 : : // pack bitfields into a char
133 : 0 : unsigned char e = detail::bitfields_to_char(p);
134 : :
135 : 0 : packers<unsigned char>::pack(e, buffer); buffer += sizeof(unsigned char);
136 : 0 : packers<unsigned char>::pack(
137 : 0 : p.classification, buffer); buffer += sizeof(unsigned char);
138 : :
139 : 0 : packers<char>::pack(p.scan_angle_rank, buffer); buffer += sizeof(char);
140 : 0 : packers<char>::pack(p.user_data, buffer); buffer += sizeof(char);
141 : 0 : packers<unsigned short>::pack(
142 : 0 : p.point_source_ID, buffer);
143 : :
144 : 0 : }
145 : : };
146 : :
147 : : // specialize field to compress point 10
148 : : //
149 : : template<>
150 : 0 : struct field<las::point10> {
151 : : typedef las::point10 type;
152 : :
153 : 0 : field() : compressor_inited_(false), decompressors_inited_(false) { }
154 : :
155 : : template<
156 : : typename TEncoder
157 : : >
158 : : inline const char *compressWith(TEncoder& enc, const char *buf)
159 : : {
160 : :
161 : : las::point10 this_val;
162 : : this_val = packers<las::point10>::unpack(buf);
163 : :
164 : : if (!compressor_inited_) {
165 : : compressors_.init();
166 : : compressor_inited_ = true;
167 : : }
168 : :
169 : : if (!common_.have_last_) {
170 : : // don't have the first data yet, just push it to our have last stuff and move on
171 : : common_.have_last_ = true;
172 : : common_.last_ = this_val;
173 : :
174 : : // write this out to the encoder as it is
175 : : enc.getOutStream().putBytes((const unsigned char*)buf,
176 : : sizeof(las::point10));
177 : : return buf + sizeof(las::point10);
178 : : }
179 : :
180 : : // this is not the first point we're trying to compress, do crazy things
181 : : //
182 : : unsigned int r = this_val.return_number,
183 : : n = this_val.number_of_returns_of_given_pulse,
184 : : m = utils::number_return_map[n][r],
185 : : l = utils::number_return_level[n][r];
186 : :
187 : : unsigned int k_bits;
188 : : int median, diff;
189 : :
190 : : // compress which other values have changed
191 : : int changed_values = detail::changed_values(this_val, common_.last_, common_.last_intensity[m]);
192 : :
193 : : enc.encodeSymbol(common_.m_changed_values, changed_values);
194 : :
195 : : // if any of the bit fields changed, compress them
196 : : if (changed_values & (1 << 5)) {
197 : : unsigned char b = detail::bitfields_to_char(this_val),
198 : : last_b = detail::bitfields_to_char(common_.last_);
199 : : enc.encodeSymbol(*common_.m_bit_byte[last_b], b);
200 : : }
201 : :
202 : : // if the intensity changed, compress it
203 : : if (changed_values & (1 << 4)) {
204 : : compressors_.ic_intensity.compress(enc, common_.last_intensity[m], this_val.intensity, (m < 3 ? m : 3));
205 : : common_.last_intensity[m] = this_val.intensity;
206 : : }
207 : :
208 : : // if the classification has changed, compress it
209 : : if (changed_values & (1 << 3)) {
210 : : enc.encodeSymbol(*common_.m_classification[common_.last_.classification], this_val.classification);
211 : : }
212 : :
213 : : // if the scan angle rank has changed, compress it
214 : : if (changed_values & (1 << 2)) {
215 : : enc.encodeSymbol(*common_.m_scan_angle_rank[this_val.scan_direction_flag],
216 : : U8_FOLD(this_val.scan_angle_rank - common_.last_.scan_angle_rank));
217 : : }
218 : :
219 : : // encode user data if changed
220 : : if (changed_values & (1 << 1)) {
221 : : enc.encodeSymbol(*common_.m_user_data[common_.last_.user_data], this_val.user_data);
222 : : }
223 : :
224 : : // if the point source id was changed, compress it
225 : : if (changed_values & 1) {
226 : : compressors_.ic_point_source_ID.compress(enc, common_.last_.point_source_ID, this_val.point_source_ID, 0);
227 : : }
228 : :
229 : : // compress x coordinate
230 : : median = common_.last_x_diff_median5[m].get();
231 : : diff = this_val.x - common_.last_.x;
232 : : compressors_.ic_dx.compress(enc, median, diff, n == 1);
233 : : common_.last_x_diff_median5[m].add(diff);
234 : :
235 : : // compress y coordinate
236 : : k_bits = compressors_.ic_dx.getK();
237 : : median = common_.last_y_diff_median5[m].get();
238 : : diff = this_val.y - common_.last_.y;
239 : : compressors_.ic_dy.compress(enc, median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
240 : : common_.last_y_diff_median5[m].add(diff);
241 : :
242 : : // compress z coordinate
243 : : k_bits = (compressors_.ic_dx.getK() + compressors_.ic_dy.getK()) / 2;
244 : : compressors_.ic_z.compress(enc, common_.last_height[l], this_val.z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
245 : : common_.last_height[l] = this_val.z;
246 : :
247 : : common_.last_ = this_val;
248 : : return buf + sizeof(las::point10);
249 : : }
250 : :
251 : : template<
252 : : typename TDecoder
253 : : >
254 : 0 : inline char *decompressWith(TDecoder& dec, char *buf)
255 : : {
256 : 0 : if (!decompressors_inited_) {
257 : 0 : decompressors_.init();
258 : 0 : decompressors_inited_ = true;
259 : 0 : }
260 : :
261 : 0 : if (!common_.have_last_) {
262 : : // don't have the first data yet, read the whole point out of the stream
263 : 0 : common_.have_last_ = true;
264 : :
265 : 0 : dec.getInStream().getBytes((unsigned char*)buf,
266 : : sizeof(las::point10));
267 : : // decode this value
268 : 0 : common_.last_ = packers<las::point10>::unpack(buf);
269 : : // we are done here
270 : :
271 : 0 : common_.last_.intensity = 0;
272 : 0 : return buf + sizeof(las::point10);
273 : : }
274 : :
275 : : unsigned int r, n, m, l, k_bits;
276 : : int median, diff;
277 : :
278 : : // decompress which other values have changed
279 : 0 : int changed_values = dec.decodeSymbol(common_.m_changed_values);
280 : 0 : if (changed_values) {
281 : : // there was some change in one of the fields (other than x, y and z)
282 : :
283 : : // decode bit fields if they have changed
284 : 0 : if (changed_values & (1 << 5)) {
285 : 0 : unsigned char b = detail::bitfields_to_char(common_.last_);
286 : 0 : b = (unsigned char)dec.decodeSymbol(*common_.m_bit_byte[b]);
287 : 0 : detail::char_to_bitfields(b, common_.last_);
288 : 0 : }
289 : :
290 : 0 : r = common_.last_.return_number;
291 : 0 : n = common_.last_.number_of_returns_of_given_pulse;
292 : 0 : m = utils::number_return_map[n][r];
293 : 0 : l = utils::number_return_level[n][r];
294 : :
295 : : // decompress the intensity if it has changed
296 : 0 : if (changed_values & (1 << 4)) {
297 : 0 : common_.last_.intensity = static_cast<unsigned short>(decompressors_.ic_intensity.decompress(dec, common_.last_intensity[m], (m < 3 ? m : 3)));
298 : 0 : common_.last_intensity[m] = common_.last_.intensity;
299 : 0 : }
300 : : else {
301 : 0 : common_.last_.intensity = common_.last_intensity[m];
302 : : }
303 : :
304 : : // decompress the classification ... if it has changed
305 : 0 : if (changed_values & (1 << 3)) {
306 : 0 : common_.last_.classification =
307 : 0 : (unsigned char)dec.decodeSymbol(*common_.m_classification[common_.last_.classification]);
308 : 0 : }
309 : :
310 : : // decompress the scan angle rank if needed
311 : 0 : if (changed_values & (1 << 2)) {
312 : 0 : int val = dec.decodeSymbol(*common_.m_scan_angle_rank[common_.last_.scan_direction_flag]);
313 : 0 : common_.last_.scan_angle_rank = static_cast<unsigned char>(U8_FOLD(val + common_.last_.scan_angle_rank));
314 : 0 : }
315 : :
316 : : // decompress the user data
317 : 0 : if (changed_values & (1 << 1)) {
318 : 0 : common_.last_.user_data = (unsigned char)dec.decodeSymbol(*common_.m_user_data[common_.last_.user_data]);
319 : 0 : }
320 : :
321 : : // decompress the point source ID
322 : 0 : if (changed_values & 1) {
323 : 0 : common_.last_.point_source_ID = (unsigned short)decompressors_.ic_point_source_ID.decompress(dec,
324 : 0 : common_.last_.point_source_ID, 0);
325 : 0 : }
326 : 0 : }
327 : : else {
328 : 0 : r = common_.last_.return_number;
329 : 0 : n = common_.last_.number_of_returns_of_given_pulse;
330 : 0 : m = utils::number_return_map[n][r];
331 : 0 : l = utils::number_return_level[n][r];
332 : : }
333 : :
334 : : // decompress x coordinate
335 : 0 : median = common_.last_x_diff_median5[m].get();
336 : :
337 : 0 : diff = decompressors_.ic_dx.decompress(dec, median, n==1);
338 : 0 : common_.last_.x += diff;
339 : 0 : common_.last_x_diff_median5[m].add(diff);
340 : :
341 : : // decompress y coordinate
342 : 0 : median = common_.last_y_diff_median5[m].get();
343 : 0 : k_bits = decompressors_.ic_dx.getK();
344 : 0 : diff = decompressors_.ic_dy.decompress(dec, median, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
345 : 0 : common_.last_.y += diff;
346 : 0 : common_.last_y_diff_median5[m].add(diff);
347 : :
348 : : // decompress z coordinate
349 : 0 : k_bits = (decompressors_.ic_dx.getK() + decompressors_.ic_dy.getK()) / 2;
350 : 0 : common_.last_.z = decompressors_.ic_z.decompress(dec, common_.last_height[l], (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
351 : 0 : common_.last_height[l] = common_.last_.z;
352 : :
353 : 0 : packers<las::point10>::pack(common_.last_, buf);
354 : 0 : return buf + sizeof(las::point10);
355 : 0 : }
356 : :
357 : : // All the things we need to compress a point, group them into structs
358 : : // so we don't have too many names flying around
359 : :
360 : : // Common parts for both a compressor and decompressor go here
361 : : struct __common {
362 : : las::point10 last_;
363 : :
364 : : std::array<unsigned short, 16> last_intensity;
365 : :
366 : : std::array<utils::streaming_median<int>, 16> last_x_diff_median5;
367 : : std::array<utils::streaming_median<int>, 16> last_y_diff_median5;
368 : :
369 : : std::array<int, 8> last_height;
370 : :
371 : : models::arithmetic m_changed_values;
372 : :
373 : : // Arithmetic model has no default constructor, so we store they here as raw pointers
374 : : //
375 : : std::array<models::arithmetic*, 2> m_scan_angle_rank;
376 : : std::array<models::arithmetic*, 256> m_bit_byte;
377 : : std::array<models::arithmetic*, 256> m_classification;
378 : : std::array<models::arithmetic*, 256> m_user_data;
379 : :
380 : : bool have_last_;
381 : :
382 : 0 : __common() :
383 : 0 : m_changed_values(64),
384 : 0 : have_last_(false) {
385 : 0 : last_intensity.fill(0);
386 : :
387 : 0 : m_scan_angle_rank[0] = new models::arithmetic(256);
388 : 0 : m_scan_angle_rank[1] = new models::arithmetic(256);
389 : :
390 : 0 : last_height.fill(0);
391 : :
392 : 0 : for (int i = 0 ; i < 256 ; i ++) {
393 : 0 : m_bit_byte[i] = new models::arithmetic(256);
394 : 0 : m_classification[i] = new models::arithmetic(256);
395 : 0 : m_user_data[i] = new models::arithmetic(256);
396 : 0 : }
397 : 0 : }
398 : :
399 : :
400 : 0 : ~__common() {
401 : 0 : delete m_scan_angle_rank[0];
402 : 0 : delete m_scan_angle_rank[1];
403 : :
404 : 0 : for (int i = 0 ; i < 256 ; i ++) {
405 : 0 : delete m_bit_byte[i];
406 : 0 : delete m_classification[i];
407 : 0 : delete m_user_data[i];
408 : 0 : }
409 : 0 : }
410 : : } common_;
411 : :
412 : : // These compressors are specific to a compressor usage, so we keep them separate here
413 : 0 : struct __compressors {
414 : : compressors::integer ic_intensity;
415 : : compressors::integer ic_point_source_ID;
416 : : compressors::integer ic_dx;
417 : : compressors::integer ic_dy;
418 : : compressors::integer ic_z;
419 : :
420 : 0 : __compressors() :
421 : 0 : ic_intensity(16, 4),
422 : 0 : ic_point_source_ID(16),
423 : 0 : ic_dx(32, 2),
424 : 0 : ic_dy(32, 22),
425 : 0 : ic_z(32, 20) { }
426 : :
427 : : void init() {
428 : : ic_intensity.init();
429 : : ic_point_source_ID.init();
430 : : ic_dx.init();
431 : : ic_dy.init();
432 : : ic_z.init();
433 : : }
434 : : } compressors_;
435 : :
436 : 0 : struct __decompressors {
437 : : decompressors::integer ic_intensity;
438 : : decompressors::integer ic_point_source_ID;
439 : : decompressors::integer ic_dx;
440 : : decompressors::integer ic_dy;
441 : : decompressors::integer ic_z;
442 : :
443 : 0 : __decompressors() :
444 : 0 : ic_intensity(16, 4),
445 : 0 : ic_point_source_ID(16),
446 : 0 : ic_dx(32, 2),
447 : 0 : ic_dy(32, 22),
448 : 0 : ic_z(32, 20) { }
449 : :
450 : 0 : void init() {
451 : 0 : ic_intensity.init();
452 : 0 : ic_point_source_ID.init();
453 : 0 : ic_dx.init();
454 : 0 : ic_dy.init();
455 : 0 : ic_z.init();
456 : 0 : }
457 : : } decompressors_;
458 : :
459 : : bool compressor_inited_;
460 : : bool decompressors_inited_;
461 : : };
462 : : }
463 : : }
|