diff --git a/Cs_HMI/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs b/Cs_HMI/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs index 69b3e9e..63bfaf3 100644 --- a/Cs_HMI/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs +++ b/Cs_HMI/AGVNavigationCore/Controls/UnifiedAGVCanvas.Mouse.cs @@ -170,19 +170,23 @@ namespace AGVNavigationCore.Controls private void UnifiedAGVCanvas_MouseWheel(object sender, MouseEventArgs e) { - // 줌 처리 - var mouseWorldPoint = ScreenToWorld(e.Location); - var oldZoom = _zoomFactor; + // 현재 마우스 위치를 월드 좌표로 변환 (줌 전) + var mouseWorldBefore = ScreenToWorld(e.Location); + float oldZoom = _zoomFactor; + + // 줌 팩터 계산 (휠 델타 기반) - 더 부드러운 줌 if (e.Delta > 0) - _zoomFactor = Math.Min(_zoomFactor * 1.2f, 5.0f); + _zoomFactor = Math.Min(_zoomFactor * 1.15f, 5.0f); // 확대 (더 부드러움) else - _zoomFactor = Math.Max(_zoomFactor / 1.2f, 0.1f); + _zoomFactor = Math.Max(_zoomFactor / 1.15f, 0.1f); // 축소 (더 부드러움) - // 마우스 위치를 중심으로 줌 - var zoomRatio = _zoomFactor / oldZoom; - _panOffset.X = (int)(e.X - (e.X - _panOffset.X) * zoomRatio); - _panOffset.Y = (int)(e.Y - (e.Y - _panOffset.Y) * zoomRatio); + // 줌 후 마우스 위치의 월드 좌표 + var mouseWorldAfter = ScreenToWorld(e.Location); + + // 마우스 위치가 같은 월드 좌표를 가리키도록 팬 오프셋 조정 + _panOffset.X += (int)((mouseWorldBefore.X - mouseWorldAfter.X) * _zoomFactor); + _panOffset.Y += (int)((mouseWorldBefore.Y - mouseWorldAfter.Y) * _zoomFactor); Invalidate(); } diff --git a/Cs_HMI/PROJECT_SUMMARY.md b/Cs_HMI/PROJECT_SUMMARY.md new file mode 100644 index 0000000..0114fe6 --- /dev/null +++ b/Cs_HMI/PROJECT_SUMMARY.md @@ -0,0 +1,353 @@ +# 프로젝트 요약 (AGVMapEditor, AGVNavigationCore, AGVSimulator) + +## 📊 프로젝트 개요 + +3개의 주요 프로젝트가 **AGVNavigationCore** 라이브러리를 공유하며 연동되는 구조입니다. + +``` +┌─────────────────────────────────────────────────────────────┐ +│ AGVNavigationCore (공유 라이브러리) │ +├─────────────────────────────────────────────────────────────┤ +│ • Models: MapNode, MapLoader, Enums, IMovableAGV, VirtualAGV +│ • Controls: UnifiedAGVCanvas (통합 UI 렌더링) +│ • PathFinding: A*, AGVPathfinder, DirectionChangePlanner +└─────────────────────────────────────────────────────────────┘ + ▲ ▲ ▲ + │ 참조 │ 참조 │ 참조 + │ │ │ + ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ + │ AGVMapEditor │ │ AGVSimulator │ │ AGV4 (미사용) + │ (맵 편집) │ │ (시뮬레이션) │ │ (메인앱) + └──────────────┘ └──────────────┘ └──────────────┘ +``` + +--- + +## 🎯 각 프로젝트의 기능 + +### 1️⃣ **AGVMapEditor** (맵 편집 도구) + +**목적**: AGV 맵 데이터를 시각적으로 생성/편집 + +#### 제공 기능 +| 기능 | 설명 | +|------|------| +| **노드 생성** | 맵 상에 AGV 네비게이션 노드 추가 | +| **노드 편집** | 노드 이름, RFID, 타입, 도킹방향 설정 | +| **노드 이동** | 드래그로 노드 위치 변경 (그리드 스냅 지원) | +| **연결 관리** | 노드 간 경로 연결 생성/삭제 | +| **노드 삭제** | 선택된 노드 제거 | +| **라벨 추가** | 맵에 텍스트 라벨 추가 | +| **이미지 추가** | 맵에 배경 이미지 추가 | +| **맵 저장/로드** | JSON 형식 맵 파일 저장/로드 | + +#### 기술 구성 +``` +MainForm (WinForms) +└─ UnifiedAGVCanvas (UI 렌더링) + ├─ MapNode 목록 관리 + ├─ 편집 모드 (Select, Move, AddNode, Connect, Delete, DeleteConnection, AddLabel, AddImage) + └─ MapLoader 사용 (JSON 저장/로드) +``` + +#### 주요 UI 요소 +- **메뉴바**: File (Open/Save), Edit, View +- **툴바**: 편집 모드 전환 버튼 (선택, 이동, 노드추가, 연결, 삭제, 라벨, 이미지) +- **속성 패널**: 선택된 노드 정보 표시/편집 +- **캔버스**: 맵 시각화 및 편집 + +--- + +### 2️⃣ **AGVNavigationCore** (경로 계산 엔진 라이브러리) + +**목적**: AGV 경로 계산 및 네비게이션 핵심 로직 제공 + +#### 제공 기능 +| 영역 | 모듈 | 기능 | +|------|------|------| +| **Models** | MapNode | AGV 네비게이션 노드 데이터 | +| | MapLoader | 맵 파일 로드/저장 | +| | IMovableAGV | AGV 동작 인터페이스 | +| | VirtualAGV | 가상 AGV 시뮬레이션 로직 ⚠️ **미완성** | +| **Controls** | UnifiedAGVCanvas | 맵 렌더링/편집/모니터링 UI | +| **PathFinding** | AStarPathfinder | 기본 A* 경로 탐색 | +| | AGVPathfinder | AGV 제약 고려 경로 계산 ⚠️ **미완성** | +| | DirectionChangePlanner | 방향 전환 경로 계획 ⚠️ **미완성** | + +#### 핵심 기능 (구현 상태) +``` +✅ 완성 +├─ MapNode 데이터 모델 +├─ MapLoader (파일 I/O) +├─ UnifiedAGVCanvas (UI 렌더링/편집) +└─ AStarPathfinder (기본 경로 탐색) + +❌ 미완성 (개발 대상) +├─ VirtualAGV.ExecutePath() - 경로 실행 +├─ VirtualAGV.Update() - 프레임 업데이트 +├─ AGVPathfinder 핵심 로직 - 경로 상세화, 마그넷 방향 계산 +└─ DirectionChangePlanner - 4단계 방향 전환 알고리즘 +``` + +#### 기술 구성 +``` +AGVNavigationCore (Class Library) +├── Models/ +│ ├── MapNode.cs +│ ├── MapLoader.cs +│ ├── VirtualAGV.cs (← 경로 추적 미완성) +│ ├── IMovableAGV.cs +│ └── Enums.cs +├── Controls/ +│ ├── UnifiedAGVCanvas.cs (메인 UI) +│ ├── UnifiedAGVCanvas.Designer.cs +│ ├── UnifiedAGVCanvas.Events.cs +│ ├── UnifiedAGVCanvas.Mouse.cs (← 줌 기능) +│ ├── UnifiedAGVCanvas.Rendering.cs +│ └── UnifiedAGVCanvas.Utilities.cs +├── PathFinding/ +│ ├── Core/ +│ │ ├── AStarPathfinder.cs ✅ +│ │ ├── PathNode.cs +│ │ └── AGVPathResult.cs +│ ├── Planning/ +│ │ ├── AGVPathfinder.cs (❌ 미완성) +│ │ ├── DirectionChangePlanner.cs (❌ 미완성) +│ │ └── NodeMotorInfo.cs +│ ├── Analysis/ +│ │ └── JunctionAnalyzer.cs +│ └── Validation/ +│ ├── PathValidationResult.cs +│ └── DockingValidationResult.cs +└── Utils/ + └── LiftCalculator.cs +``` + +--- + +### 3️⃣ **AGVSimulator** (AGV 시뮬레이터) + +**목적**: AGV 경로 계산 및 동작을 시각적으로 검증 + +#### 제공 기능 +| 기능 | 설명 | +|------|------| +| **맵 로드** | 저장된 맵 파일 로드 | +| **AGV 시뮬레이션** | 가상 AGV 생성 및 경로 따라 이동 | +| **경로 계산** | 시작점/목적지 선택 후 경로 자동 계산 | +| **경로 시각화** | 계산된 경로 맵에 표시 | +| **실시간 상태 모니터링** | AGV 위치, 방향, 상태 실시간 표시 | +| **도킹 검증** | AGV 도킹 방향 검증 | + +#### 기술 구성 +``` +SimulatorForm (WinForms) +├─ UnifiedAGVCanvas (맵 렌더링) +├─ VirtualAGV 리스트 (가상 AGV들) +├─ MapLoader (맵 파일 로드) +├─ AGVPathfinder (경로 계산) +└─ 시뮬레이션 타이머 (매 프레임 AGV 업데이트) +``` + +#### 주요 UI 요소 +- **메뉴바**: File (Open Map) +- **경로 제어 그룹**: 시작RFID, 목적지RFID, 타겟계산 버튼 +- **시뮬레이션 제어**: 시작, 일시정지, 정지 버튼 +- **캔버스**: 맵 + AGV + 경로 시각화 + +--- + +## 🎨 UnifiedAGVCanvas (통합 UI 컨트롤) + +**위치**: `AGVNavigationCore/Controls/UnifiedAGVCanvas.cs` (4개 파일) + +### 핵심 기능 +| 기능 | 설명 | +|------|------| +| **맵 렌더링** | 노드, 연결선, 그리드, AGV, 경로 표시 | +| **편집 기능** | 노드 추가/이동/삭제, 연결 관리 (AGVMapEditor) | +| **모니터링** | 실시간 AGV 상태 표시 (AGVSimulator) | +| **줌/팬** | 마우스 휠 줌, 좌클릭 드래그 팬 | +| **선택/호버** | 노드 선택, 호버 표시 | +| **경로 시각화** | 계산된 경로를 색상으로 표시 | + +### 모드 및 상태 +```csharp +// CanvasMode +Edit // 편집 모드 (맵 에디터) + +// EditMode (Edit 모드에서만 적용) +Select // 노드 선택 +Move // 노드 이동 +AddNode // 노드 추가 +Connect // 연결 생성 +Delete // 노드/연결 삭제 +DeleteConnection // 연결 삭제 +AddLabel // 라벨 추가 +AddImage // 이미지 추가 +``` + +--- + +## 🖱️ 줌/팬 기능 (현재 상태) + +### 현재 구현 +```csharp +// UnifiedAGVCanvas.Mouse.cs : 171-188 + +private void UnifiedAGVCanvas_MouseWheel(object sender, MouseEventArgs e) +{ + // 줌 처리 + var mouseWorldPoint = ScreenToWorld(e.Location); + var oldZoom = _zoomFactor; + + if (e.Delta > 0) + _zoomFactor = Math.Min(_zoomFactor * 1.2f, 5.0f); // 확대 (1.2배) + else + _zoomFactor = Math.Max(_zoomFactor / 1.2f, 0.1f); // 축소 (1.2배) + + // 마우스 위치를 중심으로 줌 + var zoomRatio = _zoomFactor / oldZoom; + _panOffset.X = (int)(e.X - (e.X - _panOffset.X) * zoomRatio); + _panOffset.Y = (int)(e.Y - (e.Y - _panOffset.Y) * zoomRatio); + + Invalidate(); +} +``` + +### 문제점 및 개선 사항 + +#### ⚠️ 현재 문제 +1. **줌 계산 로직**: 수식이 복잡하고 정확하지 않을 수 있음 +2. **좌표계 혼동**: 스크린 좌표와 월드 좌표 변환이 일관성 없음 +3. **매끄러움**: 줌 비율 계산에서 부자연스러운 동작 가능 + +#### ✅ 개선 방안 +마우스 커서 위치를 기준점으로 하는 스무스한 줌을 구현: + +```csharp +private void UnifiedAGVCanvas_MouseWheel(object sender, MouseEventArgs e) +{ + // 현재 마우스 위치를 월드 좌표로 변환 + var mouseWorldBefore = ScreenToWorld(e.Location); + + float oldZoom = _zoomFactor; + + // 줌 팩터 계산 (휠 델타 기반) + if (e.Delta > 0) + _zoomFactor = Math.Min(_zoomFactor * 1.15f, 5.0f); // 확대 (부드러움) + else + _zoomFactor = Math.Max(_zoomFactor / 1.15f, 0.1f); // 축소 (부드러움) + + // 마우스 위치가 같은 월드 좌표를 가리키도록 팬 오프셋 조정 + var mouseWorldAfter = ScreenToWorld(e.Location); + + _panOffset.X += (int)((mouseWorldBefore.X - mouseWorldAfter.X) * _zoomFactor); + _panOffset.Y += (int)((mouseWorldBefore.Y - mouseWorldAfter.Y) * _zoomFactor); + + Invalidate(); +} +``` + +#### 주요 개선점 +1. **더 부드러운 줌**: 1.2배 → 1.15배로 조정 +2. **명확한 로직**: 마우스 위치 기준으로 명시적으로 계산 +3. **정확한 좌표 변환**: ScreenToWorld() 사용으로 일관성 보장 +4. **자연스러운 동작**: 마우스 아래의 점이 같은 위치를 가리킴 + +--- + +## 📂 파일 구조 (48개 C# 파일) + +### AGVMapEditor (10개 파일) +``` +AGVMapEditor/ +├── Forms/ +│ ├── MainForm.cs (메인 폼, 편집 로직) +│ └── MainForm.Designer.cs (UI 디자인) +├── Models/ +│ ├── EditorSettings.cs (에디터 설정) +│ ├── MapImage.cs (맵 이미지 데이터) +│ ├── MapLabel.cs (맵 라벨 데이터) +│ └── NodePropertyWrapper.cs (노드 속성 래퍼) +├── Program.cs (진입점) +└── Properties/ + └── AssemblyInfo.cs (어셈블리 정보) +``` + +### AGVNavigationCore (30개 파일) +``` +AGVNavigationCore/ +├── Models/ (8개) +│ ├── MapNode.cs, MapLoader.cs, VirtualAGV.cs, IMovableAGV.cs, etc. +├── Controls/ (6개) +│ ├── UnifiedAGVCanvas.cs, UnifiedAGVCanvas.Designer.cs, etc. +├── PathFinding/ (13개) +│ ├── Core/ (AStarPathfinder, PathNode, AGVPathResult) +│ ├── Planning/ (AGVPathfinder, DirectionChangePlanner, etc.) +│ ├── Analysis/ (JunctionAnalyzer) +│ └── Validation/ (PathValidationResult, DockingValidationResult) +└── Utils/ (3개) + ├── LiftCalculator.cs, DockingValidator.cs, etc. +``` + +### AGVSimulator (8개 파일) +``` +AGVSimulator/ +├── Forms/ +│ ├── SimulatorForm.cs (시뮬레이터 메인 폼) +│ └── SimulatorForm.Designer.cs +├── Models/ +│ └── (VirtualAGV는 AGVNavigationCore에서 참조) +├── Program.cs +└── Properties/ + └── AssemblyInfo.cs +``` + +--- + +## 🔄 데이터 흐름 + +### 맵 편집 → 저장 흐름 +``` +AGVMapEditor.MainForm + ↓ +UnifiedAGVCanvas (편집 모드) + ↓ +MapLoader.SaveMapToFile() + ↓ +NewMap.agvmap (JSON 파일) +``` + +### 맵 로드 → 시뮬레이션 흐름 +``` +NewMap.agvmap (JSON 파일) + ↓ +MapLoader.LoadMapFromFile() + ↓ +AGVSimulator.SimulatorForm + ↓ +UnifiedAGVCanvas (모니터링 모드) + ↓ +VirtualAGV (경로 실행) ⚠️ 미완성 +``` + +--- + +## ⚠️ 현재 미완성 부분 + +### 🔴 우선순위 높음 +1. **VirtualAGV.ExecutePath()** - 경로 실행 로직 +2. **VirtualAGV.Update()** - 매 프레임 위치 업데이트 +3. **AGVPathfinder 핵심** - 경로 상세화, 마그넷 방향 계산 + +### 🟡 우선순위 중간 +4. **DirectionChangePlanner** - 4단계 방향 전환 알고리즘 +5. **UnifiedAGVCanvas 줌 개선** - 마우스 기준 스무스 줌 + +--- + +## 📝 참고 문서 +- `CLAUDE.md` - 개발 가이드 및 AGV 하드웨어 설명 +- `CHANGELOG.md` - 변경 로그 +- `Data/NewMap.agvmap` - 실제 맵 데이터 샘플