PeriDyno 1.0.0
Loading...
Searching...
No Matches
FastSweepingMethod.cpp
Go to the documentation of this file.
2
3namespace dyno
4{
6
7 template<typename TDataType>
12
13 template<typename TDataType>
15 {
16 faceList.clear();
17 vertList.clear();
18 phi.clear();
19 }
20
21 template<typename TDataType>
23 {
24 this->loadClosedSurface();
25
26 if (this->outLevelSet()->isEmpty()) {
27 this->outLevelSet()->allocate();
28 }
29 DistanceField3D<TDataType>& sdf = this->outLevelSet()->getDataPtr()->getSDF();
30
31 Coord p0(origin.x, origin.y, origin.z);
32 Coord p1(maxPoint.x, maxPoint.y, maxPoint.z);
33
34 sdf.setSpace(p0, p1, this->varSpacing()->getValue());
35 sdf.setDistance(phi);
36 }
37
38 template<typename TDataType>
40 {
41 Vec3f min_box(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
42 Vec3f max_box(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
43
44 auto& mPoints = inTriangleSet()->getDataPtr()->getPoints();
45 auto& mTriangles = inTriangleSet()->getDataPtr()->getTriangles();
46
47 CArray<Coord> cPoints;
48 cPoints.assign(mPoints);
49
51 cTriangles.resize(mTriangles.size());
52 cTriangles.assign(mTriangles);
53
54 vertList.clear();
55 faceList.clear();
56
57 for (int i = 0; i < cPoints.size(); i++) {
58 Coord point = cPoints[i];
59 vertList.pushBack(point);
60 min_box = min_box.minimum(point);
61 max_box = max_box.maximum(point);
62 }
63
64 for (int i = 0; i < cTriangles.size(); i++) {
65 faceList.pushBack(Vec3ui(cTriangles[i][0], cTriangles[i][1], cTriangles[i][2]));
66 }
67
68 Real dx = this->varSpacing()->getValue();
69 uint padding = this->varPadding()->getValue();
70
71 Vec3f unit(1, 1, 1);
72 min_box -= padding * dx * unit;
73 max_box += padding * dx * unit;
74
75 ni = std::floor((max_box[0] - min_box[0]) / dx);
76 nj = std::floor((max_box[1] - min_box[1]) / dx);
77 nk = std::floor((max_box[2] - min_box[2]) / dx);
78
79 origin = min_box;
80 maxPoint = max_box;
81
83
84 cPoints.clear();
85 cTriangles.clear();
86 printf("Uniform grids: %f %f %f, %f %f %f, %f, %d %d %d, %d \n", origin[0], origin[1], origin[2], maxPoint[0], maxPoint[1], maxPoint[2], dx, ni, nj, nk, padding);
87 }
88
89 // find distance x0 is from segment x1-x2
90 static float point_segment_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2)
91 {
92 Vec3f dx(x2 - x1);
93 double m2 = dx.normSquared();
94 // find parameter value of closest point on segment
95 float s12 = (float)((x2 - x0).dot(dx) / m2);
96 if (s12 < 0) {
97 s12 = 0;
98 }
99 else if (s12 > 1) {
100 s12 = 1;
101 }
102 // and find the distance
103 return (x0 - (s12*x1 + (1 - s12)*x2)).norm();
104 }
105
106 // find distance x0 is from triangle x1-x2-x3
107 static float point_triangle_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2, const Vec3f &x3)
108 {
109 // first find barycentric coordinates of closest point on infinite plane
110 Vec3f x13(x1 - x3), x23(x2 - x3), x03(x0 - x3);
111 float m13 = x13.normSquared(), m23 = x23.normSquared(), d = x13.dot(x23);
112 float invdet = 1.f / std::max(m13*m23 - d * d, 1e-30f);
113 float a = x13.dot(x03), b = x23.dot(x03);
114 // the barycentric coordinates themselves
115 float w23 = invdet * (m23*a - d * b);
116 float w31 = invdet * (m13*b - d * a);
117 float w12 = 1 - w23 - w31;
118 if (w23 >= 0 && w31 >= 0 && w12 >= 0) { // if we're inside the triangle
119 return (x0 - (w23*x1 + w31 * x2 + w12 * x3)).norm();
120 }
121 else { // we have to clamp to one of the edges
122 if (w23 > 0) // this rules out edge 2-3 for us
123 return std::min(point_segment_distance(x0, x1, x2), point_segment_distance(x0, x1, x3));
124 else if (w31 > 0) // this rules out edge 1-3
125 return std::min(point_segment_distance(x0, x1, x2), point_segment_distance(x0, x2, x3));
126 else // w12 must be >0, ruling out edge 1-2
127 return std::min(point_segment_distance(x0, x1, x3), point_segment_distance(x0, x2, x3));
128 }
129 }
130
131 static void FSM_CheckNeighbour(const CArray<Vec3ui> &tri, const CArray<Vec3f> &vert,
132 CArray3f &phi, CArray3i &closest_tri,
133 const Vec3f &gx, int i0, int j0, int k0, int i1, int j1, int k1)
134 {
135 if (closest_tri(i1, j1, k1) >= 0) {
136 unsigned int p, q, r;
137 Vec3ui trijk = tri[closest_tri(i1, j1, k1)];
138 p = trijk[0];
139 q = trijk[1];
140 r = trijk[2];
141 float d = point_triangle_distance(gx, vert[p], vert[q], vert[r]);
142 if (d < phi(i0, j0, k0)) {
143 phi(i0, j0, k0) = d;
144 closest_tri(i0, j0, k0) = closest_tri(i1, j1, k1);
145 }
146 }
147 }
148
149 static void sweep(const CArray<Vec3ui> &tri, const CArray<Vec3f> &x,
150 CArray3f &phi, CArray3i &closest_tri, const Vec3f &origin, float dx,
151 int di, int dj, int dk)
152 {
153 int i0, i1;
154 if (di > 0) {
155 i0 = 1; i1 = phi.nx();
156 }
157 else {
158 i0 = phi.nx() - 2; i1 = -1;
159 }
160 int j0, j1;
161 if (dj > 0) {
162 j0 = 1; j1 = phi.ny();
163 }
164 else {
165 j0 = phi.ny() - 2; j1 = -1;
166 }
167 int k0, k1;
168 if (dk > 0) {
169 k0 = 1; k1 = phi.nz();
170 }
171 else {
172 k0 = phi.nz() - 2; k1 = -1;
173 }
174 for (int k = k0; k != k1; k += dk) for (int j = j0; j != j1; j += dj) for (int i = i0; i != i1; i += di) {
175 Vec3f gx(i*dx + origin[0], j*dx + origin[1], k*dx + origin[2]);
176 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i - di, j, k);
177 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j - dj, k);
178 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i - di, j - dj, k);
179 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j, k - dk);
180 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i - di, j, k - dk);
181 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i, j - dj, k - dk);
182 FSM_CheckNeighbour(tri, x, phi, closest_tri, gx, i, j, k, i - di, j - dj, k - dk);
183 }
184 }
185
186 // calculate twice signed area of triangle (0,0)-(x1,y1)-(x2,y2)
187 // return an SOS-determined sign (-1, +1, or 0 only if it's a truly degenerate triangle)
188 static int orientation(double x1, double y1, double x2, double y2, double &twice_signed_area)
189 {
190 twice_signed_area = y1 * x2 - x1 * y2;
191 if (twice_signed_area > 0) return 1;
192 else if (twice_signed_area < 0) return -1;
193 else if (y2 > y1) return 1;
194 else if (y2 < y1) return -1;
195 else if (x1 > x2) return 1;
196 else if (x1 < x2) return -1;
197 else return 0; // only true when x1==x2 and y1==y2
198 }
199
200 // robust test of (x0,y0) in the triangle (x1,y1)-(x2,y2)-(x3,y3)
201 // if true is returned, the barycentric coordinates are set in a,b,c.
202 static bool point_in_triangle_2d(double x0, double y0,
203 double x1, double y1, double x2, double y2, double x3, double y3,
204 double& a, double& b, double& c)
205 {
206 x1 -= x0; x2 -= x0; x3 -= x0;
207 y1 -= y0; y2 -= y0; y3 -= y0;
208 int signa = orientation(x2, y2, x3, y3, a);
209 if (signa == 0) return false;
210 int signb = orientation(x3, y3, x1, y1, b);
211 if (signb != signa) return false;
212 int signc = orientation(x1, y1, x2, y2, c);
213 if (signc != signa) return false;
214 double sum = a + b + c;
215 assert(sum != 0); // if the SOS signs match and are nonkero, there's no way all of a, b, and c are zero.
216 a /= sum;
217 b /= sum;
218 c /= sum;
219 return true;
220 }
221
222#define TRI_MIN(x, y, z) std::min(x, std::min(y, z))
223#define TRI_MAX(x, y, z) std::max(x, std::max(y, z))
224
225 template<typename TDataType>
227 {
228 const int exact_band = 1;
229 Real dx = this->varSpacing()->getValue();
230
231 phi.resize(ni, nj, nk);
232 phi.assign((ni + nj + nk)*dx);
233 //TODO: phi.assign((ni + nj + nk)*dx); // upper bound on distance
234 CArray3i closest_tri(ni, nj, nk);//CArray3i closest_tri(ni, nj, nk, -1);
235 closest_tri.assign(-1);
236 CArray3i intersection_count(ni, nj, nk); //CArray3i intersection_count(ni, nj, nk, 0); // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k}
237 intersection_count.assign(0);
238 // we begin by initializing distances near the mesh, and figuring out intersection counts
239 for (uint t = 0; t < faceList.size(); ++t) {
240 uint p, q, r;
241 p = faceList[t][0];
242 q = faceList[t][1];
243 r = faceList[t][2];
244 // coordinates in grid to high precision
245 double fip = ((double)vertList[p][0] - origin[0]) / dx;
246 double fjp = ((double)vertList[p][1] - origin[1]) / dx;
247 double fkp = ((double)vertList[p][2] - origin[2]) / dx;
248 double fiq = ((double)vertList[q][0] - origin[0]) / dx;
249 double fjq = ((double)vertList[q][1] - origin[1]) / dx;
250 double fkq = ((double)vertList[q][2] - origin[2]) / dx;
251 double fir = ((double)vertList[r][0] - origin[0]) / dx;
252 double fjr = ((double)vertList[r][1] - origin[1]) / dx;
253 double fkr = ((double)vertList[r][2] - origin[2]) / dx;
254 // do distances nearby
255 int i0 = clamp(int(TRI_MIN(fip, fiq, fir)) - exact_band, 0, ni - 1);
256 int i1 = clamp(int(TRI_MAX(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
257 int j0 = clamp(int(TRI_MIN(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
258 int j1 = clamp(int(TRI_MAX(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
259 int k0 = clamp(int(TRI_MIN(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
260 int k1 = clamp(int(TRI_MAX(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);
261 for (int k = k0; k <= k1; ++k) for (int j = j0; j <= j1; ++j) for (int i = i0; i <= i1; ++i) {
262 Vec3f gx(i*dx + origin[0], j*dx + origin[1], k*dx + origin[2]);
263 float d = point_triangle_distance(gx, vertList[p], vertList[q], vertList[r]);
264 if (d < phi(i, j, k)) {
265 phi(i, j, k) = d;
266 closest_tri(i, j, k) = t;
267 }
268 }
269 // and do intersection counts
270 j0 = clamp((int)std::ceil(TRI_MIN(fjp, fjq, fjr)), 0, nj - 1);
271 j1 = clamp((int)std::floor(TRI_MAX(fjp, fjq, fjr)), 0, nj - 1);
272 k0 = clamp((int)std::ceil(TRI_MIN(fkp, fkq, fkr)), 0, nk - 1);
273 k1 = clamp((int)std::floor(TRI_MAX(fkp, fkq, fkr)), 0, nk - 1);
274 for (int k = k0; k <= k1; ++k) for (int j = j0; j <= j1; ++j) {
275 double a, b, c;
276 if (point_in_triangle_2d(j, k, fjp, fkp, fjq, fkq, fjr, fkr, a, b, c)) {
277 double fi = a * fip + b * fiq + c * fir; // intersection i coordinate
278 int i_interval = int(std::ceil(fi)); // intersection is in (i_interval-1,i_interval]
279 if (i_interval < 0) ++intersection_count(0, j, k); // we enlarge the first interval to include everything to the -x direction
280 else if (i_interval < ni) ++intersection_count(i_interval, j, k);
281 // we ignore intersections that are beyond the +x side of the grid
282 }
283 }
284 }
285 // and now we fill in the rest of the distances with fast sweeping
286 for (unsigned int pass = 0; pass < 2; ++pass) {
287 sweep(faceList, vertList, phi, closest_tri, origin, dx, +1, +1, +1);
288 sweep(faceList, vertList, phi, closest_tri, origin, dx, -1, -1, -1);
289 sweep(faceList, vertList, phi, closest_tri, origin, dx, +1, +1, -1);
290 sweep(faceList, vertList, phi, closest_tri, origin, dx, -1, -1, +1);
291 sweep(faceList, vertList, phi, closest_tri, origin, dx, +1, -1, +1);
292 sweep(faceList, vertList, phi, closest_tri, origin, dx, -1, +1, -1);
293 sweep(faceList, vertList, phi, closest_tri, origin, dx, +1, -1, -1);
294 sweep(faceList, vertList, phi, closest_tri, origin, dx, -1, +1, +1);
295 }
296 // then figure out signs (inside/outside) from intersection counts
297 for (int k = 0; k < nk; ++k) for (int j = 0; j < nj; ++j) {
298 int total_count = 0;
299 for (int i = 0; i < ni; ++i) {
300 total_count += intersection_count(i, j, k);
301 if (total_count % 2 == 1) { // if parity of intersections so far is odd,
302 phi(i, j, k) = -phi(i, j, k); // we are inside the mesh
303 }
304 }
305 }
306 }
307
309}
#define TRI_MAX(x, y, z)
#define TRI_MIN(x, y, z)
#define DEFINE_CLASS(name)
Definition Object.h:140
#define IMPLEMENT_TCLASS(name, T1)
Definition Object.h:103
assert(queueCount >=1)
void setDistance(CArray3D< Real > distance)
void setSpace(const Coord p0, const Coord p1, Real h)
This is a CPU-based implementation of grid-based signed distance field (level set) generator for tria...
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
static bool point_in_triangle_2d(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double &a, double &b, double &c)
static float point_segment_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2)
DYN_FUNC T dot(Vector< T, 2 > const &U, Vector< T, 2 > const &V)
Definition SimpleMath.h:199
CArray3D< int > CArray3i
static int orientation(double x1, double y1, double x2, double y2, double &twice_signed_area)
static float point_triangle_distance(const Vec3f &x0, const Vec3f &x1, const Vec3f &x2, const Vec3f &x3)
static void FSM_CheckNeighbour(const CArray< Vec3ui > &tri, const CArray< Vec3f > &vert, CArray3f &phi, CArray3i &closest_tri, const Vec3f &gx, int i0, int j0, int k0, int i1, int j1, int k1)
static void sweep(const CArray< Vec3ui > &tri, const CArray< Vec3f > &x, CArray3f &phi, CArray3i &closest_tri, const Vec3f &origin, float dx, int di, int dj, int dk)
Vector< unsigned int, 3 > Vec3ui
Vector< float, 3 > Vec3f
Definition Vector3D.h:93
DYN_FUNC T clamp(const T &v, const T &lo, const T &hi)
Definition SimpleMath.h:42
Array< T, DeviceType::CPU > CArray
Definition Array.h:151
unsigned int uint
Definition VkProgram.h:14
CArray3D< float > CArray3f