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