// // ******************************************************************** // * DISCLAIMER * // * * // * The following disclaimer summarizes all the specific disclaimers * // * of contributors to this software. The specific disclaimers,which * // * govern, are listed with their locations in: * // * http://cern.ch/geant4/license * // * * // * 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. * // * * // * This code implementation is the intellectual property of the * // * GEANT4 collaboration. * // * By copying, distributing or modifying the Program (or any work * // * based on the Program) you indicate your acceptance of this * // * statement, and all its terms. * // ******************************************************************** // // // $Id: G4VoxelNavigation.cc,v 1.14 2003/06/16 16:55:00 gunter Exp $ // GEANT4 tag $Name: geant4-05-02 $ // // // class G4VoxelNavigation Implementation // // Author: P.Kent, 1996 // // ******************************************************************** #include "G4VoxelNavigation.hh" // ******************************************************************** // Constructor // ******************************************************************** // G4VoxelNavigation::G4VoxelNavigation() : fVoxelDepth(-1), fVoxelAxisStack(kNavigatorVoxelStackMax,kXAxis), fVoxelNoSlicesStack(kNavigatorVoxelStackMax,0), fVoxelSliceWidthStack(kNavigatorVoxelStackMax,0.), fVoxelNodeNoStack(kNavigatorVoxelStackMax,0), fVoxelHeaderStack(kNavigatorVoxelStackMax,(G4SmartVoxelHeader*)0), fVoxelNode(0) { } // ******************************************************************** // Destructor // ******************************************************************** // G4VoxelNavigation::~G4VoxelNavigation() { #ifdef G4DEBUG_NAVIGATION G4cout << "G4VoxelNavigation::~G4VoxelNavigation() called." << G4endl; #endif } // ******************************************************************** // ComputeStep // ******************************************************************** // G4double G4VoxelNavigation::ComputeStep( const G4ThreeVector& localPoint, const G4ThreeVector& localDirection, const G4double currentProposedStepLength, G4double& newSafety, G4NavigationHistory& history, G4bool& validExitNormal, G4ThreeVector& exitNormal, G4bool& exiting, G4bool& entering, G4VPhysicalVolume *(*pBlockedPhysical), G4int& blockedReplicaNo ) { G4VPhysicalVolume *motherPhysical, *samplePhysical, *blockedExitedVol=0; G4LogicalVolume *motherLogical; G4VSolid *motherSolid; G4ThreeVector sampleDirection; G4double ourStep=currentProposedStepLength, motherSafety, ourSafety; G4int localNoDaughters, sampleNo; G4bool initialNode, noStep; G4SmartVoxelNode *curVoxelNode; G4int curNoVolumes, contentNo; G4double voxelSafety; motherPhysical = history.GetTopVolume(); motherLogical = motherPhysical->GetLogicalVolume(); motherSolid = motherLogical->GetSolid(); // // Compute mother safety // motherSafety = motherSolid->DistanceToOut(localPoint); ourSafety = motherSafety; // Working isotropic safety // // Compute daughter safeties & intersections // // Exiting normal optimisation // if ( exiting && validExitNormal ) { if ( localDirection.dot(exitNormal)>=kMinExitingNormalCosine ) { // Block exited daughter volume // blockedExitedVol = *pBlockedPhysical; ourSafety = 0; } } exiting = false; entering = false; localNoDaughters = motherLogical->GetNoDaughters(); fBList.Enlarge(localNoDaughters); fBList.Reset(); initialNode = true; noStep = true; while (noStep) { curVoxelNode = fVoxelNode; curNoVolumes = curVoxelNode->GetNoContained(); for (contentNo=curNoVolumes-1; contentNo>=0; contentNo--) { sampleNo = curVoxelNode->GetVolume(contentNo); if ( !fBList.IsBlocked(sampleNo) ) { fBList.BlockVolume(sampleNo); samplePhysical = motherLogical->GetDaughter(sampleNo); if ( samplePhysical!=blockedExitedVol ) { samplePhysical->Setup(motherPhysical); G4AffineTransform sampleTf(samplePhysical->GetRotation(), samplePhysical->GetTranslation()); sampleTf.Invert(); const G4ThreeVector samplePoint = sampleTf.TransformPoint(localPoint); const G4VSolid *sampleSolid = samplePhysical->GetLogicalVolume()->GetSolid(); const G4double sampleSafety = sampleSolid->DistanceToIn(samplePoint); if ( sampleSafetyDistanceToIn(samplePoint, sampleDirection); if ( sampleStep<=ourStep ) { ourStep = sampleStep; entering = true; exiting = false; *pBlockedPhysical = samplePhysical; blockedReplicaNo = -1; } } } } } if (initialNode) { initialNode = false; voxelSafety = ComputeVoxelSafety(localPoint); if ( voxelSafetyDistanceToOut(localPoint, localDirection, true, &validExitNormal, &exitNormal); if ( motherStep<=ourStep ) { ourStep = motherStep; exiting = true; entering = false; if ( validExitNormal ) { const G4RotationMatrix *rot = motherPhysical->GetRotation(); if (rot) { exitNormal *= rot->inverse(); } } } else { validExitNormal = false; } } } newSafety = ourSafety; } if (noStep) { noStep = LocateNextVoxel(localPoint, localDirection, ourStep); } } // end -while (noStep)- loop return ourStep; } // ******************************************************************** // ComputeVoxelSafety // // Computes safety from specified point to voxel boundaries // using already located point // o collected boundaries for most derived level // o adjacent boundaries for previous levels // ******************************************************************** // G4double G4VoxelNavigation::ComputeVoxelSafety(const G4ThreeVector& localPoint) const { G4SmartVoxelHeader *curHeader; G4double voxelSafety, curNodeWidth; G4double curNodeOffset, minCurCommonDelta, maxCurCommonDelta; G4int minCurNodeNoDelta, maxCurNodeNoDelta; G4int localVoxelDepth, curNodeNo; EAxis curHeaderAxis; localVoxelDepth = fVoxelDepth; curHeader = fVoxelHeaderStack[localVoxelDepth]; curHeaderAxis = fVoxelAxisStack[localVoxelDepth]; curNodeNo = fVoxelNodeNoStack[localVoxelDepth]; curNodeWidth = fVoxelSliceWidthStack[localVoxelDepth]; // Compute linear intersection distance to boundaries of max/min // to collected nodes at current level // curNodeOffset = curNodeNo*curNodeWidth; maxCurNodeNoDelta = fVoxelNode->GetMaxEquivalentSliceNo()-curNodeNo; minCurNodeNoDelta = curNodeNo-fVoxelNode->GetMinEquivalentSliceNo(); minCurCommonDelta = localPoint(curHeaderAxis) - curHeader->GetMinExtent() - curNodeOffset; maxCurCommonDelta = curNodeWidth-minCurCommonDelta; if ( minCurNodeNoDelta0) && (voxelSafety>0) ) { localVoxelDepth--; curHeader = fVoxelHeaderStack[localVoxelDepth]; curHeaderAxis = fVoxelAxisStack[localVoxelDepth]; curNodeNo = fVoxelNodeNoStack[localVoxelDepth]; curNodeWidth = fVoxelSliceWidthStack[localVoxelDepth]; curNodeOffset = curNodeNo*curNodeWidth; minCurCommonDelta = localPoint(curHeaderAxis) - curHeader->GetMinExtent() - curNodeOffset; maxCurCommonDelta = curNodeWidth-minCurCommonDelta; if ( minCurCommonDeltaGetMinExtent(); workCoord = targetPoint(workHeaderAxis); minVal = workMinExtent+workNodeNo*workNodeWidth; if ( minVal<=workCoord+kCarTolerance*0.5 ) { maxVal = minVal+workNodeWidth; if ( maxVal<=workCoord-kCarTolerance*0.5 ) { // Must consider next voxel // newNodeNo = workNodeNo+1; newHeader = workHeader; newDistance = (maxVal-localPoint(workHeaderAxis)) / localDirection(workHeaderAxis); isNewVoxel = true; newDepth = depth; } } else { newNodeNo = workNodeNo-1; newHeader = workHeader; newDistance = (minVal-localPoint(workHeaderAxis)) / localDirection(workHeaderAxis); isNewVoxel = true; newDepth = depth; } currentDistance = newDistance; } targetPoint = localPoint+localDirection*currentDistance; // Check if end of Step within collected boundaries of current voxel // depth = fVoxelDepth; { workHeader = fVoxelHeaderStack[depth]; workHeaderAxis = fVoxelAxisStack[depth]; workNodeNo = fVoxelNodeNoStack[depth]; workNodeWidth = fVoxelSliceWidthStack[depth]; workMinExtent = workHeader->GetMinExtent(); workCoord = targetPoint(workHeaderAxis); minVal = workMinExtent+fVoxelNode->GetMinEquivalentSliceNo()*workNodeWidth; if ( minVal<=workCoord+kCarTolerance*0.5 ) { maxVal = workMinExtent+(fVoxelNode->GetMaxEquivalentSliceNo()+1) *workNodeWidth; if ( maxVal<=workCoord-kCarTolerance*0.5 ) { newNodeNo = fVoxelNode->GetMaxEquivalentSliceNo()+1; newHeader = workHeader; newDistance = (maxVal-localPoint(workHeaderAxis)) / localDirection(workHeaderAxis); isNewVoxel = true; newDepth = depth; } } else { newNodeNo = fVoxelNode->GetMinEquivalentSliceNo()-1; newHeader = workHeader; newDistance = (minVal-localPoint(workHeaderAxis)) / localDirection(workHeaderAxis); isNewVoxel = true; newDepth = depth; } currentDistance = newDistance; } if (isNewVoxel) { // Compute new voxel & adjust voxel stack // // newNodeNo=Candidate node no at // newDepth =refinement depth of crossed voxel boundary // newHeader=Header for crossed voxel // newDistance=distance to crossed voxel boundary (along the track) // if ( (newNodeNo<0) || (newNodeNo>=newHeader->GetNoSlices())) { // Leaving mother volume // isNewVoxel = false; } else { // Compute intersection point on the least refined // voxel boundary that is hit // voxelPoint = localPoint+localDirection*newDistance; fVoxelNodeNoStack[newDepth] = newNodeNo; fVoxelDepth = newDepth; newVoxelNode = 0; while ( !newVoxelNode ) { newProxy = newHeader->GetSlice(newNodeNo); if (newProxy->IsNode()) { newVoxelNode = newProxy->GetNode(); } else { fVoxelDepth++; newHeader = newProxy->GetHeader(); newHeaderAxis = newHeader->GetAxis(); newHeaderNoSlices = newHeader->GetNoSlices(); newHeaderMin = newHeader->GetMinExtent(); newHeaderNodeWidth = (newHeader->GetMaxExtent()-newHeaderMin) / newHeaderNoSlices; newNodeNo = G4int( (voxelPoint(newHeaderAxis)-newHeaderMin) / newHeaderNodeWidth ); // Rounding protection // if ( newNodeNo<0 ) { newNodeNo=0; } else if ( newNodeNo>=newHeaderNoSlices ) { newNodeNo = newHeaderNoSlices-1; } // Stack info for stepping // fVoxelAxisStack[fVoxelDepth] = newHeaderAxis; fVoxelNoSlicesStack[fVoxelDepth] = newHeaderNoSlices; fVoxelSliceWidthStack[fVoxelDepth] = newHeaderNodeWidth; fVoxelNodeNoStack[fVoxelDepth] = newNodeNo; fVoxelHeaderStack[fVoxelDepth] = newHeader; } } fVoxelNode = newVoxelNode; } } return isNewVoxel; } // ******************************************************************** // ComputeSafety // // Calculates the isotropic distance to the nearest boundary from the // specified point in the local coordinate system. // The localpoint utilised must be within the current volume. // ******************************************************************** // G4double G4VoxelNavigation::ComputeSafety(const G4ThreeVector& localPoint, const G4NavigationHistory& history, const G4double ) { G4VPhysicalVolume *motherPhysical, *samplePhysical; G4LogicalVolume *motherLogical; G4VSolid *motherSolid; G4double motherSafety, ourSafety; G4int localNoDaughters, sampleNo; G4SmartVoxelNode *curVoxelNode; G4int curNoVolumes, contentNo; G4double voxelSafety; motherPhysical = history.GetTopVolume(); motherLogical = motherPhysical->GetLogicalVolume(); motherSolid = motherLogical->GetSolid(); // // Compute mother safety // motherSafety = motherSolid->DistanceToOut(localPoint); ourSafety = motherSafety; // Working isotropic safety // // Compute daughter safeties // localNoDaughters = motherLogical->GetNoDaughters(); // Look only inside the current Voxel only (in the first version). // curVoxelNode = fVoxelNode; curNoVolumes = curVoxelNode->GetNoContained(); for ( contentNo=curNoVolumes-1; contentNo>=0; contentNo-- ) { sampleNo = curVoxelNode->GetVolume(contentNo); samplePhysical = motherLogical->GetDaughter(sampleNo); samplePhysical->Setup(motherPhysical); G4AffineTransform sampleTf(samplePhysical->GetRotation(), samplePhysical->GetTranslation()); sampleTf.Invert(); const G4ThreeVector samplePoint = sampleTf.TransformPoint(localPoint); const G4VSolid *sampleSolid = samplePhysical->GetLogicalVolume()->GetSolid(); G4double sampleSafety = sampleSolid->DistanceToIn(samplePoint); if ( sampleSafety