1363 lines
50 KiB
C#
1363 lines
50 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Linq;
|
||
using System.Windows.Input;
|
||
using Autodesk.Navisworks.Api;
|
||
using NavisworksTransport.Utils;
|
||
using NavisworksTransport.Commands;
|
||
using NavisworksTransport.Core.Animation;
|
||
using System.IO;
|
||
using System.Text;
|
||
using Microsoft.Win32;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Media.Imaging;
|
||
using NavisworksTransport.UI.WPF.Views;
|
||
using ImageFormat = System.Drawing.Imaging.ImageFormat;
|
||
|
||
namespace NavisworksTransport.UI.WPF.ViewModels
|
||
{
|
||
/// <summary>
|
||
/// 碰撞报告显示状态枚举
|
||
/// </summary>
|
||
public enum CollisionReportStatus
|
||
{
|
||
/// <summary>正在生成报告</summary>
|
||
Generating,
|
||
/// <summary>报告已生成</summary>
|
||
Generated,
|
||
/// <summary>生成失败</summary>
|
||
Failed,
|
||
/// <summary>空报告</summary>
|
||
Empty
|
||
}
|
||
|
||
/// <summary>
|
||
/// 碰撞报告项目UI模型
|
||
/// </summary>
|
||
public class CollisionReportItem
|
||
{
|
||
public int Index { get; set; }
|
||
public string Title { get; set; }
|
||
public string Description { get; set; }
|
||
public string StatusText { get; set; }
|
||
public string StatusColor { get; set; }
|
||
public string Details { get; set; }
|
||
public string Item1FullPath { get; set; }
|
||
public string Item2FullPath { get; set; }
|
||
public CollisionResult CollisionData { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 碰撞报告统计信息UI模型
|
||
/// </summary>
|
||
public class CollisionReportStatistics
|
||
{
|
||
public int TotalCollisions { get; set; }
|
||
public int AnimationCollisions { get; set; }
|
||
public int NewCollisions { get; set; }
|
||
public int ActiveCollisions { get; set; }
|
||
public int ReviewedCollisions { get; set; }
|
||
public int ApprovedCollisions { get; set; }
|
||
public int ResolvedCollisions { get; set; }
|
||
public string GenerationTime { get; set; }
|
||
public string ReportType { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 碰撞报告对话框ViewModel
|
||
/// </summary>
|
||
public class CollisionReportViewModel : ViewModelBase
|
||
{
|
||
#region 私有字段
|
||
|
||
private CollisionReportStatus _reportStatus;
|
||
private string _reportTitle;
|
||
private CollisionReportStatistics _statistics;
|
||
private ObservableCollection<CollisionReportItem> _animationCollisions;
|
||
private string _progressMessage;
|
||
private int _progressPercentage;
|
||
private bool _isGenerating;
|
||
private bool _hasCollisions;
|
||
private string _summaryMessage;
|
||
private string _recommendationMessage;
|
||
private string _movingObjectInfo;
|
||
private ObservableCollection<string> _collidedObjectsList;
|
||
private int _uniqueCollidedObjectsCount;
|
||
private string _pathName;
|
||
private int _frameRate;
|
||
private double _duration;
|
||
private double _detectionTolerance;
|
||
private CollisionReportResult _currentReport;
|
||
private ObservableCollection<ExcludedObjectRecord> _excludedObjects;
|
||
|
||
// 保存运动物体原始状态,用于碰撞查看后恢复
|
||
private ModelItemTransformHelper.ObjectStateSnapshot _savedAnimatedObjectState;
|
||
private ModelItem _currentAnimatedObject;
|
||
|
||
#endregion
|
||
|
||
#region 公共属性
|
||
|
||
/// <summary>
|
||
/// 报告状态
|
||
/// </summary>
|
||
public CollisionReportStatus ReportStatus
|
||
{
|
||
get => _reportStatus;
|
||
set => SetProperty(ref _reportStatus, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 报告标题
|
||
/// </summary>
|
||
public string ReportTitle
|
||
{
|
||
get => _reportTitle;
|
||
set => SetProperty(ref _reportTitle, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 统计信息
|
||
/// </summary>
|
||
public CollisionReportStatistics Statistics
|
||
{
|
||
get => _statistics;
|
||
set => SetProperty(ref _statistics, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画过程碰撞列表
|
||
/// </summary>
|
||
public ObservableCollection<CollisionReportItem> AnimationCollisions
|
||
{
|
||
get => _animationCollisions;
|
||
set => SetProperty(ref _animationCollisions, value);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 进度消息
|
||
/// </summary>
|
||
public string ProgressMessage
|
||
{
|
||
get => _progressMessage;
|
||
set => SetProperty(ref _progressMessage, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进度百分比
|
||
/// </summary>
|
||
public int ProgressPercentage
|
||
{
|
||
get => _progressPercentage;
|
||
set => SetProperty(ref _progressPercentage, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否正在生成报告
|
||
/// </summary>
|
||
public bool IsGenerating
|
||
{
|
||
get => _isGenerating;
|
||
set
|
||
{
|
||
if (SetProperty(ref _isGenerating, value))
|
||
{
|
||
// 刷新命令状态
|
||
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有碰撞
|
||
/// </summary>
|
||
public bool HasCollisions
|
||
{
|
||
get => _hasCollisions;
|
||
set
|
||
{
|
||
if (SetProperty(ref _hasCollisions, value))
|
||
{
|
||
// 刷新命令状态
|
||
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 总结消息
|
||
/// </summary>
|
||
public string SummaryMessage
|
||
{
|
||
get => _summaryMessage;
|
||
set => SetProperty(ref _summaryMessage, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 建议消息
|
||
/// </summary>
|
||
public string RecommendationMessage
|
||
{
|
||
get => _recommendationMessage;
|
||
set => SetProperty(ref _recommendationMessage, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运动构件信息
|
||
/// </summary>
|
||
public string MovingObjectInfo
|
||
{
|
||
get => _movingObjectInfo;
|
||
set => SetProperty(ref _movingObjectInfo, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 被撞物体清单
|
||
/// </summary>
|
||
public ObservableCollection<string> CollidedObjectsList
|
||
{
|
||
get => _collidedObjectsList;
|
||
set => SetProperty(ref _collidedObjectsList, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 去重后的被撞物体总数
|
||
/// </summary>
|
||
public int UniqueCollidedObjectsCount
|
||
{
|
||
get => _uniqueCollidedObjectsCount;
|
||
set => SetProperty(ref _uniqueCollidedObjectsCount, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径名称
|
||
/// </summary>
|
||
public string PathName
|
||
{
|
||
get => _pathName;
|
||
set => SetProperty(ref _pathName, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画帧率
|
||
/// </summary>
|
||
public int FrameRate
|
||
{
|
||
get => _frameRate;
|
||
set => SetProperty(ref _frameRate, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动画时长
|
||
/// </summary>
|
||
public double Duration
|
||
{
|
||
get => _duration;
|
||
set => SetProperty(ref _duration, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测容差
|
||
/// </summary>
|
||
public double DetectionTolerance
|
||
{
|
||
get => _detectionTolerance;
|
||
set => SetProperty(ref _detectionTolerance, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前报告结果
|
||
/// </summary>
|
||
public CollisionReportResult CurrentReport
|
||
{
|
||
get => _currentReport;
|
||
set => SetProperty(ref _currentReport, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 截图预览图像源(兼容旧版本,返回当前选中的截图)
|
||
/// </summary>
|
||
public BitmapImage ScreenshotPreviewSource => GetScreenshotBitmap(SelectedScreenshot);
|
||
|
||
/// <summary>
|
||
/// 截图列表
|
||
/// </summary>
|
||
private ObservableCollection<CollisionReportScreenshot> _screenshots = new ObservableCollection<CollisionReportScreenshot>();
|
||
public ObservableCollection<CollisionReportScreenshot> Screenshots
|
||
{
|
||
get => _screenshots;
|
||
set
|
||
{
|
||
if (SetProperty(ref _screenshots, value))
|
||
{
|
||
OnPropertyChanged(nameof(HasScreenshots));
|
||
OnPropertyChanged(nameof(ScreenshotPreviewSource));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前选中的截图
|
||
/// </summary>
|
||
private CollisionReportScreenshot _selectedScreenshot;
|
||
public CollisionReportScreenshot SelectedScreenshot
|
||
{
|
||
get => _selectedScreenshot;
|
||
set
|
||
{
|
||
if (SetProperty(ref _selectedScreenshot, value))
|
||
{
|
||
OnPropertyChanged(nameof(ScreenshotPreviewSource));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有截图
|
||
/// </summary>
|
||
public bool HasScreenshots => Screenshots?.Count > 0;
|
||
|
||
/// <summary>
|
||
/// 截图数量
|
||
/// </summary>
|
||
public int ScreenshotCount => Screenshots?.Count ?? 0;
|
||
|
||
/// <summary>
|
||
/// 排除对象列表
|
||
/// </summary>
|
||
public ObservableCollection<ExcludedObjectRecord> ExcludedObjects
|
||
{
|
||
get => _excludedObjects;
|
||
set
|
||
{
|
||
if (SetProperty(ref _excludedObjects, value))
|
||
{
|
||
OnPropertyChanged(nameof(HasExcludedObjects));
|
||
OnPropertyChanged(nameof(ExcludedObjectsCount));
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有排除对象
|
||
/// </summary>
|
||
public bool HasExcludedObjects => ExcludedObjects?.Count > 0;
|
||
|
||
/// <summary>
|
||
/// 排除对象数量
|
||
/// </summary>
|
||
public int ExcludedObjectsCount => ExcludedObjects?.Count ?? 0;
|
||
|
||
/// <summary>
|
||
/// 获取截图的BitmapImage
|
||
/// </summary>
|
||
private BitmapImage GetScreenshotBitmap(CollisionReportScreenshot screenshot)
|
||
{
|
||
if (screenshot == null || string.IsNullOrEmpty(screenshot.FilePath) || !File.Exists(screenshot.FilePath))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
var bitmap = new BitmapImage();
|
||
bitmap.BeginInit();
|
||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||
bitmap.UriSource = new Uri(screenshot.FilePath);
|
||
bitmap.EndInit();
|
||
bitmap.Freeze();
|
||
return bitmap;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"加载截图预览失败: {ex.Message}");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令属性
|
||
|
||
/// <summary>
|
||
/// 导出报告命令
|
||
/// </summary>
|
||
public ICommand ExportReportCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 关闭窗口命令
|
||
/// </summary>
|
||
public ICommand CloseCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 添加截图命令
|
||
/// </summary>
|
||
public ICommand AddScreenshotCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 删除截图命令
|
||
/// </summary>
|
||
public ICommand DeleteScreenshotCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 选择截图命令
|
||
/// </summary>
|
||
public ICommand SelectScreenshotCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 截图设置命令
|
||
/// </summary>
|
||
public ICommand ScreenshotSettingsCommand { get; }
|
||
|
||
/// <summary>
|
||
/// 高亮碰撞对象命令
|
||
/// </summary>
|
||
public ICommand HighlightCollisionCommand { get; }
|
||
|
||
#endregion
|
||
|
||
#region 截图设置属性
|
||
|
||
// 默认截图设置
|
||
private int _screenshotWidth = 1920;
|
||
private int _screenshotHeight = 1080;
|
||
private ImageFormat _screenshotFormat = ImageFormat.Png;
|
||
|
||
/// <summary>
|
||
/// 截图宽度
|
||
/// </summary>
|
||
public int ScreenshotWidthSetting
|
||
{
|
||
get => _screenshotWidth;
|
||
set => SetProperty(ref _screenshotWidth, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 截图高度
|
||
/// </summary>
|
||
public int ScreenshotHeightSetting
|
||
{
|
||
get => _screenshotHeight;
|
||
set => SetProperty(ref _screenshotHeight, value);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 截图格式
|
||
/// </summary>
|
||
public ImageFormat ScreenshotFormatSetting
|
||
{
|
||
get => _screenshotFormat;
|
||
set => SetProperty(ref _screenshotFormat, value);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
public CollisionReportViewModel()
|
||
{
|
||
// 初始化集合
|
||
AnimationCollisions = new ObservableCollection<CollisionReportItem>();
|
||
CollidedObjectsList = new ObservableCollection<string>();
|
||
ExcludedObjects = new ObservableCollection<ExcludedObjectRecord>();
|
||
|
||
Statistics = new CollisionReportStatistics();
|
||
|
||
// 初始化命令
|
||
ExportReportCommand = new RelayCommand(async () => await ExportReportAsync(), () => !IsGenerating);
|
||
CloseCommand = new RelayCommand(CloseWindow);
|
||
HighlightCollisionCommand = new RelayCommand<CollisionReportItem>(HighlightCollision, item => item?.CollisionData != null);
|
||
AddScreenshotCommand = new RelayCommand(ExecuteAddScreenshot, CanExecuteAddScreenshot);
|
||
DeleteScreenshotCommand = new RelayCommand<CollisionReportScreenshot>(ExecuteDeleteScreenshot, s => s != null);
|
||
SelectScreenshotCommand = new RelayCommand<CollisionReportScreenshot>(ExecuteSelectScreenshot);
|
||
ScreenshotSettingsCommand = new RelayCommand(ExecuteScreenshotSettings);
|
||
|
||
// 初始化状态
|
||
ReportStatus = CollisionReportStatus.Generating;
|
||
ReportTitle = "NavisworksTransport - 碰撞检测报告";
|
||
IsGenerating = false;
|
||
HasCollisions = false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 公共方法
|
||
|
||
/// <summary>
|
||
/// 初始化报告数据
|
||
/// </summary>
|
||
/// <param name="reportResult">报告结果</param>
|
||
public void InitializeReport(CollisionReportResult reportResult)
|
||
{
|
||
if (reportResult == null)
|
||
{
|
||
SetEmptyReport();
|
||
return;
|
||
}
|
||
|
||
// 保存当前报告结果
|
||
CurrentReport = reportResult;
|
||
|
||
try
|
||
{
|
||
IsGenerating = true;
|
||
ReportStatus = CollisionReportStatus.Generating;
|
||
ProgressMessage = "正在解析报告数据...";
|
||
ProgressPercentage = 0;
|
||
|
||
// 清空现有数据
|
||
AnimationCollisions.Clear();
|
||
CollidedObjectsList.Clear();
|
||
Screenshots.Clear();
|
||
ExcludedObjects.Clear();
|
||
|
||
// 加载截图列表
|
||
if (reportResult.Screenshots?.Count > 0)
|
||
{
|
||
foreach (var screenshot in reportResult.Screenshots.OrderBy(s => s.SortOrder))
|
||
{
|
||
Screenshots.Add(screenshot);
|
||
}
|
||
// 默认选中第一张
|
||
SelectedScreenshot = Screenshots.FirstOrDefault();
|
||
LogManager.Info($"碰撞报告加载了 {Screenshots.Count} 张截图");
|
||
}
|
||
|
||
// 设置运动构件信息
|
||
MovingObjectInfo = reportResult.MovingObjectInfo;
|
||
|
||
// 设置被撞物体清单和计数
|
||
UniqueCollidedObjectsCount = reportResult.UniqueCollidedObjectsCount;
|
||
if (reportResult.CollidedObjectsList != null)
|
||
{
|
||
foreach (var objName in reportResult.CollidedObjectsList)
|
||
{
|
||
CollidedObjectsList.Add(objName);
|
||
}
|
||
}
|
||
|
||
// 加载排除对象列表
|
||
if (reportResult.ExcludedObjects?.Count > 0)
|
||
{
|
||
foreach (var excludedObj in reportResult.ExcludedObjects)
|
||
{
|
||
ExcludedObjects.Add(excludedObj);
|
||
}
|
||
LogManager.Info($"碰撞报告加载了 {ExcludedObjects.Count} 个排除对象");
|
||
}
|
||
|
||
// 设置动画参数
|
||
PathName = reportResult.PathName;
|
||
FrameRate = reportResult.FrameRate;
|
||
Duration = reportResult.Duration;
|
||
DetectionTolerance = reportResult.DetectionTolerance;
|
||
|
||
// 更新统计信息
|
||
UpdateStatistics(reportResult);
|
||
|
||
// 分类并添加碰撞项
|
||
ProcessCollisionData(reportResult.AllCollisions);
|
||
|
||
// 生成总结和建议
|
||
GenerateSummaryAndRecommendations(reportResult);
|
||
|
||
// 更新状态
|
||
HasCollisions = reportResult.TotalCollisions > 0;
|
||
ReportStatus = HasCollisions ? CollisionReportStatus.Generated : CollisionReportStatus.Empty;
|
||
|
||
ProgressMessage = "报告生成完成";
|
||
ProgressPercentage = 100;
|
||
|
||
LogManager.Info($"碰撞报告ViewModel初始化完成,发现 {reportResult.TotalCollisions} 个碰撞");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"初始化碰撞报告失败: {ex.Message}");
|
||
SetFailedReport(ex.Message);
|
||
}
|
||
finally
|
||
{
|
||
IsGenerating = false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新进度
|
||
/// </summary>
|
||
/// <param name="percentage">进度百分比</param>
|
||
/// <param name="message">进度消息</param>
|
||
public void UpdateProgress(int percentage, string message)
|
||
{
|
||
SafeExecute(() =>
|
||
{
|
||
ProgressPercentage = Math.Max(0, Math.Min(100, percentage));
|
||
ProgressMessage = message ?? "";
|
||
}, "更新报告生成进度", true);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 更新统计信息
|
||
/// </summary>
|
||
private void UpdateStatistics(CollisionReportResult reportResult)
|
||
{
|
||
Statistics = new CollisionReportStatistics
|
||
{
|
||
TotalCollisions = reportResult.TotalCollisions,
|
||
AnimationCollisions = reportResult.AnimationCollisions,
|
||
GenerationTime = $"{reportResult.GenerationTimeMs}ms",
|
||
ReportType = "综合碰撞报告"
|
||
};
|
||
|
||
// 计算状态统计
|
||
if (reportResult.AllCollisions?.Count > 0)
|
||
{
|
||
Statistics.NewCollisions = reportResult.AllCollisions.Count(c => c.Status == Autodesk.Navisworks.Api.Clash.ClashResultStatus.New);
|
||
Statistics.ActiveCollisions = reportResult.AllCollisions.Count(c => c.Status == Autodesk.Navisworks.Api.Clash.ClashResultStatus.Active);
|
||
Statistics.ReviewedCollisions = reportResult.AllCollisions.Count(c => c.Status == Autodesk.Navisworks.Api.Clash.ClashResultStatus.Reviewed);
|
||
Statistics.ApprovedCollisions = reportResult.AllCollisions.Count(c => c.Status == Autodesk.Navisworks.Api.Clash.ClashResultStatus.Approved);
|
||
Statistics.ResolvedCollisions = reportResult.AllCollisions.Count(c => c.Status == Autodesk.Navisworks.Api.Clash.ClashResultStatus.Resolved);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理碰撞数据
|
||
/// </summary>
|
||
private void ProcessCollisionData(List<CollisionResult> collisions)
|
||
{
|
||
if (collisions == null || collisions.Count == 0)
|
||
return;
|
||
|
||
var collisionItems = new List<CollisionReportItem>();
|
||
int index = 1;
|
||
|
||
foreach (var collision in collisions)
|
||
{
|
||
var item = CreateCollisionReportItem(collision, index++);
|
||
collisionItems.Add(item);
|
||
}
|
||
|
||
// 更新UI集合(按序号排序保持顺序)
|
||
SafeExecute(() =>
|
||
{
|
||
foreach (var item in collisionItems.OrderBy(i => i.Index))
|
||
AnimationCollisions.Add(item);
|
||
|
||
}, "更新碰撞报告项目列表", true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建碰撞报告项目
|
||
/// </summary>
|
||
private CollisionReportItem CreateCollisionReportItem(CollisionResult collision, int index)
|
||
{
|
||
// 获取元素名称和全路径
|
||
var item1Name = ModelItemAnalysisHelper.GetSafeDisplayName(collision.Item1);
|
||
var item2Name = ModelItemAnalysisHelper.GetSafeDisplayName(collision.Item2);
|
||
var item1Path = GetModelItemFullPath(collision.Item1);
|
||
var item2Path = GetModelItemFullPath(collision.Item2);
|
||
|
||
var title = $"{item1Name} ↔ {item2Name}";
|
||
|
||
var item = new CollisionReportItem
|
||
{
|
||
Index = index,
|
||
Title = string.IsNullOrEmpty(title.Trim().Replace("↔", "").Trim()) ? "未命名碰撞" : title,
|
||
StatusText = GetStatusDisplayText(collision.Status),
|
||
StatusColor = GetStatusColor(collision.Status),
|
||
Details = $"位置: ({collision.Center.X:F2}, {collision.Center.Y:F2}, {collision.Center.Z:F2})",
|
||
Item1FullPath = $"🚛 运动物体: {item1Path}",
|
||
Item2FullPath = $"💥 被撞对象: {item2Path}",
|
||
CollisionData = collision
|
||
};
|
||
|
||
return item;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取ModelItem的完整层级路径
|
||
/// </summary>
|
||
private string GetModelItemFullPath(ModelItem item)
|
||
{
|
||
if (item == null) return "未知对象";
|
||
|
||
try
|
||
{
|
||
var pathParts = new List<string>();
|
||
var current = item;
|
||
int levels = 0;
|
||
|
||
while (current != null && levels < 20)
|
||
{
|
||
var name = ModelItemAnalysisHelper.GetSafeDisplayName(current);
|
||
if (!string.IsNullOrEmpty(name) && name != "未命名对象")
|
||
{
|
||
pathParts.Insert(0, name);
|
||
}
|
||
current = current.Parent;
|
||
levels++;
|
||
}
|
||
|
||
return pathParts.Count > 0 ? string.Join(" > ", pathParts) : "未知对象";
|
||
}
|
||
catch
|
||
{
|
||
return ModelItemAnalysisHelper.GetSafeDisplayName(item);
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取状态显示文本
|
||
/// </summary>
|
||
private string GetStatusDisplayText(Autodesk.Navisworks.Api.Clash.ClashResultStatus status)
|
||
{
|
||
switch (status)
|
||
{
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.New:
|
||
return "新发现";
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Active:
|
||
return "活跃";
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Reviewed:
|
||
return "已审阅";
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Approved:
|
||
return "已批准";
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Resolved:
|
||
return "已解决";
|
||
default:
|
||
return "未知";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取状态颜色
|
||
/// </summary>
|
||
private string GetStatusColor(Autodesk.Navisworks.Api.Clash.ClashResultStatus status)
|
||
{
|
||
switch (status)
|
||
{
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.New:
|
||
return "#FF6B6B"; // 红色 - 新问题
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Active:
|
||
return "#FFA500"; // 橙色 - 活跃
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Reviewed:
|
||
return "#87CEEB"; // 天蓝色 - 已审阅
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Approved:
|
||
return "#98FB98"; // 浅绿色 - 已批准
|
||
case Autodesk.Navisworks.Api.Clash.ClashResultStatus.Resolved:
|
||
return "#90EE90"; // 绿色 - 已解决
|
||
default:
|
||
return "#D3D3D3"; // 灰色 - 未知
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成总结和建议
|
||
/// </summary>
|
||
private void GenerateSummaryAndRecommendations(CollisionReportResult reportResult)
|
||
{
|
||
if (reportResult.TotalCollisions == 0)
|
||
{
|
||
SummaryMessage = "✅ 未发现碰撞问题,路径规划良好。";
|
||
RecommendationMessage = "当前路径设计合理,无需调整。建议定期进行碰撞检测以确保持续的安全性。";
|
||
}
|
||
else
|
||
{
|
||
SummaryMessage = $"⚠️ 发现 {reportResult.TotalCollisions} 个碰撞问题,需要采取措施处理。";
|
||
|
||
var recommendations = new List<string>
|
||
{
|
||
"1. 调整路径规划,避开碰撞区域",
|
||
"2. 检查物体尺寸和安全边距设置",
|
||
"3. 考虑增加临时障碍物标记",
|
||
"4. 重新评估物流流程设计",
|
||
"5. 建议进行更详细的碰撞检测分析"
|
||
};
|
||
|
||
RecommendationMessage = string.Join("\n", recommendations);
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 设置空报告状态
|
||
/// </summary>
|
||
private void SetEmptyReport()
|
||
{
|
||
ReportStatus = CollisionReportStatus.Empty;
|
||
IsGenerating = false;
|
||
HasCollisions = false;
|
||
SummaryMessage = "📄 暂无碰撞数据";
|
||
RecommendationMessage = "请先运行碰撞检测或动画播放以生成碰撞数据。";
|
||
Statistics = new CollisionReportStatistics { ReportType = "空报告" };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置失败报告状态
|
||
/// </summary>
|
||
private void SetFailedReport(string errorMessage)
|
||
{
|
||
ReportStatus = CollisionReportStatus.Failed;
|
||
IsGenerating = false;
|
||
HasCollisions = false;
|
||
SummaryMessage = "❌ 报告生成失败";
|
||
RecommendationMessage = $"错误信息: {errorMessage}";
|
||
Statistics = new CollisionReportStatistics { ReportType = "生成失败" };
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令方法
|
||
|
||
/// <summary>
|
||
/// 导出报告
|
||
/// </summary>
|
||
private async Task ExportReportAsync()
|
||
{
|
||
try
|
||
{
|
||
var saveFileDialog = new SaveFileDialog
|
||
{
|
||
Title = "导出碰撞报告",
|
||
Filter = "HTML报告 (*.html)|*.html|碰撞报告 (*.txt)|*.txt|所有文件 (*.*)|*.*",
|
||
DefaultExt = "html",
|
||
FileName = $"NavisworksTransport_CollisionReport_{DateTime.Now:yyyyMMdd_HHmmss}"
|
||
};
|
||
|
||
if (saveFileDialog.ShowDialog() == true)
|
||
{
|
||
await Task.Run(() =>
|
||
{
|
||
var content = GenerateExportContent(Path.GetExtension(saveFileDialog.FileName).ToLower(), saveFileDialog.FileName);
|
||
File.WriteAllText(saveFileDialog.FileName, content, Encoding.UTF8);
|
||
});
|
||
|
||
LogManager.Info($"碰撞报告已导出到: {saveFileDialog.FileName}");
|
||
|
||
// 这里可以显示导出成功的提示
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"导出碰撞报告失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动导出报告到默认目录(关闭窗口时调用)
|
||
/// </summary>
|
||
public async Task AutoExportReportAsync()
|
||
{
|
||
try
|
||
{
|
||
if (CurrentReport == null || !HasCollisions) return;
|
||
|
||
// 生成默认文件名和路径
|
||
var sanitizedName = PathHelper.SanitizeFileName(CurrentReport.PathName ?? "未知路径");
|
||
var fileName = $"NavisworksTransport_CollisionReport_{sanitizedName}_{DateTime.Now:yyyyMMdd_HHmmss}.html";
|
||
var reportDir = PathHelper.GetReportDirectory();
|
||
var filePath = Path.Combine(reportDir, fileName);
|
||
|
||
await Task.Run(() =>
|
||
{
|
||
var content = GenerateHtmlReport(filePath);
|
||
File.WriteAllText(filePath, content, Encoding.UTF8);
|
||
});
|
||
|
||
LogManager.Info($"报告已自动导出到: {filePath}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"自动导出报告失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成导出内容
|
||
/// </summary>
|
||
private string GenerateExportContent(string fileExtension, string filePath = null)
|
||
{
|
||
if (fileExtension == ".html")
|
||
{
|
||
return GenerateHtmlReport(filePath);
|
||
}
|
||
else
|
||
{
|
||
return GenerateTextReport();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成文本报告
|
||
/// </summary>
|
||
private string GenerateTextReport()
|
||
{
|
||
var report = new StringBuilder();
|
||
var now = DateTime.Now;
|
||
|
||
// 报告头部
|
||
report.AppendLine("========================================");
|
||
report.AppendLine(" NavisworksTransport 碰撞检测报告");
|
||
report.AppendLine("========================================");
|
||
report.AppendLine($"生成时间: {now:yyyy年MM月dd日 HH:mm:ss}");
|
||
report.AppendLine($"报告类型: {Statistics.ReportType}");
|
||
report.AppendLine($"路径名称: {PathName}");
|
||
|
||
// 总体统计
|
||
report.AppendLine("=== 总体统计 ===");
|
||
report.AppendLine($"总碰撞数: {Statistics.TotalCollisions}");
|
||
report.AppendLine($"碰撞构件: {UniqueCollidedObjectsCount}个");
|
||
report.AppendLine($"检测点: {Statistics.AnimationCollisions}个");
|
||
report.AppendLine();
|
||
|
||
// 动画参数
|
||
report.AppendLine("=== 动画参数 ===");
|
||
report.AppendLine($"帧率: {FrameRate} FPS");
|
||
report.AppendLine($"时长: {Duration:F1} 秒");
|
||
report.AppendLine($"检测容差: {DetectionTolerance:F2} 米");
|
||
report.AppendLine();
|
||
|
||
// 运动构件信息
|
||
if (!string.IsNullOrEmpty(MovingObjectInfo))
|
||
{
|
||
report.AppendLine($"{MovingObjectInfo}");
|
||
}
|
||
report.AppendLine();
|
||
|
||
// 被撞物体清单
|
||
if (CollidedObjectsList?.Count > 0)
|
||
{
|
||
report.AppendLine("=== 碰撞构件清单 ===");
|
||
int index = 1;
|
||
foreach (var objName in CollidedObjectsList.Take(20)) // 限制显示前20个
|
||
{
|
||
report.AppendLine($" {index}. {objName}");
|
||
index++;
|
||
}
|
||
if (CollidedObjectsList.Count > 20)
|
||
{
|
||
report.AppendLine($" ... 还有 {CollidedObjectsList.Count - 20} 个构件");
|
||
}
|
||
report.AppendLine();
|
||
}
|
||
|
||
// 详细碰撞信息
|
||
if (HasCollisions)
|
||
{
|
||
AddCollisionDetailsToTextReport(report, "碰撞详情", AnimationCollisions);
|
||
}
|
||
|
||
// 总结和建议
|
||
report.AppendLine("=== 总结与建议 ===");
|
||
report.AppendLine(SummaryMessage);
|
||
report.AppendLine();
|
||
report.AppendLine("建议措施:");
|
||
report.AppendLine(RecommendationMessage);
|
||
report.AppendLine();
|
||
|
||
report.AppendLine("========================================");
|
||
report.AppendLine($"报告生成完成 - {now:HH:mm:ss}");
|
||
report.AppendLine("========================================");
|
||
|
||
return report.ToString();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加碰撞详细信息到文本报告
|
||
/// </summary>
|
||
private void AddCollisionDetailsToTextReport(StringBuilder report, string sectionTitle, ObservableCollection<CollisionReportItem> items)
|
||
{
|
||
if (items?.Count > 0)
|
||
{
|
||
report.AppendLine($"--- {sectionTitle} ---");
|
||
foreach (var item in items.Take(10)) // 限制显示数量
|
||
{
|
||
report.AppendLine($"• {item.Title}");
|
||
report.AppendLine($" 状态: {item.StatusText}");
|
||
report.AppendLine($" {item.Details.Replace("\n", "\n ")}");
|
||
report.AppendLine();
|
||
}
|
||
if (items.Count > 10)
|
||
{
|
||
report.AppendLine($"... 还有 {items.Count - 10} 个{sectionTitle}未显示");
|
||
}
|
||
report.AppendLine();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成HTML报告 - 统一使用 CollisionReportHtmlGenerator
|
||
/// </summary>
|
||
private string GenerateHtmlReport(string htmlFilePath = null)
|
||
{
|
||
// 确保 CurrentReport 的截图列表与 ViewModel 同步
|
||
if (CurrentReport != null && Screenshots != null)
|
||
{
|
||
CurrentReport.Screenshots = Screenshots.ToList();
|
||
}
|
||
|
||
return CollisionReportHtmlGenerator.GenerateHtmlReport(CurrentReport, htmlFilePath);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 高亮碰撞对象
|
||
/// </summary>
|
||
private void HighlightCollision(CollisionReportItem item)
|
||
{
|
||
try
|
||
{
|
||
if (item?.CollisionData == null)
|
||
return;
|
||
|
||
// 使用 ClashDetectiveResultsCategory(深红色),不是预计算高亮
|
||
var collisions = new List<CollisionResult> { item.CollisionData };
|
||
ModelHighlightHelper.ManageCollisionHighlightsByCategory(
|
||
ModelHighlightHelper.ClashDetectiveResultsCategory,
|
||
collisions,
|
||
clearOtherCategories: true);
|
||
LogManager.Info($"高亮碰撞对象: {item.Title}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"高亮碰撞对象失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭窗口
|
||
/// </summary>
|
||
private void CloseWindow()
|
||
{
|
||
// 这个方法会由View中的代码调用
|
||
LogManager.Info("关闭碰撞报告窗口");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行添加新截图(使用默认设置,不弹出对话框)
|
||
/// </summary>
|
||
private void ExecuteAddScreenshot()
|
||
{
|
||
try
|
||
{
|
||
// 使用默认设置直接生成截图,不弹出对话框
|
||
string screenshotPath = PathHelper.GenerateSceneScreenshot(
|
||
CurrentReport.PathName ?? "collision",
|
||
ScreenshotWidthSetting,
|
||
ScreenshotHeightSetting,
|
||
ScreenshotFormatSetting,
|
||
"collision"
|
||
);
|
||
|
||
if (screenshotPath != null)
|
||
{
|
||
// 创建截图对象
|
||
var screenshot = new CollisionReportScreenshot
|
||
{
|
||
FilePath = screenshotPath,
|
||
Format = PathHelper.ImageFormatToExtension(ScreenshotFormatSetting).ToUpper(),
|
||
Width = ScreenshotWidthSetting,
|
||
Height = ScreenshotHeightSetting,
|
||
SortOrder = Screenshots.Count
|
||
};
|
||
|
||
// 添加到列表
|
||
Screenshots.Add(screenshot);
|
||
SelectedScreenshot = screenshot;
|
||
|
||
// 同步到报告数据
|
||
if (CurrentReport.Screenshots == null)
|
||
CurrentReport.Screenshots = new List<CollisionReportScreenshot>();
|
||
CurrentReport.Screenshots.Add(screenshot);
|
||
|
||
// 保存到数据库
|
||
try
|
||
{
|
||
var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
|
||
// 使用 ResultId 精确关联到当前报告记录
|
||
if (pathDatabase != null && CurrentReport.ResultId > 0)
|
||
{
|
||
int dbId = pathDatabase.SaveCollisionReportScreenshot(
|
||
CurrentReport.ResultId,
|
||
screenshotPath,
|
||
screenshot.Format,
|
||
screenshot.Width,
|
||
screenshot.Height,
|
||
screenshot.SortOrder
|
||
);
|
||
screenshot.DatabaseId = dbId; // 保存数据库Id用于后续删除
|
||
LogManager.Info($"新截图已保存到数据库: DatabaseId={dbId}, ResultId={CurrentReport.ResultId}, Path={screenshotPath}");
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning($"无法保存截图到数据库: ResultId={CurrentReport.ResultId}, RouteId={CurrentReport.RouteId}");
|
||
}
|
||
}
|
||
catch (Exception dbEx)
|
||
{
|
||
LogManager.Error($"保存新截图到数据库失败: {dbEx.Message}");
|
||
}
|
||
|
||
OnPropertyChanged(nameof(HasScreenshots));
|
||
OnPropertyChanged(nameof(ScreenshotCount));
|
||
|
||
LogManager.Info($"已添加新截图,当前共 {Screenshots.Count} 张");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"添加截图失败: {ex.Message}");
|
||
System.Windows.MessageBox.Show($"添加截图失败: {ex.Message}", "错误",
|
||
System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否可以添加截图
|
||
/// </summary>
|
||
private bool CanExecuteAddScreenshot()
|
||
{
|
||
return CurrentReport != null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行截图设置 - 打开对话框修改截图参数
|
||
/// </summary>
|
||
private void ExecuteScreenshotSettings()
|
||
{
|
||
try
|
||
{
|
||
var dialog = new GenerateNavigationMapDialog();
|
||
dialog.Title = "截图设置";
|
||
|
||
// 设置当前值,保留当前报告窗口的设置
|
||
dialog.SetInitialValues(ScreenshotWidthSetting, ScreenshotHeightSetting, ScreenshotFormatSetting);
|
||
|
||
var mainWindow = System.Windows.Application.Current.MainWindow;
|
||
if (mainWindow != null && mainWindow.IsLoaded)
|
||
{
|
||
dialog.Owner = mainWindow;
|
||
}
|
||
|
||
if (dialog.ShowDialog() == true)
|
||
{
|
||
// 更新设置
|
||
ScreenshotWidthSetting = dialog.ImageWidth;
|
||
ScreenshotHeightSetting = dialog.ImageHeight;
|
||
ScreenshotFormatSetting = dialog.ImageFormat;
|
||
|
||
LogManager.Info($"截图设置已更新: {ScreenshotWidthSetting}x{ScreenshotHeightSetting}, {ScreenshotFormatSetting}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"打开截图设置失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行删除截图
|
||
/// </summary>
|
||
private void ExecuteDeleteScreenshot(CollisionReportScreenshot screenshot)
|
||
{
|
||
if (screenshot == null) return;
|
||
|
||
try
|
||
{
|
||
var result = System.Windows.MessageBox.Show(
|
||
"确定要删除这张截图吗?",
|
||
"确认删除",
|
||
System.Windows.MessageBoxButton.YesNo,
|
||
System.Windows.MessageBoxImage.Question);
|
||
|
||
if (result != System.Windows.MessageBoxResult.Yes) return;
|
||
|
||
// 从数据库删除(如果知道DatabaseId)
|
||
if (screenshot.DatabaseId > 0)
|
||
{
|
||
try
|
||
{
|
||
var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
|
||
pathDatabase?.DeleteCollisionReportScreenshot(screenshot.DatabaseId);
|
||
LogManager.Debug($"从数据库删除截图: DatabaseId={screenshot.DatabaseId}");
|
||
}
|
||
catch (Exception dbEx)
|
||
{
|
||
LogManager.Error($"从数据库删除截图失败: {dbEx.Message}");
|
||
}
|
||
}
|
||
|
||
// 从列表移除
|
||
Screenshots.Remove(screenshot);
|
||
|
||
// 从报告数据移除
|
||
CurrentReport.Screenshots?.Remove(screenshot);
|
||
|
||
// 更新选中项
|
||
if (SelectedScreenshot == screenshot)
|
||
{
|
||
SelectedScreenshot = Screenshots.FirstOrDefault();
|
||
}
|
||
|
||
// 重新排序并更新数据库
|
||
for (int i = 0; i < Screenshots.Count; i++)
|
||
{
|
||
Screenshots[i].SortOrder = i;
|
||
}
|
||
|
||
OnPropertyChanged(nameof(HasScreenshots));
|
||
OnPropertyChanged(nameof(ScreenshotCount));
|
||
|
||
LogManager.Info($"已删除截图,剩余 {Screenshots.Count} 张");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"删除截图失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行选择截图
|
||
/// </summary>
|
||
private void ExecuteSelectScreenshot(CollisionReportScreenshot screenshot)
|
||
{
|
||
if (screenshot != null)
|
||
{
|
||
SelectedScreenshot = screenshot;
|
||
LogManager.Debug($"选中截图: {screenshot.FilePath}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 高亮并聚焦到碰撞项目中的被撞对象(Item2)
|
||
/// 同时将运动物体(Item1)移动到碰撞时的位置和朝向,还原碰撞场景
|
||
/// </summary>
|
||
public void HighlightAndFocusCollisionItem(CollisionReportItem collisionItem)
|
||
{
|
||
if (collisionItem?.CollisionData == null) return;
|
||
|
||
try
|
||
{
|
||
var collisionData = collisionItem.CollisionData;
|
||
|
||
// 获取被撞对象(Item2是运动物体碰撞的静态对象)
|
||
var hitObject = collisionData.Item2;
|
||
if (hitObject == null)
|
||
{
|
||
// 如果没有Item2,使用Item1
|
||
hitObject = collisionData.Item1;
|
||
}
|
||
|
||
if (hitObject != null)
|
||
{
|
||
// 清除之前的高亮
|
||
ModelHighlightHelper.ClearAllHighlights();
|
||
|
||
// 高亮被撞对象(使用碰撞检测结果专用红色)
|
||
ModelHighlightHelper.HighlightItems(ModelHighlightHelper.ClashDetectiveResultsCategory, new[] { hitObject });
|
||
|
||
// 聚焦到被撞对象
|
||
ViewpointHelper.FocusOnModelItem(hitObject, viewAngleDegrees: 60.0, targetViewRatio: 0.25);
|
||
|
||
LogManager.Info($"聚焦到被撞对象: {collisionItem.Title}");
|
||
}
|
||
|
||
// 还原运动物体到碰撞时的位置和朝向
|
||
LogManager.Debug($"[碰撞详情点击] Item1={collisionData.Item1?.DisplayName}, HasPositionInfo={collisionData.HasPositionInfo}, Item1Position={collisionData.Item1Position}");
|
||
if (collisionData.Item1 != null && collisionData.HasPositionInfo && collisionData.Item1Position != null)
|
||
{
|
||
// 首次查看碰撞时保存运动物体状态
|
||
if (_savedAnimatedObjectState == null || _currentAnimatedObject != collisionData.Item1)
|
||
{
|
||
_currentAnimatedObject = collisionData.Item1;
|
||
// 🔥 关键:从 PathAnimationManager 获取当前实际朝向
|
||
// 因为 Transform 返回的是CAD原始朝向,不是当前实际朝向
|
||
var pam = PathAnimationManager.GetInstance();
|
||
var currentYaw = pam.CurrentYaw;
|
||
var transformYaw = ModelItemTransformHelper.GetYawFromTransform(collisionData.Item1.Transform);
|
||
LogManager.Debug($"[碰撞查看调试] PathAnimationManager.CurrentYaw={currentYaw * 180 / Math.PI:F2}°, Transform.Yaw={transformYaw * 180 / Math.PI:F2}°");
|
||
_savedAnimatedObjectState = ModelItemTransformHelper.SaveObjectState(collisionData.Item1, currentYaw);
|
||
LogManager.Info($"[碰撞查看] 已保存运动物体原始状态: pos=({_savedAnimatedObjectState.Position.X:F2},{_savedAnimatedObjectState.Position.Y:F2},{_savedAnimatedObjectState.Position.Z:F2}), yaw={currentYaw * 180 / Math.PI:F2}°");
|
||
}
|
||
|
||
RestoreAnimatedObjectToCollisionPosition(collisionData);
|
||
}
|
||
else
|
||
{
|
||
LogManager.Warning($"[碰撞详情点击] 无法还原运动物体位置: Item1={(collisionData.Item1 != null ? "有" : "无")}, HasPositionInfo={collisionData.HasPositionInfo}, Item1Position={(collisionData.Item1Position != null ? "有" : "无")}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"聚焦到被撞对象失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将运动物体还原到碰撞时的位置和朝向
|
||
/// 使用ModelItemTransformHelper.MoveItemToPositionAndYaw从CAD原始状态精确定位
|
||
/// </summary>
|
||
private void RestoreAnimatedObjectToCollisionPosition(CollisionResult collisionData)
|
||
{
|
||
try
|
||
{
|
||
var animatedObject = collisionData.Item1;
|
||
var targetPosition = collisionData.Item1Position;
|
||
var targetYaw = collisionData.Item1YawRadians;
|
||
|
||
if (animatedObject == null || targetPosition == null)
|
||
{
|
||
LogManager.Warning("[还原碰撞位置] 运动物体或位置信息为空");
|
||
return;
|
||
}
|
||
|
||
// 计算目标底面位置(Item1Position存储的是包围盒中心,需要转换为底面)
|
||
var currentBounds = animatedObject.BoundingBox();
|
||
double halfHeight = (currentBounds.Max.Z - currentBounds.Min.Z) / 2.0;
|
||
var targetGroundPosition = new Point3D(
|
||
targetPosition.X,
|
||
targetPosition.Y,
|
||
targetPosition.Z - halfHeight
|
||
);
|
||
|
||
// 使用工具方法从CAD原始状态移动到目标位置
|
||
ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, targetYaw);
|
||
|
||
LogManager.Info($"[还原碰撞位置] 运动物体已移动到碰撞位置: ({targetGroundPosition.X:F2}, {targetGroundPosition.Y:F2}, {targetGroundPosition.Z:F2}), 朝向: {targetYaw * 180 / Math.PI:F2}°");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[还原碰撞位置] 失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复运动物体到原始状态(查看碰撞前保存的状态)
|
||
/// </summary>
|
||
public void RestoreAnimatedObjectToOriginalState()
|
||
{
|
||
try
|
||
{
|
||
if (_currentAnimatedObject != null && _savedAnimatedObjectState != null)
|
||
{
|
||
ModelItemTransformHelper.RestoreObjectState(_currentAnimatedObject, _savedAnimatedObjectState);
|
||
LogManager.Info("[碰撞查看] 运动物体已恢复到原始状态");
|
||
|
||
// 清除保存的状态
|
||
_savedAnimatedObjectState = null;
|
||
_currentAnimatedObject = null;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[恢复运动物体状态] 失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |