优化路径分析功能;把资源文件集中到resources目录
This commit is contained in:
parent
77b9da40fc
commit
3138b73a5f
@ -275,6 +275,7 @@
|
||||
<Compile Include="src\UI\WPF\ViewModels\PathAnalysisViewModel.cs" />
|
||||
<Compile Include="src\UI\WPF\ViewModels\TimeTagViewModel.cs" />
|
||||
<Compile Include="src\UI\WPF\ViewModels\BatchTaskManagementViewModel.cs" />
|
||||
<!-- UI - WPF Helpers -->
|
||||
<!-- UI - WPF Collections -->
|
||||
<Compile Include="src\UI\WPF\Collections\ThreadSafeObservableCollection.cs" />
|
||||
<!-- UI - WPF Interfaces -->
|
||||
@ -448,18 +449,25 @@
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets" Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets')" />
|
||||
<ItemGroup>
|
||||
<!-- Localization Files -->
|
||||
<None Include="src\Resources\NavisworksTransportPlugin.name.txt">
|
||||
<None Include="resources\TransportPlugin.name.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Link>NavisworksTransportPlugin.name.txt</Link>
|
||||
<Link>TransportPlugin.name.txt</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- Import NETStandard.Library targets to support .NET Standard 2.0 libraries -->
|
||||
<Import Project="packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" />
|
||||
<ItemGroup>
|
||||
<!-- Configuration Template File -->
|
||||
<None Include="default_config.toml">
|
||||
<!-- Configuration Template File (in resources folder) -->
|
||||
<None Include="resources\default_config.toml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Link>resources\default_config.toml</Link>
|
||||
</None>
|
||||
<!-- Plugin Name File (in resources folder) -->
|
||||
<None Include="resources\TransportPlugin.name.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Link>resources\TransportPlugin.name.txt</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -12,7 +12,12 @@ set "TARGET_DIR=C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\Naviswork
|
||||
if not exist "%TARGET_DIR%" mkdir "%TARGET_DIR%"
|
||||
|
||||
copy "bin\x64\Release\NavisworksTransportPlugin.dll" "%TARGET_DIR%\" >nul
|
||||
if exist "bin\x64\Release\NavisworksTransportPlugin.name.txt" copy "bin\x64\Release\NavisworksTransportPlugin.name.txt" "%TARGET_DIR%\" >nul
|
||||
if exist "bin\x64\Release\default_config.toml" copy "bin\x64\Release\default_config.toml" "%TARGET_DIR%\" >nul
|
||||
|
||||
:: 复制resources文件夹(包含chart.js等本地资源)
|
||||
if exist "bin\x64\Release\resources" (
|
||||
if not exist "%TARGET_DIR%\resources" mkdir "%TARGET_DIR%\resources"
|
||||
copy "bin\x64\Release\resources\*" "%TARGET_DIR%\resources\" >nul
|
||||
echo Resources folder deployed.
|
||||
)
|
||||
|
||||
echo Plugin deployed successfully!
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
## 功能点
|
||||
|
||||
### [2026/2/14]
|
||||
|
||||
1. [x] (优化)实现完整的路径分析功能
|
||||
|
||||
### [2026/2/8]
|
||||
|
||||
1. [x] (功能)增加预计算结果分析和排除建议
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
## 一、项目背景与目标
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
- **应用场景**: 大型装置内进行精密组件物流仿真
|
||||
- **核心目标**: 确保组件能安全到达安装位置(终点)
|
||||
- **最高优先级**: 减少碰撞(安全性)
|
||||
@ -16,6 +17,7 @@
|
||||
- **不涉及**: 经济成本
|
||||
|
||||
### 1.2 设计原则
|
||||
|
||||
1. **实用优先**: 指标不在于多,而在于有用
|
||||
2. **聚焦终点**: 核心目标是"找出到同一安装位置的最佳路径"
|
||||
3. **可解释性**: 每个指标和评分都要有明确的物理意义
|
||||
@ -27,11 +29,11 @@
|
||||
|
||||
### 2.1 三种分析策略
|
||||
|
||||
| 策略 | 权重配置(安全/效率/转弯/曲折/冗余) | 适用场景 |
|
||||
|-----|-----------------------------------|---------|
|
||||
| **安全优先** | 50% / 20% / 10% / 10% / 10% | 精密/易损组件,首次运输 |
|
||||
| **效率优先** | 20% / 40% / 15% / 15% / 10% | 紧急任务,多次往返 |
|
||||
| **平衡模式** | 35% / 30% / 10% / 15% / 10% | 通用场景(默认) |
|
||||
| 策略 | 权重配置(安全/效率/转弯/直达) | 适用场景 |
|
||||
|-----|--------------------------------|---------|
|
||||
| **安全优先** | 50% / 30% / 10% / 10% | 精密/易损组件,首次运输 |
|
||||
| **效率优先** | 20% / 50% / 15% / 15% | 紧急任务,多次往返 |
|
||||
| **平衡模式** | 35% / 35% / 15% / 15% | 通用场景(默认) |
|
||||
|
||||
### 2.2 权重配置代码
|
||||
|
||||
@ -42,19 +44,19 @@ public static class AnalysisStrategies
|
||||
public const string EfficiencyFirst = "效率优先";
|
||||
public const string Balanced = "平衡模式";
|
||||
|
||||
// 权重顺序: 安全、效率、转弯、曲折、冗余
|
||||
// 权重顺序: 安全、效率、转弯、直达
|
||||
public static readonly Dictionary<string, double[]> Weights = new Dictionary<string, double[]>
|
||||
{
|
||||
[SafetyFirst] = new[] { 0.50, 0.20, 0.10, 0.10, 0.10 },
|
||||
[EfficiencyFirst] = new[] { 0.20, 0.40, 0.15, 0.15, 0.10 },
|
||||
[Balanced] = new[] { 0.35, 0.30, 0.10, 0.15, 0.10 }
|
||||
[SafetyFirst] = new[] { 0.50, 0.30, 0.10, 0.10 },
|
||||
[EfficiencyFirst] = new[] { 0.20, 0.50, 0.15, 0.15 },
|
||||
[Balanced] = new[] { 0.35, 0.35, 0.15, 0.15 }
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、指标体系(5维度)
|
||||
## 三、指标体系(4维度)
|
||||
|
||||
### 3.1 安全性(碰撞风险指数)- 权重最高
|
||||
|
||||
@ -108,7 +110,7 @@ RadiusPenalty = MinRadius < 2.0 ? 20 : 0;
|
||||
TurnDifficultyScore = Max(0, 100 - TurnPenalty - RadiusPenalty);
|
||||
```
|
||||
|
||||
### 3.4 平顺性(路径曲折度)
|
||||
### 3.4 直达性(路径曲折度)
|
||||
|
||||
```csharp
|
||||
// 计算起点到终点的直线距离
|
||||
@ -123,27 +125,7 @@ Tortuosity = TotalLength / StraightDistance;
|
||||
TortuosityScore = Max(0, 100 - (Tortuosity - 1.0) * 50);
|
||||
```
|
||||
|
||||
### 3.5 冗余度(通道冗余度)
|
||||
|
||||
```csharp
|
||||
// 获取路径经过的通道
|
||||
Channels = GetChannelsAlongPath(this);
|
||||
|
||||
// 通道最小限宽限高
|
||||
MinChannelWidth = Channels.Min(c => c.WidthLimit);
|
||||
MinChannelHeight = Channels.Min(c => c.HeightLimit);
|
||||
|
||||
// 车辆实际尺寸(含安全间隙)
|
||||
EffectiveVehicleWidth = MaxVehicleWidth + SafetyMargin;
|
||||
EffectiveVehicleHeight = MaxVehicleHeight + SafetyMargin;
|
||||
|
||||
// 冗余率
|
||||
WidthRedundancy = (MinChannelWidth - EffectiveVehicleWidth) / EffectiveVehicleWidth;
|
||||
HeightRedundancy = (MinChannelHeight - EffectiveVehicleHeight) / EffectiveVehicleHeight;
|
||||
|
||||
// 冗余度分(0-100)
|
||||
RedundancyScore = Min(100, (WidthRedundancy + HeightRedundancy) / 2 * 100);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -234,6 +216,7 @@ public PathRoute FindBestPathInGroup(EndpointGroup group, string strategy)
|
||||
## 五、碰撞热点计算
|
||||
|
||||
### 5.1 热点定义
|
||||
|
||||
- **范围**: 3米半径球体
|
||||
- **阈值**: 范围内 ≥2 次碰撞
|
||||
- **数据来源**: `ClashDetectiveCollisionObjects` 表的 `Item1PosX/Y/Z`
|
||||
@ -295,7 +278,7 @@ public List<CollisionHotspot> DetectHotspots(List<CollisionResult> collisions, d
|
||||
| **安全建议** | 碰撞数>0 | 发现X次碰撞,其中Y个热点,建议检查碰撞位置 |
|
||||
| **效率建议** | 长度差异率>30% | 该路径比组内最短路径长X%,建议优化路线 |
|
||||
| **转弯建议** | 转弯次数>3 | 路径包含X个转弯,建议减少急转弯 |
|
||||
| **冗余建议** | 冗余度<20% | 通道余量较小,建议确认车辆尺寸匹配 |
|
||||
| **直达建议** | 直达性<70% | 路径较为曲折,建议考虑更直接的路线 |
|
||||
| **组内对比** | 组内路径>1 | 本组共X条路径,推荐【路径名】为最佳选择 |
|
||||
|
||||
### 6.2 建议生成示例
|
||||
@ -344,8 +327,7 @@ public List<string> GenerateSuggestions(PathDetailedAnalysis analysis, EndpointG
|
||||
-- AnalysisResults 表扩展字段
|
||||
ALTER TABLE AnalysisResults ADD COLUMN
|
||||
TurnDifficultyScore REAL, -- 转弯难度分
|
||||
TortuosityScore REAL, -- 曲折度分
|
||||
RedundancyScore REAL, -- 冗余度分
|
||||
TortuosityScore REAL, -- 直达性分
|
||||
HotspotCount INTEGER, -- 热点数量
|
||||
AnalysisStrategy TEXT, -- 分析策略
|
||||
GroupId TEXT, -- 所属终点组ID
|
||||
@ -399,16 +381,15 @@ CREATE TABLE IF NOT EXISTS CollisionHotspots (
|
||||
| 任务 | 文件 | 说明 |
|
||||
|-----|------|------|
|
||||
| 2.1 ViewModel更新 | `src/UI/WPF/ViewModels/PathAnalysisViewModel.cs` | 修改,增加新属性和命令 |
|
||||
| 2.2 对话框更新 | `src/UI/WPF/Views/PathAnalysisDialog.xaml` | 修改,增加可视化元素 |
|
||||
| 2.3 图表组件 | `src/UI/WPF/Views/PathAnalysisCharts.xaml` | 新建,雷达图/柱状图 |
|
||||
| 2.2 对话框更新 | `src/UI/WPF/Views/PathAnalysisDialog.xaml` | 修改,增加Canvas图表区域 |
|
||||
| 2.3 图表绘制 | `src/UI/WPF/Views/PathAnalysisDialog.xaml.cs` | 修改,Canvas自绘柱状图和雷达图 |
|
||||
|
||||
### Phase 3: HTML报告(第三步)
|
||||
|
||||
| 任务 | 文件 | 说明 |
|
||||
|-----|------|------|
|
||||
| 3.1 报告生成器 | `src/Core/PathAnalysisReportGenerator.cs` | 新建,HTML生成逻辑 |
|
||||
| 3.2 Chart.js部署 | `resources/js/chart.min.js` | 下载本地Chart.js |
|
||||
| 3.3 报告模板 | `resources/templates/` | 新建,HTML模板文件 |
|
||||
| 3.2 报告样式 | 嵌入式CSS | 使用内联样式,无需外部依赖 |
|
||||
|
||||
---
|
||||
|
||||
@ -425,16 +406,14 @@ public double CalculateWeightedScore(PathDetailedAnalysis analysis, string strat
|
||||
double safety = analysis.SafetyScore; // 安全
|
||||
double efficiency = analysis.EfficiencyScore; // 效率
|
||||
double turn = analysis.TurnDifficultyScore; // 转弯
|
||||
double tortuosity = analysis.TortuosityScore; // 曲折
|
||||
double redundancy = analysis.RedundancyScore; // 冗余
|
||||
double tortuosity = analysis.TortuosityScore; // 直达
|
||||
|
||||
// 加权计算
|
||||
double weightedScore =
|
||||
safety * weights[0] +
|
||||
efficiency * weights[1] +
|
||||
turn * weights[2] +
|
||||
tortuosity * weights[3] +
|
||||
redundancy * weights[4];
|
||||
tortuosity * weights[3];
|
||||
|
||||
return Math.Round(weightedScore, 1);
|
||||
}
|
||||
@ -464,7 +443,6 @@ public PathDetailedAnalysis AnalyzePath(PathRoute route, AnalysisContext context
|
||||
analysis.EfficiencyScore = CalculateEfficiencyScore(route, context.GroupMinTime);
|
||||
analysis.TurnDifficultyScore = CalculateTurnDifficultyScore(route.Edges);
|
||||
analysis.TortuosityScore = CalculateTortuosityScore(route);
|
||||
analysis.RedundancyScore = CalculateRedundancyScore(route, context.Channels);
|
||||
|
||||
// 4. 计算综合评分
|
||||
analysis.WeightedScore = CalculateWeightedScore(analysis, context.Strategy);
|
||||
@ -484,35 +462,46 @@ public PathDetailedAnalysis AnalyzePath(PathRoute route, AnalysisContext context
|
||||
| 路径分析 - 多路径对比 [关闭] |
|
||||
+----------------------------------------------------------+
|
||||
| +----------------+ +------------------+ +-----------+ |
|
||||
| | 路径选择 | | 对比分析表格 | | 分析结果 | |
|
||||
| | - 路径A | | 名称|安全|效率|... | | 最佳路径 | |
|
||||
| | - 路径B [x] | | A | 90 | 85 |... | | 优化建议 | |
|
||||
| | - 路径C [x] | | B |100 | 70 |... | | ... | |
|
||||
| | | | C | 80 | 90 |... | | | |
|
||||
| | [全选][清空] | +------------------+ +-----------+ |
|
||||
| | | +------------------+ |
|
||||
| | 策略: | | 雷达图可视化 | |
|
||||
| | ○ 安全优先 | | | |
|
||||
| | ○ 效率优先 | +------------------+ |
|
||||
| | ● 平衡模式 | +------------------+ |
|
||||
| | | | 同终点组分析 | |
|
||||
| | [开始分析] | | 组1: 终点A (3条) | |
|
||||
| +----------------+ | - 路径B [推荐] | |
|
||||
| | 路径选择 | | 🏆 推荐最佳路径 | | 💡 优化建议| |
|
||||
| | - 路径A | | 路径名称 | | 建议1... | |
|
||||
| | - 路径B [x] | | 长度: XXm | 评分 | | 建议2... | |
|
||||
| | - 路径C [x] | +------------------+ | ... | |
|
||||
| | | +------------------+ +-----------+ |
|
||||
| | [全选][清空] | | 📊 多路径对比图表 | |
|
||||
| | | | +--------------+ | |
|
||||
| | 策略: | | | 柱状图 | | |
|
||||
| | ○ 安全优先 | | | (4维度对比) | | |
|
||||
| | ○ 效率优先 | | +--------------+ | |
|
||||
| | ● 平衡模式 | | +--------------+ | |
|
||||
| | | | | 雷达图 | | |
|
||||
| | [开始分析] | | | (组内对比) | | |
|
||||
| +----------------+ +------------------+ |
|
||||
| +------------------+ |
|
||||
| | 🎯 同终点路径组 | |
|
||||
| | 组1: 终点 (2条) | |
|
||||
| | - 路径B (最佳) | |
|
||||
| | - 路径A | |
|
||||
| | - 路径C | |
|
||||
| +------------------+ |
|
||||
+----------------------------------------------------------+
|
||||
| [导出报告] [关闭] |
|
||||
+----------------------------------------------------------+
|
||||
```
|
||||
|
||||
### 11.2 可视化元素
|
||||
### 11.2 可视化元素(WPF Canvas自绘)
|
||||
|
||||
1. **雷达图**: 展示单条路径5维度分数
|
||||
2. **柱状图**: 组内路径长度/时间对比
|
||||
3. **表格**: 所有路径的详细指标
|
||||
4. **推荐卡片**: 高亮显示最佳路径
|
||||
5. **热点标记**: 在路径上标注碰撞热点位置
|
||||
1. **柱状图**: 使用WPF Canvas绘制,展示各路径4维度分数对比(安全/效率/转弯/直达)
|
||||
- 每个柱子显示具体分数
|
||||
- 路径名称水平显示在柱组下方
|
||||
- 右上角显示图例
|
||||
|
||||
2. **雷达图**: 使用WPF Canvas绘制,展示选中组内所有路径的4维度表现
|
||||
- 五边形网格背景
|
||||
- 不同颜色区分各路径
|
||||
- 最佳路径用粗线标识
|
||||
|
||||
3. **推荐卡片**: 显示最佳路径名称、长度和综合评分
|
||||
|
||||
4. **优化建议列表**: 分类显示安全、效率、转弯等建议
|
||||
|
||||
---
|
||||
|
||||
@ -524,15 +513,15 @@ public PathDetailedAnalysis AnalyzePath(PathRoute route, AnalysisContext context
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>路径分析报告</title>
|
||||
<!-- 本地Chart.js -->
|
||||
<script src="./js/chart.min.js"></script>
|
||||
<style>
|
||||
/* 简洁专业风格(蓝白配色) */
|
||||
:root { --primary: #2c5aa0; --success: #28a745; --warning: #ffc107; --danger: #dc3545; }
|
||||
body { font-family: 'Microsoft YaHei', Arial; margin: 40px; }
|
||||
.header { text-align: center; border-bottom: 3px solid var(--primary); padding-bottom: 20px; }
|
||||
.best-path-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 12px; }
|
||||
.metric-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px; }
|
||||
.score-bar-container { background: #e9ecef; height: 24px; border-radius: 12px; position: relative; }
|
||||
.score-bar { height: 100%; border-radius: 12px; }
|
||||
.score-text { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-weight: bold; }
|
||||
.comparison-table { width: 100%; border-collapse: collapse; }
|
||||
.comparison-table th { background: var(--primary); color: white; padding: 12px; }
|
||||
/* ... */
|
||||
@ -541,15 +530,15 @@ public PathDetailedAnalysis AnalyzePath(PathRoute route, AnalysisContext context
|
||||
<body>
|
||||
<!-- 1. 头部 -->
|
||||
<!-- 2. 执行摘要+最佳路径 -->
|
||||
<!-- 3. 雷达图 -->
|
||||
<!-- 4. 同终点组分析 -->
|
||||
<!-- 5. 详细数据表格 -->
|
||||
<!-- 6. 优化建议 -->
|
||||
<!-- 7. 技术参数 -->
|
||||
<!-- 3. 同终点组分析 -->
|
||||
<!-- 4. 详细数据表格(带分数条) -->
|
||||
<!-- 5. 优化建议 -->
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**说明**: HTML报告使用纯CSS样式,无需外部JavaScript库,可离线打开。
|
||||
|
||||
---
|
||||
|
||||
## 十三、风险评估与应对
|
||||
@ -566,25 +555,43 @@ public PathDetailedAnalysis AnalyzePath(PathRoute route, AnalysisContext context
|
||||
## 十四、验收标准
|
||||
|
||||
### 14.1 Phase 1 验收
|
||||
|
||||
- [ ] 能正确计算5维度分数
|
||||
- [ ] 能正确检测碰撞热点(3米范围)
|
||||
- [ ] 能按策略计算加权评分
|
||||
- [ ] 数据能正确保存到数据库
|
||||
|
||||
### 14.2 Phase 2 验收
|
||||
- [ ] UI能显示5维度雷达图
|
||||
|
||||
- [ ] UI能显示4维度柱状图(WPF Canvas绘制)
|
||||
- [ ] UI能显示雷达图(WPF Canvas绘制)
|
||||
- [ ] 同终点组能正确分组(2米阈值)
|
||||
- [ ] 能正确标识组内最佳路径
|
||||
- [ ] 优化建议具体且可执行
|
||||
|
||||
### 14.3 Phase 3 验收
|
||||
- [ ] HTML报告能离线打开(使用本地Chart.js)
|
||||
|
||||
- [ ] HTML报告能离线打开(纯CSS样式,无外部依赖)
|
||||
- [ ] 报告包含所有必要信息
|
||||
- [ ] 图表能正确显示
|
||||
- [ ] 表格分数条能正确显示
|
||||
- [ ] 样式符合专业报告标准
|
||||
|
||||
---
|
||||
|
||||
## 十五、资源文件路径
|
||||
|
||||
所有资源文件统一存放在 `resources` 目录下:
|
||||
|
||||
| 文件 | 路径 | 说明 |
|
||||
|-----|------|------|
|
||||
| 默认配置 | `resources/default_config.toml` | 系统默认配置模板 |
|
||||
| 插件名称 | `resources/TransportPlugin.name.txt` | 插件显示名称 |
|
||||
| 单位立方体 | `resources/unit_cube.nwc` | 虚拟车辆碰撞检测用 |
|
||||
|
||||
**部署说明**: 编译时资源文件会自动复制到输出目录,部署脚本会将整个 `resources` 文件夹复制到插件目录。
|
||||
|
||||
---
|
||||
|
||||
## 附录:参考文件
|
||||
|
||||
- 现有碰撞报告生成器: `src/Utils/CollisionReportHtmlGenerator.cs`
|
||||
|
||||
29
resources/TransportPlugin.name.txt
Normal file
29
resources/TransportPlugin.name.txt
Normal file
@ -0,0 +1,29 @@
|
||||
# Navisworks Transport Plugin Localization File
|
||||
# This file contains localized strings for the plugin
|
||||
|
||||
# Plugin Display Names
|
||||
HelloWorldText=物流路径规划插件已加载
|
||||
PluginDisplayName=物流路径规划
|
||||
PluginToolTip=物流路径规划和动画仿真插件
|
||||
|
||||
# Tab Names
|
||||
ModelSettingsTab=类别设置
|
||||
PathEditingTab=路径编辑
|
||||
AnimationControlTab=检测动画
|
||||
SystemManagementTab=系统管理
|
||||
|
||||
# Button Labels
|
||||
ShowAllButton=显示全部
|
||||
HideAllButton=隐藏全部
|
||||
RefreshButton=刷新
|
||||
NewPathButton=新建路径
|
||||
StartEditButton=开始编辑
|
||||
StartAnimationButton=开始动画
|
||||
HelpButton=帮助
|
||||
AboutButton=关于
|
||||
|
||||
# Status Messages
|
||||
InitializingPlugin=正在初始化插件...
|
||||
PluginReady=插件就绪
|
||||
SelectModelsInstruction=请在主界面中点击选择模型
|
||||
OpenModelInstruction=请先打开一个Navisworks模型文件
|
||||
@ -1,48 +0,0 @@
|
||||
# Unit Cube 1m x 1m x 1m
|
||||
# Bottom center at origin (0, 0, 0)
|
||||
# For Navisworks Virtual Vehicle
|
||||
|
||||
# Vertices (8 corners)
|
||||
# Bottom face (Z = 0)
|
||||
v -0.5 -0.5 0.0
|
||||
v 0.5 -0.5 0.0
|
||||
v 0.5 0.5 0.0
|
||||
v -0.5 0.5 0.0
|
||||
# Top face (Z = 1)
|
||||
v -0.5 -0.5 1.0
|
||||
v 0.5 -0.5 1.0
|
||||
v 0.5 0.5 1.0
|
||||
v -0.5 0.5 1.0
|
||||
|
||||
# Normals
|
||||
vn 0 0 -1
|
||||
vn 0 0 1
|
||||
vn 0 -1 0
|
||||
vn 0 1 0
|
||||
vn -1 0 0
|
||||
vn 1 0 0
|
||||
|
||||
# Faces (6 faces, 2 triangles each)
|
||||
# Bottom face (Z = 0, normal -Z)
|
||||
f 1//1 3//1 2//1
|
||||
f 1//1 4//1 3//1
|
||||
|
||||
# Top face (Z = 1, normal +Z)
|
||||
f 5//2 6//2 7//2
|
||||
f 5//2 7//2 8//2
|
||||
|
||||
# Front face (Y = -0.5, normal -Y)
|
||||
f 1//3 2//3 6//3
|
||||
f 1//3 6//3 5//3
|
||||
|
||||
# Back face (Y = 0.5, normal +Y)
|
||||
f 3//4 4//4 8//4
|
||||
f 3//4 8//4 7//4
|
||||
|
||||
# Left face (X = -0.5, normal -X)
|
||||
f 1//5 5//5 8//5
|
||||
f 1//5 8//5 4//5
|
||||
|
||||
# Right face (X = 0.5, normal +X)
|
||||
f 2//6 3//6 7//6
|
||||
f 2//6 7//6 6//6
|
||||
@ -130,7 +130,7 @@ namespace NavisworksTransport.Core.Config
|
||||
{
|
||||
// 从插件当前目录获取模板文件
|
||||
var pluginDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
return Path.Combine(pluginDirectory, "default_config.toml");
|
||||
return Path.Combine(pluginDirectory, "resources", "default_config.toml");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -198,11 +198,13 @@ namespace NavisworksTransport.Core
|
||||
.score-bar.low { background: #DC3545; }
|
||||
.score-text {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
transform: translate(-50%, -50%);
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
text-shadow: 0 0 2px rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
/* 建议样式 */
|
||||
@ -363,7 +365,6 @@ namespace NavisworksTransport.Core
|
||||
sb.AppendLine(" <tr>");
|
||||
sb.AppendLine(" <th>路径名称</th>");
|
||||
sb.AppendLine(" <th>长度(m)</th>");
|
||||
sb.AppendLine(" <th>时间(s)</th>");
|
||||
sb.AppendLine(" <th>碰撞</th>");
|
||||
sb.AppendLine(" <th>安全分</th>");
|
||||
sb.AppendLine(" <th>效率分</th>");
|
||||
|
||||
@ -379,13 +379,11 @@ namespace NavisworksTransport.Core
|
||||
var assemblyLocation = Assembly.GetExecutingAssembly().Location;
|
||||
var pluginDir = Path.GetDirectoryName(assemblyLocation);
|
||||
|
||||
// 尝试多个可能的位置
|
||||
// 尝试多个可能的位置(现在统一放在resources目录下)
|
||||
var possiblePaths = new[]
|
||||
{
|
||||
Path.Combine(pluginDir, "resources", "unit_cube.nwc"),
|
||||
Path.Combine(pluginDir, "unit_cube.nwc"),
|
||||
Path.Combine(pluginDir, "..", "resources", "unit_cube.nwc"),
|
||||
// 开发时的位置
|
||||
// 开发时的备用位置
|
||||
@"c:\Users\Tellme\apps\NavisworksTransport\resources\unit_cube.nwc"
|
||||
};
|
||||
|
||||
|
||||
@ -11,6 +11,15 @@ using NavisworksTransport.Core.Models;
|
||||
|
||||
namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// 分析完成事件参数
|
||||
/// </summary>
|
||||
public class AnalysisCompletedEventArgs : EventArgs
|
||||
{
|
||||
public List<EndpointGroupViewModel> EndpointGroups { get; set; }
|
||||
public EndpointGroupViewModel SelectedGroup { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 路径分析视图模型 - 扩展版
|
||||
/// 支持多维度评分和同终点组分析
|
||||
@ -140,6 +149,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// </summary>
|
||||
public ObservableCollection<DimensionScoreViewModel> DimensionScores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有分析结果(用于控制图表显示)
|
||||
/// </summary>
|
||||
public bool HasAnalysisResults => EndpointGroups != null && EndpointGroups.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// 分析完成事件(用于通知UI绘制图表)
|
||||
/// </summary>
|
||||
public event EventHandler<AnalysisCompletedEventArgs> AnalysisCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// 命令
|
||||
/// </summary>
|
||||
@ -385,6 +404,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Info($"[路径分析UI] 选中第一个组: {SelectedGroup.GroupName}");
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(HasAnalysisResults));
|
||||
|
||||
// 触发分析完成事件,通知UI绘制图表
|
||||
AnalysisCompleted?.Invoke(this, new AnalysisCompletedEventArgs
|
||||
{
|
||||
EndpointGroups = EndpointGroups.ToList(),
|
||||
SelectedGroup = SelectedGroup
|
||||
});
|
||||
|
||||
LogManager.Info($"[路径分析UI] 更新完成: EndpointGroups={EndpointGroups.Count}, Suggestions={CategorizedSuggestions.Count}");
|
||||
}
|
||||
|
||||
@ -411,6 +439,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
SelectedPathAnalysis = SelectedGroup.BestPath;
|
||||
UpdateDimensionScores(SelectedGroup.BestPath);
|
||||
|
||||
// 选中组变更时触发事件(更新雷达图)
|
||||
AnalysisCompleted?.Invoke(this, new AnalysisCompletedEventArgs
|
||||
{
|
||||
EndpointGroups = EndpointGroups.ToList(),
|
||||
SelectedGroup = SelectedGroup
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -194,27 +194,19 @@ NavisworksTransport 路径规划分析对话框 V2
|
||||
<!-- 最佳路径卡片 -->
|
||||
<Border Style="{StaticResource BestPathCardStyle}"
|
||||
Visibility="{Binding RecommendedPath, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock FontSize="12" Foreground="#FF28A745" FontWeight="SemiBold">
|
||||
🏆 推荐最佳路径
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding RecommendedPath.Name}" FontSize="18" FontWeight="Bold"
|
||||
Foreground="#FF2C3E50" Margin="0,5"/>
|
||||
<TextBlock FontSize="12" Foreground="#FF6C757D">
|
||||
<Run Text="长度: "/>
|
||||
<Run Text="{Binding RecommendedPath.Length, StringFormat={}{0:F1}m}"/>
|
||||
<Run Text=" | 评分: "/>
|
||||
<Run Text="{Binding RecommendedPath.Score, StringFormat={}{0:F1}}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Content="高亮显示" Command="{Binding HighlightBestPathCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}" Width="90" Height="32"/>
|
||||
</Grid>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="12" Foreground="#FF28A745" FontWeight="SemiBold">
|
||||
🏆 推荐最佳路径
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding RecommendedPath.Name}" FontSize="18" FontWeight="Bold"
|
||||
Foreground="#FF2C3E50" Margin="0,5"/>
|
||||
<TextBlock FontSize="12" Foreground="#FF6C757D">
|
||||
<Run Text="长度: "/>
|
||||
<Run Text="{Binding RecommendedPath.Length, StringFormat={}{0:F1}m}"/>
|
||||
<Run Text=" | 评分: "/>
|
||||
<Run Text="{Binding RecommendedPath.Score, StringFormat={}{0:F1}}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 同终点组列表 -->
|
||||
@ -252,31 +244,35 @@ NavisworksTransport 路径规划分析对话框 V2
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 五维度分数展示 -->
|
||||
<Border Style="{StaticResource CardStyle}" Margin="0,10,0,0">
|
||||
<!-- 图表展示区域 -->
|
||||
<Border Style="{StaticResource CardStyle}" Margin="0,10,0,0"
|
||||
Visibility="{Binding HasAnalysisResults, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="📊 四维度评分" FontSize="14" FontWeight="Bold"
|
||||
<TextBlock Text="📊 多路径对比图表" FontSize="14" FontWeight="Bold"
|
||||
Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,10"/>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding DimensionScores}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{Binding Name}" FontSize="11"
|
||||
VerticalAlignment="Center"/>
|
||||
<ProgressBar Grid.Column="1" Value="{Binding Score}"
|
||||
Maximum="{Binding MaxScore}" Style="{StaticResource ScoreBarStyle}"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Score, StringFormat={}{0:F1}}"
|
||||
FontSize="11" FontWeight="Bold" HorizontalAlignment="Right"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<!-- 柱状图 -->
|
||||
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="4" Height="280" Margin="0,0,0,10">
|
||||
<Grid>
|
||||
<TextBlock Text="各维度分数对比" FontSize="12" FontWeight="Bold"
|
||||
Foreground="#2C5AA0" HorizontalAlignment="Center" Margin="0,5"/>
|
||||
<Canvas x:Name="BarChartCanvas" Margin="10,30,10,10"
|
||||
Width="530" Height="240"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- 雷达图 -->
|
||||
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="4" Height="200">
|
||||
<Grid>
|
||||
<TextBlock Text="雷达图对比" FontSize="12" FontWeight="Bold"
|
||||
Foreground="#2C5AA0" HorizontalAlignment="Center" Margin="0,5"/>
|
||||
<Canvas x:Name="RadarChartCanvas" Margin="10,30,10,10"
|
||||
Width="530" Height="160"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="提示:柱形图对比各路径维度得分,雷达图展示选中组内所有路径的四维度表现"
|
||||
FontSize="10" Foreground="#FF6C757D" Margin="0,8,0,0" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
@ -318,9 +314,6 @@ NavisworksTransport 路径规划分析对话框 V2
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<Button Grid.Row="2" Content="导出分析报告" Command="{Binding ExportReportCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}" Height="38" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
@ -329,8 +322,8 @@ NavisworksTransport 路径规划分析对话框 V2
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#FFE0E0E0" BorderThickness="0,1,0,0"
|
||||
Padding="20,12">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="重新分析" Style="{StaticResource SecondaryButtonStyle}" Width="100" Margin="0,0,10,0"/>
|
||||
<Button Content="应用推荐" Style="{StaticResource ActionButtonStyle}" Width="100" Margin="0,0,10,0"/>
|
||||
<Button Content="导出报告" Command="{Binding ExportReportCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}" Width="100" Margin="0,0,10,0"/>
|
||||
<Button Content="关闭" Click="CloseButton_Click" Style="{StaticResource SecondaryButtonStyle}" Width="80"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using NavisworksTransport.Core;
|
||||
using NavisworksTransport.Core.Models;
|
||||
using NavisworksTransport.UI.WPF.ViewModels;
|
||||
|
||||
namespace NavisworksTransport.UI.WPF.Views
|
||||
@ -26,7 +31,12 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
try
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = new ViewModels.PathAnalysisViewModel();
|
||||
var viewModel = new ViewModels.PathAnalysisViewModel();
|
||||
DataContext = viewModel;
|
||||
|
||||
// 订阅分析完成事件,绘制图表
|
||||
viewModel.AnalysisCompleted += OnAnalysisCompleted;
|
||||
|
||||
LogManager.Info("PathAnalysisDialog初始化完成");
|
||||
Title = $"路径规划分析 - 多路径对比 [{DateTime.Now:MM-dd HH:mm}]";
|
||||
}
|
||||
@ -36,6 +46,339 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分析完成时绘制图表
|
||||
/// </summary>
|
||||
private void OnAnalysisCompleted(object sender, AnalysisCompletedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
DrawBarChart(e.EndpointGroups);
|
||||
DrawRadarChart(e.SelectedGroup);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"绘制图表失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制柱状图
|
||||
/// </summary>
|
||||
private void DrawBarChart(List<EndpointGroupViewModel> groups)
|
||||
{
|
||||
if (groups == null || groups.Count == 0) return;
|
||||
|
||||
var canvas = BarChartCanvas;
|
||||
canvas.Children.Clear();
|
||||
|
||||
// 收集所有路径数据
|
||||
var allPaths = new List<PathDetailedAnalysis>();
|
||||
foreach (var group in groups)
|
||||
{
|
||||
allPaths.AddRange(group.PathAnalyses);
|
||||
}
|
||||
|
||||
if (allPaths.Count == 0) return;
|
||||
|
||||
// 限制显示数量
|
||||
var displayPaths = allPaths.Take(8).ToList();
|
||||
|
||||
double canvasWidth = canvas.Width;
|
||||
double canvasHeight = canvas.Height;
|
||||
double marginLeft = 60;
|
||||
double marginRight = 20;
|
||||
double marginTop = 30;
|
||||
double marginBottom = 50;
|
||||
double chartWidth = canvasWidth - marginLeft - marginRight;
|
||||
double chartHeight = canvasHeight - marginTop - marginBottom;
|
||||
|
||||
// 绘制坐标轴
|
||||
DrawAxis(canvas, marginLeft, marginTop, chartWidth, chartHeight);
|
||||
|
||||
// 四个维度的颜色
|
||||
var colors = new[] {
|
||||
Color.FromRgb(40, 167, 69), // 安全性 - 绿
|
||||
Color.FromRgb(0, 123, 255), // 效率 - 蓝
|
||||
Color.FromRgb(255, 193, 7), // 转弯 - 黄
|
||||
Color.FromRgb(23, 162, 184) // 直达性 - 青
|
||||
};
|
||||
var dimensionNames = new[] { "安全", "效率", "转弯", "直达" };
|
||||
|
||||
int barGroupCount = displayPaths.Count;
|
||||
double groupWidth = chartWidth / barGroupCount;
|
||||
double barWidth = groupWidth * 0.7 / 4; // 4个柱子
|
||||
|
||||
for (int i = 0; i < displayPaths.Count; i++)
|
||||
{
|
||||
var analysis = displayPaths[i];
|
||||
double groupX = marginLeft + i * groupWidth + groupWidth * 0.15;
|
||||
double[] scores = new[] { analysis.SafetyScore, analysis.EfficiencyScore,
|
||||
analysis.TurnDifficultyScore, analysis.TortuosityScore };
|
||||
|
||||
// 绘制每个维度的柱子
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
double barHeight = scores[j] / 100.0 * chartHeight;
|
||||
double barX = groupX + j * barWidth;
|
||||
double barY = marginTop + chartHeight - barHeight;
|
||||
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = barWidth - 2,
|
||||
Height = barHeight,
|
||||
Fill = new SolidColorBrush(colors[j]),
|
||||
RadiusX = 2,
|
||||
RadiusY = 2
|
||||
};
|
||||
Canvas.SetLeft(rect, barX);
|
||||
Canvas.SetTop(rect, barY);
|
||||
canvas.Children.Add(rect);
|
||||
|
||||
// 在柱子上方显示分数
|
||||
var scoreText = new TextBlock
|
||||
{
|
||||
Text = scores[j].ToString("F0"),
|
||||
FontSize = 8,
|
||||
FontWeight = FontWeights.Bold,
|
||||
Foreground = new SolidColorBrush(colors[j]),
|
||||
TextAlignment = TextAlignment.Center,
|
||||
Width = barWidth
|
||||
};
|
||||
Canvas.SetLeft(scoreText, barX);
|
||||
Canvas.SetTop(scoreText, barY - 12);
|
||||
canvas.Children.Add(scoreText);
|
||||
}
|
||||
|
||||
// 路径名称(水平显示)
|
||||
var label = new TextBlock
|
||||
{
|
||||
Text = analysis.RouteName,
|
||||
FontSize = 9,
|
||||
Foreground = new SolidColorBrush(Colors.Gray),
|
||||
TextAlignment = TextAlignment.Center,
|
||||
Width = groupWidth * 0.85,
|
||||
TextWrapping = TextWrapping.Wrap
|
||||
};
|
||||
Canvas.SetLeft(label, groupX);
|
||||
Canvas.SetTop(label, marginTop + chartHeight + 5);
|
||||
canvas.Children.Add(label);
|
||||
}
|
||||
|
||||
// 绘制图例
|
||||
DrawLegend(canvas, dimensionNames, colors, canvasWidth - 150, 5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制雷达图
|
||||
/// </summary>
|
||||
private void DrawRadarChart(EndpointGroupViewModel selectedGroup)
|
||||
{
|
||||
if (selectedGroup?.PathAnalyses == null || selectedGroup.PathAnalyses.Count == 0) return;
|
||||
|
||||
var canvas = RadarChartCanvas;
|
||||
canvas.Children.Clear();
|
||||
|
||||
var analyses = selectedGroup.PathAnalyses.Take(5).ToList();
|
||||
|
||||
double canvasWidth = canvas.Width;
|
||||
double canvasHeight = canvas.Height;
|
||||
double centerX = canvasWidth / 2;
|
||||
double centerY = canvasHeight / 2 + 10;
|
||||
double radius = Math.Min(canvasWidth, canvasHeight) / 2 - 30;
|
||||
|
||||
var dimensions = new[] { "安全性", "效率", "转弯难度", "直达性" };
|
||||
int dimensionCount = dimensions.Length;
|
||||
|
||||
// 绘制网格
|
||||
for (int i = 1; i <= 5; i++)
|
||||
{
|
||||
double r = radius * i / 5;
|
||||
var polygon = new Polygon
|
||||
{
|
||||
Stroke = new SolidColorBrush(Color.FromRgb(200, 200, 200)),
|
||||
StrokeThickness = 0.5,
|
||||
Fill = Brushes.Transparent
|
||||
};
|
||||
|
||||
for (int j = 0; j < dimensionCount; j++)
|
||||
{
|
||||
double angle = j * 2 * Math.PI / dimensionCount - Math.PI / 2;
|
||||
double x = centerX + r * Math.Cos(angle);
|
||||
double y = centerY + r * Math.Sin(angle);
|
||||
polygon.Points.Add(new Point(x, y));
|
||||
}
|
||||
canvas.Children.Add(polygon);
|
||||
}
|
||||
|
||||
// 绘制轴线和标签
|
||||
for (int i = 0; i < dimensionCount; i++)
|
||||
{
|
||||
double angle = i * 2 * Math.PI / dimensionCount - Math.PI / 2;
|
||||
double x = centerX + radius * Math.Cos(angle);
|
||||
double y = centerY + radius * Math.Sin(angle);
|
||||
|
||||
// 轴线
|
||||
var line = new Line
|
||||
{
|
||||
X1 = centerX,
|
||||
Y1 = centerY,
|
||||
X2 = x,
|
||||
Y2 = y,
|
||||
Stroke = new SolidColorBrush(Color.FromRgb(200, 200, 200)),
|
||||
StrokeThickness = 0.5
|
||||
};
|
||||
canvas.Children.Add(line);
|
||||
|
||||
// 标签
|
||||
var labelX = centerX + (radius + 20) * Math.Cos(angle);
|
||||
var labelY = centerY + (radius + 20) * Math.Sin(angle);
|
||||
var label = new TextBlock
|
||||
{
|
||||
Text = dimensions[i],
|
||||
FontSize = 10,
|
||||
FontWeight = FontWeights.Bold,
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(44, 90, 160))
|
||||
};
|
||||
Canvas.SetLeft(label, labelX - 15);
|
||||
Canvas.SetTop(label, labelY - 8);
|
||||
canvas.Children.Add(label);
|
||||
}
|
||||
|
||||
// 绘制数据
|
||||
var pathColors = new[] {
|
||||
Colors.Red, Colors.Blue, Colors.Green, Colors.Orange, Colors.Purple
|
||||
};
|
||||
|
||||
for (int i = 0; i < analyses.Count; i++)
|
||||
{
|
||||
var analysis = analyses[i];
|
||||
double[] scores = new[] { analysis.SafetyScore, analysis.EfficiencyScore,
|
||||
analysis.TurnDifficultyScore, analysis.TortuosityScore };
|
||||
|
||||
var polygon = new Polygon
|
||||
{
|
||||
Stroke = new SolidColorBrush(pathColors[i % pathColors.Length]),
|
||||
StrokeThickness = analysis.IsBestInGroup ? 2.5 : 1.5,
|
||||
Fill = new SolidColorBrush(pathColors[i % pathColors.Length]) { Opacity = 0.1 }
|
||||
};
|
||||
|
||||
for (int j = 0; j < dimensionCount; j++)
|
||||
{
|
||||
double angle = j * 2 * Math.PI / dimensionCount - Math.PI / 2;
|
||||
double r = radius * scores[j] / 100;
|
||||
double x = centerX + r * Math.Cos(angle);
|
||||
double y = centerY + r * Math.Sin(angle);
|
||||
polygon.Points.Add(new Point(x, y));
|
||||
}
|
||||
|
||||
canvas.Children.Add(polygon);
|
||||
|
||||
// 数据点
|
||||
for (int j = 0; j < dimensionCount; j++)
|
||||
{
|
||||
double angle = j * 2 * Math.PI / dimensionCount - Math.PI / 2;
|
||||
double r = radius * scores[j] / 100;
|
||||
double x = centerX + r * Math.Cos(angle);
|
||||
double y = centerY + r * Math.Sin(angle);
|
||||
|
||||
var ellipse = new Ellipse
|
||||
{
|
||||
Width = 4,
|
||||
Height = 4,
|
||||
Fill = new SolidColorBrush(pathColors[i % pathColors.Length])
|
||||
};
|
||||
Canvas.SetLeft(ellipse, x - 2);
|
||||
Canvas.SetTop(ellipse, y - 2);
|
||||
canvas.Children.Add(ellipse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAxis(Canvas canvas, double left, double top, double width, double height)
|
||||
{
|
||||
// Y轴
|
||||
var yAxis = new Line
|
||||
{
|
||||
X1 = left,
|
||||
Y1 = top,
|
||||
X2 = left,
|
||||
Y2 = top + height,
|
||||
Stroke = new SolidColorBrush(Colors.Gray),
|
||||
StrokeThickness = 1
|
||||
};
|
||||
canvas.Children.Add(yAxis);
|
||||
|
||||
// X轴
|
||||
var xAxis = new Line
|
||||
{
|
||||
X1 = left,
|
||||
Y1 = top + height,
|
||||
X2 = left + width,
|
||||
Y2 = top + height,
|
||||
Stroke = new SolidColorBrush(Colors.Gray),
|
||||
StrokeThickness = 1
|
||||
};
|
||||
canvas.Children.Add(xAxis);
|
||||
|
||||
// Y轴刻度和标签
|
||||
for (int i = 0; i <= 5; i++)
|
||||
{
|
||||
double y = top + height - i * height / 5;
|
||||
var tick = new Line
|
||||
{
|
||||
X1 = left - 3,
|
||||
Y1 = y,
|
||||
X2 = left,
|
||||
Y2 = y,
|
||||
Stroke = new SolidColorBrush(Colors.Gray),
|
||||
StrokeThickness = 1
|
||||
};
|
||||
canvas.Children.Add(tick);
|
||||
|
||||
var label = new TextBlock
|
||||
{
|
||||
Text = (i * 20).ToString(),
|
||||
FontSize = 9,
|
||||
Foreground = new SolidColorBrush(Colors.Gray)
|
||||
};
|
||||
Canvas.SetLeft(label, left - 20);
|
||||
Canvas.SetTop(label, y - 6);
|
||||
canvas.Children.Add(label);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLegend(Canvas canvas, string[] names, Color[] colors, double x, double y)
|
||||
{
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
var rect = new Rectangle
|
||||
{
|
||||
Width = 10,
|
||||
Height = 10,
|
||||
Fill = new SolidColorBrush(colors[i]),
|
||||
RadiusX = 2,
|
||||
RadiusY = 2
|
||||
};
|
||||
Canvas.SetLeft(rect, x + i * 35);
|
||||
Canvas.SetTop(rect, y);
|
||||
canvas.Children.Add(rect);
|
||||
|
||||
var label = new TextBlock
|
||||
{
|
||||
Text = names[i],
|
||||
FontSize = 9,
|
||||
Foreground = new SolidColorBrush(Colors.Gray)
|
||||
};
|
||||
Canvas.SetLeft(label, x + i * 35 + 12);
|
||||
Canvas.SetTop(label, y - 1);
|
||||
canvas.Children.Add(label);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示路径分析窗口(单例模式,非模态)
|
||||
/// </summary>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user