1 /*
2 ===============================================================================
3 
4   FILE:  field_xyz.hpp
5 
6   CONTENTS:
7 	XYZ fields encoder
8 
9 
10   PROGRAMMERS:
11 
12     martin.isenburg@rapidlasso.com  -  http://rapidlasso.com
13     uday.karan@gmail.com - Hobu, Inc.
14 
15   COPYRIGHT:
16 
17     (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
18     (c) 2014, Uday Verma, Hobu, Inc.
19 
20     This is free software; you can redistribute and/or modify it under the
21     terms of the GNU Lesser General Licence as published by the Free Software
22     Foundation. See the COPYING file for more information.
23 
24     This software is distributed WITHOUT ANY WARRANTY and without even the
25     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26 
27   CHANGE HISTORY:
28 
29 ===============================================================================
30 */
31 
32 #ifndef __las_hpp__
33 #error Cannot directly include this file, this is a part of las.hpp
34 #endif
35 
36 namespace laszip {
37 	namespace formats {
38 		// Teach packers how to pack unpack the xyz struct
39 		//
40 		template<>
41 		struct packers<las::xyz> {
unpacklaszip::formats::packers42 			inline static las::xyz unpack(const char *in) {
43 				// blind casting will cause problems for ARM and Emscripten targets
44 				//
45 				las::xyz p;
46 
47 				p.x = packers<int>::unpack(in);						in += sizeof(int);
48 				p.y = packers<int>::unpack(in);						in += sizeof(int);
49 				p.z = packers<int>::unpack(in);
50 
51 				return p;
52 			}
53 
packlaszip::formats::packers54 			inline static void pack(const las::xyz& p, char *buffer) {
55 				packers<int>::pack(p.x, buffer);					buffer += sizeof(int);
56 				packers<int>::pack(p.y, buffer);					buffer += sizeof(int);
57 				packers<int>::pack(p.z, buffer);
58 			}
59 		};
60 
61 		// specialize field to compress point 10
62 		//
63 		template<>
64 		struct field<las::xyz> {
65 			typedef las::xyz type;
66 
fieldlaszip::formats::field67 			field() : compressor_inited_(false), decompressors_inited_(false) { }
68 
69 			template<
70 				typename TEncoder
71 			>
compressWithlaszip::formats::field72             inline const char *compressWith(TEncoder& enc, const char *buf)
73             {
74 				if (!compressor_inited_) {
75 					compressors_.init();
76 					compressor_inited_ = true;
77 				}
78 
79                 las::xyz this_val = packers<las::xyz>::unpack(buf);
80 				if (!common_.have_last_) {
81 					// don't have the first data yet, just push it to our have last stuff and move on
82 					common_.have_last_ = true;
83 					common_.last_ = this_val;
84 
85 					enc.getOutStream().putBytes((const unsigned char*)buf,
86                         sizeof(las::xyz));
87 
88 					// we are done here
89 					return buf + sizeof(las::xyz);
90 				}
91 
92 				unsigned int k_bits;
93 				int median, diff;
94 
95 				// compress x coordinate
96 				median = common_.last_x_diff_median5.get();
97 				diff = this_val.x - common_.last_.x;
98 				compressors_.ic_dx.compress(enc, median, diff, 0);
99 				common_.last_x_diff_median5.add(diff);
100 
101 				// compress y coordinate
102 				k_bits = compressors_.ic_dx.getK();
103 				median = common_.last_y_diff_median5.get();
104 				diff = this_val.y - common_.last_.y;
105 				compressors_.ic_dy.compress(enc, median, diff, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
106 				common_.last_y_diff_median5.add(diff);
107 
108 				// compress z coordinate
109 				k_bits = (compressors_.ic_dx.getK() + compressors_.ic_dy.getK()) / 2;
110 				compressors_.ic_z.compress(enc, common_.last_height, this_val.z, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
111 				common_.last_height = this_val.z;
112 
113 				common_.last_ = this_val;
114                 return buf + sizeof(las::xyz);
115 			}
116 
117 			template<
118 				typename TDecoder
119 			>
decompressWithlaszip::formats::field120 			inline char *decompressWith(TDecoder& dec, char *buf)
121             {
122 				if (!decompressors_inited_) {
123 					decompressors_.init();
124 					decompressors_inited_ = true;
125 				}
126 
127 				if (!common_.have_last_) {
128 					// don't have the first data yet, read the whole point out of the stream
129 					common_.have_last_ = true;
130 
131 					dec.getInStream().getBytes((unsigned char*)buf,
132                         sizeof(las::xyz));
133 
134 					// decode this value
135 					common_.last_ = packers<las::xyz>::unpack(buf);
136 
137 					// we are done here
138 					return buf + sizeof(las::xyz);
139 				}
140 
141 				unsigned int k_bits;
142 				int median, diff;
143 
144 				// decompress x coordinate
145 				median = common_.last_x_diff_median5.get();
146 
147 				diff = decompressors_.ic_dx.decompress(dec, median, 0);
148 				common_.last_.x += diff;
149 				common_.last_x_diff_median5.add(diff);
150 
151 				// decompress y coordinate
152 				median = common_.last_y_diff_median5.get();
153 				k_bits = decompressors_.ic_dx.getK();
154 				diff = decompressors_.ic_dy.decompress(dec, median, ( k_bits < 20 ? U32_ZERO_BIT_0(k_bits) : 20 ));
155 				common_.last_.y += diff;
156 				common_.last_y_diff_median5.add(diff);
157 
158 				// decompress z coordinate
159 				k_bits = (decompressors_.ic_dx.getK() + decompressors_.ic_dy.getK()) / 2;
160 				common_.last_.z = decompressors_.ic_z.decompress(dec, common_.last_height, (k_bits < 18 ? U32_ZERO_BIT_0(k_bits) : 18));
161 				common_.last_height = common_.last_.z;
162 
163                 packers<las::xyz>::pack(common_.last_, buf);
164 				return buf + sizeof(las::xyz);
165 			}
166 
167 			// All the things we need to compress a point, group them into structs
168 			// so we don't have too many names flying around
169 
170 			// Common parts for both a compressor and decompressor go here
171 			struct __common {
172 				type last_;
173 
174 				utils::streaming_median<int>    last_x_diff_median5;
175 				utils::streaming_median<int>    last_y_diff_median5;
176 
177 				int last_height;
178 				bool have_last_;
179 
__commonlaszip::formats::field::__common180 				__common() :
181                     last_height(0),
182 					have_last_(false) {
183 				}
184 
~__commonlaszip::formats::field::__common185 				~__common() {
186 				}
187 			} common_;
188 
189 			// These compressors are specific to a compressor usage, so we keep them separate here
190 			struct __compressors {
191 				compressors::integer ic_dx;
192 				compressors::integer ic_dy;
193 				compressors::integer ic_z;
194 
__compressorslaszip::formats::field::__compressors195 				__compressors() :
196 					ic_dx(32, 2),
197 					ic_dy(32, 22),
198 					ic_z(32, 20) { }
199 
initlaszip::formats::field::__compressors200 				void init() {
201 					ic_dx.init();
202 					ic_dy.init();
203 					ic_z.init();
204 				}
205 			} compressors_;
206 
207 			struct __decompressors {
208 				decompressors::integer ic_dx;
209 				decompressors::integer ic_dy;
210 				decompressors::integer ic_z;
211 
__decompressorslaszip::formats::field::__decompressors212 				__decompressors() :
213 					ic_dx(32, 2),
214 					ic_dy(32, 22),
215 					ic_z(32, 20) { }
216 
initlaszip::formats::field::__decompressors217 				void init() {
218 					ic_dx.init();
219 					ic_dy.init();
220 					ic_z.init();
221 				}
222 			} decompressors_;
223 
224 			bool compressor_inited_;
225 			bool decompressors_inited_;
226 		};
227 	}
228 }
229