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/mesh/mesh_are_equivalent.h"
16
17 #include <algorithm>
18
19 namespace draco {
20
PrintPosition(const Mesh & mesh,FaceIndex f,int32_t c)21 void MeshAreEquivalent::PrintPosition(const Mesh &mesh, FaceIndex f,
22 int32_t c) {
23 fprintf(stderr, "Printing position for (%i,%i)\n", f.value(), c);
24 const auto pos_att = mesh.GetNamedAttribute(GeometryAttribute::POSITION);
25 const PointIndex ver_index = mesh.face(f)[c];
26 const AttributeValueIndex pos_index = pos_att->mapped_index(ver_index);
27 const auto pos = pos_att->GetValue<float, 3>(pos_index);
28 fprintf(stderr, "Position (%f,%f,%f)\n", pos[0], pos[1], pos[2]);
29 }
30
GetPosition(const Mesh & mesh,FaceIndex f,int32_t c)31 Vector3f MeshAreEquivalent::GetPosition(const Mesh &mesh, FaceIndex f,
32 int32_t c) {
33 const auto pos_att = mesh.GetNamedAttribute(GeometryAttribute::POSITION);
34 const PointIndex ver_index = mesh.face(f)[c];
35 const AttributeValueIndex pos_index = pos_att->mapped_index(ver_index);
36 const auto pos = pos_att->GetValue<float, 3>(pos_index);
37 return Vector3f(pos[0], pos[1], pos[2]);
38 }
39
InitCornerIndexOfSmallestPointXYZ()40 void MeshAreEquivalent::InitCornerIndexOfSmallestPointXYZ() {
41 DRACO_DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(), 0);
42 DRACO_DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(), 0);
43 for (int i = 0; i < 2; ++i) {
44 mesh_infos_[i].corner_index_of_smallest_vertex.reserve(num_faces_);
45 for (FaceIndex f(0); f < num_faces_; ++f) {
46 mesh_infos_[i].corner_index_of_smallest_vertex.push_back(
47 ComputeCornerIndexOfSmallestPointXYZ(mesh_infos_[i].mesh, f));
48 }
49 }
50 DRACO_DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(),
51 num_faces_);
52 DRACO_DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(),
53 num_faces_);
54 }
55
InitOrderedFaceIndex()56 void MeshAreEquivalent::InitOrderedFaceIndex() {
57 DRACO_DCHECK_EQ(mesh_infos_[0].ordered_index_of_face.size(), 0);
58 DRACO_DCHECK_EQ(mesh_infos_[1].ordered_index_of_face.size(), 0);
59 for (int32_t i = 0; i < 2; ++i) {
60 mesh_infos_[i].ordered_index_of_face.reserve(num_faces_);
61 for (FaceIndex j(0); j < num_faces_; ++j) {
62 mesh_infos_[i].ordered_index_of_face.push_back(j);
63 }
64 const FaceIndexLess less(mesh_infos_[i]);
65 std::sort(mesh_infos_[i].ordered_index_of_face.begin(),
66 mesh_infos_[i].ordered_index_of_face.end(), less);
67
68 DRACO_DCHECK_EQ(mesh_infos_[i].ordered_index_of_face.size(), num_faces_);
69 DRACO_DCHECK(std::is_sorted(mesh_infos_[i].ordered_index_of_face.begin(),
70 mesh_infos_[i].ordered_index_of_face.end(),
71 less));
72 }
73 }
74
ComputeCornerIndexOfSmallestPointXYZ(const Mesh & mesh,FaceIndex f)75 int32_t MeshAreEquivalent::ComputeCornerIndexOfSmallestPointXYZ(
76 const Mesh &mesh, FaceIndex f) {
77 Vector3f pos[3]; // For the three corners.
78 for (int32_t i = 0; i < 3; ++i) {
79 pos[i] = GetPosition(mesh, f, i);
80 }
81 const auto min_it = std::min_element(pos, pos + 3);
82 return static_cast<int32_t>(min_it - pos);
83 }
84
Init(const Mesh & mesh0,const Mesh & mesh1)85 void MeshAreEquivalent::Init(const Mesh &mesh0, const Mesh &mesh1) {
86 mesh_infos_.clear();
87 DRACO_DCHECK_EQ(mesh_infos_.size(), 0);
88
89 num_faces_ = mesh1.num_faces();
90 mesh_infos_.push_back(MeshInfo(mesh0));
91 mesh_infos_.push_back(MeshInfo(mesh1));
92
93 DRACO_DCHECK_EQ(mesh_infos_.size(), 2);
94 DRACO_DCHECK_EQ(mesh_infos_[0].corner_index_of_smallest_vertex.size(), 0);
95 DRACO_DCHECK_EQ(mesh_infos_[1].corner_index_of_smallest_vertex.size(), 0);
96 DRACO_DCHECK_EQ(mesh_infos_[0].ordered_index_of_face.size(), 0);
97 DRACO_DCHECK_EQ(mesh_infos_[1].ordered_index_of_face.size(), 0);
98
99 InitCornerIndexOfSmallestPointXYZ();
100 InitOrderedFaceIndex();
101 }
102
operator ()(const Mesh & mesh0,const Mesh & mesh1)103 bool MeshAreEquivalent::operator()(const Mesh &mesh0, const Mesh &mesh1) {
104 if (mesh0.num_faces() != mesh1.num_faces()) {
105 return false;
106 }
107 if (mesh0.num_attributes() != mesh1.num_attributes()) {
108 return false;
109 }
110
111 // The following function inits mesh info, i.e., computes the order of
112 // faces with respect to the lex order. This way one can then compare the
113 // the two meshes face by face. It also determines the first corner of each
114 // face with respect to lex order.
115 Init(mesh0, mesh1);
116
117 // Check for every attribute that is valid that every corner is identical.
118 typedef GeometryAttribute::Type AttributeType;
119 const int att_max = AttributeType::NAMED_ATTRIBUTES_COUNT;
120 for (int att_id = 0; att_id < att_max; ++att_id) {
121 // First check for existence of the attribute in both meshes.
122 const PointAttribute *const att0 =
123 mesh0.GetNamedAttribute(AttributeType(att_id));
124 const PointAttribute *const att1 =
125 mesh1.GetNamedAttribute(AttributeType(att_id));
126 if (att0 == nullptr && att1 == nullptr) {
127 continue;
128 }
129 if (att0 == nullptr) {
130 return false;
131 }
132 if (att1 == nullptr) {
133 return false;
134 }
135 if (att0->data_type() != att1->data_type()) {
136 return false;
137 }
138 if (att0->num_components() != att1->num_components()) {
139 return false;
140 }
141 if (att0->normalized() != att1->normalized()) {
142 return false;
143 }
144 if (att0->byte_stride() != att1->byte_stride()) {
145 return false;
146 }
147
148 DRACO_DCHECK(att0->IsValid());
149 DRACO_DCHECK(att1->IsValid());
150
151 // Prepare blocks of memory to hold data of corners for this attribute.
152 std::unique_ptr<uint8_t[]> data0(new uint8_t[att0->byte_stride()]);
153 std::unique_ptr<uint8_t[]> data1(new uint8_t[att0->byte_stride()]);
154
155 // Check every corner of every face.
156 for (int i = 0; i < num_faces_; ++i) {
157 const FaceIndex f0 = mesh_infos_[0].ordered_index_of_face[i];
158 const FaceIndex f1 = mesh_infos_[1].ordered_index_of_face[i];
159 const int c0_off = mesh_infos_[0].corner_index_of_smallest_vertex[f0];
160 const int c1_off = mesh_infos_[1].corner_index_of_smallest_vertex[f1];
161
162 for (int c = 0; c < 3; ++c) {
163 // Get the index of each corner.
164 const PointIndex corner0 = mesh0.face(f0)[(c0_off + c) % 3];
165 const PointIndex corner1 = mesh1.face(f1)[(c1_off + c) % 3];
166 // Map it to the right index for that attribute.
167 const AttributeValueIndex index0 = att0->mapped_index(corner0);
168 const AttributeValueIndex index1 = att1->mapped_index(corner1);
169
170 // Obtaining the data.
171 att0->GetValue(index0, data0.get());
172 att1->GetValue(index1, data1.get());
173 // Compare the data as is in memory.
174 if (memcmp(data0.get(), data1.get(), att0->byte_stride()) != 0) {
175 return false;
176 }
177 }
178 }
179 }
180 return true;
181 }
182
operator ()(FaceIndex f0,FaceIndex f1) const183 bool MeshAreEquivalent::FaceIndexLess::operator()(FaceIndex f0,
184 FaceIndex f1) const {
185 if (f0 == f1) {
186 return false;
187 }
188 const int c0 = mesh_info.corner_index_of_smallest_vertex[f0];
189 const int c1 = mesh_info.corner_index_of_smallest_vertex[f1];
190
191 for (int i = 0; i < 3; ++i) {
192 const Vector3f vf0 = GetPosition(mesh_info.mesh, f0, (c0 + i) % 3);
193 const Vector3f vf1 = GetPosition(mesh_info.mesh, f1, (c1 + i) % 3);
194 if (vf0 < vf1) {
195 return true;
196 }
197 if (vf1 < vf0) {
198 return false;
199 }
200 }
201 // In case the two faces are equivalent.
202 return false;
203 }
204
205 } // namespace draco
206