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