diff --git a/Views/UserControl/Viewport3D.xaml b/Views/UserControl/Viewport3D.xaml index d1b5eb3..138e33b 100644 --- a/Views/UserControl/Viewport3D.xaml +++ b/Views/UserControl/Viewport3D.xaml @@ -67,13 +67,15 @@ + + MouseLeftButtonDown="Viewport3Dx_MouseLeftButtonDown" + MouseDoubleClick="Viewport3Dx_OnMouseLeftButtonDown"> @@ -85,8 +87,12 @@ - + + diff --git a/Views/UserControl/Viewport3D.xaml.cs b/Views/UserControl/Viewport3D.xaml.cs index 2b629e2..6b6f033 100644 --- a/Views/UserControl/Viewport3D.xaml.cs +++ b/Views/UserControl/Viewport3D.xaml.cs @@ -15,6 +15,7 @@ using HelixToolkit.Wpf.SharpDX; using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; +using MathNet.Numerics; namespace SparkClient.Views.UserControl; @@ -60,6 +61,10 @@ public partial class Viewport3D var a = Viewport3Dx.Items; +#if DEBUG + Viewport3Dx.ShowViewCube = true; + Viewport3Dx.ShowCoordinateSystem = true; +#endif } @@ -405,6 +410,17 @@ public partial class Viewport3D //双击选择面的选择同类面 ViewportManager.DoubleClickSelectShowPlaneType = checkResult; ViewportManager.ResetChooseAddModels(); + break; + case "ViewportRightMenuShowMeshLines": + var maxDimension = ViewportManager.ModelBounds.Size.Length(); + var distance = maxDimension * 1.2; // 调整相机到模型的距离,保证视野范围内 + var center = ViewportManager.ModelBounds.Center; + var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.PerspectiveCamera; + camera.Position = new Point3D(center.X, center.Y - distance, center.Z); // 从底部看,Y轴负方向 + camera.UpDirection = new Vector3D(0, 0, -1); + ViewportManager.ShowMeshLines(checkResult); + //camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z); + break; } } @@ -578,4 +594,16 @@ public partial class Viewport3D //Viewport3Dx.ShowFrameRate = !Viewport3Dx.ShowFrameRate; //Viewport3Dx.ShowTriangleCountInfo = !Viewport3Dx.ShowTriangleCountInfo; } + + private void Viewport3Dx_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + var mousePosition = e.GetPosition(Viewport3Dx); + var hits = Viewport3Dx.FindHits(mousePosition); + // 如果没有命中任何 3D 对象 + if (hits == null || hits.Count == 0) + { + ViewportManager.ClearDicModels(); + return; + } + } } \ No newline at end of file diff --git a/Views/UserControl/ViewportData/Helper/LineCalculationHelper.cs b/Views/UserControl/ViewportData/Helper/LineCalculationHelper.cs new file mode 100644 index 0000000..cdc7622 --- /dev/null +++ b/Views/UserControl/ViewportData/Helper/LineCalculationHelper.cs @@ -0,0 +1,99 @@ +using SharpDX; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Media3D; + +namespace SparkClient.Views.UserControl.ViewportData.Helper +{ + internal class LineCalculationHelper + { + private readonly float Y = -0.01F; + private Vector3 point1; + private Vector3 point2; + /// + /// 常数a(y=ax+b) + /// + private float a; + /// + /// 常数b(y=ax+b) + /// + private float b; + public LineCalculationHelper(Vector3 point1, Vector3 point2) { + this.point1 = point1; + this.point2 = point2; + this.a = calA(point1, point2); + this.b = calB(point1, a); + } + /// + /// 常数a的计算 + /// + /// + /// + /// + private float calA(Vector3 point1, Vector3 point2) + { + return (point1.Z - point2.Z) / (point1.X - point2.X); + } + /// + /// 常数b的计算 + /// + /// + /// + /// + private float calB(Vector3 point1, float a) + { + return -(a * point1.X)+point1.Z; + } + + public Tuple calXline(float length) + { + var x1 = 5; + var z1 = calZ(x1); + var x2 = -5; + var z2 = calZ(x2); + return new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2)); + } + public Tuple calYline(float length) + { + var x1 = 5; + var z1 = calZVertical(x1); + var x2 = -5; + var z2 = calZVertical(x2); + return new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2)); + } + + public Tuple calLineOfOffset(Tuple tuple, float d) + { + var point1 = tuple.Item1; + var point2 = tuple.Item2; + var x1 = point1.X - d * (point2.Z - point1.Z)/ + (float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z)); + var z1 = point1.Z + d * (point2.X - point1.X) / + (float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z)); + + var x2 = point2.X - d * (point2.Z - point1.Z) / + (float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z)); + var z2 = point2.Z + d * (point2.X - point1.X) / + (float)Math.Sqrt(Square(point2.X - point1.X) + Square(point2.Z - point1.Z)); + return new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2)); + } + + float Square(float number) + { + return number * number; + } + + public float calZ(float x, float offset = 0) + { + return a * x + b + offset; + } + + public float calZVertical(float x, float offset = 0) + { + return (-x / a) + b + offset; + } + } +} diff --git a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs index b5fe55e..3500a2c 100644 --- a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs +++ b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs @@ -21,13 +21,15 @@ using SparkClient.Views.UserControl.ViewportData.Enum; using SparkClient.Views.UserControl.ViewportData.Entity; using Color = SharpDX.Color; using GeometryModel3D = HelixToolkit.Wpf.SharpDX.GeometryModel3D; +using NPOI.SS.Formula.Functions; +using MeshGeometry3D = HelixToolkit.Wpf.SharpDX.MeshGeometry3D; namespace SparkClient.Views.UserControl.ViewportData.Helper; public class ViewportHelperPro { private static readonly ILog Logger = LogManager.GetLogger(typeof(ViewportHelperPro)); - /// + /// /// 对指定类型的面进行标色 /// /// @@ -35,12 +37,12 @@ public class ViewportHelperPro /// 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); + var entities = ViewportManager.ViewportTriangle.Where(e => e.PlaneType == planeType).ToList(); + return GenerateModelByEntity(entities, color ?? ViewportManager.ColorConfig.ErrFacetColor); } #region 已经确定和调整好的方法 - /// + /// /// 通过三角形实体集合生成面模型(生成并添加) /// /// @@ -62,11 +64,11 @@ public class ViewportHelperPro { var meshBuilder = new MeshBuilder(true, false); foreach (var entity in entities) - { + { if (entity.PlaneType == PlaneType.Girdle) { meshBuilder.AddTriangleFan(new List() { entity.Point1, entity.Point2, entity.Point3 }, - new List() { new Vector3(0,0,0), new Vector3(0,0,0), new Vector3(0,0,0) }); + new List() { new Vector3(0, 0, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 0) }); } else { @@ -74,11 +76,11 @@ public class ViewportHelperPro } } var mesh = meshBuilder.ToMeshGeometry3D(); - + var material = new PBRMaterial { - AlbedoColor = new Color4(0.0f, 0f,0f,1f), // 黑色,避免其他光照影响 - EmissiveColor =color ?? ViewportManager.ColorConfig.MainFacetColor , // LightGray #D3D3D3 + AlbedoColor = new Color4(0.0f, 0f, 0f, 1f), // 黑色,避免其他光照影响 + EmissiveColor = color ?? ViewportManager.ColorConfig.MainFacetColor, // LightGray #D3D3D3 MetallicFactor = 0.0, // 非金属 RoughnessFactor = 1.0, // 高粗糙度,避免反射效果 ReflectanceFactor = 0.0, // 无反射 @@ -99,7 +101,7 @@ public class ViewportHelperPro Material = material, }; } - + /// /// 通过三角形实体集合生成面模型(只生成不添加) /// @@ -111,7 +113,7 @@ public class ViewportHelperPro var groupedDict = entities .GroupBy(e => e.PlaneType) .ToDictionary(g => g.Key, g => g.ToList()); - + var result = new List(); foreach (var group in groupedDict) { @@ -128,7 +130,7 @@ public class ViewportHelperPro { case PlaneType.Girdle: return ViewportManager.ColorConfig.GirdleFacetColor; - case PlaneType.TableFacet : + case PlaneType.TableFacet: return ViewportManager.ColorConfig.TableFacetColor; case PlaneType.UpperMainFacet: return ViewportManager.ColorConfig.UpperMainFacetColor; @@ -136,12 +138,12 @@ public class ViewportHelperPro return ViewportManager.ColorConfig.StarFacetColor; case PlaneType.UpperGirdleFacet: return ViewportManager.ColorConfig.UpperGirdleFacetColor; - case PlaneType.PavilionMainFacet: + case PlaneType.PavilionMainFacet: return ViewportManager.ColorConfig.PavilionFacetColor; case PlaneType.LowerGirdleFact: return ViewportManager.ColorConfig.LowerGirdleFacetColor; case PlaneType.Culet: - return ViewportManager.ColorConfig.CuletFacetColor; + return ViewportManager.ColorConfig.CuletFacetColor; } return null; @@ -177,12 +179,12 @@ public class ViewportHelperPro { if (viewport == null) viewport = ViewportManager.GetViewport3D(); - + var generationTask = VideoHelper.StartGenerationAndRotation(viewport); - + List pngList = await generationTask; - - await VideoHelper.CreateVideoFromPngListAsync(pngList, filePath); + + await VideoHelper.CreateVideoFromPngListAsync(pngList, filePath); } /// @@ -200,7 +202,7 @@ public class ViewportHelperPro writer.WriteLine("solid exportedModel"); foreach (var model in viewport.Items.OfType()) { - + if (model.Geometry is HelixToolkit.Wpf.SharpDX.Geometry3D geometry) { var positions = geometry.Positions; @@ -241,7 +243,7 @@ public class ViewportHelperPro /// /// /// - public static async Task ExportModelsToStlASync( string filePath) + public static async Task ExportModelsToStlASync(string filePath) { Viewport3DX viewport = ViewportManager.GetViewport3D(); @@ -249,7 +251,7 @@ public class ViewportHelperPro List, IList>> geometries = new List, IList>>(); // 在 UI 线程中收集几何信息 - await Application.Current.Dispatcher.InvokeAsync(() => + await Application.Current.Dispatcher.InvokeAsync(() => { foreach (var model in viewport.Items.OfType()) { @@ -341,7 +343,7 @@ public class ViewportHelperPro selFaceVector.Add(entity.Point3); } HashSet uniqueVectors = new HashSet(selFaceVector); - + for (int i = 0; i < selFaceVector.ToList().Count - 1; i++) { var nowItem = selFaceVector.ToList()[i]; @@ -350,11 +352,11 @@ public class ViewportHelperPro if (IsLineSegmentParallelToYAxis(line)) { lines.Add(line); - result.Add(DisplayLineModel3D(new List(){nowItem,nextItem }, color??ViewportManager.ColorConfig.MainBorderColor, thickness)); + result.Add(DisplayLineModel3D(new List() { nowItem, nextItem }, color ?? ViewportManager.ColorConfig.MainBorderColor, thickness)); } } } - + CalculateLineSegmentStats(lines, out ViewportManager.MainModelGirdleMaxLines, out ViewportManager.MainModelGirdleMinLines, out ViewportManager.MainModelGirdleAvgLines); ViewportManager.MainModelGirdleLines = lines; return result; @@ -374,12 +376,12 @@ public class ViewportHelperPro List waistList = entities .Where(entity => entity.PlaneType == PlaneType.Girdle) .ToList(); - + Dictionary> 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); @@ -390,9 +392,9 @@ public class ViewportHelperPro temp.Add(entity.Point2); temp.Add(entity.Point3); } - result.Add(DisplayLineModel3D(VectorClockwiseSort(new HashSet(temp).ToList()), color??ViewportManager.ColorConfig.MainBorderColor, thickness)); + result.Add(DisplayLineModel3D(VectorClockwiseSort(new HashSet(temp).ToList()), color ?? ViewportManager.ColorConfig.MainBorderColor, thickness)); } - + //腰 - 特殊 List selFaceVector = new List(); if (waistList.Count > 0) @@ -412,28 +414,28 @@ public class ViewportHelperPro ViewportManager.GirdleBottomLines.Clear(); foreach (var vector in uniqueVectors) { - if(vector.Y < mid) + 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 GenerateLineTextModelsByType(PlaneType type, Color4? textColor = null, bool showAll = false) { - - List entities = new List(); + + List entities = new List(); string planCode = ""; ViewportManager.ViewportTriangle.ForEach(e => { - if (e.PlaneType == type && (e.PlaneCode==planCode || string.IsNullOrEmpty(planCode))) + if (e.PlaneType == type && (e.PlaneCode == planCode || string.IsNullOrEmpty(planCode))) { planCode = e.PlaneCode; entities.Add(e); @@ -449,12 +451,12 @@ public class ViewportHelperPro /// 三角形集合 /// 指定数据集 /// - public static List GenerateLineTextModels(List entities, string valKey = "") + public static List GenerateLineTextModels(List entities, string valKey = "") { Logger.Info("【面文本生成】开始生成面相关文本信息"); var selFacet = entities; var selFacetType = entities.First().PlaneType; - + var result = new List(); if (selFacetType == PlaneType.Girdle && string.IsNullOrWhiteSpace(valKey)) { @@ -474,11 +476,11 @@ public class ViewportHelperPro 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 facetPoints = new List(); + + List facetPoints = new List(); 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); @@ -495,35 +497,35 @@ public class ViewportHelperPro case 0: case 3: var longestLine1 = GetLongestOrShortestLineSegment(facetPoints, returnLongest: true); - result.Add(DisplayLineModel3D(new List>(){longestLine1}, new Color4(1f, 0, 0, 1f) , 2f)); + result.Add(DisplayLineModel3D(new List>() { longestLine1 }, new Color4(1f, 0, 0, 1f), 2f)); break; case 1: case 2: var longestLine2 = GetLongestOrShortestLineSegment(facetPoints, returnLongest: false); - result.Add(DisplayLineModel3D(new List>(){longestLine2}, new Color4(1f, 0, 0, 1f) , 2f)); + result.Add(DisplayLineModel3D(new List>() { longestLine2 }, new Color4(1f, 0, 0, 1f), 2f)); break; } //开始找值 string param = string.Empty; var valueIndex = 0; - if (facetIndex % 8 == 0 || (facetIndex+1) % 8 == 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) + } else if (linePointType == 3 || linePointType == 0) { //风筝面 Logger.Info($"【面文本生成】 腰面值 波峰【风筝面】"); - valueIndex = (facetIndex / 8) ; + valueIndex = (facetIndex / 8); param = "GIRDLE_BEZEL"; } else { //腰厚比 Logger.Info($"【面文本生成】 腰面值 波峰【腰厚比】"); - valueIndex = (facetIndex / 4) ; + valueIndex = (facetIndex / 4); param = "GIRDLE_VALLEY"; } @@ -542,7 +544,7 @@ public class ViewportHelperPro return result; } Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} ==={paramValue}"); - var valueFloat = (Math.Floor(float.Parse(paramValue.ToString())*1000)/10).ToString(); + 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)); @@ -567,7 +569,7 @@ public class ViewportHelperPro // */ // // } - }else if (selFacetType == PlaneType.Girdle && !string.IsNullOrWhiteSpace(valKey)) + } else if (selFacetType == PlaneType.Girdle && !string.IsNullOrWhiteSpace(valKey)) { Logger.Info($"【面文本生成】 命中面{selFacetType},是腰,显示值{valKey}"); /*** @@ -584,11 +586,11 @@ public class ViewportHelperPro { switch (valKey) { - case "GIRDLE_BEZEL": if(i%8==4)resultDic.Add($"0_{i}", groupedDic[$"0_{i}"]); + 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}"]); + 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}"]); + case "GIRDLE_VALLEY": if (i % 4 == 2) resultDic.Add($"0_{i}", groupedDic[$"0_{i}"]); break; } } @@ -601,12 +603,12 @@ public class ViewportHelperPro foreach (var dic in resultDic) { //高亮四边形左边的线,并绑定值 - List facetPoints = new List(); + List facetPoints = new List(); dic.Value.ForEach(e => { facetPoints.Add(e.Point1); facetPoints.Add(e.Point2); facetPoints.Add(e.Point3); }); //高亮的线 var showLine = GetLeftParallelLineSegment(facetPoints); - if(showLine == null)continue; - + if (showLine == null) continue; + //文字显示位置 var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector); var resIndex = resultDic.Keys.ToList().IndexOf(dic.Key); @@ -625,11 +627,11 @@ public class ViewportHelperPro Logger.Info($"【面文本生成】 {valKey}_DETAIL.{valKey}_{resIndex} Key不存在"); return result; } - result.Add(DisplayLineModel3D(new List>(){showLine}, new Color4(1f, 0, 0, 1f) , 2f)); - var valueFloat = ValueFormat(paramValue.ToString(),valKey); + result.Add(DisplayLineModel3D(new List>() { showLine }, new Color4(1f, 0, 0, 1f), 2f)); + var valueFloat = ValueFormat(paramValue.ToString(), valKey); result.Add(DisplayText3D($" {resIndex} \r\n {valueFloat}", facetTextPoint)); } - + } else { @@ -647,14 +649,14 @@ public class ViewportHelperPro var key = kv.Key; var facetIndex = -1; int.TryParse(key.Split("_")[1], out facetIndex); - List facetPoints = new List(); + List facetPoints = new List(); 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; + 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}"]; @@ -663,12 +665,12 @@ public class ViewportHelperPro Logger.Info($"【面文本生成】 {param} Key不存在"); continue; } - var valueFloat = ValueFormat(paramValue.ToString(),param); + 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) + + } else if (groupedDic.Count == 16) { facetIndex += 1; valueIndex = facetIndex == 16 ? 1 : facetIndex % 2 == 0 ? valueIndex + 1 : valueIndex; @@ -687,15 +689,15 @@ public class ViewportHelperPro } Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{valueIndex} ==={paramValue}"); - var valueFloat = ValueFormat(paramValue.ToString(),param); + 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))); - + 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) { @@ -711,7 +713,7 @@ public class ViewportHelperPro } Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{facetIndex} ==={paramValue}"); - var valueFloat = ValueFormat(paramValue.ToString(),param); + var valueFloat = ValueFormat(paramValue.ToString(), param); Logger.Info($"【面文本生成】 {valueFloat} -- {facetIndex}"); var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector); result.Add(DisplayText3D($" {facetIndex} \r\n {valueFloat}", facetTextPoint)); @@ -733,7 +735,7 @@ public class ViewportHelperPro * ②在从算法结果数据对应好面组的索引,做成值-组面id的文本,计算出这个文本的大小 * ③在拼接的图片中心,平行于平面,向中心点外偏移“文本大小高度+0.1"个单位 显示文本 */ - + // var selFaceVector = entities // .SelectMany(entity => new[] { entity.Point1, entity.Point2, entity.Point3 }) // .Distinct() @@ -760,7 +762,7 @@ public class ViewportHelperPro // } } - + return result; } @@ -770,10 +772,10 @@ public class ViewportHelperPro /// 三角形ID /// 生成范围 /// - public static List GentrateChosenView(string triangleCode, string valKey = "", params SelShowType[] selType) + public static List GentrateChosenView(string triangleCode, string valKey = "", params SelShowType[] selType) { var res = ViewportManager.ViewportTriangle.Find(e => triangleCode.Equals(e.TriangleCode)); - if(res != null) + if (res != null) return GentrateChosenView(res, valKey, selType); return new List(); } @@ -797,12 +799,12 @@ public class ViewportHelperPro throw new Exception("Invalid SelShowType collection"); } List result = new List(); - + //选中的面 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)); + selPanel.ForEach(e => selPanelType.Remove(e)); foreach (var type in selType) { switch (type) @@ -826,7 +828,7 @@ public class ViewportHelperPro break; case SelShowType.BorderAngle: //选中面 每条边向内的夹角 - if(PlaneType.Girdle == entity.PlaneType)break; + if (PlaneType.Girdle == entity.PlaneType) break; result.AddRange(GenerateLineAngleTextModels(selPanel)); break; } @@ -835,7 +837,7 @@ public class ViewportHelperPro return result; } - + /// /// 生成线段夹角文本(不绘制) /// @@ -901,7 +903,7 @@ public class ViewportHelperPro ViewportManager.ClearDicModels(); // 设置旋转的中心点和旋转轴 var rotateTransform = new RotateTransform3D(); - var rotation = new AxisAngleRotation3D(axis, 0); + var rotation = new AxisAngleRotation3D(axis, 0); rotateTransform.Rotation = rotation; rotateTransform.CenterX = ViewportManager.CenterVector.X; rotateTransform.CenterY = ViewportManager.CenterVector.Y; @@ -909,16 +911,16 @@ public class ViewportHelperPro // 将旋转变换应用到模型 ViewportManager.MainModel3D.Transform = rotateTransform; - if(hasLine) + 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)), + Duration = new Duration(TimeSpan.FromSeconds(speed)), FillBehavior = FillBehavior.HoldEnd }; @@ -938,11 +940,11 @@ public class ViewportHelperPro var billboardText = new BillboardText3D(); billboardText.TextInfo.Add(new TextInfo(text, position) { - Foreground = color??ViewportManager.ColorConfig.SelFontColor, + Foreground = color ?? ViewportManager.ColorConfig.SelFontColor, Scale = 0.8f, VerticalAlignment = BillboardVerticalAlignment.Center, HorizontalAlignment = BillboardHorizontalAlignment.Center - + }); billboardTextModel.Geometry = billboardText; return billboardTextModel; @@ -978,8 +980,8 @@ public class ViewportHelperPro SlopeScaledDepthBias = 1.0f, IsDepthClipEnabled = true }; - - + + return billboardTextModel; } /// @@ -998,7 +1000,7 @@ public class ViewportHelperPro var nowItem = points[i]; var nextItem = points[i + 1]; edgeLines.Add(new Tuple(nowItem, nextItem)); - + } edgeLines.Add(new Tuple(points.Last(), points.First())); return DisplayLineModel3D(edgeLines, lineColor, thickness); @@ -1040,7 +1042,7 @@ public class ViewportHelperPro FieldOfView = fieldOfView, }; } - + /// /// 绘制箭头(相机指向模型中心) /// @@ -1054,8 +1056,8 @@ public class ViewportHelperPro /// 模型边界范围 1 /// public static MeshGeometryModel3D CreateArrow( - Vector3 cameraPosition, - Vector3 modelCenter, + Vector3 cameraPosition, + Vector3 modelCenter, BoundingBox modelBounds, float totalLength = 1.5f, // 箭头总长度 float cylinderRatio = 0.7f,// 圆柱部分占比 @@ -1100,7 +1102,7 @@ public class ViewportHelperPro EmissiveColor = Color.Red // 箭头自发光颜色 }; - + // 创建 3D 模型 return new MeshGeometryModel3D @@ -1109,8 +1111,8 @@ public class ViewportHelperPro Material = material }; } - - + + /// /// 生成线对象 /// @@ -1126,8 +1128,8 @@ public class ViewportHelperPro { lineBuilder.AddLine(line.Item1, line.Item2); } - - + + var edgeLinesModel = new LineGeometryModel3D { Geometry = lineBuilder.ToLineGeometry3D(), @@ -1144,9 +1146,9 @@ public class ViewportHelperPro /// public static List GenerateLightingForModel(Viewport3DX viewport) { - + List result = new List(); - + var models = viewport.Items.OfType(); if (!models.Any()) throw new Exception("Model in view not found"); var largestModel = models @@ -1184,7 +1186,7 @@ public class ViewportHelperPro { Position = corner, Color = color, - Range = (float)size.Length() + Range = (float)size.Length() }; result.Add(pointLight); } @@ -1208,7 +1210,7 @@ public class ViewportHelperPro { Color = Colors.LightGray }); - + result.Add(new AmbientLight3D { Color = Colors.Gray // 设置环境光颜色 @@ -1218,7 +1220,7 @@ public class ViewportHelperPro result.ForEach(e => viewport.Items.Add(e)); return result; } - + public static Vector3 GetCenterOfTriangles(List triangles) { if (triangles == null || triangles.Count == 0) @@ -1239,7 +1241,7 @@ public class ViewportHelperPro // 计算平均坐标 return total / vertexCount; } - + public static Vector3 CalculateCenter(List girdleTopLines, List girdleBottomLines) { // 计算 GirdleTopLines 的中心点 @@ -1274,8 +1276,80 @@ public class ViewportHelperPro lights.ForEach(item => viewport.Items.Remove(item)); } + public static List ShowMeshLines(List entities, double thickness = 1.0) + { + List lines = new(); + var Y = -0.01F; + var center = ViewportManager.CenterVector; + center.Y = Y; + Viewport3DTriangleEntity firstPoint = entities.Where(x => x.PlaneType == PlaneType.TableFacet).FirstOrDefault(); + + //var b = ((center.Z * firstPoint.Point1.X) - (firstPoint.Point1.Z * center.X)) / (firstPoint.Point1.X - center.X); + //var a = (firstPoint.Point1.Z - b) / firstPoint.Point1.X; + var lineCal = new LineCalculationHelper(firstPoint.Point1, center); + + var edgeLines = new List>(); + Color4 XlineColor =new Color4(255f, 0f, 0f, 1f); + var x1 = 5; + var z1 = lineCal.calZ(x1); + var x2 = -5; + var z2 = lineCal.calZ(x2); + edgeLines.Add(new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2))); + lines.Add(DisplayLineModel3D(edgeLines, XlineColor)); + + edgeLines.Add(lineCal.calLineOfOffset(new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2)),2)); + lines.Add(DisplayLineModel3D(edgeLines, XlineColor)); + + edgeLines.Add(lineCal.calLineOfOffset(new Tuple(new Vector3(x1, Y, z1), new Vector3(x2, Y, z2)), -2)); + lines.Add(DisplayLineModel3D(edgeLines, XlineColor)); + + Color4 YlineColor = new Color4(0F, 255f, 0f, 1f); + var x3 = 5; + var z3 = lineCal.calZVertical(x3); + var x4 = -5; + var z4 = lineCal.calZVertical(x4); + edgeLines.Add(new Tuple(new Vector3(x3, Y, z3), new Vector3(x4, Y, z4))); + lines.Add(DisplayLineModel3D(edgeLines, YlineColor)); + + edgeLines.Add(lineCal.calLineOfOffset(new Tuple(new Vector3(x3, Y, z3), new Vector3(x4, Y, z4)), 2)); + lines.Add(DisplayLineModel3D(edgeLines, YlineColor)); + + edgeLines.Add(lineCal.calLineOfOffset(new Tuple(new Vector3(x3, Y, z3), new Vector3(x4, Y, z4)), -2)); + lines.Add(DisplayLineModel3D(edgeLines, YlineColor)); + return lines; + } + public static LineGeometryModel3D ShowCircleLine(double radius = 1.0, double thickness = 1.0) + { + var Y = -0.01F; + var center = ViewportManager.CenterVector; + center.Y = Y; + return UpdateCircleGeometry(center); + } + private static LineGeometryModel3D UpdateCircleGeometry(Vector3 center, double radius = 1.0) + { + // 生成圆形线的点 + int segments = 100; // 圆的细分段数 + var positions = new List(); + var indices = new List(); + + 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); + } + + // 更新圆形线的几何形状 + return DisplayLineModel3D(positions, Color4.Black); + } + #region 私有方法 - + /// /// 向量按中心点顺时针排序 /// diff --git a/Views/UserControl/ViewportData/Helper/ViewportManager.cs b/Views/UserControl/ViewportData/Helper/ViewportManager.cs index ea13ac8..ef7644c 100644 --- a/Views/UserControl/ViewportData/Helper/ViewportManager.cs +++ b/Views/UserControl/ViewportData/Helper/ViewportManager.cs @@ -1,6 +1,8 @@ using System.Text.Json.Nodes; +using System.Windows.Controls; using System.Windows.Media.Media3D; using HelixToolkit.Wpf.SharpDX; +using MathNet.Numerics; using SharpDX; using SharpDX.Direct3D11; using SparkClient.Views.UserControl.ViewportData.Entity; @@ -15,7 +17,7 @@ public class ViewportManager /// 视图中三角形实体们 /// public static List ViewportTriangle = new List(); - + public static JsonObject DiamondData = new JsonObject(); /// /// 模型正方向(从模型中心出发的方向) @@ -46,23 +48,31 @@ public class ViewportManager /// public static List MainModelLines = new List(); /// + /// 网格线 + /// + public static List MainModelMeshLines = new List(); + /// + /// 网格线(圈) + /// + public static LineGeometryModel3D MainModelCircleLine = new LineGeometryModel3D(); + /// /// 腰垂直线 /// public static List> MainModelGirdleLines = new List>(); public static Tuple MainModelGirdleMaxLines = null; public static Tuple MainModelGirdleMinLines = null; public static Tuple MainModelGirdleAvgLines = null; - + /// /// 模型光照 /// public static List MainModelLighting = new List(); - + public static List MainModelMeshes = new List(); - - + + public static ColorConfigEntity ColorConfig = new ColorConfigEntity(); - + /// /// 模型控件对象映射 /// @@ -73,7 +83,7 @@ public class ViewportManager { ClearDicModels(); _viewport.Items.Clear(); - + } _viewport = viewport3D; @@ -83,7 +93,7 @@ public class ViewportManager if (_viewport == null) throw new Exception("Viewport is not set"); return _viewport; - + } #region 模型选中交互管理 //是否双击选中 @@ -94,7 +104,7 @@ public class ViewportManager public static bool DoubleClickSelectShowBorderLength = false; //选中边框夹角文字 public static bool DoubleClickSelectShowBorderAngle = false; - + public static bool DoubleClickSelectShowInfoText = true; //选中同类面 public static bool DoubleClickSelectShowPlaneType = true; @@ -116,11 +126,11 @@ public class ViewportManager ClearDicModels(); HashSet models = new HashSet(); models.Add(SelShowType.SelPanel); - if(DoubleClickSelectShowBorder) models.Add(SelShowType.Border); + if (DoubleClickSelectShowBorder) models.Add(SelShowType.Border); if (DoubleClickSelectShowInfoText) models.Add(SelShowType.LengthText); // if (DoubleClickSelectShowBorderAngle) models.Add(SelShowType.BorderAngle); if (DoubleClickSelectShowPlaneType) models.Add(SelShowType.IsTypePanel); - ChooseAddModels.AddRange( ViewportHelperPro.GentrateChosenView(ChooseTriangleCode,valType, models.ToArray())); + ChooseAddModels.AddRange(ViewportHelperPro.GentrateChosenView(ChooseTriangleCode, valType, models.ToArray())); ChooseAddModels.ForEach(e => _viewport.Items.Add(e)); } /// @@ -153,12 +163,12 @@ public class ViewportManager ClearDicModels(); return; } - + List entities = ViewportHelperPro.GenerateLineTextModelsByType(planeType); if (entities.Count <= 0) { ClearDicModels(); - } + } ChooseTriangleCode = entities[0].TriangleCode; ResetChooseAddModels(planTypeStr); } @@ -191,17 +201,17 @@ public class ViewportManager {"COC", PlaneType.Culet}, {"TWIST", PlaneType.UpperMainFacet}, {"CULET_TO_TABLE", PlaneType.Culet}, - + {"DIAMETER", PlaneType.Girdle}, {"GIRDLE_BEZEL", PlaneType.Girdle}, {"GIRDLE_BONE", PlaneType.Girdle}, {"GIRDLE_VALLEY", PlaneType.Girdle}, - - + + }; #endregion #endregion - + #region 统一控制方法 public static MeshGeometryModel3D PointTowardsTheFrontModel = new MeshGeometryModel3D(); @@ -210,7 +220,7 @@ public class ViewportManager if (isPoint) { var camera = ViewportHelperPro.CalculateCamera(PositiveDirection, ModelBounds); - PointTowardsTheFrontModel = ViewportHelperPro.CreateArrow(camera.Position.ToVector3(), ModelBounds.Center, ModelBounds); + PointTowardsTheFrontModel = ViewportHelperPro.CreateArrow(camera.Position.ToVector3(), ModelBounds.Center, ModelBounds); _viewport.Items.Add(PointTowardsTheFrontModel); } else @@ -244,27 +254,31 @@ public class ViewportManager { entities.AddRange(ViewportTriangle); } - + //重置 _viewport.Items.Clear(); ChooseTriangleCode = string.Empty; ChooseAddModels.Clear(); ResetChooseAddModels(); - + //刷新三角形 ViewportTriangle.Clear(); ViewportTriangle.AddRange(entities); - + //初始化 MainModel3D = ViewportHelperPro.GenerateModelByEntity(_viewport, entities); MainModelLines = ViewportHelperPro.GentrateLineByEntity(_viewport, entities); MainModelLighting = ViewportHelperPro.GenerateLightingForModel(_viewport); MainModelMeshes = ViewportHelperPro.GenerateModelByEntityGroupByType(entities); - MainModelLines.AddRange(ViewportHelperPro.GentrateLineGirdleByEntity(entities)); + MainModelLines.AddRange(ViewportHelperPro.GentrateLineGirdleByEntity(entities)); + //切换相机视角 _viewport.Camera = ViewportHelperPro.CalculateCamera(PositiveDirection, ModelBounds); _viewport.Camera.UpDirection = new Vector3D(0, -1, 0); _viewport.RenderHost.MSAA = MSAALevel.Maximum; + // TODO: + MainModelMeshLines.AddRange(ViewportHelperPro.ShowMeshLines(entities)); + MainModelCircleLine = ViewportHelperPro.ShowCircleLine(); } /// @@ -277,7 +291,7 @@ public class ViewportManager if (_viewport == null) return; if (isShow) { - if(_viewport.Items.Contains(MainModel3D)) + if (_viewport.Items.Contains(MainModel3D)) return; else _viewport.Items.Add(MainModel3D); @@ -287,7 +301,7 @@ public class ViewportManager _viewport.Items.Remove(MainModel3D); } } - + /// /// 是否显示主体模型 /// @@ -300,7 +314,7 @@ public class ViewportManager { MainModelMeshes.ForEach(e => { - if(!_viewport.Items.Contains(e)) + if (!_viewport.Items.Contains(e)) _viewport.Items.Add(e); }); } @@ -308,11 +322,11 @@ public class ViewportManager { MainModelMeshes.ForEach(e => { - _viewport.Items.Remove(e); + _viewport.Items.Remove(e); }); } } - + public static void ShowMainModelLines(bool isShow) { @@ -321,7 +335,7 @@ public class ViewportManager { MainModelLines.ForEach(e => { - if(!_viewport.Items.Contains(e)) + if (!_viewport.Items.Contains(e)) _viewport.Items.Add(e); }); } @@ -338,7 +352,7 @@ public class ViewportManager { MainModelLighting.ForEach(e => { - if(!_viewport.Items.Contains(e)) + if (!_viewport.Items.Contains(e)) _viewport.Items.Add(e); }); } @@ -359,16 +373,16 @@ public class ViewportManager MainModel3D.Material = _material; } } - + public static void TranslucentTex(bool isShow) { if (_viewport == null) return; if (isShow) { string texturePath2 = "pack://Appliction:,,,/Res/morning_racing_circuit_16k.dds"; - + var texture2 = TextureModel.Create(texturePath2); - + var material = new PBRMaterial { AlbedoColor = new SharpDX.Color4(0.0f, 1.0f, 1.0f, 1.0f), // 白色基色 @@ -406,6 +420,26 @@ public class ViewportManager } } + public static void ShowMeshLines(bool isShow) { + + if (_viewport == null) return; + if (isShow) + { + MainModelMeshLines.ForEach(e => + { + if (!_viewport.Items.Contains(e)) + _viewport.Items.Add(e); + }); + if (!_viewport.Items.Contains(MainModelCircleLine)) + _viewport.Items.Add(MainModelCircleLine); + + } + else + { + MainModelMeshLines.ForEach(e => _viewport.Items.Remove(e)); + _viewport.Items.Remove(MainModelCircleLine); + } + } #endregion