Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // G4TriangularFacet implementation 27 // 28 // 31.10.2004, P R Truscott, QinetiQ Ltd, UK - Created. 29 // 01.08.2007, P R Truscott, QinetiQ Ltd, UK 30 // Significant modification to correct for errors and enhance 31 // based on patches/observations kindly provided by Rickard 32 // Holmberg. 33 // 12.10.2012, M Gayer, CERN 34 // New implementation reducing memory requirements by 50%, 35 // and considerable CPU speedup together with the new 36 // implementation of G4TessellatedSolid. 37 // 23.02.2016, E Tcherniaev, CERN 38 // Improved test to detect degenerate (too small or 39 // too narrow) triangles. 40 // -------------------------------------------------------------------- 41 42 #include "G4TriangularFacet.hh" 43 44 #include "Randomize.hh" 45 #include "G4TessellatedGeometryAlgorithms.hh" 46 47 using namespace std; 48 49 /////////////////////////////////////////////////////////////////////////////// 50 // 51 // Definition of triangular facet using absolute vectors to fVertices. 52 // From this for first vector is retained to define the facet location and 53 // two relative vectors (E0 and E1) define the sides and orientation of 54 // the outward surface normal. 55 // 56 G4TriangularFacet::G4TriangularFacet (const G4ThreeVector& vt0, 57 const G4ThreeVector& vt1, 58 const G4ThreeVector& vt2, 59 G4FacetVertexType vertexType) 60 { 61 fVertices = new vector<G4ThreeVector>(3); 62 63 SetVertex(0, vt0); 64 if (vertexType == ABSOLUTE) 65 { 66 SetVertex(1, vt1); 67 SetVertex(2, vt2); 68 fE1 = vt1 - vt0; 69 fE2 = vt2 - vt0; 70 } 71 else 72 { 73 SetVertex(1, vt0 + vt1); 74 SetVertex(2, vt0 + vt2); 75 fE1 = vt1; 76 fE2 = vt2; 77 } 78 79 G4ThreeVector E1xE2 = fE1.cross(fE2); 80 fArea = 0.5 * E1xE2.mag(); 81 for (G4int i = 0; i < 3; ++i) fIndices[i] = -1; 82 83 fIsDefined = true; 84 G4double delta = kCarTolerance; // Set tolerance for checking 85 86 // Check length of edges 87 // 88 G4double leng1 = fE1.mag(); 89 G4double leng2 = (fE2-fE1).mag(); 90 G4double leng3 = fE2.mag(); 91 if (leng1 <= delta || leng2 <= delta || leng3 <= delta) 92 { 93 fIsDefined = false; 94 } 95 96 // Check min height of triangle 97 // 98 if (fIsDefined) 99 { 100 if (2.*fArea/std::max(std::max(leng1,leng2),leng3) <= delta) 101 { 102 fIsDefined = false; 103 } 104 } 105 106 // Define facet 107 // 108 if (!fIsDefined) 109 { 110 ostringstream message; 111 message << "Facet is too small or too narrow." << G4endl 112 << "Triangle area = " << fArea << G4endl 113 << "P0 = " << GetVertex(0) << G4endl 114 << "P1 = " << GetVertex(1) << G4endl 115 << "P2 = " << GetVertex(2) << G4endl 116 << "Side1 length (P0->P1) = " << leng1 << G4endl 117 << "Side2 length (P1->P2) = " << leng2 << G4endl 118 << "Side3 length (P2->P0) = " << leng3; 119 G4Exception("G4TriangularFacet::G4TriangularFacet()", 120 "GeomSolids1001", JustWarning, message); 121 fSurfaceNormal.set(0,0,0); 122 fA = fB = fC = 0.0; 123 fDet = 0.0; 124 fCircumcentre = vt0 + 0.5*fE1 + 0.5*fE2; 125 fArea = fRadius = 0.0; 126 } 127 else 128 { 129 fSurfaceNormal = E1xE2.unit(); 130 fA = fE1.mag2(); 131 fB = fE1.dot(fE2); 132 fC = fE2.mag2(); 133 fDet = std::fabs(fA*fC - fB*fB); 134 135 fCircumcentre = 136 vt0 + (E1xE2.cross(fE1)*fC + fE2.cross(E1xE2)*fA) / (2.*E1xE2.mag2()); 137 fRadius = (fCircumcentre - vt0).mag(); 138 } 139 } 140 141 /////////////////////////////////////////////////////////////////////////////// 142 // 143 G4TriangularFacet::G4TriangularFacet () 144 { 145 fVertices = new vector<G4ThreeVector>(3); 146 G4ThreeVector zero(0,0,0); 147 SetVertex(0, zero); 148 SetVertex(1, zero); 149 SetVertex(2, zero); 150 for (G4int i = 0; i < 3; ++i) fIndices[i] = -1; 151 fIsDefined = false; 152 fSurfaceNormal.set(0,0,0); 153 fA = fB = fC = 0; 154 fE1 = zero; 155 fE2 = zero; 156 fDet = 0.0; 157 fArea = fRadius = 0.0; 158 } 159 160 /////////////////////////////////////////////////////////////////////////////// 161 // 162 G4TriangularFacet::~G4TriangularFacet () 163 { 164 SetVertices(nullptr); 165 } 166 167 /////////////////////////////////////////////////////////////////////////////// 168 // 169 void G4TriangularFacet::CopyFrom (const G4TriangularFacet& rhs) 170 { 171 auto p = (char *) &rhs; 172 copy(p, p + sizeof(*this), (char *)this); 173 174 if (fIndices[0] < 0 && fVertices == nullptr) 175 { 176 fVertices = new vector<G4ThreeVector>(3); 177 for (G4int i = 0; i < 3; ++i) (*fVertices)[i] = (*rhs.fVertices)[i]; 178 } 179 } 180 181 /////////////////////////////////////////////////////////////////////////////// 182 // 183 void G4TriangularFacet::MoveFrom (G4TriangularFacet& rhs) 184 { 185 fSurfaceNormal = std::move(rhs.fSurfaceNormal); 186 fArea = rhs.fArea; 187 fCircumcentre = std::move(rhs.fCircumcentre); 188 fRadius = rhs.fRadius; 189 fIndices = rhs.fIndices; 190 fA = rhs.fA; fB = rhs.fB; fC = rhs.fC; 191 fDet = rhs.fDet; 192 fSqrDist = rhs.fSqrDist; 193 fE1 = std::move(rhs.fE1); fE2 = std::move(rhs.fE2); 194 fIsDefined = rhs.fIsDefined; 195 fVertices = rhs.fVertices; 196 rhs.fVertices = nullptr; 197 } 198 199 /////////////////////////////////////////////////////////////////////////////// 200 // 201 G4TriangularFacet::G4TriangularFacet (const G4TriangularFacet& rhs) 202 : G4VFacet(rhs) 203 { 204 CopyFrom(rhs); 205 } 206 207 /////////////////////////////////////////////////////////////////////////////// 208 // 209 G4TriangularFacet::G4TriangularFacet (G4TriangularFacet&& rhs) noexcept 210 : G4VFacet(rhs) 211 { 212 MoveFrom(rhs); 213 } 214 215 /////////////////////////////////////////////////////////////////////////////// 216 // 217 G4TriangularFacet& 218 G4TriangularFacet::operator=(const G4TriangularFacet& rhs) 219 { 220 SetVertices(nullptr); 221 222 if (this != &rhs) 223 { 224 delete fVertices; 225 CopyFrom(rhs); 226 } 227 228 return *this; 229 } 230 231 /////////////////////////////////////////////////////////////////////////////// 232 // 233 G4TriangularFacet& 234 G4TriangularFacet::operator=(G4TriangularFacet&& rhs) noexcept 235 { 236 SetVertices(nullptr); 237 238 if (this != &rhs) 239 { 240 delete fVertices; 241 MoveFrom(rhs); 242 } 243 244 return *this; 245 } 246 247 /////////////////////////////////////////////////////////////////////////////// 248 // 249 // GetClone 250 // 251 // Simple member function to generate fA duplicate of the triangular facet. 252 // 253 G4VFacet* G4TriangularFacet::GetClone () 254 { 255 auto fc = new G4TriangularFacet (GetVertex(0), GetVertex(1), 256 GetVertex(2), ABSOLUTE); 257 return fc; 258 } 259 260 /////////////////////////////////////////////////////////////////////////////// 261 // 262 // GetFlippedFacet 263 // 264 // Member function to generate an identical facet, but with the normal vector 265 // pointing at 180 degrees. 266 // 267 G4TriangularFacet* G4TriangularFacet::GetFlippedFacet () 268 { 269 auto flipped = new G4TriangularFacet (GetVertex(0), GetVertex(1), 270 GetVertex(2), ABSOLUTE); 271 return flipped; 272 } 273 274 /////////////////////////////////////////////////////////////////////////////// 275 // 276 // Distance (G4ThreeVector) 277 // 278 // Determines the vector between p and the closest point on the facet to p. 279 // This is based on the algorithm published in "Geometric Tools for Computer 280 // Graphics," Philip J Scheider and David H Eberly, Elsevier Science (USA), 281 // 2003. at the time of writing, the algorithm is also available in fA 282 // technical note "Distance between point and triangle in 3D," by David Eberly 283 // at http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf 284 // 285 // The by-product is the square-distance fSqrDist, which is retained 286 // in case needed by the other "Distance" member functions. 287 // 288 G4ThreeVector G4TriangularFacet::Distance (const G4ThreeVector& p) 289 { 290 G4ThreeVector D = GetVertex(0) - p; 291 G4double d = fE1.dot(D); 292 G4double e = fE2.dot(D); 293 G4double f = D.mag2(); 294 G4double q = fB*e - fC*d; 295 G4double t = fB*d - fA*e; 296 fSqrDist = 0.; 297 298 if (q+t <= fDet) 299 { 300 if (q < 0.0) 301 { 302 if (t < 0.0) 303 { 304 // 305 // We are in region 4. 306 // 307 if (d < 0.0) 308 { 309 t = 0.0; 310 if (-d >= fA) {q = 1.0; fSqrDist = fA + 2.0*d + f;} 311 else {q = -d/fA; fSqrDist = d*q + f;} 312 } 313 else 314 { 315 q = 0.0; 316 if (e >= 0.0) {t = 0.0; fSqrDist = f;} 317 else if (-e >= fC) {t = 1.0; fSqrDist = fC + 2.0*e + f;} 318 else {t = -e/fC; fSqrDist = e*t + f;} 319 } 320 } 321 else 322 { 323 // 324 // We are in region 3. 325 // 326 q = 0.0; 327 if (e >= 0.0) {t = 0.0; fSqrDist = f;} 328 else if (-e >= fC) {t = 1.0; fSqrDist = fC + 2.0*e + f;} 329 else {t = -e/fC; fSqrDist = e*t + f;} 330 } 331 } 332 else if (t < 0.0) 333 { 334 // 335 // We are in region 5. 336 // 337 t = 0.0; 338 if (d >= 0.0) {q = 0.0; fSqrDist = f;} 339 else if (-d >= fA) {q = 1.0; fSqrDist = fA + 2.0*d + f;} 340 else {q = -d/fA; fSqrDist = d*q + f;} 341 } 342 else 343 { 344 // 345 // We are in region 0. 346 // 347 G4double dist = fSurfaceNormal.dot(D); 348 fSqrDist = dist*dist; 349 return fSurfaceNormal*dist; 350 } 351 } 352 else 353 { 354 if (q < 0.0) 355 { 356 // 357 // We are in region 2. 358 // 359 G4double tmp0 = fB + d; 360 G4double tmp1 = fC + e; 361 if (tmp1 > tmp0) 362 { 363 G4double numer = tmp1 - tmp0; 364 G4double denom = fA - 2.0*fB + fC; 365 if (numer >= denom) {q = 1.0; t = 0.0; fSqrDist = fA + 2.0*d + f;} 366 else 367 { 368 q = numer/denom; 369 t = 1.0 - q; 370 fSqrDist = q*(fA*q + fB*t +2.0*d) + t*(fB*q + fC*t + 2.0*e) + f; 371 } 372 } 373 else 374 { 375 q = 0.0; 376 if (tmp1 <= 0.0) {t = 1.0; fSqrDist = fC + 2.0*e + f;} 377 else if (e >= 0.0) {t = 0.0; fSqrDist = f;} 378 else {t = -e/fC; fSqrDist = e*t + f;} 379 } 380 } 381 else if (t < 0.0) 382 { 383 // 384 // We are in region 6. 385 // 386 G4double tmp0 = fB + e; 387 G4double tmp1 = fA + d; 388 if (tmp1 > tmp0) 389 { 390 G4double numer = tmp1 - tmp0; 391 G4double denom = fA - 2.0*fB + fC; 392 if (numer >= denom) {t = 1.0; q = 0.0; fSqrDist = fC + 2.0*e + f;} 393 else 394 { 395 t = numer/denom; 396 q = 1.0 - t; 397 fSqrDist = q*(fA*q + fB*t +2.0*d) + t*(fB*q + fC*t + 2.0*e) + f; 398 } 399 } 400 else 401 { 402 t = 0.0; 403 if (tmp1 <= 0.0) {q = 1.0; fSqrDist = fA + 2.0*d + f;} 404 else if (d >= 0.0) {q = 0.0; fSqrDist = f;} 405 else {q = -d/fA; fSqrDist = d*q + f;} 406 } 407 } 408 else 409 // 410 // We are in region 1. 411 // 412 { 413 G4double numer = fC + e - fB - d; 414 if (numer <= 0.0) 415 { 416 q = 0.0; 417 t = 1.0; 418 fSqrDist = fC + 2.0*e + f; 419 } 420 else 421 { 422 G4double denom = fA - 2.0*fB + fC; 423 if (numer >= denom) {q = 1.0; t = 0.0; fSqrDist = fA + 2.0*d + f;} 424 else 425 { 426 q = numer/denom; 427 t = 1.0 - q; 428 fSqrDist = q*(fA*q + fB*t + 2.0*d) + t*(fB*q + fC*t + 2.0*e) + f; 429 } 430 } 431 } 432 } 433 // 434 // 435 // Do fA check for rounding errors in the distance-squared. It appears that 436 // the conventional methods for calculating fSqrDist breaks down when very 437 // near to or at the surface (as required by transport). 438 // We'll therefore also use the magnitude-squared of the vector displacement. 439 // (Note that I've also tried to get around this problem by using the 440 // existing equations for 441 // 442 // fSqrDist = function(fA,fB,fC,d,q,t) 443 // 444 // and use fA more accurate addition process which minimises errors and 445 // breakdown of cummutitivity [where (A+B)+C != A+(B+C)] but this still 446 // doesn't work. 447 // Calculation from u = D + q*fE1 + t*fE2 is less efficient, but appears 448 // more robust. 449 // 450 if (fSqrDist < 0.0) fSqrDist = 0.; 451 G4ThreeVector u = D + q*fE1 + t*fE2; 452 G4double u2 = u.mag2(); 453 // 454 // The following (part of the roundoff error check) is from Oliver Merle'q 455 // updates. 456 // 457 if (fSqrDist > u2) fSqrDist = u2; 458 459 return u; 460 } 461 462 /////////////////////////////////////////////////////////////////////////////// 463 // 464 // Distance (G4ThreeVector, G4double) 465 // 466 // Determines the closest distance between point p and the facet. This makes 467 // use of G4ThreeVector G4TriangularFacet::Distance, which stores the 468 // square of the distance in variable fSqrDist. If approximate methods show 469 // the distance is to be greater than minDist, then forget about further 470 // computation and return fA very large number. 471 // 472 G4double G4TriangularFacet::Distance (const G4ThreeVector& p, 473 G4double minDist) 474 { 475 // 476 // Start with quicky test to determine if the surface of the sphere enclosing 477 // the triangle is any closer to p than minDist. If not, then don't bother 478 // about more accurate test. 479 // 480 G4double dist = kInfinity; 481 if ((p-fCircumcentre).mag()-fRadius < minDist) 482 { 483 // 484 // It's possible that the triangle is closer than minDist, 485 // so do more accurate assessment. 486 // 487 dist = Distance(p).mag(); 488 } 489 return dist; 490 } 491 492 /////////////////////////////////////////////////////////////////////////////// 493 // 494 // Distance (G4ThreeVector, G4double, G4bool) 495 // 496 // Determine the distance to point p. kInfinity is returned if either: 497 // (1) outgoing is TRUE and the dot product of the normal vector to the facet 498 // and the displacement vector from p to the triangle is negative. 499 // (2) outgoing is FALSE and the dot product of the normal vector to the facet 500 // and the displacement vector from p to the triangle is positive. 501 // If approximate methods show the distance is to be greater than minDist, then 502 // forget about further computation and return fA very large number. 503 // 504 // This method has been heavily modified thanks to the valuable comments and 505 // corrections of Rickard Holmberg. 506 // 507 G4double G4TriangularFacet::Distance (const G4ThreeVector& p, 508 G4double minDist, 509 const G4bool outgoing) 510 { 511 // 512 // Start with quicky test to determine if the surface of the sphere enclosing 513 // the triangle is any closer to p than minDist. If not, then don't bother 514 // about more accurate test. 515 // 516 G4double dist = kInfinity; 517 if ((p-fCircumcentre).mag()-fRadius < minDist) 518 { 519 // 520 // It's possible that the triangle is closer than minDist, 521 // so do more accurate assessment. 522 // 523 G4ThreeVector v = Distance(p); 524 G4double dist1 = sqrt(fSqrDist); 525 G4double dir = v.dot(fSurfaceNormal); 526 G4bool wrongSide = (dir > 0.0 && !outgoing) || (dir < 0.0 && outgoing); 527 if (dist1 <= kCarTolerance) 528 { 529 // 530 // Point p is very close to triangle. Check if it's on the wrong side, 531 // in which case return distance of 0.0 otherwise . 532 // 533 if (wrongSide) dist = 0.0; 534 else dist = dist1; 535 } 536 else if (!wrongSide) dist = dist1; 537 } 538 return dist; 539 } 540 541 /////////////////////////////////////////////////////////////////////////////// 542 // 543 // Extent 544 // 545 // Calculates the furthest the triangle extends in fA particular direction 546 // defined by the vector axis. 547 // 548 G4double G4TriangularFacet::Extent (const G4ThreeVector axis) 549 { 550 G4double ss = GetVertex(0).dot(axis); 551 G4double sp = GetVertex(1).dot(axis); 552 if (sp > ss) ss = sp; 553 sp = GetVertex(2).dot(axis); 554 if (sp > ss) ss = sp; 555 return ss; 556 } 557 558 /////////////////////////////////////////////////////////////////////////////// 559 // 560 // Intersect 561 // 562 // Member function to find the next intersection when going from p in the 563 // direction of v. If: 564 // (1) "outgoing" is TRUE, only consider the face if we are going out through 565 // the face. 566 // (2) "outgoing" is FALSE, only consider the face if we are going in through 567 // the face. 568 // Member functions returns TRUE if there is an intersection, FALSE otherwise. 569 // Sets the distance (distance along w), distFromSurface (orthogonal distance) 570 // and normal. 571 // 572 // Also considers intersections that happen with negative distance for small 573 // distances of distFromSurface = 0.5*kCarTolerance in the wrong direction. 574 // This is to detect kSurface without doing fA full Inside(p) in 575 // G4TessellatedSolid::Distance(p,v) calculation. 576 // 577 // This member function is thanks the valuable work of Rickard Holmberg. PT. 578 // However, "gotos" are the Work of the Devil have been exorcised with 579 // extreme prejudice!! 580 // 581 // IMPORTANT NOTE: These calculations are predicated on v being fA unit 582 // vector. If G4TessellatedSolid or other classes call this member function 583 // with |v| != 1 then there will be errors. 584 // 585 G4bool G4TriangularFacet::Intersect (const G4ThreeVector& p, 586 const G4ThreeVector& v, 587 G4bool outgoing, 588 G4double& distance, 589 G4double& distFromSurface, 590 G4ThreeVector& normal) 591 { 592 // 593 // Check whether the direction of the facet is consistent with the vector v 594 // and the need to be outgoing or ingoing. If inconsistent, disregard and 595 // return false. 596 // 597 G4double w = v.dot(fSurfaceNormal); 598 if ((outgoing && w < -dirTolerance) || (!outgoing && w > dirTolerance)) 599 { 600 distance = kInfinity; 601 distFromSurface = kInfinity; 602 normal.set(0,0,0); 603 return false; 604 } 605 // 606 // Calculate the orthogonal distance from p to the surface containing the 607 // triangle. Then determine if we're on the right or wrong side of the 608 // surface (at fA distance greater than kCarTolerance to be consistent with 609 // "outgoing". 610 // 611 const G4ThreeVector& p0 = GetVertex(0); 612 G4ThreeVector D = p0 - p; 613 distFromSurface = D.dot(fSurfaceNormal); 614 G4bool wrongSide = (outgoing && distFromSurface < -0.5*kCarTolerance) || 615 (!outgoing && distFromSurface > 0.5*kCarTolerance); 616 617 if (wrongSide) 618 { 619 distance = kInfinity; 620 distFromSurface = kInfinity; 621 normal.set(0,0,0); 622 return false; 623 } 624 625 wrongSide = (outgoing && distFromSurface < 0.0) 626 || (!outgoing && distFromSurface > 0.0); 627 if (wrongSide) 628 { 629 // 630 // We're slightly on the wrong side of the surface. Check if we're close 631 // enough using fA precise distance calculation. 632 // 633 G4ThreeVector u = Distance(p); 634 if (fSqrDist <= kCarTolerance*kCarTolerance) 635 { 636 // 637 // We're very close. Therefore return fA small negative number 638 // to pretend we intersect. 639 // 640 // distance = -0.5*kCarTolerance 641 distance = 0.0; 642 normal = fSurfaceNormal; 643 return true; 644 } 645 else 646 { 647 // 648 // We're close to the surface containing the triangle, but sufficiently 649 // far from the triangle, and on the wrong side compared to the directions 650 // of the surface normal and v. There is no intersection. 651 // 652 distance = kInfinity; 653 distFromSurface = kInfinity; 654 normal.set(0,0,0); 655 return false; 656 } 657 } 658 if (w < dirTolerance && w > -dirTolerance) 659 { 660 // 661 // The ray is within the plane of the triangle. Project the problem into 2D 662 // in the plane of the triangle. First try to create orthogonal unit vectors 663 // mu and nu, where mu is fE1/|fE1|. This is kinda like 664 // the original algorithm due to Rickard Holmberg, but with better 665 // mathematical justification than the original method ... however, 666 // beware Rickard's was less time-consuming. 667 // 668 // Note that vprime is not fA unit vector. We need to keep it unnormalised 669 // since the values of distance along vprime (s0 and s1) for intersection 670 // with the triangle will be used to determine if we cut the plane at the 671 // same time. 672 // 673 G4ThreeVector mu = fE1.unit(); 674 G4ThreeVector nu = fSurfaceNormal.cross(mu); 675 G4TwoVector pprime(p.dot(mu), p.dot(nu)); 676 G4TwoVector vprime(v.dot(mu), v.dot(nu)); 677 G4TwoVector P0prime(p0.dot(mu), p0.dot(nu)); 678 G4TwoVector E0prime(fE1.mag(), 0.0); 679 G4TwoVector E1prime(fE2.dot(mu), fE2.dot(nu)); 680 G4TwoVector loc[2]; 681 if (G4TessellatedGeometryAlgorithms::IntersectLineAndTriangle2D(pprime, 682 vprime, P0prime, E0prime, E1prime, loc)) 683 { 684 // 685 // There is an intersection between the line and triangle in 2D. 686 // Now check which part of the line intersects with the plane 687 // containing the triangle in 3D. 688 // 689 G4double vprimemag = vprime.mag(); 690 G4double s0 = (loc[0] - pprime).mag()/vprimemag; 691 G4double s1 = (loc[1] - pprime).mag()/vprimemag; 692 G4double normDist0 = fSurfaceNormal.dot(s0*v) - distFromSurface; 693 G4double normDist1 = fSurfaceNormal.dot(s1*v) - distFromSurface; 694 695 if ((normDist0 < 0.0 && normDist1 < 0.0) 696 || (normDist0 > 0.0 && normDist1 > 0.0) 697 || (normDist0 == 0.0 && normDist1 == 0.0) ) 698 { 699 distance = kInfinity; 700 distFromSurface = kInfinity; 701 normal.set(0,0,0); 702 return false; 703 } 704 else 705 { 706 G4double dnormDist = normDist1 - normDist0; 707 if (fabs(dnormDist) < DBL_EPSILON) 708 { 709 distance = s0; 710 normal = fSurfaceNormal; 711 if (!outgoing) distFromSurface = -distFromSurface; 712 return true; 713 } 714 else 715 { 716 distance = s0 - normDist0*(s1-s0)/dnormDist; 717 normal = fSurfaceNormal; 718 if (!outgoing) distFromSurface = -distFromSurface; 719 return true; 720 } 721 } 722 } 723 else 724 { 725 distance = kInfinity; 726 distFromSurface = kInfinity; 727 normal.set(0,0,0); 728 return false; 729 } 730 } 731 // 732 // 733 // Use conventional algorithm to determine the whether there is an 734 // intersection. This involves determining the point of intersection of the 735 // line with the plane containing the triangle, and then calculating if the 736 // point is within the triangle. 737 // 738 distance = distFromSurface / w; 739 G4ThreeVector pp = p + v*distance; 740 G4ThreeVector DD = p0 - pp; 741 G4double d = fE1.dot(DD); 742 G4double e = fE2.dot(DD); 743 G4double ss = fB*e - fC*d; 744 G4double t = fB*d - fA*e; 745 746 G4double sTolerance = (fabs(fB)+ fabs(fC) + fabs(d) + fabs(e))*kCarTolerance; 747 G4double tTolerance = (fabs(fA)+ fabs(fB) + fabs(d) + fabs(e))*kCarTolerance; 748 G4double detTolerance = (fabs(fA)+ fabs(fC) + 2*fabs(fB) )*kCarTolerance; 749 750 //if (ss < 0.0 || t < 0.0 || ss+t > fDet) 751 if (ss < -sTolerance || t < -tTolerance || ( ss+t - fDet ) > detTolerance) 752 { 753 // 754 // The intersection is outside of the triangle. 755 // 756 distance = distFromSurface = kInfinity; 757 normal.set(0,0,0); 758 return false; 759 } 760 else 761 { 762 // 763 // There is an intersection. Now we only need to set the surface normal. 764 // 765 normal = fSurfaceNormal; 766 if (!outgoing) distFromSurface = -distFromSurface; 767 return true; 768 } 769 } 770 771 //////////////////////////////////////////////////////////////////////// 772 // 773 // GetPointOnFace 774 // 775 // Auxiliary method, returns a uniform random point on the facet 776 // 777 G4ThreeVector G4TriangularFacet::GetPointOnFace() const 778 { 779 G4double u = G4UniformRand(); 780 G4double v = G4UniformRand(); 781 if (u+v > 1.) { u = 1. - u; v = 1. - v; } 782 return GetVertex(0) + u*fE1 + v*fE2; 783 } 784 785 //////////////////////////////////////////////////////////////////////// 786 // 787 // GetArea 788 // 789 // Auxiliary method for returning the surface fArea 790 // 791 G4double G4TriangularFacet::GetArea() const 792 { 793 return fArea; 794 } 795 796 //////////////////////////////////////////////////////////////////////// 797 // 798 G4GeometryType G4TriangularFacet::GetEntityType () const 799 { 800 return "G4TriangularFacet"; 801 } 802 803 //////////////////////////////////////////////////////////////////////// 804 // 805 G4ThreeVector G4TriangularFacet::GetSurfaceNormal () const 806 { 807 return fSurfaceNormal; 808 } 809 810 //////////////////////////////////////////////////////////////////////// 811 // 812 void G4TriangularFacet::SetSurfaceNormal (const G4ThreeVector& normal) 813 { 814 fSurfaceNormal = normal; 815 } 816