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 #ifndef DRACO_MESH_CORNER_TABLE_H_
16 #define DRACO_MESH_CORNER_TABLE_H_
17 
18 #include <array>
19 #include <memory>
20 
21 #include "draco/attributes/geometry_indices.h"
22 #include "draco/core/draco_index_type_vector.h"
23 #include "draco/core/macros.h"
24 #include "draco/mesh/valence_cache.h"
25 
26 namespace draco {
27 
28 // CornerTable is used to represent connectivity of triangular meshes.
29 // For every corner of all faces, the corner table stores the index of the
30 // opposite corner in the neighboring face (if it exists) as illustrated in the
31 // figure below (see corner |c| and it's opposite corner |o|).
32 //
33 //     *
34 //    /c\
35 //   /   \
36 //  /n   p\
37 // *-------*
38 //  \     /
39 //   \   /
40 //    \o/
41 //     *
42 //
43 // All corners are defined by unique CornerIndex and each triplet of corners
44 // that define a single face id always ordered consecutively as:
45 //     { 3 * FaceIndex, 3 * FaceIndex + 1, 3 * FaceIndex +2 }.
46 // This representation of corners allows CornerTable to easily retrieve Next and
47 // Previous corners on any face (see corners |n| and |p| in the figure above).
48 // Using the Next, Previous, and Opposite corners then enables traversal of any
49 // 2-manifold surface.
50 // If the CornerTable is constructed from a non-manifold surface, the input
51 // non-manifold edges and vertices are automatically split.
52 class CornerTable {
53  public:
54   // Corner table face type.
55   typedef std::array<VertexIndex, 3> FaceType;
56 
57   CornerTable();
58   static std::unique_ptr<CornerTable> Create(
59       const IndexTypeVector<FaceIndex, FaceType> &faces);
60 
61   // Initializes the CornerTable from provides set of indexed faces.
62   // The input faces can represent a non-manifold topology, in which case the
63   // non-manifold edges and vertices are going to be split.
64   bool Init(const IndexTypeVector<FaceIndex, FaceType> &faces);
65 
66   // Resets the corner table to the given number of invalid faces.
67   bool Reset(int num_faces);
68 
69   // Resets the corner table to the given number of invalid faces and vertices.
70   bool Reset(int num_faces, int num_vertices);
71 
num_vertices()72   inline int num_vertices() const {
73     return static_cast<int>(vertex_corners_.size());
74   }
num_corners()75   inline int num_corners() const {
76     return static_cast<int>(corner_to_vertex_map_.size());
77   }
num_faces()78   inline int num_faces() const {
79     return static_cast<int>(corner_to_vertex_map_.size() / 3);
80   }
81 
Opposite(CornerIndex corner)82   inline CornerIndex Opposite(CornerIndex corner) const {
83     if (corner == kInvalidCornerIndex) {
84       return corner;
85     }
86     return opposite_corners_[corner];
87   }
Next(CornerIndex corner)88   inline CornerIndex Next(CornerIndex corner) const {
89     if (corner == kInvalidCornerIndex) {
90       return corner;
91     }
92     return LocalIndex(++corner) ? corner : corner - 3;
93   }
Previous(CornerIndex corner)94   inline CornerIndex Previous(CornerIndex corner) const {
95     if (corner == kInvalidCornerIndex) {
96       return corner;
97     }
98     return LocalIndex(corner) ? corner - 1 : corner + 2;
99   }
Vertex(CornerIndex corner)100   inline VertexIndex Vertex(CornerIndex corner) const {
101     if (corner == kInvalidCornerIndex) {
102       return kInvalidVertexIndex;
103     }
104     return ConfidentVertex(corner);
105   }
ConfidentVertex(CornerIndex corner)106   inline VertexIndex ConfidentVertex(CornerIndex corner) const {
107     DRACO_DCHECK_GE(corner.value(), 0);
108     DRACO_DCHECK_LT(corner.value(), num_corners());
109     return corner_to_vertex_map_[corner];
110   }
Face(CornerIndex corner)111   inline FaceIndex Face(CornerIndex corner) const {
112     if (corner == kInvalidCornerIndex) {
113       return kInvalidFaceIndex;
114     }
115     return FaceIndex(corner.value() / 3);
116   }
FirstCorner(FaceIndex face)117   inline CornerIndex FirstCorner(FaceIndex face) const {
118     if (face == kInvalidFaceIndex) {
119       return kInvalidCornerIndex;
120     }
121     return CornerIndex(face.value() * 3);
122   }
AllCorners(FaceIndex face)123   inline std::array<CornerIndex, 3> AllCorners(FaceIndex face) const {
124     const CornerIndex ci = CornerIndex(face.value() * 3);
125     return {{ci, ci + 1, ci + 2}};
126   }
LocalIndex(CornerIndex corner)127   inline int LocalIndex(CornerIndex corner) const { return corner.value() % 3; }
128 
FaceData(FaceIndex face)129   inline FaceType FaceData(FaceIndex face) const {
130     const CornerIndex first_corner = FirstCorner(face);
131     FaceType face_data;
132     for (int i = 0; i < 3; ++i) {
133       face_data[i] = corner_to_vertex_map_[first_corner + i];
134     }
135     return face_data;
136   }
137 
SetFaceData(FaceIndex face,FaceType data)138   void SetFaceData(FaceIndex face, FaceType data) {
139     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
140     const CornerIndex first_corner = FirstCorner(face);
141     for (int i = 0; i < 3; ++i) {
142       corner_to_vertex_map_[first_corner + i] = data[i];
143     }
144   }
145 
146   // Returns the left-most corner of a single vertex 1-ring. If a vertex is not
147   // on a boundary (in which case it has a full 1-ring), this function returns
148   // any of the corners mapped to the given vertex.
LeftMostCorner(VertexIndex v)149   inline CornerIndex LeftMostCorner(VertexIndex v) const {
150     return vertex_corners_[v];
151   }
152 
153   // Returns the parent vertex index of a given corner table vertex.
VertexParent(VertexIndex vertex)154   VertexIndex VertexParent(VertexIndex vertex) const {
155     if (vertex.value() < static_cast<uint32_t>(num_original_vertices_)) {
156       return vertex;
157     }
158     return non_manifold_vertex_parents_[vertex - num_original_vertices_];
159   }
160 
161   // Returns true if the corner is valid.
IsValid(CornerIndex c)162   inline bool IsValid(CornerIndex c) const {
163     return Vertex(c) != kInvalidVertexIndex;
164   }
165 
166   // Returns the valence (or degree) of a vertex.
167   // Returns -1 if the given vertex index is not valid.
168   int Valence(VertexIndex v) const;
169   // Same as above but does not check for validity and does not return -1
170   int ConfidentValence(VertexIndex v) const;
171   // Returns the valence of the vertex at the given corner.
Valence(CornerIndex c)172   inline int Valence(CornerIndex c) const {
173     if (c == kInvalidCornerIndex) {
174       return -1;
175     }
176     return ConfidentValence(c);
177   }
ConfidentValence(CornerIndex c)178   inline int ConfidentValence(CornerIndex c) const {
179     DRACO_DCHECK_LT(c.value(), num_corners());
180     return ConfidentValence(ConfidentVertex(c));
181   }
182 
183   // Returns true if the specified vertex is on a boundary.
IsOnBoundary(VertexIndex vert)184   inline bool IsOnBoundary(VertexIndex vert) const {
185     const CornerIndex corner = LeftMostCorner(vert);
186     if (SwingLeft(corner) == kInvalidCornerIndex) {
187       return true;
188     }
189     return false;
190   }
191 
192   //     *-------*
193   //    / \     / \
194   //   /   \   /   \
195   //  /   sl\c/sr   \
196   // *-------v-------*
197   // Returns the corner on the adjacent face on the right that maps to
198   // the same vertex as the given corner (sr in the above diagram).
SwingRight(CornerIndex corner)199   inline CornerIndex SwingRight(CornerIndex corner) const {
200     return Previous(Opposite(Previous(corner)));
201   }
202   // Returns the corner on the left face that maps to the same vertex as the
203   // given corner (sl in the above diagram).
SwingLeft(CornerIndex corner)204   inline CornerIndex SwingLeft(CornerIndex corner) const {
205     return Next(Opposite(Next(corner)));
206   }
207 
208   // Get opposite corners on the left and right faces respectively (see image
209   // below, where L and R are the left and right corners of a corner X.
210   //
211   // *-------*-------*
212   //  \L    /X\    R/
213   //   \   /   \   /
214   //    \ /     \ /
215   //     *-------*
GetLeftCorner(CornerIndex corner_id)216   inline CornerIndex GetLeftCorner(CornerIndex corner_id) const {
217     if (corner_id == kInvalidCornerIndex) {
218       return kInvalidCornerIndex;
219     }
220     return Opposite(Previous(corner_id));
221   }
GetRightCorner(CornerIndex corner_id)222   inline CornerIndex GetRightCorner(CornerIndex corner_id) const {
223     if (corner_id == kInvalidCornerIndex) {
224       return kInvalidCornerIndex;
225     }
226     return Opposite(Next(corner_id));
227   }
228 
229   // Returns the number of new vertices that were created as a result of
230   // splitting of non-manifold vertices of the input geometry.
NumNewVertices()231   int NumNewVertices() const { return num_vertices() - num_original_vertices_; }
NumOriginalVertices()232   int NumOriginalVertices() const { return num_original_vertices_; }
233 
234   // Returns the number of faces with duplicated vertex indices.
NumDegeneratedFaces()235   int NumDegeneratedFaces() const { return num_degenerated_faces_; }
236 
237   // Returns the number of isolated vertices (vertices that have
238   // vertex_corners_ mapping set to kInvalidCornerIndex.
NumIsolatedVertices()239   int NumIsolatedVertices() const { return num_isolated_vertices_; }
240 
241   bool IsDegenerated(FaceIndex face) const;
242 
243   // Methods that modify an existing corner table.
244   // Sets the opposite corner mapping between two corners. Caller must ensure
245   // that the indices are valid.
SetOppositeCorner(CornerIndex corner_id,CornerIndex opp_corner_id)246   inline void SetOppositeCorner(CornerIndex corner_id,
247                                 CornerIndex opp_corner_id) {
248     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
249     opposite_corners_[corner_id] = opp_corner_id;
250   }
251 
252   // Sets opposite corners for both input corners.
SetOppositeCorners(CornerIndex corner_0,CornerIndex corner_1)253   inline void SetOppositeCorners(CornerIndex corner_0, CornerIndex corner_1) {
254     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
255     if (corner_0 != kInvalidCornerIndex) {
256       SetOppositeCorner(corner_0, corner_1);
257     }
258     if (corner_1 != kInvalidCornerIndex) {
259       SetOppositeCorner(corner_1, corner_0);
260     }
261   }
262 
263   // Updates mapping between a corner and a vertex.
MapCornerToVertex(CornerIndex corner_id,VertexIndex vert_id)264   inline void MapCornerToVertex(CornerIndex corner_id, VertexIndex vert_id) {
265     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
266     corner_to_vertex_map_[corner_id] = vert_id;
267   }
268 
AddNewVertex()269   VertexIndex AddNewVertex() {
270     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
271     // Add a new invalid vertex.
272     vertex_corners_.push_back(kInvalidCornerIndex);
273     return VertexIndex(static_cast<uint32_t>(vertex_corners_.size() - 1));
274   }
275 
276   // Adds a new face connected to three vertices. Note that connectivity is not
277   // automatically updated and all opposite corners need to be set explicitly.
AddNewFace(const std::array<VertexIndex,3> & vertices)278   FaceIndex AddNewFace(const std::array<VertexIndex, 3> &vertices) {
279     // Add a new invalid face.
280     const FaceIndex new_face_index(num_faces());
281     for (int i = 0; i < 3; ++i) {
282       corner_to_vertex_map_.push_back(vertices[i]);
283       SetLeftMostCorner(vertices[i],
284                         CornerIndex(corner_to_vertex_map_.size() - 1));
285     }
286     opposite_corners_.resize(corner_to_vertex_map_.size(), kInvalidCornerIndex);
287     return new_face_index;
288   }
289 
290   // Sets a new left most corner for a given vertex.
SetLeftMostCorner(VertexIndex vert,CornerIndex corner)291   void SetLeftMostCorner(VertexIndex vert, CornerIndex corner) {
292     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
293     if (vert != kInvalidVertexIndex) {
294       vertex_corners_[vert] = corner;
295     }
296   }
297 
298   // Updates the vertex to corner map on a specified vertex. This should be
299   // called in cases where the mapping may be invalid (e.g. when the corner
300   // table was constructed manually).
UpdateVertexToCornerMap(VertexIndex vert)301   void UpdateVertexToCornerMap(VertexIndex vert) {
302     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
303     const CornerIndex first_c = vertex_corners_[vert];
304     if (first_c == kInvalidCornerIndex) {
305       return;  // Isolated vertex.
306     }
307     CornerIndex act_c = SwingLeft(first_c);
308     CornerIndex c = first_c;
309     while (act_c != kInvalidCornerIndex && act_c != first_c) {
310       c = act_c;
311       act_c = SwingLeft(act_c);
312     }
313     if (act_c != first_c) {
314       vertex_corners_[vert] = c;
315     }
316   }
317 
318   // Sets the new number of vertices. It's a responsibility of the caller to
319   // ensure that no corner is mapped beyond the range of the new number of
320   // vertices.
SetNumVertices(int num_vertices)321   inline void SetNumVertices(int num_vertices) {
322     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
323     vertex_corners_.resize(num_vertices, kInvalidCornerIndex);
324   }
325 
326   // Makes a vertex isolated (not attached to any corner).
MakeVertexIsolated(VertexIndex vert)327   void MakeVertexIsolated(VertexIndex vert) {
328     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
329     vertex_corners_[vert] = kInvalidCornerIndex;
330   }
331 
332   // Returns true if a vertex is not attached to any face.
IsVertexIsolated(VertexIndex v)333   inline bool IsVertexIsolated(VertexIndex v) const {
334     return LeftMostCorner(v) == kInvalidCornerIndex;
335   }
336 
337   // Makes a given face invalid (all corners are marked as invalid).
MakeFaceInvalid(FaceIndex face)338   void MakeFaceInvalid(FaceIndex face) {
339     DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
340     if (face != kInvalidFaceIndex) {
341       const CornerIndex first_corner = FirstCorner(face);
342       for (int i = 0; i < 3; ++i) {
343         corner_to_vertex_map_[first_corner + i] = kInvalidVertexIndex;
344       }
345     }
346   }
347 
348   // Updates mapping between faces and a vertex using the corners mapped to
349   // the provided vertex.
350   void UpdateFaceToVertexMap(const VertexIndex vertex);
351 
352   // Allows access to an internal object for caching valences.  The object can
353   // be instructed to cache or uncache all valences and then its interfaces
354   // queried directly for valences with differing performance/confidence
355   // qualities.  If the mesh or table is modified the cache should be discarded
356   // and not relied on as it does not automatically update or invalidate for
357   // performance reasons.
GetValenceCache()358   const draco::ValenceCache<CornerTable> &GetValenceCache() const {
359     return valence_cache_;
360   }
361 
362  private:
363   // Computes opposite corners mapping from the data stored in
364   // |corner_to_vertex_map_|.
365   bool ComputeOppositeCorners(int *num_vertices);
366 
367   // Finds and breaks non-manifold edges in the 1-ring neighborhood around
368   // vertices (vertices themselves will be split in the ComputeVertexCorners()
369   // function if necessary).
370   bool BreakNonManifoldEdges();
371 
372   // Computes the lookup map for going from a vertex to a corner. This method
373   // can handle non-manifold vertices by splitting them into multiple manifold
374   // vertices.
375   bool ComputeVertexCorners(int num_vertices);
376 
377   // Each three consecutive corners represent one face.
378   IndexTypeVector<CornerIndex, VertexIndex> corner_to_vertex_map_;
379   IndexTypeVector<CornerIndex, CornerIndex> opposite_corners_;
380   IndexTypeVector<VertexIndex, CornerIndex> vertex_corners_;
381 
382   int num_original_vertices_;
383   int num_degenerated_faces_;
384   int num_isolated_vertices_;
385   IndexTypeVector<VertexIndex, VertexIndex> non_manifold_vertex_parents_;
386 
387   draco::ValenceCache<CornerTable> valence_cache_;
388 };
389 
390 // A special case to denote an invalid corner table triangle.
391 static constexpr CornerTable::FaceType kInvalidFace(
392     {{kInvalidVertexIndex, kInvalidVertexIndex, kInvalidVertexIndex}});
393 
394 }  // namespace draco
395 
396 #endif  // DRACO_MESH_CORNER_TABLE_H_
397