// Copyright 2016 The Draco Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef DRACO_POINT_CLOUD_POINT_ATTRIBUTE_H_ #define DRACO_POINT_CLOUD_POINT_ATTRIBUTE_H_ #include #include "core/draco_index_type_vector.h" #include "core/hash_utils.h" #include "core/macros.h" #include "point_cloud/geometry_attribute.h" namespace draco { // Class for storing point specific data about each attribute. In general, // multiple points stored in a point cloud can share the same attribute value // and this class provides the necessary mapping between point ids and attribute // value ids. class PointAttribute : public GeometryAttribute { public: PointAttribute(); explicit PointAttribute(const GeometryAttribute &att); // Make sure the move constructor is defined (needed for better performance // when new attributes are added to PointCloud). PointAttribute(PointAttribute &&attribute) = default; PointAttribute &operator=(PointAttribute &&attribute) = default; // Prepares the attribute storage for the specified number of entries. bool Reset(size_t num_attribute_values); size_t size() const { return num_unique_entries_; } AttributeValueIndex mapped_index(PointIndex point_index) const { if (identity_mapping_) return AttributeValueIndex(point_index.value()); return indices_map_[point_index]; } DataBuffer *buffer() const { return attribute_buffer_.get(); } bool is_mapping_identity() const { return identity_mapping_; } const uint8_t *GetAddressOfMappedIndex(PointIndex point_index) const { return GetAddress(mapped_index(point_index)); } // Sets the new number of unique attribute entries for the attribute. void Resize(size_t new_num_unique_entries) { num_unique_entries_ = new_num_unique_entries; } // Functions for setting the type of mapping between point indices and // attribute entry ids. // This function sets the mapping to implicit, where point indices are equal // to attribute entry indices. void SetIdentityMapping() { identity_mapping_ = true; indices_map_.clear(); } // This function sets the mapping to be explicitly using the indices_map_ // array that needs to be initialized by the caller. void SetExplicitMapping(size_t num_points) { identity_mapping_ = false; indices_map_.resize(num_points, kInvalidAttributeValueIndex); } // Set an explicit map entry for a specific point index. void SetPointMapEntry(PointIndex point_index, AttributeValueIndex entry_index) { DCHECK(!identity_mapping_); indices_map_[point_index] = entry_index; } // Sets a value of an attribute entry. The input value must be allocated to // cover all components of a single attribute entry. void SetAttributeValue(AttributeValueIndex entry_index, const void *value) { const int64_t byte_pos = entry_index.value() * byte_stride(); buffer()->Write(byte_pos, value, byte_stride()); } // Same as GeometryAttribute::GetValue(), but using point id as the input. // Mapping to attribute value index is performed automatically. void GetMappedValue(PointIndex point_index, void *out_data) const { return GetValue(mapped_index(point_index), out_data); } // Deduplicate |in_att| values into |this| attribute. |in_att| can be equal // to |this|. // Returns -1 if the deduplication failed. AttributeValueIndex::ValueType DeduplicateValues( const GeometryAttribute &in_att); // Same as above but the values read from |in_att| are sampled with the // provided offset |in_att_offset|. AttributeValueIndex::ValueType DeduplicateValues( const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); private: template AttributeValueIndex::ValueType DeduplicateTypedValues( const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); template AttributeValueIndex::ValueType DeduplicateFormattedValues( const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); // Data storage for attribute values. GeometryAttribute itself doesn't own its // buffer so we need to allocate it here. std::unique_ptr attribute_buffer_; // Mapping between point ids and attribute value ids. IndexTypeVector indices_map_; AttributeValueIndex::ValueType num_unique_entries_; // Flag when the mapping between point ids and attribute values is identity. bool identity_mapping_; friend struct PointAttributeHasher; }; // Hasher functor for the PointAttribute class. struct PointAttributeHasher { size_t operator()(const PointAttribute &attribute) const { GeometryAttributeHasher base_hasher; size_t hash = base_hasher(attribute); hash = HashCombine(attribute.identity_mapping_, hash); hash = HashCombine(attribute.num_unique_entries_, hash); hash = HashCombine(attribute.indices_map_.size(), hash); if (attribute.indices_map_.size() > 0) { const uint64_t indices_hash = FingerprintString( reinterpret_cast(attribute.indices_map_.data()), attribute.indices_map_.size()); hash = HashCombine(indices_hash, hash); } if (attribute.attribute_buffer_ != nullptr) { const uint64_t buffer_hash = FingerprintString( reinterpret_cast(attribute.attribute_buffer_->data()), attribute.attribute_buffer_->data_size()); hash = HashCombine(buffer_hash, hash); } return hash; } }; } // namespace draco #endif // DRACO_POINT_CLOUD_POINT_ATTRIBUTE_H_