# 방향 기반 경로 탐색 구현 완료 요약 ## ✅ 구현 완료 사용자 요구사항에 따라 **이전 위치 + 현재 위치 + 진행 방향**을 기반으로 **다음 노드를 계산하는 시스템**을 완전히 구현했습니다. --- ## 📦 구현된 컴포넌트 ### 1. **VirtualAGV.GetNextNodeId()** (핵심 메서드) **파일**: `AGVNavigationCore\Models\VirtualAGV.cs` (라인 613~823) ```csharp public string GetNextNodeId(AgvDirection direction, List 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 ``` --- ## 🚀 사용 방법 ### 기본 사용 (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으로 실제 테스트