NavisworksTransport/src/Core/PathDatabase.cs

1895 lines
92 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Core.Models;
namespace NavisworksTransport
{
/// <summary>
/// 路径数据库管理器 - 简化版
/// 负责路径和碰撞数据的持久化存储
/// </summary>
public class PathDatabase : IDisposable
{
internal SQLiteConnection _connection;
private readonly string _dbPath;
/// <summary>
/// 数据库连接(供内部使用)
/// </summary>
internal SQLiteConnection Connection => _connection;
/// <summary>
/// 初始化路径数据库
/// </summary>
/// <param name="documentPath">Navisworks文档路径</param>
public PathDatabase(string documentPath)
{
// 数据库文件与nwd文件同名扩展名为.db
_dbPath = Path.ChangeExtension(documentPath, ".db");
InitializeDatabase();
}
/// <summary>
/// 初始化数据库连接和表结构
/// </summary>
private void InitializeDatabase()
{
bool isNewDatabase = !File.Exists(_dbPath);
_connection = new SQLiteConnection($"Data Source={_dbPath};Version=3;");
_connection.Open();
// 启用WAL模式Write-Ahead Logging支持并发读
ExecuteNonQuery("PRAGMA journal_mode=WAL");
ExecuteNonQuery("PRAGMA foreign_keys=ON");
// 无论数据库是否为新数据库都调用CreateTables()
// 因为使用了CREATE TABLE IF NOT EXISTS语法所以是安全的
// 这样可以确保所有表都存在,避免在旧数据库中缺少新表的问题
CreateTables();
if (isNewDatabase)
{
LogManager.Info($"创建新数据库: {_dbPath}");
}
else
{
LogManager.Info($"打开现有数据库: {_dbPath}");
}
}
/// <summary>
/// 创建数据库表结构
/// </summary>
private void CreateTables()
{
// 1. 路径基本信息表
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS PathRoutes (
Id TEXT PRIMARY KEY,
Name TEXT NOT NULL,
TotalLength REAL,
EstimatedTime REAL,
TurnRadius REAL,
IsCurved INTEGER,
MaxVehicleLength REAL,
MaxVehicleWidth REAL,
MaxVehicleHeight REAL,
SafetyMargin REAL,
GridSize REAL,
PathType INTEGER,
AerialSubType INTEGER,
LiftHeightMeters REAL,
CreatedTime DATETIME,
LastModified DATETIME
)
");
// 2. 碰撞报告表替换原有的CollisionResults表
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS CollisionReports (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
RouteId TEXT,
PathName TEXT,
AnimatedObjectName TEXT,
UniqueCollidedObjectsCount INTEGER,
FrameRate INTEGER,
Duration REAL,
DetectionGap REAL,
AnimationCollisionCount INTEGER,
ClashDetectiveCollisionCount INTEGER,
ReportTime DATETIME
)
");
// 3. 分析结果表
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS AnalysisResults (
RouteId TEXT PRIMARY KEY,
CollisionCount INTEGER,
SafetyScore REAL,
EfficiencyScore REAL,
OverallScore REAL,
AnalysisTime DATETIME,
Strategy TEXT,
FOREIGN KEY(RouteId) REFERENCES PathRoutes(Id) ON DELETE CASCADE
)
");
// 4. 路径点表(新增 CustomTurnRadius
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS PathPoints (
Id TEXT PRIMARY KEY,
RouteId TEXT NOT NULL,
SequenceNumber INTEGER NOT NULL,
Name TEXT,
X REAL,
Y REAL,
Z REAL,
Type INTEGER,
CustomTurnRadius REAL,
FOREIGN KEY(RouteId) REFERENCES PathRoutes(Id) ON DELETE CASCADE
)
");
// 5. 路径边表新增SequenceNumber字段
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS PathEdges (
Id TEXT PRIMARY KEY,
RouteId TEXT NOT NULL,
StartPointId TEXT NOT NULL,
EndPointId TEXT NOT NULL,
SegmentType INTEGER NOT NULL,
PhysicalLength REAL NOT NULL,
SequenceNumber INTEGER NOT NULL,
Ts_X REAL,
Ts_Y REAL,
Ts_Z REAL,
Te_X REAL,
Te_Y REAL,
Te_Z REAL,
ArcCenter_X REAL,
ArcCenter_Y REAL,
ArcCenter_Z REAL,
RequestedRadius REAL,
ActualRadius REAL,
DeflectionAngle REAL,
ArcLength REAL,
FOREIGN KEY(RouteId) REFERENCES PathRoutes(Id) ON DELETE CASCADE
)
");
// 6. ClashDetective结果表
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS ClashDetectiveResults (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
TestName TEXT NOT NULL UNIQUE,
PathName TEXT NOT NULL,
RouteId TEXT NOT NULL,
TestTime DATETIME NOT NULL,
CollisionCount INTEGER NOT NULL,
AnimationCollisionCount INTEGER NOT NULL,
FrameRate INTEGER,
Duration REAL,
DetectionGap REAL,
AnimatedObjectName TEXT,
IsVirtualVehicle INTEGER,
VehicleModelIndex INTEGER,
VehiclePathId TEXT,
VirtualVehicleLength REAL,
VirtualVehicleWidth REAL,
VirtualVehicleHeight REAL,
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
)
");
// 7. ClashDetective碰撞对象表
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS ClashDetectiveCollisionObjects (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ResultId INTEGER NOT NULL,
ModelIndex INTEGER,
PathId TEXT,
DisplayName TEXT,
ObjectName TEXT,
FOREIGN KEY(ResultId) REFERENCES ClashDetectiveResults(Id) ON DELETE CASCADE
)
");
// 创建索引
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_reports_route ON CollisionReports(RouteId)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_pathpoints_route ON PathPoints(RouteId)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_pathedges_route ON PathEdges(RouteId)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_path_name ON ClashDetectiveResults(PathName)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_test_time ON ClashDetectiveResults(TestTime DESC)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_objects_result ON ClashDetectiveCollisionObjects(ResultId)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_objects_path ON ClashDetectiveCollisionObjects(PathId)");
// 8. 批处理队列表简化版只维护FIFO队列
ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS BatchQueueItems (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
PathRouteId TEXT NOT NULL,
PathRouteName TEXT NOT NULL,
Status TEXT NOT NULL,
CreatedTime TEXT NOT NULL,
StartTime TEXT,
EndTime TEXT,
ErrorMessage TEXT,
FrameRate INTEGER NOT NULL,
DurationSeconds REAL NOT NULL,
DetectionToleranceMeters REAL NOT NULL,
IsVirtualVehicle INTEGER NOT NULL,
VirtualVehicleLength REAL,
VirtualVehicleWidth REAL,
VirtualVehicleHeight REAL,
VehicleObjectId TEXT,
VehicleObjectName TEXT,
DetectionItems TEXT,
DetectAllObjects INTEGER NOT NULL DEFAULT 1,
ClashDetectiveTestName TEXT,
CollisionCount INTEGER
)
");
// 批处理表索引
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_batch_queue_status ON BatchQueueItems(Status)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_batch_queue_created ON BatchQueueItems(CreatedTime)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_batch_queue_path ON BatchQueueItems(PathRouteId)");
}
/// <summary>
/// 保存路径基本信息
/// </summary>
public void SavePathRoute(PathRoute route)
{
// 使用事务确保路径和路径点一起保存
using (var transaction = _connection.BeginTransaction())
{
try
{
// 保存路径基本信息
var sql = @"
INSERT OR REPLACE INTO PathRoutes
(Id, Name, TotalLength, EstimatedTime, TurnRadius, IsCurved, MaxVehicleLength, MaxVehicleWidth, MaxVehicleHeight, SafetyMargin, GridSize, PathType, AerialSubType, LiftHeightMeters, CreatedTime, LastModified)
VALUES (@id, @name, @length, @time, @turnRadius, @isCurved, @maxLength, @maxWidth, @maxHeight, @safetyMargin, @gridSize, @pathType, @aerialSubType, @liftHeightMeters, @created, @modified)
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", route.Id);
cmd.Parameters.AddWithValue("@name", route.Name);
cmd.Parameters.AddWithValue("@length", route.TotalLength);
cmd.Parameters.AddWithValue("@time", route.EstimatedTime);
cmd.Parameters.AddWithValue("@turnRadius", route.TurnRadius);
cmd.Parameters.AddWithValue("@isCurved", route.IsCurved ? 1 : 0);
cmd.Parameters.AddWithValue("@maxLength", route.MaxVehicleLength);
cmd.Parameters.AddWithValue("@maxWidth", route.MaxVehicleWidth);
cmd.Parameters.AddWithValue("@maxHeight", route.MaxVehicleHeight);
cmd.Parameters.AddWithValue("@safetyMargin", route.SafetyMargin);
cmd.Parameters.AddWithValue("@gridSize", route.GridSize);
cmd.Parameters.AddWithValue("@pathType", (int)route.PathType);
cmd.Parameters.AddWithValue("@aerialSubType", (int)route.AerialSubType);
cmd.Parameters.AddWithValue("@liftHeightMeters", route.LiftHeightMeters);
cmd.Parameters.AddWithValue("@created", route.CreatedTime);
cmd.Parameters.AddWithValue("@modified", DateTime.Now);
cmd.ExecuteNonQuery();
}
// 删除旧的路径点和边
DeletePathPoints(route.Id);
DeletePathEdges(route.Id);
// 保存新的路径点
if (route.Points != null && route.Points.Count > 0)
{
var pointSql = @"
INSERT INTO PathPoints
(Id, RouteId, SequenceNumber, Name, X, Y, Z, Type, CustomTurnRadius)
VALUES (@id, @routeId, @seq, @name, @x, @y, @z, @type, @customRadius)
";
for (int i = 0; i < route.Points.Count; i++)
{
var point = route.Points[i];
using (var cmd = new SQLiteCommand(pointSql, _connection))
{
cmd.Parameters.AddWithValue("@id", point.Id);
cmd.Parameters.AddWithValue("@routeId", route.Id);
cmd.Parameters.AddWithValue("@seq", i);
cmd.Parameters.AddWithValue("@name", point.Name ?? "");
cmd.Parameters.AddWithValue("@x", point.Position.X);
cmd.Parameters.AddWithValue("@y", point.Position.Y);
cmd.Parameters.AddWithValue("@z", point.Position.Z);
cmd.Parameters.AddWithValue("@type", (int)point.Type);
cmd.Parameters.AddWithValue("@customRadius", point.CustomTurnRadius.HasValue ?
(object)point.CustomTurnRadius.Value : DBNull.Value);
cmd.ExecuteNonQuery();
}
}
LogManager.Info($"保存路径: {route.Name},包含 {route.Points.Count} 个路径点");
}
// 保存路径边
if (route.Edges != null && route.Edges.Count > 0)
{
for (int i = 0; i < route.Edges.Count; i++)
{
SavePathEdge(route.Id, route.Edges[i], i);
}
LogManager.Info($"保存路径: {route.Name},包含 {route.Edges.Count} 个路径边");
}
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
LogManager.Error($"保存路径失败: {ex.Message}", ex);
throw;
}
}
}
/// <summary>
/// 保存碰撞报告
/// </summary>
public void SaveCollisionReport(string routeId, string pathName, string animatedObjectName,
int uniqueCollidedObjectsCount, int frameRate, double duration, double detectionGap,
int animationCollisionCount, int clashDetectiveCollisionCount)
{
try
{
var sql = @"
INSERT INTO CollisionReports
(RouteId, PathName, AnimatedObjectName, UniqueCollidedObjectsCount, FrameRate, Duration,
DetectionGap, AnimationCollisionCount, ClashDetectiveCollisionCount, ReportTime)
VALUES (@routeId, @pathName, @animatedObjectName, @uniqueCollidedObjectsCount, @frameRate, @duration,
@detectionGap, @animationCount, @clashCount, @reportTime)
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@routeId", routeId ?? "");
cmd.Parameters.AddWithValue("@pathName", pathName ?? "未知路径");
cmd.Parameters.AddWithValue("@animatedObjectName", animatedObjectName ?? "未知对象");
cmd.Parameters.AddWithValue("@uniqueCollidedObjectsCount", uniqueCollidedObjectsCount);
cmd.Parameters.AddWithValue("@frameRate", frameRate);
cmd.Parameters.AddWithValue("@duration", duration);
cmd.Parameters.AddWithValue("@detectionGap", detectionGap);
cmd.Parameters.AddWithValue("@animationCount", animationCollisionCount);
cmd.Parameters.AddWithValue("@clashCount", clashDetectiveCollisionCount);
cmd.Parameters.AddWithValue("@reportTime", DateTime.Now);
cmd.ExecuteNonQuery();
}
LogManager.Info($"碰撞报告已保存: 路径={pathName}, 碰撞构件={uniqueCollidedObjectsCount}, 动画碰撞={animationCollisionCount}, ClashDetective碰撞={clashDetectiveCollisionCount}");
}
catch (Exception ex)
{
LogManager.Error($"保存碰撞报告失败: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 保存路径的碰撞结果(已废弃,保留以兼容旧代码)
/// </summary>
public void SaveCollisions(string routeId, List<CollisionResult> collisions)
{
// 先删除旧的碰撞数据
ExecuteNonQuery("DELETE FROM CollisionResults WHERE RouteId=@id",
new { id = routeId });
if (collisions == null || collisions.Count == 0)
return;
// 批量插入新数据
using (var transaction = _connection.BeginTransaction())
{
try
{
var sql = @"
INSERT INTO CollisionResults
(RouteId, Item1Name, Item2Name, CenterX, CenterY, CenterZ, Distance, DetectedTime)
VALUES (@rid, @i1, @i2, @x, @y, @z, @dist, @time)
";
foreach (var collision in collisions)
{
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@rid", routeId);
cmd.Parameters.AddWithValue("@i1", GetItemDisplayName(collision.Item1));
cmd.Parameters.AddWithValue("@i2", GetItemDisplayName(collision.Item2));
cmd.Parameters.AddWithValue("@x", collision.Center.X);
cmd.Parameters.AddWithValue("@y", collision.Center.Y);
cmd.Parameters.AddWithValue("@z", collision.Center.Z);
cmd.Parameters.AddWithValue("@dist", collision.Distance);
cmd.Parameters.AddWithValue("@time", DateTime.Now);
cmd.ExecuteNonQuery();
}
}
transaction.Commit();
LogManager.Info($"保存碰撞结果: RouteId={routeId}, Count={collisions.Count}");
}
catch (Exception ex)
{
transaction.Rollback();
LogManager.Error($"保存碰撞结果失败: {ex.Message}", ex);
throw;
}
}
}
#region ClashDetective结果管理
/// <summary>
/// 保存ClashDetective碰撞检测结果
/// </summary>
public int SaveClashDetectiveResult(ClashDetectiveResultRecord record)
{
try
{
// 检查TestName是否已存在
var checkSql = "SELECT COUNT(*) FROM ClashDetectiveResults WHERE TestName = @testName";
using (var checkCmd = new SQLiteCommand(checkSql, _connection))
{
checkCmd.Parameters.AddWithValue("@testName", record.TestName);
var count = Convert.ToInt32(checkCmd.ExecuteScalar());
if (count > 0)
{
throw new InvalidOperationException($"测试名称 '{record.TestName}' 已存在,无法重复保存");
}
}
var sql = @"
INSERT INTO ClashDetectiveResults
(TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualVehicle, VehicleModelIndex, VehiclePathId,
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, CreatedAt)
VALUES (@testName, @pathName, @routeId, @testTime, @collisionCount, @animationCollisionCount,
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualVehicle, @vehicleModelIndex, @vehiclePathId,
@virtualVehicleLength, @virtualVehicleWidth, @virtualVehicleHeight, @createdAt)
";
long newId = 0;
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@testName", record.TestName);
cmd.Parameters.AddWithValue("@pathName", record.PathName);
cmd.Parameters.AddWithValue("@routeId", record.RouteId);
cmd.Parameters.AddWithValue("@testTime", record.TestTime);
cmd.Parameters.AddWithValue("@collisionCount", record.CollisionCount);
cmd.Parameters.AddWithValue("@animationCollisionCount", record.AnimationCollisionCount);
cmd.Parameters.AddWithValue("@frameRate", record.FrameRate);
cmd.Parameters.AddWithValue("@duration", record.Duration);
cmd.Parameters.AddWithValue("@detectionGap", record.DetectionGap);
cmd.Parameters.AddWithValue("@animatedObjectName", record.AnimatedObjectName ?? "");
cmd.Parameters.AddWithValue("@isVirtualVehicle", record.IsVirtualVehicle);
cmd.Parameters.AddWithValue("@vehicleModelIndex", record.VehicleModelIndex.HasValue ? (object)record.VehicleModelIndex.Value : DBNull.Value);
cmd.Parameters.AddWithValue("@vehiclePathId", record.VehiclePathId ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@virtualVehicleLength", record.VirtualVehicleLength);
cmd.Parameters.AddWithValue("@virtualVehicleWidth", record.VirtualVehicleWidth);
cmd.Parameters.AddWithValue("@virtualVehicleHeight", record.VirtualVehicleHeight);
cmd.Parameters.AddWithValue("@createdAt", record.CreatedAt);
cmd.ExecuteNonQuery();
newId = _connection.LastInsertRowId;
}
LogManager.Info($"ClashDetective结果已保存: 测试={record.TestName}, 碰撞数={record.CollisionCount}, Id={newId}");
return (int)newId;
}
catch (Exception ex)
{
LogManager.Error($"保存ClashDetective结果失败: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 获取路径的所有ClashDetective检测结果
/// </summary>
public List<ClashDetectiveResultRecord> GetClashDetectiveResultsByPath(string pathName)
{
var results = new List<ClashDetectiveResultRecord>();
try
{
var sql = @"
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
FrameRate, Duration, DetectionGap, AnimatedObjectName, CreatedAt
FROM ClashDetectiveResults
WHERE PathName = @pathName
ORDER BY TestTime DESC
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@pathName", pathName);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
results.Add(new ClashDetectiveResultRecord
{
Id = Convert.ToInt32(reader["Id"]),
TestName = reader["TestName"].ToString(),
PathName = reader["PathName"].ToString(),
RouteId = reader["RouteId"]?.ToString(),
TestTime = Convert.ToDateTime(reader["TestTime"]),
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
AnimationCollisionCount = Convert.ToInt32(reader["AnimationCollisionCount"]),
FrameRate = reader["FrameRate"] != DBNull.Value ? Convert.ToInt32(reader["FrameRate"]) : 0,
Duration = reader["Duration"] != DBNull.Value ? Convert.ToDouble(reader["Duration"]) : 0.0,
DetectionGap = reader["DetectionGap"] != DBNull.Value ? Convert.ToDouble(reader["DetectionGap"]) : 0.0,
AnimatedObjectName = reader["AnimatedObjectName"]?.ToString(),
CreatedAt = Convert.ToDateTime(reader["CreatedAt"])
});
}
}
}
LogManager.Debug($"获取到 {results.Count} 条ClashDetective结果记录");
}
catch (Exception ex)
{
LogManager.Error($"获取ClashDetective结果失败: {ex.Message}", ex);
}
return results;
}
/// <summary>
/// 获取路径最新的ClashDetective检测结果
/// </summary>
public ClashDetectiveResultRecord GetLatestClashDetectiveResult(string pathName)
{
try
{
var sql = @"
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
FrameRate, Duration, DetectionGap, AnimatedObjectName, CreatedAt
FROM ClashDetectiveResults
WHERE PathName = @pathName
ORDER BY TestTime DESC
LIMIT 1
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@pathName", pathName);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return new ClashDetectiveResultRecord
{
Id = Convert.ToInt32(reader["Id"]),
TestName = reader["TestName"].ToString(),
PathName = reader["PathName"].ToString(),
RouteId = reader["RouteId"]?.ToString(),
TestTime = Convert.ToDateTime(reader["TestTime"]),
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
AnimationCollisionCount = Convert.ToInt32(reader["AnimationCollisionCount"]),
FrameRate = reader["FrameRate"] != DBNull.Value ? Convert.ToInt32(reader["FrameRate"]) : 0,
Duration = reader["Duration"] != DBNull.Value ? Convert.ToDouble(reader["Duration"]) : 0.0,
DetectionGap = reader["DetectionGap"] != DBNull.Value ? Convert.ToDouble(reader["DetectionGap"]) : 0.0,
AnimatedObjectName = reader["AnimatedObjectName"]?.ToString(),
CreatedAt = Convert.ToDateTime(reader["CreatedAt"])
};
}
}
}
}
catch (Exception ex)
{
LogManager.Error($"获取最新ClashDetective结果失败: {ex.Message}", ex);
}
return null;
}
/// <summary>
/// 删除ClashDetective检测结果
/// </summary>
public void DeleteClashDetectiveResult(int id)
{
try
{
ExecuteNonQuery("DELETE FROM ClashDetectiveResults WHERE Id=@id",
new { id = id });
LogManager.Info($"已删除ClashDetective结果记录: Id={id}");
}
catch (Exception ex)
{
LogManager.Error($"删除ClashDetective结果失败: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 保存ClashDetective碰撞对象
/// </summary>
public void SaveClashDetectiveCollisionObjects(int resultId, List<ClashDetectiveCollisionObjectRecord> objects)
{
if (objects == null || objects.Count == 0)
return;
try
{
using (var transaction = _connection.BeginTransaction())
{
var sql = @"
INSERT INTO ClashDetectiveCollisionObjects
(ResultId, ModelIndex, PathId, DisplayName, ObjectName)
VALUES (@resultId, @modelIndex, @pathId, @displayName, @objectName)
";
foreach (var obj in objects)
{
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@resultId", resultId);
cmd.Parameters.AddWithValue("@modelIndex", obj.ModelIndex.HasValue ? (object)obj.ModelIndex.Value : DBNull.Value);
cmd.Parameters.AddWithValue("@pathId", obj.PathId ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@displayName", obj.DisplayName ?? "");
cmd.Parameters.AddWithValue("@objectName", obj.ObjectName ?? "");
cmd.ExecuteNonQuery();
}
}
transaction.Commit();
LogManager.Info($"已保存 {objects.Count} 个碰撞对象到数据库ResultId={resultId}");
}
}
catch (Exception ex)
{
LogManager.Error($"保存ClashDetective碰撞对象失败: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 获取指定ClashDetective结果的所有碰撞对象
/// </summary>
public List<ClashDetectiveCollisionObjectRecord> GetClashDetectiveCollisionObjects(int resultId)
{
var results = new List<ClashDetectiveCollisionObjectRecord>();
try
{
var sql = @"
SELECT Id, ResultId, ModelIndex, PathId, DisplayName, ObjectName
FROM ClashDetectiveCollisionObjects
WHERE ResultId = @resultId
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@resultId", resultId);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
results.Add(new ClashDetectiveCollisionObjectRecord
{
Id = Convert.ToInt32(reader["Id"]),
ResultId = Convert.ToInt32(reader["ResultId"]),
ModelIndex = reader["ModelIndex"] != DBNull.Value ? Convert.ToInt32(reader["ModelIndex"]) : (int?)null,
PathId = reader["PathId"] != DBNull.Value ? reader["PathId"].ToString() : null,
DisplayName = reader["DisplayName"]?.ToString(),
ObjectName = reader["ObjectName"]?.ToString()
});
}
}
}
LogManager.Debug($"获取到 {results.Count} 个碰撞对象记录");
}
catch (Exception ex)
{
LogManager.Error($"获取ClashDetective碰撞对象失败: {ex.Message}", ex);
}
return results;
}
#endregion
/// <summary>
/// 保存分析评分结果
/// </summary>
public void SaveAnalysisScore(string routeId, int collisionCount, double safetyScore,
double efficiencyScore, string strategy)
{
var overallScore = (safetyScore + efficiencyScore) / 2.0;
var sql = @"
INSERT OR REPLACE INTO AnalysisResults
(RouteId, CollisionCount, SafetyScore, EfficiencyScore, OverallScore, AnalysisTime, Strategy)
VALUES (@id, @count, @safety, @eff, @overall, @time, @strategy)
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", routeId);
cmd.Parameters.AddWithValue("@count", collisionCount);
cmd.Parameters.AddWithValue("@safety", safetyScore);
cmd.Parameters.AddWithValue("@eff", efficiencyScore);
cmd.Parameters.AddWithValue("@overall", overallScore);
cmd.Parameters.AddWithValue("@time", DateTime.Now);
cmd.Parameters.AddWithValue("@strategy", strategy ?? "默认");
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 获取路径的碰撞数量
/// </summary>
public int GetCollisionCount(string routeId)
{
var sql = "SELECT COUNT(*) FROM CollisionResults WHERE RouteId=@id";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", routeId);
var result = cmd.ExecuteScalar();
return Convert.ToInt32(result);
}
}
/// <summary>
/// 获取路径的分析结果
/// </summary>
public PathAnalysisResult GetAnalysisResult(string routeId)
{
var sql = "SELECT * FROM AnalysisResults WHERE RouteId=@id";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", routeId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return new PathAnalysisResult
{
RouteId = reader["RouteId"].ToString(),
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
SafetyScore = Convert.ToDouble(reader["SafetyScore"]),
EfficiencyScore = Convert.ToDouble(reader["EfficiencyScore"]),
OverallScore = Convert.ToDouble(reader["OverallScore"]),
AnalysisTime = Convert.ToDateTime(reader["AnalysisTime"]),
Strategy = reader["Strategy"].ToString()
};
}
}
}
return null;
}
/// <summary>
/// 获取所有路径的分析结果
/// </summary>
public List<PathAnalysisResult> GetAllAnalysisResults()
{
var results = new List<PathAnalysisResult>();
var sql = "SELECT * FROM AnalysisResults ORDER BY OverallScore DESC";
using (var cmd = new SQLiteCommand(sql, _connection))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
results.Add(new PathAnalysisResult
{
RouteId = reader["RouteId"].ToString(),
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
SafetyScore = Convert.ToDouble(reader["SafetyScore"]),
EfficiencyScore = Convert.ToDouble(reader["EfficiencyScore"]),
OverallScore = Convert.ToDouble(reader["OverallScore"]),
AnalysisTime = Convert.ToDateTime(reader["AnalysisTime"]),
Strategy = reader["Strategy"].ToString()
});
}
}
return results;
}
/// <summary>
/// 删除路径及其相关数据
/// </summary>
/// <param name="routeId">路径ID</param>
public void DeletePathRoute(string routeId)
{
try
{
// 由于设置了外键级联删除,删除路径时会自动删除相关的碰撞结果和分析结果
var sql = "DELETE FROM PathRoutes WHERE Id = @id";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", routeId);
int affected = cmd.ExecuteNonQuery();
LogManager.Info($"删除路径记录: ID={routeId}, 影响行数={affected}");
}
}
catch (Exception ex)
{
LogManager.Error($"删除路径失败: ID={routeId}, {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 获取所有路径基本信息
/// </summary>
public List<PathRoute> GetAllPathRoutes()
{
var routes = new List<PathRoute>();
var sql = @"SELECT pr.*, ar.CollisionCount, ar.SafetyScore, ar.EfficiencyScore, ar.OverallScore
FROM PathRoutes pr
LEFT JOIN AnalysisResults ar ON pr.Id = ar.RouteId
ORDER BY pr.LastModified DESC";
using (var cmd = new SQLiteCommand(sql, _connection))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var route = new PathRoute
{
Id = reader["Id"].ToString(),
Name = reader["Name"].ToString(),
TotalLength = Convert.ToDouble(reader["TotalLength"]),
EstimatedTime = Convert.ToDouble(reader["EstimatedTime"]),
TurnRadius = reader.IsDBNull(reader.GetOrdinal("TurnRadius")) ? 0.0 : Convert.ToDouble(reader["TurnRadius"]), // 0.0 表示未设置,实际使用时从配置获取
IsCurved = reader.IsDBNull(reader.GetOrdinal("IsCurved")) ? false : Convert.ToInt32(reader["IsCurved"]) == 1,
MaxVehicleLength = reader.IsDBNull(reader.GetOrdinal("MaxVehicleLength")) ? 1.0 : Convert.ToDouble(reader["MaxVehicleLength"]),
MaxVehicleWidth = reader.IsDBNull(reader.GetOrdinal("MaxVehicleWidth")) ? 1.0 : Convert.ToDouble(reader["MaxVehicleWidth"]),
MaxVehicleHeight = reader.IsDBNull(reader.GetOrdinal("MaxVehicleHeight")) ? 2.0 : Convert.ToDouble(reader["MaxVehicleHeight"]),
SafetyMargin = reader.IsDBNull(reader.GetOrdinal("SafetyMargin")) ? 0.5 : Convert.ToDouble(reader["SafetyMargin"]),
GridSize = reader.IsDBNull(reader.GetOrdinal("GridSize")) ? 0.5 : Convert.ToDouble(reader["GridSize"]),
PathType = reader.IsDBNull(reader.GetOrdinal("PathType")) ? PathType.Ground : (PathType)Convert.ToInt32(reader["PathType"]),
AerialSubType = reader.IsDBNull(reader.GetOrdinal("AerialSubType")) ? AerialSubType.Rail : (AerialSubType)Convert.ToInt32(reader["AerialSubType"]),
LiftHeightMeters = reader.IsDBNull(reader.GetOrdinal("LiftHeightMeters")) ? 0.0 : Convert.ToDouble(reader["LiftHeightMeters"]),
CreatedTime = Convert.ToDateTime(reader["CreatedTime"]),
LastModified = Convert.ToDateTime(reader["LastModified"])
};
// 添加分析结果(如果存在)
if (!reader.IsDBNull(reader.GetOrdinal("CollisionCount")))
{
route.CollisionCount = Convert.ToInt32(reader["CollisionCount"]);
route.SafetyScore = Convert.ToDouble(reader["SafetyScore"]);
route.EfficiencyScore = Convert.ToDouble(reader["EfficiencyScore"]);
route.OverallScore = Convert.ToDouble(reader["OverallScore"]);
}
routes.Add(route);
}
}
// 为每个路径加载路径点和路径边
foreach (var route in routes)
{
LoadPathPoints(route);
LoadPathEdges(route);
}
LogManager.Info($"从数据库加载了 {routes.Count} 条路径记录");
return routes;
}
/// <summary>
/// 加载指定路径的路径点
/// </summary>
private void LoadPathPoints(PathRoute route)
{
var sql = @"SELECT * FROM PathPoints
WHERE RouteId=@routeId
ORDER BY SequenceNumber";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@routeId", route.Id);
using (var reader = cmd.ExecuteReader())
{
int index = 0;
while (reader.Read())
{
var point = new PathPoint
{
Id = reader["Id"].ToString(),
Name = reader["Name"].ToString(),
Position = new Autodesk.Navisworks.Api.Point3D(
Convert.ToDouble(reader["X"]),
Convert.ToDouble(reader["Y"]),
Convert.ToDouble(reader["Z"])
),
Type = (PathPointType)Convert.ToInt32(reader["Type"]),
Index = index++
};
// 加载自定义转向半径
if (!reader.IsDBNull(reader.GetOrdinal("CustomTurnRadius")))
{
point.CustomTurnRadius = Convert.ToDouble(reader["CustomTurnRadius"]);
}
route.Points.Add(point);
}
}
}
}
/// <summary>
/// 保存路径边
/// </summary>
private void SavePathEdge(string routeId, PathEdge edge, int sequenceNumber)
{
var sql = @"
INSERT INTO PathEdges
(Id, RouteId, StartPointId, EndPointId, SegmentType, PhysicalLength, SequenceNumber,
Ts_X, Ts_Y, Ts_Z, Te_X, Te_Y, Te_Z,
ArcCenter_X, ArcCenter_Y, ArcCenter_Z,
RequestedRadius, ActualRadius, DeflectionAngle, ArcLength)
VALUES (@id, @routeId, @startId, @endId, @segType, @length, @seqNum,
@tsx, @tsy, @tsz, @tex, @tey, @tez,
@acx, @acy, @acz,
@reqR, @actR, @angle, @arcLen)
";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@id", edge.Id);
cmd.Parameters.AddWithValue("@routeId", routeId);
cmd.Parameters.AddWithValue("@startId", edge.StartPointId ?? "");
cmd.Parameters.AddWithValue("@endId", edge.EndPointId ?? "");
cmd.Parameters.AddWithValue("@segType", (int)edge.SegmentType);
cmd.Parameters.AddWithValue("@length", edge.PhysicalLength);
cmd.Parameters.AddWithValue("@seqNum", sequenceNumber);
// 直线段:保存起止点坐标
if (edge.SegmentType == PathSegmentType.Straight && edge.SampledPoints != null && edge.SampledPoints.Count >= 2)
{
cmd.Parameters.AddWithValue("@tsx", edge.SampledPoints.First().X);
cmd.Parameters.AddWithValue("@tsy", edge.SampledPoints.First().Y);
cmd.Parameters.AddWithValue("@tsz", edge.SampledPoints.First().Z);
cmd.Parameters.AddWithValue("@tex", edge.SampledPoints.Last().X);
cmd.Parameters.AddWithValue("@tey", edge.SampledPoints.Last().Y);
cmd.Parameters.AddWithValue("@tez", edge.SampledPoints.Last().Z);
// 圆弧参数为NULL
cmd.Parameters.AddWithValue("@acx", DBNull.Value);
cmd.Parameters.AddWithValue("@acy", DBNull.Value);
cmd.Parameters.AddWithValue("@acz", DBNull.Value);
cmd.Parameters.AddWithValue("@reqR", DBNull.Value);
cmd.Parameters.AddWithValue("@actR", DBNull.Value);
cmd.Parameters.AddWithValue("@angle", DBNull.Value);
cmd.Parameters.AddWithValue("@arcLen", DBNull.Value);
}
else if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null)
{
// 圆弧段:保存圆弧轨迹数据
cmd.Parameters.AddWithValue("@tsx", edge.Trajectory.Ts.X);
cmd.Parameters.AddWithValue("@tsy", edge.Trajectory.Ts.Y);
cmd.Parameters.AddWithValue("@tsz", edge.Trajectory.Ts.Z);
cmd.Parameters.AddWithValue("@tex", edge.Trajectory.Te.X);
cmd.Parameters.AddWithValue("@tey", edge.Trajectory.Te.Y);
cmd.Parameters.AddWithValue("@tez", edge.Trajectory.Te.Z);
cmd.Parameters.AddWithValue("@acx", edge.Trajectory.ArcCenter.X);
cmd.Parameters.AddWithValue("@acy", edge.Trajectory.ArcCenter.Y);
cmd.Parameters.AddWithValue("@acz", edge.Trajectory.ArcCenter.Z);
cmd.Parameters.AddWithValue("@reqR", edge.Trajectory.RequestedRadius);
cmd.Parameters.AddWithValue("@actR", edge.Trajectory.ActualRadius);
cmd.Parameters.AddWithValue("@angle", edge.Trajectory.DeflectionAngle);
cmd.Parameters.AddWithValue("@arcLen", edge.Trajectory.ArcLength);
}
else
{
// 其他情况所有参数为NULL
cmd.Parameters.AddWithValue("@tsx", DBNull.Value);
cmd.Parameters.AddWithValue("@tsy", DBNull.Value);
cmd.Parameters.AddWithValue("@tsz", DBNull.Value);
cmd.Parameters.AddWithValue("@tex", DBNull.Value);
cmd.Parameters.AddWithValue("@tey", DBNull.Value);
cmd.Parameters.AddWithValue("@tez", DBNull.Value);
cmd.Parameters.AddWithValue("@acx", DBNull.Value);
cmd.Parameters.AddWithValue("@acy", DBNull.Value);
cmd.Parameters.AddWithValue("@acz", DBNull.Value);
cmd.Parameters.AddWithValue("@reqR", DBNull.Value);
cmd.Parameters.AddWithValue("@actR", DBNull.Value);
cmd.Parameters.AddWithValue("@angle", DBNull.Value);
cmd.Parameters.AddWithValue("@arcLen", DBNull.Value);
}
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 删除路径点
/// </summary>
private void DeletePathPoints(string routeId)
{
using (var cmd = new SQLiteCommand("DELETE FROM PathPoints WHERE RouteId = @routeId", _connection))
{
cmd.Parameters.AddWithValue("@routeId", routeId);
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 删除路径边
/// </summary>
private void DeletePathEdges(string routeId)
{
using (var cmd = new SQLiteCommand("DELETE FROM PathEdges WHERE RouteId = @routeId", _connection))
{
cmd.Parameters.AddWithValue("@routeId", routeId);
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 加载路径边
/// </summary>
private void LoadPathEdges(PathRoute route)
{
var sql = "SELECT * FROM PathEdges WHERE RouteId = @routeId ORDER BY SequenceNumber";
using (var cmd = new SQLiteCommand(sql, _connection))
{
cmd.Parameters.AddWithValue("@routeId", route.Id);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var edge = new PathEdge
{
Id = reader["Id"].ToString(),
StartPointId = reader["StartPointId"].ToString(),
EndPointId = reader["EndPointId"].ToString(),
SegmentType = (PathSegmentType)Convert.ToInt32(reader["SegmentType"]),
PhysicalLength = Convert.ToDouble(reader["PhysicalLength"])
};
// 加载圆弧轨迹数据
if (edge.SegmentType == PathSegmentType.Arc)
{
edge.Trajectory = new ArcTrajectory
{
Ts = new Point3D(
Convert.ToDouble(reader["Ts_X"]),
Convert.ToDouble(reader["Ts_Y"]),
Convert.ToDouble(reader["Ts_Z"])),
Te = new Point3D(
Convert.ToDouble(reader["Te_X"]),
Convert.ToDouble(reader["Te_Y"]),
Convert.ToDouble(reader["Te_Z"])),
ArcCenter = new Point3D(
Convert.ToDouble(reader["ArcCenter_X"]),
Convert.ToDouble(reader["ArcCenter_Y"]),
Convert.ToDouble(reader["ArcCenter_Z"])),
RequestedRadius = Convert.ToDouble(reader["RequestedRadius"]),
ActualRadius = Convert.ToDouble(reader["ActualRadius"]),
DeflectionAngle = Convert.ToDouble(reader["DeflectionAngle"]),
ArcLength = Convert.ToDouble(reader["ArcLength"])
};
}
else if (edge.SegmentType == PathSegmentType.Straight)
{
// 直线段也加载Ts和Te用于重新计算SampledPoints
if (!reader.IsDBNull(reader.GetOrdinal("Ts_X")) &&
!reader.IsDBNull(reader.GetOrdinal("Te_X")))
{
edge.Trajectory = new ArcTrajectory
{
Ts = new Point3D(
Convert.ToDouble(reader["Ts_X"]),
Convert.ToDouble(reader["Ts_Y"]),
Convert.ToDouble(reader["Ts_Z"])),
Te = new Point3D(
Convert.ToDouble(reader["Te_X"]),
Convert.ToDouble(reader["Te_Y"]),
Convert.ToDouble(reader["Te_Z"])),
ArcCenter = new Point3D(0, 0, 0), // 直线段没有圆心
RequestedRadius = 0,
ActualRadius = 0,
DeflectionAngle = 0,
ArcLength = 0
};
}
}
route.Edges.Add(edge);
}
}
}
// 重新计算SampledPoints因为数据库中没有保存采样点
if (route.Edges.Count > 0)
{
double samplingStep = ConfigManager.Instance.Current.PathEditing.ArcSamplingStep;
foreach (var edge in route.Edges)
{
if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null)
{
// 圆弧段使用PathCurveEngine重新采样
edge.SampledPoints = PathCurveEngine.SampleArc(edge.Trajectory, samplingStep);
}
else if (edge.SegmentType == PathSegmentType.Straight)
{
// 直线段从数据库加载的Ts和Te重新采样
Point3D startPoint = null;
Point3D endPoint = null;
// 尝试从Trajectory中获取直线段也可能用Trajectory存储起止点
if (edge.Trajectory != null)
{
startPoint = edge.Trajectory.Ts;
endPoint = edge.Trajectory.Te;
}
// 如果找到了起止点,重新采样
if (startPoint != null && endPoint != null)
{
int sampleCount = Math.Max(2, (int)Math.Ceiling(edge.PhysicalLength / samplingStep));
edge.SampledPoints = new List<Point3D>();
for (int i = 0; i <= sampleCount; i++)
{
double t = i / (double)sampleCount;
Point3D sampledPoint = startPoint + (endPoint - startPoint) * t;
edge.SampledPoints.Add(sampledPoint);
}
}
}
}
}
}
/// <summary>
/// 执行非查询SQL语句
/// </summary>
private void ExecuteNonQuery(string sql, object parameters = null)
{
using (var cmd = new SQLiteCommand(sql, _connection))
{
if (parameters != null)
{
var props = parameters.GetType().GetProperties();
foreach (var prop in props)
{
cmd.Parameters.AddWithValue($"@{prop.Name}", prop.GetValue(parameters));
}
}
cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 获取ModelItem的显示名称
/// </summary>
private string GetItemDisplayName(ModelItem item)
{
if (item == null)
return "未知对象";
try
{
return item.DisplayName ?? item.ToString();
}
catch
{
return "未知对象";
}
}
#region
/// <summary>
/// 创建批处理任务
/// </summary>
public async Task<int> CreateBatchTaskAsync(BatchCollisionTask task)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
INSERT INTO BatchTasks (Name, Description, CreatedTime, Status, StartTime, EndTime, TotalItems, CompletedItems, FailedItems, LastModified)
VALUES (@Name, @Description, @CreatedTime, @Status, @StartTime, @EndTime, @TotalItems, @CompletedItems, @FailedItems, @LastModified);
SELECT last_insert_rowid();";
cmd.Parameters.AddWithValue("@Name", task.Name);
cmd.Parameters.AddWithValue("@Description", task.Description ?? "");
cmd.Parameters.AddWithValue("@CreatedTime", task.CreatedTime.ToString("o"));
cmd.Parameters.AddWithValue("@Status", task.Status.ToString());
cmd.Parameters.AddWithValue("@StartTime", task.StartTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@EndTime", task.EndTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@TotalItems", task.TotalItems);
cmd.Parameters.AddWithValue("@CompletedItems", task.CompletedItems);
cmd.Parameters.AddWithValue("@FailedItems", task.FailedItems);
cmd.Parameters.AddWithValue("@LastModified", task.LastModified.ToString("o"));
return Convert.ToInt32(cmd.ExecuteScalar());
}
});
}
/// <summary>
/// 创建批处理任务项
/// </summary>
public async Task<int> CreateBatchTaskItemAsync(BatchTaskItem item)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
INSERT INTO BatchTaskItems (BatchTaskId, PathRouteId, PathRouteName, SequenceNumber, Status, StartTime, EndTime, ErrorMessage, ConfigOverride, VehicleObjectId, VehicleObjectName, DetectionItems, ClashDetectiveTestName)
VALUES (@BatchTaskId, @PathRouteId, @PathRouteName, @SequenceNumber, @Status, @StartTime, @EndTime, @ErrorMessage, @ConfigOverride, @VehicleObjectId, @VehicleObjectName, @DetectionItems, @ClashDetectiveTestName);
SELECT last_insert_rowid();";
cmd.Parameters.AddWithValue("@BatchTaskId", item.BatchTaskId);
cmd.Parameters.AddWithValue("@PathRouteId", item.PathRouteId);
cmd.Parameters.AddWithValue("@PathRouteName", item.PathRouteName ?? "");
cmd.Parameters.AddWithValue("@SequenceNumber", item.SequenceNumber);
cmd.Parameters.AddWithValue("@Status", item.Status.ToString());
cmd.Parameters.AddWithValue("@StartTime", item.StartTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@EndTime", item.EndTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@ErrorMessage", item.ErrorMessage ?? "");
cmd.Parameters.AddWithValue("@ConfigOverride", item.ConfigOverride?.ToJson() ?? "");
cmd.Parameters.AddWithValue("@VehicleObjectId", item.VehicleObjectId ?? "");
cmd.Parameters.AddWithValue("@VehicleObjectName", item.VehicleObjectName ?? "");
cmd.Parameters.AddWithValue("@DetectionItems", item.DetectionItems != null ? string.Join(",", item.DetectionItems) : "");
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
return Convert.ToInt32(cmd.ExecuteScalar());
}
});
}
/// <summary>
/// 获取批处理任务
/// </summary>
public async Task<BatchCollisionTask> GetBatchTaskAsync(int taskId)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
SELECT Id, Name, Description, CreatedTime, Status, StartTime, EndTime, TotalItems, CompletedItems, FailedItems, LastModified
FROM BatchTasks
WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", taskId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return new BatchCollisionTask
{
Id = Convert.ToInt32(reader["Id"]),
Name = reader["Name"].ToString(),
Description = reader["Description"].ToString(),
CreatedTime = DateTime.Parse(reader["CreatedTime"].ToString()),
Status = (BatchTaskStatus)Enum.Parse(typeof(BatchTaskStatus), reader["Status"].ToString()),
StartTime = reader["StartTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["StartTime"].ToString()) : null,
EndTime = reader["EndTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["EndTime"].ToString()) : null,
TotalItems = Convert.ToInt32(reader["TotalItems"]),
CompletedItems = Convert.ToInt32(reader["CompletedItems"]),
FailedItems = Convert.ToInt32(reader["FailedItems"]),
LastModified = DateTime.Parse(reader["LastModified"].ToString())
};
}
return null;
}
}
});
}
/// <summary>
/// 获取所有批处理任务
/// </summary>
public async Task<List<BatchCollisionTask>> GetBatchTasksAsync(BatchTaskStatus? statusFilter = null, int limit = 50, int offset = 0)
{
return await Task.Run(() =>
{
var tasks = new List<BatchCollisionTask>();
using (var cmd = new SQLiteCommand(_connection))
{
var sql = @"
SELECT Id, Name, Description, CreatedTime, Status, StartTime, EndTime, TotalItems, CompletedItems, FailedItems, LastModified
FROM BatchTasks";
var conditions = new List<string>();
if (statusFilter.HasValue)
{
conditions.Add("Status = @Status");
cmd.Parameters.AddWithValue("@Status", statusFilter.Value.ToString());
}
if (conditions.Count > 0)
{
sql += " WHERE " + string.Join(" AND ", conditions);
}
sql += " ORDER BY CreatedTime DESC";
if (limit > 0)
{
sql += " LIMIT @Limit";
cmd.Parameters.AddWithValue("@Limit", limit);
}
if (offset > 0)
{
sql += " OFFSET @Offset";
cmd.Parameters.AddWithValue("@Offset", offset);
}
cmd.CommandText = sql;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
tasks.Add(new BatchCollisionTask
{
Id = Convert.ToInt32(reader["Id"]),
Name = reader["Name"].ToString(),
Description = reader["Description"].ToString(),
CreatedTime = DateTime.Parse(reader["CreatedTime"].ToString()),
Status = (BatchTaskStatus)Enum.Parse(typeof(BatchTaskStatus), reader["Status"].ToString()),
StartTime = reader["StartTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["StartTime"].ToString()) : null,
EndTime = reader["EndTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["EndTime"].ToString()) : null,
TotalItems = Convert.ToInt32(reader["TotalItems"]),
CompletedItems = Convert.ToInt32(reader["CompletedItems"]),
FailedItems = Convert.ToInt32(reader["FailedItems"]),
LastModified = DateTime.Parse(reader["LastModified"].ToString())
});
}
}
}
return tasks;
});
}
/// <summary>
/// 删除批处理任务
/// </summary>
public async Task DeleteBatchTaskAsync(int taskId)
{
await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = "DELETE FROM BatchTasks WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", taskId);
cmd.ExecuteNonQuery();
}
});
}
/// <summary>
/// 更新批处理任务状态
/// </summary>
public async Task UpdateBatchTaskStatusAsync(int taskId, BatchTaskStatus status, DateTime? startTime = null, DateTime? endTime = null, int? completedItems = null, int? failedItems = null)
{
await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
var sql = "UPDATE BatchTasks SET Status = @Status, LastModified = @LastModified";
if (startTime.HasValue) sql += ", StartTime = @StartTime";
if (endTime.HasValue) sql += ", EndTime = @EndTime";
if (completedItems.HasValue) sql += ", CompletedItems = @CompletedItems";
if (failedItems.HasValue) sql += ", FailedItems = @FailedItems";
sql += " WHERE Id = @Id";
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@Status", status.ToString());
cmd.Parameters.AddWithValue("@LastModified", DateTime.Now.ToString("o"));
cmd.Parameters.AddWithValue("@Id", taskId);
if (startTime.HasValue) cmd.Parameters.AddWithValue("@StartTime", startTime.Value.ToString("o"));
if (endTime.HasValue) cmd.Parameters.AddWithValue("@EndTime", endTime.Value.ToString("o"));
if (completedItems.HasValue) cmd.Parameters.AddWithValue("@CompletedItems", completedItems.Value);
if (failedItems.HasValue) cmd.Parameters.AddWithValue("@FailedItems", failedItems.Value);
cmd.ExecuteNonQuery();
}
});
}
/// <summary>
/// 更新批处理任务项状态
/// </summary>
public async Task UpdateBatchTaskItemStatusAsync(int itemId, BatchTaskItemStatus status, DateTime? startTime = null, DateTime? endTime = null, string errorMessage = null, string clashDetectiveTestName = null)
{
await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
var sql = "UPDATE BatchTaskItems SET Status = @Status";
if (startTime.HasValue) sql += ", StartTime = @StartTime";
if (endTime.HasValue) sql += ", EndTime = @EndTime";
if (errorMessage != null) sql += ", ErrorMessage = @ErrorMessage";
if (clashDetectiveTestName != null) sql += ", ClashDetectiveTestName = @ClashDetectiveTestName";
sql += " WHERE Id = @Id";
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@Status", status.ToString());
cmd.Parameters.AddWithValue("@Id", itemId);
if (startTime.HasValue) cmd.Parameters.AddWithValue("@StartTime", startTime.Value.ToString("o"));
if (endTime.HasValue) cmd.Parameters.AddWithValue("@EndTime", endTime.Value.ToString("o"));
if (errorMessage != null) cmd.Parameters.AddWithValue("@ErrorMessage", errorMessage);
if (clashDetectiveTestName != null) cmd.Parameters.AddWithValue("@ClashDetectiveTestName", clashDetectiveTestName);
cmd.ExecuteNonQuery();
}
});
}
/// <summary>
/// 获取批处理任务的所有项
/// </summary>
public async Task<List<BatchTaskItem>> GetBatchTaskItemsAsync(int taskId)
{
return await Task.Run(() =>
{
var items = new List<BatchTaskItem>();
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
SELECT Id, BatchTaskId, PathRouteId, PathRouteName, SequenceNumber, Status, StartTime, EndTime, ErrorMessage, ConfigOverride, VehicleObjectId, VehicleObjectName, DetectionItems, ClashDetectiveTestName
FROM BatchTaskItems
WHERE BatchTaskId = @TaskId
ORDER BY SequenceNumber";
cmd.Parameters.AddWithValue("@TaskId", taskId);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
items.Add(new BatchTaskItem
{
Id = Convert.ToInt32(reader["Id"]),
BatchTaskId = Convert.ToInt32(reader["BatchTaskId"]),
PathRouteId = reader["PathRouteId"].ToString(),
PathRouteName = reader["PathRouteName"].ToString(),
SequenceNumber = Convert.ToInt32(reader["SequenceNumber"]),
Status = (BatchTaskItemStatus)Enum.Parse(typeof(BatchTaskItemStatus), reader["Status"].ToString()),
StartTime = reader["StartTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["StartTime"].ToString()) : null,
EndTime = reader["EndTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["EndTime"].ToString()) : null,
ErrorMessage = reader["ErrorMessage"].ToString(),
ConfigOverride = CollisionDetectionConfig.FromJson(reader["ConfigOverride"].ToString()),
VehicleObjectId = reader["VehicleObjectId"].ToString(),
VehicleObjectName = reader["VehicleObjectName"].ToString(),
DetectionItems = reader["DetectionItems"].ToString() != "" ? reader["DetectionItems"].ToString().Split(',').ToList() : new List<string>(),
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString()
});
}
}
}
return items;
});
}
/// <summary>
/// 根据测试名称获取碰撞检测结果
/// </summary>
public async Task<ClashDetectiveResultRecord> GetClashDetectiveResultByTestNameAsync(string testName)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount, FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualVehicle, VehicleModelIndex, VehiclePathId, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, CreatedAt
FROM ClashDetectiveResults
WHERE TestName = @TestName";
cmd.Parameters.AddWithValue("@TestName", testName);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return new ClashDetectiveResultRecord
{
Id = Convert.ToInt32(reader["Id"]),
TestName = reader["TestName"].ToString(),
PathName = reader["PathName"].ToString(),
RouteId = reader["RouteId"].ToString(),
TestTime = DateTime.Parse(reader["TestTime"].ToString()),
CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
AnimationCollisionCount = Convert.ToInt32(reader["AnimationCollisionCount"]),
FrameRate = Convert.ToInt32(reader["FrameRate"]),
Duration = Convert.ToDouble(reader["Duration"]),
DetectionGap = Convert.ToDouble(reader["DetectionGap"]),
AnimatedObjectName = reader["AnimatedObjectName"].ToString(),
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
VehicleModelIndex = !Convert.IsDBNull(reader["VehicleModelIndex"]) ? (int?)Convert.ToInt32(reader["VehicleModelIndex"]) : null,
VehiclePathId = reader["VehiclePathId"].ToString(),
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
VirtualVehicleHeight = Convert.ToDouble(reader["VirtualVehicleHeight"]),
CreatedAt = DateTime.Parse(reader["CreatedAt"].ToString())
};
}
return null;
}
}
});
}
/// <summary>
/// 根据路径ID获取路径
/// </summary>
public async Task<PathRoute> GetPathRouteAsync(string routeId)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
SELECT Id, Name, CreatedTime, LastModified, TotalLength
FROM PathRoutes
WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", routeId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
var route = new PathRoute(reader["Name"].ToString())
{
Id = reader["Id"].ToString(),
CreatedTime = DateTime.Parse(reader["CreatedTime"].ToString()),
LastModified = DateTime.Parse(reader["LastModified"].ToString()),
TotalLength = Convert.ToDouble(reader["TotalLength"])
};
// 加载路径点和路径边
LoadPathPoints(route);
LoadPathEdges(route);
return route;
}
return null;
}
}
});
}
#endregion
#region
/// <summary>
/// 创建批处理队列项
/// </summary>
public async Task<int> CreateBatchQueueItemAsync(BatchQueueItem item)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
INSERT INTO BatchQueueItems (
PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
)
VALUES (
@PathRouteId, @PathRouteName, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage,
@FrameRate, @DurationSeconds, @DetectionToleranceMeters,
@IsVirtualVehicle, @VirtualVehicleLength, @VirtualVehicleWidth, @VirtualVehicleHeight,
@VehicleObjectId, @VehicleObjectName, @DetectionItems, @DetectAllObjects,
@ClashDetectiveTestName, @CollisionCount
);
SELECT last_insert_rowid();";
cmd.Parameters.AddWithValue("@PathRouteId", item.PathRouteId);
cmd.Parameters.AddWithValue("@PathRouteName", item.PathRouteName ?? "");
cmd.Parameters.AddWithValue("@Status", item.Status.ToString());
cmd.Parameters.AddWithValue("@CreatedTime", item.CreatedTime.ToString("o"));
cmd.Parameters.AddWithValue("@StartTime", item.StartTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@EndTime", item.EndTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@ErrorMessage", item.ErrorMessage ?? "");
cmd.Parameters.AddWithValue("@FrameRate", item.FrameRate);
cmd.Parameters.AddWithValue("@DurationSeconds", item.DurationSeconds);
cmd.Parameters.AddWithValue("@DetectionToleranceMeters", item.DetectionToleranceMeters);
cmd.Parameters.AddWithValue("@IsVirtualVehicle", item.IsVirtualVehicle ? 1 : 0);
cmd.Parameters.AddWithValue("@VirtualVehicleLength", item.VirtualVehicleLength);
cmd.Parameters.AddWithValue("@VirtualVehicleWidth", item.VirtualVehicleWidth);
cmd.Parameters.AddWithValue("@VirtualVehicleHeight", item.VirtualVehicleHeight);
cmd.Parameters.AddWithValue("@VehicleObjectId", item.VehicleObjectId ?? "");
cmd.Parameters.AddWithValue("@VehicleObjectName", item.VehicleObjectName ?? "");
cmd.Parameters.AddWithValue("@DetectionItems", item.DetectionItems != null ? string.Join(",", item.DetectionItems) : "");
cmd.Parameters.AddWithValue("@DetectAllObjects", item.DetectAllObjects ? 1 : 0);
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
cmd.Parameters.AddWithValue("@CollisionCount", item.CollisionCount ?? (object)DBNull.Value);
return Convert.ToInt32(cmd.ExecuteScalar());
}
});
}
/// <summary>
/// 获取批处理队列项
/// </summary>
public async Task<BatchQueueItem> GetBatchQueueItemAsync(int itemId)
{
return await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
FROM BatchQueueItems
WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", itemId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return new BatchQueueItem
{
Id = Convert.ToInt32(reader["Id"]),
PathRouteId = reader["PathRouteId"].ToString(),
PathRouteName = reader["PathRouteName"].ToString(),
Status = (BatchQueueStatus)Enum.Parse(typeof(BatchQueueStatus), reader["Status"].ToString()),
CreatedTime = DateTime.Parse(reader["CreatedTime"].ToString()),
StartTime = reader["StartTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["StartTime"].ToString()) : null,
EndTime = reader["EndTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["EndTime"].ToString()) : null,
ErrorMessage = reader["ErrorMessage"].ToString(),
FrameRate = Convert.ToInt32(reader["FrameRate"]),
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
VirtualVehicleHeight = Convert.ToDouble(reader["VirtualVehicleHeight"]),
VehicleObjectId = reader["VehicleObjectId"].ToString(),
VehicleObjectName = reader["VehicleObjectName"].ToString(),
DetectionItems = reader["DetectionItems"].ToString() != "" ? reader["DetectionItems"].ToString().Split(',').ToList() : new List<string>(),
DetectAllObjects = Convert.ToBoolean(reader["DetectAllObjects"]),
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString(),
CollisionCount = !Convert.IsDBNull(reader["CollisionCount"]) ? (int?)Convert.ToInt32(reader["CollisionCount"]) : null
};
}
return null;
}
}
});
}
/// <summary>
/// 获取批处理队列项列表
/// </summary>
public async Task<List<BatchQueueItem>> GetBatchQueueItemsAsync(BatchQueueStatus statusFilter = BatchQueueStatus.All, int limit = 50, int offset = 0)
{
return await Task.Run(() =>
{
var items = new List<BatchQueueItem>();
using (var cmd = new SQLiteCommand(_connection))
{
var sql = @"
SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
FROM BatchQueueItems";
var conditions = new List<string>();
// 只有当 statusFilter 不是 All 时才添加筛选条件
if (statusFilter != BatchQueueStatus.All)
{
conditions.Add("Status = @Status");
cmd.Parameters.AddWithValue("@Status", statusFilter.ToString());
}
if (conditions.Count > 0)
{
sql += " WHERE " + string.Join(" AND ", conditions);
}
sql += " ORDER BY CreatedTime DESC";
if (limit > 0)
{
sql += " LIMIT @Limit";
cmd.Parameters.AddWithValue("@Limit", limit);
}
if (offset > 0)
{
sql += " OFFSET @Offset";
cmd.Parameters.AddWithValue("@Offset", offset);
}
cmd.CommandText = sql;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
items.Add(new BatchQueueItem
{
Id = Convert.ToInt32(reader["Id"]),
PathRouteId = reader["PathRouteId"].ToString(),
PathRouteName = reader["PathRouteName"].ToString(),
Status = (BatchQueueStatus)Enum.Parse(typeof(BatchQueueStatus), reader["Status"].ToString()),
CreatedTime = DateTime.Parse(reader["CreatedTime"].ToString()),
StartTime = reader["StartTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["StartTime"].ToString()) : null,
EndTime = reader["EndTime"].ToString() != "" ? (DateTime?)DateTime.Parse(reader["EndTime"].ToString()) : null,
ErrorMessage = reader["ErrorMessage"].ToString(),
FrameRate = Convert.ToInt32(reader["FrameRate"]),
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
VirtualVehicleHeight = Convert.ToDouble(reader["VirtualVehicleHeight"]),
VehicleObjectId = reader["VehicleObjectId"].ToString(),
VehicleObjectName = reader["VehicleObjectName"].ToString(),
DetectionItems = reader["DetectionItems"].ToString() != "" ? reader["DetectionItems"].ToString().Split(',').ToList() : new List<string>(),
DetectAllObjects = Convert.ToBoolean(reader["DetectAllObjects"]),
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString(),
CollisionCount = !Convert.IsDBNull(reader["CollisionCount"]) ? (int?)Convert.ToInt32(reader["CollisionCount"]) : null
});
}
}
}
return items;
});
}
/// <summary>
/// 更新批处理队列项
/// </summary>
public async Task UpdateBatchQueueItemAsync(BatchQueueItem item)
{
await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = @"
UPDATE BatchQueueItems
SET Status = @Status, StartTime = @StartTime, EndTime = @EndTime, ErrorMessage = @ErrorMessage,
ClashDetectiveTestName = @ClashDetectiveTestName, CollisionCount = @CollisionCount
WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Status", item.Status.ToString());
cmd.Parameters.AddWithValue("@StartTime", item.StartTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@EndTime", item.EndTime?.ToString("o") ?? "");
cmd.Parameters.AddWithValue("@ErrorMessage", item.ErrorMessage ?? "");
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
cmd.Parameters.AddWithValue("@CollisionCount", item.CollisionCount ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@Id", item.Id);
cmd.ExecuteNonQuery();
}
});
}
/// <summary>
/// 删除批处理队列项
/// </summary>
public async Task DeleteBatchQueueItemAsync(int itemId)
{
await Task.Run(() =>
{
using (var cmd = new SQLiteCommand(_connection))
{
cmd.CommandText = "DELETE FROM BatchQueueItems WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", itemId);
cmd.ExecuteNonQuery();
}
});
}
#endregion
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_connection?.Close();
_connection?.Dispose();
}
}
}
/// <summary>
/// ClashDetective碰撞检测结果记录
/// </summary>
public class ClashDetectiveResultRecord
{
public int Id { get; set; }
public string TestName { get; set; }
public string PathName { get; set; }
public string RouteId { get; set; }
public DateTime TestTime { get; set; }
public int CollisionCount { get; set; }
public int AnimationCollisionCount { get; set; }
public int FrameRate { get; set; }
public double Duration { get; set; }
public double DetectionGap { get; set; }
public string AnimatedObjectName { get; set; }
public bool IsVirtualVehicle { get; set; }
public int? VehicleModelIndex { get; set; }
public string VehiclePathId { get; set; }
public double VirtualVehicleLength { get; set; }
public double VirtualVehicleWidth { get; set; }
public double VirtualVehicleHeight { get; set; }
public DateTime CreatedAt { get; set; }
}
/// <summary>
/// ClashDetective碰撞对象数据模型
/// </summary>
public class ClashDetectiveCollisionObjectRecord
{
public int Id { get; set; }
public int ResultId { get; set; }
public int? ModelIndex { get; set; }
public string PathId { get; set; }
public string DisplayName { get; set; }
public string ObjectName { get; set; }
}
/// <summary>
/// 路径分析结果数据模型
/// </summary>
public class PathAnalysisResult
{
public string RouteId { get; set; }
public int CollisionCount { get; set; }
public double SafetyScore { get; set; }
public double EfficiencyScore { get; set; }
public double OverallScore { get; set; }
public DateTime AnalysisTime { get; set; }
public string Strategy { get; set; }
}
}