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 
21 namespace 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>
39  FIELD3D_VEC3_T<T> min(const FIELD3D_VEC3_T<T> &a,
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>
49  FIELD3D_VEC3_T<T> max(const FIELD3D_VEC3_T<T> &a,
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 <>
62  struct ScalarOrVector<1>
63  {
64  typedef float type;
65  };
66 
67  template <>
68  struct ScalarOrVector<3>
69  {
70  typedef V3f type;
71  };
72 
73 }
74 
75 //------------------------------------------------------------------------------
76 // FieldSampler
77 //------------------------------------------------------------------------------
78 
80 template <typename WrapperVec_T, int Dims_T>
82 {
83  enum Mode {
84  Min,
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 //------------------------------------------------------------------------------
detail::ScalarOrVector< 1 >::type
float type
Definition: FieldSampler.h:64
FIELD3D_NAMESPACE_HEADER_CLOSE
#define FIELD3D_NAMESPACE_HEADER_CLOSE
Definition: ns.h:58
FieldSampler::Field_T
WrapperVec_T::value_type::field_type Field_T
Definition: FieldSampler.h:88
FieldSampler
Interface for sampling a vector of fields of the same type.
Definition: FieldSampler.h:82
V3i
Imath::V3i V3i
Definition: SpiMathLib.h:71
FieldSampler::Mode
Mode
Definition: FieldSampler.h:83
V3d
Imath::V3d V3d
Definition: SpiMathLib.h:74
transformBounds
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 ...
Definition: FieldMapping.cpp:200
Types.h
Contains typedefs for the commonly used types in Field3D.
FieldSampler::sample
static void sample(const WrapperVec_T &f, const V3d &wsP, float *value, size_t &numHits)
Definition: FieldSampler.h:93
FieldSampler::sampleMIP
static void sampleMIP(const WrapperVec_T &f, const V3d &wsP, const float wsSpotSize, float *value, size_t &numHits)
Definition: FieldSampler.h:188
detail
Definition: CoordSys.h:97
FieldSampler::Min
@ Min
Definition: FieldSampler.h:84
detail::ScalarOrVector
Typedefs float or V3f, depending on Dims_T.
Definition: FieldSampler.h:59
V3f
Imath::V3f V3f
Definition: SpiMathLib.h:73
FieldSampler::Input_T
detail::ScalarOrVector< Dims_T >::type Input_T
Definition: FieldSampler.h:90
detail::ScalarOrVector< 3 >::type
V3f type
Definition: FieldSampler.h:70
discreteBounds
Box3i discreteBounds(const Box3d &bbox)
Converts a floating point bounding box to an integer bounding box.
Definition: Field.h:1128
ns.h
FieldSampler::getMinMaxMIP
static void getMinMaxMIP(const WrapperVec_T &f, const Box3d &wsBounds, float *min, float *max)
Definition: FieldSampler.h:360
detail::max
T max(const T a, const T2 b)
Max operation on mixed types.
Definition: FieldSampler.h:32
Box3d
Imath::Box3d Box3d
Definition: SpiMathLib.h:79
FieldSampler::sampleMIPMultiple
static void sampleMIPMultiple(const WrapperVec_T &f, const size_t neval, const float *wsPs, const float *wsSpotSizes, float *value, size_t *numHits)
Definition: FieldSampler.h:222
FieldSampler::Max
@ Max
Definition: FieldSampler.h:85
FieldSampler::Data_T
Field_T::value_type Data_T
Definition: FieldSampler.h:89
detail::max
FIELD3D_VEC3_T< T > max(const FIELD3D_VEC3_T< T > &a, const FIELD3D_VEC3_T< T2 > &b)
Max operation on mixed vector types.
Definition: FieldSampler.h:49
FIELD3D_NAMESPACE_OPEN
Definition: FieldMapping.cpp:74
detail::min
FIELD3D_VEC3_T< T > min(const FIELD3D_VEC3_T< T > &a, const FIELD3D_VEC3_T< T2 > &b)
Min operation on mixed vector types.
Definition: FieldSampler.h:39
Box3i
Imath::Box3i Box3i
Definition: SpiMathLib.h:77
FieldSampler::sampleMultiple
static void sampleMultiple(const WrapperVec_T &f, const size_t neval, const float *wsPs, float *value, size_t *numHits)
Definition: FieldSampler.h:125
clipBounds
Box3i clipBounds(const Box3i &bbox, const Box3i &bounds)
Definition: Field.h:1145
FieldSampler::getMinMax
static void getMinMax(const WrapperVec_T &f, const Box3d &wsBounds, float *min, float *max)
Definition: FieldSampler.h:318
detail::min
T min(const T a, const T2 b)
Min operation on mixed types.
Definition: FieldSampler.h:25
worldToVoxel
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 ...
Definition: FieldMapping.cpp:173
FieldSampler::getMinMaxPrefilt
static void getMinMaxPrefilt(const WrapperVec_T &f, const Box3d &wsBounds, float *result, const Mode mode)
Definition: FieldSampler.h:402