diff --git a/CMakeLists.txt b/CMakeLists.txt index 0094216..8c51af4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,8 +72,11 @@ add_library(safecrowd_domain STATIC src/domain/SafeCrowdDomain.h src/domain/SafeCrowdDomain.cpp src/domain/Geometry2D.h + src/domain/PopulationSpec.h src/domain/RawImportModel.h src/domain/CanonicalGeometry.h + src/domain/DemoFixtureService.h + src/domain/DemoFixtureService.cpp src/domain/DxfImportService.h src/domain/DxfImportService.cpp src/domain/FacilityLayout2D.h @@ -114,6 +117,7 @@ if (BUILD_TESTING) tests/EcsCoreTests.cpp tests/ImportContractsTests.cpp tests/DxfImportServiceTests.cpp + tests/DemoFixtureServiceTests.cpp tests/FacilityLayoutBuilderTests.cpp tests/WorldQueryTests.cpp tests/CommandBufferTests.cpp diff --git a/src/domain/DemoFixtureService.cpp b/src/domain/DemoFixtureService.cpp new file mode 100644 index 0000000..0bde4f6 --- /dev/null +++ b/src/domain/DemoFixtureService.cpp @@ -0,0 +1,82 @@ +#include "domain/DemoFixtureService.h" + +namespace safecrowd::domain { + +DemoFixture DemoFixtureService::createSprint1DemoFixture() const { + DemoFixture fixture; + auto& layout = fixture.layout; + layout.id = "demo-fixture-01"; + layout.name = "Sprint 1 Demo Layout"; + layout.levelId = "L1"; + + Zone2D mainRoom; + mainRoom.id = "zone-room-1"; + mainRoom.kind = ZoneKind::Room; + mainRoom.label = "Main Demo Room"; + mainRoom.area = Polygon2D{ + .outline = { + {0.0, 0.0}, + {20.0, 0.0}, + {20.0, 20.0}, + {0.0, 20.0}, + }, + }; + mainRoom.defaultCapacity = 200; + layout.zones.push_back(mainRoom); + + Zone2D exitZone; + exitZone.id = "zone-exit-1"; + exitZone.kind = ZoneKind::Exit; + exitZone.label = "Main Exit"; + exitZone.area = Polygon2D{ + .outline = { + {18.0, 20.0}, + {20.0, 20.0}, + {20.0, 22.0}, + {18.0, 22.0}, + }, + }; + exitZone.defaultCapacity = 20; + layout.zones.push_back(exitZone); + + Connection2D exitConnection; + exitConnection.id = "conn-exit-1"; + exitConnection.kind = ConnectionKind::Exit; + exitConnection.fromZoneId = mainRoom.id; + exitConnection.toZoneId = exitZone.id; + exitConnection.effectiveWidth = 2.0; + exitConnection.centerSpan = LineSegment2D{{18.0, 20.0}, {20.0, 20.0}}; + layout.connections.push_back(exitConnection); + + Barrier2D centerObstacle; + centerObstacle.id = "barrier-1"; + centerObstacle.blocksMovement = true; + centerObstacle.geometry = Polyline2D{ + .vertices = { + {8.0, 10.0}, + {12.0, 10.0}, + {12.0, 11.0}, + {8.0, 11.0}, + }, + .closed = true, + }; + layout.barriers.push_back(centerObstacle); + + fixture.population.initialPlacements.push_back({ + .id = "placement-1", + .zoneId = mainRoom.id, + .area = { + .outline = { + {1.0, 1.0}, + {5.0, 1.0}, + {5.0, 5.0}, + {1.0, 5.0}, + }, + }, + .targetAgentCount = 100, + }); + + return fixture; +} + +} // namespace safecrowd::domain diff --git a/src/domain/DemoFixtureService.h b/src/domain/DemoFixtureService.h new file mode 100644 index 0000000..228da40 --- /dev/null +++ b/src/domain/DemoFixtureService.h @@ -0,0 +1,18 @@ +#pragma once + +#include "domain/FacilityLayout2D.h" +#include "domain/PopulationSpec.h" + +namespace safecrowd::domain { + +struct DemoFixture { + FacilityLayout2D layout{}; + PopulationSpec population{}; +}; + +class DemoFixtureService { +public: + DemoFixture createSprint1DemoFixture() const; +}; + +} // namespace safecrowd::domain diff --git a/src/domain/PopulationSpec.h b/src/domain/PopulationSpec.h new file mode 100644 index 0000000..953f58e --- /dev/null +++ b/src/domain/PopulationSpec.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "domain/Geometry2D.h" + +namespace safecrowd::domain { + +struct InitialPlacement2D { + std::string id{}; + std::string zoneId{}; + Polygon2D area{}; + std::size_t targetAgentCount{0}; +}; + +struct PopulationSpec { + std::vector initialPlacements{}; +}; + +} // namespace safecrowd::domain diff --git a/tests/DemoFixtureServiceTests.cpp b/tests/DemoFixtureServiceTests.cpp new file mode 100644 index 0000000..d156b14 --- /dev/null +++ b/tests/DemoFixtureServiceTests.cpp @@ -0,0 +1,36 @@ +#include + +#include "TestSupport.h" + +#include "domain/DemoFixtureService.h" +#include "domain/ImportIssue.h" +#include "domain/ImportValidationService.h" + +SC_TEST(DemoFixtureServiceBuildsSprint1Fixture) { + safecrowd::domain::DemoFixtureService service; + const auto fixture = service.createSprint1DemoFixture(); + const auto& layout = fixture.layout; + const auto& population = fixture.population; + + SC_EXPECT_EQ(layout.id, std::string("demo-fixture-01")); + SC_EXPECT_EQ(layout.name, std::string("Sprint 1 Demo Layout")); + SC_EXPECT_EQ(layout.levelId, std::string("L1")); + SC_EXPECT_EQ(layout.zones.size(), std::size_t{2}); + SC_EXPECT_EQ(layout.zones.front().kind, safecrowd::domain::ZoneKind::Room); + SC_EXPECT_EQ(layout.zones.back().kind, safecrowd::domain::ZoneKind::Exit); + + SC_EXPECT_EQ(layout.connections.size(), std::size_t{1}); + SC_EXPECT_EQ(layout.connections.front().kind, safecrowd::domain::ConnectionKind::Exit); + SC_EXPECT_NEAR(layout.connections.front().effectiveWidth, 2.0, 1e-9); + SC_EXPECT_EQ(layout.barriers.size(), std::size_t{1}); + SC_EXPECT_TRUE(layout.barriers.front().geometry.closed); + + SC_EXPECT_EQ(population.initialPlacements.size(), std::size_t{1}); + SC_EXPECT_EQ(population.initialPlacements.front().zoneId, std::string("zone-room-1")); + SC_EXPECT_EQ(population.initialPlacements.front().targetAgentCount, std::size_t{100}); + SC_EXPECT_EQ(population.initialPlacements.front().area.outline.size(), std::size_t{4}); + + safecrowd::domain::ImportValidationService validator; + const auto issues = validator.validate(layout); + SC_EXPECT_TRUE(!safecrowd::domain::hasBlockingImportIssue(issues)); +}