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_attribute_corner_table.h"
16 #include "draco/mesh/corner_table_iterators.h"
17 #include "draco/mesh/mesh_misc_functions.h"
18 
19 namespace draco {
20 
MeshAttributeCornerTable()21 MeshAttributeCornerTable::MeshAttributeCornerTable()
22     : no_interior_seams_(true), corner_table_(nullptr), valence_cache_(*this) {}
23 
InitEmpty(const CornerTable * table)24 bool MeshAttributeCornerTable::InitEmpty(const CornerTable *table) {
25   if (table == nullptr)
26     return false;
27   valence_cache_.ClearValenceCache();
28   valence_cache_.ClearValenceCacheInaccurate();
29   is_edge_on_seam_.assign(table->num_corners(), false);
30   is_vertex_on_seam_.assign(table->num_vertices(), false);
31   corner_to_vertex_map_.assign(table->num_corners(), kInvalidVertexIndex);
32   vertex_to_attribute_entry_id_map_.reserve(table->num_vertices());
33   vertex_to_left_most_corner_map_.reserve(table->num_vertices());
34   corner_table_ = table;
35   no_interior_seams_ = true;
36   return true;
37 }
38 
InitFromAttribute(const Mesh * mesh,const CornerTable * table,const PointAttribute * att)39 bool MeshAttributeCornerTable::InitFromAttribute(const Mesh *mesh,
40                                                  const CornerTable *table,
41                                                  const PointAttribute *att) {
42   if (!InitEmpty(table))
43     return false;
44   valence_cache_.ClearValenceCache();
45   valence_cache_.ClearValenceCacheInaccurate();
46 
47   // Find all necessary data for encoding attributes. For now we check which of
48   // the mesh vertices is part of an attribute seam, because seams require
49   // special handling.
50   for (CornerIndex c(0); c < corner_table_->num_corners(); ++c) {
51     const FaceIndex f = corner_table_->Face(c);
52     if (corner_table_->IsDegenerated(f))
53       continue;  // Ignore corners on degenerated faces.
54     const CornerIndex opp_corner = corner_table_->Opposite(c);
55     if (opp_corner == kInvalidCornerIndex) {
56       // Boundary. Mark it as seam edge.
57       is_edge_on_seam_[c.value()] = true;
58       // Mark seam vertices.
59       VertexIndex v;
60       v = corner_table_->Vertex(corner_table_->Next(c));
61       is_vertex_on_seam_[v.value()] = true;
62       v = corner_table_->Vertex(corner_table_->Previous(c));
63       is_vertex_on_seam_[v.value()] = true;
64       continue;
65     }
66     if (opp_corner < c)
67       continue;  // Opposite corner was already processed.
68 
69     CornerIndex act_c(c), act_sibling_c(opp_corner);
70     for (int i = 0; i < 2; ++i) {
71       // Get the sibling corners. I.e., the two corners attached to the same
72       // vertex but divided by the seam edge.
73       act_c = corner_table_->Next(act_c);
74       act_sibling_c = corner_table_->Previous(act_sibling_c);
75       const PointIndex point_id = mesh->CornerToPointId(act_c.value());
76       const PointIndex sibling_point_id =
77           mesh->CornerToPointId(act_sibling_c.value());
78       if (att->mapped_index(point_id) != att->mapped_index(sibling_point_id)) {
79         no_interior_seams_ = false;
80         is_edge_on_seam_[c.value()] = true;
81         is_edge_on_seam_[opp_corner.value()] = true;
82         // Mark seam vertices.
83         is_vertex_on_seam_[corner_table_
84                                ->Vertex(corner_table_->Next(CornerIndex(c)))
85                                .value()] = true;
86         is_vertex_on_seam_[corner_table_
87                                ->Vertex(corner_table_->Previous(CornerIndex(c)))
88                                .value()] = true;
89         is_vertex_on_seam_
90             [corner_table_->Vertex(corner_table_->Next(opp_corner)).value()] =
91                 true;
92         is_vertex_on_seam_[corner_table_
93                                ->Vertex(corner_table_->Previous(opp_corner))
94                                .value()] = true;
95         break;
96       }
97     }
98   }
99   RecomputeVertices(mesh, att);
100   return true;
101 }
102 
AddSeamEdge(CornerIndex c)103 void MeshAttributeCornerTable::AddSeamEdge(CornerIndex c) {
104   DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
105   is_edge_on_seam_[c.value()] = true;
106   // Mark seam vertices.
107   is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(c)).value()] =
108       true;
109   is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Previous(c))
110                          .value()] = true;
111 
112   const CornerIndex opp_corner = corner_table_->Opposite(c);
113   if (opp_corner != kInvalidCornerIndex) {
114     no_interior_seams_ = false;
115     is_edge_on_seam_[opp_corner.value()] = true;
116     is_vertex_on_seam_[corner_table_->Vertex(corner_table_->Next(opp_corner))
117                            .value()] = true;
118     is_vertex_on_seam_
119         [corner_table_->Vertex(corner_table_->Previous(opp_corner)).value()] =
120             true;
121   }
122 }
123 
RecomputeVertices(const Mesh * mesh,const PointAttribute * att)124 void MeshAttributeCornerTable::RecomputeVertices(const Mesh *mesh,
125                                                  const PointAttribute *att) {
126   DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
127   if (mesh != nullptr && att != nullptr) {
128     RecomputeVerticesInternal<true>(mesh, att);
129   } else {
130     RecomputeVerticesInternal<false>(nullptr, nullptr);
131   }
132 }
133 
134 template <bool init_vertex_to_attribute_entry_map>
RecomputeVerticesInternal(const Mesh * mesh,const PointAttribute * att)135 void MeshAttributeCornerTable::RecomputeVerticesInternal(
136     const Mesh *mesh, const PointAttribute *att) {
137   DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
138   int num_new_vertices = 0;
139   for (VertexIndex v(0); v < corner_table_->num_vertices(); ++v) {
140     const CornerIndex c = corner_table_->LeftMostCorner(v);
141     if (c == kInvalidCornerIndex)
142       continue;  // Isolated vertex?
143     AttributeValueIndex first_vert_id(num_new_vertices++);
144     if (init_vertex_to_attribute_entry_map) {
145       const PointIndex point_id = mesh->CornerToPointId(c.value());
146       vertex_to_attribute_entry_id_map_.push_back(att->mapped_index(point_id));
147     } else {
148       // Identity mapping
149       vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
150     }
151     CornerIndex first_c = c;
152     CornerIndex act_c;
153     // Check if the vertex is on a seam edge, if it is we need to find the first
154     // attribute entry on the seam edge when traversing in the CCW direction.
155     if (is_vertex_on_seam_[v.value()]) {
156       // Try to swing left on the modified corner table. We need to get the
157       // first corner that defines an attribute seam.
158       act_c = SwingLeft(first_c);
159       while (act_c != kInvalidCornerIndex) {
160         first_c = act_c;
161         act_c = SwingLeft(act_c);
162       }
163     }
164     corner_to_vertex_map_[first_c.value()] = VertexIndex(first_vert_id.value());
165     vertex_to_left_most_corner_map_.push_back(first_c);
166     act_c = corner_table_->SwingRight(first_c);
167     while (act_c != kInvalidCornerIndex && act_c != first_c) {
168       if (IsCornerOppositeToSeamEdge(corner_table_->Next(act_c))) {
169         first_vert_id = AttributeValueIndex(num_new_vertices++);
170         if (init_vertex_to_attribute_entry_map) {
171           const PointIndex point_id = mesh->CornerToPointId(act_c.value());
172           vertex_to_attribute_entry_id_map_.push_back(
173               att->mapped_index(point_id));
174         } else {
175           // Identity mapping.
176           vertex_to_attribute_entry_id_map_.push_back(first_vert_id);
177         }
178         vertex_to_left_most_corner_map_.push_back(act_c);
179       }
180       corner_to_vertex_map_[act_c.value()] = VertexIndex(first_vert_id.value());
181       act_c = corner_table_->SwingRight(act_c);
182     }
183   }
184 }
185 
Valence(VertexIndex v) const186 int MeshAttributeCornerTable::Valence(VertexIndex v) const {
187   if (v == kInvalidVertexIndex)
188     return -1;
189   return ConfidentValence(v);
190 }
191 
ConfidentValence(VertexIndex v) const192 int MeshAttributeCornerTable::ConfidentValence(VertexIndex v) const {
193   DRACO_DCHECK_LT(v.value(), num_vertices());
194   draco::VertexRingIterator<MeshAttributeCornerTable> vi(this, v);
195   int valence = 0;
196   for (; !vi.End(); vi.Next()) {
197     ++valence;
198   }
199   return valence;
200 }
201 
202 }  // namespace draco
203