OpenSubdiv
Loading...
Searching...
No Matches
patchMap.h
Go to the documentation of this file.
1//
2// Copyright 2013 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://opensubdiv.org/license.
6//
7
8#ifndef OPENSUBDIV3_FAR_PATCH_MAP_H
9#define OPENSUBDIV3_FAR_PATCH_MAP_H
10
11#include "../version.h"
12
13#include "../far/patchTable.h"
14
15#include <cassert>
16
17namespace OpenSubdiv {
18namespace OPENSUBDIV_VERSION {
19
20namespace Far {
21
32class PatchMap {
33public:
34
36
41 PatchMap( PatchTable const & patchTable );
42
57 Handle const * FindPatch( int patchFaceId, double u, double v ) const;
58
59private:
60 void initializeHandles(PatchTable const & patchTable);
61 void initializeQuadtree(PatchTable const & patchTable);
62
63private:
64 // Quadtree node with 4 children, tree is just a vector of nodes
65 struct QuadNode {
66 QuadNode() { std::memset(this, 0, sizeof(QuadNode)); }
67
68 struct Child {
69 unsigned int isSet : 1; // true if the child has been set
70 unsigned int isLeaf : 1; // true if the child is a QuadNode
71 unsigned int index : 30; // child index (either QuadNode or Handle)
72 };
73
74 // sets all the children to point to the patch of given index
75 void SetChildren(int index);
76
77 // sets the child in "quadrant" to point to the node or patch of the given index
78 void SetChild(int quadrant, int index, bool isLeaf);
79
80 Child children[4];
81 };
82 typedef std::vector<QuadNode> QuadTree;
83
84 // Internal methods supporting quadtree construction and queries
85 void assignRootNode(QuadNode * node, int index);
86 QuadNode * assignLeafOrChildNode(QuadNode * node, bool isLeaf, int quad, int index);
87
88 template <class T>
89 static int transformUVToQuadQuadrant(T const & median, T & u, T & v);
90 template <class T>
91 static int transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated);
92
93private:
94 bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
95
96 int _minPatchFace; // minimum patch face index supported by the map
97 int _maxPatchFace; // maximum patch face index supported by the map
98 int _maxDepth; // maximum depth of a patch in the tree
99
100 std::vector<Handle> _handles; // all the patches in the PatchTable
101 std::vector<QuadNode> _quadtree; // quadtree nodes
102};
103
104//
105// Given a median value for both U and V, these methods transform a (u,v) pair
106// into the quadrant that contains them and returns the quadrant index.
107//
108// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
109// usage of UV bits:
110//
111// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
112// | | | |\ \ 1 |\ 0 |
113// | 2 | 3 | | \ \ | \ |
114// | | | | 2 \ \| 3 \|
115// o-----o-----o o-----o o-----o
116// | | | |\ 3 |\ \ 2 |
117// | 0 | 1 | | \ | \ \ |
118// | | | | 0 \| 1 \ \|
119// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
120//
121// The triangular case also takes and returns/affects the rotation of the
122// quadrant being searched and identified (quadrant 3 imparts a rotation).
123//
124template <class T>
125inline int
126PatchMap::transformUVToQuadQuadrant(T const & median, T & u, T & v) {
127
128 int uHalf = (u >= median);
129 if (uHalf) u -= median;
130
131 int vHalf = (v >= median);
132 if (vHalf) v -= median;
133
134 return (vHalf << 1) | uHalf;
135}
136
137template <class T>
138int inline
139PatchMap::transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated) {
140
141 if (!rotated) {
142 if (u >= median) {
143 u -= median;
144 return 1;
145 }
146 if (v >= median) {
147 v -= median;
148 return 2;
149 }
150 if ((u + v) >= median) {
151 rotated = true;
152 return 3;
153 }
154 return 0;
155 } else {
156 if (u < median) {
157 v -= median;
158 return 1;
159 }
160 if (v < median) {
161 u -= median;
162 return 2;
163 }
164 u -= median;
165 v -= median;
166 if ((u + v) < median) {
167 rotated = false;
168 return 3;
169 }
170 return 0;
171 }
172}
173
175inline PatchMap::Handle const *
176PatchMap::FindPatch( int faceid, double u, double v ) const {
177
178 //
179 // Reject patch faces not supported by this map, or those corresponding
180 // to holes or otherwise unassigned (the root node for a patch will
181 // have all or no quadrants set):
182 //
183 if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) return 0;
184
185 QuadNode const * node = &_quadtree[faceid - _minPatchFace];
186
187 if (!node->children[0].isSet) return 0;
188
189 //
190 // Search the tree for the sub-patch containing the given (u,v)
191 //
192 assert( (u>=0.0) && (u<=1.0) && (v>=0.0) && (v<=1.0) );
193
194 double median = 0.5;
195 bool triRotated = false;
196
197 for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
198
199 int quadrant = _patchesAreTriangular
200 ? transformUVToTriQuadrant(median, u, v, triRotated)
201 : transformUVToQuadQuadrant(median, u, v);
202
203 // holes should have been rejected at the root node of the face
204 assert(node->children[quadrant].isSet);
205
206 if (node->children[quadrant].isLeaf) {
207 return &_handles[node->children[quadrant].index];
208 } else {
209 node = &_quadtree[node->children[quadrant].index];
210 }
211 }
212 assert(0);
213 return 0;
214}
215
216} // end namespace Far
217
218} // end namespace OPENSUBDIV_VERSION
219using namespace OPENSUBDIV_VERSION;
220
221} // end namespace OpenSubdiv
222
223#endif /* OPENSUBDIV3_FAR_PATCH_PARAM */
An quadtree-based map connecting coarse faces to their sub-patches.
Definition patchMap.h:32
PatchMap(PatchTable const &patchTable)
Constructor.
Handle const * FindPatch(int patchFaceId, double u, double v) const
Returns a handle to the sub-patch of the face at the given (u,v). Note that the patch face ID corresp...
Definition patchMap.h:176
Container for arrays of parametric patches.
Definition patchTable.h:38
Handle that can be used as unique patch identifier within PatchTable.
Definition patchTable.h:43