44#ifndef _INCLUDED_Field3D_MIPUtil_H_
45#define _INCLUDED_Field3D_MIPUtil_H_
51#include <boost/thread/thread.hpp>
52#include <boost/thread/mutex.hpp>
75template <
typename MIPField_T,
typename Filter_T>
76typename MIPField_T::Ptr
77makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
78 const V3i &offset,
const size_t numThreads);
81template <
typename MIPField_T,
typename Filter_T>
82typename MIPField_T::Ptr
83makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
84 const size_t numThreads);
120 template <
typename Data_T>
127 template <
typename Data_T>
135 template <
typename Data_T>
138 const Box3i &tgtBox,
const float support,
141 const int intSupport =
static_cast<int>(std::ceil(support * 0.5));
142 const int pad = std::max(0, intSupport);
143 Box3i tgtBoxPad = tgtBox;
144 tgtBoxPad.min[dim] -= pad;
145 tgtBoxPad.max[dim] += pad;
146 Box3i srcBoxPad = tgtBoxPad;
147 srcBoxPad.min[dim] *= 2;
148 srcBoxPad.max[dim] *= 2;
154 static boost::mutex mutex;
155 boost::mutex::scoped_lock lock(mutex);
158 for (
int k = dbsBounds.min.z; k <= dbsBounds.max.z; ++k) {
159 for (
int j = dbsBounds.min.y; j <= dbsBounds.max.y; ++j) {
160 for (
int i = dbsBounds.min.x; i <= dbsBounds.max.x; ++i) {
176 template <
typename Field_T>
178 const Box3i &,
const float ,
186 template <
typename Field_T,
typename FilterOp_T,
bool IsAnalytic_T>
189 typedef typename Field_T::value_type
T;
192 const size_t level,
const V3i &add,
193 const FilterOp_T &filterOp,
195 const std::vector<Box3i> &blocks,
196 size_t &nextIdx, boost::mutex &mutex)
216 typedef typename Field_T::value_type Data_T;
223 const float tgtToSrcMult = 2.0;
224 const float filterCoordMult = 1.0f / (tgtToSrcMult);
232 boost::mutex::scoped_lock lock(
m_mutex);
243 for (
int k = box.min.z; k <= box.max.z; ++k) {
244 for (
int j = box.min.y; j <= box.max.y; ++j) {
245 for (
int i = box.min.x; i <= box.max.x; ++i) {
246 Value_T accumValue(
m_filterOp.initialValue());
249 const int curTgt =
V3i(i, j, k)[
m_dim];
253 static_cast<int>(std::floor(curSrc - support * tgtToSrcMult));
255 static_cast<int>(std::ceil(curSrc + support *
258 startSrc = std::max(startSrc, srcDw.min[
m_dim]);
259 endSrc = std::min(endSrc, srcDw.max[
m_dim]);
261 for (
int s = startSrc; s <= endSrc; ++s) {
263 const int xIdx =
m_dim == 0 ? s : i;
264 const int yIdx =
m_dim == 1 ? s : j;
265 const int zIdx =
m_dim == 2 ? s : k;
269 const float weight =
m_filterOp.eval(std::abs(srcP - curSrc) *
272 const Value_T value =
m_src.fastValue(xIdx, yIdx, zIdx);
275 FilterOp_T::op(accumValue, value);
280 static_cast<Value_T
>(
m_filterOp.initialValue())) {
281 m_tgt.fastLValue(i, j, k) = accumValue;
284 float accumWeight = 0.0f;
286 const int curTgt =
V3i(i, j, k)[
m_dim];
290 static_cast<int>(std::floor(curSrc - support * tgtToSrcMult));
292 static_cast<int>(std::ceil(curSrc + support *
295 startSrc = std::max(startSrc, srcDw.min[
m_dim]);
296 endSrc = std::min(endSrc, srcDw.max[
m_dim]);
298 for (
int s = startSrc; s <= endSrc; ++s) {
300 const int xIdx =
m_dim == 0 ? s : i;
301 const int yIdx =
m_dim == 1 ? s : j;
302 const int zIdx =
m_dim == 2 ? s : k;
306 const float weight =
m_filterOp.eval(std::abs(srcP - curSrc) *
309 const Value_T value =
m_src.fastValue(xIdx, yIdx, zIdx);
311 accumWeight += weight;
312 accumValue += value * weight;
315 if (accumWeight > 0.0f &&
316 accumValue !=
static_cast<Value_T
>(0.0)) {
317 m_tgt.fastLValue(i, j, k) = accumValue / accumWeight;
326 boost::mutex::scoped_lock lock(
m_mutex);
353 template <
typename Field_T,
typename FilterOp_T>
355 const V3i &oldRes,
const V3i &newRes,
const size_t level,
356 const V3i &add,
const FilterOp_T &filterOp,
357 const size_t dim,
const size_t numThreads)
362 Box3i srcDw = src.dataWindow();
368 }
else if (dim == 1) {
369 res =
V3i(newRes.x, newRes.y, oldRes.z);
371 res =
V3i(newRes.x, oldRes.y, oldRes.z);
381 std::vector<Box3i> blocks;
382 for (
int k = 0; k < res.z; k += blockSize) {
383 for (
int j = 0; j < res.y; j += blockSize) {
384 for (
int i = 0; i < res.x; i += blockSize) {
387 box.min =
V3i(i, j, k);
388 box.max = box.min +
V3i(blockSize - 1);
390 box.max.x = std::min(box.max.x, res.x - 1);
391 box.max.y = std::min(box.max.y, res.y - 1);
392 box.max.z = std::min(box.max.z, res.z - 1);
394 blocks.push_back(box);
405 boost::thread_group threads;
407 for (
size_t i = 0; i < numThreads; ++i) {
408 threads.create_thread(
410 (src, tgt, level, add, filterOp,
411 dim, blocks, nextIdx, mutex));
420 template <
typename Field_T,
typename FilterOp_T>
421 void mipResample(
const Field_T &base,
const Field_T &src, Field_T &tgt,
422 const size_t level,
const V3i &offset,
423 const FilterOp_T &filterOp,
424 const size_t numThreads)
429 const V3i add((offset.x % 2 == 0) ? 0 : 1,
430 (offset.y % 2 == 0) ? 0 : 1,
431 (offset.z % 2 == 0) ? 0 : 1);
434 const Box3i baseDw = base.dataWindow();
435 const V3i baseRes = baseDw.size() +
V3i(1);
439 const Box3i srcDw = src.dataWindow();
440 const V3i srcRes = srcDw.size() +
V3i(1);
446 mipSeparable(src, tgt, srcRes, newRes, level, add, filterOp, 0, numThreads);
448 mipSeparable(tgt, tmp, srcRes, newRes, level, add, filterOp, 1, numThreads);
450 mipSeparable(tmp, tgt, srcRes, newRes, level, add, filterOp, 2, numThreads);
453 tgt.name = base.name;
454 tgt.attribute = base.attribute;
455 tgt.setMapping(base.mapping());
456 tgt.copyMetadata(base);
464 const Box3i &extents,
475template <
typename MIPField_T,
typename Filter_T>
476typename MIPField_T::Ptr
477makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
478 const size_t numThreads)
488template <
typename MIPField_T,
typename Filter_T>
489typename MIPField_T::Ptr
490makeMIP(
const typename MIPField_T::NestedType &base,
const int minSize,
491 const V3i &baseOffset,
const size_t numThreads)
493 using namespace Field3D::detail;
495 typedef typename MIPField_T::value_type Data_T;
496 typedef typename MIPField_T::NestedType Src_T;
497 typedef typename Src_T::Ptr SrcPtr;
498 typedef typename MIPField_T::Ptr MIPPtr;
499 typedef std::vector<typename Src_T::Ptr> SrcVec;
501 if (base.extents() != base.dataWindow()) {
510 V3i res = base.extents().size() +
V3i(1);
511 V3i offset = baseOffset;
515 while ((res.x > minSize || res.y > minSize || res.z > minSize) &&
516 (res.x > 2 && res.y > 2 && res.z > 2)) {
518 SrcPtr nextField(
new Src_T);
519 mipResample(base, *result.back(), *nextField, level, offset,
520 Filter_T(), numThreads);
522 result.push_back(nextField);
524 res = nextField->dataWindow().size() +
V3i(1);
526 for (
int i = 0; i < 3; ++i) {
528 offset[i] = (offset[i] - 1) / 2;
536 MIPPtr mipField(
new MIPField_T);
537 mipField->name = base.name;
538 mipField->attribute = base.attribute;
539 mipField->copyMetadata(base);
540 mipField->setMIPOffset(baseOffset);
541 mipField->setup(result);
Box3i clipBounds(const Box3i &bbox, const Box3i &bounds)
double discToCont(int discCoord)
Goes from discrete coordinates to continuous coordinates See Graphics Gems - What is a pixel.
MIPField_T::Ptr makeMIP(const typename MIPField_T::NestedType &base, const int minSize, const V3i &offset, const size_t numThreads)
Constructs a MIP representation of the given field, with optional offset vector. The offset vector in...
FIELD3D_NAMESPACE_OPEN V3i computeOffset(const FieldRes &f)
Computes the origin/offset of a field.
Contains functions for resampling fields.
Contains the SparseField class.
Box3i blockCoords(const Box3i &dvsBounds, const SparseField< Data_T > *f)
FIELD3D_NAMESPACE_OPENtypedef ::half half
Contains typedefs for the commonly used types in Field3D.
This subclass of Field stores data in a contiguous std::vector.
boost::intrusive_ptr< FieldMapping > Ptr
const Box3i & dataWindow() const
Returns the data window. Any coordinate inside this window is safe to pass to value() in the Field su...
This Field subclass stores voxel data in block-allocated arrays.
const Data_T getBlockEmptyValue(int bi, int bj, int bk) const
Returns the constant value of an block, whether it's allocated already or not..
bool blockIsAllocated(int bi, int bj, int bk) const
Checks if a block is allocated.
int blockSize() const
Returns the block size.
Field_T::Ptr field_dynamic_cast(RefBase::Ptr field)
Dynamic cast that uses string-comparison in order to be safe even after an object crosses a shared li...
const std::string k_mipOffsetStr
void mipSeparable(const Field_T &src, Field_T &tgt, const V3i &oldRes, const V3i &newRes, const size_t level, const V3i &add, const FilterOp_T &filterOp, const size_t dim, const size_t numThreads)
Threaded implementation of separable MIP filtering.
size_t threadingBlockSize(const DenseField< Data_T > &)
Constant size for all dense fields.
FIELD3D_API V3i mipResolution(const V3i &baseRes, const size_t level, const V3i &add)
void mipResample(const Field_T &base, const Field_T &src, Field_T &tgt, const size_t level, const V3i &offset, const FilterOp_T &filterOp, const size_t numThreads)
FIELD3D_API FieldMapping::Ptr adjustedMIPFieldMapping(const FieldRes *base, const V3i &baseRes, const Box3i &extents, const size_t level)
bool checkInputEmpty(const SparseField< Data_T > &src, const SparseField< Data_T > &, const Box3i &tgtBox, const float support, const size_t dim)
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Used to delegate the choice of bit depth to process at.
MIPSeparableThreadOp(const Field_T &src, Field_T &tgt, const size_t level, const V3i &add, const FilterOp_T &filterOp, const size_t dim, const std::vector< Box3i > &blocks, size_t &nextIdx, boost::mutex &mutex)
const std::vector< Box3i > & m_blocks
const FilterOp_T & m_filterOp