Welcome to mirror list, hosted at ThFree Co, Russian Federation.

corner_table.h « mesh « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 3aa720fdeb9f31fd5f02104af16d325d5795e907 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// Copyright 2016 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_MESH_CORNER_TABLE_H_
#define DRACO_MESH_CORNER_TABLE_H_

#include <array>
#include <memory>

#include "draco/attributes/geometry_indices.h"
#include "draco/core/draco_index_type_vector.h"
#include "draco/core/macros.h"
#include "draco/mesh/valence_cache.h"

namespace draco {

// CornerTable is used to represent connectivity of triangular meshes.
// For every corner of all faces, the corner table stores the index of the
// opposite corner in the neighboring face (if it exists) as illustrated in the
// figure below (see corner |c| and it's opposite corner |o|).
//
//     *
//    /c\
//   /   \
//  /n   p\
// *-------*
//  \     /
//   \   /
//    \o/
//     *
//
// All corners are defined by unique CornerIndex and each triplet of corners
// that define a single face id always ordered consecutively as:
//     { 3 * FaceIndex, 3 * FaceIndex + 1, 3 * FaceIndex +2 }.
// This representation of corners allows CornerTable to easily retrieve Next and
// Previous corners on any face (see corners |n| and |p| in the figure above).
// Using the Next, Previous, and Opposite corners then enables traversal of any
// 2-manifold surface.
// If the CornerTable is constructed from a non-manifold surface, the input
// non-manifold edges and vertices are automatically split.
class CornerTable {
 public:
  // Corner table face type.
  typedef std::array<VertexIndex, 3> FaceType;

  CornerTable();
  static std::unique_ptr<CornerTable> Create(
      const IndexTypeVector<FaceIndex, FaceType> &faces);

  // Initializes the CornerTable from provides set of indexed faces.
  // The input faces can represent a non-manifold topology, in which case the
  // non-manifold edges and vertices are going to be split.
  bool Init(const IndexTypeVector<FaceIndex, FaceType> &faces);

  // Resets the corner table to the given number of invalid faces.
  bool Reset(int num_faces);

  // Resets the corner table to the given number of invalid faces and vertices.
  bool Reset(int num_faces, int num_vertices);

  inline int num_vertices() const {
    return static_cast<int>(vertex_corners_.size());
  }
  inline int num_corners() const {
    return static_cast<int>(corner_to_vertex_map_.size());
  }
  inline int num_faces() const {
    return static_cast<int>(corner_to_vertex_map_.size() / 3);
  }

  inline CornerIndex Opposite(CornerIndex corner) const {
    if (corner == kInvalidCornerIndex) {
      return corner;
    }
    return opposite_corners_[corner];
  }
  inline CornerIndex Next(CornerIndex corner) const {
    if (corner == kInvalidCornerIndex) {
      return corner;
    }
    return LocalIndex(++corner) ? corner : corner - 3;
  }
  inline CornerIndex Previous(CornerIndex corner) const {
    if (corner == kInvalidCornerIndex) {
      return corner;
    }
    return LocalIndex(corner) ? corner - 1 : corner + 2;
  }
  inline VertexIndex Vertex(CornerIndex corner) const {
    if (corner == kInvalidCornerIndex) {
      return kInvalidVertexIndex;
    }
    return ConfidentVertex(corner);
  }
  inline VertexIndex ConfidentVertex(CornerIndex corner) const {
    DRACO_DCHECK_GE(corner.value(), 0);
    DRACO_DCHECK_LT(corner.value(), num_corners());
    return corner_to_vertex_map_[corner];
  }
  inline FaceIndex Face(CornerIndex corner) const {
    if (corner == kInvalidCornerIndex) {
      return kInvalidFaceIndex;
    }
    return FaceIndex(corner.value() / 3);
  }
  inline CornerIndex FirstCorner(FaceIndex face) const {
    if (face == kInvalidFaceIndex) {
      return kInvalidCornerIndex;
    }
    return CornerIndex(face.value() * 3);
  }
  inline std::array<CornerIndex, 3> AllCorners(FaceIndex face) const {
    const CornerIndex ci = CornerIndex(face.value() * 3);
    return {{ci, ci + 1, ci + 2}};
  }
  inline int LocalIndex(CornerIndex corner) const { return corner.value() % 3; }

  inline FaceType FaceData(FaceIndex face) const {
    const CornerIndex first_corner = FirstCorner(face);
    FaceType face_data;
    for (int i = 0; i < 3; ++i) {
      face_data[i] = corner_to_vertex_map_[first_corner + i];
    }
    return face_data;
  }

  void SetFaceData(FaceIndex face, FaceType data) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    const CornerIndex first_corner = FirstCorner(face);
    for (int i = 0; i < 3; ++i) {
      corner_to_vertex_map_[first_corner + i] = data[i];
    }
  }

