GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
max_prediction_degree_traverser.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_COMPRESSION_MESH_TRAVERSER_MAX_PREDICTION_DEGREE_TRAVERSER_H_
16#define DRACO_COMPRESSION_MESH_TRAVERSER_MAX_PREDICTION_DEGREE_TRAVERSER_H_
17
18#include <vector>
19
22
23namespace draco {
24
25// PredictionDegreeTraverser provides framework for traversal over a corner
26// table data structure following paper "Multi-way Geometry Encoding" by
27// Cohen-or at al.'02. The traversal is implicitly guided by prediction degree
28// of the destination vertices. A prediction degree is computed as the number of
29// possible faces that can be used as source points for traversal to the given
30// destination vertex (see image below, where faces F1 and F2 are already
31// traversed and face F0 is not traversed yet. The prediction degree of vertex
32// V is then equal to two).
33//
34// X-----V-----o
35// / \ / \ / \
36// / F0\ / \ / F2\
37// X-----o-----o-----B
38// \ F1/
39// \ /
40// A
41//
42// The class implements the same interface as the DepthFirstTraverser
43// (depth_first_traverser.h) and it can be controlled via the same template
44// trait classes |CornerTableT| and |TraversalObserverT|, that are used
45// for controlling and monitoring of the traversal respectively. For details,
46// please see depth_first_traverser.h.
47template <class CornerTableT, class TraversalObserverT>
49 : public TraverserBase<CornerTable, TraversalObserverT> {
50 public:
51 typedef CornerTableT CornerTable;
52 typedef TraversalObserverT TraversalObserver;
54
56
57 // Called before any traversing starts.
59 prediction_degree_.resize(this->corner_table()->num_vertices(), 0);
60 }
61
62 // Called when all the traversing is done.
64
66 if (prediction_degree_.size() == 0) {
67 return true;
68 }
69
70 // Traversal starts from the |corner_id|. It's going to follow either the
71 // right or the left neighboring faces to |corner_id| based on their
72 // prediction degree.
73 traversal_stacks_[0].push_back(corner_id);
74 best_priority_ = 0;
75 // For the first face, check the remaining corners as they may not be
76 // processed yet.
77 const VertexIndex next_vert =
78 this->corner_table()->Vertex(this->corner_table()->Next(corner_id));
79 const VertexIndex prev_vert =
80 this->corner_table()->Vertex(this->corner_table()->Previous(corner_id));
81 if (!this->IsVertexVisited(next_vert)) {
82 this->MarkVertexVisited(next_vert);
83 this->traversal_observer().OnNewVertexVisited(
84 next_vert, this->corner_table()->Next(corner_id));
85 }
86 if (!this->IsVertexVisited(prev_vert)) {
87 this->MarkVertexVisited(prev_vert);
88 this->traversal_observer().OnNewVertexVisited(
89 prev_vert, this->corner_table()->Previous(corner_id));
90 }
91 const VertexIndex tip_vertex = this->corner_table()->Vertex(corner_id);
92 if (!this->IsVertexVisited(tip_vertex)) {
93 this->MarkVertexVisited(tip_vertex);
94 this->traversal_observer().OnNewVertexVisited(tip_vertex, corner_id);
95 }
96 // Start the actual traversal.
97 while ((corner_id = PopNextCornerToTraverse()) != kInvalidCornerIndex) {
98 FaceIndex face_id(corner_id.value() / 3);
99 // Make sure the face hasn't been visited yet.
100 if (this->IsFaceVisited(face_id)) {
101 // This face has been already traversed.
102 continue;
103 }
104
105 while (true) {
106 face_id = FaceIndex(corner_id.value() / 3);
107 this->MarkFaceVisited(face_id);
108 this->traversal_observer().OnNewFaceVisited(face_id);
109
110 // If the newly reached vertex hasn't been visited, mark it and notify
111 // the observer.
112 const VertexIndex vert_id = this->corner_table()->Vertex(corner_id);
113 if (!this->IsVertexVisited(vert_id)) {
114 this->MarkVertexVisited(vert_id);
115 this->traversal_observer().OnNewVertexVisited(vert_id, corner_id);
116 }
117
118 // Check whether we can traverse to the right and left neighboring
119 // faces.
120 const CornerIndex right_corner_id =
121 this->corner_table()->GetRightCorner(corner_id);
122 const CornerIndex left_corner_id =
123 this->corner_table()->GetLeftCorner(corner_id);
124 const FaceIndex right_face_id(
125 (right_corner_id == kInvalidCornerIndex
126 ? kInvalidFaceIndex
127 : FaceIndex(right_corner_id.value() / 3)));
128 const FaceIndex left_face_id(
129 (left_corner_id == kInvalidCornerIndex
130 ? kInvalidFaceIndex
131 : FaceIndex(left_corner_id.value() / 3)));
132 const bool is_right_face_visited = this->IsFaceVisited(right_face_id);
133 const bool is_left_face_visited = this->IsFaceVisited(left_face_id);
134
135 if (!is_left_face_visited) {
136 // We can go to the left face.
137 const int priority = ComputePriority(left_corner_id);
138 if (is_right_face_visited && priority <= best_priority_) {
139 // Right face has been already visited and the priority is equal or
140 // better than the best priority. We are sure that the left face
141 // would be traversed next so there is no need to put it onto the
142 // stack.
143 corner_id = left_corner_id;
144 continue;
145 } else {
146 AddCornerToTraversalStack(left_corner_id, priority);
147 }
148 }
149 if (!is_right_face_visited) {
150 // Go to the right face.
151 const int priority = ComputePriority(right_corner_id);
152 if (priority <= best_priority_) {
153 // We are sure that the right face would be traversed next so there
154 // is no need to put it onto the stack.
155 corner_id = right_corner_id;
156 continue;
157 } else {
158 AddCornerToTraversalStack(right_corner_id, priority);
159 }
160 }
161
162 // Couldn't proceed directly to the next corner
163 break;
164 }
165 }
166 return true;
167 }
168
169 private:
170 // Retrieves the next available corner (edge) to traverse. Edges are processed
171 // based on their priorities.
172 // Returns kInvalidCornerIndex when there is no edge available.
173 CornerIndex PopNextCornerToTraverse() {
174 for (int i = best_priority_; i < kMaxPriority; ++i) {
175 if (!traversal_stacks_[i].empty()) {
176 const CornerIndex ret = traversal_stacks_[i].back();
177 traversal_stacks_[i].pop_back();
178 best_priority_ = i;
179 return ret;
180 }
181 }
182 return kInvalidCornerIndex;
183 }
184
185 inline void AddCornerToTraversalStack(CornerIndex ci, int priority) {
186 traversal_stacks_[priority].push_back(ci);
187 // Make sure that the best available priority is up to date.
188 if (priority < best_priority_) {
189 best_priority_ = priority;
190 }
191 }
192
193 // Returns the priority of traversing edge leading to |corner_id|.
194 inline int ComputePriority(CornerIndex corner_id) {
195 const VertexIndex v_tip = this->corner_table()->Vertex(corner_id);
196 // Priority 0 when traversing to already visited vertices.
197 int priority = 0;
198 if (!this->IsVertexVisited(v_tip)) {
199 const int degree = ++prediction_degree_[v_tip];
200 // Priority 1 when prediction degree > 1, otherwise 2.
201 priority = (degree > 1 ? 1 : 2);
202 }
203 // Clamp the priority to the maximum number of buckets.
204 if (priority >= kMaxPriority) {
205 priority = kMaxPriority - 1;
206 }
207 return priority;
208 }
209
210 // For efficiency reasons, the priority traversal is implemented using buckets
211 // where each buckets represent a stack of available corners for a given
212 // priority. Corners with the highest priority are always processed first.
213 static constexpr int kMaxPriority = 3;
214 std::vector<CornerIndex> traversal_stacks_[kMaxPriority];
215
216 // Keep the track of the best available priority to improve the performance
217 // of PopNextCornerToTraverse() method.
218 int best_priority_;
219
220 // Prediction degree available for each vertex.
221 IndexTypeVector<VertexIndex, int> prediction_degree_;
222};
223
224} // namespace draco
225
226#endif // DRACO_COMPRESSION_MESH_TRAVERSER_MAX_PREDICTION_DEGREE_TRAVERSER_H_
void OnTraversalStart()
Definition max_prediction_degree_traverser.h:58
bool TraverseFromCorner(CornerIndex corner_id)
Definition max_prediction_degree_traverser.h:65
MaxPredictionDegreeTraverser()
Definition max_prediction_degree_traverser.h:55
TraverserBase< CornerTable, TraversalObserver > Base
Definition max_prediction_degree_traverser.h:53
void OnTraversalEnd()
Definition max_prediction_degree_traverser.h:63
CornerTableT CornerTable
Definition max_prediction_degree_traverser.h:51
TraversalObserverT TraversalObserver
Definition max_prediction_degree_traverser.h:52
const CornerTable * corner_table() const
Definition traverser_base.h:70
bool IsVertexVisited(VertexIndex vert_id) const
Definition traverser_base.h:63
const TraversalObserverT & traversal_observer() const
Definition traverser_base.h:71
bool IsFaceVisited(FaceIndex face_id) const
Definition traverser_base.h:45
void MarkVertexVisited(VertexIndex vert_id)
Definition traverser_base.h:66
void MarkFaceVisited(FaceIndex face_id)
Definition traverser_base.h:60
ret($return)
Definition mesh_login_result.php:5
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
W empty()
Definition ui.cc:634