1 /*
2 ===============================================================================
3 
4   FILE:  laswriteitemcompressed_v2.cpp
5 
6   CONTENTS:
7 
8     see corresponding header file
9 
10   PROGRAMMERS:
11 
12     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
13 
14   COPYRIGHT:
15 
16     (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality
17 
18     This is free software; you can redistribute and/or modify it under the
19     terms of the GNU Lesser General Licence as published by the Free Software
20     Foundation. See the COPYING file for more information.
21 
22     This software is distributed WITHOUT ANY WARRANTY and without even the
23     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 
25   CHANGE HISTORY:
26 
27     see corresponding header file
28 
29 ===============================================================================
30 */
31 
32 #include "laswriteitemcompressed_v2.hpp"
33 
34 #include <assert.h>
35 #include <string.h>
36 
37 /*
38 ===============================================================================
39                        LASwriteItemCompressed_POINT10_v2
40 ===============================================================================
41 */
42 
43 struct LASpoint10
44 {
45   I32 x;
46   I32 y;
47   I32 z;
48   U16 intensity;
49   U8 return_number : 3;
50   U8 number_of_returns_of_given_pulse : 3;
51   U8 scan_direction_flag : 1;
52   U8 edge_of_flight_line : 1;
53   U8 classification;
54   I8 scan_angle_rank;
55   U8 user_data;
56   U16 point_source_ID;
57 };
58 
LASwriteItemCompressed_POINT10_v2(ArithmeticEncoder * enc)59 LASwriteItemCompressed_POINT10_v2::LASwriteItemCompressed_POINT10_v2(ArithmeticEncoder* enc)
60 {
61   U32 i;
62 
63   /* set encoder */
64   assert(enc);
65   this->enc = enc;
66 
67   /* create models and integer compressors */
68   m_changed_values = enc->createSymbolModel(64);
69   ic_intensity = new IntegerCompressor(enc, 16, 4);
70   m_scan_angle_rank[0] = enc->createSymbolModel(256);
71   m_scan_angle_rank[1] = enc->createSymbolModel(256);
72   ic_point_source_ID = new IntegerCompressor(enc, 16);
73   for (i = 0; i < 256; i++)
74   {
75     m_bit_byte[i] = 0;
76     m_classification[i] = 0;
77     m_user_data[i] = 0;
78   }
79   ic_dx = new IntegerCompressor(enc, 32, 2);  // 32 bits, 2 context
80   ic_dy = new IntegerCompressor(enc, 32, 22); // 32 bits, 22 contexts
81   ic_z = new IntegerCompressor(enc, 32, 20);  // 32 bits, 20 contexts
82 }
83 
~LASwriteItemCompressed_POINT10_v2()84 LASwriteItemCompressed_POINT10_v2::~LASwriteItemCompressed_POINT10_v2()
85 {
86   U32 i;
87 
88   enc->destroySymbolModel(m_changed_values);
89   delete ic_intensity;
90   enc->destroySymbolModel(m_scan_angle_rank[0]);
91   enc->destroySymbolModel(m_scan_angle_rank[1]);
92   delete ic_point_source_ID;
93   for (i = 0; i < 256; i++)
94   {
95     if (m_bit_byte[i]) enc->destroySymbolModel(m_bit_byte[i]);
96     if (m_classification[i]) enc->destroySymbolModel(m_classification[i]);
97     if (m_user_data[i]) enc->destroySymbolModel(m_user_data[i]);
98   }
99   delete ic_dx;
100   delete ic_dy;
101   delete ic_z;
102 }
103 
init(const U8 * item,U32 & context)104 BOOL LASwriteItemCompressed_POINT10_v2::init(const U8* item, U32& context)
105 {
106   U32 i;
107 
108   /* init state */
109   for (i=0; i < 16; i++)
110   {
111     last_x_diff_median5[i].init();
112     last_y_diff_median5[i].init();
113     last_intensity[i] = 0;
114     last_height[i/2] = 0;
115   }
116 
117   /* init models and integer compressors */
118   enc->initSymbolModel(m_changed_values);
119   ic_intensity->initCompressor();
120   enc->initSymbolModel(m_scan_angle_rank[0]);
121   enc->initSymbolModel(m_scan_angle_rank[1]);
122   ic_point_source_ID->initCompressor();
123   for (i = 0; i < 256; i++)
124   {
125     if (m_bit_byte[i]) enc->initSymbolModel(m_bit_byte[i]);
126     if (m_classification[i]) enc->initSymbolModel(m_classification[i]);
127     if (m_user_data[i]) enc->initSymbolModel(m_user_data[i]);
128   }
129   ic_dx->initCompressor();
130   ic_dy->initCompressor();
131   ic_z->initCompressor();
132 
133   /* init last item */
134   memcpy(last_item, item, 20);
135 
136   return TRUE;
137 }
138 
write(const U8 * item,U32 & context)139 inline BOOL LASwriteItemCompressed_POINT10_v2::write(const U8* item, U32& context)
140 {
141   U32 r = ((LASpoint10*)item)->return_number;
142   U32 n = ((LASpoint10*)item)->number_of_returns_of_given_pulse;
143   U32 m = number_return_map[n][r];
144   U32 l = number_return_level[n][r];
145   U32 k_bits;
146   I32 median, diff;
147 
148   // compress which other values have changed
149   I32 changed_values = (((last_item[14] != item[14]) << 5) | // bit_byte
150                         ((last_intensity[m] != ((LASpoint10*)item)->intensity) << 4) |
151                         ((last_item[15] != item[15]) << 3) | // classification
152                         ((last_item[16] != item[16]) << 2) | // scan_angle_rank
153                         ((last_item[17] != item[17]) << 1) | // user_data
154                         (((LASpoint10*)last_item)->point_source_ID != ((LASpoint10*)item)->point_source_ID));
155 
156   enc->encodeSymbol(m_changed_values, changed_values);
157 
158   // compress the bit_byte (edge_of_flight_line, scan_direction_flag, returns, ...) if it has changed
159   if (changed_values & 32)
160   {
161     if (m_bit_byte[last_item[14]] == 0)
162     {
163       m_bit_byte[last_item[14]] = enc->createSymbolModel(256);
164       enc->initSymbolModel(m_bit_byte[last_item[14]]);
165     }
166     enc->encodeSymbol(m_bit_byte[last_item[14]], item[14]);
167   }
168 
169   // compress the intensity if it has changed
170   if (changed_values & 16)
171   {
172     ic_intensity->compress(last_intensity[m], ((LASpoint10*)item)->intensity, (m < 3 ? m : 3));
173     last_intensity[m] = ((LASpoint10*)item)->intensity;
174   }
175 
176   // compress the classification ... if it has changed
177   if (changed_values & 8)
178   {
179     if (m_classification[last_item[15]] == 0)
180     {
181       m_classification[last_item[15]] = enc->createSymbolModel(256);
182       enc->initSymbolModel(m_classification[last_item[15]]);
183     }
184     enc->encodeSymbol(m_classification[last_item[15]], item[15]);
185   }
186 
187   // compress the scan_angle_rank ... if it has changed
188   if (changed_values & 4)
189   {
190     enc->encodeSymbol(m_scan_angle_rank[((LASpoint10*)item)->scan_direction_flag], U8_FOLD(item[16]-last_item[16]));
191   }
192 
193   // compress the user_data ... if it has changed
194   if (changed_values & 2)
195   {
196     if (m_user_data[last_item[17]] == 0)
197     {
198       m_user_data[last_item[17]] = enc->createSymbolModel(256);
199       enc->initSymbolModel(m_user_data[last_item[17]]);
200     }
201     enc->encodeSymbol(m_user_data[last_item[17]], item[17]);
202   }
203 
204   // compress the point_source_ID ... if it has changed
205   if (changed_values & 1)
206   {
207     ic_point_source_ID->compress(((LASpoint10*)last_item)->point_source_ID, ((LASpoint10*)item)->point_source_ID);
208   }
209 
210   // compress x coordinate
211   median = last_x_diff_median5[m].get();
212   diff = ((LASpoint10*)item)->x - ((LASpoint10*)last_item)->x;
213   ic_dx->compress(median, diff, n==1);
214   last_x_diff_median5[m].add(diff);
215 
216   // compress y coordinate
217   k_bits = ic_dx->getK();
218   median = last_y_diff_median5[m].get();
219   diff = ((LASpoint10*)item)->y - ((LASpoint10*)last_item)->y;
220   ic_dy->compress(median, diff, (n==1) + ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
221   last_y_diff_median5[m].add(diff);
222 
223   // compress z coordinate
224   k_bits = (ic_dx->getK() + ic_dy->getK()) / 2;
225   ic_z->compress(last_height[l], ((LASpoint10*)item)->z, (n==1) + (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
226   last_height[l] = ((LASpoint10*)item)->z;
227 
228   // copy the last item
229   memcpy(last_item, item, 20);
230   return TRUE;
231 }
232 
233 /*
234 ===============================================================================
235                        LASwriteItemCompressed_GPSTIME11_v2
236 ===============================================================================
237 */
238 
239 #define LASZIP_GPSTIME_MULTI 500
240 #define LASZIP_GPSTIME_MULTI_MINUS -10
241 #define LASZIP_GPSTIME_MULTI_UNCHANGED (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 1)
242 #define LASZIP_GPSTIME_MULTI_CODE_FULL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 2)
243 
244 #define LASZIP_GPSTIME_MULTI_TOTAL (LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS + 6)
245 
LASwriteItemCompressed_GPSTIME11_v2(ArithmeticEncoder * enc)246 LASwriteItemCompressed_GPSTIME11_v2::LASwriteItemCompressed_GPSTIME11_v2(ArithmeticEncoder* enc)
247 {
248   /* set encoder */
249   assert(enc);
250   this->enc = enc;
251   /* create entropy models and integer compressors */
252   m_gpstime_multi = enc->createSymbolModel(LASZIP_GPSTIME_MULTI_TOTAL);
253   m_gpstime_0diff = enc->createSymbolModel(6);
254   ic_gpstime = new IntegerCompressor(enc, 32, 9); // 32 bits, 9 contexts
255 }
256 
~LASwriteItemCompressed_GPSTIME11_v2()257 LASwriteItemCompressed_GPSTIME11_v2::~LASwriteItemCompressed_GPSTIME11_v2()
258 {
259   enc->destroySymbolModel(m_gpstime_multi);
260   enc->destroySymbolModel(m_gpstime_0diff);
261   delete ic_gpstime;
262 }
263 
init(const U8 * item,U32 & context)264 BOOL LASwriteItemCompressed_GPSTIME11_v2::init(const U8* item, U32& context)
265 {
266   /* init state */
267   last = 0, next = 0;
268   last_gpstime_diff[0] = 0;
269   last_gpstime_diff[1] = 0;
270   last_gpstime_diff[2] = 0;
271   last_gpstime_diff[3] = 0;
272   multi_extreme_counter[0] = 0;
273   multi_extreme_counter[1] = 0;
274   multi_extreme_counter[2] = 0;
275   multi_extreme_counter[3] = 0;
276 
277   /* init models and integer compressors */
278   enc->initSymbolModel(m_gpstime_multi);
279   enc->initSymbolModel(m_gpstime_0diff);
280   ic_gpstime->initCompressor();
281 
282   /* init last item */
283   last_gpstime[0].u64 = *((U64*)item);
284   last_gpstime[1].u64 = 0;
285   last_gpstime[2].u64 = 0;
286   last_gpstime[3].u64 = 0;
287   return TRUE;
288 }
289 
write(const U8 * item,U32 & context)290 inline BOOL LASwriteItemCompressed_GPSTIME11_v2::write(const U8* item, U32& context)
291 {
292   U64I64F64 this_gpstime;
293   this_gpstime.i64 = *((I64*)item);
294 
295   if (last_gpstime_diff[last] == 0) // if the last integer difference was zero
296   {
297     if (this_gpstime.i64 == last_gpstime[last].i64)
298     {
299       enc->encodeSymbol(m_gpstime_0diff, 0); // the doubles have not changed
300     }
301     else
302     {
303       // calculate the difference between the two doubles as an integer
304       I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[last].i64;
305       I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64;
306       if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff))
307       {
308         enc->encodeSymbol(m_gpstime_0diff, 1); // the difference can be represented with 32 bits
309         ic_gpstime->compress(0, curr_gpstime_diff, 0);
310         last_gpstime_diff[last] = curr_gpstime_diff;
311         multi_extreme_counter[last] = 0;
312       }
313       else // the difference is huge
314       {
315         U32 i;
316         // maybe the double belongs to another time sequence
317         for (i = 1; i < 4; i++)
318         {
319           I64 other_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[(last+i)&3].i64;
320           I32 other_gpstime_diff = (I32)other_gpstime_diff_64;
321           if (other_gpstime_diff_64 == (I64)(other_gpstime_diff))
322           {
323             enc->encodeSymbol(m_gpstime_0diff, i+2); // it belongs to another sequence
324             last = (last+i)&3;
325             return write(item, context);
326           }
327         }
328         // no other sequence found. start new sequence.
329         enc->encodeSymbol(m_gpstime_0diff, 2);
330         ic_gpstime->compress((I32)(last_gpstime[last].u64 >> 32), (I32)(this_gpstime.u64 >> 32), 8);
331         enc->writeInt((U32)(this_gpstime.u64));
332         next = (next+1)&3;
333         last = next;
334         last_gpstime_diff[last] = 0;
335         multi_extreme_counter[last] = 0;
336       }
337       last_gpstime[last].i64 = this_gpstime.i64;
338     }
339   }
340   else // the last integer difference was *not* zero
341   {
342     if (this_gpstime.i64 == last_gpstime[last].i64)
343     {
344       // if the doubles have not changed use a special symbol
345       enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_UNCHANGED);
346     }
347     else
348     {
349       // calculate the difference between the two doubles as an integer
350       I64 curr_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[last].i64;
351       I32 curr_gpstime_diff = (I32)curr_gpstime_diff_64;
352 
353       // if the current gpstime difference can be represented with 32 bits
354       if (curr_gpstime_diff_64 == (I64)(curr_gpstime_diff))
355       {
356         // compute multiplier between current and last integer difference
357         F32 multi_f = (F32)curr_gpstime_diff / (F32)(last_gpstime_diff[last]);
358         I32 multi = I32_QUANTIZE(multi_f);
359 
360         // compress the residual curr_gpstime_diff in dependance on the multiplier
361         if (multi == 1)
362         {
363           // this is the case we assume we get most often for regular spaced pulses
364           enc->encodeSymbol(m_gpstime_multi, 1);
365           ic_gpstime->compress(last_gpstime_diff[last], curr_gpstime_diff, 1);
366           multi_extreme_counter[last] = 0;
367         }
368         else if (multi > 0)
369         {
370           if (multi < LASZIP_GPSTIME_MULTI) // positive multipliers up to LASZIP_GPSTIME_MULTI are compressed directly
371           {
372             enc->encodeSymbol(m_gpstime_multi, multi);
373             if (multi < 10)
374               ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 2);
375             else
376               ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 3);
377           }
378           else
379           {
380             enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI);
381             ic_gpstime->compress(LASZIP_GPSTIME_MULTI*last_gpstime_diff[last], curr_gpstime_diff, 4);
382             multi_extreme_counter[last]++;
383             if (multi_extreme_counter[last] > 3)
384             {
385               last_gpstime_diff[last] = curr_gpstime_diff;
386               multi_extreme_counter[last] = 0;
387             }
388           }
389         }
390         else if (multi < 0)
391         {
392           if (multi > LASZIP_GPSTIME_MULTI_MINUS) // negative multipliers larger than LASZIP_GPSTIME_MULTI_MINUS are compressed directly
393           {
394             enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI - multi);
395             ic_gpstime->compress(multi*last_gpstime_diff[last], curr_gpstime_diff, 5);
396           }
397           else
398           {
399             enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI - LASZIP_GPSTIME_MULTI_MINUS);
400             ic_gpstime->compress(LASZIP_GPSTIME_MULTI_MINUS*last_gpstime_diff[last], curr_gpstime_diff, 6);
401             multi_extreme_counter[last]++;
402             if (multi_extreme_counter[last] > 3)
403             {
404               last_gpstime_diff[last] = curr_gpstime_diff;
405               multi_extreme_counter[last] = 0;
406             }
407           }
408         }
409         else
410         {
411           enc->encodeSymbol(m_gpstime_multi, 0);
412           ic_gpstime->compress(0, curr_gpstime_diff, 7);
413           multi_extreme_counter[last]++;
414           if (multi_extreme_counter[last] > 3)
415           {
416             last_gpstime_diff[last] = curr_gpstime_diff;
417             multi_extreme_counter[last] = 0;
418           }
419         }
420       }
421       else // the difference is huge
422       {
423         U32 i;
424         // maybe the double belongs to another time sequence
425         for (i = 1; i < 4; i++)
426         {
427           I64 other_gpstime_diff_64 = this_gpstime.i64 - last_gpstime[(last+i)&3].i64;
428           I32 other_gpstime_diff = (I32)other_gpstime_diff_64;
429           if (other_gpstime_diff_64 == (I64)(other_gpstime_diff))
430           {
431             // it belongs to this sequence
432             enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL+i);
433             last = (last+i)&3;
434             return write(item, context);
435           }
436         }
437         // no other sequence found. start new sequence.
438         enc->encodeSymbol(m_gpstime_multi, LASZIP_GPSTIME_MULTI_CODE_FULL);
439         ic_gpstime->compress((I32)(last_gpstime[last].u64 >> 32), (I32)(this_gpstime.u64 >> 32), 8);
440         enc->writeInt((U32)(this_gpstime.u64));
441         next = (next+1)&3;
442         last = next;
443         last_gpstime_diff[last] = 0;
444         multi_extreme_counter[last] = 0;
445       }
446       last_gpstime[last].i64 = this_gpstime.i64;
447     }
448   }
449   return TRUE;
450 }
451 
452 /*
453 ===============================================================================
454                        LASwriteItemCompressed_RGB12_v2
455 ===============================================================================
456 */
457 
LASwriteItemCompressed_RGB12_v2(ArithmeticEncoder * enc)458 LASwriteItemCompressed_RGB12_v2::LASwriteItemCompressed_RGB12_v2(ArithmeticEncoder* enc)
459 {
460   /* set encoder */
461   assert(enc);
462   this->enc = enc;
463 
464   /* create models and integer compressors */
465   m_byte_used = enc->createSymbolModel(128);
466   m_rgb_diff_0 = enc->createSymbolModel(256);
467   m_rgb_diff_1 = enc->createSymbolModel(256);
468   m_rgb_diff_2 = enc->createSymbolModel(256);
469   m_rgb_diff_3 = enc->createSymbolModel(256);
470   m_rgb_diff_4 = enc->createSymbolModel(256);
471   m_rgb_diff_5 = enc->createSymbolModel(256);
472 }
473 
~LASwriteItemCompressed_RGB12_v2()474 LASwriteItemCompressed_RGB12_v2::~LASwriteItemCompressed_RGB12_v2()
475 {
476   enc->destroySymbolModel(m_byte_used);
477   enc->destroySymbolModel(m_rgb_diff_0);
478   enc->destroySymbolModel(m_rgb_diff_1);
479   enc->destroySymbolModel(m_rgb_diff_2);
480   enc->destroySymbolModel(m_rgb_diff_3);
481   enc->destroySymbolModel(m_rgb_diff_4);
482   enc->destroySymbolModel(m_rgb_diff_5);
483 }
484 
init(const U8 * item,U32 & context)485 BOOL LASwriteItemCompressed_RGB12_v2::init(const U8* item, U32& context)
486 {
487   /* init state */
488 
489   /* init models and integer compressors */
490   enc->initSymbolModel(m_byte_used);
491   enc->initSymbolModel(m_rgb_diff_0);
492   enc->initSymbolModel(m_rgb_diff_1);
493   enc->initSymbolModel(m_rgb_diff_2);
494   enc->initSymbolModel(m_rgb_diff_3);
495   enc->initSymbolModel(m_rgb_diff_4);
496   enc->initSymbolModel(m_rgb_diff_5);
497 
498   /* init last item */
499   memcpy(last_item, item, 6);
500   return TRUE;
501 }
502 
write(const U8 * item,U32 & context)503 inline BOOL LASwriteItemCompressed_RGB12_v2::write(const U8* item, U32& context)
504 {
505   I32 diff_l = 0;
506   I32 diff_h = 0;
507   I32 corr;
508   U32 sym = ((last_item[0]&0x00FF) != (((U16*)item)[0]&0x00FF)) << 0;
509   sym |= ((last_item[0]&0xFF00) != (((U16*)item)[0]&0xFF00)) << 1;
510   sym |= ((last_item[1]&0x00FF) != (((U16*)item)[1]&0x00FF)) << 2;
511   sym |= ((last_item[1]&0xFF00) != (((U16*)item)[1]&0xFF00)) << 3;
512   sym |= ((last_item[2]&0x00FF) != (((U16*)item)[2]&0x00FF)) << 4;
513   sym |= ((last_item[2]&0xFF00) != (((U16*)item)[2]&0xFF00)) << 5;
514   sym |= (((((U16*)item)[0]&0x00FF) != (((U16*)item)[1]&0x00FF)) || ((((U16*)item)[0]&0x00FF) != (((U16*)item)[2]&0x00FF)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[1]&0xFF00)) || ((((U16*)item)[0]&0xFF00) != (((U16*)item)[2]&0xFF00))) << 6;
515   enc->encodeSymbol(m_byte_used, sym);
516   if (sym & (1 << 0))
517   {
518     diff_l = ((int)(((U16*)item)[0]&255)) - (last_item[0]&255);
519     enc->encodeSymbol(m_rgb_diff_0, U8_FOLD(diff_l));
520   }
521   if (sym & (1 << 1))
522   {
523     diff_h = ((int)(((U16*)item)[0]>>8)) - (last_item[0]>>8);
524     enc->encodeSymbol(m_rgb_diff_1, U8_FOLD(diff_h));
525   }
526   if (sym & (1 << 6))
527   {
528     if (sym & (1 << 2))
529     {
530       corr = ((int)(((U16*)item)[1]&255)) - U8_CLAMP(diff_l + (last_item[1]&255));
531       enc->encodeSymbol(m_rgb_diff_2, U8_FOLD(corr));
532     }
533     if (sym & (1 << 4))
534     {
535       diff_l = (diff_l + (((U16*)item)[1]&255) - (last_item[1]&255)) / 2;
536       corr = ((int)(((U16*)item)[2]&255)) - U8_CLAMP(diff_l + (last_item[2]&255));
537       enc->encodeSymbol(m_rgb_diff_4, U8_FOLD(corr));
538     }
539     if (sym & (1 << 3))
540     {
541       corr = ((int)(((U16*)item)[1]>>8)) - U8_CLAMP(diff_h + (last_item[1]>>8));
542       enc->encodeSymbol(m_rgb_diff_3, U8_FOLD(corr));
543     }
544     if (sym & (1 << 5))
545     {
546       diff_h = (diff_h + (((U16*)item)[1]>>8) - (last_item[1]>>8)) / 2;
547       corr = ((int)(((U16*)item)[2]>>8)) - U8_CLAMP(diff_h + (last_item[2]>>8));
548       enc->encodeSymbol(m_rgb_diff_5, U8_FOLD(corr));
549     }
550   }
551   memcpy(last_item, item, 6);
552   return TRUE;
553 }
554 
555 /*
556 ===============================================================================
557                        LASwriteItemCompressed_BYTE_v2
558 ===============================================================================
559 */
560 
LASwriteItemCompressed_BYTE_v2(ArithmeticEncoder * enc,U32 number)561 LASwriteItemCompressed_BYTE_v2::LASwriteItemCompressed_BYTE_v2(ArithmeticEncoder* enc, U32 number)
562 {
563   U32 i;
564 
565   /* set encoder */
566   assert(enc);
567   this->enc = enc;
568   assert(number);
569   this->number = number;
570 
571   /* create models and integer compressors */
572   m_byte = new ArithmeticModel*[number];
573   for (i = 0; i < number; i++)
574   {
575     m_byte[i] = enc->createSymbolModel(256);
576   }
577 
578   /* create last item */
579   last_item = new U8[number];
580 }
581 
~LASwriteItemCompressed_BYTE_v2()582 LASwriteItemCompressed_BYTE_v2::~LASwriteItemCompressed_BYTE_v2()
583 {
584   U32 i;
585   for (i = 0; i < number; i++)
586   {
587     enc->destroySymbolModel(m_byte[i]);
588   }
589   delete [] m_byte;
590   delete [] last_item;
591 }
592 
init(const U8 * item,U32 & context)593 BOOL LASwriteItemCompressed_BYTE_v2::init(const U8* item, U32& context)
594 {
595   U32 i;
596   /* init state */
597 
598   /* init models and integer compressors */
599   for (i = 0; i < number; i++)
600   {
601     enc->initSymbolModel(m_byte[i]);
602   }
603 
604   /* init last point */
605   memcpy(last_item, item, number);
606   return TRUE;
607 }
608 
write(const U8 * item,U32 & context)609 inline BOOL LASwriteItemCompressed_BYTE_v2::write(const U8* item, U32& context)
610 {
611   U32 i;
612   I32 diff;
613   for (i = 0; i < number; i++)
614   {
615     diff = item[i] - last_item[i];
616     enc->encodeSymbol(m_byte[i], U8_FOLD(diff));
617   }
618   memcpy(last_item, item, number);
619   return TRUE;
620 }
621 
622