using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf.SharpDX;
using log4net;
using SharpDX;
using SharpDX.Direct3D11;
using SparkClient.Views.UserControl.ViewportData.Enum;
using SparkClient.Views.UserControl.ViewportData.Entity;
using Color = SharpDX.Color;
using GeometryModel3D = HelixToolkit.Wpf.SharpDX.GeometryModel3D;
using MeshGeometry3D = HelixToolkit.Wpf.SharpDX.MeshGeometry3D;
using Point = System.Windows.Point;
using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera;
using System.Windows.Controls;
using HelixToolkit.Wpf;
using MeshBuilder = HelixToolkit.Wpf.SharpDX.MeshBuilder;
using OrthographicCamera = HelixToolkit.Wpf.SharpDX.OrthographicCamera;
using System.Windows.Input;


namespace SparkClient.Views.UserControl.ViewportData.Helper;

public class ViewportHelperPro
{
    private static readonly ILog Logger = LogManager.GetLogger(typeof(ViewportHelperPro));
    /// <summary>
    /// 对指定类型的面进行标色
    /// </summary>
    /// <param name="planeType"></param>
    /// <param name="color"></param>
    /// <returns></returns>
    public static MeshGeometryModel3D GenerateTypePanelHot(PlaneType planeType, Color4? color = null)
    {
        var entities = ViewportManager.ViewportTriangle.Where(e => e.PlaneType == planeType).ToList();
        return GenerateModelByEntity(entities, color ?? ViewportManager.ColorConfig.ErrFacetColor);
    }

    #region 已经确定和调整好的方法
    /// <summary>
    /// 通过三角形实体集合生成面模型(生成并添加)
    /// </summary>
    /// <param name="viewport"></param>
    /// <param name="entities"></param>
    public static MeshGeometryModel3D GenerateModelByEntity(Viewport3DX viewport, List<Viewport3DTriangleEntity> entities, Color4? color = null)
    {
        var geometryModel = GenerateModelByEntity(entities, color);
        viewport.Items.Add(geometryModel);
        return geometryModel;
    }

    /// <summary>
    /// 通过三角形实体集合生成面模型(只生成不添加)
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="color"></param>
    /// <returns></returns>
    public static MeshGeometryModel3D GenerateModelByEntity(List<Viewport3DTriangleEntity> entities, Color4? color = null)
    {
        var meshBuilder = new MeshBuilder(true, false);
        foreach (var entity in entities)
        {
            if (entity.PlaneType == PlaneType.Girdle)
            {
                meshBuilder.AddTriangleFan(new List<Vector3>() { entity.Point1, entity.Point2, entity.Point3 },
                    new List<Vector3>() { new Vector3(0, 0, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 0) });
            }
            else
            {
                meshBuilder.AddPolygon(new List<Vector3>() { entity.Point1, entity.Point2, entity.Point3 });
            }
        }
        var mesh = meshBuilder.ToMeshGeometry3D();

        var material = new PBRMaterial
        {
            AlbedoColor = new Color4(0.0f, 0f,0f,0.8f), // 黑色,避免其他光照影响
            EmissiveColor =color ?? ViewportManager.ColorConfig.MainFacetColor , // LightGray #D3D3D3
            MetallicFactor = 0.0, // 非金属
            RoughnessFactor = 1.0, // 高粗糙度,避免反射效果
            ReflectanceFactor = 0.0, // 无反射
            ClearCoatStrength = 0.0, // 无清漆效果
            ClearCoatRoughness = 1.0, // 高粗糙度
            SurfaceMapSampler = new SamplerStateDescription
            {
                Filter = Filter.MinMagMipLinear,
                AddressU = TextureAddressMode.Wrap,
                AddressV = TextureAddressMode.Wrap,
                AddressW = TextureAddressMode.Wrap
            },
            // NormalMap = texture
        };
        return new MeshGeometryModel3D
        {
            Geometry = mesh,
            Material = material,
        };
    }

    /// <summary>
    /// 通过三角形实体集合生成面模型(只生成不添加)
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="color"></param>
    /// <returns></returns>
    public static List<MeshGeometryModel3D> GenerateModelByEntityGroupByType(List<Viewport3DTriangleEntity> entities)
    {
        var groupedDict = entities
            .GroupBy(e => e.PlaneType)
            .ToDictionary(g => g.Key, g => g.ToList());

        var result = new List<MeshGeometryModel3D>();
        foreach (var group in groupedDict)
        {
            var key = group.Key;
            result.Add(GenerateModelByEntity(group.Value, GenFaceColor4(key)));
        }

        return result;
    }

    private static Color4? GenFaceColor4(PlaneType planeType)
    {
        switch (planeType)
        {
            case PlaneType.Girdle:
                return ViewportManager.ColorConfig.GirdleFacetColor;
            case PlaneType.TableFacet:
                return ViewportManager.ColorConfig.TableFacetColor;
            case PlaneType.UpperMainFacet:
                return ViewportManager.ColorConfig.UpperMainFacetColor;
            case PlaneType.StarFacet:
                return ViewportManager.ColorConfig.StarFacetColor;
            case PlaneType.UpperGirdleFacet:
                return ViewportManager.ColorConfig.UpperGirdleFacetColor;
            case PlaneType.PavilionMainFacet:
                return ViewportManager.ColorConfig.PavilionFacetColor;
            case PlaneType.LowerGirdleFact:
                return ViewportManager.ColorConfig.LowerGirdleFacetColor;
            case PlaneType.Culet:
                return ViewportManager.ColorConfig.CuletFacetColor;
        }

        return null;
    }

