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:
barry 2018-09-11 16:13:06 -07:00
parent c566e8f2ab
commit f58330fdee
7 changed files with 359 additions and 89 deletions

View File

@ -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);
}
}
}
}
//

View File

@ -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());
if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex) &&
_patchBuilder->IsFaceALeaf(levelIndex, faceIndex)) {
// 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();
_patches.push_back(PatchTuple(faceIndex, levelIndex));
for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
// 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);
}
if (_patchBuilder->IsFaceAPatch(levelIndex, faceIndex) &&
_patchBuilder->IsFaceALeaf(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();

View File

@ -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
@ -140,17 +144,21 @@ public:
/// the base level in addition to the last level while indices for face-varying
/// patches include only the last level.
///
/// @param refiner TopologyRefiner from which to generate patches
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param options Options controlling the creation of the table
/// @param options Options controlling the creation of the table
///
/// @return A new instance of PatchTable
/// @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;

View File

@ -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,24 +451,35 @@ 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
/// @param uderivs Destination buffer for the interpolated 'u'
/// derivative primvar data
///
/// @param vderivs Destination buffer for the interpolated 'v'
/// derivative primvar data
/// @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,28 +487,41 @@ 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
/// @param uuderivs Destination buffer for the interpolated 'uu'
/// derivative primvar data
///
/// @param uvderivs Destination buffer for the interpolated 'uv'
/// derivative primvar data
/// @param uvderivs Destination buffer for the interpolated 'uv'
/// derivative primvar data
///
/// @param vvderivs Destination buffer for the interpolated 'vv'
/// derivative primvar data
/// @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,17 +599,34 @@ StencilTableReal<REAL>::update(T const *controlValues, T *values,
}
int nstencils = end - std::max(0, start);
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
for (int j=0; j<*sizes; ++j, ++indices, ++weights) {
values[i].AddWithWeight( controlValues[*indices], *weights );
// Use separate loops for single and split buffers
if (srcNonBaseValues == 0) {
for (int i=0; i<nstencils; ++i, ++sizes) {
dstValues[i].Clear();
for (int j=0; j<*sizes; ++j, ++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>
inline void

View File

@ -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 {
selector.selectFace(face);
// 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;
}
}
}
}

View File

@ -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
/// @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;

View File

@ -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) {