File indexing completed on 2025-12-12 09:02:30
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Visualization/GeometryView3D.hpp"
0010
0011 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0012 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0013 #include "Acts/Geometry/Extent.hpp"
0014 #include "Acts/Geometry/GeometryIdentifier.hpp"
0015 #include "Acts/Geometry/Layer.hpp"
0016 #include "Acts/Geometry/Polyhedron.hpp"
0017 #include "Acts/Geometry/TrackingVolume.hpp"
0018 #include "Acts/Geometry/Volume.hpp"
0019 #include "Acts/Surfaces/ConeBounds.hpp"
0020 #include "Acts/Surfaces/ConeSurface.hpp"
0021 #include "Acts/Surfaces/CylinderBounds.hpp"
0022 #include "Acts/Surfaces/CylinderSurface.hpp"
0023 #include "Acts/Surfaces/DiscSurface.hpp"
0024 #include "Acts/Surfaces/RadialBounds.hpp"
0025 #include "Acts/Surfaces/Surface.hpp"
0026 #include "Acts/Surfaces/SurfaceArray.hpp"
0027 #include "Acts/Utilities/BinningType.hpp"
0028 #include "Acts/Utilities/IAxis.hpp"
0029 #include "Acts/Utilities/UnitVectors.hpp"
0030 #include "Acts/Visualization/IVisualization3D.hpp"
0031
0032 #include <algorithm>
0033 #include <cmath>
0034 #include <filesystem>
0035 #include <memory>
0036 #include <utility>
0037 #include <vector>
0038
0039 void Acts::GeometryView3D::drawPolyhedron(IVisualization3D& helper,
0040 const Polyhedron& polyhedron,
0041 const ViewConfig& viewConfig) {
0042 polyhedron.visualize(helper, viewConfig);
0043 }
0044
0045 void Acts::GeometryView3D::drawSurface(IVisualization3D& helper,
0046 const Surface& surface,
0047 const GeometryContext& gctx,
0048 const Transform3& ,
0049 const ViewConfig& viewConfig) {
0050 surface.visualize(helper, gctx, viewConfig);
0051 }
0052
0053 void Acts::GeometryView3D::drawSurfaceArray(
0054 IVisualization3D& helper, const SurfaceArray& surfaceArray,
0055 const GeometryContext& gctx, const Transform3& transform,
0056 const ViewConfig& sensitiveConfig, const ViewConfig& passiveConfig,
0057 const ViewConfig& gridConfig, const std::filesystem::path& outputDir) {
0058
0059 Extent arrayExtent;
0060 for (const auto& sf : surfaceArray.surfaces()) {
0061 ViewConfig vConfig = sf->associatedDetectorElement() != nullptr
0062 ? sensitiveConfig
0063 : passiveConfig;
0064 drawSurface(helper, *sf, gctx, transform, vConfig);
0065 auto sfExtent = sf->polyhedronRepresentation(gctx, 1).extent();
0066 arrayExtent.extend(sfExtent);
0067 }
0068
0069 if (!sensitiveConfig.outputName.empty()) {
0070 helper.write(outputDir / sensitiveConfig.outputName);
0071 helper.clear();
0072 }
0073
0074 double thickness = gridConfig.lineThickness;
0075
0076 auto binning = surfaceArray.binningValues();
0077 auto axes = surfaceArray.getAxes();
0078 if (!binning.empty() && binning.size() == 2 && axes.size() == 2) {
0079
0080 if (binning[0] == AxisDirection::AxisPhi &&
0081 binning[1] == AxisDirection::AxisZ) {
0082 double R = arrayExtent.medium(AxisDirection::AxisR) + gridConfig.offset;
0083 auto phiValues = axes[0]->getBinEdges();
0084 auto zValues = axes[1]->getBinEdges();
0085 ViewConfig gridRadConfig = gridConfig;
0086
0087 for (auto phi : phiValues) {
0088 double cphi = std::cos(phi);
0089 double sphi = std::sin(phi);
0090 Vector3 p1(R * cphi, R * sphi, axes[1]->getMin());
0091 Vector3 p0(R * cphi, R * sphi, axes[1]->getMax());
0092 drawSegment(helper, transform * p0, transform * p1, gridConfig);
0093 }
0094 CylinderVolumeBounds cvb(R - 0.5 * thickness, R + 0.5 * thickness,
0095 0.5 * thickness);
0096 auto cvbOrientedSurfaces = cvb.orientedSurfaces();
0097 for (auto z : zValues) {
0098 for (const auto& cvbSf : cvbOrientedSurfaces) {
0099 drawSurface(helper, *cvbSf.surface, gctx,
0100 Translation3(0., 0., z) * transform, gridRadConfig);
0101 }
0102 }
0103
0104 } else if (binning[0] == AxisDirection::AxisR &&
0105 binning[1] == AxisDirection::AxisPhi) {
0106 double z = arrayExtent.medium(AxisDirection::AxisZ) + gridConfig.offset;
0107 auto rValues = axes[0]->getBinEdges();
0108 auto phiValues = axes[1]->getBinEdges();
0109 ViewConfig gridRadConfig = gridConfig;
0110 gridRadConfig.quarterSegments = phiValues.size();
0111 for (auto r : rValues) {
0112 CylinderVolumeBounds cvb(r - 0.5 * thickness, r + 0.5 * thickness,
0113 0.5 * thickness);
0114 auto cvbOrientedSurfaces = cvb.orientedSurfaces();
0115 for (const auto& cvbSf : cvbOrientedSurfaces) {
0116 drawSurface(helper, *cvbSf.surface, gctx,
0117 Translation3(0., 0., z) * transform, gridRadConfig);
0118 }
0119 }
0120 double rMin = axes[0]->getMin();
0121 double rMax = axes[0]->getMax();
0122 for (auto phi : phiValues) {
0123 double cphi = std::cos(phi);
0124 double sphi = std::sin(phi);
0125 Vector3 p1(rMax * cphi, rMax * sphi, z);
0126 Vector3 p0(rMin * cphi, rMin * sphi, z);
0127 drawSegment(helper, transform * p0, transform * p1, gridConfig);
0128 }
0129 }
0130 }
0131
0132 if (!gridConfig.outputName.empty()) {
0133 helper.write(outputDir / gridConfig.outputName);
0134 helper.clear();
0135 }
0136 }
0137
0138 void Acts::GeometryView3D::drawVolume(IVisualization3D& helper,
0139 const Volume& volume,
0140 const GeometryContext& gctx,
0141 const Transform3& ,
0142 const ViewConfig& viewConfig) {
0143 volume.visualize(helper, gctx, viewConfig);
0144 }
0145
0146 void Acts::GeometryView3D::drawLayer(
0147 IVisualization3D& helper, const Layer& layer, const GeometryContext& gctx,
0148 const ViewConfig& layerConfig, const ViewConfig& sensitiveConfig,
0149 const ViewConfig& gridConfig, const std::filesystem::path& outputDir) {
0150 if (layerConfig.visible) {
0151 auto layerVolume = layer.representingVolume();
0152 if (layerVolume != nullptr) {
0153 drawVolume(helper, *layerVolume, gctx, Transform3::Identity(),
0154 layerConfig);
0155 } else {
0156 const auto& layerSurface = layer.surfaceRepresentation();
0157 drawSurface(helper, layerSurface, gctx, Transform3::Identity(),
0158 layerConfig);
0159 }
0160 if (!layerConfig.outputName.empty()) {
0161 helper.write(outputDir / layerConfig.outputName);
0162 helper.clear();
0163 }
0164 }
0165
0166 if (sensitiveConfig.visible || gridConfig.visible) {
0167 auto surfaceArray = layer.surfaceArray();
0168 if (surfaceArray != nullptr) {
0169 drawSurfaceArray(helper, *surfaceArray, gctx, Transform3::Identity(),
0170 sensitiveConfig, layerConfig, gridConfig, outputDir);
0171 }
0172 }
0173 }
0174
0175 void Acts::GeometryView3D::drawTrackingVolume(
0176 IVisualization3D& helper, const TrackingVolume& tVolume,
0177 const GeometryContext& gctx, const ViewConfig& containerView,
0178 const ViewConfig& volumeView, const ViewConfig& layerView,
0179 const ViewConfig& sensitiveView, const ViewConfig& gridView, bool writeIt,
0180 const std::string& tag, const std::filesystem::path& outputDir) {
0181 if (tVolume.confinedVolumes() != nullptr) {
0182 const auto& subVolumes = tVolume.confinedVolumes()->arrayObjects();
0183 for (const auto& tv : subVolumes) {
0184 drawTrackingVolume(helper, *tv, gctx, containerView, volumeView,
0185 layerView, sensitiveView, gridView, writeIt, tag,
0186 outputDir);
0187 }
0188 }
0189
0190 ViewConfig cConfig = containerView;
0191 ViewConfig vConfig = volumeView;
0192 ViewConfig lConfig = layerView;
0193 ViewConfig sConfig = sensitiveView;
0194 ViewConfig gConfig = gridView;
0195 gConfig.quarterSegments = 8;
0196
0197 ViewConfig vcConfig = cConfig;
0198 std::string vname = tVolume.volumeName();
0199 if (writeIt) {
0200 std::vector<std::string> repChar = {"::" };
0201 for (const auto& rchar : repChar) {
0202 while (vname.find(rchar) != std::string::npos) {
0203 vname.replace(vname.find(rchar), rchar.size(), std::string("_"));
0204 }
0205 }
0206 if (tVolume.confinedVolumes() == nullptr) {
0207 vcConfig = vConfig;
0208 vcConfig.outputName =
0209 std::filesystem::path(vname + std::string("_boundaries") + tag);
0210 } else {
0211 std::vector<GeometryIdentifier::Value> ids{tVolume.geometryId().volume()};
0212
0213 for (const auto* current = &tVolume; current->motherVolume() != nullptr;
0214 current = current->motherVolume()) {
0215 ids.push_back(current->motherVolume()->geometryId().volume());
0216 }
0217
0218 std::ranges::reverse(ids);
0219 vname = "Container";
0220 for (const auto& id : ids) {
0221 vname += "_v" + std::to_string(id);
0222 }
0223
0224 vcConfig.outputName =
0225 std::filesystem::path(vname + std::string("_boundaries") + tag);
0226 }
0227 }
0228
0229 auto bSurfaces = tVolume.boundarySurfaces();
0230 for (const auto& bs : bSurfaces) {
0231 drawSurface(helper, bs->surfaceRepresentation(), gctx,
0232 Transform3::Identity(), vcConfig);
0233 }
0234 if (writeIt) {
0235 const std::filesystem::path outputName = outputDir / vcConfig.outputName;
0236 helper.write(outputName);
0237 helper.clear();
0238 }
0239
0240 if (tVolume.confinedLayers() != nullptr) {
0241 const auto& layers = tVolume.confinedLayers()->arrayObjects();
0242 std::size_t il = 0;
0243 for (const auto& tl : layers) {
0244 if (writeIt) {
0245 lConfig.outputName = std::filesystem::path(
0246 vname + std::string("_passives_l") + std::to_string(il) + tag);
0247 sConfig.outputName = std::filesystem::path(
0248 vname + std::string("_sensitives_l") + std::to_string(il) + tag);
0249 gConfig.outputName = std::filesystem::path(
0250 vname + std::string("_grids_l") + std::to_string(il) + tag);
0251 }
0252 drawLayer(helper, *tl, gctx, lConfig, sConfig, gConfig, outputDir);
0253 ++il;
0254 }
0255 }
0256 }
0257
0258 void Acts::GeometryView3D::drawSegmentBase(IVisualization3D& helper,
0259 const Vector3& start,
0260 const Vector3& end, int arrows,
0261 double arrowLength,
0262 double arrowWidth,
0263 const ViewConfig& viewConfig) {
0264 double thickness = viewConfig.lineThickness;
0265
0266
0267 auto direction = Vector3(end - start).normalized();
0268 double hlength = 0.5 * Vector3(end - start).norm();
0269
0270 auto unitVectors = createCurvilinearUnitVectors(direction);
0271 RotationMatrix3 lrotation;
0272 lrotation.col(0) = unitVectors.first;
0273 lrotation.col(1) = unitVectors.second;
0274 lrotation.col(2) = direction;
0275
0276 Vector3 lcenter = 0.5 * (start + end);
0277 double alength = (thickness > 0.) ? arrowLength * thickness : 2.;
0278 if (alength > hlength) {
0279 alength = hlength;
0280 }
0281
0282 if (arrows == 2) {
0283 hlength -= alength;
0284 } else if (arrows != 0) {
0285 hlength -= 0.5 * alength;
0286 lcenter -= Vector3(arrows * 0.5 * alength * direction);
0287 }
0288
0289
0290 if (thickness > 0.) {
0291 auto ltransform = Transform3::Identity();
0292 ltransform.prerotate(lrotation);
0293 ltransform.pretranslate(lcenter);
0294
0295 auto lbounds = std::make_shared<CylinderBounds>(thickness, hlength);
0296 auto line = Surface::makeShared<CylinderSurface>(ltransform, lbounds);
0297
0298 drawSurface(helper, *line, GeometryContext(), Transform3::Identity(),
0299 viewConfig);
0300 } else {
0301 helper.line(start, end, viewConfig.color);
0302 }
0303
0304
0305 if (arrows != 0) {
0306 double awith = thickness * arrowWidth;
0307 double alpha = std::atan2(thickness * arrowWidth, alength);
0308 auto plateBounds = std::make_shared<RadialBounds>(thickness, awith);
0309
0310 if (arrows > 0) {
0311 auto aetransform = Transform3::Identity();
0312 aetransform.prerotate(lrotation);
0313 aetransform.pretranslate(end);
0314
0315 auto coneBounds = std::make_shared<ConeBounds>(alpha, -alength, 0.);
0316 auto cone = Surface::makeShared<ConeSurface>(aetransform, coneBounds);
0317 drawSurface(helper, *cone, GeometryContext(), Transform3::Identity(),
0318 viewConfig);
0319
0320 auto aptransform = Transform3::Identity();
0321 aptransform.prerotate(lrotation);
0322 aptransform.pretranslate(Vector3(end - alength * direction));
0323
0324 auto plate = Surface::makeShared<DiscSurface>(aptransform, plateBounds);
0325 drawSurface(helper, *plate, GeometryContext(), Transform3::Identity(),
0326 viewConfig);
0327 }
0328 if (arrows < 0 || arrows == 2) {
0329 auto astransform = Transform3::Identity();
0330 astransform.prerotate(lrotation);
0331 astransform.pretranslate(start);
0332
0333
0334 auto coneBounds = std::make_shared<ConeBounds>(alpha, 0., alength);
0335 auto cone = Surface::makeShared<ConeSurface>(astransform, coneBounds);
0336 drawSurface(helper, *cone, GeometryContext(), Transform3::Identity(),
0337 viewConfig);
0338
0339 auto aptransform = Transform3::Identity();
0340 aptransform.prerotate(lrotation);
0341 aptransform.pretranslate(Vector3(start + alength * direction));
0342
0343 auto plate = Surface::makeShared<DiscSurface>(aptransform, plateBounds);
0344 drawSurface(helper, *plate, GeometryContext(), Transform3::Identity(),
0345 viewConfig);
0346 }
0347 }
0348 }
0349
0350 void Acts::GeometryView3D::drawSegment(IVisualization3D& helper,
0351 const Vector3& start, const Vector3& end,
0352 const ViewConfig& viewConfig) {
0353 drawSegmentBase(helper, start, end, 0, 0., 0., viewConfig);
0354 }
0355
0356 void Acts::GeometryView3D::drawArrowBackward(
0357 IVisualization3D& helper, const Vector3& start, const Vector3& end,
0358 double arrowLength, double arrowWidth, const ViewConfig& viewConfig) {
0359 drawSegmentBase(helper, start, end, -1, arrowLength, arrowWidth, viewConfig);
0360 }
0361
0362 void Acts::GeometryView3D::drawArrowForward(
0363 IVisualization3D& helper, const Vector3& start, const Vector3& end,
0364 double arrowLength, double arrowWidth, const ViewConfig& viewConfig) {
0365 drawSegmentBase(helper, start, end, 1, arrowLength, arrowWidth, viewConfig);
0366 }
0367
0368 void Acts::GeometryView3D::drawArrowsBoth(IVisualization3D& helper,
0369 const Vector3& start,
0370 const Vector3& end,
0371 double arrowLength, double arrowWidth,
0372 const ViewConfig& viewConfig) {
0373 drawSegmentBase(helper, start, end, 2, arrowLength, arrowWidth, viewConfig);
0374 }