NavisworksTransport/src/Commands/AutoPathPlanningCommand.cs

496 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}