11module G4Vis
22 using Geant4
3+ using Geant4. SystemOfUnits: g, cm3, cm
34 using Makie
45 using Colors
56
@@ -14,6 +15,7 @@ module G4Vis
1415 function convert(:: Type{Point3{Float64}} , v:: G4ThreeVector )
1516 Point3{Float64}(x(v), y(v), z(v))
1617 end
18+
1719 function convert(:: Type{RotMatrix3{Float64}} , r:: CxxPtr{G4RotationMatrix} )
1820 if r == C_NULL
1921 one(RotMatrix3{Float64})
@@ -22,12 +24,14 @@ module G4Vis
2224 end
2325 end
2426
27+ # ---Color conversion-----------------------------------------------------------------------------
28+ const LVColor = Union{ColorTypes. Color, Tuple{ColorTypes. RGB{Float64}, Float64}}
2529 function convert(:: Type{Tuple{RGB, Float64}} , c:: ConstCxxRef{G4Colour} )
2630 return (RGB(GetRed(c),GetGreen(c), GetBlue(c)),GetAlpha(c))
2731 end
28- # ---Create GeometryBasics Mesh from G4VSolid-------------------------------------------------------
29- function GeometryBasics . mesh(s :: G4VSolid ; withnormals :: Bool = false )
30- println( " Creating mesh for solid of type: " , GetEntityType(s) )
32+
33+ # ---Get vertices and facets from G4VSolid---------------------------------------------------------
34+ function mesh_constituents(s :: G4VSolid ; withnormals :: Bool = false )
3135 ph = GetPolyhedron(s)
3236 nv = GetNoVertices(ph)
3337 nf = GetNoFacets(ph)
@@ -48,34 +52,28 @@ module G4Vis
4852 end
4953 end
5054 if withnormals
51- face_normals = map(1 : nf) do i
55+ normals = map(1 : nf) do i
5256 n = GetNormal(ph, i)
5357 Vec3{Float64}(n[1 ], n[2 ], n[3 ])
5458 end
55- return GeometryBasics . Mesh (points, faces; normal = per_face(face_normals,faces) )
59+ return (points, faces, normals )
5660 else
57- return GeometryBasics . Mesh (points, faces)
61+ return (points, faces, nothing )
5862 end
5963 end
6064
61- # ---Visualization functions---------------------------------------------------------------------
62- colors = colormap(" Grays" , 8 )
63-
64- function Geant4. draw(pv:: G4VPhysicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
65- lv = GetLogicalVolume(pv)
66- fig = Figure(size= (1280 , 720 ))
67- s = LScene(fig[1 ,1 ])
68- draw!(s, lv[], one(Transformation3D{Float64}), 1 , wireframe, maxlevel)
69- return fig
70- end
71-
72- function Geant4. draw(lv:: G4LogicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
73- fig = Figure(size= (1280 , 720 ))
74- s = LScene(fig[1 ,1 ])
75- draw!(s, lv, one(Transformation3D{Float64}), 1 , wireframe, maxlevel)
76- return fig
65+ # ---Create GeometryBasics Mesh from G4VSolid-------------------------------------------------------
66+ function GeometryBasics. mesh(s:: G4VSolid ; withnormals:: Bool = false )
67+ p, f, n = mesh_constituents(s; withnormals= withnormals)
68+ if withnormals
69+ return GeometryBasics. Mesh(p, f; normal= per_face(n,f))
70+ else
71+ return GeometryBasics. Mesh(p, f)
72+ end
7773 end
7874
75+ # ---Visualization functions---------------------------------------------------------------------
76+ # ---Solid-level drawing---------------------------------------------------------------------
7977 function Geant4. draw(solid:: G4VSolid ; wireframe:: Bool = false , kwargs... )
8078 if wireframe
8179 m = GeometryBasics. mesh(solid)
@@ -86,46 +84,69 @@ module G4Vis
8684 end
8785 end
8886
87+ # ---PhysicalVolume-level drawing--------------------------------------------------------------
88+ function Geant4. draw(pv:: G4VPhysicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
89+ fig = Figure()
90+ s = LScene(fig[1 , 1 ])
91+ draw!(s, GetLogicalVolume(pv)[]; wireframe= wireframe, maxlevel= maxlevel)
92+ end
8993 function Geant4. draw!(s, pv:: G4VPhysicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
90- lv = GetLogicalVolume(pv)
91- draw!(s, lv[], one(Transformation3D{Float64}), 1 , wireframe, maxlevel)
94+ draw!(s, GetLogicalVolume(pv)[]; wireframe= wireframe, maxlevel= maxlevel)
9295 end
9396
94- using Geant4. SystemOfUnits: cm3,g
97+ # ---CxxPtr overloads---------------------------------------------------------------------------
98+ function Geant4. draw(pv:: CxxPtr{G4VPhysicalVolume} ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
99+ fig = Figure()
100+ s = LScene(fig[1 , 1 ])
101+ draw!(s, GetLogicalVolume(pv[])[]; wireframe= wireframe, maxlevel= maxlevel)
102+ end
103+ function Geant4. draw!(s, pv:: CxxPtr{G4VPhysicalVolume} ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
104+ draw!(s, GetLogicalVolume(pv[])[]; wireframe= wireframe, maxlevel= maxlevel)
105+ end
95106
96- function GetReplicaParameters(pv:: CxxPtr{G4VPhysicalVolume} )
97- axis = Ref{EAxis}(kYAxis)
98- nReplicas = Ref{Int32}(0 )
99- width = Ref{Float64}(0. )
100- offset = Ref{Float64}(0. )
101- consuming = Ref{UInt8}(0 )
102- GetReplicationData(pv, axis, nReplicas, width, offset, consuming)
103- return (axis[], nReplicas[], width[])
107+ # ---LogicalVolume-level drawing----------------------------------------------------------------
108+ function Geant4. draw(lv:: G4LogicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
109+ fig = Figure()
110+ s = LScene(fig[1 , 1 ])
111+ Geant4. draw!(s, lv; wireframe= wireframe, maxlevel= maxlevel)
112+ return fig
104113 end
105114
115+ function Geant4. draw!(s, lv:: G4LogicalVolume ; wireframe:: Bool = false , maxlevel:: Int64 = 999 )
116+ # ---Collect the meshes recursively and Vis attributes recursively--------------------------
117+ # This assumes that all Placements of a given LogicalVolume are drawn with the same visibility and color
118+ lv_meshes = Dict{G4LogicalVolume, Tuple{Vector{GeometryBasics. Mesh}, LVColor, Bool}}()
119+ collect_meshes(lv, lv_meshes, one(Transformation3D{Float64}), 1 , maxlevel)
120+ # ---Draw all collected meshes----------------------------------------------------------------
121+ for (clv, (meshes, color, visible)) in lv_meshes
122+ m = merge(meshes)
123+ if wireframe
124+ Makie. wireframe!(s, m; linewidth= 1 , visible= visible)
125+ else
126+ Makie. mesh!(s, m; color= color, transparency= true , visible= visible)
127+ end
128+ end
129+ end
130+
131+ # ---Helper functions for recursive drawing------------------------------------------------------
132+ const colors = colormap(" Grays" , 8 )
106133 const UnitOnAxis = [( 1 ,0 ,0 ), (0 ,1 ,0 ), (0 ,0 ,1 )]
107134
108- function Geant4. draw!(s, lv:: G4LogicalVolume , t:: Transformation3D{Float64} , level:: Int64 , wireframe:: Bool , maxlevel:: Int64 )
109- vsolid = GetSolid(lv)
110- tsolid = GetEntityType(vsolid)
111- shape = getproperty(Geant4,Symbol(tsolid))
112- solid = CxxRef{shape}(vsolid)
113- m = GeometryBasics. mesh(solid[])
135+ function collect_meshes(lv:: G4LogicalVolume , lv_meshes:: Dict{G4LogicalVolume, Tuple{Vector{GeometryBasics.Mesh}, LVColor, Bool}} , t:: Transformation3D{Float64} , level:: Int64 , maxlevel:: Int64 )
136+ solid = GetSolid(lv)
114137 g4vis = GetVisAttributes(lv)
115- if ! isempty(m)
116- if ! isone(t)
117- points = GeometryBasics. coordinates(m)
118- faces = GeometryBasics. faces(m)
119- map!(c -> c * t, points, points)
120- m = GeometryBasics. mesh(points, faces, normal= GeometryBasics. normals(points, faces, Vec3f))
121- end
138+ points, faces, normals = mesh_constituents(solid[], withnormals= true )
139+ if ! isone(t)
140+ map!(c -> c * t, points, points)
141+ map!(n -> t. rotation * n, normals, normals)
142+ end
143+ m = GeometryBasics. Mesh(points, faces, normal= per_face(normals, faces))
144+ if haskey(lv_meshes, lv)
145+ push!(lv_meshes[lv][1 ], m)
146+ else
122147 color = g4vis != C_NULL ? convert(Tuple{RGB, Float64}, GetColour(g4vis)) : (colors[level], GetDensity(GetMaterial(lv))/ (12 g/ cm3))
123148 visible = g4vis != C_NULL ? IsVisible(g4vis) : true
124- if wireframe
125- wireframe!(s, m, linewidth= 1 , visible= visible)
126- else
127- mesh!(s, m, color= color, transparency= true , visible= visible )
128- end
149+ lv_meshes[lv] = ([m], color, visible)
129150 end
130151 # Go down to the daughters (eventually)
131152 level >= maxlevel && return
@@ -139,18 +160,28 @@ module G4Vis
139160 for i in 1 : nReplicas
140161 g4t = unitV * (- width* (nReplicas- 1 )* 0.5 + (i- 1 )* width)
141162 transformation = Transformation3D{Float64}(one(RotMatrix3{Float64}), convert(Vector3{Float64}, g4t))
142- draw!(s, volume[], transformation * t, level+ 1 , wireframe , maxlevel)
163+ collect_meshes( volume[], lv_meshes, transformation * t, level+ 1 , maxlevel)
143164 end
144165 else
145166 g4t = GetTranslation(daughter)
146167 g4r = GetRotation(daughter)
147168 transformation = Transformation3D{Float64}(convert(RotMatrix3{Float64}, g4r), convert(Vector3{Float64}, g4t))
148169 volume = GetLogicalVolume(daughter)
149- draw!(s, volume[], transformation * t, level+ 1 , wireframe , maxlevel)
170+ collect_meshes( volume[], lv_meshes, transformation * t, level+ 1 , maxlevel)
150171 end
151172 end
152173 end
153174
175+ function GetReplicaParameters(pv:: CxxPtr{G4VPhysicalVolume} )
176+ axis = Ref{EAxis}(kYAxis)
177+ nReplicas = Ref{Int32}(0 )
178+ width = Ref{Float64}(0. )
179+ offset = Ref{Float64}(0. )
180+ consuming = Ref{UInt8}(0 )
181+ GetReplicationData(pv, axis, nReplicas, width, offset, consuming)
182+ return (axis[], nReplicas[], width[])
183+ end
184+
154185# ---Testing functions------------------------------------------------------------
155186 @inline Base.:* (a:: G4ThreeVector , b:: Vector3{Float64} ) = G4ThreeVector(x(a)* b[1 ], y(a)* b[2 ], z(a)* b[3 ])
156187 function Geant4. drawDistanceToOut(solid:: G4VSolid , N:: Int )
0 commit comments