1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
26 University of Massachusetts Amherst
28 \*---------------------------------------------------------------------------*/
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 // Compute clip-planes
36 inline void tetIntersection::computeClipPlanes()
38 // Define edge vectors
39 vector edge10 = clipTet_[1] - clipTet_[0];
40 vector edge20 = clipTet_[2] - clipTet_[0];
41 vector edge30 = clipTet_[3] - clipTet_[0];
42 vector edge21 = clipTet_[2] - clipTet_[1];
43 vector edge31 = clipTet_[3] - clipTet_[1];
46 clipPlanes_[0].first() = (edge20 ^ edge10);
47 clipPlanes_[1].first() = (edge10 ^ edge30);
48 clipPlanes_[2].first() = (edge30 ^ edge20);
49 clipPlanes_[3].first() = (edge21 ^ edge31);
52 clipPlanes_[0].first() /= mag(clipPlanes_[0].first()) + VSMALL;
53 clipPlanes_[1].first() /= mag(clipPlanes_[1].first()) + VSMALL;
54 clipPlanes_[2].first() /= mag(clipPlanes_[2].first()) + VSMALL;
55 clipPlanes_[3].first() /= mag(clipPlanes_[3].first()) + VSMALL;
57 // Compute magnitude of clipping tetrahedron
58 clipTetMag_ = (1.0 / 6.0) * (edge10 & clipPlanes_[3].first());
60 if (clipTetMag_ < 0.0)
62 // Reverse normal directions
63 clipPlanes_[0].first() = -clipPlanes_[0].first();
64 clipPlanes_[1].first() = -clipPlanes_[1].first();
65 clipPlanes_[2].first() = -clipPlanes_[2].first();
66 clipPlanes_[3].first() = -clipPlanes_[3].first();
69 clipTetMag_ = mag(clipTetMag_);
72 // Determine plane constants
73 clipPlanes_[0].second() = (clipTet_[0] & clipPlanes_[0].first());
74 clipPlanes_[1].second() = (clipTet_[1] & clipPlanes_[1].first());
75 clipPlanes_[2].second() = (clipTet_[2] & clipPlanes_[2].first());
76 clipPlanes_[3].second() = (clipTet_[3] & clipPlanes_[3].first());
80 // Split and decompose
81 inline void tetIntersection::splitAndDecompose
83 const label tetPlaneIndex,
84 FixedList<point, 4>& tetra,
85 DynamicList<FixedList<point, 4> >& decompTets
88 FixedList<scalar, 4> C;
89 FixedList<vector, 4> tmpTetra;
90 FixedList<label, 4> pos, neg, zero;
91 label i = 0, nPos = 0, nNeg = 0, nZero = 0;
93 // Fetch reference to plane
94 const hPlane& tetPlane = clipPlanes_[tetPlaneIndex];
96 for (i = 0; i < 4; ++i)
98 // Compute distance to plane
99 C[i] = (tetra[i] & tetPlane.first()) - tetPlane.second();
123 decompTets.append(tetra);
127 // Tetrahedron is split by plane. Determine how it is split and how to
128 // decompose the negative-side portion into tetrahedra (6 cases).
129 scalar w0, w1, invCDiff;
135 for (i = 0; i < nPos; ++i)
137 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
139 w0 = -C[neg[0]] * invCDiff;
140 w1 = +C[pos[i]] * invCDiff;
142 tetra[pos[i]] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
145 decompTets.append(tetra);
153 for (i = 0; i < nPos; ++i)
155 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
157 w0 = -C[neg[0]] * invCDiff;
158 w1 = +C[pos[i]] * invCDiff;
160 intp[i] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
163 for (i = 0; i < nNeg; ++i)
165 invCDiff = (1.0 / (C[pos[i]] - C[neg[1]]));
167 w0 = -C[neg[1]] * invCDiff;
168 w1 = +C[pos[i]] * invCDiff;
170 intp[i+2] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[1]]);
173 tetra[pos[0]] = intp[2];
174 tetra[pos[1]] = intp[1];
176 decompTets.append(tetra);
178 tmpTetra[0] = tetra[neg[1]];
179 tmpTetra[1] = intp[3];
180 tmpTetra[2] = intp[2];
181 tmpTetra[3] = intp[1];
183 decompTets.append(tmpTetra);
185 tmpTetra[0] = tetra[neg[0]];
186 tmpTetra[1] = intp[0];
187 tmpTetra[2] = intp[1];
188 tmpTetra[3] = intp[2];
190 decompTets.append(tmpTetra);
195 for (i = 0; i < nPos; ++i)
197 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
199 w0 = -C[neg[0]] * invCDiff;
200 w1 = +C[pos[i]] * invCDiff;
202 tetra[pos[i]] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
205 decompTets.append(tetra);
214 for (i = 0; i < nNeg; ++i)
216 invCDiff = (1.0 / (C[pos[0]] - C[neg[i]]));
218 w0 = -C[neg[i]] * invCDiff;
219 w1 = +C[pos[0]] * invCDiff;
221 intp[i] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[i]]);
224 tetra[pos[0]] = intp[0];
226 decompTets.append(tetra);
228 tmpTetra[0] = intp[0];
229 tmpTetra[1] = tetra[neg[1]];
230 tmpTetra[2] = tetra[neg[2]];
231 tmpTetra[3] = intp[1];
233 decompTets.append(tmpTetra);
235 tmpTetra[0] = tetra[neg[2]];
236 tmpTetra[1] = intp[1];
237 tmpTetra[2] = intp[2];
238 tmpTetra[3] = intp[0];
240 decompTets.append(tmpTetra);
246 for (i = 0; i < nNeg; ++i)
248 invCDiff = (1.0 / (C[pos[0]] - C[neg[i]]));
250 w0 = -C[neg[i]] * invCDiff;
251 w1 = +C[pos[0]] * invCDiff;
253 intp[i] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[i]]);
256 tetra[pos[0]] = intp[0];
258 decompTets.append(tetra);
260 tmpTetra[0] = intp[1];
261 tmpTetra[1] = tetra[zero[0]];
262 tmpTetra[2] = tetra[neg[1]];
263 tmpTetra[3] = intp[0];
265 decompTets.append(tmpTetra);
270 invCDiff = (1.0 / (C[pos[0]] - C[neg[0]]));
272 w0 = -C[neg[0]] * invCDiff;
273 w1 = +C[pos[0]] * invCDiff;
275 tetra[pos[0]] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[0]]);
277 decompTets.append(tetra);
283 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
285 inline tetIntersection::tetIntersection(const FixedList<point, 4>& clipTet)
292 // Pre-compute clipping planes
297 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
299 inline tetIntersection::~tetIntersection()
303 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
305 // Return magnitude of clipping tetrahedron
306 inline scalar tetIntersection::clipTetMag() const
312 // Evaluate for intersections
313 inline bool tetIntersection::evaluate(const FixedList<point, 4>& subjectTet)
319 // Add initial tetrahedron to list
320 allTets_.append(subjectTet);
322 // Clip second tetrahedron against planes of clipping tetrahedron
323 for (label i = 0; i < 4; i++)
325 forAll(allTets_, tetI)
327 splitAndDecompose(i, allTets_[tetI], inside_);
330 // Prep for next clipping plane
335 return (allTets_.size() > 0);
339 // Return intersections
340 inline const DynamicList<FixedList<point, 4> >&
341 tetIntersection::getIntersection() const
347 //- Evaluate and return volume / centroid
348 inline void tetIntersection::getVolumeAndCentre
355 centre = vector::zero;
357 forAll(allTets_, tetI)
359 const FixedList<point, 4>& t = allTets_[tetI];
361 // Calculate volume (no check for orientation)
368 ((t[1] - t[0]) ^ (t[2] - t[0])) & (t[3] - t[0])
373 // Calculate centroid
374 vector tC = (0.25 * (t[0] + t[1] + t[2] + t[3]));
380 centre /= volume + VSMALL;
386 // ************************************************************************* //