LevelSetUtils-Impl.h
Go to the documentation of this file.
1 /*************************************************************************
2 > File Name: LevelSetUtils-Impl.h
3 > Project Name: CubbyFlow
4 > Author: Chan-Ho Chris Ohk
5 > Purpose: Level set util functions for CubbyFlow.
6 > Created Time: 2017/07/13
7 > Copyright (c) 2018, Chan-Ho Chris Ohk
8 *************************************************************************/
9 
10 // Function fractionInside is originally from Christopher Batty's code:
11 //
12 // http://www.cs.ubc.ca/labs/imager/tr/2007/Batty_VariationalFluids/
13 //
14 // and
15 //
16 // https://github.com/christopherbatty/Fluid3D
17 
18 #ifndef CUBBYFLOW_LEVEL_SET_UTILS_IMPL_H
19 #define CUBBYFLOW_LEVEL_SET_UTILS_IMPL_H
20 
21 #include <Core/Utils/Constants.h>
22 
23 #include <algorithm>
24 #include <cmath>
25 
26 namespace CubbyFlow
27 {
28  template <typename T>
29  bool IsInsideSDF(T phi)
30  {
31  return phi < 0;
32  }
33 
34  template <typename T>
35  inline T SmearedHeavisideSDF(T phi)
36  {
37  if (phi > 1.5)
38  {
39  return 1;
40  }
41 
42  if (phi < -1.5)
43  {
44  return 0;
45  }
46 
47  return 0.5f + phi / 3.0 + 0.5f * (1 / PI<T>()) * std::sin(PI<T>() * phi / 1.5);
48  }
49 
50  template <typename T>
51  inline T SmearedDeltaSDF(T phi)
52  {
53  if (std::fabs(phi) > 1.5)
54  {
55  return 0;
56  }
57 
58  return 1.0 / 3.0 + 1.0 / 3.0 * std::cos(PI<T>() * phi / 1.5);
59  }
60 
61  template <typename T>
62  T FractionInsideSDF(T phi0, T phi1)
63  {
64  if (IsInsideSDF(phi0) && IsInsideSDF(phi1))
65  {
66  return 1;
67  }
68 
69  if (IsInsideSDF(phi0) && !IsInsideSDF(phi1))
70  {
71  return phi0 / (phi0 - phi1);
72  }
73 
74  if (!IsInsideSDF(phi0) && IsInsideSDF(phi1))
75  {
76  return phi1 / (phi1 - phi0);
77  }
78 
79  return 0;
80  }
81 
82  template <typename T>
83  void CycleArray(T* arr, int size)
84  {
85  T t = arr[0];
86 
87  for (int i = 0; i < size - 1; ++i)
88  {
89  arr[i] = arr[i + 1];
90  }
91 
92  arr[size - 1] = t;
93  }
94 
95  template <typename T>
96  T FractionInside(T phiBottomLeft, T phiBottomRight, T phiTopLeft, T phiTopRight)
97  {
98  int insideCount = (phiBottomLeft < 0 ? 1 : 0) + (phiTopLeft < 0 ? 1 : 0) + (phiBottomRight < 0 ? 1 : 0) + (phiTopRight < 0 ? 1 : 0);
99  T list[] = { phiBottomLeft, phiBottomRight, phiTopRight, phiTopLeft };
100 
101  if (insideCount == 4)
102  {
103  return 1;
104  }
105 
106  if (insideCount == 3)
107  {
108  // Rotate until the positive value is in the first position
109  while (list[0] < 0)
110  {
111  CycleArray(list, 4);
112  }
113 
114  // Work out the area of the exterior triangle
115  T side0 = 1 - FractionInsideSDF(list[0], list[3]);
116  T side1 = 1 - FractionInsideSDF(list[0], list[1]);
117 
118  return 1 - 0.5f * side0 * side1;
119  }
120 
121  if (insideCount == 2)
122  {
123  // Rotate until a negative value is in the first position, and the next
124  // negative is in either slot 1 or 2.
125  while (list[0] >= 0 || !(list[1] < 0 || list[2] < 0))
126  {
127  CycleArray(list, 4);
128  }
129 
130  // The matching signs are adjacent
131  if (list[1] < 0)
132  {
133  T side_left = FractionInsideSDF(list[0], list[3]);
134  T side_right = FractionInsideSDF(list[1], list[2]);
135 
136  return 0.5f * (side_left + side_right);
137  }
138 
139  // Matching signs are diagonally opposite
140  // determine the center point's sign to disambiguate this case
141  T middle_point = 0.25f * (list[0] + list[1] + list[2] + list[3]);
142  if (middle_point < 0)
143  {
144  T area = 0;
145 
146  // First triangle (top left)
147  T side1 = 1 - FractionInsideSDF(list[0], list[3]);
148  T side3 = 1 - FractionInsideSDF(list[2], list[3]);
149 
150  area += 0.5f * side1 * side3;
151 
152  // Second triangle (top right)
153  T side2 = 1 - FractionInsideSDF(list[2], list[1]);
154  T side0 = 1 - FractionInsideSDF(list[0], list[1]);
155 
156  area += 0.5f * side0 * side2;
157 
158  return 1 - area;
159  }
160 
161  T area = 0;
162 
163  // First triangle (bottom left)
164  T side0 = FractionInsideSDF(list[0], list[1]);
165  T side1 = FractionInsideSDF(list[0], list[3]);
166  area += 0.5f * side0 * side1;
167 
168  // Second triangle (top right)
169  T side2 = FractionInsideSDF(list[2], list[1]);
170  T side3 = FractionInsideSDF(list[2], list[3]);
171  area += 0.5f * side2 * side3;
172  return area;
173  }
174 
175  if (insideCount == 1)
176  {
177  // Rotate until the negative value is in the first position
178  while (list[0] >= 0)
179  {
180  CycleArray(list, 4);
181  }
182 
183  // Work out the area of the interior triangle, and subtract from 1.
184  T side0 = FractionInsideSDF(list[0], list[3]);
185  T side1 = FractionInsideSDF(list[0], list[1]);
186 
187  return 0.5f * side0 * side1;
188  }
189 
190  return 0;
191  }
192 
193  template <typename T>
194  T DistanceToZeroLevelSet(T phi0, T phi1)
195  {
196  if (std::fabs(phi0) + std::fabs(phi1) > std::numeric_limits<double>::epsilon())
197  {
198  return std::fabs(phi0) / (std::fabs(phi0) + std::fabs(phi1));
199  }
200 
201  return static_cast<T>(0.5);
202  }
203 }
204 
205 #endif
T FractionInside(T phiBottomLeft, T phiBottomRight, T phiTopLeft, T phiTopRight)
Returns the fraction occupied by the implicit surface.
Definition: LevelSetUtils-Impl.h:96
bool IsInsideSDF(T phi)
Returns true if phi is inside the implicit surface (< 0).
Definition: LevelSetUtils-Impl.h:29
T FractionInsideSDF(T phi0, T phi1)
Returns the fraction occupied by the implicit surface.
Definition: LevelSetUtils-Impl.h:62
void CycleArray(T *arr, int size)
Definition: LevelSetUtils-Impl.h:83
T SmearedHeavisideSDF(T phi)
Returns smeared Heaviside function.
Definition: LevelSetUtils-Impl.h:35
Definition: pybind11Utils.h:24
T DistanceToZeroLevelSet(T phi0, T phi1)
Definition: LevelSetUtils-Impl.h:194
T SmearedDeltaSDF(T phi)
Returns smeared delta function.
Definition: LevelSetUtils-Impl.h:51