fix: Add motor direction parameter to magnet direction calculation in pathfinding

- Fixed critical issue in ConvertToDetailedPath where motor direction was not passed to GetRequiredMagnetDirection
- Motor direction is essential for backward movement as Left/Right directions must be inverted
- Modified AGVPathfinder.cs line 280 to pass currentDirection parameter
- Ensures backward motor direction properly inverts magnet sensor directions

feat: Add waypoint support to pathfinding system

- Added FindPath overload with params string[] waypointNodeIds in AStarPathfinder
- Supports sequential traversal through multiple intermediate nodes
- Validates waypoints and prevents duplicates in sequence
- Returns combined path result with aggregated metrics

feat: Implement path result merging with DetailedPath preservation

- Added CombineResults method in AStarPathfinder for intelligent path merging
- Automatically deduplicates nodes when last of previous path equals first of current
- Preserves DetailedPath information including motor and magnet directions
- Essential for multi-segment path operations

feat: Integrate magnet direction with motor direction awareness

- Modified JunctionAnalyzer.GetRequiredMagnetDirection to accept AgvDirection parameter
- Inverts Left/Right magnet directions when moving Backward
- Properly handles motor direction context throughout pathfinding

feat: Add automatic start node selection in simulator

- Added SetStartNodeToCombo method to SimulatorForm
- Automatically selects start node combo box when AGV position is set via RFID
- Improves UI usability and workflow efficiency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
backuppc
2025-10-24 15:46:16 +09:00
parent 3ddecf63ed
commit d932b8d332
47 changed files with 7473 additions and 1088 deletions

View File

