tetrahedronI.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2018-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "triangle.H"
30 #include "IOstreams.H"
31 #include "plane.H"
32 
33 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
34 
36 (
37  const point& p0,
38  const point& p1,
39  const point& p2,
40  const point& p3
41 )
42 {
43  a() = p0;
44  b() = p1;
45  c() = p2;
46  d() = p3;
47 }
48 
49 
51 {
52  a() = pts.a();
53  b() = pts.b();
54  c() = pts.c();
55  d() = pts.d();
56 }
57 
58 
60 :
61  FixedList<point, 4>(pts)
62 {}
63 
64 
66 (
67  const UList<point>& points,
68  const FixedList<label, 4>& indices
69 )
70 :
71  FixedList<point, 4>(points, indices)
72 {}
73 
74 
75 template<class Point, class PointRef>
77 (
78  const Point& p0,
79  const Point& p1,
80  const Point& p2,
81  const Point& p3
82 )
83 :
84  a_(p0),
85  b_(p1),
86  c_(p2),
87  d_(p3)
88 {}
89 
90 
91 template<class Point, class PointRef>
93 (
95 )
96 :
97  a_(pts.template get<0>()),
98  b_(pts.template get<1>()),
99  c_(pts.template get<2>()),
100  d_(pts.template get<3>())
101 {}
102 
103 
104 template<class Point, class PointRef>
106 (
107  const UList<Point>& points,
108  const FixedList<label, 4>& indices
109 )
110 :
111  a_(points[indices.template get<0>()]),
112  b_(points[indices.template get<1>()]),
113  c_(points[indices.template get<2>()]),
114  d_(points[indices.template get<3>()])
115 {}
116 
117 
118 template<class Point, class PointRef>
120 {
121  is >> *this;
122 }
123 
124 
125 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
128 {
129  return tetPointRef(a(), b(), c(), d());
130 }
131 
132 
133 inline void Foam::tetPoints::flip()
134 {
135  // swap pt2 <-> pt3
136  point t(c());
137  c() = d();
138  d() = t;
139 }
140 
141 
142 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
143 
144 template<class Point, class PointRef>
146 (
147  const Point& p0,
148  const Point& p1,
149  const Point& p2,
150  const Point& p3
151 )
152 {
153  return Pair<Point>
154  (
155  min(p0, min(p1, min(p2, p3))),
156  max(p0, max(p1, max(p2, p3)))
157  );
158 }
159 
160 
161 template<class Point, class PointRef>
163 {
164  return tetrahedron<Point, PointRef>::box(a_, b_, c_, d_);
165 }
166 
167 
169 {
170  return tetPointRef::box(a(), b(), c(), d());
171 }
172 
173 
174 template<class Point, class PointRef>
176 {
177  return treeBoundBox(box());
178 }
179 
180 
182 {
183  return treeBoundBox(box());
184 }
186 
187 // Warning. Ordering of faces needs to be the same for a tetrahedron class,
188 // tetrahedron cell shape model and a tetCell
189 
190 template<class Point, class PointRef>
192 (
193  const label facei
194 ) const
195 {
196  // Warning. Ordering of faces needs to be the same for a tetrahedron
197  // class, a tetrahedron cell shape model and a tetCell
198 
199  if (facei == 0)
200  {
201  return triPointRef(b_, c_, d_);
202  }
203  else if (facei == 1)
204  {
205  return triPointRef(a_, d_, c_);
206  }
207  else if (facei == 2)
208  {
209  return triPointRef(a_, b_, d_);
210  }
211  else if (facei == 3)
212  {
213  return triPointRef(a_, c_, b_);
214  }
215 
217  << "Face index (" << facei << ") out of range 0..3\n"
218  << abort(FatalError);
219  return triPointRef(b_, c_, d_);
220 }
221 
222 
223 template<class Point, class PointRef>
225 {
226  return triangle<Point, PointRef>::areaNormal(b_, c_, d_);
227 }
228 
229 
230 template<class Point, class PointRef>
232 {
233  return triangle<Point, PointRef>::areaNormal(a_, d_, c_);
234 }
235 
236 
237 template<class Point, class PointRef>
239 {
240  return triangle<Point, PointRef>::areaNormal(a_, b_, d_);
241 }
242 
243 
244 template<class Point, class PointRef>
246 {
247  return triangle<Point, PointRef>::areaNormal(a_, c_, b_);
248 }
249 
250 
251 template<class Point, class PointRef>
253 {
254  return 0.25*(a_ + b_ + c_ + d_);
255 }
256 
257 
258 template<class Point, class PointRef>
259 inline Foam::scalar Foam::tetrahedron<Point, PointRef>::mag() const
260 {
261  return (1.0/6.0)*(((b_ - a_) ^ (c_ - a_)) & (d_ - a_));
262 }
263 
264 
265 template<class Point, class PointRef>
267 {
268  vector a = b_ - a_;
269  vector b = c_ - a_;
270  vector c = d_ - a_;
271 
272  scalar lambda = magSqr(c) - (a & c);
273  scalar mu = magSqr(b) - (a & b);
274 
275  vector ba = b ^ a;
276  vector ca = c ^ a;
277 
278  vector num = lambda*ba - mu*ca;
279  scalar denom = (c & ba);
280 
281  if (Foam::mag(denom) < ROOTVSMALL)
282  {
283  // Degenerate tetrahedron, returning centre instead of circumCentre.
284 
285  return centre();
286  }
287 
288  return a_ + 0.5*(a + num/denom);
289 }
290 
291 
292 template<class Point, class PointRef>
293 inline Foam::scalar Foam::tetrahedron<Point, PointRef>::circumRadius() const
294 {
295  vector a = b_ - a_;
296  vector b = c_ - a_;
297  vector c = d_ - a_;
298 
299  scalar lambda = magSqr(c) - (a & c);
300  scalar mu = magSqr(b) - (a & b);
301 
302  vector ba = b ^ a;
303  vector ca = c ^ a;
304 
305  vector num = lambda*ba - mu*ca;
306  scalar denom = (c & ba);
307 
308  if (Foam::mag(denom) < ROOTVSMALL)
309  {
310  // Degenerate tetrahedron, returning GREAT for circumRadius.
311  return GREAT;
312  }
313 
314  return Foam::mag(0.5*(a + num/denom));
315 }
316 
317 
318 template<class Point, class PointRef>
319 inline Foam::scalar Foam::tetrahedron<Point, PointRef>::quality() const
320 {
321  return
322  mag()
323  /(
324  8.0/(9.0*sqrt(3.0))
325  *pow3(Foam::min(circumRadius(), GREAT))
326  + ROOTVSMALL
327  );
328 }
329 
330 
331 template<class Point, class PointRef>
333 (
334  Random& rndGen
335 ) const
336 {
337  return barycentricToPoint(barycentric01(rndGen));
338 }
339 
340 
341 template<class Point, class PointRef>
343 (
344  const barycentric& bary
345 ) const
346 {
347  return Point(bary.a()*a_ + bary.b()*b_ + bary.c()*c_ + bary.d()*d_);
348 }
349 
350 
351 template<class Point, class PointRef>
353 (
354  const point& pt
355 ) const
356 {
357  barycentric bary;
358  pointToBarycentric(pt, bary);
359  return bary;
360 }
361 
362 
363 template<class Point, class PointRef>
365 (
366  const point& pt,
367  barycentric& bary
368 ) const
369 {
370  // Reference:
371  // http://en.wikipedia.org/wiki/Barycentric_coordinate_system_(mathematics)
372 
373  vector e0(a_ - d_);
374  vector e1(b_ - d_);
375  vector e2(c_ - d_);
376 
377  tensor t
378  (
379  e0.x(), e1.x(), e2.x(),
380  e0.y(), e1.y(), e2.y(),
381  e0.z(), e1.z(), e2.z()
382  );
383 
384  scalar detT = det(t);
385 
386  if (Foam::mag(detT) < SMALL)
387  {
388  // Degenerate tetrahedron, returning 1/4 barycentric coordinates
389 
390  bary = barycentric(0.25, 0.25, 0.25, 0.25);
391 
392  return detT;
393  }
394 
395  vector res = inv(t, detT) & (pt - d_);
396 
397  bary[0] = res.x();
398  bary[1] = res.y();
399  bary[2] = res.z();
400  bary[3] = 1 - bary[0] - bary[1] - bary[2];
402  return detT;
403 }
404 
405 
406 template<class Point, class PointRef>
408 (
409  const point& p
410 ) const
411 {
412  // Adapted from:
413  // Real-time collision detection, Christer Ericson, 2005, p142-144
414 
415  // Assuming initially that the point is inside all of the
416  // halfspaces, so closest to itself.
417 
418  point closestPt = p;
419 
420  scalar minOutsideDistance = VGREAT;
421 
422  bool inside = true;
423 
424  // Side a
425  {
426  const triangle<Point, PointRef> tria(b_, c_, d_);
427 
428  if (((p - b_) & tria.areaNormal()) >= 0)
429  {
430  // p is outside halfspace plane of tri
431  pointHit info = tria.nearestPoint(p);
432 
433  inside = false;
434 
435  if (info.distance() < minOutsideDistance)
436  {
437  closestPt = info.point();
438 
439  minOutsideDistance = info.distance();
440  }
441  }
442  }
443 
444  // Side b
445  {
446  const triangle<Point, PointRef> tria(a_, d_, c_);
447 
448  if (((p - a_) & tria.areaNormal()) >= 0)
449  {
450  // p is outside halfspace plane of tri
451  pointHit info = tria.nearestPoint(p);
452 
453  inside = false;
454 
455  if (info.distance() < minOutsideDistance)
456  {
457  closestPt = info.point();
458 
459  minOutsideDistance = info.distance();
460  }
461  }
462  }
463 
464  // Side c
465  {
466  const triangle<Point, PointRef> tria(a_, b_, d_);
467 
468  if (((p - a_) & tria.areaNormal()) >= 0)
469  {
470  // p is outside halfspace plane of tri
471  pointHit info = tria.nearestPoint(p);
472 
473  inside = false;
474 
475  if (info.distance() < minOutsideDistance)
476  {
477  closestPt = info.point();
478 
479  minOutsideDistance = info.distance();
480  }
481  }
482  }
483 
484  // Side c
485  {
486  const triangle<Point, PointRef> tria(a_, c_, b_);
487 
488  if (((p - a_) & tria.areaNormal()) >= 0)
489  {
490  // p is outside halfspace plane of tri
491  pointHit info = tria.nearestPoint(p);
492 
493  inside = false;
494 
495  if (info.distance() < minOutsideDistance)
496  {
497  closestPt = info.point();
498 
499  minOutsideDistance = info.distance();
500  }
501  }
502  }
503 
504  // If the point is inside, then the distance to the closest point
505  // is zero
506  if (inside)
507  {
508  minOutsideDistance = 0;
509  }
510 
511  return pointHit
512  (
513  inside,
514  closestPt,
515  minOutsideDistance,
516  !inside
517  );
518 }
519 
520 
521 template<class Point, class PointRef>
523 {
524  // For robustness, assuming that the point is in the tet unless
525  // "definitively" shown otherwise by obtaining a positive dot
526  // product greater than a tolerance of SMALL.
527 
528  // The tet is defined: tet(Cc, tetBasePt, pA, pB) where the area normal
529  // vectors and base points for the half-space planes are:
530  // area[0] = Sa();
531  // area[1] = Sb();
532  // area[2] = Sc();
533  // area[3] = Sd();
534  // planeBase[0] = tetBasePt = b_
535  // planeBase[1] = ptA = c_
536  // planeBase[2] = tetBasePt = b_
537  // planeBase[3] = tetBasePt = b_
538 
539  // Side a
540  {
541  const triangle<Point, PointRef> tria(b_, c_, d_);
542 
543  if (((p - b_) & tria.unitNormal()) > SMALL)
544  {
545  return false;
546  }
547  }
548 
549  // Side b
550  {
551  const triangle<Point, PointRef> tria(a_, d_, c_);
552 
553  if (((p - a_) & tria.unitNormal()) > SMALL)
554  {
555  return false;
556  }
557  }
558 
559  // Side c
560  {
561  const triangle<Point, PointRef> tria(a_, b_, d_);
562 
563  if (((p - a_) & tria.unitNormal()) > SMALL)
564  {
565  return false;
566  }
567  }
568 
569  // Side d
570  {
571  const triangle<Point, PointRef> tria(a_, c_, b_);
572 
573  if (((p - a_) & tria.unitNormal()) > SMALL)
574  {
575  return false;
576  }
577  }
579  return true;
580 }
581 
582 
583 template<class Point, class PointRef>
585 (
586  const tetPoints&
587 )
588 {}
589 
590 
591 template<class Point, class PointRef>
593 :
594  vol_(0.0)
595 {}
596 
597 
598 template<class Point, class PointRef>
600 (
601  const tetPoints& tet
602 )
603 {
604  vol_ += tet.tet().mag();
605 }
606 
607 
608 template<class Point, class PointRef>
610 (
611  tetIntersectionList& tets,
612  label& nTets
613 )
614 :
615  tets_(tets),
616  nTets_(nTets)
617 {}
618 
619 
620 template<class Point, class PointRef>
622 (
623  const tetPoints& tet
624 )
625 {
626  tets_[nTets_++] = tet;
627 }
628 
629 
630 template<class Point, class PointRef>
632 (
633  const FixedList<scalar, 4>& d,
634  const tetPoints& t,
635  const label negI,
636  const label posI
637 )
638 {
639  return
640  (d[posI]*t[negI] - d[negI]*t[posI])
641  / (-d[negI]+d[posI]);
642 }
643 
644 
645 template<class Point, class PointRef>
646 template<class TetOp>
648 (
649  const FixedList<point, 6>& points,
650  TetOp& op
651 )
652 {
653  op(tetPoints(points[1], points[3], points[2], points[0]));
654  op(tetPoints(points[1], points[2], points[3], points[4]));
655  op(tetPoints(points[4], points[2], points[3], points[5]));
656 }
657 
658 
659 template<class Point, class PointRef>
660 template<class AboveTetOp, class BelowTetOp>
662 (
663  const plane& pln,
664  const tetPoints& tet,
665  AboveTetOp& aboveOp,
666  BelowTetOp& belowOp
667 )
668 {
669  // Distance to plane
670  FixedList<scalar, 4> d;
671  label nPos = 0;
672  forAll(tet, i)
673  {
674  d[i] = pln.signedDistance(tet[i]);
675  if (d[i] > 0)
676  {
677  ++nPos;
678  }
679  }
680 
681  if (nPos == 4)
682  {
683  aboveOp(tet);
684  }
685  else if (nPos == 3)
686  {
687  // Sliced into below tet and above prism.
688  // Prism gets split into two tets.
689 
690  // Find the below tet
691  label i0 = -1;
692  forAll(d, i)
693  {
694  if (d[i] <= 0)
695  {
696  i0 = i;
697  break;
698  }
699  }
700 
701  label i1 = d.fcIndex(i0);
702  label i2 = d.fcIndex(i1);
703  label i3 = d.fcIndex(i2);
704 
705  point p01(planeIntersection(d, tet, i0, i1));
706  point p02(planeIntersection(d, tet, i0, i2));
707  point p03(planeIntersection(d, tet, i0, i3));
708 
709  // i0 = tetCell vertex 0: p01,p02,p03 outwards pointing triad
710  // ,, 1 : ,, inwards pointing triad
711  // ,, 2 : ,, outwards pointing triad
712  // ,, 3 : ,, inwards pointing triad
713 
714  //Pout<< "Split 3pos tet " << tet << " d:" << d << " into" << nl;
715 
716  if (i0 == 0 || i0 == 2)
717  {
718  tetPoints t(tet[i0], p01, p02, p03);
719  //Pout<< " belowtet:" << t << " around i0:" << i0 << endl;
720  //checkTet(t, "nPos 3, belowTet i0==0 or 2");
721  belowOp(t);
722 
723  // Prism
724  FixedList<point, 6> p
725  (
726  {
727  tet[i1],
728  tet[i3],
729  tet[i2],
730  p01,
731  p03,
732  p02
733  }
734  );
735 
736  //Pout<< " aboveprism:" << p << endl;
737  decomposePrism(p, aboveOp);
738  }
739  else
740  {
741  tetPoints t(p01, p02, p03, tet[i0]);
742  //Pout<< " belowtet:" << t << " around i0:" << i0 << endl;
743  //checkTet(t, "nPos 3, belowTet i0==1 or 3");
744  belowOp(t);
745 
746  // Prism
747  FixedList<point, 6> p
748  (
749  {
750  tet[i3],
751  tet[i1],
752  tet[i2],
753  p03,
754  p01,
755  p02
756  }
757  );
758  //Pout<< " aboveprism:" << p << endl;
759  decomposePrism(p, aboveOp);
760  }
761  }
762  else if (nPos == 2)
763  {
764  // Tet cut into two prisms. Determine the positive one.
765  label pos0 = -1;
766  label pos1 = -1;
767  forAll(d, i)
768  {
769  if (d[i] > 0)
770  {
771  if (pos0 == -1)
772  {
773  pos0 = i;
774  }
775  else
776  {
777  pos1 = i;
778  }
779  }
780  }
781 
782  //Pout<< "Split 2pos tet " << tet << " d:" << d
783  // << " around pos0:" << pos0 << " pos1:" << pos1
784  // << " neg0:" << neg0 << " neg1:" << neg1 << " into" << nl;
785 
786  const edge posEdge(pos0, pos1);
787 
788  if (posEdge == edge(0, 1))
789  {
790  point p02(planeIntersection(d, tet, 0, 2));
791  point p03(planeIntersection(d, tet, 0, 3));
792  point p12(planeIntersection(d, tet, 1, 2));
793  point p13(planeIntersection(d, tet, 1, 3));
794  // Split the resulting prism
795  {
796  FixedList<point, 6> p
797  (
798  {
799  tet[0],
800  p02,
801  p03,
802  tet[1],
803  p12,
804  p13
805  }
806  );
807 
808  //Pout<< " 01 aboveprism:" << p << endl;
809  decomposePrism(p, aboveOp);
810  }
811  {
812  FixedList<point, 6> p
813  (
814  {
815  tet[2],
816  p02,
817  p12,
818  tet[3],
819  p03,
820  p13
821  }
822  );
823 
824  //Pout<< " 01 belowprism:" << p << endl;
825  decomposePrism(p, belowOp);
826  }
827  }
828  else if (posEdge == edge(1, 2))
829  {
830  point p01(planeIntersection(d, tet, 0, 1));
831  point p13(planeIntersection(d, tet, 1, 3));
832  point p02(planeIntersection(d, tet, 0, 2));
833  point p23(planeIntersection(d, tet, 2, 3));
834  // Split the resulting prism
835  {
836  FixedList<point, 6> p
837  (
838  {
839  tet[1],
840  p01,
841  p13,
842  tet[2],
843  p02,
844  p23
845  }
846  );
847 
848  //Pout<< " 12 aboveprism:" << p << endl;
849  decomposePrism(p, aboveOp);
850  }
851  {
852  FixedList<point, 6> p
853  (
854  {
855  tet[3],
856  p23,
857  p13,
858  tet[0],
859  p02,
860  p01
861  }
862  );
863 
864  //Pout<< " 12 belowprism:" << p << endl;
865  decomposePrism(p, belowOp);
866  }
867  }
868  else if (posEdge == edge(2, 0))
869  {
870  point p01(planeIntersection(d, tet, 0, 1));
871  point p03(planeIntersection(d, tet, 0, 3));
872  point p12(planeIntersection(d, tet, 1, 2));
873  point p23(planeIntersection(d, tet, 2, 3));
874  // Split the resulting prism
875  {
876  FixedList<point, 6> p
877  (
878  {
879  tet[2],
880  p12,
881  p23,
882  tet[0],
883  p01,
884  p03
885  }
886  );
887 
888  //Pout<< " 20 aboveprism:" << p << endl;
889  decomposePrism(p, aboveOp);
890  }
891  {
892  FixedList<point, 6> p
893  (
894  {
895  tet[1],
896  p12,
897  p01,
898  tet[3],
899  p23,
900  p03
901  }
902  );
903 
904  //Pout<< " 20 belowprism:" << p << endl;
905  decomposePrism(p, belowOp);
906  }
907  }
908  else if (posEdge == edge(0, 3))
909  {
910  point p01(planeIntersection(d, tet, 0, 1));
911  point p02(planeIntersection(d, tet, 0, 2));
912  point p13(planeIntersection(d, tet, 1, 3));
913  point p23(planeIntersection(d, tet, 2, 3));
914  // Split the resulting prism
915  {
916  FixedList<point, 6> p
917  (
918  {
919  tet[3],
920  p23,
921  p13,
922  tet[0],
923  p02,
924  p01
925  }
926  );
927 
928  //Pout<< " 03 aboveprism:" << p << endl;
929  decomposePrism(p, aboveOp);
930  }
931  {
932  FixedList<point, 6> p
933  (
934  {
935  tet[2],
936  p23,
937  p02,
938  tet[1],
939  p13,
940  p01
941  }
942  );
943 
944  //Pout<< " 03 belowprism:" << p << endl;
945  decomposePrism(p, belowOp);
946  }
947  }
948  else if (posEdge == edge(1, 3))
949  {
950  point p01(planeIntersection(d, tet, 0, 1));
951  point p12(planeIntersection(d, tet, 1, 2));
952  point p03(planeIntersection(d, tet, 0, 3));
953  point p23(planeIntersection(d, tet, 2, 3));
954  // Split the resulting prism
955  {
956  FixedList<point, 6> p
957  (
958  {
959  tet[1],
960  p12,
961  p01,
962  tet[3],
963  p23,
964  p03
965  }
966  );
967 
968  //Pout<< " 13 aboveprism:" << p << endl;
969  decomposePrism(p, aboveOp);
970  }
971  {
972  FixedList<point, 6> p
973  (
974  {
975  tet[2],
976  p12,
977  p23,
978  tet[0],
979  p01,
980  p03
981  }
982  );
983 
984  //Pout<< " 13 belowprism:" << p << endl;
985  decomposePrism(p, belowOp);
986  }
987  }
988  else if (posEdge == edge(2, 3))
989  {
990  point p02(planeIntersection(d, tet, 0, 2));
991  point p12(planeIntersection(d, tet, 1, 2));
992  point p03(planeIntersection(d, tet, 0, 3));
993  point p13(planeIntersection(d, tet, 1, 3));
994  // Split the resulting prism
995  {
996  FixedList<point, 6> p
997  (
998  {
999  tet[2],
1000  p02,
1001  p12,
1002  tet[3],
1003  p03,
1004  p13
1005  }
1006  );
1007 
1008  //Pout<< " 23 aboveprism:" << p << endl;
1009  decomposePrism(p, aboveOp);
1010  }
1011  {
1012  FixedList<point, 6> p
1013  (
1014  {
1015  tet[0],
1016  p02,
1017  p03,
1018  tet[1],
1019  p12,
1020  p13
1021  }
1022  );
1023 
1024  //Pout<< " 23 belowprism:" << p << endl;
1025  decomposePrism(p, belowOp);
1026  }
1027  }
1028  else
1029  {
1031  << "Missed edge:" << posEdge
1032  << abort(FatalError);
1033  }
1034  }
1035  else if (nPos == 1)
1036  {
1037  // Find the positive tet
1038  label i0 = -1;
1039  forAll(d, i)
1040  {
1041  if (d[i] > 0)
1042  {
1043  i0 = i;
1044  break;
1045  }
1046  }
1047 
1048  label i1 = d.fcIndex(i0);
1049  label i2 = d.fcIndex(i1);
1050  label i3 = d.fcIndex(i2);
1051 
1052  point p01(planeIntersection(d, tet, i0, i1));
1053  point p02(planeIntersection(d, tet, i0, i2));
1054  point p03(planeIntersection(d, tet, i0, i3));
1055 
1056  //Pout<< "Split 1pos tet " << tet << " d:" << d << " into" << nl;
1057 
1058  if (i0 == 0 || i0 == 2)
1059  {
1060  tetPoints t(tet[i0], p01, p02, p03);
1061  //Pout<< " abovetet:" << t << " around i0:" << i0 << endl;
1062  //checkTet(t, "nPos 1, aboveTets i0==0 or 2");
1063  aboveOp(t);
1064 
1065  // Prism
1066  FixedList<point, 6> p
1067  (
1068  {
1069  tet[i1],
1070  tet[i3],
1071  tet[i2],
1072  p01,
1073  p03,
1074  p02
1075  }
1076  );
1077 
1078  //Pout<< " belowprism:" << p << endl;
1079  decomposePrism(p, belowOp);
1080  }
1081  else
1082  {
1083  tetPoints t(p01, p02, p03, tet[i0]);
1084  //Pout<< " abovetet:" << t << " around i0:" << i0 << endl;
1085  //checkTet(t, "nPos 1, aboveTets i0==1 or 3");
1086  aboveOp(t);
1087 
1088  // Prism
1089  FixedList<point, 6> p
1090  (
1091  {
1092  tet[i3],
1093  tet[i1],
1094  tet[i2],
1095  p03,
1096  p01,
1097  p02
1098  }
1099  );
1100 
1101  //Pout<< " belowprism:" << p << endl;
1102  decomposePrism(p, belowOp);
1103  }
1104  }
1105  else // nPos == 0
1106  {
1107  belowOp(tet);
1108  }
1109 }
1110 
1111 
1112 template<class Point, class PointRef>
1113 template<class AboveTetOp, class BelowTetOp>
1115 (
1116  const plane& pl,
1117  AboveTetOp& aboveOp,
1118  BelowTetOp& belowOp
1119 ) const
1120 {
1121  tetSliceWithPlane(pl, tetPoints(a_, b_, c_, d_), aboveOp, belowOp);
1122 }
1123 
1124 
1125 // * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
1126 
1127 template<class Point, class PointRef>
1128 inline Foam::Istream& Foam::operator>>
1129 (
1130  Istream& is,
1131  tetrahedron<Point, PointRef>& t
1132 )
1133 {
1134  is.readBegin("tetrahedron");
1135  is >> t.a_ >> t.b_ >> t.c_ >> t.d_;
1136  is.readEnd("tetrahedron");
1137 
1138  is.check(FUNCTION_NAME);
1139 
1140  return is;
1141 }
1142 
1143 
1144 template<class Point, class PointRef>
1145 inline Foam::Ostream& Foam::operator<<
1146 (
1147  Ostream& os,
1148  const tetrahedron<Point, PointRef>& t
1149 )
1150 {
1151  // Format like FixedList
1152  os << nl
1154  << t.a_ << token::SPACE
1155  << t.b_ << token::SPACE
1156  << t.c_ << token::SPACE
1157  << t.d_
1158  << token::END_LIST;
1159 
1160  return os;
1161 }
1162 
1163 
1164 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
treeBoundBox bounds() const
The bounding box for the tetrahedron.
Definition: tetrahedronI.H:174
A tetrahedron primitive.
Definition: tetrahedron.H:58
A triangle primitive used to calculate face normals and swept volumes. Uses referred points...
Definition: triangle.H:217
Pair< Point > box() const
The enclosing (bounding) box for the tetrahedron.
Definition: tetrahedronI.H:155
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
barycentric barycentric01(Random &rndGen)
Generate a random barycentric coordinate within the unit tetrahedron.
Definition: barycentric.C:66
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
scalar circumRadius() const
Return circum-radius.
Definition: tetrahedronI.H:286
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
Point circumCentre() const
Return circum-centre.
Definition: tetrahedronI.H:259
bool readBegin(const char *funcName)
Begin read of data chunk, starts with &#39;(&#39;.
Definition: Istream.C:134
tetrahedron(const Point &p0, const Point &p1, const Point &p2, const Point &p3)
Construct from four points.
Definition: tetrahedronI.H:70
tetrahedron< point, const point & > tetPointRef
A tetrahedron using referred points.
Definition: tetrahedron.H:72
tetPointRef tet() const
Return as tetrahedron reference.
Definition: tetrahedronI.H:120
vector Sd() const
Face area normal for side d.
Definition: tetrahedronI.H:238
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
const point & a() const noexcept
The first vertex.
Definition: tetrahedron.H:144
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Random rndGen
Definition: createFields.H:23
dimensionedScalar sqrt(const dimensionedScalar &ds)
storeOp(tetIntersectionList &, label &)
Definition: tetrahedronI.H:603
tetPoints()=default
Default construct.
Begin list [isseparator].
Definition: token.H:161
const point & c() const noexcept
The third vertex.
Definition: tetrahedron.H:154
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
Definition: barycentric.H:41
dimensionedScalar det(const dimensionedSphericalTensor &dt)
const Cmpt & b() const noexcept
Definition: Barycentric.H:115
Point barycentricToPoint(const barycentric &bary) const
Calculate the point from the given barycentric coordinates.
Definition: tetrahedronI.H:336
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
pointHit nearestPoint(const point &p) const
Return nearest point to p on triangle.
Definition: triangleI.H:861
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: instant.H:46
const pointField & points
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
static vector areaNormal(const Point &p0, const Point &p1, const Point &p2)
The area normal for a triangle defined by three points (right-hand rule). Magnitude equal to area of ...
Definition: triangleI.H:140
dimensionedScalar lambda("lambda", dimTime/sqr(dimLength), laminarTransport)
const Cmpt & c() const noexcept
Definition: Barycentric.H:116
scalar quality() const
Return quality: Ratio of tetrahedron and circum-sphere volume, scaled so that a regular tetrahedron h...
Definition: tetrahedronI.H:312
vector Sb() const
Face area normal for side b.
Definition: tetrahedronI.H:224
Space [isspace].
Definition: token.H:131
scalar mag() const
Return volume.
Definition: tetrahedronI.H:252
vector Sa() const
Face area normal for side a.
Definition: tetrahedronI.H:217
End list [isseparator].
Definition: token.H:162
Vector< scalar > vector
Definition: vector.H:57
Describes the interaction of a object and a (templated) point. It carries the info of a successful hi...
Definition: pointHit.H:43
Point centre() const
Return centre (centroid)
Definition: tetrahedronI.H:245
bool inside(const point &pt) const
Return true if point is inside tetrahedron.
Definition: tetrahedronI.H:515
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
Random number generator.
Definition: Random.H:55
Pair< point > box() const
The enclosing (bounding) box for the tetrahedron.
Definition: tetrahedronI.H:161
const Cmpt & d() const noexcept
Definition: Barycentric.H:117
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
dimensionedScalar pos0(const dimensionedScalar &ds)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
void sliceWithPlane(const plane &pl, AboveTetOp &aboveOp, BelowTetOp &belowOp) const
Decompose tet into tets above and below plane.
CGAL::Point_3< K > Point
const point & b() const noexcept
The second vertex.
Definition: tetrahedron.H:149
const dimensionedScalar mu
Atomic mass unit.
triPointRef tri(const label facei) const
Return i-th face.
Definition: tetrahedronI.H:185
dimensionedScalar pow3(const dimensionedScalar &ds)
barycentric pointToBarycentric(const point &pt) const
Calculate the barycentric coordinates from the given point.
Definition: tetrahedronI.H:346
vector point
Point is a vector.
Definition: point.H:37
Tet point storage. Default constructable (tetrahedron is not)
Definition: tetrahedron.H:82
const dimensionedScalar c
Speed of light in a vacuum.
scalar distance() const noexcept
Return distance to hit.
Definition: pointHit.H:169
pointHit nearestPoint(const point &p) const
Return nearest point to p on tetrahedron. Is p itself.
Definition: tetrahedronI.H:401
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangleFwd.H:39
treeBoundBox bounds() const
The bounding box for the tetrahedron.
Definition: tetrahedronI.H:168
const point_type & point() const noexcept
Return the point, no checks.
Definition: pointHit.H:161
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
Point randomPoint(Random &rndGen) const
Return a random point in the tetrahedron from a uniform distribution.
Definition: tetrahedronI.H:326
const Cmpt & a() const noexcept
Definition: Barycentric.H:114
volScalarField & p
vector Sc() const
Face area normal for side c.
Definition: tetrahedronI.H:231
Tensor of scalars, i.e. Tensor<scalar>.
const point & d() const noexcept
The fourth vertex.
Definition: tetrahedron.H:159
void flip()
Invert tetrahedron by swapping third and fourth vertices.
Definition: tetrahedronI.H:126
const volScalarField & p0
Definition: EEqn.H:36
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
PointHit< point > pointHit
A PointHit with a 3D point.
Definition: pointHit.H:43
vector areaNormal() const
The area normal - with magnitude equal to area of triangle.
Definition: triangleI.H:151
const pointField & pts