File indexing completed on 2025-07-11 07:51:16
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/context.hpp>
0010 #include <boost/test/tools/old/interface.hpp>
0011 #include <boost/test/unit_test.hpp>
0012 #include <boost/test/unit_test_suite.hpp>
0013
0014 #include "Acts/Definitions/Units.hpp"
0015 #include "Acts/Geometry/CompositePortalLink.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Geometry/GridPortalLink.hpp"
0019 #include "Acts/Geometry/Portal.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/TrivialPortalLink.hpp"
0022 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0023 #include "Acts/Surfaces/CylinderSurface.hpp"
0024 #include "Acts/Surfaces/DiscSurface.hpp"
0025 #include "Acts/Surfaces/RadialBounds.hpp"
0026 #include "Acts/Surfaces/Surface.hpp"
0027 #include "Acts/Surfaces/SurfaceMergingException.hpp"
0028 #include "Acts/Utilities/ThrowAssert.hpp"
0029
0030 #include <stdexcept>
0031
0032 using namespace Acts::UnitLiterals;
0033
0034 namespace Acts::Test {
0035
0036 auto logger = Acts::getDefaultLogger("UnitTests", Acts::Logging::VERBOSE);
0037
0038 struct Fixture {
0039 Logging::Level m_level;
0040 Fixture() {
0041 m_level = Acts::Logging::getFailureThreshold();
0042 Acts::Logging::setFailureThreshold(Acts::Logging::FATAL);
0043 }
0044
0045 ~Fixture() { Acts::Logging::setFailureThreshold(m_level); }
0046 };
0047
0048 std::shared_ptr<TrackingVolume> makeDummyVolume() {
0049 return std::make_shared<TrackingVolume>(
0050 Transform3::Identity(),
0051 std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0052 }
0053
0054 GeometryContext gctx;
0055
0056 BOOST_FIXTURE_TEST_SUITE(Geometry, Fixture)
0057
0058 BOOST_AUTO_TEST_SUITE(Portals)
0059 BOOST_AUTO_TEST_SUITE(Merging)
0060
0061 BOOST_AUTO_TEST_CASE(Cylinder) {
0062 auto vol1 = makeDummyVolume();
0063 vol1->setVolumeName("vol1");
0064 auto vol2 = makeDummyVolume();
0065 vol2->setVolumeName("vol2");
0066
0067 auto cyl1 = Surface::makeShared<CylinderSurface>(
0068 Transform3{Translation3{Vector3::UnitZ() * -100_mm}}, 50_mm, 100_mm);
0069
0070 auto cyl2 = Surface::makeShared<CylinderSurface>(
0071 Transform3{Translation3{Vector3::UnitZ() * 100_mm}}, 50_mm, 100_mm);
0072
0073 Portal portal1{Direction::AlongNormal(),
0074 std::make_unique<TrivialPortalLink>(cyl1, *vol1)};
0075 BOOST_CHECK(portal1.isValid());
0076
0077 BOOST_CHECK_EQUAL(
0078 portal1
0079 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -100_mm}, Vector3::UnitX())
0080 .value(),
0081 vol1.get());
0082
0083 BOOST_CHECK_EQUAL(
0084 portal1
0085 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -100_mm}, -Vector3::UnitX())
0086 .value(),
0087 nullptr);
0088
0089 Portal portal2{Direction::AlongNormal(), cyl2, *vol2};
0090 BOOST_CHECK(portal2.isValid());
0091
0092 BOOST_CHECK_EQUAL(
0093 portal2
0094 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 100_mm}, -Vector3::UnitX())
0095 .value(),
0096 nullptr);
0097
0098 BOOST_CHECK_EQUAL(
0099 portal2
0100 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 100_mm}, Vector3::UnitX())
0101 .value(),
0102 vol2.get());
0103
0104 Portal portal3{gctx, std::make_unique<TrivialPortalLink>(cyl2, *vol2),
0105 nullptr};
0106 BOOST_CHECK(portal3.isValid());
0107
0108 BOOST_CHECK_NE(portal3.getLink(Direction::AlongNormal()), nullptr);
0109 BOOST_CHECK_EQUAL(portal3.getLink(Direction::OppositeNormal()), nullptr);
0110
0111 Portal portal4{gctx, nullptr,
0112 std::make_unique<TrivialPortalLink>(cyl2, *vol2)};
0113 BOOST_CHECK(portal4.isValid());
0114
0115 BOOST_CHECK_EQUAL(portal4.getLink(Direction::AlongNormal()), nullptr);
0116 BOOST_CHECK_NE(portal4.getLink(Direction::OppositeNormal()), nullptr);
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 BOOST_CHECK_THROW(
0129 Portal::merge(gctx, portal1, portal4, AxisDirection::AxisZ, *logger),
0130 PortalMergingException);
0131
0132
0133
0134 BOOST_CHECK(portal1.isValid());
0135 BOOST_CHECK(portal2.isValid());
0136
0137 BOOST_CHECK_EQUAL(
0138 portal2.resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, Vector3::UnitX())
0139 .value(),
0140 vol2.get());
0141
0142 BOOST_CHECK_EQUAL(
0143 portal2
0144 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, -Vector3::UnitX())
0145 .value(),
0146 nullptr);
0147
0148
0149 BOOST_CHECK_THROW(
0150 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisRPhi, *logger),
0151 SurfaceMergingException);
0152
0153
0154
0155 BOOST_CHECK(!portal1.isValid());
0156 BOOST_CHECK(!portal2.isValid());
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0167 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0168
0169 Portal merged12 =
0170 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger);
0171 BOOST_CHECK_NE(merged12.getLink(Direction::AlongNormal()), nullptr);
0172 BOOST_CHECK_EQUAL(merged12.getLink(Direction::OppositeNormal()), nullptr);
0173
0174 auto composite12 = dynamic_cast<const CompositePortalLink*>(
0175 merged12.getLink(Direction::AlongNormal()));
0176 BOOST_REQUIRE_NE(composite12, nullptr);
0177
0178 BOOST_CHECK_EQUAL(
0179 merged12
0180 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -50_mm}, Vector3::UnitX())
0181 .value(),
0182 vol1.get());
0183
0184 BOOST_CHECK_EQUAL(
0185 merged12
0186 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, Vector3::UnitX())
0187 .value(),
0188 vol2.get());
0189
0190 BOOST_CHECK_EQUAL(
0191 merged12
0192 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -50_mm}, -Vector3::UnitX())
0193 .value(),
0194 nullptr);
0195
0196 BOOST_CHECK_EQUAL(
0197 merged12
0198 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, -Vector3::UnitX())
0199 .value(),
0200 nullptr);
0201
0202 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0203
0204
0205 BOOST_CHECK_THROW(
0206 Portal::merge(gctx, portal1, portal1, AxisDirection::AxisZ, *logger),
0207 PortalMergingException);
0208
0209
0210 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0211 portal2 = Portal{gctx, {.alongNormal = {cyl1, *vol2}}};
0212 BOOST_CHECK_THROW(
0213 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0214 AssertionFailureException);
0215
0216
0217 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0218 MaterialSlab::Nothing());
0219 cyl2->assignSurfaceMaterial(material);
0220 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0221 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0222 BOOST_CHECK_THROW(
0223 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0224 PortalMergingException);
0225 }
0226
0227 BOOST_AUTO_TEST_CASE(Disc) {
0228 auto vol1 = makeDummyVolume();
0229 vol1->setVolumeName("vol1");
0230 auto vol2 = makeDummyVolume();
0231 vol2->setVolumeName("vol2");
0232 auto vol3 = makeDummyVolume();
0233 vol3->setVolumeName("vol3");
0234 auto vol4 = makeDummyVolume();
0235 vol4->setVolumeName("vol4");
0236
0237 auto disc1 = Surface::makeShared<DiscSurface>(
0238 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0239
0240 auto disc2 = Surface::makeShared<DiscSurface>(
0241 Transform3::Identity(), std::make_shared<RadialBounds>(100_mm, 150_mm));
0242
0243 Portal portal1{
0244 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0245
0246 Portal portal2{
0247 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0248
0249 BOOST_CHECK(portal1.isValid());
0250 BOOST_CHECK(portal2.isValid());
0251
0252 BOOST_CHECK_EQUAL(
0253 portal1.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0254 .value(),
0255 vol1.get());
0256 BOOST_CHECK_EQUAL(
0257 portal1.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0258 .value(),
0259 vol2.get());
0260
0261 BOOST_CHECK_EQUAL(
0262 portal2.resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0263 .value(),
0264 vol3.get());
0265 BOOST_CHECK_EQUAL(
0266 portal2
0267 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0268 .value(),
0269 vol4.get());
0270
0271 BOOST_CHECK_THROW(
0272 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0273 AssertionFailureException);
0274
0275 BOOST_CHECK(portal1.isValid());
0276 BOOST_CHECK(portal2.isValid());
0277
0278 BOOST_CHECK_THROW(
0279 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisPhi, *logger),
0280 SurfaceMergingException);
0281
0282
0283
0284 BOOST_CHECK(!portal1.isValid());
0285 BOOST_CHECK(!portal2.isValid());
0286
0287
0288 portal1 = Portal{
0289 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0290
0291 portal2 = Portal{
0292 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303 Portal merged12 =
0304 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisR, *logger);
0305
0306 BOOST_CHECK_EQUAL(
0307 merged12.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0308 .value(),
0309 vol1.get());
0310 BOOST_CHECK_EQUAL(
0311 merged12
0312 .resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0313 .value(),
0314 vol2.get());
0315
0316 BOOST_CHECK_EQUAL(
0317 merged12
0318 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0319 .value(),
0320 vol3.get());
0321 BOOST_CHECK_EQUAL(
0322 merged12
0323 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0324 .value(),
0325 vol4.get());
0326
0327
0328 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0329 MaterialSlab::Nothing());
0330 disc2->assignSurfaceMaterial(material);
0331 portal1 = Portal{
0332 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0333 portal2 = Portal{
0334 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0335 BOOST_CHECK_THROW(
0336 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisR, *logger),
0337 PortalMergingException);
0338 }
0339
0340 BOOST_AUTO_TEST_SUITE_END()
0341
0342 BOOST_AUTO_TEST_SUITE(Fusing)
0343
0344 BOOST_AUTO_TEST_CASE(Separated) {
0345 auto vol1 = makeDummyVolume();
0346 vol1->setVolumeName("vol1");
0347 auto vol2 = makeDummyVolume();
0348 vol2->setVolumeName("vol2");
0349
0350 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0351 50_mm, 100_mm);
0352
0353 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0354 60_mm, 100_mm);
0355
0356 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0357
0358 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0359
0360 BOOST_CHECK(portal1.isValid());
0361 BOOST_CHECK(portal2.isValid());
0362
0363
0364 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal2, *logger),
0365 PortalFusingException);
0366
0367 BOOST_CHECK(portal1.isValid());
0368 BOOST_CHECK(portal2.isValid());
0369
0370
0371 BOOST_CHECK_THROW(
0372 portal1.setLink(gctx, Direction::AlongNormal(), cyl2, *vol2),
0373 PortalFusingException);
0374 BOOST_CHECK_EQUAL(portal1.getLink(Direction::AlongNormal()), nullptr);
0375
0376 Portal portal1b{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0377 BOOST_CHECK(portal1b.isValid());
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal1b, *logger),
0388 PortalFusingException);
0389 BOOST_CHECK(portal1.isValid());
0390 BOOST_CHECK(portal1b.isValid());
0391
0392 auto disc1 = Surface::makeShared<DiscSurface>(
0393 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0394
0395 auto disc2 = Surface::makeShared<DiscSurface>(
0396 Transform3{Translation3{Vector3{0, 0, 5_mm}}},
0397 std::make_shared<RadialBounds>(50_mm, 100_mm));
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407 Portal portal2b{gctx, {.alongNormal = {disc2, *vol2}}};
0408
0409 BOOST_CHECK_THROW(Portal::fuse(gctx, portal2, portal2b, *logger),
0410 PortalFusingException);
0411 BOOST_CHECK(portal1.isValid());
0412 BOOST_CHECK(portal2.isValid());
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422 Portal portal2c{
0423 gctx, {.alongNormal = {disc2, *vol1}, .oppositeNormal = {disc2, *vol2}}};
0424 BOOST_CHECK(portal2c.isValid());
0425
0426 BOOST_CHECK_THROW(Portal::fuse(gctx, portal2, portal2c, *logger),
0427 PortalFusingException);
0428 BOOST_CHECK(portal2.isValid());
0429 BOOST_CHECK(portal2c.isValid());
0430 }
0431
0432 BOOST_AUTO_TEST_CASE(Success) {
0433 auto vol1 = makeDummyVolume();
0434 vol1->setVolumeName("vol1");
0435 auto vol2 = makeDummyVolume();
0436 vol2->setVolumeName("vol2");
0437
0438 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0439 50_mm, 100_mm);
0440
0441 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0442 50_mm, 100_mm);
0443
0444 BOOST_CHECK(*cyl1 == *cyl2);
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0455 BOOST_CHECK_EQUAL(&portal1.getLink(Direction::OppositeNormal())->surface(),
0456 cyl1.get());
0457
0458 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0459
0460 BOOST_CHECK(portal1.isValid());
0461 BOOST_CHECK(portal2.isValid());
0462
0463 Portal portal3 = Portal::fuse(gctx, portal1, portal2, *logger);
0464
0465 BOOST_CHECK(!portal1.isValid());
0466 BOOST_CHECK(!portal2.isValid());
0467 BOOST_CHECK(portal3.isValid());
0468
0469 BOOST_CHECK_EQUAL(portal3.surface().surfaceMaterial(), nullptr);
0470
0471
0472 BOOST_CHECK_EQUAL(&portal3.surface(), cyl2.get());
0473
0474 BOOST_CHECK_EQUAL(&portal3.getLink(Direction::OppositeNormal())->surface(),
0475 cyl2.get());
0476 }
0477
0478 BOOST_AUTO_TEST_CASE(Material) {
0479 auto vol1 = makeDummyVolume();
0480 auto vol2 = makeDummyVolume();
0481
0482 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0483 50_mm, 100_mm);
0484
0485 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0486 50_mm, 100_mm);
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0497 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0498
0499 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0500 MaterialSlab::Nothing());
0501
0502 cyl1->assignSurfaceMaterial(material);
0503
0504 Portal portal12 = Portal::fuse(gctx, portal1, portal2, *logger);
0505
0506
0507 BOOST_CHECK_EQUAL(&portal12.surface(), cyl1.get());
0508 BOOST_CHECK_EQUAL(portal12.surface().surfaceMaterial(), material.get());
0509
0510
0511 portal1 = Portal{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0512 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0513 cyl2->assignSurfaceMaterial(material);
0514
0515
0516 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal2, *logger),
0517 PortalFusingException);
0518
0519 BOOST_CHECK(portal1.isValid());
0520 BOOST_CHECK(portal2.isValid());
0521
0522 cyl1->assignSurfaceMaterial(nullptr);
0523
0524 portal12 = Portal::fuse(gctx, portal1, portal2, *logger);
0525
0526
0527 BOOST_CHECK_EQUAL(&portal12.surface(), cyl2.get());
0528 BOOST_CHECK_EQUAL(portal12.surface().surfaceMaterial(), material.get());
0529 }
0530
0531 BOOST_AUTO_TEST_CASE(GridCreationOnFuse) {
0532 Transform3 base = Transform3::Identity();
0533
0534 auto vol1 = std::make_shared<TrackingVolume>(
0535 base, std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0536
0537 auto vol2 = std::make_shared<TrackingVolume>(
0538 base, std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0539
0540 auto vol3 = std::make_shared<TrackingVolume>(
0541 base, std::make_shared<CylinderVolumeBounds>(40_mm, 50_mm, 100_mm));
0542
0543 auto vol4 = std::make_shared<TrackingVolume>(
0544 base, std::make_shared<CylinderVolumeBounds>(40_mm, 50_mm, 100_mm));
0545
0546 auto disc1 =
0547 Surface::makeShared<DiscSurface>(Transform3::Identity(), 30_mm, 60_mm);
0548
0549 auto disc2 =
0550 Surface::makeShared<DiscSurface>(Transform3::Identity(), 60_mm, 90_mm);
0551
0552 auto disc3 =
0553 Surface::makeShared<DiscSurface>(Transform3::Identity(), 90_mm, 120_mm);
0554
0555 auto trivial1 = std::make_unique<TrivialPortalLink>(disc1, *vol1);
0556 BOOST_REQUIRE(trivial1);
0557 auto trivial2 = std::make_unique<TrivialPortalLink>(disc2, *vol2);
0558 BOOST_REQUIRE(trivial2);
0559 auto trivial3 = std::make_unique<TrivialPortalLink>(disc3, *vol3);
0560 BOOST_REQUIRE(trivial3);
0561
0562 std::vector<std::unique_ptr<PortalLinkBase>> links;
0563 links.push_back(std::move(trivial1));
0564 links.push_back(std::move(trivial2));
0565 links.push_back(std::move(trivial3));
0566
0567 auto composite = std::make_unique<CompositePortalLink>(std::move(links),
0568 AxisDirection::AxisR);
0569
0570 auto discOpposite =
0571 Surface::makeShared<DiscSurface>(Transform3::Identity(), 30_mm, 120_mm);
0572
0573 auto trivialOpposite =
0574 std::make_unique<TrivialPortalLink>(discOpposite, *vol4);
0575
0576 Portal aPortal{gctx, std::move(composite), nullptr};
0577 Portal bPortal{gctx, nullptr, std::move(trivialOpposite)};
0578
0579 Portal fused = Portal::fuse(gctx, aPortal, bPortal, *logger);
0580
0581 BOOST_CHECK_NE(dynamic_cast<const TrivialPortalLink*>(
0582 fused.getLink(Direction::OppositeNormal())),
0583 nullptr);
0584
0585 const auto* grid = dynamic_cast<const GridPortalLink*>(
0586 fused.getLink(Direction::AlongNormal()));
0587 BOOST_REQUIRE_NE(grid, nullptr);
0588
0589 BOOST_CHECK_EQUAL(grid->grid().axes().front()->getNBins(), 3);
0590 }
0591
0592 BOOST_AUTO_TEST_SUITE_END()
0593
0594 BOOST_AUTO_TEST_CASE(Construction) {
0595 auto vol1 = makeDummyVolume();
0596
0597
0598 auto disc1 = Surface::makeShared<DiscSurface>(
0599 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0600
0601 auto disc2 = Surface::makeShared<DiscSurface>(
0602 Transform3{Translation3{Vector3{0, 0, 5_mm}}},
0603 std::make_shared<RadialBounds>(50_mm, 100_mm));
0604
0605 BOOST_CHECK_THROW(std::make_unique<Portal>(
0606 gctx, std::make_unique<TrivialPortalLink>(disc1, *vol1),
0607 std::make_unique<TrivialPortalLink>(disc2, *vol1)),
0608 PortalFusingException);
0609
0610 BOOST_CHECK_THROW((Portal{gctx, nullptr, nullptr}), std::invalid_argument);
0611 BOOST_CHECK_THROW(Portal(gctx, {}), std::invalid_argument);
0612 }
0613
0614 BOOST_AUTO_TEST_CASE(InvalidConstruction) {
0615 BOOST_CHECK_THROW(Portal(Direction::AlongNormal(), nullptr),
0616 std::invalid_argument);
0617
0618 auto vol1 = makeDummyVolume();
0619
0620 BOOST_CHECK_THROW(Portal(Direction::AlongNormal(), nullptr, *vol1),
0621 std::invalid_argument);
0622
0623 auto disc1 = Surface::makeShared<DiscSurface>(
0624 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0625 Portal portal(Direction::AlongNormal(), disc1, *vol1);
0626
0627 BOOST_CHECK_THROW(portal.setLink(gctx, Direction::AlongNormal(), nullptr),
0628 std::invalid_argument);
0629 }
0630
0631 BOOST_AUTO_TEST_CASE(PortalFill) {
0632 auto vol1 = makeDummyVolume();
0633 auto vol2 = makeDummyVolume();
0634
0635 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0636 50_mm, 100_mm);
0637
0638 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0639 Portal portal2{gctx, {.alongNormal = {cyl1, *vol2}}};
0640
0641
0642 Portal::fuse(gctx, portal1, portal2, *logger);
0643
0644 BOOST_CHECK_THROW(portal1.fill(*vol2), std::logic_error);
0645
0646 portal1 = Portal{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0647 portal2 = Portal{gctx, {.alongNormal = {cyl1, *vol2}}};
0648
0649 BOOST_CHECK_EQUAL(portal1.getLink(Direction::AlongNormal()), nullptr);
0650 BOOST_CHECK_NE(portal1.getLink(Direction::OppositeNormal()), nullptr);
0651
0652 portal1.fill(*vol2);
0653 BOOST_CHECK_NE(portal1.getLink(Direction::AlongNormal()), nullptr);
0654 BOOST_CHECK_NE(portal1.getLink(Direction::OppositeNormal()), nullptr);
0655
0656 BOOST_CHECK_THROW(portal1.fill(*vol2), std::logic_error);
0657 }
0658
0659 BOOST_AUTO_TEST_SUITE_END()
0660
0661 BOOST_AUTO_TEST_SUITE_END()
0662
0663 }