From cc8842dcd81d98d51a518b46a0218a47b5a15706 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 12 Sep 2025 22:44:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=8A=E5=8A=A8=E7=94=BB=E6=94=B9=E6=88=90?= =?UTF-8?q?=E6=AD=A5=E8=BF=9B=E5=BC=8F=EF=BC=8C=E5=9C=A8=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E7=94=9F=E6=88=90=E9=98=B6=E6=AE=B5=E8=BF=9B=E8=A1=8C=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E7=A2=B0=E6=92=9E=E8=AE=A1=E7=AE=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/working/2017/步进式动画方案.md | 368 +++++++++++++++ src/Core/Animation/PathAnimationManager.cs | 418 +++++++++++++++++- .../Collision/ClashDetectiveIntegration.cs | 220 +-------- src/Core/PathPlanningManager.cs | 154 +++---- src/Core/UIStateManager.cs | 2 - src/PathPlanning/AutoPathFinder.cs | 12 +- src/PathPlanning/PathOptimizer.cs | 70 +-- src/Utils/ModelItemAnalysisHelper.cs | 16 +- 8 files changed, 846 insertions(+), 414 deletions(-) create mode 100644 doc/working/2017/步进式动画方案.md diff --git a/doc/working/2017/步进式动画方案.md b/doc/working/2017/步进式动画方案.md new file mode 100644 index 0000000..1673e2e --- /dev/null +++ b/doc/working/2017/步进式动画方案.md @@ -0,0 +1,368 @@ +步进式动画系统完整方案 │ + │ │ + │ 核心架构 │ + │ │ + │ - 步进式播放:基于帧索引而非时间 │ + │ - 预计算碰撞:提前计算所有碰撞点 │ + │ - 逐帧控制:支持单帧前进/后退 │ + │ - 双向导航:可以在任意帧之间跳转 │ + │ │ + │ 实现方案 │ + │ │ + │ 1. 步进式动画数据结构 │ + │ │ + │ // 动画帧数据 │ + │ public class AnimationFrame │ + │ { │ + │ public int FrameIndex { get; set; } │ + │ public double Progress { get; set; } // 0-1之间的进度 │ + │ public Point3D Position { get; set; } // 该帧的位置 │ + │ public List Collisions { get; set; } // 该帧的碰撞信息 │ + │ public DateTime Timestamp { get; set; } // 帧时间戳(用于性能分析) │ + │ } │ + │ │ + │ public class CollisionInfo │ + │ { │ + │ public ModelItem CollidingObject { get; set; } │ + │ public Point3D CollidingPosition { get; set; } │ + │ public double Distance { get; set; } │ + │ } │ + │ │ + │ // 在PathAnimationManager中添加 │ + │ private List _animationFrames; // 所有动画帧 │ + │ private int _currentFrameIndex = 0; // 当前帧索引 │ + │ private int _totalFrames = 0; // 总帧数 │ + │ private double _frameStepSize = 0.01; // 帧步进大小(1%) │ + │ private bool _isSteppingMode = true; // 是否步进模式 │ + │ │ + │ 2. 预计算所有帧(SetupAnimation) │ + │ │ + │ public void SetupAnimation(ModelItem animatedObject, List pathPoints, double durationSeconds = 10.0) │ + │ { │ + │ // ... 现有验证代码 ... │ + │ │ + │ // 计算总帧数 │ + │ _totalFrames = (int)(1.0 / _frameStepSize); // 如0.01步进=100帧 │ + │ _animationFrames = new List(); │ + │ │ + │ LogManager.Info($"=== 开始预计算动画帧 ==="); │ + │ LogManager.Info($"总帧数: {_totalFrames}, 步进大小: {_frameStepSize:F3}"); │ + │ │ + │ PrecomputeAllFrames(); │ + │ │ + │ LogManager.Info($"=== 预计算完成 ==="); │ + │ LogManager.Info($"总帧数: {_animationFrames.Count}"); │ + │ LogManager.Info($"包含碰撞的帧: {_animationFrames.Count(f => f.Collisions.Count > 0)}"); │ + │ │ + │ // 移动到起点 │ + │ MoveToFrame(0); │ + │ } │ + │ │ + │ private void PrecomputeAllFrames() │ + │ { │ + │ var modelItems = new ModelItemCollection { _animatedObject }; │ + │ var originalPosition = _currentPosition; │ + │ │ + │ // 初始化碰撞检测 │ + │ ClashDetectiveIntegration.Instance.Initialize(); │ + │ │ + │ for (int i = 0; i <= _totalFrames; i++) │ + │ { │ + │ double progress = (double)i / _totalFrames; │ + │ var framePosition = InterpolatePosition(progress); │ + │ │ + │ // 临时移动到该帧位置 │ + │ MoveObjectToPosition(framePosition); │ + │ │ + │ // 执行碰撞检测 │ + │ var collisions = ClashDetectiveIntegration.Instance.DetectCollisions( │ + │ _animatedObject, null, _detectionGap); │ + │ │ + │ // 创建帧数据 │ + │ var frame = new AnimationFrame │ + │ { │ + │ FrameIndex = i, │ + │ Progress = progress, │ + │ Position = framePosition, │ + │ Collisions = new List(), │ + │ Timestamp = DateTime.Now │ + │ }; │ + │ │ + │ // 记录碰撞信息 │ + │ foreach (var collision in collisions) │ + │ { │ + │ frame.Collisions.Add(new CollisionInfo │ + │ { │ + │ CollidingObject = collision.Item2, │ + │ CollidingPosition = GetObjectPosition(collision.Item2), │ + │ Distance = collision.Distance │ + │ }); │ + │ } │ + │ │ + │ _animationFrames.Add(frame); │ + │ │ + │ // 进度报告 │ + │ if (i % 10 == 0) │ + │ { │ + │ LogManager.Info($"预计算进度: {i}/{_totalFrames} ({progress*100:F1}%)"); │ + │ } │ + │ } │ + │ │ + │ // 恢复原始位置 │ + │ MoveObjectToPosition(originalPosition); │ + │ } │ + │ │ + │ 3. 步进式播放控制 │ + │ │ + │ // 播放模式枚举 │ + │ public enum PlaybackMode │ + │ { │ + │ Continuous, // 连续播放 │ + │ StepByStep, // 逐帧步进 │ + │ Manual // 手动控制 │ + │ } │ + │ │ + │ private PlaybackMode _playbackMode = PlaybackMode.StepByStep; │ + │ │ + │ // 修改OnApplicationIdle - 支持步进模式 │ + │ private void OnApplicationIdle(object sender, EventArgs e) │ + │ { │ + │ if (_currentState != AnimationState.Playing) │ + │ return; │ + │ │ + │ // 帧率控制 │ + │ var now = DateTime.Now; │ + │ var elapsed = (now - _lastFrameTime).TotalMilliseconds; │ + │ │ + │ if (elapsed < _frameInterval) │ + │ return; │ + │ │ + │ // 根据播放模式执行 │ + │ switch (_playbackMode) │ + │ { │ + │ case PlaybackMode.Continuous: │ + │ // 自动步进到下一帧 │ + │ if (_currentFrameIndex < _totalFrames) │ + │ { │ + │ MoveToFrame(_currentFrameIndex + 1); │ + │ _lastFrameTime = now; │ + │ } │ + │ else │ + │ { │ + │ FinishAnimation(); │ + │ } │ + │ break; │ + │ │ + │ case PlaybackMode.StepByStep: │ + │ // 等待用户触发下一帧 │ + │ // 不自动前进 │ + │ break; │ + │ │ + │ case PlaybackMode.Manual: │ + │ // 完全手动控制 │ + │ break; │ + │ } │ + │ } │ + │ │ + │ 4. 帧导航方法 │ + │ │ + │ // 移动到指定帧 │ + │ public void MoveToFrame(int frameIndex) │ + │ { │ + │ if (frameIndex < 0 || frameIndex >= _animationFrames.Count) │ + │ { │ + │ LogManager.Warning($"帧索引 {frameIndex} 超出范围 [0, {_animationFrames.Count-1}]"); │ + │ return; │ + │ } │ + │ │ + │ var frame = _animationFrames[frameIndex]; │ + │ _currentFrameIndex = frameIndex; │ + │ │ + │ // 更新位置 │ + │ UpdateObjectPosition(frame.Position); │ + │ _currentPosition = frame.Position; │ + │ │ + │ // 更新碰撞高亮 │ + │ HighlightFrameCollisions(frame); │ + │ │ + │ // 触发进度事件 │ + │ ProgressChanged?.Invoke(this, frame.Progress * 100); │ + │ │ + │ // 更新TimeLiner │ + │ if (_timeLinerManager != null && !string.IsNullOrEmpty(_currentTaskId)) │ + │ { │ + │ _timeLinerManager.UpdateTaskProgress(_currentTaskId, frame.Progress, _currentState); │ + │ } │ + │ │ + │ LogManager.Debug($"移动到帧 {frameIndex}/{_totalFrames} (进度: {frame.Progress*100:F1}%)"); │ + │ } │ + │ │ + │ // 前进一帧 │ + │ public void StepForward() │ + │ { │ + │ if (_currentFrameIndex < _totalFrames - 1) │ + │ { │ + │ MoveToFrame(_currentFrameIndex + 1); │ + │ } │ + │ else │ + │ { │ + │ LogManager.Info("已到达最后一帧"); │ + │ } │ + │ } │ + │ │ + │ // 后退一帧 │ + │ public void StepBackward() │ + │ { │ + │ if (_currentFrameIndex > 0) │ + │ { │ + │ MoveToFrame(_currentFrameIndex - 1); │ + │ } │ + │ else │ + │ { │ + │ LogManager.Info("已到达第一帧"); │ + │ } │ + │ } │ + │ │ + │ // 跳转到指定进度 │ + │ public void JumpToProgress(double progress) │ + │ { │ + │ int targetFrame = (int)(progress * _totalFrames); │ + │ MoveToFrame(targetFrame); │ + │ } │ + │ │ + │ // 快进/快退 │ + │ public void FastForward(int frames = 10) │ + │ { │ + │ int targetFrame = Math.Min(_currentFrameIndex + frames, _totalFrames - 1); │ + │ MoveToFrame(targetFrame); │ + │ } │ + │ │ + │ public void FastBackward(int frames = 10) │ + │ { │ + │ int targetFrame = Math.Max(_currentFrameIndex - frames, 0); │ + │ MoveToFrame(targetFrame); │ + │ } │ + │ │ + │ 5. 碰撞高亮管理 │ + │ │ + │ private HashSet _currentHighlightedItems = new HashSet(); │ + │ │ + │ private void HighlightFrameCollisions(AnimationFrame frame) │ + │ { │ + │ var newHighlights = new HashSet(frame.Collisions.Select(c => c.CollidingObject)); │ + │ │ + │ // 只在高亮集合变化时更新 │ + │ if (!newHighlights.SetEquals(_currentHighlightedItems)) │ + │ { │ + │ // 清除旧高亮 │ + │ if (_currentHighlightedItems.Count > 0) │ + │ { │ + │ ClashDetectiveIntegration.Instance.ClearHighlight(); │ + │ } │ + │ │ + │ // 应用新高亮 │ + │ if (newHighlights.Count > 0) │ + │ { │ + │ var collisionResults = frame.Collisions.Select(c => new CollisionResult │ + │ { │ + │ Item1 = _animatedObject, │ + │ Item2 = c.CollidingObject, │ + │ Distance = c.Distance │ + │ }).ToList(); │ + │ │ + │ ClashDetectiveIntegration.Instance.HighlightCollisions(collisionResults); │ + │ } │ + │ │ + │ _currentHighlightedItems = newHighlights; │ + │ │ + │ if (frame.Collisions.Count > 0) │ + │ { │ + │ LogManager.Info($"帧 {frame.FrameIndex}: 高亮 {frame.Collisions.Count} 个碰撞"); │ + │ } │ + │ } │ + │ } │ + │ │ + │ 6. 播放控制API │ + │ │ + │ // 开始连续播放 │ + │ public void Play() │ + │ { │ + │ _playbackMode = PlaybackMode.Continuous; │ + │ SetState(AnimationState.Playing); │ + │ NavisApplication.Idle += OnApplicationIdle; │ + │ } │ + │ │ + │ // 暂停(保持当前帧) │ + │ public void Pause() │ + │ { │ + │ _playbackMode = PlaybackMode.StepByStep; │ + │ SetState(AnimationState.Paused); │ + │ } │ + │ │ + │ // 设置播放速度(通过调整帧间隔) │ + │ public void SetPlaybackSpeed(double speed) │ + │ { │ + │ _frameInterval = (1000.0 / _animationFrameRate) / speed; │ + │ LogManager.Info($"播放速度设置为 {speed}x"); │ + │ } │ + │ │ + │ // 获取当前帧信息 │ + │ public AnimationFrame GetCurrentFrame() │ + │ { │ + │ if (_currentFrameIndex >= 0 && _currentFrameIndex < _animationFrames.Count) │ + │ return _animationFrames[_currentFrameIndex]; │ + │ return null; │ + │ } │ + │ │ + │ // 获取帧统计信息 │ + │ public string GetFrameStatistics() │ + │ { │ + │ var current = GetCurrentFrame(); │ + │ if (current != null) │ + │ { │ + │ return $"帧 {_currentFrameIndex}/{_totalFrames} | " + │ + │ $"进度 {current.Progress*100:F1}% | " + │ + │ $"碰撞 {current.Collisions.Count}"; │ + │ } │ + │ return "无帧数据"; │ + │ } │ + │ │ + │ 7. UI集成建议 │ + │ │ + │ // 动画控制面板应添加的控件 │ + │ public class AnimationControlPanel │ + │ { │ + │ // 播放控制 │ + │ Button PlayButton; // 连续播放 │ + │ Button PauseButton; // 暂停 │ + │ Button StepForwardButton; // 前进一帧 │ + │ Button StepBackButton; // 后退一帧 │ + │ Button FastForwardButton; // 快进10帧 │ + │ Button FastRewindButton; // 快退10帧 │ + │ │ + │ // 进度控制 │ + │ Slider ProgressSlider; // 进度条(可拖动跳转) │ + │ Label FrameLabel; // 当前帧信息 │ + │ Label CollisionLabel; // 碰撞信息 │ + │ │ + │ // 速度控制 │ + │ Slider SpeedSlider; // 播放速度(0.1x - 5x) │ + │ ComboBox PlayModeCombo; // 播放模式选择 │ + │ } │ + │ │ + │ 优势 │ + │ │ + │ 1. 完全可控:每一帧都可以精确控制 │ + │ 2. 双向导航:支持前进和后退 │ + │ 3. 性能优秀:预计算避免实时检测 │ + │ 4. 调试友好:可以逐帧分析碰撞 │ + │ 5. 灵活播放:支持多种播放模式 │ + │ │ + │ 实施步骤 │ + │ │ + │ 1. 添加AnimationFrame数据结构 │ + │ 2. 实现预计算所有帧逻辑 │ + │ 3. 改造播放控制为步进式 │ + │ 4. 实现帧导航方法 │ + │ 5. 更新UI添加步进控制 │ + │ 6. 测试各种播放模式 \ No newline at end of file diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index a79eaef..f65518c 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Autodesk.Navisworks.Api; using NavisApplication = Autodesk.Navisworks.Api.Application; @@ -24,16 +25,37 @@ namespace NavisworksTransport.Core.Animation /// 注意:由于Navisworks API限制,无法直接使用Animator API,因此使用OverridePermanentTransform实现动画 /// 已集成 TimeLiner 功能,支持在 TimeLiner 中显示和管理动画任务 /// + /// + /// 动画帧数据(包含位置和碰撞信息) + /// + public class AnimationFrame + { + public int Index { get; set; } // 帧索引 + public double Progress { get; set; } // 进度(0-1) + public Point3D Position { get; set; } // 该帧的位置 + public List Collisions { get; set; } // 该帧的碰撞结果 + public bool HasCollision => Collisions?.Count > 0; + + public AnimationFrame() + { + Collisions = new List(); + } + } + public class PathAnimationManager { private static PathAnimationManager _instance; private ModelItem _animatedObject; private List _pathPoints; + // === 预计算动画系统 === + private List _animationFrames; // 所有帧数据 + private int _currentFrameIndex = 0; // 当前帧索引 + private HashSet _currentHighlightedItems; // 当前高亮的对象 + // === Idle事件动画系统 === private double _frameInterval; // 帧间隔(毫秒) private DateTime _lastFrameTime = DateTime.MinValue; // 上一帧时间 - private int _collisionCheckCounter = 0; // 碰撞检测计数器(用于降频) // === 动画参数 === private double _animationDuration = 10.0; // 动画总时长(秒) @@ -81,6 +103,8 @@ namespace NavisworksTransport.Core.Animation public PathAnimationManager() { _pathPoints = new List(); + _animationFrames = new List(); + _currentHighlightedItems = new HashSet(); // 初始化动画模式 _frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔 @@ -173,6 +197,9 @@ namespace NavisworksTransport.Core.Animation var originalBoundingBox = animatedObject.BoundingBox(); _originalCenter = originalBoundingBox.Center; + // 预计算动画帧和碰撞 + PrecomputeAnimationFrames(); + // 关键修复:将车辆立即移动到路径起点 // 这样动画就从路径起点开始,而不是从车辆当前位置开始 MoveVehicleToPathStart(); @@ -247,6 +274,240 @@ namespace NavisworksTransport.Core.Animation } } + /// + /// 预计算所有动画帧和碰撞信息 + /// + private void PrecomputeAnimationFrames() + { + try + { + // 基于动画时长和帧率计算总帧数 + int totalFrames = (int)(_animationDuration * _animationFrameRate); + + // 反向计算检测精度(确保每帧都检测) + var totalDistance = CalculateTotalPathDistance(); + _collisionDetectionAccuracy = totalDistance / totalFrames; + + LogManager.Info($"=== 预计算动画帧 ==="); + LogManager.Info($"动画时长: {_animationDuration}秒"); + LogManager.Info($"动画帧率: {_animationFrameRate} FPS"); + LogManager.Info($"总帧数: {totalFrames}"); + LogManager.Info($"路径总长: {totalDistance:F2}米"); + LogManager.Info($"检测精度: {_collisionDetectionAccuracy:F3}米/帧"); + + // 初始化帧列表 + _animationFrames = new List(); + _currentHighlightedItems = new HashSet(); + _currentFrameIndex = 0; + + // 初始化碰撞检测系统 + ClashDetectiveIntegration.Instance.Initialize(); + + // 获取动画对象的包围盒信息 + 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 + ); + + // 获取场景中所有可能碰撞的对象 + var potentialColliders = GetPotentialColliders(); + LogManager.Info($"潜在碰撞对象数: {potentialColliders.Count}"); + + // 预计算每一帧 + for (int i = 0; i <= totalFrames; i++) + { + double progress = (double)i / totalFrames; + var framePosition = InterpolatePosition(progress); + + // 创建帧数据 + var frame = new AnimationFrame + { + Index = i, + Progress = progress, + Position = framePosition, + Collisions = new List() + }; + + // 虚拟碰撞检测(不移动实际物体) + var virtualBoundingBox = CreateVirtualBoundingBox(framePosition, boundingBoxSize); + + // 检测与所有潜在对象的碰撞 + foreach (var collider in potentialColliders) + { + var colliderBox = collider.BoundingBox(); + + // 使用包围盒检测 + if (BoundingBoxesIntersectWithGap(virtualBoundingBox, colliderBox, _detectionGap)) + { + frame.Collisions.Add(new CollisionResult + { + Item1 = _animatedObject, + Item2 = collider, + Distance = CalculateBoundingBoxDistance(virtualBoundingBox, colliderBox) + }); + } + } + + _animationFrames.Add(frame); + + // 进度报告 + if (i % 30 == 0) // 每秒报告一次(30fps) + { + LogManager.Info($"预计算进度: 帧 {i}/{totalFrames} ({progress*100:F1}%)"); + if (frame.HasCollision) + { + LogManager.Debug($" 帧 {i} 检测到 {frame.Collisions.Count} 个碰撞"); + } + } + } + + // 统计碰撞信息 + 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}"); + } + catch (Exception ex) + { + LogManager.Error($"预计算动画帧失败: {ex.Message}"); + // 如果预计算失败,创建空帧列表以避免崩溃 + _animationFrames = new List(); + } + } + + /// + /// 获取潜在碰撞对象列表 + /// + private List GetPotentialColliders() + { + try + { + LogManager.Info("开始获取潜在碰撞对象"); + + // 确保ClashDetectiveIntegration已初始化并构建了通道缓存 + ClashDetectiveIntegration.Instance.Initialize(); + ClashDetectiveIntegration.Instance.BuildChannelObjectsCache(); + ClashDetectiveIntegration.BuildAllGeometryItemsCache(); + + // 获取所有有几何体的对象 + var allItems = Application.ActiveDocument.Models.RootItemDescendantsAndSelf + .Where(item => item.HasGeometry) + .ToList(); + + // 构建排除列表:动画对象本身及其子对象 + var excludeList = new ModelItemCollection(); + excludeList.AddRange(_animatedObject.DescendantsAndSelf); + + // 使用ClashDetectiveIntegration的碰撞检测方法,它会自动排除通道对象 + // 创建一个较大的检测间隙来获取路径范围内所有潜在碰撞对象 + var detectionGap = 100.0; // 100米范围内的对象都视为潜在碰撞对象 + + // 调用ClashDetectiveIntegration的DetectCollisions方法 + // 该方法内部会自动排除通道对象(通过IsChannelObject方法) + var collisionResults = ClashDetectiveIntegration.Instance.DetectCollisions( + _animatedObject, + excludeList, + detectionGap + ); + + // 从碰撞结果中提取唯一的碰撞对象 + var potentialColliders = new HashSet(); + foreach (var result in collisionResults) + { + if (result.Item2 != null && !potentialColliders.Contains(result.Item2)) + { + potentialColliders.Add(result.Item2); + } + } + + var finalList = potentialColliders.ToList(); + + LogManager.Info($"获取潜在碰撞对象完成: 总对象={allItems.Count}, " + + $"排除自身及子对象={excludeList.Count}, " + + $"检测范围内潜在碰撞对象={finalList.Count}(已自动排除通道)"); + + return finalList; + } + catch (Exception ex) + { + LogManager.Error($"获取潜在碰撞对象失败: {ex.Message}"); + return new List(); + } + } + + /// + /// 计算路径的包围盒 + /// + private BoundingBox3D CalculatePathBounds() + { + if (_pathPoints == null || _pathPoints.Count == 0) + return new BoundingBox3D(); + + var minX = _pathPoints.Min(p => p.X); + var minY = _pathPoints.Min(p => p.Y); + var minZ = _pathPoints.Min(p => p.Z); + var maxX = _pathPoints.Max(p => p.X); + var maxY = _pathPoints.Max(p => p.Y); + var maxZ = _pathPoints.Max(p => p.Z); + + return new BoundingBox3D( + new Point3D(minX, minY, minZ), + new Point3D(maxX, maxY, maxZ) + ); + } + + /// + /// 创建虚拟包围盒(用于碰撞检测) + /// + private BoundingBox3D CreateVirtualBoundingBox(Point3D position, Vector3D size) + { + return new BoundingBox3D( + new Point3D( + position.X - size.X / 2, + position.Y - size.Y / 2, + position.Z + ), + new Point3D( + position.X + size.X / 2, + position.Y + size.Y / 2, + position.Z + size.Z + ) + ); + } + + /// + /// 包围盒碰撞检测(带间隙) + /// + private bool BoundingBoxesIntersectWithGap(BoundingBox3D box1, BoundingBox3D box2, double gap) + { + return !(box1.Max.X + gap < box2.Min.X || box2.Max.X + gap < box1.Min.X || + box1.Max.Y + gap < box2.Min.Y || box2.Max.Y + gap < box1.Min.Y || + box1.Max.Z + gap < box2.Min.Z || box2.Max.Z + gap < box1.Min.Z); + } + + /// + /// 计算包围盒中心距离 + /// + private double CalculateBoundingBoxDistance(BoundingBox3D box1, BoundingBox3D box2) + { + var center1 = new Point3D( + (box1.Min.X + box1.Max.X) / 2, + (box1.Min.Y + box1.Max.Y) / 2, + (box1.Min.Z + box1.Max.Z) / 2 + ); + var center2 = new Point3D( + (box2.Min.X + box2.Max.X) / 2, + (box2.Min.Y + box2.Max.Y) / 2, + (box2.Min.Z + box2.Max.Z) / 2 + ); + + return CalculateDistance(center1, center2); + } + /// /// 开始播放动画 /// @@ -309,7 +570,6 @@ namespace NavisworksTransport.Core.Animation // 重置Idle模式状态 _lastFrameTime = DateTime.MinValue; - _collisionCheckCounter = 0; _fpsFrameCount = 0; _fpsCounterStart = DateTime.Now; _frameInterval = 1000.0 / _animationFrameRate; @@ -345,8 +605,41 @@ namespace NavisworksTransport.Core.Animation NavisApplication.Idle -= OnApplicationIdle; LogManager.Debug("[Idle模式] Idle事件已注销"); + // 收集整个路径上的所有碰撞对象 + var allCollisionResults = new List(); + var uniqueCollidedItems = new HashSet(); + + 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); + } + } + } + } + + // 高亮显示所有碰撞过的对象 + if (allCollisionResults.Count > 0) + { + ClashDetectiveIntegration.Instance.HighlightCollisions(allCollisionResults); + LogManager.Info($"动画停止,高亮显示路径上的 {uniqueCollidedItems.Count} 个碰撞对象"); + } + else + { + ClashDetectiveIntegration.Instance.ClearHighlights(); + LogManager.Info("动画停止,路径上无碰撞对象"); + } + SetState(AnimationState.Stopped); _pausedProgress = 0.0; // 重置暂停进度 + _currentFrameIndex = 0; // 重置帧索引 LogManager.Info("动画已停止"); // 动画停止时不创建碰撞测试汇总,由动画完成事件统一处理 @@ -377,6 +670,38 @@ namespace NavisworksTransport.Core.Animation // 重置暂停进度 _pausedProgress = 0.0; + // 收集整个路径上的所有碰撞对象 + var allCollisionResults = new List(); + var uniqueCollidedItems = new HashSet(); + + 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); + } + } + } + } + + // 高亮显示所有碰撞过的对象 + if (allCollisionResults.Count > 0) + { + ClashDetectiveIntegration.Instance.HighlightCollisions(allCollisionResults); + LogManager.Info($"动画完成,高亮显示路径上的 {uniqueCollidedItems.Count} 个碰撞对象"); + } + else + { + ClashDetectiveIntegration.Instance.ClearHighlights(); + LogManager.Info("动画完成,路径上无碰撞对象"); + } + // 直接设置为完成状态,避免中间状态切换 SetState(AnimationState.Finished); @@ -1274,6 +1599,60 @@ namespace NavisworksTransport.Core.Animation /// /// Idle事件处理器 - 新的动画核心 /// + /// + /// 根据当前帧索引更新碰撞高亮 + /// + private void UpdateCollisionHighlightFromFrame() + { + try + { + // 确保帧索引有效 + if (_currentFrameIndex < 0 || _currentFrameIndex >= _animationFrames.Count) + { + return; + } + + // 获取当前帧数据 + var currentFrame = _animationFrames[_currentFrameIndex]; + + // 使用ClashDetectiveIntegration的高亮方法 + if (currentFrame.HasCollision) + { + // 高亮当前帧的碰撞对象 + ClashDetectiveIntegration.Instance.HighlightCollisions(currentFrame.Collisions); + + // 缓存碰撞结果用于动画结束后的处理 + var animatedObjectPosition = currentFrame.Position; + foreach (var collision in currentFrame.Collisions) + { + var collisionObjectPosition = GetObjectPosition(collision.Item2); + ClashDetectiveIntegration.Instance.CacheCollisionDuringAnimation( + _animatedObject, + animatedObjectPosition, + collision.Item2, + collisionObjectPosition + ); + } + + LogManager.Debug($"帧 {_currentFrameIndex}: 检测到 {currentFrame.Collisions.Count} 个碰撞"); + + // 触发碰撞事件 + var eventArgs = new CollisionDetectedEventArgs(currentFrame.Collisions); + OnCollisionDetected(eventArgs); + } + else + { + // 清除高亮(没有碰撞时) + ClashDetectiveIntegration.Instance.ClearHighlights(); + LogManager.Debug($"帧 {_currentFrameIndex}: 无碰撞"); + } + } + catch (Exception ex) + { + LogManager.Error($"更新碰撞高亮失败: {ex.Message}"); + } + } + private void OnApplicationIdle(object sender, EventArgs e) { try @@ -1305,9 +1684,27 @@ namespace NavisworksTransport.Core.Animation var totalElapsed = (now - _animationStartTime).TotalSeconds; var progress = Math.Min(totalElapsed / _animationDuration, 1.0); - // 更新动画位置(使用原有逻辑) - Point3D newPosition = InterpolatePosition(progress); - UpdateObjectPosition(newPosition); + // 根据进度计算当前帧索引 + int targetFrameIndex = (int)(progress * (_animationFrames.Count - 1)); + targetFrameIndex = Math.Min(targetFrameIndex, _animationFrames.Count - 1); + + // 如果帧索引发生变化,更新位置和碰撞高亮 + if (targetFrameIndex != _currentFrameIndex || _currentFrameIndex == 0) + { + _currentFrameIndex = targetFrameIndex; + + // 使用预计算的帧位置 + if (_currentFrameIndex < _animationFrames.Count) + { + var frameData = _animationFrames[_currentFrameIndex]; + UpdateObjectPosition(frameData.Position); + + // 更新碰撞高亮(基于预计算结果) + UpdateCollisionHighlightFromFrame(); + + LogManager.Debug($"帧 {_currentFrameIndex}/{_animationFrames.Count-1}, 进度: {progress*100:F1}%, 位置: ({frameData.Position.X:F2},{frameData.Position.Y:F2},{frameData.Position.Z:F2})"); + } + } // 触发进度事件 var progressPercent = progress * 100; @@ -1319,17 +1716,6 @@ namespace NavisworksTransport.Core.Animation _timeLinerManager.UpdateTaskProgress(_currentTaskId, progress, _currentState); } - // 碰撞检测(降频执行,每3帧检测一次) - _collisionCheckCounter++; - if (_collisionCheckCounter >= 3) - { - _collisionCheckCounter = 0; - if (_currentState == AnimationState.Playing) - { - CheckAndHighlightCollisionsWithClashDetective(); - } - } - // 记录帧时间 _lastFrameTime = now; _animationFrameCount++; diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index 95a1034..66275ad 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -106,40 +106,6 @@ namespace NavisworksTransport } - - /// - /// 执行动态碰撞检测 - /// - /// 动画对象 - /// 排除对象 - /// 检测间隙(米) - /// 碰撞结果 - public List DetectCollisions(ModelItem animatedObject, - ModelItemCollection excludeObjects = null, double detectionGap = 0.2) - { - try - { - // 使用简化检测模式 - LogManager.Debug($"使用简化检测模式进行碰撞检测,检测间隙: {detectionGap}米"); - var results = DetectCollisionsSimple(animatedObject, excludeObjects, detectionGap); - - // 在动画过程中不创建Clash Detective测试,避免影响性能 - // 只有在动画结束后手动测试时才创建完整的测试 - - // 触发事件 - OnCollisionDetected(new CollisionDetectedEventArgs(results)); - - LogManager.Debug($"碰撞检测完成,发现 {results.Count} 个碰撞"); - return results; - } - catch (Exception ex) - { - LogManager.Error($"碰撞检测失败: {ex.Message}"); - // 回退到简化检测 - return DetectCollisionsSimple(animatedObject, excludeObjects, detectionGap); - } - } - /// /// 创建碰撞快照(动画结束后一次性更新结果) /// @@ -187,34 +153,6 @@ namespace NavisworksTransport { try { - // 🔍 添加碰撞缓存开始的详细日志 - LogManager.Debug($"=== [碰撞缓存-开始] ==="); - LogManager.Debug($"[碰撞缓存-开始] 动画对象: {animatedObject?.DisplayName ?? "NULL"}"); - LogManager.Debug($"[碰撞缓存-开始] 碰撞对象: {collisionObject?.DisplayName ?? "NULL"}"); - - // 🔍 对象验证详情 - if (animatedObject == null) - { - LogManager.Error($"[碰撞缓存-错误] 动画对象为NULL!"); - } - - if (collisionObject == null) - { - LogManager.Error($"[碰撞缓存-错误] 碰撞对象为NULL!"); - } - - // 🔍 位置信息详情 - LogManager.Debug($"[碰撞缓存-位置] 动画对象位置: ({animatedObjectPosition.X:F3},{animatedObjectPosition.Y:F3},{animatedObjectPosition.Z:F3})"); - - if (collisionObjectPosition != null) - { - LogManager.Debug($"[碰撞缓存-位置] 碰撞对象位置: ({collisionObjectPosition.X:F3},{collisionObjectPosition.Y:F3},{collisionObjectPosition.Z:F3})"); - } - else - { - LogManager.Debug($"[碰撞缓存-位置] 碰撞对象位置: NULL (将自动计算)"); - } - if (!IsModelItemValid(animatedObject) || !IsModelItemValid(collisionObject)) { LogManager.Warning($"[诊断-无效对象] 对象验证失败,退出缓存过程"); @@ -229,43 +167,19 @@ namespace NavisworksTransport bool hasMapping1 = !mappedAnimatedObject.Equals(animatedObject); bool hasMapping2 = !mappedCollisionObject.Equals(collisionObject); - LogManager.Info($"[容器映射] 动画对象: '{animatedObject.DisplayName}' -> '{mappedAnimatedObject.DisplayName}' (映射: {hasMapping1})"); - LogManager.Info($"[容器映射] 碰撞对象: '{collisionObject.DisplayName}' -> '{mappedCollisionObject.DisplayName}' (映射: {hasMapping2})"); - // 使用包围盒碰撞检测算法 var animatedBoundingBox = animatedObject.BoundingBox(); var collisionBoundingBox = collisionObject.BoundingBox(); - - LogManager.Debug($"[碰撞缓存-包围盒] 动画对象包围盒: Min({animatedBoundingBox.Min.X:F3},{animatedBoundingBox.Min.Y:F3},{animatedBoundingBox.Min.Z:F3}) Max({animatedBoundingBox.Max.X:F3},{animatedBoundingBox.Max.Y:F3},{animatedBoundingBox.Max.Z:F3})"); - LogManager.Debug($"[碰撞缓存-包围盒] 碰撞对象包围盒: Min({collisionBoundingBox.Min.X:F3},{collisionBoundingBox.Min.Y:F3},{collisionBoundingBox.Min.Z:F3}) Max({collisionBoundingBox.Max.X:F3},{collisionBoundingBox.Max.Y:F3},{collisionBoundingBox.Max.Z:F3})"); - + if (BoundingBoxGeometryUtils.BoundingBoxesIntersect(animatedBoundingBox, collisionBoundingBox)) { // 🔍 计算并验证位置信息 var finalCollisionPosition = collisionObjectPosition ?? GetObjectPosition(collisionObject); - - LogManager.Debug($"[碰撞缓存-位置计算] 最终使用的碰撞对象位置: ({finalCollisionPosition.X:F3},{finalCollisionPosition.Y:F3},{finalCollisionPosition.Z:F3})"); - - // 🔍 检查位置是否相同(可能的自碰撞标志) - var positionDistance = Math.Sqrt( - Math.Pow(animatedObjectPosition.X - finalCollisionPosition.X, 2) + - Math.Pow(animatedObjectPosition.Y - finalCollisionPosition.Y, 2) + - Math.Pow(animatedObjectPosition.Z - finalCollisionPosition.Z, 2)); - - LogManager.Debug($"[碰撞缓存-距离计算] 动画对象与碰撞对象的位置距离: {positionDistance:F4}"); - - if (positionDistance < 0.001) // 位置基本相同 - { - LogManager.Warning($"[诊断-位置警告] 两个对象位置几乎相同 (距离: {positionDistance:F6}),这可能是自碰撞的标志!"); - } - + // 创建碰撞结果 var collisionDistance = BoundingBoxGeometryUtils.CalculateDistance(animatedBoundingBox, collisionBoundingBox); var collisionCenter = BoundingBoxGeometryUtils.CalculateCenter(animatedBoundingBox, collisionBoundingBox); - - LogManager.Debug($"[碰撞缓存-距离] 包围盒碰撞距离: {collisionDistance:F4}"); - LogManager.Debug($"[碰撞缓存-中心点] 碰撞中心: ({collisionCenter.X:F3},{collisionCenter.Y:F3},{collisionCenter.Z:F3})"); - + var collision = new CollisionResult { ClashGuid = Guid.NewGuid(), @@ -293,10 +207,6 @@ namespace NavisworksTransport _cachedResults.Add(collision); } } - else - { - LogManager.Debug($"[碰撞缓存-包围盒] 包围盒不相交,跳过缓存"); - } } catch (Exception ex) { @@ -341,7 +251,7 @@ namespace NavisworksTransport { LogManager.Info($"=== 动画结束,开始创建ClashDetective碰撞测试(容差: {detectionGap}米) ==="); - // 🔧 修复:在处理前记录动画过程中的碰撞数量 + // 在处理前记录动画过程中的碰撞数量 _animationCollisionCount = _cachedResults.Count; LogManager.Info($"记录动画过程碰撞数量: {_animationCollisionCount}"); @@ -352,34 +262,6 @@ namespace NavisworksTransport } LogManager.Info($"[缓存分析-统计] 共有 {_cachedResults.Count} 个原始缓存结果"); - - // 🔍 详细分析每个缓存项 - LogManager.Info($"[缓存分析-原始] 开始分析所有原始缓存结果:"); - for (int i = 0; i < _cachedResults.Count; i++) - { - var item = _cachedResults[i]; - LogManager.Info($"[缓存分析-{i+1:00}] 对象: {item.Item1?.DisplayName ?? "NULL"} <-> {item.Item2?.DisplayName ?? "NULL"}"); - LogManager.Info($"[缓存分析-{i+1:00}] 时间: {item.CreatedTime:HH:mm:ss.fff}"); - LogManager.Info($"[缓存分析-{i+1:00}] 动画位置: ({item.Item1Position.X:F3},{item.Item1Position.Y:F3},{item.Item1Position.Z:F3})"); - LogManager.Info($"[缓存分析-{i+1:00}] 碰撞位置: ({item.Item2Position.X:F3},{item.Item2Position.Y:F3},{item.Item2Position.Z:F3})"); - LogManager.Info($"[缓存分析-{i+1:00}] 距离: {item.Distance:F4}"); - LogManager.Info($"[缓存分析-{i+1:00}] GUID: {item.ClashGuid}"); - LogManager.Info($"[缓存分析-{i+1:00}] HasPositionInfo: {item.HasPositionInfo}"); - - // 验证对象有效性 - var item1Valid = IsModelItemValid(item.Item1); - var item2Valid = IsModelItemValid(item.Item2); - LogManager.Info($"[缓存分析-{i+1:00}] 对象有效性: Item1={item1Valid}, Item2={item2Valid}"); - - if (!item1Valid) - { - LogManager.Warning($"[缓存分析-{i+1:00}] Item1无效: {item.Item1?.DisplayName ?? "NULL"}"); - } - if (!item2Valid) - { - LogManager.Warning($"[缓存分析-{i+1:00}] Item2无效: {item.Item2?.DisplayName ?? "NULL"}"); - } - } // 获取动画对象和当前动画终点位置(用于后续恢复) ModelItem animatedObject = null; @@ -419,38 +301,8 @@ namespace NavisworksTransport LogManager.Info($"[去重分析-结果] 去重后得到 {uniqueCollisions.Count} 个唯一碰撞对"); LogManager.Info($"[去重分析-效率] 去重前: {_cachedResults.Count}, 去重后: {uniqueCollisions.Count}, 压缩率: {(1.0 - (double)uniqueCollisions.Count / _cachedResults.Count) * 100:F1}%"); - - // 🔍 分析每个唯一碰撞对的详情 - for (int i = 0; i < uniqueCollisions.Count; i++) - { - var group = uniqueCollisions[i]; - LogManager.Info($"[去重分析-唯一{i+1:00}] 碰撞对: {group.Collision.Item1?.DisplayName ?? "NULL"} <-> {group.Collision.Item2?.DisplayName ?? "NULL"}"); - LogManager.Info($"[去重分析-唯一{i+1:00}] 重复次数: {group.Count}"); - LogManager.Info($"[去重分析-唯一{i+1:00}] 时间范围: {group.FirstTime:HH:mm:ss.fff} ~ {group.LastTime:HH:mm:ss.fff}"); - LogManager.Info($"[去重分析-唯一{i+1:00}] 选择记录: 时间={group.Collision.CreatedTime:HH:mm:ss.fff}, 距离={group.Collision.Distance:F4}"); - - // 如果有重复,分析所有重复项 - if (group.Count > 1) - { - LogManager.Info($"[去重分析-唯一{i+1:00}] 重复项详情:"); - for (int j = 0; j < group.AllItems.Count; j++) - { - var dupItem = group.AllItems[j]; - LogManager.Info($" [{j+1}] 时间: {dupItem.CreatedTime:HH:mm:ss.fff}, 距离: {dupItem.Distance:F4}, GUID: {dupItem.ClashGuid}"); - } - } - - // 验证去重键的具体值 - var key1Name = group.Collision.Item1?.DisplayName ?? "NULL"; - var key2Name = group.Collision.Item2?.DisplayName ?? "NULL"; - var key1Guid = group.Collision.Item1?.InstanceGuid.ToString() ?? "NULL"; - var key2Guid = group.Collision.Item2?.InstanceGuid.ToString() ?? "NULL"; - - LogManager.Debug($"[去重分析-唯一{i+1:00}] 去重键: Item1Name='{key1Name}', Item2Name='{key2Name}'"); - LogManager.Debug($"[去重分析-唯一{i+1:00}] 去重键: Item1GUID='{key1Guid}', Item2GUID='{key2Guid}'"); - } - var doc = Autodesk.Navisworks.Api.Application.ActiveDocument; + var doc = Application.ActiveDocument; // 使用分组方案:创建一个主测试和一个包含所有碰撞结果的组 LogManager.Info("=== 开始分组方案:创建主测试和碰撞分组 ==="); @@ -882,8 +734,6 @@ namespace NavisworksTransport } } - private DateTime _lastTestCreationTime = DateTime.MinValue; - /// /// 高亮显示碰撞对象 /// @@ -926,12 +776,6 @@ namespace NavisworksTransport // 高亮碰撞对象(使用指定颜色) doc.Models.OverrideTemporaryColor(collidingItems, highlightColor); - - LogManager.Info($"高亮显示 {collidingItems.Count} 个碰撞对象,颜色: {highlightColor}"); - } - else - { - LogManager.Debug("没有碰撞结果需要高亮"); } } catch (Exception ex) @@ -1017,12 +861,6 @@ namespace NavisworksTransport // 记录活跃高亮 _activeHighlights[category] = collidingItems; - - LogManager.Info($"类别 '{category}' 高亮显示 {collidingItems.Count} 个碰撞对象,颜色: {highlightColor}"); - } - else - { - LogManager.Debug($"类别 '{category}' 没有碰撞结果需要高亮"); } } } @@ -1096,17 +934,14 @@ namespace NavisworksTransport /// /// 基于包围盒的快速碰撞检测(不用Clash Detective) /// - private List DetectCollisionsSimple(ModelItem animatedObject, + public List DetectCollisions(ModelItem animatedObject, ModelItemCollection excludeObjects, double detectionGap) { var results = new List(); try - { - LogManager.Debug($"开始快速碰撞检测,动画对象: {animatedObject.DisplayName}"); - + { var animatedBoundingBox = animatedObject.BoundingBox(); - LogManager.Debug($"动画对象包围盒: Min({animatedBoundingBox.Min.X:F2}, {animatedBoundingBox.Min.Y:F2}, {animatedBoundingBox.Min.Z:F2}) Max({animatedBoundingBox.Max.X:F2}, {animatedBoundingBox.Max.Y:F2}, {animatedBoundingBox.Max.Z:F2})"); // 性能分析计时器 var exclusionStopwatch = new System.Diagnostics.Stopwatch(); @@ -1135,7 +970,6 @@ namespace NavisworksTransport } } exclusionStopwatch.Stop(); - LogManager.Debug($"构建排除列表完成,耗时: {exclusionStopwatch.ElapsedMilliseconds}ms,排除对象: {exclusionList.Count} 个"); // 🔥 使用预构建的缓存获取对象列表 getAllItemsStopwatch.Start(); @@ -1147,7 +981,6 @@ namespace NavisworksTransport { // 从缓存中过滤掉动画对象本身 itemList = _allGeometryItemsCache.Where(item => !item.Equals(animatedObject)).ToList(); - LogManager.Debug($"使用缓存获取对象列表,缓存对象总数: {_allGeometryItemsCache.Count},过滤后: {itemList.Count}"); } else { @@ -1160,7 +993,6 @@ namespace NavisworksTransport } getAllItemsStopwatch.Stop(); - LogManager.Debug($"获取对象列表完成,耗时: {getAllItemsStopwatch.ElapsedMilliseconds}ms,对象总数: {itemList.Count}"); int checkedCount = 0; int excludedCount = 0; @@ -1217,10 +1049,7 @@ namespace NavisworksTransport // 检查是否进行了容器映射 bool hasMapping1 = !mappedAnimatedObject.Equals(animatedObject); bool hasMapping2 = !mappedCollisionObject.Equals(item); - - LogManager.Info($"[容器映射] 原始对象: {animatedObject.DisplayName} -> 容器对象: {mappedAnimatedObject.DisplayName} (映射: {hasMapping1})"); - LogManager.Info($"[容器映射] 原始对象: {item.DisplayName} -> 容器对象: {mappedCollisionObject.DisplayName} (映射: {hasMapping2})"); - + var result = new CollisionResult { ClashGuid = Guid.NewGuid(), @@ -1237,7 +1066,6 @@ namespace NavisworksTransport }; results.Add(result); - LogManager.Info($"检测到碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName},距离: {result.Distance:F2}"); } } @@ -1340,11 +1168,9 @@ namespace NavisworksTransport try { var document = Application.ActiveDocument; - LogManager.Debug("[通道缓存] 开始使用SearchAPI构建通道对象缓存"); - // 🔥 一行调用:直接获取所有可通行的物流模型项(使用优化后的SearchAPI) + // 获取所有可通行的物流模型项 var allChannelItems = CategoryAttributeManager.GetAllTraversableLogisticsItems(document); - LogManager.Info($"[通道缓存] 使用SearchAPI直接获取到 {allChannelItems.Count} 个可通行物流元素"); if (allChannelItems.Count == 0) { @@ -1357,19 +1183,14 @@ namespace NavisworksTransport foreach (var channelItem in allChannelItems) { try - { - LogManager.Debug($"[通道收集] 开始处理通道节点: '{channelItem.DisplayName}'"); - - // 🔥 直接使用 ModelItemAnalysisHelper 的方法收集相关节点 + { var itemRelatedNodes = ModelItemAnalysisHelper.CollectRelatedNodes(channelItem); // 将结果添加到缓存中 foreach (var node in itemRelatedNodes) { _channelObjectsCache.Add(node); - } - - LogManager.Debug($"[通道收集] 从 '{channelItem.DisplayName}' 收集到 {itemRelatedNodes.Count} 个相关节点"); + } } catch (Exception ex) { @@ -1383,21 +1204,6 @@ namespace NavisworksTransport LogManager.Info($"通道对象缓存构建完成,耗时: {cacheStopwatch.ElapsedMilliseconds}ms"); LogManager.Info($" - 可通行物流根对象: {allChannelItems.Count} 个"); LogManager.Info($" - 缓存总对象数: {_channelObjectsCache.Count} 个"); - - // 列出找到的通道根对象 - if (allChannelItems.Count > 0) - { - LogManager.Info("[通道缓存] 找到的可通行物流对象列表:"); - for (int i = 0; i < Math.Min(allChannelItems.Count, 10); i++) // 最多显示前10个 - { - var item = allChannelItems[i]; - LogManager.Info($" {i + 1}. {item.DisplayName} (HasGeometry: {item.HasGeometry})"); - } - if (allChannelItems.Count > 10) - { - LogManager.Info($" ... 还有 {allChannelItems.Count - 10} 个对象(省略显示)"); - } - } } catch (Exception ex) { @@ -1520,9 +1326,7 @@ namespace NavisworksTransport // 否则查找有名称的父级容器 var containerObject = ModelItemAnalysisHelper.FindNamedParentContainer(originalItem); - - LogManager.Info($"[碰撞对象映射] 原对象: '{originalItem.DisplayName}' -> 容器对象: '{containerObject?.DisplayName}'"); - + return containerObject ?? originalItem; } diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index 2415c74..613663b 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -25,7 +25,7 @@ namespace NavisworksTransport private CoordinateConverter _coordinateConverter; private PathPointRenderPlugin _renderPlugin; - private List _selectedChannels; + private List _walkableAreas; private List _routes; private PathRoute _currentRoute; private ChannelBounds _combinedChannelBounds; @@ -131,7 +131,7 @@ namespace NavisworksTransport _renderPlugin = null; } - _selectedChannels = new List(); + _walkableAreas = new List(); _routes = new List(); _currentRoute = new PathRoute("默认路径"); _historyManager = new PathHistoryManager(50); // 最多保存50个历史记录 @@ -195,7 +195,7 @@ namespace NavisworksTransport /// internal List ModifiableRoutes => _routes; - public IReadOnlyList SelectedChannels => _selectedChannels.AsReadOnly(); + public IReadOnlyList SelectedChannels => _walkableAreas.AsReadOnly(); public PathPointType CurrentPointType { @@ -1082,7 +1082,7 @@ namespace NavisworksTransport { try { - _selectedChannels.Clear(); + _walkableAreas.Clear(); if (useCurrentSelection) { @@ -1090,8 +1090,8 @@ namespace NavisworksTransport var currentSelection = Application.ActiveDocument.CurrentSelection.SelectedItems; if (currentSelection.Any()) { - _selectedChannels.AddRange(currentSelection); - RaiseStatusChanged($"已选择 {_selectedChannels.Count} 个模型作为通道", PathPlanningStatusType.Success); + _walkableAreas.AddRange(currentSelection); + RaiseStatusChanged($"已选择 {_walkableAreas.Count} 个模型作为通道", PathPlanningStatusType.Success); } else { @@ -1107,23 +1107,23 @@ namespace NavisworksTransport { var allLogisticsItems = CategoryAttributeManager.GetAllLogisticsItems(document); var channelItems = CategoryAttributeManager.FilterByLogisticsType(allLogisticsItems, CategoryAttributeManager.LogisticsElementType.通道); - _selectedChannels.AddRange(channelItems); + _walkableAreas.AddRange(channelItems); LogManager.Info($"[SelectChannels] 通过CategoryAttributeManager直接筛选到 {channelItems.Count} 个通道"); } - RaiseStatusChanged($"通过类别筛选到 {_selectedChannels.Count} 个通道", PathPlanningStatusType.Success); + RaiseStatusChanged($"通过类别筛选到 {_walkableAreas.Count} 个通道", PathPlanningStatusType.Success); } - if (_selectedChannels.Any()) + if (_walkableAreas.Any()) { // 计算组合边界 CalculateCombinedBounds(); // 触发通道选择变更事件 - RaiseChannelSelectionChanged(_selectedChannels, useCurrentSelection ? "手动选择" : "类别筛选"); + RaiseChannelSelectionChanged(_walkableAreas, useCurrentSelection ? "手动选择" : "类别筛选"); } - return _selectedChannels.Count; + return _walkableAreas.Count; } catch (Exception ex) { @@ -1254,7 +1254,7 @@ namespace NavisworksTransport // 更新路径关联的通道ID route.AssociatedChannelIds.Clear(); - foreach (var channel in _selectedChannels) + foreach (var channel in _walkableAreas) { route.AssociatedChannelIds.Add(channel.InstanceGuid.ToString()); } @@ -1294,7 +1294,7 @@ namespace NavisworksTransport AutoSelectLogisticsChannels(); // 检查是否有可通行的物流模型 - if (_selectedChannels == null || _selectedChannels.Count == 0) + if (_walkableAreas == null || _walkableAreas.Count == 0) { RaiseErrorOccurred("没有找到任何可通行的物流模型,请先为模型设置可通行的物流属性"); // 重置状态 @@ -1974,7 +1974,7 @@ namespace NavisworksTransport /// 统计信息字符串 public string GetStatistics() { - var stats = $"通道数量: {_selectedChannels.Count}\n"; + var stats = $"通道数量: {_walkableAreas.Count}\n"; stats += $"路径数量: {_routes.Count}\n"; if (_currentRoute != null) @@ -2021,7 +2021,7 @@ namespace NavisworksTransport errors.Add("当前文档中没有加载的模型"); // 检查通道选择状态 - if (_selectedChannels.Count == 0) + if (_walkableAreas.Count == 0) errors.Add("没有选择任何通道模型"); if (errors.Count > 0) @@ -2116,7 +2116,7 @@ namespace NavisworksTransport private void CalculateCombinedBounds() { // 保留原有实现,但移除UI相关调用 - if (!_selectedChannels.Any()) + if (!_walkableAreas.Any()) { _combinedChannelBounds = null; return; @@ -2129,7 +2129,7 @@ namespace NavisworksTransport var allBounds = new List(); - foreach (var channel in _selectedChannels) + foreach (var channel in _walkableAreas) { try { @@ -2214,7 +2214,7 @@ namespace NavisworksTransport var document = Application.ActiveDocument; if (document?.Models == null) return; - _selectedChannels.Clear(); + _walkableAreas.Clear(); LogManager.Info("[通道自动选择] 开始搜索可通行的物流模型"); @@ -2229,19 +2229,19 @@ namespace NavisworksTransport // 将可通行的物流模型添加到_selectedChannels foreach (ModelItem item in traversableItems) { - _selectedChannels.Add(item); + _walkableAreas.Add(item); LogManager.Info($"[通道自动选择] 添加可通行模型: '{item.DisplayName}'"); } - if (_selectedChannels.Count > 0) + if (_walkableAreas.Count > 0) { // 计算组合边界 CalculateCombinedBounds(); // 触发通道选择变更事件 - RaiseChannelSelectionChanged(_selectedChannels, "自动选择"); + RaiseChannelSelectionChanged(_walkableAreas, "自动选择"); - LogManager.Info($"[通道自动选择] ✅ 自动选择了 {_selectedChannels.Count} 个可通行的物流模型"); + LogManager.Info($"[通道自动选择] ✅ 自动选择了 {_walkableAreas.Count} 个可通行的物流模型"); } else { @@ -2373,8 +2373,8 @@ namespace NavisworksTransport } catch (Exception ex) { - LogManager.WriteLog($"[ToolPlugin] 激活异常: {ex.Message}"); - LogManager.WriteLog($"[ToolPlugin] 堆栈: {ex.StackTrace}"); + LogManager.Error($"[ToolPlugin] 激活异常: {ex.Message}"); + LogManager.Error($"[ToolPlugin] 堆栈: {ex.StackTrace}"); return false; } } @@ -2425,7 +2425,7 @@ namespace NavisworksTransport } catch (Exception ex) { - LogManager.WriteLog($"[ReactivateToolPlugin] 重新激活失败: {ex.Message}"); + LogManager.Error($"[ReactivateToolPlugin] 重新激活失败: {ex.Message}"); RaiseErrorOccurred($"重新激活工具失败: {ex.Message}", ex); } } @@ -2437,11 +2437,6 @@ namespace NavisworksTransport { try { - LogManager.WriteLog("[ToolPlugin事件-V2] ===== 收到精确点击坐标 ====="); - LogManager.WriteLog($"[ToolPlugin事件-V2] 精确坐标: ({pickResult.Point.X:F3}, {pickResult.Point.Y:F3}, {pickResult.Point.Z:F3})"); - LogManager.WriteLog($"[ToolPlugin事件-V2] 选中对象: {pickResult.ModelItem?.DisplayName ?? "NULL"}"); - LogManager.WriteLog($"[ToolPlugin事件-V2] 当前点类型: {CurrentPointType}"); - // 如果在自动路径规划模式,则跳过处理(应该由PathEditingViewModel处理) if (IsInAutoPathMode) { @@ -2454,8 +2449,8 @@ namespace NavisworksTransport } catch (Exception ex) { - LogManager.WriteLog($"[ToolPlugin事件] 处理异常: {ex.Message}"); - LogManager.WriteLog($"[ToolPlugin事件] 堆栈: {ex.StackTrace}"); + LogManager.Error($"[ToolPlugin事件] 处理异常: {ex.Message}"); + LogManager.Error($"[ToolPlugin事件] 堆栈: {ex.StackTrace}"); } } @@ -2465,17 +2460,17 @@ namespace NavisworksTransport private void ProcessManualPathEditing(PickItemResult pickResult) { // 检查当前选中的通道状态 - LogManager.WriteLog($"[手动编辑] 当前_selectedChannels状态: {(_selectedChannels == null ? "NULL" : $"包含{_selectedChannels.Count}个项目")}"); + LogManager.WriteLog($"[手动编辑] 当前_selectedChannels状态: {(_walkableAreas == null ? "NULL" : $"包含{_walkableAreas.Count}个项目")}"); // 如果没有选中的通道,尝试实时搜索 - if (_selectedChannels == null || _selectedChannels.Count == 0) + if (_walkableAreas == null || _walkableAreas.Count == 0) { LogManager.WriteLog("[手动编辑] 没有预选通道,开始实时搜索可通行的物流模型"); SearchAndSetTraversableChannels(); } // 检查是否在可通行的物流模型内并处理点击 - if (_selectedChannels != null && _selectedChannels.Any()) + if (_walkableAreas != null && _walkableAreas.Any()) { bool isInTraversableLogisticsModel = IsItemInSelectedChannels(pickResult.ModelItem) || IsItemChildOfSelectedChannels(pickResult.ModelItem); @@ -2557,12 +2552,12 @@ namespace NavisworksTransport LogManager.WriteLog($"[搜索通道] 筛选出 {traversableItems.Count} 个可通行的物流模型"); // 临时设置为选中通道 - if (_selectedChannels == null) _selectedChannels = new List(); - _selectedChannels.Clear(); + if (_walkableAreas == null) _walkableAreas = new List(); + _walkableAreas.Clear(); foreach (ModelItem item in traversableItems) { - _selectedChannels.Add(item); + _walkableAreas.Add(item); LogManager.WriteLog($"[搜索通道] 添加可通行模型: '{item.DisplayName}'"); } } @@ -2647,19 +2642,14 @@ namespace NavisworksTransport try { // 清理资源 - if (_renderPlugin != null) - { - _renderPlugin.ClearAllPaths(); - _renderPlugin = null; - } + _renderPlugin?.ClearAllPaths(); + _renderPlugin = null; // 停用ToolPlugin if (_isToolPluginActive) { DeactivateToolPlugin(); } - - LogManager.Info($"PathPlanningManager已释放,ManagerId: {_managerId}"); } catch (Exception ex) { @@ -2677,20 +2667,14 @@ namespace NavisworksTransport try { - LogManager.WriteLog("[ToolPlugin] ===== 开始停用ToolPlugin ====="); - // 1. 取消事件订阅 - LogManager.WriteLog("[ToolPlugin] 步骤1: 取消事件订阅"); PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked; - LogManager.WriteLog("[ToolPlugin] ✓ 事件订阅已取消"); // 2. 重置为无活动工具状态 - LogManager.WriteLog("[ToolPlugin] 步骤2: 重置为默认工具"); try { // 使用Tool.None重置到无活动工具状态,让Navisworks处理默认导航 Application.MainDocument.Tool.Value = Tool.None; - LogManager.WriteLog("[ToolPlugin] ✓ 已重置工具为None状态"); } catch (Exception ex) { @@ -2703,8 +2687,8 @@ namespace NavisworksTransport } catch (Exception ex) { - LogManager.WriteLog($"[ToolPlugin] 停用异常: {ex.Message}"); - LogManager.WriteLog($"[ToolPlugin] 堆栈: {ex.StackTrace}"); + LogManager.Error($"[ToolPlugin] 停用异常: {ex.Message}"); + LogManager.Error($"[ToolPlugin] 堆栈: {ex.StackTrace}"); return false; } } @@ -2762,59 +2746,27 @@ namespace NavisworksTransport { try { - var document = Application.ActiveDocument; - if (document?.Models == null || !document.Models.Any()) + // 如果没有选中的可通行区域,自动搜索 + if (_walkableAreas == null || _walkableAreas.Count == 0) { - LogManager.Warning("文档中没有模型"); - return null; + LogManager.Info("未找到预定义的可通行区域,尝试自动搜索..."); + AutoSelectLogisticsChannels(); } - // 如果有选中的通道,使用通道边界 - if (_selectedChannels != null && _selectedChannels.Count > 0) + // 检查是否找到可通行区域 + if (_walkableAreas == null || _walkableAreas.Count == 0) { - LogManager.Info($"使用选中通道边界,通道数量: {_selectedChannels.Count}"); - return CalculateChannelsBounds(_selectedChannels); + LogManager.Error("没有找到任何可通行区域(通道、门、电梯、楼梯等)"); + throw new InvalidOperationException("无法进行路径规划:模型中没有定义可通行的物流区域。请先设置物流属性。"); } - // 否则使用限制范围的模型边界 - LogManager.Info("使用限制范围的模型边界"); - var allBounds = new List(); - - foreach (var model in document.Models) - { - if (model.RootItem != null) - { - var modelBounds = model.RootItem.BoundingBox(); - if (modelBounds != null) - { - allBounds.Add(modelBounds); - } - } - } - - if (!allBounds.Any()) - { - LogManager.Warning("无法获取任何模型的边界框"); - return null; - } - - // 计算组合边界 - var minX = allBounds.Min(b => b.Min.X); - var minY = allBounds.Min(b => b.Min.Y); - var minZ = allBounds.Min(b => b.Min.Z); - var maxX = allBounds.Max(b => b.Max.X); - var maxY = allBounds.Max(b => b.Max.Y); - var maxZ = allBounds.Max(b => b.Max.Z); - - return new BoundingBox3D( - new Point3D(minX, minY, minZ), - new Point3D(maxX, maxY, maxZ) - ); + // 使用可通行区域的边界作为路径规划范围 + return CalculateChannelsBounds(_walkableAreas); } catch (Exception ex) { LogManager.Error($"获取模型边界失败: {ex.Message}"); - return null; + throw; } } @@ -2889,10 +2841,10 @@ namespace NavisworksTransport } // 如果用户已选择通道,优先使用用户选择的通道 - if (_selectedChannels != null && _selectedChannels.Count > 0) + if (_walkableAreas != null && _walkableAreas.Count > 0) { - LogManager.Info($"[通道数据] 使用用户选择的通道,数量: {_selectedChannels.Count}"); - channelItems.AddRange(_selectedChannels); + LogManager.Info($"[通道数据] 使用用户选择的通道,数量: {_walkableAreas.Count}"); + channelItems.AddRange(_walkableAreas); return channelItems; } @@ -3018,7 +2970,7 @@ namespace NavisworksTransport /// 是否在选定通道中 private bool IsItemInSelectedChannels(ModelItem item) { - return _selectedChannels.Contains(item) || IsItemChildOfSelectedChannels(item); + return _walkableAreas.Contains(item) || IsItemChildOfSelectedChannels(item); } /// @@ -3028,7 +2980,7 @@ namespace NavisworksTransport /// 是否为子项 private bool IsItemChildOfSelectedChannels(ModelItem item) { - foreach (var channel in _selectedChannels) + foreach (var channel in _walkableAreas) { if (IsChildOf(item, channel)) { diff --git a/src/Core/UIStateManager.cs b/src/Core/UIStateManager.cs index 658fb57..121baac 100644 --- a/src/Core/UIStateManager.cs +++ b/src/Core/UIStateManager.cs @@ -703,8 +703,6 @@ namespace NavisworksTransport.Core _flushInterval, // 最小间隔50ms 10 // 高优先级,UI更新很重要 ); - - LogManager.Debug($"已注册UI更新队列处理到IdleEventManager,最小间隔: {_flushInterval}ms"); } catch (Exception ex) { diff --git a/src/PathPlanning/AutoPathFinder.cs b/src/PathPlanning/AutoPathFinder.cs index 2dd5d59..38bd13a 100644 --- a/src/PathPlanning/AutoPathFinder.cs +++ b/src/PathPlanning/AutoPathFinder.cs @@ -758,17 +758,17 @@ namespace NavisworksTransport.PathPlanning { // 可以直线连接,更新最远索引 farthestIndex = testIndex; - LogManager.Debug($"[斜线优化] ✓ 成功连接:点{currentIndex}→点{testIndex},距离={distance:F2}m"); + //LogManager.Debug($"[斜线优化] ✓ 成功连接:点{currentIndex}→点{testIndex},距离={distance:F2}m"); } else { // 新增:记录失败详情 var startGrid = gridMap.WorldToGrid(startPoint); var endGrid = gridMap.WorldToGrid(endPoint); - LogManager.Debug($"[斜线优化] ✗ 连接失败:" + - $"点{currentIndex}[网格({startGrid.X},{startGrid.Y})]→点{testIndex}[网格({endGrid.X},{endGrid.Y})]," + - $"世界坐标:({startPoint.X:F2},{startPoint.Y:F2})→({endPoint.X:F2},{endPoint.Y:F2})," + - $"距离={distance:F2}m,跨越{Math.Abs(endGrid.X-startGrid.X)+Math.Abs(endGrid.Y-startGrid.Y)}个网格"); + // LogManager.Debug($"[斜线优化] ✗ 连接失败:" + + // $"点{currentIndex}[网格({startGrid.X},{startGrid.Y})]→点{testIndex}[网格({endGrid.X},{endGrid.Y})]," + + // $"世界坐标:({startPoint.X:F2},{startPoint.Y:F2})→({endPoint.X:F2},{endPoint.Y:F2})," + + // $"距离={distance:F2}m,跨越{Math.Abs(endGrid.X-startGrid.X)+Math.Abs(endGrid.Y-startGrid.Y)}个网格"); } // 🔧 关键改进:不像现有算法那样遇到失败就停止,而是继续尝试更远的点 // 这样可以发现更多斜线连接机会 @@ -778,7 +778,7 @@ namespace NavisworksTransport.PathPlanning if (farthestIndex > currentIndex + 1) { int skippedPoints = farthestIndex - currentIndex - 1; - LogManager.Info($"[斜线优化] 从点{currentIndex}直连到点{farthestIndex},跳过{skippedPoints}个中间点"); + //LogManager.Info($"[斜线优化] 从点{currentIndex}直连到点{farthestIndex},跳过{skippedPoints}个中间点"); } currentIndex = farthestIndex; diff --git a/src/PathPlanning/PathOptimizer.cs b/src/PathPlanning/PathOptimizer.cs index 547944d..cb11a46 100644 --- a/src/PathPlanning/PathOptimizer.cs +++ b/src/PathPlanning/PathOptimizer.cs @@ -104,13 +104,11 @@ namespace NavisworksTransport.PathPlanning { if (gridMap != null) { - LogManager.Info("[路径优化] 执行基于网格的路径简化"); optimizedPoints = SimplifyGridBasedPath(optimizedPoints, gridMap); LogManager.Info($"[路径优化] 简化完成,点数:{originalCount} -> {optimizedPoints.Count}"); } else { - LogManager.Info("[路径优化] 执行传统共线点简化"); optimizedPoints = SimplifyCollinearPoints(optimizedPoints); LogManager.Info($"[路径优化] 简化完成,点数:{originalCount} -> {optimizedPoints.Count}"); } @@ -123,13 +121,6 @@ namespace NavisworksTransport.PathPlanning // optimizedPoints = SmoothPath(optimizedPoints); } - // 3. 未来扩展:碰撞检测验证 - if (_config.EnableCollisionCheck) - { - LogManager.Info("[路径优化] 碰撞检测功能尚未实现"); - // ValidatePathCollision(optimizedPoints); - } - // 创建优化后的路径 var optimizedRoute = CreateOptimizedRoute(originalPath, optimizedPoints); @@ -160,26 +151,6 @@ namespace NavisworksTransport.PathPlanning var worldPath = points.Select(p => p.Position).ToList(); var gridPath = worldPath.Select(p => gridMap.WorldToGrid(p)).ToList(); - // 检查重复点(调试用) - int duplicateCount = 0; - for (int i = 1; i < gridPath.Count; i++) - { - if (gridPath[i].Equals(gridPath[i-1])) - { - duplicateCount++; - LogManager.Warning($"[路径优化] 发现重复网格点:索引 {i-1} 和 {i} 都是 ({gridPath[i].X}, {gridPath[i].Y})"); - } - } - - if (duplicateCount > 0) - { - LogManager.Warning($"[路径优化] 总共发现 {duplicateCount} 个重复网格点,开始去重处理"); - } - else - { - LogManager.Info("[路径优化] 未发现重复网格点,A*算法输出正常"); - } - // 步骤1:先去除重复点 var dedupedGridPath = new List(); var dedupedPoints = new List(); @@ -191,15 +162,7 @@ namespace NavisworksTransport.PathPlanning dedupedPoints.Add(points[i]); } } - - LogManager.Info($"[路径优化] 去重完成:{gridPath.Count} -> {dedupedGridPath.Count} 个点"); - - if (dedupedGridPath.Count < 3) - { - LogManager.Info("[路径优化] 去重后点数不足3个,直接返回"); - return dedupedPoints; - } - + // 步骤2:基于去重后的网格路径进行方向优化 var simplified = new List { dedupedGridPath[0] }; @@ -264,7 +227,6 @@ namespace NavisworksTransport.PathPlanning var simplified = new List(); simplified.Add(points[0]); // 添加起点 - LogManager.Info($"[共线简化] 开始简化,原始点数:{points.Count}"); int removedCount = 0; // 遍历中间点,只保留转折点 @@ -281,13 +243,11 @@ namespace NavisworksTransport.PathPlanning { // 这是一个转折点,需要保留 simplified.Add(currPoint); - LogManager.Debug($"[共线简化] 保留转折点 {i}:{currPoint.Name}"); } else { // 这是直线上的冗余点,跳过 removedCount++; - LogManager.Debug($"[共线简化] 移除冗余点 {i}:{currPoint.Name}"); } } @@ -332,8 +292,7 @@ namespace NavisworksTransport.PathPlanning if (isSegment1Zero || isSegment2Zero) { - // 🔥 关键修复:只有在真正重复点时才认为共线 - LogManager.Debug($"[共线检测] ✅ 包含真正重复点,视为共线:({p1.X:F3},{p1.Y:F3}) -> ({p2.X:F3},{p2.Y:F3}) -> ({p3.X:F3},{p3.Y:F3})"); + // 🔥 在真正重复点时才认为共线 return true; } @@ -348,39 +307,18 @@ namespace NavisworksTransport.PathPlanning if (isSegment1Horizontal && isSegment2Horizontal) { // 检查水平方向是否一致(同向或反向都可以) - bool sameDirection = (dx12 * dx23 > 0) || Math.Abs(dx12) < tolerance || Math.Abs(dx23) < tolerance; - if (sameDirection) - { - LogManager.Debug($"[共线检测] ✅ 水平共线:({p1.X:F3},{p1.Y:F3}) -> ({p2.X:F3},{p2.Y:F3}) -> ({p3.X:F3},{p3.Y:F3})"); - return true; - } - else - { - LogManager.Debug($"[共线检测] ❌ 水平线段方向相反:dx12={dx12:F3}, dx23={dx23:F3}"); - return false; - } + return (dx12 * dx23 > 0) || Math.Abs(dx12) < tolerance || Math.Abs(dx23) < tolerance; } else if (isSegment1Vertical && isSegment2Vertical) { // 检查垂直方向是否一致(同向或反向都可以) - bool sameDirection = (dy12 * dy23 > 0) || Math.Abs(dy12) < tolerance || Math.Abs(dy23) < tolerance; - if (sameDirection) - { - LogManager.Debug($"[共线检测] ✅ 垂直共线:({p1.X:F3},{p1.Y:F3}) -> ({p2.X:F3},{p2.Y:F3}) -> ({p3.X:F3},{p3.Y:F3})"); - return true; - } - else - { - LogManager.Debug($"[共线检测] ❌ 垂直线段方向相反:dy12={dy12:F3}, dy23={dy23:F3}"); - return false; - } + return (dy12 * dy23 > 0) || Math.Abs(dy12) < tolerance || Math.Abs(dy23) < tolerance; } else { // 🔥 关键:不同类型的线段(一个水平一个垂直,或包含斜线)一律拒绝 string seg1Type = isSegment1Horizontal ? "水平" : (isSegment1Vertical ? "垂直" : "斜线"); string seg2Type = isSegment2Horizontal ? "水平" : (isSegment2Vertical ? "垂直" : "斜线"); - LogManager.Debug($"[共线检测] ❌ 线段类型不匹配:线段1={seg1Type}({dx12:F3},{dy12:F3}), 线段2={seg2Type}({dx23:F3},{dy23:F3})"); return false; } } diff --git a/src/Utils/ModelItemAnalysisHelper.cs b/src/Utils/ModelItemAnalysisHelper.cs index c96cc9f..6c5c42d 100644 --- a/src/Utils/ModelItemAnalysisHelper.cs +++ b/src/Utils/ModelItemAnalysisHelper.cs @@ -82,9 +82,7 @@ namespace NavisworksTransport.Utils { var nodeType = GetModelItemType(current); var displayName = GetSafeDisplayName(current); - - LogManager.Debug($"[容器查找] 检查节点: '{displayName}' (类型:{nodeType}, 层级:{levels})"); - + // 根据节点类型决策 switch (nodeType) { @@ -93,19 +91,11 @@ namespace NavisworksTransport.Utils // 集合节点或混合节点:有意义的容器,停止查找 if (!string.IsNullOrEmpty(displayName)) { - LogManager.Debug($"[智能容器映射] 找到有意义容器: '{GetSafeDisplayName(geometryItem)}' -> '{displayName}' (向上{levels}层, 类型:{nodeType})"); return current; } - else - { - LogManager.Debug($"[容器查找] {nodeType}节点无名称,继续向上查找"); - } break; - case ModelItemType.PureGeometry: case ModelItemType.EmptyNode: - // 纯几何体或空节点:通常无意义,需要继续向上查找父节点 - LogManager.Debug($"[容器查找] {nodeType}节点,向上查找父节点"); break; } @@ -230,22 +220,18 @@ namespace NavisworksTransport.Utils if (hasGeometry && childCount == 0) { - LogManager.Debug($"[节点类型判断] '{item.DisplayName}' -> 纯几何体节点"); return ModelItemType.PureGeometry; } else if (!hasGeometry && childCount > 0) { - LogManager.Debug($"[节点类型判断] '{item.DisplayName}' -> 集合节点 (子节点数: {childCount})"); return ModelItemType.GroupNode; } else if (hasGeometry && childCount > 0) { - LogManager.Debug($"[节点类型判断] '{item.DisplayName}' -> 混合节点 (子节点数: {childCount})"); return ModelItemType.HybridNode; } else { - LogManager.Debug($"[节点类型判断] '{item.DisplayName}' -> 空节点"); return ModelItemType.EmptyNode; } }