18#include "BDSColourScaleMagma.hh"
19#include "BDSColourScaleViridis.hh"
20#include "BDSFieldQueryForVis.hh"
21#include "BDSFieldQueryInfo.hh"
22#include "BDSVisFieldModel.hh"
24#include "G4ArrowModel.hh"
29#include "G4ThreeVector.hh"
31#include "G4VGraphicsScene.hh"
32#include "G4VMarker.hh"
33#include "G4VisAttributes.hh"
34#include "BDSWarning.hh"
50BDSVisFieldModel::BDSVisFieldModel(
const std::vector<BDSFieldQueryInfo*>& queriesIn):
55 fGlobalTag =
"BDSVisFieldModel";
56 fGlobalDescription =
"Field view #" + std::to_string(instanceCounter);
60 pointVisB =
new G4VisAttributes(bFieldColour.GetValue(0));
62 pointVisE =
new G4VisAttributes(eFieldColour.GetValue(0));
64 pointVisB->SetForceSolid(
true);
65 pointVisE->SetForceSolid(
true);
68BDSVisFieldModel::~BDSVisFieldModel()
74void BDSVisFieldModel::DescribeYourselfTo(G4VGraphicsScene& sceneHandler)
80 for (
const auto& query :
queries)
83 G4double maxFieldB = querier.MaxFieldB();
84 G4double maxFieldE = querier.MaxFieldE();
85 const std::vector<std::array<G4double, 9>> xyzBEs = querier.Values();
88 if (arrowLength > 0.01 * std::numeric_limits<G4double>::max())
89 {arrowLength = 1e-3 * sceneHandler.GetExtent().GetExtentRadius();}
91 G4double arrowWidth = 0.3*arrowLength;
92 G4double pointSize = std::max(0.1*arrowWidth, 5.0);
94 G4bool drawArrows = query->drawArrows;
95 G4bool drawBoxes = query->drawBoxes;
97 if (!drawArrows && !drawBoxes)
99 BDS::Warning(
"Neither drawArrows or drawBoxes are turned on in query \"" + query->name +
"\" -> skipping");
103 G4double boxAlpha = query->boxAlpha;
106 BDS::Warning(
"boxAlpha in query \"" + query->name +
"\" must be > 0. Setting to 0.01");
111 BDS::Warning(
"boxAlpha in query \"" + query->name +
"\" must be <= 1. Setting to 1.0");
116 G4AffineTransform qTransform = query->globalTransform;
117 G4RotationMatrix qRotation = qTransform.NetRotation().inverse();
118 G4Box aBox(
"b", boxHalfSize.x(), boxHalfSize.y(), boxHalfSize.z());
119 G4Polyhedron* baseBoxPoly = aBox.GetPolyhedron();
121 if (query->queryMagnetic)
123 G4Colour boxZeroColourB =
pointVisB->GetColor();
124 G4Colour boxZeroColourB2(boxZeroColourB.GetRed(), boxZeroColourB.GetGreen(), boxZeroColourB.GetBlue(), boxAlpha);
125 G4VisAttributes* boxZeroVisB =
new G4VisAttributes(boxZeroColourB2);
126 G4String arrowPrefix = query->name +
"_B_";
127 for (
const auto& xyzBE: xyzBEs)
130 G4ThreeVector B(xyzBE[3], xyzBE[4], xyzBE[5]);
131 G4ThreeVector unitB = B.unit();
132 G4double bMag = B.mag();
133 G4ThreeVector midPoint(xyzBE[0], xyzBE[1], xyzBE[2]);
139 G4Polyhedron boxPoly(*baseBoxPoly);
140 boxPoly.Transform(G4Transform3D(qRotation, midPoint));
144 sceneHandler.BeginPrimitives();
147 G4Circle aPoint({xyzBE[0], xyzBE[1], xyzBE[2]});
149 aPoint.SetDiameter(G4VMarker::SizeType::world, pointSize);
150 aPoint.SetFillStyle(G4VMarker::FillStyle::filled);
151 sceneHandler.AddPrimitive(aPoint);
155 boxPoly.SetVisAttributes(boxZeroVisB);
156 sceneHandler.AddPrimitive(boxPoly);
158 sceneHandler.EndPrimitives();
161 G4ThreeVector startPoint = midPoint - 0.5*arrowLength*unitB;
162 G4ThreeVector endPoint = midPoint + 0.5*arrowLength*unitB;
163 G4double normalisedValue = bMag / maxFieldB;
164 if (!std::isfinite(normalisedValue))
165 {normalisedValue = 0.0;}
166 G4Colour arrowColour = bFieldColour.GetValue(normalisedValue);
169 G4Colour boxColour(arrowColour.GetRed(), arrowColour.GetGreen(), arrowColour.GetBlue(), boxAlpha);
170 sceneHandler.BeginPrimitives();
171 boxPoly.SetVisAttributes(G4VisAttributes(boxColour));
172 sceneHandler.AddPrimitive(boxPoly);
173 sceneHandler.EndPrimitives();
177 std::stringstream ss;
178 ss << std::setw(2) << std::fixed << xyzBE[0] <<
"_" << xyzBE[1] <<
"_" << xyzBE[2];
179 std::string arrowName = ss.str();
180 G4ArrowModel FArrow(startPoint.x(), startPoint.y(), startPoint.z(),
181 endPoint.x(), endPoint.y(), endPoint.z(),
182 arrowWidth, arrowColour, arrowName);
183 FArrow.DescribeYourselfTo(sceneHandler);
189 if (query->queryElectric)
191 G4Colour boxZeroColourE =
pointVisE->GetColor();
192 G4Colour boxZeroColourE2(boxZeroColourE.GetRed(),
193 boxZeroColourE.GetGreen(),
194 boxZeroColourE.GetBlue(),
196 G4VisAttributes* boxZeroVisE =
new G4VisAttributes(boxZeroColourE2);
197 G4String arrowPrefix = query->name +
"_E_";
198 for (
const auto& xyzBE: xyzBEs)
201 G4ThreeVector E(xyzBE[6], xyzBE[7], xyzBE[8]);
202 G4ThreeVector unitE = E.unit();
203 G4double eMag = E.mag();
204 G4ThreeVector midPoint(xyzBE[0], xyzBE[1], xyzBE[2]);
206 G4Polyhedron boxPoly(*baseBoxPoly);
207 boxPoly.Transform(G4Transform3D(qRotation, midPoint));
210 sceneHandler.BeginPrimitives();
213 G4Circle aPoint({xyzBE[0], xyzBE[1], xyzBE[2]});
215 aPoint.SetDiameter(G4VMarker::SizeType::world, pointSize);
216 aPoint.SetFillStyle(G4VMarker::FillStyle::filled);
217 sceneHandler.AddPrimitive(aPoint);
221 boxPoly.SetVisAttributes(boxZeroVisE);
222 sceneHandler.AddPrimitive(boxPoly);
224 sceneHandler.EndPrimitives();
227 G4ThreeVector startPoint = midPoint - 0.5*arrowLength*unitE;
228 G4ThreeVector endPoint = midPoint + 0.5*arrowLength*unitE;
229 G4double normalisedValue = eMag / maxFieldE;
230 if (!std::isfinite(normalisedValue))
231 {normalisedValue = 0.0;}
232 G4Colour arrowColour = eFieldColour.GetValue(normalisedValue);
235 G4Colour boxColour(arrowColour.GetRed(), arrowColour.GetGreen(), arrowColour.GetBlue(), boxAlpha);
236 sceneHandler.BeginPrimitives();
237 boxPoly.SetVisAttributes(G4VisAttributes(boxColour));
238 sceneHandler.AddPrimitive(boxPoly);
239 sceneHandler.EndPrimitives();
243 std::stringstream ss;
244 ss << std::setw(2) << std::fixed << xyzBE[0] <<
"_" << xyzBE[1] <<
"_" << xyzBE[2];
245 std::string arrowName = ss.str();
246 G4ArrowModel FArrow(startPoint.x(), startPoint.y(), startPoint.z(),
247 endPoint.x(), endPoint.y(), endPoint.z(),
248 arrowWidth, arrowColour, arrowName);
249 FArrow.DescribeYourselfTo(sceneHandler);
261 G4double result = std::min({
QIL(query->xInfo),
QIL(query->yInfo),
QIL(query->zInfo)});
268 {
return std::numeric_limits<G4double>::max();}
270 G4double step = std::abs((qi.max - qi.min) / ((G4double)qi.n));
276 G4double minSize = std::numeric_limits<double>::max();
277 G4ThreeVector result(0,0,0);
278 std::array<G4bool,3> nonZero = {
false,
false,
false};
279 std::array<const BDSFieldQueryInfo::QueryDimensionInfo,3> dims = {qi->xInfo, qi->yInfo, qi->zInfo};
282 for (G4int i = 0; i < 3; i++)
284 nonZero[i] = dims[i].n > 1;
288 result[i] = dims[i].StepSize();
289 minSize = std::min(minSize, result[i]);
295 {thinSize = 0.1 * minSize;}
297 {thinSize = 1e-2 * minSize;}
298 for (G4int i = 0; i < 3; i++)
299 {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