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