NavisworksTransport/src/Core/PathAnalysisService.cs
2026-02-14 17:39:40 +08:00

407 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.Collections.Generic;
using System.Linq;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Models;
using NavisworksTransport.Core.Collision;
namespace NavisworksTransport
{
/// <summary>
/// 路径分析服务 - 扩展版
/// 负责路径碰撞分析、多维度评分计算和同终点组分析
/// </summary>
public class PathAnalysisService
{
private readonly PathDatabase _database;
private readonly PathAnalysisEngine _analysisEngine;
public PathAnalysisService(PathDatabase database)
{
_database = database ?? throw new ArgumentNullException(nameof(database));
_analysisEngine = new PathAnalysisEngine(database);
// 确保数据库表结构已扩展
_database.EnsureAnalysisResultsTableExtended();
}
/// <summary>
/// 分析单条路径
/// </summary>
/// <param name="route">路径对象</param>
/// <param name="strategy">分析策略:安全优先/效率优先</param>
/// <returns>分析结果</returns>
public PathAnalysisResult AnalyzePath(PathRoute route, string strategy = "安全优先")
{
try
{
// 1. 执行碰撞检测
var collisions = DetectCollisions(route);
// 2. 保存碰撞结果到数据库
_database.SaveCollisions(route.Id, collisions);
// 3. 计算评分
var safetyScore = CalculateSafetyScore(collisions.Count, route.TotalLength);
var efficiencyScore = CalculateEfficiencyScore(route.TotalLength, route.EstimatedTime);
// 4. 保存分析结果到数据库
_database.SaveAnalysisScore(route.Id, collisions.Count, safetyScore, efficiencyScore, strategy);
LogManager.Info($"路径分析完成: {route.Name}, 碰撞={collisions.Count}, 安全分={safetyScore:F1}, 效率分={efficiencyScore:F1}");
return _database.GetAnalysisResult(route.Id);
}
catch (Exception ex)
{
LogManager.Error($"路径分析失败: {route?.Name ?? ""}, {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 对比多条路径,返回最佳路径和建议
/// </summary>
/// <param name="routes">路径列表</param>
/// <param name="strategy">分析策略</param>
/// <returns>对比结果</returns>
public PathComparisonResult CompareRoutes(List<PathRoute> routes, string strategy = "安全优先")
{
if (routes == null || routes.Count == 0)
throw new ArgumentException("路径列表不能为空");
var result = new PathComparisonResult
{
Strategy = strategy,
Analyses = new List<PathAnalysisResult>()
};
// 1. 分析每条路径
foreach (var route in routes)
{
var analysis = AnalyzePath(route, strategy);
result.Analyses.Add(analysis);
}
// 2. 根据策略选择最佳路径
PathAnalysisResult bestRoute;
if (strategy == "安全优先")
{
// 优先选择碰撞少、安全分高的路径
bestRoute = result.Analyses
.OrderBy(a => a.CollisionCount)
.ThenByDescending(a => a.SafetyScore)
.First();
}
else // 效率优先
{
// 优先选择效率分高、长度短的路径
bestRoute = result.Analyses
.OrderByDescending(a => a.EfficiencyScore)
.ThenBy(a => a.CollisionCount)
.First();
}
result.BestRouteId = bestRoute.RouteId;
result.BestRouteName = routes.First(r => r.Id == bestRoute.RouteId).Name;
// 3. 生成优化建议
result.Suggestions = GenerateSuggestions(result.Analyses, routes, strategy);
LogManager.Info($"路径对比完成: 共{routes.Count}条路径, 最佳路径={result.BestRouteName}, 策略={strategy}");
return result;
}
/// <summary>
/// 执行碰撞检测
/// 注意:实际的碰撞检测需要在路径动画执行时进行
/// 这里优先从数据库加载已有的碰撞结果
/// </summary>
private List<CollisionResult> DetectCollisions(PathRoute route)
{
try
{
// 先尝试从数据库获取已有的碰撞数据
var existingCount = _database.GetCollisionCount(route.Id);
if (existingCount > 0)
{
LogManager.Info($"从数据库加载碰撞数据: {route.Name}, 碰撞数={existingCount}");
// 返回空列表,碰撞数量已经从数据库获取
return new List<CollisionResult>();
}
// 如果数据库没有碰撞数据,返回空列表
// TODO: 未来可以在这里触发实际的碰撞检测
LogManager.Info($"路径{route.Name}暂无碰撞数据");
return new List<CollisionResult>();
}
catch (Exception ex)
{
LogManager.Error($"获取碰撞数据失败: {route.Name}, {ex.Message}", ex);
return new List<CollisionResult>();
}
}
/// <summary>
/// 计算安全评分100分制
/// 碰撞越少分数越高
/// </summary>
private double CalculateSafetyScore(int collisionCount, double pathLength)
{
// 基础分100分
double baseScore = 100.0;
// 每次碰撞扣10分
double collisionPenalty = collisionCount * 10.0;
// 长路径额外扣分每100米扣1分
double lengthPenalty = (pathLength / 100.0) * 0.5;
double score = baseScore - collisionPenalty - lengthPenalty;
// 分数不低于0
return Math.Max(0, score);
}
/// <summary>
/// 计算效率评分100分制
/// 路径越短、速度越快分数越高
/// </summary>
private double CalculateEfficiencyScore(double pathLength, double estimatedTime)
{
if (estimatedTime <= 0)
return 0;
// 计算平均速度 (m/s)
double avgSpeed = pathLength / estimatedTime;
// 速度分数:速度越快分数越高
// 假设理想速度为1.0 m/s速度每提升0.1则加10分
double speedScore = Math.Min(100, avgSpeed * 100);
// 路径长度惩罚:路径越短越好
// 基准长度100米每超过10米扣1分
double lengthPenalty = Math.Max(0, (pathLength - 100) / 10);
double score = speedScore - lengthPenalty;
return Math.Max(0, Math.Min(100, score));
}
/// <summary>
/// 生成优化建议(基于简单规则)
/// </summary>
private List<string> GenerateSuggestions(List<PathAnalysisResult> analyses,
List<PathRoute> routes, string strategy)
{
var suggestions = new List<string>();
// 规则1碰撞过多
var maxCollision = analyses.Max(a => a.CollisionCount);
if (maxCollision > 5)
{
suggestions.Add($"✅ 优先处理碰撞热点,当前最多{maxCollision}次碰撞");
}
else if (maxCollision > 0)
{
suggestions.Add($"⚠️ 存在{maxCollision}次碰撞,建议优化路径避让");
}
// 规则2路径长度差异大
var avgLength = routes.Average(r => r.TotalLength);
var longRoutes = routes.Where(r => r.TotalLength > avgLength * 1.3).ToList();
if (longRoutes.Count > 0)
{
suggestions.Add($"✅ {longRoutes.Count}条路径偏长超过平均值30%),建议优化路线");
}
// 规则3时间效率建议
var avgTime = routes.Average(r => r.EstimatedTime);
var slowRoutes = routes.Where(r => r.EstimatedTime > avgTime * 1.2).ToList();
if (slowRoutes.Count > 0)
{
suggestions.Add($"⚠️ {slowRoutes.Count}条路径耗时较长,考虑提高通行速度或缩短路径");
}
// 规则4零碰撞路径推荐
var zeroCollisionRoutes = analyses.Where(a => a.CollisionCount == 0).ToList();
if (zeroCollisionRoutes.Count > 0)
{
suggestions.Add($"✅ {zeroCollisionRoutes.Count}条路径无碰撞,优先推荐使用");
}
// 规则5策略特定建议
if (strategy == "安全优先")
{
suggestions.Add("💡 当前策略:安全优先 - 建议选择碰撞最少的路径");
}
else
{
suggestions.Add("💡 当前策略:效率优先 - 建议选择最短路径,但需注意安全");
}
// 如果没有任何建议,添加默认建议
if (suggestions.Count == 0)
{
suggestions.Add("✅ 所有路径表现良好,可根据实际需求选择");
}
return suggestions;
}
}
/// <summary>
/// 路径对比结果
/// </summary>
public class PathComparisonResult
{
/// <summary>最佳路径ID</summary>
public string BestRouteId { get; set; }
/// <summary>最佳路径名称</summary>
public string BestRouteName { get; set; }
/// <summary>分析策略</summary>
public string Strategy { get; set; }
/// <summary>所有路径的分析结果</summary>
public List<PathAnalysisResult> Analyses { get; set; }
/// <summary>优化建议列表</summary>
public List<string> Suggestions { get; set; }
}
#region
public class ExtendedPathAnalysisService
{
private readonly PathAnalysisEngine _engine;
private readonly PathDatabase _database;
public ExtendedPathAnalysisService(PathDatabase database)
{
_database = database;
_engine = new PathAnalysisEngine(database);
}
/// <summary>
/// 执行完整的多维度路径分析
/// </summary>
public PathDetailedAnalysis AnalyzePathDetailed(PathRoute route, string strategy)
{
var context = new AnalysisContext { Strategy = strategy };
return _engine.AnalyzePath(route, context);
}
/// <summary>
/// 分析多条路径并按终点分组
/// </summary>
public List<EndpointGroup> AnalyzePathsWithGrouping(List<PathRoute> routes, string strategy)
{
return _engine.AnalyzeAndGroupPaths(routes, strategy);
}
/// <summary>
/// 获取同终点组的详细分析
/// </summary>
public EndpointGroupAnalysis GetEndpointGroupAnalysis(EndpointGroup group, string strategy)
{
var analysis = new EndpointGroupAnalysis
{
Group = group,
BestPath = _engine.FindBestPathInGroup(group, strategy),
Suggestions = new List<CategorizedSuggestion>()
};
// 为组内每条路径生成建议
foreach (var pathAnalysis in group.PathAnalyses)
{
var pathSuggestions = _engine.GenerateSuggestions(pathAnalysis, group);
analysis.Suggestions.AddRange(pathSuggestions);
}
// 去重并排序
analysis.Suggestions = analysis.Suggestions
.GroupBy(s => s.Title)
.Select(g => g.First())
.OrderByDescending(s => s.Priority)
.ToList();
return analysis;
}
/// <summary>
/// 保存详细分析结果到数据库
/// </summary>
public void SaveDetailedAnalysis(PathDetailedAnalysis analysis)
{
var result = new PathAnalysisResult
{
RouteId = analysis.RouteId,
CollisionCount = analysis.CollisionCount,
SafetyScore = analysis.SafetyScore,
EfficiencyScore = analysis.EfficiencyScore,
TurnDifficultyScore = analysis.TurnDifficultyScore,
TortuosityScore = analysis.TortuosityScore,
RedundancyScore = analysis.RedundancyScore,
OverallScore = analysis.WeightedScore,
HotspotCount = analysis.HotspotCount,
AnalysisTime = analysis.AnalysisTime,
Strategy = analysis.Strategy,
GroupId = analysis.GroupId,
GroupRanking = analysis.GroupRanking
};
_database.SaveDetailedAnalysisResult(result);
}
/// <summary>
/// 生成建议供View使用
/// </summary>
public List<CategorizedSuggestion> GenerateSuggestionsForView(PathDetailedAnalysis analysis, EndpointGroup group)
{
return _engine.GenerateSuggestions(analysis, group);
}
}
/// <summary>
/// 同终点组详细分析结果
/// </summary>
public class EndpointGroupAnalysis
{
/// <summary>组信息</summary>
public EndpointGroup Group { get; set; }
/// <summary>最佳路径</summary>
public PathDetailedAnalysis BestPath { get; set; }
/// <summary>组内路径对比</summary>
public List<PathComparisonDetail> Comparisons { get; set; } = new List<PathComparisonDetail>();
/// <summary>优化建议</summary>
public List<CategorizedSuggestion> Suggestions { get; set; } = new List<CategorizedSuggestion>();
/// <summary>分析策略</summary>
public string Strategy { get; set; }
}
/// <summary>
/// 路径对比详情
/// </summary>
public class PathComparisonDetail
{
public string PathAId { get; set; }
public string PathAName { get; set; }
public string PathBId { get; set; }
public string PathBName { get; set; }
public double LengthDiffPercent { get; set; }
public double TimeDiffPercent { get; set; }
public int CollisionDiff { get; set; }
public string Advantage { get; set; }
}
#endregion
}