feat: Improve mouse-centered zoom with smooth scaling
- UnifiedAGVCanvas 마우스 휠 줌 로직 개선 - 마우스 커서 위치를 기준점으로 하는 정확한 줌 구현 - 줌 비율 1.2배 → 1.15배로 조정 (더 부드러운 동작) - 스크린 좌표와 월드 좌표 변환을 명시적으로 처리 - 마우스 위치가 줌 전후 동일한 월드 좌표를 가리키도록 보장 개선 효과: ✅ 마우스 아래의 콘텐츠가 줌 중심 ✅ 더 자연스럽고 예측 가능한 줌 동작 ✅ 좌표 계산 로직 명확화 추가: - PROJECT_SUMMARY.md: 3개 프로젝트 상세 요약 - AGVMapEditor (맵 편집 도구) - AGVNavigationCore (경로 계산 엔진) - AGVSimulator (시뮬레이터) - UnifiedAGVCanvas 기능 설명 - 현재 미완성 부분 정리 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
353
Cs_HMI/PROJECT_SUMMARY.md
Normal file
353
Cs_HMI/PROJECT_SUMMARY.md
Normal file
@@ -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` - 실제 맵 데이터 샘플
|
||||
Reference in New Issue
Block a user