496 lines
19 KiB
C#
496 lines
19 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using Autodesk.Navisworks.Api;
|
||
using NavisworksTransport.Core;
|
||
|
||
namespace NavisworksTransport.Commands
|
||
{
|
||
/// <summary>
|
||
/// 自动路径规划命令参数
|
||
/// </summary>
|
||
public class AutoPathPlanningParameters
|
||
{
|
||
/// <summary>
|
||
/// 起点位置
|
||
/// </summary>
|
||
public Point3D StartPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 终点位置
|
||
/// </summary>
|
||
public Point3D EndPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 物体长度(米)
|
||
/// </summary>
|
||
public double ObjectLengthMeters { get; set; } = 1.0;
|
||
|
||
/// <summary>
|
||
/// 物体宽度(米)
|
||
/// </summary>
|
||
public double ObjectWidthMeters { get; set; } = 1.0;
|
||
|
||
/// <summary>
|
||
/// 物体高度(米)
|
||
/// </summary>
|
||
public double ObjectHeightMeters { get; set; } = 2.0;
|
||
|
||
/// <summary>
|
||
/// 安全边距(米)
|
||
/// </summary>
|
||
public double SafetyMarginMeters { get; set; } = 0.5;
|
||
|
||
/// <summary>
|
||
/// 网格大小(米),-1表示自动选择
|
||
/// </summary>
|
||
public double GridSizeMeters { get; set; } = -1;
|
||
|
||
/// <summary>
|
||
/// 路径名称
|
||
/// </summary>
|
||
public string PathName { get; set; }
|
||
|
||
/// <summary>
|
||
/// 是否自动绘制可视化
|
||
/// </summary>
|
||
public bool AutoDrawVisualization { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 路径规划策略(默认为最短路径)
|
||
/// </summary>
|
||
public PathStrategy Strategy { get; set; } = PathStrategy.Shortest;
|
||
|
||
/// <summary>
|
||
/// 验证参数
|
||
/// </summary>
|
||
public PathPlanningResult ValidateParameters()
|
||
{
|
||
var errors = new List<string>();
|
||
|
||
if (StartPoint == null)
|
||
errors.Add("起点不能为空");
|
||
|
||
if (EndPoint == null)
|
||
errors.Add("终点不能为空");
|
||
|
||
if (ObjectLengthMeters <= 0 || ObjectLengthMeters > 20)
|
||
errors.Add("物体长度必须在0-20米之间");
|
||
|
||
if (ObjectWidthMeters <= 0 || ObjectWidthMeters > 10)
|
||
errors.Add("物体宽度必须在0-10米之间");
|
||
|
||
if (ObjectHeightMeters <= 0 || ObjectHeightMeters > 10)
|
||
errors.Add("物体高度必须在0-10米之间");
|
||
|
||
if (SafetyMarginMeters < 0 || SafetyMarginMeters > 5)
|
||
errors.Add("安全边距必须在0-5米之间");
|
||
|
||
if (GridSizeMeters > 0 && (GridSizeMeters < 0.01 || GridSizeMeters > 5.0))
|
||
errors.Add("网格精度必须在0.01-5.0米之间");
|
||
|
||
if (string.IsNullOrWhiteSpace(PathName))
|
||
PathName = $"自动路径_{DateTime.Now:HHmmss}";
|
||
|
||
if (StartPoint != null && EndPoint != null)
|
||
{
|
||
var distance = CalculateDistance(StartPoint, EndPoint);
|
||
if (distance < 0.1)
|
||
errors.Add("起点和终点距离过近(小于0.1米)");
|
||
}
|
||
|
||
return errors.Count == 0
|
||
? PathPlanningResult.Success("参数验证通过")
|
||
: PathPlanningResult.ValidationFailure(string.Join("; ", errors));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算两点之间的距离
|
||
/// </summary>
|
||
private double CalculateDistance(Point3D p1, Point3D p2)
|
||
{
|
||
var dx = p1.X - p2.X;
|
||
var dy = p1.Y - p2.Y;
|
||
var dz = p1.Z - p2.Z;
|
||
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划命令结果
|
||
/// </summary>
|
||
public class AutoPathPlanningResult
|
||
{
|
||
/// <summary>
|
||
/// 生成的路径
|
||
/// </summary>
|
||
public PathRoute GeneratedRoute { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径长度(米)
|
||
/// </summary>
|
||
public double PathLength { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径点数量
|
||
/// </summary>
|
||
public int PathPointCount { get; set; }
|
||
|
||
/// <summary>
|
||
/// 计算耗时(毫秒)
|
||
/// </summary>
|
||
public long ComputationTimeMs { get; set; }
|
||
|
||
/// <summary>
|
||
/// 使用的网格大小
|
||
/// </summary>
|
||
public double UsedGridSize { get; set; }
|
||
|
||
/// <summary>
|
||
/// 算法统计信息
|
||
/// </summary>
|
||
public string AlgorithmStatistics { get; set; }
|
||
|
||
/// <summary>
|
||
/// 警告信息
|
||
/// </summary>
|
||
public List<string> Warnings { get; set; } = new List<string>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动路径规划命令实现
|
||
/// 展示Command Pattern在路径规划业务中的应用
|
||
/// </summary>
|
||
public class AutoPathPlanningCommand : CommandBase
|
||
{
|
||
#region 字段和属性
|
||
|
||
private readonly AutoPathPlanningParameters _parameters;
|
||
private readonly PathPlanningManager _pathPlanningManager;
|
||
private readonly UIStateManager _uiStateManager;
|
||
|
||
/// <summary>
|
||
/// 命令参数
|
||
/// </summary>
|
||
public AutoPathPlanningParameters Parameters => _parameters;
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
/// <summary>
|
||
/// 初始化自动路径规划命令
|
||
/// </summary>
|
||
/// <param name="parameters">路径规划参数</param>
|
||
/// <param name="pathPlanningManager">路径规划管理器</param>
|
||
public AutoPathPlanningCommand(AutoPathPlanningParameters parameters, PathPlanningManager pathPlanningManager = null)
|
||
: base("AutoPathPlanning", "自动路径规划", "使用A*算法自动规划最优路径")
|
||
{
|
||
_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
|
||
_pathPlanningManager = pathPlanningManager ?? throw new ArgumentNullException(nameof(pathPlanningManager));
|
||
_uiStateManager = UIStateManager.Instance;
|
||
|
||
LogInfo("自动路径规划命令初始化完成");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region CommandBase实现
|
||
|
||
/// <summary>
|
||
/// 验证命令参数
|
||
/// </summary>
|
||
protected override PathPlanningResult ValidateParameters()
|
||
{
|
||
LogInfo("开始验证自动路径规划参数");
|
||
|
||
try
|
||
{
|
||
// 验证基础参数
|
||
var basicValidation = _parameters.ValidateParameters();
|
||
if (!basicValidation.IsSuccess)
|
||
{
|
||
LogWarning($"基础参数验证失败: {basicValidation.ErrorMessage}");
|
||
return basicValidation;
|
||
}
|
||
|
||
// 验证PathPlanningManager状态
|
||
if (_pathPlanningManager == null)
|
||
{
|
||
return PathPlanningResult.ValidationFailure("路径规划管理器未初始化");
|
||
}
|
||
|
||
// 验证Navisworks文档状态
|
||
var document = Application.ActiveDocument;
|
||
if (document?.Models == null || !document.Models.Any())
|
||
{
|
||
return PathPlanningResult.ValidationFailure("当前没有加载的Navisworks模型");
|
||
}
|
||
|
||
// 基本验证:检查通道选择状态
|
||
if (_pathPlanningManager.SelectedChannels.Count == 0)
|
||
{
|
||
return PathPlanningResult.ValidationFailure("没有选择可通行的通道模型,请先选择通道");
|
||
}
|
||
|
||
// 验证起点终点距离
|
||
var distance = CalculateDistance(_parameters.StartPoint, _parameters.EndPoint);
|
||
if (distance > 1000) // 距离过远可能导致计算时间过长
|
||
{
|
||
LogWarning($"起点和终点距离较远({distance:F2}米),可能需要较长的计算时间");
|
||
}
|
||
|
||
LogInfo("参数验证通过");
|
||
return PathPlanningResult.Success("所有参数验证通过");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError("参数验证过程中发生异常", ex);
|
||
return PathPlanningResult.ValidationFailure($"验证过程异常: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行自动路径规划的核心逻辑
|
||
/// </summary>
|
||
protected override async Task<PathPlanningResult> ExecuteInternalAsync(CancellationToken cancellationToken)
|
||
{
|
||
LogInfo("开始执行自动路径规划");
|
||
var startTime = DateTime.UtcNow;
|
||
|
||
try
|
||
{
|
||
// 第一阶段:初始化(10%)
|
||
UpdateProgress(10, "正在初始化路径规划环境...");
|
||
ThrowIfCancellationRequested(cancellationToken);
|
||
|
||
// 更新UI状态为路径规划中
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
LogInfo("UI状态更新:路径规划进行中");
|
||
});
|
||
|
||
// 第二阶段:参数准备(20%)
|
||
UpdateProgress(20, "正在准备规划参数...");
|
||
ThrowIfCancellationRequested(cancellationToken);
|
||
|
||
var actualGridSize = _parameters.GridSizeMeters > 0 ? _parameters.GridSizeMeters : -1;
|
||
LogInfo($"使用参数 - 起点: ({_parameters.StartPoint.X:F2}, {_parameters.StartPoint.Y:F2}), " +
|
||
$"终点: ({_parameters.EndPoint.X:F2}, {_parameters.EndPoint.Y:F2}), " +
|
||
$"物体宽度: {_parameters.ObjectWidthMeters}米, 安全边距: {_parameters.SafetyMarginMeters}米, " +
|
||
$"网格大小: {(actualGridSize > 0 ? $"用户设置 {actualGridSize:F2}米" : "自动选择")}");
|
||
|
||
// 第三阶段:执行路径规划(30% - 80%)
|
||
UpdateProgress(30, "正在计算最优路径...");
|
||
ThrowIfCancellationRequested(cancellationToken);
|
||
|
||
PathRoute generatedRoute = null;
|
||
|
||
// 调用PathPlanningManager的真实A*算法进行路径规划
|
||
try
|
||
{
|
||
LogInfo("开始调用PathPlanningManager进行A*路径规划");
|
||
|
||
// 创建起点和终点对象
|
||
var startPathPoint = new PathPoint
|
||
{
|
||
Name = "起点",
|
||
Position = _parameters.StartPoint,
|
||
Type = PathPointType.StartPoint
|
||
};
|
||
|
||
var endPathPoint = new PathPoint
|
||
{
|
||
Name = "终点",
|
||
Position = _parameters.EndPoint,
|
||
Type = PathPointType.EndPoint
|
||
};
|
||
|
||
// 计算物体半径:基于长度和宽度的较大值的一半
|
||
var objectRadius = Math.Max(_parameters.ObjectLengthMeters, _parameters.ObjectWidthMeters) / 2.0;
|
||
LogInfo($"使用物体半径: {objectRadius}m(基于物体长度{_parameters.ObjectLengthMeters}m和宽度{_parameters.ObjectWidthMeters}m的较大值)");
|
||
|
||
// 调用PathPlanningManager的AutoPlanPath方法执行真实的A*算法
|
||
var pathPlanTask = _pathPlanningManager.AutoPlanPath(
|
||
startPathPoint,
|
||
endPathPoint,
|
||
objectRadius,
|
||
_parameters.SafetyMarginMeters,
|
||
actualGridSize,
|
||
_parameters.ObjectHeightMeters, // 使用参数中的物体高度
|
||
_parameters.Strategy); // 使用参数中指定的路径策略
|
||
|
||
generatedRoute = await pathPlanTask;
|
||
|
||
if (generatedRoute == null)
|
||
{
|
||
throw new Exception("PathPlanningManager未能生成有效路径");
|
||
}
|
||
|
||
// 如果指定了路径名称,则更新路径名称
|
||
if (!string.IsNullOrWhiteSpace(_parameters.PathName))
|
||
{
|
||
generatedRoute.Name = _parameters.PathName;
|
||
}
|
||
|
||
LogInfo($"A*算法路径规划完成: {generatedRoute.Name},包含 {generatedRoute.Points.Count} 个点,长度 {generatedRoute.TotalLength:F2}米");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"调用PathPlanningManager进行A*路径规划失败: {ex.Message}", ex);
|
||
throw;
|
||
}
|
||
|
||
if (generatedRoute == null)
|
||
{
|
||
return PathPlanningResult.Failure("路径规划失败:未能生成有效路径");
|
||
}
|
||
|
||
UpdateProgress(70, "路径规划完成,正在处理结果...");
|
||
ThrowIfCancellationRequested(cancellationToken);
|
||
|
||
// 第四阶段:设置路径名称(80%)
|
||
if (!string.IsNullOrWhiteSpace(_parameters.PathName))
|
||
{
|
||
generatedRoute.Name = _parameters.PathName;
|
||
}
|
||
|
||
UpdateProgress(80, "正在应用路径配置...");
|
||
LogInfo($"生成路径成功:{generatedRoute.Name},包含 {generatedRoute.Points.Count} 个点,总长度 {generatedRoute.TotalLength:F2} 米");
|
||
|
||
// 第五阶段:添加路径到管理器(90%)
|
||
if (_parameters.AutoDrawVisualization)
|
||
{
|
||
UpdateProgress(90, "正在添加路径到管理器...");
|
||
ThrowIfCancellationRequested(cancellationToken);
|
||
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
try
|
||
{
|
||
_pathPlanningManager.AddRoute(generatedRoute);
|
||
LogInfo("路径已添加到管理器");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogWarning($"添加路径到管理器失败: {ex.Message}");
|
||
}
|
||
});
|
||
}
|
||
|
||
// 完成(100%)
|
||
UpdateProgress(100, "自动路径规划完成");
|
||
|
||
var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
|
||
LogInfo($"自动路径规划执行完成,总耗时: {elapsedMs:F0}ms");
|
||
|
||
// 创建结果对象
|
||
var result = PathPlanningResult<AutoPathPlanningResult>.Success(
|
||
new AutoPathPlanningResult
|
||
{
|
||
GeneratedRoute = generatedRoute,
|
||
PathLength = generatedRoute.TotalLength,
|
||
PathPointCount = generatedRoute.Points.Count,
|
||
ComputationTimeMs = (long)elapsedMs,
|
||
UsedGridSize = actualGridSize > 0 ? actualGridSize : 0.5, // 实际使用的网格大小
|
||
AlgorithmStatistics = $"A*算法路径规划完成,生成{generatedRoute.Points.Count}个路径点"
|
||
},
|
||
$"自动路径规划成功完成:{generatedRoute.Name}"
|
||
);
|
||
|
||
result.ElapsedMilliseconds = (long)elapsedMs;
|
||
return result;
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
LogInfo("自动路径规划被用户取消");
|
||
throw; // 让基类处理取消异常
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
|
||
LogError($"自动路径规划执行失败,已耗时: {elapsedMs:F0}ms", ex);
|
||
|
||
// 尝试恢复UI状态
|
||
try
|
||
{
|
||
await _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||
{
|
||
LogInfo("尝试恢复UI状态");
|
||
});
|
||
}
|
||
catch (Exception uiEx)
|
||
{
|
||
LogError("UI状态恢复失败", uiEx);
|
||
}
|
||
|
||
return PathPlanningResult.Failure($"自动路径规划失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有辅助方法
|
||
|
||
/// <summary>
|
||
/// 计算两点之间的距离
|
||
/// </summary>
|
||
private double CalculateDistance(Point3D p1, Point3D p2)
|
||
{
|
||
var dx = p1.X - p2.X;
|
||
var dy = p1.Y - p2.Y;
|
||
var dz = p1.Z - p2.Z;
|
||
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 公共方法
|
||
|
||
/// <summary>
|
||
/// 创建自动路径规划命令的快捷方法
|
||
/// </summary>
|
||
/// <param name="startPoint">起点</param>
|
||
/// <param name="endPoint">终点</param>
|
||
/// <param name="objectSize">物体尺寸(应用于长度和宽度)</param>
|
||
/// <param name="pathName">路径名称</param>
|
||
/// <param name="objectHeight">物体高度(可选,默认2.0米)</param>
|
||
/// <param name="strategy">路径策略(可选,默认最短路径)</param>
|
||
/// <returns>自动路径规划命令实例</returns>
|
||
public static AutoPathPlanningCommand CreateQuick(Point3D startPoint, Point3D endPoint,
|
||
double objectSize = 1.0, string pathName = null, double objectHeight = 2.0, PathStrategy strategy = PathStrategy.Shortest)
|
||
{
|
||
var parameters = new AutoPathPlanningParameters
|
||
{
|
||
StartPoint = startPoint,
|
||
EndPoint = endPoint,
|
||
ObjectLengthMeters = objectSize,
|
||
ObjectWidthMeters = objectSize,
|
||
ObjectHeightMeters = objectHeight,
|
||
SafetyMarginMeters = 0.5,
|
||
GridSizeMeters = -1, // 自动选择
|
||
PathName = pathName,
|
||
AutoDrawVisualization = true,
|
||
Strategy = strategy
|
||
};
|
||
|
||
return new AutoPathPlanningCommand(parameters);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取命令执行摘要信息
|
||
/// </summary>
|
||
/// <returns>命令信息摘要</returns>
|
||
public string GetExecutionSummary()
|
||
{
|
||
return $"自动路径规划命令 - 起点:({_parameters.StartPoint?.X:F1}, {_parameters.StartPoint?.Y:F1}), " +
|
||
$"终点:({_parameters.EndPoint?.X:F1}, {_parameters.EndPoint?.Y:F1}), " +
|
||
$"物体尺寸:长{_parameters.ObjectLengthMeters}×宽{_parameters.ObjectWidthMeters}×高{_parameters.ObjectHeightMeters}米, " +
|
||
$"状态:{Status}";
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |