Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ add_library(ecs_engine STATIC
src/engine/EcsCore.h
src/engine/EngineConfig.h
src/engine/EngineRuntime.h
src/engine/EngineWorld.h
src/engine/EngineState.h
src/engine/EngineStats.h
src/engine/EngineStepContext.h
Expand All @@ -58,6 +59,7 @@ add_library(ecs_engine STATIC
src/engine/EntityRegistry.cpp
src/engine/EngineRuntime.cpp
src/engine/FrameClock.cpp
src/engine/internal/EngineWorldFactory.h
src/engine/SystemScheduler.cpp
)

Expand All @@ -72,8 +74,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
Expand Down Expand Up @@ -121,6 +126,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
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/프로젝트 구조.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Project/
- `EngineRuntime` : 엔진 상태와 실행 루프를 관리하는 진입점
- `Entity` : `index + generation` 기반 식별자. 재사용된 entity ID의 stale reference를 막기 위한 기본 핸들
- `EngineWorld` : query / resources / commands를 통해 월드 상태에 접근하는 공유 파사드
- `WorldQuery`, `WorldResources`, `WorldCommands` : 컴포넌트 조회·값 접근 / 리소스 접근 / 구조 변경 요청을 분리한 접근면
- `WorldQuery`, `WorldResources`, `WorldCommands` : 컴포넌트 조회·값 접근 / 리소스 접근 / 구조 변경 요청을 분리한 접근면. 상위 계층은 `WorldQuery`를 직접 생성하지 않고 `EngineWorld::query()`로 획득한다.
- `WorldCommands` : 엔티티 생성/삭제와 컴포넌트 추가/제거 같은 구조 변경을 즉시 ECS에 반영하지 않고 command buffer에 기록하며, 실제 반영은 runtime이 phase 경계에서 수행
- `FrameClock` : 고정 timestep 누적과 catch-up step 계산 담당
- `EngineSystem` : `update(world, stepContext)` 형태로 월드와 프레임 컨텍스트를 받는 범용 시스템 인터페이스
Expand Down
113 changes: 113 additions & 0 deletions docs/제출용/종합설계/Pathfinder_반영_발표_초안.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Pathfinder 반영 발표 초안

## 발표 전략
- 이번 발표에서는 Pathfinder 조사 결과가 SafeCrowd 설계와 구현 계획에 어떻게 반영됐는지를 설명한다.
- 설명은 기능 반영 내용, backlog 수정, 관리 체계, 현재 구현 상태 순서로 간다.
- Pathfinder 조사를 통해 제품 구조와 구현 계획이 더 구체화되었다는 흐름으로 말한다.

## 전체 슬라이드 흐름
1. Pathfinder 조사 후 우리 주제에 맞게 반영한 기능
2. Pathfinder 반영 결과 Backlog가 어떻게 바뀌었는가
3. Sprint와 우선순위가 왜 다시 배치되었는가
4. GitHub Project, UML, Issue 세팅 반영 상태
5. 현재 구현 완료 범위

---

## 슬라이드 1. Pathfinder 조사 후 반영한 기능

### 슬라이드에 넣을 문구
- 공간 구조를 실행 가능한 토폴로지로 정리
- 연결 구조와 이동 제약 반영
- 시나리오 제어와 행동 전환 반영
- 반복 실행과 재현성 반영
- 결과 아티팩트와 비교 분석 구조 반영

### 슬라이드에 넣을 세부 bullet
- `Floor / Room / Wall / Door / Obstruction / Obstacle` 기준으로 공간 요소를 나눠 다루는 구조
- `stairs / ramp / escalator / walkway`를 공통 connector + modifier로 다루는 방식
- 사람 유형별 이동 제약, 사용할 수 있는 연결 경로 제한, 속도/가속/간격 분포 파라미터
- 단순 최단거리 대신 `국소 이동 시간 + 대기 + 잔여 경로`를 반영하는 기본 출구 선택 비용
- 행동 순서, 조건에 따른 행동 전환, 인원 그룹별 제어
- 초기 배치 + 동적 인원 유입 + 반복 실행과 실행별 비교 구조
- 출입구별 통과 인원과 시간, 공간별 인원 변화, 특정 구역 혼잡도, 전체 실행 요약을 남기는 결과 구조
- heatmap, 핵심 지표 요약, 시나리오 비교, 추천 연결을 위한 결과 파이프라인

### 발표 대본
교수님 피드백 이후 저희는 Pathfinder를 기능을 공식 문서를 통해 조사했고, 그 조사 결과를 반영했습니다.
이 슬라이드에서는 그 반영 내용 중 중요한 부분들을 입력부터 결과 분석 흐름 순서로 설명드리겠습니다.
먼저 공간 구조 쪽에서는 단순히 도면을 불러오는 수준이 아니라, Floor, Room, Wall, Door, Obstruction, Obstacle처럼 실행 가능한 토폴로지로 나눠 다루는 구조를 반영했습니다.
또 계단, 램프, 에스컬레이터, 무빙워크처럼 이동 연결에 해당하는 요소는 각각 따로 보기보다 connector와 modifier 관점으로 정리했습니다.
인원 모델 쪽에서는 사람 유형별 이동 제약과 사용할 수 있는 연결 경로 제한, 그리고 속도나 간격 같은 분포형 파라미터를 반영했습니다.
경로 선택도 단순 최단거리 대신, 국소 이동 시간과 대기, 남은 경로를 함께 고려하는 출구 선택 비용 구조로 정리했습니다.
시나리오 제어 쪽에서는 행동 순서, 조건에 따른 행동 전환, 인원 그룹별 제어 같은 방식을 반영했고, 실행 쪽에서는 초기 배치뿐 아니라 시간대별 인원 유입, 반복 실행, 반복 실험 간 비교가 가능한 구조를 반영했습니다.
마지막으로 결과 쪽에서는 출입구별 통과 기록, 공간별 인원 변화 기록, 특정 구역의 혼잡도 측정 결과, 전체 실행 요약 같은 결과를 남기고, 이걸 heatmap, 핵심 지표 요약, 시나리오 비교, 그리고 이후 추천 기능으로 연결하는 흐름을 반영했습니다.

### 발표 포인트
- 조사한 기능을 `공간`, `연결`, `인원`, `경로`, `제어`, `실행`, `결과` 순서로 소개하면 흐름이 자연스럽다

---

## 슬라이드 2. Pathfinder 반영 결과 Backlog 수정 내용 (Product Backlog - Pathfinder 반영안.md의 (수정) 이라는 텍스트가 붙은 부분들 참고)

### 슬라이드에 넣을 문구
- Acceptance Criteria 보강

### 슬라이드에 넣을 세부 bullet
- 공간 import 결과에 `Room`, `Door`, `Obstruction`, `Obstacle`, `Connector` 검토 기준 추가
- 시나리오 생성에 인원 배치 조건, 연결 경로 사용 제한, 경로 선택 규칙 기준 추가
- 운영 이벤트에 행동 전환, 인원 그룹 구분, 발동 조건 추가
- 실행과 반복 실행에 시간대별 인원 유입, seed, 반복 실행 기록 기준 추가
- 결과 분석에 출입구별 통과 기록, 공간별 인원 변화 기록, 특정 구역 측정 결과, 반복 실행/전체 실행 요약 기준 추가

### 발표 대본
Backlog에서 변화는 acceptance criteria를 구체적으로 세분화한 부분입니다.
먼저 공간 입력 쪽에서는 import 결과를 단순 도면 불러오기로 두지 않고, Room, Door, Obstruction, Obstacle, Connector 후보를 구분해서 검토할 수 있도록 기준을 세화했습니다.
시나리오 생성 쪽에서는 인원 배치 조건, 어떤 연결 경로를 사용할 수 있는지, 어떤 기준으로 출구를 선택하는지 같은 설정 요소를 acceptance criteria에 넣었습니다.
운영 이벤트 쪽도 단순한 상태 변경이 아니라, 행동 전환, 인원 그룹 구분, 어떤 조건에서 이벤트가 발동하는지까지 포함하도록 구체화했습니다.
실행 쪽에서는 초기 배치뿐 아니라 시간대별 인원 유입, seed, 반복 실행 기록 기준을 추가해서 반복 실행과 재현성을 더 명확히 적었습니다.
마지막으로 결과 쪽에서는 출입구별 통과 기록, 공간별 인원 변화 기록, 특정 구역 측정 결과, 반복 실행 요약, 전체 실행 요약 같은 결과 단위를 acceptance criteria에 반영했습니다.
---

## 슬라이드 3. Sprint와 구현 순서 재배치 (Product_Backlog_2팀.docx 후반 참고)

### 슬라이드에 넣을 문구
- Sprint 1: 공간 토폴로지와 기본 실행
- Sprint 2: 핵심 위험 분석과 결과 파이프라인
- Sprint 3: 추가 기능과 추천 연결

### 슬라이드에 넣을 세부 bullet
- Sprint 1: E1, E2 기본, E3 기본 실행
- Sprint 2: E4 핵심 위험 축, E5 요약/비교
- Sprint 3: 템플릿, 추가 위험 축, 저장/내보내기, 추천
- 후속 단계 기능과 추가 조사 항목은 분리 유지

### 발표 대본
Backlog를 수정하면서 Sprint 배치도 같이 바꿨습니다.
Sprint 1은 공간 토폴로지와 기본 실행입니다. 즉, 도면을 실행 가능한 구조로 만들고, 기준 시나리오와 운영 이벤트를 정의하고, 실제로 실행이 돌아가는 기반을 먼저 확보하는 단계입니다.
Sprint 2는 핵심 위험 분석과 결과 파이프라인입니다. 여기서는 병목과 정체, 근접도와 압박 전조, 운영 갈등 같은 핵심 위험 축을 잡고, heatmap과 핵심 지표, 기준안 대비 대안 비교까지 연결합니다.
Sprint 3은 추가 기능과 추천 연결 단계입니다. 시나리오 템플릿, 추가 위험 축, 저장과 내보내기, 그리고 운영 대안 추천을 이 단계에 둡니다.

---

## 슬라이드 4. GitHub Project, UML, Issue 세팅 반영 상태

### 슬라이드에 넣을 문구
- UML, Issue, Project를 같은 기준으로 동기화

### 슬라이드에 넣을 세부 bullet
- UML 5종 추가
- Github Issue
- Project

### 발표 대본
실제로 구현이 따라갈 수 있도록 UML, Issue, GitHub Project 운영 방식까지 같이 맞췄습니다.
수정된 Backlog 문서의 기준에 맞춰 UML에 반영했습니다.
다음으로 이 설계를 GitHub 작업 체계에 연결했습니다.
Project에서는 진행상황을 한 눈에 보이게 추적할 수 있습니다.

---

## 슬라이드 5. 현재 구현 완료 범위 (예정)

---
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ flowchart LR
FC["FrameClock"]
ER["EntityRegistry"]
PCS["PackedComponentStorage"]
SYS["EngineSystem / WorldQuery / CommandBuffer"]
SYS["EngineWorld / EngineSystem / CommandBuffer"]
end

QT["Qt6 Widgets"] --> Application
Expand All @@ -130,7 +130,7 @@ flowchart LR
| --- | --- | --- | --- |
| `application` | `MainWindow`, Qt signal/slot, 향후 import/scenario/result UI | 사용자 입력 수집, 도메인 서비스 호출, 상태 표시 | ECS 내부 로직과 위험 계산식을 직접 가지지 않음 |
| `domain` | `SafeCrowdDomain`, `DxfImportService`, `FacilityLayoutBuilder`, `ImportValidationService`, 향후 시나리오/위험/추천 모듈 | SafeCrowd 문제 영역 규칙, 공간 구조 정규화, 실행 가능성 검토, 위험 지표 정의 | Qt UI 의존 금지 |
| `engine` | `EngineRuntime`, `FrameClock`, `EntityRegistry`, `ComponentRegistry`, `PackedComponentStorage`, `WorldQuery`, `CommandBuffer` | 범용 ECS runtime, fixed timestep, world 상태 관리, 시스템 실행 기반 제공 | SafeCrowd 도메인 지식 의존 금지 |
| `engine` | `EngineRuntime`, `EngineWorld`, `FrameClock`, `EntityRegistry`, `ComponentRegistry`, `PackedComponentStorage`, `WorldQuery`(`EngineWorld::query()` 경유), `CommandBuffer` | 범용 ECS runtime, fixed timestep, world 상태 관리, 시스템 실행 기반 제공 | SafeCrowd 도메인 지식 의존 금지 |

핵심 의존 방향은 아래 한 줄로 요약된다.

Expand Down
131 changes: 70 additions & 61 deletions src/domain/DemoFixtureService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,81 @@

namespace safecrowd::domain {

FacilityLayout2D DemoFixtureService::createSprint1DemoLayout() const {
FacilityLayout2D layout;
layout.id = "demo-fixture-01";
layout.name = "Sprint 1 Demo Layout";
layout.levelId = "L1";
DemoFixture DemoFixtureService::createSprint1DemoFixture() const {
DemoFixture fixture;
auto& layout = fixture.layout;
layout.id = "demo-fixture-01";
layout.name = "Sprint 1 Demo Layout";
layout.levelId = "L1";

// 1. ���� ���� ���� (20m x 20m ���簢�� ��)
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 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);

// 2. �ⱸ ���� (���� ��� 18~20 ����)
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);
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);

// 3. �����
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);
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);

