using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport.Utils.CoordinateSystem;

namespace NavisworksTransport.PathPlanning
{
    /// <summary>
    /// 通道地面高度检测器
    /// 负责检测路径点在通道中的精确地面高度
    /// 支持动态坐标系（Z-Up 或 Y-Up）
    /// </summary>
    public class ChannelHeightDetector
    {
        /// <summary>
        /// 默认射线投射容差（米）- 与配置中的安全间隙一致
        /// </summary>
        private const double DEFAULT_RAYCAST_TOLERANCE_METERS = 0.1;

        /// <summary>
        /// 当前使用的坐标系
        /// </summary>
        private readonly ICoordinateSystem _coordinateSystem;
        private readonly Dictionary<string, ChannelHeightInfo> _heightCache;
        private readonly double _raycastTolerance;

        /// <summary>
        /// 构造函数（自动使用当前坐标系）
        /// </summary>
        /// <param name="raycastTolerance">射线投射容差（米）</param>
        public ChannelHeightDetector(double raycastTolerance = DEFAULT_RAYCAST_TOLERANCE_METERS) 
            : this(CoordinateSystemManager.Instance.Current, raycastTolerance)
        {
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="coordinateSystem">坐标系</param>
        /// <param name="raycastTolerance">射线投射容差（米）</param>
        public ChannelHeightDetector(ICoordinateSystem coordinateSystem, double raycastTolerance = DEFAULT_RAYCAST_TOLERANCE_METERS)
        {
            _coordinateSystem = coordinateSystem ?? throw new ArgumentNullException(nameof(coordinateSystem));
            _heightCache = new Dictionary<string, ChannelHeightInfo>();
            _raycastTolerance = raycastTolerance;
        }

        /// <summary>
        /// 获取指定位置的通道地面高度（底面高度）
        /// 注意：此方法返回楼板/通道结构的底面高度，用于传统的高度检测
        /// 对于物体路径规划，建议使用GetChannelTopHeight获取顶面行驶表面高度
        /// </summary>
        /// <param name="position">世界坐标位置</param>
        /// <param name="channelItems">通道模型项集合（可能包含楼板、走廊等可通行结构）</param>
        /// <returns>通道底面高度（米）</returns>
        public double GetChannelFloorHeight(Point3D position, IEnumerable<ModelItem> channelItems)
        {
            try
            {
                //LogManager.Info($"[高度检测] 🔍 开始检测位置 ({position.X:F2}, {position.Y:F2}, {position.Z:F2}) 的地面高度，通道数={channelItems?.Count() ?? 0}");

                // 寻找包含该位置的通道
                var containingChannel = FindContainingChannel(position, channelItems);
                if (containingChannel == null)
                {
                    double fallbackElevation = _coordinateSystem.GetElevation(position);
                    LogManager.Info($"[高度检测] ❌ 位置 ({position.X:F2}, {position.Y:F2}, {position.Z:F2}) 未找到包含的通道，使用当前宿主高程: {fallbackElevation:F2}");
                    return fallbackElevation;
                }
                
                //LogManager.Info($"[高度检测] ✅ 找到包含通道: {containingChannel.DisplayName}");

                // 检查缓存
                var cacheKey = GenerateCacheKey(containingChannel, position);
                if (_heightCache.TryGetValue(cacheKey, out var cachedInfo))
                {
                    // 使用缓存的高度信息，但调用精确高度计算方法来确定最终高度
                    var preciseHeight = CalculatePreciseHeightAtPosition(position, cachedInfo, containingChannel);
                    LogManager.Debug($"[高度检测] 使用缓存的高度信息: {preciseHeight:F2}");
                    return preciseHeight;
                }

                // 分析通道几何，获取高度信息
                var heightInfo = AnalyzeChannelGeometry(containingChannel);
                if (heightInfo != null)
                {
                    _heightCache[cacheKey] = heightInfo;
                    
                    // 根据位置在通道中的具体位置计算精确高度
                    var preciseHeight = CalculatePreciseHeightAtPosition(position, heightInfo, containingChannel);
                    LogManager.Debug($"[高度检测] 计算得到精确高度: {preciseHeight:F2}");
                    return preciseHeight;
                }

                // 如果几何分析失败，使用射线投射方法
                var raycastHeight = GetHeightByRaycast(position, containingChannel);
                LogManager.Debug($"[高度检测] 射线投射得到高度: {raycastHeight:F2}");
                return raycastHeight;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[高度检测] 检测高度时发生错误: {ex.Message}");
                return _coordinateSystem.GetElevation(position);
            }
        }

        /// <summary>
        /// 获取通道顶面高度（物体行驶表面）
        /// 专门用于物体路径规划的高度校正，返回楼板/通道结构的顶面高度
        /// 
        /// 应用场景：
        /// - 楼板结构：物体在楼板顶面行驶，而不是底面
        /// - 走廊/通道：返回可行驶表面的高度
        /// - 路径规划：确保物体路径点位于正确的行驶表面
        /// </summary>
        /// <param name="position">位置坐标</param>
        /// <param name="channelItems">通道模型项集合（包含楼板、走廊等可通行结构）</param>
        /// <returns>通道顶面高度（米），即物体实际行驶的表面高度</returns>
        public double GetChannelTopHeight(Point3D position, IEnumerable<ModelItem> channelItems)
        {
            try
            {
                //LogManager.Info($"[高度检测] 🔍 开始检测位置 ({position.X:F2}, {position.Y:F2}, {position.Z:F2}) 的顶面高度，通道数={channelItems?.Count() ?? 0}");

                // 寻找包含该位置的通道
                var containingChannel = FindContainingChannel(position, channelItems);
                if (containingChannel == null)
                {
                    double fallbackElevation = _coordinateSystem.GetElevation(position);
                    LogManager.Info($"[高度检测] ❌ 位置 ({position.X:F2}, {position.Y:F2}, {position.Z:F2}) 未找到包含的通道，使用当前宿主高程: {fallbackElevation:F2}");
                    return fallbackElevation;
                }
                
                //LogManager.Info($"[高度检测] ✅ 找到包含通道: {containingChannel.DisplayName}");

                // 检查缓存
                var cacheKey = GenerateCacheKey(containingChannel, position);
                if (_heightCache.TryGetValue(cacheKey, out var cachedInfo))
                {
                    // 🔥 关键修改：返回通道顶面高度而不是底面高度
                    var topHeight = cachedInfo.CeilingHeight;
                    //LogManager.Info($"[高度检测] 使用缓存的顶面高度信息: {topHeight:F2}");
                    return topHeight;
                }

                // 分析通道几何，获取高度信息
                var heightInfo = AnalyzeChannelGeometry(containingChannel);
                if (heightInfo != null)
                {
                    _heightCache[cacheKey] = heightInfo;
                    
                    // 🔥 关键修改：返回通道顶面高度（楼板表面，物体行驶面）
                    var topHeight = heightInfo.CeilingHeight;
                    //LogManager.Info($"[高度检测] 计算得到通道顶面高度: {topHeight:F2}");
                    return topHeight;
                }

                // 如果几何分析失败，尝试使用边界框获取顶面高度
                var bounds = containingChannel.BoundingBox();
                if (bounds != null)
                {
                    var (_, fallbackTopHeight) = GetBoundsElevationRange(bounds, _coordinateSystem);
                    LogManager.Info($"[高度检测] 使用边界框顶面高度: {fallbackTopHeight:F2}");
                    return fallbackTopHeight;
                }

                // 最后的备选方案
                double finalFallbackElevation = _coordinateSystem.GetElevation(position);
                LogManager.Warning($"[高度检测] ⚠️ 无法获取通道顶面高度，使用当前宿主高程: {finalFallbackElevation:F2}");
                return finalFallbackElevation;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[高度检测] 检测顶面高度时发生错误: {ex.Message}");
                return _coordinateSystem.GetElevation(position);
            }
        }

        /// <summary>
        /// 分析通道几何，提取高度信息
        /// </summary>
        /// <param name="channel">通道模型项</param>
        /// <returns>通道高度信息</returns>
        public ChannelHeightInfo AnalyzeChannelGeometry(ModelItem channel)
        {
            try
            {
                if (channel?.Geometry == null)
                {
                    LogManager.Warning("[高度检测] 通道没有几何信息");
                    return null;
                }

                // 获取通道的边界框
                var bounds = channel.Geometry.BoundingBox;
                if (bounds == null)
                {
                    LogManager.Warning("[高度检测] 无法获取通道边界框");
                    return null;
                }

                var (floorHeight, ceilingHeight) = GetBoundsElevationRange(bounds, _coordinateSystem);

                // 创建高度信息对象
                var heightInfo = new ChannelHeightInfo
                {
                    FloorHeight = floorHeight,
                    CeilingHeight = ceilingHeight,
                    Type = ChannelType.Other, // 不再依赖类型判断
                    HeightProfile = new List<HeightSample>()
                };

                // 采样通道高度剖面
                SampleChannelHeightProfile(channel, heightInfo);

                return heightInfo;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[高度检测] 分析通道几何时发生错误: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 寻找包含指定位置的通道
        /// </summary>
        /// <param name="position">位置点</param>
        /// <param name="channelItems">通道集合</param>
        /// <returns>包含该位置的通道</returns>
        private ModelItem FindContainingChannel(Point3D position, IEnumerable<ModelItem> channelItems)
        {
            if (channelItems == null) return null;

            foreach (var channel in channelItems)
            {
                if (IsPositionInChannel(position, channel))
                {
                    //LogManager.Debug($"[高度检测] 找到包含位置的通道: {channel.DisplayName}");
                    return channel;
                }
            }

            return null;
        }

        /// <summary>
        /// 检查位置是否在通道内
        /// </summary>
        /// <param name="position">位置点</param>
        /// <param name="channel">通道模型项</param>
        /// <returns>是否在通道内</returns>
        private bool IsPositionInChannel(Point3D position, ModelItem channel)
        {
            try
            {
                if (channel?.Geometry?.BoundingBox == null)
                    return false;

                var bounds = channel.Geometry.BoundingBox;
                return IsPositionWithinBounds(position, bounds, _coordinateSystem, 2.0);
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 采样通道高度剖面
        /// </summary>
        /// <param name="channel">通道模型项</param>
        /// <param name="heightInfo">高度信息对象</param>
        private void SampleChannelHeightProfile(ModelItem channel, ChannelHeightInfo heightInfo)
        {
            try
            {
                var bounds = channel.Geometry.BoundingBox;
                var sampleCount = 10; // 采样10个点
                
                // 沿通道长度方向采样
                for (int i = 0; i < sampleCount; i++)
                {
                    double ratio = (double)i / (sampleCount - 1);
                    var samplePosition = CreateHeightProfileSamplePoint(bounds, _coordinateSystem, ratio);
                    var (floorHeight, ceilingHeight) = GetBoundsElevationRange(bounds, _coordinateSystem);
                    
                    var sample = new HeightSample
                    {
                        Position = samplePosition,
                        FloorHeight = floorHeight,
                        CeilingHeight = ceilingHeight
                    };
                    
                    heightInfo.HeightProfile.Add(sample);
                }
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[高度检测] 采样高度剖面时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 根据位置在通道中计算精确高度
        /// </summary>
        /// <param name="position">位置点</param>
        /// <param name="heightInfo">通道高度信息</param>
        /// <param name="channel">通道模型项</param>
        /// <returns>精确高度</returns>
        private double CalculatePreciseHeightAtPosition(Point3D position, ChannelHeightInfo heightInfo, ModelItem channel)
        {
            LogManager.Info($"[高度计算] 开始精确表面高度检测: 位置({position.X:F2}, {position.Y:F2})");
            
            // 方法1: 尝试使用几何射线投射进行精确表面检测
            if (TryGeometricRaycast(position, channel, out double raycastHeight))
            {
                LogManager.Info($"[高度计算] ✅ 几何射线投射成功: {raycastHeight:F2}");
                return raycastHeight;
            }
            
            // 方法2: 如果几何射线投射失败，尝试使用View API作为备选
            if (TryGetGeometricSurfaceHeight(position, channel, out double viewApiHeight))
            {
                LogManager.Info($"[高度计算] ✅ View API备选检测成功: {viewApiHeight:F2}");
                return viewApiHeight;
            }
            
            // 方法3: 最后使用几何分析
            var surfaceHeight = AnalyzeSurfaceHeightAtPosition(position, channel, heightInfo.FloorHeight, heightInfo.CeilingHeight);
            LogManager.Info($"[高度计算] 📐 几何分析结果: {surfaceHeight:F2}");
            return surfaceHeight;
        }

        /// <summary>
        /// 从高度剖面插值计算高度
        /// </summary>
        /// <param name="position">位置点</param>
        /// <param name="heightProfile">高度剖面</param>
        /// <returns>插值高度</returns>
        private double InterpolateHeightFromProfile(Point3D position, List<HeightSample> heightProfile)
        {
            if (heightProfile.Count == 0) return 0;
            if (heightProfile.Count == 1) return heightProfile[0].CeilingHeight;

            // 找到最近的两个采样点进行插值
            var closestSamples = heightProfile
                .OrderBy(s => CalculatePlanarDistance(s.Position, position, _coordinateSystem))
                .Take(2)
                .ToList();

            if (closestSamples.Count == 1)
            {
                return closestSamples[0].CeilingHeight;
            }

            // 线性插值
            var sample1 = closestSamples[0];
            var sample2 = closestSamples[1];
            
            var distance1 = CalculatePlanarDistance(sample1.Position, position, _coordinateSystem);
            var distance2 = CalculatePlanarDistance(sample2.Position, position, _coordinateSystem);
            var totalDistance = distance1 + distance2;

            if (totalDistance < 0.001) return sample1.CeilingHeight;

            var weight1 = 1.0 - (distance1 / totalDistance);
            var weight2 = 1.0 - (distance2 / totalDistance);

            return (sample1.CeilingHeight * weight1 + sample2.CeilingHeight * weight2) / (weight1 + weight2);
        }

        /// <summary>
        /// 使用射线投射获取高度
        /// </summary>
        /// <param name="position">位置点</param>
        /// <param name="channel">通道模型项</param>
        /// <returns>射线投射得到的高度</returns>
        private double GetHeightByRaycast(Point3D position, ModelItem channel)
        {
            try
            {
                // 尝试使用Navisworks几何分析获取更精确的表面高度
                if (channel?.Geometry?.BoundingBox != null)
                {
                    var bbox = channel.Geometry.BoundingBox;
                    
                    if (IsPositionWithinBounds(position, bbox, _coordinateSystem, 0.0))
                    {
                        // 位置在通道范围内，尝试分析表面高度
                        var (floorHeight, ceilingHeight) = GetBoundsElevationRange(bbox, _coordinateSystem);
                        var surfaceHeight = AnalyzeSurfaceHeightAtPosition(position, channel, floorHeight, ceilingHeight);
                        LogManager.Debug($"[射线投射] 表面高度分析结果: {surfaceHeight:F2}");
                        return surfaceHeight;
                    }
                    else
                    {
                        LogManager.Warning($"[射线投射] 位置({position.X:F2}, {position.Y:F2}, {position.Z:F2})不在通道范围内");
                        return _coordinateSystem.GetElevation(position);
                    }
                }
                
                double fallbackElevation = _coordinateSystem.GetElevation(position);
                LogManager.Warning($"[射线投射] 通道几何信息无效，使用当前宿主高程: {fallbackElevation:F2}");
                return fallbackElevation;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[射线投射] 射线投射计算失败: {ex.Message}");
                return _coordinateSystem.GetElevation(position);
            }
        }

        /// <summary>
        /// 分析指定位置的表面高度
        /// </summary>
        /// <param name="position">位置</param>
        /// <param name="channel">通道模型</param>
        /// <param name="floorHeight">地面高度</param>
        /// <param name="ceilingHeight">顶面高度</param>
        /// <returns>表面高度</returns>
        private double AnalyzeSurfaceHeightAtPosition(Point3D position, ModelItem channel, double floorHeight, double ceilingHeight)
        {
            try
            {
                LogManager.Info($"[表面分析] 开始分析位置({position.X:F2}, {position.Y:F2})的实际表面高度");
                LogManager.Info($"[表面分析] 通道边界: 地面={floorHeight:F2}, 顶面={ceilingHeight:F2}");
                
                // 尝试多种方法获取真实表面高度
                
                // 方法1: 使用射线投射从上方检测表面
                var raycastHeight = TryRaycastFromAbove(position, channel, ceilingHeight);
                if (raycastHeight.HasValue)
                {
                    LogManager.Info($"[表面分析] ✅ 射线投射检测到表面高度: {raycastHeight.Value:F2}");
                    return raycastHeight.Value;
                }
                
                // 方法2: 使用多点采样获取局部表面高度
                var sampledHeight = TryMultiPointSampling(position, channel);
                if (sampledHeight.HasValue)
                {
                    LogManager.Info($"[表面分析] ✅ 多点采样检测到表面高度: {sampledHeight.Value:F2}");
                    return sampledHeight.Value;
                }
                
                // 方法3: 作为最后手段，返回几何中心高度
                var midHeight = (floorHeight + ceilingHeight) / 2.0;
                LogManager.Warning($"[表面分析] ⚠️ 无法检测到精确表面，使用几何中心高度: {midHeight:F2}");
                return midHeight;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[表面分析] 表面高度分析失败: {ex.Message}，使用顶面高度");
                return ceilingHeight;
            }
        }

        /// <summary>
        /// 尝试获取几何表面高度（使用View投影和PickItemFromPoint方法）
        /// </summary>
        private bool TryGetGeometricSurfaceHeight(Point3D position, ModelItem channel, out double height)
        {
            height = 0;
            try
            {
                // 获取当前激活的视图
                var activeView = Application.ActiveDocument?.ActiveView;
                if (activeView == null)
                {
                    LogManager.Debug($"[几何分析] 无法获取活动视图");
                    return false;
                }

                // 将3D世界坐标投影到屏幕坐标
                if (TryProjectWorldToScreen(position, activeView, out GridPoint2D screenPoint))
                {
                    // 检查屏幕坐标是否在视图范围内
                    if (screenPoint.X >= 0 && screenPoint.X < activeView.Width &&
                        screenPoint.Y >= 0 && screenPoint.Y < activeView.Height)
                    {
                        // 使用PickItemFromPoint获取该屏幕位置的实际表面点
                        var pickResult = activeView.PickItemFromPoint((int)screenPoint.X, (int)screenPoint.Y);
                        if (pickResult != null)
                        {
                            LogManager.Debug($"[几何分析] PickItemFromPoint结果: 模型={pickResult.ModelItem?.DisplayName ?? "NULL"}, 3D点=({pickResult.Point.X:F2}, {pickResult.Point.Y:F2}, {pickResult.Point.Z:F2})");
                            
                            // 验证拾取到的模型是否为目标通道（或其子项）
                            if (pickResult.ModelItem.Equals(channel) || ModelItemAnalysisHelper.IsChildOf(pickResult.ModelItem, channel))
                            {
                                height = GetPickedSurfaceElevation(
                                    pickResult.Point.X,
                                    pickResult.Point.Y,
                                    pickResult.Point.Z,
                                    _coordinateSystem.Type);
                                LogManager.Info($"[几何分析] ✅ 使用投影法获得精确表面高度: {height:F2}，通道: {channel.DisplayName}");
                                return true;
                            }
                            else
                            {
                                LogManager.Debug($"[几何分析] 拾取到的模型不是目标通道: 拾取={pickResult.ModelItem?.DisplayName}, 目标={channel.DisplayName}");
                            }
                        }
                        else
                        {
                            LogManager.Debug($"[几何分析] PickItemFromPoint在屏幕坐标 ({screenPoint.X:F1}, {screenPoint.Y:F1}) 处未找到模型");
                        }
                    }
                    else
                    {
                        LogManager.Debug($"[几何分析] 投影的屏幕坐标 ({screenPoint.X:F1}, {screenPoint.Y:F1}) 超出视图范围 ({activeView.Width}x{activeView.Height})");
                    }
                }
                else
                {
                    LogManager.Debug($"[几何分析] 3D坐标投影到屏幕失败");
                }

                return false;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[几何分析] 几何表面高度获取失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 将3D世界坐标投影到屏幕坐标
        /// </summary>
        private bool TryProjectWorldToScreen(Point3D worldPoint, View view, out GridPoint2D screenPoint)
        {
            screenPoint = new GridPoint2D(0, 0);
            try
            {
                // 使用Navisworks View API的ProjectPoint方法进行精确投影
                var projectionResult = view.ProjectPoint(worldPoint, false, false);
                if (projectionResult != null)
                {
                    screenPoint = new GridPoint2D((int)projectionResult.X, (int)projectionResult.Y);
                    LogManager.Debug($"[投影] 3D世界坐标 ({worldPoint.X:F2}, {worldPoint.Y:F2}, {worldPoint.Z:F2}) 投影到屏幕坐标 ({projectionResult.X:F1}, {projectionResult.Y:F1})");
                    return true;
                }
                else
                {
                    LogManager.Debug($"[投影] 投影失败，ProjectPoint返回null");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogManager.Debug($"[投影] 投影计算失败: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 计算位置在通道中的相对位置
        /// </summary>
        private Point3D CalculateRelativePositionInChannel(Point3D position, BoundingBox3D bbox)
        {
            var (positionH1, positionH2) = _coordinateSystem.GetHorizontalCoords(position);
            var (minH1, maxH1, minH2, maxH2) = _coordinateSystem.GetHorizontalRange(bbox);
            var (minElevation, maxElevation) = GetBoundsElevationRange(bbox, _coordinateSystem);

            var relativeX = Math.Abs(maxH1 - minH1) < 1e-9 ? 0.0 : (positionH1 - minH1) / (maxH1 - minH1);
            var relativeY = Math.Abs(maxH2 - minH2) < 1e-9 ? 0.0 : (positionH2 - minH2) / (maxH2 - minH2);
            var currentElevation = _coordinateSystem.GetElevation(position);
            var relativeZ = Math.Abs(maxElevation - minElevation) < 1e-9 ? 0.0 : (currentElevation - minElevation) / (maxElevation - minElevation);
            
            return new Point3D(relativeX, relativeY, relativeZ);
        }


        /// <summary>
        /// 检查两个边界框是否重叠
        /// </summary>
        private bool BoundingBoxesOverlap(BoundingBox3D bbox1, BoundingBox3D bbox2)
        {
            return !(bbox1.Max.X < bbox2.Min.X || bbox2.Max.X < bbox1.Min.X ||
                     bbox1.Max.Y < bbox2.Min.Y || bbox2.Max.Y < bbox1.Min.Y ||
                     bbox1.Max.Z < bbox2.Min.Z || bbox2.Max.Z < bbox1.Min.Z);
        }

        /// <summary>
        /// 生成缓存键
        /// </summary>
        /// <param name="channel">通道模型项</param>
        /// <param name="position">位置点</param>
        /// <returns>缓存键</returns>
        private string GenerateCacheKey(ModelItem channel, Point3D position)
        {
            // 使用通道的实例ID和位置的网格坐标作为缓存键
            var (h1, h2) = _coordinateSystem.GetHorizontalCoords(position);
            var gridX = (int)(h1 / 1.0);
            var gridY = (int)(h2 / 1.0);
            return $"{channel.InstanceGuid}_{gridX}_{gridY}";
        }

        /// <summary>
        /// 清除高度缓存
        /// </summary>
        public void ClearCache()
        {
            _heightCache.Clear();
            LogManager.Info("[高度检测] 高度缓存已清除");
        }

        /// <summary>
        /// 获取缓存统计信息
        /// </summary>
        /// <returns>缓存项数量</returns>
        public int GetCacheCount()
        {
            return _heightCache.Count;
        }

        /// <summary>
        /// 尝试从上方进行射线投射检测表面高度
        /// </summary>
        /// <param name="position">目标位置</param>
        /// <param name="channel">通道模型</param>
        /// <param name="maxHeight">最大高度</param>
        /// <returns>检测到的表面高度，如果失败则返回null</returns>
        private double? TryRaycastFromAbove(Point3D position, ModelItem channel, double maxHeight)
        {
            try
            {
                LogManager.Info($"[射线投射] 从上方({position.X:F2}, {position.Y:F2}, {maxHeight:F2})向下投射射线");
                
                // 获取当前活动视图
                var activeView = Application.ActiveDocument?.ActiveView;
                if (activeView == null)
                {
                    LogManager.Debug($"[射线投射] 无法获取活动视图");
                    return null;
                }

                // 从通道上方的点开始，向下投射多条射线
                var testHeights = new[] { maxHeight + 100, maxHeight + 50, maxHeight + 10 };
                
                foreach (var testHeight in testHeights)
                {
                    var testPoint = _coordinateSystem.SetElevation(position, testHeight);
                    
                    // 将3D点投影到屏幕
                    if (TryProjectWorldToScreen(testPoint, activeView, out GridPoint2D screenPoint))
                    {
                        // 检查屏幕坐标是否在视图范围内
                        if (screenPoint.X >= 0 && screenPoint.X < activeView.Width &&
                            screenPoint.Y >= 0 && screenPoint.Y < activeView.Height)
                        {
                            // 使用PickItemFromPoint获取该屏幕位置的实际表面点
                            var pickResult = activeView.PickItemFromPoint(screenPoint.X, screenPoint.Y);
                            if (pickResult != null && (pickResult.ModelItem.Equals(channel) || ModelItemAnalysisHelper.IsChildOf(pickResult.ModelItem, channel)))
                            {
                                double detectedElevation = _coordinateSystem.GetElevation(pickResult.Point);
                                LogManager.Info($"[射线投射] ✅ 成功检测到表面点高程: {detectedElevation:F2}");
                                return detectedElevation;
                            }
                        }
                    }
                }
                
                LogManager.Debug($"[射线投射] 所有射线投射尝试均失败");
                return null;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[射线投射] 射线投射失败: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 尝试COM API几何射线投射获取精确表面高度
        /// </summary>
        /// <param name="position">目标位置</param>
        /// <param name="channel">通道模型</param>
        /// <param name="surfaceHeight">输出的表面高度</param>
        /// <returns>是否成功获取表面高度</returns>
        private bool TryGeometricRaycast(Point3D position, ModelItem channel, out double surfaceHeight)
        {
            surfaceHeight = 0.0;
            try
            {
                LogManager.Info($"[COM几何射线] 开始从ModelItem提取三角形几何数据: {channel.DisplayName}");

                // 使用COM API提取三角形几何数据
                var triangles = GeometryHelper.ExtractTriangles(new[] { channel });
                if (triangles.Count == 0)
                {
                    LogManager.Warning($"[COM几何射线] 未能从ModelItem提取到三角形数据: {channel.DisplayName}");
                    return false;
                }

                LogManager.Info($"[COM几何射线] 成功提取到 {triangles.Count} 个三角形，开始射线-三角形交点计算");

                // 执行垂直射线与三角形的交点检测
                var intersectionPoints = PerformRayTriangleIntersection(position, triangles);
                
                if (intersectionPoints.Count > 0)
                {
                    // 选择最高的交点作为表面高度
                    surfaceHeight = intersectionPoints.Max();
                    LogManager.Info($"[COM几何射线] ✅ 射线-三角形交点检测成功: 找到 {intersectionPoints.Count} 个交点，最高点Z={surfaceHeight:F2}");
                    return true;
                }
                else
                {
                    LogManager.Warning($"[COM几何射线] 射线-三角形交点检测失败: 位置({position.X:F2}, {position.Y:F2})未与任何三角形相交");
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"[COM几何射线] COM API几何射线投射出错: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 执行射线与三角形的交点检测
        /// </summary>
        /// <param name="position">射线起点的水平坐标</param>
        /// <param name="triangles">三角形列表</param>
        /// <returns>交点的高度值列表</returns>
        private List<double> PerformRayTriangleIntersection(Point3D position, List<Triangle3D> triangles)
        {
            var intersectionPoints = new List<double>();
            
            try
            {
                // 获取坐标系的垂直扫描方向
                var scanDirection = _coordinateSystem.VerticalScanDirection;
                
                // 计算三角形在垂直方向上的最大范围
                double maxHeight = 0;
                if (triangles.Count > 0)
                {
                    maxHeight = triangles.Max(t => 
                        Math.Max(
                            _coordinateSystem.GetElevation(t.Point1),
                            Math.Max(
                                _coordinateSystem.GetElevation(t.Point2),
                                _coordinateSystem.GetElevation(t.Point3)
                            )
                        )
                    );
                }
                
                // 从最高点上方开始扫描
                var scanStartHeight = maxHeight + 1000.0;
                var rayOrigin = _coordinateSystem.SetElevation(position, scanStartHeight);
                
                // 使用坐标系的垂直扫描方向（转换为 Point3D）
                var rayDirection = new Point3D(scanDirection.X, scanDirection.Y, scanDirection.Z);
                                
                int intersectionCount = 0;
                foreach (var triangle in triangles)
                {
                    if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionElevation))
                    {
                        intersectionPoints.Add(intersectionElevation);
                        intersectionCount++;
                    }
                }
                
                LogManager.Debug($"[射线-三角形] 找到 {intersectionCount} 个交点，扫描方向: ({rayDirection.X:F2}, {rayDirection.Y:F2}, {rayDirection.Z:F2})");
                
                return intersectionPoints;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[射线-三角形] 射线-三角形交点计算失败: {ex.Message}");
                return intersectionPoints;
            }
        }

        /// <summary>
        /// 尝试多点采样获取表面高度
        /// </summary>
        /// <param name="position">中心位置</param>
        /// <param name="channel">通道模型</param>
        /// <returns>采样得到的表面高度，如果失败则返回null</returns>
        private double? TryMultiPointSampling(Point3D position, ModelItem channel)
        {
            try
            {
                LogManager.Info($"[多点采样] 在位置({position.X:F2}, {position.Y:F2})周围进行多点采样");
                
                var activeView = Application.ActiveDocument?.ActiveView;
                if (activeView == null)
                {
                    LogManager.Debug($"[多点采样] 无法获取活动视图");
                    return null;
                }

                var validHeights = new List<double>();
                var sampleRadius = 50.0; // 50单位半径内采样
                var samplePoints = new[]
                {
                    CreatePlanarOffsetPoint(position, _coordinateSystem, 0.0, 0.0),
                    CreatePlanarOffsetPoint(position, _coordinateSystem, sampleRadius, 0.0),
                    CreatePlanarOffsetPoint(position, _coordinateSystem, -sampleRadius, 0.0),
                    CreatePlanarOffsetPoint(position, _coordinateSystem, 0.0, sampleRadius),
                    CreatePlanarOffsetPoint(position, _coordinateSystem, 0.0, -sampleRadius),
                };

                foreach (var samplePoint in samplePoints)
                {
                    if (TryProjectWorldToScreen(samplePoint, activeView, out GridPoint2D screenPoint))
                    {
                        if (screenPoint.X >= 0 && screenPoint.X < activeView.Width &&
                            screenPoint.Y >= 0 && screenPoint.Y < activeView.Height)
                        {
                            var pickResult = activeView.PickItemFromPoint((int)screenPoint.X, (int)screenPoint.Y);
                            if (pickResult != null && (pickResult.ModelItem.Equals(channel) || ModelItemAnalysisHelper.IsChildOf(pickResult.ModelItem, channel)))
                            {
                                double detectedElevation = _coordinateSystem.GetElevation(pickResult.Point);
                                validHeights.Add(detectedElevation);
                                LogManager.Debug($"[多点采样] 采样点({samplePoint.X:F1}, {samplePoint.Y:F1}, {samplePoint.Z:F1})高程: {detectedElevation:F2}");
                            }
                        }
                    }
                }

                if (validHeights.Count > 0)
                {
                    // 使用中位数减少异常值影响
                    validHeights.Sort();
                    var medianHeight = validHeights[validHeights.Count / 2];
                    LogManager.Info($"[多点采样] ✅ 采样成功，采样点数={validHeights.Count}，中位数高度={medianHeight:F2}");
                    return medianHeight;
                }

                LogManager.Debug($"[多点采样] 没有找到有效的采样点");
                return null;
            }
            catch (Exception ex)
            {
                LogManager.Warning($"[多点采样] 多点采样失败: {ex.Message}");
                return null;
            }
        }

        private static (double min, double max) GetBoundsElevationRange(BoundingBox3D bounds, ICoordinateSystem coordinateSystem)
        {
            if (bounds == null)
            {
                throw new ArgumentNullException(nameof(bounds));
            }

            if (coordinateSystem == null)
            {
                throw new ArgumentNullException(nameof(coordinateSystem));
            }

            return GetBoundsElevationRange(
                bounds.Min.X, bounds.Min.Y, bounds.Min.Z,
                bounds.Max.X, bounds.Max.Y, bounds.Max.Z,
                coordinateSystem.Type);
        }

        private static Point3D CreateHeightProfileSamplePoint(BoundingBox3D bounds, ICoordinateSystem coordinateSystem, double ratio)
        {
            if (bounds == null)
            {
                throw new ArgumentNullException(nameof(bounds));
            }

            if (coordinateSystem == null)
            {
                throw new ArgumentNullException(nameof(coordinateSystem));
            }

            return CreateHeightProfileSamplePoint(
                bounds.Min.X, bounds.Min.Y, bounds.Min.Z,
                bounds.Max.X, bounds.Max.Y, bounds.Max.Z,
                coordinateSystem.Type,
                ratio);
        }

        private static bool IsPositionWithinBounds(Point3D position, BoundingBox3D bounds, ICoordinateSystem coordinateSystem, double elevationTolerance)
        {
            if (position == null || bounds == null || coordinateSystem == null)
            {
                return false;
            }

            var (positionH1, positionH2) = coordinateSystem.GetHorizontalCoords(position);
            var (minH1, maxH1, minH2, maxH2) = coordinateSystem.GetHorizontalRange(bounds);
            var (minElevation, maxElevation) = coordinateSystem.GetHeightRange(bounds);
            var elevation = coordinateSystem.GetElevation(position);

            return positionH1 >= minH1 && positionH1 <= maxH1 &&
                   positionH2 >= minH2 && positionH2 <= maxH2 &&
                   elevation >= minElevation - elevationTolerance &&
                   elevation <= maxElevation + elevationTolerance;
        }

        private static double CalculatePlanarDistance(Point3D pointA, Point3D pointB, ICoordinateSystem coordinateSystem)
        {
            var (aH1, aH2) = coordinateSystem.GetHorizontalCoords(pointA);
            var (bH1, bH2) = coordinateSystem.GetHorizontalCoords(pointB);
            return Math.Sqrt(Math.Pow(aH1 - bH1, 2) + Math.Pow(aH2 - bH2, 2));
        }

        private static Point3D CreatePlanarOffsetPoint(Point3D position, ICoordinateSystem coordinateSystem, double deltaH1, double deltaH2)
        {
            var (h1, h2) = coordinateSystem.GetHorizontalCoords(position);
            var elevation = coordinateSystem.GetElevation(position);
            return coordinateSystem.CreatePoint(h1 + deltaH1, h2 + deltaH2, elevation);
        }

        private static (double min, double max) GetBoundsElevationRange(
            double minX, double minY, double minZ,
            double maxX, double maxY, double maxZ,
            CoordinateSystemType coordinateSystemType)
        {
            var adapter = new HostCoordinateAdapter(coordinateSystemType);
            double elevation1 = HostPlanarGridHelper.GetElevation3(
                new System.Numerics.Vector3((float)minX, (float)minY, (float)minZ),
                adapter);
            double elevation2 = HostPlanarGridHelper.GetElevation3(
                new System.Numerics.Vector3((float)maxX, (float)maxY, (float)maxZ),
                adapter);
            return (Math.Min(elevation1, elevation2), Math.Max(elevation1, elevation2));
        }

        private static Point3D CreateHeightProfileSamplePoint(
            double minX, double minY, double minZ,
            double maxX, double maxY, double maxZ,
            CoordinateSystemType coordinateSystemType,
            double ratio)
        {
            var samplePoint = CreateHeightProfileSamplePoint3(
                minX, minY, minZ,
                maxX, maxY, maxZ,
                coordinateSystemType,
                ratio);
            return new Point3D(samplePoint.X, samplePoint.Y, samplePoint.Z);
        }

        private static System.Numerics.Vector3 CreateHeightProfileSamplePoint3(
            double minX, double minY, double minZ,
            double maxX, double maxY, double maxZ,
            CoordinateSystemType coordinateSystemType,
            double ratio)
        {
            var adapter = new HostCoordinateAdapter(coordinateSystemType);
            var hostMin = new System.Numerics.Vector3((float)minX, (float)minY, (float)minZ);
            var hostMax = new System.Numerics.Vector3((float)maxX, (float)maxY, (float)maxZ);
            var (minH1, maxH1, minH2, maxH2) = HostPlanarGridHelper.GetHorizontalRange3(hostMin, hostMax, adapter);
            var (minElevation, _) = GetBoundsElevationRange(minX, minY, minZ, maxX, maxY, maxZ, coordinateSystemType);
            double sampleH1 = minH1 + (maxH1 - minH1) * ratio;
            double sampleH2 = minH2 + (maxH2 - minH2) * ratio;
            return HostPlanarGridHelper.CreateHostPoint3(sampleH1, sampleH2, minElevation, adapter);
        }

        private static double GetPickedSurfaceElevation(
            double pointX,
            double pointY,
            double pointZ,
            CoordinateSystemType coordinateSystemType)
        {
            var adapter = new HostCoordinateAdapter(coordinateSystemType);
            return HostPlanarGridHelper.GetElevation3(
                new System.Numerics.Vector3((float)pointX, (float)pointY, (float)pointZ),
                adapter);
        }
    }

    /// <summary>
    /// 通道高度信息
    /// </summary>
    public class ChannelHeightInfo
    {
        /// <summary>
        /// 地面高度（米）
        /// </summary>
        public double FloorHeight { get; set; }

        /// <summary>
        /// 顶面高度（米）
        /// </summary>
        public double CeilingHeight { get; set; }

        /// <summary>
        /// 通道类型
        /// </summary>
        public ChannelType Type { get; set; }

        /// <summary>
        /// 高度剖面采样点
        /// </summary>
        public List<HeightSample> HeightProfile { get; set; } = new List<HeightSample>();
    }

    /// <summary>
    /// 高度采样点
    /// </summary>
    public class HeightSample
    {
        /// <summary>
        /// 采样位置
        /// </summary>
        public Point3D Position { get; set; }

        /// <summary>
        /// 该位置的地面高度
        /// </summary>
        public double FloorHeight { get; set; }

        /// <summary>
        /// 该位置的顶面高度
        /// </summary>
        public double CeilingHeight { get; set; }
    }

    /// <summary>
    /// 通道类型枚举
    /// </summary>
    public enum ChannelType
    {
        /// <summary>
        /// 走廊/通道
        /// </summary>
        Corridor,

        /// <summary>
        /// 楼梯
        /// </summary>
        Stairs,

        /// <summary>
        /// 坡道
        /// </summary>
        Ramp,

        /// <summary>
        /// 电梯
        /// </summary>
        Elevator,

        /// <summary>
        /// 其他
        /// </summary>
        Other
    }

}
