Field3D
FieldSampler.h
Go to the documentation of this file.
1//----------------------------------------------------------------------------//
2
3#ifndef __F3DUTIL_FIELDSAMPLER_H__
4#define __F3DUTIL_FIELDSAMPLER_H__
5
6//------------------------------------------------------------------------------
7
8// Project includes
9#include "Types.h"
10
11//----------------------------------------------------------------------------//
12
13#include "ns.h"
14
16
17//------------------------------------------------------------------------------
18// detail namespace
19//------------------------------------------------------------------------------
20
21namespace detail {
22
24 template <typename T, typename T2>
25 T min(const T a, const T2 b)
26 {
27 return std::min(a, static_cast<T>(b));
28 }
29
31 template <typename T, typename T2>
32 T max(const T a, const T2 b)
33 {
34 return std::max(a, static_cast<T>(b));
35 }
36
38 template <typename T, typename T2>
40 const FIELD3D_VEC3_T<T2> &b)
41 {
42 return FIELD3D_VEC3_T<T>(std::min(a.x, static_cast<T>(b.x)),
43 std::min(a.y, static_cast<T>(b.y)),
44 std::min(a.z, static_cast<T>(b.z)));
45 }
46
48 template <typename T, typename T2>
50 const FIELD3D_VEC3_T<T2> &b)
51 {
52 return FIELD3D_VEC3_T<T>(std::max(a.x, static_cast<T>(b.x)),
53 std::max(a.y, static_cast<T>(b.y)),
54 std::max(a.z, static_cast<T>(b.z)));
55 }
56
58 template <int Dims_T>
60
61 template <>
63 {
64 typedef float type;
65 };
66
67 template <>
69 {
70 typedef V3f type;
71 };
72
73}
74
75//------------------------------------------------------------------------------
76// FieldSampler
77//------------------------------------------------------------------------------
78
80template <typename WrapperVec_T, int Dims_T>
82{
83 enum Mode {
85 Max
86 };
87
88 typedef typename WrapperVec_T::value_type::field_type Field_T;
89 typedef typename Field_T::value_type Data_T;
91
92 // Ordinary fields
93 static void sample(const WrapperVec_T &f, const V3d &wsP, float *value,
94 size_t &numHits)
95 {
96 // Reinterpret the pointer according to Dims_T
97 Input_T *data = reinterpret_cast<Input_T*>(value);
98 // Loop over fields in vector
99 for (size_t i = 0, end = f.size(); i < end; ++i) {
100 V3d vsP;
101 // Apply world to object transform
102 if (f[i].doOsToWs) {
103 V3d osP;
104 f[i].wsToOs.multVecMatrix(wsP, osP);
105 f[i].mapping->worldToVoxel(osP, vsP);
106 } else {
107 f[i].mapping->worldToVoxel(wsP, vsP);
108 }
109 // Sample
110 if (f[i].vsBounds.intersects(vsP)) {
111 // Count as within field
112 numHits++;
113 // Sample and remap
114 if (f[i].valueRemapOp) {
115 const Data_T unremapped = f[i].interp.sample(*f[i].field, vsP);
116 *data += f[i].valueRemapOp->remap(unremapped);
117 } else {
118 *data += f[i].interp.sample(*f[i].field, vsP);
119 }
120 }
121 }
122 }
123
124 // Ordinary fields
125 static void sampleMultiple(const WrapperVec_T &f, const size_t neval,
126 const float *wsPs, float *value, size_t *numHits)
127 {
128 // Loop over fields in vector
129 for (size_t i = 0; i < f.size(); ++i) {
130 const typename WrapperVec_T::value_type &field = f[i];
131
132 // Reinterpret the pointer according to Dims_T
133 Input_T *data = reinterpret_cast<Input_T*>(value);
134
135 if (field.doOsToWs || field.valueRemapOp) {
136
137 // Loop over samples
138 for (size_t ieval = 0; ieval < neval; ++ieval) {
139 const V3d wsP(*reinterpret_cast<const V3f*>(wsPs + 3 * ieval));
140 V3d vsP;
141 // Apply world to object transform
142 if (field.doOsToWs) {
143 V3d osP;
144 field.wsToOs.multVecMatrix(wsP, osP);
145 field.mapping->worldToVoxel(osP, vsP);
146 } else {
147 field.mapping->worldToVoxel(wsP, vsP);
148 }
149 // Sample
150 if (field.vsBounds.intersects(vsP)) {
151 // Count as within field
152 numHits[ieval]++;
153 // Sample and remap
154 if (field.valueRemapOp) {
155 const Data_T unremapped = field.interp.sample(*field.field, vsP);
156 data[ieval] += field.valueRemapOp->remap(unremapped);
157 } else {
158 data[ieval] += field.interp.sample(*field.field, vsP);
159 }
160 }
161 }
162
163 } else {
164
165 const Imath::Box3d &vsBounds_d = field.vsBounds;
166
167 // Loop over samples
168 for (size_t ieval = 0; ieval < neval; ++ieval) {
169 const V3d wsP(*reinterpret_cast<const V3f*>(wsPs + 3 * ieval));
170 V3d vsP;
171
172 // Apply world to object transform
173 field.mapping->worldToVoxel(wsP, vsP);
174
175 // Sample
176 if (vsBounds_d.intersects(vsP)) {
177 // Count as within field
178 numHits[ieval]++;
179 // Sample
180 data[ieval] += field.interp.sample(*field.field, vsP);
181 }
182 }
183 }
184 }
185 }
186
187 // MIP fields
188 static void sampleMIP(const WrapperVec_T &f, const V3d &wsP,
189 const float wsSpotSize, float *value, size_t &numHits)
190 {
191 // Reinterpret the pointer according to Dims_T
192 Input_T *data = reinterpret_cast<Input_T*>(value);
193 // Loop over fields in vector
194 for (size_t i = 0, end = f.size(); i < end; ++i) {
195 V3d vsP;
196 float spotSize = wsSpotSize / f[i].worldScale;
197 // Apply world to object transform
198 if (f[i].doOsToWs) {
199 V3d osP;
200 f[i].wsToOs.multVecMatrix(wsP, osP);
201 f[i].mapping->worldToVoxel(osP, vsP);
202 spotSize = wsSpotSize / f[i].worldScale;
203 } else {
204 f[i].mapping->worldToVoxel(wsP, vsP);
205 }
206 // Sample
207 if (f[i].vsBounds.intersects(vsP)) {
208 // Count as within field
209 numHits++;
210 // Sample and remap
211 if (f[i].valueRemapOp) {
212 const Data_T unremapped = f[i].interp->sample(vsP, spotSize);
213 *data += f[i].valueRemapOp->remap(unremapped);
214 } else {
215 *data += f[i].interp->sample(vsP, spotSize);
216 }
217 }
218 }
219 }
220
221 // MIP fields
222 static void sampleMIPMultiple(const WrapperVec_T &f, const size_t neval,
223 const float *wsPs, const float *wsSpotSizes,
224 float *value, size_t *numHits)
225 {
226 // Loop over fields in vector
227 for (size_t i = 0; i < f.size(); ++i) {
228 const typename WrapperVec_T::value_type &field = f[i];
229
230 // Reinterpret the pointer according to Dims_T
231 Input_T *data = reinterpret_cast<Input_T*>(value);
232
233 if (field.doOsToWs || field.valueRemapOp) {
234
235 if (field.valueRemapOp && field.doWsBoundsOptimization) {
236
237 // Loop over samples
238 for (size_t ieval = 0; ieval < neval; ++ieval) {
239 const V3f &wsP = *reinterpret_cast<const V3f*>(wsPs + 3 * ieval);
240
241 if (field.wsBounds.intersects(wsP)) {
242
243 // Apply world to object transform
244 V3d vsP;
245
246 field.wsToVs.multVecMatrix(V3d(wsP), vsP);
247
248 // Sample
249 if (field.vsBounds.intersects(vsP)) {
250 // Count as within field
251 numHits[ieval]++;
252 const float spotSize = wsSpotSizes[ieval] / field.worldScale;
253 const Data_T unremapped = field.interp->sample(vsP, spotSize);
254 data[ieval] += field.valueRemapOp->remap(unremapped);
255 }
256 }
257 }
258
259 } else {
260 // Loop over samples
261 for (size_t ieval = 0; ieval < neval; ++ieval) {
262 const V3d wsP(*reinterpret_cast<const V3f*>(wsPs + 3 * ieval));
263 const float wsSpotSize = wsSpotSizes[ieval];
264 Input_T *idata = data + ieval;
265
266 V3d vsP;
267 float spotSize = wsSpotSize / field.worldScale;
268 // Apply world to object transform
269 if (field.doOsToWs) {
270 V3d osP;
271
272 field.wsToOs.multVecMatrix(wsP, osP);
273 field.mapping->worldToVoxel(osP, vsP);
274 spotSize = wsSpotSize / field.worldScale;
275 } else {
276 field.mapping->worldToVoxel(wsP, vsP);
277 }
278 // Sample
279 if (field.vsBounds.intersects(vsP)) {
280 // Count as within field
281 numHits[ieval]++;
282 if (field.valueRemapOp) {
283 const Data_T unremapped = field.interp->sample(vsP, spotSize);
284 *idata += field.valueRemapOp->remap(unremapped);
285 } else {
286 *idata += field.interp->sample(vsP, spotSize);
287 }
288 }
289 }
290 }
291 } else {
292
293 const Imath::Box3d &vsBounds_d = field.vsBounds;
294 const double worldScale = field.worldScale;
295
296 // Loop over samples
297 for (size_t ieval = 0; ieval < neval; ++ieval) {
298 const V3d wsP(*reinterpret_cast<const V3f*>(wsPs + 3 * ieval));
299 V3d vsP;
300
301 // Apply world to object transform
302 field.mapping->worldToVoxel(wsP, vsP);
303
304 // Sample
305 if (vsBounds_d.intersects(vsP)) {
306 // Count as within field
307 numHits[ieval]++;
308 const double spotSize = wsSpotSizes[ieval] / worldScale;
309
310 data[ieval] += field.interp->sample(vsP, spotSize);
311 }
312 }
313 }
314 }
315 }
316
317 // Get min/max
318 static void getMinMax(const WrapperVec_T &f,
319 const Box3d &wsBounds, float *min, float *max)
320 {
321 // Reinterpret the pointer according to Dims_T
322 Input_T *minData = reinterpret_cast<Input_T*>(min);
323 Input_T *maxData = reinterpret_cast<Input_T*>(max);
324 // Loop over fields in vector
325 for (size_t field = 0, end = f.size(); field < end; ++field) {
326 // Data window
327 const Box3i dw = f[field].field->dataWindow();
328 // Transform corners to voxel space and compute bounds
329 Box3i dvsBounds;
330 if (wsBounds.isInfinite()) {
331 dvsBounds = dw;
332 } else {
333 Box3d vsBounds;
334 if (f[field].doOsToWs) {
335 Box3d osBounds;
336 transformBounds(f[field].wsToOs, wsBounds, osBounds);
337 worldToVoxel(f[field].mapping, osBounds, vsBounds);
338 } else {
339 worldToVoxel(f[field].mapping, wsBounds, vsBounds);
340 }
341 dvsBounds = clipBounds(discreteBounds(vsBounds), dw);
342 // Early termination if no intersection
343 if (!dw.intersects(dvsBounds)) {
344 return;
345 }
346 }
347 for (int k = dvsBounds.min.z; k <= dvsBounds.max.z; ++k) {
348 for (int j = dvsBounds.min.y; j <= dvsBounds.max.y; ++j) {
349 for (int i = dvsBounds.min.x; i <= dvsBounds.max.x; ++i) {
350 const Data_T val = f[field].field->fastValue(i, j, k);
351 *minData = detail::min(val, *minData);
352 *maxData = detail::max(val, *maxData);
353 }
354 }
355 }
356 }
357 }
358
359 // Get min/max from MIP (uses finest level)
360 static void getMinMaxMIP(const WrapperVec_T &f,
361 const Box3d &wsBounds, float *min, float *max)
362 {
363 // Reinterpret the pointer according to Dims_T
364 Input_T *minData = reinterpret_cast<Input_T*>(min);
365 Input_T *maxData = reinterpret_cast<Input_T*>(max);
366 // Loop over fields in vector
367 for (size_t field = 0, end = f.size(); field < end; ++field) {
368 // Data window
369 const Box3i dw = f[field].field->dataWindow();
370 // Transform corners to voxel space and compute bounds
371 Box3i dvsBounds;
372 if (wsBounds.isInfinite()) {
373 dvsBounds = dw;
374 } else {
375 Box3d vsBounds;
376 if (f[field].doOsToWs) {
377 Box3d osBounds;
378 transformBounds(f[field].wsToOs, wsBounds, osBounds);
379 worldToVoxel(f[field].mapping, osBounds, vsBounds);
380 } else {
381 worldToVoxel(f[field].mapping, wsBounds, vsBounds);
382 }
383 dvsBounds = clipBounds(discreteBounds(vsBounds), dw);
384 // Early termination if no intersection
385 if (!dw.intersects(dvsBounds)) {
386 return;
387 }
388 }
389 for (int k = dvsBounds.min.z; k <= dvsBounds.max.z; ++k) {
390 for (int j = dvsBounds.min.y; j <= dvsBounds.max.y; ++j) {
391 for (int i = dvsBounds.min.x; i <= dvsBounds.max.x; ++i) {
392 const Data_T val = f[field].field->fastMipValue(0, i, j, k);
393 *minData = detail::min(val, *minData);
394 *maxData = detail::max(val, *maxData);
395 }
396 }
397 }
398 }
399 }
400
401 // Get min/max for pre-filtered data
402 static void getMinMaxPrefilt(const WrapperVec_T &f,
403 const Box3d &wsBounds,
404 float *result,
405 const Mode mode)
406 {
407 // Reinterpret the pointer according to Dims_T
408 Input_T *data = reinterpret_cast<Input_T*>(result);
409 // Loop over fields in vector
410 for (size_t field = 0, end = f.size(); field < end; ++field) {
411 // Choose the MIP level to check
412 const size_t numLevels = f[field].field->numLevels();
413 size_t level = 0;
414 Box3i dvsBounds;
415 // Infinite bounds?
416 if (wsBounds.isInfinite()) {
417 // Use the coarsest level
418 level = numLevels - 1;
419 dvsBounds = f[field].field->mipLevel(level)->dataWindow();
420 } else {
421 for (size_t i = 0; i < numLevels; ++i) {
422 // Update current level
423 level = i;
424 // Data window of current level
425 const Box3i dw = f[field].field->mipLevel(level)->dataWindow();
426 Box3d vsBounds;
427 if (f[field].doOsToWs) {
428 Box3d osBounds;
429 transformBounds(f[field].wsToOs, wsBounds, osBounds);
430 worldToVoxel(f[field].field->mipLevel(level)->mapping().get(),
431 osBounds, vsBounds);
432 } else {
433 worldToVoxel(f[field].field->mipLevel(level)->mapping().get(),
434 wsBounds, vsBounds);
435 }
436 dvsBounds = clipBounds(discreteBounds(vsBounds), dw);
437 // If size of dvsBounds is <= 2, stop
438 Imath::V3i size = dvsBounds.size();
439 if (std::max(size.x, std::max(size.y, size.z)) <= 2) {
440 break;
441 }
442 }
443 }
444 // Level chosen. Run loop
445 for (int k = dvsBounds.min.z; k <= dvsBounds.max.z; ++k) {
446 for (int j = dvsBounds.min.y; j <= dvsBounds.max.y; ++j) {
447 for (int i = dvsBounds.min.x; i <= dvsBounds.max.x; ++i) {
448 const Data_T val = f[field].field->fastMipValue(level, i, j, k);
449 if (mode == Min) {
450 *data = detail::min(val, *data);
451 } else {
452 *data = detail::max(val, *data);
453 }
454 }
455 }
456 }
457 }
458 }
459
460};
461
462//----------------------------------------------------------------------------//
463
465
466//------------------------------------------------------------------------------
467
468#endif // include guard
469
470//------------------------------------------------------------------------------
void worldToVoxel(const Field3D::FieldMapping *mapping, const Box3d &wsBounds, Box3d &vsBounds)
Computes a voxel space bounds given a bounding box in world space. This is done by transforming each ...
void transformBounds(const M44d &mtx, const Box3d &fromBounds, Box3d &toBounds)
Transforms a bounding box by a 4x4 matrix This is done by transforming each corner vertex from world ...
Box3i discreteBounds(const Box3d &bbox)
Converts a floating point bounding box to an integer bounding box.
Definition Field.h:1128
Box3i clipBounds(const Box3i &bbox, const Box3i &bounds)
Definition Field.h:1145
Imath::Box3d Box3d
Definition SpiMathLib.h:79
Imath::V3d V3d
Definition SpiMathLib.h:74
#define FIELD3D_VEC3_T
Definition SpiMathLib.h:88
Imath::Box3i Box3i
Definition SpiMathLib.h:77
Imath::V3f V3f
Definition SpiMathLib.h:73
Contains typedefs for the commonly used types in Field3D.
T max(const T a, const T2 b)
Max operation on mixed types.
T min(const T a, const T2 b)
Min operation on mixed types.
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Definition ns.h:58
Interface for sampling a vector of fields of the same type.
WrapperVec_T::value_type::field_type Field_T
static void sampleMIP(const WrapperVec_T &f, const V3d &wsP, const float wsSpotSize, float *value, size_t &numHits)
static void sample(const WrapperVec_T &f, const V3d &wsP, float *value, size_t &numHits)
Field_T::value_type Data_T
static void sampleMultiple(const WrapperVec_T &f, const size_t neval, const float *wsPs, float *value, size_t *numHits)
static void getMinMaxMIP(const WrapperVec_T &f, const Box3d &wsBounds, float *min, float *max)
static void getMinMax(const WrapperVec_T &f, const Box3d &wsBounds, float *min, float *max)
static void sampleMIPMultiple(const WrapperVec_T &f, const size_t neval, const float *wsPs, const float *wsSpotSizes, float *value, size_t *numHits)
static void getMinMaxPrefilt(const WrapperVec_T &f, const Box3d &wsBounds, float *result, const Mode mode)
detail::ScalarOrVector< Dims_T >::type Input_T
Typedefs float or V3f, depending on Dims_T.