//using System; //using System.Collections.Generic; //using System.Drawing; //using System.Linq; //using AGVMapEditor.Models; //using AGVNavigationCore.Models; //using AGVNavigationCore.PathFinding; //using AGVNavigationCore.PathFinding.Core; //using AGVNavigationCore.Controls; //namespace AGVSimulator.Models //{ // /// // /// 가상 AGV 클래스 // /// 실제 AGV의 동작을 시뮬레이션 // /// // public class VirtualAGV : IAGV // { // #region Events // /// // /// AGV 상태 변경 이벤트 // /// // public event EventHandler StateChanged; // /// // /// 위치 변경 이벤트 // /// // public event EventHandler<(Point, AgvDirection, MapNode)> PositionChanged; // /// // /// RFID 감지 이벤트 // /// // public event EventHandler RfidDetected; // /// // /// 경로 완료 이벤트 // /// // public event EventHandler PathCompleted; // /// // /// 오류 발생 이벤트 // /// // public event EventHandler ErrorOccurred; // #endregion // #region Fields // private string _agvId; // private Point _currentPosition; // private Point _targetPosition; // private string _targetId; // private string _currentId; // private AgvDirection _currentDirection; // private AgvDirection _targetDirection; // private AGVState _currentState; // private float _currentSpeed; // // 경로 관련 // private AGVPathResult _currentPath; // private List _remainingNodes; // private int _currentNodeIndex; // private MapNode _currentNode; // private MapNode _targetNode; // // 이동 관련 // private System.Windows.Forms.Timer _moveTimer; // private DateTime _lastMoveTime; // private Point _moveStartPosition; // private Point _moveTargetPosition; // private float _moveProgress; // // 도킹 관련 // private DockingDirection _dockingDirection; // // 시뮬레이션 설정 // private readonly float _moveSpeed = 50.0f; // 픽셀/초 // private readonly float _rotationSpeed = 90.0f; // 도/초 // private readonly int _updateInterval = 50; // ms // #endregion // #region Properties // /// // /// AGV ID // /// // public string AgvId => _agvId; // /// // /// 현재 위치 // /// // public Point CurrentPosition // { // get => _currentPosition; // set => _currentPosition = value; // } // /// // /// 현재 방향 // /// 모터의 동작 방향 // /// // public AgvDirection CurrentDirection // { // get => _currentDirection; // set => _currentDirection = value; // } // /// // /// 현재 상태 // /// // public AGVState CurrentState // { // get => _currentState; // set => _currentState = value; // } // /// // /// 현재 속도 // /// // public float CurrentSpeed => _currentSpeed; // /// // /// 현재 경로 // /// // public AGVPathResult CurrentPath => _currentPath; // /// // /// 현재 노드 ID // /// // public string CurrentNodeId => _currentNode.NodeId; // /// // /// 목표 위치 // /// // public Point? TargetPosition => _targetPosition; // /// // /// 배터리 레벨 (시뮬레이션) // /// // public float BatteryLevel { get; set; } = 100.0f; // /// // /// 목표 노드 ID // /// // public string TargetNodeId => _targetNode.NodeId; // /// // /// 도킹 방향 // /// // public DockingDirection DockingDirection => _dockingDirection; // #endregion // #region Constructor // /// // /// 생성자 // /// // /// AGV ID // /// 시작 위치 // /// 시작 방향 // public VirtualAGV(string agvId, Point startPosition, AgvDirection startDirection = AgvDirection.Forward) // { // _agvId = agvId; // _currentPosition = startPosition; // _currentDirection = startDirection; // _currentState = AGVState.Idle; // _currentSpeed = 0; // _dockingDirection = DockingDirection.Forward; // 기본값: 전진 도킹 // _currentNode = null; // = string.Empty; // _targetNode = null;// string.Empty; // InitializeTimer(); // } // #endregion // #region Initialization // private void InitializeTimer() // { // _moveTimer = new System.Windows.Forms.Timer(); // _moveTimer.Interval = _updateInterval; // _moveTimer.Tick += OnMoveTimer_Tick; // _lastMoveTime = DateTime.Now; // } // #endregion // #region Public Methods // /// // /// 경로 실행 시작 // /// // /// 실행할 경로 // /// 맵 노드 목록 // public void StartPath(AGVPathResult path, List mapNodes) // { // if (path == null || !path.Success) // { // OnError("유효하지 않은 경로입니다."); // return; // } // _currentPath = path; // _remainingNodes = new List(path.Path); // _currentNodeIndex = 0; // // 시작 노드와 목표 노드 설정 // if (_remainingNodes.Count > 0) // { // var startNode = mapNodes.FirstOrDefault(n => n.NodeId == _remainingNodes[0]); // if (startNode != null) // { // _currentNode = startNode; // // 목표 노드 설정 (경로의 마지막 노드) // if (_remainingNodes.Count > 1) // { // var _targetNodeId = _remainingNodes[_remainingNodes.Count - 1]; // var targetNode = mapNodes.FirstOrDefault(n => n.NodeId == _targetNodeId); // // 목표 노드의 타입에 따라 도킹 방향 결정 // if (targetNode != null) // { // _dockingDirection = GetDockingDirection(targetNode.Type); // } // } // StartMovement(); // } // else // { // OnError($"시작 노드를 찾을 수 없습니다: {_remainingNodes[0]}"); // } // } // } // /// // /// 경로 정지 // /// // public void StopPath() // { // _moveTimer.Stop(); // _currentPath = null; // _remainingNodes?.Clear(); // SetState(AGVState.Idle); // _currentSpeed = 0; // } // /// // /// 긴급 정지 // /// // public void EmergencyStop() // { // StopPath(); // OnError("긴급 정지가 실행되었습니다."); // } // /// // /// 수동 이동 (테스트용) // /// // /// 목표 위치 // public void MoveTo(Point targetPosition) // { // _targetPosition = targetPosition; // _moveStartPosition = _currentPosition; // _moveTargetPosition = targetPosition; // _moveProgress = 0; // SetState(AGVState.Moving); // _moveTimer.Start(); // } // /// // /// 수동 회전 (테스트용) // /// // /// 회전 방향 // public void Rotate(AgvDirection direction) // { // if (_currentState != AGVState.Idle) // return; // SetState(AGVState.Rotating); // // 시뮬레이션: 즉시 방향 변경 (실제로는 시간이 걸림) // _currentDirection = direction; // System.Threading.Thread.Sleep(500); // 회전 시간 시뮬레이션 // SetState(AGVState.Idle); // } // /// // /// AGV 위치 직접 설정 (시뮬레이터용) // /// TargetPosition을 이전 위치로 저장하여 리프트 방향 계산이 가능하도록 함 // /// // /// 새로운 위치 // /// 모터이동방향 // public void SetPosition(MapNode node, Point newPosition, AgvDirection motorDirection) // { // // 현재 위치를 이전 위치로 저장 (리프트 방향 계산용) // if (_currentPosition != Point.Empty) // { // _targetPosition = _currentPosition; // 이전 위치 (previousPos 역할) // _targetDirection = _currentDirection; // _targetNode = node; // } // // 새로운 위치 설정 // _currentPosition = newPosition; // _currentDirection = motorDirection; // _currentNode = node; // // 위치 변경 이벤트 발생 // PositionChanged?.Invoke(this, (_currentPosition, _currentDirection, _currentNode)); // } // /// // /// 충전 시작 (시뮬레이션) // /// // public void StartCharging() // { // if (_currentState == AGVState.Idle) // { // SetState(AGVState.Charging); // // 충전 시뮬레이션 시작 // } // } // /// // /// 충전 종료 // /// // public void StopCharging() // { // if (_currentState == AGVState.Charging) // { // SetState(AGVState.Idle); // } // } // /// // /// AGV 정보 조회 // /// // public string GetStatus() // { // return $"AGV[{_agvId}] 위치:({_currentPosition.X},{_currentPosition.Y}) " + // $"방향:{_currentDirection} 상태:{_currentState} " + // $"속도:{_currentSpeed:F1} 배터리:{BatteryLevel:F1}%"; // } // /// // /// 현재 RFID 시뮬레이션 (현재 위치 기준) // /// // public string SimulateRfidReading(List mapNodes) // { // // 현재 위치에서 가장 가까운 노드 찾기 // var closestNode = FindClosestNode(_currentPosition, mapNodes); // if (closestNode == null) // return null; // // 해당 노드의 RFID 정보 반환 (MapNode에 RFID 정보 포함) // return closestNode.HasRfid() ? closestNode.RfidId : null; // } // #endregion // #region Private Methods // private void StartMovement() // { // SetState(AGVState.Moving); // _moveTimer.Start(); // _lastMoveTime = DateTime.Now; // } // private void OnMoveTimer_Tick(object sender, EventArgs e) // { // var now = DateTime.Now; // var deltaTime = (float)(now - _lastMoveTime).TotalSeconds; // _lastMoveTime = now; // UpdateMovement(deltaTime); // UpdateBattery(deltaTime); // // 위치 변경 이벤트 발생 // PositionChanged?.Invoke(this, (_currentPosition, _currentDirection, _currentNode)); // } // private void UpdateMovement(float deltaTime) // { // if (_currentState != AGVState.Moving) // return; // // 목표 위치까지의 거리 계산 // var distance = CalculateDistance(_currentPosition, _moveTargetPosition); // if (distance < 5.0f) // 도달 임계값 // { // // 목표 도달 // _currentPosition = _moveTargetPosition; // _currentSpeed = 0; // // 다음 노드로 이동 // ProcessNextNode(); // } // else // { // // 계속 이동 // var moveDistance = _moveSpeed * deltaTime; // var direction = new PointF( // _moveTargetPosition.X - _currentPosition.X, // _moveTargetPosition.Y - _currentPosition.Y // ); // // 정규화 // var length = (float)Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y); // if (length > 0) // { // direction.X /= length; // direction.Y /= length; // } // // 새 위치 계산 // _currentPosition = new Point( // (int)(_currentPosition.X + direction.X * moveDistance), // (int)(_currentPosition.Y + direction.Y * moveDistance) // ); // _currentSpeed = _moveSpeed; // } // } // private void UpdateBattery(float deltaTime) // { // // 배터리 소모 시뮬레이션 // if (_currentState == AGVState.Moving) // { // BatteryLevel -= 0.1f * deltaTime; // 이동시 소모 // } // else if (_currentState == AGVState.Charging) // { // BatteryLevel += 5.0f * deltaTime; // 충전 // BatteryLevel = Math.Min(100.0f, BatteryLevel); // } // BatteryLevel = Math.Max(0, BatteryLevel); // // 배터리 부족 경고 // if (BatteryLevel < 20.0f && _currentState != AGVState.Charging) // { // OnError($"배터리 부족: {BatteryLevel:F1}%"); // } // } // private void ProcessNextNode() // { // if (_remainingNodes == null || _currentNodeIndex >= _remainingNodes.Count - 1) // { // // 경로 완료 // _moveTimer.Stop(); // SetState(AGVState.Idle); // PathCompleted?.Invoke(this, _currentPath); // return; // } // // 다음 노드로 이동 // _currentNodeIndex++; // var nextNodeId = _remainingNodes[_currentNodeIndex]; // // RFID 감지 시뮬레이션 // RfidDetected?.Invoke(this, $"RFID_{nextNodeId}"); // //_currentNodeId = nextNodeId; // // 다음 목표 위치 설정 (실제로는 맵에서 좌표 가져와야 함) // // 여기서는 간단히 현재 위치에서 랜덤 오프셋으로 설정 // var random = new Random(); // _moveTargetPosition = new Point( // _currentPosition.X + random.Next(-100, 100), // _currentPosition.Y + random.Next(-100, 100) // ); // } // private MapNode FindClosestNode(Point position, List mapNodes) // { // if (mapNodes == null || mapNodes.Count == 0) // return null; // MapNode closestNode = null; // float closestDistance = float.MaxValue; // foreach (var node in mapNodes) // { // var distance = CalculateDistance(position, node.Position); // if (distance < closestDistance) // { // closestDistance = distance; // closestNode = node; // } // } // // 일정 거리 내에 있는 노드만 반환 // return closestDistance < 50.0f ? closestNode : null; // } // private float CalculateDistance(Point from, Point to) // { // var dx = to.X - from.X; // var dy = to.Y - from.Y; // return (float)Math.Sqrt(dx * dx + dy * dy); // } // private void SetState(AGVState newState) // { // if (_currentState != newState) // { // _currentState = newState; // StateChanged?.Invoke(this, newState); // } // } // private DockingDirection GetDockingDirection(NodeType nodeType) // { // switch (nodeType) // { // case NodeType.Charging: // return DockingDirection.Forward; // 충전기: 전진 도킹 // case NodeType.Docking: // return DockingDirection.Backward; // 장비 (로더, 클리너, 오프로더, 버퍼): 후진 도킹 // default: // return DockingDirection.Forward; // 기본값: 전진 // } // } // private void OnError(string message) // { // SetState(AGVState.Error); // ErrorOccurred?.Invoke(this, message); // } // #endregion // #region Cleanup // /// // /// 리소스 정리 // /// // public void Dispose() // { // _moveTimer?.Stop(); // _moveTimer?.Dispose(); // } // #endregion // } //}