  // Returns the left-most corner of a single vertex 1-ring. If a vertex is not
  // on a boundary (in which case it has a full 1-ring), this function returns
  // any of the corners mapped to the given vertex.
  inline CornerIndex LeftMostCorner(VertexIndex v) const {
    return vertex_corners_[v];
  }

  // Returns the parent vertex index of a given corner table vertex.
  VertexIndex VertexParent(VertexIndex vertex) const {
    if (vertex.value() < static_cast<uint32_t>(num_original_vertices_)) {
      return vertex;
    }
    return non_manifold_vertex_parents_[vertex - num_original_vertices_];
  }

  // Returns true if the corner is valid.
  inline bool IsValid(CornerIndex c) const {
    return Vertex(c) != kInvalidVertexIndex;
  }

  // Returns the valence (or degree) of a vertex.
  // Returns -1 if the given vertex index is not valid.
  int Valence(VertexIndex v) const;
  // Same as above but does not check for validity and does not return -1
  int ConfidentValence(VertexIndex v) const;
  // Returns the valence of the vertex at the given corner.
  inline int Valence(CornerIndex c) const {
    if (c == kInvalidCornerIndex) {
      return -1;
    }
    return ConfidentValence(c);
  }
  inline int ConfidentValence(CornerIndex c) const {
    DRACO_DCHECK_LT(c.value(), num_corners());
    return ConfidentValence(ConfidentVertex(c));
  }

  // Returns true if the specified vertex is on a boundary.
  inline bool IsOnBoundary(VertexIndex vert) const {
    const CornerIndex corner = LeftMostCorner(vert);
    if (SwingLeft(corner) == kInvalidCornerIndex) {
      return true;
    }
    return false;
  }

  //     *-------*
  //    / \     / \
  //   /   \   /   \
  //  /   sl\c/sr   \
  // *-------v-------*
  // Returns the corner on the adjacent face on the right that maps to
  // the same vertex as the given corner (sr in the above diagram).
  inline CornerIndex SwingRight(CornerIndex corner) const {
    return Previous(Opposite(Previous(corner)));
  }
  // Returns the corner on the left face that maps to the same vertex as the
  // given corner (sl in the above diagram).
  inline CornerIndex SwingLeft(CornerIndex corner) const {
    return Next(Opposite(Next(corner)));
  }

  // Get opposite corners on the left and right faces respectively (see image
  // below, where L and R are the left and right corners of a corner X.
  //
  // *-------*-------*
  //  \L    /X\    R/
  //   \   /   \   /
  //    \ /     \ /
  //     *-------*
  inline CornerIndex GetLeftCorner(CornerIndex corner_id) const {
    if (corner_id == kInvalidCornerIndex) {
      return kInvalidCornerIndex;
    }
    return Opposite(Previous(corner_id));
  }
  inline CornerIndex GetRightCorner(CornerIndex corner_id) const {
    if (corner_id == kInvalidCornerIndex) {
      return kInvalidCornerIndex;
    }
    return Opposite(Next(corner_id));
  }

  // Returns the number of new vertices that were created as a result of
  // splitting of non-manifold vertices of the input geometry.
  int NumNewVertices() const { return num_vertices() - num_original_vertices_; }
  int NumOriginalVertices() const { return num_original_vertices_; }

  // Returns the number of faces with duplicated vertex indices.
  int NumDegeneratedFaces() const { return num_degenerated_faces_; }

  // Returns the number of isolated vertices (vertices that have
  // vertex_corners_ mapping set to kInvalidCornerIndex.
  int NumIsolatedVertices() const { return num_isolated_vertices_; }

  bool IsDegenerated(FaceIndex face) const;

