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