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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/draco/dracoenc/src/draco/mesh/corner_table.cc')
-rw-r--r--extern/draco/dracoenc/src/draco/mesh/corner_table.cc312
1 files changed, 312 insertions, 0 deletions
diff --git a/extern/draco/dracoenc/src/draco/mesh/corner_table.cc b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc
new file mode 100644
index 00000000000..e4608fe8f9d
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc
@@ -0,0 +1,312 @@
+// 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.
+//
+#include "draco/mesh/corner_table.h"
+
+#include <limits>
+
+#include "draco/mesh/corner_table_iterators.h"
+
+namespace draco {
+
+CornerTable::CornerTable()
+ : num_original_vertices_(0),
+ num_degenerated_faces_(0),
+ num_isolated_vertices_(0),
+ valence_cache_(*this) {}
+
+std::unique_ptr<CornerTable> CornerTable::Create(
+ const IndexTypeVector<FaceIndex, FaceType> &faces) {
+ std::unique_ptr<CornerTable> ct(new CornerTable());
+ if (!ct->Init(faces))
+ return nullptr;
+ return ct;
+}
+
+bool CornerTable::Init(const IndexTypeVector<FaceIndex, FaceType> &faces) {
+ valence_cache_.ClearValenceCache();
+ valence_cache_.ClearValenceCacheInaccurate();
+ corner_to_vertex_map_.resize(faces.size() * 3);
+ for (FaceIndex fi(0); fi < static_cast<uint32_t>(faces.size()); ++fi) {
+ for (int i = 0; i < 3; ++i) {
+ corner_to_vertex_map_[FirstCorner(fi) + i] = faces[fi][i];
+ }
+ }
+ int num_vertices = -1;
+ if (!ComputeOppositeCorners(&num_vertices))
+ return false;
+ if (!ComputeVertexCorners(num_vertices))
+ return false;
+ return true;
+}
+
+bool CornerTable::Reset(int num_faces) {
+ return Reset(num_faces, num_faces * 3);
+}
+
+bool CornerTable::Reset(int num_faces, int num_vertices) {
+ if (num_faces < 0 || num_vertices < 0)
+ return false;
+ if (static_cast<unsigned int>(num_faces) >
+ std::numeric_limits<CornerIndex::ValueType>::max() / 3)
+ return false;
+ corner_to_vertex_map_.assign(num_faces * 3, kInvalidVertexIndex);
+ opposite_corners_.assign(num_faces * 3, kInvalidCornerIndex);
+ vertex_corners_.reserve(num_vertices);
+ valence_cache_.ClearValenceCache();
+ valence_cache_.ClearValenceCacheInaccurate();
+ return true;
+}
+
+bool CornerTable::ComputeOppositeCorners(int *num_vertices) {
+ DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
+ if (num_vertices == nullptr)
+ return false;
+ opposite_corners_.resize(num_corners(), kInvalidCornerIndex);
+
+ // Out implementation for finding opposite corners is based on keeping track
+ // of outgoing half-edges for each vertex of the mesh. Half-edges (defined by
+ // their opposite corners) are processed one by one and whenever a new
+ // half-edge (corner) is processed, we check whether the sink vertex of
+ // this half-edge contains its sibling half-edge. If yes, we connect them and
+ // remove the sibling half-edge from the sink vertex, otherwise we add the new
+ // half-edge to its source vertex.
+
+ // First compute the number of outgoing half-edges (corners) attached to each
+ // vertex.
+ std::vector<int> num_corners_on_vertices;
+ num_corners_on_vertices.reserve(num_corners());
+ for (CornerIndex c(0); c < num_corners(); ++c) {
+ const VertexIndex v1 = Vertex(c);
+ if (v1.value() >= static_cast<int>(num_corners_on_vertices.size()))
+ num_corners_on_vertices.resize(v1.value() + 1, 0);
+ // For each corner there is always exactly one outgoing half-edge attached
+ // to its vertex.
+ num_corners_on_vertices[v1.value()]++;
+ }
+
+ // Create a storage for half-edges on each vertex. We store all half-edges in
+ // one array, where each entry is identified by the half-edge's sink vertex id
+ // and the associated half-edge corner id (corner opposite to the half-edge).
+ // Each vertex will be assigned storage for up to
+ // |num_corners_on_vertices[vert_id]| half-edges. Unused half-edges are marked
+ // with |sink_vert| == kInvalidVertexIndex.
+ struct VertexEdgePair {
+ VertexEdgePair()
+ : sink_vert(kInvalidVertexIndex), edge_corner(kInvalidCornerIndex) {}
+ VertexIndex sink_vert;
+ CornerIndex edge_corner;
+ };
+ std::vector<VertexEdgePair> vertex_edges(num_corners(), VertexEdgePair());
+
+ // For each vertex compute the offset (location where the first half-edge
+ // entry of a given vertex is going to be stored). This way each vertex is
+ // guaranteed to have a non-overlapping storage with respect to the other
+ // vertices.
+ std::vector<int> vertex_offset(num_corners_on_vertices.size());
+ int offset = 0;
+ for (size_t i = 0; i < num_corners_on_vertices.size(); ++i) {
+ vertex_offset[i] = offset;
+ offset += num_corners_on_vertices[i];
+ }
+
+ // Now go over the all half-edges (using their opposite corners) and either
+ // insert them to the |vertex_edge| array or connect them with existing
+ // half-edges.
+ for (CornerIndex c(0); c < num_corners(); ++c) {
+ const VertexIndex tip_v = Vertex(c);
+ const VertexIndex source_v = Vertex(Next(c));
+ const VertexIndex sink_v = Vertex(Previous(c));
+
+ const FaceIndex face_index = Face(c);
+ if (c == FirstCorner(face_index)) {
+ // Check whether the face is degenerated, if so ignore it.
+ const VertexIndex v0 = Vertex(c);
+ if (v0 == source_v || v0 == sink_v || source_v == sink_v) {
+ ++num_degenerated_faces_;
+ c += 2; // Ignore the next two corners of the same face.
+ continue;
+ }
+ }
+
+ CornerIndex opposite_c(kInvalidCornerIndex);
+ // The maximum number of half-edges attached to the sink vertex.
+ const int num_corners_on_vert = num_corners_on_vertices[sink_v.value()];
+ // Where to look for the first half-edge on the sink vertex.
+ offset = vertex_offset[sink_v.value()];
+ for (int i = 0; i < num_corners_on_vert; ++i, ++offset) {
+ const VertexIndex other_v = vertex_edges[offset].sink_vert;
+ if (other_v == kInvalidVertexIndex)
+ break; // No matching half-edge found on the sink vertex.
+ if (other_v == source_v) {
+ if (tip_v == Vertex(vertex_edges[offset].edge_corner))
+ continue; // Don't connect mirrored faces.
+ // A matching half-edge was found on the sink vertex. Mark the
+ // half-edge's opposite corner.
+ opposite_c = vertex_edges[offset].edge_corner;
+ // Remove the half-edge from the sink vertex. We remap all subsequent
+ // half-edges one slot down.
+ // TODO(ostava): This can be optimized a little bit, by remapping only
+ // the half-edge on the last valid slot into the deleted half-edge's
+ // slot.
+ for (int j = i + 1; j < num_corners_on_vert; ++j, ++offset) {
+ vertex_edges[offset] = vertex_edges[offset + 1];
+ if (vertex_edges[offset].sink_vert == kInvalidVertexIndex)
+ break; // Unused half-edge reached.
+ }
+ // Mark the last entry as unused.
+ vertex_edges[offset].sink_vert = kInvalidVertexIndex;
+ break;
+ }
+ }
+ if (opposite_c == kInvalidCornerIndex) {
+ // No opposite corner found. Insert the new edge
+ const int num_corners_on_source_vert =
+ num_corners_on_vertices[source_v.value()];
+ offset = vertex_offset[source_v.value()];
+ for (int i = 0; i < num_corners_on_source_vert; ++i, ++offset) {
+ // Find the first unused half-edge slot on the source vertex.
+ if (vertex_edges[offset].sink_vert == kInvalidVertexIndex) {
+ vertex_edges[offset].sink_vert = sink_v;
+ vertex_edges[offset].edge_corner = c;
+ break;
+ }
+ }
+ } else {
+ // Opposite corner found.
+ opposite_corners_[c] = opposite_c;
+ opposite_corners_[opposite_c] = c;
+ }
+ }
+ *num_vertices = static_cast<int>(num_corners_on_vertices.size());
+ return true;
+}
+
+bool CornerTable::ComputeVertexCorners(int num_vertices) {
+ DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
+ num_original_vertices_ = num_vertices;
+ vertex_corners_.resize(num_vertices, kInvalidCornerIndex);
+ // Arrays for marking visited vertices and corners that allow us to detect
+ // non-manifold vertices.
+ std::vector<bool> visited_vertices(num_vertices, false);
+ std::vector<bool> visited_corners(num_corners(), false);
+
+ for (FaceIndex f(0); f < num_faces(); ++f) {
+ const CornerIndex first_face_corner = FirstCorner(f);
+ // Check whether the face is degenerated. If so ignore it.
+ if (IsDegenerated(f))
+ continue;
+
+ for (int k = 0; k < 3; ++k) {
+ const CornerIndex c = first_face_corner + k;
+ if (visited_corners[c.value()])
+ continue;
+ VertexIndex v = corner_to_vertex_map_[c];
+ // Note that one vertex maps to many corners, but we just keep track
+ // of the vertex which has a boundary on the left if the vertex lies on
+ // the boundary. This means that all the related corners can be accessed
+ // by iterating over the SwingRight() operator.
+ // In case of a vertex inside the mesh, the choice is arbitrary.
+ bool is_non_manifold_vertex = false;
+ if (visited_vertices[v.value()]) {
+ // A visited vertex of an unvisited corner found. Must be a non-manifold
+ // vertex.
+ // Create a new vertex for it.
+ vertex_corners_.push_back(kInvalidCornerIndex);
+ non_manifold_vertex_parents_.push_back(v);
+ visited_vertices.push_back(false);
+ v = VertexIndex(num_vertices++);
+ is_non_manifold_vertex = true;
+ }
+ // Mark the vertex as visited.
+ visited_vertices[v.value()] = true;
+
+ // First swing all the way to the left and mark all corners on the way.
+ CornerIndex act_c(c);
+ while (act_c != kInvalidCornerIndex) {
+ visited_corners[act_c.value()] = true;
+ // Vertex will eventually point to the left most corner.
+ vertex_corners_[v] = act_c;
+ if (is_non_manifold_vertex) {
+ // Update vertex index in the corresponding face.
+ corner_to_vertex_map_[act_c] = v;
+ }
+ act_c = SwingLeft(act_c);
+ if (act_c == c)
+ break; // Full circle reached.
+ }
+ if (act_c == kInvalidCornerIndex) {
+ // If we have reached an open boundary we need to swing right from the
+ // initial corner to mark all corners in the opposite direction.
+ act_c = SwingRight(c);
+ while (act_c != kInvalidCornerIndex) {
+ visited_corners[act_c.value()] = true;
+ if (is_non_manifold_vertex) {
+ // Update vertex index in the corresponding face.
+ corner_to_vertex_map_[act_c] = v;
+ }
+ act_c = SwingRight(act_c);
+ }
+ }
+ }
+ }
+
+ // Count the number of isolated (unprocessed) vertices.
+ num_isolated_vertices_ = 0;
+ for (bool visited : visited_vertices) {
+ if (!visited)
+ ++num_isolated_vertices_;
+ }
+ return true;
+}
+
+bool CornerTable::IsDegenerated(FaceIndex face) const {
+ if (face == kInvalidFaceIndex)
+ return true;
+ const CornerIndex first_face_corner = FirstCorner(face);
+ const VertexIndex v0 = Vertex(first_face_corner);
+ const VertexIndex v1 = Vertex(Next(first_face_corner));
+ const VertexIndex v2 = Vertex(Previous(first_face_corner));
+ if (v0 == v1 || v0 == v2 || v1 == v2)
+ return true;
+ return false;
+}
+
+int CornerTable::Valence(VertexIndex v) const {
+ if (v == kInvalidVertexIndex)
+ return -1;
+ return ConfidentValence(v);
+}
+
+int CornerTable::ConfidentValence(VertexIndex v) const {
+ DRACO_DCHECK_GE(v.value(), 0);
+ DRACO_DCHECK_LT(v.value(), num_vertices());
+ VertexRingIterator<CornerTable> vi(this, v);
+ int valence = 0;
+ for (; !vi.End(); vi.Next()) {
+ ++valence;
+ }
+ return valence;
+}
+
+void CornerTable::UpdateFaceToVertexMap(const VertexIndex vertex) {
+ DRACO_DCHECK(GetValenceCache().IsCacheEmpty());
+ VertexCornersIterator<CornerTable> it(this, vertex);
+ for (; !it.End(); ++it) {
+ const CornerIndex corner = *it;
+ corner_to_vertex_map_[corner] = vertex;
+ }
+}
+
+} // namespace draco