GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
dynamic_integer_points_kd_tree_encoder.h
Go to the documentation of this file.
1// Copyright 2016 The Draco Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15#ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_DYNAMIC_INTEGER_POINTS_KD_TREE_ENCODER_H_
16#define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_DYNAMIC_INTEGER_POINTS_KD_TREE_ENCODER_H_
17
18#include <algorithm>
19#include <array>
20#include <memory>
21#include <stack>
22#include <vector>
23
32
33namespace draco {
34
35// This policy class provides several configurations for the encoder that allow
36// to trade speed vs compression rate. Level 0 is fastest while 6 is the best
37// compression rate. The decoder must select the same level.
38template <int compression_level_t>
42
43template <>
51
52template <>
57
58template <>
63
64template <>
69
70// This class encodes a given integer point cloud based on the point cloud
71// compression algorithm in:
72// Olivier Devillers and Pierre-Marie Gandoin
73// "Geometric compression for interactive transmission"
74//
75// In principle the algorithm keeps on splitting the point cloud in the middle
76// while alternating the axes. In 3D this results in an Octree like structure.
77// In each step we encode the number of points in the first half.
78// The algorithm does not preserve the order of points.
79//
80// However, the algorithm here differs from the original as follows:
81// The algorithm keeps on splitting the point cloud in the middle of the axis
82// that keeps the point cloud as clustered as possible, which gives a better
83// compression rate.
84// The number of points is encode by the deviation from the half of the points
85// in the smaller half of the two. This results in a better compression rate as
86// there are more leading zeros, which is then compressed better by the
87// arithmetic encoding.
88template <int compression_level_t>
90 static_assert(compression_level_t >= 0, "Compression level must in [0..6].");
91 static_assert(compression_level_t <= 6, "Compression level must in [0..6].");
93 compression_level_t>
94 Policy;
95 typedef typename Policy::NumbersEncoder NumbersEncoder;
96 typedef typename Policy::AxisEncoder AxisEncoder;
97 typedef typename Policy::HalfEncoder HalfEncoder;
98 typedef typename Policy::RemainingBitsEncoder RemainingBitsEncoder;
99 typedef std::vector<uint32_t> VectorUint32;
100
101 public:
103 : bit_length_(0),
104 dimension_(dimension),
105 deviations_(dimension, 0),
106 num_remaining_bits_(dimension, 0),
107 axes_(dimension, 0),
108 base_stack_(32 * dimension + 1, VectorUint32(dimension, 0)),
109 levels_stack_(32 * dimension + 1, VectorUint32(dimension, 0)) {}
110
111 // Encodes an integer point cloud given by [begin,end) into buffer.
112 // |bit_length| gives the highest bit used for all coordinates.
113 template <class RandomAccessIteratorT>
114 bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end,
115 const uint32_t &bit_length, EncoderBuffer *buffer);
116
117 // Encodes an integer point cloud given by [begin,end) into buffer.
118 template <class RandomAccessIteratorT>
119 bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end,
120 EncoderBuffer *buffer) {
121 return EncodePoints(begin, end, 32, buffer);
122 }
123
124 const uint32_t dimension() const { return dimension_; }
125
126 private:
127 template <class RandomAccessIteratorT>
128 uint32_t GetAndEncodeAxis(RandomAccessIteratorT begin,
129 RandomAccessIteratorT end,
130 const VectorUint32 &old_base,
131 const VectorUint32 &levels, uint32_t last_axis);
132 template <class RandomAccessIteratorT>
133 void EncodeInternal(RandomAccessIteratorT begin, RandomAccessIteratorT end);
134
135 class Splitter {
136 public:
137 Splitter(uint32_t axis, uint32_t value) : axis_(axis), value_(value) {}
138 template <class PointT>
139 bool operator()(const PointT &a) const {
140 return a[axis_] < value_;
141 }
142
143 private:
144 const uint32_t axis_;
145 const uint32_t value_;
146 };
147
148 void EncodeNumber(int nbits, uint32_t value) {
149 numbers_encoder_.EncodeLeastSignificantBits32(nbits, value);
150 }
151
152 template <class RandomAccessIteratorT>
153 struct EncodingStatus {
154 EncodingStatus(RandomAccessIteratorT begin_, RandomAccessIteratorT end_,
155 uint32_t last_axis_, uint32_t stack_pos_)
156 : begin(begin_),
157 end(end_),
158 last_axis(last_axis_),
159 stack_pos(stack_pos_) {
160 num_remaining_points = static_cast<uint32_t>(end - begin);
161 }
162
163 RandomAccessIteratorT begin;
164 RandomAccessIteratorT end;
165 uint32_t last_axis;
166 uint32_t num_remaining_points;
167 uint32_t stack_pos; // used to get base and levels
168 };
169
170 uint32_t bit_length_;
171 uint32_t num_points_;
172 uint32_t dimension_;
173 NumbersEncoder numbers_encoder_;
174 RemainingBitsEncoder remaining_bits_encoder_;
175 AxisEncoder axis_encoder_;
176 HalfEncoder half_encoder_;
177 VectorUint32 deviations_;
178 VectorUint32 num_remaining_bits_;
179 VectorUint32 axes_;
180 std::vector<VectorUint32> base_stack_;
181 std::vector<VectorUint32> levels_stack_;
182};
183
184template <int compression_level_t>
185template <class RandomAccessIteratorT>
187 RandomAccessIteratorT begin, RandomAccessIteratorT end,
188 const uint32_t &bit_length, EncoderBuffer *buffer) {
189 bit_length_ = bit_length;
190 num_points_ = static_cast<uint32_t>(end - begin);
191
192 buffer->Encode(bit_length_);
193 buffer->Encode(num_points_);
194 if (num_points_ == 0) {
195 return true;
196 }
197
198 numbers_encoder_.StartEncoding();
199 remaining_bits_encoder_.StartEncoding();
200 axis_encoder_.StartEncoding();
201 half_encoder_.StartEncoding();
202
203 EncodeInternal(begin, end);
204
205 numbers_encoder_.EndEncoding(buffer);
206 remaining_bits_encoder_.EndEncoding(buffer);
207 axis_encoder_.EndEncoding(buffer);
208 half_encoder_.EndEncoding(buffer);
209
210 return true;
211}
212template <int compression_level_t>
213template <class RandomAccessIteratorT>
214uint32_t
215DynamicIntegerPointsKdTreeEncoder<compression_level_t>::GetAndEncodeAxis(
216 RandomAccessIteratorT begin, RandomAccessIteratorT end,
217 const VectorUint32 &old_base, const VectorUint32 &levels,
218 uint32_t last_axis) {
219 if (!Policy::select_axis) {
220 return DRACO_INCREMENT_MOD(last_axis, dimension_);
221 }
222
223 // For many points this function selects the axis that should be used
224 // for the split by keeping as many points as possible bundled.
225 // In the best case we do not split the point cloud at all.
226 // For lower number of points, we simply choose the axis that is refined the
227 // least so far.
228
229 DRACO_DCHECK_EQ(true, end - begin != 0);
230
231 uint32_t best_axis = 0;
232 if (end - begin < 64) {
233 for (uint32_t axis = 1; axis < dimension_; ++axis) {
234 if (levels[best_axis] > levels[axis]) {
235 best_axis = axis;
236 }
237 }
238 } else {
239 const uint32_t size = static_cast<uint32_t>(end - begin);
240 for (uint32_t i = 0; i < dimension_; i++) {
241 deviations_[i] = 0;
242 num_remaining_bits_[i] = bit_length_ - levels[i];
243 if (num_remaining_bits_[i] > 0) {
244 const uint32_t split =
245 old_base[i] + (1 << (num_remaining_bits_[i] - 1));
246 for (auto it = begin; it != end; ++it) {
247 deviations_[i] += ((*it)[i] < split);
248 }
249 deviations_[i] = std::max(size - deviations_[i], deviations_[i]);
250 }
251 }
252
253 uint32_t max_value = 0;
254 best_axis = 0;
255 for (uint32_t i = 0; i < dimension_; i++) {
256 // If axis can be subdivided.
257 if (num_remaining_bits_[i]) {
258 // Check if this is the better axis.
259 if (max_value < deviations_[i]) {
260 max_value = deviations_[i];
261 best_axis = i;
262 }
263 }
264 }
265 axis_encoder_.EncodeLeastSignificantBits32(4, best_axis);
266 }
267
268 return best_axis;
269}
270
271template <int compression_level_t>
272template <class RandomAccessIteratorT>
273void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
274 RandomAccessIteratorT begin, RandomAccessIteratorT end) {
275 typedef EncodingStatus<RandomAccessIteratorT> Status;
276
277 base_stack_[0] = VectorUint32(dimension_, 0);
278 levels_stack_[0] = VectorUint32(dimension_, 0);
279 Status init_status(begin, end, 0, 0);
280 std::stack<Status> status_stack;
281 status_stack.push(init_status);
282
283 // TODO(b/199760123): Use preallocated vector instead of stack.
284 while (!status_stack.empty()) {
285 Status status = status_stack.top();
286 status_stack.pop();
287
288 begin = status.begin;
289 end = status.end;
290 const uint32_t last_axis = status.last_axis;
291 const uint32_t stack_pos = status.stack_pos;
292 const VectorUint32 &old_base = base_stack_[stack_pos];
293 const VectorUint32 &levels = levels_stack_[stack_pos];
294
295 const uint32_t axis =
296 GetAndEncodeAxis(begin, end, old_base, levels, last_axis);
297 const uint32_t level = levels[axis];
298 const uint32_t num_remaining_points = static_cast<uint32_t>(end - begin);
299
300 // If this happens all axis are subdivided to the end.
301 if ((bit_length_ - level) == 0) {
302 continue;
303 }
304
305 // Fast encoding of remaining bits if number of points is 1 or 2.
306 // Doing this also for 2 gives a slight additional speed up.
307 if (num_remaining_points <= 2) {
308 // TODO(b/199760123): |axes_| not necessary, remove would change
309 // bitstream!
310 axes_[0] = axis;
311 for (uint32_t i = 1; i < dimension_; i++) {
312 axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
313 }
314 for (uint32_t i = 0; i < num_remaining_points; ++i) {
315 const auto &p = *(begin + i);
316 for (uint32_t j = 0; j < dimension_; j++) {
317 const uint32_t num_remaining_bits = bit_length_ - levels[axes_[j]];
318 if (num_remaining_bits) {
319 remaining_bits_encoder_.EncodeLeastSignificantBits32(
320 num_remaining_bits, p[axes_[j]]);
321 }
322 }
323 }
324 continue;
325 }
326
327 const uint32_t num_remaining_bits = bit_length_ - level;
328 const uint32_t modifier = 1 << (num_remaining_bits - 1);
329 base_stack_[stack_pos + 1] = old_base; // copy
330 base_stack_[stack_pos + 1][axis] += modifier;
331 const VectorUint32 &new_base = base_stack_[stack_pos + 1];
332
333 const RandomAccessIteratorT split =
334 std::partition(begin, end, Splitter(axis, new_base[axis]));
335
336 DRACO_DCHECK_EQ(true, (end - begin) > 0);
337
338 // Encode number of points in first and second half.
339 const int required_bits = MostSignificantBit(num_remaining_points);
340
341 const uint32_t first_half = static_cast<uint32_t>(split - begin);
342 const uint32_t second_half = static_cast<uint32_t>(end - split);
343 const bool left = first_half < second_half;
344
345 if (first_half != second_half) {
346 half_encoder_.EncodeBit(left);
347 }
348
349 if (left) {
350 EncodeNumber(required_bits, num_remaining_points / 2 - first_half);
351 } else {
352 EncodeNumber(required_bits, num_remaining_points / 2 - second_half);
353 }
354
355 levels_stack_[stack_pos][axis] += 1;
356 levels_stack_[stack_pos + 1] = levels_stack_[stack_pos]; // copy
357 if (split != begin) {
358 status_stack.push(Status(begin, split, axis, stack_pos));
359 }
360 if (split != end) {
361 status_stack.push(Status(split, end, axis, stack_pos + 1));
362 }
363 }
364}
365extern template class DynamicIntegerPointsKdTreeEncoder<0>;
366extern template class DynamicIntegerPointsKdTreeEncoder<2>;
367extern template class DynamicIntegerPointsKdTreeEncoder<4>;
368extern template class DynamicIntegerPointsKdTreeEncoder<6>;
369
370} // namespace draco
371
372#endif // DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_DYNAMIC_INTEGER_POINTS_KD_TREE_ENCODER_H_
void split(std::vector< FontInterfaceImpl::Bezier2d > &vec, FontInterfaceImpl::Bezier2d orig, float t, bool emit_left, bool emit_right)
Definition FreeType2.cc:134
Definition GraphI.hh:2130
Definition direct_bit_encoder.h:25
Definition dynamic_integer_points_kd_tree_encoder.h:89
const uint32_t dimension() const
Definition dynamic_integer_points_kd_tree_encoder.h:124
bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end, EncoderBuffer *buffer)
Definition dynamic_integer_points_kd_tree_encoder.h:119
bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end, const uint32_t &bit_length, EncoderBuffer *buffer)
Definition dynamic_integer_points_kd_tree_encoder.h:186
DynamicIntegerPointsKdTreeEncoder(uint32_t dimension)
Definition dynamic_integer_points_kd_tree_encoder.h:102
Definition encoder_buffer.h:29
bool Encode(const T &data)
Definition encoder_buffer.h:60
Definition folded_integer_bit_encoder.h:33
Definition rans_bit_encoder.h:28
Definition status.h:25
#define DRACO_DCHECK_EQ(a, b)
Definition macros.h:81
#define DRACO_INCREMENT_MOD(I, M)
Definition math_utils.h:24
n< br > font size
Definition meshpage.php:3536
not_this_one end(...)
not_this_one begin(...)
Definition attribute_octahedron_transform.cc:21
int MostSignificantBit(uint32_t n)
Definition bit_utils.h:58
DirectBitEncoder AxisEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:46
DirectBitEncoder HalfEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:47
DirectBitEncoder NumbersEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:45
DirectBitEncoder RemainingBitsEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:48
static constexpr bool select_axis
Definition dynamic_integer_points_kd_tree_encoder.h:49
RAnsBitEncoder NumbersEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:55
FoldedBit32Encoder< RAnsBitEncoder > NumbersEncoder
Definition dynamic_integer_points_kd_tree_encoder.h:61
static constexpr bool select_axis
Definition dynamic_integer_points_kd_tree_encoder.h:67
Definition dynamic_integer_points_kd_tree_encoder.h:41