    /// <summary>
    /// 保存模型截图
    /// </summary>
    /// <param name="viewport"></param>
    /// <param name="filePath"></param>
    public static void SaveViewportAsImage(Viewport3DX viewport, string filePath)
    {
        // 定义图像大小
        int width = (int)viewport.ActualWidth;
        int height = (int)viewport.ActualHeight;

        // 创建 RenderTargetBitmap,捕获 Viewport3DX 的内容
        var renderTargetBitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
        renderTargetBitmap.Render(viewport);

        // 使用 PngBitmapEncoder 保存为 PNG 文件
        var encoder = new PngBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));

        using (var fileStream = new FileStream(filePath, FileMode.Create))
        {
            encoder.Save(fileStream);
        }
    }


    public static async Task ExportModelsToVideo(Viewport3DX viewport, string filePath)
    {
        if (viewport == null)
            viewport = ViewportManager.GetViewport3D();
        
        var generationTask = VideoHelper.StartGenerationAndRotation(viewport);

        List<PngBitmapEncoder> pngList = await generationTask;

        await VideoHelper.CreateVideoFromPngListAsync(pngList, filePath);
    }

    /// <summary>
    /// 导出模型
    /// </summary>
    /// <param name="viewport"></param>
    /// <param name="filePath"></param>
    public static void ExportModelsToStl(Viewport3DX viewport, string filePath)
    {
        if (viewport == null)
            viewport = ViewportManager.GetViewport3D();
        // 打开文件写入流
        using (StreamWriter writer = new StreamWriter(filePath))
        {
            writer.WriteLine("solid exportedModel");
            foreach (var model in viewport.Items.OfType<MeshGeometryModel3D>())
            {

                if (model.Geometry is HelixToolkit.Wpf.SharpDX.Geometry3D geometry)
                {
                    var positions = geometry.Positions;
                    var indices = geometry.Indices;

                    // 每三个索引构成一个三角形
                    for (int i = 0; i < indices.Count; i += 3)
                    {
                        int index0 = indices[i];
                        int index1 = indices[i + 1];
                        int index2 = indices[i + 2];

                        var p0 = positions[index0];
                        var p1 = positions[index1];
                        var p2 = positions[index2];

                        // 计算法线
                        var normal = CalculateNormal(p0, p1, p2);

                        // 写入三角形信息到 STL 文件
                        writer.WriteLine($"  facet normal {normal.X} {normal.Z} {normal.Y}");
                        writer.WriteLine("    outer loop");
                        writer.WriteLine($"      vertex {p0.X} {p0.Z} {p0.Y}");
                        writer.WriteLine($"      vertex {p1.X} {p1.Z} {p1.Y}");
                        writer.WriteLine($"      vertex {p2.X} {p2.Z} {p2.Y}");
                        writer.WriteLine("    endloop");
                        writer.WriteLine("  endfacet");
                    }
                }
            }

            // 写入 STL 文件结束
            writer.WriteLine("endsolid exportedModel");
        }
    }
    /// <summary>
    /// 导出模型
    /// </summary>
    /// <param name="viewport"></param>
    /// <param name="filePath"></param>
    public static async Task ExportModelsToStlASync(string filePath)
    {
        Viewport3DX viewport = ViewportManager.GetViewport3D();

        // 创建一个集合来存储几何信息
        List<Tuple<IList<Vector3>, IList<int>>> geometries = new List<Tuple<IList<Vector3>, IList<int>>>();

        // 在 UI 线程中收集几何信息
        await Application.Current.Dispatcher.InvokeAsync(() =>
        {
            foreach (var model in viewport.Items.OfType<MeshGeometryModel3D>())
            {
                if (model.Geometry is HelixToolkit.Wpf.SharpDX.Geometry3D geometry)
                {
                    geometries.Add(new Tuple<IList<Vector3>, IList<int>>(geometry.Positions, geometry.Indices));
                }
            }
        });

        // 在后台线程中处理几何信息并写入 STL 文件
        await Task.Run(() =>
        {
            using (StreamWriter writer = new StreamWriter(filePath))
            {
                writer.WriteLine("solid exportedModel");

                foreach (var geometry in geometries)
                {
                    var positions = geometry.Item1;
                    var indices = geometry.Item2;

                    // 每三个索引构成一个三角形
                    for (int i = 0; i < indices.Count; i += 3)
                    {
                        int index0 = indices[i];
                        int index1 = indices[i + 1];
                        int index2 = indices[i + 2];

                        var p0 = positions[index0];
                        var p1 = positions[index1];
                        var p2 = positions[index2];

                        // 计算法线
                        var normal = CalculateNormal(p0, p1, p2);

                        // 写入三角形信息到 STL 文件
                        writer.WriteLine($"  facet normal {normal.X} {normal.Y} {normal.Z}");
                        writer.WriteLine("    outer loop");
                        writer.WriteLine($"      vertex {p0.X} {p0.Y} {p0.Z}");
                        writer.WriteLine($"      vertex {p1.X} {p1.Y} {p1.Z}");
                        writer.WriteLine($"      vertex {p2.X} {p2.Y} {p2.Z}");
                        writer.WriteLine("    endloop");
                        writer.WriteLine("  endfacet");
                    }
                }

                // 写入 STL 文件结束
                writer.WriteLine("endsolid exportedModel");
            }
        }).ConfigureAwait(false);

    }
    /// <summary>
    /// 通过三角形实体集合生成每个面的边框线
    /// </summary>
    /// <param name="viewport"></param>
    /// <param name="entities"></param>
    public static List<LineGeometryModel3D> GentrateLineByEntity(Viewport3DX viewport, List<Viewport3DTriangleEntity> entities, Color4? color = null, double thickness = 1.0)
    {
        List<LineGeometryModel3D> result = GentrateLineByEntity(entities, color, thickness);
        result.ForEach(e => viewport.Items.Add(e));
        return result;
    }

    /// <summary>
    /// 通过三角形实体集合生成每个面的边框线(只生成不添加)
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="color"></param>
    /// <param name="thickness"></param>
    /// <returns></returns>
    public static List<LineGeometryModel3D> GentrateLineGirdleByEntity(List<Viewport3DTriangleEntity> entities,
        Color4? color = null, double thickness = 1.0)
    {
        List<LineGeometryModel3D> result = new List<LineGeometryModel3D>();
        //按面分组,腰面特殊单独生成
        List<Viewport3DTriangleEntity> waistList = entities
            .Where(entity => entity.PlaneType == PlaneType.Girdle)
            .ToList();
        List<Vector3> selFaceVector = new List<Vector3>();
        List<Tuple<Vector3, Vector3>> lines = new List<Tuple<Vector3, Vector3>>();
        if (waistList.Count > 0)
        {
            foreach (var entity in waistList)
            {
                selFaceVector.Add(entity.Point1);
                selFaceVector.Add(entity.Point2);
                selFaceVector.Add(entity.Point3);
            }
            HashSet<Vector3> uniqueVectors = new HashSet<Vector3>(selFaceVector);

            for (int i = 0; i < selFaceVector.ToList().Count - 1; i++)
            {
                var nowItem = selFaceVector.ToList()[i];
                var nextItem = selFaceVector.ToList()[i + 1];
                var line = new Tuple<Vector3, Vector3>(nowItem, nextItem);
                if (IsLineSegmentParallelToYAxis(line))
                {
                    lines.Add(line);
                    result.Add(DisplayLineModel3D(new List<Vector3>() { nowItem, nextItem }, color ?? ViewportManager.ColorConfig.MainBorderColor, thickness));
                }
            }
        }

        CalculateLineSegmentStats(lines, out ViewportManager.MainModelGirdleMaxLines, out ViewportManager.MainModelGirdleMinLines, out ViewportManager.MainModelGirdleAvgLines);
        ViewportManager.MainModelGirdleLines = lines;
        return result;
    }

    /// <summary>
    /// 通过三角形实体集合生成每个面的边框线(只生成不添加)
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="color"></param>
    /// <param name="thickness"></param>
    /// <returns></returns>
    public static List<LineGeometryModel3D> GentrateLineByEntity(List<Viewport3DTriangleEntity> entities, Color4? color = null, double thickness = 1.0)
    {
        List<LineGeometryModel3D> result = new List<LineGeometryModel3D>();
        //按面分组,腰面特殊单独生成
        List<Viewport3DTriangleEntity> waistList = entities
            .Where(entity => entity.PlaneType == PlaneType.Girdle)
            .ToList();

        Dictionary<string, List<Viewport3DTriangleEntity>> feactList = entities
            .Where(entity => entity.PlaneType != PlaneType.Girdle)
            .GroupBy(entity => entity.PlaneCode)
            .ToDictionary(group => group.Key, group => group.ToList());

        foreach (var item in feactList)
        {
            //GenerateLineTextModelByEntity(viewport, item.Value, Viewport3DManager.Gray);
            List<Vector3> temp = new List<Vector3>();
            foreach (var entity in item.Value)
            {
                temp.Add(entity.Point1);
                temp.Add(entity.Point2);
                temp.Add(entity.Point3);
            }
            result.Add(DisplayLineModel3D(VectorClockwiseSort(new HashSet<Vector3>(temp).ToList()), color ?? ViewportManager.ColorConfig.MainBorderColor, thickness));
        }

        //腰 - 特殊
        List<Vector3> selFaceVector = new List<Vector3>();
        if (waistList.Count > 0)
        {
            //顶线和底线
            foreach (var entity in waistList)
            {
                selFaceVector.Add(entity.Point1);
                selFaceVector.Add(entity.Point2);
                selFaceVector.Add(entity.Point3);
            }
            HashSet<Vector3> uniqueVectors = new HashSet<Vector3>(selFaceVector);
            float maxY = uniqueVectors.Max(v => v.Y);
            float minY = uniqueVectors.Min(v => v.Y);
            float mid = (maxY + minY) / 2;
            ViewportManager.GirdleTopLines.Clear();
            ViewportManager.GirdleBottomLines.Clear();
            foreach (var vector in uniqueVectors)
            {
                if (vector.Y < mid)
                    ViewportManager.GirdleBottomLines.Add(vector);
                else
                    ViewportManager.GirdleTopLines.Add(vector);
            }
            // result.Add(DisplayLineModel3D( VectorClockwiseSort(ViewportManager.GirdleBottomLines),   color??ViewportManager.ColorConfig.MainBorderColor, thickness));
            // result.Add(DisplayLineModel3D( VectorClockwiseSort(ViewportManager.GirdleTopLines),  color??ViewportManager.ColorConfig.MainBorderColor, thickness));

        }

        return result;
    }

    public static List<Viewport3DTriangleEntity> GenerateLineTextModelsByType(PlaneType type, Color4? textColor = null,
        bool showAll = false)
    {

        List<Viewport3DTriangleEntity> entities = new List<Viewport3DTriangleEntity>();
        string planCode = "";
        ViewportManager.ViewportTriangle.ForEach(e =>
        {
            if (e.PlaneType == type && (e.PlaneCode == planCode || string.IsNullOrEmpty(planCode)))
            {
                planCode = e.PlaneCode;
                entities.Add(e);
            }
        });

        return entities;
    }

    /// <summary>
    /// 选择面生成文本信息
    /// </summary>
    /// <param name="entities">三角形集合</param>
    /// <param name="valKey">指定数据集</param>
    /// <returns></returns>
    public static List<GeometryModel3D> GenerateLineTextModels(List<Viewport3DTriangleEntity> entities, string valKey = "")
    {
        Logger.Info("【面文本生成】开始生成面相关文本信息");
        var selFacet = entities;
        var selFacetType = entities.First().PlaneType;

        var result = new List<GeometryModel3D>();
        if (selFacetType == PlaneType.Girdle && string.IsNullOrWhiteSpace(valKey))
        {
            Logger.Info($"【面文本生成】 命中面{selFacetType},是腰");
            // if (ViewportManager.MainModelGirdleMaxLines != null || ViewportManager.MainModelGirdleMinLines != null ||
            //     ViewportManager.MainModelGirdleAvgLines != null)
            // {
            //     result.Add(DisplayLineModel3D(new List<Tuple<Vector3,Vector3>>(){ViewportManager.MainModelGirdleMaxLines}, new Color4(1f, 0, 0, 1f) ));
            //     result.Add(DisplayLineModel3D(new List<Tuple<Vector3,Vector3>>(){ViewportManager.MainModelGirdleMinLines}, new Color4(0f, 1f, 0, 1f) ));
            //     result.Add(DisplayLineModel3D(new List<Tuple<Vector3,Vector3>>(){ViewportManager.MainModelGirdleAvgLines}, new Color4(1f, 0.5f, 0, 1f) ));
            //     result.Add(DisplayText3D($"{CalculateLength(ViewportManager.MainModelGirdleMaxLines)}mm", ViewportManager.MainModelGirdleMaxLines.Item1, textColor));
            //     result.Add(DisplayText3D($"{CalculateLength(ViewportManager.MainModelGirdleMinLines)}mm", ViewportManager.MainModelGirdleMinLines.Item1, textColor));
            //     result.Add(DisplayText3D($"{CalculateLength(ViewportManager.MainModelGirdleAvgLines)}mm", ViewportManager.MainModelGirdleAvgLines.Item1, textColor));
            // }
            List<Viewport3DTriangleEntity> facetTypeAll =
                ViewportManager.ViewportTriangle.FindAll(e => e.PlaneType == selFacetType);
            var groupedDic = facetTypeAll.GroupBy(entity => entity.PlaneCode)
                .ToDictionary(group => group.Key, group => group.ToList());
            Logger.Info($"【面文本生成】 腰由{groupedDic.Count}个面组成");

            var selPlaneCode = entities.First().PlaneCode;
            Logger.Info($"【面文本生成】 当前选择{selPlaneCode}");

            List<Vector3> facetPoints = new List<Vector3>();
            entities.ForEach(e => { facetPoints.Add(e.Point1); facetPoints.Add(e.Point2); facetPoints.Add(e.Point3); });
            var facetIndex = -1;
            int.TryParse(selPlaneCode.Split("_")[1], out facetIndex);

            if (facetIndex == -1)
            {
                Logger.Info($"【面文本生成】 面索引解析失败{selPlaneCode}");
                return result;
            }
            int linePointType = facetIndex % 4;

            switch (linePointType)
            {
                case 0:
                case 3:
                    var longestLine1 = GetLongestOrShortestLineSegment(facetPoints, returnLongest: true);
                    result.Add(DisplayLineModel3D(new List<Tuple<Vector3, Vector3>>() { longestLine1 }, new Color4(1f, 0, 0, 1f), 2f));
                    break;
                case 1:
                case 2:
                    var longestLine2 = GetLongestOrShortestLineSegment(facetPoints, returnLongest: false);
                    result.Add(DisplayLineModel3D(new List<Tuple<Vector3, Vector3>>() { longestLine2 }, new Color4(1f, 0, 0, 1f), 2f));
                    break;
            }
            //开始找值
            string param = string.Empty;
            var valueIndex = 0;
            if (facetIndex % 8 == 0 || (facetIndex + 1) % 8 == 0)
            {
                //上腰面
                Logger.Info($"【面文本生成】 腰面值 波峰【上腰面】");
                valueIndex = (int)Math.Ceiling(facetIndex / 8.0) == 8 ? 0 : (int)Math.Ceiling(facetIndex / 8.0);
                param = "GIRDLE_BONE";
            } else if (linePointType == 3 || linePointType == 0)
            {
                //风筝面
                Logger.Info($"【面文本生成】 腰面值 波峰【风筝面】");
                valueIndex = (facetIndex / 8);
                param = "GIRDLE_BEZEL";
            }
            else
            {
                //腰厚比
                Logger.Info($"【面文本生成】 腰面值 波峰【腰厚比】");
                valueIndex = (facetIndex / 4);
                param = "GIRDLE_VALLEY";
            }

            valueIndex += 1;
            var detail = ViewportManager.DiamondData[$"{param}_DETAIL"];
            if (detail == null)
            {
                Logger.Info($"【面文本生成】 {param}_DETAIL Key不存在");
                return result;
            }
            Logger.Info($"【面文本生成】 {param}_DETAIL == {detail}");
            var paramValue = detail[$"{param}_{valueIndex}"];
            if (paramValue == null)
            {
                Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} Key不存在");
                return result;
            }
            Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} ==={paramValue}");
            var valueFloat = (Math.Floor(float.Parse(paramValue.ToString()) * 1000) / 10).ToString();
            Logger.Info($"【面文本生成】 {valueFloat} -- {valueIndex}");
            var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
            result.Add(DisplayText3D($"{valueFloat}", facetTextPoint));
            // foreach (var kv in groupedDic)
            // {
            //     var value = kv.Value;
            //     var key = kv.Key;
            //     var facetIndex = -1;
            //     int.TryParse(key.Split("_")[1], out facetIndex);
            //     List<Vector3> facetPoints  = new List<Vector3>();
            //     value.ForEach(e => { facetPoints.Add(e.Point1); facetPoints.Add(e.Point2); facetPoints.Add(e.Point3); });
            //
            //     int linePointType = facetIndex % 4;
            //     /***
            //      *  0 1 2 3
            //      *  4 5 6 7
            //      *  面index+1 % 4  = 0
            //      *  面id-loop4 = 0 - 高亮左边的竖线 - 波峰 -
            //      *  面id-loop4 = 1 - 高亮右边的竖线 - 波谷
            //      *  面id-loop4 = 2 - 高亮左边的竖线 - 波谷
            //      *  面id-loop4 = 3 - 高亮右边的竖线 - 波峰
            //      */
            //
            // }
        } else if (selFacetType == PlaneType.Girdle && !string.IsNullOrWhiteSpace(valKey))
        {
            Logger.Info($"【面文本生成】 命中面{selFacetType},是腰,显示值{valKey}");
            /***
             * GIRDLE_BEZEL   风筝
             * GIRDLE_BONE    上腰
             * GIRDLE_VALLEY  波谷
             */
            List<Viewport3DTriangleEntity> facetTypeAll =
                ViewportManager.ViewportTriangle.FindAll(e => e.PlaneType == selFacetType);
            var groupedDic = facetTypeAll.GroupBy(entity => entity.PlaneCode)
                .ToDictionary(group => group.Key, group => group.ToList());
            var resultDic = new Dictionary<string, List<Viewport3DTriangleEntity>>();
            for (int i = 0; i < groupedDic.Count; i++)
            {
                switch (valKey)
                {
                    case "GIRDLE_BEZEL": if (i % 8 == 4) resultDic.Add($"0_{i}", groupedDic[$"0_{i}"]);
                        break;
                    case "GIRDLE_BONE": if (i % 8 == 0) resultDic.Add($"0_{i}", groupedDic[$"0_{i}"]);
                        break;
                    case "GIRDLE_VALLEY": if (i % 4 == 2) resultDic.Add($"0_{i}", groupedDic[$"0_{i}"]);
                        break;
                }
            }

            if (resultDic.Count == 0)
            {
                Logger.Info($"【面文本生成】 关联面获取失败");
            }

            foreach (var dic in resultDic)
            {
                //高亮四边形左边的线,并绑定值
                List<Vector3> facetPoints = new List<Vector3>();
                dic.Value.ForEach(e => { facetPoints.Add(e.Point1); facetPoints.Add(e.Point2); facetPoints.Add(e.Point3); });
                //高亮的线
                var showLine = GetLeftParallelLineSegment(facetPoints);
                if (showLine == null) continue;

                //文字显示位置
                var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
                var resIndex = resultDic.Keys.ToList().IndexOf(dic.Key);
                if (resIndex == -1) continue;
                resIndex += 1;
                var detail = ViewportManager.DiamondData[$"{valKey}_DETAIL"];
                if (detail == null)
                {
                    Logger.Info($"【面文本生成】 {valKey}_DETAIL Key不存在");
                    return result;
                }
                Logger.Info($"【面文本生成】 {valKey}_DETAIL == {detail}");
                var paramValue = detail[$"{valKey}_{resIndex}"];
                if (paramValue == null)
                {
                    Logger.Info($"【面文本生成】 {valKey}_DETAIL.{valKey}_{resIndex} Key不存在");
                    return result;
                }
                result.Add(DisplayLineModel3D(new List<Tuple<Vector3, Vector3>>() { showLine }, new Color4(1f, 0, 0, 1f), 2f));
                var valueFloat = ValueFormat(paramValue.ToString(), valKey);
                result.Add(DisplayText3D($"   {resIndex} \r\n {valueFloat}", facetTextPoint));
            }

        }
        else
        {
            Logger.Info($"【面文本生成】 命中面{selFacetType},不是腰");
            //查找同类面
            List<Viewport3DTriangleEntity> facetTypeAll =
                ViewportManager.ViewportTriangle.FindAll(e => e.PlaneType == selFacetType);
            var groupedDic = facetTypeAll.GroupBy(entity => entity.PlaneCode)
                .ToDictionary(group => group.Key, group => group.ToList());
            Logger.Info($"【面文本生成】 同类面{groupedDic.Count}个");
            var valueIndex = 1;
            foreach (var kv in groupedDic)
            {
                var value = kv.Value;
                var key = kv.Key;
                var facetIndex = -1;
                int.TryParse(key.Split("_")[1], out facetIndex);
                List<Vector3> facetPoints = new List<Vector3>();
                value.ForEach(e => { facetPoints.Add(e.Point1); facetPoints.Add(e.Point2); facetPoints.Add(e.Point3); });
                var param = string.IsNullOrWhiteSpace(valKey) ? ViewportManager.DicFacetToValueParam.ContainsKey(selFacetType) ? ViewportManager.DicFacetToValueParam[selFacetType] : null : valKey;
                if (param == null)
                {
                    continue;
                }

                if (groupedDic.Count == 1)
                {
                    var paramValue = ViewportManager.DiamondData[$"{param}"];
                    if (paramValue == null)
                    {
                        Logger.Info($"【面文本生成】 {param} Key不存在");
                        continue;
                    }
                    var valueFloat = ValueFormat(paramValue.ToString(), param);
                    Logger.Info($"【面文本生成】 {valueFloat} -- {facetIndex}");
                    var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
                    result.Add(DisplayText3D($"{valueFloat}", facetTextPoint));

                } else if (groupedDic.Count == 16)
                {
                    facetIndex += 1;
                    valueIndex = facetIndex == 16 ? 1 : facetIndex % 2 == 0 ? valueIndex + 1 : valueIndex;
                    var detail = ViewportManager.DiamondData[$"{param}_DETAIL"];
                    if (detail == null)
                    {
                        Logger.Info($"【面文本生成】 {param}_DETAIL Key不存在");
                        continue;
                    }
                    Logger.Info($"【面文本生成】 {param}_DETAIL == {detail}");
                    var paramValue = detail[$"{param}_{valueIndex}"];
                    if (paramValue == null)
                    {
                        Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} Key不存在");
                        continue;
                    }
                    Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} ==={paramValue}");

                    var valueFloat = ValueFormat(paramValue.ToString(), param);
                    Logger.Info($"【面文本生成】 {valueFloat} -- {valueIndex}");
                    var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
                    result.Add(DisplayText3D($"   {facetIndex} \r\n {valueFloat}", new Vector3(facetTextPoint.X, facetTextPoint.Y + 0.1f, facetTextPoint.Z)));

                } else if (ViewportManager.DiamondData.Count > 1 && facetIndex != -1)
                {
                    facetIndex += 1;

                    var detail = ViewportManager.DiamondData[$"{param}_DETAIL"];
                    if (detail == null)
                    {
                        Logger.Info($"【面文本生成】 {param}_DETAIL Key不存在");
                        continue;
                    }
                    Logger.Info($"【面文本生成】 {param}_DETAIL == {detail}");
                    var paramValue = detail[$"{param}_{facetIndex}"];
                    if (paramValue == null)
                    {
                        Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{facetIndex} Key不存在");
                        continue;
                    }
                    Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{facetIndex} ==={paramValue}");

                    var valueFloat = ValueFormat(paramValue.ToString(), param);
                    Logger.Info($"【面文本生成】 {valueFloat} -- {facetIndex}");
                    var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
                    result.Add(DisplayText3D($"   {facetIndex} \r\n {valueFloat}", facetTextPoint));
                }
            }

            /***
             * 思路:
             * 1、以面分组,1组为台面、底面,8组、16组、64组、other
             * 2、每组数据区别
             *     1组:取第一个数据
             *     8组:按索引0-7 -> 1-8
             *    16组:1-2、3-4、5-6、7-8、9-10、11-12、13-14、15-0共享数据
             *    64组:这组特殊理论上是腰,按照else里的东西来
             * 3、这个方法是主动点击,被动触发理论上通用
             * 4、主动触发:循环遍历面组,根据面类型获取算法存储的数据,在Manager里制定面-参数的一对多关系,主动触发时,取参数的首位为默认
             * 5、被动触发:根据结果页传入的参数编号,找到对应的面,循环遍历面组,根据面类型获取算法存储的数据,根据被动传入参数找到值
             * 6、  ①组面可能由至少两个三角形组成,计算出三角形拼接出的多边形的中心作为文字显示的中心
             *      ②在从算法结果数据对应好面组的索引,做成值-组面id的文本,计算出这个文本的大小
             *      ③在拼接的图片中心,平行于平面,向中心点外偏移“文本大小高度+0.1"个单位 显示文本
             */

            // var selFaceVector = entities
            //     .SelectMany(entity => new[] { entity.Point1, entity.Point2, entity.Point3 })
            //     .Distinct()
            //     .ToList();
            // var uniqueLines = new HashSet<string>();
            // var sortedVectors = VectorClockwiseSort(selFaceVector);
            // for (int i = 0; i < sortedVectors.Count; i++)
            // {
            //     var current = sortedVectors[i];
            //     var next = sortedVectors[(i + 1) % sortedVectors.Count];
            //
            //     double length = (next - current).Length();
            //     string lineKey = $"{length:F2}";
            //     if (showAll == false)
            //     {
            //         if (uniqueLines.Contains(lineKey)) continue;
            //         uniqueLines.Add(lineKey);
            //     }
            //     var midPoint = (current + next) / 2;
            //     var text = $"{length:F2}mm";
            //     var textY = midPoint.Y > ViewportManager.CenterVector.Y ? midPoint.Y + 0.3f : midPoint.Y - 0.3f;
            //     var lengthTextModel = DisplayText3D(text, new Vector3(midPoint.X, textY, midPoint.Z),next - current, textColor);
            //     result.Add(lengthTextModel);
            // }
        }


        return result;
    }

    /// <summary>
    /// 生成选择的视图()
    /// </summary>
    /// <param name="triangleCode">三角形ID</param>
    /// <param name="selType">生成范围</param>
    /// <returns></returns>
    public static List<GeometryModel3D> GentrateChosenView(string triangleCode, string valKey = "", params SelShowType[] selType)
    {
        var res = ViewportManager.ViewportTriangle.Find(e => triangleCode.Equals(e.TriangleCode));
        if (res != null)
            return GentrateChosenView(res, valKey, selType);
        return new List<GeometryModel3D>();
    }

    /// <summary>
    /// 生成选择的视图(只生成,不添加!!)
    /// </summary>
    /// <param name="entity">选中的实体</param>
    /// <param name="selType">生成范围</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static List<GeometryModel3D> GentrateChosenView(Viewport3DTriangleEntity entity, string valKey = "", params SelShowType[] selType)
    {
        if (entity == null || entity.TriangleCode == null || entity.TriangleCode.Length == 0)
        {
            throw new Exception("Invalid Viewport3DTriangleEntity object!");
        }

        if (selType == null || selType.Length == 0)
        {
            throw new Exception("Invalid SelShowType collection");
        }
        List<GeometryModel3D> result = new List<GeometryModel3D>();

        //选中的面
        var selPanel = ViewportManager.ViewportTriangle.Where(e => entity.PlaneCode.Equals(e.PlaneCode)).ToList();
        //选中同类的面
        var selPanelType = ViewportManager.ViewportTriangle.Where(e => entity.PlaneType.Equals(e.PlaneType)).ToList();
        selPanel.ForEach(e => selPanelType.Remove(e));
        foreach (var type in selType)
        {
            switch (type)
            {
                case SelShowType.SelPanel:
                    //选中面的高亮
                    result.Add(GenerateModelByEntity(selPanel, ViewportManager.ColorConfig.SelFacetColor));
                    break;
                case SelShowType.Border:
                    //选中面边框的高亮
                    result.AddRange(GentrateLineByEntity(selPanel, ViewportManager.ColorConfig.SelBorderColor));
                    break;
                case SelShowType.IsTypePanel:
                    //选中面的同类面高亮
                    result.Add(GenerateModelByEntity(selPanelType, ViewportManager.ColorConfig.SelTypeColor));
                    break;
                case SelShowType.LengthText:
                    //选中面 每条边长度标记
                    // if(PlaneType.Girdle == entity.PlaneType)break;
                    result.AddRange(GenerateLineTextModels(selPanel, valKey));
                    break;
                case SelShowType.BorderAngle:
                    //选中面 每条边向内的夹角
                    if (PlaneType.Girdle == entity.PlaneType) break;
                    result.AddRange(GenerateLineAngleTextModels(selPanel));
                    break;
            }
        }
        //生成的需要添加的元素
        return result;
    }


    /// <summary>
    /// 生成线段夹角文本(不绘制)
    /// </summary>
    /// <param name="entities">线集合</param>
    /// <param name="textColor">文本颜色(默认红)</param>
    /// <param name="showAll">是否显示全部(默认否)</param>
    /// <returns></returns>
    public static List<GeometryModel3D> GenerateLineAngleTextModels(List<Viewport3DTriangleEntity> entities,
        Color4? textColor = null, bool showAll = false)
    {
        var result = new List<GeometryModel3D>();
        var uniqueAngles = new HashSet<string>();
        var selFaceVector = entities
            .SelectMany(entity => new[] { entity.Point1, entity.Point2, entity.Point3 })
            .Distinct()
            .ToList();

        var sortedVectors = VectorClockwiseSort(selFaceVector);

        for (int i = 0; i < sortedVectors.Count; i++)
        {
            int prevIndex = (i - 1 + sortedVectors.Count) % sortedVectors.Count;
            int nextIndex = (i + 1) % sortedVectors.Count;

            var p1 = sortedVectors[prevIndex];
            var p2 = sortedVectors[i];
            var p3 = sortedVectors[nextIndex];

            // 向量
            var v1 = Vector3.Normalize(p1 - p2);
            var v2 = Vector3.Normalize(p3 - p2);

            // 计算内角(考虑方向性)
            double angle = Math.Acos(Vector3.Dot(v1, v2)) * (180 / Math.PI);

            string angleKey = $"{angle:F2}"; // 唯一标识
            if (showAll == false)
            {
                if (uniqueAngles.Contains(angleKey)) continue;
                uniqueAngles.Add(angleKey);
            }

            // 显示内角
            var text = $"{angle:F2}°";
            var textY = p2.Y > ViewportManager.CenterVector.Y ? p2.Y + 0.3f : p2.Y - 0.3f;
            var angleTextModel = DisplayText3D(text, new Vector3(p2.X, textY, p2.Z), textColor);
            result.Add(angleTextModel);
        }

        return result;
    }

    #endregion

    /// <summary>
    /// 旋转主体
    /// </summary>
    /// <param name="axis">中心</param>
    /// <param name="hasLine">是否包含线</param>
    /// <param name="speed">旋转时间  秒</param>
    public static void RotateModel(Vector3D axis, bool hasLine = true, int speed = 7, int to = 360)
    {
        ViewportManager.GetViewport().ViewportRightMenuShowModelFaceByType.IsChecked = false;
        ViewportManager.ClearDicModels();
        ViewportManager.ClearMeshLines();
        ViewportManager.DoubleClickSelect = false;

        // 设置旋转的中心点和旋转轴
        var rotateTransform = new RotateTransform3D();
        var rotation = new AxisAngleRotation3D(axis, 0);
        rotateTransform.Rotation = rotation;
        rotateTransform.CenterX = ViewportManager.CenterVector.X;
        rotateTransform.CenterY = ViewportManager.CenterVector.Y;
        rotateTransform.CenterZ = ViewportManager.CenterVector.Z;

        // 将旋转变换应用到模型
        ViewportManager.MainModel3D.Transform = rotateTransform;
        if (hasLine)
            ViewportManager.MainModelLines.ForEach(e => e.Transform = rotateTransform);

        double currentAngle = rotation.Angle;
        // 创建旋转动画
        var rotateAnimation = new DoubleAnimation
        {
            From = currentAngle,
            To = to + currentAngle,
            Duration = new Duration(TimeSpan.FromSeconds(speed)),
            FillBehavior = FillBehavior.HoldEnd
        };

        // 应用动画
        rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, rotateAnimation);
    }

    /// <summary>
    /// 在场景中添加文字
    /// </summary>
    /// <param name="text">文字</param>
    /// <param name="position">位置</param>
    /// <returns></returns>
    public static BillboardTextModel3D DisplayText3D(string text, Vector3 position, Color4? color = null)
    {
        var billboardTextModel = new BillboardTextModel3D();
        var billboardText = new BillboardText3D();
        billboardText.TextInfo.Add(new TextInfo(text, position)
        {
            Foreground = color ?? ViewportManager.ColorConfig.SelFontColor,
            Scale = 0.8f,
            VerticalAlignment = BillboardVerticalAlignment.Center,
            HorizontalAlignment = BillboardHorizontalAlignment.Center

        });
        billboardTextModel.Geometry = billboardText;
        return billboardTextModel;
    }
    /// <summary>
    /// 在场景中添加文字
    /// </summary>
    /// <param name="text"></param>
    /// <param name="position"></param>
    /// <param name="direction"></param>
    /// <param name="color"></param>
    /// <returns></returns>
    public static BillboardTextModel3D DisplayText3D(string text, Vector3 position, Vector3 direction, Color4? color = null)
    {
        // 计算线段方向的角度
        double angle = Math.Atan2(direction.Y, direction.X) * (180 / Math.PI);

        var billboardTextModel = new BillboardTextModel3D()
        {
            Geometry = new BillboardText3D()
            {
                TextInfo = new ObservableCollection<TextInfo>()
                {
                    new TextInfo(text, position){
                        Foreground = color ?? ViewportManager.ColorConfig.SelFontColor,
                        Scale = 0.5f,
                        Offset = new Vector2(0.2f, 0.2f),
                        // Angle = (float)angle // 设置文字的旋转角度
                    }
                }
            },
            DepthBias = -99,
            SlopeScaledDepthBias = 1.0f,
            IsDepthClipEnabled = true
        };


        return billboardTextModel;
    }
    /// <summary>
    /// 生成线对象
    /// </summary>
    /// <param name="points">点集合(自动闭环)</param>
    /// <param name="lineColor">线颜色</param>
    /// <param name="thickness">线粗细 默认1</param>
    /// <returns></returns>
    public static LineGeometryModel3D DisplayLineModel3D(List<Vector3> points, Color4 lineColor,
        double thickness = 1.0)
    {
        var edgeLines = new List<Tuple<Vector3, Vector3>>();
        for (int i = 0; i < points.Count - 1; i++)
        {
            var nowItem = points[i];
            var nextItem = points[i + 1];
            edgeLines.Add(new Tuple<Vector3, Vector3>(nowItem, nextItem));

        }
        edgeLines.Add(new Tuple<Vector3, Vector3>(points.Last(), points.First()));
        return DisplayLineModel3D(edgeLines, lineColor, thickness);
    }
    /// <summary>
    /// 在正方向生成相机
    /// </summary>
    /// <param name="positiveDirection"></param>
    /// <param name="boundingBox"></param>
    /// <param name="fieldOfView"></param>
    /// <param name="aspectRatio"></param>
    /// <returns></returns>
    public static HelixToolkit.Wpf.SharpDX.OrthographicCamera CalculateCamera(Vector3 positiveDirection, BoundingBox boundingBox, double fieldOfView = 45, double aspectRatio = 16.0 / 9.0)
    {
        // 单位化正方向
        var normalizedDirection = Vector3.Normalize(positiveDirection);

        // 计算模型中心和最大尺寸
        var center = boundingBox.Center;                // 包围盒中心
        var maxDimension = boundingBox.Size.Length();   // 包围盒对角线长度

        // 计算视场角的一半(弧度制)
        var halfFov = Math.PI * fieldOfView / 360.0;

        // 计算相机距离
        var distance = maxDimension / (2 * Math.Tan(halfFov));

        // 相机位置和朝向
        var cameraPosition = center - normalizedDirection * (float)distance; // 沿正方向放置相机
        var lookDirection = center - cameraPosition;                        // 朝向模型中心

        double width = ViewportManager.calCameraWidth();

        // 创建并返回相机
        return new HelixToolkit.Wpf.SharpDX.OrthographicCamera
        {
            Position = cameraPosition.ToPoint3D(),
            LookDirection = lookDirection.ToVector3D(),
            UpDirection = new Vector3D(0, 1, 0), // 默认全局 Y 轴为上方向
            NearPlaneDistance = 0.1f,
            FarPlaneDistance=1000,
            Width = width
        };
    }

    /// <summary>
    /// 绘制箭头(相机指向模型中心)
    /// </summary>
    /// <param name="cameraPosition">相机位置</param>
    /// <param name="modelCenter">中心位置</param>
    /// <param name="modelBounds">模型</param>
    /// <param name="totalLength">箭头总长度 D:5</param>
    /// <param name="cylinderRatio">圆柱部分占比 0.7</param>
    /// <param name="diameter">箭头直径 1</param>
    /// <param name="headDiameterRatio">圆锥直径与圆柱直径的比例 1.5</param>
    /// <param name="padding">模型边界范围 1</param>
    /// <returns></returns>
    public static MeshGeometryModel3D CreateArrow(
        Vector3 cameraPosition,
        Vector3 modelCenter,
        BoundingBox modelBounds,
        float totalLength = 1.5f,    // 箭头总长度
        float cylinderRatio = 0.7f,// 圆柱部分占比
        float diameter = 0.25f,     // 箭头直径
        float headDiameterRatio = 2f, // 圆锥直径与圆柱直径的比例
        float padding = 1.0f
        )
    {
        // 计算模型的半径(对角线的一半)
        var modelSize = modelBounds.Size;
        var modelRadius = modelSize.Length() / 2;

        // 计算方向向量(从相机位置指向模型中心)
        var direction = Vector3.Normalize(modelCenter - cameraPosition);

        // 调整箭头起点,避免与模型交集
        var adjustedStart = modelCenter - direction * (modelRadius + padding);

        // 计算圆柱和圆锥部分长度
        float cylinderLength = totalLength * cylinderRatio;
        float coneLength = totalLength - cylinderLength;

        // 箭头圆柱终点
        var cylinderEnd = adjustedStart + direction * cylinderLength;

        // 箭头终点(圆锥部分终点)
        var arrowEnd = cylinderEnd + direction * coneLength;

        // 创建箭头几何体
        var builder = new MeshBuilder();

        // 添加圆柱部分
        builder.AddCylinder(adjustedStart, cylinderEnd, diameter, 20);

        // 添加圆锥部分
        builder.AddCone(cylinderEnd, arrowEnd, diameter * headDiameterRatio, true, 20);

        // 设置箭头自发光材质
        var material = new PhongMaterial
        {
            DiffuseColor = Color.Red,      // 箭头的基本颜色
            EmissiveColor = Color.Red     // 箭头自发光颜色
        };



        // 创建 3D 模型
        return new MeshGeometryModel3D
        {
            Geometry = builder.ToMeshGeometry3D(),
            Material = material
        };
    }


    /// <summary>
    /// 生成线对象
    /// </summary>
    /// <param name="points">线段集合</param>
    /// <param name="lineColor">线段颜色</param>
    /// <param name="thickness">线段粗细</param>
    /// <returns></returns>
    public static LineGeometryModel3D DisplayLineModel3D(List<Tuple<Vector3, Vector3>> points, Color4 lineColor,
        double thickness = 1.0)
    {
        var lineBuilder = new LineBuilder();
        foreach (var line in points)
        {
            lineBuilder.AddLine(line.Item1, line.Item2);
        }


        var edgeLinesModel = new LineGeometryModel3D
        {
            Geometry = lineBuilder.ToLineGeometry3D(),
            Color = lineColor.ToColor(),
            Thickness = thickness,
        };
        return edgeLinesModel;
    }

    /// <summary>
    /// 根据视图中模型生成光照
    /// </summary>
    /// <param name="viewport"></param>
    /// <returns></returns>
    public static List<Light3D> GenerateLightingForModel(Viewport3DX viewport)
    {

        List<Light3D> result = new List<Light3D>();

        var models = viewport.Items.OfType<MeshGeometryModel3D>();
        if (!models.Any()) throw new Exception("Model in view not found");
        var largestModel = models
            .OrderByDescending(m => GetBoundingBoxVolume(m.Geometry.Bound))
            .FirstOrDefault();
        if (largestModel == null) throw new Exception("Model in view not found");
        var boundingBox = largestModel.Geometry.Bound;
        var size = boundingBox.Size;
        var center = boundingBox.Center;
        ViewportManager.CenterVector = center;
        ViewportManager.ModelBounds = boundingBox;
        var yao = CalculateCenter(ViewportManager.GirdleTopLines, ViewportManager.GirdleBottomLines);
        var corners = new List<Point3D>
        {
            new Point3D(boundingBox.Minimum.X-0.5, boundingBox.Minimum.Y-boundingBox.Maximum.Y/2, boundingBox.Minimum.Z-0.5), // 右下后
            new Point3D(boundingBox.Maximum.X+0.5, boundingBox.Minimum.Y-boundingBox.Maximum.Y/2, boundingBox.Minimum.Z-0.5), // 右下后
            new Point3D(boundingBox.Minimum.X-0.5, boundingBox.Minimum.Y-boundingBox.Maximum.Y/2, boundingBox.Maximum.Z+0.5), // 左下前
            new Point3D(boundingBox.Maximum.X+0.5, boundingBox.Minimum.Y-boundingBox.Maximum.Y/2, boundingBox.Maximum.Z+0.5),  // 右下前
            
            // new Point3D(boundingBox.Minimum.X-1, yao.Y, boundingBox.Minimum.Z-1), // 右下后
            // new Point3D(boundingBox.Maximum.X+1, yao.Y, boundingBox.Minimum.Z-1), // 右下后
            // new Point3D(boundingBox.Minimum.X-1, yao.Y, boundingBox.Maximum.Z+1), // 左下前
            // new Point3D(boundingBox.Maximum.X+1, yao.Y, boundingBox.Maximum.Z+1),  // 右下前
            
            new Point3D(boundingBox.Minimum.X-0.5, boundingBox.Maximum.Y+boundingBox.Maximum.Y/4, boundingBox.Minimum.Z-0.5), // 左上后
            new Point3D(boundingBox.Maximum.X+0.5, boundingBox.Maximum.Y+boundingBox.Maximum.Y/4,boundingBox.Maximum.Z+0.5),                                               // 右上前
            new Point3D(boundingBox.Maximum.X+0.5, boundingBox.Maximum.Y+boundingBox.Maximum.Y/4, boundingBox.Minimum.Z-0.5), // 右上后
            new Point3D(boundingBox.Minimum.X-0.5, boundingBox.Maximum.Y+boundingBox.Maximum.Y/4, boundingBox.Maximum.Z+0.5), // 左上前
        };
        for (int i = 0; i < corners.Count; i++)
        {
            var corner = corners[i];
            var color = i % 2 == 0 ? Colors.LightGoldenrodYellow : Colors.LightSkyBlue;
            var pointLight = new PointLight3D
            {
                Position = corner,
                Color = color,
                Range = (float)size.Length()
            };
            result.Add(pointLight);
        }
        // var topLightPositions = new List<Point3D>
        // {
        //     new Point3D(center.X, center.Y, center.Z),
        // };
        // foreach (var position in topLightPositions)
        // {
        //     var topLight = new PointLight3D
        //     {
        //         Position = position,
        //         Color = Colors.LightGoldenrodYellow,
        //         Range = (float)size.Length() * 0.5, // 增加光的照射范围
        //         Attenuation = new Vector3D(1, 0.1f, 0.05f) // 控制光的衰减,使光在距离内更有效
        //     };
        //     result.Add(topLight);
        // }
        // 添加环境光以柔化整体效果并增加亮度
        result.Add(new AmbientLight3D
        {
            Color = Colors.LightGray
        });

        result.Add(new AmbientLight3D
        {
            Color = Colors.Gray // 设置环境光颜色
        });

        RemoveLightingInViewport(viewport);
        result.ForEach(e => viewport.Items.Add(e));
        return result;
    }

    public static Vector3 GetCenterOfTriangles(List<Viewport3DTriangleEntity> triangles)
    {
        if (triangles == null || triangles.Count == 0)
            throw new ArgumentException("The list of triangles cannot be null or empty.");

        // 累加所有顶点的坐标
        Vector3 total = Vector3.Zero;
        int vertexCount = 0;

        foreach (var triangle in triangles)
        {
            total += triangle.Point1;
            total += triangle.Point2;
            total += triangle.Point3;
            vertexCount += 3; // 每个三角形有3个顶点
        }

        // 计算平均坐标
        return total / vertexCount;
    }

    public static Vector3 CalculateCenter(List<Vector3> girdleTopLines, List<Vector3> girdleBottomLines)
    {
        // 计算 GirdleTopLines 的中心点
        Vector3 topCenter = GetCenter(girdleTopLines);

        // 计算 GirdleBottomLines 的中心点
        Vector3 bottomCenter = GetCenter(girdleBottomLines);

        // 计算两个中心点的中点作为垂直方向的中心点
        Vector3 centerInVertical = new Vector3(
            (topCenter.X + bottomCenter.X) / 2,
            (topCenter.Y + bottomCenter.Y) / 2,
            (topCenter.Z + bottomCenter.Z) / 2
        );

        return centerInVertical;
    }
    /// <summary>
    /// 删除视图中的照明
    /// </summary>
    /// <param name="viewport"></param>
    public static void RemoveLightingInViewport(Viewport3DX viewport)
    {
        List<Light3D> lights = new List<Light3D>();
        foreach (var item in viewport.Items)
        {
            if (item is Light3D light3D)
            {
                lights.Add(light3D);
            }
        }
        lights.ForEach(item => viewport.Items.Remove(item));
    }
    private static Dictionary<Guid, Guid> moveLines = new Dictionary<Guid, Guid>();
    public static void InitMeshLines()
    {
        moveLines = new();
    }
    /// <summary>
    /// 网状参考线
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="thickness"></param>
    /// <returns></returns>
    public static List<LineGeometryModel3D> ShowMeshLines(bool isCrown = true, double thickness = 0.2)
    {
        List<LineGeometryModel3D> lines = new();
        var Y = -0.01F;
        if (!isCrown)
        {
            Y = ViewportManager.ModelBounds.Maximum.Y + 0.01f;
        }
        var center = ViewportManager.CenterVector;
        center.Y = Y;
        Viewport3DTriangleEntity firstPoint = ViewportManager.ViewportTriangle.Where(x => x.PlaneType == PlaneType.TableFacet).FirstOrDefault();

      
        var lineCal = new LineCalculationHelper(firstPoint.Point1, center);
        
        var edgeLines = new List<Tuple<Vector3, Vector3>>();
        Color4 XlineColor =new Color4(80f, 0f, 0f, 1f);
        float r =5;
        if(double.TryParse(ViewportManager.DiamondData["M2"].ToString(), out var v))
        {
            r = (float)(v*0.51);
        }
       
        edgeLines = new List<Tuple<Vector3, Vector3>>();
        var XLine = lineCal.calXline(r);
        edgeLines.Add(XLine);
        lines.Add(DisplayLineModel3D(edgeLines, XlineColor, thickness));

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(XLine, 2));
        var lineA = DisplayLineModel3D(edgeLines, XlineColor, thickness);
        lines.Add(lineA);
       
        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(XLine, -2));
        var lineB = DisplayLineModel3D(edgeLines, XlineColor, thickness);
        lines.Add(lineB);
        bindingMoveLine(lineA, lineB);

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(XLine, 4));
        var lineE = DisplayLineModel3D(edgeLines, XlineColor, thickness);
        lines.Add(lineE);

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(XLine, -4));
        var lineF = DisplayLineModel3D(edgeLines, XlineColor, thickness);
        lines.Add(lineF);
        bindingMoveLine(lineE, lineF);

        Color4 YlineColor = new Color4(0F, 80f, 0f, 1f);
        edgeLines = new List<Tuple<Vector3, Vector3>>();
        var YLine = lineCal.calYline(r);
        edgeLines.Add(YLine);
        lines.Add(DisplayLineModel3D(edgeLines, YlineColor, thickness));

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(YLine, 2));
        var lineC = DisplayLineModel3D(edgeLines, YlineColor, thickness);
        lines.Add(lineC);

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(YLine, -2));
        var lineD = DisplayLineModel3D(edgeLines, YlineColor, thickness);
        lines.Add(lineD);
        bindingMoveLine(lineC, lineD);

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(YLine, 4));
        var lineG = DisplayLineModel3D(edgeLines, YlineColor, thickness);
        lines.Add(lineG);

        edgeLines = new List<Tuple<Vector3, Vector3>>();
        edgeLines.Add(lineCal.calLineOfOffset(YLine, -4));
        var lineH = DisplayLineModel3D(edgeLines, YlineColor, thickness);
        lines.Add(lineH);
        bindingMoveLine(lineG, lineH);
        return lines;
    }
    private static readonly double HitTestThickness = 5;
    /// <summary>
    /// 网状参考线 对向移动绑定
    /// </summary>
    /// <param name="lineA"></param>
    /// <param name="lineB"></param>
    private static void bindingMoveLine(LineGeometryModel3D lineA, LineGeometryModel3D lineB)
    {
        lineA.HitTestThickness = HitTestThickness;
        lineA.MouseDown3D += LineA_MouseDown3D;
        lineA.MouseUp3D += LineA_MouseUp3D;
        lineA.MouseMove3D += LineA_MouseMove3D;
        moveLines.Add(lineA.GUID, lineB.GUID);
        lineB.HitTestThickness = HitTestThickness;
        lineB.MouseDown3D += LineA_MouseDown3D;
        lineB.MouseUp3D += LineA_MouseUp3D;
        lineB.MouseMove3D += LineA_MouseMove3D;
        moveLines.Add(lineB.GUID, lineA.GUID);
    }
    private static bool isDrawing = false;
    private static Point startDragPoint = new Point();
    private static Transform3D initialTransform;
    private static Transform3D initialOtherTransform;
    private static void LineA_MouseMove3D(object sender, RoutedEventArgs e)
    {
        if (isDrawing)
        {
            if (e is HelixToolkit.Wpf.SharpDX.MouseMove3DEventArgs ev)
            {
                var line = sender as LineGeometryModel3D;
                var Y = line.Geometry.Positions[0].Y;
                // 定义中心点和半径
                var center = ViewportManager.CenterVector;
                center.Y = Y;
                double radius = 5;
                if (double.TryParse(ViewportManager.DiamondData["M2"].ToString(), out var v))
                {
                    radius = (v * 0.5);
                }

                var minDistance = 0.01;
                // 直线方向分量
                var lineDirection = line.Geometry.Positions[1] - line.Geometry.Positions[0];
                lineDirection.Normalize();
                // 现在鼠标对于3d模型的位置
                var mousePosition = ev.Position;
                var currentMousePosition = Get3DPointFromMouse(mousePosition);
                currentMousePosition.Y = Y;
                var hitPoint = Get3DPointFromMouse(startDragPoint); 
                hitPoint.Y = Y;
                // 计算鼠标移动的方向
                var moveDirection = currentMousePosition - hitPoint;
                // 计算垂直于线的移动分量
                var perpendicularDirection = Vector3D.CrossProduct(lineDirection.ToVector3D(), Vector3D.CrossProduct(moveDirection, lineDirection.ToVector3D()));
                perpendicularDirection.Normalize();

                double scaleFactor = 0.7; // 缩放因子
                // 计算垂直距离
                double perpendicularDistance = Vector3D.DotProduct(moveDirection, perpendicularDirection);
                
                // 垂直方向偏移量
                Vector3D projectedVector = perpendicularDistance * perpendicularDirection * scaleFactor;
                projectedVector.Y = 0;
                Console.WriteLine($"距离:{perpendicularDistance}\t 移动分量:{perpendicularDirection.X},{perpendicularDirection.Y},{perpendicularDirection.Z}\t偏移量:{projectedVector.X},\t{projectedVector.Z}");
                // 计算直线的新位置
                var transform = new TranslateTransform3D(projectedVector);
                var newTransform = new MatrixTransform3D(transform.Value * initialTransform.Value);
                var newProjectedVector = new Vector3D(newTransform.Matrix.OffsetX ,0, newTransform.Matrix.OffsetZ);
                var newPosition1 = line.Geometry.Positions[0].ToVector3D();
                newPosition1.X += newTransform.Matrix.OffsetX;
                newPosition1.Z += newTransform.Matrix.OffsetZ;
                var newPosition2 = line.Geometry.Positions[1].ToVector3D();
                newPosition2.X += newTransform.Matrix.OffsetX;
                newPosition2.Z += newTransform.Matrix.OffsetZ;
                // 计算直线的新中心点
                Point3D newCenter = new Point3D(
                    (newPosition1.X + newPosition2.X) / 2,
                    (newPosition1.Y + newPosition2.Y) / 2,
                    (newPosition1.Z + newPosition2.Z) / 2
                );

                // 计算上一帧中心点与中心点的距离
                Point3D previousCenter = new Point3D(
                    (line.Geometry.Positions[0].X + line.Geometry.Positions[1].X) / 2,
                    (line.Geometry.Positions[0].Y + line.Geometry.Positions[1].Y) / 2,
                    (line.Geometry.Positions[0].Z + line.Geometry.Positions[1].Z) / 2
                );
                
                // 检查新中心点是否满足距离条件
                if (IsPointInRange(newCenter, center.ToPoint3D(), radius, minDistance))
                {

                }
                else
                {
                    //// 如果新中心点不满足条件,将位置限制在范围内
                    //projectedVector = LimitToRange(newCenter, center.ToPoint3D(), radius, minDistance) - newCenter;
                    // 如果新中心点超出范围,将直线位置固定到最大允许位置
                    Point3D maxCenter = LimitToMaxPosition(center.ToPoint3D(), radius, newCenter);
                    // 计算直线的起点和终点在最大允许位置
                    newProjectedVector = maxCenter - previousCenter;
                    projectedVector.Y = 0;
                    
                    transform = new TranslateTransform3D(newProjectedVector);
                    newTransform = new MatrixTransform3D(transform.Value);
                    //Logger.Info($"X:{projectedVector.X},Z:{projectedVector.Z}");
                    Logger.Info("超出范围,停止移动");
                }

                line.Transform = newTransform;
           
                // 更新上一帧的鼠标位置
                // previousMousePosition = currentMousePosition;
                var otherLineGuid = moveLines[line.GUID];
                var Viewport = ViewportManager.GetViewport3D();
                var otherLine = Viewport.Items.Where(x => x.GUID == otherLineGuid).FirstOrDefault();
                if (otherLine != null)
                {
                    var otherTranslateTransform = new TranslateTransform3D(-newProjectedVector);
                    otherLine.Transform = otherTranslateTransform;
                }
            }
        }
    }
    // 检查点是否在范围内(距离大于 minDistance 且小于等于 radius)
    private static bool IsPointInRange(Point3D point, Point3D center, double radius, double minDistance)
    {
        double distance = (point - center).Length;
        Logger.Info("距离:" + distance);
        return distance > minDistance && distance <= radius;
    }

    private static Point3D LimitToMaxPosition(Point3D center, double radius, Point3D currentCenter)
    {
        // 计算当前中心点与中心点的方向
        Vector3D direction = currentCenter - center;
        direction.Normalize();

        // 计算最大允许位置
        return center + direction * radius;
    }

    private static void LineA_MouseUp3D(object sender, RoutedEventArgs e)
    {
        isDrawing = false;
        var Viewport = ViewportManager.GetViewport3D();
        Viewport.Cursor = Cursors.Arrow;
        startDragPoint = new Point();
    }

    private static void LineA_MouseDown3D(object sender, RoutedEventArgs e)
    {
        isDrawing = true;
        if(e is HelixToolkit.Wpf.SharpDX.MouseDown3DEventArgs ev){
            var Viewport = ViewportManager.GetViewport3D();
            Viewport.Cursor = Cursors.SizeAll;
            startDragPoint = ev.Position;
            var line = sender as LineGeometryModel3D;
            initialTransform = line.Transform ?? Transform3D.Identity;
            // var line = sender as LineGeometryModel3D;
            var otherLineGuid = moveLines[line.GUID];
            var otherLine = Viewport.Items.Where(x => x.GUID == otherLineGuid).FirstOrDefault();
            if (otherLine!= null)
            {
                initialOtherTransform = otherLine.Transform ?? Transform3D.Identity;
            }
        }
    }
    private static Point3D Get3DPointFromMouse(Point mousePosition)
    {
        // 使用 HelixToolkit 的 Ray3D 和 Plane3D
        var Viewport = ViewportManager.GetViewport3D();

        // 获取射线
        var ray = GetRayFromMouse(mousePosition, Viewport);
        // 创建平面(假设平面为 Y=0)
        var plane = new Plane3D(new Point3D(0,0,0), new Vector3D(0, 1, 0));

        // 计算射线与平面的交点
        var intersection = GetIntersection(ray, plane);

        if (intersection == null)
        {
            // 如果没有交点,返回默认值或抛出异常
            throw new InvalidOperationException("No intersection found.");
        }
        return intersection.Value;
    }

    private static Ray3D GetRayFromMouse(Point mousePosition, Viewport3DX viewport)
    {
        // 将鼠标坐标转换为归一化设备坐标 (NDC)
        var ndc = new Vector2(
            (float)(2.0 * mousePosition.X / viewport.ActualWidth - 1.0),
            (float)(1.0 - 2.0 * mousePosition.Y / viewport.ActualHeight)
        );
        // 使用 UnProject 方法获取射线
        // var ray = viewport.UnProject(ndc);
        var cameraPosition = viewport.Camera.Position;
        var cameraLookDirection = viewport.Camera.LookDirection;
        var cameraUpDirection = viewport.Camera.UpDirection;
        var cameraRightDirection = Vector3D.CrossProduct(cameraLookDirection, cameraUpDirection);
        var ray = (cameraLookDirection + ndc.X * cameraRightDirection + ndc.Y * cameraUpDirection);
        ray.Normalize();
        // 返回射线
        return new Ray3D(cameraPosition, ray);
    }

    private static Point3D? GetIntersection(Ray3D ray, Plane3D plane)
    {
        // 计算射线方向与平面法向量的点积
        double denominator = Vector3D.DotProduct(ray.Direction, plane.Normal);

        // 如果点积为 0,说明射线与平面平行,没有交点
        if (Math.Abs(denominator) < 1e-6)
            return null;

        // 计算射线起点到平面的距离
        double t = Vector3D.DotProduct(plane.Position - ray.Origin, plane.Normal) / denominator;

        // 如果 t 为负数,说明交点在射线起点后方
        if (t < 0)
            return null;

        // 返回交点
        return ray.Origin + ray.Direction * t;
    }

    //private static Point3D? GetIntersection(Ray3D ray, Plane3D plane)
    //{
    //    // 将射线转换为直线(起点和终点)
    //    Point3D rayEnd = ray.Origin + ray.Direction * 1000; // 延长射线

    //    // 使用 Plane3D.LineIntersection 方法计算交点
    //    return plane.LineIntersection(ray.Origin, rayEnd);
    //}
    private static double initialRadius = 1.0; // 初始半径
    /// <summary>
    /// 圆圈参考线
    /// </summary>
    /// <param name="radius"></param>
    /// <param name="thickness"></param>
    /// <returns></returns>
    public static LineGeometryModel3D ShowCircleLine(bool isCrown = true, double radius = 1.0, double thickness = 0.2)
    {
        var Y = -0.01F;
        if (!isCrown)
        {
            Y = ViewportManager.ModelBounds.Maximum.Y + 0.01f;
        }
        var center = ViewportManager.CenterVector;
        center.Y = Y;
        var Circle = UpdateCircleGeometry(center, initialRadius, thickness);
        Circle.HitTestThickness = HitTestThickness;
        Circle.MouseDown3D += Circle_MouseDown3D;
        Circle.MouseUp3D += Circle_MouseUp3D;
        Circle.MouseMove3D += Circle_MouseMove3D;
        return Circle;
    }
    private static LineGeometryModel3D UpdateCircleGeometry(Vector3 center, double radius = 1.0, double thickness = 1.0)
    {
        // 生成圆形线的点
        int segments = 100; // 圆的细分段数
        var positions = new List<Vector3>();
        var indices = new List<int>();

        for (int i = 0; i < segments; i++)
        {
            float angle = (float)(2 * Math.PI * i / segments);
            float x = (float)(center.X + radius * Math.Cos(angle));
            float y = (float)(center.Y);
            float z = (float)(center.Z + radius * Math.Sin(angle));

            positions.Add(new Vector3(x, y, z));
            indices.Add(i);
            indices.Add((i + 1) % segments);
        }
        var Circle = DisplayLineModel3D(positions, Colors.Orange.ToColor4(),thickness);

        // 更新圆形线的几何形状
        return Circle;
    }

    private static void Circle_MouseMove3D(object sender, RoutedEventArgs e)
    {
        if (isDrawing)
        {
            if (e is HelixToolkit.Wpf.SharpDX.MouseMove3DEventArgs ev)
            {
                var line = sender as LineGeometryModel3D;

                if (line==null)
                {
                    return;
                }
                var MinRadius = 0.1;
                var MaxRadius = (ViewportManager.ModelBounds.Maximum.X - ViewportManager.ModelBounds.Minimum.X) * 0.6;
                // 现在鼠标对于3d模型的位置
                var mousePosition = ev.Position;
                var Y = line.Geometry.Positions[0].Y;
                var center = ViewportManager.CenterVector;
                center.Y = Y;

                Point3D mouseWorldPosition = Get3DPointFromMouse(mousePosition);
                mouseWorldPosition.Y = Y;
                // Console.WriteLine($"鼠标在3D模型中的位置:{mouseWorldPosition.X},{mouseWorldPosition.Y},{mouseWorldPosition.Z}");
                // 计算鼠标与圆心的距离
                double distance = CalculateDistance(mouseWorldPosition, center.ToPoint3D());
                // Console.WriteLine($"与圆心之间距离{distance}");
                double scaleFactor = 0.7;

                // 计算新的半径
                double newRadius = distance * scaleFactor; // 缩放因子

                // 限制半径范围
                newRadius = Math.Clamp(newRadius, MinRadius, MaxRadius);

                var scaleTransform = new ScaleTransform3D(newRadius, 1, newRadius); // 缩放变换
                line.Transform = scaleTransform;
            }
        }
    }
    // 计算两点之间的距离
    private static double CalculateDistance(Point3D p1, Point3D p2)
    {
        double dx = p2.X - p1.X;
        double dy = p2.Y - p1.Y;
        double dz = p2.Z - p1.Z;

        return Math.Sqrt(dx * dx + dy * dy + dz * dz);
    }
    private static void Circle_MouseUp3D(object sender, RoutedEventArgs e)
    {
        isDrawing = false;
        var Viewport = ViewportManager.GetViewport3D();
        Viewport.Cursor = Cursors.Arrow;
        // 释放鼠标捕获
        Viewport.ReleaseMouseCapture();
    }

    private static void Circle_MouseDown3D(object sender, RoutedEventArgs e)
    {
        isDrawing = true;
        if (e is HelixToolkit.Wpf.SharpDX.MouseDown3DEventArgs ev)
        {
            var line = sender as LineGeometryModel3D;
            var Viewport = ViewportManager.GetViewport3D();
            Viewport.Cursor = Cursors.SizeAll;
            // 捕获鼠标
            Viewport.CaptureMouse();
        }
    }
    public static bool IsCrown()
    {
        bool isCrown = false;
        var camera = ViewportManager.GetViewport3D().Camera;
        if (camera.LookDirection.Y >= 0 && camera.UpDirection.Y <= 0)
        {
            isCrown = true;
        }
        return isCrown;
    }
    #region 私有方法

    /// <summary>
    /// 向量按中心点顺时针排序
    /// </summary>
    /// <param name="points"></param>
    /// <returns></returns>
    public static List<Vector3> VectorClockwiseSort(List<Vector3> points)
    {
        Vector3 center = GetCentroid(points);
        return VectorClockwiseSort(points, center);
    }
    
    /// <summary>
    /// 向量按中心点顺时针排序
    /// </summary>
    /// <param name="points"></param>
    /// <param name="center"></param>
    /// <returns></returns>
    public static List<Vector3> VectorClockwiseSort(List<Vector3> points, Vector3 center)
    {
        points.Sort((v1, v2) =>
        {
            double angle1 = Math.Atan2(v1.Z - center.Z, v1.X - center.X); 
            double angle2 = Math.Atan2(v2.Z - center.Z, v2.X - center.X); 
            return angle1.CompareTo(angle2); 
        });
        return points;
    }
    
    private static Vector3 GetCenter(List<Vector3> points)
    {
        float x = points.Average(p => p.X);
        float y = points.Average(p => p.Y);
        float z = points.Average(p => p.Z);
        return new Vector3(x, y, z);
    }

    /// <summary>
    /// 计算点集合的中心点(几何质心)
    /// </summary>
    /// <param name="vectors"></param>
    /// <returns></returns>
    public static Vector3 GetCentroid(List<Vector3> vectors)
    {
        float x = vectors.Sum(v => v.X) / vectors.Count;
        float y = vectors.Sum(v => v.Y) / vectors.Count;
        float z = vectors.Sum(v => v.Z) / vectors.Count;
        return new Vector3(x, y, z);
    }
    public static Vector3 GetOffsetCenter(List<Vector3> facetVector, Vector3 center, float dev = 0.4f)
    {
        // 1. 去重 facetVector
        var distinctFacetVector = facetVector.Distinct().ToList();

        // 2. 计算多边形的几何中心
        Vector3 polygonCenter = GetCentroid(distinctFacetVector);

        // 3. 计算从模型中心点到几何中心的向量
        Vector3 direction = polygonCenter - center;

        // 4. 归一化方向向量并根据偏移量 dev 计算最终的偏移位置
        Vector3 offsetCenter = polygonCenter + Vector3.Normalize(direction) * dev;

        return offsetCenter;
    }
    /// <summary>
    /// 计算夹角度数
    /// </summary>
    /// <param name="v1"></param>
    /// <param name="v2"></param>
    /// <returns></returns>
    private static float AngleBetween(Vector3 v1, Vector3 v2)
    {
        // 计算两个向量的点积
        float dotProduct = Vector3.Dot(v1, v2);

        // 计算每个向量的模长
        float magnitudeV1 = v1.Length();
        float magnitudeV2 = v2.Length();

        // 防止除以零错误
        if (magnitudeV1 == 0 || magnitudeV2 == 0)
        {
            return 0f;
        }

        // 计算夹角的余弦值
        float cosTheta = dotProduct / (magnitudeV1 * magnitudeV2);

        // 限制cosTheta的值范围在 -1 到 1 之间,以防计算机浮点误差
        cosTheta = Math.Max(-1f, Math.Min(1f, cosTheta));

        // 返回角度,单位是度
        return (float)(Math.Acos(cosTheta) * (180.0 / Math.PI));
    }

    private static double GetBoundingBoxVolume(BoundingBox bound)
    {
        var size = bound.Size;
        return size.X * size.Y * size.Z;
    }
    
    private static Vector3 CalculateNormal(Vector3 p0, Vector3 p1, Vector3 p2)
    {
        var u = p1 - p0;
        var v = p2 - p0;
        return Vector3.Cross(u, v);
    }
    private  static bool IsLineSegmentParallelToYAxis(Tuple<Vector3, Vector3> lineSegment,float epsilon = 1e-6f)
    {
        Vector3 nowItem = lineSegment.Item1;
        Vector3 nextItem = lineSegment.Item2;
        
        if (Math.Abs(nowItem.X - nextItem.X) < epsilon && Math.Abs(nowItem.Z - nextItem.Z) < epsilon)
        {
            return true; // 平行于 Y 轴
        }
        return false; // 不平行于 Y 轴
    }
    // 计算两个点之间的距离
    private static float GetDistance(Vector3 point1, Vector3 point2)
    {
        return (float)Math.Sqrt(Math.Pow(point2.X - point1.X, 2) + Math.Pow(point2.Y - point1.Y, 2) + Math.Pow(point2.Z - point1.Z, 2));
    }

