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 #include "draco/compression/point_cloud/algorithms/float_points_tree_decoder.h"
16 
17 #include <algorithm>
18 
19 #include "draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h"
20 #include "draco/compression/point_cloud/algorithms/quantize_points_3.h"
21 #include "draco/core/math_utils.h"
22 #include "draco/core/quantization_utils.h"
23 
24 namespace draco {
25 
26 struct Converter {
27   typedef std::vector<uint32_t> SourceType;
28   typedef Point3ui TargetType;
operator ()draco::Converter29   Point3ui operator()(const std::vector<uint32_t> &v) {
30     return Point3ui(v[0], v[1], v[2]);
31   }
32 };
33 
34 // Output iterator that is used to decode values directly into the data buffer
35 // of the modified PointAttribute.
36 template <class OutputIterator, class Converter>
37 class ConversionOutputIterator {
38   typedef ConversionOutputIterator<OutputIterator, Converter> Self;
39   typedef typename Converter::SourceType SourceType;
40   typedef typename Converter::TargetType TargetType;
41 
42  public:
ConversionOutputIterator(OutputIterator oit)43   explicit ConversionOutputIterator(OutputIterator oit) : oit_(oit) {}
44 
operator ++()45   const Self &operator++() {
46     ++oit_;
47     return *this;
48   }
operator ++(int)49   Self operator++(int) {
50     Self copy = *this;
51     ++oit_;
52     return copy;
53   }
operator *()54   Self &operator*() { return *this; }
operator =(const SourceType & source)55   const Self &operator=(const SourceType &source) {
56     *oit_ = Converter()(source);
57     return *this;
58   }
59 
60  private:
61   OutputIterator oit_;
62 };
63 
FloatPointsTreeDecoder()64 FloatPointsTreeDecoder::FloatPointsTreeDecoder()
65     : num_points_(0), compression_level_(0), num_points_from_header_(0) {
66   qinfo_.quantization_bits = 0;
67   qinfo_.range = 0;
68 }
69 
DecodePointCloudKdTreeInternal(DecoderBuffer * buffer,std::vector<Point3ui> * qpoints)70 bool FloatPointsTreeDecoder::DecodePointCloudKdTreeInternal(
71     DecoderBuffer *buffer, std::vector<Point3ui> *qpoints) {
72   if (!buffer->Decode(&qinfo_.quantization_bits)) {
73     return false;
74   }
75   if (qinfo_.quantization_bits > 31) {
76     return false;
77   }
78   if (!buffer->Decode(&qinfo_.range)) {
79     return false;
80   }
81   if (!buffer->Decode(&num_points_)) {
82     return false;
83   }
84   if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) {
85     return false;
86   }
87   if (!buffer->Decode(&compression_level_)) {
88     return false;
89   }
90 
91   // Only allow compression level in [0..6].
92   if (6 < compression_level_) {
93     DRACO_LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
94                compression_level_);
95     return false;
96   }
97 
98   std::back_insert_iterator<std::vector<Point3ui>> oit_qpoints =
99       std::back_inserter(*qpoints);
100   ConversionOutputIterator<std::back_insert_iterator<std::vector<Point3ui>>,
101                            Converter>
102       oit(oit_qpoints);
103   if (num_points_ > 0) {
104     qpoints->reserve(num_points_);
105     switch (compression_level_) {
106       case 0: {
107         DynamicIntegerPointsKdTreeDecoder<0> qpoints_decoder(3);
108         qpoints_decoder.DecodePoints(buffer, oit);
109         break;
110       }
111       case 1: {
112         DynamicIntegerPointsKdTreeDecoder<1> qpoints_decoder(3);
113         qpoints_decoder.DecodePoints(buffer, oit);
114         break;
115       }
116       case 2: {
117         DynamicIntegerPointsKdTreeDecoder<2> qpoints_decoder(3);
118         qpoints_decoder.DecodePoints(buffer, oit);
119         break;
120       }
121       case 3: {
122         DynamicIntegerPointsKdTreeDecoder<3> qpoints_decoder(3);
123         qpoints_decoder.DecodePoints(buffer, oit);
124         break;
125       }
126       case 4: {
127         DynamicIntegerPointsKdTreeDecoder<4> qpoints_decoder(3);
128         qpoints_decoder.DecodePoints(buffer, oit);
129         break;
130       }
131       case 5: {
132         DynamicIntegerPointsKdTreeDecoder<5> qpoints_decoder(3);
133         qpoints_decoder.DecodePoints(buffer, oit);
134         break;
135       }
136       case 6: {
137         DynamicIntegerPointsKdTreeDecoder<6> qpoints_decoder(3);
138         qpoints_decoder.DecodePoints(buffer, oit);
139         break;
140       }
141       default:
142         return false;
143     }
144   }
145 
146   if (qpoints->size() != num_points_) {
147     return false;
148   }
149   return true;
150 }
151 
152 }  // namespace draco
153