19#include "BDSColourScaleMagma.hh"
20#include "BDSColourScaleViridis.hh"
21#include "BDSFieldQueryForVis.hh"
22#include "BDSFieldQueryInfo.hh"
23#include "BDSVisFieldModel.hh"
25#include "G4ArrowModel.hh"
30#include "G4ThreeVector.hh"
32#include "G4VGraphicsScene.hh"
33#include "G4VMarker.hh"
34#include "G4VisAttributes.hh"
35#include "BDSWarning.hh"
48BDSVisFieldModel::BDSVisFieldModel(
const std::vector<BDSFieldQueryInfo*>& queriesIn):
53 fGlobalTag =
"BDSVisFieldModel";
54 fGlobalDescription =
"Field view #" + std::to_string(instanceCounter);
58 pointVisB =
new G4VisAttributes(bFieldColour.GetValue(0));
60 pointVisE =
new G4VisAttributes(eFieldColour.GetValue(0));
62 pointVisB->SetForceSolid(
true);
63 pointVisE->SetForceSolid(
true);
66BDSVisFieldModel::~BDSVisFieldModel()
72void BDSVisFieldModel::DescribeYourselfTo(G4VGraphicsScene& sceneHandler)
78 for (
const auto& query :
queries)
81 G4double maxFieldB = querier.MaxFieldB();
82 G4double maxFieldE = querier.MaxFieldE();
83 const std::vector<std::array<G4double, 9>> xyzBEs = querier.Values();
86 if (arrowLength > 0.01 * std::numeric_limits<G4double>::max())
87 {arrowLength = 1e-3 * sceneHandler.GetExtent().GetExtentRadius();}
89 G4double arrowWidth = 0.3*arrowLength;
90 G4double pointSize = std::max(0.1*arrowWidth, 5.0);
92 G4bool drawArrows = query->drawArrows;
93 G4bool drawBoxes = query->drawBoxes;
95 if (!drawArrows && !drawBoxes)
97 BDS::Warning(
"Neither drawArrows or drawBoxes are turned on in query \"" + query->name +
"\" -> skipping");
101 G4double boxAlpha = query->boxAlpha;
104 BDS::Warning(
"boxAlpha in query \"" + query->name +
"\" must be > 0. Setting to 0.01");
109 BDS::Warning(
"boxAlpha in query \"" + query->name +
"\" must be <= 1. Setting to 1.0");
114 G4AffineTransform qTransform = query->globalTransform;
115 G4RotationMatrix qRotation = qTransform.NetRotation().inverse();
116 G4Box aBox(
"b", boxHalfSize.x(), boxHalfSize.y(), boxHalfSize.z());
117 G4Polyhedron* baseBoxPoly = aBox.GetPolyhedron();
119 if (query->queryMagnetic)
121 G4Colour boxZeroColourB =
pointVisB->GetColor();
122 G4Colour boxZeroColourB2(boxZeroColourB.GetRed(), boxZeroColourB.GetGreen(), boxZeroColourB.GetBlue(), boxAlpha);
123 G4VisAttributes* boxZeroVisB =
new G4VisAttributes(boxZeroColourB2);
124 G4String arrowPrefix = query->name +
"_B_";
125 for (
const auto& xyzBE: xyzBEs)
128 G4ThreeVector B(xyzBE[3], xyzBE[4], xyzBE[5]);
129 G4ThreeVector unitB = B.unit();
130 G4double bMag = B.mag();
131 G4ThreeVector midPoint(xyzBE[0], xyzBE[1], xyzBE[2]);
137 G4Polyhedron boxPoly(*baseBoxPoly);
138 boxPoly.Transform(G4Transform3D(qRotation, midPoint));
142 sceneHandler.BeginPrimitives();
145 G4Circle aPoint({xyzBE[0], xyzBE[1], xyzBE[2]});
147 aPoint.SetDiameter(G4VMarker::SizeType::world, pointSize);
148 aPoint.SetFillStyle(G4VMarker::FillStyle::filled);
149 sceneHandler.AddPrimitive(aPoint);
153 boxPoly.SetVisAttributes(boxZeroVisB);
154 sceneHandler.AddPrimitive(boxPoly);
156 sceneHandler.EndPrimitives();
159 G4ThreeVector startPoint = midPoint - 0.5*arrowLength*unitB;
160 G4ThreeVector endPoint = midPoint + 0.5*arrowLength*unitB;
161 G4double normalisedValue = bMag / maxFieldB;
162 if (!std::isfinite(normalisedValue))
163 {normalisedValue = 0.0;}
164 G4Colour arrowColour = bFieldColour.GetValue(normalisedValue);
167 G4Colour boxColour(arrowColour.GetRed(), arrowColour.GetGreen(), arrowColour.GetBlue(), boxAlpha);
168 sceneHandler.BeginPrimitives();
169 boxPoly.SetVisAttributes(G4VisAttributes(boxColour));
170 sceneHandler.AddPrimitive(boxPoly);
171 sceneHandler.EndPrimitives();
176 sprintf(buf,
"(%.2g, %.2g, %.2g)", xyzBE[0], xyzBE[1], xyzBE[2]);
177 std::string arrowName = buf;
178 G4ArrowModel FArrow(startPoint.x(), startPoint.y(), startPoint.z(),
179 endPoint.x(), endPoint.y(), endPoint.z(),
180 arrowWidth, arrowColour, arrowName);
181 FArrow.DescribeYourselfTo(sceneHandler);
187 if (query->queryElectric)
189 G4Colour boxZeroColourE =
pointVisE->GetColor();
190 G4Colour boxZeroColourE2(boxZeroColourE.GetRed(),
191 boxZeroColourE.GetGreen(),
192 boxZeroColourE.GetBlue(),
194 G4VisAttributes* boxZeroVisE =
new G4VisAttributes(boxZeroColourE2);
195 G4String arrowPrefix = query->name +
"_E_";
196 for (
const auto& xyzBE: xyzBEs)
199 G4ThreeVector E(xyzBE[3], xyzBE[4], xyzBE[5]);
200 G4ThreeVector unitE = E.unit();
201 G4double eMag = E.mag();
202 G4ThreeVector midPoint(xyzBE[0], xyzBE[1], xyzBE[2]);
204 G4Polyhedron boxPoly(*baseBoxPoly);
205 boxPoly.Transform(G4Transform3D(qRotation, midPoint));
208 sceneHandler.BeginPrimitives();
211 G4Circle aPoint({xyzBE[0], xyzBE[1], xyzBE[2]});
213 aPoint.SetDiameter(G4VMarker::SizeType::world, pointSize);
214 aPoint.SetFillStyle(G4VMarker::FillStyle::filled);
215 sceneHandler.AddPrimitive(aPoint);
219 boxPoly.SetVisAttributes(boxZeroVisE);
220 sceneHandler.AddPrimitive(boxPoly);
222 sceneHandler.EndPrimitives();
225 G4ThreeVector startPoint = midPoint - 0.5*arrowLength*unitE;
226 G4ThreeVector endPoint = midPoint + 0.5*arrowLength*unitE;
227 G4double normalisedValue = eMag / maxFieldE;
228 if (!std::isfinite(normalisedValue))
229 {normalisedValue = 0.0;}
230 G4Colour arrowColour = eFieldColour.GetValue(normalisedValue);
233 G4Colour boxColour(arrowColour.GetRed(), arrowColour.GetGreen(), arrowColour.GetBlue(), boxAlpha);
234 sceneHandler.BeginPrimitives();
235 boxPoly.SetVisAttributes(G4VisAttributes(boxColour));
236 sceneHandler.AddPrimitive(boxPoly);
237 sceneHandler.EndPrimitives();
242 sprintf(buf,
"(%.2g, %.2g, %.2g)", xyzBE[0], xyzBE[1], xyzBE[2]);
243 std::string arrowName = buf;
245 G4ArrowModel FArrow(startPoint.x(), startPoint.y(), startPoint.z(),
246 endPoint.x(), endPoint.y(), endPoint.z(),
247 arrowWidth, arrowColour, arrowName);
248 FArrow.DescribeYourselfTo(sceneHandler);
260 G4double result = std::min({
QIL(query->xInfo),
QIL(query->yInfo),
QIL(query->zInfo)});
267 {
return std::numeric_limits<G4double>::max();}
269 G4double step = std::abs((qi.max - qi.min) / ((G4double)qi.n));
275 G4double minSize = std::numeric_limits<double>::max();
276 G4ThreeVector result(0,0,0);
277 std::array<G4bool,3> nonZero = {
false,
false,
false};
278 std::array<const BDSFieldQueryInfo::QueryDimensionInfo,3> dims = {qi->xInfo, qi->yInfo, qi->zInfo};
281 for (G4int i = 0; i < 3; i++)
283 nonZero[i] = dims[i].n > 1;
287 result[i] = dims[i].StepSize();
288 minSize = std::min(minSize, result[i]);
294 {thinSize = 0.1 * minSize;}
296 {thinSize = 1e-2 * minSize;}
297 for (G4int i = 0; i < 3; i++)
298 {result[i] = nonZero[i] ? result[i]*0.5 : thinSize;}
Colour scale based on magma colour map.
Colour scale based on viridis colour map.
Wrapper class of BDSFieldQuery that accumulates values for visualisation.
virtual void QueryField(const BDSFieldQueryInfo *query)
Reserve the vector size we need first, then proceed as normal. Avoids big copies.
virtual void CleanUp()
Call the base class method and also clear the vector of values in this class.
Holder class for all information required for a field query.
G4double CalculateArrowLength(const BDSFieldQueryInfo *query) const
Return the minimum of 0.8 x the step length in x,y,z.
const std::vector< BDSFieldQueryInfo * > queries
Cache of queries.
G4ThreeVector BoxHalfSize(const BDSFieldQueryInfo *qi) const
G4double QIL(const BDSFieldQueryInfo::QueryDimensionInfo &qi) const
Query Info Length. For one dimension, return 0.8 x step size.
G4VisAttributes * pointVisB
The vis attributes for a zero-field marker.
G4VisAttributes * pointVisE
The vis attributes for a zero-field marker.
static G4int instanceCounter