HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SIM_FieldUtils.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: SIM_FieldUtils.h ( SIM Library, C++)
7  *
8  * COMMENTS:
9  * Templated functions for common behaviours
10  * in SIM_Fields.
11  */
12 
13 #ifndef __SIM_FieldUtils__
14 #define __SIM_FieldUtils__
15 
16 #include <GU/GU_Types.h>
17 
18 #include "SIM_ScalarField.h"
19 #include "SIM_MatrixField.h"
20 #include "SIM_VectorField.h"
21 #include "SIM_IndexField.h"
22 
23 namespace SIM { namespace FieldUtils
24 {
25  template<typename Functor>
26  void
27  forEachVoxelRange(const UT_Vector3I& start, const UT_Vector3I& end, const Functor &f)
28  {
29  for (exint i = start[0]; i < end[0]; ++i)
30  for (exint j = start[1]; j < end[1]; ++j)
31  for (exint k = start[2]; k < end[2]; ++k)
32  f(UT_Vector3I(i,j,k));
33  };
34 
35  // Helper functions to read/write from grids
37  void
39  {
40  field.fieldNC()->setValue(cell[0], cell[1], cell[2], value);
41  }
42 
44  fpreal32
45  getFieldValue(const SIM_RawField &field, const UT_Vector3I &cell)
46  {
47  return (*field.field())(cell[0], cell[1], cell[2]);
48  }
49 
51  void
53  {
54  field.fieldNC()->setValue(cell[0], cell[1], cell[2], value);
55  }
56 
58  exint
59  getFieldValue(const SIM_RawIndexField &field, const UT_Vector3I &cell)
60  {
61  return (*field.field())(cell[0], cell[1], cell[2]);
62  }
63 
64  // Helper functions to map between components of the grid.
67  cellToFaceMap(const UT_Vector3I &cell, const int axis, const int direction)
68  {
69  UT_Vector3I face(cell);
70  // The convention for offset directions is [0,1] where
71  // 0 is in the negative direction and 1 is in the positive.
72  // The face in the negative direction has the same index as
73  // the cell.
74  if (direction == 1)
75  ++face[axis];
76  else
77  UT_ASSERT_P(direction == 0);
78 
79  return face;
80  }
81 
84  cellToCellMap(const UT_Vector3I &cell, const int axis, const int direction)
85  {
86  UT_Vector3I adjacent_cell(cell);
87 
88  // The convention for offset directions is [0,1] where
89  // 0 is in the negative direction and 1 is in the positive.
90  // For adjacent cells, we offset by one in the positive or
91  // negative direction along the specified axis.
92  if (direction == 0)
93  --adjacent_cell[axis];
94  else
95  {
96  UT_ASSERT_P(direction == 1);
97  ++adjacent_cell[axis];
98  }
99 
100  return adjacent_cell;
101  }
102 
103  // The edge axis corresponds to the axis that the edge is pointing. For example,
104  // SIM_SAMPLE_EDGEXY refers to an edge pointing in the normal direction to the xy-plane,
105  // which is the z-axis. The edge index points to one of the four edges adjacent to the cell.
106  // This index is used as a bit-mask for offsetting in the planar axes orthogonal to the edge.
109  cellToEdgeMap(const UT_Vector3I &cell, const int edge_axis, const int edge_index)
110  {
111  UT_ASSERT_P(edge_axis >= 0 && edge_axis < 3);
112  UT_ASSERT_P(edge_index >= 0 && edge_index < 4);
113 
114  UT_Vector3I edge(cell);
115 
116  for (int axis_offset : {0,1})
117  {
118  if (edge_index & (1 << axis_offset))
119  {
120  int localAxis = (edge_axis + 1 + axis_offset) % 3;
121  ++edge[localAxis];
122  }
123  }
124 
125  return edge;
126  }
127 
130  cellToNodeMap(const UT_Vector3I &cell, const int node_index)
131  {
132  UT_ASSERT_P(node_index >= 0 && node_index < 8);
133 
134  UT_Vector3I node(cell);
135 
136  // The node at the bottom corner of the cell will have the
137  // same ijk index as the cell. We offset in the positive direction
138  // along each axis according to the 3-bit node index.
139  for (int axis : {0,1,2})
140  {
141  if (node_index & (1 << axis))
142  ++node[axis];
143  }
144 
145  return node;
146  }
147 
150  faceToCellMap(const UT_Vector3I &face, const int axis, const int direction)
151  {
152  UT_Vector3I cell(face);
153 
154  // The convention for mapping faces to cells is the inverse of cells to faces.
155  // A backward direction corresponds to a negative offset while the forward direction
156  // doesn't apply any offset.
157  if (direction == 0)
158  --cell[axis];
159  else
160  UT_ASSERT_P(direction == 1);
161 
162  return cell;
163  }
164 
167  faceToEdgeMap(const UT_Vector3I &face, const int face_axis,
168  const int edge_axis, const int direction)
169  {
170  UT_ASSERT_P(face_axis >= 0 && face_axis < 3 && edge_axis >= 0 && edge_axis < 3);
171  UT_ASSERT_P(face_axis != edge_axis);
172 
173  UT_Vector3I edge(face);
174 
175  if (direction == 1)
176  {
177  int axis_offset = 3 - face_axis - edge_axis;
178  ++edge[axis_offset];
179  }
180  else
181  UT_ASSERT_P(direction == 0);
182 
183  return edge;
184  }
185 
188  faceToNodeMap(const UT_Vector3I &face, const int face_axis, const int node_index)
189  {
190  UT_ASSERT_P(face_axis >= 0 && face_axis < 3);
191  UT_ASSERT_P(node_index >= 0 && node_index < 4);
192 
193  UT_Vector3I node(face);
194 
195  for (int axis_offset : {0,1})
196  {
197  if (node_index & (1 << axis_offset))
198  {
199  int local_axis = (face_axis + 1 + axis_offset) % 3;
200  ++node[local_axis];
201  }
202  }
203 
204  return node;
205  }
206 
209  edgeToFaceMap(const UT_Vector3I &edge, const int edge_axis,
210  const int face_axis, const int direction)
211  {
212  UT_ASSERT_P(face_axis >= 0 && face_axis < 3 && edge_axis >= 0 && edge_axis < 3);
213  UT_ASSERT_P(face_axis != edge_axis);
214 
215  UT_Vector3I face(edge);
216  if (direction == 0)
217  {
218  int axis_offset = 3 - face_axis - edge_axis;
219  --face[axis_offset];
220  }
221  else
222  UT_ASSERT_P(direction == 1);
223 
224  return face;
225  }
226 
229  edgeToCellMap(const UT_Vector3I &edge, const int edge_axis, const int cell_index)
230  {
231  UT_ASSERT_P(edge_axis >= 0 && edge_axis < 3);
232  UT_ASSERT_P(cell_index >= 0 && cell_index < 4);
233 
234  UT_Vector3I cell(edge);
235  for (int axis_offset : {0,1})
236  {
237  if (!(cell_index & (1 << axis_offset)))
238  {
239  int local_axis = (edge_axis + 1 + axis_offset) % 3;
240  --cell[local_axis];
241  }
242  }
243 
244  return cell;
245  }
246 
249  nodeToFaceMap(const UT_Vector3I &node, const int face_axis, const int face_index)
250  {
251  UT_ASSERT_P(face_axis >= 0 && face_axis < 3);
252  UT_ASSERT_P(face_index >= 0 && face_index < 4);
253 
254  UT_Vector3I face(node);
255 
256  for (int axis_offset : {0,1})
257  {
258  if (!(face_index & (1 << axis_offset)))
259  {
260  int local_axis = (face_axis + 1 + axis_offset) % 3;
261  --face[local_axis];
262  }
263  }
264 
265  return face;
266  }
267 
270  nodeToCellMap(const UT_Vector3I &node, const int cell_index)
271  {
272  UT_ASSERT_P(cell_index >= 0 && cell_index < 8);
273 
274  UT_Vector3I cell(node);
275  for (int axis : {0,1,2})
276  {
277  if (!(cell_index & (1 << axis)))
278  --cell[axis];
279  }
280 
281  return cell;
282  }
283 
284 }}
285 
286 
287 ///
288 /// Returns true if there is a slice to be performed.
289 /// The slice is the half inclusive interval [minvxl, maxvxl)
290 ///
291 inline bool
292 SIMfieldUtilsComputeSliceWithBorder(const UT_Vector3 &slice, const UT_Vector3 &totaldiv, UT_Vector3 overlapneg, UT_Vector3 overlappos, int slicenum, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
293 {
294  if (slice.isEqual(UT_Vector3(1, 1, 1)))
295  {
296  minvxl = UT_Vector3(0, 0, 0);
297  maxvxl = totaldiv;
298  // Trivially unsliced
299  return false;
300  }
301 
302  int sx, sy, sz;
303  int x, y, z;
304 
305  sx = SYSrint(slice(0));
306  sy = SYSrint(slice(1));
307  sz = SYSrint(slice(2));
308 
309  if (slicenum < 0 || slicenum >= sx*sy*sz)
310  {
311  // Unclear if this should be impossible via UI, and if so,
312  // how to make it so.
313  slicenum = 0;
314  }
315  x = slicenum % sx;
316  slicenum -= x;
317  slicenum /= sx;
318  y = slicenum % sy;
319  slicenum -= y;
320  slicenum /= sy;
321  z = slicenum;
322 
323  minvxl.x() = SYSrint( x * (totaldiv.x() / sx) );
324  maxvxl.x() = SYSrint( (x+1) * (totaldiv.x() / sx) );
325  minvxl.y() = SYSrint( y * (totaldiv.y() / sy) );
326  maxvxl.y() = SYSrint( (y+1) * (totaldiv.y() / sy) );
327  minvxl.z() = SYSrint( z * (totaldiv.z() / sz) );
328  maxvxl.z() = SYSrint( (z+1) * (totaldiv.z() / sz) );
329 
330  // Adjust for our borders.
331  minvxl -= overlapneg;
332  maxvxl += overlappos;
333 
334  minvxl.x() = SYSclamp(minvxl.x(), 0.0, totaldiv.x());
335  maxvxl.x() = SYSclamp(maxvxl.x(), 0.0, totaldiv.x());
336  minvxl.y() = SYSclamp(minvxl.y(), 0.0, totaldiv.y());
337  maxvxl.y() = SYSclamp(maxvxl.y(), 0.0, totaldiv.y());
338  minvxl.z() = SYSclamp(minvxl.z(), 0.0, totaldiv.z());
339  maxvxl.z() = SYSclamp(maxvxl.z(), 0.0, totaldiv.z());
340 
341  // Special case: we need at least one voxel in each direction.
342  if (maxvxl.x() - minvxl.x() < 1)
343  maxvxl.x()++;
344  if (maxvxl.y() - minvxl.y() < 1)
345  maxvxl.y()++;
346  if (maxvxl.z() - minvxl.z() < 1)
347  maxvxl.z()++;
348 
349  // Clamp again...
350  maxvxl.x() = SYSclamp(maxvxl.x(), 0.0, totaldiv.x());
351  maxvxl.y() = SYSclamp(maxvxl.y(), 0.0, totaldiv.y());
352  maxvxl.z() = SYSclamp(maxvxl.z(), 0.0, totaldiv.z());
353 
354  // Verify we are still valid.
355  if (maxvxl.x() - minvxl.x() < 1)
356  minvxl.x()--;
357  if (maxvxl.y() - minvxl.y() < 1)
358  minvxl.y()--;
359  if (maxvxl.z() - minvxl.z() < 1)
360  minvxl.z()--;
361 
362  return true;
363 }
364 
365 template <typename FIELDTYPE>
366 bool
367 SIMfieldUtilsComputeSliceWithBorder(const FIELDTYPE *field, const UT_Vector3 &totaldiv, UT_Vector3 overlapneg, UT_Vector3 overlappos, int slicenum, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
368 {
369  UT_Vector3 slice = field->getSliceDivisions();
370 
371  return SIMfieldUtilsComputeSliceWithBorder(slice, totaldiv, overlapneg, overlappos, slicenum, minvxl, maxvxl);
372 }
373 
374 
375 template <typename FIELDTYPE>
376 bool
377 SIMfieldUtilsComputeSlice(const FIELDTYPE *field, const UT_Vector3 &totaldiv, int slicenum, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
378 {
380  field, totaldiv,
381  field->getSliceOverlapNeg(), field->getSliceOverlapPos(),
382  slicenum, minvxl, maxvxl);
383 }
384 
385 /// Returns true if there is any overlap between the two
386 /// slices. [minvxl, maxvxl) is the region of overlap.
387 /// This is the intersection of the two slice fields.
388 template <typename FIELDTYPE>
389 bool
390 SIMfieldUtilsGetSliceBorder(const FIELDTYPE *field,
391  int a_slice, int b_slice,
392  UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
393 {
394  UT_Vector3 a_min, a_max, b_min, b_max;
395  UT_Vector3 div;
396 
398 
399  SIMfieldUtilsComputeSlice(field, div, a_slice, a_min, a_max);
400  SIMfieldUtilsComputeSlice(field, div, b_slice, b_min, b_max);
401 
402  UT_BoundingBox a_box(a_min, a_max), b_box(b_min, b_max);
403 
404  if (!a_box.computeIntersection(b_box))
405  return false;
406 
407  minvxl = a_box.minvec();
408  maxvxl = a_box.maxvec();
409 
410  return true;
411 }
412 
413 template <typename FIELDTYPE>
415 SIMfieldUtilsGetDivisionsNoSlice(const FIELDTYPE *field)
416 {
417  UT_Vector3 div;
418  int uniform;
419 
420  uniform = field->getUniformVoxels();
421  if (uniform)
422  {
423  UT_Vector3 size, searchsize;
424  int axis, a;
425  fpreal voxelsize;
426  fpreal uniformdiv;
427 
428  size = field->getRawSize();
429  uniformdiv = field->getRawUniformDivisions();
430 
431  searchsize = size;
432 
433  // Force voxels to be uniform, by hook or by crook.
434  // This axis will be taken as authoritative.
435  axis = uniform-1;
436 
437  if (field->getTwoDField())
438  {
439  // We cannot use an axis that isn't represented.
440  // For maximum axis case, we clamp the non represented
441  // axis to 0 size to make sure we ignore it.
442  switch (field->getVoxelPlane())
443  {
444  case GU_PLANE_XY:
445  if (axis == 2)
446  axis = 0;
447  searchsize(2) = 0.0;
448  break;
449  case GU_PLANE_YZ:
450  if (axis == 0)
451  axis = 1;
452  searchsize(0) = 0.0;
453  break;
454  case GU_PLANE_XZ:
455  if (axis == 1)
456  axis = 2;
457  searchsize(1) = 0.0;
458  break;
459  }
460  }
461 
462  // Check to see if they requested a maximum voxel option.
463  if (axis == 3)
464  {
465  axis = searchsize.findMaxAbsAxis();
466  }
467 
468  // If the user is specifying by voxel size...
469  if (axis == 4)
470  {
471  voxelsize = field->getRawDivisionSize();
472  }
473  else
474  {
475  voxelsize = size(axis) / uniformdiv;
476  }
477 
478 
479  // It is possible for the user to accidentally specify a
480  // zero size through use of a ladder handle, which, obviously,
481  // leads to bad things.
482  if (SYSequalZero(voxelsize))
483  {
484  // This, presumeably, also means that all axes are
485  // the same as we found no maximum!
486  div = uniformdiv;
487  }
488  else
489  {
490  // Determine the dimensions of the divisions.
491  for (a = 0; a < 3; a++)
492  {
493  div(a) = SYSrint(size(a)/voxelsize);
494  if (div(a) < 1.0)
495  div(a) = 1.0;
496  }
497  // div(axis) should evaluate to uniformdiv.
498  // The exception will be if we are currently building
499  // our divisions and thus have uniformdiv == 0.
500  // Similarly, if we have specified by voxel size, they
501  // will not match.
502  UT_ASSERT(!uniformdiv || (axis == 4) || SYSisEqual(div(axis), uniformdiv));
503  }
504  }
505  else
506  {
507  div = field->getRawDivisions();
508  }
509 
510  if (field->getTwoDField())
511  {
512  // Clamp to twod.
513  switch (field->getVoxelPlane())
514  {
515  case GU_PLANE_XY:
516  div.z() = 1.0;
517  break;
518  case GU_PLANE_YZ:
519  div.x() = 1.0;
520  break;
521  case GU_PLANE_XZ:
522  div.y() = 1.0;
523  break;
524  }
525  }
526 
527  return div;
528 }
529 
530 template <typename FIELDTYPE>
532 SIMfieldUtilsGetDivisions(const FIELDTYPE *field)
533 {
534  UT_Vector3 minvxl, maxvxl;
535  UT_Vector3 div;
536 
538 
539  // Now compute divisions for our particular slice.
540  SIMfieldUtilsComputeSlice(field, div, field->getSlice(), minvxl, maxvxl);
541 
542  maxvxl -= minvxl;
543 
544  return maxvxl;
545 }
546 
547 template <typename FIELDTYPE>
549 SIMfieldUtilsGetSizeNoSlice(const FIELDTYPE *field)
550 {
552  int uniform;
553 
554  size = field->getRawSize();
555 
556  uniform = field->getUniformVoxels();
557 
558  if (uniform)
559  {
560  int axis;
561  fpreal voxelsize;
562  UT_Vector3 div;
563  UT_Vector3 searchsize;
564 
565  searchsize = size;
566  axis = uniform-1;
567 
568  if (field->getTwoDField())
569  {
570  // We cannot use an axis that isn't represented.
571  switch (field->getVoxelPlane())
572  {
573  case GU_PLANE_XY:
574  if (axis == 2)
575  axis = 0;
576  searchsize(2) = 0;
577  break;
578  case GU_PLANE_YZ:
579  if (axis == 0)
580  axis = 1;
581  searchsize(0) = 0;
582  break;
583  case GU_PLANE_XZ:
584  if (axis == 1)
585  axis = 2;
586  searchsize(1) = 0;
587  break;
588  }
589  }
590 
591  // Check to see if they requested a maximum voxel option.
592  if (axis == 3)
593  axis = searchsize.findMaxAbsAxis();
594 
595  // Taking into account 2d and uniformality:
597 
598  // Recompute voxelsize...
599  if (axis == 4)
600  voxelsize = field->getRawDivisionSize();
601  else
602  voxelsize = size(axis) / div(axis);
603 
604  // Now the other dimensions are a direct copy
605  size = voxelsize * div;
606  }
607 
608  // Size should never be zero. We demand at least one voxel, so
609  // should have computed a non-zero size if we had a non-zero voxel
610  // size. If we get a zero voxelsize, thi sis the cahcne to fix
611  // it. 1.0 is a random number here, there is no good answer
612  // in these cases.
613  if (size.x() == 0)
614  size.x() = 1;
615  if (size.y() == 0)
616  size.y() = 1;
617  if (size.z() == 0)
618  size.z() = 1;
619 
620  return size;
621 }
622 
623 template <typename FIELDTYPE>
625 SIMfieldUtilsGetSize(const FIELDTYPE *field)
626 {
628  UT_Vector3 div;
629  UT_Vector3 minvxl, maxvxl;
630 
632  size = SIMfieldUtilsGetSizeNoSlice(field);
633 
634  if (SIMfieldUtilsComputeSlice(field, div, field->getSlice(), minvxl, maxvxl))
635  {
636  UT_Vector3 voxelsize;
637 
638  voxelsize = size / div;
639 
640  // Get actual sliced size.
641  maxvxl -= minvxl;
642 
643  // Recompute oursize from there.
644  size = maxvxl * voxelsize;
645  }
646 
647  return size;
648 }
649 
650 template <typename FIELDTYPE>
652 SIMfieldUtilsGetCenter(const FIELDTYPE *field)
653 {
655  UT_Vector3 div;
656  UT_Vector3 minvxl, maxvxl;
658 
660  center = field->getRawCenter();
661 
662  if (SIMfieldUtilsComputeSlice(field, div, field->getSlice(), minvxl, maxvxl))
663  {
664  UT_Vector3 voxelsize;
665 
666  size = SIMfieldUtilsGetSizeNoSlice(field);
667 
668  voxelsize = size / div;
669  // My actual center is found by averaging min/maxvxl and
670  // casting back into our large voxel space.
671  minvxl += maxvxl;
672  minvxl *= 0.5;
673 
674  // Make our coordinates relative to the center of the box
675  minvxl -= div / 2;
676 
677  // Convert to space
678  minvxl *= voxelsize;
679 
680  center += minvxl;
681  }
682 
683  return center;
684 }
685 
686 
687 template <typename FIELDTYPE, typename F2>
688 void
689 SIMfieldUtilsMatch(FIELDTYPE *field, const F2 *srcfield)
690 {
691  field->setUniformVoxels(srcfield->getUniformVoxels());
692  field->setTwoDField(srcfield->getTwoDField());
693  field->setVoxelPlane(srcfield->getVoxelPlane());
694 
695  field->setRawDivisions(srcfield->getRawDivisions());
696  field->setRawDivisionSize(srcfield->getRawDivisionSize());
697  field->setRawUniformDivisions(srcfield->getRawUniformDivisions());
698  field->setRawSize(srcfield->getRawSize());
699  field->setRawCenter(srcfield->getRawCenter());
700 
701  field->setSlice(srcfield->getSlice());
702  field->setSliceDivisions(srcfield->getSliceDivisions());
703  field->setSliceOverlapNeg(srcfield->getSliceOverlapNeg());
704  field->setSliceOverlapPos(srcfield->getSliceOverlapPos());
705 
706  UT_String pospath;
707  srcfield->getPositionPath(pospath);
708  field->setPositionPath(pospath);
709 
710  field->testForNan();
711 
712  field->updateTotalVoxels();
713 
714  field->setVoxelSize(srcfield->getVoxelSize());
715 }
716 
717 inline void
719 {
720  raw[0] = field->stealField();
721 }
722 
723 inline void
725 {
726  raw[0] = field->stealField();
727 }
728 
729 inline void
731 {
732  for (int i = 0; i < 3; i++)
733  raw[i] = field->stealField(i);
734 }
735 
736 inline void
738 {
739  for (int i = 0; i < 3; i++)
740  for (int j = 0; j < 3; j++)
741  raw[i*3+j] = field->stealField(i, j);
742 }
743 
744 template <typename RAWFIELD>
745 void
747  const char *address, int port,
748  RAWFIELD *dest,
749  RAWFIELD *src,
750  int slicenum,
751  int offx, int offy, int offz,
752  UT_Vector3 olddiv, UT_Vector3 newdiv,
753  UT_Vector3 slicediv,
754  UT_Vector3 overlapneg, UT_Vector3 overlappos);
755 
756 inline void
758  int offx, int offy, int offz,
759  bool keepdata,
760  UT_Vector3 olddivvec, UT_Vector3 newdivvec,
761  const char *address,
762  int port)
763 {
764  if (keepdata)
765  {
766  if((offx & TILEMASK) == 0 && (offy & TILEMASK) == 0
767  && (offz & TILEMASK) == 0)
768  field->getField()->fieldNC()->moveTilesWithOffset(*raw[0]->fieldNC(),
769  offx >> TILEBITS, offy >> TILEBITS, offz >> TILEBITS);
770  else
771  field->getField()->fieldNC()->copyWithOffset(*raw[0]->field(),
772  offx, offy, offz);
773  if (UTisstring(address) && port > 0)
774  {
776  address, port,
777  field->getField(),
778  raw[0],
779  field->getSlice(),
780  offx, offy, offz,
781  olddivvec, newdivvec,
782  field->getSliceDivisions(),
783  field->getSliceOverlapNeg(),
784  field->getSliceOverlapPos());
785  }
786 
787  }
788  delete raw[0];
789 }
790 
791 inline void
793  int offx, int offy, int offz,
794  bool keepdata,
795  UT_Vector3 olddivvec, UT_Vector3 newdivvec,
796  const char *address,
797  int port)
798 {
799  if (keepdata)
800  {
801  if((offx & TILEMASK) == 0 && (offy & TILEMASK) == 0
802  && (offz & TILEMASK) == 0)
803  field->getField()->fieldNC()->moveTilesWithOffset(*raw[0]->fieldNC(),
804  offx >> TILEBITS, offy >> TILEBITS, offz >> TILEBITS);
805  else
806  field->getField()->fieldNC()->copyWithOffset(*raw[0]->field(),
807  offx, offy, offz);
808  if (UTisstring(address) && port > 0)
809  {
811  address, port,
812  field->getField(),
813  raw[0],
814  field->getSlice(),
815  offx, offy, offz,
816  olddivvec, newdivvec,
817  field->getSliceDivisions(),
818  field->getSliceOverlapNeg(),
819  field->getSliceOverlapPos());
820  }
821  }
822  delete raw[0];
823 }
824 
825 inline void
827  int offx, int offy, int offz,
828  bool keepdata,
829  UT_Vector3 olddivvec, UT_Vector3 newdivvec,
830  const char *address,
831  int port)
832 {
833  for (int i = 0; i < 3; i++)
834  {
835  if (keepdata)
836  {
837  if((offx & TILEMASK) == 0 && (offy & TILEMASK) == 0
838  && (offz & TILEMASK) == 0)
839  field->getField(i)->fieldNC()->moveTilesWithOffset(*raw[i]->fieldNC(),
840  offx >> TILEBITS, offy >> TILEBITS, offz >> TILEBITS);
841  else
842  field->getField(i)->fieldNC()->copyWithOffset(*raw[i]->field(),
843  offx, offy, offz);
844  if (UTisstring(address) && port > 0)
845  {
847  address, port,
848  field->getField(i),
849  raw[i],
850  field->getSlice(),
851  offx, offy, offz,
852  olddivvec, newdivvec,
853  field->getSliceDivisions(),
854  field->getSliceOverlapNeg(),
855  field->getSliceOverlapPos());
856  }
857  }
858  delete raw[i];
859  }
860 }
861 
862 inline void
864  int offx, int offy, int offz,
865  bool keepdata,
866  UT_Vector3 olddivvec, UT_Vector3 newdivvec,
867  const char *address,
868  int port)
869 {
870  for (int i = 0; i < 3; i++)
871  for (int j = 0; j < 3; j++)
872  {
873  if (keepdata)
874  {
875  if((offx & TILEMASK) == 0 && (offy & TILEMASK) == 0
876  && (offz & TILEMASK) == 0)
877  field->getField(i, j)->fieldNC()->moveTilesWithOffset(
878  *raw[i*3+j]->fieldNC(), offx >> TILEBITS, offy >> TILEBITS,
879  offz >> TILEBITS);
880  else
881  field->getField(i, j)->fieldNC()->copyWithOffset(*raw[i*3+j]->field(),
882  offx, offy, offz);
883 
884  if (UTisstring(address) && port > 0)
885  {
887  address, port,
888  field->getField(i, j),
889  raw[i*3+j],
890  field->getSlice(),
891  offx, offy, offz,
892  olddivvec, newdivvec,
893  field->getSliceDivisions(),
894  field->getSliceOverlapNeg(),
895  field->getSliceOverlapPos());
896  }
897  }
898  delete raw[i*3+j];
899  }
900 }
901 
902 template <typename FIELDTYPE>
903 void
906  bool keepdata,
907  const char *address,
908  int port,
909  bool &snapvalid,
910  UT_Vector3 &snapsize, UT_Vector3 &snapcenter)
911 {
912  UT_Vector3 voxelsize, newsize, newcenter;
913  UT_Vector3 oldcenter, oldsize, offset;
914  typename FIELDTYPE::rawfield_type *oldfields[9];
915  int voxeloffset[3];
916  int newdiv[3], olddiv[3], uniformdiv, axis;
917  UT_Vector3 olddivvec, searchsize;
918 
919  voxelsize = field->getVoxelSize();
920 
921  if (SYSequalZero(voxelsize.x()) ||
922  SYSequalZero(voxelsize.y()) ||
923  SYSequalZero(voxelsize.z()))
924  {
925  // Zero sized voxels can't be resized as we can't
926  // meaningfully find a new size for them.
927  return;
928  }
929 
930  // We need the unsliced sizes.
931  oldcenter = field->getRawCenter();
932  oldsize = SIMfieldUtilsGetSizeNoSlice(field);
933  olddivvec = SIMfieldUtilsGetDivisionsNoSlice(field);
934  olddiv[0] = (int) SYSrint(olddivvec.x());
935  olddiv[1] = (int) SYSrint(olddivvec.y());
936  olddiv[2] = (int) SYSrint(olddivvec.z());
937 
938  // Find what range this slice consisted of before the slice.
939  UT_Vector3 oldslicemin, oldslicemax;
940  SIMfieldUtilsComputeSlice(field, olddivvec, field->getSlice(), oldslicemin, oldslicemax);
941 
942  // This is the offset into voxel space. We basically want
943  // to quantize all of our coordinates to be integer voxelsize
944  // steps from this offset.
945  // Note it is not the old center, as it is valid to center
946  // on the mid point of a voxel if we have an odd number of
947  // voxels! Thus it is quanitzed as per the bottom left.
948  UT_Vector3 oldoffset;
949 
950  oldoffset = oldcenter - oldsize/2.0f;
951 
952  // Get the coordinates of our new boxes edges and quantize to
953  // exact voxel numbers.
954  UT_Vector3 newbot, newtop;
955 
956  newbot = center - size/2;
957  newtop = center + size/2;
958 
959  newbot -= oldoffset;
960  newtop -= oldoffset;
961  newbot /= voxelsize;
962  newtop /= voxelsize;
963  // It is depressingly common for things to exactly match up
964  // due to users using a size 0.1 and unit boxes.
965  newtop.x() = SYSrint(newtop.x() + 0.0001);
966  newtop.y() = SYSrint(newtop.y() + 0.0001);
967  newtop.z() = SYSrint(newtop.z() + 0.0001);
968  newbot.x() = SYSrint(newbot.x() - 0.0001);
969  newbot.y() = SYSrint(newbot.y() - 0.0001);
970  newbot.z() = SYSrint(newbot.z() - 0.0001);
971  newbot *= voxelsize;
972  newtop *= voxelsize;
973  newbot += oldoffset;
974  newtop += oldoffset;
975 
976  // We can now recompute our desired center and size from
977  // these quantized values.
978  newcenter = (newbot + newtop) / 2;
979  newsize = newtop - newbot;
980 
981  // Calculate our new size as an integer number of voxels from the
982  // old size.
983  newdiv[0] = SYSrint(newsize.x()/voxelsize.x());
984  newdiv[1] = SYSrint(newsize.y()/voxelsize.y());
985  newdiv[2] = SYSrint(newsize.z()/voxelsize.z());
986 
987  // We can't have zero divisions on any axis.
988  // Note we need to bump our center half a voxel in this case
989  // because it needs to now be voxel centered.
990  if (newdiv[0] == 0)
991  {
992  newcenter.x() -= voxelsize.x()/2;
993  newdiv[0] = 1;
994  }
995  if (newdiv[1] == 0)
996  {
997  newcenter.y() -= voxelsize.y()/2;
998  newdiv[1] = 1;
999  }
1000  if (newdiv[2] == 0)
1001  {
1002  newcenter.z() -= voxelsize.z()/2;
1003  newdiv[2] = 1;
1004  }
1005 
1006  // Compute our new size from the new divisions.
1007  newsize.x() = newdiv[0] * voxelsize.x();
1008  newsize.y() = newdiv[1] * voxelsize.y();
1009  newsize.z() = newdiv[2] * voxelsize.z();
1010 
1011  // We refuse to move the voxel plane if it is 2d.
1012  if (field->getTwoDField())
1013  {
1014  switch (field->getVoxelPlane())
1015  {
1016  case GU_PLANE_XY:
1017  newcenter.z() = oldcenter.z();
1018  break;
1019  case GU_PLANE_YZ:
1020  newcenter.x() = oldcenter.x();
1021  break;
1022  case GU_PLANE_XZ:
1023  newcenter.y() = oldcenter.y();
1024  break;
1025  }
1026  }
1027 
1028  // Check to see if we have a no-op.
1029  if (oldcenter.isEqual(newcenter) &&
1030  olddiv[0] == newdiv[0] &&
1031  olddiv[1] == newdiv[1] &&
1032  olddiv[2] == newdiv[2])
1033  return;
1034 
1035  // Before we adjust our settings, we better steal the old
1036  // field as this will cause it to be rebuilt!
1037  SIMfieldUtilsStealFields(oldfields, field);
1038 
1039  // Reset our raw division and uniform division choices
1040  // so we'll compute newdiv in the end.
1041  field->setRawDivisions(UT_Vector3(newdiv[0], newdiv[1], newdiv[2]));
1042 
1043  uniformdiv = newdiv[0];
1044  axis = field->getUniformVoxels()-1;
1045 
1046  // Avoid non-existent axes:
1047  searchsize = newsize;
1048  if (field->getTwoDField())
1049  {
1050  switch (field->getVoxelPlane())
1051  {
1052  case GU_PLANE_XY:
1053  if (axis == 2)
1054  axis = 0;
1055  searchsize(2) = 0.0;
1056  break;
1057  case GU_PLANE_YZ:
1058  if (axis == 0)
1059  axis = 1;
1060  searchsize(0) = 0.0;
1061  break;
1062  case GU_PLANE_XZ:
1063  if (axis == 1)
1064  axis = 2;
1065  searchsize(1) = 0.0;
1066  break;
1067  }
1068  }
1069 
1070  // Check to see if they requested a maximum voxel option.
1071  if (axis == 3)
1072  {
1073  axis = searchsize.findMaxAbsAxis();
1074  }
1075 
1076  // Read up the appropriate choice
1077  if (axis >= 0 && axis < 3)
1078  uniformdiv = newdiv[axis];
1079 
1080  field->setRawUniformDivisions(uniformdiv);
1081 
1082  // We do not need to set our DivisionSize since it is unaffected.
1083  if (snapvalid)
1084  {
1085  if (snapcenter.isEqual(newcenter) &&
1086  snapsize.isEqual(newsize))
1087  {
1088  newcenter = snapcenter;
1089  newsize = snapsize;
1090  }
1091  }
1092  snapcenter = newcenter;
1093  snapsize = newsize;
1094  snapvalid = true;
1095 
1096  field->setCenter(newcenter);
1097  // Not setSize as we want to keep 2d/uniform!
1098  field->setRawSize(newsize);
1099  // This is not the same as it will round off voxels and deal
1100  // with 2d!
1101  newsize = SIMfieldUtilsGetSizeNoSlice(field);
1102  UT_Vector3 newdivvec = SIMfieldUtilsGetDivisionsNoSlice(field);
1103 
1104  // Now fill in the values...
1105  // We determine a voxel offset between our two fields
1106  offset = (newcenter - newsize/2) - (oldcenter - oldsize / 2);
1107  offset /= voxelsize;
1108 
1109  // field[x] = oldfield[x+offset];
1110  // However, oldfield is relative to oldslicemin, new field to
1111  // newslicemin
1112  UT_Vector3 newslicemin, newslicemax;
1113  SIMfieldUtilsComputeSlice(field, newdivvec, field->getSlice(), newslicemin, newslicemax);
1114 
1115  offset += newslicemin - oldslicemin;
1116 
1117  voxeloffset[0] = SYSrint(offset.x());
1118  voxeloffset[1] = SYSrint(offset.y());
1119  voxeloffset[2] = SYSrint(offset.z());
1120 
1121  // Filling in is very simple.
1122  SIMfieldUtilsCopyWithOffset(field, oldfields,
1123  voxeloffset[0],
1124  voxeloffset[1],
1125  voxeloffset[2],
1126  keepdata,
1127  olddivvec, newdivvec,
1128  address, port);
1129 
1130  field->updateTotalVoxels();
1131 
1132  field->pubHandleModification();
1133 
1134  field->setVoxelSize(voxelsize);
1135 }
1136 
1137 template <typename FIELDTYPE>
1138 void
1141  bool keepdata,
1142  const char *address,
1143  int port)
1144 {
1145  bool snapvalid = false;
1146  UT_Vector3 snapcenter, snapsize;
1147  SIMfieldUtilsResizeKeepDataAndSnap(field, size, center,
1148  keepdata, address, port,
1149  snapvalid, snapsize, snapcenter);
1150 }
1151 
1152 
1153 /// Returns true if two fields have voxels aligned.
1154 /// They do not have to be of the same resolution or share origin.
1155 /// However, using the `offset` allows to access this field with index
1156 /// of the other field.
1157 /// i.e. field1->indexToPos(index + offset) == field2->indexToPos(index)
1158 template <typename FIELDTYPE1, typename FIELDTYPE2>
1159 bool
1160 SIMfieldUtilsIsColocated(const FIELDTYPE1 *field1, const FIELDTYPE2 *field2, UT_Vector3I &offset){
1161 
1162  if (field1->getVoxelSize() == field2->getVoxelSize())
1163  {
1164  UT_Vector3 origin1 = field1->getOrig();
1165  UT_Vector3 origin2 = field2->getOrig();
1166 
1167  UT_Vector3 off = (origin2 - origin1) / field1->getVoxelSize();
1168 
1169  offset = UT_Vector3I{
1170  (exint)SYSrint(off.x()),
1171  (exint)SYSrint(off.y()),
1172  (exint)SYSrint(off.z())};
1173 
1174  // This makes sure that the offset is really by whole number of
1175  // voxels
1176  float error = SYSabs(off - (UT_Vector3F)offset).maxComponent();
1177 
1178  // I did some testing and the error is around 1e-6
1179  if (error < 1e-4)
1180  {
1181  return true;
1182  }
1183  else
1184  {
1185  return false;
1186  }
1187  }
1188  return false;
1189 }
1190 
1191 
1192 
1193 #endif
1194 
void SIMfieldUtilsStealFields(SIM_RawIndexField **raw, SIM_IndexField *field)
SYS_FORCE_INLINE UT_Vector3I cellToNodeMap(const UT_Vector3I &cell, const int node_index)
void SIMfieldUtilsResizeKeepDataAndSnap(FIELDTYPE *field, UT_Vector3 size, UT_Vector3 center, bool keepdata, const char *address, int port, bool &snapvalid, UT_Vector3 &snapsize, UT_Vector3 &snapcenter)
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
GA_API const UT_StringHolder div
int findMaxAbsAxis() const
These allow you to find out what indices to use for different axes.
Definition: UT_Vector3.h:562
const UT_VoxelArrayI * field() const
SYS_FORCE_INLINE UT_Vector3I cellToEdgeMap(const UT_Vector3I &cell, const int edge_axis, const int edge_index)
SIM_RawField * stealField(int i, int j)
void setValue(UT_Vector3I index, T value)
SIM_RawField * stealField(int axis)
void forEachVoxelRange(const UT_Vector3I &start, const UT_Vector3I &end, const Functor &f)
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
SYS_FORCE_INLINE UT_Vector3I faceToCellMap(const UT_Vector3I &face, const int axis, const int direction)
GLuint start
Definition: glcorearb.h:475
UT_Vector3T< float > UT_Vector3
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
UT_Vector3 SIMfieldUtilsGetSizeNoSlice(const FIELDTYPE *field)
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
int64 exint
Definition: SYS_Types.h:125
const SIM_RawField * getField(int axis) const
Retrieve raw field.
UT_VoxelArrayF * fieldNC() const
Definition: SIM_RawField.h:507
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
#define SYSabs(a)
Definition: SYS_Math.h:1540
GLint y
Definition: glcorearb.h:103
This class holds a three dimensional scalar field.
UT_Vector3 SIMfieldUtilsGetDivisionsNoSlice(const FIELDTYPE *field)
void copyWithOffset(const UT_VoxelArray< T > &src, int offx, int offy, int offz)
UT_Vector3T< int64 > UT_Vector3I
void SIMfieldUtilsResizeKeepData(FIELDTYPE *field, UT_Vector3 size, UT_Vector3 center, bool keepdata, const char *address, int port)
float fpreal32
Definition: SYS_Types.h:200
SYS_FORCE_INLINE UT_Vector3I faceToEdgeMap(const UT_Vector3I &face, const int face_axis, const int edge_axis, const int direction)
SYS_FORCE_INLINE UT_Vector3I edgeToFaceMap(const UT_Vector3I &edge, const int edge_axis, const int face_axis, const int direction)
bool SIMfieldUtilsComputeSliceWithBorder(const UT_Vector3 &slice, const UT_Vector3 &totaldiv, UT_Vector3 overlapneg, UT_Vector3 overlappos, int slicenum, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
UT_Vector3 SIMfieldUtilsGetSize(const FIELDTYPE *field)
< returns > If no error
Definition: snippets.dox:2
SIM_RawIndexField * stealField()
SYS_FORCE_INLINE void setFieldValue(SIM_RawField &field, const UT_Vector3I &cell, fpreal32 value)
void moveTilesWithOffset(UT_VoxelArray< T > &src, int tileoffx, int tileoffy, int tileoffz)
void SIMfieldUtilsCopyWithOffset(SIM_IndexField *field, SIM_RawIndexField **raw, int offx, int offy, int offz, bool keepdata, UT_Vector3 olddivvec, UT_Vector3 newdivvec, const char *address, int port)
GLfloat f
Definition: glcorearb.h:1926
void SIMfieldUtilsMatch(FIELDTYPE *field, const F2 *srcfield)
GLintptr offset
Definition: glcorearb.h:665
SYS_FORCE_INLINE UT_Vector3I cellToCellMap(const UT_Vector3I &cell, const int axis, const int direction)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
UT_Vector3 SIMfieldUtilsGetDivisions(const FIELDTYPE *field)
SYS_FORCE_INLINE UT_Vector3I nodeToCellMap(const UT_Vector3I &node, const int cell_index)
GLuint GLuint end
Definition: glcorearb.h:475
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
Definition: UT_Vector3.h:1057
SYS_FORCE_INLINE fpreal32 getFieldValue(const SIM_RawField &field, const UT_Vector3I &cell)
void SIMfieldUtilsExchangeFields(const char *address, int port, RAWFIELD *dest, RAWFIELD *src, int slicenum, int offx, int offy, int offz, UT_Vector3 olddiv, UT_Vector3 newdiv, UT_Vector3 slicediv, UT_Vector3 overlapneg, UT_Vector3 overlappos)
SIM_RawField * stealField()
This class holds a three dimensional tensor field.
GLint GLenum GLint x
Definition: glcorearb.h:409
bool SIMfieldUtilsGetSliceBorder(const FIELDTYPE *field, int a_slice, int b_slice, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
fpreal32 SYSrint(fpreal32 val)
Definition: SYS_Floor.h:163
UT_Vector3 SIMfieldUtilsGetCenter(const FIELDTYPE *field)
SYS_FORCE_INLINE UT_Vector3I faceToNodeMap(const UT_Vector3I &face, const int face_axis, const int node_index)
bool SYSequalZero(const UT_Vector3T< T > &v)
Definition: UT_Vector3.h:1069
bool SIMfieldUtilsComputeSlice(const FIELDTYPE *field, const UT_Vector3 &totaldiv, int slicenum, UT_Vector3 &minvxl, UT_Vector3 &maxvxl)
GLint j
Definition: glad.h:2733
const SIM_RawField * getField() const
Retrieve raw field.
GLsizeiptr size
Definition: glcorearb.h:664
fpreal64 fpreal
Definition: SYS_Types.h:277
constexpr SYS_FORCE_INLINE bool isEqual(const UT_Vector3T &b, const T tolerance=SYS_FTOLERANCE) const noexcept
Definition: UT_Vector3.h:403
SYS_FORCE_INLINE bool UTisstring(const char *s)
SYS_FORCE_INLINE UT_Vector3I cellToFaceMap(const UT_Vector3I &cell, const int axis, const int direction)
SYS_FORCE_INLINE UT_Vector3I edgeToCellMap(const UT_Vector3I &edge, const int edge_axis, const int cell_index)
const SIM_RawIndexField * getField() const
Retrieve raw field.
This class holds a three dimensional scalar field.
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
UT_VoxelArrayI * fieldNC() const
Definition: core.h:1131
bool SIMfieldUtilsIsColocated(const FIELDTYPE1 *field1, const FIELDTYPE2 *field2, UT_Vector3I &offset)
SYS_FORCE_INLINE UT_Vector3I nodeToFaceMap(const UT_Vector3I &node, const int face_axis, const int face_index)
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
bool SYSisEqual(const UT_Vector2T< T > &a, const UT_Vector2T< T > &b, S tol=SYS_FTOLERANCE)
Componentwise equality.
Definition: UT_Vector2.h:674
const SIM_RawField * getField(int i, int j) const
Retrieve raw field.
This class holds a three dimensional vector field.
UT_VoxelArrayF UT_VoxelArrayF & field
GLenum src
Definition: glcorearb.h:1793
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663