GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 4 / 0 / 4
Functions: 100.0% 3 / 0 / 3
Branches: -% 0 / 0 / 0

include/G4OCCT/G4OCCTAssemblyVolume.hh
Line Branch Exec Source
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright (C) 2026 G4OCCT Contributors
3
4 /// @file G4OCCTAssemblyVolume.hh
5 /// @brief Declaration of G4OCCTAssemblyVolume.
6
7 #ifndef G4OCCT_G4OCCTAssemblyVolume_hh
8 #define G4OCCT_G4OCCTAssemblyVolume_hh
9
10 #include "G4OCCT/G4OCCTLogicalVolume.hh"
11 #include "G4OCCT/G4OCCTMaterialMap.hh"
12 #include "G4OCCT/G4OCCTSensitiveDetectorMap.hh"
13
14 #include <G4AssemblyVolume.hh>
15 #include <G4String.hh>
16
17 // OCCT (forward-declared where possible; full includes in .cc)
18 #include <TDF_Label.hxx>
19 #include <gp_Trsf.hxx>
20
21 #include <map>
22 #include <string>
23
24 /**
25 * @brief Extends Geant4's G4AssemblyVolume with an OCCT XDE label reference.
26 *
27 * Imports a STEP assembly file using the OCCT Extended Data Exchange (XDE)
28 * layer and constructs the corresponding Geant4 volume hierarchy.
29 *
30 * ## OCCT XDE to Geant4 mapping
31 *
32 * | XDE entity | Geant4 result |
33 * |-------------------------------------|-------------------------------------|
34 * | Top-level assembly label | `G4OCCTAssemblyVolume` (this class) |
35 * | Simple-shape label (first use) | `G4OCCTSolid` + `G4OCCTLogicalVolume` |
36 * | Simple-shape label (repeated use) | Shared `G4OCCTLogicalVolume` |
37 * | Reference label + TopLoc_Location | `AddPlacedVolume()` on parent assembly |
38 * | XDE name attribute | Volume name string |
39 * | XDE material attribute (if present) | `G4Material*` via `G4OCCTMaterialMap` |
40 * | Part name (fallback when no mat attr) | `G4Material*` via `G4OCCTMaterialMap` |
41 *
42 * ## Instance sharing
43 *
44 * When the same XDE shape label is referenced from multiple locations the
45 * corresponding `G4OCCTLogicalVolume` is created only once and reused for
46 * each placement (incrementing the copy number each time). This mirrors
47 * Geant4's own convention.
48 *
49 * ## Thread safety
50 *
51 * This class constructs the Geant4 geometry during `FromSTEP()` and is
52 * subsequently read-only. It inherits `G4AssemblyVolume`'s thread-safety
53 * guarantees after construction.
54 *
55 * ## Usage
56 * ```cpp
57 * G4OCCTMaterialMap matMap;
58 * matMap.Add("Al 6061-T6", G4NistManager::Instance()->FindOrBuildMaterial("G4_Al"));
59 *
60 * auto* assembly = G4OCCTAssemblyVolume::FromSTEP("detector.step", matMap);
61 *
62 * // In ConstructSDandField():
63 * G4OCCTSensitiveDetectorMap sdMap;
64 * sdMap.Add("Absorber", myAbsoSD);
65 * assembly->ApplySDMap(sdMap);
66 *
67 * // Imprint into the world logical volume
68 * G4ThreeVector pos;
69 * G4RotationMatrix rot;
70 * assembly->MakeImprint(worldLV, pos, &rot);
71 * ```
72 *
73 * See docs/step_assembly_import.md for the full design and background.
74 */
75 class G4OCCTAssemblyVolume : public G4AssemblyVolume {
76 public:
77 19 G4OCCTAssemblyVolume() = default;
78 19 ~G4OCCTAssemblyVolume() = default;
79
80 /**
81 * Import a STEP assembly file and construct the Geant4 volume hierarchy.
82 *
83 * Reads the STEP file at @p path using `STEPCAFControl_Reader` (the OCCT
84 * XDE reader that preserves assembly structure, names, and material
85 * attributes). The label tree is traversed depth-first; each simple-shape
86 * leaf creates a `G4OCCTSolid` + `G4OCCTLogicalVolume`, and each placement
87 * is recorded via `AddPlacedVolume()` on the top-level assembly.
88 *
89 * Every material name encountered in the STEP file must be present in
90 * @p materialMap; an unresolved name triggers a fatal `G4Exception`.
91 * When a shape carries no XDE material attribute, its part (label) name
92 * is used as the lookup key instead, accommodating STEP writers that do
93 * not write material attributes.
94 *
95 * The leaf shapes are recentered (bounding-box centroid moved to the OCCT
96 * origin) before being wrapped in `G4OCCTSolid`; the recentering offset is
97 * absorbed into the placement transformation so that parts appear at their
98 * correct world positions.
99 *
100 * @param path Filesystem path to the STEP file.
101 * @param materialMap Map from STEP material name or part name to `G4Material*`.
102 * @return Pointer to a newly heap-allocated `G4OCCTAssemblyVolume` owned by
103 * the caller. The returned object already contains all child
104 * volumes; call `MakeImprint()` to place it in the world.
105 * @throws std::runtime_error if the file cannot be read or yields no shapes.
106 */
107 static G4OCCTAssemblyVolume* FromSTEP(const std::string& path,
108 const G4OCCTMaterialMap& materialMap);
109
110 /**
111 * Return all logical volumes created during import, keyed by part name.
112 *
113 * The map is populated during `FromSTEP()`. When two STEP parts share
114 * the same name the later name is suffixed with `_<n>` so that every entry
115 * is unique.
116 */
117 17 const std::map<G4String, G4OCCTLogicalVolume*>& GetLogicalVolumes() const {
118 17 return fLogicalVolumes;
119 }
120
121 /**
122 * Assign sensitive detectors to all logical volumes whose names match
123 * entries in @p sdMap.
124 *
125 * Iterates all logical volumes created during `FromSTEP()` and calls
126 * `sdMap.Resolve(name)` for each. When a non-null sensitive detector is
127 * returned, `G4LogicalVolume::SetSensitiveDetector()` is called on the
128 * corresponding logical volume.
129 *
130 * @param sdMap Map from volume-name patterns to sensitive detector pointers.
131 * @return Number of logical volumes for which a sensitive detector was assigned.
132 *
133 * @note Call this from `G4VUserDetectorConstruction::ConstructSDandField()`
134 * **after** both `FromSTEP()` and the SD objects have been created and
135 * registered with `G4SDManager`.
136 */
137 std::size_t ApplySDMap(const G4OCCTSensitiveDetectorMap& sdMap);
138
139 private:
140 /// All G4OCCTLogicalVolume objects created during import, keyed by unique name.
141 std::map<G4String, G4OCCTLogicalVolume*> fLogicalVolumes;
142
143 /// Build context passed through the recursive traversal.
144 struct BuildContext;
145
146 /**
147 * Recursively import an XDE label into the Geant4 hierarchy.
148 *
149 * @param label XDE label to import (assembly, simple shape, or reference).
150 * @param parentAssembly Non-null assembly to add child volumes to; may be
151 * @c this (the top-level) or an intermediate
152 * `G4AssemblyVolume`.
153 * @param composedTrsf Accumulated rigid-body transformation from the root
154 * to this label's coordinate frame.
155 * @param ctx Mutable build context (prototype map, copy counter, …).
156 */
157 static void ImportLabel(const TDF_Label& label, G4AssemblyVolume* parentAssembly,
158 const gp_Trsf& composedTrsf, BuildContext& ctx);
159 };
160
161 #endif // G4OCCT_G4OCCTAssemblyVolume_hh
162