G4SmartVoxelHeader.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id$
00028 //
00029 // 
00030 // class G4SmartVoxelHeader
00031 //
00032 // Implementation
00033 //
00034 // Define G4GEOMETRY_VOXELDEBUG for debugging information on G4cout
00035 //
00036 // History:
00037 // 29.04.02 Use 3D voxelisation for non consuming replication - G.C.
00038 // 18.04.01 Migrated to STL vector - G.C.
00039 // 12.02.99 Introduction of new quality/smartless: max for (slices/candid) S.G.
00040 // 11.02.99 Voxels at lower levels are now built for collapsed slices      S.G.
00041 // 21.07.95 Full implementation, supporting non divided physical volumes
00042 // 14.07.95 Initial version - stubb definitions only
00043 // --------------------------------------------------------------------
00044 
00045 #include "G4SmartVoxelHeader.hh"
00046 
00047 #include "G4ios.hh"
00048 
00049 #include "G4LogicalVolume.hh"
00050 #include "G4VPhysicalVolume.hh"
00051 #include "G4VoxelLimits.hh"
00052 
00053 #include "voxeldefs.hh"
00054 #include "G4AffineTransform.hh"
00055 #include "G4VSolid.hh"
00056 #include "G4VPVParameterisation.hh"
00057 
00058 // ***************************************************************************
00059 // Constructor for topmost header, to begin voxel construction at a
00060 // given logical volume.
00061 // Constructs target List of volumes, calls "Build and refine" constructor.
00062 // Assumes all daughters represent single volumes (ie. no divisions
00063 // or parametric)
00064 // ***************************************************************************
00065 //
00066 G4SmartVoxelHeader::G4SmartVoxelHeader(G4LogicalVolume* pVolume,
00067                                        G4int pSlice)
00068   : fminEquivalent(pSlice),
00069     fmaxEquivalent(pSlice),
00070     fparamAxis(kUndefined)
00071 {
00072   G4int nDaughters = pVolume->GetNoDaughters();
00073   G4VoxelLimits limits;   // Create `unlimited' limits object
00074 
00075   // Determine whether daughter is replicated
00076   //
00077   if ((nDaughters!=1) || (!pVolume->GetDaughter(0)->IsReplicated()))
00078   {
00079     // Daughter not replicated => conventional voxel Build
00080     // where each daughters extents are computed
00081     //
00082     BuildVoxels(pVolume);
00083   }
00084   else
00085   {
00086     // Single replicated daughter
00087     //
00088     BuildReplicaVoxels(pVolume);
00089   }
00090 }
00091 
00092 // ***************************************************************************
00093 // Protected constructor:
00094 // builds and refines voxels between specified limits, considering only
00095 // the physical volumes numbered `pCandidates'. `pSlice' is used to set max
00096 // and min equivalent slice nos for the header - they apply to the level
00097 // of the header, not its nodes.
00098 // ***************************************************************************
00099 //
00100 G4SmartVoxelHeader::G4SmartVoxelHeader(G4LogicalVolume* pVolume,
00101                                  const G4VoxelLimits& pLimits,
00102                                  const G4VolumeNosVector* pCandidates,
00103                                        G4int pSlice)
00104   : fminEquivalent(pSlice),
00105     fmaxEquivalent(pSlice),
00106     fparamAxis(kUndefined)
00107 {
00108 #ifdef G4GEOMETRY_VOXELDEBUG
00109   G4cout << "**** G4SmartVoxelHeader::G4SmartVoxelHeader" << G4endl
00110          << "     Limits " << pLimits << G4endl
00111          << "     Candidate #s = " ;
00112   for (size_t i=0;i<pCandidates->size();i++)
00113   {
00114     G4cout << (*pCandidates)[i] << " ";
00115   }
00116   G4cout << G4endl;
00117 #endif   
00118 
00119   BuildVoxelsWithinLimits(pVolume,pLimits,pCandidates);
00120 }
00121 
00122 // ***************************************************************************
00123 // Destructor:
00124 // deletes all proxies and underlying objects.
00125 // ***************************************************************************
00126 //
00127 G4SmartVoxelHeader::~G4SmartVoxelHeader()
00128 {
00129   // Manually destroy underlying nodes/headers
00130   // Delete collected headers and nodes once only
00131   //
00132   G4int node, proxy, maxNode=fslices.size();
00133   G4SmartVoxelProxy *lastProxy=0;
00134   G4SmartVoxelNode *dyingNode, *lastNode=0;
00135   G4SmartVoxelHeader *dyingHeader, *lastHeader=0;
00136 
00137   for (node=0; node<maxNode; node++)
00138   {
00139     if (fslices[node]->IsHeader())
00140     {
00141       dyingHeader = fslices[node]->GetHeader();
00142       if (lastHeader!=dyingHeader)
00143       {
00144         lastHeader = dyingHeader;
00145         lastNode = 0;
00146         delete dyingHeader;
00147       }
00148     }
00149     else
00150     {
00151       dyingNode = fslices[node]->GetNode();
00152       if (dyingNode!=lastNode)
00153       {
00154         lastNode=dyingNode;
00155         lastHeader=0;
00156         delete dyingNode;
00157       }
00158     }
00159   }
00160   // Delete proxies
00161   //
00162   for (proxy=0; proxy<maxNode; proxy++)
00163   {
00164     if (fslices[proxy]!=lastProxy)
00165     {
00166       lastProxy = fslices[proxy];
00167       delete lastProxy;
00168     }
00169   }
00170   // Don't need to clear slices
00171   // fslices.clear();
00172 }
00173 
00174 // ***************************************************************************
00175 // Equality operator: returns true if contents are equivalent.
00176 // Implies a deep search through contained nodes/header.
00177 // Compares headers' axes,sizes,extents. Returns false if different.
00178 // For each contained proxy, determines whether node/header, compares and
00179 // returns if different. Compares and returns if proxied nodes/headers
00180 // are different.
00181 // ***************************************************************************
00182 //
00183 G4bool G4SmartVoxelHeader::operator == (const G4SmartVoxelHeader& pHead) const
00184 {
00185   if ( (GetAxis()      == pHead.GetAxis())
00186     && (GetNoSlices()  == pHead.GetNoSlices())
00187     && (GetMinExtent() == pHead.GetMinExtent())
00188     && (GetMaxExtent() == pHead.GetMaxExtent()) )
00189   {
00190     G4int node, maxNode;
00191     G4SmartVoxelProxy *leftProxy, *rightProxy;
00192     G4SmartVoxelHeader *leftHeader, *rightHeader;
00193     G4SmartVoxelNode *leftNode, *rightNode;
00194 
00195     maxNode=GetNoSlices();
00196     for (node=0; node<maxNode; node++)
00197     {
00198       leftProxy  = GetSlice(node);
00199       rightProxy = pHead.GetSlice(node);
00200       if (leftProxy->IsHeader())
00201       {
00202         if (rightProxy->IsNode())
00203         {
00204           return false;
00205         }
00206         else
00207         {
00208           leftHeader  = leftProxy->GetHeader();
00209           rightHeader = rightProxy->GetHeader();
00210           if (!(*leftHeader==*rightHeader))
00211           {
00212             return false;
00213           }
00214         }
00215       }
00216       else
00217       {
00218         if (rightProxy->IsHeader())
00219         {
00220           return false;
00221         }
00222         else
00223         {
00224           leftNode  = leftProxy->GetNode();
00225           rightNode = rightProxy->GetNode();
00226           if (!(*leftNode==*rightNode))
00227           {
00228             return false;
00229           }
00230         }
00231       }
00232     }
00233     return true;
00234   }
00235   else
00236   {
00237     return false;
00238   }
00239 }
00240 
00241 // ***************************************************************************
00242 // Builds voxels for daughters specified volume, in NON-REPLICATED case
00243 // o Create List of target volume nos (all daughters; 0->noDaughters-1)
00244 // o BuildWithinLimits does Build & also determines mother dimensions.
00245 // ***************************************************************************
00246 //
00247 void G4SmartVoxelHeader::BuildVoxels(G4LogicalVolume* pVolume)
00248 {
00249   G4VoxelLimits limits;   // Create `unlimited' limits object
00250   G4int nDaughters = pVolume->GetNoDaughters();
00251 
00252   G4VolumeNosVector targetList;
00253   targetList.reserve(nDaughters);
00254   for (G4int i=0; i<nDaughters; i++)
00255   {
00256     targetList.push_back(i);
00257   }
00258   BuildVoxelsWithinLimits(pVolume, limits, &targetList);
00259 }
00260 
00261 // ***************************************************************************
00262 // Builds voxels for specified volume containing a single replicated volume.
00263 // If axis is not specified (i.e. "kUndefined"), 3D voxelisation is applied,
00264 // and the best axis is determined according to heuristics as for placements.
00265 // ***************************************************************************
00266 //
00267 void G4SmartVoxelHeader::BuildReplicaVoxels(G4LogicalVolume* pVolume)
00268 {
00269   G4VPhysicalVolume *pDaughter=0;
00270 
00271   // Replication data
00272   //
00273   EAxis axis;
00274   G4int nReplicas;
00275   G4double width,offset;
00276   G4bool consuming;
00277 
00278   // Consistency check: pVolume should contain single replicated volume
00279   //
00280   if ( (pVolume->GetNoDaughters()==1)
00281     && (pVolume->GetDaughter(0)->IsReplicated()==true) )
00282   {
00283     // Obtain replication data
00284     //
00285     pDaughter=pVolume->GetDaughter(0);
00286     pDaughter->GetReplicationData(axis,nReplicas,width,offset,consuming);
00287     fparamAxis = axis;
00288     if ( consuming==false )
00289     {
00290       G4VoxelLimits limits;   // Create `unlimited' limits object
00291       G4VolumeNosVector targetList;
00292       targetList.reserve(nReplicas);
00293       for (G4int i=0; i<nReplicas; i++)
00294       {
00295         targetList.push_back(i);
00296       }
00297       if (axis != kUndefined)
00298       {
00299         // Apply voxelisation along the specified axis only
00300 
00301         G4ProxyVector* pSlices=BuildNodes(pVolume,limits,&targetList,axis);
00302         faxis = axis;
00303         fslices = *pSlices;
00304         delete pSlices;
00305 
00306         // Calculate and set min and max extents given our axis
00307         //
00308         const G4AffineTransform origin;
00309         pVolume->GetSolid()->CalculateExtent(faxis, limits, origin,
00310                                              fminExtent, fmaxExtent);
00311         // Calculate equivalent nos
00312         //
00313         BuildEquivalentSliceNos();
00314         CollectEquivalentNodes();   // Collect common nodes
00315       }
00316       else
00317       {
00318         // Build voxels similarly as for normal placements considering
00319         // all three cartesian axes.
00320 
00321         BuildVoxelsWithinLimits(pVolume, limits, &targetList);
00322       }
00323     }
00324     else
00325     {
00326       // Replication is consuming -> Build voxels directly
00327       //
00328       // o Cartesian axes - range is -width*nREplicas/2 to +width*nREplicas/2
00329       //                    nReplicas replications result
00330       // o Radial axis (rho) = range is 0 to width*nReplicas
00331       //                    nReplicas replications result
00332       // o Phi axi       - range is offset to offset+width*nReplicas radians
00333       //
00334       // Equivalent slices no computation & collection not required - all
00335       // slices are different
00336       //
00337       switch (axis)
00338       {
00339         case kXAxis:
00340         case kYAxis:
00341         case kZAxis:
00342           fminExtent = -width*nReplicas*0.5;
00343           fmaxExtent =  width*nReplicas*0.5;
00344           break;
00345         case kRho:
00346           fminExtent = offset;
00347           fmaxExtent = width*nReplicas+offset;
00348           break;
00349         case kPhi:
00350           fminExtent = offset;
00351           fmaxExtent = offset+width*nReplicas;
00352           break;
00353         default:
00354           G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels()",
00355                       "GeomMgt0002", FatalException, "Illegal axis.");
00356           break;
00357       }  
00358       faxis = axis;   // Set axis
00359       BuildConsumedNodes(nReplicas);
00360       if ( (axis==kXAxis) || (axis==kYAxis) || (axis==kZAxis) )
00361       {
00362         // Sanity check on extent
00363         //
00364         G4double emin = kInfinity, emax = -kInfinity;
00365         G4VoxelLimits limits;
00366         G4AffineTransform origin;
00367         pVolume->GetSolid()->CalculateExtent(axis, limits, origin, emin, emax);
00368         if ( (std::fabs((emin-fminExtent)/fminExtent) +
00369               std::fabs((emax-fmaxExtent)/fmaxExtent)) > 0.05)
00370         {
00371           std::ostringstream message;
00372           message << "Sanity check: wrong solid extent." << G4endl
00373                   << "        Replicated geometry, logical volume: "
00374                   << pVolume->GetName();
00375           G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels",
00376                       "GeomMgt0002", FatalException, message);
00377         }
00378       }
00379     }
00380   }
00381   else
00382   {
00383     G4Exception("G4SmartVoxelHeader::BuildReplicaVoxels", "GeomMgt0002",
00384                 FatalException, "Only one replicated daughter is allowed !");
00385   }
00386 }
00387 
00388 // ***************************************************************************
00389 // Builds `consumed nodes': nReplicas nodes each containing one replication,
00390 // numbered in sequence 0->nReplicas-1
00391 // o Modifies fslices `in place'
00392 // o faxis,fminExtent,fmaxExtent NOT modified.
00393 // ***************************************************************************
00394 //
00395 void G4SmartVoxelHeader::BuildConsumedNodes(G4int nReplicas)
00396 {
00397   G4int nNode, nVol;
00398   G4SmartVoxelNode *pNode;
00399   G4SmartVoxelProxy *pProxyNode;
00400 
00401   // Create and fill nodes in temporary G4NodeVector (on stack)
00402   //
00403   G4NodeVector nodeList;
00404   nodeList.reserve(nReplicas);
00405   for (nNode=0; nNode<nReplicas; nNode++)
00406   {
00407     pNode=new G4SmartVoxelNode(nNode);
00408     if (!pNode)
00409     {
00410       G4Exception("G4SmartVoxelHeader::BuildConsumedNodes()", "GeomMgt0003",
00411                   FatalException, "Node allocation error.");
00412     }
00413     nodeList.push_back(pNode);
00414   }
00415   for (nVol=0; nVol<nReplicas; nVol++)
00416   {
00417     nodeList[nVol]->Insert(nVol);   // Insert replication of number
00418   }                                 // identical to voxel number
00419 
00420   // Create & fill proxy List `in place' by modifying instance data fslices
00421   //
00422   fslices.clear();
00423   for (nNode=0; nNode<nReplicas; nNode++)
00424   {
00425     pProxyNode = new G4SmartVoxelProxy(nodeList[nNode]);
00426     if (!pProxyNode)
00427     {
00428       G4Exception("G4SmartVoxelHeader::BuildConsumedNodes()", "GeomMgt0003",
00429                   FatalException, "Proxy node allocation error.");
00430     }
00431     fslices.push_back(pProxyNode);
00432   }
00433 }
00434 
00435 // ***************************************************************************
00436 // Builds and refines voxels between specified limits, considering only
00437 // the physical volumes numbered `pCandidates'.
00438 // o Chooses axis
00439 // o Determines min and max extents (of mother solid) within limits.
00440 // ***************************************************************************
00441 //
00442 void
00443 G4SmartVoxelHeader::BuildVoxelsWithinLimits(G4LogicalVolume* pVolume,
00444                                             G4VoxelLimits pLimits,
00445                                       const G4VolumeNosVector* pCandidates)
00446 {
00447   // Choose best axis for slicing by:
00448   // 1. Trying all unlimited cartesian axes
00449   // 2. Select axis which gives greatest no slices
00450 
00451   G4ProxyVector *pGoodSlices=0, *pTestSlices, *tmpSlices;
00452   G4double goodSliceScore=kInfinity, testSliceScore;
00453   EAxis goodSliceAxis = kXAxis;
00454   EAxis testAxis      = kXAxis;
00455   G4int node, maxNode, iaxis;
00456   G4VoxelLimits noLimits;
00457 
00458   // Try all non-limited cartesian axes
00459   //
00460   for (iaxis=0; iaxis<3; iaxis++)
00461   {
00462     switch(iaxis)
00463     {
00464       case 0:
00465         testAxis = kXAxis;
00466         break;
00467       case 1:
00468         testAxis = kYAxis;
00469         break;
00470       case 2:
00471         testAxis = kZAxis;
00472         break;
00473     }
00474     if (!pLimits.IsLimited(testAxis))
00475     {
00476       pTestSlices = BuildNodes(pVolume,pLimits,pCandidates,testAxis);
00477       testSliceScore = CalculateQuality(pTestSlices);
00478       if ( (!pGoodSlices) || (testSliceScore<goodSliceScore) )
00479       {
00480         goodSliceAxis  = testAxis;
00481         goodSliceScore = testSliceScore;
00482         tmpSlices      = pGoodSlices;
00483         pGoodSlices    = pTestSlices;
00484         pTestSlices    = tmpSlices;
00485       }
00486       if (pTestSlices)
00487       {
00488         // Destroy pTestSlices and all its contents
00489         //
00490         maxNode=pTestSlices->size();
00491         for (node=0; node<maxNode; node++)
00492         {
00493           delete (*pTestSlices)[node]->GetNode();
00494         }
00495         G4SmartVoxelProxy* tmpProx;
00496         while (pTestSlices->size()>0)
00497         {
00498           tmpProx = pTestSlices->back();
00499           pTestSlices->pop_back();
00500           for (G4ProxyVector::iterator i=pTestSlices->begin();
00501                                        i!=pTestSlices->end(); )
00502           {
00503             if (*i==tmpProx)
00504             {
00505               i = pTestSlices->erase(i);
00506             }
00507             else
00508             {
00509               ++i;
00510             }
00511           }
00512           if ( tmpProx ) { delete tmpProx; }
00513         }
00514         delete pTestSlices;
00515       }
00516     }
00517   }
00518   // Check for error case.. when limits already 3d,
00519   // so cannot select a new axis
00520   //
00521   if (!pGoodSlices)
00522   {
00523     G4Exception("G4SmartVoxelHeader::BuildVoxelsWithinLimits()",
00524                 "GeomMgt0002", FatalException,
00525                 "Cannot select more than 3 axis for optimisation.");
00526     return;
00527   }
00528 
00529   // 
00530   // We have selected pGoodSlices, with a score testSliceScore
00531   //
00532 
00533   // Store chosen axis, slice ptr
00534   //
00535   fslices=*pGoodSlices; // Set slice information, copy ptrs in collection
00536   delete pGoodSlices;   // Destroy slices vector, but not contained
00537                         // proxies or nodes
00538   faxis=goodSliceAxis;
00539 
00540 #ifdef G4GEOMETRY_VOXELDEBUG
00541   G4cout << G4endl << "     Volume = " << pVolume->GetName()
00542          << G4endl << "     Selected axis = " << faxis << G4endl;
00543   for (size_t islice=0; islice<fslices.size(); islice++)
00544   {
00545     G4cout << "     Node #" << islice << " = {";
00546     for (G4int j=0; j<fslices[islice]->GetNode()->GetNoContained(); j++)
00547     {
00548       G4cout << " " << fslices[islice]->GetNode()->GetVolume(j);
00549     }
00550     G4cout << " }" << G4endl;
00551   }
00552   G4cout << G4endl;
00553 #endif
00554 
00555   // Calculate and set min and max extents given our axis
00556   //
00557   G4VSolid* outerSolid = pVolume->GetSolid();
00558   const G4AffineTransform origin;
00559   if(!outerSolid->CalculateExtent(faxis,pLimits,origin,fminExtent,fmaxExtent))
00560   {
00561     outerSolid->CalculateExtent(faxis,noLimits,origin,fminExtent,fmaxExtent);
00562   }
00563 
00564   // Calculate equivalent nos
00565   //
00566   BuildEquivalentSliceNos();
00567   CollectEquivalentNodes();     // Collect common nodes
00568   RefineNodes(pVolume,pLimits); // Refine nodes creating headers
00569 
00570   // No common headers can exist because collapsed by construction
00571 }
00572 
00573 // ***************************************************************************
00574 // Calculates and stores the minimum and maximum equivalent neighbour
00575 // values for all slices at our level.
00576 //
00577 // Precondition: all slices are nodes.
00578 // For each potential start of a group of equivalent nodes:
00579 // o searches forwards in fslices to find group end
00580 // o loops from start to end setting start and end slices.
00581 // ***************************************************************************
00582 //
00583 void G4SmartVoxelHeader::BuildEquivalentSliceNos()
00584 {
00585   G4int sliceNo, minNo, maxNo, equivNo;
00586   G4int maxNode = fslices.size();
00587   G4SmartVoxelNode *startNode, *sampleNode;
00588   for (sliceNo=0; sliceNo<maxNode; sliceNo++)
00589   {
00590     minNo = sliceNo;
00591 
00592     // Get first node (see preconditions - will throw exception if a header)
00593     //
00594     startNode = fslices[minNo]->GetNode();
00595 
00596     // Find max equivalent
00597     //
00598     for (equivNo=minNo+1; equivNo<maxNode; equivNo++)
00599     {
00600       sampleNode = fslices[equivNo]->GetNode();
00601       if (!((*startNode) == (*sampleNode))) { break; }
00602     }
00603     maxNo = equivNo-1;
00604     if (maxNo != minNo)
00605     {
00606       // Set min and max nos
00607       //
00608       for (equivNo=minNo; equivNo<=maxNo; equivNo++)
00609       {
00610         sampleNode = fslices[equivNo]->GetNode();
00611         sampleNode->SetMinEquivalentSliceNo(minNo);
00612         sampleNode->SetMaxEquivalentSliceNo(maxNo);
00613       }
00614       // Advance outer loop to end of equivalent group
00615       //
00616       sliceNo = maxNo;
00617     }
00618   }
00619 }
00620 
00621 // ***************************************************************************
00622 // Collects common nodes at our level, deleting all but one to save
00623 // memory, and adjusting stored slice pointers appropriately.
00624 //
00625 // Preconditions:
00626 // o the slices have not previously be "collected"
00627 // o all of the slices are nodes.
00628 // ***************************************************************************
00629 //
00630 void G4SmartVoxelHeader::CollectEquivalentNodes()
00631 {
00632   G4int sliceNo, maxNo, equivNo;
00633   G4int maxNode=fslices.size();
00634   G4SmartVoxelNode *equivNode;
00635   G4SmartVoxelProxy *equivProxy;
00636 
00637   for (sliceNo=0; sliceNo<maxNode; sliceNo++)
00638   {
00639     equivProxy=fslices[sliceNo];
00640 
00641     // Assumption (see preconditions): all slices are nodes
00642     //
00643     equivNode = equivProxy->GetNode();
00644     maxNo = equivNode->GetMaxEquivalentSliceNo();
00645     if (maxNo != sliceNo)
00646     {
00647 #ifdef G4GEOMETRY_VOXELDEBUG
00648       G4cout << "**** G4SmartVoxelHeader::CollectEquivalentNodes" << G4endl
00649              << "     Collecting Nodes = " 
00650              << sliceNo << " - " << maxNo << G4endl;
00651 #endif
00652       // Do collection between sliceNo and maxNo inclusive
00653       //
00654       for (equivNo=sliceNo+1; equivNo<=maxNo; equivNo++)
00655       {
00656         delete fslices[equivNo]->GetNode();
00657         delete fslices[equivNo];
00658         fslices[equivNo] = equivProxy;
00659       }
00660       sliceNo = maxNo;
00661     }
00662   }
00663 }
00664 
00665 // ***************************************************************************
00666 // Collects common headers at our level, deleting all but one to save
00667 // memory, and adjusting stored slice pointers appropriately.
00668 // 
00669 // Preconditions:
00670 // o if a header forms part of a range of equivalent slices
00671 //   (ie. GetMaxEquivalentSliceNo()>GetMinEquivalentSliceNo()),
00672 //   it is assumed that all slices in the range are headers.
00673 // o this will be true if a constant Expression is used to evaluate
00674 //   when to refine nodes.
00675 // ***************************************************************************
00676 //
00677 void G4SmartVoxelHeader::CollectEquivalentHeaders()
00678 {
00679   G4int sliceNo, maxNo, equivNo;
00680   G4int maxNode = fslices.size();
00681   G4SmartVoxelHeader *equivHeader, *sampleHeader;
00682   G4SmartVoxelProxy *equivProxy;
00683 
00684   for (sliceNo=0; sliceNo<maxNode; sliceNo++)
00685   {
00686     equivProxy = fslices[sliceNo];
00687     if (equivProxy->IsHeader())
00688     {
00689       equivHeader = equivProxy->GetHeader();
00690       maxNo = equivHeader->GetMaxEquivalentSliceNo();
00691       if (maxNo != sliceNo)
00692       {
00693         // Attempt collection between sliceNo and maxNo inclusive:
00694         // look for common headers. All slices between sliceNo and maxNo
00695         // are guaranteed to be headers but may not have equal contents
00696         //
00697 #ifdef G4GEOMETRY_VOXELDEBUG
00698         G4cout << "**** G4SmartVoxelHeader::CollectEquivalentHeaders" << G4endl
00699                << "     Collecting Headers =";
00700 #endif
00701         for (equivNo=sliceNo+1; equivNo<=maxNo; equivNo++)
00702         {
00703           sampleHeader = fslices[equivNo]->GetHeader();
00704           if ( (*sampleHeader) == (*equivHeader) )
00705           {
00706 #ifdef G4GEOMETRY_VOXELDEBUG
00707             G4cout << " " << equivNo;
00708 #endif
00709             // Delete sampleHeader + proxy and replace with equivHeader/Proxy
00710             //
00711             delete sampleHeader;
00712             delete fslices[equivNo];
00713             fslices[equivNo] = equivProxy;
00714           }
00715           else
00716           {
00717             // Not equal. Set this header to be
00718             // the current header for comparisons
00719             //
00720             equivProxy  = fslices[equivNo];
00721             equivHeader = equivProxy->GetHeader();
00722           }
00723 
00724         }
00725 #ifdef G4GEOMETRY_VOXELDEBUG
00726         G4cout << G4endl;
00727 #endif
00728         // Skip past examined slices
00729         //
00730         sliceNo = maxNo;
00731       }
00732     }
00733   }
00734 }
00735 
00736 // ***************************************************************************
00737 // Builds the nodes corresponding to slices between the specified limits
00738 // and along the specified axis, using candidate volume no.s in the vector
00739 // pCandidates. If the `daughters' are replicated volumes (ie. the logical
00740 // volume has a single replicated/parameterised volume for a daughter)
00741 // the candidate no.s are interpreted as PARAMETERISED volume no.s & 
00742 // PARAMETERISATIONs are applied to compute transformations & solid
00743 // dimensions appropriately. The volume must be parameterised - ie. has a
00744 // parameterisation object & non-consuming) - in this case.
00745 // 
00746 // Returns pointer to built node "structure" (guaranteed non NULL) consisting
00747 // of G4SmartVoxelNodeProxies referring to G4SmartVoxelNodes.
00748 // ***************************************************************************
00749 //
00750 G4ProxyVector* G4SmartVoxelHeader::BuildNodes(G4LogicalVolume* pVolume,
00751                                               G4VoxelLimits pLimits,
00752                                         const G4VolumeNosVector* pCandidates,
00753                                               EAxis pAxis)
00754 {
00755   G4double motherMinExtent= kInfinity, motherMaxExtent= -kInfinity,
00756            targetMinExtent= kInfinity, targetMaxExtent= -kInfinity;
00757   G4VPhysicalVolume *pDaughter=0;
00758   G4VPVParameterisation *pParam=0;
00759   G4VSolid *targetSolid;
00760   G4AffineTransform targetTransform;
00761   G4bool replicated;
00762   G4int nCandidates = pCandidates->size();
00763   G4int nVol, nNode, targetVolNo;
00764   G4VoxelLimits noLimits;
00765     
00766 #ifdef G4GEOMETRY_VOXELDEBUG
00767   G4cout << "**** G4SmartVoxelHeader::BuildNodes" << G4endl
00768          << "     Limits = " << pLimits << G4endl
00769          << "       Axis = " << pAxis << G4endl
00770          << " Candidates = " << nCandidates << G4endl;
00771 #endif
00772 
00773   // Compute extent of logical volume's solid along this axis
00774   // NOTE: results stored locally and not preserved/reused
00775   //
00776   G4VSolid* outerSolid = pVolume->GetSolid();
00777   const G4AffineTransform origin;
00778   if( !outerSolid->CalculateExtent(pAxis, pLimits, origin,
00779                                    motherMinExtent, motherMaxExtent) )
00780   {
00781     outerSolid->CalculateExtent(pAxis, noLimits, origin,
00782                                 motherMinExtent, motherMaxExtent);
00783   }
00784   G4VolumeExtentVector minExtents(nCandidates,0.);
00785   G4VolumeExtentVector maxExtents(nCandidates,0.);
00786 
00787   if ( (pVolume->GetNoDaughters()==1)
00788     && (pVolume->GetDaughter(0)->IsReplicated()==true) )
00789   {
00790     // Replication data not required: only parameterisation object 
00791     // and volume no. List used
00792     //
00793     pDaughter = pVolume->GetDaughter(0);
00794     pParam = pDaughter->GetParameterisation();
00795     if (!pParam)
00796     {
00797       std::ostringstream message;
00798       message << "PANIC! - Missing parameterisation." << G4endl
00799               << "         Replicated volume with no parameterisation object !";
00800       G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0003",
00801                   FatalException, message);
00802       return 0;
00803     }
00804 
00805     // Setup daughter's transformations
00806     //
00807     targetTransform = G4AffineTransform(pDaughter->GetRotation(),
00808                                         pDaughter->GetTranslation());
00809     replicated = true;
00810   }
00811     else
00812   {
00813     replicated = false;
00814   }
00815     
00816   // Compute extents
00817   //
00818   for (nVol=0; nVol<nCandidates; nVol++)
00819   {
00820     targetVolNo=(*pCandidates)[nVol];
00821     if (replicated == false)
00822     {
00823       pDaughter=pVolume->GetDaughter(targetVolNo);
00824 
00825       // Setup daughter's transformations
00826       //
00827       targetTransform = G4AffineTransform(pDaughter->GetRotation(),
00828                                           pDaughter->GetTranslation());
00829       // Get underlying (and setup) solid
00830       //
00831       targetSolid = pDaughter->GetLogicalVolume()->GetSolid();
00832     }
00833     else
00834     {
00835       // Find  solid
00836       //
00837       targetSolid = pParam->ComputeSolid(targetVolNo,pDaughter);
00838 
00839       // Setup solid
00840       //
00841       targetSolid->ComputeDimensions(pParam,targetVolNo,pDaughter);
00842 
00843       // Setup transform
00844       //
00845       pParam->ComputeTransformation(targetVolNo,pDaughter);
00846       targetTransform = G4AffineTransform(pDaughter->GetRotation(),
00847                                           pDaughter->GetTranslation());
00848     }
00849     // Calculate extents
00850     //
00851     if(!targetSolid->CalculateExtent(pAxis, pLimits, targetTransform,
00852                                      targetMinExtent, targetMaxExtent))
00853     {
00854       targetSolid->CalculateExtent(pAxis, noLimits, targetTransform,
00855                                    targetMinExtent,targetMaxExtent);
00856     }
00857     minExtents[nVol] = targetMinExtent;
00858     maxExtents[nVol] = targetMaxExtent;
00859 
00860 #ifdef G4GEOMETRY_VOXELDEBUG
00861    G4cout << "---------------------------------------------------" << G4endl
00862           << "     Volume = " << pDaughter->GetName() << G4endl
00863           << " Min Extent = " << targetMinExtent << G4endl
00864           << " Max Extent = " << targetMaxExtent << G4endl
00865           << "---------------------------------------------------" << G4endl;
00866 #endif
00867 
00868     // Check not entirely outside mother when processing toplevel nodes
00869     //
00870     if ( (!pLimits.IsLimited()) && ((targetMaxExtent<=motherMinExtent)
00871                                   ||(targetMinExtent>=motherMaxExtent)) )
00872     {
00873       std::ostringstream message;
00874       message << "PANIC! - Overlapping daughter with mother volume." << G4endl
00875               << "         Daughter physical volume "
00876               << pDaughter->GetName() << G4endl
00877               << "         is entirely outside mother logical volume "
00878               << pVolume->GetName() << " !!";
00879       G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0002",
00880                   FatalException, message);
00881     }
00882 
00883 #ifdef G4GEOMETRY_VOXELDEBUG
00884     // Check for straddling volumes when debugging.
00885     // If a volume is >kStraddlePercent percent over the mother
00886     // boundary, print a warning.
00887     //
00888     if (!pLimits.IsLimited())
00889     {
00890       G4double width;
00891       G4int kStraddlePercent=5;
00892       width = maxExtents[nVol]-minExtents[nVol];
00893       if ( (((motherMinExtent-minExtents[nVol])*100/width) > kStraddlePercent)
00894          ||(((maxExtents[nVol]-motherMaxExtent)*100/width) > kStraddlePercent) )
00895       {
00896         G4cout << "**** G4SmartVoxelHeader::BuildNodes" << G4endl
00897                << "     WARNING : Daughter # " << nVol
00898                << " name = " << pDaughter->GetName() << G4endl
00899                << "     Crosses mother boundary of logical volume, name = " 
00900                << pVolume->GetName() << G4endl
00901                << "     by more than " << kStraddlePercent 
00902                << "%" << G4endl;
00903       }
00904     }
00905 #endif
00906   }
00907 
00908   // Extents of all daughters known
00909 
00910   // Calculate minimum slice width, only including volumes inside the limits
00911   //
00912   G4double minWidth = kInfinity;
00913   G4double currentWidth;
00914   for (nVol=0; nVol<nCandidates; nVol++)
00915   {
00916     // currentWidth should -always- be a positive value. Inaccurate computed extent
00917     // from the solid or situations of malformed geometries (overlaps) may lead to
00918     // negative values and therefore unpredictable crashes !
00919     //
00920     currentWidth = std::abs(maxExtents[nVol]-minExtents[nVol]);
00921     if ( (currentWidth<minWidth)
00922       && (maxExtents[nVol]>=pLimits.GetMinExtent(pAxis))
00923       && (minExtents[nVol]<=pLimits.GetMaxExtent(pAxis)) )
00924     {
00925       minWidth = currentWidth;
00926     }
00927   }
00928 
00929   // No. of Nodes formula - nearest integer to
00930   // mother width/half min daughter width +1
00931   //
00932   G4double noNodesExactD = ((motherMaxExtent-motherMinExtent)*2.0/minWidth)+1.0;
00933 
00934   // Compare with "smartless quality", i.e. the average number of slices
00935   // used per contained volume.
00936   //
00937   G4double smartlessComputed = noNodesExactD / nCandidates;
00938   G4double smartlessUser = pVolume->GetSmartless();
00939   G4double smartless = (smartlessComputed <= smartlessUser)
00940                        ? smartlessComputed : smartlessUser;
00941   G4double noNodesSmart = smartless*nCandidates;
00942   G4int    noNodesExactI = G4int(noNodesSmart);
00943   G4int    noNodes = ((noNodesSmart-noNodesExactI)>=0.5)
00944                      ? noNodesExactI+1 : noNodesExactI;
00945   if( noNodes == 0 ) { noNodes=1; }
00946 
00947 #ifdef G4GEOMETRY_VOXELDEBUG
00948   G4cout << "     Smartless computed = " << smartlessComputed << G4endl
00949          << "     Smartless volume = " << smartlessUser
00950          << " => # Smartless = " << smartless << G4endl;
00951   G4cout << "     Min width = " << minWidth
00952          << " => # Nodes = " << noNodes << G4endl;
00953 #endif
00954 
00955   if (noNodes>kMaxVoxelNodes)
00956   {
00957     noNodes=kMaxVoxelNodes;
00958 #ifdef G4GEOMETRY_VOXELDEBUG
00959     G4cout << "     Nodes Clipped to = " << kMaxVoxelNodes << G4endl;
00960 #endif   
00961   }
00962   G4double nodeWidth = (motherMaxExtent-motherMinExtent)/noNodes;
00963 
00964   // Create G4VoxelNodes. Will Add proxies before setting fslices
00965   //
00966   G4NodeVector* nodeList = new G4NodeVector();
00967   if (!nodeList)
00968   {
00969     G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0003",
00970                 FatalException, "NodeList allocation error.");
00971     return 0;
00972   }
00973   nodeList->reserve(noNodes);
00974 
00975   for (nNode=0; nNode<noNodes; nNode++)
00976   {
00977     G4SmartVoxelNode *pNode;
00978     pNode = new G4SmartVoxelNode(nNode);
00979     if (!pNode)
00980     {
00981       G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0003",
00982                   FatalException, "Node allocation error.");
00983       return 0;
00984     }
00985     nodeList->push_back(pNode);
00986   }
00987 
00988   // All nodes created (empty)
00989 
00990   // Fill nodes: Step through extent lists
00991   //
00992   for (nVol=0; nVol<nCandidates; nVol++)
00993   {
00994     G4int nodeNo, minContainingNode, maxContainingNode;
00995     minContainingNode = G4int((minExtents[nVol]-motherMinExtent)/nodeWidth);
00996     maxContainingNode = G4int((maxExtents[nVol]-motherMinExtent)/nodeWidth);
00997 
00998     // Only add nodes that are inside the limits of the axis
00999     //
01000     if ( (maxContainingNode>=0) && (minContainingNode<noNodes) )
01001     {
01002       // If max extent is on max boundary => maxContainingNode=noNodes:
01003       // should be one less as nodeList has noNodes entries
01004       //
01005       if (maxContainingNode>=noNodes)
01006       {
01007         maxContainingNode = noNodes-1;
01008       }
01009       //
01010       // Protection against protruding volumes
01011       //
01012       if (minContainingNode<0)
01013       {
01014         minContainingNode=0;
01015       }
01016       for (nodeNo=minContainingNode; nodeNo<=maxContainingNode; nodeNo++)
01017       {
01018         (*nodeList)[nodeNo]->Insert((*pCandidates)[nVol]);
01019       }
01020     }
01021   }
01022 
01023   // All nodes filled
01024 
01025   // Create proxy List : caller has deletion responsibility
01026   // (but we must delete nodeList *itself* - not the contents)
01027   //
01028   G4ProxyVector* proxyList = new G4ProxyVector();
01029   if (!proxyList)
01030   {
01031     G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0003",
01032                 FatalException, "Proxy list allocation error.");
01033     return 0;
01034   }
01035   proxyList->reserve(noNodes);
01036 
01037   //
01038   // Fill proxy List
01039   //
01040   for (nNode=0; nNode<noNodes; nNode++)
01041   {
01042     // Get rid of possible excess capacity in the internal node vector
01043     //
01044     ((*nodeList)[nNode])->Shrink();
01045     G4SmartVoxelProxy* pProxyNode = new G4SmartVoxelProxy((*nodeList)[nNode]);
01046     if (!pProxyNode)
01047     {
01048       G4Exception("G4SmartVoxelHeader::BuildNodes()", "GeomMgt0003",
01049                   FatalException, "Proxy node allocation failed.");
01050       return 0;
01051     }
01052     proxyList->push_back(pProxyNode);
01053   }
01054   delete nodeList;
01055   return proxyList;
01056 }
01057 
01058 // ***************************************************************************
01059 // Calculate a "quality value" for the specified vector of voxels.
01060 // The value returned should be >0 and such that the smaller the number
01061 // the higher the quality of the slice.
01062 //
01063 // Preconditions: pSlice must consist of G4SmartVoxelNodeProxies only
01064 // Process:
01065 // o Examine each node in turn, summing:
01066 //      no. of non-empty nodes
01067 //      no. of volumes in each node
01068 // o Calculate Quality=sigma(volumes in nod)/(no. of non-empty nodes)
01069 //      if all nodes empty, return kInfinity
01070 // o Call G4Exception on finding a G4SmartVoxelHeaderProxy
01071 // ***************************************************************************
01072 //
01073 G4double G4SmartVoxelHeader::CalculateQuality(G4ProxyVector *pSlice)
01074 {
01075   G4double quality;
01076   G4int nNodes = pSlice->size();
01077   G4int noContained, maxContained=0, sumContained=0, sumNonEmptyNodes=0;
01078   G4SmartVoxelNode *node;
01079 
01080   for (G4int i=0; i<nNodes; i++)
01081   {
01082     if ((*pSlice)[i]->IsNode())
01083     {
01084       // Definitely a node. Add info to running totals
01085       //
01086       node = (*pSlice)[i]->GetNode();
01087       noContained = node->GetNoContained();
01088       if (noContained)
01089       {
01090         sumNonEmptyNodes++;
01091         sumContained += noContained;
01092         //
01093         // Calc maxContained for statistics
01094         //
01095         if (noContained>maxContained)
01096         {
01097           maxContained = noContained;
01098         }
01099       }
01100     }
01101     else
01102     {
01103       G4Exception("G4SmartVoxelHeader::CalculateQuality()", "GeomMgt0001",
01104                   FatalException, "Not applicable to replicated volumes.");
01105     }
01106   }
01107 
01108   // Calculate quality with protection against no non-empty nodes
01109   //
01110   if (sumNonEmptyNodes)
01111   {
01112     quality = sumContained/sumNonEmptyNodes;
01113   }
01114   else
01115   {
01116     quality = kInfinity;
01117   }
01118 
01119 #ifdef G4GEOMETRY_VOXELDEBUG
01120   G4cout << "**** G4SmartVoxelHeader::CalculateQuality" << G4endl
01121          << "     Quality = " << quality << G4endl
01122          << "     Nodes = " << nNodes 
01123          << " of which " << sumNonEmptyNodes << " non empty" << G4endl
01124          << "     Max Contained = " << maxContained << G4endl;
01125 #endif
01126 
01127   return quality;
01128 }
01129 
01130 // ***************************************************************************
01131 // Examined each contained node, refines (creates a replacement additional
01132 // dimension of voxels) when there is more than one voxel in the slice.
01133 // Does not refine further if already limited in two dimensions (=> this
01134 // is the third level of limits)
01135 //
01136 // Preconditions: slices (nodes) have been built.
01137 // ***************************************************************************
01138 //
01139 void G4SmartVoxelHeader::RefineNodes(G4LogicalVolume* pVolume,
01140                                      G4VoxelLimits pLimits)
01141 {
01142   G4int refinedDepth=0, minVolumes;
01143   G4int maxNode = fslices.size();
01144 
01145   if (pLimits.IsXLimited()) 
01146   {
01147     refinedDepth++;
01148   }
01149   if (pLimits.IsYLimited()) 
01150   {
01151     refinedDepth++;
01152   }
01153   if (pLimits.IsZLimited()) 
01154   {
01155     refinedDepth++;
01156   }
01157 
01158   // Calculate minimum number of volumes necessary to refine
01159   //
01160   switch (refinedDepth)
01161   {
01162     case 0:
01163       minVolumes=kMinVoxelVolumesLevel2;
01164       break;
01165     case 1:
01166       minVolumes=kMinVoxelVolumesLevel3;
01167       break;
01168     default:
01169       minVolumes=10000;   // catch refinedDepth=3 and errors
01170       break;
01171   }
01172 
01173   if (refinedDepth<2)
01174   {
01175     G4int targetNo, noContainedDaughters, minNo, maxNo, replaceNo, i;
01176     G4double sliceWidth = (fmaxExtent-fminExtent)/maxNode;
01177     G4VoxelLimits newLimits;
01178     G4SmartVoxelNode* targetNode;
01179     G4SmartVoxelProxy* targetNodeProxy;
01180     G4SmartVoxelHeader* replaceHeader;
01181     G4SmartVoxelProxy* replaceHeaderProxy;
01182     G4VolumeNosVector* targetList;
01183     G4SmartVoxelProxy* lastProxy;
01184       
01185     for (targetNo=0; targetNo<maxNode; targetNo++)
01186     {
01187       // Assume all slices are nodes (see preconditions)
01188       //
01189       targetNodeProxy = fslices[targetNo];
01190       targetNode = targetNodeProxy->GetNode();
01191 
01192       if (targetNode->GetNoContained() >= minVolumes)
01193       {
01194         noContainedDaughters = targetNode->GetNoContained();
01195         targetList = new G4VolumeNosVector();
01196         if (!targetList)
01197         {
01198           G4Exception("G4SmartVoxelHeader::RefineNodes()",
01199                       "GeomMgt0003", FatalException,
01200                       "Target volume node list allocation error.");
01201           return;
01202         }
01203         targetList->reserve(noContainedDaughters);
01204         for (i=0; i<noContainedDaughters; i++)
01205         {
01206           targetList->push_back(targetNode->GetVolume(i));
01207         }
01208         minNo = targetNode->GetMinEquivalentSliceNo();
01209         maxNo = targetNode->GetMaxEquivalentSliceNo();
01210 
01211 #ifdef G4GEOMETRY_VOXELDEBUG
01212         G4cout << "**** G4SmartVoxelHeader::RefineNodes" << G4endl
01213                << "     Refining nodes " << minNo 
01214                << " - " << maxNo << " inclusive" << G4endl;
01215 #endif
01216         if (minNo > maxNo)    // Delete node and list to be replaced
01217         {                     // and avoid further action ...
01218           delete targetNode;
01219           delete targetList;
01220           return;
01221         }
01222 
01223         // Delete node proxies at start of collected sets of nodes/headers
01224         //
01225         lastProxy=0;
01226         for (replaceNo=minNo; replaceNo<=maxNo; replaceNo++)
01227         {
01228           if (lastProxy != fslices[replaceNo])
01229           {
01230             lastProxy=fslices[replaceNo];
01231             delete lastProxy;
01232           }
01233         }
01234         // Delete node to be replaced
01235         //
01236         delete targetNode;
01237 
01238         // Create new headers + proxies and replace in fslices
01239         //
01240         newLimits = pLimits;
01241         newLimits.AddLimit(faxis,fminExtent+sliceWidth*minNo,
01242                            fminExtent+sliceWidth*(maxNo+1));
01243         replaceHeader = new G4SmartVoxelHeader(pVolume,newLimits,
01244                                                targetList,replaceNo);
01245         if (!replaceHeader)
01246         {
01247           G4Exception("G4SmartVoxelHeader::RefineNodes()", "GeomMgt0003",
01248                       FatalException, "Refined VoxelHeader allocation error.");
01249           return;
01250         }
01251         replaceHeader->SetMinEquivalentSliceNo(minNo);
01252         replaceHeader->SetMaxEquivalentSliceNo(maxNo);
01253         replaceHeaderProxy = new G4SmartVoxelProxy(replaceHeader);
01254         if (!replaceHeaderProxy)
01255         {
01256           G4Exception("G4SmartVoxelHeader::RefineNodes()", "GeomMgt0003",
01257                       FatalException, "Refined VoxelProxy allocation error.");
01258           return;
01259         }
01260         for (replaceNo=minNo; replaceNo<=maxNo; replaceNo++)
01261         {
01262           fslices[replaceNo] = replaceHeaderProxy;
01263         }
01264         // Finished replacing current `equivalent' group
01265         //
01266         delete targetList;
01267         targetNo=maxNo;
01268       }
01269     }
01270   }
01271 }
01272 
01273 // ***************************************************************************
01274 // Returns true if all slices have equal contents.
01275 // Preconditions: all equal slices have been collected.
01276 // Procedure:
01277 // o checks all slice proxy pointers are equal
01278 // o returns true if only one slice or all slice proxies pointers equal.
01279 // ***************************************************************************
01280 //
01281 G4bool G4SmartVoxelHeader::AllSlicesEqual() const
01282 {
01283   G4int noSlices = fslices.size();
01284   G4SmartVoxelProxy* refProxy;
01285 
01286   if (noSlices>1)
01287   {
01288     refProxy=fslices[0];
01289     for (G4int i=1; i<noSlices; i++)
01290     {
01291       if (refProxy!=fslices[i])
01292       {
01293         return false;
01294       }
01295     }
01296   }
01297   return true;
01298 }
01299 
01300 // ***************************************************************************
01301 // Streaming operator for debugging.
01302 // ***************************************************************************
01303 //
01304 std::ostream& operator << (std::ostream& os, const G4SmartVoxelHeader& h)
01305 {
01306   os << "Axis = " << G4int(h.faxis) << G4endl;
01307   G4SmartVoxelProxy *collectNode=0, *collectHead=0;
01308   G4int collectNodeNo=0;
01309   G4int collectHeadNo=0;
01310   size_t i, j;
01311   G4bool haveHeaders=false;
01312 
01313   for (i=0; i<h.fslices.size(); i++)
01314   {
01315     os << "Slice #" << i << " = ";
01316     if (h.fslices[i]->IsNode())
01317     {
01318       if (h.fslices[i]!=collectNode)
01319       {
01320         os << "{";
01321         for (G4int k=0; k<h.fslices[i]->GetNode()->GetNoContained(); k++)
01322         {
01323           os << " " << h.fslices[i]->GetNode()->GetVolume(k);
01324         }
01325         os << " }" << G4endl;
01326         collectNode = h.fslices[i];
01327         collectNodeNo = i;
01328       }
01329       else
01330       {
01331         os << "As slice #" << collectNodeNo << G4endl;
01332       }
01333     }
01334     else
01335     {
01336       haveHeaders=true;
01337       if (h.fslices[i] != collectHead)
01338       {
01339         os << "Header" << G4endl;
01340         collectHead = h.fslices[i];
01341         collectHeadNo = i;
01342       }
01343       else
01344       {
01345         os << "As slice #" << collectHeadNo << G4endl;
01346       }
01347     }
01348   }
01349 
01350   if (haveHeaders)
01351   {
01352     collectHead=0;
01353     for (j=0; j<h.fslices.size(); j++)
01354     {
01355       if (h.fslices[j]->IsHeader())
01356       {
01357         os << "Header at Slice #" << j << " = ";
01358         if (h.fslices[j] != collectHead)
01359         {
01360           os << G4endl 
01361              << (*(h.fslices[j]->GetHeader()));
01362           collectHead = h.fslices[j];
01363           collectHeadNo = j;
01364         }
01365         else
01366         {
01367           os << "As slice #" << collectHeadNo << G4endl;
01368         }
01369       }
01370     }
01371   }
01372   return os;
01373 }

Generated on Mon May 27 17:49:51 2013 for Geant4 by  doxygen 1.4.7