// 判断是否平行于Y轴的线段,返回较长或者较短的线段
    private static Tuple<Vector3, Vector3> GetLongestOrShortestLineSegment(List<Vector3> facetPoints, bool returnLongest = true)
    {
        Tuple<Vector3, Vector3> resultSegment = null;
        float resultLength = returnLongest ? float.MinValue : float.MaxValue;  // 初始化为最小或最大长度

        // 遍历所有相邻的点,构成线段
        for (int i = 0; i < facetPoints.Count; i++)
        {
            Vector3 currentPoint = facetPoints[i];
            Vector3 nextPoint = facetPoints[(i + 1) % facetPoints.Count]; // 用模运算实现环形结构,最后一个点与第一个点连接
        
            // 计算线段是否平行于 Y 轴
            if (IsLineSegmentParallelToYAxis(new Tuple<Vector3, Vector3>(currentPoint, nextPoint)))
            {
                // 计算线段的长度
                float segmentLength = GetDistance(currentPoint, nextPoint);

                // 根据需要选择较长或较短的线段
                if ((returnLongest && segmentLength > resultLength) || (!returnLongest && segmentLength < resultLength))
                {
                    resultSegment = new Tuple<Vector3, Vector3>(currentPoint, nextPoint);
                    resultLength = segmentLength;
                }
            }
        }

        return resultSegment; // 返回符合条件的线段
    }
    private static void CalculateLineSegmentStats(List<Tuple<Vector3, Vector3>> lines, 
        out Tuple<Vector3, Vector3> maxLine, 
        out Tuple<Vector3, Vector3> minLine, 
        out Tuple<Vector3, Vector3> avgLine)
    {
        // 计算所有线段的长度
        var lineLengths = lines.Select(line => new
        {
            Line = line,
            Length = CalculateLength(line)
        }).ToList();

        // 找到最大、最小和平均长度对应的线段
        maxLine = lineLengths.OrderByDescending(l => l.Length).First().Line;
        minLine = lineLengths.OrderBy(l => l.Length).First().Line;
        avgLine = lineLengths.OrderBy(l => Math.Abs(l.Length - lineLengths.Average(ll => ll.Length)))
            .First().Line;
    }
    private static double CalculateLength(Tuple<Vector3, Vector3> line)
    {
        Vector3 startPoint = line.Item1;
        Vector3 endPoint = line.Item2;
        return Math.Round(Vector3.Distance(startPoint, endPoint), 2);
    }
    
    /// <summary>
    /// 获取四边形内平行于Y轴且位于左侧的边线
    /// </summary>
    /// <param name="facetPoints">四边形的顶点列表</param>
    /// <param name="returnLongest">是否返回最长的边线</param>
    /// <returns>符合条件的边线,如果不存在则返回null</returns>
    public static Tuple<Vector3, Vector3> GetLeftParallelLineSegment(
        List<Vector3> facetPoints)
    {
        if (facetPoints == null || facetPoints.Count < 4)
            throw new ArgumentException("facetPoints must contain at least four points.");

        // 计算多边形(四边形)的中心点
        Vector3 center = GetCenter(facetPoints);

        float minX = float.MaxValue;
        Tuple<Vector3, Vector3> resultLine = null;

        // 遍历所有边线
        for (int i = 0; i < facetPoints.Count; i++)
        {
            Vector3 p1 = facetPoints[i];
            Vector3 p2 = facetPoints[(i + 1) % facetPoints.Count]; // 环形连接

            var lineSegment = new Tuple<Vector3, Vector3>(p1, p2);

            // 判断该边线是否平行于 Y 轴
            if (IsLineSegmentParallelToYAxis(lineSegment))
            {
                return lineSegment;
            }
        }

        return resultLine;
    }
    

    
    private static string ValueFormat(string value, string type, bool hasUnit = false)
    {
        if (double.TryParse(value, out var v) )
        {
            switch (type)
            {
                case "GIRDLE_BEZEL":
                case "GIRDLE_BONE":
                case "GIRDLE_VALLEY":
                    v = Math.Floor(v * 1000) / 1000;
                    return hasUnit ? $"{(v*100).ToString("F1")}mm" : (v*100).ToString("F1");
                case "DIAMETER":
                    v = Math.Floor(v * 10) / 10;
                    return hasUnit ? $"{v.ToString("F1")}mm" : v.ToString("F1");
                case "PAV_ANGLE":
                case "TWIST": 
                    v = Math.Floor(v * 10) / 10;
                    return hasUnit ? $"{v.ToString("F1")}°" : v.ToString("F1");
                case "CROWN_ANGLE":
                    v = Math.Floor(v * 10) / 10;
                    return hasUnit ? $"{v.ToString("F1")}°" :v.ToString("F1");
                case "TABLE":
                // case "CROWN HEIGHT":
                // case "PAV DEPTH":
                     v *= 100;
                    return hasUnit ? $"{(Math.Round(v / 0.5) * 0.5).ToString("F1")}%" : (Math.Round(v / 0.5) * 0.5).ToString("F1");
                default:
                     v = Math.Floor(v * 1000) / 1000;
                    return hasUnit ? $"{(v*100).ToString("F1")}%" : (v*100).ToString("F1");
            }
        }

        return "--";
    }

    #endregion

}