iMSTK
Interactive Medical Simulation Toolkit
imstkSignedDistanceField.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkSignedDistanceField.h"
8 #include "imstkDataArray.h"
9 #include "imstkImageData.h"
10 #include "imstkLogger.h"
11 
12 namespace imstk
13 {
18 template<typename T>
19 static T
20 trilinearSample(const Vec3d& structuredPt, T* imgPtr, const Vec3i& dim, const int numComps, const int comp)
21 {
22  // minima of voxel, clamped to bounds
23  const Vec3i s1 = structuredPt.cast<int>().cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
24 
25  // maxima of voxel, clamped to bounds
26  const Vec3i s2 = (structuredPt.cast<int>() + Vec3i(1, 1, 1)).cwiseMax(0).cwiseMin(dim - Vec3i(1, 1, 1));
27 
28  const size_t index000 = ImageData::getScalarIndex(s1.x(), s1.y(), s1.z(), dim, numComps) + comp;
29  const size_t index100 = ImageData::getScalarIndex(s2.x(), s1.y(), s1.z(), dim, numComps) + comp;
30  const size_t index110 = ImageData::getScalarIndex(s2.x(), s2.y(), s1.z(), dim, numComps) + comp;
31  const size_t index010 = ImageData::getScalarIndex(s1.x(), s2.y(), s1.z(), dim, numComps) + comp;
32  const size_t index001 = ImageData::getScalarIndex(s1.x(), s1.y(), s2.z(), dim, numComps) + comp;
33  const size_t index101 = ImageData::getScalarIndex(s2.x(), s1.y(), s2.z(), dim, numComps) + comp;
34  const size_t index111 = ImageData::getScalarIndex(s2.x(), s2.y(), s2.z(), dim, numComps) + comp;
35  const size_t index011 = ImageData::getScalarIndex(s1.x(), s2.y(), s2.z(), dim, numComps) + comp;
36 
37  const double val000 = static_cast<double>(imgPtr[index000]);
38  const double val100 = static_cast<double>(imgPtr[index100]);
39  const double val110 = static_cast<double>(imgPtr[index110]);
40  const double val010 = static_cast<double>(imgPtr[index010]);
41 
42  const double val001 = static_cast<double>(imgPtr[index001]);
43  const double val101 = static_cast<double>(imgPtr[index101]);
44  const double val111 = static_cast<double>(imgPtr[index111]);
45  const double val011 = static_cast<double>(imgPtr[index011]);
46 
47  // Interpolants
48  //const Vec3d t = s2.cast<double>() - structuredPt;
49  const Vec3d t = structuredPt - s2.cast<double>();
50 
51  // Interpolate along x
52  const double ax = val000 + (val100 - val000) * t[0];
53  const double bx = val010 + (val110 - val010) * t[0];
54 
55  const double dx = val001 + (val101 - val001) * t[0];
56  const double ex = val011 + (val111 - val011) * t[0];
57 
58  // Interpolate along y
59  const double cy = ax + (bx - ax) * t[1];
60  const double fy = dx + (ex - dx) * t[1];
61 
62  // Interpolate along z
63  const double gz = cy + (fy - cy) * t[2];
64 
65  return static_cast<T>(gz);
66 }
67 
68 SignedDistanceField::SignedDistanceField(std::shared_ptr<ImageData> imageData) :
69  m_imageDataSdf(imageData), m_scale(1.0)
70 {
71  m_invSpacing = m_imageDataSdf->getInvSpacing();
72  m_bounds = m_imageDataSdf->getBounds();
73  m_shift = m_imageDataSdf->getOrigin() - m_imageDataSdf->getSpacing() * 0.5;
74 
75  m_scalars = std::dynamic_pointer_cast<DataArray<double>>(m_imageDataSdf->getScalars());
76 
77  CHECK(m_scalars != nullptr)
78  << "SignedDistanceField requires doubles in the input image";
79 
80  // \todo: Verify the SDF distances
81 }
82 
83 double
85 {
86  // origin at center of first voxel
87  if (pos[0] < m_bounds[1] && pos[0] > m_bounds[0]
88  && pos[1] < m_bounds[3] && pos[1] > m_bounds[2]
89  && pos[2] < m_bounds[5] && pos[2] > m_bounds[4])
90  {
91  const Vec3d structuredPt = (pos - m_shift).cwiseProduct(m_invSpacing);
92  return trilinearSample(structuredPt, m_scalars->getPointer(), m_imageDataSdf->getDimensions(), 1, 0) * m_scale;
93  }
94  else
95  {
96  // If outside of the bounds, return positive (assume not inside)
97  return IMSTK_DOUBLE_MAX;
98  }
99 }
100 
101 void
102 SignedDistanceField::computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent)
103 {
104  return m_imageDataSdf->computeBoundingBox(min, max, paddingPercent);
105 }
106 } // namespace imstk
SignedDistanceField(std::shared_ptr< ImageData > imageData)
Constructor.
size_t getScalarIndex(int x, int y, int z=0)
Returns index of data in scalar array given structured image coordinate, does no bounds checking...
Compound Geometry.
void computeBoundingBox(Vec3d &min, Vec3d &max, const double paddingPercent) override
Compute the bounding box for the geometry.
double getFunctionValue(const Vec3d &pos) const
Returns signed distance to surface at pos, returns clamped/nearest if out of bounds.