Coverage Report

Created: 2024-09-08 06:47

/src/draco/src/draco/attributes/point_attribute.cc
Line
Count
Source (jump to first uncovered line)
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/attributes/point_attribute.h"
16
17
#include <tuple>
18
#include <unordered_map>
19
using std::unordered_map;
20
21
// Shortcut for typed conditionals.
22
template <bool B, class T, class F>
23
using conditional_t = typename std::conditional<B, T, F>::type;
24
25
namespace draco {
26
27
PointAttribute::PointAttribute()
28
0
    : num_unique_entries_(0), identity_mapping_(false) {}
29
30
PointAttribute::PointAttribute(const GeometryAttribute &att)
31
    : GeometryAttribute(att),
32
      num_unique_entries_(0),
33
66.8k
      identity_mapping_(false) {}
34
35
void PointAttribute::Init(Type attribute_type, int8_t num_components,
36
                          DataType data_type, bool normalized,
37
0
                          size_t num_attribute_values) {
38
0
  attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
39
0
  GeometryAttribute::Init(attribute_type, attribute_buffer_.get(),
40
0
                          num_components, data_type, normalized,
41
0
                          DataTypeLength(data_type) * num_components, 0);
42
0
  Reset(num_attribute_values);
43
0
  SetIdentityMapping();
44
0
}
45
46
69
void PointAttribute::CopyFrom(const PointAttribute &src_att) {
47
69
  if (buffer() == nullptr) {
48
    // If the destination attribute doesn't have a valid buffer, create it.
49
0
    attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
50
0
    ResetBuffer(attribute_buffer_.get(), 0, 0);
51
0
  }
52
69
  if (!GeometryAttribute::CopyFrom(src_att)) {
53
0
    return;
54
0
  }
55
69
  identity_mapping_ = src_att.identity_mapping_;
56
69
  num_unique_entries_ = src_att.num_unique_entries_;
57
69
  indices_map_ = src_att.indices_map_;
58
69
  if (src_att.attribute_transform_data_) {
59
4
    attribute_transform_data_ = std::unique_ptr<AttributeTransformData>(
60
4
        new AttributeTransformData(*src_att.attribute_transform_data_));
61
65
  } else {
62
65
    attribute_transform_data_ = nullptr;
63
65
  }
64
69
}
65
66
4.10k
bool PointAttribute::Reset(size_t num_attribute_values) {
67
4.10k
  if (attribute_buffer_ == nullptr) {
68
4.10k
    attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
69
4.10k
  }
70
4.10k
  const int64_t entry_size = DataTypeLength(data_type()) * num_components();
71
4.10k
  if (!attribute_buffer_->Update(nullptr, num_attribute_values * entry_size)) {
72
0
    return false;
73
0
  }
74
  // Assign the new buffer to the parent attribute.
75
4.10k
  ResetBuffer(attribute_buffer_.get(), entry_size, 0);
76
4.10k
  num_unique_entries_ = static_cast<uint32_t>(num_attribute_values);
77
4.10k
  return true;
78
4.10k
}
79
80
0
void PointAttribute::Resize(size_t new_num_unique_entries) {
81
0
  num_unique_entries_ = static_cast<uint32_t>(new_num_unique_entries);
82
0
  attribute_buffer_->Resize(new_num_unique_entries * byte_stride());
83
0
}
84
85
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
86
AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
87
0
    const GeometryAttribute &in_att) {
88
0
  return DeduplicateValues(in_att, AttributeValueIndex(0));
89
0
}
90
91
AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
92
0
    const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
93
0
  AttributeValueIndex::ValueType unique_vals = 0;
94
0
  switch (in_att.data_type()) {
95
    // Currently we support only float, uint8, and uint16 arguments.
96
0
    case DT_FLOAT32:
97
0
      unique_vals = DeduplicateTypedValues<float>(in_att, in_att_offset);
98
0
      break;
99
0
    case DT_INT8:
100
0
      unique_vals = DeduplicateTypedValues<int8_t>(in_att, in_att_offset);
101
0
      break;
102
0
    case DT_UINT8:
103
0
    case DT_BOOL:
104
0
      unique_vals = DeduplicateTypedValues<uint8_t>(in_att, in_att_offset);
105
0
      break;
106
0
    case DT_UINT16:
107
0
      unique_vals = DeduplicateTypedValues<uint16_t>(in_att, in_att_offset);
108
0
      break;
109
0
    case DT_INT16:
110
0
      unique_vals = DeduplicateTypedValues<int16_t>(in_att, in_att_offset);
111
0
      break;
112
0
    case DT_UINT32:
113
0
      unique_vals = DeduplicateTypedValues<uint32_t>(in_att, in_att_offset);
114
0
      break;
115
0
    case DT_INT32:
116
0
      unique_vals = DeduplicateTypedValues<int32_t>(in_att, in_att_offset);
117
0
      break;
118
0
    default:
119
0
      return -1;  // Unsupported data type.
120
0
  }
121
0
  if (unique_vals == 0) {
122
0
    return -1;  // Unexpected error.
123
0
  }
124
0
  return unique_vals;
125
0
}
126
127
// Helper function for calling UnifyDuplicateAttributes<T,num_components_t>
128
// with the correct template arguments.
129
// Returns the number of unique attribute values.
130
template <typename T>
131
AttributeValueIndex::ValueType PointAttribute::DeduplicateTypedValues(
132
0
    const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
133
  // Select the correct method to call based on the number of attribute
134
  // components.
135
0
  switch (in_att.num_components()) {
136
0
    case 1:
137
0
      return DeduplicateFormattedValues<T, 1>(in_att, in_att_offset);
138
0
    case 2:
139
0
      return DeduplicateFormattedValues<T, 2>(in_att, in_att_offset);
140
0
    case 3:
141
0
      return DeduplicateFormattedValues<T, 3>(in_att, in_att_offset);
142
0
    case 4:
143
0
      return DeduplicateFormattedValues<T, 4>(in_att, in_att_offset);
144
0
    default:
145
0
      return 0;
146
0
  }
147
0
}
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<float>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<signed char>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned char>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned short>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<short>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned int>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<int>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
148
149
template <typename T, int num_components_t>
150
AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
151
0
    const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
