File indexing completed on 2025-09-17 08:02:20
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Geometry/TrackingVolume.hpp"
0010
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Geometry/GeometryIdentifier.hpp"
0013 #include "Acts/Geometry/GlueVolumesDescriptor.hpp"
0014 #include "Acts/Geometry/Portal.hpp"
0015 #include "Acts/Geometry/TrackingGeometryVisitor.hpp"
0016 #include "Acts/Geometry/VolumeBounds.hpp"
0017 #include "Acts/Material/IMaterialDecorator.hpp"
0018 #include "Acts/Material/IVolumeMaterial.hpp"
0019 #include "Acts/Navigation/INavigationPolicy.hpp"
0020 #include "Acts/Navigation/NavigationStream.hpp"
0021 #include "Acts/Propagator/Navigator.hpp"
0022 #include "Acts/Surfaces/RegularSurface.hpp"
0023 #include "Acts/Surfaces/Surface.hpp"
0024 #include "Acts/Surfaces/SurfaceArray.hpp"
0025 #include "Acts/Utilities/Intersection.hpp"
0026
0027 #include <algorithm>
0028 #include <memory>
0029 #include <ostream>
0030 #include <string>
0031 #include <utility>
0032
0033 #include <boost/container/small_vector.hpp>
0034
0035 namespace Acts {
0036
0037 TrackingVolume::TrackingVolume(
0038 const Transform3& transform, std::shared_ptr<VolumeBounds> volumeBounds,
0039 std::shared_ptr<const IVolumeMaterial> volumeMaterial,
0040 std::unique_ptr<const LayerArray> staticLayerArray,
0041 std::shared_ptr<const TrackingVolumeArray> containedVolumeArray,
0042 MutableTrackingVolumeVector denseVolumeVector,
0043 const std::string& volumeName)
0044 : Volume(transform, std::move(volumeBounds)),
0045 m_confinedLayers(std::move(staticLayerArray)),
0046 m_confinedVolumes(std::move(containedVolumeArray)),
0047 m_confinedDenseVolumes({}),
0048 m_volumeMaterial(std::move(volumeMaterial)),
0049 m_name(volumeName) {
0050 createBoundarySurfaces();
0051 interlinkLayers();
0052 connectDenseBoundarySurfaces(denseVolumeVector);
0053
0054 m_navigationDelegate.connect<&INavigationPolicy::noopInitializeCandidates>();
0055 }
0056
0057 TrackingVolume::TrackingVolume(Volume& volume, const std::string& volumeName)
0058 : TrackingVolume(volume.transform(), volume.volumeBoundsPtr(), nullptr,
0059 nullptr, nullptr, MutableTrackingVolumeVector{},
0060 volumeName) {}
0061
0062 TrackingVolume::TrackingVolume(const Transform3& transform,
0063 std::shared_ptr<VolumeBounds> volbounds,
0064 const std::string& volumeName)
0065 : TrackingVolume(transform, std::move(volbounds), nullptr, nullptr, nullptr,
0066 {}, volumeName) {}
0067
0068 TrackingVolume::~TrackingVolume() = default;
0069 TrackingVolume::TrackingVolume(TrackingVolume&&) noexcept = default;
0070 TrackingVolume& TrackingVolume::operator=(TrackingVolume&&) noexcept = default;
0071
0072 const TrackingVolume* TrackingVolume::lowestTrackingVolume(
0073 const GeometryContext& gctx, const Vector3& position,
0074 const double tol) const {
0075 if (!inside(position, tol)) {
0076 return nullptr;
0077 }
0078
0079
0080 if (m_confinedVolumes) {
0081 const TrackingVolume* volume = m_confinedVolumes->object(position).get();
0082 if (volume != nullptr) {
0083 return volume->lowestTrackingVolume(gctx, position, tol);
0084 }
0085 }
0086
0087
0088 if (!m_confinedDenseVolumes.empty()) {
0089 for (auto& denseVolume : m_confinedDenseVolumes) {
0090 if (denseVolume->inside(position, tol)) {
0091 return denseVolume.get();
0092 }
0093 }
0094 }
0095
0096
0097 for (const auto& volume : volumes()) {
0098 if (volume.inside(position, tol)) {
0099 return volume.lowestTrackingVolume(gctx, position, tol);
0100 }
0101 }
0102
0103
0104 return this;
0105 }
0106
0107 const TrackingVolumeBoundaries& TrackingVolume::boundarySurfaces() const {
0108 return m_boundarySurfaces;
0109 }
0110
0111 void TrackingVolume::connectDenseBoundarySurfaces(
0112 MutableTrackingVolumeVector& confinedDenseVolumes) {
0113 if (!confinedDenseVolumes.empty()) {
0114 Direction dir = Direction::Positive();
0115
0116 for (auto& confDenseVol : confinedDenseVolumes) {
0117
0118 auto& boundSur = confDenseVol->boundarySurfaces();
0119 for (std::size_t i = 0; i < boundSur.size(); i++) {
0120
0121
0122 if (boundSur.at(i) == nullptr) {
0123 continue;
0124 }
0125
0126
0127
0128 auto mutableBs =
0129 std::const_pointer_cast<BoundarySurfaceT<TrackingVolume>>(
0130 boundSur.at(i));
0131 if (mutableBs->m_oppositeVolume != nullptr &&
0132 mutableBs->m_alongVolume == nullptr) {
0133 dir = Direction::Positive();
0134 mutableBs->attachVolume(this, dir);
0135 } else {
0136 if (mutableBs->m_oppositeVolume == nullptr &&
0137 mutableBs->m_alongVolume != nullptr) {
0138 dir = Direction::Negative();
0139 mutableBs->attachVolume(this, dir);
0140 }
0141 }
0142
0143
0144 confDenseVol->updateBoundarySurface(static_cast<BoundarySurfaceFace>(i),
0145 mutableBs);
0146 }
0147
0148 m_confinedDenseVolumes.push_back(std::move(confDenseVol));
0149 }
0150 }
0151 }
0152
0153 void TrackingVolume::createBoundarySurfaces() {
0154 using Boundary = BoundarySurfaceT<TrackingVolume>;
0155
0156
0157 auto orientedSurfaces = Volume::volumeBounds().orientedSurfaces(m_transform);
0158
0159 m_boundarySurfaces.reserve(orientedSurfaces.size());
0160 for (auto& osf : orientedSurfaces) {
0161 TrackingVolume* opposite = nullptr;
0162 TrackingVolume* along = nullptr;
0163 if (osf.direction == Direction::OppositeNormal()) {
0164 opposite = this;
0165 } else {
0166 along = this;
0167 }
0168 m_boundarySurfaces.push_back(std::make_shared<const Boundary>(
0169 std::move(osf.surface), opposite, along));
0170 }
0171 }
0172
0173 void TrackingVolume::clearBoundarySurfaces() {
0174 m_boundarySurfaces.clear();
0175 }
0176
0177 void TrackingVolume::glueTrackingVolume(const GeometryContext& gctx,
0178 BoundarySurfaceFace bsfMine,
0179 TrackingVolume* neighbor,
0180 BoundarySurfaceFace bsfNeighbor) {
0181
0182
0183 Vector3 bPosition(referencePosition(gctx, AxisDirection::AxisR));
0184 Vector3 distance = Vector3(
0185 neighbor->referencePosition(gctx, AxisDirection::AxisR) - bPosition);
0186
0187 std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> bSurfaceMine =
0188 boundarySurfaces().at(bsfMine);
0189
0190
0191
0192
0193 Vector3 nvector =
0194 bSurfaceMine->surfaceRepresentation().normal(gctx, bPosition);
0195
0196 Direction dir = Direction::fromScalar(nvector.dot(distance));
0197
0198
0199 if ((m_glueVolumeDescriptor == nullptr) ||
0200 m_glueVolumeDescriptor->glueVolumes(bsfMine) == nullptr) {
0201
0202 auto mutableBSurfaceMine =
0203 std::const_pointer_cast<BoundarySurfaceT<TrackingVolume>>(bSurfaceMine);
0204 mutableBSurfaceMine->attachVolume(neighbor, dir);
0205
0206 const Surface& neighborSurface =
0207 neighbor->m_boundarySurfaces.at(bsfNeighbor)->surfaceRepresentation();
0208 auto neighborMaterial = neighborSurface.surfaceMaterialSharedPtr();
0209 const Surface& mySurface = bSurfaceMine->surfaceRepresentation();
0210 auto myMaterial = mySurface.surfaceMaterialSharedPtr();
0211
0212 if (myMaterial == nullptr && neighborMaterial != nullptr) {
0213 Surface* myMutbableSurface = const_cast<Surface*>(&mySurface);
0214 myMutbableSurface->assignSurfaceMaterial(neighborMaterial);
0215 }
0216
0217 (neighbor->m_boundarySurfaces).at(bsfNeighbor) = bSurfaceMine;
0218 }
0219 }
0220
0221 void TrackingVolume::glueTrackingVolumes(
0222 const GeometryContext& gctx, BoundarySurfaceFace bsfMine,
0223 const std::shared_ptr<TrackingVolumeArray>& neighbors,
0224 BoundarySurfaceFace bsfNeighbor) {
0225
0226
0227 std::shared_ptr<const TrackingVolume> nRefVolume =
0228 neighbors->arrayObjects().at(0);
0229
0230 Vector3 bPosition(referencePosition(gctx, AxisDirection::AxisR));
0231 Vector3 distance(nRefVolume->referencePosition(gctx, AxisDirection::AxisR) -
0232 bPosition);
0233
0234 std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> bSurfaceMine =
0235 boundarySurfaces().at(bsfMine);
0236
0237
0238
0239
0240 Vector3 nvector =
0241 bSurfaceMine->surfaceRepresentation().normal(gctx, bPosition);
0242
0243 Direction dir = Direction::fromScalar(nvector.dot(distance));
0244
0245
0246 if ((m_glueVolumeDescriptor == nullptr) ||
0247 !m_glueVolumeDescriptor->glueVolumes(bsfMine)) {
0248
0249 auto mutableBSurfaceMine =
0250 std::const_pointer_cast<BoundarySurfaceT<TrackingVolume>>(bSurfaceMine);
0251 mutableBSurfaceMine->attachVolumeArray(neighbors, dir);
0252
0253 for (auto& nVolume : neighbors->arrayObjects()) {
0254 auto mutableNVolume = std::const_pointer_cast<TrackingVolume>(nVolume);
0255 (mutableNVolume->m_boundarySurfaces).at(bsfNeighbor) = bSurfaceMine;
0256 }
0257 }
0258 }
0259
0260 void TrackingVolume::assignBoundaryMaterial(
0261 std::shared_ptr<const ISurfaceMaterial> surfaceMaterial,
0262 BoundarySurfaceFace bsFace) {
0263 auto bSurface = m_boundarySurfaces.at(bsFace);
0264 RegularSurface* surface =
0265 const_cast<RegularSurface*>(&bSurface->surfaceRepresentation());
0266 surface->assignSurfaceMaterial(std::move(surfaceMaterial));
0267 }
0268
0269 void TrackingVolume::updateBoundarySurface(
0270 BoundarySurfaceFace bsf,
0271 std::shared_ptr<const BoundarySurfaceT<TrackingVolume>> bs,
0272 bool checkmaterial) {
0273 if (checkmaterial) {
0274 auto cMaterialPtr = m_boundarySurfaces.at(bsf)
0275 ->surfaceRepresentation()
0276 .surfaceMaterialSharedPtr();
0277 auto bsMaterial = bs->surfaceRepresentation().surfaceMaterial();
0278 if (cMaterialPtr != nullptr && bsMaterial == nullptr) {
0279 RegularSurface* surface =
0280 const_cast<RegularSurface*>(&bs->surfaceRepresentation());
0281 surface->assignSurfaceMaterial(cMaterialPtr);
0282 }
0283 }
0284 m_boundarySurfaces.at(bsf) = std::move(bs);
0285 }
0286
0287 void TrackingVolume::registerGlueVolumeDescriptor(
0288 std::unique_ptr<GlueVolumesDescriptor> gvd) {
0289 m_glueVolumeDescriptor = std::move(gvd);
0290 }
0291
0292 GlueVolumesDescriptor& TrackingVolume::glueVolumesDescriptor() {
0293 if (m_glueVolumeDescriptor == nullptr) {
0294 m_glueVolumeDescriptor = std::make_unique<GlueVolumesDescriptor>();
0295 }
0296 return *m_glueVolumeDescriptor;
0297 }
0298
0299 void TrackingVolume::synchronizeLayers(double envelope) const {
0300
0301
0302
0303
0304 if (m_confinedLayers) {
0305
0306
0307
0308 for (auto& clayIter : m_confinedLayers->arrayObjects()) {
0309 if (clayIter) {
0310
0311
0312
0313
0314
0315
0316 }
0317
0318
0319 }
0320 }
0321
0322
0323 if (m_confinedVolumes) {
0324
0325
0326
0327 for (auto& cVolumesIter : m_confinedVolumes->arrayObjects()) {
0328 cVolumesIter->synchronizeLayers(envelope);
0329 }
0330 }
0331 }
0332
0333 void TrackingVolume::interlinkLayers() {
0334 if (m_confinedLayers) {
0335 auto& layers = m_confinedLayers->arrayObjects();
0336
0337
0338
0339 const Layer* lastLayer = nullptr;
0340 for (auto& layerPtr : layers) {
0341
0342 Layer& mutableLayer = *(std::const_pointer_cast<Layer>(layerPtr));
0343
0344 mutableLayer.m_nextLayerUtility = m_confinedLayers->binUtility();
0345 mutableLayer.m_nextLayers.first = lastLayer;
0346
0347 mutableLayer.encloseTrackingVolume(*this);
0348
0349 lastLayer = &mutableLayer;
0350 }
0351
0352 lastLayer = nullptr;
0353 for (auto layerIter = layers.rbegin(); layerIter != layers.rend();
0354 ++layerIter) {
0355
0356 Layer& mutableLayer = *(std::const_pointer_cast<Layer>(*layerIter));
0357 mutableLayer.m_nextLayers.second = lastLayer;
0358 lastLayer = &mutableLayer;
0359 }
0360 }
0361 }
0362
0363
0364 boost::container::small_vector<BoundaryIntersection, 4>
0365 TrackingVolume::compatibleBoundaries(const GeometryContext& gctx,
0366 const Vector3& position,
0367 const Vector3& direction,
0368 const NavigationOptions<Surface>& options,
0369 const Logger& logger) const {
0370 ACTS_VERBOSE("Finding compatibleBoundaries");
0371
0372 boost::container::small_vector<BoundaryIntersection, 4> intersections;
0373
0374
0375 double nearLimit = options.nearLimit;
0376 double farLimit = options.farLimit;
0377
0378
0379 auto checkIntersection =
0380 [&](SurfaceMultiIntersection& candidates,
0381 const BoundarySurface* boundary) -> BoundaryIntersection {
0382 for (const auto& intersection : candidates.split()) {
0383 if (!intersection.isValid()) {
0384 continue;
0385 }
0386
0387 ACTS_VERBOSE("Check intersection with surface "
0388 << boundary->surfaceRepresentation().geometryId());
0389 if (detail::checkPathLength(intersection.pathLength(), nearLimit,
0390 farLimit, logger)) {
0391 return BoundaryIntersection(intersection, boundary, nullptr);
0392 }
0393 }
0394
0395 ACTS_VERBOSE("No intersection accepted");
0396 return BoundaryIntersection(SurfaceIntersection::invalid(), nullptr,
0397 nullptr);
0398 };
0399
0400
0401 auto processBoundaries =
0402 [&](const TrackingVolumeBoundaries& boundaries) -> void {
0403
0404 for (auto& boundary : boundaries) {
0405
0406 const auto& surface = boundary->surfaceRepresentation();
0407 ACTS_VERBOSE("Consider boundary surface " << surface.geometryId());
0408
0409
0410
0411
0412 if (&surface == options.startObject) {
0413 ACTS_VERBOSE(" - Surface is excluded surface");
0414 continue;
0415 }
0416
0417 auto candidates = surface.intersect(gctx, position, direction,
0418 options.boundaryTolerance);
0419
0420 auto intersection = checkIntersection(candidates, boundary.get());
0421 if (intersection.intersection.isValid()) {
0422 ACTS_VERBOSE(" - Proceed with surface");
0423 intersections.push_back(intersection);
0424 } else {
0425 ACTS_VERBOSE(" - Surface intersecion invalid");
0426 }
0427 }
0428 };
0429
0430
0431 const auto& surfaces = boundarySurfaces();
0432 ACTS_VERBOSE("Volume reports " << surfaces.size() << " boundary surfaces");
0433 processBoundaries(surfaces);
0434
0435
0436 auto confinedDenseVolumes = denseVolumes();
0437 ACTS_VERBOSE("Volume reports " << confinedDenseVolumes.size()
0438 << " confined dense volumes");
0439 for (const auto& volume : confinedDenseVolumes) {
0440 const auto& surfacesConfined = volume->boundarySurfaces();
0441 ACTS_VERBOSE(" -> " << surfacesConfined.size() << " boundary surfaces");
0442 processBoundaries(surfacesConfined);
0443 }
0444
0445 return intersections;
0446 }
0447
0448 boost::container::small_vector<LayerIntersection, 10>
0449 TrackingVolume::compatibleLayers(
0450 const GeometryContext& gctx, const Vector3& position,
0451 const Vector3& direction, const NavigationOptions<Layer>& options) const {
0452
0453 boost::container::small_vector<LayerIntersection, 10> lIntersections;
0454
0455
0456 if (m_confinedLayers == nullptr) {
0457 return {};
0458 }
0459
0460
0461 const Layer* tLayer = options.startObject != nullptr
0462 ? static_cast<const Layer*>(options.startObject)
0463 : associatedLayer(gctx, position);
0464 while (tLayer != nullptr) {
0465
0466
0467
0468
0469
0470 if (tLayer != options.startObject && tLayer->resolve(options)) {
0471
0472
0473 auto atIntersection =
0474 tLayer->surfaceOnApproach(gctx, position, direction, options);
0475
0476 if (atIntersection.isValid()) {
0477
0478 lIntersections.push_back(LayerIntersection(atIntersection, tLayer));
0479 }
0480 }
0481
0482 tLayer = (tLayer == options.endObject)
0483 ? nullptr
0484 : tLayer->nextLayer(gctx, position, direction);
0485 }
0486
0487
0488
0489
0490 auto min = std::min_element(
0491 lIntersections.begin(), lIntersections.end(),
0492 [](const LayerIntersection& a, const LayerIntersection& b) {
0493 return a.first.pathLength() < b.first.pathLength();
0494 });
0495 std::rotate(lIntersections.begin(), min, lIntersections.end());
0496 lIntersections.resize(std::distance(min, lIntersections.end()),
0497 {SurfaceIntersection::invalid(), nullptr});
0498
0499 return lIntersections;
0500 }
0501
0502 const std::string& TrackingVolume::volumeName() const {
0503 return m_name;
0504 }
0505
0506 void TrackingVolume::setVolumeName(const std::string& volumeName) {
0507 m_name = volumeName;
0508 }
0509
0510 const IVolumeMaterial* TrackingVolume::volumeMaterial() const {
0511 return m_volumeMaterial.get();
0512 }
0513
0514 const std::shared_ptr<const IVolumeMaterial>&
0515 TrackingVolume::volumeMaterialPtr() const {
0516 return m_volumeMaterial;
0517 }
0518
0519 void TrackingVolume::assignVolumeMaterial(
0520 std::shared_ptr<const IVolumeMaterial> material) {
0521 m_volumeMaterial = std::move(material);
0522 }
0523
0524 const LayerArray* TrackingVolume::confinedLayers() const {
0525 return m_confinedLayers.get();
0526 }
0527
0528 const MutableTrackingVolumeVector TrackingVolume::denseVolumes() const {
0529 return m_confinedDenseVolumes;
0530 }
0531
0532 std::shared_ptr<const TrackingVolumeArray> TrackingVolume::confinedVolumes()
0533 const {
0534 return m_confinedVolumes;
0535 }
0536
0537 const TrackingVolume* TrackingVolume::motherVolume() const {
0538 return m_motherVolume;
0539 }
0540
0541 TrackingVolume* TrackingVolume::motherVolume() {
0542 return m_motherVolume;
0543 }
0544
0545 void TrackingVolume::setMotherVolume(TrackingVolume* mvol) {
0546 m_motherVolume = mvol;
0547 }
0548
0549 const Layer* TrackingVolume::associatedLayer(const GeometryContext& ,
0550 const Vector3& position) const {
0551
0552 if (m_confinedLayers != nullptr) {
0553 return (m_confinedLayers->object(position).get());
0554 }
0555
0556
0557 return nullptr;
0558 }
0559
0560 TrackingVolume::VolumeRange TrackingVolume::volumes() const {
0561 return VolumeRange{m_volumes};
0562 }
0563
0564 TrackingVolume::MutableVolumeRange TrackingVolume::volumes() {
0565 return MutableVolumeRange{m_volumes};
0566 }
0567
0568 TrackingVolume& TrackingVolume::addVolume(
0569 std::unique_ptr<TrackingVolume> volume) {
0570 if (volume->motherVolume() != nullptr) {
0571 throw std::invalid_argument("Volume already has a mother volume");
0572 }
0573
0574 volume->setMotherVolume(this);
0575 m_volumes.push_back(std::move(volume));
0576 return *m_volumes.back();
0577 }
0578
0579 TrackingVolume::PortalRange TrackingVolume::portals() const {
0580 return PortalRange{m_portals};
0581 }
0582
0583 TrackingVolume::MutablePortalRange TrackingVolume::portals() {
0584 return MutablePortalRange{m_portals};
0585 }
0586
0587 void TrackingVolume::addPortal(std::shared_ptr<Portal> portal) {
0588 if (portal == nullptr) {
0589 throw std::invalid_argument("Portal is nullptr");
0590 }
0591 m_portals.push_back(std::move(portal));
0592 }
0593
0594 TrackingVolume::SurfaceRange TrackingVolume::surfaces() const {
0595 return SurfaceRange{m_surfaces};
0596 }
0597
0598 TrackingVolume::MutableSurfaceRange TrackingVolume::surfaces() {
0599 return MutableSurfaceRange{m_surfaces};
0600 }
0601
0602 void TrackingVolume::addSurface(std::shared_ptr<Surface> surface) {
0603 if (surface == nullptr) {
0604 throw std::invalid_argument("Surface is nullptr");
0605 }
0606 m_surfaces.push_back(std::move(surface));
0607 }
0608
0609 void TrackingVolume::visualize(IVisualization3D& helper,
0610 const GeometryContext& gctx,
0611 const ViewConfig& viewConfig,
0612 const ViewConfig& portalViewConfig,
0613 const ViewConfig& sensitiveViewConfig) const {
0614 helper.object(volumeName());
0615 if (viewConfig.visible) {
0616 Volume::visualize(helper, gctx, viewConfig);
0617 }
0618
0619 if (sensitiveViewConfig.visible) {
0620 if (!surfaces().empty()) {
0621 helper.object(volumeName() + "_sensitives");
0622 for (const auto& surface : surfaces()) {
0623 surface.visualize(helper, gctx, sensitiveViewConfig);
0624 }
0625 }
0626 }
0627
0628 if (portalViewConfig.visible) {
0629 helper.object(volumeName() + "_portals");
0630 for (const auto& portal : portals()) {
0631 portal.surface().visualize(helper, gctx, portalViewConfig);
0632 }
0633 }
0634
0635 for (const auto& child : volumes()) {
0636 child.visualize(helper, gctx, viewConfig, portalViewConfig,
0637 sensitiveViewConfig);
0638 }
0639 }
0640
0641 const INavigationPolicy* TrackingVolume::navigationPolicy() const {
0642 return m_navigationPolicy.get();
0643 }
0644
0645 INavigationPolicy* TrackingVolume::navigationPolicy() {
0646 return m_navigationPolicy.get();
0647 }
0648
0649 void TrackingVolume::setNavigationPolicy(
0650 std::unique_ptr<INavigationPolicy> policy) {
0651 if (policy == nullptr) {
0652 throw std::invalid_argument("Navigation policy is nullptr");
0653 }
0654
0655 m_navigationPolicy = std::move(policy);
0656 m_navigationPolicy->connect(m_navigationDelegate);
0657 }
0658
0659 void TrackingVolume::initializeNavigationCandidates(
0660 const NavigationArguments& args, AppendOnlyNavigationStream& stream,
0661 const Logger& logger) const {
0662 m_navigationDelegate(args, stream, logger);
0663 }
0664
0665 namespace {
0666
0667 void visitLayer(const Layer& layer, TrackingGeometryVisitor& visitor) {
0668 visitor.visitLayer(layer);
0669
0670 if (layer.surfaceArray() != nullptr) {
0671 for (const auto& srf : layer.surfaceArray()->surfaces()) {
0672 visitor.visitSurface(*srf);
0673 }
0674 }
0675 visitor.visitSurface(layer.surfaceRepresentation());
0676 if (layer.approachDescriptor() != nullptr) {
0677 for (const auto& srf : layer.approachDescriptor()->containedSurfaces()) {
0678 visitor.visitSurface(*srf);
0679 }
0680 }
0681 }
0682
0683 }
0684
0685
0686 void TrackingVolume::apply(TrackingGeometryVisitor& visitor) const {
0687 visitor.visitVolume(*this);
0688
0689
0690 for (const auto& bs : m_boundarySurfaces) {
0691 visitor.visitBoundarySurface(*bs);
0692 }
0693
0694 for (const auto& portal : portals()) {
0695 visitor.visitPortal(portal);
0696 }
0697
0698
0699 if (m_confinedLayers != nullptr) {
0700 std::ranges::for_each(
0701 m_confinedLayers->arrayObjects(),
0702 [&](const auto& layer) { visitLayer(*layer, visitor); });
0703 }
0704
0705 if (m_confinedVolumes != nullptr) {
0706
0707 for (const auto& volume : m_confinedVolumes->arrayObjects()) {
0708 volume->apply(visitor);
0709 }
0710 }
0711
0712 for (const auto& surface : surfaces()) {
0713 visitor.visitSurface(surface);
0714 }
0715
0716 for (const auto& volume : volumes()) {
0717 volume.apply(visitor);
0718 }
0719 }
0720
0721 void TrackingVolume::apply(TrackingGeometryMutableVisitor& visitor) {
0722
0723
0724 if (visitor.visitDepthFirst()) {
0725 for (auto& volume : volumes()) {
0726 volume.apply(visitor);
0727 }
0728 }
0729
0730 visitor.visitVolume(*this);
0731
0732
0733
0734
0735
0736
0737
0738 for (const auto& bs : m_boundarySurfaces) {
0739 visitor.visitBoundarySurface(
0740 const_cast<BoundarySurfaceT<TrackingVolume>&>(*bs));
0741 visitor.visitSurface(
0742 const_cast<RegularSurface&>(bs->surfaceRepresentation()));
0743 }
0744
0745 for (auto& portal : portals()) {
0746 visitor.visitPortal(portal);
0747 visitor.visitSurface(portal.surface());
0748 }
0749
0750
0751
0752
0753
0754 if (m_confinedVolumes == nullptr) {
0755
0756 if (m_confinedLayers != nullptr) {
0757 for (const auto& layer : m_confinedLayers->arrayObjects()) {
0758 visitor.visitLayer(const_cast<Layer&>(*layer));
0759
0760 if (layer->surfaceArray() != nullptr) {
0761 for (const auto& srf : layer->surfaceArray()->surfaces()) {
0762 visitor.visitSurface(const_cast<Surface&>(*srf));
0763 }
0764 }
0765
0766 visitor.visitSurface(
0767 const_cast<Surface&>(layer->surfaceRepresentation()));
0768
0769 if (layer->approachDescriptor() != nullptr) {
0770 for (const auto& srf :
0771 layer->approachDescriptor()->containedSurfaces()) {
0772 visitor.visitSurface(const_cast<Surface&>(*srf));
0773 }
0774 }
0775 }
0776 }
0777 } else {
0778
0779 for (const auto& volume : m_confinedVolumes->arrayObjects()) {
0780 const_cast<TrackingVolume&>(*volume).apply(visitor);
0781 }
0782 }
0783
0784 for (auto& surface : surfaces()) {
0785 visitor.visitSurface(surface);
0786 }
0787
0788 if (!visitor.visitDepthFirst()) {
0789
0790
0791 for (auto& volume : volumes()) {
0792 volume.apply(visitor);
0793 }
0794 }
0795 }
0796
0797 }