增加检测记录表,完善批处理过程
This commit is contained in:
parent
749eb07cef
commit
dc1380d7fe
@ -124,6 +124,7 @@ namespace NavisworksTransport.Core.Animation
|
|||||||
|
|
||||||
// === 碰撞测试优化 ===
|
// === 碰撞测试优化 ===
|
||||||
private string _currentAnimationHash; // 当前动画配置的哈希值
|
private string _currentAnimationHash; // 当前动画配置的哈希值
|
||||||
|
private int? _currentDetectionRecordId; // 当前检测记录ID(关联CollisionDetectionRecords表)
|
||||||
|
|
||||||
// === 动画播放机制 ===
|
// === 动画播放机制 ===
|
||||||
private double _frameInterval; // 帧间隔(毫秒)
|
private double _frameInterval; // 帧间隔(毫秒)
|
||||||
@ -174,6 +175,15 @@ namespace NavisworksTransport.Core.Animation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ModelItem AnimatedObject => _animatedObject;
|
public ModelItem AnimatedObject => _animatedObject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前检测记录ID(关联CollisionDetectionRecords表)
|
||||||
|
/// </summary>
|
||||||
|
public int? CurrentDetectionRecordId
|
||||||
|
{
|
||||||
|
get => _currentDetectionRecordId;
|
||||||
|
set => _currentDetectionRecordId = value;
|
||||||
|
}
|
||||||
|
|
||||||
// --- 新增事件 ---
|
// --- 新增事件 ---
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当动画状态发生改变时触发
|
/// 当动画状态发生改变时触发
|
||||||
@ -1655,7 +1665,8 @@ namespace NavisworksTransport.Core.Animation
|
|||||||
_virtualObjectLength,
|
_virtualObjectLength,
|
||||||
_virtualObjectWidth,
|
_virtualObjectWidth,
|
||||||
_virtualObjectHeight,
|
_virtualObjectHeight,
|
||||||
_pathPoints
|
_pathPoints,
|
||||||
|
_currentDetectionRecordId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Autodesk.Navisworks.Api;
|
using Autodesk.Navisworks.Api;
|
||||||
|
using NavisworksTransport.Core.Animation;
|
||||||
using NavisworksTransport.Core.Collision;
|
using NavisworksTransport.Core.Collision;
|
||||||
using NavisworksTransport.Core.Models;
|
using NavisworksTransport.Core.Models;
|
||||||
|
|
||||||
@ -507,6 +508,19 @@ namespace NavisworksTransport.Core
|
|||||||
// 统一准备碰撞检测(根据模式自动决定是否构建全局缓存)
|
// 统一准备碰撞检测(根据模式自动决定是否构建全局缓存)
|
||||||
ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, isManualMode, manualDetectionTargets);
|
ClashDetectiveIntegration.PrepareCollisionDetection(animatedObject, isManualMode, manualDetectionTargets);
|
||||||
|
|
||||||
|
// 🔥 从数据库加载该队列项的检测记录(包括排除列表和手工目标)
|
||||||
|
var detectionRecord = await LoadDetectionRecordForQueueItemAsync(item);
|
||||||
|
var excludedObjects = detectionRecord?.ExcludedObjects ?? new List<ModelItem>();
|
||||||
|
var manualTargetsFromRecord = detectionRecord?.ManualTargets ?? new List<ModelItem>();
|
||||||
|
LogManager.Info($"[批处理] 队列项 {item.Id} (DetectionRecordId={item.DetectionRecordId}) 加载了 {excludedObjects.Count} 个排除对象, {manualTargetsFromRecord.Count} 个手工目标");
|
||||||
|
|
||||||
|
// 如果检测记录中有手工目标,使用检测记录中的(优先级高于队列项中的)
|
||||||
|
if (manualTargetsFromRecord.Count > 0)
|
||||||
|
{
|
||||||
|
manualDetectionTargets = manualTargetsFromRecord;
|
||||||
|
isManualMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
// 在主线程执行Navisworks API调用
|
// 在主线程执行Navisworks API调用
|
||||||
var result = await UIStateManager.Instance.ExecuteUIUpdateAsync(() =>
|
var result = await UIStateManager.Instance.ExecuteUIUpdateAsync(() =>
|
||||||
{
|
{
|
||||||
@ -522,6 +536,7 @@ namespace NavisworksTransport.Core
|
|||||||
CollisionDetectionEnabled = true,
|
CollisionDetectionEnabled = true,
|
||||||
ReportGenerationEnabled = true
|
ReportGenerationEnabled = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var frames = _processor.PrecomputeFrames(
|
var frames = _processor.PrecomputeFrames(
|
||||||
pathRoute,
|
pathRoute,
|
||||||
animatedObject,
|
animatedObject,
|
||||||
@ -533,7 +548,8 @@ namespace NavisworksTransport.Core
|
|||||||
config.DurationSeconds,
|
config.DurationSeconds,
|
||||||
config.DetectionToleranceMeters,
|
config.DetectionToleranceMeters,
|
||||||
manualDetectionTargets,
|
manualDetectionTargets,
|
||||||
item.ObjectRotationCorrection
|
item.ObjectRotationCorrection,
|
||||||
|
excludedObjects
|
||||||
);
|
);
|
||||||
|
|
||||||
// 检查预计算是否成功
|
// 检查预计算是否成功
|
||||||
@ -561,7 +577,8 @@ namespace NavisworksTransport.Core
|
|||||||
item.VirtualObjectLength,
|
item.VirtualObjectLength,
|
||||||
item.VirtualObjectWidth,
|
item.VirtualObjectWidth,
|
||||||
item.VirtualObjectHeight,
|
item.VirtualObjectHeight,
|
||||||
pathPoints
|
pathPoints,
|
||||||
|
item.DetectionRecordId
|
||||||
);
|
);
|
||||||
|
|
||||||
// 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数
|
// 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数
|
||||||
@ -720,7 +737,331 @@ namespace NavisworksTransport.Core
|
|||||||
await _database.DeleteBatchQueueItemAsync(itemId);
|
await _database.DeleteBatchQueueItemAsync(itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查并加载排除列表(已废弃,使用 LoadExcludedObjectsForQueueItemAsync 代替)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>排除列表</returns>
|
||||||
|
private List<ModelItem> CheckAndLoadExcludedObjects()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 首先检查 PathAnimationManager 中是否已有排除列表
|
||||||
|
var animationManager = PathAnimationManager.GetInstance();
|
||||||
|
var existingExcludedObjects = animationManager.GetExcludedObjects();
|
||||||
|
|
||||||
|
if (existingExcludedObjects != null && existingExcludedObjects.Count > 0)
|
||||||
|
{
|
||||||
|
LogManager.Info($"[批处理队列] 使用 PathAnimationManager 中的排除列表,共 {existingExcludedObjects.Count} 个物体");
|
||||||
|
return existingExcludedObjects.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从数据库加载排除列表(全局排除列表)
|
||||||
|
if (_database != null)
|
||||||
|
{
|
||||||
|
var excludedRecords = _database.GetExcludedObjects(routeId: null, includeGlobal: true);
|
||||||
|
if (excludedRecords != null && excludedRecords.Count > 0)
|
||||||
|
{
|
||||||
|
// 将记录转换为 ModelItem
|
||||||
|
var excludedObjects = new List<ModelItem>();
|
||||||
|
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||||
|
|
||||||
|
foreach (var record in excludedRecords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||||
|
{
|
||||||
|
ModelIndex = record.ModelIndex,
|
||||||
|
PathId = record.PathId
|
||||||
|
};
|
||||||
|
var modelItem = doc.Models.ResolvePathId(pathIdObj);
|
||||||
|
if (modelItem != null)
|
||||||
|
{
|
||||||
|
excludedObjects.Add(modelItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 加载排除对象失败: {record.ObjectName}, 错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludedObjects.Count > 0)
|
||||||
|
{
|
||||||
|
LogManager.Info($"[批处理队列] 从数据库加载排除列表,共 {excludedObjects.Count} 个物体");
|
||||||
|
return excludedObjects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排除列表为空,提示用户
|
||||||
|
LogManager.Warning("[批处理队列] 排除列表为空,需要用户确认");
|
||||||
|
|
||||||
|
bool shouldContinue = false;
|
||||||
|
System.Windows.Application.Current?.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var result = System.Windows.MessageBox.Show(
|
||||||
|
"排除列表为空。对于复杂路径,建议先运行\"生成动画\"进行预计算碰撞分析,设置排除列表后再进行批处理。\n\n" +
|
||||||
|
"• 是:继续批处理(不使用排除列表)\n" +
|
||||||
|
"• 否:取消批处理,先去设置排除列表\n\n" +
|
||||||
|
"提示:排除列表可以显著减少复杂路径的碰撞检测时间。",
|
||||||
|
"批处理确认",
|
||||||
|
System.Windows.MessageBoxButton.YesNo,
|
||||||
|
System.Windows.MessageBoxImage.Warning
|
||||||
|
);
|
||||||
|
shouldContinue = (result == System.Windows.MessageBoxResult.Yes);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldContinue)
|
||||||
|
{
|
||||||
|
LogManager.Info("[批处理队列] 用户选择继续批处理(不使用排除列表)");
|
||||||
|
return new List<ModelItem>(); // 返回空列表,允许继续
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogManager.Info("[批处理队列] 用户选择取消批处理,去设置排除列表");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[批处理队列] 检查排除列表失败: {ex.Message}");
|
||||||
|
// 发生错误时,允许继续(不阻止批处理)
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取批处理用的排除列表(已废弃,使用 LoadExcludedObjectsForQueueItemAsync 代替)
|
||||||
|
/// </summary>
|
||||||
|
private List<ModelItem> GetExcludedObjectsForBatchProcessing()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 首先检查 PathAnimationManager 中是否已有排除列表
|
||||||
|
var animationManager = PathAnimationManager.GetInstance();
|
||||||
|
var existingExcludedObjects = animationManager.GetExcludedObjects();
|
||||||
|
|
||||||
|
if (existingExcludedObjects != null && existingExcludedObjects.Count > 0)
|
||||||
|
{
|
||||||
|
return existingExcludedObjects.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从数据库加载排除列表(全局排除列表)
|
||||||
|
if (_database != null)
|
||||||
|
{
|
||||||
|
var excludedRecords = _database.GetExcludedObjects(routeId: null, includeGlobal: true);
|
||||||
|
if (excludedRecords != null && excludedRecords.Count > 0)
|
||||||
|
{
|
||||||
|
var excludedObjects = new List<ModelItem>();
|
||||||
|
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||||
|
|
||||||
|
foreach (var record in excludedRecords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||||
|
{
|
||||||
|
ModelIndex = record.ModelIndex,
|
||||||
|
PathId = record.PathId
|
||||||
|
};
|
||||||
|
var modelItem = doc.Models.ResolvePathId(pathIdObj);
|
||||||
|
if (modelItem != null)
|
||||||
|
{
|
||||||
|
excludedObjects.Add(modelItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 加载排除对象失败: {record.ObjectName}, 错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return excludedObjects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[批处理队列] 获取排除列表失败: {ex.Message}");
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从数据库加载指定队列项的排除列表
|
||||||
|
/// 从 ExcludedObjects 表读取,根据队列项对应的路径ID (RouteId) 获取
|
||||||
|
/// </summary>
|
||||||
|
private async Task<List<ModelItem>> LoadExcludedObjectsForQueueItemAsync(BatchQueueItem item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_database == null)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 数据库未初始化,无法加载队列项 {item.Id} 的排除列表");
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 ExcludedObjects 表加载该路径的排除对象
|
||||||
|
// 排除列表在生成动画时已保存,按 RouteId 关联
|
||||||
|
var excludedRecords = await Task.Run(() =>
|
||||||
|
_database.GetExcludedObjects(item.RouteId, includeGlobal: true));
|
||||||
|
|
||||||
|
if (excludedRecords == null || excludedRecords.Count == 0)
|
||||||
|
{
|
||||||
|
LogManager.Info($"[批处理队列] 队列项 {item.Id} (RouteId={item.RouteId}) 没有排除对象");
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var excludedObjects = new List<ModelItem>();
|
||||||
|
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||||
|
|
||||||
|
foreach (var record in excludedRecords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||||
|
{
|
||||||
|
ModelIndex = record.ModelIndex,
|
||||||
|
PathId = record.PathId
|
||||||
|
};
|
||||||
|
var modelItem = doc.Models.ResolvePathId(pathIdObj);
|
||||||
|
if (modelItem != null)
|
||||||
|
{
|
||||||
|
excludedObjects.Add(modelItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 无法通过 PathId 找到排除对象: ModelIndex={record.ModelIndex}, PathId={record.PathId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 加载排除对象失败: {record.ObjectName}, 错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Info($"[批处理队列] 队列项 {item.Id} 加载了 {excludedObjects.Count}/{excludedRecords.Count} 个排除对象");
|
||||||
|
return excludedObjects;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[批处理队列] 加载队列项 {item.Id} 的排除列表失败: {ex.Message}");
|
||||||
|
return new List<ModelItem>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载队列项关联的检测记录(包含排除列表和手工目标)
|
||||||
|
/// </summary>
|
||||||
|
private async Task<DetectionRecordData> LoadDetectionRecordForQueueItemAsync(BatchQueueItem item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_database == null || !item.DetectionRecordId.HasValue)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 队列项 {item.Id} 没有关联的检测记录");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取检测记录
|
||||||
|
var record = await Task.Run(() => _database.GetCollisionDetectionRecord(item.DetectionRecordId.Value));
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 未找到检测记录 (Id={item.DetectionRecordId})");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new DetectionRecordData
|
||||||
|
{
|
||||||
|
RecordId = record.Id,
|
||||||
|
RouteId = record.RouteId,
|
||||||
|
FrameRate = record.FrameRate,
|
||||||
|
DurationSeconds = record.DurationSeconds,
|
||||||
|
DetectionToleranceMeters = record.DetectionToleranceMeters,
|
||||||
|
IsVirtualObject = record.IsVirtualObject,
|
||||||
|
DetectAllObjects = record.DetectAllObjects,
|
||||||
|
ObjectRotationCorrection = record.ObjectRotationCorrection,
|
||||||
|
ExcludedObjects = new List<ModelItem>(),
|
||||||
|
ManualTargets = new List<ModelItem>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||||
|
|
||||||
|
// 加载排除列表
|
||||||
|
var excludedRecords = await Task.Run(() => _database.GetCollisionDetectionExcludedObjects(record.Id));
|
||||||
|
foreach (var excludedRecord in excludedRecords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||||
|
{
|
||||||
|
ModelIndex = excludedRecord.ModelIndex,
|
||||||
|
PathId = excludedRecord.PathId
|
||||||
|
};
|
||||||
|
var modelItem = doc.Models.ResolvePathId(pathIdObj);
|
||||||
|
if (modelItem != null)
|
||||||
|
{
|
||||||
|
result.ExcludedObjects.Add(modelItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 加载排除对象失败: {excludedRecord.ObjectName}, {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载手工目标
|
||||||
|
var manualTargetRecords = await Task.Run(() => _database.GetCollisionDetectionManualTargets(record.Id));
|
||||||
|
foreach (var targetRecord in manualTargetRecords)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||||
|
{
|
||||||
|
ModelIndex = targetRecord.ModelIndex,
|
||||||
|
PathId = targetRecord.PathId
|
||||||
|
};
|
||||||
|
var modelItem = doc.Models.ResolvePathId(pathIdObj);
|
||||||
|
if (modelItem != null)
|
||||||
|
{
|
||||||
|
result.ManualTargets.Add(modelItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[批处理队列] 加载手工目标失败: {targetRecord.ObjectName}, {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Info($"[批处理队列] 加载检测记录 (Id={record.Id}): 排除对象={result.ExcludedObjects.Count}, 手工目标={result.ManualTargets.Count}");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[批处理队列] 加载检测记录失败: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检测记录数据(用于批处理)
|
||||||
|
/// </summary>
|
||||||
|
public class DetectionRecordData
|
||||||
|
{
|
||||||
|
public int RecordId { get; set; }
|
||||||
|
public string RouteId { get; set; }
|
||||||
|
public int FrameRate { get; set; }
|
||||||
|
public double DurationSeconds { get; set; }
|
||||||
|
public double DetectionToleranceMeters { get; set; }
|
||||||
|
public bool IsVirtualObject { get; set; }
|
||||||
|
public bool DetectAllObjects { get; set; }
|
||||||
|
public double ObjectRotationCorrection { get; set; }
|
||||||
|
public List<ModelItem> ExcludedObjects { get; set; }
|
||||||
|
public List<ModelItem> ManualTargets { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -34,7 +34,8 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
double duration,
|
double duration,
|
||||||
double detectionGap,
|
double detectionGap,
|
||||||
List<ModelItem> manualDetectionTargets = null,
|
List<ModelItem> manualDetectionTargets = null,
|
||||||
double objectRotationCorrection = 0.0)
|
double objectRotationCorrection = 0.0,
|
||||||
|
List<ModelItem> excludedObjects = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -52,6 +53,13 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
_animationManager.SetManualCollisionTargets(manualDetectionTargets);
|
_animationManager.SetManualCollisionTargets(manualDetectionTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置排除列表(关键:批处理时使用排除列表)
|
||||||
|
if (excludedObjects != null && excludedObjects.Count > 0)
|
||||||
|
{
|
||||||
|
_animationManager.SetExcludedObjectsAndClearCache(excludedObjects);
|
||||||
|
LogManager.Info($"[批处理] 已设置排除列表,共 {excludedObjects.Count} 个物体");
|
||||||
|
}
|
||||||
|
|
||||||
// 调用预计算方法(内部不涉及UI操作)
|
// 调用预计算方法(内部不涉及UI操作)
|
||||||
var frames = _animationManager.PrecomputeAnimationFramesInternal();
|
var frames = _animationManager.PrecomputeAnimationFramesInternal();
|
||||||
|
|
||||||
@ -81,7 +89,8 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
double virtualObjectLength,
|
double virtualObjectLength,
|
||||||
double virtualObjectWidth,
|
double virtualObjectWidth,
|
||||||
double virtualObjectHeight,
|
double virtualObjectHeight,
|
||||||
List<Point3D> pathPoints = null)
|
List<Point3D> pathPoints = null,
|
||||||
|
int? detectionRecordId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -99,7 +108,8 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
virtualObjectLength,
|
virtualObjectLength,
|
||||||
virtualObjectWidth,
|
virtualObjectWidth,
|
||||||
virtualObjectHeight,
|
virtualObjectHeight,
|
||||||
pathPoints
|
pathPoints,
|
||||||
|
detectionRecordId
|
||||||
);
|
);
|
||||||
|
|
||||||
LogManager.Info($"[批处理] ClashDetective测试创建完成 - 测试名称: {testName}");
|
LogManager.Info($"[批处理] ClashDetective测试创建完成 - 测试名称: {testName}");
|
||||||
|
|||||||
@ -224,7 +224,7 @@ namespace NavisworksTransport
|
|||||||
int frameRate, double duration, double detectionGap,
|
int frameRate, double duration, double detectionGap,
|
||||||
ModelItem animatedObject, bool isVirtualObject,
|
ModelItem animatedObject, bool isVirtualObject,
|
||||||
double virtualObjectLength, double virtualObjectWidth, double virtualObjectHeight,
|
double virtualObjectLength, double virtualObjectWidth, double virtualObjectHeight,
|
||||||
int precomputedCollisionCount = 0)
|
int precomputedCollisionCount = 0, int? detectionRecordId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -269,7 +269,8 @@ namespace NavisworksTransport
|
|||||||
VirtualObjectLength = virtualObjectLength,
|
VirtualObjectLength = virtualObjectLength,
|
||||||
VirtualObjectWidth = virtualObjectWidth,
|
VirtualObjectWidth = virtualObjectWidth,
|
||||||
VirtualObjectHeight = virtualObjectHeight,
|
VirtualObjectHeight = virtualObjectHeight,
|
||||||
CreatedAt = DateTime.Now
|
CreatedAt = DateTime.Now,
|
||||||
|
DetectionRecordId = detectionRecordId // 关联到检测记录
|
||||||
};
|
};
|
||||||
var resultId = pathDatabase.SaveClashDetectiveResult(record);
|
var resultId = pathDatabase.SaveClashDetectiveResult(record);
|
||||||
LogManager.Info($"ClashDetective结果已保存到数据库,Id={resultId}, IsVirtualObject={isVirtualObject}");
|
LogManager.Info($"ClashDetective结果已保存到数据库,Id={resultId}, IsVirtualObject={isVirtualObject}");
|
||||||
@ -699,7 +700,8 @@ namespace NavisworksTransport
|
|||||||
double virtualObjectWidth,
|
double virtualObjectWidth,
|
||||||
double virtualObjectHeight,
|
double virtualObjectHeight,
|
||||||
Progress progress = null,
|
Progress progress = null,
|
||||||
int precomputedCollisionCount = 0)
|
int precomputedCollisionCount = 0,
|
||||||
|
int? detectionRecordId = null)
|
||||||
{
|
{
|
||||||
LogManager.Info($"[ClashDetective] 开始运行碰撞检测并保存到数据库(容差: {detectionGap}米)");
|
LogManager.Info($"[ClashDetective] 开始运行碰撞检测并保存到数据库(容差: {detectionGap}米)");
|
||||||
|
|
||||||
@ -765,7 +767,8 @@ namespace NavisworksTransport
|
|||||||
virtualObjectLength,
|
virtualObjectLength,
|
||||||
virtualObjectWidth,
|
virtualObjectWidth,
|
||||||
virtualObjectHeight,
|
virtualObjectHeight,
|
||||||
precomputedCollisionCount
|
precomputedCollisionCount,
|
||||||
|
detectionRecordId
|
||||||
);
|
);
|
||||||
|
|
||||||
return (null, addedMainTest, 0, false);
|
return (null, addedMainTest, 0, false);
|
||||||
@ -1122,7 +1125,7 @@ namespace NavisworksTransport
|
|||||||
|
|
||||||
// 保存到数据库(使用去重后的结果)
|
// 保存到数据库(使用去重后的结果)
|
||||||
SaveClashDetectiveResultToDatabase(routeId, finalClashResults, frameRate, duration, detectionGap, animatedObject, isVirtualObject,
|
SaveClashDetectiveResultToDatabase(routeId, finalClashResults, frameRate, duration, detectionGap, animatedObject, isVirtualObject,
|
||||||
virtualObjectLength, virtualObjectWidth, virtualObjectHeight, precomputedCollisionCount);
|
virtualObjectLength, virtualObjectWidth, virtualObjectHeight, precomputedCollisionCount, detectionRecordId);
|
||||||
|
|
||||||
LogManager.Info($"[ClashDetective] 结果已保存到数据库");
|
LogManager.Info($"[ClashDetective] 结果已保存到数据库");
|
||||||
|
|
||||||
@ -1159,7 +1162,8 @@ namespace NavisworksTransport
|
|||||||
double virtualObjectLength,
|
double virtualObjectLength,
|
||||||
double virtualObjectWidth,
|
double virtualObjectWidth,
|
||||||
double virtualObjectHeight,
|
double virtualObjectHeight,
|
||||||
List<Point3D> pathPoints = null)
|
List<Point3D> pathPoints = null,
|
||||||
|
int? detectionRecordId = null)
|
||||||
{
|
{
|
||||||
// 重置取消标志
|
// 重置取消标志
|
||||||
_wasLastTestCanceled = false;
|
_wasLastTestCanceled = false;
|
||||||
@ -1212,7 +1216,8 @@ namespace NavisworksTransport
|
|||||||
virtualObjectWidth,
|
virtualObjectWidth,
|
||||||
virtualObjectHeight,
|
virtualObjectHeight,
|
||||||
progress,
|
progress,
|
||||||
precomputedCollisionCount
|
precomputedCollisionCount,
|
||||||
|
detectionRecordId
|
||||||
);
|
);
|
||||||
collisionGroup = result.collisionGroup;
|
collisionGroup = result.collisionGroup;
|
||||||
addedMainTest = result.addedMainTest;
|
addedMainTest = result.addedMainTest;
|
||||||
@ -2127,7 +2132,8 @@ namespace NavisworksTransport
|
|||||||
double virtualObjectLength,
|
double virtualObjectLength,
|
||||||
double virtualObjectWidth,
|
double virtualObjectWidth,
|
||||||
double virtualObjectHeight,
|
double virtualObjectHeight,
|
||||||
List<Point3D> pathPoints = null)
|
List<Point3D> pathPoints = null,
|
||||||
|
int? detectionRecordId = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -2152,7 +2158,8 @@ namespace NavisworksTransport
|
|||||||
virtualObjectWidth,
|
virtualObjectWidth,
|
||||||
virtualObjectHeight,
|
virtualObjectHeight,
|
||||||
null,
|
null,
|
||||||
precomputedCollisionCount
|
precomputedCollisionCount,
|
||||||
|
detectionRecordId
|
||||||
);
|
);
|
||||||
|
|
||||||
var collisionGroup = result.collisionGroup;
|
var collisionGroup = result.collisionGroup;
|
||||||
|
|||||||
@ -24,6 +24,8 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
/// <param name="duration">持续时间(秒)</param>
|
/// <param name="duration">持续时间(秒)</param>
|
||||||
/// <param name="detectionGap">检测间隙(米)</param>
|
/// <param name="detectionGap">检测间隙(米)</param>
|
||||||
/// <param name="manualDetectionTargets">手动指定的检测目标(可选)</param>
|
/// <param name="manualDetectionTargets">手动指定的检测目标(可选)</param>
|
||||||
|
/// <param name="objectRotationCorrection">物体旋转修正角度(度)</param>
|
||||||
|
/// <param name="excludedObjects">排除列表(可选)</param>
|
||||||
/// <returns>动画帧列表</returns>
|
/// <returns>动画帧列表</returns>
|
||||||
List<AnimationFrame> PrecomputeFrames(
|
List<AnimationFrame> PrecomputeFrames(
|
||||||
PathRoute route,
|
PathRoute route,
|
||||||
@ -36,7 +38,8 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
double duration,
|
double duration,
|
||||||
double detectionGap,
|
double detectionGap,
|
||||||
List<ModelItem> manualDetectionTargets = null,
|
List<ModelItem> manualDetectionTargets = null,
|
||||||
double objectRotationCorrection = 0.0);
|
double objectRotationCorrection = 0.0,
|
||||||
|
List<ModelItem> excludedObjects = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建并运行ClashDetective测试(纯计算,无UI操作)
|
/// 创建并运行ClashDetective测试(纯计算,无UI操作)
|
||||||
@ -54,6 +57,7 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
/// <param name="virtualObjectWidth">虚拟物体宽度(米)</param>
|
/// <param name="virtualObjectWidth">虚拟物体宽度(米)</param>
|
||||||
/// <param name="virtualObjectHeight">虚拟物体高度(米)</param>
|
/// <param name="virtualObjectHeight">虚拟物体高度(米)</param>
|
||||||
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
|
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
|
||||||
|
/// <param name="detectionRecordId">检测记录ID(关联CollisionDetectionRecords表)</param>
|
||||||
/// <returns>ClashDetective测试名称</returns>
|
/// <returns>ClashDetective测试名称</returns>
|
||||||
string CreateAndRunClashDetectiveTest(
|
string CreateAndRunClashDetectiveTest(
|
||||||
List<CollisionResult> precomputedCollisions,
|
List<CollisionResult> precomputedCollisions,
|
||||||
@ -67,6 +71,7 @@ namespace NavisworksTransport.Core.Collision
|
|||||||
double virtualObjectLength,
|
double virtualObjectLength,
|
||||||
double virtualObjectWidth,
|
double virtualObjectWidth,
|
||||||
double virtualObjectHeight,
|
double virtualObjectHeight,
|
||||||
List<Point3D> pathPoints = null);
|
List<Point3D> pathPoints = null,
|
||||||
|
int? detectionRecordId = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,6 +37,9 @@ namespace NavisworksTransport.Core.Models
|
|||||||
// 角度修正配置
|
// 角度修正配置
|
||||||
public double ObjectRotationCorrection { get; set; }
|
public double ObjectRotationCorrection { get; set; }
|
||||||
|
|
||||||
|
// 关联的检测记录ID(每次生成动画时创建)
|
||||||
|
public int? DetectionRecordId { get; set; }
|
||||||
|
|
||||||
// 结果
|
// 结果
|
||||||
public string ClashDetectiveTestName { get; set; }
|
public string ClashDetectiveTestName { get; set; }
|
||||||
public int? CollisionCount { get; set; }
|
public int? CollisionCount { get; set; }
|
||||||
|
|||||||
@ -200,7 +200,9 @@ namespace NavisworksTransport
|
|||||||
VirtualObjectLength REAL,
|
VirtualObjectLength REAL,
|
||||||
VirtualObjectWidth REAL,
|
VirtualObjectWidth REAL,
|
||||||
VirtualObjectHeight REAL,
|
VirtualObjectHeight REAL,
|
||||||
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
DetectionRecordId INTEGER,
|
||||||
|
FOREIGN KEY(DetectionRecordId) REFERENCES CollisionDetectionRecords(Id) ON DELETE SET NULL
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
@ -381,6 +383,77 @@ namespace NavisworksTransport
|
|||||||
");
|
");
|
||||||
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_excluded_result ON ClashDetectiveExcludedObjects(ResultId)");
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_excluded_result ON ClashDetectiveExcludedObjects(ResultId)");
|
||||||
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_excluded_object ON ClashDetectiveExcludedObjects(ExcludedObjectId)");
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_excluded_object ON ClashDetectiveExcludedObjects(ExcludedObjectId)");
|
||||||
|
|
||||||
|
// 13. 碰撞检测记录表(每次点击"生成动画"创建一条记录,保存当时的完整配置)
|
||||||
|
// 先添加新列到 BatchQueueItems 表
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ExecuteNonQuery("ALTER TABLE BatchQueueItems ADD COLUMN DetectionRecordId INTEGER");
|
||||||
|
LogManager.Info("[数据库] 已添加 DetectionRecordId 列到 BatchQueueItems 表");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 列已存在,忽略错误
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecuteNonQuery(@"
|
||||||
|
CREATE TABLE IF NOT EXISTS CollisionDetectionRecords (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
RouteId TEXT NOT NULL,
|
||||||
|
CreatedTime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
-- 动画参数
|
||||||
|
FrameRate INTEGER NOT NULL,
|
||||||
|
DurationSeconds REAL NOT NULL,
|
||||||
|
-- 碰撞检测参数
|
||||||
|
DetectionToleranceMeters REAL NOT NULL,
|
||||||
|
-- 运动物体参数
|
||||||
|
IsVirtualObject INTEGER NOT NULL DEFAULT 0,
|
||||||
|
AnimatedObjectName TEXT,
|
||||||
|
ObjectModelIndex INTEGER,
|
||||||
|
ObjectPathId TEXT,
|
||||||
|
VirtualObjectLength REAL,
|
||||||
|
VirtualObjectWidth REAL,
|
||||||
|
VirtualObjectHeight REAL,
|
||||||
|
-- 检测模式
|
||||||
|
DetectAllObjects INTEGER NOT NULL DEFAULT 1,
|
||||||
|
-- 角度修正
|
||||||
|
ObjectRotationCorrection REAL DEFAULT 0.0,
|
||||||
|
-- 备注/描述
|
||||||
|
Description TEXT,
|
||||||
|
FOREIGN KEY(RouteId) REFERENCES PathRoutes(Id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_detection_route ON CollisionDetectionRecords(RouteId)");
|
||||||
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_detection_time ON CollisionDetectionRecords(CreatedTime DESC)");
|
||||||
|
|
||||||
|
// 14. 碰撞检测记录排除对象关联表(记录每次检测时的排除列表)
|
||||||
|
ExecuteNonQuery(@"
|
||||||
|
CREATE TABLE IF NOT EXISTS CollisionDetectionExcludedObjects (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
DetectionRecordId INTEGER NOT NULL,
|
||||||
|
ModelIndex INTEGER NOT NULL,
|
||||||
|
PathId TEXT NOT NULL,
|
||||||
|
DisplayName TEXT,
|
||||||
|
ObjectName TEXT,
|
||||||
|
Reason TEXT,
|
||||||
|
FOREIGN KEY(DetectionRecordId) REFERENCES CollisionDetectionRecords(Id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_detection_excluded_record ON CollisionDetectionExcludedObjects(DetectionRecordId)");
|
||||||
|
|
||||||
|
// 15. 碰撞检测记录手工目标关联表(记录每次检测时的手工碰撞目标)
|
||||||
|
ExecuteNonQuery(@"
|
||||||
|
CREATE TABLE IF NOT EXISTS CollisionDetectionManualTargets (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
DetectionRecordId INTEGER NOT NULL,
|
||||||
|
ModelIndex INTEGER NOT NULL,
|
||||||
|
PathId TEXT NOT NULL,
|
||||||
|
DisplayName TEXT,
|
||||||
|
ObjectName TEXT,
|
||||||
|
FOREIGN KEY(DetectionRecordId) REFERENCES CollisionDetectionRecords(Id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_detection_manual_record ON CollisionDetectionManualTargets(DetectionRecordId)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -801,10 +874,10 @@ namespace NavisworksTransport
|
|||||||
INSERT INTO ClashDetectiveResults
|
INSERT INTO ClashDetectiveResults
|
||||||
(TestName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
|
(TestName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
|
||||||
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualObject, ObjectModelIndex, ObjectPathId,
|
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualObject, ObjectModelIndex, ObjectPathId,
|
||||||
VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight, CreatedAt)
|
VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight, CreatedAt, DetectionRecordId)
|
||||||
VALUES (@testName, @routeId, @testTime, @collisionCount, @animationCollisionCount,
|
VALUES (@testName, @routeId, @testTime, @collisionCount, @animationCollisionCount,
|
||||||
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualObject, @objectModelIndex, @objectPathId,
|
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualObject, @objectModelIndex, @objectPathId,
|
||||||
@virtualObjectLength, @virtualObjectWidth, @virtualObjectHeight, @createdAt)
|
@virtualObjectLength, @virtualObjectWidth, @virtualObjectHeight, @createdAt, @detectionRecordId)
|
||||||
";
|
";
|
||||||
|
|
||||||
long newId = 0;
|
long newId = 0;
|
||||||
@ -826,6 +899,7 @@ namespace NavisworksTransport
|
|||||||
cmd.Parameters.AddWithValue("@virtualObjectWidth", record.VirtualObjectWidth);
|
cmd.Parameters.AddWithValue("@virtualObjectWidth", record.VirtualObjectWidth);
|
||||||
cmd.Parameters.AddWithValue("@virtualObjectHeight", record.VirtualObjectHeight);
|
cmd.Parameters.AddWithValue("@virtualObjectHeight", record.VirtualObjectHeight);
|
||||||
cmd.Parameters.AddWithValue("@createdAt", record.CreatedAt);
|
cmd.Parameters.AddWithValue("@createdAt", record.CreatedAt);
|
||||||
|
cmd.Parameters.AddWithValue("@detectionRecordId", record.DetectionRecordId ?? (object)DBNull.Value);
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
newId = _connection.LastInsertRowId;
|
newId = _connection.LastInsertRowId;
|
||||||
}
|
}
|
||||||
@ -2110,6 +2184,321 @@ namespace NavisworksTransport
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 碰撞检测记录
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存碰撞检测记录
|
||||||
|
/// 每次点击"生成动画"创建一条记录
|
||||||
|
/// </summary>
|
||||||
|
public int SaveCollisionDetectionRecord(CollisionDetectionRecord record)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
INSERT INTO CollisionDetectionRecords (
|
||||||
|
RouteId, CreatedTime, FrameRate, DurationSeconds, DetectionToleranceMeters,
|
||||||
|
IsVirtualObject, AnimatedObjectName, ObjectModelIndex, ObjectPathId,
|
||||||
|
VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight,
|
||||||
|
DetectAllObjects, ObjectRotationCorrection, Description
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
@RouteId, @CreatedTime, @FrameRate, @DurationSeconds, @DetectionToleranceMeters,
|
||||||
|
@IsVirtualObject, @AnimatedObjectName, @ObjectModelIndex, @ObjectPathId,
|
||||||
|
@VirtualObjectLength, @VirtualObjectWidth, @VirtualObjectHeight,
|
||||||
|
@DetectAllObjects, @ObjectRotationCorrection, @Description
|
||||||
|
);
|
||||||
|
SELECT last_insert_rowid();
|
||||||
|
";
|
||||||
|
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@RouteId", record.RouteId);
|
||||||
|
cmd.Parameters.AddWithValue("@CreatedTime", record.CreatedTime);
|
||||||
|
cmd.Parameters.AddWithValue("@FrameRate", record.FrameRate);
|
||||||
|
cmd.Parameters.AddWithValue("@DurationSeconds", record.DurationSeconds);
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionToleranceMeters", record.DetectionToleranceMeters);
|
||||||
|
cmd.Parameters.AddWithValue("@IsVirtualObject", record.IsVirtualObject ? 1 : 0);
|
||||||
|
cmd.Parameters.AddWithValue("@AnimatedObjectName", record.AnimatedObjectName ?? "");
|
||||||
|
cmd.Parameters.AddWithValue("@ObjectModelIndex", record.ObjectModelIndex ?? (object)DBNull.Value);
|
||||||
|
cmd.Parameters.AddWithValue("@ObjectPathId", record.ObjectPathId ?? "");
|
||||||
|
cmd.Parameters.AddWithValue("@VirtualObjectLength", record.VirtualObjectLength ?? (object)DBNull.Value);
|
||||||
|
cmd.Parameters.AddWithValue("@VirtualObjectWidth", record.VirtualObjectWidth ?? (object)DBNull.Value);
|
||||||
|
cmd.Parameters.AddWithValue("@VirtualObjectHeight", record.VirtualObjectHeight ?? (object)DBNull.Value);
|
||||||
|
cmd.Parameters.AddWithValue("@DetectAllObjects", record.DetectAllObjects ? 1 : 0);
|
||||||
|
cmd.Parameters.AddWithValue("@ObjectRotationCorrection", record.ObjectRotationCorrection);
|
||||||
|
cmd.Parameters.AddWithValue("@Description", record.Description ?? "");
|
||||||
|
|
||||||
|
var id = Convert.ToInt32(cmd.ExecuteScalar());
|
||||||
|
LogManager.Info($"保存碰撞检测记录: Id={id}, RouteId={record.RouteId}");
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"保存碰撞检测记录失败: {ex.Message}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存碰撞检测记录的排除对象
|
||||||
|
/// </summary>
|
||||||
|
public void SaveCollisionDetectionExcludedObjects(int detectionRecordId, List<CollisionDetectionExcludedObjectRecord> objects)
|
||||||
|
{
|
||||||
|
if (objects == null || objects.Count == 0) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var transaction = _connection.BeginTransaction())
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
INSERT INTO CollisionDetectionExcludedObjects
|
||||||
|
(DetectionRecordId, ModelIndex, PathId, DisplayName, ObjectName, Reason)
|
||||||
|
VALUES (@DetectionRecordId, @ModelIndex, @PathId, @DisplayName, @ObjectName, @Reason)
|
||||||
|
";
|
||||||
|
|
||||||
|
foreach (var obj in objects)
|
||||||
|
{
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionRecordId", detectionRecordId);
|
||||||
|
cmd.Parameters.AddWithValue("@ModelIndex", obj.ModelIndex);
|
||||||
|
cmd.Parameters.AddWithValue("@PathId", obj.PathId);
|
||||||
|
cmd.Parameters.AddWithValue("@DisplayName", obj.DisplayName ?? "");
|
||||||
|
cmd.Parameters.AddWithValue("@ObjectName", obj.ObjectName ?? "");
|
||||||
|
cmd.Parameters.AddWithValue("@Reason", obj.Reason ?? "");
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.Commit();
|
||||||
|
LogManager.Info($"保存检测记录排除对象: DetectionRecordId={detectionRecordId}, 数量={objects.Count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"保存检测记录排除对象失败: {ex.Message}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存碰撞检测记录的手工目标
|
||||||
|
/// </summary>
|
||||||
|
public void SaveCollisionDetectionManualTargets(int detectionRecordId, List<CollisionDetectionManualTargetRecord> targets)
|
||||||
|
{
|
||||||
|
if (targets == null || targets.Count == 0) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var transaction = _connection.BeginTransaction())
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
INSERT INTO CollisionDetectionManualTargets
|
||||||
|
(DetectionRecordId, ModelIndex, PathId, DisplayName, ObjectName)
|
||||||
|
VALUES (@DetectionRecordId, @ModelIndex, @PathId, @DisplayName, @ObjectName)
|
||||||
|
";
|
||||||
|
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionRecordId", detectionRecordId);
|
||||||
|
cmd.Parameters.AddWithValue("@ModelIndex", target.ModelIndex);
|
||||||
|
cmd.Parameters.AddWithValue("@PathId", target.PathId);
|
||||||
|
cmd.Parameters.AddWithValue("@DisplayName", target.DisplayName ?? "");
|
||||||
|
cmd.Parameters.AddWithValue("@ObjectName", target.ObjectName ?? "");
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.Commit();
|
||||||
|
LogManager.Info($"保存检测记录手工目标: DetectionRecordId={detectionRecordId}, 数量={targets.Count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"保存检测记录手工目标失败: {ex.Message}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取碰撞检测记录
|
||||||
|
/// </summary>
|
||||||
|
public CollisionDetectionRecord GetCollisionDetectionRecord(int id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
SELECT * FROM CollisionDetectionRecords WHERE Id = @Id
|
||||||
|
";
|
||||||
|
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@Id", id);
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
return ReadCollisionDetectionRecordFromReader(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"获取碰撞检测记录失败: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取路径的最新碰撞检测记录
|
||||||
|
/// </summary>
|
||||||
|
public CollisionDetectionRecord GetLatestCollisionDetectionRecord(string routeId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
SELECT * FROM CollisionDetectionRecords
|
||||||
|
WHERE RouteId = @RouteId
|
||||||
|
ORDER BY CreatedTime DESC
|
||||||
|
LIMIT 1
|
||||||
|
";
|
||||||
|
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@RouteId", routeId);
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
return ReadCollisionDetectionRecordFromReader(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"获取最新碰撞检测记录失败: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取碰撞检测记录的排除对象
|
||||||
|
/// </summary>
|
||||||
|
public List<CollisionDetectionExcludedObjectRecord> GetCollisionDetectionExcludedObjects(int detectionRecordId)
|
||||||
|
{
|
||||||
|
var results = new List<CollisionDetectionExcludedObjectRecord>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
SELECT * FROM CollisionDetectionExcludedObjects
|
||||||
|
WHERE DetectionRecordId = @DetectionRecordId
|
||||||
|
";
|
||||||
|
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionRecordId", detectionRecordId);
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
results.Add(new CollisionDetectionExcludedObjectRecord
|
||||||
|
{
|
||||||
|
Id = Convert.ToInt32(reader["Id"]),
|
||||||
|
DetectionRecordId = Convert.ToInt32(reader["DetectionRecordId"]),
|
||||||
|
ModelIndex = Convert.ToInt32(reader["ModelIndex"]),
|
||||||
|
PathId = reader["PathId"].ToString(),
|
||||||
|
DisplayName = reader["DisplayName"]?.ToString(),
|
||||||
|
ObjectName = reader["ObjectName"]?.ToString(),
|
||||||
|
Reason = reader["Reason"]?.ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"获取检测记录排除对象失败: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取碰撞检测记录的手工目标
|
||||||
|
/// </summary>
|
||||||
|
public List<CollisionDetectionManualTargetRecord> GetCollisionDetectionManualTargets(int detectionRecordId)
|
||||||
|
{
|
||||||
|
var results = new List<CollisionDetectionManualTargetRecord>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sql = @"
|
||||||
|
SELECT * FROM CollisionDetectionManualTargets
|
||||||
|
WHERE DetectionRecordId = @DetectionRecordId
|
||||||
|
";
|
||||||
|
|
||||||
|
using (var cmd = new SQLiteCommand(sql, _connection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionRecordId", detectionRecordId);
|
||||||
|
using (var reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
results.Add(new CollisionDetectionManualTargetRecord
|
||||||
|
{
|
||||||
|
Id = Convert.ToInt32(reader["Id"]),
|
||||||
|
DetectionRecordId = Convert.ToInt32(reader["DetectionRecordId"]),
|
||||||
|
ModelIndex = Convert.ToInt32(reader["ModelIndex"]),
|
||||||
|
PathId = reader["PathId"].ToString(),
|
||||||
|
DisplayName = reader["DisplayName"]?.ToString(),
|
||||||
|
ObjectName = reader["ObjectName"]?.ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"获取检测记录手工目标失败: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从DataReader读取碰撞检测记录
|
||||||
|
/// </summary>
|
||||||
|
private CollisionDetectionRecord ReadCollisionDetectionRecordFromReader(SQLiteDataReader reader)
|
||||||
|
{
|
||||||
|
return new CollisionDetectionRecord
|
||||||
|
{
|
||||||
|
Id = Convert.ToInt32(reader["Id"]),
|
||||||
|
RouteId = reader["RouteId"].ToString(),
|
||||||
|
CreatedTime = Convert.ToDateTime(reader["CreatedTime"]),
|
||||||
|
FrameRate = Convert.ToInt32(reader["FrameRate"]),
|
||||||
|
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
|
||||||
|
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
|
||||||
|
IsVirtualObject = Convert.ToInt32(reader["IsVirtualObject"]) == 1,
|
||||||
|
AnimatedObjectName = reader["AnimatedObjectName"]?.ToString(),
|
||||||
|
ObjectModelIndex = reader["ObjectModelIndex"] != DBNull.Value ? Convert.ToInt32(reader["ObjectModelIndex"]) : (int?)null,
|
||||||
|
ObjectPathId = reader["ObjectPathId"]?.ToString(),
|
||||||
|
VirtualObjectLength = reader["VirtualObjectLength"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectLength"]) : (double?)null,
|
||||||
|
VirtualObjectWidth = reader["VirtualObjectWidth"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectWidth"]) : (double?)null,
|
||||||
|
VirtualObjectHeight = reader["VirtualObjectHeight"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectHeight"]) : (double?)null,
|
||||||
|
DetectAllObjects = Convert.ToInt32(reader["DetectAllObjects"]) == 1,
|
||||||
|
ObjectRotationCorrection = Convert.ToDouble(reader["ObjectRotationCorrection"]),
|
||||||
|
Description = reader["Description"]?.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行非查询SQL语句
|
/// 执行非查询SQL语句
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -2275,14 +2664,16 @@ namespace NavisworksTransport
|
|||||||
FrameRate, DurationSeconds, DetectionToleranceMeters,
|
FrameRate, DurationSeconds, DetectionToleranceMeters,
|
||||||
IsVirtualObject, VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight,
|
IsVirtualObject, VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight,
|
||||||
DetectAllObjects,
|
DetectAllObjects,
|
||||||
ClashDetectiveTestName, CollisionCount, ObjectRotationCorrection
|
ClashDetectiveTestName, CollisionCount, ObjectRotationCorrection,
|
||||||
|
DetectionRecordId
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
@RouteId, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage,
|
@RouteId, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage,
|
||||||
@FrameRate, @DurationSeconds, @DetectionToleranceMeters,
|
@FrameRate, @DurationSeconds, @DetectionToleranceMeters,
|
||||||
@IsVirtualObject, @VirtualObjectLength, @VirtualObjectWidth, @VirtualObjectHeight,
|
@IsVirtualObject, @VirtualObjectLength, @VirtualObjectWidth, @VirtualObjectHeight,
|
||||||
@DetectAllObjects,
|
@DetectAllObjects,
|
||||||
@ClashDetectiveTestName, @CollisionCount, @ObjectRotationCorrection
|
@ClashDetectiveTestName, @CollisionCount, @ObjectRotationCorrection,
|
||||||
|
@DetectionRecordId
|
||||||
);
|
);
|
||||||
SELECT last_insert_rowid();";
|
SELECT last_insert_rowid();";
|
||||||
|
|
||||||
@ -2303,6 +2694,7 @@ namespace NavisworksTransport
|
|||||||
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
|
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
|
||||||
cmd.Parameters.AddWithValue("@CollisionCount", item.CollisionCount ?? (object)DBNull.Value);
|
cmd.Parameters.AddWithValue("@CollisionCount", item.CollisionCount ?? (object)DBNull.Value);
|
||||||
cmd.Parameters.AddWithValue("@ObjectRotationCorrection", item.ObjectRotationCorrection);
|
cmd.Parameters.AddWithValue("@ObjectRotationCorrection", item.ObjectRotationCorrection);
|
||||||
|
cmd.Parameters.AddWithValue("@DetectionRecordId", item.DetectionRecordId ?? (object)DBNull.Value);
|
||||||
|
|
||||||
var queueItemId = Convert.ToInt32(cmd.ExecuteScalar());
|
var queueItemId = Convert.ToInt32(cmd.ExecuteScalar());
|
||||||
|
|
||||||
@ -2345,7 +2737,8 @@ namespace NavisworksTransport
|
|||||||
DetectAllObjects = Convert.ToBoolean(reader["DetectAllObjects"]),
|
DetectAllObjects = Convert.ToBoolean(reader["DetectAllObjects"]),
|
||||||
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString(),
|
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString(),
|
||||||
CollisionCount = !Convert.IsDBNull(reader["CollisionCount"]) ? (int?)Convert.ToInt32(reader["CollisionCount"]) : null,
|
CollisionCount = !Convert.IsDBNull(reader["CollisionCount"]) ? (int?)Convert.ToInt32(reader["CollisionCount"]) : null,
|
||||||
ObjectRotationCorrection = Convert.ToDouble(reader["ObjectRotationCorrection"])
|
ObjectRotationCorrection = Convert.ToDouble(reader["ObjectRotationCorrection"]),
|
||||||
|
DetectionRecordId = !Convert.IsDBNull(reader["DetectionRecordId"]) ? (int?)Convert.ToInt32(reader["DetectionRecordId"]) : null
|
||||||
};
|
};
|
||||||
|
|
||||||
// 填充 MovingObjectName 属性
|
// 填充 MovingObjectName 属性
|
||||||
@ -2378,7 +2771,8 @@ namespace NavisworksTransport
|
|||||||
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
||||||
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
||||||
bqi.DetectAllObjects,
|
bqi.DetectAllObjects,
|
||||||
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection
|
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection,
|
||||||
|
bqi.DetectionRecordId
|
||||||
FROM BatchQueueItems bqi
|
FROM BatchQueueItems bqi
|
||||||
INNER JOIN PathRoutes pr ON bqi.RouteId = pr.Id";
|
INNER JOIN PathRoutes pr ON bqi.RouteId = pr.Id";
|
||||||
var conditions = new List<string>();
|
var conditions = new List<string>();
|
||||||
@ -2437,7 +2831,8 @@ namespace NavisworksTransport
|
|||||||
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
||||||
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
||||||
bqi.DetectAllObjects,
|
bqi.DetectAllObjects,
|
||||||
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection
|
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection,
|
||||||
|
bqi.DetectionRecordId
|
||||||
FROM BatchQueueItems bqi
|
FROM BatchQueueItems bqi
|
||||||
INNER JOIN PathRoutes pr ON bqi.RouteId = pr.Id
|
INNER JOIN PathRoutes pr ON bqi.RouteId = pr.Id
|
||||||
WHERE bqi.Id = @Id";
|
WHERE bqi.Id = @Id";
|
||||||
@ -3030,6 +3425,7 @@ namespace NavisworksTransport
|
|||||||
public double VirtualObjectWidth { get; set; }
|
public double VirtualObjectWidth { get; set; }
|
||||||
public double VirtualObjectHeight { get; set; }
|
public double VirtualObjectHeight { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public int? DetectionRecordId { get; set; } // 关联到检测记录
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -3053,6 +3449,73 @@ namespace NavisworksTransport
|
|||||||
public bool HasPositionInfo { get; set; }
|
public bool HasPositionInfo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 碰撞检测记录
|
||||||
|
/// 每次点击"生成动画"创建一条记录,保存当时的完整配置
|
||||||
|
/// </summary>
|
||||||
|
public class CollisionDetectionRecord
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string RouteId { get; set; }
|
||||||
|
public DateTime CreatedTime { get; set; }
|
||||||
|
|
||||||
|
// 动画参数
|
||||||
|
public int FrameRate { get; set; }
|
||||||
|
public double DurationSeconds { get; set; }
|
||||||
|
|
||||||
|
// 碰撞检测参数
|
||||||
|
public double DetectionToleranceMeters { get; set; }
|
||||||
|
|
||||||
|
// 运动物体参数
|
||||||
|
public bool IsVirtualObject { get; set; }
|
||||||
|
public string AnimatedObjectName { get; set; }
|
||||||
|
public int? ObjectModelIndex { get; set; }
|
||||||
|
public string ObjectPathId { get; set; }
|
||||||
|
public double? VirtualObjectLength { get; set; }
|
||||||
|
public double? VirtualObjectWidth { get; set; }
|
||||||
|
public double? VirtualObjectHeight { get; set; }
|
||||||
|
|
||||||
|
// 检测模式
|
||||||
|
public bool DetectAllObjects { get; set; }
|
||||||
|
|
||||||
|
// 角度修正
|
||||||
|
public double ObjectRotationCorrection { get; set; }
|
||||||
|
|
||||||
|
// 备注
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
// 关联数据(不存入数据库,查询时填充)
|
||||||
|
public List<CollisionDetectionExcludedObjectRecord> ExcludedObjects { get; set; }
|
||||||
|
public List<CollisionDetectionManualTargetRecord> ManualTargets { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 碰撞检测记录排除对象
|
||||||
|
/// </summary>
|
||||||
|
public class CollisionDetectionExcludedObjectRecord
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int DetectionRecordId { get; set; }
|
||||||
|
public int ModelIndex { get; set; }
|
||||||
|
public string PathId { get; set; }
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string ObjectName { get; set; }
|
||||||
|
public string Reason { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 碰撞检测记录手工目标
|
||||||
|
/// </summary>
|
||||||
|
public class CollisionDetectionManualTargetRecord
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int DetectionRecordId { get; set; }
|
||||||
|
public int ModelIndex { get; set; }
|
||||||
|
public string PathId { get; set; }
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string ObjectName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 碰撞报告截图记录
|
/// 碰撞报告截图记录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -2023,8 +2023,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
// 获取路由ID
|
// 获取路由ID
|
||||||
string routeId = CurrentPathRoute?.Id ?? "";
|
string routeId = CurrentPathRoute?.Id ?? "";
|
||||||
|
|
||||||
// 先保存排除对象到数据库(确保排除对象有记录ID)
|
// 注意:检测记录(包括排除列表)已在生成动画时保存到 CollisionDetectionRecords 表
|
||||||
_pathAnimationManager?.SaveExcludedObjectsToDatabase(pathDatabase, routeId);
|
// 这里只保存碰撞报告,不重复保存排除列表
|
||||||
|
|
||||||
// 从报告中获取所有需要的数据
|
// 从报告中获取所有需要的数据
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
@ -2979,6 +2979,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
// 用户选择直接继续(无排除对象)
|
// 用户选择直接继续(无排除对象)
|
||||||
LogManager.Info("[碰撞分析] 用户选择直接继续生成");
|
LogManager.Info("[碰撞分析] 用户选择直接继续生成");
|
||||||
UpdateMainStatus($"预计算碰撞分析完成,共 {totalCollisions} 个候选碰撞");
|
UpdateMainStatus($"预计算碰撞分析完成,共 {totalCollisions} 个候选碰撞");
|
||||||
|
|
||||||
|
// 🔥 保存检测记录到数据库(唯一保存位置:生成动画完成后)
|
||||||
|
SaveCollisionDetectionRecord();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -2987,6 +2990,142 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存检测记录到数据库
|
||||||
|
/// 在生成动画完成后调用,创建检测记录并保存当时的完整配置
|
||||||
|
/// </summary>
|
||||||
|
private int? SaveCollisionDetectionRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathDatabase = _pathPlanningManager?.GetPathDatabase();
|
||||||
|
if (pathDatabase == null)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[检测记录] 数据库未初始化,无法保存检测记录");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string routeId = CurrentPathRoute?.Id ?? "";
|
||||||
|
|
||||||
|
// 创建检测记录
|
||||||
|
var record = new CollisionDetectionRecord
|
||||||
|
{
|
||||||
|
RouteId = routeId,
|
||||||
|
CreatedTime = DateTime.Now,
|
||||||
|
FrameRate = _animationFrameRate,
|
||||||
|
DurationSeconds = AnimationDuration,
|
||||||
|
DetectionToleranceMeters = _detectionTolerance,
|
||||||
|
IsVirtualObject = UseVirtualObject,
|
||||||
|
AnimatedObjectName = UseVirtualObject ? "虚拟物体" : SelectedAnimatedObject?.DisplayName,
|
||||||
|
DetectAllObjects = !IsManualCollisionTargetEnabled,
|
||||||
|
ObjectRotationCorrection = _objectRotationCorrection,
|
||||||
|
Description = $"动画生成于 {DateTime.Now:yyyy-MM-dd HH:mm:ss}"
|
||||||
|
};
|
||||||
|
|
||||||
|
// 虚拟物体尺寸
|
||||||
|
if (UseVirtualObject)
|
||||||
|
{
|
||||||
|
record.VirtualObjectLength = VirtualObjectLength;
|
||||||
|
record.VirtualObjectWidth = VirtualObjectWidth;
|
||||||
|
record.VirtualObjectHeight = VirtualObjectHeight;
|
||||||
|
}
|
||||||
|
// 真实物体信息
|
||||||
|
else if (SelectedAnimatedObject != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathId = Autodesk.Navisworks.Api.Application.ActiveDocument.Models.CreatePathId(SelectedAnimatedObject);
|
||||||
|
record.ObjectModelIndex = pathId.ModelIndex;
|
||||||
|
record.ObjectPathId = pathId.PathId;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[检测记录] 获取运动物体PathId失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存检测记录
|
||||||
|
int recordId = pathDatabase.SaveCollisionDetectionRecord(record);
|
||||||
|
LogManager.Info($"[检测记录] 已创建记录 (Id={recordId})");
|
||||||
|
|
||||||
|
// 🔥 设置当前检测记录ID到PathAnimationManager(供碰撞结果保存时关联使用)
|
||||||
|
_pathAnimationManager.CurrentDetectionRecordId = recordId;
|
||||||
|
|
||||||
|
// 保存排除列表
|
||||||
|
var excludedObjects = _pathAnimationManager?.GetExcludedObjects();
|
||||||
|
if (excludedObjects != null && excludedObjects.Count > 0)
|
||||||
|
{
|
||||||
|
var excludedRecords = new List<CollisionDetectionExcludedObjectRecord>();
|
||||||
|
foreach (var obj in excludedObjects)
|
||||||
|
{
|
||||||
|
if (obj == null) continue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathId = Autodesk.Navisworks.Api.Application.ActiveDocument.Models.CreatePathId(obj);
|
||||||
|
excludedRecords.Add(new CollisionDetectionExcludedObjectRecord
|
||||||
|
{
|
||||||
|
DetectionRecordId = recordId,
|
||||||
|
ModelIndex = pathId.ModelIndex,
|
||||||
|
PathId = pathId.PathId,
|
||||||
|
DisplayName = obj.DisplayName,
|
||||||
|
ObjectName = obj.DisplayName,
|
||||||
|
Reason = "预计算碰撞分析排除"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[检测记录] 准备排除对象记录失败: {obj.DisplayName}, {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludedRecords.Count > 0)
|
||||||
|
{
|
||||||
|
pathDatabase.SaveCollisionDetectionExcludedObjects(recordId, excludedRecords);
|
||||||
|
LogManager.Info($"[检测记录] 已保存 {excludedRecords.Count} 个排除对象");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存手工目标
|
||||||
|
if (IsManualCollisionTargetEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0)
|
||||||
|
{
|
||||||
|
var manualTargetRecords = new List<CollisionDetectionManualTargetRecord>();
|
||||||
|
foreach (var target in _manualCollisionTargets)
|
||||||
|
{
|
||||||
|
if (target?.ModelItem == null) continue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathId = Autodesk.Navisworks.Api.Application.ActiveDocument.Models.CreatePathId(target.ModelItem);
|
||||||
|
manualTargetRecords.Add(new CollisionDetectionManualTargetRecord
|
||||||
|
{
|
||||||
|
DetectionRecordId = recordId,
|
||||||
|
ModelIndex = pathId.ModelIndex,
|
||||||
|
PathId = pathId.PathId,
|
||||||
|
DisplayName = target.ModelItem.DisplayName,
|
||||||
|
ObjectName = target.ModelItem.DisplayName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Warning($"[检测记录] 准备手工目标记录失败: {target.DisplayName}, {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manualTargetRecords.Count > 0)
|
||||||
|
{
|
||||||
|
pathDatabase.SaveCollisionDetectionManualTargets(recordId, manualTargetRecords);
|
||||||
|
LogManager.Info($"[检测记录] 已保存 {manualTargetRecords.Count} 个手工目标");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[检测记录] 保存失败: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteToggleWireframeMode()
|
private void ExecuteToggleWireframeMode()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -4568,8 +4707,49 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔥 检查排除列表是否已设置
|
||||||
|
var excludedObjects = _pathAnimationManager?.GetExcludedObjects();
|
||||||
|
if (excludedObjects == null || excludedObjects.Count == 0)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[批处理] 排除列表为空,提示用户");
|
||||||
|
var result = System.Windows.MessageBox.Show(
|
||||||
|
"排除列表为空。对于复杂路径,建议先运行\"生成动画\"进行预计算碰撞分析,设置排除列表后再添加到批处理。\n\n" +
|
||||||
|
"• 是:继续添加(不推荐,可能检测时间过长)\n" +
|
||||||
|
"• 否:取消添加,先去设置排除列表\n\n" +
|
||||||
|
"提示:排除列表可以显著减少复杂路径的碰撞检测时间。",
|
||||||
|
"添加到批处理确认",
|
||||||
|
System.Windows.MessageBoxButton.YesNo,
|
||||||
|
System.Windows.MessageBoxImage.Warning
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == System.Windows.MessageBoxResult.No)
|
||||||
|
{
|
||||||
|
LogManager.Info("[批处理] 用户选择取消添加,去设置排除列表");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Info("[批处理] 用户选择继续添加(不使用排除列表)");
|
||||||
|
}
|
||||||
|
|
||||||
LogManager.Info($"[批处理] 添加路径到批处理队列: {CurrentPathRoute.Name}");
|
LogManager.Info($"[批处理] 添加路径到批处理队列: {CurrentPathRoute.Name}");
|
||||||
|
|
||||||
|
// 🔥 获取该路径最新的检测记录ID
|
||||||
|
int? detectionRecordId = null;
|
||||||
|
var pathDatabase = _pathPlanningManager?.GetPathDatabase();
|
||||||
|
if (pathDatabase != null)
|
||||||
|
{
|
||||||
|
var latestRecord = pathDatabase.GetLatestCollisionDetectionRecord(CurrentPathRoute.Id);
|
||||||
|
detectionRecordId = latestRecord?.Id;
|
||||||
|
if (detectionRecordId.HasValue)
|
||||||
|
{
|
||||||
|
LogManager.Info($"[批处理] 关联检测记录 (Id={detectionRecordId})");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogManager.Warning("[批处理] 未找到检测记录,请先运行\"生成动画\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建批处理队列项
|
// 创建批处理队列项
|
||||||
var queueItem = new BatchQueueItem
|
var queueItem = new BatchQueueItem
|
||||||
{
|
{
|
||||||
@ -4594,7 +4774,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
DetectAllObjects = !IsManualCollisionTargetEnabled,
|
DetectAllObjects = !IsManualCollisionTargetEnabled,
|
||||||
|
|
||||||
// 角度修正配置
|
// 角度修正配置
|
||||||
ObjectRotationCorrection = _objectRotationCorrection
|
ObjectRotationCorrection = _objectRotationCorrection,
|
||||||
|
|
||||||
|
// 🔥 关联的检测记录ID
|
||||||
|
DetectionRecordId = detectionRecordId
|
||||||
};
|
};
|
||||||
|
|
||||||
// 调用批处理管理器添加到队列
|
// 调用批处理管理器添加到队列
|
||||||
@ -4669,6 +4852,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔥 注意:排除列表和手工目标已通过 DetectionRecordId 关联到 CollisionDetectionRecords 表
|
||||||
|
// 不需要再保存到 ModelItemReferences 表
|
||||||
|
|
||||||
LogManager.Info($"[批处理] 已创建队列项: {CurrentPathRoute.Name}, " +
|
LogManager.Info($"[批处理] 已创建队列项: {CurrentPathRoute.Name}, " +
|
||||||
$"虚拟物体: {queueItem.IsVirtualObject}, " +
|
$"虚拟物体: {queueItem.IsVirtualObject}, " +
|
||||||
$"帧率: {queueItem.FrameRate}, " +
|
$"帧率: {queueItem.FrameRate}, " +
|
||||||
|
|||||||
@ -96,8 +96,6 @@
|
|||||||
<!-- 热点列表 -->
|
<!-- 热点列表 -->
|
||||||
<Border Grid.Row="3" BorderBrush="{StaticResource NavisworksLightBrush}"
|
<Border Grid.Row="3" BorderBrush="{StaticResource NavisworksLightBrush}"
|
||||||
BorderThickness="1" CornerRadius="3" Margin="0,0,0,12">
|
BorderThickness="1" CornerRadius="3" Margin="0,0,0,12">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
|
||||||
HorizontalScrollBarVisibility="Disabled">
|
|
||||||
<DataGrid x:Name="HotspotsDataGrid"
|
<DataGrid x:Name="HotspotsDataGrid"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
CanUserAddRows="False"
|
CanUserAddRows="False"
|
||||||
@ -107,8 +105,6 @@
|
|||||||
HeadersVisibility="Column"
|
HeadersVisibility="Column"
|
||||||
RowBackground="White"
|
RowBackground="White"
|
||||||
AlternatingRowBackground="{StaticResource NavisworksBackgroundBrush}"
|
AlternatingRowBackground="{StaticResource NavisworksBackgroundBrush}"
|
||||||
MinHeight="350"
|
|
||||||
MaxHeight="450"
|
|
||||||
SelectionChanged="HotspotsDataGrid_SelectionChanged">
|
SelectionChanged="HotspotsDataGrid_SelectionChanged">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="序号" Width="45"
|
<DataGridTextColumn Header="序号" Width="45"
|
||||||
@ -161,7 +157,6 @@
|
|||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</ScrollViewer>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 选中物体详情 -->
|
<!-- 选中物体详情 -->
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user