Skip to content

Commit

Permalink
Merging changes from our private repo:
Browse files Browse the repository at this point in the history
1. More optimized selection of prediction schemes for different
compression levels on the encoder side.

2. Improved robustness to tampered input data (.drc)

3. Added support for strognly typed vectors of bools

4. Support for logging and squared lenght to our VectorND class

5. Added support for partially defined indices in .OBJ files

6. Added support for loading of normal vectors in .PLY files
  • Loading branch information
ondys committed Feb 8, 2017
1 parent 8c0911d commit 8374e14
Show file tree
Hide file tree
Showing 20 changed files with 343 additions and 55 deletions.
Expand Up @@ -16,6 +16,36 @@

namespace draco {

PredictionSchemeMethod SelectPredictionMethod(
int att_id, const PointCloudEncoder *encoder) {
if (encoder->options()->GetSpeed() >= 10) {
return PREDICTION_NONE; // No prediction when the fastest speed is
// requested.
}
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
// Use speed setting to select the best encoding method.
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
if (encoder->options()->GetSpeed() < 4) {
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
return MESH_PREDICTION_TEX_COORDS;
}
}
// Handle other attribute types.
if (encoder->options()->GetSpeed() >= 8) {
return PREDICTION_DIFFERENCE;
}
if (encoder->options()->GetSpeed() >= 2) {
// Parallelogram prediction is used for speeds 2 - 7.
return MESH_PREDICTION_PARALLELOGRAM;
}
// Multi-parallelogram is used for speeds 0, 1.
return MESH_PREDICTION_MULTI_PARALLELOGRAM;
}
// Default option is delta coding.
return PREDICTION_DIFFERENCE;
}

