00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <OpenFOAM/IOstreams.H>
00027 #include <OpenFOAM/pointHit.H>
00028 #include <OpenFOAM/mathematicalConstants.H>
00029
00030
00031
00032 namespace Foam
00033 {
00034
00035
00036
00037 template<class Point, class PointRef>
00038 pointHit triangle<Point, PointRef>::nearestPoint
00039 (
00040 const Point& baseVertex,
00041 const vector& E0,
00042 const vector& E1,
00043 const point& P
00044 )
00045 {
00046
00047 const vector D(baseVertex - P);
00048
00049
00050 const scalar a = E0 & E0;
00051 const scalar b = E0 & E1;
00052 const scalar c = E1 & E1;
00053
00054
00055 const scalar d = E0 & D;
00056 const scalar e = E1 & D;
00057 const scalar f = D & D;
00058
00059
00060 const scalar det = a*c - b*b;
00061 scalar s = b*e - c*d;
00062 scalar t = b*d - a*e;
00063
00064 bool inside = false;
00065
00066 if (s+t < det)
00067 {
00068 if (s < 0)
00069 {
00070 if (t < 0)
00071 {
00072
00073 if (e > 0)
00074 {
00075
00076 t = 0;
00077 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00078 }
00079 else
00080 {
00081
00082 s = 0;
00083 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00084 }
00085 }
00086 else
00087 {
00088
00089 s = 0;
00090 t = (e >= 0 ? 0 : (-e >= c ? 1 : -e/c));
00091 }
00092 }
00093 else if (t < 0)
00094 {
00095
00096 t = 0;
00097 s = (d >= 0 ? 0 : (-d >= a ? 1 : -d/a));
00098 }
00099 else
00100 {
00101
00102 const scalar invDet = 1/det;
00103 s *= invDet;
00104 t *= invDet;
00105
00106 inside = true;
00107 }
00108 }
00109 else
00110 {
00111 if (s < 0)
00112 {
00113
00114 const scalar tmp0 = b + d;
00115 const scalar tmp1 = c + e;
00116 if (tmp1 > tmp0)
00117 {
00118
00119 const scalar numer = tmp1 - tmp0;
00120 const scalar denom = a-2*b+c;
00121 s = (numer >= denom ? 1 : numer/denom);
00122 t = 1 - s;
00123 }
00124 else
00125 {
00126
00127 s = 0;
00128 t = (tmp1 <= 0 ? 1 : (e >= 0 ? 0 : - e/c));
00129 }
00130 }
00131 else if (t < 0)
00132 {
00133
00134 const scalar tmp0 = b + d;
00135 const scalar tmp1 = c + e;
00136 if (tmp1 > tmp0)
00137 {
00138
00139 const scalar numer = tmp1 - tmp0;
00140 const scalar denom = a-2*b+c;
00141 s = (numer >= denom ? 1 : numer/denom);
00142 t = 1 - s;
00143 }
00144 else
00145 {
00146
00147 t = 0;
00148 s = (tmp1 <= 0 ? 1 : (d >= 0 ? 0 : - d/a));
00149 }
00150 }
00151 else
00152 {
00153
00154 const scalar numer = c+e-(b+d);
00155 if (numer <= 0)
00156 {
00157 s = 0;
00158 }
00159 else
00160 {
00161 const scalar denom = a-2*b+c;
00162 s = (numer >= denom ? 1 : numer/denom);
00163 }
00164 }
00165
00166 t = 1 - s;
00167 }
00168
00169
00170
00171
00172
00173
00174 return pointHit
00175 (
00176 inside,
00177 baseVertex + s*E0 + t*E1,
00178 Foam::sqrt
00179 (
00180 Foam::mag(a*s*s + 2*b*s*t + c*t*t + 2*d*s + 2*e*t + f)
00181 ),
00182 !inside
00183 );
00184 }
00185
00186
00187
00188
00189 template<class Point, class PointRef>
00190 inline triangle<Point, PointRef>::triangle
00191 (
00192 const Point& a,
00193 const Point& b,
00194 const Point& c
00195 )
00196 :
00197 a_(a),
00198 b_(b),
00199 c_(c)
00200 {}
00201
00202
00203 template<class Point, class PointRef>
00204 inline triangle<Point, PointRef>::triangle(Istream& is)
00205 {
00206
00207 is.readBegin("triangle");
00208
00209 is >> a_ >> b_ >> c_;
00210
00211
00212 is.readEnd("triangle");
00213
00214
00215 is.check("triangle::triangle(Istream& is)");
00216 }
00217
00218
00219
00220
00221 template<class Point, class PointRef>
00222 inline const Point& triangle<Point, PointRef>::a() const
00223 {
00224 return a_;
00225 }
00226
00227 template<class Point, class PointRef>
00228 inline const Point& triangle<Point, PointRef>::b() const
00229 {
00230 return b_;
00231 }
00232
00233 template<class Point, class PointRef>
00234 inline const Point& triangle<Point, PointRef>::c() const
00235 {
00236 return c_;
00237 }
00238
00239
00240 template<class Point, class PointRef>
00241 inline Point triangle<Point, PointRef>::centre() const
00242 {
00243 return (1.0/3.0)*(a_ + b_ + c_);
00244 }
00245
00246
00247 template<class Point, class PointRef>
00248 inline scalar triangle<Point, PointRef>::mag() const
00249 {
00250 return ::Foam::mag(normal());
00251 }
00252
00253
00254 template<class Point, class PointRef>
00255 inline vector triangle<Point, PointRef>::normal() const
00256 {
00257 return 0.5*((b_ - a_)^(c_ - a_));
00258 }
00259
00260
00261 template<class Point, class PointRef>
00262 inline vector triangle<Point, PointRef>::circumCentre() const
00263 {
00264 scalar d1 = (c_ - a_)&(b_ - a_);
00265 scalar d2 = -(c_ - b_)&(b_ - a_);
00266 scalar d3 = (c_ - a_)&(c_ - b_);
00267
00268 scalar c1 = d2*d3;
00269 scalar c2 = d3*d1;
00270 scalar c3 = d1*d2;
00271
00272 scalar c = c1 + c2 + c3;
00273
00274 return
00275 (
00276 ((c2 + c3)*a_ + (c3 + c1)*b_ + (c1 + c2)*c_)/(2*c)
00277 );
00278 }
00279
00280
00281 template<class Point, class PointRef>
00282 inline scalar triangle<Point, PointRef>::circumRadius() const
00283 {
00284 scalar d1 = (c_ - a_) & (b_ - a_);
00285 scalar d2 = - (c_ - b_) & (b_ - a_);
00286 scalar d3 = (c_ - a_) & (c_ - b_);
00287
00288 scalar denom = d2*d3 + d3*d1 + d1*d2;
00289
00290 if (Foam::mag(denom) < VSMALL)
00291 {
00292 return GREAT;
00293 }
00294 else
00295 {
00296 scalar a = (d1 + d2)*(d2 + d3)*(d3 + d1) / denom;
00297
00298 return 0.5*Foam::sqrt(min(GREAT, max(0, a)));
00299 }
00300 }
00301
00302
00303 template<class Point, class PointRef>
00304 inline scalar triangle<Point, PointRef>::quality() const
00305 {
00306 return
00307 mag()
00308 / (
00309 mathematicalConstant::pi
00310 * Foam::sqr(circumRadius())
00311 * 0.413497
00312 + VSMALL
00313 );
00314 }
00315
00316
00317 template<class Point, class PointRef>
00318 inline scalar triangle<Point, PointRef>::sweptVol(const triangle& t) const
00319 {
00320 return (1.0/12.0)*
00321 (
00322 ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
00323 + ((t.b_ - b_) & ((c_ - b_)^(t.a_ - b_)))
00324 + ((c_ - t.c_) & ((t.b_ - t.c_)^(t.a_ - t.c_)))
00325
00326 + ((t.a_ - a_) & ((b_ - a_)^(c_ - a_)))
00327 + ((b_ - t.b_) & ((t.a_ - t.b_)^(t.c_ - t.b_)))
00328 + ((c_ - t.c_) & ((b_ - t.c_)^(t.a_ - t.c_)))
00329 );
00330 }
00331
00332
00333 template<class Point, class PointRef>
00334 inline pointHit triangle<Point, PointRef>::ray
00335 (
00336 const point& p,
00337 const vector& q,
00338 const intersection::algorithm alg,
00339 const intersection::direction dir
00340 ) const
00341 {
00342
00343
00344 vector E0 = b_ - a_;
00345 vector E1 = c_ - a_;
00346
00347
00348 pointHit inter(p);
00349
00350 vector n(0.5*(E0 ^ E1));
00351 scalar area = Foam::mag(n);
00352
00353 if (area < VSMALL)
00354 {
00355
00356 inter.setMiss(false);
00357
00358
00359 inter.setPoint(a_);
00360
00361
00362
00363
00364 inter.setDistance(Foam::mag(a_ - p));
00365
00366 return inter;
00367 }
00368
00369 vector q1 = q/Foam::mag(q);
00370
00371 if (dir == intersection::CONTACT_SPHERE)
00372 {
00373 n /= area;
00374
00375 return ray(p, q1 - n, alg, intersection::VECTOR);
00376 }
00377
00378
00379 point pInter;
00380
00381 bool hit;
00382 {
00383
00384
00385 pointHit fastInter = intersection(p, q1, intersection::FULL_RAY);
00386 hit = fastInter.hit();
00387
00388 if (hit)
00389 {
00390 pInter = fastInter.rawPoint();
00391 }
00392 else
00393 {
00394
00395 vector v = a_ - p;
00396 pInter = p + (q1&v)*q1;
00397 }
00398 }
00399
00400
00401 scalar dist = q1 & (pInter - p);
00402
00403 const scalar planarPointTol =
00404 Foam::min
00405 (
00406 Foam::min
00407 (
00408 Foam::mag(E0),
00409 Foam::mag(E1)
00410 ),
00411 Foam::mag(c_ - b_)
00412 )*intersection::planarTol();
00413
00414 bool eligible =
00415 alg == intersection::FULL_RAY
00416 || (alg == intersection::HALF_RAY && dist > -planarPointTol)
00417 || (
00418 alg == intersection::VISIBLE
00419 && ((q1 & normal()) < -VSMALL)
00420 );
00421
00422 if (hit && eligible)
00423 {
00424
00425 inter.setHit();
00426 inter.setPoint(pInter);
00427 inter.setDistance(dist);
00428 }
00429 else
00430 {
00431
00432 inter.setMiss(eligible);
00433
00434
00435 inter.setPoint(nearestPoint(a_, E0, E1, p).rawPoint());
00436
00437
00438
00439 inter.setDistance(Foam::mag(pInter - p));
00440 }
00441
00442
00443 return inter;
00444 }
00445
00446
00447
00448
00449 template<class Point, class PointRef>
00450 inline pointHit triangle<Point, PointRef>::intersection
00451 (
00452 const point& orig,
00453 const vector& dir,
00454 const intersection::algorithm alg,
00455 const scalar tol
00456 ) const
00457 {
00458 const vector edge1 = b_ - a_;
00459 const vector edge2 = c_ - a_;
00460
00461
00462 const vector pVec = dir ^ edge2;
00463
00464
00465 const scalar det = edge1 & pVec;
00466
00467
00468 pointHit intersection(false, vector::zero, GREAT, false);
00469
00470 if (alg == intersection::VISIBLE)
00471 {
00472
00473 if (det < ROOTVSMALL)
00474 {
00475
00476 return intersection;
00477 }
00478 }
00479 else if (alg == intersection::HALF_RAY || alg == intersection::FULL_RAY)
00480 {
00481
00482 if (det > -ROOTVSMALL && det < ROOTVSMALL)
00483 {
00484
00485 return intersection;
00486 }
00487 }
00488
00489 const scalar inv_det = 1.0 / det;
00490
00491
00492 const vector tVec = orig-a_;
00493
00494
00495 const scalar u = (tVec & pVec)*inv_det;
00496
00497 if (u < -tol || u > 1.0+tol)
00498 {
00499
00500 return intersection;
00501 }
00502
00503
00504 const vector qVec = tVec ^ edge1;
00505
00506
00507 const scalar v = (dir & qVec) * inv_det;
00508
00509 if (v < -tol || u + v > 1.0+tol)
00510 {
00511
00512 return intersection;
00513 }
00514
00515
00516 const scalar t = (edge2 & qVec) * inv_det;
00517
00518 if (alg == intersection::HALF_RAY && t < -tol)
00519 {
00520
00521 return intersection;
00522 }
00523
00524 intersection.setHit();
00525 intersection.setPoint(a_ + u*edge1 + v*edge2);
00526 intersection.setDistance(t);
00527
00528 return intersection;
00529 }
00530
00531
00532 template<class Point, class PointRef>
00533 inline pointHit triangle<Point, PointRef>::nearestPoint
00534 (
00535 const point& p
00536 ) const
00537 {
00538
00539
00540 vector E0 = b_ - a_;
00541 vector E1 = c_ - a_;
00542
00543 return nearestPoint(a_, E0, E1, p);
00544 }
00545
00546
00547 template<class Point, class PointRef>
00548 inline bool triangle<Point, PointRef>::classify
00549 (
00550 const point& p,
00551 const scalar tol,
00552 label& nearType,
00553 label& nearLabel
00554 ) const
00555 {
00556 const vector E0 = b_ - a_;
00557 const vector E1 = c_ - a_;
00558 const vector n = 0.5*(E0 ^ E1);
00559
00560
00561 scalar magX = Foam::mag(n.x());
00562 scalar magY = Foam::mag(n.y());
00563 scalar magZ = Foam::mag(n.z());
00564
00565 label i0 = -1;
00566 if ((magX >= magY) && (magX >= magZ))
00567 {
00568 i0 = 0;
00569 }
00570 else if ((magY >= magX) && (magY >= magZ))
00571 {
00572 i0 = 1;
00573 }
00574 else
00575 {
00576 i0 = 2;
00577 }
00578
00579
00580 label i1 = (i0 + 1) % 3;
00581 label i2 = (i1 + 1) % 3;
00582
00583
00584 scalar u1 = E0[i1];
00585 scalar v1 = E0[i2];
00586
00587 scalar u2 = E1[i1];
00588 scalar v2 = E1[i2];
00589
00590 scalar det = v2*u1 - u2*v1;
00591
00592 scalar u0 = p[i1] - a_[i1];
00593 scalar v0 = p[i2] - a_[i2];
00594
00595 scalar alpha = 0;
00596 scalar beta = 0;
00597
00598 bool hit = false;
00599
00600 if (Foam::mag(u1) < ROOTVSMALL)
00601 {
00602 beta = u0/u2;
00603
00604 alpha = (v0 - beta*v2)/v1;
00605
00606 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
00607 }
00608 else
00609 {
00610 beta = (v0*u1 - u0*v1)/det;
00611
00612 alpha = (u0 - beta*u2)/u1;
00613
00614 hit = ((alpha >= 0) && ((alpha + beta) <= 1));
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 if (hit)
00628 {
00629
00630 alpha = max(0.0, min(1.0, alpha));
00631 beta = max(0.0, min(1.0, beta));
00632 }
00633
00634 nearType = NONE;
00635 nearLabel = -1;
00636
00637 if (Foam::mag(alpha+beta-1) <= tol)
00638 {
00639
00640
00641 if (Foam::mag(alpha) <= tol)
00642 {
00643 nearType = POINT;
00644 nearLabel = 2;
00645 }
00646 else if (Foam::mag(beta) <= tol)
00647 {
00648 nearType = POINT;
00649 nearLabel = 1;
00650 }
00651 else if ((alpha >= 0) && (alpha <= 1) && (beta >= 0) && (beta <= 1))
00652 {
00653 nearType = EDGE;
00654 nearLabel = 1;
00655 }
00656 }
00657 else if (Foam::mag(alpha) <= tol)
00658 {
00659
00660
00661 if (Foam::mag(beta) <= tol)
00662 {
00663 nearType = POINT;
00664 nearLabel = 0;
00665 }
00666 else if (Foam::mag(beta-1) <= tol)
00667 {
00668 nearType = POINT;
00669 nearLabel = 2;
00670 }
00671 else if ((beta >= 0) && (beta <= 1))
00672 {
00673 nearType = EDGE;
00674 nearLabel = 2;
00675 }
00676 }
00677 else if (Foam::mag(beta) <= tol)
00678 {
00679
00680
00681 if (Foam::mag(alpha) <= tol)
00682 {
00683 nearType = POINT;
00684 nearLabel = 0;
00685 }
00686 else if (Foam::mag(alpha-1) <= tol)
00687 {
00688 nearType = POINT;
00689 nearLabel = 1;
00690 }
00691 else if ((alpha >= 0) && (alpha <= 1))
00692 {
00693 nearType = EDGE;
00694 nearLabel = 0;
00695 }
00696 }
00697
00698 return hit;
00699 }
00700
00701
00702
00703
00704
00705
00706
00707 template<class point, class pointRef>
00708 inline Istream& operator>>(Istream& is, triangle<point, pointRef>& t)
00709 {
00710
00711 is.readBegin("triangle");
00712
00713 is >> t.a_ >> t.b_ >> t.c_;
00714
00715
00716 is.readEnd("triangle");
00717
00718
00719 is.check("Istream& operator>>(Istream&, triangle&)");
00720
00721 return is;
00722 }
00723
00724
00725 template<class Point, class PointRef>
00726 inline Ostream& operator<<(Ostream& os, const triangle<Point, PointRef>& t)
00727 {
00728 os << nl
00729 << token::BEGIN_LIST
00730 << t.a_ << token::SPACE << t.b_ << token::SPACE << t.c_
00731 << token::END_LIST;
00732
00733 return os;
00734 }
00735
00736
00737
00738
00739 }
00740
00741
00742