using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Autodesk.Navisworks.Api;
using System.Text;
using System.Linq;
using System.IO;
using NavisworksTransport.Utils;
using NavisworksTransport.Core.Config;
namespace NavisworksTransport
{
///
/// 路径编辑状态枚举
///
public enum PathEditState
{
///
/// 无状态 - 默认状态
///
None,
///
/// 查看状态 - 只能查看路径,不能编辑
///
Viewing,
///
/// 新建状态 - 正在创建新路径
///
Creating,
///
/// 编辑状态 - 正在编辑现有路径
///
Editing,
///
/// 添加路径点状态 - 正在添加路径点
///
AddingPoints,
///
/// 修改路径点状态 - 正在修改现有路径点
///
EditingPoint
}
///
/// 路径类型枚举 - 分离空轨和吊装为独立类型
///
public enum PathType
{
///
/// 地面路径 - 物体在地面运行
///
Ground = 0,
///
/// 空轨路径 - 物体沿空轨移动(可能有坡度),可以获取中心线并吸附
///
Rail = 1,
///
/// 吊装路径 - 起点吊起 → 平移 → 终点吊下
///
Hoisting = 2
}
///
/// PathType枚举扩展方法
///
public static class PathTypeExtensions
{
///
/// 获取路径类型的中文名称
///
public static string GetDisplayName(this PathType pathType)
{
switch (pathType)
{
case PathType.Ground:
return "地面";
case PathType.Rail:
return "空轨";
case PathType.Hoisting:
return "吊装";
default:
return "未知";
}
}
}
///
/// 吊装路径点方向类型
/// 用于标识吊装路径中每个路径点的移动方向
///
public enum HoistingPointDirection
{
///
/// 垂直移动(起吊/下降)
///
Vertical,
///
/// 纵向移动(X轴方向)
///
Longitudinal,
///
/// 横向移动(Y轴方向)
///
Lateral
}
///
/// Rail 路径安装方式
///
public enum RailMountMode
{
///
/// 轨下安装
///
UnderRail = 0,
///
/// 轨上安装
///
OverRail = 1
}
///
/// Rail 路径的参考线定义方式
///
public enum RailPathDefinitionMode
{
///
/// 旧版兼容模式:路径点即轨下悬挂参考点
///
LegacySuspensionPoint = 0,
///
/// 新版模式:路径点表示双轨参考中心线
///
RailCenterLine = 1
}
///
/// 通道检测结果
///
public class ChannelDetectionResult
{
///
/// 是否为有效位置
///
public bool IsValidLocation { get; set; }
///
/// 检测消息
///
public string Message { get; set; }
///
/// 检测方法
///
public string DetectionMethod { get; set; }
}
///
/// 物流通道检测结果
///
public class LogisticsChannelDetectionResult
{
///
/// 是否为有效通道
///
public bool IsValidChannel { get; set; }
///
/// 通道类型名称
///
public string ChannelType { get; set; }
///
/// 检测到的通道模型项
///
public ModelItem DetectedChannel { get; set; }
///
/// 物流类别
///
public CategoryAttributeManager.LogisticsElementType? LogisticsCategory { get; set; }
///
/// 检测置信度
///
public double DetectionConfidence { get; set; }
///
/// 错误消息
///
public string ErrorMessage { get; set; }
}
///
/// 几何分析结果
///
public class GeometryAnalysisResult
{
///
/// 是否可能是通道
///
public bool IsLikelyChannel { get; set; }
///
/// 分析原因
///
public string Reason { get; set; }
///
/// 最可能的通道模型项
///
public ModelItem MostLikelyChannel { get; set; }
///
/// 置信度
///
public double Confidence { get; set; }
}
///
/// 路径规划策略枚举
///
public enum PathStrategy
{
///
/// 最短路径 - 标准A*算法,所有边具有相同权重(默认策略)
///
Shortest = 0,
///
/// 直线优先路径 - 优先选择主方向的路径,减少转弯次数
///
Straightest = 1,
///
/// 安全优先路径 - 基于障碍物距离选择安全路径,适合大型物体居中行驶
///
SafestCenter = 2
}
///
/// 路径点类型枚举
///
public enum PathPointType
{
///
/// 起点
///
StartPoint,
///
/// 终点
///
EndPoint,
///
/// 路径点
///
WayPoint,
///
/// 中间点
///
IntermediatePoint
}
///
/// 路径点数据模型
///
[Serializable]
public class PathPoint
{
///
/// 路径点唯一标识符
///
public string Id { get; set; }
///
/// 路径点3D位置(不参与XML序列化)
///
[XmlIgnore]
public Point3D Position { get; set; }
///
/// X坐标(用于XML序列化)
///
[XmlElement("X")]
public double X
{
get => Position.X;
set
{
if (Position == null)
Position = new Point3D(value, 0, 0);
else
Position = new Point3D(value, Position.Y, Position.Z);
}
}
///
/// Y坐标(用于XML序列化)
///
[XmlElement("Y")]
public double Y
{
get => Position.Y;
set
{
if (Position == null)
Position = new Point3D(0, value, 0);
else
Position = new Point3D(Position.X, value, Position.Z);
}
}
///
/// Z坐标(用于XML序列化)
///
[XmlElement("Z")]
public double Z
{
get => Position.Z;
set
{
if (Position == null)
Position = new Point3D(0, 0, value);
else
Position = new Point3D(Position.X, Position.Y, value);
}
}
///
/// 路径点名称
///
public string Name { get; set; }
///
/// 路径点类型
///
public PathPointType Type { get; set; }
///
/// 创建时间
///
public DateTime CreatedTime { get; set; }
///
/// 路径点序号
///
public int Index { get; set; }
///
/// 备注信息
///
public string Notes { get; set; }
///
/// 限速(米/秒),0表示未设置限速
///
public double SpeedLimit { get; set; }
///
/// 自定义转向半径(模型单位),用于局部急转弯场景
/// 为 null 时使用全局默认值
///
public double? CustomTurnRadius { get; set; }
///
/// 方向类型(仅吊装路径使用)
/// 用于标识吊装路径点的移动方向:垂直、纵向(X轴)、横向(Y轴)
///
public HoistingPointDirection Direction { get; set; } = HoistingPointDirection.Vertical;
///
/// 构造函数
///
public PathPoint()
{
Id = Guid.NewGuid().ToString();
Position = new Point3D();
Name = string.Empty;
Type = PathPointType.WayPoint;
CreatedTime = DateTime.Now;
Index = 0;
Notes = string.Empty;
SpeedLimit = 0;
CustomTurnRadius = null;
Direction = HoistingPointDirection.Vertical;
}
///
/// 带参数构造函数
///
/// 3D坐标
/// 名称
/// 类型
public PathPoint(Point3D position, string name, PathPointType type)
{
Id = Guid.NewGuid().ToString();
Position = position;
Name = name;
Type = type;
CreatedTime = DateTime.Now;
Index = 0;
Notes = string.Empty;
SpeedLimit = 0;
CustomTurnRadius = null;
Direction = HoistingPointDirection.Vertical;
}
///
/// 返回路径点描述字符串
///
///
public override string ToString()
{
return $"{Name} ({Type}) - X:{Position.X:F2}, Y:{Position.Y:F2}, Z:{Position.Z:F2}";
}
}
///
/// 路径段类型
///
public enum PathSegmentType
{
///
/// 直线段
///
Straight,
///
/// 圆弧段
///
Arc
}
///
/// 圆弧轨迹数据
///
[Serializable]
public class ArcTrajectory
{
///
/// 进入切点
///
public Point3D Ts { get; set; }
///
/// 退出切点
///
public Point3D Te { get; set; }
///
/// 圆心位置
///
public Point3D ArcCenter { get; set; }
///
/// 请求半径(配置的转向半径)
///
public double RequestedRadius { get; set; }
///
/// 实际半径(安全截断后)
///
public double ActualRadius { get; set; }
///
/// 偏转角(弧度)
///
public double DeflectionAngle { get; set; }
///
/// 圆弧长度(米)
///
public double ArcLength { get; set; }
}
///
/// 路径边 - 连接两个连续控制点的物理路径段
///
[Serializable]
public class PathEdge
{
///
/// 边唯一标识符
///
public string Id { get; set; }
///
/// 起始控制点ID
///
public string StartPointId { get; set; }
///
/// 结束控制点ID
///
public string EndPointId { get; set; }
///
/// 路径段类型
///
public PathSegmentType SegmentType { get; set; }
///
/// 圆弧轨迹数据(仅当 SegmentType == Arc 时有效)
///
public ArcTrajectory Trajectory { get; set; }
///
/// 边的物理长度(米)
/// 直线段:两点间距离;圆弧段:直线段长度 + 圆弧长度
///
public double PhysicalLength { get; set; }
///
/// 采样点序列(用于碰撞检测和动画)
///
[XmlIgnore]
public List SampledPoints { get; set; }
public PathEdge()
{
Id = Guid.NewGuid().ToString();
SampledPoints = new List();
}
}
///
/// 路径路线数据模型
///
[Serializable]
public class PathRoute
{
public static bool IsTopPayloadAnchorForMountMode(RailMountMode railMountMode)
{
return railMountMode == RailMountMode.UnderRail;
}
///
/// 路径点集合(控制点)
///
public List Points { get; set; }
///
/// 路径边集合 - 存储物理路径段
///
public List Edges { get; set; }
///
/// 路径名称
///
public string Name { get; set; }
///
/// 路径ID
///
public string Id { get; set; }
///
/// 预估时间(秒)
///
public double EstimatedTime { get; set; }
///
/// 关联通道模型ID集合
///
public List AssociatedChannelIds { get; set; }
///
/// 路径总长度(米)- 只读计算属性
///
/// 【重要】此属性实时从几何数据计算,不从数据库存储或加载。
/// 数据库中的 TotalLength 字段已废弃,保留仅用于兼容旧版本。
///
/// 计算方式:
/// - 地面路径(Ground):从 Edges.PhysicalLength 累加(支持圆弧)
/// - 空轨路径(Rail):从 Points 计算直线距离
/// - 吊装路径(Hoisting):从 Points 计算直线距离
///
public double TotalLength
{
get
{
if (Points.Count < 2) return 0.0;
// 地面路径:优先使用 Edges(支持圆弧),否则从 Points 计算
if (PathType == PathType.Ground)
{
if (Edges.Count > 0)
{
double lengthInModelUnits = Edges.Sum(e => e.PhysicalLength);
return NavisworksTransport.Utils.UnitsConverter.ConvertToMeters(lengthInModelUnits);
}
return CalculateLengthFromPoints();
}
// 空轨/吊装路径:使用直线距离
if (PathType == PathType.Rail || PathType == PathType.Hoisting)
{
return CalculateLengthFromPoints();
}
// 未知类型:默认直线计算
return CalculateLengthFromPoints();
}
}
///
/// 从路径点计算直线距离总长度(辅助方法)
///
private double CalculateLengthFromPoints()
{
double totalLength = 0.0;
var sortedPoints = GetSortedPoints();
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var p1 = sortedPoints[i].Position;
var p2 = sortedPoints[i + 1].Position;
double dx = p2.X - p1.X;
double dy = p2.Y - p1.Y;
double dz = p2.Z - p1.Z;
double distanceInModelUnits = Math.Sqrt(dx*dx + dy*dy + dz*dz);
totalLength += NavisworksTransport.Utils.UnitsConverter.ConvertToMeters(distanceInModelUnits);
}
return totalLength;
}
///
/// 创建时间
///
public DateTime CreatedTime { get; set; }
///
/// 最后修改时间
///
public DateTime LastModified { get; set; }
///
/// 路径描述
///
public string Description { get; set; }
///
/// 路径是否完整到达终点
///
public bool IsComplete { get; set; }
///
/// 原始终点坐标(用于显示灰色未到达点)
///
public Point3D OriginalEndPoint { get; set; }
///
/// 实际到达点坐标
///
public Point3D ActualEndPoint { get; set; }
///
/// 完成百分比(0-100)
///
public double CompletionPercentage { get; set; }
///
/// 关联的网格地图(用于网格可视化)
///
[XmlIgnore]
public NavisworksTransport.PathPlanning.GridMap AssociatedGridMap { get; set; }
///
/// 网格大小(模型单位)
///
public double GridSize { get; set; }
///
/// 最大物体长度(模型单位) - 路径适用的物体长度限制
///
public double MaxObjectLength { get; set; }
///
/// 最大物体宽度(模型单位) - 路径适用的物体宽度限制
///
public double MaxObjectWidth { get; set; }
///
/// 最大物体高度(模型单位) - 路径适用的物体高度限制
///
public double MaxObjectHeight { get; set; }
///
/// 安全间隙(模型单位)
///
public double SafetyMargin { get; set; }
///
/// 路径转弯半径(模型单位)- 路径允许的最大转弯半径
/// 物体的最小转弯半径必须小于等于此值
///
public double TurnRadius { get; set; }
///
/// 是否已曲线化
///
public bool IsCurved { get; set; }
///
/// 路径类型
///
public PathType PathType { get; set; } = PathType.Ground;
///
/// 吊装的提升高度(模型单位,仅当 PathType == Hoisting 时有效)
///
public double LiftHeight { get; set; }
///
/// Rail 路径安装方式(仅当 PathType == Rail 时有效)
///
public RailMountMode RailMountMode { get; set; }
///
/// Rail 路径参考线定义方式(仅当 PathType == Rail 时有效)
///
public RailPathDefinitionMode RailPathDefinitionMode { get; set; }
// 数据库分析相关属性
///
/// 碰撞数量(从数据库加载)
///
public int? CollisionCount { get; set; }
///
/// 安全评分(从数据库加载)
///
public double? SafetyScore { get; set; }
///
/// 效率评分(从数据库加载)
///
public double? EfficiencyScore { get; set; }
///
/// 综合评分(从数据库加载)
///
public double? OverallScore { get; set; }
///
/// 构造函数
///
public PathRoute()
{
Points = new List();
Edges = new List();
Name = string.Empty;
Id = Guid.NewGuid().ToString();
EstimatedTime = 0.0;
AssociatedChannelIds = new List();
// TotalLength:计算属性,自动从几何数据计算,无需初始化
CreatedTime = DateTime.Now;
LastModified = DateTime.Now;
Description = string.Empty;
TurnRadius = 0.0; // 0.0 表示未设置,实际使用时从配置获取默认值
IsCurved = false;
RailMountMode = RailMountMode.UnderRail;
RailPathDefinitionMode = RailPathDefinitionMode.LegacySuspensionPoint;
}
///
/// 带参数构造函数
///
/// 路径名称
public PathRoute(string name)
{
Points = new List();
Edges = new List();
Name = name;
Id = Guid.NewGuid().ToString();
EstimatedTime = 0.0;
AssociatedChannelIds = new List();
// TotalLength:计算属性,自动从几何数据计算,无需初始化
CreatedTime = DateTime.Now;
TurnRadius = 0.0; // 0.0 表示未设置,实际使用时从配置获取默认值
IsCurved = false;
LastModified = DateTime.Now;
Description = string.Empty;
RailMountMode = RailMountMode.UnderRail;
RailPathDefinitionMode = RailPathDefinitionMode.LegacySuspensionPoint;
}
///
/// 添加路径点
///
/// 路径点
public void AddPoint(PathPoint point)
{
Points.Add(point);
// 调用统一更新函数(内部会重新设置索引)
RecalculateAndSaveRoute("添加路径点");
}
///
/// 在指定位置插入路径点
///
/// 要插入的路径点
/// 插入位置索引
public void InsertPoint(PathPoint point, int insertIndex)
{
Points.Insert(insertIndex, point);
// 调用统一更新函数(内部会重新设置索引)
RecalculateAndSaveRoute("插入路径点");
}
///
/// 移除路径点
///
/// 路径点
public bool RemovePoint(PathPoint point)
{
bool removed = Points.Remove(point);
if (removed)
{
// 调用统一更新函数(内部会重新设置索引)
RecalculateAndSaveRoute("移除路径点");
}
return removed;
}
///
/// 根据ID移除路径点
///
/// 路径点ID
/// 是否成功移除
public bool RemovePoint(string pointId)
{
var point = Points.FirstOrDefault(p => p.Id == pointId);
if (point != null)
{
return RemovePoint(point);
}
return false;
}
///
/// 清空所有路径点
///
public void ClearPoints()
{
Points.Clear();
Edges.Clear();
IsCurved = false;
// 调用统一更新函数
RecalculateAndSaveRoute("清空路径点");
}
///
/// 获取起点
///
///
public PathPoint GetStartPoint()
{
return Points.Find(p => p.Type == PathPointType.StartPoint);
}
///
/// 获取终点
///
///
public PathPoint GetEndPoint()
{
return Points.Find(p => p.Type == PathPointType.EndPoint);
}
///
/// 获取所有路径点(按序号排序)
///
///
public List GetSortedPoints()
{
var sortedPoints = new List(Points);
sortedPoints.Sort((p1, p2) => p1.Index.CompareTo(p2.Index));
return sortedPoints;
}
///
/// 重新计算路径数据(不保存到数据库)
/// 用于路径优化等临时计算场景
///
/// 上下文信息(用于日志)
public void RecalculateRoute(string context = "路径数据更新")
{
if (Points.Count < 2)
{
LogManager.Debug($"跳过路径数据计算(路径点不足): {Name}, 原因: {context}");
return;
}
try
{
// 1. 重新设置路径点索引
for (int i = 0; i < Points.Count; i++)
{
Points[i].Index = i;
}
// 2. 根据路径类型决定是否重新计算曲线
if (PathType == PathType.Ground)
{
// 地面路径:进行曲线化
double samplingStep = ConfigManager.Instance.Current.PathEditing.ArcSamplingStep;
TurnRadius = ConfigManager.Instance.Current.PathEditing.DefaultPathTurnRadius;
List warnings;
PathCurveEngine.ApplyCurvatureToRoute(this, samplingStep, out warnings);
LogManager.Debug($"地面路径已曲线化: {Name}, 原因: {context}, 转弯半径: {TurnRadius:F2}, 边数: {Edges.Count}");
// 如果有警告,记录日志
if (warnings != null && warnings.Count > 0)
{
foreach (var warning in warnings)
{
LogManager.Warning($"路径曲线化警告: {warning}");
}
}
}
else if (PathType == PathType.Rail || PathType == PathType.Hoisting)
{
// 空轨/吊装路径:使用直线,不需要曲线化
Edges.Clear();
IsCurved = false;
string pathTypeName = PathType == PathType.Rail ? "空轨" : "吊装";
LogManager.Debug($"{pathTypeName}路径已更新(直线模式): {Name}, 原因: {context}");
}
else
{
// 未知路径类型:使用直线
Edges.Clear();
IsCurved = false;
LogManager.Debug($"未知路径类型,使用直线模式: {Name}, 原因: {context}");
}
// 3. 更新最后修改时间
LastModified = DateTime.Now;
LogManager.Debug($"路径数据已计算: {Name}, 原因: {context}, 总长度: {TotalLength:F2}米");
}
catch (Exception ex)
{
LogManager.Error($"路径数据计算失败({context}): {ex.Message}", ex);
}
}
///
/// 重新计算路径数据并保存到数据库
/// 统一的路径数据更新入口:重新设置索引、更新长度、计算曲线、保存到数据库
///
/// 上下文信息(用于日志)
public void RecalculateAndSaveRoute(string context = "路径数据更新")
{
// 先执行计算
RecalculateRoute(context);
// 然后保存到数据库
try
{
if (Points.Count >= 2)
{
var pathPlanningManager = PathPlanningManager.Instance;
if (pathPlanningManager != null)
{
pathPlanningManager.SavePathToDatabase(this);
LogManager.Info($"路径数据已保存到数据库: {Name}, 原因: {context}, 总长度: {TotalLength:F2}米");
}
}
}
catch (Exception ex)
{
LogManager.Error($"路径数据保存失败({context}): {ex.Message}", ex);
}
}
///
/// 验证路径有效性
///
///
public bool IsValid()
{
// 至少需要起点和终点
if (Points.Count < 2) return false;
// 必须有且仅有一个起点和一个终点
var startPoints = Points.FindAll(p => p.Type == PathPointType.StartPoint);
var endPoints = Points.FindAll(p => p.Type == PathPointType.EndPoint);
return startPoints.Count == 1 && endPoints.Count == 1;
}
///
/// 克隆路径
///
/// 克隆的路径对象
public PathRoute Clone()
{
var clonedRoute = new PathRoute(Name + "_Copy")
{
Id = Guid.NewGuid().ToString(),
EstimatedTime = EstimatedTime,
// TotalLength:计算属性,自动从几何数据计算,克隆时会重新计算
CreatedTime = CreatedTime,
LastModified = DateTime.Now,
Description = Description,
AssociatedChannelIds = new List(AssociatedChannelIds),
IsComplete = IsComplete,
OriginalEndPoint = OriginalEndPoint,
ActualEndPoint = ActualEndPoint,
CompletionPercentage = CompletionPercentage,
AssociatedGridMap = AssociatedGridMap, // 共享引用,不深拷贝
GridSize = GridSize,
MaxObjectLength = MaxObjectLength,
MaxObjectWidth = MaxObjectWidth,
MaxObjectHeight = MaxObjectHeight,
SafetyMargin = SafetyMargin,
RailMountMode = RailMountMode,
RailPathDefinitionMode = RailPathDefinitionMode
};
// 克隆所有路径点
foreach (var point in Points)
{
var clonedPoint = new PathPoint(point.Position, point.Name, point.Type)
{
Id = Guid.NewGuid().ToString(),
Index = point.Index,
CreatedTime = point.CreatedTime,
Notes = point.Notes
};
clonedRoute.Points.Add(clonedPoint);
}
return clonedRoute;
}
///
/// 返回路径描述字符串
///
///
public override string ToString()
{
return $"{Name} - 点数:{Points.Count}, 长度:{TotalLength:F2}m, 预估时间:{EstimatedTime:F1}s";
}
}
///
/// 2D地图坐标
///
[Serializable]
public class MapPoint2D
{
///
/// X坐标
///
public double X { get; set; }
///
/// Y坐标
///
public double Y { get; set; }
///
/// 构造函数
///
public MapPoint2D()
{
X = 0.0;
Y = 0.0;
}
///
/// 带参数构造函数
///
/// X坐标
/// Y坐标
public MapPoint2D(double x, double y)
{
X = x;
Y = y;
}
///
/// 返回坐标描述字符串
///
///
public override string ToString()
{
return $"({X:F2}, {Y:F2})";
}
}
///
/// 通道边界信息
///
[Serializable]
public class ChannelBounds
{
///
/// 最小坐标点
///
public Point3D MinPoint { get; set; }
///
/// 最大坐标点
///
public Point3D MaxPoint { get; set; }
///
/// 中心点
///
public Point3D Center { get; set; }
///
/// 通道高度(Z轴方向)
///
public double Height { get; set; }
///
/// 构造函数
///
public ChannelBounds()
{
MinPoint = new Point3D();
MaxPoint = new Point3D();
Center = new Point3D();
Height = 0.0;
}
///
/// 带包围盒参数构造函数
///
/// Navisworks包围盒
public ChannelBounds(BoundingBox3D boundingBox)
{
MinPoint = boundingBox.Min;
MaxPoint = boundingBox.Max;
Center = new Point3D(
(MinPoint.X + MaxPoint.X) / 2,
(MinPoint.Y + MaxPoint.Y) / 2,
(MinPoint.Z + MaxPoint.Z) / 2
);
Height = MaxPoint.Z - MinPoint.Z;
}
///
/// 获取2D投影范围
///
/// 最小点
/// 最大点
public void Get2DProjection(out MapPoint2D min, out MapPoint2D max)
{
min = new MapPoint2D(MinPoint.X, MinPoint.Y);
max = new MapPoint2D(MaxPoint.X, MaxPoint.Y);
}
}
///
/// 通道选择结果
///
public class ChannelSelectionResult
{
///
/// 是否成功
///
public bool Success { get; set; } = false;
///
/// 结果消息
///
public string Message { get; set; } = "";
///
/// 总模型项数量
///
public int TotalModelItems { get; set; } = 0;
///
/// 自动检测的通道
///
public ModelItemCollection AutoDetectedChannels { get; set; } = new ModelItemCollection();
///
/// 已标记物流属性的模型项
///
public ModelItemCollection LogisticsMarkedItems { get; set; } = new ModelItemCollection();
///
/// 可通行区域
///
public ModelItemCollection TraversableAreas { get; set; } = new ModelItemCollection();
///
/// 通道类型模型项
///
public ModelItemCollection ChannelItems { get; set; } = new ModelItemCollection();
}
///
/// 通道选择对话框结果
///
public class ChannelSelectionDialogResult
{
///
/// 是否成功
///
public bool Success { get; set; } = false;
///
/// 结果消息
///
public string Message { get; set; } = "";
///
/// 选中的通道
///
public ModelItemCollection SelectedChannels { get; set; } = new ModelItemCollection();
///
/// 选择方法
///
public ChannelSelectionMethod SelectionMethod { get; set; } = ChannelSelectionMethod.Manual;
///
/// 高度限制(米)
///
public double HeightLimit { get; set; } = 3.0;
}
///
/// 通道选择方法枚举
///
public enum ChannelSelectionMethod
{
///
/// 手动选择
///
Manual,
///
/// 自动检测
///
AutoDetect,
///
/// 基于物流属性
///
LogisticsAttribute,
///
/// 可通行区域
///
TraversableAreas,
///
/// 通道类型
///
ChannelType
}
///
/// 通道选择对话框
///
public class ChannelSelectionDialog : System.Windows.Forms.Form
{
private ChannelSelectionResult _analysisResult;
private ModelItemCollection _selectedChannels;
private ChannelSelectionMethod _selectionMethod;
private double _heightLimit;
private const string ChannelPreviewHighlightCategory = "channel_preview";
///
/// 选中的通道
///
public ModelItemCollection SelectedChannels { get { return _selectedChannels; } }
///
/// 选择方法
///
public ChannelSelectionMethod SelectionMethod { get { return _selectionMethod; } }
///
/// 高度限制(米)
///
public double HeightLimit { get { return _heightLimit; } }
///
/// 构造函数
///
/// 通道分析结果
public ChannelSelectionDialog(ChannelSelectionResult analysisResult)
{
_analysisResult = analysisResult ?? new ChannelSelectionResult();
_selectedChannels = new ModelItemCollection();
_selectionMethod = ChannelSelectionMethod.Manual;
_heightLimit = 3.0;
InitializeComponent();
LoadAnalysisData();
}
// UI控件
private System.Windows.Forms.TabControl tabControl;
private System.Windows.Forms.ListView channelListView;
private System.Windows.Forms.Label statisticsLabel;
private System.Windows.Forms.NumericUpDown heightLimitNumericUpDown;
private System.Windows.Forms.Button previewButton;
private System.Windows.Forms.Button clearHighlightButton;
private System.Windows.Forms.CheckBox selectAllCheckBox;
///
/// 初始化对话框组件
///
private void InitializeComponent()
{
this.Text = "通道选择";
this.Size = new System.Drawing.Size(700, 500);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
// 创建选项卡控件
tabControl = new System.Windows.Forms.TabControl
{
Location = new System.Drawing.Point(10, 10),
Size = new System.Drawing.Size(670, 350),
Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left |
System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Bottom
};
// 创建通道列表选项卡
var channelListTab = new System.Windows.Forms.TabPage("通道列表");
CreateChannelListTab(channelListTab);
tabControl.TabPages.Add(channelListTab);
// 创建筛选选项卡
var filterTab = new System.Windows.Forms.TabPage("筛选选项");
CreateFilterTab(filterTab);
tabControl.TabPages.Add(filterTab);
this.Controls.Add(tabControl);
// 统计信息标签
statisticsLabel = new System.Windows.Forms.Label
{
Location = new System.Drawing.Point(10, 370),
Size = new System.Drawing.Size(400, 60),
Text = "正在加载通道信息...",
Font = new System.Drawing.Font("微软雅黑", 8),
Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left
};
this.Controls.Add(statisticsLabel);
// 预览按钮
previewButton = new System.Windows.Forms.Button
{
Text = "预览选中",
Size = new System.Drawing.Size(80, 25),
Location = new System.Drawing.Point(420, 370),
Font = new System.Drawing.Font("微软雅黑", 8),
Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left
};
previewButton.Click += PreviewButton_Click;
this.Controls.Add(previewButton);
// 清除高亮按钮
clearHighlightButton = new System.Windows.Forms.Button
{
Text = "清除高亮",
Size = new System.Drawing.Size(80, 25),
Location = new System.Drawing.Point(510, 370),
Font = new System.Drawing.Font("微软雅黑", 8),
Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left
};
clearHighlightButton.Click += ClearHighlightButton_Click;
this.Controls.Add(clearHighlightButton);
// 确定按钮
var okButton = new System.Windows.Forms.Button
{
Text = "确定",
Size = new System.Drawing.Size(75, 30),
Location = new System.Drawing.Point(520, 440),
Font = new System.Drawing.Font("微软雅黑", 8),
DialogResult = System.Windows.Forms.DialogResult.OK,
Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right
};
okButton.Click += OkButton_Click;
this.Controls.Add(okButton);
// 取消按钮
var cancelButton = new System.Windows.Forms.Button
{
Text = "取消",
Size = new System.Drawing.Size(75, 30),
Location = new System.Drawing.Point(605, 440),
Font = new System.Drawing.Font("微软雅黑", 8),
DialogResult = System.Windows.Forms.DialogResult.Cancel,
Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right
};
this.Controls.Add(cancelButton);
}
///
/// 创建通道列表选项卡
///
private void CreateChannelListTab(System.Windows.Forms.TabPage tabPage)
{
// 全选复选框
selectAllCheckBox = new System.Windows.Forms.CheckBox
{
Text = "全选",
Location = new System.Drawing.Point(10, 10),
Size = new System.Drawing.Size(60, 20),
Font = new System.Drawing.Font("微软雅黑", 8)
};
selectAllCheckBox.CheckedChanged += SelectAllCheckBox_CheckedChanged;
tabPage.Controls.Add(selectAllCheckBox);
// 通道列表
channelListView = new System.Windows.Forms.ListView
{
Location = new System.Drawing.Point(10, 35),
Size = new System.Drawing.Size(640, 280),
View = System.Windows.Forms.View.Details,
FullRowSelect = true,
GridLines = true,
CheckBoxes = true,
Font = new System.Drawing.Font("微软雅黑", 8),
Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left |
System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Bottom
};
// 添加列
channelListView.Columns.Add("名称", 200);
channelListView.Columns.Add("类型", 80);
channelListView.Columns.Add("可通行", 60);
channelListView.Columns.Add("物体尺寸", 80);
channelListView.Columns.Add("长度(m)", 80);
channelListView.Columns.Add("宽度(m)", 80);
channelListView.Columns.Add("高度(m)", 80);
channelListView.ItemChecked += ChannelListView_ItemChecked;
tabPage.Controls.Add(channelListView);
}
///
/// 创建筛选选项卡
///
private void CreateFilterTab(System.Windows.Forms.TabPage tabPage)
{
// 高度限制选择
var heightLimitLabel = new System.Windows.Forms.Label
{
Text = "高度限制(m):",
Location = new System.Drawing.Point(10, 20),
Size = new System.Drawing.Size(80, 20),
Font = new System.Drawing.Font("微软雅黑", 8)
};
tabPage.Controls.Add(heightLimitLabel);
heightLimitNumericUpDown = new System.Windows.Forms.NumericUpDown
{
Location = new System.Drawing.Point(100, 18),
Size = new System.Drawing.Size(120, 25),
Font = new System.Drawing.Font("微软雅黑", 8),
Minimum = 1.0m,
Maximum = 20.0m,
DecimalPlaces = 1,
Value = 3.0m
};
heightLimitNumericUpDown.ValueChanged += HeightLimitNumericUpDown_ValueChanged;
tabPage.Controls.Add(heightLimitNumericUpDown);
// 筛选方式选择
var filterMethodLabel = new System.Windows.Forms.Label
{
Text = "筛选方式:",
Location = new System.Drawing.Point(10, 60),
Size = new System.Drawing.Size(200, 20),
Font = new System.Drawing.Font("微软雅黑", 8)
};
tabPage.Controls.Add(filterMethodLabel);
var filterOptions = new System.Windows.Forms.RadioButton[]
{
new System.Windows.Forms.RadioButton { Text = "显示所有检测到的通道", Location = new System.Drawing.Point(20, 85), Size = new System.Drawing.Size(200, 20), Checked = true },
new System.Windows.Forms.RadioButton { Text = "仅显示已标记物流属性的通道", Location = new System.Drawing.Point(20, 110), Size = new System.Drawing.Size(200, 20) },
new System.Windows.Forms.RadioButton { Text = "仅显示可通行区域", Location = new System.Drawing.Point(20, 135), Size = new System.Drawing.Size(200, 20) },
new System.Windows.Forms.RadioButton { Text = "自动检测通道", Location = new System.Drawing.Point(20, 160), Size = new System.Drawing.Size(200, 20) }
};
foreach (var option in filterOptions)
{
option.Font = new System.Drawing.Font("微软雅黑", 8);
option.CheckedChanged += FilterOption_CheckedChanged;
tabPage.Controls.Add(option);
}
// 应用筛选按钮
var applyFilterButton = new System.Windows.Forms.Button
{
Text = "应用筛选",
Location = new System.Drawing.Point(20, 200),
Size = new System.Drawing.Size(100, 30),
Font = new System.Drawing.Font("微软雅黑", 8)
};
applyFilterButton.Click += ApplyFilterButton_Click;
tabPage.Controls.Add(applyFilterButton);
}
///
/// 加载分析数据
///
private void LoadAnalysisData()
{
try
{
if (channelListView == null) return;
channelListView.Items.Clear();
// 根据分析结果填充通道列表
var channelsToShow = _analysisResult.ChannelItems.Count > 0
? _analysisResult.ChannelItems
: _analysisResult.AutoDetectedChannels;
foreach (ModelItem channel in channelsToShow)
{
var item = new System.Windows.Forms.ListViewItem(channel.DisplayName ?? "未命名通道");
item.Tag = channel;
// 获取通道属性信息
string channelType = "通道";
string traversable = "是";
string objectSize = "标准";
try
{
if (CategoryAttributeManager.HasLogisticsAttributes(channel))
{
// 这里可以添加更详细的属性读取逻辑
}
}
catch (Exception ex)
{
LogManager.Debug($"[通道列表] 获取物流属性失败: {ex.Message}");
}
// 获取尺寸信息
double length = 0, width = 0, height = 0;
try
{
var boundingBox = channel.BoundingBox();
if (boundingBox != null)
{
length = Math.Abs(boundingBox.Max.X - boundingBox.Min.X);
width = Math.Abs(boundingBox.Max.Y - boundingBox.Min.Y);
height = Math.Abs(boundingBox.Max.Z - boundingBox.Min.Z);
}
}
catch (Exception ex)
{
LogManager.Debug($"[通道列表] 获取包围盒失败: {ex.Message}");
}
// 添加子项
item.SubItems.Add(channelType);
item.SubItems.Add(traversable);
item.SubItems.Add(objectSize);
item.SubItems.Add(length.ToString("F2"));
item.SubItems.Add(width.ToString("F2"));
item.SubItems.Add(height.ToString("F2"));
channelListView.Items.Add(item);
}
// 更新统计信息
UpdateStatistics();
// 默认选择所有通道
if (_analysisResult.Success && channelsToShow.Count > 0)
{
_selectedChannels = new ModelItemCollection();
foreach (ModelItem channel in channelsToShow)
{
_selectedChannels.Add(channel);
}
}
}
catch (Exception ex)
{
if (statisticsLabel != null)
{
statisticsLabel.Text = $"加载通道数据失败: {ex.Message}";
}
}
}
///
/// 更新统计信息
///
private void UpdateStatistics()
{
if (statisticsLabel == null) return;
var totalChannels = channelListView.Items.Count;
var selectedChannels = channelListView.CheckedItems.Count;
var logisticsMarked = _analysisResult.LogisticsMarkedItems.Count;
var autoDetected = _analysisResult.AutoDetectedChannels.Count;
statisticsLabel.Text = $"统计信息:\n" +
$"总通道数: {totalChannels} 已选择: {selectedChannels}\n" +
$"已标记物流属性: {logisticsMarked} 自动检测: {autoDetected}";
}
#region 事件处理方法
///
/// 预览按钮点击事件
///
private void PreviewButton_Click(object sender, EventArgs e)
{
try
{
var selectedItems = new ModelItemCollection();
foreach (System.Windows.Forms.ListViewItem item in channelListView.CheckedItems)
{
if (item.Tag is ModelItem channel)
{
selectedItems.Add(channel);
}
}
if (selectedItems.Count > 0)
{
// 高亮显示选中的通道
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show($"预览失败: {ex.Message}", "错误",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
///
/// 清除高亮按钮点击事件
///
private void ClearHighlightButton_Click(object sender, EventArgs e)
{
try
{
ModelHighlightHelper.ClearCategory(ChannelPreviewHighlightCategory);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show($"清除高亮失败: {ex.Message}", "错误",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
///
/// 确定按钮点击事件
///
private void OkButton_Click(object sender, EventArgs e)
{
try
{
_selectedChannels.Clear();
foreach (System.Windows.Forms.ListViewItem item in channelListView.CheckedItems)
{
if (item.Tag is ModelItem channel)
{
_selectedChannels.Add(channel);
}
}
_heightLimit = (double)(heightLimitNumericUpDown?.Value ?? 3.0m);
_selectionMethod = ChannelSelectionMethod.Manual; // 可以根据选项卡或筛选方式设置
// 清除高亮
try
{
ModelHighlightHelper.ClearCategory(ChannelPreviewHighlightCategory);
}
catch (Exception ex)
{
LogManager.Debug($"[通道预览] 清除高亮失败: {ex.Message}");
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show($"确认选择失败: {ex.Message}", "错误",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
///
/// 全选复选框状态改变事件
///
private void SelectAllCheckBox_CheckedChanged(object sender, EventArgs e)
{
try
{
bool isChecked = selectAllCheckBox.Checked;
foreach (System.Windows.Forms.ListViewItem item in channelListView.Items)
{
item.Checked = isChecked;
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show($"全选操作失败: {ex.Message}", "错误",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
///
/// 通道列表项选中状态改变事件
///
private void ChannelListView_ItemChecked(object sender, System.Windows.Forms.ItemCheckedEventArgs e)
{
UpdateStatistics();
}
///
/// 高度限制数值改变事件
///
private void HeightLimitNumericUpDown_ValueChanged(object sender, EventArgs e)
{
_heightLimit = (double)heightLimitNumericUpDown.Value;
}
///
/// 筛选选项改变事件
///
private void FilterOption_CheckedChanged(object sender, EventArgs e)
{
// 可以根据需要实现筛选逻辑
}
///
/// 应用筛选按钮点击事件
///
private void ApplyFilterButton_Click(object sender, EventArgs e)
{
try
{
// 重新加载数据应用筛选
LoadAnalysisData();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show($"应用筛选失败: {ex.Message}", "错误",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
}
}
#endregion
}
#region 路径验证与优化相关数据结构
///
/// 路径验证结果
///
public class PathValidationResult
{
///
/// 路径ID
///
public string RouteId { get; set; } = "";
///
/// 路径名称
///
public string RouteName { get; set; } = "";
///
/// 验证是否通过
///
public bool IsValid { get; set; } = false;
///
/// 验证消息
///
public string Message { get; set; } = "";
///
/// 错误列表
///
public List Errors { get; set; } = new List();
///
/// 警告列表
///
public List Warnings { get; set; } = new List();
///
/// 验证时间
///
public DateTime ValidationTime { get; set; } = DateTime.Now;
///
/// 添加错误信息
///
/// 错误信息
public void AddError(string error)
{
if (!string.IsNullOrEmpty(error) && !Errors.Contains(error))
{
Errors.Add(error);
}
}
///
/// 添加警告信息
///
/// 警告信息
public void AddWarning(string warning)
{
if (!string.IsNullOrEmpty(warning) && !Warnings.Contains(warning))
{
Warnings.Add(warning);
}
}
///
/// 获取详细验证报告
///
/// 验证报告文本
public string GetDetailedReport()
{
var report = new StringBuilder();
report.AppendLine($"路径验证报告 - {RouteName} ({RouteId})");
report.AppendLine($"验证时间: {ValidationTime:yyyy-MM-dd HH:mm:ss}");
report.AppendLine($"验证结果: {(IsValid ? "通过" : "失败")}");
report.AppendLine($"消息: {Message}");
if (Errors.Count > 0)
{
report.AppendLine("\n错误列表:");
for (int i = 0; i < Errors.Count; i++)
{
report.AppendLine($" {i + 1}. {Errors[i]}");
}
}
if (Warnings.Count > 0)
{
report.AppendLine("\n警告列表:");
for (int i = 0; i < Warnings.Count; i++)
{
report.AppendLine($" {i + 1}. {Warnings[i]}");
}
}
return report.ToString();
}
}
///
/// 路径优化选项
///
public class PathOptimizationOptions
{
///
/// 移除重复点
///
public bool RemoveDuplicatePoints { get; set; } = true;
///
/// 路径平滑化
///
public bool SmoothPath { get; set; } = true;
///
/// 优化路径角度
///
public bool OptimizeAngles { get; set; } = true;
///
/// 调整到通道中心
///
public bool AdjustToChannels { get; set; } = false;
///
/// 重复点检测阈值(米)
///
public double DuplicatePointThreshold { get; set; } = 0.01;
///
/// 角度优化容差(弧度)
///
public double AngleOptimizationTolerance { get; set; } = 0.1;
///
/// 平滑强度(0-1)
///
public double SmoothingStrength { get; set; } = 0.5;
///
/// 创建默认优化选项
///
/// 默认优化选项
public static PathOptimizationOptions CreateDefault()
{
return new PathOptimizationOptions
{
RemoveDuplicatePoints = true,
SmoothPath = true,
OptimizeAngles = true,
AdjustToChannels = false,
DuplicatePointThreshold = 0.01,
AngleOptimizationTolerance = 0.1,
SmoothingStrength = 0.5
};
}
///
/// 创建保守优化选项(仅基础优化)
///
/// 保守优化选项
public static PathOptimizationOptions CreateConservative()
{
return new PathOptimizationOptions
{
RemoveDuplicatePoints = true,
SmoothPath = false,
OptimizeAngles = false,
AdjustToChannels = false,
DuplicatePointThreshold = 0.001
};
}
///
/// 创建激进优化选项(所有优化)
///
/// 激进优化选项
public static PathOptimizationOptions CreateAggressive()
{
return new PathOptimizationOptions
{
RemoveDuplicatePoints = true,
SmoothPath = true,
OptimizeAngles = true,
AdjustToChannels = true,
DuplicatePointThreshold = 0.05,
AngleOptimizationTolerance = 0.2,
SmoothingStrength = 0.8
};
}
}
///
/// 路径优化结果
///
public class PathOptimizationResult
{
///
/// 优化是否成功
///
public bool Success { get; set; } = false;
///
/// 优化消息
///
public string Message { get; set; } = "";
///
/// 原始路径
///
public PathRoute OriginalRoute { get; set; }
///
/// 优化后的路径
///
public PathRoute OptimizedRoute { get; set; }
///
/// 原始路径长度
///
public double OriginalLength { get; set; } = 0.0;
///
/// 优化后路径长度
///
public double OptimizedLength { get; set; } = 0.0;
///
/// 长度减少量
///
public double LengthReduction { get; set; } = 0.0;
///
/// 长度减少百分比
///
public double LengthReductionPercentage => OriginalLength > 0 ? (LengthReduction / OriginalLength) * 100 : 0;
///
/// 原始点数
///
public int OriginalPointCount { get; set; } = 0;
///
/// 优化后点数
///
public int OptimizedPointCount { get; set; } = 0;
///
/// 点数减少量
///
public int PointReduction { get; set; } = 0;
///
/// 点数减少百分比
///
public double PointReductionPercentage => OriginalPointCount > 0 ? ((double)PointReduction / OriginalPointCount) * 100 : 0;
///
/// 优化步骤记录
///
public List OptimizationSteps { get; set; } = new List();
///
/// 优化时间
///
public DateTime OptimizationTime { get; set; } = DateTime.Now;
///
/// 优化耗时(毫秒)
///
public long ElapsedMilliseconds { get; set; } = 0;
///
/// 添加优化步骤记录
///
/// 优化步骤描述
public void AddOptimizationStep(string step)
{
if (!string.IsNullOrEmpty(step))
{
OptimizationSteps.Add($"[{DateTime.Now:HH:mm:ss}] {step}");
}
}
///
/// 获取详细优化报告
///
/// 优化报告文本
public string GetDetailedReport()
{
var report = new StringBuilder();
report.AppendLine($"路径优化报告");
report.AppendLine($"优化时间: {OptimizationTime:yyyy-MM-dd HH:mm:ss}");
report.AppendLine($"耗时: {ElapsedMilliseconds} 毫秒");
report.AppendLine($"优化结果: {(Success ? "成功" : "失败")}");
report.AppendLine($"消息: {Message}");
if (Success)
{
report.AppendLine($"\n原始路径:");
report.AppendLine($" 长度: {OriginalLength:F3} 米");
report.AppendLine($" 点数: {OriginalPointCount}");
report.AppendLine($"\n优化后路径:");
report.AppendLine($" 长度: {OptimizedLength:F3} 米");
report.AppendLine($" 点数: {OptimizedPointCount}");
report.AppendLine($"\n优化效果:");
report.AppendLine($" 长度减少: {LengthReduction:F3} 米 ({LengthReductionPercentage:F1}%)");
report.AppendLine($" 点数减少: {PointReduction} 个 ({PointReductionPercentage:F1}%)");
}
if (OptimizationSteps.Count > 0)
{
report.AppendLine("\n优化步骤:");
for (int i = 0; i < OptimizationSteps.Count; i++)
{
report.AppendLine($" {i + 1}. {OptimizationSteps[i]}");
}
}
return report.ToString();
}
///
/// 获取优化摘要
///
/// 优化摘要文本
public string GetSummary()
{
if (!Success)
{
return $"优化失败: {Message}";
}
return $"优化成功: 长度减少 {LengthReduction:F3}m ({LengthReductionPercentage:F1}%), " +
$"点数减少 {PointReduction} 个 ({PointReductionPercentage:F1}%), " +
$"共执行 {OptimizationSteps.Count} 个优化步骤";
}
}
#endregion
///
/// 路径点标记类型
///
public enum PathPointMarkerType
{
///
/// 文本标注
///
TextLabel
}
///
/// 路径点3D标记信息
///
public class PathPointMarker
{
///
/// 关联的路径点
///
public PathPoint PathPoint { get; set; }
///
/// 标记类型
///
public PathPointMarkerType MarkerType { get; set; }
///
/// 标注文本
///
public string LabelText { get; set; }
///
/// 标注位置
///
public Point3D LabelPosition { get; set; }
///
/// 创建时间
///
public DateTime CreatedTime { get; set; } = DateTime.Now;
}
///
/// 路径历史记录项
///
[Serializable]
public class PathHistoryEntry
{
///
/// 历史记录唯一标识符
///
public string Id { get; set; }
///
/// 关联的路径ID
///
public string RouteId { get; set; }
///
/// 操作类型
///
public PathHistoryOperationType OperationType { get; set; }
///
/// 路径快照(操作前的状态)
///
public PathRoute RouteSnapshot { get; set; }
///
/// 操作时间
///
public DateTime OperationTime { get; set; }
///
/// 操作描述
///
public string Description { get; set; }
///
/// 版本号
///
public int Version { get; set; }
public PathHistoryEntry()
{
Id = Guid.NewGuid().ToString();
OperationTime = DateTime.Now;
Description = string.Empty;
Version = 1;
}
public PathHistoryEntry(string routeId, PathHistoryOperationType operationType, PathRoute routeSnapshot, string description = "")
{
Id = Guid.NewGuid().ToString();
RouteId = routeId;
OperationType = operationType;
RouteSnapshot = routeSnapshot?.Clone(); // 创建副本
OperationTime = DateTime.Now;
Description = description;
Version = 1;
}
}
///
/// 路径历史操作类型
///
public enum PathHistoryOperationType
{
///
/// 创建路径
///
Created,
///
/// 编辑路径
///
Edited,
///
/// 删除路径点
///
PointRemoved,
///
/// 添加路径点
///
PointAdded,
///
/// 路径优化
///
Optimized,
///
/// 手动保存
///
ManualSave
}
///
/// 路径历史管理器
///
public class PathHistoryManager
{
private Dictionary> _routeHistories;
private int _maxHistoryCount;
///
/// 历史记录变更事件
///
public event EventHandler HistoryEntryAdded;
public PathHistoryManager(int maxHistoryCount = 50)
{
_routeHistories = new Dictionary>();
_maxHistoryCount = maxHistoryCount;
}
///
/// 保存路径到历史记录
///
public void SaveToHistory(PathRoute route)
{
if (route != null)
{
var entry = new PathHistoryEntry(route.Id, PathHistoryOperationType.ManualSave, route, "手动保存");
AddHistoryEntry(entry);
}
}
///
/// 添加历史记录
///
public void AddHistoryEntry(PathHistoryEntry entry)
{
if (string.IsNullOrEmpty(entry.RouteId)) return;
if (!_routeHistories.ContainsKey(entry.RouteId))
{
_routeHistories[entry.RouteId] = new List();
}
var histories = _routeHistories[entry.RouteId];
// 设置版本号
entry.Version = histories.Count + 1;
histories.Add(entry);
// 限制历史记录数量
if (histories.Count > _maxHistoryCount)
{
histories.RemoveAt(0);
// 重新计算版本号
for (int i = 0; i < histories.Count; i++)
{
histories[i].Version = i + 1;
}
}
HistoryEntryAdded?.Invoke(this, entry);
}
///
/// 获取路径的历史记录
///
public List GetRouteHistory(string routeId)
{
return _routeHistories.ContainsKey(routeId) ?
new List(_routeHistories[routeId]) :
new List();
}
///
/// 获取最新的历史记录
///
public PathHistoryEntry GetLatestHistory(string routeId)
{
var histories = GetRouteHistory(routeId);
return histories.LastOrDefault();
}
///
/// 清理路径的历史记录
///
public void ClearRouteHistory(string routeId)
{
if (_routeHistories.ContainsKey(routeId))
{
_routeHistories.Remove(routeId);
}
}
///
/// 获取所有路径的历史记录统计
///
public Dictionary GetHistoryStatistics()
{
return _routeHistories.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Count
);
}
///
/// 获取所有历史记录
///
/// 所有历史记录的列表,按时间倒序排列
public List GetAllHistoryEntries()
{
var allEntries = new List();
foreach (var routeHistory in _routeHistories.Values)
{
allEntries.AddRange(routeHistory);
}
// 按操作时间倒序排列(最新的在前)
return allEntries.OrderByDescending(entry => entry.OperationTime).ToList();
}
}
///
/// 路径文件序列化帮助类
///
public static class PathFileSerializer
{
///
/// 将路径保存为XML文件
///
public static bool SaveToXml(PathRoute route, string filePath)
{
try
{
var serializer = new XmlSerializer(typeof(PathRoute));
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
serializer.Serialize(writer, route);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"保存XML文件失败: {ex.Message}");
return false;
}
}
///
/// 从XML文件加载路径
///
public static PathRoute LoadFromXml(string filePath)
{
try
{
var serializer = new XmlSerializer(typeof(PathRoute));
using (var reader = new StreamReader(filePath, Encoding.UTF8))
{
return (PathRoute)serializer.Deserialize(reader);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"加载XML文件失败: {ex.Message}");
return null;
}
}
///
/// 将路径保存为JSON文件(简化版)
///
public static bool SaveToJson(PathRoute route, string filePath)
{
try
{
// 使用简单的字符串格式化代替JSON序列化
var json = new StringBuilder();
json.AppendLine("{");
json.AppendLine($" \"Id\": \"{route.Id}\",");
json.AppendLine($" \"Name\": \"{route.Name}\",");
json.AppendLine($" \"Description\": \"{route.Description}\",");
json.AppendLine($" \"CreatedTime\": \"{route.CreatedTime:yyyy-MM-dd HH:mm:ss}\",");
json.AppendLine($" \"TotalLength\": {route.TotalLength},");
json.AppendLine($" \"EstimatedTime\": {route.EstimatedTime},");
json.AppendLine(" \"Points\": [");
for (int i = 0; i < route.Points.Count; i++)
{
var point = route.Points[i];
json.AppendLine(" {");
json.AppendLine($" \"Id\": \"{point.Id}\",");
json.AppendLine($" \"Name\": \"{point.Name}\",");
json.AppendLine($" \"Type\": \"{point.Type}\",");
json.AppendLine($" \"Position\": {{\"X\": {point.Position.X}, \"Y\": {point.Position.Y}, \"Z\": {point.Position.Z}}},");
json.AppendLine($" \"CreatedTime\": \"{point.CreatedTime:yyyy-MM-dd HH:mm:ss}\",");
json.AppendLine($" \"Index\": {point.Index},");
json.AppendLine($" \"Notes\": \"{point.Notes}\"");
json.AppendLine(i < route.Points.Count - 1 ? " }," : " }");
}
json.AppendLine(" ]");
json.AppendLine("}");
File.WriteAllText(filePath, json.ToString(), Encoding.UTF8);
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"保存JSON文件失败: {ex.Message}");
return false;
}
}
///
/// 从JSON文件加载路径(简化版,仅支持基本格式)
///
public static PathRoute LoadFromJson(string filePath)
{
try
{
// 简化实现:仅支持基本的JSON格式
// 由于不依赖外部JSON库,这里使用XML格式作为fallback
System.Diagnostics.Debug.WriteLine("JSON加载功能简化,建议使用XML格式");
return null;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"加载JSON文件失败: {ex.Message}");
return null;
}
}
///
/// 将多个路径保存为XML文件
///
public static bool SaveRoutesToXml(List routes, string filePath)
{
try
{
var container = new PathRouteContainer { Routes = routes };
var serializer = new XmlSerializer(typeof(PathRouteContainer));
using (var writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
serializer.Serialize(writer, container);
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"保存多路径XML文件失败: {ex.Message}");
return false;
}
}
///
/// 从XML文件加载多个路径
///
public static List LoadRoutesFromXml(string filePath)
{
try
{
var serializer = new XmlSerializer(typeof(PathRouteContainer));
using (var reader = new StreamReader(filePath, Encoding.UTF8))
{
var container = (PathRouteContainer)serializer.Deserialize(reader);
return container?.Routes ?? new List();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"加载多路径XML文件失败: {ex.Message}");
return new List();
}
}
///
/// 检测文件格式
///
public static string DetectFileFormat(string filePath)
{
var extension = Path.GetExtension(filePath).ToLowerInvariant();
switch (extension)
{
case ".xml":
return "XML";
case ".json":
return "JSON";
default:
// 尝试检测内容
try
{
var content = File.ReadAllText(filePath).Trim();
if (content.StartsWith("<") && content.EndsWith(">"))
return "XML";
if (content.StartsWith("{") && content.EndsWith("}"))
return "JSON";
}
catch (Exception ex)
{
LogManager.Debug($"[路径格式检测] 读取文件失败: {ex.Message}");
}
return "未知";
}
}
}
///
/// 路径容器(用于保存多个路径)
///
[Serializable]
public class PathRouteContainer
{
public List Routes { get; set; } = new List();
public DateTime CreatedTime { get; set; } = DateTime.Now;
public string Version { get; set; } = "1.0";
public string Description { get; set; } = "";
}
#region 多层阶梯式吊装路径数据模型
///
/// 吊装路径模式枚举
///
public enum HoistingMode
{
///
/// 单层吊装(传统模式,向后兼容)
///
SingleLevel,
///
/// 多层阶梯式吊装
///
MultiLevel
}
///
/// 吊装层级信息 - 表示多层吊装中的一个水平移动层级
///
[Serializable]
public class HoistingLevel
{
///
/// 层级序号(从0开始)
///
public int Index { get; set; }
///
/// 该层级的高度(相对于起吊点的垂直高度,米)
///
public double HeightInMeters { get; set; }
///
/// 该层级的水平移动目标点(XY位置,Z坐标会被忽略)
///
public Point3D HorizontalTarget { get; set; }
///
/// 运动方向:true=从上一位置上升到此高度,false=从上一位置下降到此高度
///
public bool IsRise { get; set; }
///
/// 层级描述(如"桁车移动层"、"避让层"等)
///
public string Description { get; set; }
///
/// 创建时间
///
public DateTime CreatedTime { get; set; }
///
/// 默认构造函数
///
public HoistingLevel()
{
Index = 0;
HeightInMeters = 0.0;
HorizontalTarget = new Point3D();
IsRise = true;
Description = string.Empty;
CreatedTime = DateTime.Now;
}
///
/// 带参数构造函数
///
/// 层级序号
/// 高度(米)
/// 水平目标点
/// 是否为上升
/// 描述
public HoistingLevel(int index, double heightInMeters, Point3D horizontalTarget, bool isRise = true, string description = "")
{
Index = index;
HeightInMeters = heightInMeters;
HorizontalTarget = horizontalTarget ?? new Point3D();
IsRise = isRise;
Description = description ?? string.Empty;
CreatedTime = DateTime.Now;
}
///
/// 返回层级描述字符串
///
public override string ToString()
{
string direction = IsRise ? "上升" : "下降";
return $"层级{Index + 1}: {direction}到{HeightInMeters:F2}米,目标({HorizontalTarget.X:F2}, {HorizontalTarget.Y:F2}) {(string.IsNullOrEmpty(Description) ? "" : $"- {Description}")}";
}
}
#endregion
}