@@ -0,0 +1,311 @@
# 방향 기반 경로 탐색 구현 완료 요약
## ✅ 구현 완료
사용자 요구사항에 따라 **이전 위치 + 현재 위치 + 진행 방향**을 기반으로 **다음 노드를 계산하는 시스템**을 완전히 구현했습니다.
---
## 📦 구현된 컴포넌트
### 1. **VirtualAGV.GetNextNodeId()** (핵심 메서드)
**파일**: `AGVNavigationCore\Models\VirtualAGV.cs` (라인 613~823)
```csharp
public string GetNextNodeId(AgvDirection direction, List<MapNode> allNodes)
```
#### 특징:
- ✅ VirtualAGV의 `_prevPosition`, `_currentPosition`, `_currentNode` 사용
- ✅ 최소 2개 위치 히스토리 검증 (prev/current 모두 설정되어야 함)
- ✅ 벡터 기반 방향 계산 (내적, 외적)
- ✅ Forward/Backward/Left/Right 모든 방향 지원
- ✅ Backward 시 좌우 방향 자동 반전
#### 동작 방식:
```
입력: direction (Forward/Backward/Left/Right), allNodes
1⃣ 히스토리 검증: _prevPosition, _currentPosition 확인
2⃣ 연결된 노드 필터링: currentNode의 ConnectedNodes에서 후보 선택
3⃣ 이동 벡터 계산: _currentPosition - _prevPosition
4⃣ 벡터 정규화: 길이를 1로 만듦
5⃣ 각 후보에 대해 점수 계산:
- 내적: 진행 방향과의 유사도
- 외적: 좌우 판별
- direction에 따라 가중치 적용
6⃣ 최고 점수 노드 반환
```
---
## 🧮 방향 점수 계산 로직
### Forward (전진) 모드
```
내적 값 (dotProduct) 점수
────────────────────────────
> 0.9 (거의 같은 방향) 100
0.5~0.9 (비슷한 방향) 80
0~0.5 (약간 다른 방향) 50
-0.5~0 (거의 반대) 20
< -0.5 (완전 반대) 0
```
### Backward (후진) 모드
```
내적 값 (dotProduct) 점수
────────────────────────────
< -0.9 (거의 반대) 100
-0.5~-0.9 (비슷하게 반대) 80
-0.5~0 (약간 다른) 50
0~0.5 (거의 같은 방향) 20
> 0.5 (완전 같은 방향) 0
```
### Left (좌측) 모드
```
Forward 상태 (dotProduct > 0): Backward 상태 (dotProduct < 0):
─────────────────────────────────────────────────────────────────────
crossProduct > 0.5 → 100 (좌측) crossProduct < -0.5 → 100 (좌측 반전)
0~0.5 → 70 -0.5~0 → 70
-0.5~0 → 50 0~0.5 → 50
< -0.5 → 30 > 0.5 → 30
```
### Right (우측) 모드
```
Forward 상태 (dotProduct > 0): Backward 상태 (dotProduct < 0):
─────────────────────────────────────────────────────────────────────
crossProduct < -0.5 → 100 (우측) crossProduct > 0.5 → 100 (우측 반전)
-0.5~0 → 70 0~0.5 → 70
0~0.5 → 50 -0.5~0 → 50
> 0.5 → 30 < -0.5 → 30
```
---
## 📋 테스트 시나리오
### 시나리오 1: 직선 경로 전진
```
001 (65, 229) → 002 (206, 244) → GetNextNodeId(Forward)
이동 벡터: (141, 15)
002→003: (72, 34)
내적: 0.939 → Forward 점수: 100 ✓
결과: 003
```
### 시나리오 2: 좌회전
```
002 (206, 244) → 003 (278, 278) → GetNextNodeId(Left)
이동 벡터에 대해 Left 가중치 적용
외적: crossProduct 양수 선호
```
### 시나리오 3: 우회전
```
003 (278, 278) → 004 (380, 340) → GetNextNodeId(Right)
이동 벡터에 대해 Right 가중치 적용
외적: crossProduct 음수 선호
결과: 030 또는 N022 (맵 구조에 따라)
```
### 시나리오 4: 후진
```
004 → 003 → GetNextNodeId(Backward)
역진 가중치 적용 (dotProduct < -0.9 = 100점)
결과: 002
```
### 시나리오 5: Backward 시 좌우 반전
```
004 → 003 (Backward) → GetNextNodeId(Left)
Backward 상태에서 Left = 원래 Right 방향
좌우 자동 반전으로 올바른 방향 계산
```
---
## 🏗️ 추가 구현 파일들
### 1. **DirectionalPathfinder.cs**
**파일**: `PathFinding\Planning\DirectionalPathfinder.cs`
- 독립적인 벡터 기반 경로 탐색 엔진
- VirtualAGV와 분리된 재사용 가능한 컴포넌트
- 방향 가중치 커스터마이징 지원
### 2. **AGVDirectionCalculator.cs**
**파일**: `Utils\AGVDirectionCalculator.cs`
- VirtualAGV와 실제 AGV 시스템을 위한 통합 인터페이스
- RFID 위치 기반 계산
- 선택된 방향 역추적 기능
### 3. **DirectionalPathfinderTest.cs**
**파일**: `Utils\DirectionalPathfinderTest.cs`
- NewMap.agvmap 파일 로드 및 파싱
- 테스트 시나리오 실행
- 결과 검증 및 출력
### 4. **TestRunner.cs**
**파일**: `Utils\TestRunner.cs`
- 전체 테스트 프로그램 실행
- 모든 시나리오 자동 테스트
---
## 📊 .csproj 수정 사항
**파일**: `AGVNavigationCore\AGVNavigationCore.csproj`
추가된 항목:
```xml
<Compile Include="PathFinding\Planning\DirectionalPathfinder.cs" />
<Compile Include="Utils\AGVDirectionCalculator.cs" />
<Compile Include="Utils\DirectionalPathfinderTest.cs" />
<Compile Include="Utils\TestRunner.cs" />
```
---
## 🚀 사용 방법
### 기본 사용 (VirtualAGV)
```csharp
// VirtualAGV 인스턴스
var agv = new VirtualAGV("AGV001");
// 위치 설정 (최소 2번)
agv.SetPosition(node001, new Point(65, 229), AgvDirection.Forward);
agv.SetPosition(node002, new Point(206, 244), AgvDirection.Forward);
// 다음 노드 계산
string nextNodeId = agv.GetNextNodeId(AgvDirection.Forward, allNodes);
Console.WriteLine($"다음 노드: {nextNodeId}"); // 003
```
### 고급 사용 (독립적인 계산기)
```csharp
var calculator = new AGVDirectionCalculator();
string nextNodeId = calculator.GetNextNodeId(
previousRfidPos: new Point(206, 244),
currentNode: node003,
currentRfidPos: new Point(278, 278),
direction: AgvDirection.Right,
allNodes: allNodes
);
// 실제 선택된 방향 분석
AgvDirection selectedDir = calculator.AnalyzeSelectedDirection(
new Point(206, 244),
new Point(278, 278),
selectedNextNode,
connectedNodes
);
```
---
## ⚠️ 중요 주의사항
### 1. 2개 위치 히스토리 필수
```csharp
// ❌ 잘못된 사용 (처음 호출 시)
string next = agv.GetNextNodeId(direction, allNodes); // null 반환
// ✅ 올바른 사용
agv.SetPosition(node1, pos1, AgvDirection.Forward); // 첫 번째
agv.SetPosition(node2, pos2, AgvDirection.Forward); // 두 번째
string next = agv.GetNextNodeId(direction, allNodes); // 결과 반환
```
### 2. 벡터 정규화
- 매우 작은 이동(<0.001px)은 거리 0으로 간주
- 이 경우 첫 번째 연결 노드 반환
### 3. 좌표계 유지
- 모든 좌표는 맵 기준 (화면 좌표가 아님)
- 줌/팬 상태에서는 별도 변환 필요
### 4. 내적/외적 이해
```
내적 (Dot Product):
= v1.x * v2.x + v1.y * v2.y
범위: -1 ~ 1
1 = 같은 방향, 0 = 직각, -1 = 반대 방향
외적 (Cross Product):
= v1.x * v2.y - v1.y * v2.x
양수 = 좌측, 음수 = 우측
```
---
## 📁 최종 파일 구조
```
AGVNavigationCore/
├── Models/
│ └── VirtualAGV.cs ⭐ (GetNextNodeId 추가)
├── PathFinding/
│ └── Planning/
│ ├── DirectionalPathfinder.cs (NEW)
│ ├── AGVPathfinder.cs
│ └── ...
├── Utils/
│ ├── AGVDirectionCalculator.cs (NEW)
│ ├── DirectionalPathfinderTest.cs (NEW)
│ ├── TestRunner.cs (NEW)
│ └── ...
└── AGVNavigationCore.csproj (MODIFIED)
```
---
## 🎯 핵심 요구사항 검증
| 요구사항 | 상태 | 구현 위치 |
|---------|------|----------|
| GetNextNodeID(direction) 메서드 | ✅ 완료 | VirtualAGV:628 |
| 2개 위치 히스토리 검증 | ✅ 완료 | VirtualAGV:630-634 |
| Forward/Backward/Left/Right 지원 | ✅ 완료 | VirtualAGV:743-817 |
| 좌우 반전 로직 | ✅ 완료 | VirtualAGV:780, 806 |
| 벡터 기반 계산 | ✅ 완료 | VirtualAGV:658-678 |
| NewMap.agvmap 테스트 지원 | ✅ 완료 | DirectionalPathfinderTest |
---
## 📝 다음 단계 (선택사항)
1. **실제 맵에서 테스트**
- TestRunner로 NewMap.agvmap 검증
- 실제 RFID 번호로 시나리오 테스트
2. **성능 최적화**
- 벡터 계산 캐싱
- 점수 계산 병렬화
3. **기능 확장**
- 3D 좌표 지원
- A* 알고리즘 통합
- 동적 가중치 조정
4. **시뮬레이터 통합**
- AGVSimulator에 GetNextNodeId 연결
- 실시간 경로 변경 시연
---
## 📚 관련 문서
- `ANALYSIS_AGV_Direction_Storage.md` - VirtualAGV 필드 분석
- `IMPLEMENTATION_DirectionalPathfinder.md` - 상세 구현 가이드
---
**완료 일시**: 2025-10-23
**상태**: 🟢 구현 완료, 테스트 대기
**다음 작업**: NewMap.agvmap으로 실제 테스트