mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-04 11:25:44 +08:00
189 lines
7.2 KiB
C++
189 lines
7.2 KiB
C++
// 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.
|
|
//
|
|
#include "mesh/mesh_are_equivalent.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace draco {
|
|
|
|
void MeshAreEquivalent::PrintPostion(const Mesh &mesh, FaceIndex f, int32_t c) {
|
|
fprintf(stderr, "Printing position for (%i,%i)\n", f.value(), c);
|
|
const auto pos_att = mesh.GetNamedAttribute(GeometryAttribute::POSITION);
|
|
const PointIndex ver_index = mesh.face(f)[c];
|
|
const AttributeValueIndex pos_index = pos_att->mapped_index(ver_index);
|
|
const auto pos = pos_att->GetValue<float, 3>(pos_index);
|
|
fprintf(stderr, "Position (%f,%f,%f)\n", pos[0], pos[1], pos[2]);
|
|
}
|
|
|
|
Vector3f MeshAreEquivalent::GetPostion(const Mesh &mesh, FaceIndex f,
|
|
int32_t c) {
|
|
const auto pos_att = mesh.GetNamedAttribute(GeometryAttribute::POSITION);
|
|
const PointIndex ver_index = mesh.face(f)[c];
|
|
const AttributeValueIndex pos_index = pos_att->mapped_index(ver_index);
|
|
const auto pos = pos_att->GetValue<float, 3>(pos_index);
|
|
return Vector3f(pos[0], pos[1], pos[2]);
|
|
}
|
|
|
|
void MeshAreEquivalent::InitCornerIndexOfSmallestPointXYZ() {
|
|
DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(), 0);
|
|
DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(), 0);
|
|
for (int i = 0; i < 2; ++i) {
|
|
mesh_infos_[i].corner_index_of_smallest_vertex.reserve(num_faces_);
|
|
for (FaceIndex f(0); f < num_faces_; ++f) {
|
|
mesh_infos_[i].corner_index_of_smallest_vertex.push_back(
|
|
ComputeCornerIndexOfSmallestPointXYZ(mesh_infos_[i].mesh, f));
|
|
}
|
|
}
|
|
DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(), num_faces_);
|
|
DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(), num_faces_);
|
|
}
|
|
|
|
void MeshAreEquivalent::InitOrderedFaceIndex() {
|
|
DCHECK_EQ(mesh_infos_[0].ordered_index_of_face.size(), 0);
|
|
DCHECK_EQ(mesh_infos_[1].ordered_index_of_face.size(), 0);
|
|
for (int32_t i = 0; i < 2; ++i) {
|
|
mesh_infos_[i].ordered_index_of_face.reserve(num_faces_);
|
|
for (FaceIndex j(0); j < num_faces_; ++j) {
|
|
mesh_infos_[i].ordered_index_of_face.push_back(j);
|
|
}
|
|
const FaceIndexLess less(mesh_infos_[i]);
|
|
std::sort(mesh_infos_[i].ordered_index_of_face.begin(),
|
|
mesh_infos_[i].ordered_index_of_face.end(), less);
|
|
|
|
DCHECK_EQ(mesh_infos_[i].ordered_index_of_face.size(), num_faces_);
|
|
DCHECK(std::is_sorted(mesh_infos_[i].ordered_index_of_face.begin(),
|
|
mesh_infos_[i].ordered_index_of_face.end(), less));
|
|
}
|
|
}
|
|
|
|
int32_t MeshAreEquivalent::ComputeCornerIndexOfSmallestPointXYZ(
|
|
const Mesh &mesh, FaceIndex f) {
|
|
Vector3f pos[3]; // For the three corners.
|
|
for (int32_t i = 0; i < 3; ++i) {
|
|
pos[i] = GetPostion(mesh, f, i);
|
|
}
|
|
const auto min_it = std::min_element(pos, pos + 3);
|
|
return min_it - pos;
|
|
}
|
|
|
|
void MeshAreEquivalent::Init(const Mesh &mesh0, const Mesh &mesh1) {
|
|
mesh_infos_.clear();
|
|
DCHECK_EQ(mesh_infos_.size(), 0);
|
|
|
|
num_faces_ = mesh1.num_faces();
|
|
mesh_infos_.push_back(MeshInfo(mesh0));
|
|
mesh_infos_.push_back(MeshInfo(mesh1));
|
|
|
|
DCHECK_EQ(mesh_infos_.size(), 2);
|
|
DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(), 0);
|
|
DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(), 0);
|
|
DCHECK_EQ(mesh_infos_[0].ordered_index_of_face.size(), 0);
|
|
DCHECK_EQ(mesh_infos_[1].ordered_index_of_face.size(), 0);
|
|
|
|
InitCornerIndexOfSmallestPointXYZ();
|
|
InitOrderedFaceIndex();
|
|
}
|
|
|
|
bool MeshAreEquivalent::operator()(const Mesh &mesh0, const Mesh &mesh1) {
|
|
if (mesh0.num_faces() != mesh1.num_faces())
|
|
return false;
|
|
if (mesh0.num_attributes() != mesh1.num_attributes())
|
|
return false;
|
|
|
|
// The following function inits mesh info, i.e., computes the order of
|
|
// faces with respect to the lex order. This way one can then compare the
|
|
// the two meshes face by face. It also determines the first corner of each
|
|
// face with respect to lex order.
|
|
Init(mesh0, mesh1);
|
|
|
|
// Check for every attribute that is valid that every corner is identical.
|
|
typedef GeometryAttribute::Type AttributeType;
|
|
const int att_max = AttributeType::NAMED_ATTRIBUTES_COUNT;
|
|
for (int att_id = 0; att_id < att_max; ++att_id) {
|
|
// First check for existence of the attribute in both meshes.
|
|
const PointAttribute *const att0 =
|
|
mesh0.GetNamedAttribute(AttributeType(att_id));
|
|
const PointAttribute *const att1 =
|
|
mesh1.GetNamedAttribute(AttributeType(att_id));
|
|
if (att0 == nullptr && att1 == nullptr)
|
|
continue;
|
|
if (att0 == nullptr)
|
|
return false;
|
|
if (att1 == nullptr)
|
|
return false;
|
|
if (att0->data_type() != att1->data_type())
|
|
return false;
|
|
if (att0->components_count() != att1->components_count())
|
|
return false;
|
|
if (att0->normalized() != att1->normalized())
|
|
return false;
|
|
if (att0->byte_stride() != att1->byte_stride())
|
|
return false;
|
|
|
|
DCHECK(att0->IsValid());
|
|
DCHECK(att1->IsValid());
|
|
|
|
// Prepare blocks of memomry to hold data of corners for this attribute.
|
|
std::unique_ptr<uint8_t[]> data0(new uint8_t[att0->byte_stride()]);
|
|
std::unique_ptr<uint8_t[]> data1(new uint8_t[att0->byte_stride()]);
|
|
|
|
// Check every corner of every face.
|
|
for (int i = 0; i < num_faces_; ++i) {
|
|
const FaceIndex f0 = mesh_infos_[0].ordered_index_of_face[i];
|
|
const FaceIndex f1 = mesh_infos_[1].ordered_index_of_face[i];
|
|
const int c0_off = mesh_infos_[0].corner_index_of_smallest_vertex[f0];
|
|
const int c1_off = mesh_infos_[1].corner_index_of_smallest_vertex[f1];
|
|
|
|
for (int c = 0; c < 3; ++c) {
|
|
// Get the index of each corner.
|
|
const PointIndex corner0 = mesh0.face(f0)[(c0_off + c) % 3];
|
|
const PointIndex corner1 = mesh1.face(f1)[(c1_off + c) % 3];
|
|
// Map it to the right index for that attribute.
|
|
const AttributeValueIndex index0 = att0->mapped_index(corner0);
|
|
const AttributeValueIndex index1 = att1->mapped_index(corner1);
|
|
|
|
// Obtaining the data.
|
|
att0->GetValue(index0, data0.get());
|
|
att1->GetValue(index1, data1.get());
|
|
// Compare the data as is in memory.
|
|
if (memcmp(data0.get(), data1.get(), att0->byte_stride()) != 0)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MeshAreEquivalent::FaceIndexLess::operator()(FaceIndex f0,
|
|
FaceIndex f1) const {
|
|
if (f0 == f1)
|
|
return false;
|
|
const int c0 = mesh_info.corner_index_of_smallest_vertex[f0];
|
|
const int c1 = mesh_info.corner_index_of_smallest_vertex[f1];
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
const Vector3f vf0 = GetPostion(mesh_info.mesh, f0, (c0 + i) % 3);
|
|
const Vector3f vf1 = GetPostion(mesh_info.mesh, f1, (c1 + i) % 3);
|
|
if (vf0 < vf1)
|
|
return true;
|
|
if (vf1 < vf0)
|
|
return false;
|
|
}
|
|
// In case the two faces are equivalent.
|
|
return false;
|
|
}
|
|
|
|
} // namespace draco
|