1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM 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 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 University of Massachusetts Amherst
29 \*---------------------------------------------------------------------------*/
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 // Compute clip-planes
37 inline void tetIntersection::computeClipPlanes()
39 // Define edge vectors
40 vector edge10 = clipTet_[1] - clipTet_[0];
41 vector edge20 = clipTet_[2] - clipTet_[0];
42 vector edge30 = clipTet_[3] - clipTet_[0];
43 vector edge21 = clipTet_[2] - clipTet_[1];
44 vector edge31 = clipTet_[3] - clipTet_[1];
47 clipPlanes_[0].first() = (edge20 ^ edge10);
48 clipPlanes_[1].first() = (edge10 ^ edge30);
49 clipPlanes_[2].first() = (edge30 ^ edge20);
50 clipPlanes_[3].first() = (edge21 ^ edge31);
53 clipPlanes_[0].first() /= mag(clipPlanes_[0].first()) + VSMALL;
54 clipPlanes_[1].first() /= mag(clipPlanes_[1].first()) + VSMALL;
55 clipPlanes_[2].first() /= mag(clipPlanes_[2].first()) + VSMALL;
56 clipPlanes_[3].first() /= mag(clipPlanes_[3].first()) + VSMALL;
58 // Compute magnitude of clipping tetrahedron
59 clipTetMag_ = (1.0 / 6.0) * (edge10 & clipPlanes_[3].first());
61 if (clipTetMag_ < 0.0)
63 // Reverse normal directions
64 clipPlanes_[0].first() = -clipPlanes_[0].first();
65 clipPlanes_[1].first() = -clipPlanes_[1].first();
66 clipPlanes_[2].first() = -clipPlanes_[2].first();
67 clipPlanes_[3].first() = -clipPlanes_[3].first();
70 clipTetMag_ = mag(clipTetMag_);
73 // Determine plane constants
74 clipPlanes_[0].second() = (clipTet_[0] & clipPlanes_[0].first());
75 clipPlanes_[1].second() = (clipTet_[1] & clipPlanes_[1].first());
76 clipPlanes_[2].second() = (clipTet_[2] & clipPlanes_[2].first());
77 clipPlanes_[3].second() = (clipTet_[3] & clipPlanes_[3].first());
81 // Split and decompose
82 inline void tetIntersection::splitAndDecompose
84 const label tetPlaneIndex,
85 FixedList<point, 4>& tetra,
86 DynamicList<FixedList<point, 4> >& decompTets
89 FixedList<scalar, 4> C;
90 FixedList<vector, 4> tmpTetra;
91 FixedList<label, 4> pos, neg, zero;
92 label i = 0, nPos = 0, nNeg = 0, nZero = 0;
94 // Fetch reference to plane
95 const hPlane& tetPlane = clipPlanes_[tetPlaneIndex];
97 for (i = 0; i < 4; ++i)
99 // Compute distance to plane
100 C[i] = (tetra[i] & tetPlane.first()) - tetPlane.second();
124 decompTets.append(tetra);
128 // Tetrahedron is split by plane. Determine how it is split and how to
129 // decompose the negative-side portion into tetrahedra (6 cases).
130 scalar w0, w1, invCDiff;
136 for (i = 0; i < nPos; ++i)
138 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
140 w0 = -C[neg[0]] * invCDiff;
141 w1 = +C[pos[i]] * invCDiff;
143 tetra[pos[i]] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
146 decompTets.append(tetra);
154 for (i = 0; i < nPos; ++i)
156 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
158 w0 = -C[neg[0]] * invCDiff;
159 w1 = +C[pos[i]] * invCDiff;
161 intp[i] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
164 for (i = 0; i < nNeg; ++i)
166 invCDiff = (1.0 / (C[pos[i]] - C[neg[1]]));
168 w0 = -C[neg[1]] * invCDiff;
169 w1 = +C[pos[i]] * invCDiff;
171 intp[i+2] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[1]]);
174 tetra[pos[0]] = intp[2];
175 tetra[pos[1]] = intp[1];
177 decompTets.append(tetra);
179 tmpTetra[0] = tetra[neg[1]];
180 tmpTetra[1] = intp[3];
181 tmpTetra[2] = intp[2];
182 tmpTetra[3] = intp[1];
184 decompTets.append(tmpTetra);
186 tmpTetra[0] = tetra[neg[0]];
187 tmpTetra[1] = intp[0];
188 tmpTetra[2] = intp[1];
189 tmpTetra[3] = intp[2];
191 decompTets.append(tmpTetra);
196 for (i = 0; i < nPos; ++i)
198 invCDiff = (1.0 / (C[pos[i]] - C[neg[0]]));
200 w0 = -C[neg[0]] * invCDiff;
201 w1 = +C[pos[i]] * invCDiff;
203 tetra[pos[i]] = (w0 * tetra[pos[i]]) + (w1 * tetra[neg[0]]);
206 decompTets.append(tetra);
215 for (i = 0; i < nNeg; ++i)
217 invCDiff = (1.0 / (C[pos[0]] - C[neg[i]]));
219 w0 = -C[neg[i]] * invCDiff;
220 w1 = +C[pos[0]] * invCDiff;
222 intp[i] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[i]]);
225 tetra[pos[0]] = intp[0];
227 decompTets.append(tetra);
229 tmpTetra[0] = intp[0];
230 tmpTetra[1] = tetra[neg[1]];
231 tmpTetra[2] = tetra[neg[2]];
232 tmpTetra[3] = intp[1];
234 decompTets.append(tmpTetra);
236 tmpTetra[0] = tetra[neg[2]];
237 tmpTetra[1] = intp[1];
238 tmpTetra[2] = intp[2];
239 tmpTetra[3] = intp[0];
241 decompTets.append(tmpTetra);
247 for (i = 0; i < nNeg; ++i)
249 invCDiff = (1.0 / (C[pos[0]] - C[neg[i]]));
251 w0 = -C[neg[i]] * invCDiff;
252 w1 = +C[pos[0]] * invCDiff;
254 intp[i] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[i]]);
257 tetra[pos[0]] = intp[0];
259 decompTets.append(tetra);
261 tmpTetra[0] = intp[1];
262 tmpTetra[1] = tetra[zero[0]];
263 tmpTetra[2] = tetra[neg[1]];
264 tmpTetra[3] = intp[0];
266 decompTets.append(tmpTetra);
271 invCDiff = (1.0 / (C[pos[0]] - C[neg[0]]));
273 w0 = -C[neg[0]] * invCDiff;
274 w1 = +C[pos[0]] * invCDiff;
276 tetra[pos[0]] = (w0 * tetra[pos[0]]) + (w1 * tetra[neg[0]]);
278 decompTets.append(tetra);
284 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
286 inline tetIntersection::tetIntersection(const FixedList<point, 4>& clipTet)
293 // Pre-compute clipping planes
298 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
300 inline tetIntersection::~tetIntersection()
304 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
306 // Return magnitude of clipping tetrahedron
307 inline scalar tetIntersection::clipTetMag() const
313 // Evaluate for intersections
314 inline bool tetIntersection::evaluate(const FixedList<point, 4>& subjectTet)
320 // Add initial tetrahedron to list
321 allTets_.append(subjectTet);
323 // Clip second tetrahedron against planes of clipping tetrahedron
324 for (label i = 0; i < 4; i++)
326 forAll(allTets_, tetI)
328 splitAndDecompose(i, allTets_[tetI], inside_);
331 // Prep for next clipping plane
336 return (allTets_.size() > 0);
340 // Return intersections
341 inline const DynamicList<FixedList<point, 4> >&
342 tetIntersection::getIntersection() const
348 //- Evaluate and return volume / centroid
349 inline void tetIntersection::getVolumeAndCentre
356 centre = vector::zero;
358 forAll(allTets_, tetI)
360 const FixedList<point, 4>& t = allTets_[tetI];
362 // Calculate volume (no check for orientation)
369 ((t[1] - t[0]) ^ (t[2] - t[0])) & (t[3] - t[0])
374 // Calculate centroid
375 vector tC = (0.25 * (t[0] + t[1] + t[2] + t[3]));
381 centre /= volume + VSMALL;
387 // ************************************************************************* //