// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // // $Id: G4Trap.cc,v 1.45 2008/04/23 09:49:57 gcosmo Exp $ // GEANT4 tag $Name: geant4-09-04-beta-01 $ // // class G4Trap // // Implementation for G4Trap class // // History: // // 28.04.05 V.Grichine: new SurfaceNormal according to J. Apostolakis proposal // 26.04.05 V.Grichine: new SurfaceNormal is default // 19.04.05 V.Grichine: bug fixed in G4Trap("name",G4ThreeVector[8] vp) // 12.12.04 V.Grichine: SurfaceNormal with edges/vertices // 15.11.04 V.Grichine: bug fixed in G4Trap("name",G4ThreeVector[8] vp) // 13.12.99 V.Grichine: bug fixed in DistanceToIn(p,v) // 19.11.99 V.Grichine: kUndef was added to Eside enum // 04.06.99 S.Giani: Fixed CalculateExtent in rotated case. // 08.12.97 J.Allison: Added "nominal" constructor and method SetAllParameters. // 01.11.96 V.Grichine: Costructor for Right Angular Wedge from STEP, G4Trd/Para // 09.09.96 V.Grichine: Final modifications before to commit // 21.03.95 P.Kent: Modified for `tolerant' geometry // //////////////////////////////////////////////////////////////////////////////////// #include "G4Trap.hh" #include "globals.hh" #include "G4VoxelLimits.hh" #include "G4AffineTransform.hh" #include "G4VPVParameterisation.hh" #include "Randomize.hh" #include "G4VGraphicsScene.hh" #include "G4Polyhedron.hh" #include "G4NURBS.hh" #include "G4NURBSbox.hh" using namespace CLHEP; //////////////////////////////////////////////////////////////////////// // // Accuracy of coplanarity const G4double kCoplanar_Tolerance = 1E-4 ; ////////////////////////////////////////////////////////////////////////// // // Private enum: Not for external use enum Eside {kUndef,ks0,ks1,ks2,ks3,kPZ,kMZ}; ////////////////////////////////////////////////////////////////////////// // // Constructor - check and set half-widths as well as angles: // final check of coplanarity G4Trap::G4Trap( const G4String& pName, G4double pDz, G4double pTheta, G4double pPhi, G4double pDy1, G4double pDx1, G4double pDx2, G4double pAlp1, G4double pDy2, G4double pDx3, G4double pDx4, G4double pAlp2) : G4CSGSolid(pName) { if ( pDz > 0 && pDy1 > 0 && pDx1 > 0 && pDx2 > 0 && pDy2 > 0 && pDx3 > 0 && pDx4 > 0 ) { fDz=pDz; fTthetaCphi=std::tan(pTheta)*std::cos(pPhi); fTthetaSphi=std::tan(pTheta)*std::sin(pPhi); fDy1=pDy1; fDx1=pDx1; fDx2=pDx2; fTalpha1=std::tan(pAlp1); fDy2=pDy2; fDx3=pDx3; fDx4=pDx4; fTalpha2=std::tan(pAlp2); MakePlanes(); } else { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl << " Invalid dimensions !" << G4endl << " X - " << pDx1 << ", " << pDx2 << ", " << pDx3 << ", " << pDx4 << G4endl << " Y - " << pDy1 << ", " << pDy2 << G4endl << " Z - " << pDz << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Invalid length G4Trap parameters."); } } //////////////////////////////////////////////////////////////////////////// // // Constructor - Design of trapezoid based on 8 G4ThreeVector parameters, // which are its vertices. Checking of planarity with preparation of // fPlanes[] and than calculation of other members G4Trap::G4Trap( const G4String& pName, const G4ThreeVector pt[8] ) : G4CSGSolid(pName) { // Start with check of centering - the center of gravity trap line // should cross the origin of frame if ( pt[0].z() < 0 && pt[0].z() == pt[1].z() && pt[0].z() == pt[2].z() && pt[0].z() == pt[3].z() && pt[4].z() > 0 && pt[4].z() == pt[5].z() && pt[4].z() == pt[6].z() && pt[4].z() == pt[7].z() && std::fabs( pt[0].z() + pt[4].z() ) < kCarTolerance && pt[0].y() == pt[1].y() && pt[2].y() == pt[3].y() && pt[4].y() == pt[5].y() && pt[6].y() == pt[7].y() && std::fabs( pt[0].y() + pt[2].y() + pt[4].y() + pt[6].y() ) < kCarTolerance && std::fabs( pt[0].x() + pt[1].x() + pt[4].x() + pt[5].x() + pt[2].x() + pt[3].x() + pt[6].x() + pt[7].x() ) < kCarTolerance ) { G4bool good; // Bottom side with normal approx. -Y good = MakePlane(pt[0],pt[4],pt[5],pt[1],fPlanes[0]); if (!good) { DumpInfo(); G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-Y not planar."); } // Top side with normal approx. +Y good = MakePlane(pt[2],pt[3],pt[7],pt[6],fPlanes[1]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+Y not planar."); } // Front side with normal approx. -X good = MakePlane(pt[0],pt[2],pt[6],pt[4],fPlanes[2]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-X not planar."); } // Back side iwth normal approx. +X good = MakePlane(pt[1],pt[5],pt[7],pt[3],fPlanes[3]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+X not planar."); } fDz = (pt[7]).z() ; fDy1 = ((pt[2]).y()-(pt[1]).y())*0.5; fDx1 = ((pt[1]).x()-(pt[0]).x())*0.5; fDx2 = ((pt[3]).x()-(pt[2]).x())*0.5; fTalpha1 = ((pt[2]).x()+(pt[3]).x()-(pt[1]).x()-(pt[0]).x())*0.25/fDy1; fDy2 = ((pt[6]).y()-(pt[5]).y())*0.5; fDx3 = ((pt[5]).x()-(pt[4]).x())*0.5; fDx4 = ((pt[7]).x()-(pt[6]).x())*0.5; fTalpha2 = ((pt[6]).x()+(pt[7]).x()-(pt[5]).x()-(pt[4]).x())*0.25/fDy2; fTthetaCphi = ((pt[4]).x()+fDy2*fTalpha2+fDx3)/fDz; fTthetaSphi = ((pt[4]).y()+fDy2)/fDz; } else { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Invalid vertice coordinates."); } } ////////////////////////////////////////////////////////////////////////////// // // Constructor for Right Angular Wedge from STEP G4Trap::G4Trap( const G4String& pName, G4double pZ, G4double pY, G4double pX, G4double pLTX ) : G4CSGSolid(pName) { G4bool good; if ( pZ>0 && pY>0 && pX>0 && pLTX>0 && pLTX<=pX ) { fDz = 0.5*pZ ; fTthetaCphi = 0 ; fTthetaSphi = 0 ; fDy1 = 0.5*pY; fDx1 = 0.5*pX ; fDx2 = 0.5*pLTX; fTalpha1 = 0.5*(pLTX - pX)/pY; fDy2 = fDy1 ; fDx3 = fDx1; fDx4 = fDx2 ; fTalpha2 = fTalpha1 ; G4ThreeVector pt[8] ; pt[0]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[1]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[2]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[3]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[4]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[5]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[6]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); pt[7]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); // Bottom side with normal approx. -Y // good=MakePlane(pt[0],pt[4],pt[5],pt[1],fPlanes[0]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-Y not planar."); } // Top side with normal approx. +Y // good=MakePlane(pt[2],pt[3],pt[7],pt[6],fPlanes[1]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+Y not planar."); } // Front side with normal approx. -X // good=MakePlane(pt[0],pt[2],pt[6],pt[4],fPlanes[2]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-X not planar."); } // Back side iwth normal approx. +X // good=MakePlane(pt[1],pt[5],pt[7],pt[3],fPlanes[3]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+X not planar."); } } else { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Invalid length G4Trap parameters."); } } /////////////////////////////////////////////////////////////////////////////// // // Constructor for G4Trd G4Trap::G4Trap( const G4String& pName, G4double pDx1, G4double pDx2, G4double pDy1, G4double pDy2, G4double pDz ) : G4CSGSolid(pName) { G4bool good; if ( pDz>0 && pDy1>0 && pDx1>0 && pDx2>0 && pDy2>0 ) { fDz = pDz; fTthetaCphi = 0 ; fTthetaSphi = 0 ; fDy1 = pDy1 ; fDx1 = pDx1 ; fDx2 = pDx1 ; fTalpha1 = 0 ; fDy2 = pDy2 ; fDx3 = pDx2 ; fDx4 = pDx2 ; fTalpha2 = 0 ; G4ThreeVector pt[8] ; pt[0]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[1]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[2]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[3]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[4]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[5]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[6]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); pt[7]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); // Bottom side with normal approx. -Y // good=MakePlane(pt[0],pt[4],pt[5],pt[1],fPlanes[0]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-Y not planar."); } // Top side with normal approx. +Y // good=MakePlane(pt[2],pt[3],pt[7],pt[6],fPlanes[1]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+Y not planar."); } // Front side with normal approx. -X // good=MakePlane(pt[0],pt[2],pt[6],pt[4],fPlanes[2]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-X not planar."); } // Back side iwth normal approx. +X // good=MakePlane(pt[1],pt[5],pt[7],pt[3],fPlanes[3]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+X not planar."); } } else { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Invalid length G4Trap parameters."); } } //////////////////////////////////////////////////////////////////////////// // // Constructor for G4Para G4Trap::G4Trap( const G4String& pName, G4double pDx, G4double pDy, G4double pDz, G4double pAlpha, G4double pTheta, G4double pPhi) : G4CSGSolid(pName) { G4bool good; if ( pDz>0 && pDy>0 && pDx>0 ) { fDz = pDz ; fTthetaCphi = std::tan(pTheta)*std::cos(pPhi) ; fTthetaSphi = std::tan(pTheta)*std::sin(pPhi) ; fDy1 = pDy ; fDx1 = pDx ; fDx2 = pDx ; fTalpha1 = std::tan(pAlpha) ; fDy2 = pDy ; fDx3 = pDx ; fDx4 = pDx ; fTalpha2 = fTalpha1 ; G4ThreeVector pt[8] ; pt[0]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[1]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[2]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[3]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[4]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[5]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[6]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); pt[7]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); // Bottom side with normal approx. -Y // good=MakePlane(pt[0],pt[4],pt[5],pt[1],fPlanes[0]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-Y not planar."); } // Top side with normal approx. +Y // good=MakePlane(pt[2],pt[3],pt[7],pt[6],fPlanes[1]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+Y not planar."); } // Front side with normal approx. -X // good=MakePlane(pt[0],pt[2],pt[6],pt[4],fPlanes[2]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~-X not planar."); } // Back side iwth normal approx. +X // good=MakePlane(pt[1],pt[5],pt[7],pt[3],fPlanes[3]); if (!good) { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Face at ~+X not planar."); } } else { G4cerr << "ERROR - G4Trap()::G4Trap(): " << GetName() << G4endl; G4Exception("G4Trap::G4Trap()", "InvalidSetup", FatalException, "Invalid length G4Trap parameters."); } } /////////////////////////////////////////////////////////////////////////// // // Nominal constructor for G4Trap whose parameters are to be set by // a G4VParamaterisation later. Check and set half-widths as well as // angles: final check of coplanarity G4Trap::G4Trap( const G4String& pName ) : G4CSGSolid (pName), fDz (1.), fTthetaCphi (0.), fTthetaSphi (0.), fDy1 (1.), fDx1 (1.), fDx2 (1.), fTalpha1 (0.), fDy2 (1.), fDx3 (1.), fDx4 (1.), fTalpha2 (0.) { MakePlanes(); } /////////////////////////////////////////////////////////////////////// // // Fake default constructor - sets only member data and allocates memory // for usage restricted to object persistency. // G4Trap::G4Trap( __void__& a ) : G4CSGSolid(a) { } //////////////////////////////////////////////////////////////////////// // // Destructor G4Trap::~G4Trap() { } /////////////////////////////////////////////////////////////////////// // // Set all parameters, as for constructor - check and set half-widths // as well as angles: final check of coplanarity void G4Trap::SetAllParameters ( G4double pDz, G4double pTheta, G4double pPhi, G4double pDy1, G4double pDx1, G4double pDx2, G4double pAlp1, G4double pDy2, G4double pDx3, G4double pDx4, G4double pAlp2 ) { fCubicVolume= 0.; fSurfaceArea= 0.; fpPolyhedron = 0; if ( pDz>0 && pDy1>0 && pDx1>0 && pDx2>0 && pDy2>0 && pDx3>0 && pDx4>0 ) { fDz=pDz; fTthetaCphi=std::tan(pTheta)*std::cos(pPhi); fTthetaSphi=std::tan(pTheta)*std::sin(pPhi); fDy1=pDy1; fDx1=pDx1; fDx2=pDx2; fTalpha1=std::tan(pAlp1); fDy2=pDy2; fDx3=pDx3; fDx4=pDx4; fTalpha2=std::tan(pAlp2); MakePlanes(); } else { G4cerr << "ERROR - G4Trap()::SetAllParameters(): " << GetName() << G4endl << " Invalid dimensions !" << G4endl << " X - " << pDx1 << ", " << pDx2 << ", " << pDx3 << ", " << pDx4 << G4endl << " Y - " << pDy1 << ", " << pDy2 << G4endl << " Z - " << pDz << G4endl; G4Exception("G4Trap::SetAllParameters()", "InvalidSetup", FatalException, "Invalid Length Parameters."); } } ////////////////////////////////////////////////////////////////////////// // // Checking of coplanarity G4bool G4Trap::MakePlanes() { G4bool good = true; G4ThreeVector pt[8] ; pt[0]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[1]=G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[2]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[3]=G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[4]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[5]=G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[6]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); pt[7]=G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); // Bottom side with normal approx. -Y // good=MakePlane(pt[0],pt[4],pt[5],pt[1],fPlanes[0]) ; if (!good) { G4cerr << "ERROR - G4Trap()::MakePlanes(): " << GetName() << G4endl; G4Exception("G4Trap::MakePlanes()", "InvalidSetup", FatalException, "Face at ~-Y not planar."); } // Top side with normal approx. +Y // good=MakePlane(pt[2],pt[3],pt[7],pt[6],fPlanes[1]); if (!good) { G4cerr << "ERROR - G4Trap()::MakePlanes(): " << GetName() << G4endl; G4Exception("G4Trap::MakePlanes()", "InvalidSetup", FatalException, "Face at ~+Y not planar."); } // Front side with normal approx. -X // good=MakePlane(pt[0],pt[2],pt[6],pt[4],fPlanes[2]); if (!good) { G4cerr << "ERROR - G4Trap()::MakePlanes(): " << GetName() << G4endl; G4Exception("G4Trap::MakePlanes()", "InvalidSetup", FatalException, "Face at ~-X not planar."); } // Back side iwth normal approx. +X // good = MakePlane(pt[1],pt[5],pt[7],pt[3],fPlanes[3]); if ( !good ) { G4cerr << "ERROR - G4Trap()::MakePlanes(): " << GetName() << G4endl; G4Exception("G4Trap::MakePlanes()", "InvalidSetup", FatalException, "Face at ~+X not planar"); } return good; } ////////////////////////////////////////////////////////////////////////////// // // Calculate the coef's of the plane p1->p2->p3->p4->p1 // where the ThreeVectors 1-4 are in anti-clockwise order when viewed from // infront of the plane (i.e. from normal direction). // // Return true if the ThreeVectors are coplanar + set coef;s // false if ThreeVectors are not coplanar G4bool G4Trap::MakePlane( const G4ThreeVector& p1, const G4ThreeVector& p2, const G4ThreeVector& p3, const G4ThreeVector& p4, TrapSidePlane& plane ) { G4double a, b, c, s; G4ThreeVector v12, v13, v14, Vcross; G4bool good; v12 = p2 - p1; v13 = p3 - p1; v14 = p4 - p1; Vcross = v12.cross(v13); if (std::fabs(Vcross.dot(v14)/(Vcross.mag()*v14.mag())) > kCoplanar_Tolerance) { good = false; } else { // a,b,c correspond to the x/y/z components of the // normal vector to the plane // a = (p2.y()-p1.y())*(p1.z()+p2.z())+(p3.y()-p2.y())*(p2.z()+p3.z()); // a += (p4.y()-p3.y())*(p3.z()+p4.z())+(p1.y()-p4.y())*(p4.z()+p1.z()); // ? // b = (p2.z()-p1.z())*(p1.x()+p2.x())+(p3.z()-p2.z())*(p2.x()+p3.x()); // b += (p4.z()-p3.z())*(p3.x()+p4.x())+(p1.z()-p4.z())*(p4.x()+p1.x()); // ? // c = (p2.x()-p1.x())*(p1.y()+p2.y())+(p3.x()-p2.x())*(p2.y()+p3.y()); // c += (p4.x()-p3.x())*(p3.y()+p4.y())+(p1.x()-p4.x())*(p4.y()+p1.y()); // ? // Let create diagonals 4-2 and 3-1 than (4-2)x(3-1) provides // vector perpendicular to the plane directed to outside !!! // and a,b,c, = f(1,2,3,4) external relative to trap normal a = +(p4.y() - p2.y())*(p3.z() - p1.z()) - (p3.y() - p1.y())*(p4.z() - p2.z()); b = -(p4.x() - p2.x())*(p3.z() - p1.z()) + (p3.x() - p1.x())*(p4.z() - p2.z()); c = +(p4.x() - p2.x())*(p3.y() - p1.y()) - (p3.x() - p1.x())*(p4.y() - p2.y()); s = std::sqrt( a*a + b*b + c*c ); // so now vector plane.(a,b,c) is unit if( s > 0 ) { plane.a = a/s; plane.b = b/s; plane.c = c/s; } else { G4cerr << "ERROR - G4Trap()::MakePlane(): " << GetName() << G4endl; G4Exception("G4Trap::MakePlanes()", "InvalidSetup", FatalException, "Invalid parameters: norm.mod() <= 0") ; } // Calculate D: p1 in in plane so D=-n.p1.Vect() plane.d = -( plane.a*p1.x() + plane.b*p1.y() + plane.c*p1.z() ); good = true; } return good; } ////////////////////////////////////////////////////////////////////////////// // // Dispatch to parameterisation for replication mechanism dimension // computation & modification. void G4Trap::ComputeDimensions( G4VPVParameterisation* p, const G4int n, const G4VPhysicalVolume* pRep ) { p->ComputeDimensions(*this,n,pRep); } //////////////////////////////////////////////////////////////////////// // // Calculate extent under transform and specified limit G4bool G4Trap::CalculateExtent( const EAxis pAxis, const G4VoxelLimits& pVoxelLimit, const G4AffineTransform& pTransform, G4double& pMin, G4double& pMax) const { G4double xMin, xMax, yMin, yMax, zMin, zMax; G4bool flag; if (!pTransform.IsRotated()) { // Special case handling for unrotated trapezoids // Compute z/x/y/ mins and maxs respecting limits, with early returns // if outside limits. Then switch() on pAxis G4int i ; G4double xoffset; G4double yoffset; G4double zoffset; G4double temp[8] ; // some points for intersection with zMin/zMax G4ThreeVector pt[8]; // vertices after translation xoffset=pTransform.NetTranslation().x(); yoffset=pTransform.NetTranslation().y(); zoffset=pTransform.NetTranslation().z(); pt[0]=G4ThreeVector(xoffset-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, yoffset-fDz*fTthetaSphi-fDy1,zoffset-fDz); pt[1]=G4ThreeVector(xoffset-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, yoffset-fDz*fTthetaSphi-fDy1,zoffset-fDz); pt[2]=G4ThreeVector(xoffset-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, yoffset-fDz*fTthetaSphi+fDy1,zoffset-fDz); pt[3]=G4ThreeVector(xoffset-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, yoffset-fDz*fTthetaSphi+fDy1,zoffset-fDz); pt[4]=G4ThreeVector(xoffset+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, yoffset+fDz*fTthetaSphi-fDy2,zoffset+fDz); pt[5]=G4ThreeVector(xoffset+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, yoffset+fDz*fTthetaSphi-fDy2,zoffset+fDz); pt[6]=G4ThreeVector(xoffset+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, yoffset+fDz*fTthetaSphi+fDy2,zoffset+fDz); pt[7]=G4ThreeVector(xoffset+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, yoffset+fDz*fTthetaSphi+fDy2,zoffset+fDz); zMin=zoffset-fDz; zMax=zoffset+fDz; if ( pVoxelLimit.IsZLimited() ) { if ( (zMin > pVoxelLimit.GetMaxZExtent() + kCarTolerance) || (zMax < pVoxelLimit.GetMinZExtent() - kCarTolerance) ) { return false; } else { if ( zMin < pVoxelLimit.GetMinZExtent() ) { zMin = pVoxelLimit.GetMinZExtent() ; } if ( zMax > pVoxelLimit.GetMaxZExtent() ) { zMax = pVoxelLimit.GetMaxZExtent() ; } } } temp[0] = pt[0].y()+(pt[4].y()-pt[0].y())*(zMin-pt[0].z()) /(pt[4].z()-pt[0].z()) ; temp[1] = pt[0].y()+(pt[4].y()-pt[0].y())*(zMax-pt[0].z()) /(pt[4].z()-pt[0].z()) ; temp[2] = pt[2].y()+(pt[6].y()-pt[2].y())*(zMin-pt[2].z()) /(pt[6].z()-pt[2].z()) ; temp[3] = pt[2].y()+(pt[6].y()-pt[2].y())*(zMax-pt[2].z()) /(pt[6].z()-pt[2].z()) ; yMax = yoffset - std::fabs(fDz*fTthetaSphi) - fDy1 - fDy2 ; yMin = -yMax ; for( i = 0 ; i < 4 ; i++ ) { if( temp[i] > yMax ) yMax = temp[i] ; if( temp[i] < yMin ) yMin = temp[i] ; } if ( pVoxelLimit.IsYLimited() ) { if ( (yMin > pVoxelLimit.GetMaxYExtent() + kCarTolerance) || (yMax < pVoxelLimit.GetMinYExtent() - kCarTolerance) ) { return false; } else { if ( yMin < pVoxelLimit.GetMinYExtent() ) { yMin = pVoxelLimit.GetMinYExtent() ; } if ( yMax > pVoxelLimit.GetMaxYExtent() ) { yMax = pVoxelLimit.GetMaxYExtent() ; } } } temp[0] = pt[0].x()+(pt[4].x()-pt[0].x()) *(zMin-pt[0].z())/(pt[4].z()-pt[0].z()) ; temp[1] = pt[0].x()+(pt[4].x()-pt[0].x()) *(zMax-pt[0].z())/(pt[4].z()-pt[0].z()) ; temp[2] = pt[2].x()+(pt[6].x()-pt[2].x()) *(zMin-pt[2].z())/(pt[6].z()-pt[2].z()) ; temp[3] = pt[2].x()+(pt[6].x()-pt[2].x()) *(zMax-pt[2].z())/(pt[6].z()-pt[2].z()) ; temp[4] = pt[3].x()+(pt[7].x()-pt[3].x()) *(zMin-pt[3].z())/(pt[7].z()-pt[3].z()) ; temp[5] = pt[3].x()+(pt[7].x()-pt[3].x()) *(zMax-pt[3].z())/(pt[7].z()-pt[3].z()) ; temp[6] = pt[1].x()+(pt[5].x()-pt[1].x()) *(zMin-pt[1].z())/(pt[5].z()-pt[1].z()) ; temp[7] = pt[1].x()+(pt[5].x()-pt[1].x()) *(zMax-pt[1].z())/(pt[5].z()-pt[1].z()) ; xMax = xoffset - std::fabs(fDz*fTthetaCphi) - fDx1 - fDx2 -fDx3 - fDx4 ; xMin = -xMax ; for( i = 0 ; i < 8 ; i++ ) { if( temp[i] > xMax) xMax = temp[i] ; if( temp[i] < xMin) xMin = temp[i] ; } if (pVoxelLimit.IsXLimited()) // xMax/Min = f(yMax/Min) ? { if ( (xMin > pVoxelLimit.GetMaxXExtent() + kCarTolerance) || (xMax < pVoxelLimit.GetMinXExtent() - kCarTolerance) ) { return false; } else { if ( xMin < pVoxelLimit.GetMinXExtent() ) { xMin = pVoxelLimit.GetMinXExtent() ; } if ( xMax > pVoxelLimit.GetMaxXExtent() ) { xMax = pVoxelLimit.GetMaxXExtent() ; } } } switch (pAxis) { case kXAxis: pMin=xMin; pMax=xMax; break; case kYAxis: pMin=yMin; pMax=yMax; break; case kZAxis: pMin=zMin; pMax=zMax; break; default: break; } pMin -= kCarTolerance; pMax += kCarTolerance; flag = true; } else // General rotated case - { G4bool existsAfterClip = false ; G4ThreeVectorList* vertices; pMin = +kInfinity; pMax = -kInfinity; // Calculate rotated vertex coordinates. Operator 'new' is called vertices = CreateRotatedVertices(pTransform); xMin = +kInfinity; yMin = +kInfinity; zMin = +kInfinity; xMax = -kInfinity; yMax = -kInfinity; zMax = -kInfinity; for( G4int nv = 0 ; nv < 8 ; nv++ ) { if( (*vertices)[nv].x() > xMax ) xMax = (*vertices)[nv].x(); if( (*vertices)[nv].y() > yMax ) yMax = (*vertices)[nv].y(); if( (*vertices)[nv].z() > zMax ) zMax = (*vertices)[nv].z(); if( (*vertices)[nv].x() < xMin ) xMin = (*vertices)[nv].x(); if( (*vertices)[nv].y() < yMin ) yMin = (*vertices)[nv].y(); if( (*vertices)[nv].z() < zMin ) zMin = (*vertices)[nv].z(); } if ( pVoxelLimit.IsZLimited() ) { if ( (zMin > pVoxelLimit.GetMaxZExtent() + kCarTolerance) || (zMax < pVoxelLimit.GetMinZExtent() - kCarTolerance) ) { delete vertices ; // 'new' in the function called return false; } else { if ( zMin < pVoxelLimit.GetMinZExtent() ) { zMin = pVoxelLimit.GetMinZExtent() ; } if ( zMax > pVoxelLimit.GetMaxZExtent() ) { zMax = pVoxelLimit.GetMaxZExtent() ; } } } if ( pVoxelLimit.IsYLimited() ) { if ( (yMin > pVoxelLimit.GetMaxYExtent() + kCarTolerance) || (yMax < pVoxelLimit.GetMinYExtent() - kCarTolerance) ) { delete vertices ; // 'new' in the function called return false; } else { if ( yMin < pVoxelLimit.GetMinYExtent() ) { yMin = pVoxelLimit.GetMinYExtent() ; } if ( yMax > pVoxelLimit.GetMaxYExtent() ) { yMax = pVoxelLimit.GetMaxYExtent() ; } } } if ( pVoxelLimit.IsXLimited() ) { if ( (xMin > pVoxelLimit.GetMaxXExtent() + kCarTolerance) || (xMax < pVoxelLimit.GetMinXExtent() - kCarTolerance) ) { delete vertices ; // 'new' in the function called return false ; } else { if ( xMin < pVoxelLimit.GetMinXExtent() ) { xMin = pVoxelLimit.GetMinXExtent() ; } if ( xMax > pVoxelLimit.GetMaxXExtent() ) { xMax = pVoxelLimit.GetMaxXExtent() ; } } } switch (pAxis) { case kXAxis: pMin=xMin; pMax=xMax; break; case kYAxis: pMin=yMin; pMax=yMax; break; case kZAxis: pMin=zMin; pMax=zMax; break; default: break; } if ( (pMin != kInfinity) || (pMax != -kInfinity) ) { existsAfterClip=true; // Add tolerance to avoid precision troubles // pMin -= kCarTolerance ; pMax += kCarTolerance ; } delete vertices ; // 'new' in the function called flag = existsAfterClip ; } return flag; } //////////////////////////////////////////////////////////////////////// // // Return whether point inside/outside/on surface, using tolerance EInside G4Trap::Inside( const G4ThreeVector& p ) const { EInside in; G4double Dist; G4int i; if ( std::fabs(p.z()) <= fDz-kCarTolerance*0.5) { in = kInside; for ( i = 0;i < 4;i++ ) { Dist = fPlanes[i].a*p.x() + fPlanes[i].b*p.y() +fPlanes[i].c*p.z() + fPlanes[i].d; if (Dist > kCarTolerance*0.5) return in = kOutside; else if (Dist > -kCarTolerance*0.5) in = kSurface; } } else if (std::fabs(p.z()) <= fDz+kCarTolerance*0.5) { in = kSurface; for ( i = 0; i < 4; i++ ) { Dist = fPlanes[i].a*p.x() + fPlanes[i].b*p.y() +fPlanes[i].c*p.z() + fPlanes[i].d; if (Dist > kCarTolerance*0.5) return in = kOutside; } } else in = kOutside; return in; } ///////////////////////////////////////////////////////////////////////////// // // Calculate side nearest to p, and return normal // If 2+ sides equidistant, first side's normal returned (arbitrarily) G4ThreeVector G4Trap::SurfaceNormal( const G4ThreeVector& p ) const { G4int i, imin = 0, noSurfaces = 0; G4double dist, distz, distx, disty, distmx, distmy, safe = kInfinity; G4double delta = 0.5*kCarTolerance; G4ThreeVector norm, sumnorm(0.,0.,0.); for (i = 0; i < 4; i++) { dist = std::fabs(fPlanes[i].a*p.x() + fPlanes[i].b*p.y() + fPlanes[i].c*p.z() + fPlanes[i].d); if ( dist < safe ) { safe = dist; imin = i; } } distz = std::fabs( std::fabs( p.z() ) - fDz ); distmy = std::fabs( fPlanes[0].a*p.x() + fPlanes[0].b*p.y() + fPlanes[0].c*p.z() + fPlanes[0].d ); disty = std::fabs( fPlanes[1].a*p.x() + fPlanes[1].b*p.y() + fPlanes[1].c*p.z() + fPlanes[1].d ); distmx = std::fabs( fPlanes[2].a*p.x() + fPlanes[2].b*p.y() + fPlanes[2].c*p.z() + fPlanes[2].d ); distx = std::fabs( fPlanes[3].a*p.x() + fPlanes[3].b*p.y() + fPlanes[3].c*p.z() + fPlanes[3].d ); G4ThreeVector nX = G4ThreeVector(fPlanes[3].a,fPlanes[3].b,fPlanes[3].c); G4ThreeVector nmX = G4ThreeVector(fPlanes[2].a,fPlanes[2].b,fPlanes[2].c); G4ThreeVector nY = G4ThreeVector(fPlanes[1].a,fPlanes[1].b,fPlanes[1].c); G4ThreeVector nmY = G4ThreeVector(fPlanes[0].a,fPlanes[0].b,fPlanes[0].c); G4ThreeVector nZ = G4ThreeVector(0.,0.,1.0); if (distx <= delta) { noSurfaces ++; sumnorm += nX; } if (distmx <= delta) { noSurfaces ++; sumnorm += nmX; } if (disty <= delta) { noSurfaces ++; sumnorm += nY; } if (distmy <= delta) { noSurfaces ++; sumnorm += nmY; } if (distz <= delta) { noSurfaces ++; if ( p.z() >= 0.) sumnorm += nZ; else sumnorm -= nZ; } if ( noSurfaces == 0 ) { #ifdef G4CSGDEBUG G4Exception("G4Trap::SurfaceNormal(p)", "Notification", JustWarning, "Point p is not on surface !?" ); #endif norm = ApproxSurfaceNormal(p); } else if ( noSurfaces == 1 ) norm = sumnorm; else norm = sumnorm.unit(); return norm; } //////////////////////////////////////////////////////////////////////////////////// // // Algorithm for SurfaceNormal() following the original specification // for points not on the surface G4ThreeVector G4Trap::ApproxSurfaceNormal( const G4ThreeVector& p ) const { G4double safe=kInfinity,Dist,safez; G4int i,imin=0; for (i=0;i<4;i++) { Dist=std::fabs(fPlanes[i].a*p.x()+fPlanes[i].b*p.y() +fPlanes[i].c*p.z()+fPlanes[i].d); if (Dist0) { return G4ThreeVector(0,0,1); } else { return G4ThreeVector(0,0,-1); } } } //////////////////////////////////////////////////////////////////////////// // // Calculate distance to shape from outside - return kInfinity if no intersection // // ALGORITHM: // For each component, calculate pair of minimum and maximum intersection // values for which the particle is in the extent of the shape // - The smallest (MAX minimum) allowed distance of the pairs is intersect G4double G4Trap::DistanceToIn( const G4ThreeVector& p, const G4ThreeVector& v ) const { G4double snxt; // snxt = default return value G4double max,smax,smin; G4double pdist,Comp,vdist; G4int i; // // Z Intersection range // if ( v.z() > 0 ) { max = fDz - p.z() ; if (max > 0.5*kCarTolerance) { smax = max/v.z(); smin = (-fDz-p.z())/v.z(); } else { return snxt=kInfinity; } } else if (v.z() < 0 ) { max = - fDz - p.z() ; if (max < -0.5*kCarTolerance ) { smax=max/v.z(); smin=(fDz-p.z())/v.z(); } else { return snxt=kInfinity; } } else { if (std::fabs(p.z())= -0.5*kCarTolerance ) // was >0 { // // Outside the plane -> this is an extent entry distance // if (Comp >= 0) // was >0 { return snxt=kInfinity ; } else { vdist=-pdist/Comp; if (vdist>smin) { if (vdist couble be an extent exit distance (smax) // if (Comp>0) // Will leave extent { vdist=-pdist/Comp; if (vdistsmin) { smax=vdist; } else { return snxt=kInfinity; } } } } } // // Checks in non z plane intersections ensure smin=0 ) { snxt = smin ; } else { snxt = 0 ; } return snxt; } /////////////////////////////////////////////////////////////////////////// // // Calculate exact shortest distance to any boundary from outside // This is the best fast estimation of the shortest distance to trap // - Returns 0 is ThreeVector inside G4double G4Trap::DistanceToIn( const G4ThreeVector& p ) const { G4double safe=0.0,Dist; G4int i; safe=std::fabs(p.z())-fDz; for (i=0;i<4;i++) { Dist=fPlanes[i].a*p.x()+fPlanes[i].b*p.y() +fPlanes[i].c*p.z()+fPlanes[i].d; if (Dist > safe) safe=Dist; } if (safe<0) safe=0; return safe; } ///////////////////////////////////////////////////////////////////////////////// // // Calculate distance to surface of shape from inside // Calculate distance to x/y/z planes - smallest is exiting distance G4double G4Trap::DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v, const G4bool calcNorm, G4bool *validNorm, G4ThreeVector *n) const { Eside side = kUndef; G4double snxt; // snxt = return value G4double pdist,Comp,vdist,max; // // Z Intersections // if (v.z()>0) { max=fDz-p.z(); if (max>kCarTolerance/2) { snxt=max/v.z(); side=kPZ; } else { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(0,0,1); } return snxt=0; } } else if (v.z()<0) { max=-fDz-p.z(); if (max<-kCarTolerance/2) { snxt=max/v.z(); side=kMZ; } else { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(0,0,-1); } return snxt=0; } } else { snxt=kInfinity; } // // Intersections with planes[0] (expanded because of setting enum) // pdist=fPlanes[0].a*p.x()+fPlanes[0].b*p.y()+fPlanes[0].c*p.z()+fPlanes[0].d; Comp=fPlanes[0].a*v.x()+fPlanes[0].b*v.y()+fPlanes[0].c*v.z(); if (pdist>0) { // Outside the plane if (Comp>0) { // Leaving immediately if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[0].a,fPlanes[0].b,fPlanes[0].c); } return snxt=0; } } else if (pdist<-kCarTolerance/2) { // Inside the plane if (Comp>0) { // Will leave extent vdist=-pdist/Comp; if (vdist0) { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[0].a,fPlanes[0].b,fPlanes[0].c); } return snxt=0; } } // // Intersections with planes[1] (expanded because of setting enum) // pdist=fPlanes[1].a*p.x()+fPlanes[1].b*p.y()+fPlanes[1].c*p.z()+fPlanes[1].d; Comp=fPlanes[1].a*v.x()+fPlanes[1].b*v.y()+fPlanes[1].c*v.z(); if (pdist>0) { // Outside the plane if (Comp>0) { // Leaving immediately if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[1].a,fPlanes[1].b,fPlanes[1].c); } return snxt=0; } } else if (pdist<-kCarTolerance/2) { // Inside the plane if (Comp>0) { // Will leave extent vdist=-pdist/Comp; if (vdist0) { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[1].a,fPlanes[1].b,fPlanes[1].c); } return snxt=0; } } // // Intersections with planes[2] (expanded because of setting enum) // pdist=fPlanes[2].a*p.x()+fPlanes[2].b*p.y()+fPlanes[2].c*p.z()+fPlanes[2].d; Comp=fPlanes[2].a*v.x()+fPlanes[2].b*v.y()+fPlanes[2].c*v.z(); if (pdist>0) { // Outside the plane if (Comp>0) { // Leaving immediately if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[2].a,fPlanes[2].b,fPlanes[2].c); } return snxt=0; } } else if (pdist<-kCarTolerance/2) { // Inside the plane if (Comp>0) { // Will leave extent vdist=-pdist/Comp; if (vdist0) { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[2].a,fPlanes[2].b,fPlanes[2].c); } return snxt=0; } } // // Intersections with planes[3] (expanded because of setting enum) // pdist=fPlanes[3].a*p.x()+fPlanes[3].b*p.y()+fPlanes[3].c*p.z()+fPlanes[3].d; Comp=fPlanes[3].a*v.x()+fPlanes[3].b*v.y()+fPlanes[3].c*v.z(); if (pdist>0) { // Outside the plane if (Comp>0) { // Leaving immediately if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[3].a,fPlanes[3].b,fPlanes[3].c); } return snxt=0; } } else if (pdist<-kCarTolerance/2) { // Inside the plane if (Comp>0) { // Will leave extent vdist=-pdist/Comp; if (vdist0) { if (calcNorm) { *validNorm=true; *n=G4ThreeVector(fPlanes[3].a,fPlanes[3].b,fPlanes[3].c); } return snxt=0; } } // set normal if (calcNorm) { *validNorm=true; switch(side) { case ks0: *n=G4ThreeVector(fPlanes[0].a,fPlanes[0].b,fPlanes[0].c); break; case ks1: *n=G4ThreeVector(fPlanes[1].a,fPlanes[1].b,fPlanes[1].c); break; case ks2: *n=G4ThreeVector(fPlanes[2].a,fPlanes[2].b,fPlanes[2].c); break; case ks3: *n=G4ThreeVector(fPlanes[3].a,fPlanes[3].b,fPlanes[3].c); break; case kMZ: *n=G4ThreeVector(0,0,-1); break; case kPZ: *n=G4ThreeVector(0,0,1); break; default: G4cout.precision(16); G4cout << G4endl; DumpInfo(); G4cout << "Position:" << G4endl << G4endl; G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl; G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl; G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl; G4cout << "Direction:" << G4endl << G4endl; G4cout << "v.x() = " << v.x() << G4endl; G4cout << "v.y() = " << v.y() << G4endl; G4cout << "v.z() = " << v.z() << G4endl << G4endl; G4cout << "Proposed distance :" << G4endl << G4endl; G4cout << "snxt = " << snxt/mm << " mm" << G4endl << G4endl; G4Exception("G4Trap::DistanceToOut(p,v,..)","Notification",JustWarning, "Undefined side for valid surface normal to solid."); break; } } return snxt; } ////////////////////////////////////////////////////////////////////////////// // // Calculate exact shortest distance to any boundary from inside // - Returns 0 is ThreeVector outside G4double G4Trap::DistanceToOut( const G4ThreeVector& p ) const { G4double safe=0.0,Dist; G4int i; #ifdef G4CSGDEBUG if( Inside(p) == kOutside ) { G4cout.precision(16) ; G4cout << G4endl ; DumpInfo(); G4cout << "Position:" << G4endl << G4endl ; G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ; G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ; G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ; G4Exception("G4Trap::DistanceToOut(p)", "Notification", JustWarning, "Point p is outside !?" ); } #endif safe=fDz-std::fabs(p.z()); if (safe<0) safe=0; else { for (i=0;i<4;i++) { Dist=-(fPlanes[i].a*p.x()+fPlanes[i].b*p.y() +fPlanes[i].c*p.z()+fPlanes[i].d); if (Distreserve(8); if (vertices) { G4ThreeVector vertex0(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); G4ThreeVector vertex1(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); G4ThreeVector vertex2(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); G4ThreeVector vertex3(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); G4ThreeVector vertex4(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); G4ThreeVector vertex5(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); G4ThreeVector vertex6(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); G4ThreeVector vertex7(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); vertices->push_back(pTransform.TransformPoint(vertex0)); vertices->push_back(pTransform.TransformPoint(vertex1)); vertices->push_back(pTransform.TransformPoint(vertex2)); vertices->push_back(pTransform.TransformPoint(vertex3)); vertices->push_back(pTransform.TransformPoint(vertex4)); vertices->push_back(pTransform.TransformPoint(vertex5)); vertices->push_back(pTransform.TransformPoint(vertex6)); vertices->push_back(pTransform.TransformPoint(vertex7)); } else { DumpInfo(); G4Exception("G4Trap::CreateRotatedVertices()", "FatalError", FatalException, "Error in allocation of vertices. Out of memory !"); } return vertices; } ////////////////////////////////////////////////////////////////////////// // // GetEntityType G4GeometryType G4Trap::GetEntityType() const { return G4String("G4Trap"); } ////////////////////////////////////////////////////////////////////////// // // Stream object contents to an output stream std::ostream& G4Trap::StreamInfo( std::ostream& os ) const { os << "-----------------------------------------------------------\n" << " *** Dump for solid - " << GetName() << " ***\n" << " ===================================================\n" << " Solid type: G4Trap\n" << " Parameters: \n" << " half length Z: " << fDz/mm << " mm \n" << " half length Y of face -fDz: " << fDy1/mm << " mm \n" << " half length X of side -fDy1, face -fDz: " << fDx1/mm << " mm \n" << " half length X of side +fDy1, face -fDz: " << fDx2/mm << " mm \n" << " half length Y of face +fDz: " << fDy2/mm << " mm \n" << " half length X of side -fDy2, face +fDz: " << fDx3/mm << " mm \n" << " half length X of side +fDy2, face +fDz: " << fDx4/mm << " mm \n" << " std::tan(theta)*std::cos(phi): " << fTthetaCphi/degree << " degrees \n" << " std::tan(theta)*std::sin(phi): " << fTthetaSphi/degree << " degrees \n" << " std::tan(alpha), -fDz: " << fTalpha1/degree << " degrees \n" << " std::tan(alpha), +fDz: " << fTalpha2/degree << " degrees \n" << " trap side plane equations:\n" << " " << fPlanes[0].a << " X + " << fPlanes[0].b << " Y + " << fPlanes[0].c << " Z + " << fPlanes[0].d << " = 0\n" << " " << fPlanes[1].a << " X + " << fPlanes[1].b << " Y + " << fPlanes[1].c << " Z + " << fPlanes[1].d << " = 0\n" << " " << fPlanes[2].a << " X + " << fPlanes[2].b << " Y + " << fPlanes[2].c << " Z + " << fPlanes[2].d << " = 0\n" << " " << fPlanes[3].a << " X + " << fPlanes[3].b << " Y + " << fPlanes[3].c << " Z + " << fPlanes[3].d << " = 0\n" << "-----------------------------------------------------------\n"; return os; } ///////////////////////////////////////////////////////////////////////// // // GetPointOnPlane // // Auxiliary method for Get Point on Surface G4ThreeVector G4Trap::GetPointOnPlane(G4ThreeVector p0, G4ThreeVector p1, G4ThreeVector p2, G4ThreeVector p3, G4double& area) const { G4double lambda1, lambda2, chose, aOne, aTwo; G4ThreeVector t, u, v, w, Area, normal; t = p1 - p0; u = p2 - p1; v = p3 - p2; w = p0 - p3; Area = G4ThreeVector(w.y()*v.z() - w.z()*v.y(), w.z()*v.x() - w.x()*v.z(), w.x()*v.y() - w.y()*v.x()); aOne = 0.5*Area.mag(); Area = G4ThreeVector(t.y()*u.z() - t.z()*u.y(), t.z()*u.x() - t.x()*u.z(), t.x()*u.y() - t.y()*u.x()); aTwo = 0.5*Area.mag(); area = aOne + aTwo; chose = RandFlat::shoot(0.,aOne+aTwo); if( (chose>=0.) && (chose < aOne) ) { lambda1 = RandFlat::shoot(0.,1.); lambda2 = RandFlat::shoot(0.,lambda1); return (p2+lambda1*v+lambda2*w); } // else lambda1 = RandFlat::shoot(0.,1.); lambda2 = RandFlat::shoot(0.,lambda1); return (p0+lambda1*t+lambda2*u); } /////////////////////////////////////////////////////////////// // // GetPointOnSurface G4ThreeVector G4Trap::GetPointOnSurface() const { G4double aOne, aTwo, aThree, aFour, aFive, aSix, chose; G4ThreeVector One, Two, Three, Four, Five, Six, test; G4ThreeVector pt[8]; pt[0] = G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1-fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[1] = G4ThreeVector(-fDz*fTthetaCphi-fDy1*fTalpha1+fDx1, -fDz*fTthetaSphi-fDy1,-fDz); pt[2] = G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1-fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[3] = G4ThreeVector(-fDz*fTthetaCphi+fDy1*fTalpha1+fDx2, -fDz*fTthetaSphi+fDy1,-fDz); pt[4] = G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2-fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[5] = G4ThreeVector(+fDz*fTthetaCphi-fDy2*fTalpha2+fDx3, +fDz*fTthetaSphi-fDy2,+fDz); pt[6] = G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2-fDx4, +fDz*fTthetaSphi+fDy2,+fDz); pt[7] = G4ThreeVector(+fDz*fTthetaCphi+fDy2*fTalpha2+fDx4, +fDz*fTthetaSphi+fDy2,+fDz); // make sure we provide the points in a clockwise fashion One = GetPointOnPlane(pt[0],pt[1],pt[3],pt[2], aOne); Two = GetPointOnPlane(pt[4],pt[5],pt[7],pt[6], aTwo); Three = GetPointOnPlane(pt[6],pt[7],pt[3],pt[2], aThree); Four = GetPointOnPlane(pt[4],pt[5],pt[1],pt[0], aFour); Five = GetPointOnPlane(pt[0],pt[2],pt[6],pt[4], aFive); Six = GetPointOnPlane(pt[1],pt[3],pt[7],pt[5], aSix); chose = RandFlat::shoot(0.,aOne+aTwo+aThree+aFour+aFive+aSix); if( (chose>=0.) && (chose=aOne) && (chose=aOne+aTwo) && (chose=aOne+aTwo+aThree) && (chose=aOne+aTwo+aThree+aFour) && (chose