152
  // We want to detect duplicates using a hash map but we cannot hash floating
153
  // point numbers directly so bit-copy floats to the same sized integers and
154
  // hash them.
155
156
  // First we need to determine which int type to use (1, 2, 4 or 8 bytes).
157
  // Note, this is done at compile time using std::conditional struct.
158
  // Conditional is in form <bool-expression, true, false>. If bool-expression
159
  // is true the "true" branch is used and vice versa. All at compile time.
160
0
  typedef conditional_t<sizeof(T) == 1, uint8_t,
161
0
                        conditional_t<sizeof(T) == 2, uint16_t,
162
0
                                      conditional_t<sizeof(T) == 4, uint32_t,
163
0
                                                    /*else*/ uint64_t>>>
164
0
      HashType;
165
166
0
  AttributeValueIndex unique_vals(0);
167
0
  typedef std::array<T, num_components_t> AttributeValue;
168
0
  typedef std::array<HashType, num_components_t> AttributeHashableValue;
169
0
  typedef unordered_map<AttributeHashableValue, AttributeValueIndex,
170
0
                        HashArray<AttributeHashableValue>>
171
0
      ValueToIndexMap;
172
173
  // Hash map storing index of the first attribute with a given value.
174
0
  ValueToIndexMap value_to_index_map;
175
0
  AttributeValue att_value;
176
0
  AttributeHashableValue hashable_value;
177
0
  IndexTypeVector<AttributeValueIndex, AttributeValueIndex> value_map(
178
0
      num_unique_entries_);
179
0
  for (AttributeValueIndex i(0); i < num_unique_entries_; ++i) {
180
0
    const AttributeValueIndex att_pos = i + in_att_offset;
181
0
    att_value = in_att.GetValue<T, num_components_t>(att_pos);
182
    // Convert the value to hashable type. Bit-copy real attributes to integers.
183
0
    memcpy(&(hashable_value[0]), &(att_value[0]), sizeof(att_value));
184
185
0
    typename ValueToIndexMap::iterator it;
186
0
    bool inserted;
187
0
    std::tie(it, inserted) = value_to_index_map.insert(
188
0
        std::pair<AttributeHashableValue, AttributeValueIndex>(hashable_value,
189
0
                                                               unique_vals));
190
191
    // Try to update the hash map with a new entry pointing to the latest unique
192
    // vertex index.
193
0
    if (!inserted) {
194
      // Duplicated value found. Update index mapping.
195
0
      value_map[i] = it->second;
196
0
    } else {
197
      // New unique value.
198
0
      SetAttributeValue(unique_vals, &att_value);
199
      // Update index mapping.
200
0
      value_map[i] = unique_vals;
201
202
0
      ++unique_vals;
203
0
    }
204
0
  }
205
0
  if (unique_vals == num_unique_entries_) {
206
0
    return unique_vals.value();  // Nothing has changed.
207
0
  }
208
0
  if (is_mapping_identity()) {
209
    // Change identity mapping to the explicit one.
210
    // The number of points is equal to the number of old unique values.
211
0
    SetExplicitMapping(num_unique_entries_);
212
    // Update the explicit map.
213
0
    for (uint32_t i = 0; i < num_unique_entries_; ++i) {
214
0
      SetPointMapEntry(PointIndex(i), value_map[AttributeValueIndex(i)]);
215
0
    }
216
0
  } else {
217
    // Update point to value map using the mapping between old and new values.
218
0
    for (PointIndex i(0); i < static_cast<uint32_t>(indices_map_.size()); ++i) {
219
0
      SetPointMapEntry(i, value_map[indices_map_[i]]);
220
0
    }
221
0
  }
222
0
  num_unique_entries_ = unique_vals.value();
223
0
  return num_unique_entries_;
224
0
}
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>)
225
#endif
226
227
#ifdef DRACO_TRANSCODER_SUPPORTED
228
void PointAttribute::RemoveUnusedValues() {
229
  if (is_mapping_identity()) {
230
    return;  // For identity mapping, all values are always used.
231
  }
232
  // For explicit mapping we need to check if any point is mapped to a value.
233
  // If not we can delete the value.
234
  IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false);
235
  int num_used_values = 0;
236
  for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
237
    const AttributeValueIndex avi = indices_map_[pi];
238
    if (!is_value_used[avi]) {
239
      is_value_used[avi] = true;
240
      num_used_values++;
241
    }
242
  }
243
  if (num_used_values == size()) {
244
    return;  // All values are used.
245
  }
246
247
  // Remap the values and update the point to value mapping.
248
  IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
249
      old_to_new_value_map(size(), kInvalidAttributeValueIndex);
250
  AttributeValueIndex new_avi(0);
251
  for (AttributeValueIndex avi(0); avi < size(); ++avi) {
252
    if (!is_value_used[avi]) {
253
      continue;
254
    }
255
    if (avi != new_avi) {
256
      SetAttributeValue(new_avi, GetAddress(avi));
257
    }
258
    old_to_new_value_map[avi] = new_avi++;
259
  }
260
261
  // Remap all points to the new attribute values.
262
  for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
263
    indices_map_[pi] = old_to_new_value_map[indices_map_[pi]];
264
  }
265
266
  num_unique_entries_ = num_used_values;
267
}
268
#endif
269
270
}  // namespace draco