完善碰撞报告高亮和截图保存机制
This commit is contained in:
parent
d5d50d7568
commit
1e1d740aef
@ -2,6 +2,10 @@
|
||||
|
||||
## 功能点
|
||||
|
||||
### [2026/1/26]
|
||||
|
||||
1. [ ] (优化)完善碰撞报告截图保存机制,自动导出html报告。
|
||||
|
||||
### [2026/1/18]
|
||||
|
||||
1. [x] (功能)实现吊装路径,支持3步吊运过程
|
||||
|
||||
@ -40,9 +40,9 @@ namespace NavisworksTransport.Commands
|
||||
public bool IncludeDetails { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动高亮报告中的碰撞对象
|
||||
/// 碰撞结果是否已经被高亮过了(用于避免重复高亮)
|
||||
/// </summary>
|
||||
public bool AutoHighlight { get; set; } = false;
|
||||
public bool HasHighlighted { get; set; } = false;
|
||||
|
||||
public PathPlanningResult ValidateParameters()
|
||||
{
|
||||
@ -63,6 +63,9 @@ namespace NavisworksTransport.Commands
|
||||
|
||||
// 新增:被撞物体去重统计
|
||||
public HashSet<string> UniqueCollidedObjects { get; set; } = new HashSet<string>();
|
||||
|
||||
// 新增:截图路径
|
||||
public string ScreenshotPath { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -164,10 +167,11 @@ namespace NavisworksTransport.Commands
|
||||
result.FrameRate = animationManager.AnimationFrameRate;
|
||||
result.Duration = animationManager.AnimationDuration;
|
||||
result.DetectionTolerance = animationManager.DetectionTolerance;
|
||||
// PathName需要从动画管理器获取
|
||||
result.PathName = animationManager.PathName ?? "未知路径";
|
||||
}
|
||||
|
||||
// 从数据库获取路径名称(不依赖动画管理器的状态,使用同步方法避免死锁)
|
||||
result.PathName = GetPathNameFromDatabase(targetTestName) ?? "未知路径";
|
||||
|
||||
LogManager.Info($"碰撞报告计数 - 检查点: {result.AnimationCollisions}, Clash Detective: {result.TotalCollisions}");
|
||||
|
||||
UpdateProgress(70, "生成报告内容...");
|
||||
@ -177,50 +181,88 @@ namespace NavisworksTransport.Commands
|
||||
|
||||
UpdateProgress(90, "处理报告显示...");
|
||||
|
||||
// 自动高亮(如果启用)
|
||||
if (_parameters.AutoHighlight && collisionData.AllCollisions.Count > 0)
|
||||
// 如果碰撞结果还没有高亮,则执行高亮(不清除之前的高亮,避免影响其他场景)
|
||||
if (!_parameters.HasHighlighted && collisionData.AllCollisions.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var highlightIntegration = ClashDetectiveIntegration.Instance;
|
||||
if (highlightIntegration != null)
|
||||
{
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, clearPrevious: true);
|
||||
LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
|
||||
ModelHighlightHelper.HighlightCollisionResults(collisionData.AllCollisions, clearPrevious: false);
|
||||
LogManager.Info($"碰撞报告生成前高亮 {collisionData.AllCollisions.Count} 个碰撞对象");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"自动高亮报告对象失败: {ex.Message}");
|
||||
LogManager.Error($"高亮碰撞对象失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateProgress(95, "生成碰撞场景截图...");
|
||||
|
||||
// 自动生成默认截图(1920x1080, JPG格式)
|
||||
try
|
||||
{
|
||||
string screenshotPath = PathHelper.GenerateSceneScreenshot(
|
||||
result.PathName ?? "collision",
|
||||
1920,
|
||||
1080,
|
||||
System.Drawing.Imaging.ImageFormat.Jpeg,
|
||||
"collision"
|
||||
);
|
||||
// 检查是否已有截图路径(从数据库)
|
||||
var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
|
||||
var existingScreenshotPath = pathDatabase != null ?
|
||||
pathDatabase.GetClashDetectiveResultByTestName(targetTestName)?.ScreenshotPath : null;
|
||||
|
||||
if (screenshotPath != null)
|
||||
{
|
||||
result.ScreenshotPath = screenshotPath;
|
||||
result.ScreenshotFormat = "JPG";
|
||||
result.ScreenshotWidth = 1920;
|
||||
result.ScreenshotHeight = 1080;
|
||||
LogManager.Info($"碰撞场景截图已自动生成: {screenshotPath}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (!string.IsNullOrEmpty(existingScreenshotPath) && System.IO.File.Exists(existingScreenshotPath))
|
||||
{
|
||||
LogManager.Error($"自动生成碰撞场景截图失败: {ex.Message}");
|
||||
// 截图失败不影响报告生成
|
||||
// 使用数据库中保存的截图路径
|
||||
result.ScreenshotPath = existingScreenshotPath;
|
||||
result.ScreenshotFormat = "JPG";
|
||||
result.ScreenshotWidth = 1920;
|
||||
result.ScreenshotHeight = 1080;
|
||||
LogManager.Info($"使用数据库中保存的截图: {existingScreenshotPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 生成新截图
|
||||
try
|
||||
{
|
||||
string screenshotPath = PathHelper.GenerateSceneScreenshot(
|
||||
result.PathName ?? "collision",
|
||||
1920,
|
||||
1080,
|
||||
System.Drawing.Imaging.ImageFormat.Jpeg,
|
||||
"collision"
|
||||
);
|
||||
|
||||
if (screenshotPath != null)
|
||||
{
|
||||
result.ScreenshotPath = screenshotPath;
|
||||
result.ScreenshotFormat = "JPG";
|
||||
result.ScreenshotWidth = 1920;
|
||||
result.ScreenshotHeight = 1080;
|
||||
LogManager.Info($"碰撞场景截图已自动生成: {screenshotPath}");
|
||||
|
||||
// 保存截图路径到数据库
|
||||
if (pathDatabase != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var updateSql = "UPDATE ClashDetectiveResults SET ScreenshotPath = @screenshotPath WHERE TestName = @testName";
|
||||
using (var cmd = new System.Data.SQLite.SQLiteCommand(updateSql, pathDatabase._connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@screenshotPath", screenshotPath);
|
||||
cmd.Parameters.AddWithValue("@testName", targetTestName);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
LogManager.Info($"已保存截图路径到数据库: {screenshotPath}");
|
||||
}
|
||||
catch (Exception dbEx)
|
||||
{
|
||||
LogManager.Error($"保存截图路径到数据库失败: {dbEx.Message}");
|
||||
// 数据库更新失败不影响报告生成
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"自动生成碰撞场景截图失败: {ex.Message}");
|
||||
// 截图失败不影响报告生成
|
||||
}
|
||||
}
|
||||
|
||||
UpdateProgress(100, "报告生成完成");
|
||||
@ -299,6 +341,17 @@ namespace NavisworksTransport.Commands
|
||||
// 直接使用缓存中的CollisionResult对象(已经过复合对象处理和去重)
|
||||
allCollisions.AddRange(testCollisionsRaw);
|
||||
|
||||
// 从数据库获取测试信息(包括截图路径)
|
||||
var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
|
||||
if (pathDatabase != null)
|
||||
{
|
||||
var testInfo = pathDatabase.GetClashDetectiveResultByTestName(targetTestName);
|
||||
if (testInfo != null && !string.IsNullOrEmpty(testInfo.ScreenshotPath))
|
||||
{
|
||||
result.ScreenshotPath = testInfo.ScreenshotPath;
|
||||
}
|
||||
}
|
||||
|
||||
// 统计碰撞总数
|
||||
result.ClashDetectiveCollisionCount = testCollisionsRaw.Count;
|
||||
LogManager.Debug($"测试 '{targetTestName}' 包含 {testCollisionsRaw.Count} 个碰撞");
|
||||
@ -359,6 +412,30 @@ namespace NavisworksTransport.Commands
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据库获取路径名称(同步方法,避免在主线程中使用await造成死锁)
|
||||
/// </summary>
|
||||
private string GetPathNameFromDatabase(string testName)
|
||||
{
|
||||
var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
|
||||
if (pathDatabase == null)
|
||||
{
|
||||
LogManager.Warning("无法获取PathDatabase实例");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var testInfo = pathDatabase.GetClashDetectiveResultByTestName(testName);
|
||||
return testInfo?.PathName;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"从数据库获取路径名称失败: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成报告内容
|
||||
/// </summary>
|
||||
@ -573,13 +650,13 @@ namespace NavisworksTransport.Commands
|
||||
/// <summary>
|
||||
/// 创建综合报告命令
|
||||
/// </summary>
|
||||
public static GenerateCollisionReportCommand CreateComprehensive(bool autoHighlight = false)
|
||||
public static GenerateCollisionReportCommand CreateComprehensive(bool hasHighlighted = false)
|
||||
{
|
||||
return new GenerateCollisionReportCommand(new CollisionReportParameters
|
||||
{
|
||||
Type = CollisionReportParameters.ReportType.Comprehensive,
|
||||
IncludeDetails = true,
|
||||
AutoHighlight = autoHighlight
|
||||
HasHighlighted = hasHighlighted
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -298,30 +298,13 @@ namespace NavisworksTransport.Core
|
||||
// 保存测试名称
|
||||
item.ClashDetectiveTestName = testName;
|
||||
|
||||
// 🔥 高亮碰撞结果(用于批处理中的截图和报告生成)
|
||||
if (!string.IsNullOrEmpty(testName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var clashIntegration = ClashDetectiveIntegration.Instance;
|
||||
var clashResults = clashIntegration.GetCurrentPathClashResults(testName);
|
||||
if (clashResults != null && clashResults.Count > 0)
|
||||
{
|
||||
ModelHighlightHelper.HighlightClashDetectiveResults(testName, clashIntegration.GetCurrentPathClashResults);
|
||||
}
|
||||
}
|
||||
catch (Exception highlightEx)
|
||||
{
|
||||
LogManager.Error($"[批处理队列] 高亮碰撞结果失败: {highlightEx.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 生成碰撞报告(包括截图)
|
||||
// 批处理检测结束时会自动高亮,所以 hasHighlighted=true
|
||||
if (!string.IsNullOrEmpty(testName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var reportCommand = new Commands.GenerateCollisionReportCommand();
|
||||
var reportCommand = Commands.GenerateCollisionReportCommand.CreateComprehensive(hasHighlighted: false);
|
||||
reportCommand.SetTestName(testName);
|
||||
|
||||
// 同步执行报告生成(在UI线程中)
|
||||
@ -335,16 +318,6 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 清除高亮(报告生成后)
|
||||
try
|
||||
{
|
||||
ModelHighlightHelper.ClearClashDetectiveHighlights();
|
||||
}
|
||||
catch (Exception clearEx)
|
||||
{
|
||||
LogManager.Error($"[批处理队列] 清除高亮失败: {clearEx.Message}");
|
||||
}
|
||||
|
||||
return testName;
|
||||
});
|
||||
|
||||
|
||||
@ -259,7 +259,7 @@ namespace NavisworksTransport
|
||||
// 1. 从数据库读取测试信息
|
||||
var testInfoSql = @"
|
||||
SELECT Id, PathName, RouteId, IsVirtualVehicle, VehicleModelIndex, VehiclePathId,
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, ScreenshotPath
|
||||
FROM ClashDetectiveResults
|
||||
WHERE TestName = @testName
|
||||
";
|
||||
@ -282,7 +282,8 @@ namespace NavisworksTransport
|
||||
VehiclePathId = reader["VehiclePathId"] != DBNull.Value ? reader["VehiclePathId"].ToString() : null,
|
||||
VirtualVehicleLength = reader["VirtualVehicleLength"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleLength"]) : 0.0,
|
||||
VirtualVehicleWidth = reader["VirtualVehicleWidth"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleWidth"]) : 0.0,
|
||||
VirtualVehicleHeight = reader["VirtualVehicleHeight"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleHeight"]) : 0.0
|
||||
VirtualVehicleHeight = reader["VirtualVehicleHeight"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleHeight"]) : 0.0,
|
||||
ScreenshotPath = reader["ScreenshotPath"] != DBNull.Value ? reader["ScreenshotPath"].ToString() : null
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -508,7 +509,7 @@ namespace NavisworksTransport
|
||||
LogManager.Info($"[ClashDetective] 有效碰撞数量: {validCollisions.Count}");
|
||||
|
||||
// 第一步:创建主测试(不包含选择集,纯容器)
|
||||
var mainTestName = $"碰撞检测_{DateTime.Now:MMdd_HHmmss}";
|
||||
var mainTestName = $"碰撞检测_{DateTime.Now:MMdd_HHmmssfff}";
|
||||
_currentTestName = mainTestName;
|
||||
LogManager.Info($"[分组测试] 创建主测试: {mainTestName}");
|
||||
|
||||
|
||||
@ -186,6 +186,7 @@ namespace NavisworksTransport
|
||||
VirtualVehicleLength REAL,
|
||||
VirtualVehicleWidth REAL,
|
||||
VirtualVehicleHeight REAL,
|
||||
ScreenshotPath TEXT,
|
||||
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
");
|
||||
@ -457,10 +458,10 @@ namespace NavisworksTransport
|
||||
INSERT INTO ClashDetectiveResults
|
||||
(TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
|
||||
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualVehicle, VehicleModelIndex, VehiclePathId,
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, CreatedAt)
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, ScreenshotPath, CreatedAt)
|
||||
VALUES (@testName, @pathName, @routeId, @testTime, @collisionCount, @animationCollisionCount,
|
||||
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualVehicle, @vehicleModelIndex, @vehiclePathId,
|
||||
@virtualVehicleLength, @virtualVehicleWidth, @virtualVehicleHeight, @createdAt)
|
||||
@virtualVehicleLength, @virtualVehicleWidth, @virtualVehicleHeight, @screenshotPath, @createdAt)
|
||||
";
|
||||
|
||||
long newId = 0;
|
||||
@ -482,6 +483,7 @@ namespace NavisworksTransport
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleLength", record.VirtualVehicleLength);
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleWidth", record.VirtualVehicleWidth);
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleHeight", record.VirtualVehicleHeight);
|
||||
cmd.Parameters.AddWithValue("@screenshotPath", record.ScreenshotPath ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@createdAt", record.CreatedAt);
|
||||
cmd.ExecuteNonQuery();
|
||||
newId = _connection.LastInsertRowId;
|
||||
@ -618,6 +620,55 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据测试名称获取ClashDetective结果记录
|
||||
/// </summary>
|
||||
public ClashDetectiveResultRecord GetClashDetectiveResultByTestName(string testName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sql = @"
|
||||
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
|
||||
FrameRate, Duration, DetectionGap, AnimatedObjectName, CreatedAt, ScreenshotPath
|
||||
FROM ClashDetectiveResults
|
||||
WHERE TestName = @testName
|
||||
";
|
||||
|
||||
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@testName", testName);
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
return new ClashDetectiveResultRecord
|
||||
{
|
||||
Id = Convert.ToInt32(reader["Id"]),
|
||||
TestName = reader["TestName"].ToString(),
|
||||
PathName = reader["PathName"].ToString(),
|
||||
RouteId = reader["RouteId"]?.ToString(),
|
||||
TestTime = Convert.ToDateTime(reader["TestTime"]),
|
||||
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
|
||||
AnimationCollisionCount = Convert.ToInt32(reader["AnimationCollisionCount"]),
|
||||
FrameRate = reader["FrameRate"] != DBNull.Value ? Convert.ToInt32(reader["FrameRate"]) : 0,
|
||||
Duration = reader["Duration"] != DBNull.Value ? Convert.ToDouble(reader["Duration"]) : 0.0,
|
||||
DetectionGap = reader["DetectionGap"] != DBNull.Value ? Convert.ToDouble(reader["DetectionGap"]) : 0.0,
|
||||
AnimatedObjectName = reader["AnimatedObjectName"]?.ToString(),
|
||||
CreatedAt = Convert.ToDateTime(reader["CreatedAt"]),
|
||||
ScreenshotPath = reader["ScreenshotPath"] != DBNull.Value ? reader["ScreenshotPath"].ToString() : null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"根据测试名称获取ClashDetective结果失败: {ex.Message}", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存ClashDetective碰撞对象
|
||||
/// </summary>
|
||||
@ -1862,6 +1913,7 @@ namespace NavisworksTransport
|
||||
public double VirtualVehicleLength { get; set; }
|
||||
public double VirtualVehicleWidth { get; set; }
|
||||
public double VirtualVehicleHeight { get; set; }
|
||||
public string ScreenshotPath { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@ -165,7 +165,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Info($"[历史报告] 开始生成历史碰撞报告: {testName}");
|
||||
|
||||
// 直接使用现有的报告生成命令,但指定测试名称
|
||||
var command = GenerateCollisionReportCommand.CreateComprehensive(autoHighlight: false);
|
||||
// 常规检测已经高亮了,所以 hasHighlighted=true
|
||||
var command = GenerateCollisionReportCommand.CreateComprehensive(hasHighlighted: true);
|
||||
command.SetTestName(testName);
|
||||
_ = command.ExecuteAsync();
|
||||
}
|
||||
|
||||
@ -329,7 +329,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Info($"[批处理队列] 开始生成历史碰撞报告: {testName}");
|
||||
|
||||
// 复用碰撞历史列表中的报告按钮代码
|
||||
var command = GenerateCollisionReportCommand.CreateComprehensive(autoHighlight: false);
|
||||
// 历史报告需要重新高亮,所以 hasHighlighted=false
|
||||
var command = GenerateCollisionReportCommand.CreateComprehensive(hasHighlighted: false);
|
||||
command.SetTestName(testName);
|
||||
await command.ExecuteAsync();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user