// 4. ��ֹ� (�� �Ѱ�� ��ġ�� 4x1 ũ���� ��. ������Ʈ ȸ�� �׽�Ʈ��)
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);
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);

// 5. ���� ���� (���� �ϴ�, 100�� ����)
SpawnZone2D spawnArea;
spawnArea.id = "spawn-1";
spawnArea.targetAgentCount = 100; // Sprint 1 ���� �䱸����
spawnArea.area = Polygon2D{
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}
}
};
layout.spawnZones.push_back(spawnArea);
{1.0, 1.0},
{5.0, 1.0},
{5.0, 5.0},
{1.0, 5.0},
},
},
.targetAgentCount = 100,
});

return layout;
}
return fixture;
}

} // namespace safecrowd::domain
} // namespace safecrowd::domain
17 changes: 11 additions & 6 deletions src/domain/DemoFixtureService.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
#pragma once

#include "domain/FacilityLayout2D.h"
#include "domain/PopulationSpec.h"

namespace safecrowd::domain {

class DemoFixtureService {
public:
// Sprint 1 ���� ���� 20x20 ũ���� ���� ���� ����
FacilityLayout2D createSprint1DemoLayout() const;
};
struct DemoFixture {
FacilityLayout2D layout{};
PopulationSpec population{};
};

} // namespace safecrowd::domain
class DemoFixtureService {
public:
DemoFixture createSprint1DemoFixture() const;
};

} // namespace safecrowd::domain
22 changes: 22 additions & 0 deletions src/domain/PopulationSpec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <cstddef>
#include <string>
#include <vector>

#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<InitialPlacement2D> initialPlacements{};
};

} // namespace safecrowd::domain
2 changes: 1 addition & 1 deletion src/engine/EngineRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ EngineConfig normalizeConfig(EngineConfig config) {
EngineRuntime::EngineRuntime(EngineConfig config)
: config_(normalizeConfig(config)),
scheduler_(core_, buffer_),
world_(core_, buffer_),
world_(EngineWorld::ConstructionToken{}, core_, buffer_),
frameClock_(config_) {
}

Expand Down
1 change: 1 addition & 0 deletions src/engine/EngineRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "engine/EngineConfig.h"
#include "engine/EngineStats.h"
#include "engine/EngineSystem.h"
#include "engine/EngineWorld.h"
#include "engine/FrameClock.h"
#include "engine/SystemDescriptor.h"
#include "engine/SystemScheduler.h"
Expand Down
Loading
Loading