NavisworksTransport/NavigationMapWindow.cs

1601 lines
64 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Navisworks.Api;
using System.IO;
namespace NavisworksTransport
{
/// <summary>
/// 通道几何信息
/// </summary>
public class ChannelGeometry
{
/// <summary>
/// 通道模型项
/// </summary>
public ModelItem ChannelItem { get; set; }
/// <summary>
/// 通道名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 2D投影顶点集合世界坐标
/// </summary>
public List<Point3D> WorldVertices { get; set; }
/// <summary>
/// 2D投影顶点集合地图坐标
/// </summary>
public List<PointF> MapVertices { get; set; }
/// <summary>
/// 包围盒(用于快速绘制)
/// </summary>
public Rectangle BoundingRect { get; set; }
/// <summary>
/// 是否显示详细几何
/// </summary>
public bool ShowDetailedGeometry { get; set; }
/// <summary>
/// 是否显示顶点标签
/// </summary>
public bool ShowVertexLabels { get; set; }
public ChannelGeometry()
{
WorldVertices = new List<Point3D>();
MapVertices = new List<PointF>();
ShowDetailedGeometry = true;
ShowVertexLabels = true;
}
}
/// <summary>
/// 2D导航地图窗口
/// 提供可视化的路径规划界面
/// </summary>
public partial class NavigationMapWindow : Form
{
private static string _logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NavisworksTransport_Debug.log");
/// <summary>
/// 写入调试日志同时输出到Debug和文件
/// </summary>
/// <param name="message">日志消息</param>
private static void WriteLog(string message)
{
var logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {message}";
System.Diagnostics.Debug.WriteLine(logMessage);
try
{
File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);
}
catch
{
// 忽略文件写入错误
}
}
private CoordinateConverter _coordinateConverter;
private PathRoute _currentRoute;
private List<ModelItem> _channelItems;
private List<Rectangle> _channelOutlines;
private List<ChannelGeometry> _channelGeometries;
private PathPlanningManager _pathPlanningManager;
// UI控件
private Panel _mapPanel;
private Label _coordinateLabel;
private TextBox _pointNameTextBox;
private ComboBox _pointTypeComboBox;
private Button _addPointButton;
private Button _removePointButton;
private Button _clearAllButton;
private Button _generatePathButton;
private ListBox _pointsListBox;
private GroupBox _coordinateGroupBox;
private TextBox _xCoordinateTextBox;
private TextBox _yCoordinateTextBox;
private TextBox _zCoordinateTextBox;
private Button _updateCoordinateButton;
// 绘制相关
private Bitmap _mapBuffer;
private System.Drawing.Graphics _mapGraphics;
private PathPoint _selectedPoint;
private bool _isDragging;
private System.Drawing.Point _lastMousePosition;
// 常量定义
private const int POINT_RADIUS = 6;
private const int POINT_SELECT_RADIUS = 10;
private readonly System.Drawing.Color START_POINT_COLOR = System.Drawing.Color.Green;
private readonly System.Drawing.Color END_POINT_COLOR = System.Drawing.Color.Red;
private readonly System.Drawing.Color WAY_POINT_COLOR = System.Drawing.Color.Blue;
private readonly System.Drawing.Color CHANNEL_COLOR = System.Drawing.Color.LightGray;
private readonly System.Drawing.Color PATH_LINE_COLOR = System.Drawing.Color.DarkBlue;
// 工具栏按钮
private System.Windows.Forms.Button btnZoomIn;
private System.Windows.Forms.Button btnZoomOut;
private System.Windows.Forms.Button btnResetView;
private System.Windows.Forms.Button btnClearPaths;
private System.Windows.Forms.Button btnValidatePath;
private System.Windows.Forms.Button btnOptimizePath;
private System.Windows.Forms.Button btnToggleGeometry;
private System.Windows.Forms.Button btnToggleLabels;
private System.Windows.Forms.Button btnRecalculateBounds;
// 状态栏
private System.Windows.Forms.StatusStrip statusStrip;
private System.Windows.Forms.ToolStripStatusLabel statusLabel;
public event EventHandler<PathRoute> PathGenerated;
public event EventHandler<PathPoint> PointSelected;
public event EventHandler<PathPoint> PointAdded;
public event EventHandler<PathPoint> PointRemoved;
/// <summary>
/// 当前路径
/// </summary>
public PathRoute CurrentRoute
{
get { return _currentRoute; }
set { _currentRoute = value; UpdatePointsList(); RedrawMap(); }
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="coordinateConverter">坐标转换器</param>
/// <param name="channelItems">通道模型集合</param>
public NavigationMapWindow(CoordinateConverter coordinateConverter, List<ModelItem> channelItems)
{
_coordinateConverter = coordinateConverter ?? throw new ArgumentNullException(nameof(coordinateConverter));
_channelItems = channelItems ?? new List<ModelItem>();
_currentRoute = new PathRoute("新路径");
_channelOutlines = new List<Rectangle>();
_channelGeometries = new List<ChannelGeometry>();
_pathPlanningManager = new PathPlanningManager();
WriteLog($"=== NavigationMapWindow 初始化开始 ===");
WriteLog($"通道项数量: {_channelItems.Count}");
WriteLog($"地图尺寸: {coordinateConverter.MapWidth} x {coordinateConverter.MapHeight}");
WriteLog($"日志文件位置: {_logFilePath}");
InitializeComponent();
SetupEventHandlers();
GenerateChannelOutlines();
InitializeMapBuffer();
RedrawMap();
WriteLog($"=== NavigationMapWindow 初始化完成 ===");
}
/// <summary>
/// 初始化UI组件
/// </summary>
private void InitializeComponent()
{
this.Text = "路径规划地图";
this.Size = new Size(1000, 700);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.MinimumSize = new Size(800, 600);
// 创建主布局
var mainLayout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 1
};
mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70F));
mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));
// 地图面板
_mapPanel = new Panel
{
Dock = DockStyle.Fill,
BackColor = System.Drawing.Color.White,
BorderStyle = BorderStyle.FixedSingle
};
// 控制面板
var controlPanel = CreateControlPanel();
// 创建工具栏按钮
btnZoomIn = new System.Windows.Forms.Button()
{
Text = "放大",
Size = new Size(60, 25),
Location = new Point(5, 5),
FlatStyle = FlatStyle.Flat
};
btnZoomIn.Click += (s, e) => { /* 放大功能 - 暂未实现 */ };
btnZoomOut = new System.Windows.Forms.Button()
{
Text = "缩小",
Size = new Size(60, 25),
Location = new Point(70, 5),
FlatStyle = FlatStyle.Flat
};
btnZoomOut.Click += (s, e) => { /* 缩小功能 - 暂未实现 */ };
btnResetView = new System.Windows.Forms.Button()
{
Text = "重置",
Size = new Size(60, 25),
Location = new Point(135, 5),
FlatStyle = FlatStyle.Flat
};
btnResetView.Click += (s, e) => { RedrawMap(); };
btnClearPaths = new System.Windows.Forms.Button()
{
Text = "清除路径",
Size = new Size(80, 25),
Location = new Point(200, 5),
BackColor = System.Drawing.Color.FromArgb(255, 128, 128),
FlatStyle = FlatStyle.Flat
};
btnClearPaths.Click += (s, e) => { _currentRoute?.Points.Clear(); RedrawMap(); };
btnValidatePath = new System.Windows.Forms.Button()
{
Text = "验证路径",
Size = new Size(80, 25),
Location = new Point(285, 5),
BackColor = System.Drawing.Color.FromArgb(255, 255, 128),
FlatStyle = FlatStyle.Flat
};
btnValidatePath.Click += BtnValidatePath_Click;
btnOptimizePath = new System.Windows.Forms.Button()
{
Text = "优化路径",
Size = new Size(80, 25),
Location = new Point(370, 5),
BackColor = System.Drawing.Color.FromArgb(128, 255, 128),
FlatStyle = FlatStyle.Flat
};
btnOptimizePath.Click += BtnOptimizePath_Click;
btnToggleGeometry = new System.Windows.Forms.Button()
{
Text = "详细几何",
Size = new Size(80, 25),
Location = new Point(455, 5),
BackColor = System.Drawing.Color.FromArgb(128, 200, 255),
FlatStyle = FlatStyle.Flat
};
btnToggleGeometry.Click += BtnToggleGeometry_Click;
btnToggleLabels = new System.Windows.Forms.Button()
{
Text = "坐标标注",
Size = new Size(80, 25),
Location = new Point(540, 5),
BackColor = System.Drawing.Color.FromArgb(255, 200, 128),
FlatStyle = FlatStyle.Flat
};
btnToggleLabels.Click += BtnToggleLabels_Click;
btnRecalculateBounds = new System.Windows.Forms.Button()
{
Text = "重算边界",
Size = new Size(80, 25),
Location = new Point(625, 5),
BackColor = System.Drawing.Color.FromArgb(255, 255, 128),
FlatStyle = FlatStyle.Flat
};
btnRecalculateBounds.Click += BtnRecalculateBounds_Click;
// 工具栏面板
var toolPanel = new Panel()
{
Dock = DockStyle.Top,
Height = 35,
BackColor = System.Drawing.Color.LightGray
};
toolPanel.Controls.Add(btnZoomIn);
toolPanel.Controls.Add(btnZoomOut);
toolPanel.Controls.Add(btnResetView);
toolPanel.Controls.Add(btnClearPaths);
toolPanel.Controls.Add(btnValidatePath);
toolPanel.Controls.Add(btnOptimizePath);
toolPanel.Controls.Add(btnToggleGeometry);
toolPanel.Controls.Add(btnToggleLabels);
toolPanel.Controls.Add(btnRecalculateBounds);
// 状态栏
statusStrip = new StatusStrip();
statusLabel = new ToolStripStatusLabel("就绪");
statusStrip.Items.Add(statusLabel);
mainLayout.Controls.Add(_mapPanel, 0, 0);
mainLayout.Controls.Add(controlPanel, 1, 0);
this.Controls.Add(toolPanel);
this.Controls.Add(mainLayout);
this.Controls.Add(statusStrip);
}
/// <summary>
/// 创建控制面板
/// </summary>
/// <returns></returns>
private Panel CreateControlPanel()
{
var panel = new Panel { Dock = DockStyle.Fill, Padding = new Padding(10) };
var layout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 6
};
// 点信息组
var pointInfoGroup = new GroupBox { Text = "路径点信息", Height = 120 };
var pointInfoLayout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 3 };
pointInfoLayout.Controls.Add(new Label { Text = "名称:", Anchor = AnchorStyles.Left }, 0, 0);
_pointNameTextBox = new TextBox { Dock = DockStyle.Fill };
pointInfoLayout.Controls.Add(_pointNameTextBox, 1, 0);
pointInfoLayout.Controls.Add(new Label { Text = "类型:", Anchor = AnchorStyles.Left }, 0, 1);
_pointTypeComboBox = new ComboBox
{
Dock = DockStyle.Fill,
DropDownStyle = ComboBoxStyle.DropDownList
};
_pointTypeComboBox.Items.AddRange(new[] { "起点", "终点", "路径点" });
_pointTypeComboBox.SelectedIndex = 2;
pointInfoLayout.Controls.Add(_pointTypeComboBox, 1, 1);
var buttonLayout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1 };
_addPointButton = new Button { Text = "添加点", Dock = DockStyle.Fill };
_removePointButton = new Button { Text = "删除点", Dock = DockStyle.Fill, Enabled = false };
buttonLayout.Controls.Add(_addPointButton, 0, 0);
buttonLayout.Controls.Add(_removePointButton, 1, 0);
pointInfoLayout.Controls.Add(buttonLayout, 0, 2);
pointInfoLayout.SetColumnSpan(buttonLayout, 2);
pointInfoGroup.Controls.Add(pointInfoLayout);
// 坐标编辑组
_coordinateGroupBox = new GroupBox { Text = "坐标编辑", Height = 140 };
var coordLayout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 4 };
coordLayout.Controls.Add(new Label { Text = "X:", Anchor = AnchorStyles.Left }, 0, 0);
_xCoordinateTextBox = new TextBox { Dock = DockStyle.Fill };
coordLayout.Controls.Add(_xCoordinateTextBox, 1, 0);
coordLayout.Controls.Add(new Label { Text = "Y:", Anchor = AnchorStyles.Left }, 0, 1);
_yCoordinateTextBox = new TextBox { Dock = DockStyle.Fill };
coordLayout.Controls.Add(_yCoordinateTextBox, 1, 1);
coordLayout.Controls.Add(new Label { Text = "Z:", Anchor = AnchorStyles.Left }, 0, 2);
_zCoordinateTextBox = new TextBox { Dock = DockStyle.Fill };
coordLayout.Controls.Add(_zCoordinateTextBox, 1, 2);
_updateCoordinateButton = new Button { Text = "更新坐标", Dock = DockStyle.Fill, Enabled = false };
coordLayout.Controls.Add(_updateCoordinateButton, 0, 3);
coordLayout.SetColumnSpan(_updateCoordinateButton, 2);
_coordinateGroupBox.Controls.Add(coordLayout);
// 路径点列表
var listGroup = new GroupBox { Text = "路径点列表", Height = 200 };
_pointsListBox = new ListBox { Dock = DockStyle.Fill };
listGroup.Controls.Add(_pointsListBox);
// 操作按钮
var actionLayout = new TableLayoutPanel { Height = 80, Dock = DockStyle.Top, ColumnCount = 1, RowCount = 2 };
_generatePathButton = new Button { Text = "生成路径", Dock = DockStyle.Fill };
_clearAllButton = new Button { Text = "清空所有", Dock = DockStyle.Fill };
actionLayout.Controls.Add(_generatePathButton, 0, 0);
actionLayout.Controls.Add(_clearAllButton, 0, 1);
// 状态标签
_coordinateLabel = new Label
{
Text = "点击地图添加路径点",
Dock = DockStyle.Bottom,
Height = 20,
ForeColor = System.Drawing.Color.DarkBlue
};
layout.Controls.Add(pointInfoGroup, 0, 0);
layout.Controls.Add(_coordinateGroupBox, 0, 1);
layout.Controls.Add(listGroup, 0, 2);
layout.Controls.Add(actionLayout, 0, 3);
layout.Controls.Add(_coordinateLabel, 0, 4);
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
layout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
panel.Controls.Add(layout);
return panel;
}
/// <summary>
/// 设置事件处理器
/// </summary>
private void SetupEventHandlers()
{
_mapPanel.Paint += MapPanel_Paint;
_mapPanel.MouseClick += MapPanel_MouseClick;
_mapPanel.MouseMove += MapPanel_MouseMove;
_mapPanel.MouseDown += MapPanel_MouseDown;
_mapPanel.MouseUp += MapPanel_MouseUp;
_mapPanel.Resize += MapPanel_Resize;
_addPointButton.Click += AddPointButton_Click;
_removePointButton.Click += RemovePointButton_Click;
_clearAllButton.Click += ClearAllButton_Click;
_generatePathButton.Click += GeneratePathButton_Click;
_updateCoordinateButton.Click += UpdateCoordinateButton_Click;
_pointsListBox.SelectedIndexChanged += PointsListBox_SelectedIndexChanged;
_pointNameTextBox.TextChanged += PointNameTextBox_TextChanged;
_pointTypeComboBox.SelectedIndexChanged += PointTypeComboBox_SelectedIndexChanged;
}
/// <summary>
/// 生成通道轮廓
/// </summary>
private void GenerateChannelOutlines()
{
WriteLog($"=== 开始生成通道轮廓 ===");
_channelOutlines.Clear();
_channelGeometries.Clear();
foreach (var channel in _channelItems)
{
try
{
WriteLog($"处理通道: {channel.DisplayName}");
var boundingBox = channel.BoundingBox();
var channelBounds = new ChannelBounds(boundingBox);
MapPoint2D min2D, max2D;
channelBounds.Get2DProjection(out min2D, out max2D);
var minMap = _coordinateConverter.WorldToMap(new Autodesk.Navisworks.Api.Point3D(min2D.X, min2D.Y, 0));
var maxMap = _coordinateConverter.WorldToMap(new Autodesk.Navisworks.Api.Point3D(max2D.X, max2D.Y, 0));
var rect = new Rectangle(
(int)Math.Min(minMap.X, maxMap.X),
(int)Math.Min(minMap.Y, maxMap.Y),
(int)Math.Abs(maxMap.X - minMap.X),
(int)Math.Abs(maxMap.Y - minMap.Y)
);
WriteLog($"简单轮廓矩形: ({rect.X},{rect.Y},{rect.Width},{rect.Height})");
_channelOutlines.Add(rect);
// 创建详细几何信息
var geometry = CreateChannelGeometry(channel, boundingBox);
if (geometry != null)
{
_channelGeometries.Add(geometry);
WriteLog($"已添加几何: {geometry.Name}");
}
else
{
WriteLog($"几何创建失败: {channel.DisplayName}");
}
}
catch (Exception ex)
{
WriteLog($"处理通道失败: {channel.DisplayName}, 错误: {ex.Message}");
continue;
}
}
WriteLog($"=== 通道轮廓生成完成,总数: {_channelGeometries.Count} ===");
}
/// <summary>
/// 创建通道几何信息
/// </summary>
/// <param name="channel">通道模型项</param>
/// <param name="boundingBox">包围盒</param>
/// <returns>通道几何信息</returns>
private ChannelGeometry CreateChannelGeometry(ModelItem channel, BoundingBox3D boundingBox)
{
try
{
WriteLog($"=== 为通道创建几何: {channel.DisplayName} ===");
WriteLog($"包围盒: Min({boundingBox.Min.X:F2},{boundingBox.Min.Y:F2},{boundingBox.Min.Z:F2}) Max({boundingBox.Max.X:F2},{boundingBox.Max.Y:F2},{boundingBox.Max.Z:F2})");
var geometry = new ChannelGeometry
{
ChannelItem = channel,
Name = channel.DisplayName ?? "未命名通道"
};
// 从包围盒提取关键顶点(简化版,实际应该提取真实几何顶点)
var vertices = ExtractChannelVertices(boundingBox);
geometry.WorldVertices.AddRange(vertices);
WriteLog($"提取到 {vertices.Count} 个世界顶点");
// 转换为地图坐标
foreach (var worldVertex in vertices)
{
var mapPoint = _coordinateConverter.WorldToMap(worldVertex);
geometry.MapVertices.Add(new PointF((float)mapPoint.X, (float)mapPoint.Y));
WriteLog($"世界坐标 ({worldVertex.X:F2},{worldVertex.Y:F2}) -> 地图坐标 ({mapPoint.X:F2},{mapPoint.Y:F2})");
}
// 计算包围矩形
if (geometry.MapVertices.Count > 0)
{
var minX = geometry.MapVertices.Min(p => p.X);
var maxX = geometry.MapVertices.Max(p => p.X);
var minY = geometry.MapVertices.Min(p => p.Y);
var maxY = geometry.MapVertices.Max(p => p.Y);
geometry.BoundingRect = new Rectangle(
(int)minX, (int)minY,
(int)(maxX - minX), (int)(maxY - minY)
);
WriteLog($"计算的边界矩形: ({geometry.BoundingRect.X},{geometry.BoundingRect.Y},{geometry.BoundingRect.Width},{geometry.BoundingRect.Height})");
}
else
{
WriteLog("警告:没有有效的地图顶点");
}
// 默认启用详细几何显示和坐标标注
geometry.ShowDetailedGeometry = true;
geometry.ShowVertexLabels = true;
WriteLog($"=== 通道几何创建完成 ===");
return geometry;
}
catch (Exception ex)
{
WriteLog($"创建通道几何信息失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 提取通道顶点
/// </summary>
/// <param name="boundingBox">包围盒</param>
/// <returns>顶点集合</returns>
private List<Point3D> ExtractChannelVertices(BoundingBox3D boundingBox)
{
var vertices = new List<Point3D>();
// 检查包围盒尺寸是否合理
var width = boundingBox.Max.X - boundingBox.Min.X;
var length = boundingBox.Max.Y - boundingBox.Min.Y;
var height = boundingBox.Max.Z - boundingBox.Min.Z;
WriteLog($"通道原始尺寸 - 宽度:{width:F2}m, 长度:{length:F2}m, 高度:{height:F2}m");
// 如果包围盒过大,可能是坐标系统问题,进行限制
var maxDimension = Math.Max(width, Math.Max(length, height));
if (maxDimension > 1000) // 超过1公里
{
WriteLog($"警告:通道包围盒过大 - 宽度:{width:F2}m, 长度:{length:F2}m, 高度:{height:F2}m");
// 限制到合理范围假设是100米范围内的通道
var centerX = (boundingBox.Min.X + boundingBox.Max.X) / 2;
var centerY = (boundingBox.Min.Y + boundingBox.Max.Y) / 2;
var limitedSize = Math.Min(100, maxDimension / 100); // 限制在100米或原尺寸的1%
var halfSize = limitedSize / 2;
var minZ = boundingBox.Min.Z + 0.1;
vertices.Add(new Point3D(centerX - halfSize, centerY - halfSize, minZ)); // 左下
vertices.Add(new Point3D(centerX + halfSize, centerY - halfSize, minZ)); // 右下
vertices.Add(new Point3D(centerX + halfSize, centerY + halfSize, minZ)); // 右上
vertices.Add(new Point3D(centerX - halfSize, centerY + halfSize, minZ)); // 左上
WriteLog($"使用限制尺寸 {limitedSize:F2}m中心点 ({centerX:F2},{centerY:F2})");
}
else
{
// 使用包围盒的四个角点作为基本顶点(俯视图)
var minZ = boundingBox.Min.Z + 0.1; // 稍微抬高以便可视化
vertices.Add(new Point3D(boundingBox.Min.X, boundingBox.Min.Y, minZ)); // 左下
vertices.Add(new Point3D(boundingBox.Max.X, boundingBox.Min.Y, minZ)); // 右下
vertices.Add(new Point3D(boundingBox.Max.X, boundingBox.Max.Y, minZ)); // 右上
vertices.Add(new Point3D(boundingBox.Min.X, boundingBox.Max.Y, minZ)); // 左上
WriteLog($"使用原始包围盒Z={minZ:F2}");
}
WriteLog($"生成顶点数量: {vertices.Count}");
foreach (var vertex in vertices)
{
WriteLog($" 顶点: ({vertex.X:F2},{vertex.Y:F2},{vertex.Z:F2})");
}
return vertices;
}
/// <summary>
/// 初始化地图缓冲区
/// </summary>
private void InitializeMapBuffer()
{
if (_mapBuffer != null)
{
_mapBuffer.Dispose();
_mapGraphics?.Dispose();
}
_mapBuffer = new Bitmap(_mapPanel.Width, _mapPanel.Height);
_mapGraphics = System.Drawing.Graphics.FromImage(_mapBuffer);
_mapGraphics.SmoothingMode = SmoothingMode.AntiAlias;
// 更新坐标转换器的地图尺寸
_coordinateConverter.UpdateMapSize(_mapPanel.Width, _mapPanel.Height);
}
/// <summary>
/// 重绘地图
/// </summary>
private void RedrawMap()
{
if (_mapGraphics == null) return;
// 清空背景
_mapGraphics.Clear(System.Drawing.Color.White);
// 绘制通道轮廓
DrawChannelOutlines();
// 绘制路径线
DrawPathLines();
// 绘制路径点
DrawPathPoints();
// 刷新显示
_mapPanel.Invalidate();
}
/// <summary>
/// 绘制通道轮廓
/// </summary>
private void DrawChannelOutlines()
{
// 绘制详细几何信息
foreach (var geometry in _channelGeometries)
{
DrawChannelGeometry(geometry);
}
// 如果没有详细几何信息,回退到简单矩形绘制
if (_channelGeometries.Count == 0)
{
using (var brush = new SolidBrush(CHANNEL_COLOR))
using (var pen = new Pen(System.Drawing.Color.Gray, 1))
{
foreach (var outline in _channelOutlines)
{
_mapGraphics.FillRectangle(brush, outline);
_mapGraphics.DrawRectangle(pen, outline);
}
}
}
}
/// <summary>
/// 绘制单个通道几何
/// </summary>
/// <param name="geometry">通道几何信息</param>
private void DrawChannelGeometry(ChannelGeometry geometry)
{
WriteLog($"准备绘制通道: {geometry.Name}, 地图顶点数: {geometry.MapVertices.Count}");
if (geometry.MapVertices.Count < 3)
{
WriteLog($"跳过绘制 {geometry.Name}: 顶点数不足 ({geometry.MapVertices.Count})");
// 即使顶点数不足,也尝试绘制边界矩形
if (geometry.BoundingRect.Width > 0 && geometry.BoundingRect.Height > 0)
{
WriteLog($"使用边界矩形绘制: ({geometry.BoundingRect.X},{geometry.BoundingRect.Y},{geometry.BoundingRect.Width},{geometry.BoundingRect.Height})");
using (var brush = new SolidBrush(System.Drawing.Color.FromArgb(128, CHANNEL_COLOR)))
using (var pen = new Pen(System.Drawing.Color.Gray, 2))
{
_mapGraphics.FillRectangle(brush, geometry.BoundingRect);
_mapGraphics.DrawRectangle(pen, geometry.BoundingRect);
}
}
return;
}
try
{
WriteLog($"开始绘制通道 {geometry.Name},详细几何: {geometry.ShowDetailedGeometry}");
// 绘制通道填充区域
using (var brush = new SolidBrush(System.Drawing.Color.FromArgb(128, CHANNEL_COLOR)))
using (var pen = new Pen(System.Drawing.Color.Gray, 2))
using (var vertexBrush = new SolidBrush(System.Drawing.Color.Red))
using (var labelFont = new Font("微软雅黑", 8))
using (var labelBrush = new SolidBrush(System.Drawing.Color.DarkBlue))
{
// 绘制多边形填充
if (geometry.ShowDetailedGeometry && geometry.MapVertices.Count >= 3)
{
_mapGraphics.FillPolygon(brush, geometry.MapVertices.ToArray());
_mapGraphics.DrawPolygon(pen, geometry.MapVertices.ToArray());
}
else
{
// 确保边界矩形有效
if (geometry.BoundingRect.Width > 0 && geometry.BoundingRect.Height > 0)
{
_mapGraphics.FillRectangle(brush, geometry.BoundingRect);
_mapGraphics.DrawRectangle(pen, geometry.BoundingRect);
}
else
{
// 回退方案:绘制一个基于顶点的简单矩形
if (geometry.MapVertices.Count >= 2)
{
var minX = geometry.MapVertices.Min(p => p.X);
var maxX = geometry.MapVertices.Max(p => p.X);
var minY = geometry.MapVertices.Min(p => p.Y);
var maxY = geometry.MapVertices.Max(p => p.Y);
var rect = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
if (rect.Width > 0 && rect.Height > 0)
{
_mapGraphics.FillRectangle(brush, rect);
_mapGraphics.DrawRectangle(pen, rect);
}
}
}
}
// 绘制顶点和坐标标注
if (geometry.ShowVertexLabels && geometry.ShowDetailedGeometry)
{
for (int i = 0; i < geometry.MapVertices.Count; i++)
{
var mapVertex = geometry.MapVertices[i];
var worldVertex = geometry.WorldVertices[i];
// 绘制顶点标记
var vertexRect = new RectangleF(mapVertex.X - 3, mapVertex.Y - 3, 6, 6);
_mapGraphics.FillEllipse(vertexBrush, vertexRect);
// 绘制坐标标签
var label = $"({worldVertex.X:F1},{worldVertex.Y:F1})";
var labelSize = _mapGraphics.MeasureString(label, labelFont);
// 计算标签位置,避免重叠
var labelX = mapVertex.X + 8;
var labelY = mapVertex.Y - labelSize.Height / 2;
// 如果标签超出边界,调整位置
if (labelX + labelSize.Width > _mapPanel.Width)
labelX = mapVertex.X - labelSize.Width - 8;
if (labelY < 0)
labelY = mapVertex.Y + 8;
if (labelY + labelSize.Height > _mapPanel.Height)
labelY = mapVertex.Y - labelSize.Height - 8;
// 绘制标签背景
var labelRect = new RectangleF(labelX - 2, labelY - 1, labelSize.Width + 4, labelSize.Height + 2);
_mapGraphics.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(200, System.Drawing.Color.White)), labelRect);
_mapGraphics.DrawRectangle(new Pen(System.Drawing.Color.Gray, 1), Rectangle.Round(labelRect));
// 绘制坐标文本
_mapGraphics.DrawString(label, labelFont, labelBrush, labelX, labelY);
}
}
// 绘制通道名称
if (!string.IsNullOrEmpty(geometry.Name))
{
var centerX = geometry.MapVertices.Average(p => p.X);
var centerY = geometry.MapVertices.Average(p => p.Y);
using (var nameFont = new Font("微软雅黑", 10, FontStyle.Bold))
using (var nameBrush = new SolidBrush(System.Drawing.Color.DarkGreen))
{
var nameSize = _mapGraphics.MeasureString(geometry.Name, nameFont);
var nameX = centerX - nameSize.Width / 2;
var nameY = centerY - nameSize.Height / 2;
// 绘制名称背景
var nameRect = new RectangleF(nameX - 2, nameY - 1, nameSize.Width + 4, nameSize.Height + 2);
_mapGraphics.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(180, System.Drawing.Color.Yellow)), nameRect);
// 绘制名称文本
_mapGraphics.DrawString(geometry.Name, nameFont, nameBrush, nameX, nameY);
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制通道几何失败: {ex.Message}");
}
}
/// <summary>
/// 绘制路径线
/// </summary>
private void DrawPathLines()
{
if (_currentRoute.Points.Count < 2) return;
var sortedPoints = _currentRoute.GetSortedPoints();
using (var pen = new Pen(PATH_LINE_COLOR, 2))
{
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var point1 = _coordinateConverter.WorldToMap(sortedPoints[i].Position);
var point2 = _coordinateConverter.WorldToMap(sortedPoints[i + 1].Position);
_mapGraphics.DrawLine(pen,
(float)point1.X, (float)point1.Y,
(float)point2.X, (float)point2.Y);
}
}
}
/// <summary>
/// 绘制路径点
/// </summary>
private void DrawPathPoints()
{
foreach (var point in _currentRoute.Points)
{
var mapPos = _coordinateConverter.WorldToMap(point.Position);
var color = GetPointColor(point.Type);
var isSelected = point == _selectedPoint;
using (var brush = new SolidBrush(color))
using (var pen = new Pen(isSelected ? System.Drawing.Color.Black : System.Drawing.Color.DarkGray, isSelected ? 2 : 1))
{
var rect = new Rectangle(
(int)mapPos.X - POINT_RADIUS,
(int)mapPos.Y - POINT_RADIUS,
POINT_RADIUS * 2,
POINT_RADIUS * 2
);
_mapGraphics.FillEllipse(brush, rect);
_mapGraphics.DrawEllipse(pen, rect);
}
// 绘制点名称
if (!string.IsNullOrEmpty(point.Name))
{
using (var font = new Font("微软雅黑", 8))
using (var brush = new SolidBrush(System.Drawing.Color.Black))
{
var textPos = new PointF((float)mapPos.X + POINT_RADIUS + 2, (float)mapPos.Y - POINT_RADIUS);
_mapGraphics.DrawString(point.Name, font, brush, textPos);
}
}
}
}
/// <summary>
/// 获取路径点颜色
/// </summary>
/// <param name="type">路径点类型</param>
/// <returns>颜色</returns>
private System.Drawing.Color GetPointColor(PathPointType type)
{
switch (type)
{
case PathPointType.StartPoint: return START_POINT_COLOR;
case PathPointType.EndPoint: return END_POINT_COLOR;
case PathPointType.WayPoint: return WAY_POINT_COLOR;
default: return WAY_POINT_COLOR;
}
}
/// <summary>
/// 查找指定位置的路径点
/// </summary>
/// <param name="mapPosition">地图位置</param>
/// <returns>路径点如果没有找到返回null</returns>
private PathPoint FindPointAtPosition(System.Drawing.Point mapPosition)
{
foreach (var point in _currentRoute.Points)
{
var pointMapPos = _coordinateConverter.WorldToMap(point.Position);
var distance = Math.Sqrt(
Math.Pow(mapPosition.X - pointMapPos.X, 2) +
Math.Pow(mapPosition.Y - pointMapPos.Y, 2)
);
if (distance <= POINT_SELECT_RADIUS)
{
return point;
}
}
return null;
}
/// <summary>
/// 更新路径点列表显示
/// </summary>
private void UpdatePointsList()
{
_pointsListBox.Items.Clear();
var sortedPoints = _currentRoute.GetSortedPoints();
foreach (var point in sortedPoints)
{
_pointsListBox.Items.Add(point.ToString());
}
}
/// <summary>
/// 更新选中点的信息显示
/// </summary>
private void UpdateSelectedPointInfo()
{
if (_selectedPoint != null)
{
_pointNameTextBox.Text = _selectedPoint.Name;
_pointTypeComboBox.SelectedIndex = (int)_selectedPoint.Type;
_xCoordinateTextBox.Text = _selectedPoint.Position.X.ToString("F3");
_yCoordinateTextBox.Text = _selectedPoint.Position.Y.ToString("F3");
_zCoordinateTextBox.Text = _selectedPoint.Position.Z.ToString("F3");
_removePointButton.Enabled = true;
_updateCoordinateButton.Enabled = true;
_coordinateGroupBox.Enabled = true;
}
else
{
_pointNameTextBox.Text = "";
_pointTypeComboBox.SelectedIndex = 2;
_xCoordinateTextBox.Text = "";
_yCoordinateTextBox.Text = "";
_zCoordinateTextBox.Text = "";
_removePointButton.Enabled = false;
_updateCoordinateButton.Enabled = false;
_coordinateGroupBox.Enabled = false;
}
}
#region
private void MapPanel_Paint(object sender, PaintEventArgs e)
{
if (_mapBuffer != null)
{
e.Graphics.DrawImage(_mapBuffer, 0, 0);
}
// 绘制调试信息
DrawDebugInfo(e.Graphics);
}
/// <summary>
/// 绘制调试信息
/// </summary>
/// <param name="graphics">绘图对象</param>
private void DrawDebugInfo(System.Drawing.Graphics graphics)
{
try
{
using (var font = new Font("Consolas", 9))
using (var brush = new SolidBrush(System.Drawing.Color.Black))
using (var bgBrush = new SolidBrush(System.Drawing.Color.FromArgb(200, System.Drawing.Color.White)))
{
var info = new List<string>();
// 坐标转换器信息
if (_coordinateConverter != null)
{
double scaleX, scaleY;
_coordinateConverter.GetMapScale(out scaleX, out scaleY);
info.Add($"地图尺寸: {_coordinateConverter.MapWidth:F0} x {_coordinateConverter.MapHeight:F0}");
info.Add($"世界范围: ({_coordinateConverter.ChannelBounds.MinPoint.X:F2},{_coordinateConverter.ChannelBounds.MinPoint.Y:F2}) - ({_coordinateConverter.ChannelBounds.MaxPoint.X:F2},{_coordinateConverter.ChannelBounds.MaxPoint.Y:F2})");
info.Add($"缩放比例: {scaleX:F6} x {scaleY:F6} (m/px)");
}
// 通道信息
info.Add($"通道数量: {_channelItems.Count}");
info.Add($"几何数量: {_channelGeometries.Count}");
// 显示第一个通道的详细信息
if (_channelGeometries.Count > 0)
{
var firstGeometry = _channelGeometries[0];
info.Add($"第一个通道: {firstGeometry.Name}");
info.Add($"世界顶点数: {firstGeometry.WorldVertices.Count}");
info.Add($"地图顶点数: {firstGeometry.MapVertices.Count}");
info.Add($"边界矩形: ({firstGeometry.BoundingRect.X},{firstGeometry.BoundingRect.Y},{firstGeometry.BoundingRect.Width},{firstGeometry.BoundingRect.Height})");
info.Add($"详细几何: {firstGeometry.ShowDetailedGeometry}");
info.Add($"显示标注: {firstGeometry.ShowVertexLabels}");
if (firstGeometry.WorldVertices.Count > 0)
{
var vertex = firstGeometry.WorldVertices[0];
info.Add($"世界顶点示例: ({vertex.X:F2},{vertex.Y:F2},{vertex.Z:F2})");
}
if (firstGeometry.MapVertices.Count > 0)
{
var mapVertex = firstGeometry.MapVertices[0];
info.Add($"地图顶点示例: ({mapVertex.X:F2},{mapVertex.Y:F2})");
}
}
// 路径信息
if (_currentRoute != null)
{
info.Add($"路径点数: {_currentRoute.Points.Count}");
info.Add($"路径长度: {_currentRoute.TotalLength:F3}m");
}
// 绘制信息框
var y = 10;
foreach (var line in info)
{
var size = graphics.MeasureString(line, font);
var rect = new RectangleF(10, y, size.Width + 4, size.Height + 2);
graphics.FillRectangle(bgBrush, rect);
graphics.DrawString(line, font, brush, 12, y + 1);
y += (int)size.Height + 2;
}
}
}
catch (Exception ex)
{
WriteLog($"绘制调试信息失败: {ex.Message}");
}
}
private void MapPanel_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var clickedPoint = FindPointAtPosition(e.Location);
if (clickedPoint != null)
{
// 选中现有点
_selectedPoint = clickedPoint;
UpdateSelectedPointInfo();
PointSelected?.Invoke(this, _selectedPoint);
}
else if (!_isDragging)
{
// 添加新点
AddPointAtPosition(e.Location);
}
RedrawMap();
}
}
private void MapPanel_MouseMove(object sender, MouseEventArgs e)
{
var mapPoint = new MapPoint2D(e.X, e.Y);
var worldPoint = _coordinateConverter.MapToWorld(mapPoint);
// 显示更详细的坐标信息
double scaleX, scaleY;
_coordinateConverter.GetMapScale(out scaleX, out scaleY);
_coordinateLabel.Text = $"坐标: X={worldPoint.X:F2}, Y={worldPoint.Y:F2}, Z={worldPoint.Z:F2} | 比例: {scaleX:F4}m/px";
if (_isDragging && _selectedPoint != null)
{
// 拖拽移动点
_selectedPoint.Position = worldPoint;
UpdateSelectedPointInfo();
RedrawMap();
}
}
private void MapPanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var clickedPoint = FindPointAtPosition(e.Location);
if (clickedPoint != null)
{
_isDragging = true;
_selectedPoint = clickedPoint;
_lastMousePosition = e.Location;
}
}
}
private void MapPanel_MouseUp(object sender, MouseEventArgs e)
{
_isDragging = false;
}
private void MapPanel_Resize(object sender, EventArgs e)
{
if (_mapPanel.Width > 0 && _mapPanel.Height > 0)
{
// 更新坐标转换器的地图尺寸
if (_coordinateConverter != null)
{
_coordinateConverter.UpdateMapSize(_mapPanel.Width, _mapPanel.Height);
}
InitializeMapBuffer();
GenerateChannelOutlines();
RedrawMap();
}
}
private void AddPointButton_Click(object sender, EventArgs e)
{
// 在地图中心添加点
var centerMap = new MapPoint2D(_mapPanel.Width / 2.0, _mapPanel.Height / 2.0);
AddPointAtPosition(new System.Drawing.Point((int)centerMap.X, (int)centerMap.Y));
}
private void RemovePointButton_Click(object sender, EventArgs e)
{
if (_selectedPoint != null)
{
_currentRoute.RemovePoint(_selectedPoint);
PointRemoved?.Invoke(this, _selectedPoint);
_selectedPoint = null;
UpdateSelectedPointInfo();
UpdatePointsList();
RedrawMap();
}
}
private void ClearAllButton_Click(object sender, EventArgs e)
{
if (MessageBox.Show("确定要清空所有路径点吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
_currentRoute.Points.Clear();
_selectedPoint = null;
UpdateSelectedPointInfo();
UpdatePointsList();
RedrawMap();
}
}
private void GeneratePathButton_Click(object sender, EventArgs e)
{
if (_currentRoute.IsValid())
{
PathGenerated?.Invoke(this, _currentRoute);
MessageBox.Show($"路径生成成功!\n总长度: {_currentRoute.TotalLength:F2}米", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("路径无效!必须至少包含一个起点和一个终点。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void UpdateCoordinateButton_Click(object sender, EventArgs e)
{
if (_selectedPoint != null)
{
try
{
double x = double.Parse(_xCoordinateTextBox.Text);
double y = double.Parse(_yCoordinateTextBox.Text);
double z = double.Parse(_zCoordinateTextBox.Text);
_selectedPoint.Position = new Autodesk.Navisworks.Api.Point3D(x, y, z);
UpdatePointsList();
RedrawMap();
}
catch (FormatException)
{
MessageBox.Show("坐标格式错误,请输入有效的数字。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
private void PointsListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (_pointsListBox.SelectedIndex >= 0)
{
var sortedPoints = _currentRoute.GetSortedPoints();
_selectedPoint = sortedPoints[_pointsListBox.SelectedIndex];
UpdateSelectedPointInfo();
RedrawMap();
}
}
private void PointNameTextBox_TextChanged(object sender, EventArgs e)
{
if (_selectedPoint != null)
{
_selectedPoint.Name = _pointNameTextBox.Text;
UpdatePointsList();
RedrawMap();
}
}
private void PointTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (_selectedPoint != null)
{
_selectedPoint.Type = (PathPointType)_pointTypeComboBox.SelectedIndex;
UpdatePointsList();
RedrawMap();
}
}
#endregion
/// <summary>
/// 在指定位置添加路径点
/// </summary>
/// <param name="position">地图位置</param>
private void AddPointAtPosition(System.Drawing.Point position)
{
var mapPoint = new MapPoint2D(position.X, position.Y);
var worldPoint = _coordinateConverter.MapToWorld(mapPoint);
var pointType = (PathPointType)_pointTypeComboBox.SelectedIndex;
var pointName = string.IsNullOrEmpty(_pointNameTextBox.Text) ?
$"{GetPointTypeName(pointType)}{_currentRoute.Points.Count + 1}" :
_pointNameTextBox.Text;
var newPoint = new PathPoint(worldPoint, pointName, pointType);
_currentRoute.AddPoint(newPoint);
_selectedPoint = newPoint;
UpdateSelectedPointInfo();
UpdatePointsList();
PointAdded?.Invoke(this, newPoint);
}
/// <summary>
/// 获取路径点类型名称
/// </summary>
/// <param name="type">路径点类型</param>
/// <returns>类型名称</returns>
private string GetPointTypeName(PathPointType type)
{
switch (type)
{
case PathPointType.StartPoint: return "起点";
case PathPointType.EndPoint: return "终点";
case PathPointType.WayPoint: return "路径点";
default: return "点";
}
}
/// <summary>
/// 释放资源
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
_mapBuffer?.Dispose();
_mapGraphics?.Dispose();
}
base.Dispose(disposing);
}
#region
/// <summary>
/// 验证路径按钮点击事件
/// </summary>
private void BtnValidatePath_Click(object sender, EventArgs e)
{
try
{
if (_currentRoute == null || _currentRoute.Points.Count == 0)
{
statusLabel.Text = "当前没有可验证的路径";
MessageBox.Show("请先创建路径点", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 显示验证进度
statusLabel.Text = "正在验证路径...";
System.Windows.Forms.Application.DoEvents();
// 执行路径验证
var validationResult = _pathPlanningManager.ValidatePath(_currentRoute);
// 显示验证结果
statusLabel.Text = validationResult.IsValid ? "路径验证通过" : "路径验证失败";
var resultDialog = new PathValidationResultDialog(validationResult);
resultDialog.ShowDialog(this);
// 如果验证失败,在地图上高亮显示问题区域
if (!validationResult.IsValid)
{
HighlightValidationIssues(validationResult);
}
}
catch (Exception ex)
{
statusLabel.Text = "路径验证失败";
MessageBox.Show($"路径验证时发生错误:{ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 优化路径按钮点击事件
/// </summary>
private void BtnOptimizePath_Click(object sender, EventArgs e)
{
try
{
if (_currentRoute == null || _currentRoute.Points.Count == 0)
{
statusLabel.Text = "当前没有可优化的路径";
MessageBox.Show("请先创建路径点", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 显示优化选项对话框
var optionsDialog = new PathOptimizationOptionsDialog();
if (optionsDialog.ShowDialog(this) != DialogResult.OK)
{
return;
}
// 显示优化进度
statusLabel.Text = "正在优化路径...";
System.Windows.Forms.Application.DoEvents();
// 执行路径优化
var optimizationResult = _pathPlanningManager.OptimizePath(_currentRoute, optionsDialog.SelectedOptions);
// 显示优化结果
if (optimizationResult.Success)
{
// 更新当前路径为优化后的路径
_currentRoute = optimizationResult.OptimizedRoute;
// 重新绘制地图
_mapPanel.Invalidate();
statusLabel.Text = $"路径优化完成 - 长度减少{optimizationResult.LengthReduction:F3}m";
var resultDialog = new PathOptimizationResultDialog(optimizationResult);
resultDialog.ShowDialog(this);
}
else
{
statusLabel.Text = "路径优化失败";
MessageBox.Show($"路径优化失败:{optimizationResult.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
statusLabel.Text = "路径优化失败";
MessageBox.Show($"路径优化时发生错误:{ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 在地图上高亮显示验证问题区域
/// </summary>
/// <param name="validationResult">验证结果</param>
private void HighlightValidationIssues(PathValidationResult validationResult)
{
// 简化实现:重新绘制地图,使用不同颜色标识有问题的路径段
_mapPanel.Invalidate();
}
/// <summary>
/// 切换详细几何显示
/// </summary>
private void BtnToggleGeometry_Click(object sender, EventArgs e)
{
foreach (var geometry in _channelGeometries)
{
geometry.ShowDetailedGeometry = !geometry.ShowDetailedGeometry;
}
// 更新按钮文本
var anyDetailedShown = _channelGeometries.Any(g => g.ShowDetailedGeometry);
btnToggleGeometry.Text = anyDetailedShown ? "简化显示" : "详细几何";
RedrawMap();
}
/// <summary>
/// 切换坐标标注显示
/// </summary>
private void BtnToggleLabels_Click(object sender, EventArgs e)
{
foreach (var geometry in _channelGeometries)
{
geometry.ShowVertexLabels = !geometry.ShowVertexLabels;
}
// 更新按钮文本
var anyLabelsShown = _channelGeometries.Any(g => g.ShowVertexLabels);
btnToggleLabels.Text = anyLabelsShown ? "隐藏坐标" : "坐标标注";
RedrawMap();
}
/// <summary>
/// 重新计算边界按钮点击事件
/// </summary>
private void BtnRecalculateBounds_Click(object sender, EventArgs e)
{
try
{
// 重新生成通道轮廓
GenerateChannelOutlines();
// 如果有PathPlanningManager重新计算其边界
if (_pathPlanningManager != null)
{
// 设置选中的通道为活动通道,这会触发边界重新计算
var channelCollection = new ModelItemCollection();
foreach (var channel in _channelItems)
{
channelCollection.Add(channel);
}
_pathPlanningManager.SetActiveChannels(channelCollection);
}
// 更新坐标转换器的地图尺寸(以防窗口已调整大小)
if (_coordinateConverter != null)
{
_coordinateConverter.UpdateMapSize(_mapPanel.Width, _mapPanel.Height);
}
// 重新绘制地图
RedrawMap();
statusLabel.Text = "边界已重新计算,通道设置已更新";
}
catch (Exception ex)
{
statusLabel.Text = "重新计算边界失败";
System.Diagnostics.Debug.WriteLine($"重新计算边界失败: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 路径优化选项对话框(简化实现)
/// </summary>
private class PathOptimizationOptionsDialog : Form
{
public PathOptimizationOptions SelectedOptions { get; private set; }
private CheckBox chkRemoveDuplicates;
private CheckBox chkSmoothPath;
private CheckBox chkOptimizeAngles;
private CheckBox chkAdjustToChannels;
public PathOptimizationOptionsDialog()
{
InitializeDialog();
SelectedOptions = PathOptimizationOptions.CreateDefault();
}
private void InitializeDialog()
{
Text = "路径优化选项";
Size = new Size(300, 200);
StartPosition = FormStartPosition.CenterParent;
chkRemoveDuplicates = new CheckBox { Text = "移除重复点", Location = new Point(10, 10), Checked = true };
chkSmoothPath = new CheckBox { Text = "路径平滑", Location = new Point(10, 40), Checked = true };
chkOptimizeAngles = new CheckBox { Text = "优化角度", Location = new Point(10, 70), Checked = true };
chkAdjustToChannels = new CheckBox { Text = "调整到通道中心", Location = new Point(10, 100), Checked = false };
var btnOK = new Button { Text = "确定", Location = new Point(110, 130), DialogResult = DialogResult.OK };
var btnCancel = new Button { Text = "取消", Location = new Point(190, 130), DialogResult = DialogResult.Cancel };
btnOK.Click += (s, e) => {
SelectedOptions.RemoveDuplicatePoints = chkRemoveDuplicates.Checked;
SelectedOptions.SmoothPath = chkSmoothPath.Checked;
SelectedOptions.OptimizeAngles = chkOptimizeAngles.Checked;
SelectedOptions.AdjustToChannels = chkAdjustToChannels.Checked;
};
Controls.AddRange(new Control[] { chkRemoveDuplicates, chkSmoothPath, chkOptimizeAngles, chkAdjustToChannels, btnOK, btnCancel });
}
}
/// <summary>
/// 路径验证结果对话框(简化实现)
/// </summary>
private class PathValidationResultDialog : Form
{
public PathValidationResultDialog(PathValidationResult result)
{
Text = "路径验证结果";
Size = new Size(400, 300);
StartPosition = FormStartPosition.CenterParent;
var textBox = new TextBox
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
ReadOnly = true,
Dock = DockStyle.Fill,
Text = result.GetDetailedReport()
};
var btnClose = new Button
{
Text = "关闭",
Dock = DockStyle.Bottom,
Height = 30,
DialogResult = DialogResult.OK
};
Controls.Add(textBox);
Controls.Add(btnClose);
}
}
/// <summary>
/// 路径优化结果对话框(简化实现)
/// </summary>
private class PathOptimizationResultDialog : Form
{
public PathOptimizationResultDialog(PathOptimizationResult result)
{
Text = "路径优化结果";
Size = new Size(400, 300);
StartPosition = FormStartPosition.CenterParent;
var textBox = new TextBox
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
ReadOnly = true,
Dock = DockStyle.Fill,
Text = result.GetDetailedReport()
};
var btnClose = new Button
{
Text = "关闭",
Dock = DockStyle.Bottom,
Height = 30,
DialogResult = DialogResult.OK
};
Controls.Add(textBox);
Controls.Add(btnClose);
}
}
#endregion
}
}