Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/visualization/modeling/src/G4VFieldModel.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /visualization/modeling/src/G4VFieldModel.cc (Version 11.3.0) and /visualization/modeling/src/G4VFieldModel.cc (Version 11.0)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 // Michael Kelsey  31 January 2019                 26 // Michael Kelsey  31 January 2019
 27 //                                                 27 //
 28 // Class Description:                              28 // Class Description:
 29 //                                                 29 //
 30 // Abstract base class to implement drawing ve     30 // Abstract base class to implement drawing vector field geometries
 31 // (e.g., electric, magnetic or gravity).  Imp     31 // (e.g., electric, magnetic or gravity).  Implementation extracted
 32 // from G4MagneticFieldModel, with field-value     32 // from G4MagneticFieldModel, with field-value access left pure
 33 // virtual for implementation by base classes.     33 // virtual for implementation by base classes.
 34                                                    34 
 35 #include "G4VFieldModel.hh"                        35 #include "G4VFieldModel.hh"
 36                                                    36 
 37 #include "G4ArrowModel.hh"                         37 #include "G4ArrowModel.hh"
 38 #include "G4Colour.hh"                             38 #include "G4Colour.hh"
 39 #include "G4Field.hh"                              39 #include "G4Field.hh"
 40 #include "G4FieldManager.hh"                       40 #include "G4FieldManager.hh"
 41 #include "G4PVPlacement.hh"                        41 #include "G4PVPlacement.hh"
 42 #include "G4PVParameterised.hh"                    42 #include "G4PVParameterised.hh"
 43 #include "G4Point3D.hh"                            43 #include "G4Point3D.hh"
 44 #include "G4Polyline.hh"                           44 #include "G4Polyline.hh"
 45 #include "G4SystemOfUnits.hh"                      45 #include "G4SystemOfUnits.hh"
 46 #include "G4TransportationManager.hh"              46 #include "G4TransportationManager.hh"
 47 #include "G4VGraphicsScene.hh"                     47 #include "G4VGraphicsScene.hh"
 48 #include "G4VPhysicalVolume.hh"                    48 #include "G4VPhysicalVolume.hh"
 49 #include "G4VisAttributes.hh"                      49 #include "G4VisAttributes.hh"
 50                                                    50 
 51 #include <sstream>                                 51 #include <sstream>
 52 #include <limits>                                  52 #include <limits>
 53 #include <vector>                                  53 #include <vector>
 54                                                    54 
 55 #define G4warn G4cout                          << 
 56                                                    55 
 57 // Constructor and destructor                      56 // Constructor and destructor
 58                                                    57 
 59 G4VFieldModel::~G4VFieldModel() {;}                58 G4VFieldModel::~G4VFieldModel() {;}
 60                                                    59 
 61 G4VFieldModel::G4VFieldModel                       60 G4VFieldModel::G4VFieldModel
 62 (const G4String& typeOfField, const G4String&      61 (const G4String& typeOfField, const G4String& symbol,
 63  const G4VisExtent& extentForField,                62  const G4VisExtent& extentForField,
 64  const std::vector<G4PhysicalVolumesSearchScen     63  const std::vector<G4PhysicalVolumesSearchScene::Findings>& pvFindings,
 65  G4int nDataPointsPerMaxHalfExtent,                64  G4int nDataPointsPerMaxHalfExtent,
 66  Representation representation,                    65  Representation representation,
 67  G4int arrow3DLineSegmentsPerCircle)               66  G4int arrow3DLineSegmentsPerCircle)
 68 : fExtentForField(extentForField)                  67 : fExtentForField(extentForField)
 69 , fPVFindings(pvFindings)                          68 , fPVFindings(pvFindings)
 70 , fNDataPointsPerMaxHalfExtent(nDataPointsPerM     69 , fNDataPointsPerMaxHalfExtent(nDataPointsPerMaxHalfExtent)
 71 , fRepresentation(representation)                  70 , fRepresentation(representation)
 72 , fArrow3DLineSegmentsPerCircle(arrow3DLineSeg     71 , fArrow3DLineSegmentsPerCircle(arrow3DLineSegmentsPerCircle)
 73 , fTypeOfField(typeOfField)                        72 , fTypeOfField(typeOfField)
 74 , fArrowPrefix(symbol)                             73 , fArrowPrefix(symbol)
 75 {                                                  74 {
 76   fType = "G4"+typeOfField+"FieldModel";           75   fType = "G4"+typeOfField+"FieldModel";
 77   fGlobalTag = fType;                              76   fGlobalTag = fType;
 78                                                    77 
 79   std::ostringstream oss;                          78   std::ostringstream oss;
 80   oss << ':' << fNDataPointsPerMaxHalfExtent       79   oss << ':' << fNDataPointsPerMaxHalfExtent
 81   << ':' << fArrow3DLineSegmentsPerCircle;         80   << ':' << fArrow3DLineSegmentsPerCircle;
 82   if (fExtentForField == G4VisExtent::GetNullE     81   if (fExtentForField == G4VisExtent::GetNullExtent()) {
 83     oss << " whole scene";                         82     oss << " whole scene";
 84   } else {                                         83   } else {
 85     oss                                            84     oss
 86     << ':' << fExtentForField.GetXmin()            85     << ':' << fExtentForField.GetXmin()
 87     << ':' << fExtentForField.GetXmax()            86     << ':' << fExtentForField.GetXmax()
 88     << ':' << fExtentForField.GetYmin()            87     << ':' << fExtentForField.GetYmin()
 89     << ':' << fExtentForField.GetYmax()            88     << ':' << fExtentForField.GetYmax()
 90     << ':' << fExtentForField.GetZmin()            89     << ':' << fExtentForField.GetZmin()
 91     << ':' << fExtentForField.GetZmax();           90     << ':' << fExtentForField.GetZmax();
 92   }                                                91   }
 93   for (const auto& findings: fPVFindings) {        92   for (const auto& findings: fPVFindings) {
 94     oss                                            93     oss
 95     << ',' << findings.fpFoundPV->GetName()        94     << ',' << findings.fpFoundPV->GetName()
 96     << ':' << findings.fFoundPVCopyNo;             95     << ':' << findings.fFoundPVCopyNo;
 97   }                                                96   }
 98   if (fRepresentation == Representation::fullA     97   if (fRepresentation == Representation::fullArrow) {
 99     oss << " full arrow";                          98     oss << " full arrow";
100   } else if (fRepresentation == Representation     99   } else if (fRepresentation == Representation::lightArrow) {
101     oss << " light arrow";                        100     oss << " light arrow";
102   }                                               101   }
103                                                   102 
104   fGlobalDescription = fType + oss.str();         103   fGlobalDescription = fType + oss.str();
105 }                                                 104 }
106                                                   105 
107                                                   106 
108 // The main task of a model is to describe its    107 // The main task of a model is to describe itself to the graphics scene.
109                                                   108 
110 void G4VFieldModel::DescribeYourselfTo(G4VGrap    109 void G4VFieldModel::DescribeYourselfTo(G4VGraphicsScene& sceneHandler) {
111 //  G4cout << "G4VFieldModel::DescribeYourself    110 //  G4cout << "G4VFieldModel::DescribeYourselfTo" << G4endl;
112                                                   111 
113   G4TransportationManager* tMgr =                 112   G4TransportationManager* tMgr =
114   G4TransportationManager::GetTransportationMa    113   G4TransportationManager::GetTransportationManager();
115   assert(tMgr);                                   114   assert(tMgr);
116   G4Navigator* navigator = tMgr->GetNavigatorF    115   G4Navigator* navigator = tMgr->GetNavigatorForTracking();
117   assert(navigator);                              116   assert(navigator);
118                                                   117 
119   G4FieldManager* globalFieldMgr = tMgr->GetFi    118   G4FieldManager* globalFieldMgr = tMgr->GetFieldManager();
120   const G4Field* globalField = 0;                 119   const G4Field* globalField = 0;
121   const G4String intro = "G4VFieldModel::Descr    120   const G4String intro = "G4VFieldModel::DescribeYourselfTo: ";
122   if (globalFieldMgr) {                           121   if (globalFieldMgr) {
123     if (globalFieldMgr->DoesFieldExist()) {       122     if (globalFieldMgr->DoesFieldExist()) {
124       globalField = globalFieldMgr->GetDetecto    123       globalField = globalFieldMgr->GetDetectorField();
125       if (!globalField) {                         124       if (!globalField) {
126         static G4bool warned = false;             125         static G4bool warned = false;
127         if (!warned) {                            126         if (!warned) {
128           G4warn << intro << "Null global fiel << 127           G4cout << intro << "Null global field pointer." << G4endl;
129           warned = true;                          128           warned = true;
130         }                                         129         }
131       }                                           130       }
132     }                                             131     }
133   } else {                                        132   } else {
134     static G4bool warned = false;                 133     static G4bool warned = false;
135     if (!warned) {                                134     if (!warned) {
136       G4warn << intro << "No global field mana << 135       G4cout << intro << "No global field manager." << G4endl;
137       warned = true;                              136       warned = true;
138     }                                             137     }
139   }                                               138   }
140                                                   139 
141   G4VisExtent extent = sceneHandler.GetExtent(    140   G4VisExtent extent = sceneHandler.GetExtent();
142   if (fExtentForField == G4VisExtent::GetNullE    141   if (fExtentForField == G4VisExtent::GetNullExtent()) {
143     extent = sceneHandler.GetExtent();            142     extent = sceneHandler.GetExtent();
144   } else {                                        143   } else {
145     extent = fExtentForField;                     144     extent = fExtentForField;
146   }                                               145   }
147   const G4double& xMin = extent.GetXmin();        146   const G4double& xMin = extent.GetXmin();
148   const G4double& yMin = extent.GetYmin();        147   const G4double& yMin = extent.GetYmin();
149   const G4double& zMin = extent.GetZmin();        148   const G4double& zMin = extent.GetZmin();
150   const G4double& xMax = extent.GetXmax();        149   const G4double& xMax = extent.GetXmax();
151   const G4double& yMax = extent.GetYmax();        150   const G4double& yMax = extent.GetYmax();
152   const G4double& zMax = extent.GetZmax();        151   const G4double& zMax = extent.GetZmax();
153   const G4double xHalfScene = 0.5 * (xMax - xM    152   const G4double xHalfScene = 0.5 * (xMax - xMin);
154   const G4double yHalfScene = 0.5 * (yMax - yM    153   const G4double yHalfScene = 0.5 * (yMax - yMin);
155   const G4double zHalfScene = 0.5 * (zMax - zM    154   const G4double zHalfScene = 0.5 * (zMax - zMin);
156   const G4double xSceneCentre = 0.5 * (xMax +     155   const G4double xSceneCentre = 0.5 * (xMax + xMin);
157   const G4double ySceneCentre = 0.5 * (yMax +     156   const G4double ySceneCentre = 0.5 * (yMax + yMin);
158   const G4double zSceneCentre = 0.5 * (zMax +     157   const G4double zSceneCentre = 0.5 * (zMax + zMin);
159   const G4double maxHalfScene =                   158   const G4double maxHalfScene =
160   std::max(xHalfScene,std::max(yHalfScene,zHal    159   std::max(xHalfScene,std::max(yHalfScene,zHalfScene));
161   if (maxHalfScene <= 0.) {                       160   if (maxHalfScene <= 0.) {
162     G4warn << "Scene extent non-positive." <<  << 161     G4cout << "Scene extent non-positive." << G4endl;
163     return;                                       162     return;
164   }                                               163   }
165                                                   164 
166   // Constants                                    165   // Constants
167   const G4double interval = maxHalfScene / fND    166   const G4double interval = maxHalfScene / fNDataPointsPerMaxHalfExtent;
168   const G4int nDataPointsPerXHalfScene = G4int    167   const G4int nDataPointsPerXHalfScene = G4int(xHalfScene / interval);
169   const G4int nDataPointsPerYHalfScene = G4int    168   const G4int nDataPointsPerYHalfScene = G4int(yHalfScene / interval);
170   const G4int nDataPointsPerZHalfScene = G4int    169   const G4int nDataPointsPerZHalfScene = G4int(zHalfScene / interval);
171   const G4int nXSamples = 2 * nDataPointsPerXH    170   const G4int nXSamples = 2 * nDataPointsPerXHalfScene + 1;
172   const G4int nYSamples = 2 * nDataPointsPerYH    171   const G4int nYSamples = 2 * nDataPointsPerYHalfScene + 1;
173   const G4int nZSamples = 2 * nDataPointsPerZH    172   const G4int nZSamples = 2 * nDataPointsPerZHalfScene + 1;
174   const G4int nSamples = nXSamples * nYSamples    173   const G4int nSamples = nXSamples * nYSamples * nZSamples;
175   const G4double arrowLengthMax = 0.8 * interv    174   const G4double arrowLengthMax = 0.8 * interval;
176                                                   175 
177   // Working vectors for field values, etc.       176   // Working vectors for field values, etc.
178   std::vector<G4Point3D> Field(nSamples);         177   std::vector<G4Point3D> Field(nSamples);          // Initialises to (0,0,0)
179   std::vector<G4Point3D> xyz(nSamples);           178   std::vector<G4Point3D> xyz(nSamples);            // Initialises to (0,0,0)
180   G4double FieldMagnitudeMax = -std::numeric_l    179   G4double FieldMagnitudeMax = -std::numeric_limits<G4double>::max();
181                                                   180 
182   // Get field values and ascertain maximum fi    181   // Get field values and ascertain maximum field.
183   for (G4int i = 0; i < nXSamples; i++) {         182   for (G4int i = 0; i < nXSamples; i++) {
184     G4double x = xSceneCentre + (i - nDataPoin    183     G4double x = xSceneCentre + (i - nDataPointsPerXHalfScene) * interval;
185                                                   184 
186     for (G4int j = 0; j < nYSamples; j++) {       185     for (G4int j = 0; j < nYSamples; j++) {
187       G4double y = ySceneCentre + (j - nDataPo    186       G4double y = ySceneCentre + (j - nDataPointsPerYHalfScene) * interval;
188                                                   187 
189       for (G4int k = 0; k < nZSamples; k++) {     188       for (G4int k = 0; k < nZSamples; k++) {
190         G4double z = zSceneCentre + (k - nData    189         G4double z = zSceneCentre + (k - nDataPointsPerZHalfScene) * interval;
191                                                   190 
192         // Calculate indices into working vect    191         // Calculate indices into working vectors
193         const G4int ijk = i * nYSamples * nZSa    192         const G4int ijk = i * nYSamples * nZSamples + j * nZSamples + k;
194   xyz[ijk].set(x,y,z);                            193   xyz[ijk].set(x,y,z);
195                                                   194 
196         G4ThreeVector pos(x,y,z);                 195         G4ThreeVector pos(x,y,z);
197                                                   196 
198         // Check if point is in findings          197         // Check if point is in findings
199         if (!fPVFindings.empty()) {               198         if (!fPVFindings.empty()) {
200           G4bool isInPV = false;                  199           G4bool isInPV = false;
201           for (const auto& findings: fPVFindin    200           for (const auto& findings: fPVFindings) {
202             G4VPhysicalVolume* pv = findings.f    201             G4VPhysicalVolume* pv = findings.fpFoundPV;
203             G4int copyNo = findings.fFoundPVCo    202             G4int copyNo = findings.fFoundPVCopyNo;
204             G4VSolid* solid = pv->GetLogicalVo    203             G4VSolid* solid = pv->GetLogicalVolume()->GetSolid();
205             G4PVParameterised* pvParam = dynam    204             G4PVParameterised* pvParam = dynamic_cast<G4PVParameterised*>(pv);
206             if (pvParam) {                        205             if (pvParam) {
207               auto* param = pvParam->GetParame    206               auto* param = pvParam->GetParameterisation();
208               solid = param->ComputeSolid(copy    207               solid = param->ComputeSolid(copyNo,pvParam);
209               solid->ComputeDimensions(param,c    208               solid->ComputeDimensions(param,copyNo,pvParam);
210             }                                     209             }
211             // Transform point to local coordi    210             // Transform point to local coordinate system
212             const auto& transform = findings.f    211             const auto& transform = findings.fFoundObjectTransformation;
213             auto rotation = transform.getRotat    212             auto rotation = transform.getRotation();
214             auto translation = transform.getTr    213             auto translation = transform.getTranslation();
215             G4ThreeVector lPos = pos; lPos -=     214             G4ThreeVector lPos = pos; lPos -= translation; lPos.transform(rotation.invert());
216             if (solid->Inside(lPos)==kInside)     215             if (solid->Inside(lPos)==kInside) {
217               isInPV = true;                      216               isInPV = true;
218               break;                              217               break;
219             }                                     218             }
220           }                                       219           }
221           if (!isInPV) continue;                  220           if (!isInPV) continue;
222         }                                         221         }
223         // Point is in findings - or there wer    222         // Point is in findings - or there were no findings
224                                                   223 
225         // Find volume and field at this locat    224         // Find volume and field at this location.
226         const G4VPhysicalVolume* pPV =            225         const G4VPhysicalVolume* pPV =
227         navigator->LocateGlobalPointAndSetup(p    226         navigator->LocateGlobalPointAndSetup(pos,0,false,true);
228         const G4Field* field = globalField;       227         const G4Field* field = globalField;
229         if (pPV) {                                228         if (pPV) {
230           // Get logical volume.                  229           // Get logical volume.
231           const G4LogicalVolume* pLV = pPV->Ge    230           const G4LogicalVolume* pLV = pPV->GetLogicalVolume();
232           if (pLV) {                              231           if (pLV) {
233             // Value for Region, if any, overr    232             // Value for Region, if any, overrides
234             G4Region* pRegion = pLV->GetRegion    233             G4Region* pRegion = pLV->GetRegion();
235             if (pRegion) {                        234             if (pRegion) {
236               G4FieldManager* pRegionFieldMgr     235               G4FieldManager* pRegionFieldMgr = pRegion->GetFieldManager();
237               if (pRegionFieldMgr) {              236               if (pRegionFieldMgr) {
238                 field = pRegionFieldMgr->GetDe    237                 field = pRegionFieldMgr->GetDetectorField();
239                 // G4cout << "Region with fiel    238                 // G4cout << "Region with field" << G4endl;
240               }                                   239               }
241             }                                     240             }
242             // 'Local' value from logical volu    241             // 'Local' value from logical volume, if any, overrides
243             G4FieldManager* pLVFieldMgr = pLV-    242             G4FieldManager* pLVFieldMgr = pLV->GetFieldManager();
244             if (pLVFieldMgr) {                    243             if (pLVFieldMgr) {
245               field = pLVFieldMgr->GetDetector    244               field = pLVFieldMgr->GetDetectorField();
246               // G4cout << "Logical volume wit    245               // G4cout << "Logical volume with field" << G4endl;
247             }                                     246             }
248           }                                       247           }
249         }                                         248         }
250                                                   249 
251   G4double time = 0.; // FIXME:  Can we get ev    250   G4double time = 0.; // FIXME:  Can we get event time in some way?
252                                                   251 
253   // Subclasses will have implemented this for    252   // Subclasses will have implemented this for their own field
254   GetFieldAtLocation(field, xyz[ijk], time, Fi    253   GetFieldAtLocation(field, xyz[ijk], time, Field[ijk]);
255                                                   254 
256   G4double mag = Field[ijk].mag();                255   G4double mag = Field[ijk].mag();
257   if (mag > FieldMagnitudeMax) FieldMagnitudeM    256   if (mag > FieldMagnitudeMax) FieldMagnitudeMax = mag;
258       } // for (k, z                              257       } // for (k, z
259     } // for (j, y                                258     } // for (j, y
260   } // for (i, x                                  259   } // for (i, x
261                                                   260 
262   if (FieldMagnitudeMax <= 0.) {                  261   if (FieldMagnitudeMax <= 0.) {
263     G4warn << "No " << fTypeOfField << " field << 262     G4cout << "No " << fTypeOfField << " field in this extent." << G4endl;
264     return;                                       263     return;
265   }                                               264   }
266                                                   265 
267   for (G4int i = 0; i < nSamples; i++) {          266   for (G4int i = 0; i < nSamples; i++) {
268     const G4double Fmag = Field[i].mag();         267     const G4double Fmag = Field[i].mag();
269     const G4double f = Fmag / FieldMagnitudeMa    268     const G4double f = Fmag / FieldMagnitudeMax;
270     if (f <= 0.) continue;  // Skip zero field    269     if (f <= 0.) continue;  // Skip zero field locations
271                                                   270 
272     G4double red = 0., green = 0., blue = 0.,     271     G4double red = 0., green = 0., blue = 0., alpha = 1.;
273     if (f < 0.5) {  // Linear colour scale: 0-    272     if (f < 0.5) {  // Linear colour scale: 0->0.5->1 is red->green->blue.
274       green = 2. * f;                             273       green = 2. * f;
275       red = 2. * (0.5 - f);                       274       red = 2. * (0.5 - f);
276     } else {                                      275     } else {
277       blue = 2. * (f - 0.5);                      276       blue = 2. * (f - 0.5);
278       green = 2. * (1.0 - f);                     277       green = 2. * (1.0 - f);
279     }                                             278     }
280     const G4Colour arrowColour(red,green,blue,    279     const G4Colour arrowColour(red,green,blue,alpha);
281                                                   280 
282     // Very small arrows are difficult to see.    281     // Very small arrows are difficult to see. Better to draw a line.
283     G4bool drawAsLine = false;                    282     G4bool drawAsLine = false;
284     switch (fRepresentation) {                    283     switch (fRepresentation) {
285       case Representation::fullArrow:             284       case Representation::fullArrow:
286         if (f < 0.1) {                            285         if (f < 0.1) {
287           drawAsLine = true;                      286           drawAsLine = true;
288         }                                         287         }
289         break;                                    288         break;
290       case Representation::lightArrow:            289       case Representation::lightArrow:
291         drawAsLine = true;                        290         drawAsLine = true;
292         break;                                    291         break;
293       default:                                    292       default:
294         break;                                    293         break;
295     }                                             294     }
296                                                   295 
297     // Head of arrow depends on field directio    296     // Head of arrow depends on field direction and strength...
298     G4double arrowLength = arrowLengthMax * f;    297     G4double arrowLength = arrowLengthMax * f;
299     // ...but limit the length so it's visible    298     // ...but limit the length so it's visible.
300     if (f < 0.01) arrowLength = arrowLengthMax    299     if (f < 0.01) arrowLength = arrowLengthMax * 0.01;
301     const G4Point3D head = xyz[i] + arrowLengt    300     const G4Point3D head = xyz[i] + arrowLength*Field[i]/Fmag;
302                                                   301 
303     if (drawAsLine) {                             302     if (drawAsLine) {
304       G4Polyline FArrowLite;                      303       G4Polyline FArrowLite;
305       G4VisAttributes va(arrowColour);            304       G4VisAttributes va(arrowColour);
306       va.SetLineWidth(2.);                        305       va.SetLineWidth(2.);
307       FArrowLite.SetVisAttributes(va);            306       FArrowLite.SetVisAttributes(va);
308       FArrowLite.push_back(xyz[i]);               307       FArrowLite.push_back(xyz[i]);
309       FArrowLite.push_back(head);                 308       FArrowLite.push_back(head);
310       sceneHandler.BeginPrimitives();             309       sceneHandler.BeginPrimitives();
311       sceneHandler.AddPrimitive(FArrowLite);      310       sceneHandler.AddPrimitive(FArrowLite);
312       sceneHandler.EndPrimitives();               311       sceneHandler.EndPrimitives();
313     } else {                                      312     } else {
314       G4ArrowModel FArrow(xyz[i].x(), xyz[i].y    313       G4ArrowModel FArrow(xyz[i].x(), xyz[i].y(), xyz[i].z(),
315                           head.x(), head.y(),     314                           head.x(), head.y(), head.z(),
316                           arrowLength/5, arrow    315                           arrowLength/5, arrowColour,
317                           fArrowPrefix+"Field"    316                           fArrowPrefix+"Field",
318                           fArrow3DLineSegments    317                           fArrow3DLineSegmentsPerCircle);
319       FArrow.DescribeYourselfTo(sceneHandler);    318       FArrow.DescribeYourselfTo(sceneHandler);
320     }                                             319     }
321   } // for (i, nSamples                           320   } // for (i, nSamples
322 }                                                 321 }
323                                                   322