using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Core.Spatial;
using NavisworksTransport.Utils;
using NavisApplication = Autodesk.Navisworks.Api.Application;

namespace NavisworksTransport.Core.Animation
{
    /// <summary>
    /// 定义动画播放的状态
    /// </summary>
    public enum AnimationState
    {
        Idle,      // 空闲，未生成动画
        Ready,     // 已就绪，动画已生成但未播放
        Playing,   // 播放中
        Paused,    // 暂停
        Stopped,   // 已停止
        Finished   // 已完成
    }

    /// <summary>
    /// 碰撞对象对，用于去重
    /// </summary>
    public class CollisionPair : IEquatable<CollisionPair>
    {
        public ModelItem AnimatedObject { get; set; }
        public ModelItem CollisionObject { get; set; }

        public bool Equals(CollisionPair other)
        {
            if (other == null) return false;
            return ReferenceEquals(AnimatedObject, other.AnimatedObject) &&
                   ReferenceEquals(CollisionObject, other.CollisionObject);
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as CollisionPair);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int hash = 17;
                hash = hash * 31 + (AnimatedObject?.GetHashCode() ?? 0);
                hash = hash * 31 + (CollisionObject?.GetHashCode() ?? 0);
                return hash;
            }
        }
    }


    /// <summary>
    /// 路径动画管理器 - 基于TimeLiner和动态变换实现沿路径的动画效果
    /// 注意：由于Navisworks API限制，无法直接使用Animator API，因此使用OverridePermanentTransform实现动画
    /// 已集成 TimeLiner 功能，支持在 TimeLiner 中显示和管理动画任务
    /// </summary>
    /// <summary>
    /// 动画帧数据（包含位置、朝向和碰撞信息）
    /// </summary>
    public class AnimationFrame
    {
        public int Index { get; set; }                    // 帧索引
        public double Progress { get; set; }              // 进度(0-1)
        public Point3D Position { get; set; }             // 该帧的位置
        public double YawRadians { get; set; }            // 绕Z轴的偏航角（弧度）
        public List<CollisionResult> Collisions { get; set; } // 该帧的碰撞结果
        public bool HasCollision => Collisions?.Count > 0;

        public AnimationFrame()
        {
            Collisions = new List<CollisionResult>();
            YawRadians = 0.0;
        }
    }

    public class PathAnimationManager
    {
        private static PathAnimationManager _instance;
        private static readonly HashSet<string> _completedCollisionTests = new HashSet<string>(); // 记录已完成碰撞检测的动画配置
        private static readonly Dictionary<string, List<AnimationFrame>> _animationFrameCache = new Dictionary<string, List<AnimationFrame>>(); // 动画帧缓存
        private static readonly Dictionary<string, List<CollisionResult>> _collisionResultCache = new Dictionary<string, List<CollisionResult>>(); // 碰撞结果缓存
        private ModelItem _animatedObject;
        private List<Point3D> _pathPoints;
        private List<ModelItem> _manualCollisionTargets = new List<ModelItem>();
        private bool _manualCollisionOverrideEnabled = false;

        // === 碰撞排除列表缓存管理（从LogisticsAnimationManager迁移）===
        private ModelItem _currentCachedAnimationObject;
        private List<ModelItem> _cachedExclusionList;
        private DateTime _cacheCreatedTime;
        private readonly TimeSpan _cacheValidDuration = TimeSpan.FromMinutes(30); // 缓存有效期30分钟

        // === 预计算动画系统 ===
        private List<AnimationFrame> _animationFrames;        // 所有帧数据
        private int _currentFrameIndex = 0;                   // 当前帧索引

        private List<CollisionResult> _allCollisionResults; // 所有碰撞结果（不去重）
        private bool _lastHighlightState = false;             // 上一帧的高亮状态
        private HashSet<ModelItem> _lastCollisionObjects = new HashSet<ModelItem>(); // 上一帧碰撞对象的集合

        // === 路径相关 ===
        private PathRoute _route = null;                      // 路径引用

        // === 碰撞测试优化 ===
        private string _currentAnimationHash = "";            // 当前动画配置的哈希值

        // === 动画播放机制 ===
        private double _frameInterval; // 帧间隔（毫秒）
        private DateTime _lastFrameTime = DateTime.MinValue; // 上一帧时间
        private DispatcherTimer _animationTimer;  // 备用DispatcherTimer定时器

        // === 动画参数 ===
        private double _animationDuration = 10.0; // 动画总时长（秒）
        private DateTime _animationStartTime;
        private int _animationFrameRate = 30; // 动画帧率（默认30FPS）
        private int _animationFrameCount = 0; // 动画帧计数
        private double _collisionDetectionAccuracy = 0.1; // 检测精度（内部存储：模型单位/帧）
        private double _movementSpeed = 1.0; // 运动速度（仅用于显示，单位：米/秒）
        private double _detectionGap = 0.05; // 检测间隙（内部存储：模型单位）
        private string _pathName = "未知路径"; // 路径名称
        private string _currentRouteId = null; // 当前路由ID
        private string _animatedObjectName = null; // 动画对象名称

        // === 双向播放和步进控制 ===
        private int _playbackDirection = 1; // 播放方向：1=正向，-1=反向
        private double _playbackSpeed = 1.0; // 播放速度倍率

        // === 性能监控 ===
        private int _fpsFrameCount = 0;
        private DateTime _fpsCounterStart = DateTime.Now;
        private double _actualFPS = 0;

        private Transform3D _originalTransform;
        private Point3D _originalCenter; // 存储部件的原始中心位置
        private Point3D _currentPosition; // 存储部件的当前位置
        private AnimationState _currentState = AnimationState.Idle;
        private double _pausedProgress = 0.0; // 暂停时的进度（0-1之间）
        private double _currentYaw = 0.0; // 当前偏航角（弧度）

        // TimeLiner 集成
        private TimeLinerIntegrationManager _timeLinerManager;
        private string _currentTaskId;

        // === 调试辅助 ===
        private static HashSet<int> _arcInfoPrinted = new HashSet<int>(); // 记录已打印信息的圆弧段索引

        /// <summary>
        /// 当前正在进行动画的对象
        /// </summary>
        public ModelItem AnimatedObject => _animatedObject;

        // --- 新增事件 ---
        /// <summary>
        /// 当动画状态发生改变时触发
        /// </summary>
        public event EventHandler<AnimationState> StateChanged;

        /// <summary>
        /// 当动画进度更新时触发 (0.0-100.0)
        /// </summary>
        public event EventHandler<double> ProgressChanged;

        /// <summary>
        /// 当检测到碰撞时触发
        /// </summary>
        public event EventHandler<CollisionDetectedEventArgs> CollisionDetected;

        public PathAnimationManager()
        {
            _pathPoints = new List<Point3D>();
            _animationFrames = new List<AnimationFrame>();
            _allCollisionResults = new List<CollisionResult>();

            // 初始化动画模式
            _frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔
            _lastFrameTime = DateTime.MinValue;
            _fpsCounterStart = DateTime.Now;

            // 初始化备用DispatcherTimer
            _animationTimer = new DispatcherTimer(DispatcherPriority.Render)
            {
                Interval = TimeSpan.FromMilliseconds(_frameInterval)
            };
            _animationTimer.Tick += OnTimerTick;

            // 初始化 TimeLiner 集成
            try
            {
                _timeLinerManager = new TimeLinerIntegrationManager();
                LogManager.Info($"PathAnimationManager 初始化完成 - DispatcherTimer模式, 目标FPS: {_animationFrameRate}");
            }
            catch (Exception ex)
            {
                LogManager.Warning($"TimeLiner 集成初始化失败，将使用基础动画功能: {ex.Message}");
                _timeLinerManager = null;
            }

            // 订阅文档状态事件
            DocumentStateManager.Instance.DocumentInvalidated += OnDocumentInvalidated;
        }

        /// <summary>
        /// 获取单例实例
        /// </summary>
        public static PathAnimationManager GetInstance()
        {
            if (_instance == null)
            {
                _instance = new PathAnimationManager();
            }
            return _instance;
        }

        /// <summary>
        /// 清理当前所有的动画生成结果（帧列表、碰撞结果、状态）
        /// </summary>
        public void ClearAnimationResults()
        {
            _animationFrames = null;
            _allCollisionResults = null;
            _arcInfoPrinted.Clear(); // 清除圆弧段信息打印记录
            SetState(AnimationState.Idle);
            LogManager.Info("[PathAnimationManager] 动画数据和状态已重置为 Idle");
        }

        /// <summary>
        /// 仅仅将物理模型同步到路径起点（不清理数据，不重置状态）
        /// </summary>
        public void SyncToPathStart(ModelItem item, List<Point3D> points)
        {
            try
            {
                if (item == null || points == null || points.Count == 0) return;

                // 更新引用，确保后续 MoveVehicleToPathStart 使用正确物体
                _animatedObject = item;
                _pathPoints = new List<Point3D>(points);

                // 记录原始位置（用于归位）
                _originalTransform = item.Transform;
                _currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
                _originalCenter = item.BoundingBox().Center;
                _currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, item.BoundingBox().Min.Z);

                if (points.Count >= 2)
                {
                    double yaw = Math.Atan2(points[1].Y - points[0].Y, points[1].X - points[0].X);
                    UpdateObjectPosition(points[0], yaw);
                }
                else
                {
                    UpdateObjectPosition(points[0]);
                }

                LogManager.Debug($"[Sync] 物体 {item.DisplayName} 已移动到起点");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[Sync] 同步到起点失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 将动画对象彻底恢复到 CAD 原始位置（清除所有覆盖变换）
        /// 常用于模式切换或彻底清除动画干扰
        /// </summary>
        public void RestoreObjectToCADPosition()
        {
            try
            {
                var doc = NavisApplication.ActiveDocument;
                if (doc == null || _animatedObject == null) return;

                var modelItems = new ModelItemCollection { _animatedObject };

                // 1. 彻底清除 Navisworks 中的所有覆盖变换，强制恢复到设计文件定义的原始状态
                doc.Models.ResetPermanentTransform(modelItems);

                // 2. 重置内部跟踪变量（同步到 CAD 原始状态）
                // 注意：ResetPermanentTransform 后物体的 Transform 属性会自动变回 CAD 原始值
                _currentYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform);

                var originalBoundingBox = _animatedObject.BoundingBox();
                _currentPosition = new Point3D(
                    originalBoundingBox.Center.X,
                    originalBoundingBox.Center.Y,
                    originalBoundingBox.Min.Z
                );

                LogManager.Info($"[归位] 物体 {_animatedObject.DisplayName} 已彻底恢复到 CAD 原始位置, yaw={_currentYaw:F3}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[归位] 恢复物体到 CAD 位置失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 生成动画帧
        /// </summary>
        /// <param name="animatedObject">要动画化的模型对象</param>
        /// <param name="pathPoints">路径点列表</param>
        /// <param name="durationSeconds">动画持续时间（秒）</param>
        public void SetRoute(PathRoute route)
        {
            _route = route;
        }

        public void SetupAnimation(
            ModelItem animatedObject,
            double durationSeconds,
            PathRoute route)
        {
            try
            {
                if (route == null)
                    throw new ArgumentNullException(nameof(route), "必须提供路径");

                _animatedObject = animatedObject;
                _animationDuration = durationSeconds;
                _route = route;

                LogManager.Info($"使用路径,边数:{route.Edges.Count},总长度:{route.TotalLength:F2}米,动画时长:{durationSeconds:F1}秒");

                // 计算动画配置哈希（基于路径边，可以区分不同的曲线化路径）
                _currentAnimationHash = ComputeAnimationConfigHashFromRoute(animatedObject, route);
                LogManager.Info($"动画配置哈希: {_currentAnimationHash}");

                // 检查动画帧缓存
                if (_animationFrameCache.TryGetValue(_currentAnimationHash, out var cachedFrames))
                {
                    _animationFrames = cachedFrames;
                    // 同时加载缓存的碰撞结果
                    if (_collisionResultCache.TryGetValue(_currentAnimationHash, out var cachedCollisions))
                    {
                        _allCollisionResults = cachedCollisions;
                        LogManager.Info($"使用缓存的动画帧和碰撞结果，帧数: {_animationFrames.Count}, 碰撞数: {_allCollisionResults.Count}");
                    }
                    else
                    {
                        _allCollisionResults = new List<CollisionResult>();
                        LogManager.Info($"使用缓存的动画帧，但碰撞结果缓存缺失，帧数: {_animationFrames.Count}");
                    }
                }
                else
                {
                    // 缓存未命中，重新计算动画帧
                    LogManager.Info("缓存未命中，重新计算动画帧和碰撞结果");
                    PrecomputeAnimationFrames();

                    // 缓存动画帧和碰撞结果
                    if (_animationFrames != null && _animationFrames.Count > 0)
                    {
                        _animationFrameCache[_currentAnimationHash] = _animationFrames;
                        if (_allCollisionResults != null)
                        {
                            _collisionResultCache[_currentAnimationHash] = _allCollisionResults;
                        }
                        LogManager.Info($"动画帧和碰撞结果已缓存，帧数: {_animationFrames.Count}, 碰撞数: {_allCollisionResults?.Count ?? 0}");
                    }
                }

                // 验证预计算结果
                if (_animationFrames == null || _animationFrames.Count == 0)
                {
                    throw new InvalidOperationException("动画帧预计算失败，无法创建动画");
                }

                LogManager.Info($"动画设置完成：对象={_animatedObject.DisplayName}, 时长={_animationDuration}秒");
            }
            catch (Exception ex)
            {
                LogManager.Error($"设置动画失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 将车辆移动到路径起点
        /// </summary>
        private void MoveVehicleToPathStart()
        {
            try
            {
                if (_pathPoints.Count == 0 || _animationFrames == null || _animationFrames.Count == 0) return;

                var firstFrame = _animationFrames[0];

                // 使用 UpdateObjectPosition 统一处理移动和旋转
                // 这将物体从当前位置（底面中心）移动到第一帧的位置，并旋转到第一帧的朝向
                UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians);

                LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2},{firstFrame.Position.Z:F2}), yaw={firstFrame.YawRadians:F3}rad");
            }
            catch (Exception ex)
            {
                LogManager.Error($"初始化物体到路径起点失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 预计算所有动画帧和碰撞信息
        /// </summary>
        private void PrecomputeAnimationFrames()
        {
            try
            {
                LogManager.Info("=== 使用路径预计算动画帧 ===");

                int totalFrames = (int)(_animationDuration * _animationFrameRate);

                // 1. 构建完整的采样点序列(按边顺序拼接)
                var allSampledPoints = new List<Point3D>();
                var edgeLengths = new List<double>();
                var edgeStartIndices = new List<int>();

                foreach (var edge in _route.Edges)
                {
                    if (edge.SampledPoints == null || edge.SampledPoints.Count == 0)
                    {
                        var samplingStep = ConfigManager.Instance.Current.PathEditing.ArcSamplingStep;
                        edge.SampledPoints = PathCurveEngine.GenerateSampledPoints(edge, samplingStep);
                    }

                    edgeStartIndices.Add(allSampledPoints.Count);
                    allSampledPoints.AddRange(edge.SampledPoints);
                    edgeLengths.Add(edge.PhysicalLength);
                }

                double totalLength = _route.TotalLength;
                LogManager.Info($"路径总长度: {totalLength:F2}米, 采样点数: {allSampledPoints.Count}");

                // 2. 按帧数采样生成动画帧
                _animationFrames = new List<AnimationFrame>();
                _allCollisionResults = new List<CollisionResult>();
                _currentFrameIndex = 0;

                // 获取动画对象的包围盒信息
                var originalBoundingBox = _animatedObject.BoundingBox();
                var boundingBoxSize = new Vector3D(
                    originalBoundingBox.Max.X - originalBoundingBox.Min.X,
                    originalBoundingBox.Max.Y - originalBoundingBox.Min.Y,
                    originalBoundingBox.Max.Z - originalBoundingBox.Min.Z
                );

                // 空间索引设置
                SpatialIndexManager spatialIndexManager = null;
                double searchRadiusInModelUnits = 0;
                var manualTargetsSnapshot = new List<ModelItem>();
                bool manualOverrideActive = _manualCollisionOverrideEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0;

                if (manualOverrideActive)
                {
                    manualTargetsSnapshot = _manualCollisionTargets
                        .Where(item => item != null && ModelItemAnalysisHelper.IsModelItemValid(item) && !ReferenceEquals(item, _animatedObject))
                        .Distinct()
                        .ToList();

                    if (manualTargetsSnapshot.Count == 0)
                    {
                        manualOverrideActive = false;
                        LogManager.Warning("[手工碰撞] 手工碰撞对象列表为空或无效，自动回退到空间索引模式");
                    }
                    else
                    {
                        LogManager.Info($"[手工碰撞] 启用手工碰撞对象模式，数量: {manualTargetsSnapshot.Count}，跳过空间索引构建");
                    }
                }

                if (!manualOverrideActive)
                {
                    LogManager.Info("=== 构建全局空间索引 ===");
                    spatialIndexManager = SpatialIndexManager.Instance;

                    double vehicleWidthMeters = ConfigManager.Instance.Current.PathEditing.VehicleWidthMeters;
                    double cellSizeInModelUnits = UnitsConverter.ConvertFromMeters(vehicleWidthMeters);

                    LogManager.Info($"[空间索引] 车辆宽度: {vehicleWidthMeters:F2}米 → 格子大小: {cellSizeInModelUnits:F2}模型单位");

                    if (!spatialIndexManager.IsInitialized)
                    {
                        LogManager.Info("[空间索引] 空间索引未初始化，开始构建...");
                        spatialIndexManager.BuildGlobalIndex(cellSizeInModelUnits);
                    }
                    else
                    {
                        LogManager.Info("[空间索引] 使用已缓存的空间索引");
                    }

                    LogManager.Info(spatialIndexManager.GetStatistics());

                    // 🔥 修改：使用车辆的最大水平尺寸而不是对角线
                    // 原因：车辆在通道上水平移动，主要检测侧面碰撞
                    double maxHorizontalDimension = Math.Max(boundingBoxSize.X, boundingBoxSize.Y);

                    searchRadiusInModelUnits = maxHorizontalDimension + _detectionGap;
                    LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2})");
                }

                // 3. 生成每一帧
                double distancePerFrame = totalLength / totalFrames;
                LogManager.Info($"总帧数: {totalFrames}, 总长度: {totalLength:F2}米, 每帧移动距离: {distancePerFrame:F4}米");

                for (int i = 0; i < totalFrames; i++)
                {
                    double targetDistance = i * distancePerFrame;  // 按距离采样，不是按进度

                    // 找到当前在哪条边上
                    int edgeIndex = FindEdgeForDistance(targetDistance, edgeLengths);
                    if (edgeIndex < 0 || edgeIndex >= _route.Edges.Count)
                    {
                        LogManager.Warning($"无法找到边,目标距离:{targetDistance:F2}米");
                        continue;
                    }

                    var edge = _route.Edges[edgeIndex];
                    double accumulatedLength = edgeLengths.Take(edgeIndex).Sum();
                    double edgeProgress = (targetDistance - accumulatedLength) / edge.PhysicalLength;

                    // 在边内插值位置
                    Point3D framePosition;
                    if (edge.SegmentType == PathSegmentType.Straight)
                    {
                        framePosition = InterpolateOnStraightEdge(edge, edgeProgress);
                    }
                    else // Arc
                    {
                        framePosition = InterpolateOnArcEdge(edge, edgeProgress);
                    }

                    double yawRadians = ComputeYawOnPath(i, allSampledPoints, edgeIndex, edgeProgress);

                    // 创建帧并检测碰撞
                    var frame = new AnimationFrame
                    {
                        Index = i,
                        Progress = (double)i / (totalFrames - 1),
                        Position = framePosition,
                        YawRadians = yawRadians,
                        Collisions = new List<CollisionResult>()
                    };

                    // 虚拟碰撞检测

                    // 计算车辆包围盒相对于framePosition的偏移
                    var currentVehicleBoundingBox = _animatedObject.BoundingBox();
                    var originalCenter = new Point3D(
                        (currentVehicleBoundingBox.Min.X + currentVehicleBoundingBox.Max.X) / 2,
                        (currentVehicleBoundingBox.Min.Y + currentVehicleBoundingBox.Max.Y) / 2,
                        (currentVehicleBoundingBox.Min.Z + currentVehicleBoundingBox.Max.Z) / 2
                    );

                    // 计算偏移量（当前包围盒中心到framePosition的偏移）
                    var offsetX = framePosition.X - originalCenter.X;
                    var offsetY = framePosition.Y - originalCenter.Y;
                    var offsetZ = framePosition.Z - currentVehicleBoundingBox.Min.Z;  // Z方向：framePosition是底面，originalCenter是中心

                    // 创建新的包围盒（将当前包围盒移动到framePosition）
                    var virtualBoundingBox = new BoundingBox3D(
                        new Point3D(
                            currentVehicleBoundingBox.Min.X + offsetX,
                            currentVehicleBoundingBox.Min.Y + offsetY,
                            framePosition.Z  // 底面Z坐标
                        ),
                        new Point3D(
                            currentVehicleBoundingBox.Max.X + offsetX,
                            currentVehicleBoundingBox.Max.Y + offsetY,
                            framePosition.Z + (currentVehicleBoundingBox.Max.Z - currentVehicleBoundingBox.Min.Z)  // 保持高度
                        )
                    );

                    IEnumerable<ModelItem> nearbyObjects;
                    if (manualOverrideActive)
                    {
                        nearbyObjects = manualTargetsSnapshot;
                    }
                    else
                    {
                        nearbyObjects = spatialIndexManager.FindNearbyObjects(
                            framePosition,
                            searchRadiusInModelUnits,
                            excludeObject: _animatedObject
                        );
                    }

                    foreach (var collider in nearbyObjects)
                    {
                        var colliderBox = collider.BoundingBox();

                        // 使用改进的精确距离检测方法（先检查相交，再计算精确距离）
                        double preciseDistance = BoundingBoxGeometryUtils.CalculatePreciseDistance(virtualBoundingBox, colliderBox);
                        bool intersects = preciseDistance <= _detectionGap;

                        if (intersects)
                        {
                            var collisionResult = new CollisionResult
                            {
                                ClashGuid = Guid.NewGuid(),
                                DisplayName = $"预计算碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}",
                                Status = ClashResultStatus.New,
                                Item1 = _animatedObject,
                                Item2 = collider,
                                CreatedTime = DateTime.Now,
                                Distance = BoundingBoxGeometryUtils.CalculateCenterDistance(virtualBoundingBox, colliderBox),
                                Center = new Point3D(
                                    (virtualBoundingBox.Min.X + virtualBoundingBox.Max.X + colliderBox.Min.X + colliderBox.Max.X) / 4,
                                    (virtualBoundingBox.Min.Y + virtualBoundingBox.Max.Y + colliderBox.Min.Y + colliderBox.Max.Y) / 4,
                                    (virtualBoundingBox.Min.Z + virtualBoundingBox.Max.Z + colliderBox.Min.Z + colliderBox.Max.Z) / 4
                                ),
                                // 🔥 重要：记录虚拟车辆的包围盒中心，而不是底面中心
                                // 原因：
                                // 1. framePosition是路径点，代表车辆在地面上的位置（底面中心）
                                // 2. ClashDetective移动逻辑使用包围盒中心进行定位
                                // 3. 如果记录底面中心，ClashDetective会把包围盒中心移动到底面位置，导致车辆下沉半个高度
                                // 4. 记录包围盒中心可以确保ClashDetective移动后的位置与预计算时的虚拟车辆位置一致
                                Item1Position = new Point3D(
                                    framePosition.X,
                                    framePosition.Y,
                                    framePosition.Z + (virtualBoundingBox.Max.Z - virtualBoundingBox.Min.Z) / 2
                                ),
                                Item2Position = GetObjectPosition(collider),
                                HasPositionInfo = true
                            };

                            frame.Collisions.Add(collisionResult);
                            _allCollisionResults.Add(collisionResult);
                        }
                    }

                    _animationFrames.Add(frame);
                }

                // 统计碰撞信息
                var framesWithCollision = _animationFrames.Count(f => f.HasCollision);
                var totalCollisions = _animationFrames.Sum(f => f.Collisions.Count);
                LogManager.Info($"=== 预计算完成 ===");
                LogManager.Info($"总帧数: {_animationFrames.Count}");
                LogManager.Info($"包含碰撞的帧: {framesWithCollision}");
                LogManager.Info($"总碰撞次数: {totalCollisions}");
                LogManager.Info($"记录的碰撞结果总数: {_allCollisionResults.Count} 个");
            }
            catch (Exception ex)
            {
                LogManager.Error($"预计算动画帧失败: {ex.Message}");
                _animationFrames = new List<AnimationFrame>();
            }
        }

        /// <summary>
        /// 根据路径计算指定帧的yaw角度
        /// </summary>
        /// <summary>
        /// 计算路径上的朝向(改进版)
        /// </summary>
        private double ComputeYawOnPath(
            int frameIndex,
            List<Point3D> allSampledPoints,
            int currentEdgeIndex,
            double edgeProgress)
        {
            var edge = _route.Edges[currentEdgeIndex];

            if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null)
            {
                // 圆弧段: 使用切线法计算精确朝向
                Vector3D startVec = (edge.Trajectory.Ts - edge.Trajectory.ArcCenter).Normalize();
                double signedAngle = edge.Trajectory.DeflectionAngle;
                double currentAngle = edgeProgress * signedAngle;

                // 计算切点Ts的朝向（进入切点的切线方向）
                Vector3D tsRadiusVec = (edge.Trajectory.Ts - edge.Trajectory.ArcCenter).Normalize();
                Vector3D rotationAxis = GetArcRotationAxis(edge.Trajectory);
                Point3D tsTangent;
                if (signedAngle >= 0)
                {
                    tsTangent = GeometryHelper.CrossProduct(
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z),
                        new Point3D(tsRadiusVec.X, tsRadiusVec.Y, tsRadiusVec.Z)
                    );
                }
                else
                {
                    tsTangent = GeometryHelper.CrossProduct(
                        new Point3D(tsRadiusVec.X, tsRadiusVec.Y, tsRadiusVec.Z),
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z)
                    );
                }
                double tsYaw = Math.Atan2(tsTangent.Y, tsTangent.X);

                // 计算切点Te的朝向（退出切点的切线方向）
                Vector3D teRadiusVec = (edge.Trajectory.Te - edge.Trajectory.ArcCenter).Normalize();
                Point3D teTangent;
                if (signedAngle >= 0)
                {
                    teTangent = GeometryHelper.CrossProduct(
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z),
                        new Point3D(teRadiusVec.X, teRadiusVec.Y, teRadiusVec.Z)
                    );
                }
                else
                {
                    teTangent = GeometryHelper.CrossProduct(
                        new Point3D(teRadiusVec.X, teRadiusVec.Y, teRadiusVec.Z),
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z)
                    );
                }
                double teYaw = Math.Atan2(teTangent.Y, teTangent.X);

                // 计算当前帧的朝向
                Point3D rotatedPoint = GeometryHelper.RotatePointAroundAxis(
                    edge.Trajectory.Ts,
                    edge.Trajectory.ArcCenter,
                    rotationAxis,
                    currentAngle
                );

                Vector3D radiusVec = (rotatedPoint - edge.Trajectory.ArcCenter).Normalize();

                // 计算切线方向：根据旋转方向确定切线顺序
                Point3D tangentPoint;
                if (signedAngle >= 0)
                {
                    tangentPoint = GeometryHelper.CrossProduct(
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z),
                        new Point3D(radiusVec.X, radiusVec.Y, radiusVec.Z)
                    );
                }
                else
                {
                    tangentPoint = GeometryHelper.CrossProduct(
                        new Point3D(radiusVec.X, radiusVec.Y, radiusVec.Z),
                        new Point3D(rotationAxis.X, rotationAxis.Y, rotationAxis.Z)
                    );
                }

                double currentYaw = Math.Atan2(tangentPoint.Y, tangentPoint.X);
                double yawChange = teYaw - tsYaw;

                // 计算圆弧段前后直线段的朝向
                double prevStraightYaw = 0;
                double nextStraightYaw = 0;

                // 圆弧段前的直线段朝向
                if (currentEdgeIndex > 0 && _route.Edges[currentEdgeIndex - 1].SegmentType == PathSegmentType.Straight)
                {
                    var prevEdge = _route.Edges[currentEdgeIndex - 1];
                    if (prevEdge.SampledPoints != null && prevEdge.SampledPoints.Count >= 2)
                    {
                        Point3D p1 = prevEdge.SampledPoints[0];
                        Point3D p2 = prevEdge.SampledPoints[prevEdge.SampledPoints.Count - 1];
                        prevStraightYaw = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
                    }
                }

                // 圆弧段后的直线段朝向
                if (currentEdgeIndex < _route.Edges.Count - 1 && _route.Edges[currentEdgeIndex + 1].SegmentType == PathSegmentType.Straight)
                {
                    var nextEdge = _route.Edges[currentEdgeIndex + 1];
                    if (nextEdge.SampledPoints != null && nextEdge.SampledPoints.Count >= 2)
                    {
                        Point3D p1 = nextEdge.SampledPoints[0];
                        Point3D p2 = nextEdge.SampledPoints[nextEdge.SampledPoints.Count - 1];
                        nextStraightYaw = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
                    }
                }

                // 在第一帧打印完整信息（使用静态变量确保每个圆弧段只打印一次）
                if (!_arcInfoPrinted.Contains(currentEdgeIndex))
                {
                    LogManager.Debug($"圆弧段[{currentEdgeIndex}]朝向信息:");
                    LogManager.Debug($"  前直线段朝向: {prevStraightYaw * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  进入切点(Ts)朝向: {tsYaw * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  圆弧偏转角度: {signedAngle * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  退出切点(Te)朝向: {teYaw * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  后直线段朝向: {nextStraightYaw * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  前后直线段朝向差: {(nextStraightYaw - prevStraightYaw) * 180.0 / Math.PI:F2}度");
                    LogManager.Debug($"  圆弧段朝向变化: {yawChange * 180.0 / Math.PI:F2}度");
                    _arcInfoPrinted.Add(currentEdgeIndex);
                }

                // 每一帧都打印当前朝向
                LogManager.Debug($"帧[{frameIndex}] 圆弧段[{currentEdgeIndex}]: 进度={edgeProgress:F4}, 当前朝向={currentYaw * 180.0 / Math.PI:F2}度");

                return currentYaw;
            }
            else
            {
                // 直线段: 使用直线方向向量，避免边界处的前后帧差分问题
                Point3D startPos = edge.SampledPoints[0];
                Point3D endPos = edge.SampledPoints[edge.SampledPoints.Count - 1];

                double dx = endPos.X - startPos.X;
                double dy = endPos.Y - startPos.Y;
                double length = Math.Sqrt(dx * dx + dy * dy);

                if (length < 1e-6)
                {
                    // 直线段长度太短，尝试使用前后帧差分
                    Point3D currentPos = allSampledPoints.Count > 0 ? allSampledPoints[Math.Min(frameIndex, allSampledPoints.Count - 1)] : new Point3D();
                    int nextIndex = Math.Min(frameIndex + 1, allSampledPoints.Count - 1);
                    Point3D nextPos = allSampledPoints[nextIndex];

                    dx = nextPos.X - currentPos.X;
                    dy = nextPos.Y - currentPos.Y;
                    length = Math.Sqrt(dx * dx + dy * dy);

                    if (length < 1e-6)
                    {
                        return 0.0;
                    }
                }

                return Math.Atan2(dy, dx);
            }
        }

        /// <summary>
        /// 获取圆弧旋转轴
        /// </summary>
        private Vector3D GetArcRotationAxis(ArcTrajectory trajectory)
        {
            Vector3D startVec = (trajectory.Ts - trajectory.ArcCenter).Normalize();
            Vector3D endVec = (trajectory.Te - trajectory.ArcCenter).Normalize();

            Point3D cross = GeometryHelper.CrossProduct(
                new Point3D(startVec.X, startVec.Y, startVec.Z),
                new Point3D(endVec.X, endVec.Y, endVec.Z)
            );

            return new Vector3D(cross.X, cross.Y, cross.Z).Normalize();
        }

        /// <summary>
        /// 开始播放动画
        /// </summary>
        public void StartAnimation()
        {
            try
            {
                if (_animatedObject == null || _pathPoints.Count < 2)
                {
                    throw new InvalidOperationException("请先调用SetupAnimation设置动画参数");
                }

                // 创建 TimeLiner 任务（如果可用且未创建过）
                if (_timeLinerManager != null && _timeLinerManager.IsTimeLinerAvailable)
                {
                    string objectName = "UnknownObject";
                    try
                    {
                        objectName = _animatedObject?.DisplayName ?? "UnknownObject";
                    }
                    catch (Exception)
                    {
                        objectName = "DisposedObject";
                    }

                    // 使用动画配置hash作为任务标识
                    var hashPrefix = _currentAnimationHash.Substring(0, Math.Min(8, _currentAnimationHash.Length));
                    var taskName = $"{objectName}_运输_{hashPrefix}";

                    // 检查是否已存在相同配置的任务
                    var existingTaskId = _timeLinerManager.FindTaskByName(taskName);
                    if (!string.IsNullOrEmpty(existingTaskId))
                    {
                        _currentTaskId = existingTaskId;
                        LogManager.Info($"复用现有 TimeLiner 任务: {taskName} (ID: {_currentTaskId})");
                    }
                    else
                    {
                        // 创建新任务
                        var duration = TimeSpan.FromSeconds(_animationDuration);
                        LogManager.Info($"创建 TimeLiner 任务: {taskName}");

                        _currentTaskId = _timeLinerManager.CreateTransportTask(
                            taskName,
                            _pathPoints,
                            duration,
                            _animatedObject);

                        if (!string.IsNullOrEmpty(_currentTaskId))
                        {
                            LogManager.Info($"✓ TimeLiner 任务创建成功: {taskName} (ID: {_currentTaskId})");
                        }
                        else
                        {
                            LogManager.Warning("TimeLiner 任务创建失败，继续使用基础动画功能");
                        }
                    }
                }
                else
                {
                    LogManager.Info("TimeLiner 不可用，使用基础动画功能");
                }

                // 设置碰撞检测转发（用于高亮显示和UI更新）
                SetupCollisionReportForwarding();

                // 初始化动画状态
                _animationStartTime = DateTime.Now;
                _animationFrameCount = 0; // 重置帧计数
                _currentFrameIndex = 0; // 重置当前帧索引，确保从第一帧开始
                _pausedProgress = 0.0; // 重置暂停进度

                // 初始化动画状态时不再强行覆盖 _currentYaw 为第一帧的 yaw
                // 这样在 UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians) 时
                // deltaYaw = firstFrame.YawRadians - 物体初始Yaw，从而产生旋转增量让物体转向

                if (_animationFrames != null && _animationFrames.Count > 0)
                {
                    var firstFrame = _animationFrames[0];

                    // 立即设置到第一帧的位置和朝向（由于MoveVehicleToPathStart已经设置过了，这里主要是确保状态同步）
                    UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians);
                    LogManager.Debug($"[动画开始] 确认初始位置和朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
                }
                else
                {
                    _currentYaw = 0.0;
                }

                // 重置动画状态
                _lastFrameTime = DateTime.MinValue;
                _fpsFrameCount = 0;
                _fpsCounterStart = DateTime.Now;
                _frameInterval = 1000.0 / _animationFrameRate;
                _lastHighlightState = false; // 重置高亮状态
                _lastCollisionObjects.Clear(); // 重置碰撞对象集合

                // 清除所有碰撞高亮
                ModelHighlightHelper.ClearCollisionHighlights();
                LogManager.Debug("[动画开始] 已清除所有碰撞高亮");

                // 启动动画播放
                StartAnimationPlayback();

                SetState(AnimationState.Playing);
                LogManager.Info($"动画开始播放 - DispatcherTimer模式");
            }
            catch (Exception ex)
            {
                LogManager.Error($"启动动画失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 启动动画播放（DispatcherTimer）
        /// </summary>
        private void StartAnimationPlayback()
        {
            try
            {
                // 停止之前的播放
                StopAnimationPlayback();

                // 使用DispatcherTimer模式
                _animationTimer.Interval = TimeSpan.FromMilliseconds(_frameInterval);
                _animationTimer.Start();
                LogManager.Debug("[播放模式] 启动DispatcherTimer模式");
            }
            catch (Exception ex)
            {
                LogManager.Error($"启动动画播放失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 停止动画播放（停止DispatcherTimer）
        /// </summary>
        private void StopAnimationPlayback()
        {
            try
            {
                // 停止DispatcherTimer
                if (_animationTimer != null)
                {
                    _animationTimer.Stop();
                }

                LogManager.Debug("[播放模式] 已停止DispatcherTimer");
            }
            catch (Exception ex)
            {
                LogManager.Warning($"停止动画播放时出现警告: {ex.Message}");
            }
        }

        /// <summary>
        /// DispatcherTimer事件处理器 - 主要动画机制
        /// </summary>
        private void OnTimerTick(object sender, EventArgs e)
        {
            try
            {
                // 处理动画帧
                ProcessAnimationFrame();

                // 关键改进：显式请求重绘，解决卡顿
                NavisApplication.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
            }
            catch (Exception ex)
            {
                LogManager.Error($"[DispatcherTimer模式] 动画更新异常: {ex.Message}");
                // 发生异常时停止动画
                ShutdownAnimation();
            }
        }


        /// <summary>
        /// 停止动画
        /// </summary>
        public void CancelAnimation()
        {
            try
            {
                // 检查动画状态，避免重复停止
                if (_currentState == AnimationState.Stopped || _currentState == AnimationState.Idle)
                {
                    LogManager.Debug($"动画已处于{_currentState}状态，跳过重复停止操作");
                    return;
                }

                // 停止播放机制
                StopAnimationPlayback();

                // 收集整个路径上的所有碰撞对象
                var allCollisionResults = new List<CollisionResult>();
                var uniqueCollidedItems = new HashSet<ModelItem>();

                foreach (var frame in _animationFrames)
                {
                    if (frame.HasCollision)
                    {
                        foreach (var collision in frame.Collisions)
                        {
                            // 收集唯一的碰撞对象
                            if (!uniqueCollidedItems.Contains(collision.Item2))
                            {
                                uniqueCollidedItems.Add(collision.Item2);
                                allCollisionResults.Add(collision);
                            }
                        }
                    }
                }

                SetState(AnimationState.Stopped);
                _pausedProgress = 0.0; // 重置暂停进度
                _currentFrameIndex = 0; // 重置帧索引

                // 将物体移回起点位置并恢复初始朝向
                if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
                {
                    MoveVehicleToPathStart();
                    LogManager.Info($"物体已移回起点位置并恢复初始朝向");
                }

                LogManager.Info("动画已停止");

                // 动画停止时不创建碰撞测试汇总，由动画完成事件统一处理
                LogManager.Info("动画停止，等待动画完成事件统一处理碰撞测试...");

                // 更新 TimeLiner 任务状态
                if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId))
                {
                    _timeLinerManager.UpdateTaskProgress(_currentTaskId, 0.0, AnimationState.Stopped);
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"停止动画失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 程序关闭时的动画清理（不执行UI操作）
        /// </summary>
        public void ShutdownAnimation()
        {
            try
            {
                LogManager.Info("[PathAnimationManager] 程序关闭，执行动画清理");

                // 检查动画状态，避免重复停止
                if (_currentState == AnimationState.Stopped || _currentState == AnimationState.Idle)
                {
                    LogManager.Debug($"动画已处于{_currentState}状态，跳过关闭清理");
                    return;
                }

                // 停止播放机制（关闭时不记录详细日志）
                try
                {
                    if (_animationTimer != null) _animationTimer.Stop();
                }
                catch (Exception stopEx)
                {
                    LogManager.Debug($"关闭清理时停止播放机制异常: {stopEx.Message}");
                }

                // 直接设置状态为停止，不执行任何UI操作
                SetState(AnimationState.Stopped);
                _pausedProgress = 0.0; // 重置暂停进度
                _currentFrameIndex = 0; // 重置帧索引

                LogManager.Info("[PathAnimationManager] 动画关闭清理完成");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[PathAnimationManager] 关闭动画清理失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 完成动画（当动画自然播放结束时调用）- 优化版本，使用预计算碰撞结果
        /// </summary>
        private void FinishAnimation()
        {
            try
            {
                // 停止播放机制
                StopAnimationPlayback();

                // 重置暂停进度
                _pausedProgress = 0.0;

                // 使用预计算的所有碰撞结果进行高亮显示（需要去重以避免重复高亮）
                var allCollisionResults = _allCollisionResults
                    .GroupBy(c => new { c.Item1, c.Item2 })
                    .Select(g => g.First())
                    .ToList();

                // 将物体移回起点位置并恢复初始朝向
                if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
                {
                    RestoreObjectToCADPosition();
                    MoveVehicleToPathStart();
                    LogManager.Info($"动画播放自然结束，物体已移回起点位置并恢复初始朝向");
                }

                // 直接设置为完成状态，避免中间状态切换
                SetState(AnimationState.Finished);

                // 修复：显示正确的总帧数，而不是最后一帧的索引
                var actualTotalFrames = _animationFrames?.Count ?? 0;
                LogManager.Info($"动画播放完成，总帧数: {actualTotalFrames}, 平均FPS: {_actualFPS:F1}");

                // 更新 TimeLiner 任务状态
                if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId))
                {
                    _timeLinerManager.UpdateTaskProgress(_currentTaskId, 1.0, AnimationState.Finished);
                }

                // 检查此动画配置是否已经进行过碰撞检测
                if (!_completedCollisionTests.Contains(_currentAnimationHash) && _allCollisionResults.Count > 0)
                {
                    LogManager.Info($"此动画配置首次完成，开始创建碰撞测试汇总（基于 {_allCollisionResults.Count} 个预计算碰撞记录）...");
                    ClashDetectiveIntegration.Instance.CreateAllAnimationCollisionTests(
                        _allCollisionResults,
                        _detectionGap,
                        _pathName,
                        _currentRouteId,
                        _animatedObjectName,
                        _animationFrameRate,
                        _animationDuration
                    );
                    _completedCollisionTests.Add(_currentAnimationHash); // 记录此配置已完成碰撞检测
                    LogManager.Info($"碰撞测试汇总已创建并记录，此配置后续播放将跳过碰撞检测");
                }
                else if (_completedCollisionTests.Contains(_currentAnimationHash))
                {
                    LogManager.Info("此动画配置的碰撞测试已存在，跳过重复创建");
                }
                else
                {
                    LogManager.Info("无碰撞数据，跳过碰撞测试创建");
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"完成动画失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 暂停动画
        /// </summary>
        public void PauseAnimation()
        {
            try
            {
                if (_currentState == AnimationState.Playing)
                {
                    // 计算并保存当前进度
                    double elapsedSeconds = (DateTime.Now - _animationStartTime).TotalSeconds;
                    _pausedProgress = Math.Min(elapsedSeconds / _animationDuration, 1.0);

                    // 停止播放机制
                    StopAnimationPlayback();

                    SetState(AnimationState.Paused);
                    LogManager.Info($"动画已暂停，当前进度: {_pausedProgress:F3}");

                    // 更新 TimeLiner 任务状态
                    if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId))
                    {
                        _timeLinerManager.UpdateTaskProgress(_currentTaskId, _pausedProgress, AnimationState.Paused);
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"暂停动画失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 恢复动画
        /// </summary>
        public void ResumeAnimation()
        {
            try
            {
                if (_currentState == AnimationState.Paused)
                {
                    // 使用保存的暂停进度重新设置动画开始时间
                    // 设置开始时间，使得当前时间对应保存的暂停进度
                    _animationStartTime = DateTime.Now.AddSeconds(-(_pausedProgress * _animationDuration));

                    // 重新启动播放机制
                    _lastFrameTime = DateTime.MinValue; // 确保下一帧立即执行
                    StartAnimationPlayback();

                    SetState(AnimationState.Playing);
                    LogManager.Info($"动画已恢复，从进度 {_pausedProgress:F3} 继续播放");

                    // 更新 TimeLiner 任务状态
                    if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId))
                    {
                        _timeLinerManager.UpdateTaskProgress(_currentTaskId, _pausedProgress, AnimationState.Playing);
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"恢复动画失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 重置动画对象到原始位置
        /// </summary>
        public void ResetAnimation()
        {
            try
            {
                // 只在需要时停止动画，避免重复调用
                if (_currentState == AnimationState.Playing || _currentState == AnimationState.Paused)
                {
                    CancelAnimation(); // 停止当前动画
                }

                // 恢复对象的原始变换（安全检查Navisworks对象可用性）
                if (_animatedObject != null)
                {
                    try
                    {
                        // 检查Navisworks应用程序和文档是否仍然可用
                        var activeDoc = NavisApplication.ActiveDocument;
                        if (activeDoc != null && activeDoc.Models != null)
                        {
                            // 第一步：仅仅彻底归位到 CAD 原始位置（不涉及路径起点），这是“清除”按钮的逻辑
                            RestoreObjectToCADPosition();

                            // 第二步：如果已经生成了动画路径，则重新对齐到起点（带旋转）
                            if (_animationFrames != null && _animationFrames.Count > 0)
                            {
                                MoveVehicleToPathStart();
                                LogManager.Info("已重新对齐到路径起点");
                            }
                        }
                        else
                        {
                            LogManager.Info("Navisworks文档已不可用，跳回空闲状态");
                        }
                    }
                    catch (Exception resetEx)
                    {
                        LogManager.Warning($"重置对象位置时出现警告: {resetEx.Message}");
                        // 不再抛出异常，因为在资源清理阶段这是正常的
                    }
                }

                // 重置UI状态（这些操作不依赖Navisworks对象）
                try
                {
                    ProgressChanged?.Invoke(this, 0); // 重置进度条
                    SetState(AnimationState.Ready); // 重置后回到就绪状态
                }
                catch (Exception uiEx)
                {
                    LogManager.Warning($"重置UI状态时出现警告: {uiEx.Message}");
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"重置动画过程中发生异常: {ex.Message}");
                // 在资源清理阶段不再抛出异常，避免影响程序正常关闭
            }
        }


        /// <summary>
        /// 安全获取ModelItem的DisplayName，避免访问已释放对象的警告
        /// </summary>
        /// <param name="item">ModelItem对象</param>
        /// <returns>安全的显示名称</returns>
        private string GetSafeObjectName(ModelItem item)
        {
            try
            {
                if (item == null)
                {
                    return "NULL";
                }

                // 尝试访问DisplayName，如果对象已被释放会抛出异常
                return item.DisplayName ?? "未命名对象";
            }
            catch (System.ObjectDisposedException)
            {
                return "已释放对象";
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                return "COM对象已释放";
            }
            catch (Exception ex)
            {
                return $"访问失败({ex.GetType().Name})";
            }
        }


        /// <summary>
        /// 根据进度插值计算当前位置
        /// </summary>
        private Point3D InterpolatePosition(double progress)
        {
            if (_pathPoints.Count < 2)
                return _pathPoints[0];

            // 确保进度在0-1范围内
            progress = Math.Max(0.0, Math.Min(1.0, progress));

            // 如果进度达到100%，直接返回终点
            if (progress >= 1.0)
            {
                return _pathPoints[_pathPoints.Count - 1];
            }

            // 计算总路径长度
            var totalDistance = CalculateTotalPathDistance();

            // 检查总距离是否有效
            if (totalDistance <= 0.0 || double.IsNaN(totalDistance) || double.IsInfinity(totalDistance))
            {
                LogManager.Error($"路径总长度无效: {totalDistance}，返回起点坐标");
                return _pathPoints[0];
            }

            var targetDistance = totalDistance * progress;

            // 找到当前应该在哪两个点之间
            var accumulatedDistance = 0.0;
            for (int i = 0; i < _pathPoints.Count - 1; i++)
            {
                var segmentDistance = CalculateDistance(_pathPoints[i], _pathPoints[i + 1]);

                // 检查段距离是否有效
                if (double.IsNaN(segmentDistance) || double.IsInfinity(segmentDistance))
                {
                    LogManager.Error($"路径段[{i}-{i + 1}]距离无效: {segmentDistance}，跳过此段");
                    continue;
                }

                if (accumulatedDistance + segmentDistance > targetDistance || i == _pathPoints.Count - 2)
                {
                    // 在这个线段内，或者是最后一个线段
                    var segmentProgress = segmentDistance > 0 ? (targetDistance - accumulatedDistance) / segmentDistance : 0.0;

                    // 确保段内进度在0-1范围内
                    segmentProgress = Math.Max(0.0, Math.Min(1.0, segmentProgress));

                    var interpolatedPoint = InterpolatePoints(_pathPoints[i], _pathPoints[i + 1], segmentProgress);

                    // 验证插值结果
                    if (double.IsNaN(interpolatedPoint.X) || double.IsNaN(interpolatedPoint.Y) || double.IsNaN(interpolatedPoint.Z))
                    {
                        LogManager.Error($"插值计算结果无效: ({interpolatedPoint.X},{interpolatedPoint.Y},{interpolatedPoint.Z})，返回起点");
                        return _pathPoints[0];
                    }

                    return interpolatedPoint;
                }

                accumulatedDistance += segmentDistance;
            }

            // 如果到达这里，返回最后一个点
            return _pathPoints[_pathPoints.Count - 1];
        }

        /// <summary>
        /// 在两点间插值
        /// </summary>
        private Point3D InterpolatePoints(Point3D point1, Point3D point2, double t)
        {
            return new Point3D(
                point1.X + (point2.X - point1.X) * t,
                point1.Y + (point2.Y - point1.Y) * t,
                point1.Z + (point2.Z - point1.Z) * t
            );
        }

        /// <summary>
        /// 在直线边上插值位置
        /// </summary>
        private Point3D InterpolateOnStraightEdge(PathEdge edge, double progress)
        {
            if (edge.SampledPoints == null || edge.SampledPoints.Count < 2)
                return edge.Trajectory?.Ts ?? new Point3D();

            int pointIndex = (int)(progress * (edge.SampledPoints.Count - 1));
            pointIndex = Math.Max(0, Math.Min(pointIndex, edge.SampledPoints.Count - 1));

            return edge.SampledPoints[pointIndex];
        }

        /// <summary>
        /// 在圆弧边上插值位置
        /// </summary>
        private Point3D InterpolateOnArcEdge(PathEdge edge, double progress)
        {
            if (edge.Trajectory == null || edge.SampledPoints == null || edge.SampledPoints.Count < 2)
                return edge.Trajectory?.Ts ?? new Point3D();

            int pointIndex = (int)(progress * (edge.SampledPoints.Count - 1));
            pointIndex = Math.Max(0, Math.Min(pointIndex, edge.SampledPoints.Count - 1));

            return edge.SampledPoints[pointIndex];
        }

        /// <summary>
        /// 查找指定距离对应的边索引
        /// </summary>
        private int FindEdgeForDistance(double targetDistance, List<double> edgeLengths)
        {
            double accumulatedLength = 0.0;

            for (int i = 0; i < edgeLengths.Count; i++)
            {
                if (accumulatedLength + edgeLengths[i] >= targetDistance)
                {
                    return i;
                }
                accumulatedLength += edgeLengths[i];
            }

            return edgeLengths.Count - 1;
        }

        /// <summary>
        /// 计算路径总长度
        /// </summary>
        private double CalculateTotalPathDistance()
        {
            var totalDistance = 0.0;
            for (int i = 0; i < _pathPoints.Count - 1; i++)
            {
                totalDistance += CalculateDistance(_pathPoints[i], _pathPoints[i + 1]);
            }
            return totalDistance;
        }

        /// <summary>
        /// 获取对象当前位置
        /// </summary>
        private Point3D GetObjectPosition(ModelItem item)
        {
            try
            {
                if (item == null) return new Point3D(0, 0, 0);

                var bounds = item.BoundingBox();
                if (bounds != null)
                {
                    return new Point3D(
                        (bounds.Min.X + bounds.Max.X) / 2,
                        (bounds.Min.Y + bounds.Max.Y) / 2,
                        (bounds.Min.Z + bounds.Max.Z) / 2
                    );
                }
                return new Point3D(0, 0, 0);
            }
            catch (Exception ex)
            {
                LogManager.Error($"获取对象位置失败: {ex.Message}");
                return new Point3D(0, 0, 0);
            }
        }

        /// <summary>
        /// 计算两点间距离
        /// </summary>
        private double CalculateDistance(Point3D point1, Point3D point2)
        {
            var dx = point2.X - point1.X;
            var dy = point2.Y - point1.Y;
            var dz = point2.Z - point1.Z;
            return Math.Sqrt(dx * dx + dy * dy + dz * dz);
        }

        /// <summary>
        /// 更新对象位置和朝向（支持绕物体中心旋转）
        /// </summary>
        private void UpdateObjectPosition(Point3D newPosition, double newYaw = double.NaN)
        {
            try
            {
                var doc = NavisApplication.ActiveDocument;
                var modelItems = new ModelItemCollection { _animatedObject };

                // 计算平移和旋转的增量
                var deltaPos = new Vector3D(
                    newPosition.X - _currentPosition.X,
                    newPosition.Y - _currentPosition.Y,
                    newPosition.Z - _currentPosition.Z
                );

                Transform3D incrementalTransform;

                if (!double.IsNaN(newYaw))
                {
                    // 有旋转：需要实现"绕物体当前位置自转"
                    // 由于Transform3DComponents.Rotation总是绕世界原点旋转
                    // 我们需要手动计算旋转导致的位置偏移，并补偿

                    double deltaYaw = newYaw - _currentYaw;

                    // 计算绕当前位置旋转的等效变换：
                    // 1. 如果绕原点旋转deltaYaw，当前位置_currentPosition会移动到哪里？
                    double cos = Math.Cos(deltaYaw);
                    double sin = Math.Sin(deltaYaw);
                    double rotatedX = _currentPosition.X * cos - _currentPosition.Y * sin;
                    double rotatedY = _currentPosition.X * sin + _currentPosition.Y * cos;

                    // 2. 但我们希望物体绕自己旋转，位置移动到newPosition
                    // 所以需要的平移 = newPosition - (旋转后的位置)
                    var compensatedTranslation = new Vector3D(
                        newPosition.X - rotatedX,
                        newPosition.Y - rotatedY,
                        newPosition.Z - _currentPosition.Z  // Z保持deltaPos
                    );

                    // 3. 组合：先旋转（绕原点），再平移（补偿+目标位置）
                    var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
                    var components = identity.Factor();
                    components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
                    components.Translation = compensatedTranslation;

                    incrementalTransform = components.Combine();

                    _currentYaw = newYaw;
                }
                else
                {
                    // 纯平移
                    incrementalTransform = Transform3D.CreateTranslation(deltaPos);
                }

                // 应用增量变换（false = 增量模式）
                doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);

                // 更新当前位置
                _currentPosition = newPosition;
            }
            catch (Exception ex)
            {
                LogManager.Error($"更新部件位置失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取文档单位信息（用于日志记录）
        /// </summary>
        private string GetDocumentUnitsInfo()
        {
            try
            {
                var doc = NavisApplication.ActiveDocument;
                var units = doc.Units;
                LogManager.Debug($"[单位检测] 文档单位: {units}");
                return units.ToString();
            }
            catch (Exception ex)
            {
                LogManager.Error($"获取文档单位信息失败: {ex.Message}");
                return "Unknown";
            }
        }

        /// <summary>
        /// 获取模型当前变换
        /// </summary>
        private Transform3D GetCurrentTransform(ModelItem item)
        {
            // 获取包围盒中心作为参考点
            var boundingBox = item.BoundingBox();
            var center = boundingBox.Center;

            // 创建基于中心点的单位变换
            return Transform3D.CreateTranslation(new Vector3D(center.X, center.Y, center.Z));
        }

        /// <summary>
        /// 设置碰撞报告转发（用于高亮显示和UI更新）
        /// </summary>
        private void SetupCollisionReportForwarding()
        {
            try
            {
                // 订阅碰撞检测事件
                ClashDetectiveIntegration.Instance.CollisionDetected += OnClashDetectiveCollisionDetected;

                LogManager.Info("碰撞报告转发设置完成");
            }
            catch (Exception ex)
            {
                LogManager.Error($"设置碰撞报告转发失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 处理 Clash Detective 碰撞检测事件
        /// </summary>
        private void OnClashDetectiveCollisionDetected(object sender, CollisionDetectedEventArgs e)
        {
            try
            {
                // 将碰撞结果转发到动画管理器的事件
                OnCollisionDetected(e);

                LogManager.Debug($"Clash Detective 检测到 {e.CollisionCount} 个碰撞");
            }
            catch (Exception ex)
            {
                LogManager.Error($"处理 Clash Detective 碰撞事件失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 触发碰撞检测事件
        /// </summary>
        protected virtual void OnCollisionDetected(CollisionDetectedEventArgs e)
        {
            CollisionDetected?.Invoke(this, e);
        }

        /// <summary>
        /// 设置动画持续时间
        /// </summary>
        public void SetAnimationDuration(double durationSeconds)
        {
            _animationDuration = Math.Max(1.0, durationSeconds);
        }

        /// <summary>
        /// 获取动画状态
        /// </summary>
        public bool IsAnimating => _currentState == AnimationState.Playing;

        /// <summary>
        /// 获取 TimeLiner 是否可用
        /// </summary>
        public bool IsTimeLinerAvailable => _timeLinerManager?.IsTimeLinerAvailable ?? false;

        /// <summary>
        /// 获取当前动画状态
        /// </summary>
        public AnimationState CurrentState => _currentState;

        /// <summary>
        /// 获取当前 TimeLiner 任务ID
        /// </summary>
        public string CurrentTaskId => _currentTaskId;

        /// <summary>
        /// 获取 TimeLiner 集成管理器
        /// </summary>
        public TimeLinerIntegrationManager TimeLinerManager => _timeLinerManager;

        #region 帧控制功能

        /// <summary>
        /// 获取当前帧索引
        /// </summary>
        public int CurrentFrame => _currentFrameIndex;

        /// <summary>
        /// 获取总帧数
        /// </summary>
        public int TotalFrames => _animationFrames?.Count ?? 0;

        /// <summary>
        /// 获取播放方向（1=正向，-1=反向）
        /// </summary>
        public int PlaybackDirection => _playbackDirection;

        /// <summary>
        /// 获取播放速度倍率
        /// </summary>
        public double PlaybackSpeed => _playbackSpeed;

        /// <summary>
        /// 获取是否正在反向播放
        /// </summary>
        public bool IsPlayingReverse => _playbackDirection == -1;

        /// <summary>
        /// 设置播放方向
        /// </summary>
        /// <param name="reverse">true=反向播放，false=正向播放</param>
        public void SetPlaybackDirection(bool reverse)
        {
            _playbackDirection = reverse ? -1 : 1;
            LogManager.Info($"播放方向设置为: {(reverse ? "反向" : "正向")}");
        }

        /// <summary>
        /// 设置播放速度
        /// </summary>
        /// <param name="speed">播放速度倍率，负值表示反向</param>
        public void SetPlaybackSpeed(double speed)
        {
            _playbackSpeed = Math.Abs(speed);
            _playbackDirection = speed >= 0 ? 1 : -1;

            // 更新帧间隔
            _frameInterval = 1000.0 / (_animationFrameRate * _playbackSpeed);
            LogManager.Info($"播放速度设置为: {speed}x，方向: {(speed >= 0 ? "正向" : "反向")}");
        }

        /// <summary>
        /// 跳转到指定帧
        /// </summary>
        /// <param name="frameIndex">目标帧索引</param>
        public void SeekToFrame(int frameIndex)
        {
            try
            {
                if (_animationFrames == null || _animationFrames.Count == 0)
                {
                    LogManager.Warning("无动画帧数据，无法跳转");
                    return;
                }

                // 限制帧索引范围
                frameIndex = Math.Max(0, Math.Min(frameIndex, _animationFrames.Count - 1));

                if (frameIndex == _currentFrameIndex)
                {
                    LogManager.Debug($"已处于目标帧 {frameIndex}，无需跳转");
                    return;
                }

                _currentFrameIndex = frameIndex;

                // 更新对象位置和朝向
                var frameData = _animationFrames[_currentFrameIndex];
                UpdateObjectPosition(frameData.Position, frameData.YawRadians);

                // 更新碰撞高亮
                UpdateCollisionHighlightFromFrame();

                // 计算并触发进度事件
                double progress = TotalFrames > 1 ? (double)_currentFrameIndex / (TotalFrames - 1) * 100 : 0;
                ProgressChanged?.Invoke(this, progress);
            }
            catch (Exception ex)
            {
                LogManager.Error($"跳转到帧失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 跳转到指定进度
        /// </summary>
        /// <param name="progress">进度值（0.0-1.0）</param>
        public void SeekToProgress(double progress)
        {
            try
            {
                progress = Math.Max(0.0, Math.Min(1.0, progress));
                int targetFrame = TotalFrames > 1 ? (int)(progress * (TotalFrames - 1)) : 0;
                SeekToFrame(targetFrame);
            }
            catch (Exception ex)
            {
                LogManager.Error($"跳转到进度失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 单帧前进
        /// </summary>
        public void StepForward()
        {
            StepForward(1);
        }

        /// <summary>
        /// 前进指定帧数
        /// </summary>
        /// <param name="frames">帧数</param>
        public void StepForward(int frames)
        {
            try
            {
                if (frames <= 0) return;

                int targetFrame = _currentFrameIndex + frames;
                targetFrame = Math.Min(targetFrame, TotalFrames - 1);

                SeekToFrame(targetFrame);
            }
            catch (Exception ex)
            {
                LogManager.Error($"前进步进失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 单帧后退
        /// </summary>
        public void StepBackward()
        {
            StepBackward(1);
        }

        /// <summary>
        /// 后退指定帧数
        /// </summary>
        /// <param name="frames">帧数</param>
        public void StepBackward(int frames)
        {
            try
            {
                if (frames <= 0) return;

                int targetFrame = _currentFrameIndex - frames;
                targetFrame = Math.Max(targetFrame, 0);

                SeekToFrame(targetFrame);
            }
            catch (Exception ex)
            {
                LogManager.Error($"后退步进失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 快进10帧
        /// </summary>
        public void FastForward()
        {
            StepForward(10);
        }

        /// <summary>
        /// 快退10帧
        /// </summary>
        public void FastBackward()
        {
            StepBackward(10);
        }

        /// <summary>
        /// 开始正向播放
        /// </summary>
        public void PlayForward()
        {
            try
            {
                SetPlaybackDirection(false);
                if (_currentState == AnimationState.Paused)
                {
                    ResumeAnimation();  // 从暂停位置继续
                }
                else if (_currentState != AnimationState.Playing)
                {
                    StartAnimation();   // 只有非播放和非暂停状态才从头开始
                }
                LogManager.Info("开始正向播放");
            }
            catch (Exception ex)
            {
                LogManager.Error($"正向播放失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 开始反向播放
        /// </summary>
        public void PlayReverse()
        {
            try
            {
                SetPlaybackDirection(true);
                if (_currentState == AnimationState.Paused)
                {
                    ResumeAnimation();  // 从暂停位置继续
                }
                else if (_currentState != AnimationState.Playing)
                {
                    StartAnimation();   // 只有非播放和非暂停状态才从头开始
                }
                LogManager.Info("开始反向播放");
            }
            catch (Exception ex)
            {
                LogManager.Error($"反向播放失败: {ex.Message}");
            }
        }

        #endregion

        /// <summary>
        /// 清理对象引用
        /// </summary>
        public void ClearReferences()
        {
            try
            {
                LogManager.Info("[PathAnimationManager] 清理对象引用");

                // 停止动画
                if (_currentState == AnimationState.Playing || _currentState == AnimationState.Paused)
                {
                    ShutdownAnimation();
                }

                // 清空对象引用
                _animatedObject = null;
                _pathPoints?.Clear();
                _currentPosition = new Point3D(0, 0, 0);
                _originalCenter = new Point3D(0, 0, 0);

                LogManager.Info("[PathAnimationManager] 对象引用已清理");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[PathAnimationManager] 清理对象引用失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 验证动画对象是否有效
        /// </summary>
        private bool IsAnimatedObjectValid()
        {
            if (_animatedObject == null)
                return false;

            // 使用DocumentStateManager验证
            return DocumentStateManager.Instance.IsModelItemValid(_animatedObject);
        }

        /// <summary>
        /// 文档失效事件处理
        /// </summary>
        private void OnDocumentInvalidated(object sender, EventArgs e)
        {
            try
            {
                LogManager.Info("[PathAnimationManager] 文档失效，停止动画并清理");
                ClearReferences();
            }
            catch (Exception ex)
            {
                LogManager.Error($"[PathAnimationManager] 处理文档失效事件失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 资源清理
        /// </summary>
        public void Dispose()
        {
            try
            {
                LogManager.Info("开始清理PathAnimationManager资源");

                // 1. 优先停止动画（最小化的操作，不触发复杂的重置逻辑）
                // 只有在动画运行时才停止，避免重复调用
                try
                {
                    if (_currentState == AnimationState.Playing || _currentState == AnimationState.Paused)
                    {
                        ShutdownAnimation();
                    }
                }
                catch (Exception stopEx)
                {
                    LogManager.Warning($"停止动画时出现警告: {stopEx.Message}，继续清理其他资源");
                }

                // 2. 在Dispose中不进行重置操作，避免访问已释放的对象
                // 程序关闭时，对象位置重置是不必要的
                LogManager.Info("跳过动画重置操作（程序关闭时不需要恢复对象位置）");

                // 3. 清理 TimeLiner 资源
                if (_timeLinerManager != null)
                {
                    try
                    {
                        _timeLinerManager.Dispose();
                        _timeLinerManager = null;
                        LogManager.Info("TimeLiner 集成资源已清理");
                    }
                    catch (Exception ex)
                    {
                        LogManager.Warning($"清理 TimeLiner 资源时出现警告: {ex.Message}");
                    }
                }

                // 4. 清理DispatcherTimer资源
                if (_animationTimer != null)
                {
                    try
                    {
                        _animationTimer.Stop();
                        // DispatcherTimer不需要Dispose
                        _animationTimer = null;
                        LogManager.Info("DispatcherTimer资源已清理");
                    }
                    catch (Exception ex)
                    {
                        LogManager.Warning($"清理DispatcherTimer资源时出现警告: {ex.Message}");
                    }
                }

                // 5. 取消订阅文档事件
                DocumentStateManager.Instance.DocumentInvalidated -= OnDocumentInvalidated;

                LogManager.Info("PathAnimationManager资源清理完成");
            }
            catch (Exception ex)
            {
                LogManager.Error($"PathAnimationManager资源清理过程中发生异常: {ex.Message}");
                // 不抛出异常，避免影响应用程序正常关闭
            }
        }

        /// <summary>
        /// 设置动画帧率
        /// </summary>
        public void SetAnimationFrameRate(int frameRate)
        {
            _animationFrameRate = Math.Max(10, Math.Min(60, frameRate)); // 限制在10-60FPS之间
            _frameInterval = 1000.0 / _animationFrameRate; // 重新计算帧间隔

            // 动态更新DispatcherTimer间隔
            if (_animationTimer != null)
            {
                _animationTimer.Interval = TimeSpan.FromMilliseconds(_frameInterval);
                LogManager.Info($"DispatcherTimer间隔已更新: {_frameInterval:F1}ms");
            }

            LogManager.Info($"动画帧率设置为: {_animationFrameRate}FPS (间隔: {_frameInterval:F1}ms)");
        }

        /// <summary>
        /// 设置碰撞检测精度（参数单位：米）
        /// </summary>
        public void SetCollisionDetectionAccuracy(double accuracyInMeters)
        {
            // 转换为模型单位存储
            var accuracyInModelUnits = UnitsConverter.ConvertFromMeters(Math.Max(0.01, accuracyInMeters));
            _collisionDetectionAccuracy = accuracyInModelUnits;
            LogManager.Info($"碰撞检测精度设置为: {accuracyInMeters:F3}米");
        }

        /// <summary>
        /// 设置运动速度
        /// </summary>
        public void SetMovementSpeed(double speed)
        {
            _movementSpeed = Math.Max(0.1, speed); // 最小0.1米/秒
            LogManager.Info($"运动速度设置为: {_movementSpeed}m/s");
        }

        /// <summary>
        /// 设置检测间隙（参数单位：米）
        /// </summary>
        public void SetDetectionGap(double gapInMeters)
        {
            // 转换为模型单位存储
            var gapInModelUnits = UnitsConverter.ConvertFromMeters(Math.Max(0.0, gapInMeters));
            var roundedGapInModelUnits = Math.Round(gapInModelUnits, 4); // 模型单位保留更多精度

            // 只在值真正改变时才更新和记录日志
            if (Math.Abs(_detectionGap - roundedGapInModelUnits) > 0.0001)
            {
                _detectionGap = roundedGapInModelUnits;
                LogManager.Info($"检测间隙设置为: {gapInMeters:F2}米");
            }
        }

        /// <summary>
        /// 设置手工碰撞对象覆写列表
        /// </summary>
        public void SetManualCollisionTargets(IEnumerable<ModelItem> targets, bool enabled)
        {
            if (!enabled)
            {
                _manualCollisionOverrideEnabled = false;
                _manualCollisionTargets = new List<ModelItem>();
                LogManager.Info("[PathAnimationManager] 手工碰撞对象覆写已关闭");
                return;
            }

            if (targets == null)
            {
                _manualCollisionOverrideEnabled = false;
                _manualCollisionTargets = new List<ModelItem>();
                LogManager.Warning("[PathAnimationManager] 手工碰撞对象覆写启用但目标为空，已回退到默认模式");
                return;
            }

            var validTargets = targets
                .Where(item => item != null && ModelItemAnalysisHelper.IsModelItemValid(item))
                .Where(item => !ReferenceEquals(item, _animatedObject))
                .Distinct()
                .ToList();

            if (validTargets.Count == 0)
            {
                _manualCollisionOverrideEnabled = false;
                _manualCollisionTargets = new List<ModelItem>();
                LogManager.Warning("[PathAnimationManager] 手工碰撞对象覆写启用但均无效，已回退到默认模式");
                return;
            }

            _manualCollisionOverrideEnabled = true;
            _manualCollisionTargets = validTargets;
            LogManager.Info($"[PathAnimationManager] 启用手工碰撞对象覆写，共 {validTargets.Count} 个对象");
        }

        /// <summary>
        /// 获取当前动画帧率
        /// </summary>
        public int AnimationFrameRate => _animationFrameRate;

        /// <summary>
        /// 获取当前碰撞检测精度
        /// </summary>
        public double CollisionDetectionAccuracy => _collisionDetectionAccuracy;

        /// <summary>
        /// 获取当前运动速度
        /// </summary>
        public double MovementSpeed => _movementSpeed;

        /// <summary>
        /// 获取当前检测间隙（单位：米）
        /// </summary>
        public double DetectionGap
        {
            get
            {
                // 将内部模型单位转换为米制单位
                var modelUnitsToMeters = UnitsConverter.GetUnitsToMetersConversionFactor();
                return _detectionGap * modelUnitsToMeters;
            }
        }

        /// <summary>
        /// 获取路径名称
        /// </summary>
        public string PathName => _pathName;

        /// <summary>
        /// 获取动画时长
        /// </summary>
        public double AnimationDuration => _animationDuration;

        /// <summary>
        /// 设置并触发状态变更事件
        /// </summary>
        /// <param name="newState">新的动画状态</param>
        private void SetState(AnimationState newState)
        {
            if (_currentState != newState)
            {
                _currentState = newState;
                StateChanged?.Invoke(this, _currentState);
            }
        }

        /// <summary>
        /// 创建动画
        /// </summary>
        /// <param name="animatedObject">要动画化的模型对象</param>
        /// <param name="pathPoints">路径点列表</param>
        /// <param name="durationSeconds">动画持续时间（秒）</param>
        /// <param name="pathName">路径名称</param>
        /// <param name="routeId">路由ID</param>
        public void CreateAnimation(ModelItem animatedObject, List<Point3D> pathPoints, double durationSeconds = 10.0, string pathName = "未知路径", string routeId = null)
        {
            _pathName = pathName;
            _currentRouteId = routeId;
            _animatedObjectName = animatedObject?.DisplayName ?? "未知对象";

            LogManager.Info($"[PathAnimationManager.CreateAnimation] 接收到参数: pathName='{pathName}', routeId='{routeId}', animatedObjectName='{_animatedObjectName}'");
            LogManager.Info($"[PathAnimationManager.CreateAnimation] 存储的值: _pathName='{_pathName}', _currentRouteId='{_currentRouteId}'");

            // 注意：pathPoints参数已废弃，现在使用PathRoute
            SetupAnimation(animatedObject, durationSeconds, _route);
            SetState(AnimationState.Ready);
        }

        #region 动画实现方法


        /// <summary>
        /// DispatcherTimer动画处理核心
        /// </summary>
        /// <summary>
        /// 根据当前帧索引更新碰撞高亮（状态跟踪优化版本）
        /// </summary>
        private void UpdateCollisionHighlightFromFrame()
        {
            try
            {
                // 确保帧索引有效
                if (_currentFrameIndex < 0 || _currentFrameIndex >= _animationFrames.Count)
                {
                    return;
                }

                // 获取当前帧数据
                var currentFrame = _animationFrames[_currentFrameIndex];
                bool currentHasCollision = currentFrame.HasCollision;

                // 收集当前帧碰撞对象的集合
                var currentCollisionObjects = new HashSet<ModelItem>();
                if (currentHasCollision && currentFrame.Collisions != null)
                {
                    foreach (var collision in currentFrame.Collisions)
                    {
                        var item1 = collision.GetValidItem1();
                        var item2 = collision.GetValidItem2();
                        
                        if (item1 != null)
                            currentCollisionObjects.Add(item1);
                        if (item2 != null)
                            currentCollisionObjects.Add(item2);
                    }
                }

                // 检查是否需要更新高亮：
                // 1. 碰撞状态改变（有碰撞 vs 无碰撞）
                // 2. 碰撞对象集合改变（碰撞的物体变了）
                bool stateChanged = currentHasCollision != _lastHighlightState;
                bool objectsChanged = !currentCollisionObjects.SetEquals(_lastCollisionObjects);

                if (stateChanged || objectsChanged)
                {
                    if (currentHasCollision)
                    {
                        // 有碰撞：高亮当前帧的碰撞对象
                        ClashDetectiveIntegration.Instance.HighlightCollisions(currentFrame.Collisions);
                        LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 高亮碰撞 ({currentFrame.Collisions.Count}个, 对象{currentCollisionObjects.Count}个)");
                    }
                    else
                    {
                        // 无碰撞：清除高亮
                        ModelHighlightHelper.ClearCollisionHighlights();
                        LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除高亮");
                    }

                    // 更新状态记录
                    _lastHighlightState = currentHasCollision;
                    _lastCollisionObjects = currentCollisionObjects;
                }

                // 每次都触发碰撞事件（用于UI更新等）
                if (currentHasCollision)
                {
                    var eventArgs = new CollisionDetectedEventArgs(currentFrame.Collisions);
                    OnCollisionDetected(eventArgs);
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"更新碰撞高亮失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 统一的动画帧处理逻辑（DispatcherTimer专用）
        /// </summary>
        private void ProcessAnimationFrame()
        {
            // 检查动画状态
            if (_currentState != AnimationState.Playing)
            {
                return; // 非播放状态，跳过更新
            }

            // 验证动画对象是否仍然有效
            if (!IsAnimatedObjectValid())
            {
                LogManager.Warning("[PathAnimationManager] 动画对象已失效，停止动画");
                ShutdownAnimation();
                return;
            }

            // DispatcherTimer已经控制了调用间隔，无需手动帧率控制
            var now = DateTime.Now;

            // 计算下一帧索引（考虑播放方向和速度）
            int nextFrameIndex = _currentFrameIndex;

            if (_playbackDirection == 1) // 正向播放
            {
                nextFrameIndex = _currentFrameIndex + 1;
                if (nextFrameIndex >= _animationFrames.Count)
                {
                    // 正向播放到达终点
                    nextFrameIndex = _animationFrames.Count - 1;
                    StopAnimationPlayback();
                    FinishAnimation();
                    return;
                }
            }
            else // 反向播放
            {
                nextFrameIndex = _currentFrameIndex - 1;
                if (nextFrameIndex < 0)
                {
                    // 反向播放到达起点
                    nextFrameIndex = 0;
                    StopAnimationPlayback();
                    FinishAnimation();
                    return;
                }
            }

            // 更新帧索引和位置
            if (nextFrameIndex != _currentFrameIndex)
            {
                _currentFrameIndex = nextFrameIndex;

                // 使用预计算的帧位置和朝向
                if (_currentFrameIndex < _animationFrames.Count)
                {
                    var frameData = _animationFrames[_currentFrameIndex];
                    UpdateObjectPosition(frameData.Position, frameData.YawRadians);

                    // 更新碰撞高亮（基于预计算结果）
                    UpdateCollisionHighlightFromFrame();

                    // 计算当前进度（基于帧索引）
                    double progress = _animationFrames.Count > 1 ? (double)_currentFrameIndex / (_animationFrames.Count - 1) : 0;

                    // 触发进度事件
                    var progressPercent = progress * 100;
                    ProgressChanged?.Invoke(this, progressPercent);

                    // 同步进度到 TimeLiner（如果可用）
                    if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId))
                    {
                        _timeLinerManager.UpdateTaskProgress(_currentTaskId, progress, _currentState);
                    }
                }
            }

            // 记录帧时间和统计
            _lastFrameTime = now;
            _animationFrameCount++;

            // 性能监控和自动切换
            UpdateFPSCounterAndCheckSwitch();
        }


        /// <summary>
        /// 更新FPS计数器（DispatcherTimer模式）
        /// </summary>
        private void UpdateFPSCounterAndCheckSwitch()
        {
            _fpsFrameCount++;
            var elapsed = (DateTime.Now - _fpsCounterStart).TotalSeconds;

            // 每秒更新一次FPS统计
            if (elapsed >= 1.0)
            {
                _actualFPS = _fpsFrameCount / elapsed;
                LogManager.Debug($"[性能监控] 实际FPS: {_actualFPS:F1} (目标: {_animationFrameRate}) - DispatcherTimer模式");

                // 重置计数器
                _fpsFrameCount = 0;
                _fpsCounterStart = DateTime.Now;
            }
        }

        #region 碰撞测试优化方法

        /// <summary>
        /// 计算动画配置的哈希值（基于路径点和对象）
        /// </summary>
        private string ComputeAnimationConfigHash(ModelItem animatedObject, List<Point3D> pathPoints)
        {
            try
            {
                var sb = new StringBuilder();

                // 包含对象名称
                sb.Append(animatedObject?.DisplayName ?? "null");
                sb.Append("|");

                // 包含路径点信息
                if (pathPoints != null)
                {
                    foreach (var point in pathPoints)
                    {
                        sb.Append($"{point.X:F2},{point.Y:F2},{point.Z:F2};");
                    }
                }

                // 计算哈希
                using (var md5 = System.Security.Cryptography.MD5.Create())
                {
                    var inputBytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
                    var hashBytes = md5.ComputeHash(inputBytes);
                    return BitConverter.ToString(hashBytes).Replace("-", "");
                }
            }
            catch (Exception ex)
            {
                LogManager.Warning($"计算动画配置哈希失败: {ex.Message}");
                return DateTime.Now.Ticks.ToString(); // 回退到时间戳
            }
        }

        /// <summary>
        /// 计算动画配置的哈希值（基于PathRoute的Edges，可以区分不同的曲线化路径）
        /// </summary>
        private string ComputeAnimationConfigHashFromRoute(ModelItem animatedObject, PathRoute route)
        {
            try
            {
                var sb = new StringBuilder();

                // 包含对象名称
                sb.Append(animatedObject?.DisplayName ?? "null");
                sb.Append("|");

                // 包含路径ID（区分不同的路径）
                sb.Append(route?.Id ?? "null");
                sb.Append("|");

                // 包含动画参数（确保参数改变时重新检测）
                sb.Append($"Duration:{_animationDuration:F2}s");
                sb.Append($"|FrameRate:{_animationFrameRate}");
                sb.Append($"|DetectionGap:{_detectionGap:F4}");
                sb.Append("|");

                // 包含虚拟车辆尺寸（确保车辆尺寸改变时重新检测）
                var vehicleConfig = ConfigManager.Instance.Current.PathEditing;
                sb.Append($"Vehicle:{vehicleConfig.VehicleLengthMeters:F2}x{vehicleConfig.VehicleWidthMeters:F2}x{vehicleConfig.VehicleHeightMeters:F2}");
                sb.Append("|");

                // 包含手工检测对象列表（确保手工指定模式的目标变化时重新检测）
                if (_manualCollisionOverrideEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0)
                {
                    sb.Append("ManualTargets:");
                    foreach (var target in _manualCollisionTargets.OrderBy(t => t.DisplayName))
                    {
                        try
                        {
                            sb.Append(target.DisplayName);
                            sb.Append(",");
                        }
                        catch (Exception)
                        {
                            // 忽略无效对象
                        }
                    }
                    sb.Append("|");
                }

                // 包含路径边的摘要信息（区分不同的曲线化结果）
                if (route?.Edges != null)
                {
                    foreach (var edge in route.Edges)
                    {
                        sb.Append(edge.SegmentType.ToString());
                        sb.Append($"({edge.PhysicalLength:F2})");
                        if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null)
                        {
                            sb.Append($"_R{edge.Trajectory.ActualRadius:F2}");
                            sb.Append($"_A{edge.Trajectory.DeflectionAngle:F2}");
                        }
                        sb.Append(";");
                    }
                }

                // 计算哈希
                using (var md5 = System.Security.Cryptography.MD5.Create())
                {
                    var inputBytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
                    var hashBytes = md5.ComputeHash(inputBytes);
                    return BitConverter.ToString(hashBytes).Replace("-", "");
                }
            }
            catch (Exception ex)
            {
                LogManager.Warning($"计算动画配置哈希失败: {ex.Message}");
                return DateTime.Now.Ticks.ToString(); // 回退到时间戳
            }
        }

        /// <summary>
        /// 强制重新创建碰撞测试（清除指定配置的碰撞检测记录）
        /// </summary>
        public void ForceRecreateCollisionTest()
        {
            if (!string.IsNullOrEmpty(_currentAnimationHash))
            {
                _completedCollisionTests.Remove(_currentAnimationHash);
                LogManager.Info($"已清除动画配置 {_currentAnimationHash} 的碰撞检测记录，下次播放时将重新创建");
            }
        }

        /// <summary>
        /// 清除所有碰撞测试记录
        /// </summary>
        public static void ClearAllCollisionTestRecords()
        {
            _completedCollisionTests.Clear();
            LogManager.Info("已清除所有碰撞测试记录");
        }

        #endregion

        #region 碰撞排除列表缓存管理（从LogisticsAnimationManager迁移）

        /// <summary>
        /// 为动画对象预计算并缓存排除列表
        /// </summary>
        /// <param name="animationObject">动画对象</param>
        /// <returns>是否成功缓存</returns>
        public bool PrecomputeCollisionExclusions(ModelItem animationObject)
        {
            try
            {
                LogManager.Info($"[缓存管理] 开始为动画对象预计算排除列表: {animationObject?.DisplayName ?? "NULL"}");

                if (animationObject == null)
                {
                    LogManager.Warning("[缓存管理] 动画对象为空，清除缓存");
                    ClearExclusionCache();
                    return false;
                }

                // 检查是否需要重新计算
                if (IsCacheValid(animationObject))
                {
                    LogManager.Info($"[缓存管理] 缓存仍然有效，跳过重新计算");
                    return true;
                }

                var startTime = DateTime.Now;

                // 只构建特定于动画对象的逻辑排除列表
                LogManager.Info("[缓存管理] 构建逻辑排除列表...");
                var exclusionList = ModelItemAnalysisHelper.CollectRelatedNodes(animationObject);

                // 更新缓存
                _currentCachedAnimationObject = animationObject;
                _cachedExclusionList = exclusionList;
                _cacheCreatedTime = DateTime.Now;

                var elapsedMs = (DateTime.Now - startTime).TotalMilliseconds;
                LogManager.Info($"[缓存管理] 预计算完成，耗时 {elapsedMs:F1}ms，缓存 {exclusionList.Count} 个排除对象");

                return true;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[缓存管理] 预计算排除列表失败: {ex.Message}", ex);
                ClearExclusionCache();
                return false;
            }
        }

        /// <summary>
        /// 获取缓存的排除列表
        /// </summary>
        /// <param name="animationObject">动画对象</param>
        /// <returns>排除列表，如果缓存无效则返回null</returns>
        public List<ModelItem> GetCachedExclusionList(ModelItem animationObject)
        {
            try
            {
                if (!IsCacheValid(animationObject))
                {
                    LogManager.Debug($"[缓存管理] 缓存无效，建议重新预计算");
                    return null;
                }

                LogManager.Debug($"[缓存管理] 返回缓存的排除列表: {_cachedExclusionList?.Count ?? 0} 个对象");
                return _cachedExclusionList;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[缓存管理] 获取缓存失败: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 检查缓存是否有效
        /// </summary>
        /// <param name="animationObject">当前动画对象</param>
        /// <returns>缓存是否有效</returns>
        private bool IsCacheValid(ModelItem animationObject)
        {
            try
            {
                // 检查是否有缓存
                if (_currentCachedAnimationObject == null || _cachedExclusionList == null)
                {
                    return false;
                }

                // 检查对象是否相同
                if (!_currentCachedAnimationObject.Equals(animationObject))
                {
                    string cachedObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(_currentCachedAnimationObject);
                    string currentObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(animationObject);
                    LogManager.Debug($"[缓存验证] 动画对象已变更: '{cachedObjectName}' -> '{currentObjectName}'");
                    return false;
                }

                // 检查缓存时间是否过期
                if (DateTime.Now - _cacheCreatedTime > _cacheValidDuration)
                {
                    LogManager.Debug($"[缓存验证] 缓存已过期: {(DateTime.Now - _cacheCreatedTime).TotalMinutes:F1} 分钟");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[缓存验证] 验证过程异常: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 清除排除列表缓存
        /// </summary>
        public void ClearExclusionCache()
        {
            try
            {
                if (_currentCachedAnimationObject != null)
                {
                    try
                    {
                        // 安全访问DisplayName，防止WeakRef已释放的警告
                        string objectName = ModelItemAnalysisHelper.GetSafeDisplayName(_currentCachedAnimationObject);
                        LogManager.Debug($"[缓存管理] 清除缓存: {objectName}");
                    }
                    catch (Exception ex)
                    {
                        LogManager.Debug($"[缓存管理] 清除缓存时访问对象名称失败: {ex.Message}");
                    }
                }

                _currentCachedAnimationObject = null;
                _cachedExclusionList = null;
                _cacheCreatedTime = DateTime.MinValue;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[缓存管理] 清除缓存失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取缓存统计信息
        /// </summary>
        /// <returns>缓存统计信息</returns>
        public string GetCacheStats()
        {
            try
            {
                if (_currentCachedAnimationObject == null)
                {
                    return "缓存状态: 无缓存";
                }

                var age = DateTime.Now - _cacheCreatedTime;
                string objectName = ModelItemAnalysisHelper.GetSafeDisplayName(_currentCachedAnimationObject);
                var count = _cachedExclusionList?.Count ?? 0;

                return $"缓存状态: 对象='{objectName}', 排除数={count}, 年龄={age.TotalSeconds:F1}秒";
            }
            catch (Exception ex)
            {
                return $"缓存状态: 获取失败 - {ex.Message}";
            }
        }

        #endregion

        #endregion
    }
}