1977 lines
63 KiB
C#
1977 lines
63 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Xml.Serialization;
|
||
using Autodesk.Navisworks.Api;
|
||
using System.Text;
|
||
using System.Linq;
|
||
using System.IO;
|
||
|
||
namespace NavisworksTransport
|
||
{
|
||
/// <summary>
|
||
/// 路径编辑状态枚举
|
||
/// </summary>
|
||
public enum PathEditState
|
||
{
|
||
/// <summary>
|
||
/// 查看状态 - 只能查看路径,不能编辑
|
||
/// </summary>
|
||
Viewing,
|
||
|
||
/// <summary>
|
||
/// 新建状态 - 正在创建新路径
|
||
/// </summary>
|
||
Creating,
|
||
|
||
/// <summary>
|
||
/// 编辑状态 - 正在编辑现有路径
|
||
/// </summary>
|
||
Editing
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道检测结果
|
||
/// </summary>
|
||
public class ChannelDetectionResult
|
||
{
|
||
/// <summary>
|
||
/// 是否为有效位置
|
||
/// </summary>
|
||
public bool IsValidLocation { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检测消息
|
||
/// </summary>
|
||
public string Message { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检测方法
|
||
/// </summary>
|
||
public string DetectionMethod { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 物流通道检测结果
|
||
/// </summary>
|
||
public class LogisticsChannelDetectionResult
|
||
{
|
||
/// <summary>
|
||
/// 是否为有效通道
|
||
/// </summary>
|
||
public bool IsValidChannel { get; set; }
|
||
|
||
/// <summary>
|
||
/// 通道类型名称
|
||
/// </summary>
|
||
public string ChannelType { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检测到的通道模型项
|
||
/// </summary>
|
||
public ModelItem DetectedChannel { get; set; }
|
||
|
||
/// <summary>
|
||
/// 物流类别
|
||
/// </summary>
|
||
public CategoryAttributeManager.LogisticsElementType? LogisticsCategory { get; set; }
|
||
|
||
/// <summary>
|
||
/// 检测置信度
|
||
/// </summary>
|
||
public double DetectionConfidence { get; set; }
|
||
|
||
/// <summary>
|
||
/// 错误消息
|
||
/// </summary>
|
||
public string ErrorMessage { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 几何分析结果
|
||
/// </summary>
|
||
public class GeometryAnalysisResult
|
||
{
|
||
/// <summary>
|
||
/// 是否可能是通道
|
||
/// </summary>
|
||
public bool IsLikelyChannel { get; set; }
|
||
|
||
/// <summary>
|
||
/// 分析原因
|
||
/// </summary>
|
||
public string Reason { get; set; }
|
||
|
||
/// <summary>
|
||
/// 最可能的通道模型项
|
||
/// </summary>
|
||
public ModelItem MostLikelyChannel { get; set; }
|
||
|
||
/// <summary>
|
||
/// 置信度
|
||
/// </summary>
|
||
public double Confidence { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径点类型枚举
|
||
/// </summary>
|
||
public enum PathPointType
|
||
{
|
||
/// <summary>
|
||
/// 起点
|
||
/// </summary>
|
||
StartPoint,
|
||
|
||
/// <summary>
|
||
/// 终点
|
||
/// </summary>
|
||
EndPoint,
|
||
|
||
/// <summary>
|
||
/// 路径点
|
||
/// </summary>
|
||
WayPoint
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径点数据模型
|
||
/// </summary>
|
||
[Serializable]
|
||
public class PathPoint
|
||
{
|
||
/// <summary>
|
||
/// 路径点唯一标识符
|
||
/// </summary>
|
||
public string Id { get; set; }
|
||
|
||
/// <summary>
|
||
/// 3D位置坐标
|
||
/// </summary>
|
||
public Point3D Position { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径点名称
|
||
/// </summary>
|
||
public string Name { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径点类型
|
||
/// </summary>
|
||
public PathPointType Type { get; set; }
|
||
|
||
/// <summary>
|
||
/// 创建时间
|
||
/// </summary>
|
||
public DateTime CreatedTime { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径点序号
|
||
/// </summary>
|
||
public int Index { get; set; }
|
||
|
||
/// <summary>
|
||
/// 备注信息
|
||
/// </summary>
|
||
public string Notes { get; set; }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public PathPoint()
|
||
{
|
||
Id = Guid.NewGuid().ToString();
|
||
Position = new Point3D();
|
||
Name = string.Empty;
|
||
Type = PathPointType.WayPoint;
|
||
CreatedTime = DateTime.Now;
|
||
Index = 0;
|
||
Notes = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带参数构造函数
|
||
/// </summary>
|
||
/// <param name="position">3D坐标</param>
|
||
/// <param name="name">名称</param>
|
||
/// <param name="type">类型</param>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回路径点描述字符串
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override string ToString()
|
||
{
|
||
return $"{Name} ({Type}) - X:{Position.X:F2}, Y:{Position.Y:F2}, Z:{Position.Z:F2}";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径路线数据模型
|
||
/// </summary>
|
||
[Serializable]
|
||
public class PathRoute
|
||
{
|
||
/// <summary>
|
||
/// 路径点集合
|
||
/// </summary>
|
||
public List<PathPoint> Points { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径名称
|
||
/// </summary>
|
||
public string Name { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径ID
|
||
/// </summary>
|
||
public string Id { get; set; }
|
||
|
||
/// <summary>
|
||
/// 预估时间(秒)
|
||
/// </summary>
|
||
public double EstimatedTime { get; set; }
|
||
|
||
/// <summary>
|
||
/// 关联通道模型ID集合
|
||
/// </summary>
|
||
public List<string> AssociatedChannelIds { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径总长度(米)
|
||
/// </summary>
|
||
public double TotalLength { get; set; }
|
||
|
||
/// <summary>
|
||
/// 创建时间
|
||
/// </summary>
|
||
public DateTime CreatedTime { get; set; }
|
||
|
||
/// <summary>
|
||
/// 最后修改时间
|
||
/// </summary>
|
||
public DateTime LastModified { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径描述
|
||
/// </summary>
|
||
public string Description { get; set; }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public PathRoute()
|
||
{
|
||
Points = new List<PathPoint>();
|
||
Name = string.Empty;
|
||
Id = Guid.NewGuid().ToString();
|
||
EstimatedTime = 0.0;
|
||
AssociatedChannelIds = new List<string>();
|
||
TotalLength = 0.0;
|
||
CreatedTime = DateTime.Now;
|
||
LastModified = DateTime.Now;
|
||
Description = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带参数构造函数
|
||
/// </summary>
|
||
/// <param name="name">路径名称</param>
|
||
public PathRoute(string name)
|
||
{
|
||
Points = new List<PathPoint>();
|
||
Name = name;
|
||
Id = Guid.NewGuid().ToString();
|
||
EstimatedTime = 0.0;
|
||
AssociatedChannelIds = new List<string>();
|
||
TotalLength = 0.0;
|
||
CreatedTime = DateTime.Now;
|
||
LastModified = DateTime.Now;
|
||
Description = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加路径点
|
||
/// </summary>
|
||
/// <param name="point">路径点</param>
|
||
public void AddPoint(PathPoint point)
|
||
{
|
||
point.Index = Points.Count;
|
||
Points.Add(point);
|
||
LastModified = DateTime.Now;
|
||
UpdateTotalLength();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除路径点
|
||
/// </summary>
|
||
/// <param name="point">路径点</param>
|
||
public bool RemovePoint(PathPoint point)
|
||
{
|
||
bool removed = Points.Remove(point);
|
||
if (removed)
|
||
{
|
||
// 重新设置索引
|
||
for (int i = 0; i < Points.Count; i++)
|
||
{
|
||
Points[i].Index = i;
|
||
}
|
||
LastModified = DateTime.Now;
|
||
UpdateTotalLength();
|
||
}
|
||
return removed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据ID移除路径点
|
||
/// </summary>
|
||
/// <param name="pointId">路径点ID</param>
|
||
/// <returns>是否成功移除</returns>
|
||
public bool RemovePoint(string pointId)
|
||
{
|
||
var point = Points.FirstOrDefault(p => p.Id == pointId);
|
||
if (point != null)
|
||
{
|
||
return RemovePoint(point);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空所有路径点
|
||
/// </summary>
|
||
public void ClearPoints()
|
||
{
|
||
Points.Clear();
|
||
LastModified = DateTime.Now;
|
||
UpdateTotalLength();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取起点
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public PathPoint GetStartPoint()
|
||
{
|
||
return Points.Find(p => p.Type == PathPointType.StartPoint);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取终点
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public PathPoint GetEndPoint()
|
||
{
|
||
return Points.Find(p => p.Type == PathPointType.EndPoint);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有路径点(按序号排序)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public List<PathPoint> GetSortedPoints()
|
||
{
|
||
var sortedPoints = new List<PathPoint>(Points);
|
||
sortedPoints.Sort((p1, p2) => p1.Index.CompareTo(p2.Index));
|
||
return sortedPoints;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重新计算路径长度
|
||
/// </summary>
|
||
public void RecalculateLength()
|
||
{
|
||
UpdateTotalLength();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新路径总长度
|
||
/// </summary>
|
||
private void UpdateTotalLength()
|
||
{
|
||
TotalLength = 0.0;
|
||
var sortedPoints = GetSortedPoints();
|
||
|
||
for (int i = 0; i < sortedPoints.Count - 1; i++)
|
||
{
|
||
var point1 = sortedPoints[i].Position;
|
||
var point2 = sortedPoints[i + 1].Position;
|
||
|
||
// 计算两点间距离
|
||
double dx = point2.X - point1.X;
|
||
double dy = point2.Y - point1.Y;
|
||
double dz = point2.Z - point1.Z;
|
||
double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||
|
||
TotalLength += distance;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证路径有效性
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 克隆路径
|
||
/// </summary>
|
||
/// <returns>克隆的路径对象</returns>
|
||
public PathRoute Clone()
|
||
{
|
||
var clonedRoute = new PathRoute(Name + "_Copy")
|
||
{
|
||
Id = Guid.NewGuid().ToString(),
|
||
EstimatedTime = EstimatedTime,
|
||
TotalLength = TotalLength,
|
||
CreatedTime = CreatedTime,
|
||
LastModified = DateTime.Now,
|
||
Description = Description,
|
||
AssociatedChannelIds = new List<string>(AssociatedChannelIds)
|
||
};
|
||
|
||
// 克隆所有路径点
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回路径描述字符串
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override string ToString()
|
||
{
|
||
return $"{Name} - 点数:{Points.Count}, 长度:{TotalLength:F2}m, 预估时间:{EstimatedTime:F1}s";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 2D地图坐标
|
||
/// </summary>
|
||
[Serializable]
|
||
public class MapPoint2D
|
||
{
|
||
/// <summary>
|
||
/// X坐标
|
||
/// </summary>
|
||
public double X { get; set; }
|
||
|
||
/// <summary>
|
||
/// Y坐标
|
||
/// </summary>
|
||
public double Y { get; set; }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public MapPoint2D()
|
||
{
|
||
X = 0.0;
|
||
Y = 0.0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带参数构造函数
|
||
/// </summary>
|
||
/// <param name="x">X坐标</param>
|
||
/// <param name="y">Y坐标</param>
|
||
public MapPoint2D(double x, double y)
|
||
{
|
||
X = x;
|
||
Y = y;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回坐标描述字符串
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override string ToString()
|
||
{
|
||
return $"({X:F2}, {Y:F2})";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道边界信息
|
||
/// </summary>
|
||
[Serializable]
|
||
public class ChannelBounds
|
||
{
|
||
/// <summary>
|
||
/// 最小坐标点
|
||
/// </summary>
|
||
public Point3D MinPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 最大坐标点
|
||
/// </summary>
|
||
public Point3D MaxPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 中心点
|
||
/// </summary>
|
||
public Point3D Center { get; set; }
|
||
|
||
/// <summary>
|
||
/// 通道高度(Z轴方向)
|
||
/// </summary>
|
||
public double Height { get; set; }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public ChannelBounds()
|
||
{
|
||
MinPoint = new Point3D();
|
||
MaxPoint = new Point3D();
|
||
Center = new Point3D();
|
||
Height = 0.0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 带包围盒参数构造函数
|
||
/// </summary>
|
||
/// <param name="boundingBox">Navisworks包围盒</param>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取2D投影范围
|
||
/// </summary>
|
||
/// <param name="min">最小点</param>
|
||
/// <param name="max">最大点</param>
|
||
public void Get2DProjection(out MapPoint2D min, out MapPoint2D max)
|
||
{
|
||
min = new MapPoint2D(MinPoint.X, MinPoint.Y);
|
||
max = new MapPoint2D(MaxPoint.X, MaxPoint.Y);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道选择结果
|
||
/// </summary>
|
||
public class ChannelSelectionResult
|
||
{
|
||
/// <summary>
|
||
/// 是否成功
|
||
/// </summary>
|
||
public bool Success { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 结果消息
|
||
/// </summary>
|
||
public string Message { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 总模型项数量
|
||
/// </summary>
|
||
public int TotalModelItems { get; set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 自动检测的通道
|
||
/// </summary>
|
||
public ModelItemCollection AutoDetectedChannels { get; set; } = new ModelItemCollection();
|
||
|
||
/// <summary>
|
||
/// 已标记物流属性的模型项
|
||
/// </summary>
|
||
public ModelItemCollection LogisticsMarkedItems { get; set; } = new ModelItemCollection();
|
||
|
||
/// <summary>
|
||
/// 可通行区域
|
||
/// </summary>
|
||
public ModelItemCollection TraversableAreas { get; set; } = new ModelItemCollection();
|
||
|
||
/// <summary>
|
||
/// 通道类型模型项
|
||
/// </summary>
|
||
public ModelItemCollection ChannelItems { get; set; } = new ModelItemCollection();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道选择对话框结果
|
||
/// </summary>
|
||
public class ChannelSelectionDialogResult
|
||
{
|
||
/// <summary>
|
||
/// 是否成功
|
||
/// </summary>
|
||
public bool Success { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 结果消息
|
||
/// </summary>
|
||
public string Message { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 选中的通道
|
||
/// </summary>
|
||
public ModelItemCollection SelectedChannels { get; set; } = new ModelItemCollection();
|
||
|
||
/// <summary>
|
||
/// 选择方法
|
||
/// </summary>
|
||
public ChannelSelectionMethod SelectionMethod { get; set; } = ChannelSelectionMethod.Manual;
|
||
|
||
/// <summary>
|
||
/// 车辆尺寸
|
||
/// </summary>
|
||
public string VehicleSize { get; set; } = "标准";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道选择方法枚举
|
||
/// </summary>
|
||
public enum ChannelSelectionMethod
|
||
{
|
||
/// <summary>
|
||
/// 手动选择
|
||
/// </summary>
|
||
Manual,
|
||
|
||
/// <summary>
|
||
/// 自动检测
|
||
/// </summary>
|
||
AutoDetect,
|
||
|
||
/// <summary>
|
||
/// 基于物流属性
|
||
/// </summary>
|
||
LogisticsAttribute,
|
||
|
||
/// <summary>
|
||
/// 可通行区域
|
||
/// </summary>
|
||
TraversableAreas,
|
||
|
||
/// <summary>
|
||
/// 通道类型
|
||
/// </summary>
|
||
ChannelType
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道选择对话框
|
||
/// </summary>
|
||
public class ChannelSelectionDialog : System.Windows.Forms.Form
|
||
{
|
||
private ChannelSelectionResult _analysisResult;
|
||
private ModelItemCollection _selectedChannels;
|
||
private ChannelSelectionMethod _selectionMethod;
|
||
private string _vehicleSize;
|
||
|
||
/// <summary>
|
||
/// 选中的通道
|
||
/// </summary>
|
||
public ModelItemCollection SelectedChannels { get { return _selectedChannels; } }
|
||
|
||
/// <summary>
|
||
/// 选择方法
|
||
/// </summary>
|
||
public ChannelSelectionMethod SelectionMethod { get { return _selectionMethod; } }
|
||
|
||
/// <summary>
|
||
/// 车辆尺寸
|
||
/// </summary>
|
||
public string VehicleSize { get { return _vehicleSize; } }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="analysisResult">通道分析结果</param>
|
||
public ChannelSelectionDialog(ChannelSelectionResult analysisResult)
|
||
{
|
||
_analysisResult = analysisResult ?? new ChannelSelectionResult();
|
||
_selectedChannels = new ModelItemCollection();
|
||
_selectionMethod = ChannelSelectionMethod.Manual;
|
||
_vehicleSize = "标准";
|
||
|
||
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.ComboBox vehicleSizeComboBox;
|
||
private System.Windows.Forms.Button previewButton;
|
||
private System.Windows.Forms.Button clearHighlightButton;
|
||
private System.Windows.Forms.CheckBox selectAllCheckBox;
|
||
|
||
/// <summary>
|
||
/// 初始化对话框组件
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建通道列表选项卡
|
||
/// </summary>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建筛选选项卡
|
||
/// </summary>
|
||
private void CreateFilterTab(System.Windows.Forms.TabPage tabPage)
|
||
{
|
||
// 车辆尺寸选择
|
||
var vehicleSizeLabel = new System.Windows.Forms.Label
|
||
{
|
||
Text = "车辆尺寸:",
|
||
Location = new System.Drawing.Point(10, 20),
|
||
Size = new System.Drawing.Size(80, 20),
|
||
Font = new System.Drawing.Font("微软雅黑", 8)
|
||
};
|
||
tabPage.Controls.Add(vehicleSizeLabel);
|
||
|
||
vehicleSizeComboBox = new System.Windows.Forms.ComboBox
|
||
{
|
||
Location = new System.Drawing.Point(100, 18),
|
||
Size = new System.Drawing.Size(120, 25),
|
||
DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList,
|
||
Font = new System.Drawing.Font("微软雅黑", 8)
|
||
};
|
||
vehicleSizeComboBox.Items.AddRange(new string[] { "小型", "标准", "大型", "超大型" });
|
||
vehicleSizeComboBox.SelectedIndex = 1; // 默认选择"标准"
|
||
vehicleSizeComboBox.SelectedIndexChanged += VehicleSizeComboBox_SelectedIndexChanged;
|
||
tabPage.Controls.Add(vehicleSizeComboBox);
|
||
|
||
// 筛选方式选择
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载分析数据
|
||
/// </summary>
|
||
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 vehicleSize = "标准";
|
||
|
||
try
|
||
{
|
||
if (CategoryAttributeManager.HasLogisticsAttributes(channel))
|
||
{
|
||
// 这里可以添加更详细的属性读取逻辑
|
||
}
|
||
}
|
||
catch { }
|
||
|
||
// 获取尺寸信息
|
||
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 { }
|
||
|
||
// 添加子项
|
||
item.SubItems.Add(channelType);
|
||
item.SubItems.Add(traversable);
|
||
item.SubItems.Add(vehicleSize);
|
||
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}";
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新统计信息
|
||
/// </summary>
|
||
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 事件处理方法
|
||
|
||
/// <summary>
|
||
/// 预览按钮点击事件
|
||
/// </summary>
|
||
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)
|
||
{
|
||
// 高亮显示选中的通道
|
||
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
|
||
Application.ActiveDocument.Models.OverrideTemporaryColor(selectedItems, navisColor);
|
||
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.Forms.MessageBox.Show($"预览失败: {ex.Message}", "错误",
|
||
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除高亮按钮点击事件
|
||
/// </summary>
|
||
private void ClearHighlightButton_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
Application.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.Forms.MessageBox.Show($"清除高亮失败: {ex.Message}", "错误",
|
||
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确定按钮点击事件
|
||
/// </summary>
|
||
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);
|
||
}
|
||
}
|
||
|
||
_vehicleSize = vehicleSizeComboBox?.SelectedItem?.ToString() ?? "标准";
|
||
_selectionMethod = ChannelSelectionMethod.Manual; // 可以根据选项卡或筛选方式设置
|
||
|
||
// 清除高亮
|
||
try
|
||
{
|
||
Application.ActiveDocument.Models.ResetAllTemporaryMaterials();
|
||
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
|
||
}
|
||
catch { }
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.Forms.MessageBox.Show($"确认选择失败: {ex.Message}", "错误",
|
||
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全选复选框状态改变事件
|
||
/// </summary>
|
||
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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通道列表项选中状态改变事件
|
||
/// </summary>
|
||
private void ChannelListView_ItemChecked(object sender, System.Windows.Forms.ItemCheckedEventArgs e)
|
||
{
|
||
UpdateStatistics();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 车辆尺寸选择改变事件
|
||
/// </summary>
|
||
private void VehicleSizeComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||
{
|
||
_vehicleSize = vehicleSizeComboBox.SelectedItem?.ToString() ?? "标准";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 筛选选项改变事件
|
||
/// </summary>
|
||
private void FilterOption_CheckedChanged(object sender, EventArgs e)
|
||
{
|
||
// 可以根据需要实现筛选逻辑
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用筛选按钮点击事件
|
||
/// </summary>
|
||
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 路径验证与优化相关数据结构
|
||
|
||
/// <summary>
|
||
/// 路径验证结果
|
||
/// </summary>
|
||
public class PathValidationResult
|
||
{
|
||
/// <summary>
|
||
/// 路径ID
|
||
/// </summary>
|
||
public string RouteId { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 路径名称
|
||
/// </summary>
|
||
public string RouteName { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 验证是否通过
|
||
/// </summary>
|
||
public bool IsValid { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 验证消息
|
||
/// </summary>
|
||
public string Message { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 错误列表
|
||
/// </summary>
|
||
public List<string> Errors { get; set; } = new List<string>();
|
||
|
||
/// <summary>
|
||
/// 警告列表
|
||
/// </summary>
|
||
public List<string> Warnings { get; set; } = new List<string>();
|
||
|
||
/// <summary>
|
||
/// 验证时间
|
||
/// </summary>
|
||
public DateTime ValidationTime { get; set; } = DateTime.Now;
|
||
|
||
/// <summary>
|
||
/// 添加错误信息
|
||
/// </summary>
|
||
/// <param name="error">错误信息</param>
|
||
public void AddError(string error)
|
||
{
|
||
if (!string.IsNullOrEmpty(error) && !Errors.Contains(error))
|
||
{
|
||
Errors.Add(error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加警告信息
|
||
/// </summary>
|
||
/// <param name="warning">警告信息</param>
|
||
public void AddWarning(string warning)
|
||
{
|
||
if (!string.IsNullOrEmpty(warning) && !Warnings.Contains(warning))
|
||
{
|
||
Warnings.Add(warning);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取详细验证报告
|
||
/// </summary>
|
||
/// <returns>验证报告文本</returns>
|
||
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();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径优化选项
|
||
/// </summary>
|
||
public class PathOptimizationOptions
|
||
{
|
||
/// <summary>
|
||
/// 移除重复点
|
||
/// </summary>
|
||
public bool RemoveDuplicatePoints { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 路径平滑化
|
||
/// </summary>
|
||
public bool SmoothPath { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 优化路径角度
|
||
/// </summary>
|
||
public bool OptimizeAngles { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 调整到通道中心
|
||
/// </summary>
|
||
public bool AdjustToChannels { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 重复点检测阈值(米)
|
||
/// </summary>
|
||
public double DuplicatePointThreshold { get; set; } = 0.01;
|
||
|
||
/// <summary>
|
||
/// 角度优化容差(弧度)
|
||
/// </summary>
|
||
public double AngleOptimizationTolerance { get; set; } = 0.1;
|
||
|
||
/// <summary>
|
||
/// 平滑强度(0-1)
|
||
/// </summary>
|
||
public double SmoothingStrength { get; set; } = 0.5;
|
||
|
||
/// <summary>
|
||
/// 创建默认优化选项
|
||
/// </summary>
|
||
/// <returns>默认优化选项</returns>
|
||
public static PathOptimizationOptions CreateDefault()
|
||
{
|
||
return new PathOptimizationOptions
|
||
{
|
||
RemoveDuplicatePoints = true,
|
||
SmoothPath = true,
|
||
OptimizeAngles = true,
|
||
AdjustToChannels = false,
|
||
DuplicatePointThreshold = 0.01,
|
||
AngleOptimizationTolerance = 0.1,
|
||
SmoothingStrength = 0.5
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建保守优化选项(仅基础优化)
|
||
/// </summary>
|
||
/// <returns>保守优化选项</returns>
|
||
public static PathOptimizationOptions CreateConservative()
|
||
{
|
||
return new PathOptimizationOptions
|
||
{
|
||
RemoveDuplicatePoints = true,
|
||
SmoothPath = false,
|
||
OptimizeAngles = false,
|
||
AdjustToChannels = false,
|
||
DuplicatePointThreshold = 0.001
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建激进优化选项(所有优化)
|
||
/// </summary>
|
||
/// <returns>激进优化选项</returns>
|
||
public static PathOptimizationOptions CreateAggressive()
|
||
{
|
||
return new PathOptimizationOptions
|
||
{
|
||
RemoveDuplicatePoints = true,
|
||
SmoothPath = true,
|
||
OptimizeAngles = true,
|
||
AdjustToChannels = true,
|
||
DuplicatePointThreshold = 0.05,
|
||
AngleOptimizationTolerance = 0.2,
|
||
SmoothingStrength = 0.8
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径优化结果
|
||
/// </summary>
|
||
public class PathOptimizationResult
|
||
{
|
||
/// <summary>
|
||
/// 优化是否成功
|
||
/// </summary>
|
||
public bool Success { get; set; } = false;
|
||
|
||
/// <summary>
|
||
/// 优化消息
|
||
/// </summary>
|
||
public string Message { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 原始路径
|
||
/// </summary>
|
||
public PathRoute OriginalRoute { get; set; }
|
||
|
||
/// <summary>
|
||
/// 优化后的路径
|
||
/// </summary>
|
||
public PathRoute OptimizedRoute { get; set; }
|
||
|
||
/// <summary>
|
||
/// 原始路径长度
|
||
/// </summary>
|
||
public double OriginalLength { get; set; } = 0.0;
|
||
|
||
/// <summary>
|
||
/// 优化后路径长度
|
||
/// </summary>
|
||
public double OptimizedLength { get; set; } = 0.0;
|
||
|
||
/// <summary>
|
||
/// 长度减少量
|
||
/// </summary>
|
||
public double LengthReduction { get; set; } = 0.0;
|
||
|
||
/// <summary>
|
||
/// 长度减少百分比
|
||
/// </summary>
|
||
public double LengthReductionPercentage => OriginalLength > 0 ? (LengthReduction / OriginalLength) * 100 : 0;
|
||
|
||
/// <summary>
|
||
/// 原始点数
|
||
/// </summary>
|
||
public int OriginalPointCount { get; set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 优化后点数
|
||
/// </summary>
|
||
public int OptimizedPointCount { get; set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 点数减少量
|
||
/// </summary>
|
||
public int PointReduction { get; set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 点数减少百分比
|
||
/// </summary>
|
||
public double PointReductionPercentage => OriginalPointCount > 0 ? ((double)PointReduction / OriginalPointCount) * 100 : 0;
|
||
|
||
/// <summary>
|
||
/// 优化步骤记录
|
||
/// </summary>
|
||
public List<string> OptimizationSteps { get; set; } = new List<string>();
|
||
|
||
/// <summary>
|
||
/// 优化时间
|
||
/// </summary>
|
||
public DateTime OptimizationTime { get; set; } = DateTime.Now;
|
||
|
||
/// <summary>
|
||
/// 优化耗时(毫秒)
|
||
/// </summary>
|
||
public long ElapsedMilliseconds { get; set; } = 0;
|
||
|
||
/// <summary>
|
||
/// 添加优化步骤记录
|
||
/// </summary>
|
||
/// <param name="step">优化步骤描述</param>
|
||
public void AddOptimizationStep(string step)
|
||
{
|
||
if (!string.IsNullOrEmpty(step))
|
||
{
|
||
OptimizationSteps.Add($"[{DateTime.Now:HH:mm:ss}] {step}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取详细优化报告
|
||
/// </summary>
|
||
/// <returns>优化报告文本</returns>
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取优化摘要
|
||
/// </summary>
|
||
/// <returns>优化摘要文本</returns>
|
||
public string GetSummary()
|
||
{
|
||
if (!Success)
|
||
{
|
||
return $"优化失败: {Message}";
|
||
}
|
||
|
||
return $"优化成功: 长度减少 {LengthReduction:F3}m ({LengthReductionPercentage:F1}%), " +
|
||
$"点数减少 {PointReduction} 个 ({PointReductionPercentage:F1}%), " +
|
||
$"共执行 {OptimizationSteps.Count} 个优化步骤";
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 路径点标记类型
|
||
/// </summary>
|
||
public enum PathPointMarkerType
|
||
{
|
||
/// <summary>
|
||
/// 文本标注
|
||
/// </summary>
|
||
TextLabel
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径点3D标记信息
|
||
/// </summary>
|
||
public class PathPointMarker
|
||
{
|
||
/// <summary>
|
||
/// 关联的路径点
|
||
/// </summary>
|
||
public PathPoint PathPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 标记类型
|
||
/// </summary>
|
||
public PathPointMarkerType MarkerType { get; set; }
|
||
|
||
/// <summary>
|
||
/// 标注文本
|
||
/// </summary>
|
||
public string LabelText { get; set; }
|
||
|
||
/// <summary>
|
||
/// 标注位置
|
||
/// </summary>
|
||
public Point3D LabelPosition { get; set; }
|
||
|
||
/// <summary>
|
||
/// 创建时间
|
||
/// </summary>
|
||
public DateTime CreatedTime { get; set; } = DateTime.Now;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径历史记录项
|
||
/// </summary>
|
||
[Serializable]
|
||
public class PathHistoryEntry
|
||
{
|
||
/// <summary>
|
||
/// 历史记录唯一标识符
|
||
/// </summary>
|
||
public string Id { get; set; }
|
||
|
||
/// <summary>
|
||
/// 关联的路径ID
|
||
/// </summary>
|
||
public string RouteId { get; set; }
|
||
|
||
/// <summary>
|
||
/// 操作类型
|
||
/// </summary>
|
||
public PathHistoryOperationType OperationType { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径快照(操作前的状态)
|
||
/// </summary>
|
||
public PathRoute RouteSnapshot { get; set; }
|
||
|
||
/// <summary>
|
||
/// 操作时间
|
||
/// </summary>
|
||
public DateTime OperationTime { get; set; }
|
||
|
||
/// <summary>
|
||
/// 操作描述
|
||
/// </summary>
|
||
public string Description { get; set; }
|
||
|
||
/// <summary>
|
||
/// 版本号
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径历史操作类型
|
||
/// </summary>
|
||
public enum PathHistoryOperationType
|
||
{
|
||
/// <summary>
|
||
/// 创建路径
|
||
/// </summary>
|
||
Created,
|
||
|
||
/// <summary>
|
||
/// 编辑路径
|
||
/// </summary>
|
||
Edited,
|
||
|
||
/// <summary>
|
||
/// 删除路径点
|
||
/// </summary>
|
||
PointRemoved,
|
||
|
||
/// <summary>
|
||
/// 添加路径点
|
||
/// </summary>
|
||
PointAdded,
|
||
|
||
/// <summary>
|
||
/// 路径优化
|
||
/// </summary>
|
||
Optimized,
|
||
|
||
/// <summary>
|
||
/// 手动保存
|
||
/// </summary>
|
||
ManualSave
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径历史管理器
|
||
/// </summary>
|
||
public class PathHistoryManager
|
||
{
|
||
private Dictionary<string, List<PathHistoryEntry>> _routeHistories;
|
||
private int _maxHistoryCount;
|
||
|
||
/// <summary>
|
||
/// 历史记录变更事件
|
||
/// </summary>
|
||
public event EventHandler<PathHistoryEntry> HistoryEntryAdded;
|
||
|
||
public PathHistoryManager(int maxHistoryCount = 50)
|
||
{
|
||
_routeHistories = new Dictionary<string, List<PathHistoryEntry>>();
|
||
_maxHistoryCount = maxHistoryCount;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加历史记录
|
||
/// </summary>
|
||
public void AddHistoryEntry(PathHistoryEntry entry)
|
||
{
|
||
if (string.IsNullOrEmpty(entry.RouteId)) return;
|
||
|
||
if (!_routeHistories.ContainsKey(entry.RouteId))
|
||
{
|
||
_routeHistories[entry.RouteId] = new List<PathHistoryEntry>();
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取路径的历史记录
|
||
/// </summary>
|
||
public List<PathHistoryEntry> GetRouteHistory(string routeId)
|
||
{
|
||
return _routeHistories.ContainsKey(routeId) ?
|
||
new List<PathHistoryEntry>(_routeHistories[routeId]) :
|
||
new List<PathHistoryEntry>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最新的历史记录
|
||
/// </summary>
|
||
public PathHistoryEntry GetLatestHistory(string routeId)
|
||
{
|
||
var histories = GetRouteHistory(routeId);
|
||
return histories.LastOrDefault();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理路径的历史记录
|
||
/// </summary>
|
||
public void ClearRouteHistory(string routeId)
|
||
{
|
||
if (_routeHistories.ContainsKey(routeId))
|
||
{
|
||
_routeHistories.Remove(routeId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有路径的历史记录统计
|
||
/// </summary>
|
||
public Dictionary<string, int> GetHistoryStatistics()
|
||
{
|
||
return _routeHistories.ToDictionary(
|
||
kvp => kvp.Key,
|
||
kvp => kvp.Value.Count
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有历史记录
|
||
/// </summary>
|
||
/// <returns>所有历史记录的列表,按时间倒序排列</returns>
|
||
public List<PathHistoryEntry> GetAllHistoryEntries()
|
||
{
|
||
var allEntries = new List<PathHistoryEntry>();
|
||
foreach (var routeHistory in _routeHistories.Values)
|
||
{
|
||
allEntries.AddRange(routeHistory);
|
||
}
|
||
|
||
// 按操作时间倒序排列(最新的在前)
|
||
return allEntries.OrderByDescending(entry => entry.OperationTime).ToList();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径文件序列化帮助类
|
||
/// </summary>
|
||
public static class PathFileSerializer
|
||
{
|
||
/// <summary>
|
||
/// 将路径保存为XML文件
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从XML文件加载路径
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将路径保存为JSON文件(简化版)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从JSON文件加载路径(简化版,仅支持基本格式)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将多个路径保存为XML文件
|
||
/// </summary>
|
||
public static bool SaveRoutesToXml(List<PathRoute> 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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从XML文件加载多个路径
|
||
/// </summary>
|
||
public static List<PathRoute> 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<PathRoute>();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"加载多路径XML文件失败: {ex.Message}");
|
||
return new List<PathRoute>();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测文件格式
|
||
/// </summary>
|
||
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 { }
|
||
return "未知";
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径容器(用于保存多个路径)
|
||
/// </summary>
|
||
[Serializable]
|
||
public class PathRouteContainer
|
||
{
|
||
public List<PathRoute> Routes { get; set; } = new List<PathRoute>();
|
||
public DateTime CreatedTime { get; set; } = DateTime.Now;
|
||
public string Version { get; set; } = "1.0";
|
||
public string Description { get; set; } = "";
|
||
}
|
||
} |