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