// Returns the preferred prediction scheme based on the encoder options.
PredictionSchemeMethod GetPredictionMethodFromOptions(
int att_id, const EncoderOptions &options) {
Expand Down
Expand Up @@ -23,6 +23,11 @@

namespace draco {

// Selects a prediction method based on the input geometry type and based on the
// encoder options.
PredictionSchemeMethod SelectPredictionMethod(int att_id,
const PointCloudEncoder *encoder);

// Creates a prediction scheme for a given encoder and given prediction method.
// The prediction schemes are automatically initialized with encoder specific
// data if needed.
Expand All @@ -34,23 +39,9 @@ CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id,
const TransformT &transform) {
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
if (method == PREDICTION_UNDEFINED) {
if (encoder->options()->GetSpeed() >= 10) {
return nullptr; // No prediction when the fastest speed is requested.
}
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
// Use speed setting to select the best encoding method.
if (encoder->options()->GetSpeed() >= 8) {
method = PREDICTION_DIFFERENCE;
} else if (encoder->options()->GetSpeed() >= 5) {
method = MESH_PREDICTION_PARALLELOGRAM;
} else {
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
method = MESH_PREDICTION_TEX_COORDS;
} else {
method = MESH_PREDICTION_MULTI_PARALLELOGRAM;
}
}
}
method = SelectPredictionMethod(att_id, encoder);
if (method == PREDICTION_NONE)
return nullptr; // No prediction is used.
}
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
// Cast the encoder to mesh encoder. This is not necessarily safe if there
Expand Down
3 changes: 2 additions & 1 deletion compression/attributes/sequential_attribute_decoder.cc
Expand Up @@ -36,7 +36,8 @@ bool SequentialAttributeDecoder::InitializeStandalone(

bool SequentialAttributeDecoder::Decode(
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
attribute_->Reset(point_ids.size());
if (!attribute_->Reset(point_ids.size()))
return false;
if (!DecodeValues(point_ids, in_buffer))
return false;
return true;
Expand Down
Expand Up @@ -97,9 +97,8 @@ bool SequentialIntegerAttributeEncoder::EncodeValues(
reinterpret_cast<uint32_t *>(values_.data()));
}

if (encoder() == nullptr ||
encoder()->options()->GetGlobalBool("use_built_in_attribute_compression",
true)) {
if (encoder() == nullptr || encoder()->options()->GetGlobalBool(
"use_built_in_attribute_compression", true)) {
out_buffer->Encode(static_cast<uint8_t>(1));
EncodeSymbols(reinterpret_cast<uint32_t *>(values_.data()),
point_ids.size() * num_components, num_components,
Expand Down
2 changes: 1 addition & 1 deletion core/adaptive_rans_coding.cc
Expand Up @@ -83,7 +83,7 @@ bool AdaptiveRAnsBitDecoder::StartDecoding(DecoderBuffer *source_buffer) {
if (!source_buffer->Decode(&size_in_bytes))
return false;
if (size_in_bytes > source_buffer->remaining_size())
return false;
return false;
if (ans_read_init(&ans_decoder_,
reinterpret_cast<uint8_t *>(
const_cast<char *>(source_buffer->data_head())),
Expand Down
13 changes: 11 additions & 2 deletions core/data_buffer.cc
Expand Up @@ -18,7 +18,10 @@ namespace draco {

DataBuffer::DataBuffer() {}

void DataBuffer::Update(const void *data, int64_t size) {
bool DataBuffer::Update(const void *data, int64_t size) {
if (size < 0)
return false;

if (data == nullptr) {
// If no data is provided, just resize the buffer.
data_.resize(size);
Expand All @@ -27,19 +30,25 @@ void DataBuffer::Update(const void *data, int64_t size) {
data_.assign(byte_data, byte_data + size);
}
descriptor_.buffer_update_count++;
return true;
}

void DataBuffer::Update(const void *data, int64_t size, int64_t offset) {
bool DataBuffer::Update(const void *data, int64_t size, int64_t offset) {
if (data == nullptr) {
if (size + offset < 0)
return false;
// If no data is provided, just resize the buffer.
data_.resize(size + offset);
} else {
if (size < 0)
return false;
if (size + offset > static_cast<int64_t>(data_.size()))
data_.resize(size + offset);
const uint8_t *const byte_data = static_cast<const uint8_t *>(data);
std::copy(byte_data, byte_data + size, data_.data() + offset);
}
descriptor_.buffer_update_count++;
return true;
}

void DataBuffer::WriteDataToStream(std::ostream &stream) {
Expand Down
4 changes: 2 additions & 2 deletions core/data_buffer.h
Expand Up @@ -36,10 +36,10 @@ struct DataBufferDescriptor {
class DataBuffer {
public:
DataBuffer();
void Update(const void *data, int64_t size);
bool Update(const void *data, int64_t size);
// TODO(zhafang): The two update functions should be combined. I will
// leave for now in case it breaks any geometry compression tools.
void Update(const void *data, int64_t size, int64_t offset);
bool Update(const void *data, int64_t size, int64_t offset);
void WriteDataToStream(std::ostream &stream);
// Reads data from the buffer. Potentially unsafe, called needs to ensure
// the accessed memory is valid.
Expand Down
11 changes: 7 additions & 4 deletions core/draco_index_type_vector.h
Expand Up @@ -30,6 +30,9 @@ namespace draco {
template <class IndexTypeT, class ValueTypeT>
class IndexTypeVector {
public:
typedef typename std::vector<ValueTypeT>::const_reference const_reference;
typedef typename std::vector<ValueTypeT>::reference reference;

IndexTypeVector() {}
explicit IndexTypeVector(size_t size) : vector_(size) {}
IndexTypeVector(size_t size, const ValueTypeT &val) : vector_(size, val) {}
Expand All @@ -45,16 +48,16 @@ class IndexTypeVector {
void push_back(const ValueTypeT &val) { vector_.push_back(val); }
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }

inline ValueTypeT &operator[](const IndexTypeT &index) {
inline reference operator[](const IndexTypeT &index) {
return vector_[index.value()];
}
inline const ValueTypeT &operator[](const IndexTypeT &index) const {
inline const_reference operator[](const IndexTypeT &index) const {
return vector_[index.value()];
}
inline ValueTypeT &at(const IndexTypeT &index) {
inline reference at(const IndexTypeT &index) {
return vector_[index.value()];
}
inline const ValueTypeT &at(const IndexTypeT &index) const {
inline const_reference at(const IndexTypeT &index) const {
return vector_[index.value()];
}
const ValueTypeT *data() const { return vector_.data(); }
Expand Down
44 changes: 38 additions & 6 deletions core/vector_d.h
Expand Up @@ -24,41 +24,43 @@ namespace draco {
// D-dimensional vector class with basic operations.
template <class CoeffT, int dimension_t>
class VectorD {
public:
typedef VectorD<CoeffT, dimension_t> Self;
typedef CoeffT CoefficientType;
static constexpr int dimension = dimension_t;

public:
VectorD() {
for (int i = 0; i < dimension_t; ++i)
(*this)[i] = CoeffT(0);
}

// The following constructor does not compile in opt mode, which for now led
// to the further down, which is not ideal.
// to the constructors further down, which is not ideal.
// TODO(hemmer): fix constructor below and remove others.
// template <typename... Args>
// explicit VectorD(Args... args) : v_({args...}) {}

VectorD(const CoeffT &c0, const CoeffT &c1) : v_({{c0, c1}}) {
CHECK(dimension_t == 2);
CHECK_EQ(dimension_t, 2);
v_[0] = c0;
v_[1] = c1;
}

VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2)
: v_({{c0, c1, c2}}) {
CHECK(dimension_t == 3);
CHECK_EQ(dimension_t, 3);
}

VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
const CoeffT &c3)
: v_({{c0, c1, c2, c3}}) {
CHECK(dimension_t == 4);
CHECK_EQ(dimension_t, 4);
}

VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
const CoeffT &c3, const CoeffT &c4)
: v_({{c0, c1, c2, c3, c4}}) {
CHECK(dimension_t == 5);
CHECK_EQ(dimension_t, 5);
}

VectorD(const Self &o) {
Expand Down Expand Up @@ -160,6 +162,25 @@ VectorD<CoeffT, dimension_t> operator*(const CoeffT &o,
return v * o;
}

// Calculates the squared distance between two points.
template <class CoeffT, int dimension_t>
CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> v1,
const VectorD<CoeffT, dimension_t> v2) {
CoeffT difference;
CoeffT squared_distance = 0;
// Check each index seperately so difference is never negative and underflow
// is avoided for unsigned types.
for (int i = 0; i < dimension_t; ++i) {
if (v1[i] >= v2[i]) {
difference = v1[i] - v2[i];
} else {
difference = v2[i] - v1[i];
}
squared_distance += (difference * difference);
}
return squared_distance;
}

typedef VectorD<float, 2> Vector2f;
typedef VectorD<float, 3> Vector3f;
typedef VectorD<float, 4> Vector4f;
Expand All @@ -172,4 +193,15 @@ typedef VectorD<uint32_t, 5> Vector5ui;

} // namespace draco

template <typename Char, typename CharTraits, class CoeffT, int dimension_t>
inline ::std::basic_ostream<Char, CharTraits> &operator<<(
::std::basic_ostream<Char, CharTraits> &out,
const draco::VectorD<CoeffT, dimension_t> &vec) {
for (int i = 0; i < dimension_t - 1; ++i) {
out << vec[i] << " ";
}
out << vec[dimension_t - 1];
return out;
}

#endif // DRACO_CORE_VECTOR_D_H_
68 changes: 67 additions & 1 deletion core/vector_d_test.cc
Expand Up @@ -18,10 +18,26 @@

namespace {

using draco::Vector3f;
typedef draco::Vector2f Vector2f;
typedef draco::Vector3f Vector3f;
typedef draco::Vector4f Vector4f;
typedef draco::Vector5f Vector5f;
typedef draco::Vector2ui Vector2ui;
typedef draco::Vector3ui Vector3ui;
typedef draco::Vector4ui Vector4ui;
typedef draco::Vector5ui Vector5ui;

class VectorDTest : public ::testing::Test {
protected:
template <class CoeffT, int dimension_t>
void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1,
const draco::VectorD<CoeffT, dimension_t> v2,
const CoeffT result) {
CoeffT squared_distance = SquaredDistance(v1, v2);
ASSERT_EQ(squared_distance, result);
squared_distance = SquaredDistance(v2, v1);
ASSERT_EQ(squared_distance, result);
}
};

TEST_F(VectorDTest, TestOperators) {
Expand Down Expand Up @@ -69,4 +85,54 @@ TEST_F(VectorDTest, TestOperators) {
ASSERT_EQ(v.Dot(v), 14);
}

TEST_F(VectorDTest, TestSquaredDistance) {
// Test Vector2f: float, 2D.
Vector2f v1_2f(5.5, 10.5);
Vector2f v2_2f(3.5, 15.5);
float result_f = 29;
TestSquaredDistance(v1_2f, v2_2f, result_f);

// Test Vector3f: float, 3D.
Vector3f v1_3f(5.5, 10.5, 2.3);
Vector3f v2_3f(3.5, 15.5, 0);
result_f = 34.29;
TestSquaredDistance(v1_3f, v2_3f, result_f);

// Test Vector4f: float, 4D.
Vector4f v1_4f(5.5, 10.5, 2.3, 7.2);
Vector4f v2_4f(3.5, 15.5, 0, 9.9);
result_f = 41.58;
TestSquaredDistance(v1_4f, v2_4f, result_f);

// Test Vector5f: float, 5D.
Vector5f v1_5f(5.5, 10.5, 2.3, 7.2, 1.0);
Vector5f v2_5f(3.5, 15.5, 0, 9.9, 0.2);
result_f = 42.22;
TestSquaredDistance(v1_5f, v2_5f, result_f);

// Test Vector 2ui: uint32_t, 2D.
Vector2ui v1_2ui(5, 10);
Vector2ui v2_2ui(3, 15);
uint32_t result_ui = 29;
TestSquaredDistance(v1_2ui, v2_2ui, result_ui);

// Test Vector 3ui: uint32_t, 3D.
Vector3ui v1_3ui(5, 10, 2);
Vector3ui v2_3ui(3, 15, 0);
result_ui = 33;
TestSquaredDistance(v1_3ui, v2_3ui, result_ui);

// Test Vector 4ui: uint32_t, 4D.
Vector4ui v1_4ui(5, 10, 2, 7);
Vector4ui v2_4ui(3, 15, 0, 9);
result_ui = 37;
TestSquaredDistance(v1_4ui, v2_4ui, result_ui);

// Test Vector 5ui: uint32_t, 5D.
Vector5ui v1_5ui(5, 10, 2, 7, 1);
Vector5ui v2_5ui(3, 15, 0, 9, 12);
result_ui = 158;
TestSquaredDistance(v1_5ui, v2_5ui, result_ui);
}

} // namespace

0 comments on commit 8374e14

Please sign in to comment.