using System.Text.Json.Nodes; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media.Media3D; using HandyControl.Controls; using HelixToolkit.Wpf.SharpDX; using Microsoft.Win32; using SharpDX; using SparkClient.Model.Helper; using SparkClient.Views.UserControl.ViewportData.Entity; using SparkClient.Views.UserControl.ViewportData.Enum; using SparkClient.Views.UserControl.ViewportData.Helper; using HelixToolkit.Wpf.SharpDX; using SharpDX; using SharpDX.Direct3D11; using SharpDX.DXGI; using MathNet.Numerics; using System.Windows.Media; namespace SparkClient.Views.UserControl; public partial class Viewport3D { public Viewport3D() { InitializeComponent(); DataContext = this; this.Viewport3Dx.EffectsManager = new DefaultEffectsManager(); Viewport3Dx.ShowViewCube = false; Viewport3Dx.ShowCoordinateSystem = false; ViewportManager.SetViewport3D(Viewport3Dx); } /// /// 初始化 /// /// /// private void Viewport3D_OnLoaded(object sender, RoutedEventArgs e) { ViewportManager.SetViewport3D(Viewport3Dx); ViewportManager.SetViewport(this); ViewportManager.LoadModelByEntities(new List()); #if DEBUG #else BtnShow3DView.Visibility = Visibility.Hidden; #endif //选项初始化 显示-后端-管理类 一致 ViewportRightMenuSelectFaceFrame.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; // ViewportRightMenuSelectFaceLengthText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; // ViewportRightMenuSelectFaceAngleText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; ViewportRightMenuSelectFaceText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; ViewportRightMenuSelectFaceKind.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; ViewportRightMenuShowModelFace.IsChecked = true; ViewportRightMenuShowModelFrame.IsChecked = true; ViewportRightMenuShowLighting.IsChecked = true; ViewportRightMenuSelectFace.IsChecked = ViewportManager.DoubleClickSelect; ViewportRightMenuSelectFaceFrame.IsChecked = ViewportManager.DoubleClickSelectShowBorder; // ViewportRightMenuSelectFaceLengthText.IsChecked = ViewportManager.DoubleClickSelectShowBorderLength; // ViewportRightMenuSelectFaceAngleText.IsChecked = ViewportManager.DoubleClickSelectShowBorderAngle; ViewportRightMenuSelectFaceText.IsChecked = ViewportManager.DoubleClickSelectShowInfoText; ViewportRightMenuSelectFaceKind.IsChecked = ViewportManager.DoubleClickSelectShowPlaneType; var a = Viewport3Dx.Items; #if DEBUG //Viewport3Dx.ShowViewCube = true; //Viewport3Dx.ShowCoordinateSystem = true; //Viewport3Dx.ShowCameraInfo = true; //Viewport3Dx.ShowCameraTarget = !Viewport3Dx.ShowCameraTarget; //Viewport3Dx.ShowFrameDetails = !Viewport3Dx.ShowFrameDetails; //Viewport3Dx.ShowFrameRate = !Viewport3Dx.ShowFrameRate; //Viewport3Dx.ShowTriangleCountInfo = !Viewport3Dx.ShowTriangleCountInfo; #endif } /// /// 双击选择面 /// /// /// private void Viewport3Dx_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (ViewportManager.DoubleClickSelect == false) return; var mousePosition = e.GetPosition(Viewport3Dx); var hits = Viewport3Dx.FindHits(mousePosition); // 如果没有命中任何 3D 对象 if (hits == null || hits.Count == 0) { ViewportManager.ClearDicModels(); return; } // 获取第一个命中的对象 var hit = hits[0]; // 检查是否是 MeshGeometryModel3D if (hit.ModelHit is MeshGeometryModel3D modelHit) { // 获取几何信息 var geometry = modelHit.Geometry as HelixToolkit.Wpf.SharpDX.MeshGeometry3D; if (geometry != null) { // 获取命中的三角形索引 var triangleIndex = hit.TriangleIndices; // 获取三角形顶点 var vertex1 = geometry.Positions[triangleIndex.Item1]; var vertex2 = geometry.Positions[triangleIndex.Item2]; var vertex3 = geometry.Positions[triangleIndex.Item3]; ViewportManager.ChooseTriangleCode = CommonHelper.GenerateTriangleCode(vertex1, vertex2, vertex3); ViewportManager.ResetChooseAddModels(); } } else { ViewportManager.ClearDicModels(); } } /// /// 顶部按钮 - 视角切换 /// /// /// /// private void BtnAngle_OnClick(object sender, RoutedEventArgs e) { var directionName = ((Button)sender).Name.ToString(); var directionValue = (int) TbCustomizeRevolve.Value; var center = ViewportManager.ModelBounds.Center; var maxDimension = ViewportManager.ModelBounds.Size.Length(); var distance = maxDimension * 1.2; // 调整相机到模型的距离,保证视野范围内 // 获取当前相机 var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.OrthographicCamera; switch (directionName) { case "BtnFrontView": //测 camera.Position = new Point3D(center.X, center.Y, center.Z + distance); // 从前面看,Z轴正方向 camera.UpDirection = new Vector3D(0, -1, 0); break; break; case "BtnTopView": //顶、 camera.Position = new Point3D(center.X, center.Y - distance, center.Z); // 从底部看,Y轴负方向 camera.UpDirection = new Vector3D(0, 0, -1); break; case "BtnBottomView": //低 camera.Position = new Point3D(center.X, center.Y + distance, center.Z); // 从顶部看,Y轴正方向 camera.UpDirection = new Vector3D(0, 0, 1); break; case "BtnFrontdView": //测 camera.Position = new Point3D(center.X, center.Y, center.Z + distance); // 从前面看,Z轴正方向 camera.UpDirection = new Vector3D(0, 1, 0); break; } camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z); } /// /// 顶部按钮 - 功能 /// /// /// /// private async void BtnFunction_OnClick(object sender, RoutedEventArgs e) { var directionName = ((Button)sender).Name.ToString(); var directionValue = (int) TbCustomizeRevolve.Value; switch (directionName) { case "BtnFcuntion1View": //测 break; case "BtnFcuntion2View": //顶 break; case "BtnFcuntion3View": //低 //var center = ViewportManager.ModelBounds.Center; //var maxDimension = ViewportManager.ModelBounds.Size.Length(); //var distance = maxDimension *1.2; // 调整相机到模型的距离,保证视野范围内 //var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.OrthographicCamera; //camera.Position = new Point3D(center.X, center.Y, center.Z); // 从前面看,Z轴正方向 //camera.Width = ViewportManager.calCameraWidth(); //camera.UpDirection = new Vector3D(0, -1, 0); //camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z); var center = ViewportManager.ModelBounds.Center; ViewportManager.ClearMeshLines(); var maxDimension = ViewportManager.ModelBounds.Size.Length(); var distance = maxDimension * 1.2; // 调整相机到模型的距离,保证视野范围内 var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.OrthographicCamera; camera.Position = new Point3D(center.X, center.Y, center.Z + distance); // 从前面看,Z轴正方向 camera.UpDirection = new Vector3D(0, -1, 0); camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z); await Task.Delay(100); ViewportHelperPro.RotateModel(new Vector3D(0,-1,0)); await Task.Delay(7000); ViewportHelperPro.RotateModel(new Vector3D(-1,0,0)); await Task.Delay(7000); ViewportManager.DoubleClickSelect = !false; break; case "BtnShow3DView": UnityHelper.GenerateRender(ViewportManager.ViewportTriangle.First().TriangleCode, "123"); break; } } /// /// 按钮调整相机方向[底部按钮] /// /// /// private void BtnDirection_OnClick(object sender, RoutedEventArgs e) { var directionName = ((Button)sender).Name.ToString(); var directionValue = (int)TbCustomizeRevolve.Value; // 旋转角度(单位:度) // 获取当前相机和模型中心 var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.OrthographicCamera; if (camera == null) return; var modelCenter = ViewportManager.CenterVector; // 模型中心 var currentPosition = camera.Position; // 将相机位置转换为极坐标 var dx = currentPosition.X - modelCenter.X; var dy = currentPosition.Y - modelCenter.Y; var dz = currentPosition.Z - modelCenter.Z; var radius = Math.Sqrt(dx * dx + dy * dy + dz * dz); // 相机与模型中心的距离 var azimuth = Math.Atan2(dz, dx) * 180.0 / Math.PI; // 方位角(水平平面上的角度) var elevation = Math.Atan2(dy, Math.Sqrt(dx * dx + dz * dz)) * 180.0 / Math.PI; // 仰角(垂直方向的角度) switch (directionName) { case "BtnTop": //上 elevation += directionValue; break; case "BtnBottom": //下 elevation -= directionValue; break; case "BtnLeft": //左 azimuth -= directionValue; break; case "BtnRight": //右 azimuth += directionValue; break; } // 限制仰角范围在 -89.9 到 89.9 度,避免超出范围导致位置错误 elevation = Math.Clamp(elevation, -89.9, 89.9); azimuth = (azimuth + 360) % 360; // 方位角在 0 到 360 范围内循环 // 将极坐标转换回直角坐标 var newX = modelCenter.X + radius * Math.Cos(elevation * Math.PI / 180.0) * Math.Cos(azimuth * Math.PI / 180.0); var newY = modelCenter.Y + radius * Math.Sin(elevation * Math.PI / 180.0); var newZ = modelCenter.Z + radius * Math.Cos(elevation * Math.PI / 180.0) * Math.Sin(azimuth * Math.PI / 180.0); // 更新相机位置和视角 camera.Position = new Point3D(newX, newY, newZ); camera.LookDirection = new Vector3D(modelCenter.X - newX, modelCenter.Y - newY, modelCenter.Z - newZ); // camera.UpDirection = new Vector3D(0, 1, 0); // 保持 Y 轴为上方向 } // private void BtnDirection_OnClick(object sender, RoutedEventArgs e) // { // var directionName = ((Button)sender).Name.ToString(); // var directionValue = (int)TbCustomizeRevolve.Value; // 旋转角度(单位:度) // // if(directionValue == 0) return; // // 获取当前相机和模型中心 // var camera = Viewport3Dx.Camera as HelixToolkit.Wpf.SharpDX.PerspectiveCamera; // if (camera == null) return; // // var modelCenter = ViewportManager.CenterVector; // 模型中心 // var currentPosition = camera.Position; // // // 将相机位置转换为极坐标 // var dx = currentPosition.X - modelCenter.X; // var dy = currentPosition.Y - modelCenter.Y; // var dz = currentPosition.Z - modelCenter.Z; // // var radius = Math.Sqrt(dx * dx + dy * dy + dz * dz); // 相机与模型中心的距离 // var azimuth = Math.Atan2(dz, dx) * 180.0 / Math.PI; // 方位角(水平平面上的角度) // var elevation = Math.Atan2(dy, Math.Sqrt(dx * dx + dz * dz)) * 180.0 / Math.PI; // 仰角(垂直方向的角度) // // switch (directionName) // { // case "BtnTop": // //上 // elevation += directionValue; // break; // case "BtnBottom": // //下 // elevation -= directionValue; // break; // case "BtnLeft": // //左 // azimuth -= directionValue; // break; // case "BtnRight": // //右 // azimuth += directionValue; // break; // } // // 限制仰角范围在 -89.9 到 89.9 度,避免超出范围导致位置错误 // // elevation = elevation > 90 || elevation < -90 ? ? elevation + 90 : elevation - 90: elevation; // // elevation = elevation; // int isFan = 1; // if (elevation > 90 || elevation < -90) // { // if (elevation < -90) // { // elevation += 90; // } // else // { // elevation -= 90; // isFan = -1; // } // } // // azimuth = (azimuth + 360) % 360; // 方位角在 0 到 360 范围内循环 // // // 将极坐标转换回直角坐标 // var newX = modelCenter.X + radius * Math.Cos(elevation * Math.PI / 180.0) * Math.Cos(azimuth * Math.PI / 180.0); // var newY = modelCenter.Y + radius * Math.Sin(elevation * Math.PI / 180.0); // var newZ = modelCenter.Z + radius * Math.Cos(elevation * Math.PI / 180.0) * Math.Sin(azimuth * Math.PI / 180.0); // // // 更新相机位置和视角 // camera.Position = new Point3D(newX, newY, newZ); // camera.LookDirection = new Vector3D(modelCenter.X - newX, modelCenter.Y - newY, modelCenter.Z - newZ); // camera.UpDirection = new Vector3D(camera.UpDirection.X, camera.UpDirection.Y * isFan, camera.UpDirection.Z); // 保持 Y 轴为上方向 // // // // } #region 右键菜单事件绑定 /// /// 右键选择 /// /// /// private void MenuItem_OnCheckedChanged(object sender, RoutedEventArgs e) { ViewportRightMenuSelectFaceFrame.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; // ViewportRightMenuSelectFaceLengthText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; // ViewportRightMenuSelectFaceAngleText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; ViewportRightMenuSelectFaceText.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; ViewportRightMenuSelectFaceKind.IsEnabled = ViewportRightMenuSelectFace.IsChecked ; var controlName = ((MenuItem)sender).Name.ToString(); var checkResult = (bool)((MenuItem)sender).IsChecked; switch (controlName) { case "ViewportRightMenuShowModelFace": //显示模型面 ViewportManager.ShowMainModel3D(checkResult); // ViewportRightMenuShowModelFace.IsChecked = !checkResult; // ViewportManager.ShowMainModel3DByType(!checkResult); break; case "ViewportRightMenuShowModelFaceByType": //显示模型面 // ViewportManager.ShowMainModel3D(!checkResult); // ViewportRightMenuShowModelFaceByType.IsChecked = !checkResult; ViewportManager.ShowMainModel3DByType(checkResult); break; case "ViewportRightMenuShowModelFrame": //显示模型边框 ViewportManager.ShowMainModelLines(checkResult); break; case "ViewportRightMenuShowLighting": //显示光照 ViewportManager.ShowMainModelLighting(checkResult); break; case "ViewportRightMenuShowDefectFace": //显示瑕疵面 ViewportManager.MarkSpecificFaces(checkResult); break; case "ViewportRightMenuShowFront": //显示正方向箭头 ViewportManager.PointTowardsTheFront(checkResult); break; case "ViewportRightMenuSelectFace": //双击选择面 ViewportManager.DoubleClickSelect = checkResult; ViewportManager.ClearDicModels(); break; case "ViewportRightMenuSelectFaceFrame": //双击选择面的边框 ViewportManager.DoubleClickSelectShowBorder = checkResult; ViewportManager.ResetChooseAddModels(); break; case "ViewportRightMenuSelectFaceLengthText": //双击选择面的边框长度文字 ViewportManager.DoubleClickSelectShowBorderLength = checkResult; ViewportManager.ResetChooseAddModels(); break; case "ViewportRightMenuSelectFaceText": //双击选择面的边框长度文字 ViewportManager.DoubleClickSelectShowInfoText = checkResult; ViewportManager.ResetChooseAddModels(); break; case "ViewportRightMenuSelectFaceAngleText": //双击选择面的边框夹角文字 ViewportManager.DoubleClickSelectShowBorderAngle = checkResult; ViewportManager.ResetChooseAddModels(); break; case "ViewportRightMenuSelectFaceKind": //双击选择面的选择同类面 ViewportManager.DoubleClickSelectShowPlaneType = checkResult; ViewportManager.ResetChooseAddModels(); break; case "ViewportRightMenuShowMeshLines": ViewportManager.ShowMeshLines(checkResult, ViewportHelperPro.IsCrown()); break; } } /// /// 右键按钮 /// /// /// private void MenuItem_OnClick(object sender, RoutedEventArgs e) { var controlName = ((MenuItem)sender).Name.ToString(); switch (controlName) { case "ViewportRightMenuFront": //切换到正面 var Camear = ViewportHelperPro.CalculateCamera(ViewportManager.PositiveDirection, ViewportManager.ModelBounds); Viewport3Dx.Camera.Position = Camear.Position; Viewport3Dx.Camera.LookDirection = Camear.LookDirection; Viewport3Dx.Camera.UpDirection = new Vector3D(Camear.UpDirection.X, Camear.UpDirection.Y*-1, Camear.UpDirection.Z); break; case "ViewportRightMenuSaveViewToPNG": //保存图片 var saveFileDialog = new SaveFileDialog { Filter = "PNG Files (*.png)|*.png", Title = MultilingualHelper.getString("ViewportSelectPath"), DefaultExt = "png" }; if (saveFileDialog.ShowDialog() != true) { return; // 用户取消 } string filePath = saveFileDialog.FileName; try { ViewportHelperPro.SaveViewportAsImage(Viewport3Dx, filePath); System.Windows.MessageBox.Show(MultilingualHelper.getString("ViewportSaveSucceed")); } catch (Exception ex) { System.Windows.MessageBox.Show($"{MultilingualHelper.getString("ViewportSaveFail")}:{ex.Message}", MultilingualHelper.getString("ViewportSaveFail"), System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } break; case "ViewportRightMenuReset": ViewportManager.ResetMeshLines(); break; } } #endregion // 保存成功 // 保存失败 // 选择路径 #region 页面隐式交互 public static readonly DependencyProperty ViewportDataProperty = DependencyProperty.Register( nameof(ViewportData), typeof(ViewportData.ViewportData), typeof(Viewport3D), new PropertyMetadata(null, OnViewportDataChanged)); public ViewportData.ViewportData ViewportData { get => (ViewportData.ViewportData)GetValue(ViewportDataProperty); set => SetValue(ViewportDataProperty, value); } private static void OnViewportDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Viewport3D control && e.NewValue is ViewportData.ViewportData data) { control.Initialize(data); } } private void Initialize(ViewportData.ViewportData vpData) { } private System.Windows.Point _mouseDownPosition; private bool _isDragging = false; private void UIElement_OnPreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e) { if (_isDragging) { _isDragging = false; MainBorder.ContextMenu.Visibility = Visibility.Hidden; return; } MainBorder.ContextMenu.Visibility = Visibility.Visible; } private void UIElement_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { _mouseDownPosition = e.GetPosition(Viewport3Dx); _isDragging = false; if (MainBorder.ContextMenu.Visibility == Visibility.Visible) { MainBorder.ContextMenu.Visibility = Visibility.Hidden; MainBorder.ContextMenu.IsOpen = false; } } private void Viewport3Dx_OnPreviewMouseMove(object sender, MouseEventArgs e) { if (e.RightButton == MouseButtonState.Pressed) { var currentPosition = e.GetPosition(Viewport3Dx); var distance = (currentPosition - _mouseDownPosition).Length; MainBorder.ContextMenu.Visibility = Visibility.Hidden; MainBorder.ContextMenu.IsOpen = false; if (distance > 5) { _isDragging = true; } } } private void TbCustomizeRevolve_OnPreviewTextInput(object sender, TextCompositionEventArgs e) { e.Handled = !CommonHelper.IsTextNumeric(e.Text); } private void TbCustomizeRevolve_OnPreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Back || e.Key == Key.Delete || e.Key == Key.Tab || e.Key == Key.Left || e.Key == Key.Right) { e.Handled = false; // 不拦截 } else { e.Handled = !CommonHelper.IsKeyNumeric(e.Key); } } private void TbCustomizeRevolve_OnTextChanged(object sender, TextChangedEventArgs e) { var textBox = sender as System.Windows.Controls.TextBox; if (int.TryParse(textBox.Text, out int value)) { if (value < 0) { textBox.Text = "0"; // 如果小于0,重置为0 } else if (value > 360) { textBox.Text = "360"; // 如果大于360,重置为360 } textBox.SelectionStart = textBox.Text.Length; // 保持光标在文本末尾 } else if (!string.IsNullOrWhiteSpace(textBox.Text)) { textBox.Text = "0"; } } #endregion private void TbCustomizeRevolve_OnMouseDoubleClick(object sender, MouseButtonEventArgs e) { //Viewport3Dx.ShowCameraInfo = !Viewport3Dx.ShowCameraInfo; //Viewport3Dx.ShowCameraTarget = !Viewport3Dx.ShowCameraTarget ; //Viewport3Dx.ShowFrameDetails = !Viewport3Dx.ShowFrameDetails; //Viewport3Dx.ShowFrameRate = !Viewport3Dx.ShowFrameRate; //Viewport3Dx.ShowTriangleCountInfo = !Viewport3Dx.ShowTriangleCountInfo; } }