Branch data Line data Source code
1 : : /*
2 : : ===============================================================================
3 : :
4 : : FILE: field_rgb.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 : : // Teach packers how to pack and unpack rgb
38 : : //
39 : : template<>
40 : : struct packers<las::rgb> {
41 : 0 : inline static las::rgb unpack(const char *in) {
42 : 0 : return las::rgb(packers<uint16_t>::unpack(in),
43 : 0 : packers<uint16_t>::unpack(in+2),
44 : 0 : packers<uint16_t>::unpack(in+4));
45 : :
46 : : }
47 : :
48 : 0 : inline static void pack(const las::rgb& c, char *buffer) {
49 : 0 : packers<uint16_t>::pack(c.r, buffer);
50 : 0 : packers<uint16_t>::pack(c.g, buffer+2);
51 : 0 : packers<uint16_t>::pack(c.b, buffer+4);
52 : 0 : }
53 : : };
54 : :
55 : : namespace detail {
56 : : static inline unsigned int color_diff_bits(const las::rgb& this_val, const las::rgb& last) {
57 : :
58 : : const las::rgb& a = last,
59 : : b = this_val;
60 : :
61 : : #define __flag_diff(x,y,f) ((((x) ^ (y)) & (f)) != 0)
62 : : unsigned int r =
63 : : (__flag_diff(a.r, b.r, 0x00FF) << 0) |
64 : : (__flag_diff(a.r, b.r, 0xFF00) << 1) |
65 : : (__flag_diff(a.g, b.g, 0x00FF) << 2) |
66 : : (__flag_diff(a.g, b.g, 0xFF00) << 3) |
67 : : (__flag_diff(a.b, b.b, 0x00FF) << 4) |
68 : : (__flag_diff(a.b, b.b, 0xFF00) << 5) |
69 : : (__flag_diff(b.r, b.g, 0x00FF) |
70 : : __flag_diff(b.r, b.b, 0x00FF) |
71 : : __flag_diff(b.r, b.g, 0xFF00) |
72 : : __flag_diff(b.r, b.b, 0xFF00)) << 6;
73 : : #undef __flag_diff
74 : :
75 : : return r;
76 : : }
77 : : }
78 : :
79 : : // Figure how to compress and decompress GPS time fields
80 : : //
81 : : template<>
82 : 0 : struct field<las::rgb> {
83 : : typedef las::rgb type;
84 : :
85 : 0 : field():
86 : 0 : have_last_(false),
87 : 0 : last(),
88 : 0 : m_byte_used(128),
89 : 0 : m_rgb_diff_0(256),
90 : 0 : m_rgb_diff_1(256),
91 : 0 : m_rgb_diff_2(256),
92 : 0 : m_rgb_diff_3(256),
93 : 0 : m_rgb_diff_4(256),
94 : 0 : m_rgb_diff_5(256) {}
95 : :
96 : : template<
97 : : typename TEncoder
98 : : >
99 : : inline const char *compressWith(TEncoder& enc, const char *buf)
100 : : {
101 : : las::rgb this_val;
102 : :
103 : : this_val = packers<las::rgb>::unpack(buf);
104 : : if (!have_last_) {
105 : : // don't have the first data yet, just push it to our
106 : : // have last stuff and move on
107 : : have_last_ = true;
108 : : last = this_val;
109 : :
110 : : enc.getOutStream().putBytes((const unsigned char*)buf,
111 : : sizeof(las::rgb));
112 : :
113 : : return buf + sizeof(las::rgb);
114 : : }
115 : :
116 : : // compress color
117 : : int diff_l = 0;
118 : : int diff_h = 0;
119 : : int corr;
120 : :
121 : : unsigned int sym = detail::color_diff_bits(this_val, last);
122 : :
123 : : enc.encodeSymbol(m_byte_used, sym);
124 : :
125 : : // high and low R
126 : : if (sym & (1 << 0)) {
127 : : diff_l = (this_val.r & 0xFF) - (last.r & 0xFF);
128 : : enc.encodeSymbol(m_rgb_diff_0, U8_FOLD(diff_l));
129 : : }
130 : : if (sym & (1 << 1)) {
131 : : diff_h = static_cast<int>(this_val.r >> 8) - (last.r >> 8);
132 : : enc.encodeSymbol(m_rgb_diff_1, U8_FOLD(diff_h));
133 : : }
134 : :
135 : : if (sym & (1 << 6)) {
136 : : if (sym & (1 << 2)) {
137 : : corr = static_cast<int>(this_val.g & 0xFF) - U8_CLAMP(diff_l + (last.g & 0xFF));
138 : : enc.encodeSymbol(m_rgb_diff_2, U8_FOLD(corr));
139 : : }
140 : :
141 : : if (sym & (1 << 4)) {
142 : : diff_l = (diff_l + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2;
143 : : corr = static_cast<int>(this_val.b & 0xFF) - U8_CLAMP(diff_l + (last.b & 0xFF));
144 : : enc.encodeSymbol(m_rgb_diff_4, U8_FOLD(corr));
145 : : }
146 : :
147 : : if (sym & (1 << 3)) {
148 : : corr = static_cast<int>(this_val.g >> 8) - U8_CLAMP(diff_h + (last.g >> 8));
149 : : enc.encodeSymbol(m_rgb_diff_3, U8_FOLD(corr));
150 : : }
151 : :
152 : : if (sym & (1 << 5)) {
153 : : diff_h = (diff_h + ((this_val.g >> 8)) - (last.g >> 8)) / 2;
154 : : corr = static_cast<int>(this_val.b >> 8) - U8_CLAMP(diff_h + (last.b >> 8));
155 : : enc.encodeSymbol(m_rgb_diff_5, U8_FOLD(corr));
156 : : }
157 : : }
158 : :
159 : : last = this_val;
160 : : return buf + sizeof(las::rgb);
161 : : }
162 : :
163 : : template<
164 : : typename TDecoder
165 : : >
166 : 0 : inline char *decompressWith(TDecoder& dec, char *buf)
167 : : {
168 : 0 : if (!have_last_) {
169 : : // don't have the first data yet, read the whole point out of the stream
170 : 0 : have_last_ = true;
171 : :
172 : 0 : dec.getInStream().getBytes((unsigned char*)buf,
173 : : sizeof(las::rgb));
174 : :
175 : 0 : last = packers<las::rgb>::unpack(buf);
176 : 0 : return buf + sizeof(las::rgb);
177 : : }
178 : :
179 : : unsigned char corr;
180 : 0 : int diff = 0;
181 : 0 : unsigned int sym = dec.decodeSymbol(m_byte_used);
182 : :
183 : 0 : las::rgb this_val;
184 : :
185 : 0 : if (sym & (1 << 0)) {
186 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_0));
187 : 0 : this_val.r = static_cast<unsigned short>(U8_FOLD(corr + (last.r & 0xFF)));
188 : 0 : }
189 : : else {
190 : 0 : this_val.r = last.r & 0xFF;
191 : : }
192 : :
193 : 0 : if (sym & (1 << 1)) {
194 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_1));
195 : 0 : this_val.r |= (static_cast<unsigned short>(U8_FOLD(corr + (last.r >> 8))) << 8);
196 : 0 : }
197 : : else {
198 : 0 : this_val.r |= last.r & 0xFF00;
199 : : }
200 : :
201 : 0 : if (sym & (1 << 6)) {
202 : 0 : diff = (this_val.r & 0xFF) - (last.r & 0xFF);
203 : :
204 : 0 : if (sym & (1 << 2)) {
205 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_2));
206 : 0 : this_val.g = static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.g & 0xFF))));
207 : 0 : }
208 : : else {
209 : 0 : this_val.g = last.g & 0xFF;
210 : : }
211 : :
212 : 0 : if (sym & (1 << 4)) {
213 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_4));
214 : 0 : diff = (diff + (this_val.g & 0xFF) - (last.g & 0xFF)) / 2;
215 : 0 : this_val.b = static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff+(last.b & 0xFF))));
216 : 0 : }
217 : : else {
218 : 0 : this_val.b = last.b & 0xFF;
219 : : }
220 : :
221 : :
222 : 0 : diff = (this_val.r >> 8) - (last.r >> 8);
223 : 0 : if (sym & (1 << 3)) {
224 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_3));
225 : 0 : this_val.g |= static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.g >> 8)))) << 8;
226 : 0 : }
227 : : else {
228 : 0 : this_val.g |= last.g & 0xFF00;
229 : : }
230 : :
231 : :
232 : 0 : if (sym & (1 << 5)) {
233 : 0 : corr = static_cast<unsigned char>(dec.decodeSymbol(m_rgb_diff_5));
234 : 0 : diff = (diff + (this_val.g >> 8) - (last.g >> 8)) / 2;
235 : :
236 : 0 : this_val.b |= static_cast<unsigned short>(U8_FOLD(corr + U8_CLAMP(diff + (last.b >> 8)))) << 8;
237 : 0 : }
238 : : else {
239 : 0 : this_val.b |= (last.b & 0xFF00);
240 : : }
241 : 0 : }
242 : : else
243 : : {
244 : 0 : this_val.g = this_val.r;
245 : 0 : this_val.b = this_val.r;
246 : : }
247 : :
248 : 0 : last = this_val;
249 : 0 : packers<las::rgb>::pack(last, buf);
250 : 0 : return buf + sizeof(las::rgb);
251 : 0 : }
252 : :
253 : : // All the things we need to compress a point, group them into structs
254 : : // so we don't have too many names flying around
255 : :
256 : : // Common parts for both a compressor and decompressor go here
257 : : bool have_last_;
258 : : las::rgb last;
259 : :
260 : : models::arithmetic m_byte_used;
261 : : models::arithmetic m_rgb_diff_0,
262 : : m_rgb_diff_1,
263 : : m_rgb_diff_2,
264 : : m_rgb_diff_3,
265 : : m_rgb_diff_4,
266 : : m_rgb_diff_5;
267 : : };
268 : : }
269 : : }
|