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