GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
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// TODO(b/199760123): Make this a wrapper using
16// DynamicIntegerPointsKdTreeEncoder.
17#ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
18#define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
19
20#include <algorithm>
21#include <array>
22#include <memory>
23#include <vector>
24
34
35namespace draco {
36
37// This policy class provides several configurations for the encoder that allow
38// to trade speed vs compression rate. Level 0 is fastest while 10 is the best
39// compression rate. The decoder must select the same level.
40template <int compression_level_t>
44
45template <>
56
57template <>
62
63template <>
68
69template <>
74
75template <>
82
83template <>
89
90// This class encodes a given integer point cloud based on the point cloud
91// compression algorithm in:
92// Olivier Devillers and Pierre-Marie Gandoin
93// "Geometric compression for interactive transmission"
94//
95// In principle the algorithm keeps on splitting the point cloud in the middle
96// while alternating the axes. In 3D this results in an Octree like structure.
97// In each step we encode the number of points in the first half.
98// The algorithm does not preserve the order of points.
99//
100// However, the algorithm here differs from the original as follows:
101// The algorithm keeps on splitting the point cloud in the middle of the axis
102// that keeps the point cloud as clustered as possible, which gives a better
103// compression rate.
104// The number of points is encode by the deviation from the half of the points
105// in the smaller half of the two. This results in a better compression rate as
106// there are more leading zeros, which is then compressed better by the
107// arithmetic encoding.
108//
109// |PointDiT| is a type representing a point with uint32_t coordinates.
110// must provide construction from three uint32_t and operator[].
111template <class PointDiT, int compression_level_t>
114 Policy;
115 typedef typename Policy::NumbersEncoder NumbersEncoder;
116 typedef typename Policy::AxisEncoder AxisEncoder;
117 typedef typename Policy::HalfEncoder HalfEncoder;
118 typedef typename Policy::RemainingBitsEncoder RemainingBitsEncoder;
119
120 public:
121 IntegerPointsKdTreeEncoder() : bit_length_(0) {}
122
123 // Encodes an integer point cloud given by [begin,end) into buffer.
124 // |bit_length| gives the highest bit used for all coordinates.
125 template <class RandomAccessIteratorT>
126 bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end,
127 const uint32_t &bit_length, EncoderBuffer *buffer);
128
129 // Encodes an integer point cloud given by [begin,end) into buffer.
130 template <class RandomAccessIteratorT>
131 bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end,
132 EncoderBuffer *buffer) {
133 return EncodePoints(begin, end, 32, buffer);
134 }
135
136 private:
137 // For the sack of readability of code, we decided to make this exception
138 // from the naming scheme.
139 static constexpr int D = PointTraits<PointDiT>::Dimension();
140 template <class RandomAccessIteratorT>
141 uint32_t GetAxis(RandomAccessIteratorT begin, RandomAccessIteratorT end,
142 const PointDiT &old_base, std::array<uint32_t, D> levels,
143 uint32_t last_axis);
144
145 template <class RandomAccessIteratorT>
146 void EncodeInternal(RandomAccessIteratorT begin, RandomAccessIteratorT end,
147 PointDiT old_base, std::array<uint32_t, D> levels,
148 uint32_t last_axis);
149
150 class Splitter {
151 public:
152 Splitter(int axis, uint32_t value) : axis_(axis), value_(value) {}
153 bool operator()(const PointDiT &a) { return a[axis_] < value_; }
154
155 private:
156 int axis_;
157 uint32_t value_;
158 };
159
160 void EncodeNumber(int nbits, uint32_t value) {
161 numbers_encoder_.EncodeLeastSignificantBits32(nbits, value);
162 }
163
164 template <class RandomAccessIteratorT>
165 struct EncodingStatus {
166 EncodingStatus(
167 RandomAccessIteratorT begin_, RandomAccessIteratorT end_,
168 const PointDiT &old_base_,
169 std::array<uint32_t, PointTraits<PointDiT>::Dimension()> levels_,
170 uint32_t last_axis_)
171 : begin(begin_),
172 end(end_),
173 old_base(old_base_),
174 levels(levels_),
175 last_axis(last_axis_) {
176 num_remaining_points = end - begin;
177 }
178
179 RandomAccessIteratorT begin;
180 RandomAccessIteratorT end;
181 PointDiT old_base;
182 std::array<uint32_t, D> levels;
183 uint32_t last_axis;
184 uint32_t num_remaining_points;
185 friend bool operator<(const EncodingStatus &l, const EncodingStatus &r) {
186 return l.num_remaining_points < r.num_remaining_points;
187 }
188 };
189
190 uint32_t bit_length_;
191 uint32_t num_points_;
192 NumbersEncoder numbers_encoder_;
193 RemainingBitsEncoder remaining_bits_encoder_;
194 AxisEncoder axis_encoder_;
195 HalfEncoder half_encoder_;
196};
197
198template <class PointDiT, int compression_level_t>
199template <class RandomAccessIteratorT>
201 RandomAccessIteratorT begin, RandomAccessIteratorT end,
202 const uint32_t &bit_length, EncoderBuffer *buffer) {
203 bit_length_ = bit_length;
204 num_points_ = end - begin;
205
206 buffer->Encode(bit_length_);
207 buffer->Encode(num_points_);
208 if (num_points_ == 0) {
209 return true;
210 }
211
212 numbers_encoder_.StartEncoding();
213 remaining_bits_encoder_.StartEncoding();
214 axis_encoder_.StartEncoding();
215 half_encoder_.StartEncoding();
216
217 EncodeInternal(begin, end, PointTraits<PointDiT>::Origin(),
219
220 numbers_encoder_.EndEncoding(buffer);
221 remaining_bits_encoder_.EndEncoding(buffer);
222 axis_encoder_.EndEncoding(buffer);
223 half_encoder_.EndEncoding(buffer);
224
225 return true;
226}
227template <class PointDiT, int compression_level_t>
228template <class RandomAccessIteratorT>
229uint32_t IntegerPointsKdTreeEncoder<PointDiT, compression_level_t>::GetAxis(
230 RandomAccessIteratorT begin, RandomAccessIteratorT end,
231 const PointDiT &old_base, std::array<uint32_t, D> levels,
232 uint32_t last_axis) {
233 if (!Policy::select_axis) {
234 return DRACO_INCREMENT_MOD(last_axis, D);
235 }
236
237 // For many points this function selects the axis that should be used
238 // for the split by keeping as many points as possible bundled.
239 // In the best case we do not split the point cloud at all.
240 // For lower number of points, we simply choose the axis that is refined the
241 // least so far.
242
243 DRACO_DCHECK_EQ(true, end - begin != 0);
244
245 uint32_t best_axis = 0;
246 if (end - begin < 64) {
247 for (uint32_t axis = 1; axis < D; ++axis) {
248 if (levels[best_axis] > levels[axis]) {
249 best_axis = axis;
250 }
251 }
252 } else {
253 const uint32_t size = (end - begin);
254 std::array<uint32_t, D> num_remaining_bits =
256 for (int i = 0; i < D; i++) {
257 num_remaining_bits[i] = bit_length_ - levels[i];
258 }
259 PointDiT split(old_base);
260
261 for (int i = 0; i < D; i++) {
262 if (num_remaining_bits[i]) {
263 split[i] += 1 << (num_remaining_bits[i] - 1);
264 }
265 }
266
267 std::array<uint32_t, D> deviations = PointTraits<PointDiT>::ZeroArray();
268 for (auto it = begin; it != end; ++it) {
269 for (int i = 0; i < D; i++) {
270 deviations[i] += ((*it)[i] < split[i]);
271 }
272 }
273 for (int i = 0; i < D; i++) {
274 deviations[i] = std::max(size - deviations[i], deviations[i]);
275 }
276
277 uint32_t max_value = 0;
278 best_axis = 0;
279 for (int i = 0; i < D; i++) {
280 // If axis can be subdivided.
281 if (num_remaining_bits[i]) {
282 // Check if this is the better axis.
283 if (max_value < deviations[i]) {
284 max_value = deviations[i];
285 best_axis = i;
286 }
287 }
288 }
289 axis_encoder_.EncodeLeastSignificantBits32(4, best_axis);
290 }
291
292 return best_axis;
293}
294
295template <class PointDiT, int compression_level_t>
296template <class RandomAccessIteratorT>
297void IntegerPointsKdTreeEncoder<PointDiT, compression_level_t>::EncodeInternal(
298 RandomAccessIteratorT begin, RandomAccessIteratorT end, PointDiT old_base,
299 std::array<uint32_t, D> levels, uint32_t last_axis) {
300 EncodingStatus<RandomAccessIteratorT> init_status(begin, end, old_base,
301 levels, last_axis);
302 typename Policy::template QueuingStrategy<
303 EncodingStatus<RandomAccessIteratorT>>
304 status_q;
305
306 status_q.push(init_status);
307
308 while (!status_q.empty()) {
309 EncodingStatus<RandomAccessIteratorT> status = status_q.front();
310 status_q.pop();
311
312 begin = status.begin;
313 end = status.end;
314 old_base = status.old_base;
315 levels = status.levels;
316 last_axis = status.last_axis;
317
318 const uint32_t axis = GetAxis(begin, end, old_base, levels, last_axis);
319 const uint32_t level = levels[axis];
320 const uint32_t num_remaining_points = end - begin;
321
322 // If this happens all axis are subdivided to the end.
323 if ((bit_length_ - level) == 0) {
324 continue;
325 }
326
327 // Fast encoding of remaining bits if number of points is 1.
328 // Doing this also for 2 gives a slight additional speed up.
329 if (num_remaining_points <= 2) {
330 std::array<uint32_t, D> axes;
331 axes[0] = axis;
332 for (int i = 1; i < D; i++) {
333 axes[i] = DRACO_INCREMENT_MOD(axes[i - 1], D);
334 }
335
336 std::array<uint32_t, D> num_remaining_bits;
337 for (int i = 0; i < D; i++) {
338 num_remaining_bits[i] = bit_length_ - levels[axes[i]];
339 }
340
341 for (uint32_t i = 0; i < num_remaining_points; ++i) {
342 const PointDiT &p = *(begin + i);
343 for (int j = 0; j < D; j++) {
344 if (num_remaining_bits[j]) {
345 remaining_bits_encoder_.EncodeLeastSignificantBits32(
346 num_remaining_bits[j], p[axes[j]]);
347 }
348 }
349 }
350 continue;
351 }
352
353 const uint32_t num_remaining_bits = bit_length_ - level;
354 const uint32_t modifier = 1 << (num_remaining_bits - 1);
355 PointDiT new_base(old_base);
356 new_base[axis] += modifier;
357 const RandomAccessIteratorT split =
358 std::partition(begin, end, Splitter(axis, new_base[axis]));
359
360 DRACO_DCHECK_EQ(true, (end - begin) > 0);
361
362 // Encode number of points in first and second half.
363 const int required_bits = MostSignificantBit(num_remaining_points);
364
365 const uint32_t first_half = split - begin;
366 const uint32_t second_half = end - split;
367 const bool left = first_half < second_half;
368
369 if (first_half != second_half) {
370 half_encoder_.EncodeBit(left);
371 }
372
373 if (left) {
374 EncodeNumber(required_bits, num_remaining_points / 2 - first_half);
375 } else {
376 EncodeNumber(required_bits, num_remaining_points / 2 - second_half);
377 }
378
379 levels[axis] += 1;
380 if (split != begin) {
381 status_q.push(EncodingStatus<RandomAccessIteratorT>(
382 begin, split, old_base, levels, axis));
383 }
384 if (split != end) {
385 status_q.push(EncodingStatus<RandomAccessIteratorT>(split, end, new_base,
386 levels, axis));
387 }
388 }
389}
390
391extern template class IntegerPointsKdTreeEncoder<Point3ui, 0>;
392extern template class IntegerPointsKdTreeEncoder<Point3ui, 1>;
393extern template class IntegerPointsKdTreeEncoder<Point3ui, 2>;
394extern template class IntegerPointsKdTreeEncoder<Point3ui, 3>;
395extern template class IntegerPointsKdTreeEncoder<Point3ui, 4>;
396extern template class IntegerPointsKdTreeEncoder<Point3ui, 5>;
397extern template class IntegerPointsKdTreeEncoder<Point3ui, 6>;
398extern template class IntegerPointsKdTreeEncoder<Point3ui, 7>;
399extern template class IntegerPointsKdTreeEncoder<Point3ui, 8>;
400extern template class IntegerPointsKdTreeEncoder<Point3ui, 9>;
401extern template class IntegerPointsKdTreeEncoder<Point3ui, 10>;
402
403} // namespace draco
404
405#endif // DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_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 encoder_buffer.h:29
bool Encode(const T &data)
Definition encoder_buffer.h:60
Definition folded_integer_bit_encoder.h:33
Definition integer_points_kd_tree_encoder.h:112
IntegerPointsKdTreeEncoder()
Definition integer_points_kd_tree_encoder.h:121
bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end, const uint32_t &bit_length, EncoderBuffer *buffer)
Definition integer_points_kd_tree_encoder.h:200
bool EncodePoints(RandomAccessIteratorT begin, RandomAccessIteratorT end, EncoderBuffer *buffer)
Definition integer_points_kd_tree_encoder.h:131
Definition point_cloud_types.h:49
Definition queuing_policy.h:57
Definition queuing_policy.h:27
Definition rans_bit_encoder.h:28
Definition queuing_policy.h:42
#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
Definition GameApi.h:57
DirectBitEncoder AxisEncoder
Definition integer_points_kd_tree_encoder.h:48
DirectBitEncoder RemainingBitsEncoder
Definition integer_points_kd_tree_encoder.h:50
Stack< T > QueuingStrategy
Definition integer_points_kd_tree_encoder.h:54
DirectBitEncoder HalfEncoder
Definition integer_points_kd_tree_encoder.h:49
DirectBitEncoder NumbersEncoder
Definition integer_points_kd_tree_encoder.h:47
static constexpr bool select_axis
Definition integer_points_kd_tree_encoder.h:51
PriorityQueue< T > QueuingStrategy
Definition integer_points_kd_tree_encoder.h:87
RAnsBitEncoder NumbersEncoder
Definition integer_points_kd_tree_encoder.h:60
FoldedBit32Encoder< RAnsBitEncoder > NumbersEncoder
Definition integer_points_kd_tree_encoder.h:66
static constexpr bool select_axis
Definition integer_points_kd_tree_encoder.h:72
Queue< T > QueuingStrategy
Definition integer_points_kd_tree_encoder.h:80
FoldedBit32Encoder< AdaptiveRAnsBitEncoder > NumbersEncoder
Definition integer_points_kd_tree_encoder.h:78
Definition integer_points_kd_tree_encoder.h:43