| 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 | // $Id: G4EllipticalCone.cc,v 1.16 2008/04/25 08:45:26 gcosmo Exp $
|
|---|
| 27 | // GEANT4 tag $Name: HEAD $
|
|---|
| 28 | //
|
|---|
| 29 | // Implementation of G4EllipticalCone class
|
|---|
| 30 | //
|
|---|
| 31 | // This code implements an Elliptical Cone given explicitly by the
|
|---|
| 32 | // equation:
|
|---|
| 33 | // x^2/a^2 + y^2/b^2 = (z-h)^2
|
|---|
| 34 | // and specified by the parameters (a,b,h) and a cut parallel to the
|
|---|
| 35 | // xy plane above z = 0.
|
|---|
| 36 | //
|
|---|
| 37 | // Author: Dionysios Anninos
|
|---|
| 38 | //
|
|---|
| 39 | // --------------------------------------------------------------------
|
|---|
| 40 |
|
|---|
| 41 | #include "globals.hh"
|
|---|
| 42 |
|
|---|
| 43 | #include "G4EllipticalCone.hh"
|
|---|
| 44 |
|
|---|
| 45 | #include "G4ClippablePolygon.hh"
|
|---|
| 46 | #include "G4SolidExtentList.hh"
|
|---|
| 47 | #include "G4VoxelLimits.hh"
|
|---|
| 48 | #include "G4AffineTransform.hh"
|
|---|
| 49 | #include "G4GeometryTolerance.hh"
|
|---|
| 50 |
|
|---|
| 51 | #include "meshdefs.hh"
|
|---|
| 52 |
|
|---|
| 53 | #include "Randomize.hh"
|
|---|
| 54 |
|
|---|
| 55 | #include "G4VGraphicsScene.hh"
|
|---|
| 56 | #include "G4Polyhedron.hh"
|
|---|
| 57 | #include "G4NURBS.hh"
|
|---|
| 58 | #include "G4NURBSbox.hh"
|
|---|
| 59 | #include "G4VisExtent.hh"
|
|---|
| 60 |
|
|---|
| 61 | //#define G4SPECSDEBUG 1
|
|---|
| 62 |
|
|---|
| 63 | using namespace CLHEP;
|
|---|
| 64 |
|
|---|
| 65 | //////////////////////////////////////////////////////////////////////
|
|---|
| 66 | //
|
|---|
| 67 | // Constructor - check parameters
|
|---|
| 68 | //
|
|---|
| 69 | G4EllipticalCone::G4EllipticalCone(const G4String& pName,
|
|---|
| 70 | G4double pxSemiAxis,
|
|---|
| 71 | G4double pySemiAxis,
|
|---|
| 72 | G4double pzMax,
|
|---|
| 73 | G4double pzTopCut)
|
|---|
| 74 | : G4VSolid(pName), fpPolyhedron(0), fCubicVolume(0.), fSurfaceArea(0.),
|
|---|
| 75 | zTopCut(0.)
|
|---|
| 76 | {
|
|---|
| 77 |
|
|---|
| 78 | kRadTolerance = G4GeometryTolerance::GetInstance()->GetRadialTolerance();
|
|---|
| 79 |
|
|---|
| 80 | // Check Semi-Axis
|
|---|
| 81 | //
|
|---|
| 82 | if ( (pxSemiAxis > 0.) && (pySemiAxis > 0.) && (pzMax > 0.) )
|
|---|
| 83 | {
|
|---|
| 84 | SetSemiAxis( pxSemiAxis, pySemiAxis, pzMax );
|
|---|
| 85 | }
|
|---|
| 86 | else
|
|---|
| 87 | {
|
|---|
| 88 | G4cerr << "ERROR - G4EllipticalCone::G4EllipticalCone(): "
|
|---|
| 89 | << GetName() << G4endl
|
|---|
| 90 | << " Invalid semi-axis or height!" << G4endl;
|
|---|
| 91 | G4Exception("G4EllipticalCone::G4EllipticalCone()", "InvalidSetup",
|
|---|
| 92 | FatalException, "Invalid semi-axis or height.");
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | if ( pzTopCut > 0 )
|
|---|
| 96 | {
|
|---|
| 97 | SetZCut(pzTopCut);
|
|---|
| 98 | }
|
|---|
| 99 | else
|
|---|
| 100 | {
|
|---|
| 101 | G4cerr << "ERROR - G4EllipticalCone::G4EllipticalCone(): "
|
|---|
| 102 | << GetName() << G4endl
|
|---|
| 103 | << " Invalid z-coordinate for cutting plane !" << G4endl;
|
|---|
| 104 | G4Exception("G4EllipticalCone::G4EllipticalCone()", "InvalidSetup",
|
|---|
| 105 | FatalException, "Invalid z-coordinate for cutting plane.");
|
|---|
| 106 | }
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | ///////////////////////////////////////////////////////////////////////////////
|
|---|
| 110 | //
|
|---|
| 111 | // Fake default constructor - sets only member data and allocates memory
|
|---|
| 112 | // for usage restricted to object persistency.
|
|---|
| 113 | //
|
|---|
| 114 | G4EllipticalCone::G4EllipticalCone( __void__& a )
|
|---|
| 115 | : G4VSolid(a), fpPolyhedron(0), fCubicVolume(0.), fSurfaceArea(0.),
|
|---|
| 116 | zTopCut(0.)
|
|---|
| 117 | {
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | ///////////////////////////////////////////////////////////////////////////////
|
|---|
| 121 | //
|
|---|
| 122 | // Destructor
|
|---|
| 123 | //
|
|---|
| 124 | G4EllipticalCone::~G4EllipticalCone()
|
|---|
| 125 | {
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | ///////////////////////////////////////////////////////////////////////////////
|
|---|
| 129 | //
|
|---|
| 130 | // Calculate extent under transform and specified limit
|
|---|
| 131 | //
|
|---|
| 132 | G4bool
|
|---|
| 133 | G4EllipticalCone::CalculateExtent( const EAxis axis,
|
|---|
| 134 | const G4VoxelLimits &voxelLimit,
|
|---|
| 135 | const G4AffineTransform &transform,
|
|---|
| 136 | G4double &min, G4double &max ) const
|
|---|
| 137 | {
|
|---|
| 138 | G4SolidExtentList extentList( axis, voxelLimit );
|
|---|
| 139 |
|
|---|
| 140 | //
|
|---|
| 141 | // We are going to divide up our elliptical face into small pieces
|
|---|
| 142 | //
|
|---|
| 143 |
|
|---|
| 144 | //
|
|---|
| 145 | // Choose phi size of our segment(s) based on constants as
|
|---|
| 146 | // defined in meshdefs.hh
|
|---|
| 147 | //
|
|---|
| 148 | G4int numPhi = kMaxMeshSections;
|
|---|
| 149 | G4double sigPhi = twopi/numPhi;
|
|---|
| 150 |
|
|---|
| 151 | //
|
|---|
| 152 | // We have to be careful to keep our segments completely outside
|
|---|
| 153 | // of the elliptical surface. To do so we imagine we have
|
|---|
| 154 | // a simple (unit radius) circular cross section (as in G4Tubs)
|
|---|
| 155 | // and then "stretch" the dimensions as necessary to fit the ellipse.
|
|---|
| 156 | //
|
|---|
| 157 | G4double rFudge = 1.0/std::cos(0.5*sigPhi);
|
|---|
| 158 | G4double dxFudgeBot = xSemiAxis*2.*zheight*rFudge,
|
|---|
| 159 | dyFudgeBot = ySemiAxis*2.*zheight*rFudge;
|
|---|
| 160 | G4double dxFudgeTop = xSemiAxis*(zheight-zTopCut)*rFudge,
|
|---|
| 161 | dyFudgeTop = ySemiAxis*(zheight-zTopCut)*rFudge;
|
|---|
| 162 |
|
|---|
| 163 | //
|
|---|
| 164 | // As we work around the elliptical surface, we build
|
|---|
| 165 | // a "phi" segment on the way, and keep track of two
|
|---|
| 166 | // additional polygons for the two ends.
|
|---|
| 167 | //
|
|---|
| 168 | G4ClippablePolygon endPoly1, endPoly2, phiPoly;
|
|---|
| 169 |
|
|---|
| 170 | G4double phi = 0,
|
|---|
| 171 | cosPhi = std::cos(phi),
|
|---|
| 172 | sinPhi = std::sin(phi);
|
|---|
| 173 | G4ThreeVector v0( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut ),
|
|---|
| 174 | v1( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut ),
|
|---|
| 175 | w0, w1;
|
|---|
| 176 | transform.ApplyPointTransform( v0 );
|
|---|
| 177 | transform.ApplyPointTransform( v1 );
|
|---|
| 178 | do
|
|---|
| 179 | {
|
|---|
| 180 | phi += sigPhi;
|
|---|
| 181 | if (numPhi == 1) phi = 0; // Try to avoid roundoff
|
|---|
| 182 | cosPhi = std::cos(phi),
|
|---|
| 183 | sinPhi = std::sin(phi);
|
|---|
| 184 |
|
|---|
| 185 | w0 = G4ThreeVector( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut );
|
|---|
| 186 | w1 = G4ThreeVector( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut );
|
|---|
| 187 | transform.ApplyPointTransform( w0 );
|
|---|
| 188 | transform.ApplyPointTransform( w1 );
|
|---|
| 189 |
|
|---|
| 190 | //
|
|---|
| 191 | // Add a point to our z ends
|
|---|
| 192 | //
|
|---|
| 193 | endPoly1.AddVertexInOrder( v0 );
|
|---|
| 194 | endPoly2.AddVertexInOrder( v1 );
|
|---|
| 195 |
|
|---|
| 196 | //
|
|---|
| 197 | // Build phi polygon
|
|---|
| 198 | //
|
|---|
| 199 | phiPoly.ClearAllVertices();
|
|---|
| 200 |
|
|---|
| 201 | phiPoly.AddVertexInOrder( v0 );
|
|---|
| 202 | phiPoly.AddVertexInOrder( v1 );
|
|---|
| 203 | phiPoly.AddVertexInOrder( w1 );
|
|---|
| 204 | phiPoly.AddVertexInOrder( w0 );
|
|---|
| 205 |
|
|---|
| 206 | if (phiPoly.PartialClip( voxelLimit, axis ))
|
|---|
| 207 | {
|
|---|
| 208 | //
|
|---|
| 209 | // Get unit normal
|
|---|
| 210 | //
|
|---|
| 211 | phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
|
|---|
| 212 |
|
|---|
| 213 | extentList.AddSurface( phiPoly );
|
|---|
| 214 | }
|
|---|
| 215 |
|
|---|
| 216 | //
|
|---|
| 217 | // Next vertex
|
|---|
| 218 | //
|
|---|
| 219 | v0 = w0;
|
|---|
| 220 | v1 = w1;
|
|---|
| 221 | } while( --numPhi > 0 );
|
|---|
| 222 |
|
|---|
| 223 | //
|
|---|
| 224 | // Process the end pieces
|
|---|
| 225 | //
|
|---|
| 226 | if (endPoly1.PartialClip( voxelLimit, axis ))
|
|---|
| 227 | {
|
|---|
| 228 | static const G4ThreeVector normal(0,0,+1);
|
|---|
| 229 | endPoly1.SetNormal( transform.TransformAxis(normal) );
|
|---|
| 230 | extentList.AddSurface( endPoly1 );
|
|---|
| 231 | }
|
|---|
| 232 |
|
|---|
| 233 | if (endPoly2.PartialClip( voxelLimit, axis ))
|
|---|
| 234 | {
|
|---|
| 235 | static const G4ThreeVector normal(0,0,-1);
|
|---|
| 236 | endPoly2.SetNormal( transform.TransformAxis(normal) );
|
|---|
| 237 | extentList.AddSurface( endPoly2 );
|
|---|
| 238 | }
|
|---|
| 239 |
|
|---|
| 240 | //
|
|---|
| 241 | // Return min/max value
|
|---|
| 242 | //
|
|---|
| 243 | return extentList.GetExtent( min, max );
|
|---|
| 244 | }
|
|---|
| 245 |
|
|---|
| 246 | ////////////////////////////////////////////////////////////////////////
|
|---|
| 247 | //
|
|---|
| 248 | // Return whether point inside/outside/on surface
|
|---|
| 249 | // Split into radius, phi, theta checks
|
|---|
| 250 | // Each check modifies `in', or returns as approprate
|
|---|
| 251 | //
|
|---|
| 252 | EInside G4EllipticalCone::Inside(const G4ThreeVector& p) const
|
|---|
| 253 | {
|
|---|
| 254 | G4double rad2oo, // outside surface outer tolerance
|
|---|
| 255 | rad2oi; // outside surface inner tolerance
|
|---|
| 256 |
|
|---|
| 257 | EInside in;
|
|---|
| 258 |
|
|---|
| 259 | // check this side of z cut first, because that's fast
|
|---|
| 260 | //
|
|---|
| 261 |
|
|---|
| 262 | if ( (p.z() < -zTopCut - 0.5*kCarTolerance)
|
|---|
| 263 | || (p.z() > zTopCut + 0.5*kCarTolerance ) )
|
|---|
| 264 | {
|
|---|
| 265 | return in = kOutside;
|
|---|
| 266 | }
|
|---|
| 267 |
|
|---|
| 268 | rad2oo= sqr(p.x()/( xSemiAxis + 0.5*kRadTolerance ))
|
|---|
| 269 | + sqr(p.y()/( ySemiAxis + 0.5*kRadTolerance ));
|
|---|
| 270 |
|
|---|
| 271 | if ( rad2oo > sqr( zheight-p.z() ) )
|
|---|
| 272 | {
|
|---|
| 273 | return in = kOutside;
|
|---|
| 274 | }
|
|---|
| 275 |
|
|---|
| 276 | // rad2oi= sqr( p.x()*(1.0 + 0.5*kRadTolerance/(xSemiAxis*xSemiAxis)) )
|
|---|
| 277 | // + sqr( p.y()*(1.0 + 0.5*kRadTolerance/(ySemiAxis*ySemiAxis)) );
|
|---|
| 278 | rad2oi = sqr(p.x()/( xSemiAxis - 0.5*kRadTolerance ))
|
|---|
| 279 | + sqr(p.y()/( ySemiAxis - 0.5*kRadTolerance ));
|
|---|
| 280 |
|
|---|
| 281 | if (rad2oi < sqr( zheight-p.z() ) )
|
|---|
| 282 | {
|
|---|
| 283 | in = ( ( p.z() < -zTopCut + 0.5*kRadTolerance )
|
|---|
| 284 | || ( p.z() > zTopCut - 0.5*kRadTolerance ) ) ? kSurface : kInside;
|
|---|
| 285 | }
|
|---|
| 286 | else
|
|---|
| 287 | {
|
|---|
| 288 | in = kSurface;
|
|---|
| 289 | }
|
|---|
| 290 |
|
|---|
| 291 | return in;
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | /////////////////////////////////////////////////////////////////////////
|
|---|
| 295 | //
|
|---|
| 296 | // Return unit normal of surface closest to p not protected against p=0
|
|---|
| 297 | //
|
|---|
| 298 | G4ThreeVector G4EllipticalCone::SurfaceNormal( const G4ThreeVector& p) const
|
|---|
| 299 | {
|
|---|
| 300 |
|
|---|
| 301 | G4double rx = sqr(p.x()/xSemiAxis),
|
|---|
| 302 | ry = sqr(p.y()/ySemiAxis);
|
|---|
| 303 |
|
|---|
| 304 | G4double rad = std::sqrt(rx + ry);
|
|---|
| 305 |
|
|---|
| 306 | G4ThreeVector norm;
|
|---|
| 307 |
|
|---|
| 308 | if( (p.z() < -zTopCut) && ((rx+ry) < sqr(zTopCut + zheight)) )
|
|---|
| 309 | {
|
|---|
| 310 | return G4ThreeVector( 0., 0., -1. );
|
|---|
| 311 | }
|
|---|
| 312 |
|
|---|
| 313 | if( (p.z() > (zheight > zTopCut ? zheight : zTopCut)) &&
|
|---|
| 314 | ((rx+ry) < sqr(zheight-zTopCut)) )
|
|---|
| 315 | {
|
|---|
| 316 | return G4ThreeVector( 0., 0., 1. );
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | if( p.z() > rad + 2.*zTopCut - zheight )
|
|---|
| 320 | {
|
|---|
| 321 | if ( p.z() > zTopCut )
|
|---|
| 322 | {
|
|---|
| 323 | if( p.x() == 0. )
|
|---|
| 324 | {
|
|---|
| 325 | norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., 1. );
|
|---|
| 326 | return norm /= norm.mag();
|
|---|
| 327 | }
|
|---|
| 328 | if( p.y() == 0. )
|
|---|
| 329 | {
|
|---|
| 330 | norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., 1. );
|
|---|
| 331 | return norm /= norm.mag();
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | G4double m = std::fabs(p.x()/p.y());
|
|---|
| 335 | G4double c2 = sqr(zheight-zTopCut)/(1./sqr(xSemiAxis)+sqr(m/ySemiAxis));
|
|---|
| 336 | G4double x = std::sqrt(c2);
|
|---|
| 337 | G4double y = m*x;
|
|---|
| 338 |
|
|---|
| 339 | x /= sqr(xSemiAxis);
|
|---|
| 340 | y /= sqr(ySemiAxis);
|
|---|
| 341 |
|
|---|
| 342 | norm = G4ThreeVector( p.x() < 0. ? -x : x,
|
|---|
| 343 | p.y() < 0. ? -y : y,
|
|---|
| 344 | zheight - zTopCut );
|
|---|
| 345 | norm /= norm.mag();
|
|---|
| 346 | norm += G4ThreeVector( 0., 0., 1. );
|
|---|
| 347 | return norm /= norm.mag();
|
|---|
| 348 | }
|
|---|
| 349 |
|
|---|
| 350 | return G4ThreeVector( 0., 0., 1. );
|
|---|
| 351 | }
|
|---|
| 352 |
|
|---|
| 353 | if( p.z() < rad - 2.*zTopCut - zheight )
|
|---|
| 354 | {
|
|---|
| 355 | if( p.x() == 0. )
|
|---|
| 356 | {
|
|---|
| 357 | norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., -1. );
|
|---|
| 358 | return norm /= norm.mag();
|
|---|
| 359 | }
|
|---|
| 360 | if( p.y() == 0. )
|
|---|
| 361 | {
|
|---|
| 362 | norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., -1. );
|
|---|
| 363 | return norm /= norm.mag();
|
|---|
| 364 | }
|
|---|
| 365 |
|
|---|
| 366 | G4double m = std::fabs(p.x()/p.y());
|
|---|
| 367 | G4double c2 = sqr(zheight+zTopCut)/(1./sqr(xSemiAxis)+sqr(m/ySemiAxis));
|
|---|
| 368 | G4double x = std::sqrt(c2);
|
|---|
| 369 | G4double y = m*x;
|
|---|
| 370 |
|
|---|
| 371 | x /= sqr(xSemiAxis);
|
|---|
| 372 | y /= sqr(ySemiAxis);
|
|---|
| 373 |
|
|---|
| 374 | norm = G4ThreeVector( p.x() < 0. ? -x : x,
|
|---|
| 375 | p.y() < 0. ? -y : y,
|
|---|
| 376 | zheight - zTopCut );
|
|---|
| 377 | norm /= norm.mag();
|
|---|
| 378 | norm += G4ThreeVector( 0., 0., -1. );
|
|---|
| 379 | return norm /= norm.mag();
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | norm = G4ThreeVector(p.x()/sqr(xSemiAxis), p.y()/sqr(ySemiAxis), rad);
|
|---|
| 383 |
|
|---|
| 384 | G4double m = std::tan(pi/8.);
|
|---|
| 385 | G4double c = -zTopCut - m*(zTopCut + zheight);
|
|---|
| 386 |
|
|---|
| 387 | if( p.z() < -m*rad + c )
|
|---|
| 388 | return G4ThreeVector (0.,0.,-1.);
|
|---|
| 389 |
|
|---|
| 390 | return norm /= norm.mag();
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | //////////////////////////////////////////////////////////////////////////
|
|---|
| 394 | //
|
|---|
| 395 | // Calculate distance to shape from outside, along normalised vector
|
|---|
| 396 | // return kInfinity if no intersection, or intersection distance <= tolerance
|
|---|
| 397 | //
|
|---|
| 398 | G4double G4EllipticalCone::DistanceToIn( const G4ThreeVector& p,
|
|---|
| 399 | const G4ThreeVector& v ) const
|
|---|
| 400 | {
|
|---|
| 401 |
|
|---|
| 402 | static const G4double halfTol = 0.5*kCarTolerance;
|
|---|
| 403 |
|
|---|
| 404 | G4double distMin = kInfinity;
|
|---|
| 405 |
|
|---|
| 406 | // code from EllipticalTube
|
|---|
| 407 |
|
|---|
| 408 | G4double sigz = p.z()+zTopCut;
|
|---|
| 409 |
|
|---|
| 410 | //
|
|---|
| 411 | // Check z = -dz planer surface
|
|---|
| 412 | //
|
|---|
| 413 |
|
|---|
| 414 | if (sigz < halfTol)
|
|---|
| 415 | {
|
|---|
| 416 | //
|
|---|
| 417 | // We are "behind" the shape in z, and so can
|
|---|
| 418 | // potentially hit the rear face. Correct direction?
|
|---|
| 419 | //
|
|---|
| 420 | if (v.z() <= 0)
|
|---|
| 421 | {
|
|---|
| 422 | //
|
|---|
| 423 | // As long as we are far enough away, we know we
|
|---|
| 424 | // can't intersect
|
|---|
| 425 | //
|
|---|
| 426 | if (sigz < 0) return kInfinity;
|
|---|
| 427 |
|
|---|
| 428 | //
|
|---|
| 429 | // Otherwise, we don't intersect unless we are
|
|---|
| 430 | // on the surface of the ellipse
|
|---|
| 431 | //
|
|---|
| 432 |
|
|---|
| 433 | if ( sqr(p.x()/( xSemiAxis - halfTol ))
|
|---|
| 434 | + sqr(p.y()/( ySemiAxis - halfTol )) <= sqr( zheight+zTopCut ) )
|
|---|
| 435 | return kInfinity;
|
|---|
| 436 |
|
|---|
| 437 | }
|
|---|
| 438 | else
|
|---|
| 439 | {
|
|---|
| 440 | //
|
|---|
| 441 | // How far?
|
|---|
| 442 | //
|
|---|
| 443 | G4double s = -sigz/v.z();
|
|---|
| 444 |
|
|---|
| 445 | //
|
|---|
| 446 | // Where does that place us?
|
|---|
| 447 | //
|
|---|
| 448 | G4double xi = p.x() + s*v.x(),
|
|---|
| 449 | yi = p.y() + s*v.y();
|
|---|
| 450 |
|
|---|
| 451 | //
|
|---|
| 452 | // Is this on the surface (within ellipse)?
|
|---|
| 453 | //
|
|---|
| 454 | if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight + zTopCut ) )
|
|---|
| 455 | {
|
|---|
| 456 | //
|
|---|
| 457 | // Yup. Return s, unless we are on the surface
|
|---|
| 458 | //
|
|---|
| 459 | return (sigz < -halfTol) ? s : 0;
|
|---|
| 460 | }
|
|---|
| 461 | else if (xi/(xSemiAxis*xSemiAxis)*v.x()
|
|---|
| 462 | + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
|
|---|
| 463 | {
|
|---|
| 464 | //
|
|---|
| 465 | // Else, if we are traveling outwards, we know
|
|---|
| 466 | // we must miss
|
|---|
| 467 | //
|
|---|
| 468 | // return kInfinity;
|
|---|
| 469 | }
|
|---|
| 470 | }
|
|---|
| 471 | }
|
|---|
| 472 |
|
|---|
| 473 | //
|
|---|
| 474 | // Check z = +dz planer surface
|
|---|
| 475 | //
|
|---|
| 476 |
|
|---|
| 477 | sigz = p.z() - zTopCut;
|
|---|
| 478 |
|
|---|
| 479 | if (sigz > -halfTol)
|
|---|
| 480 | {
|
|---|
| 481 | if (v.z() >= 0)
|
|---|
| 482 | {
|
|---|
| 483 |
|
|---|
| 484 | if (sigz > 0) return kInfinity;
|
|---|
| 485 |
|
|---|
| 486 | if ( sqr(p.x()/( xSemiAxis - halfTol ))
|
|---|
| 487 | + sqr(p.y()/( ySemiAxis - halfTol )) <= sqr( zheight-zTopCut ) )
|
|---|
| 488 | return kInfinity;
|
|---|
| 489 |
|
|---|
| 490 | }
|
|---|
| 491 | else {
|
|---|
| 492 | G4double s = -sigz/v.z();
|
|---|
| 493 |
|
|---|
| 494 | G4double xi = p.x() + s*v.x(),
|
|---|
| 495 | yi = p.y() + s*v.y();
|
|---|
| 496 |
|
|---|
| 497 | if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight - zTopCut ) )
|
|---|
| 498 | {
|
|---|
| 499 | return (sigz > -halfTol) ? s : 0;
|
|---|
| 500 | }
|
|---|
| 501 | else if (xi/(xSemiAxis*xSemiAxis)*v.x()
|
|---|
| 502 | + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
|
|---|
| 503 | {
|
|---|
| 504 | // return kInfinity;
|
|---|
| 505 | }
|
|---|
| 506 | }
|
|---|
| 507 | }
|
|---|
| 508 |
|
|---|
| 509 |
|
|---|
| 510 | #if 0
|
|---|
| 511 |
|
|---|
| 512 | // check to see if Z plane is relevant
|
|---|
| 513 | //
|
|---|
| 514 | if (p.z() < -zTopCut - 0.5*kCarTolerance)
|
|---|
| 515 | {
|
|---|
| 516 | if (v.z() <= 0.0)
|
|---|
| 517 | return distMin;
|
|---|
| 518 |
|
|---|
| 519 | G4double lambda = (-zTopCut - p.z())/v.z();
|
|---|
| 520 |
|
|---|
| 521 | if ( sqr((lambda*v.x()+p.x())/xSemiAxis) +
|
|---|
| 522 | sqr((lambda*v.y()+p.y())/ySemiAxis) <=
|
|---|
| 523 | sqr(zTopCut + zheight + 0.5*kRadTolerance) )
|
|---|
| 524 | {
|
|---|
| 525 | return distMin = std::fabs(lambda);
|
|---|
| 526 | }
|
|---|
| 527 | }
|
|---|
| 528 |
|
|---|
| 529 | if (p.z() > zTopCut+0.5*kCarTolerance)
|
|---|
| 530 | {
|
|---|
| 531 | if (v.z() >= 0.0)
|
|---|
| 532 | { return distMin; }
|
|---|
| 533 |
|
|---|
| 534 | G4double lambda = (zTopCut - p.z()) / v.z();
|
|---|
| 535 |
|
|---|
| 536 | if ( sqr((lambda*v.x() + p.x())/xSemiAxis) +
|
|---|
| 537 | sqr((lambda*v.y() + p.y())/ySemiAxis) <=
|
|---|
| 538 | sqr(zheight - zTopCut + 0.5*kRadTolerance) )
|
|---|
| 539 | {
|
|---|
| 540 | return distMin = std::fabs(lambda);
|
|---|
| 541 | }
|
|---|
| 542 | }
|
|---|
| 543 |
|
|---|
| 544 | if (p.z() > zTopCut - 0.5*kCarTolerance
|
|---|
| 545 | && p.z() < zTopCut + 0.5*kCarTolerance )
|
|---|
| 546 | {
|
|---|
| 547 | if (v.z() > 0.)
|
|---|
| 548 | { return kInfinity; }
|
|---|
| 549 |
|
|---|
| 550 | return distMin = 0.;
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | if (p.z() < -zTopCut + 0.5*kCarTolerance
|
|---|
| 554 | && p.z() > -zTopCut - 0.5*kCarTolerance)
|
|---|
| 555 | {
|
|---|
| 556 | if (v.z() < 0.)
|
|---|
| 557 | { return distMin = kInfinity; }
|
|---|
| 558 |
|
|---|
| 559 | return distMin = 0.;
|
|---|
| 560 | }
|
|---|
| 561 |
|
|---|
| 562 | #endif
|
|---|
| 563 |
|
|---|
| 564 | // if we are here then it either intersects or grazes the curved surface
|
|---|
| 565 | // or it does not intersect at all
|
|---|
| 566 | //
|
|---|
| 567 |
|
|---|
| 568 | G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
|
|---|
| 569 | G4double B = 2*(v.x()*p.x()/sqr(xSemiAxis) +
|
|---|
| 570 | v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
|
|---|
| 571 | G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis) -
|
|---|
| 572 | sqr(zheight - p.z());
|
|---|
| 573 |
|
|---|
| 574 | G4double discr = B*B - 4.*A*C;
|
|---|
| 575 |
|
|---|
| 576 | // if the discriminant is negative it never hits the curved object
|
|---|
| 577 | //
|
|---|
| 578 | if ( discr < -0.5*kCarTolerance )
|
|---|
| 579 | { return distMin; }
|
|---|
| 580 |
|
|---|
| 581 | //case below is when it hits or grazes the surface
|
|---|
| 582 | //
|
|---|
| 583 | if ( (discr >= - 0.5*kCarTolerance ) && (discr < 0.5*kCarTolerance ) )
|
|---|
| 584 | {
|
|---|
| 585 | return distMin = std::fabs(-B/(2.*A));
|
|---|
| 586 | }
|
|---|
| 587 |
|
|---|
| 588 | G4double plus = (-B+std::sqrt(discr))/(2.*A);
|
|---|
| 589 | G4double minus = (-B-std::sqrt(discr))/(2.*A);
|
|---|
| 590 | // G4double lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
|
|---|
| 591 |
|
|---|
| 592 | G4double lambda = 0;
|
|---|
| 593 |
|
|---|
| 594 | if ( minus > halfTol && minus < distMin )
|
|---|
| 595 | {
|
|---|
| 596 | lambda = minus ;
|
|---|
| 597 | // check normal vector n * v < 0
|
|---|
| 598 | G4ThreeVector pin = p + lambda*v;
|
|---|
| 599 |
|
|---|
| 600 | G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
|
|---|
| 601 | pin.y()/(ySemiAxis*ySemiAxis),
|
|---|
| 602 | - ( pin.z() - zheight ));
|
|---|
| 603 | if ( truenorm*v < 0)
|
|---|
| 604 | { // yes, going inside the solid
|
|---|
| 605 | distMin = lambda;
|
|---|
| 606 | }
|
|---|
| 607 | }
|
|---|
| 608 |
|
|---|
| 609 | if ( plus > halfTol && plus < distMin )
|
|---|
| 610 | {
|
|---|
| 611 | lambda = plus ;
|
|---|
| 612 | // check normal vector n * v < 0
|
|---|
| 613 | G4ThreeVector pin = p + lambda*v;
|
|---|
| 614 |
|
|---|
| 615 | G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
|
|---|
| 616 | pin.y()/(ySemiAxis*ySemiAxis),
|
|---|
| 617 | - ( pin.z() - zheight ) );
|
|---|
| 618 | if ( truenorm*v < 0)
|
|---|
| 619 | { // yes, going inside the solid
|
|---|
| 620 | distMin = lambda;
|
|---|
| 621 | }
|
|---|
| 622 | }
|
|---|
| 623 |
|
|---|
| 624 | #ifdef G4SPECSDEBUG
|
|---|
| 625 | // G4cout << "DToIn: plus,minus, lambda = " << plus
|
|---|
| 626 | // << ", " << minus << ", " << lambda << G4endl ;
|
|---|
| 627 | // G4cout << "DToIn: distMin = " << distMin << G4endl ;
|
|---|
| 628 | #endif
|
|---|
| 629 |
|
|---|
| 630 |
|
|---|
| 631 | return distMin ;
|
|---|
| 632 | }
|
|---|
| 633 |
|
|---|
| 634 | //////////////////////////////////////////////////////////////////////////
|
|---|
| 635 | //
|
|---|
| 636 | // Calculate distance (<= actual) to closest surface of shape from outside
|
|---|
| 637 | // Return 0 if point inside
|
|---|
| 638 | //
|
|---|
| 639 | G4double G4EllipticalCone::DistanceToIn(const G4ThreeVector& p) const
|
|---|
| 640 | {
|
|---|
| 641 | G4double distR, distR2, distZ, maxDim;
|
|---|
| 642 | G4double distRad;
|
|---|
| 643 |
|
|---|
| 644 | // check if the point lies either below z=-zTopCut in bottom elliptical
|
|---|
| 645 | // region or on top within cut elliptical region
|
|---|
| 646 | //
|
|---|
| 647 | if( (p.z() <= -zTopCut) && (sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
|
|---|
| 648 | <= sqr(zTopCut + zheight + 0.5*kCarTolerance )) )
|
|---|
| 649 | {
|
|---|
| 650 | //return distZ = std::fabs(zTopCut - p.z());
|
|---|
| 651 | return distZ = std::fabs(zTopCut + p.z());
|
|---|
| 652 | }
|
|---|
| 653 |
|
|---|
| 654 | if( (p.z() >= zTopCut) && (sqr(p.x()/xSemiAxis)+sqr(p.y()/ySemiAxis)
|
|---|
| 655 | <= sqr(zheight - zTopCut + kCarTolerance/2.0 )) )
|
|---|
| 656 | {
|
|---|
| 657 | return distZ = std::fabs(p.z() - zTopCut);
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | // below we use the following approximation: we take the largest of the
|
|---|
| 661 | // axes and find the shortest distance to the circular (cut) cone of that
|
|---|
| 662 | // radius.
|
|---|
| 663 | //
|
|---|
| 664 | maxDim = xSemiAxis >= ySemiAxis ? xSemiAxis:ySemiAxis;
|
|---|
| 665 | distRad = std::sqrt(p.x()*p.x()+p.y()*p.y());
|
|---|
| 666 |
|
|---|
| 667 | if( p.z() > maxDim*distRad + zTopCut*(1.+maxDim)-sqr(maxDim)*zheight )
|
|---|
| 668 | {
|
|---|
| 669 | distR2 = sqr(p.z() - zTopCut) + sqr(distRad - maxDim*(zheight - zTopCut));
|
|---|
| 670 | return std::sqrt( distR2 );
|
|---|
| 671 | }
|
|---|
| 672 |
|
|---|
| 673 | if( distRad > maxDim*( zheight - p.z() ) )
|
|---|
| 674 | {
|
|---|
| 675 | if( p.z() > maxDim*distRad - (zTopCut*(1.+maxDim)+sqr(maxDim)*zheight) )
|
|---|
| 676 | {
|
|---|
| 677 | G4double zVal = (p.z()-maxDim*(distRad-maxDim*zheight))/(1.+sqr(maxDim));
|
|---|
| 678 | G4double rVal = maxDim*(zheight - zVal);
|
|---|
| 679 | return distR = std::sqrt(sqr(p.z() - zVal) + sqr(distRad - rVal));
|
|---|
| 680 | }
|
|---|
| 681 | }
|
|---|
| 682 |
|
|---|
| 683 | if( distRad <= maxDim*(zheight - p.z()) )
|
|---|
| 684 | {
|
|---|
| 685 | distR2 = sqr(distRad - maxDim*(zheight + zTopCut)) + sqr(p.z() + zTopCut);
|
|---|
| 686 | return std::sqrt( distR2 );
|
|---|
| 687 | }
|
|---|
| 688 |
|
|---|
| 689 | return distR = 0;
|
|---|
| 690 | }
|
|---|
| 691 |
|
|---|
| 692 | /////////////////////////////////////////////////////////////////////////
|
|---|
| 693 | //
|
|---|
| 694 | // Calculate distance to surface of shape from `inside',
|
|---|
| 695 | // allowing for tolerance
|
|---|
| 696 | //
|
|---|
| 697 | G4double G4EllipticalCone::DistanceToOut(const G4ThreeVector& p,
|
|---|
| 698 | const G4ThreeVector& v,
|
|---|
| 699 | const G4bool calcNorm,
|
|---|
| 700 | G4bool *validNorm,
|
|---|
| 701 | G4ThreeVector *n ) const
|
|---|
| 702 | {
|
|---|
| 703 | G4double distMin, lambda;
|
|---|
| 704 | enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
|
|---|
| 705 |
|
|---|
| 706 | distMin = kInfinity;
|
|---|
| 707 | surface = kNoSurf;
|
|---|
| 708 |
|
|---|
| 709 | if (v.z() < 0.0)
|
|---|
| 710 | {
|
|---|
| 711 | lambda = (-p.z() - zTopCut)/v.z();
|
|---|
| 712 |
|
|---|
| 713 | if ( (sqr((p.x() + lambda*v.x())/xSemiAxis) +
|
|---|
| 714 | sqr((p.y() + lambda*v.y())/ySemiAxis)) <
|
|---|
| 715 | sqr(zheight + zTopCut + 0.5*kCarTolerance) )
|
|---|
| 716 | {
|
|---|
| 717 | distMin = std::fabs(lambda);
|
|---|
| 718 |
|
|---|
| 719 | if (!calcNorm) { return distMin; }
|
|---|
| 720 | }
|
|---|
| 721 | distMin = std::fabs(lambda);
|
|---|
| 722 | surface = kPlaneSurf;
|
|---|
| 723 | }
|
|---|
| 724 |
|
|---|
| 725 | if (v.z() > 0.0)
|
|---|
| 726 | {
|
|---|
| 727 | lambda = (zTopCut - p.z()) / v.z();
|
|---|
| 728 |
|
|---|
| 729 | if ( (sqr((p.x() + lambda*v.x())/xSemiAxis)
|
|---|
| 730 | + sqr((p.y() + lambda*v.y())/ySemiAxis) )
|
|---|
| 731 | < (sqr(zheight - zTopCut + 0.5*kCarTolerance)) )
|
|---|
| 732 | {
|
|---|
| 733 | distMin = std::fabs(lambda);
|
|---|
| 734 | if (!calcNorm) { return distMin; }
|
|---|
| 735 | }
|
|---|
| 736 | distMin = std::fabs(lambda);
|
|---|
| 737 | surface = kPlaneSurf;
|
|---|
| 738 | }
|
|---|
| 739 |
|
|---|
| 740 | // if we are here then it either intersects or grazes the
|
|---|
| 741 | // curved surface...
|
|---|
| 742 | //
|
|---|
| 743 | G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
|
|---|
| 744 | G4double B = 2.*(v.x()*p.x()/sqr(xSemiAxis) +
|
|---|
| 745 | v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
|
|---|
| 746 | G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
|
|---|
| 747 | - sqr(zheight - p.z());
|
|---|
| 748 |
|
|---|
| 749 | G4double discr = B*B - 4.*A*C;
|
|---|
| 750 |
|
|---|
| 751 | if ( discr >= - 0.5*kCarTolerance && discr < 0.5*kCarTolerance )
|
|---|
| 752 | {
|
|---|
| 753 | if(!calcNorm) { return distMin = std::fabs(-B/(2.*A)); }
|
|---|
| 754 | }
|
|---|
| 755 |
|
|---|
| 756 | else if ( discr > 0.5*kCarTolerance )
|
|---|
| 757 | {
|
|---|
| 758 | G4double plus = (-B+std::sqrt(discr))/(2.*A);
|
|---|
| 759 | G4double minus = (-B-std::sqrt(discr))/(2.*A);
|
|---|
| 760 |
|
|---|
| 761 | if ( plus > 0.5*kCarTolerance && minus > 0.5*kCarTolerance )
|
|---|
| 762 | {
|
|---|
| 763 | // take the shorter distance
|
|---|
| 764 | //
|
|---|
| 765 | lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
|
|---|
| 766 | }
|
|---|
| 767 | else
|
|---|
| 768 | {
|
|---|
| 769 | // at least one solution is close to zero or negative
|
|---|
| 770 | // so, take small positive solution or zero
|
|---|
| 771 | //
|
|---|
| 772 | lambda = plus > -0.5*kCarTolerance ? plus : 0;
|
|---|
| 773 | }
|
|---|
| 774 |
|
|---|
| 775 | if ( std::fabs(lambda) < distMin )
|
|---|
| 776 | {
|
|---|
| 777 | distMin = std::fabs(lambda);
|
|---|
| 778 | surface = kCurvedSurf;
|
|---|
| 779 | }
|
|---|
| 780 | }
|
|---|
| 781 |
|
|---|
| 782 | // set normal if requested
|
|---|
| 783 | //
|
|---|
| 784 | if (calcNorm)
|
|---|
| 785 | {
|
|---|
| 786 | if (surface == kNoSurf)
|
|---|
| 787 | {
|
|---|
| 788 | *validNorm = false;
|
|---|
| 789 | }
|
|---|
| 790 | else
|
|---|
| 791 | {
|
|---|
| 792 | *validNorm = true;
|
|---|
| 793 | switch (surface)
|
|---|
| 794 | {
|
|---|
| 795 | case kPlaneSurf:
|
|---|
| 796 | {
|
|---|
| 797 | *n = G4ThreeVector(0.,0.,(v.z() > 0.0 ? 1. : -1.));
|
|---|
| 798 | }
|
|---|
| 799 | break;
|
|---|
| 800 |
|
|---|
| 801 | case kCurvedSurf:
|
|---|
| 802 | {
|
|---|
| 803 | G4ThreeVector pexit = p + distMin*v;
|
|---|
| 804 | G4ThreeVector truenorm(pexit.x()/(xSemiAxis*xSemiAxis),
|
|---|
| 805 | pexit.y()/(ySemiAxis*ySemiAxis),
|
|---|
| 806 | pexit.z() - zheight );
|
|---|
| 807 | truenorm /= truenorm.mag();
|
|---|
| 808 | *n= truenorm;
|
|---|
| 809 | }
|
|---|
| 810 | break;
|
|---|
| 811 |
|
|---|
| 812 | default:
|
|---|
| 813 | G4cout.precision(16);
|
|---|
| 814 | G4cout << G4endl;
|
|---|
| 815 | DumpInfo();
|
|---|
| 816 | G4cout << "Position:" << G4endl << G4endl;
|
|---|
| 817 | G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl;
|
|---|
| 818 | G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl;
|
|---|
| 819 | G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl;
|
|---|
| 820 | G4cout << "Direction:" << G4endl << G4endl;
|
|---|
| 821 | G4cout << "v.x() = " << v.x() << G4endl;
|
|---|
| 822 | G4cout << "v.y() = " << v.y() << G4endl;
|
|---|
| 823 | G4cout << "v.z() = " << v.z() << G4endl << G4endl;
|
|---|
| 824 | G4cout << "Proposed distance :" << G4endl << G4endl;
|
|---|
| 825 | G4cout << "distMin = " << distMin/mm << " mm" << G4endl << G4endl;
|
|---|
| 826 | G4Exception("G4EllipticalCone::DistanceToOut(p,v,..)",
|
|---|
| 827 | "Notification", JustWarning,
|
|---|
| 828 | "Undefined side for valid surface normal to solid.");
|
|---|
| 829 | break;
|
|---|
| 830 | }
|
|---|
| 831 | }
|
|---|
| 832 | }
|
|---|
| 833 |
|
|---|
| 834 | return distMin;
|
|---|
| 835 | }
|
|---|
| 836 |
|
|---|
| 837 | /////////////////////////////////////////////////////////////////////////
|
|---|
| 838 | //
|
|---|
| 839 | // Calculate distance (<=actual) to closest surface of shape from inside
|
|---|
| 840 | //
|
|---|
| 841 | G4double G4EllipticalCone::DistanceToOut(const G4ThreeVector& p) const
|
|---|
| 842 | {
|
|---|
| 843 | G4double rad,roo,roo1, distR, distZ, distMin=0.;
|
|---|
| 844 | G4double minAxis = xSemiAxis < ySemiAxis ? xSemiAxis : ySemiAxis;
|
|---|
| 845 |
|
|---|
| 846 | #ifdef G4SPECSDEBUG
|
|---|
| 847 | if( Inside(p) == kOutside )
|
|---|
| 848 | {
|
|---|
| 849 | G4cout.precision(16) ;
|
|---|
| 850 | G4cout << G4endl ;
|
|---|
| 851 | DumpInfo();
|
|---|
| 852 | G4cout << "Position:" << G4endl << G4endl ;
|
|---|
| 853 | G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
|
|---|
| 854 | G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
|
|---|
| 855 | G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
|
|---|
| 856 | G4Exception("G4Ellipsoid::DistanceToOut(p)", "Notification", JustWarning,
|
|---|
| 857 | "Point p is outside !?" );
|
|---|
| 858 | }
|
|---|
| 859 | #endif
|
|---|
| 860 |
|
|---|
| 861 | // since we have made the above warning, below we are working assuming p
|
|---|
| 862 | // is inside check how close it is to the circular cone with radius equal
|
|---|
| 863 | // to the smaller of the axes
|
|---|
| 864 | //
|
|---|
| 865 | if( sqr(p.x()/minAxis)+sqr(p.y()/minAxis) < sqr(zheight - p.z()) )
|
|---|
| 866 | {
|
|---|
| 867 | rad = std::sqrt(sqr(p.x()) + sqr(p.y()));
|
|---|
| 868 | roo = minAxis*(zheight-p.z()); // radius of cone at z= p.z()
|
|---|
| 869 | roo1 = minAxis*(zheight-zTopCut); // radius of cone at z=+zTopCut
|
|---|
| 870 |
|
|---|
| 871 | distZ=zTopCut - std::fabs(p.z()) ;
|
|---|
| 872 | distR=(roo-rad)/(std::sqrt(1+sqr(minAxis)));
|
|---|
| 873 |
|
|---|
| 874 | if(rad>roo1)
|
|---|
| 875 | {
|
|---|
| 876 | distMin=(zTopCut-p.z())*(roo-rad)/(roo-roo1);
|
|---|
| 877 | distMin=std::min(distMin,distR);
|
|---|
| 878 | }
|
|---|
| 879 | distMin=std::min(distR,distZ);
|
|---|
| 880 | }
|
|---|
| 881 |
|
|---|
| 882 | return distMin;
|
|---|
| 883 | }
|
|---|
| 884 |
|
|---|
| 885 | //////////////////////////////////////////////////////////////////////////
|
|---|
| 886 | //
|
|---|
| 887 | // GetEntityType
|
|---|
| 888 | //
|
|---|
| 889 | G4GeometryType G4EllipticalCone::GetEntityType() const
|
|---|
| 890 | {
|
|---|
| 891 | return G4String("G4EllipticalCone");
|
|---|
| 892 | }
|
|---|
| 893 |
|
|---|
| 894 | //////////////////////////////////////////////////////////////////////////
|
|---|
| 895 | //
|
|---|
| 896 | // Stream object contents to an output stream
|
|---|
| 897 | //
|
|---|
| 898 | std::ostream& G4EllipticalCone::StreamInfo( std::ostream& os ) const
|
|---|
| 899 | {
|
|---|
| 900 | os << "-----------------------------------------------------------\n"
|
|---|
| 901 | << " *** Dump for solid - " << GetName() << " ***\n"
|
|---|
| 902 | << " ===================================================\n"
|
|---|
| 903 | << " Solid type: G4EllipticalCone\n"
|
|---|
| 904 | << " Parameters: \n"
|
|---|
| 905 |
|
|---|
| 906 | << " semi-axis x: " << xSemiAxis/mm << " mm \n"
|
|---|
| 907 | << " semi-axis y: " << ySemiAxis/mm << " mm \n"
|
|---|
| 908 | << " height z: " << zheight/mm << " mm \n"
|
|---|
| 909 | << " half length in z: " << zTopCut/mm << " mm \n"
|
|---|
| 910 | << "-----------------------------------------------------------\n";
|
|---|
| 911 |
|
|---|
| 912 | return os;
|
|---|
| 913 | }
|
|---|
| 914 |
|
|---|
| 915 | /////////////////////////////////////////////////////////////////////////
|
|---|
| 916 | //
|
|---|
| 917 | // GetPointOnSurface
|
|---|
| 918 | //
|
|---|
| 919 | // returns quasi-uniformly distributed point on surface of elliptical cone
|
|---|
| 920 | //
|
|---|
| 921 | G4ThreeVector G4EllipticalCone::GetPointOnSurface() const
|
|---|
| 922 | {
|
|---|
| 923 |
|
|---|
| 924 | G4double phi, sinphi, cosphi, aOne, aTwo, aThree,
|
|---|
| 925 | chose, zRand, rRand1, rRand2;
|
|---|
| 926 |
|
|---|
| 927 | G4double rOne = std::sqrt(sqr(xSemiAxis)
|
|---|
| 928 | + sqr(ySemiAxis))*(zheight - zTopCut);
|
|---|
| 929 | G4double rTwo = std::sqrt(sqr(xSemiAxis)
|
|---|
| 930 | + sqr(ySemiAxis))*(zheight + zTopCut);
|
|---|
| 931 |
|
|---|
| 932 | aOne = pi*(rOne + rTwo)*std::sqrt(sqr(rOne - rTwo)+sqr(2.*zTopCut));
|
|---|
| 933 | aTwo = pi*xSemiAxis*ySemiAxis*sqr(zheight+zTopCut);
|
|---|
| 934 | aThree = pi*xSemiAxis*ySemiAxis*sqr(zheight-zTopCut);
|
|---|
| 935 |
|
|---|
| 936 | phi = RandFlat::shoot(0.,twopi);
|
|---|
| 937 | cosphi = std::cos(phi);
|
|---|
| 938 | sinphi = std::sin(phi);
|
|---|
| 939 |
|
|---|
| 940 | if(zTopCut >= zheight) aThree = 0.;
|
|---|
| 941 |
|
|---|
| 942 | chose = RandFlat::shoot(0.,aOne+aTwo+aThree);
|
|---|
| 943 | if((chose>=0.) && (chose<aOne))
|
|---|
| 944 | {
|
|---|
| 945 | zRand = RandFlat::shoot(-zTopCut,zTopCut);
|
|---|
| 946 | return G4ThreeVector(xSemiAxis*(zheight-zRand)*cosphi,
|
|---|
| 947 | ySemiAxis*(zheight-zRand)*sinphi,zRand);
|
|---|
| 948 | }
|
|---|
| 949 | else if((chose>=aOne) && (chose<aOne+aTwo))
|
|---|
| 950 | {
|
|---|
| 951 | do
|
|---|
| 952 | {
|
|---|
| 953 | rRand1 = RandFlat::shoot(0.,1.) ;
|
|---|
| 954 | rRand2 = RandFlat::shoot(0.,1.) ;
|
|---|
| 955 | } while ( rRand2 >= rRand1 ) ;
|
|---|
| 956 |
|
|---|
| 957 | // rRand2 = RandFlat::shoot(0.,std::sqrt(1.-sqr(rRand1)));
|
|---|
| 958 | return G4ThreeVector(rRand1*xSemiAxis*(zheight+zTopCut)*cosphi,
|
|---|
| 959 | rRand1*ySemiAxis*(zheight+zTopCut)*sinphi, -zTopCut);
|
|---|
| 960 |
|
|---|
| 961 | }
|
|---|
| 962 | // else
|
|---|
| 963 | //
|
|---|
| 964 |
|
|---|
| 965 | do
|
|---|
| 966 | {
|
|---|
| 967 | rRand1 = RandFlat::shoot(0.,1.) ;
|
|---|
| 968 | rRand2 = RandFlat::shoot(0.,1.) ;
|
|---|
| 969 | } while ( rRand2 >= rRand1 ) ;
|
|---|
| 970 |
|
|---|
| 971 | return G4ThreeVector(rRand1*xSemiAxis*(zheight-zTopCut)*cosphi,
|
|---|
| 972 | rRand1*ySemiAxis*(zheight-zTopCut)*sinphi, zTopCut);
|
|---|
| 973 | }
|
|---|
| 974 |
|
|---|
| 975 | //
|
|---|
| 976 | // Methods for visualisation
|
|---|
| 977 | //
|
|---|
| 978 |
|
|---|
| 979 | void G4EllipticalCone::DescribeYourselfTo (G4VGraphicsScene& scene) const
|
|---|
| 980 | {
|
|---|
| 981 | scene.AddSolid(*this);
|
|---|
| 982 | }
|
|---|
| 983 |
|
|---|
| 984 | G4VisExtent G4EllipticalCone::GetExtent() const
|
|---|
| 985 | {
|
|---|
| 986 | // Define the sides of the box into which the solid instance would fit.
|
|---|
| 987 | //
|
|---|
| 988 | G4double maxDim;
|
|---|
| 989 | maxDim = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis;
|
|---|
| 990 | maxDim = maxDim > zTopCut ? maxDim : zTopCut;
|
|---|
| 991 |
|
|---|
| 992 | return G4VisExtent (-maxDim, maxDim,
|
|---|
| 993 | -maxDim, maxDim,
|
|---|
| 994 | -maxDim, maxDim);
|
|---|
| 995 | }
|
|---|
| 996 |
|
|---|
| 997 | G4NURBS* G4EllipticalCone::CreateNURBS () const
|
|---|
| 998 | {
|
|---|
| 999 | // Box for now!!!
|
|---|
| 1000 | //
|
|---|
| 1001 | return new G4NURBSbox(xSemiAxis, ySemiAxis,zheight);
|
|---|
| 1002 | }
|
|---|
| 1003 |
|
|---|
| 1004 | G4Polyhedron* G4EllipticalCone::CreatePolyhedron () const
|
|---|
| 1005 | {
|
|---|
| 1006 | return new G4PolyhedronEllipticalCone(xSemiAxis, ySemiAxis, zheight, zTopCut);
|
|---|
| 1007 | }
|
|---|
| 1008 |
|
|---|
| 1009 | G4Polyhedron* G4EllipticalCone::GetPolyhedron () const
|
|---|
| 1010 | {
|
|---|
| 1011 | if ( (!fpPolyhedron)
|
|---|
| 1012 | || (fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
|
|---|
| 1013 | fpPolyhedron->GetNumberOfRotationSteps()) )
|
|---|
| 1014 | {
|
|---|
| 1015 | delete fpPolyhedron;
|
|---|
| 1016 | fpPolyhedron = CreatePolyhedron();
|
|---|
| 1017 | }
|
|---|
| 1018 | return fpPolyhedron;
|
|---|
| 1019 | }
|
|---|