407 lines
15 KiB
C#
407 lines
15 KiB
C#
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
|
||
}
|