9#ifndef OPENVDB_POINTS_POINT_SAMPLE_IMPL_HAS_BEEN_INCLUDED
10#define OPENVDB_POINTS_POINT_SAMPLE_IMPL_HAS_BEEN_INCLUDED
19namespace point_sample_internal {
22template<
typename FromType,
typename ToType>
23struct CompatibleTypes {
enum { value = std::is_constructible<ToType, FromType>::value }; };
26template<
typename T>
struct CompatibleTypes<
27 T, T> {
enum { value =
true }; };
28template<
typename T>
struct CompatibleTypes<
29 T, math::Vec2<T>> {
enum { value =
true }; };
30template<
typename T>
struct CompatibleTypes<
31 T, math::Vec3<T>> {
enum { value =
true }; };
32template<
typename T>
struct CompatibleTypes<
33 T, math::Vec4<T>> {
enum { value =
true }; };
34template<
typename T>
struct CompatibleTypes<
35 math::Vec2<T>, math::Vec2<T>> {
enum { value =
true }; };
36template<
typename T>
struct CompatibleTypes<
37 math::Vec3<T>, math::Vec3<T>> {
enum { value =
true }; };
38template<
typename T>
struct CompatibleTypes<
39 math::Vec4<T>, math::Vec4<T>> {
enum { value =
true }; };
40template<
typename T0,
typename T1>
struct CompatibleTypes<
41 math::Vec2<T0>, math::Vec2<T1>> {
enum { value = CompatibleTypes<T0, T1>::value }; };
42template<
typename T0,
typename T1>
struct CompatibleTypes<
43 math::Vec3<T0>, math::Vec3<T1>> {
enum { value = CompatibleTypes<T0, T1>::value }; };
44template<
typename T0,
typename T1>
struct CompatibleTypes<
45 math::Vec4<T0>, math::Vec4<T1>> {
enum { value = CompatibleTypes<T0, T1>::value }; };
46template<
typename T>
struct CompatibleTypes<
47 ValueMask, T> {
enum { value = CompatibleTypes<bool, T>::value }; };
51template <
typename T>
struct SamplerTraits {
52 static const size_t Order = 0;
55template <
size_t T0,
bool T1>
struct SamplerTraits<tools::Sampler<T0, T1>> {
56 static const size_t Order = T0;
62template <
typename ValueT,
typename SamplerT,
typename AccessorT,
bool Round,
bool Compatible = false>
63struct SampleWithRoundingOp
65 static inline void sample(ValueT&,
const AccessorT&,
const Vec3d&)
67 std::ostringstream ostr;
68 ostr <<
"Cannot sample a " << typeNameAsString<typename AccessorT::ValueType>()
69 <<
" grid on to a " << typeNameAsString<ValueT>() <<
" attribute";
74template <
typename ValueT,
typename SamplerT,
typename AccessorT>
75struct SampleWithRoundingOp<ValueT, SamplerT, AccessorT, true, true>
77 static inline void sample(ValueT& value,
const AccessorT& accessor,
const Vec3d& position)
79 value = ValueT(math::Round(SamplerT::sample(accessor, position)));
83template <
typename ValueT,
typename SamplerT,
typename AccessorT>
84struct SampleWithRoundingOp<ValueT, SamplerT, AccessorT, false, true>
86 static inline void sample(ValueT& value,
const AccessorT& accessor,
const Vec3d& position)
88 value = ValueT(SamplerT::sample(accessor, position));
93template <
typename Po
intDataGr
idT,
typename SamplerT,
typename FilterT,
typename InterrupterT>
97 PointDataSampler(
size_t order,
98 PointDataGridT& points,
99 const SamplerT& sampler,
100 const FilterT& filter,
101 InterrupterT*
const interrupter,
107 , mInterrupter(interrupter)
108 , mThreaded(threaded) { }
112 struct AlignedTransform
114 inline Vec3d transform(
const Vec3d& position)
const {
return position; }
118 struct NonAlignedTransform
120 NonAlignedTransform(
const math::Transform& source,
const math::Transform& target)
122 , mTarget(target) { }
124 inline Vec3d transform(
const Vec3d& position)
const
126 return mSource.worldToIndex(mTarget.indexToWorld(position));
130 const math::Transform& mSource;
131 const math::Transform& mTarget;
135 template <
typename ValueT,
typename SourceGr
idT,
typename Gr
idSamplerT>
136 struct SamplerWrapper
138 using ValueType = ValueT;
139 using SourceValueType =
typename SourceGridT::ValueType;
140 using SourceAccessorT =
typename SourceGridT::ConstAccessor;
143 static const bool SourceIsBool = std::is_same<SourceValueType, bool>::value ||
144 std::is_same<SourceValueType, ValueMask>::value;
145 static const bool OrderIsZero = SamplerTraits<GridSamplerT>::Order == 0;
146 static const bool IsValid = !SourceIsBool || OrderIsZero;
148 SamplerWrapper(
const SourceGridT& sourceGrid,
const SamplerT& sampler)
149 : mAccessor(sourceGrid.getConstAccessor())
150 , mSampler(sampler) { }
154 SamplerWrapper(
const SamplerWrapper& other)
155 : mAccessor(other.mAccessor.tree())
156 , mSampler(other.mSampler) { }
158 template <
bool IsVal
idT = IsVal
id>
159 inline typename std::enable_if<IsValidT, ValueT>::type
160 sample(
const Vec3d& position)
const {
161 return mSampler.template sample<ValueT, GridSamplerT, SourceAccessorT>(
162 mAccessor, position);
165 template <
bool IsVal
idT = IsVal
id>
166 inline typename std::enable_if<!IsValidT, ValueT>::type
167 sample(
const Vec3d& )
const {
168 OPENVDB_THROW(RuntimeError,
"Cannot sample bool grid with BoxSampler or QuadraticSampler.");
172 SourceAccessorT mAccessor;
173 const SamplerT& mSampler;
176 template <
typename SamplerWrapperT,
typename TransformerT>
177 inline void doSample(
const SamplerWrapperT& sampleWrapper,
const Index targetIndex,
178 const TransformerT& transformer)
180 using PointDataTreeT =
typename PointDataGridT::TreeType;
181 using LeafT =
typename PointDataTreeT::LeafNodeType;
182 using LeafManagerT =
typename tree::LeafManager<PointDataTreeT>;
184 const auto& filter(mFilter);
185 const auto& interrupter(mInterrupter);
187 auto sampleLambda = [targetIndex, &sampleWrapper, &transformer, &filter, &interrupter](
188 LeafT& leaf,
size_t )
190 using TargetHandleT = AttributeWriteHandle<typename SamplerWrapperT::ValueType>;
192 if (util::wasInterrupted(interrupter)) {
193 thread::cancelGroupExecution();
197 SamplerWrapperT newSampleWrapper(sampleWrapper);
198 auto positionHandle = AttributeHandle<Vec3f>::create(leaf.constAttributeArray(
"P"));
199 auto targetHandle = TargetHandleT::create(leaf.attributeArray(targetIndex));
200 for (
auto iter = leaf.beginIndexOn(filter); iter; ++iter) {
201 const Vec3d position = transformer.transform(
202 positionHandle->get(*iter) + iter.getCoord().asVec3d());
203 targetHandle->set(*iter, newSampleWrapper.sample(position));
207 LeafManagerT leafManager(mPoints.tree());
209 if (mInterrupter) mInterrupter->start();
211 leafManager.foreach(sampleLambda, mThreaded);
213 if (mInterrupter) mInterrupter->end();
216 template <
typename SourceGr
idT,
typename SamplerWrapperT>
217 inline void resolveTransform(
const SourceGridT& sourceGrid,
const SamplerWrapperT& sampleWrapper,
218 const Index targetIndex)
220 const auto& sourceTransform = sourceGrid.constTransform();
221 const auto& pointsTransform = mPoints.constTransform();
223 if (sourceTransform == pointsTransform) {
224 AlignedTransform transformer;
225 doSample(sampleWrapper, targetIndex, transformer);
227 NonAlignedTransform transformer(sourceTransform, pointsTransform);
228 doSample(sampleWrapper, targetIndex, transformer);
232 template <
typename SourceGr
idT,
typename TargetValueT,
size_t Order>
233 inline void resolveStaggered(
const SourceGridT& sourceGrid,
const Index targetIndex)
235 using SamplerWrapperT = SamplerWrapper<TargetValueT, SourceGridT, tools::Sampler<Order, false>>;
236 using StaggeredSamplerWrapperT = SamplerWrapper<TargetValueT, SourceGridT, tools::Sampler<Order, true>>;
238 using SourceValueType =
typename SourceGridT::ValueType;
239 if (VecTraits<SourceValueType>::Size == 3 && sourceGrid.getGridClass() == GRID_STAGGERED) {
240 StaggeredSamplerWrapperT sampleWrapper(sourceGrid, mSampler);
241 resolveTransform(sourceGrid, sampleWrapper, targetIndex);
243 SamplerWrapperT sampleWrapper(sourceGrid, mSampler);
244 resolveTransform(sourceGrid, sampleWrapper, targetIndex);
249 template <
typename SourceGr
idT,
typename TargetValueT =
typename SourceGr
idT::ValueType>
250 inline void sample(
const SourceGridT& sourceGrid, Index targetIndex)
252 using SourceValueType =
typename SourceGridT::ValueType;
253 static const bool SourceIsMask = std::is_same<SourceValueType, bool>::value ||
254 std::is_same<SourceValueType, ValueMask>::value;
256 if (SourceIsMask || mOrder == 0) {
257 resolveStaggered<SourceGridT, TargetValueT, 0>(sourceGrid, targetIndex);
258 }
else if (mOrder == 1) {
259 resolveStaggered<SourceGridT, TargetValueT, 1>(sourceGrid, targetIndex);
260 }
else if (mOrder == 2) {
261 resolveStaggered<SourceGridT, TargetValueT, 2>(sourceGrid, targetIndex);
267 PointDataGridT& mPoints;
268 const SamplerT& mSampler;
269 const FilterT& mFilter;
270 InterrupterT*
const mInterrupter;
271 const bool mThreaded;
275template <
typename Po
intDataGr
idT,
typename ValueT>
276struct AppendAttributeOp
278 static void append(PointDataGridT& points,
const Name& attribute)
280 appendAttribute<ValueT>(points.tree(), attribute);
284template <
typename Po
intDataGr
idT>
285struct AppendAttributeOp<PointDataGridT, DummySampleType>
287 static void append(PointDataGridT&,
const Name&) { }
297template<
typename ValueT,
typename SamplerT,
typename AccessorT>
298ValueT SampleWithRounding::sample(
const AccessorT& accessor,
const Vec3d& position)
const
300 using namespace point_sample_internal;
301 using SourceValueT =
typename AccessorT::ValueType;
302 static const bool staggered = SamplerTraits<SamplerT>::Staggered;
303 static const bool compatible = CompatibleTypes<SourceValueT, ValueT>::value &&
305 static const bool round = std::is_floating_point<SourceValueT>::value &&
306 std::is_integral<ValueT>::value;
308 SampleWithRoundingOp<ValueT, SamplerT, AccessorT, round, compatible>::sample(
309 value, accessor, position);
317template<
typename PointDataGridT,
typename SourceGridT,
typename TargetValueT,
318 typename SamplerT,
typename FilterT,
typename InterrupterT>
320 PointDataGridT& points,
321 const SourceGridT& sourceGrid,
322 const Name& targetAttribute,
323 const FilterT& filter,
324 const SamplerT& sampler,
325 InterrupterT*
const interrupter,
328 using point_sample_internal::AppendAttributeOp;
329 using point_sample_internal::PointDataSampler;
332 Name attribute(targetAttribute);
333 if (targetAttribute.empty()) {
334 attribute = sourceGrid.getName();
338 if (attribute ==
"P") {
342 auto leaf = points.tree().cbeginLeaf();
345 PointDataSampler<PointDataGridT, SamplerT, FilterT, InterrupterT> pointDataSampler(
346 order, points, sampler, filter, interrupter, threaded);
348 const auto& descriptor = leaf->attributeSet().descriptor();
349 size_t targetIndex = descriptor.find(attribute);
350 const bool attributeExists = targetIndex != AttributeSet::INVALID_POS;
352 if (std::is_same<TargetValueT, DummySampleType>::value) {
353 if (!attributeExists) {
355 appendAttribute<typename SourceGridT::ValueType>(points.tree(), attribute);
356 targetIndex = leaf->attributeSet().descriptor().find(attribute);
357 assert(targetIndex != AttributeSet::INVALID_POS);
360 pointDataSampler.template sample<SourceGridT>(sourceGrid,
Index(targetIndex));
362 auto targetIdx =
static_cast<Index>(targetIndex);
364 const Name& targetType = descriptor.valueType(targetIndex);
365 if (targetType == typeNameAsString<Vec3f>()) {
366 pointDataSampler.template sample<SourceGridT, Vec3f>(sourceGrid, targetIdx);
367 }
else if (targetType == typeNameAsString<Vec3d>()) {
368 pointDataSampler.template sample<SourceGridT, Vec3d>(sourceGrid, targetIdx);
369 }
else if (targetType == typeNameAsString<Vec3i>()) {
370 pointDataSampler.template sample<SourceGridT, Vec3i>(sourceGrid, targetIdx);
371 }
else if (targetType == typeNameAsString<int8_t>()) {
372 pointDataSampler.template sample<SourceGridT, int8_t>(sourceGrid, targetIdx);
373 }
else if (targetType == typeNameAsString<int16_t>()) {
374 pointDataSampler.template sample<SourceGridT, int16_t>(sourceGrid, targetIdx);
375 }
else if (targetType == typeNameAsString<int32_t>()) {
376 pointDataSampler.template sample<SourceGridT, int32_t>(sourceGrid, targetIdx);
377 }
else if (targetType == typeNameAsString<int64_t>()) {
378 pointDataSampler.template sample<SourceGridT, int64_t>(sourceGrid, targetIdx);
379 }
else if (targetType == typeNameAsString<float>()) {
380 pointDataSampler.template sample<SourceGridT, float>(sourceGrid, targetIdx);
381 }
else if (targetType == typeNameAsString<double>()) {
382 pointDataSampler.template sample<SourceGridT, double>(sourceGrid, targetIdx);
383 }
else if (targetType == typeNameAsString<bool>()) {
384 pointDataSampler.template sample<SourceGridT, bool>(sourceGrid, targetIdx);
386 std::ostringstream ostr;
387 ostr <<
"Cannot sample attribute of type - " << targetType;
392 if (!attributeExists) {
395 AppendAttributeOp<PointDataGridT, TargetValueT>::append(points, attribute);
396 targetIndex = leaf->attributeSet().descriptor().find(attribute);
397 assert(targetIndex != AttributeSet::INVALID_POS);
400 const Name targetType = typeNameAsString<TargetValueT>();
401 const Name attributeType = descriptor.valueType(targetIndex);
402 if (targetType != attributeType) {
403 std::ostringstream ostr;
404 ostr <<
"Requested attribute type " << targetType <<
" for sampling "
405 <<
" does not match existing attribute type " << attributeType;
411 pointDataSampler.template sample<SourceGridT, TargetValueT>(
412 sourceGrid,
static_cast<Index>(targetIndex));
416template<
typename Po
intDataGr
idT,
typename SourceGr
idT,
typename FilterT,
typename InterrupterT>
418 const SourceGridT& sourceGrid,
419 const Name& targetAttribute,
420 const FilterT& filter,
421 InterrupterT*
const interrupter)
424 sampleGrid(0, points, sourceGrid, targetAttribute, filter, sampler, interrupter);
427template<
typename Po
intDataGr
idT,
typename SourceGr
idT,
typename FilterT,
typename InterrupterT>
429 const SourceGridT& sourceGrid,
430 const Name& targetAttribute,
431 const FilterT& filter,
432 InterrupterT*
const interrupter)
435 sampleGrid(1, points, sourceGrid, targetAttribute, filter, sampler, interrupter);
438template<
typename Po
intDataGr
idT,
typename SourceGr
idT,
typename FilterT,
typename InterrupterT>
440 const SourceGridT& sourceGrid,
441 const Name& targetAttribute,
442 const FilterT& filter,
443 InterrupterT*
const interrupter)
446 sampleGrid(2, points, sourceGrid, targetAttribute, filter, sampler, interrupter);
Definition Exceptions.h:63
Definition Exceptions.h:64
Vec3< double > Vec3d
Definition Vec3.h:664
void sampleGrid(size_t order, PointDataGridT &points, const SourceGridT &sourceGrid, const Name &targetAttribute, const FilterT &filter=NullFilter(), const SamplerT &sampler=SampleWithRounding(), InterrupterT *const interrupter=nullptr, const bool threaded=true)
Performs sampling and conversion from a VDB grid onto a VDB Points attribute.
Definition PointSampleImpl.h:319
void boxSample(PointDataGridT &points, const SourceGridT &sourceGrid, const Name &targetAttribute="", const FilterT &filter=NullFilter(), InterrupterT *const interrupter=nullptr)
Performs tri-linear sampling from a VDB grid onto a VDB Points attribute.
Definition PointSampleImpl.h:428
void quadraticSample(PointDataGridT &points, const SourceGridT &sourceGrid, const Name &targetAttribute="", const FilterT &filter=NullFilter(), InterrupterT *const interrupter=nullptr)
Performs tri-quadratic sampling from a VDB grid onto a VDB Points attribute.
Definition PointSampleImpl.h:439
void pointSample(PointDataGridT &points, const SourceGridT &sourceGrid, const Name &targetAttribute="", const FilterT &filter=NullFilter(), InterrupterT *const interrupter=nullptr)
Performs closest point sampling from a VDB grid onto a VDB Points attribute.
Definition PointSampleImpl.h:417
std::string Name
Definition Name.h:19
Index32 Index
Definition Types.h:54
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
Definition PointSample.h:85
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212