@using Microsoft.AspNetCore.Components
@code {
private ElementReference _groupRef;
private string _arrowMarkerId = "goal-mouse-arrow-" + Guid.NewGuid().ToString("N")[..8];
private double _robotX;
private double _robotY;
private double _goalX;
private double _goalY;
private double _goalOrientationRad;
private double _mouseX;
private double _mouseY;
private string _visibility = "hidden";
/// Tọa độ X điểm đích (world coordinates).
public double GoalX => _goalX;
/// Tọa độ Y điểm đích (world coordinates).
public double GoalY => _goalY;
/// Hướng điểm đích (yaw, radians) — hướng từ goal đến mouse; 0 khi goal trùng mouse.
public double GoalYaw => _goalOrientationRad;
/// Bán kính circle = khoảng cách Goal -> mouse; 0 khi goal trùng mouse (hợp lệ).
private double _radius => Math.Sqrt((_mouseX - _goalX) * (_mouseX - _goalX) + (_mouseY - _goalY) * (_mouseY - _goalY));
///
/// Hiển thị nhóm line và circle (robot->goal, goal->mouse, circle).
///
public void Show()
{
_visibility = "visible";
StateHasChanged();
}
///
/// Ẩn nhóm line và circle.
///
public void Hide()
{
_visibility = "hidden";
StateHasChanged();
}
///
/// Đặt tọa độ robot (world coordinates).
///
public void SetRobotPosition(double x, double y)
{
_robotX = x;
_robotY = y;
StateHasChanged();
}
///
/// Đặt tọa độ điểm đích (world coordinates).
///
public void SetGoalPosition(double x, double y)
{
_goalX = x;
_goalY = y;
StateHasChanged();
}
///
/// Cập nhật vị trí chuột (world coordinates). Parent gọi từ OnMouseMove để vẽ line goal->mouse và circle.
/// Tự tính _goalOrientationRad = hướng từ goal đến mouse (radians); 0 khi goal trùng mouse.
///
public void SetMousePosition(double x, double y)
{
_mouseX = x;
_mouseY = y;
var dx = _mouseX - _goalX;
var dy = _mouseY - _goalY;
_goalOrientationRad = (Math.Abs(dx) < 1e-9 && Math.Abs(dy) < 1e-9) ? 0 : Math.Atan2(dy, dx);
StateHasChanged();
}
private const double OptimizeMinDistanceMeters = 1.0;
///
/// Nếu khoảng cách từ (GoalX, GoalY) đến (mouseX, mouseY) < 1 m thì gọi Hide().
/// Nếu khoảng cách >= 1 m thì đặt lại _mouseX, _mouseY sao cho khoảng cách đúng 1 m (giữ hướng).
/// Tọa độ trong SVG là mét (viewBox + scaleY(-1) trong MapLocalization).
///
public void Optimize()
{
var dx = _mouseX - _goalX;
var dy = _mouseY - _goalY;
var d = Math.Sqrt(dx * dx + dy * dy);
if (d < OptimizeMinDistanceMeters)
{
Hide();
return;
}
var scale = OptimizeMinDistanceMeters / d;
_mouseX = _goalX + dx * scale;
_mouseY = _goalY + dy * scale;
_goalOrientationRad = (Math.Abs(dx) < 1e-9 && Math.Abs(dy) < 1e-9) ? 0 : Math.Atan2(dy, dx);
StateHasChanged();
}
}