  // Methods that modify an existing corner table.
  // Sets the opposite corner mapping between two corners. Caller must ensure
  // that the indices are valid.
  inline void SetOppositeCorner(CornerIndex corner_id,
                                CornerIndex opp_corner_id) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    opposite_corners_[corner_id] = opp_corner_id;
  }

  // Sets opposite corners for both input corners.
  inline void SetOppositeCorners(CornerIndex corner_0, CornerIndex corner_1) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    if (corner_0 != kInvalidCornerIndex) {
      SetOppositeCorner(corner_0, corner_1);
    }
    if (corner_1 != kInvalidCornerIndex) {
      SetOppositeCorner(corner_1, corner_0);
    }
  }

  // Updates mapping between a corner and a vertex.
  inline void MapCornerToVertex(CornerIndex corner_id, VertexIndex vert_id) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    corner_to_vertex_map_[corner_id] = vert_id;
  }

  VertexIndex AddNewVertex() {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    // Add a new invalid vertex.
    vertex_corners_.push_back(kInvalidCornerIndex);
    return VertexIndex(static_cast<uint32_t>(vertex_corners_.size() - 1));
  }

  // Adds a new face connected to three vertices. Note that connectivity is not
  // automatically updated and all opposite corners need to be set explicitly.
  FaceIndex AddNewFace(const std::array<VertexIndex, 3> &vertices) {
    // Add a new invalid face.
    const FaceIndex new_face_index(num_faces());
    for (int i = 0; i < 3; ++i) {
      corner_to_vertex_map_.push_back(vertices[i]);
      SetLeftMostCorner(vertices[i],
                        CornerIndex(corner_to_vertex_map_.size() - 1));
    }
    opposite_corners_.resize(corner_to_vertex_map_.size(), kInvalidCornerIndex);
    return new_face_index;
  }

  // Sets a new left most corner for a given vertex.
  void SetLeftMostCorner(VertexIndex vert, CornerIndex corner) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    if (vert != kInvalidVertexIndex) {
      vertex_corners_[vert] = corner;
    }
  }

  // Updates the vertex to corner map on a specified vertex. This should be
  // called in cases where the mapping may be invalid (e.g. when the corner
  // table was constructed manually).
  void UpdateVertexToCornerMap(VertexIndex vert) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    const CornerIndex first_c = vertex_corners_[vert];
    if (first_c == kInvalidCornerIndex) {
      return;  // Isolated vertex.
    }
    CornerIndex act_c = SwingLeft(first_c);
    CornerIndex c = first_c;
    while (act_c != kInvalidCornerIndex && act_c != first_c) {
      c = act_c;
      act_c = SwingLeft(act_c);
    }
    if (act_c != first_c) {
      vertex_corners_[vert] = c;
    }
  }

  // Sets the new number of vertices. It's a responsibility of the caller to
  // ensure that no corner is mapped beyond the range of the new number of
  // vertices.
  inline void SetNumVertices(int num_vertices) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    vertex_corners_.resize(num_vertices, kInvalidCornerIndex);
  }

  // Makes a vertex isolated (not attached to any corner).
  void MakeVertexIsolated(VertexIndex vert) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    vertex_corners_[vert] = kInvalidCornerIndex;
  }

  // Returns true if a vertex is not attached to any face.
  inline bool IsVertexIsolated(VertexIndex v) const {
    return LeftMostCorner(v) == kInvalidCornerIndex;
  }

  // Makes a given face invalid (all corners are marked as invalid).
  void MakeFaceInvalid(FaceIndex face) {
    DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
    if (face != kInvalidFaceIndex) {
      const CornerIndex first_corner = FirstCorner(face);
      for (int i = 0; i < 3; ++i) {
        corner_to_vertex_map_[first_corner + i] = kInvalidVertexIndex;
      }
    }
  }

  // Updates mapping between faces and a vertex using the corners mapped to
  // the provided vertex.
  void UpdateFaceToVertexMap(const VertexIndex vertex);

  // Allows access to an internal object for caching valences.  The object can
  // be instructed to cache or uncache all valences and then its interfaces
  // queried directly for valences with differing performance/confidence
  // qualities.  If the mesh or table is modified the cache should be discarded
  // and not relied on as it does not automatically update or invalidate for
  // performance reasons.
  const draco::ValenceCache<CornerTable> &GetValenceCache() const {
    return valence_cache_;
  }

 private:
  // Computes opposite corners mapping from the data stored in
  // |corner_to_vertex_map_|.
  bool ComputeOppositeCorners(int *num_vertices);

  // Finds and breaks non-manifold edges in the 1-ring neighborhood around
  // vertices (vertices themselves will be split in the ComputeVertexCorners()
  // function if necessary).
  bool BreakNonManifoldEdges();

  // Computes the lookup map for going from a vertex to a corner. This method
  // can handle non-manifold vertices by splitting them into multiple manifold
  // vertices.
  bool ComputeVertexCorners(int num_vertices);

  // Each three consecutive corners represent one face.
  IndexTypeVector<CornerIndex, VertexIndex> corner_to_vertex_map_;
  IndexTypeVector<CornerIndex, CornerIndex> opposite_corners_;
  IndexTypeVector<VertexIndex, CornerIndex> vertex_corners_;

  int num_original_vertices_;
  int num_degenerated_faces_;
  int num_isolated_vertices_;
  IndexTypeVector<VertexIndex, VertexIndex> non_manifold_vertex_parents_;

  draco::ValenceCache<CornerTable> valence_cache_;
};

// A special case to denote an invalid corner table triangle.
static constexpr CornerTable::FaceType kInvalidFace(
    {{kInvalidVertexIndex, kInvalidVertexIndex, kInvalidVertexIndex}});

}  // namespace draco

#endif  // DRACO_MESH_CORNER_TABLE_H_