mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-23 08:20:06 +00:00
Minor extensions to Far classes to help manage large PatchTables:
- overloaded PatchTableFactory::Create() to take subset of base faces - overloaded TopologyRefiner::RefineAdaptive() to take subset of base faces - added TopologyRefinerFactory::Create() to create new TopologyRefiner that shares base level with another, allowing independent refinement - overloaded PatchTable::ComputeLocalPointValues...() to accept split buffers with separate base-level primvar values - overloaded StencilTable::UpdateValues() to accept split buffers as above
This commit is contained in:
parent
c566e8f2ab
commit
f58330fdee
@ -172,6 +172,10 @@ public:
|
||||
template <class T> void
|
||||
ComputeLocalPointValues(T const *src, T *dst) const;
|
||||
|
||||
template <class T> void
|
||||
ComputeLocalPointValues(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point vertex values
|
||||
StencilTable const *GetLocalPointStencilTable() const;
|
||||
|
||||
@ -198,6 +202,10 @@ public:
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesVarying(T const *src, T *dst) const;
|
||||
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesVarying(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point varying values
|
||||
StencilTable const *GetLocalPointVaryingStencilTable() const;
|
||||
|
||||
@ -226,6 +234,10 @@ public:
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel = 0) const;
|
||||
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesFaceVarying(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point face-varying values
|
||||
StencilTable const *GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
|
||||
|
||||
@ -781,6 +793,20 @@ PatchTable::ComputeLocalPointValues(T const *src, T *dst) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValues(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst) const {
|
||||
if (_localPointStencils.IsSet()) {
|
||||
if (_vertexPrecisionIsDouble) {
|
||||
_localPointStencils.Get<double>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
} else {
|
||||
_localPointStencils.Get<float>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
@ -793,6 +819,20 @@ PatchTable::ComputeLocalPointValuesVarying(T const *src, T *dst) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesVarying(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst) const {
|
||||
if (_localPointVaryingStencils.IsSet()) {
|
||||
if (_varyingPrecisionIsDouble) {
|
||||
_localPointVaryingStencils.Get<double>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
} else {
|
||||
_localPointVaryingStencils.Get<float>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
@ -807,6 +847,22 @@ PatchTable::ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel
|
||||
}
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesFaceVarying(T const *srcBase, int numBase,
|
||||
T const *srcRefined, T *dst, int channel) const {
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
if (_localPointFaceVaryingStencils[channel].IsSet()) {
|
||||
if (_faceVaryingPrecisionIsDouble) {
|
||||
_localPointFaceVaryingStencils[channel].Get<double>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
} else {
|
||||
_localPointFaceVaryingStencils[channel].Get<float>()->UpdateValues(
|
||||
srcBase, numBase, srcRefined, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
@ -103,7 +103,8 @@ public:
|
||||
//
|
||||
typedef PatchTableFactory::Options Options;
|
||||
|
||||
PatchTableBuilder(TopologyRefiner const & refiner, Options options);
|
||||
PatchTableBuilder(TopologyRefiner const & refiner, Options options,
|
||||
ConstIndexArray selectedFaces);
|
||||
~PatchTableBuilder();
|
||||
|
||||
void BuildUniform();
|
||||
@ -313,6 +314,8 @@ private:
|
||||
|
||||
// High level methods for assembling the table:
|
||||
void identifyAdaptivePatches();
|
||||
void appendAdaptivePatch(int levelIndex, Index faceIndex);
|
||||
void testAdaptivePatchRecursive(int levelIndex, Index faceIndex);
|
||||
void populateAdaptivePatches();
|
||||
|
||||
void allocateVertexTables();
|
||||
@ -325,6 +328,7 @@ private:
|
||||
// Refiner and Options passed on construction:
|
||||
TopologyRefiner const & _refiner;
|
||||
Options const _options;
|
||||
ConstIndexArray _selectedFaces;
|
||||
|
||||
// Flags indicating the need for processing based on provided options
|
||||
unsigned int _requiresLocalPoints : 1;
|
||||
@ -361,8 +365,8 @@ private:
|
||||
|
||||
// Constructor
|
||||
PatchTableBuilder::PatchTableBuilder(
|
||||
TopologyRefiner const & refiner, Options opts) :
|
||||
_refiner(refiner), _options(opts),
|
||||
TopologyRefiner const & refiner, Options opts, ConstIndexArray faces) :
|
||||
_refiner(refiner), _options(opts), _selectedFaces(faces),
|
||||
_table(0), _patchBuilder(0), _ptexIndices(refiner),
|
||||
_numRegularPatches(0), _numIrregularPatches(0),
|
||||
_legacyGregoryHelper(0) {
|
||||
@ -898,16 +902,48 @@ PatchTableBuilder::BuildAdaptive() {
|
||||
// <level,face> pairs to identify each patch for later construction, while
|
||||
// accumulating the number of regular vs irregular patches to size tables.
|
||||
//
|
||||
inline void
|
||||
PatchTableBuilder::appendAdaptivePatch(int levelIndex, Index faceIndex) {
|
||||
|
||||
_patches.push_back(PatchTuple(faceIndex, levelIndex));
|
||||
|
||||
// Count the patches here to simplify subsequent allocation.
|
||||
if (_patchBuilder->IsPatchRegular(levelIndex, faceIndex)) {
|
||||
++_numRegularPatches;
|
||||
} else {
|
||||
++_numIrregularPatches;
|
||||
|
||||
// LegacyGregory needs to distinguish boundary vs interior
|
||||
if (_requiresLegacyGregoryTables) {
|
||||
_legacyGregoryHelper->AddPatchFace(levelIndex, faceIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchTableBuilder::testAdaptivePatchRecursive(int levelIndex, Index faceIndex) {
|
||||
|
||||
if (_patchBuilder->IsFaceALeaf(levelIndex, faceIndex)) {
|
||||
if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex)) {
|
||||
appendAdaptivePatch(levelIndex, faceIndex);
|
||||
}
|
||||
} else {
|
||||
TopologyLevel const & level = _refiner.GetLevel(levelIndex);
|
||||
ConstIndexArray childFaces = level.GetFaceChildFaces(faceIndex);
|
||||
for (int i = 0; i < childFaces.size(); ++i) {
|
||||
if (Vtr::IndexIsValid(childFaces[i])) {
|
||||
testAdaptivePatchRecursive(levelIndex + 1, childFaces[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PatchTableBuilder::identifyAdaptivePatches() {
|
||||
|
||||
//
|
||||
// Iterate through the levels of refinement. Accumulate index offsets
|
||||
// for each level while inspecting faces for patches:
|
||||
// First initialize the offsets for all levels
|
||||
//
|
||||
int reservePatches = _refiner.GetNumFacesTotal();
|
||||
_patches.reserve(reservePatches);
|
||||
|
||||
_levelVertOffsets.push_back(0);
|
||||
_levelFVarValueOffsets.resize(_fvarChannelIndices.size());
|
||||
for (int fvc=0; fvc<(int)_fvarChannelIndices.size(); ++fvc) {
|
||||
@ -926,24 +962,33 @@ PatchTableBuilder::identifyAdaptivePatches() {
|
||||
_levelFVarValueOffsets[fvc].back()
|
||||
+ level.getNumFVarValues(refinerChannel));
|
||||
}
|
||||
}
|
||||
|
||||
for (int faceIndex = 0; faceIndex < level.getNumFaces(); ++faceIndex) {
|
||||
//
|
||||
// If a set of selected base faces is present, identify the patches
|
||||
// depth first. Otherwise search breadth first through the levels:
|
||||
//
|
||||
_patches.reserve(_refiner.GetNumFacesTotal());
|
||||
|
||||
// This depth-first-all test is intended for development testing only
|
||||
bool depthFirstTestForAll = false;
|
||||
if (_selectedFaces.size()) {
|
||||
for (int i = 0; i < (int)_selectedFaces.size(); ++i) {
|
||||
testAdaptivePatchRecursive(0, _selectedFaces[i]);
|
||||
}
|
||||
} else if (depthFirstTestForAll) {
|
||||
for (int baseFace = 0; baseFace < _refiner.getLevel(0).getNumFaces(); ++baseFace) {
|
||||
testAdaptivePatchRecursive(0, baseFace);
|
||||
}
|
||||
} else {
|
||||
for (int levelIndex=0; levelIndex<_refiner.GetNumLevels(); ++levelIndex) {
|
||||
int numFaces = _refiner.getLevel(levelIndex).getNumFaces();
|
||||
|
||||
for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
|
||||
|
||||
if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex) &&
|
||||
_patchBuilder->IsFaceALeaf(levelIndex, faceIndex)) {
|
||||
|
||||
_patches.push_back(PatchTuple(faceIndex, levelIndex));
|
||||
|
||||
// Count the patches here to simplify subsequent allocation.
|
||||
if (_patchBuilder->IsPatchRegular(levelIndex, faceIndex)) {
|
||||
++_numRegularPatches;
|
||||
} else {
|
||||
++_numIrregularPatches;
|
||||
|
||||
// LegacyGregory needs to distinguish boundary vs interior
|
||||
if (_requiresLegacyGregoryTables) {
|
||||
_legacyGregoryHelper->AddPatchFace(levelIndex, faceIndex);
|
||||
}
|
||||
appendAdaptivePatch(levelIndex, faceIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1889,9 +1934,11 @@ PatchTableBuilder::LegacyGregoryHelper::FinalizeVertexValence(
|
||||
// to the PatchTableBuilder implementation
|
||||
//
|
||||
PatchTable *
|
||||
PatchTableFactory::Create(TopologyRefiner const & refiner, Options options) {
|
||||
PatchTableFactory::Create(TopologyRefiner const & refiner,
|
||||
Options options,
|
||||
ConstIndexArray selectedFaces) {
|
||||
|
||||
PatchTableBuilder builder(refiner, options);
|
||||
PatchTableBuilder builder(refiner, options, selectedFaces);
|
||||
|
||||
if (refiner.IsUniform()) {
|
||||
builder.BuildUniform();
|
||||
|
@ -129,7 +129,11 @@ public:
|
||||
///
|
||||
/// For adaptively refined patches, patches are defined at different levels,
|
||||
/// including the base level, so the indices of patch vertices include
|
||||
/// vertices from all levels.
|
||||
/// vertices from all levels. A sparse set of patches can be created by
|
||||
/// restricting the patches generated to those descending from a given set
|
||||
/// of faces at the base level. This sparse set of base faces is expected
|
||||
/// to be a subset of the faces that were adaptively refined in the given
|
||||
/// TopologyRefiner, otherwise results are undefined.
|
||||
///
|
||||
/// For uniformly refined patches, all patches are completely defined within
|
||||
/// the last level. There is often no use for intermediate levels and they
|
||||
@ -144,13 +148,17 @@ public:
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
/// @param selectedFaces Only create patches for the given set of base faces.
|
||||
///
|
||||
/// @return A new instance of PatchTable
|
||||
///
|
||||
static PatchTable * Create(TopologyRefiner const & refiner,
|
||||
Options options=Options());
|
||||
Options options = Options(),
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
public:
|
||||
// PatchFaceTag
|
||||
//
|
||||
// This simple struct was previously used within the factory to take inventory of
|
||||
// various kinds of patches to fully allocate buffers prior to populating them. It
|
||||
// was not intended to be exposed as part of the public interface.
|
||||
@ -158,6 +166,9 @@ public:
|
||||
// It is no longer used internally and is being kept here to respect preservation
|
||||
// of the public interface, but it will be deprecated at the earliest opportunity.
|
||||
//
|
||||
/// \brief Obsolete internal struct accidentally exposed for public use -- due to
|
||||
/// be deprecated.
|
||||
//
|
||||
struct PatchFaceTag {
|
||||
public:
|
||||
unsigned int _hasPatch : 1;
|
||||
|
@ -193,18 +193,24 @@ public:
|
||||
/// \note The destination buffers are assumed to have allocated at least
|
||||
/// \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param controlValues Buffer with primvar data for the control vertices
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param values Destination buffer for the interpolated primvar
|
||||
/// data
|
||||
/// @param dstValues Destination buffer for the interpolated primvar data
|
||||
///
|
||||
/// @param start index of first value to update
|
||||
/// @param start Index of first destination value to update
|
||||
///
|
||||
/// @param end Index of last value to update
|
||||
/// @param end Index of last destination value to update
|
||||
///
|
||||
template <class T>
|
||||
void UpdateValues(T const *controlValues, T *values, Index start=-1, Index end=-1) const {
|
||||
this->update(controlValues, values, _weights, start, end);
|
||||
void UpdateValues(T const *srcValues, T *dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcValues, dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UpdateValues(T const *srcBaseValues, int numBaseValues, T const *srcNonBaseValues,
|
||||
T *dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcBaseValues, numBaseValues, srcNonBaseValues,
|
||||
dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
@ -214,7 +220,11 @@ protected:
|
||||
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <class T>
|
||||
void update( T const *controlValues, T *values,
|
||||
void update( T const *srcValues, T *dstValues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
template <class T>
|
||||
void update( T const *srcBaseValues, int numBaseValues,
|
||||
T const *srcNonBaseValues, T *dstalues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
|
||||
// Populate the offsets table from the stencil sizes in _sizes (factory helper)
|
||||
@ -441,7 +451,7 @@ public:
|
||||
/// \note The destination buffers ('uderivs' & 'vderivs') are assumed to
|
||||
/// have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param controlValues Buffer with primvar data for the control vertices
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uderivs Destination buffer for the interpolated 'u'
|
||||
/// derivative primvar data
|
||||
@ -449,16 +459,27 @@ public:
|
||||
/// @param vderivs Destination buffer for the interpolated 'v'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start index of first value to update
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last value to update
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T>
|
||||
void UpdateDerivs(T const *controlValues, T *uderivs, T *vderivs,
|
||||
void UpdateDerivs(T const *srcValues, T *uderivs, T *vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(controlValues, uderivs, _duWeights, start, end);
|
||||
this->update(controlValues, vderivs, _dvWeights, start, end);
|
||||
this->update(srcValues, uderivs, _duWeights, start, end);
|
||||
this->update(srcValues, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UpdateDerivs(T const *srcBaseValues, int numBaseValues,
|
||||
T const *srcNonBaseValues, T *uderivs, T *vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBaseValues, numBaseValues, srcNonBaseValues,
|
||||
uderivs, _duWeights, start, end);
|
||||
this->update(srcBaseValues, numBaseValues, srcNonBaseValues,
|
||||
vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Updates 2nd derivative values based on the control values
|
||||
@ -466,7 +487,7 @@ public:
|
||||
/// \note The destination buffers ('uuderivs', 'uvderivs', & 'vderivs') are
|
||||
/// assumed to have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param controlValues Buffer with primvar data for the control vertices
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uuderivs Destination buffer for the interpolated 'uu'
|
||||
/// derivative primvar data
|
||||
@ -477,17 +498,30 @@ public:
|
||||
/// @param vvderivs Destination buffer for the interpolated 'vv'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start index of first value to update
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last value to update
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T>
|
||||
void Update2ndDerivs(T const *controlValues, T *uuderivs, T *uvderivs, T *vvderivs,
|
||||
void Update2ndDerivs(T const *srcValues, T *uuderivs, T *uvderivs, T *vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(controlValues, uuderivs, _duuWeights, start, end);
|
||||
this->update(controlValues, uvderivs, _duvWeights, start, end);
|
||||
this->update(controlValues, vvderivs, _dvvWeights, start, end);
|
||||
this->update(srcValues, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcValues, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcValues, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Update2ndDerivs(T const *srcBaseValues, int numBaseValues,
|
||||
T const *srcOtherValues, T *uuderivs, T *uvderivs, T *vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBaseValues, numBaseValues, srcOtherValues,
|
||||
uuderivs, _duuWeights, start, end);
|
||||
this->update(srcBaseValues, numBaseValues, srcOtherValues,
|
||||
uvderivs, _duvWeights, start, end);
|
||||
this->update(srcBaseValues, numBaseValues, srcOtherValues,
|
||||
vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
@ -544,7 +578,8 @@ protected:
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <typename REAL>
|
||||
template <class T> void
|
||||
StencilTableReal<REAL>::update(T const *controlValues, T *values,
|
||||
StencilTableReal<REAL>::update(T const *srcBaseValues, int numBaseValues,
|
||||
T const *srcNonBaseValues, T *dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
int const * sizes = &_sizes.at(0);
|
||||
@ -556,7 +591,7 @@ StencilTableReal<REAL>::update(T const *controlValues, T *values,
|
||||
sizes += start;
|
||||
indices += _offsets[start];
|
||||
weights += _offsets[start];
|
||||
values += start;
|
||||
dstValues += start;
|
||||
}
|
||||
|
||||
if (end<start || end<0) {
|
||||
@ -564,16 +599,33 @@ StencilTableReal<REAL>::update(T const *controlValues, T *values,
|
||||
}
|
||||
|
||||
int nstencils = end - std::max(0, start);
|
||||
|
||||
// Use separate loops for single and split buffers
|
||||
if (srcNonBaseValues == 0) {
|
||||
for (int i=0; i<nstencils; ++i, ++sizes) {
|
||||
|
||||
// Zero out the result accumulators
|
||||
values[i].Clear();
|
||||
|
||||
// For each element in the array, add the coef's contribution
|
||||
dstValues[i].Clear();
|
||||
for (int j=0; j<*sizes; ++j, ++indices, ++weights) {
|
||||
values[i].AddWithWeight( controlValues[*indices], *weights );
|
||||
dstValues[i].AddWithWeight( srcBaseValues[*indices], *weights );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<nstencils; ++i, ++sizes) {
|
||||
dstValues[i].Clear();
|
||||
for (int j=0; j<*sizes; ++j, ++indices, ++weights) {
|
||||
T const & srcValue = (*indices < numBaseValues)
|
||||
? srcBaseValues[*indices]
|
||||
: srcNonBaseValues[*indices - numBaseValues];
|
||||
dstValues[i].AddWithWeight( srcValue, *weights );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename REAL>
|
||||
template <class T> void
|
||||
StencilTableReal<REAL>::update(T const *srcValues, T *dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
this->update(srcValues, 0, (T const *)0, dstValues, valueWeights, start, end);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
|
@ -53,7 +53,8 @@ TopologyRefiner::TopologyRefiner(Sdc::SchemeType schemeType, Sdc::Options scheme
|
||||
_totalEdges(0),
|
||||
_totalFaces(0),
|
||||
_totalFaceVertices(0),
|
||||
_maxValence(0) {
|
||||
_maxValence(0),
|
||||
_baseLevelOwned(true) {
|
||||
|
||||
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
||||
// but will probably have to settle for explicit new/delete...
|
||||
@ -63,10 +64,35 @@ TopologyRefiner::TopologyRefiner(Sdc::SchemeType schemeType, Sdc::Options scheme
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// The copy constructor is protected and used by the factory to create a new instance
|
||||
// from only the base level of the given instance -- it does not create a full copy.
|
||||
// So members reflecting any refinement are default-initialized while those dependent
|
||||
// on the base level are copied or explicitly initialized after its assignment.
|
||||
//
|
||||
TopologyRefiner::TopologyRefiner(TopologyRefiner const & source) :
|
||||
_subdivType(source._subdivType),
|
||||
_subdivOptions(source._subdivOptions),
|
||||
_isUniform(true),
|
||||
_hasHoles(source._hasHoles),
|
||||
_maxLevel(0),
|
||||
_uniformOptions(0),
|
||||
_adaptiveOptions(0),
|
||||
_baseLevelOwned(false) {
|
||||
|
||||
_levels.reserve(10);
|
||||
_levels.push_back(source._levels[0]);
|
||||
initializeInventory();
|
||||
|
||||
_farLevels.reserve(10);
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
|
||||
TopologyRefiner::~TopologyRefiner() {
|
||||
|
||||
for (int i=0; i<(int)_levels.size(); ++i) {
|
||||
delete _levels[i];
|
||||
if ((i > 0) || _baseLevelOwned) delete _levels[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)_refinements.size(); ++i) {
|
||||
@ -345,7 +371,8 @@ namespace internal {
|
||||
} // end namespace internal
|
||||
|
||||
void
|
||||
TopologyRefiner::RefineAdaptive(AdaptiveOptions options) {
|
||||
TopologyRefiner::RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray baseFacesToRefine) {
|
||||
|
||||
if (_levels[0]->getNumVertices() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
@ -436,7 +463,15 @@ TopologyRefiner::RefineAdaptive(AdaptiveOptions options) {
|
||||
//
|
||||
Vtr::internal::SparseSelector selector(*refinement);
|
||||
|
||||
selectFeatureAdaptiveComponents(selector, (i <= shallowLevel) ? moreFeaturesMask : lessFeaturesMask);
|
||||
internal::FeatureMask const & levelFeatures = (i <= shallowLevel) ? moreFeaturesMask
|
||||
: lessFeaturesMask;
|
||||
|
||||
if (i == 1) {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, baseFacesToRefine);
|
||||
} else {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, ConstIndexArray());
|
||||
}
|
||||
|
||||
if (selector.isSelectionEmpty()) {
|
||||
delete refinement;
|
||||
delete &childLevel;
|
||||
@ -667,9 +702,32 @@ namespace {
|
||||
// and will select all relevant topological features for inclusion in the subsequent sparse
|
||||
// refinement.
|
||||
//
|
||||
namespace {
|
||||
bool
|
||||
faceNextToIrregFace(Vtr::internal::Level const& level, Index faceIndex, int regFaceSize) {
|
||||
|
||||
// Wish there was a better way to determine this -- we must inspect the sizes
|
||||
// of all incident faces of all corners of the face...
|
||||
//
|
||||
Vtr::ConstIndexArray faceVerts = level.getFaceVertices(faceIndex);
|
||||
|
||||
for (int i = 0; i < faceVerts.size(); ++i) {
|
||||
ConstIndexArray vertFaces = level.getVertexFaces(faceVerts[i]);
|
||||
|
||||
for (int j = 0; j < vertFaces.size(); ++j) {
|
||||
if (level.getFaceVertices(vertFaces[j]).size() != regFaceSize) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & featureMask) {
|
||||
internal::FeatureMask const & featureMask,
|
||||
ConstIndexArray facesToRefine) {
|
||||
|
||||
Vtr::internal::Level const& level = selector.getRefinement().parent();
|
||||
int levelDepth = level.getDepth();
|
||||
@ -684,7 +742,11 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector&
|
||||
//
|
||||
// Inspect each face and the properties tagged at all of its corners:
|
||||
//
|
||||
for (Vtr::Index face = 0; face < level.getNumFaces(); ++face) {
|
||||
int numFacesToRefine = facesToRefine.size() ? facesToRefine.size() : level.getNumFaces();
|
||||
|
||||
for (int fIndex = 0; fIndex < numFacesToRefine; ++fIndex) {
|
||||
|
||||
Vtr::Index face = facesToRefine.size() ? facesToRefine[fIndex] : (Index) fIndex;
|
||||
|
||||
if (level.isFaceHole(face)) {
|
||||
continue;
|
||||
@ -694,18 +756,18 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector&
|
||||
// Testing irregular faces is only necessary at level 0, and potentially warrants
|
||||
// separating out as the caller can detect these.
|
||||
//
|
||||
// We need to also ensure that all adjacent faces to this are selected, so we
|
||||
// select every face incident every vertex of the face. This is the only place
|
||||
// where other faces are selected as a side effect and somewhat undermines the
|
||||
// whole intent of the per-face traversal.
|
||||
//
|
||||
if (selectIrregularFaces) {
|
||||
Vtr::ConstIndexArray faceVerts = level.getFaceVertices(face);
|
||||
|
||||
if (faceVerts.size() != regularFaceSize) {
|
||||
if (neighborhood == 0) {
|
||||
selector.selectFace(face);
|
||||
} else {
|
||||
|
||||
// For non-linear schemes, if the faces to refine were not explicitly
|
||||
// specified, select all faces adjacent to this irregular face. (This
|
||||
// is the only place where other faces are selected as a side effect
|
||||
// and somewhat undermines the whole intent of the per-face traversal.)
|
||||
//
|
||||
if ((neighborhood > 0) && facesToRefine.empty()) {
|
||||
for (int i = 0; i < faceVerts.size(); ++i) {
|
||||
ConstIndexArray fVertFaces = level.getVertexFaces(faceVerts[i]);
|
||||
for (int j = 0; j < fVertFaces.size(); ++j) {
|
||||
@ -714,6 +776,18 @@ TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector&
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
// For non-linear schemes, if the faces to refine were explicitly
|
||||
// specified, we can't count on this regular face be selected as
|
||||
// adjacent to an irregular face above, so see if any of its
|
||||
// neighboring faces are irregular and select if so:
|
||||
//
|
||||
if ((neighborhood > 0) && !facesToRefine.empty()) {
|
||||
if (faceNextToIrregFace(level, face, regularFaceSize)) {
|
||||
selector.selectFace(face);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,11 +174,14 @@ public:
|
||||
///< instead of child vertices of vertices
|
||||
};
|
||||
|
||||
/// \brief Feature Adaptive topology refinement (restricted to scheme Catmark)
|
||||
/// \brief Feature Adaptive topology refinement
|
||||
///
|
||||
/// @param options Options controlling adaptive refinement
|
||||
///
|
||||
void RefineAdaptive(AdaptiveOptions options);
|
||||
/// @param selectedFaces Limit adaptive refinement to the specified faces
|
||||
///
|
||||
void RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
/// \brief Returns the options specified on refinement
|
||||
AdaptiveOptions GetAdaptiveOptions() const { return _adaptiveOptions; }
|
||||
@ -216,6 +219,9 @@ protected:
|
||||
template <typename REAL>
|
||||
friend class PrimvarRefinerReal;
|
||||
|
||||
// Copy constructor exposed via the factory class:
|
||||
TopologyRefiner(TopologyRefiner const & source);
|
||||
|
||||
Vtr::internal::Level & getLevel(int l) { return *_levels[l]; }
|
||||
Vtr::internal::Level const & getLevel(int l) const { return *_levels[l]; }
|
||||
|
||||
@ -225,11 +231,11 @@ protected:
|
||||
private:
|
||||
// Not default constructible or copyable:
|
||||
TopologyRefiner() : _uniformOptions(0), _adaptiveOptions(0) { }
|
||||
TopologyRefiner(TopologyRefiner const &) : _uniformOptions(0), _adaptiveOptions(0) { }
|
||||
TopologyRefiner & operator=(TopologyRefiner const &) { return *this; }
|
||||
|
||||
void selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & mask);
|
||||
internal::FeatureMask const & mask,
|
||||
ConstIndexArray selectedFaces);
|
||||
|
||||
void initializeInventory();
|
||||
void updateInventory(Vtr::internal::Level const & newLevel);
|
||||
@ -258,7 +264,9 @@ private:
|
||||
int _totalFaceVertices;
|
||||
int _maxValence;
|
||||
|
||||
// There is some redundancy here -- to be reduced later
|
||||
// Note the base level may be shared with another instance
|
||||
bool _baseLevelOwned;
|
||||
|
||||
std::vector<Vtr::internal::Level *> _levels;
|
||||
std::vector<Vtr::internal::Refinement *> _refinements;
|
||||
|
||||
|
@ -112,6 +112,21 @@ public:
|
||||
///
|
||||
static TopologyRefiner* Create(MESH const& mesh, Options options = Options());
|
||||
|
||||
/// \brief Instantiates a TopologyRefiner from the base level of an
|
||||
/// existing instance.
|
||||
///
|
||||
/// This allows lightweight copies of the same topology to be refined
|
||||
/// differently for each new instance. As with other classes that refer
|
||||
/// to an existing TopologyRefiner, it must generally exist for the entire
|
||||
/// lifetime of the new instance. In this case, the base level of the
|
||||
/// original instance must be preserved.
|
||||
///
|
||||
/// @param baseLevel An existing TopologyRefiner to share base level.
|
||||
///
|
||||
/// @return A new instance of TopologyRefiner or 0 for failure
|
||||
///
|
||||
static TopologyRefiner* Create(TopologyRefiner const & sourceOfBaseLevel);
|
||||
|
||||
protected:
|
||||
typedef Vtr::internal::Level::TopologyError TopologyError;
|
||||
|
||||
@ -331,6 +346,13 @@ TopologyRefinerFactory<MESH>::Create(MESH const& mesh, Options options) {
|
||||
return refiner;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
TopologyRefiner*
|
||||
TopologyRefinerFactory<MESH>::Create(TopologyRefiner const & source) {
|
||||
|
||||
return new TopologyRefiner(source);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options) {
|
||||
|
Loading…
Reference in New Issue
Block a user