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_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_
16 #define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_
17 
18 #include <limits>
19 #include <vector>
20 
21 #include "draco/compression/config/compression_shared.h"
22 #include "draco/core/macros.h"
23 
24 namespace draco {
25 
26 // PredictionSchemeWrapTransform uses the min and max bounds of the original
27 // data to wrap stored correction values around these bounds centered at 0,
28 // i.e., when the range of the original values O is between <MIN, MAX> and
29 // N = MAX-MIN, we can then store any correction X = O - P, as:
30 //        X + N,   if X < -N / 2
31 //        X - N,   if X > N / 2
32 //        X        otherwise
33 // To unwrap this value, the decoder then simply checks whether the final
34 // corrected value F = P + X is out of the bounds of the input values.
35 // All out of bounds values are unwrapped using
36 //        F + N,   if F < MIN
37 //        F - N,   if F > MAX
38 // This wrapping can reduce the number of unique values, which translates to a
39 // better entropy of the stored values and better compression rates.
40 template <typename DataTypeT>
41 class PredictionSchemeWrapTransformBase {
42  public:
PredictionSchemeWrapTransformBase()43   PredictionSchemeWrapTransformBase()
44       : num_components_(0),
45         min_value_(0),
46         max_value_(0),
47         max_dif_(0),
48         max_correction_(0),
49         min_correction_(0) {}
50 
GetType()51   static constexpr PredictionSchemeTransformType GetType() {
52     return PREDICTION_TRANSFORM_WRAP;
53   }
54 
Init(int num_components)55   void Init(int num_components) {
56     num_components_ = num_components;
57     clamped_value_.resize(num_components);
58   }
59 
AreCorrectionsPositive()60   bool AreCorrectionsPositive() const { return false; }
61 
ClampPredictedValue(const DataTypeT * predicted_val)62   inline const DataTypeT *ClampPredictedValue(
63       const DataTypeT *predicted_val) const {
64     for (int i = 0; i < this->num_components(); ++i) {
65       if (predicted_val[i] > max_value_) {
66         clamped_value_[i] = max_value_;
67       } else if (predicted_val[i] < min_value_) {
68         clamped_value_[i] = min_value_;
69       } else {
70         clamped_value_[i] = predicted_val[i];
71       }
72     }
73     return &clamped_value_[0];
74   }
75 
76   // TODO(b/199760123): Consider refactoring to avoid this dummy.
quantization_bits()77   int quantization_bits() const {
78     DRACO_DCHECK(false);
79     return -1;
80   }
81 
82  protected:
InitCorrectionBounds()83   bool InitCorrectionBounds() {
84     const int64_t dif =
85         static_cast<int64_t>(max_value_) - static_cast<int64_t>(min_value_);
86     if (dif < 0 || dif >= std::numeric_limits<DataTypeT>::max()) {
87       return false;
88     }
89     max_dif_ = 1 + static_cast<DataTypeT>(dif);
90     max_correction_ = max_dif_ / 2;
91     min_correction_ = -max_correction_;
92     if ((max_dif_ & 1) == 0) {
93       max_correction_ -= 1;
94     }
95     return true;
96   }
97 
num_components()98   inline int num_components() const { return num_components_; }
min_value()99   inline DataTypeT min_value() const { return min_value_; }
set_min_value(const DataTypeT & v)100   inline void set_min_value(const DataTypeT &v) { min_value_ = v; }
max_value()101   inline DataTypeT max_value() const { return max_value_; }
set_max_value(const DataTypeT & v)102   inline void set_max_value(const DataTypeT &v) { max_value_ = v; }
max_dif()103   inline DataTypeT max_dif() const { return max_dif_; }
min_correction()104   inline DataTypeT min_correction() const { return min_correction_; }
max_correction()105   inline DataTypeT max_correction() const { return max_correction_; }
106 
107  private:
108   int num_components_;
109   DataTypeT min_value_;
110   DataTypeT max_value_;
111   DataTypeT max_dif_;
112   DataTypeT max_correction_;
113   DataTypeT min_correction_;
114   // This is in fact just a tmp variable to avoid reallocation.
115   mutable std::vector<DataTypeT> clamped_value_;
116 };
117 
118 }  // namespace draco
119 
120 #endif  // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_WRAP_TRANSFORM_BASE_H_
121