using System.Text.Json.Nodes; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using HandyControl.Controls; using HelixToolkit.Wpf.SharpDX; using SharpDX; using SparkClient.Views.UserControl.ViewportData.Entity; using SparkClient.Views.UserControl.ViewportData.Enum; using SparkClient.Views.UserControl.ViewportData.Helper; namespace SparkClient.Views.UserControl; public partial class Viewport3D { // 注册一个依赖属性,类型是 Viewport3DData public static readonly DependencyProperty ViewportDataProperty = DependencyProperty.Register( nameof(ViewportData), typeof(ViewportData.ViewportData), typeof(Viewport3D), new PropertyMetadata(null, OnViewportDataChanged)); // 公开的 CLR 属性包装器 public ViewportData.ViewportData ViewportData { get => (ViewportData.ViewportData)GetValue(ViewportDataProperty); set => SetValue(ViewportDataProperty, value); } // 当 ViewportData 属性发生变化时触发 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) { // 根据 Viewport3DData 的内容初始化控件 // 例如:设置控件内部的某些属性,渲染 3D 模型等 if (!string.IsNullOrEmpty(vpData.DiamondData)) { JsonNode? json = null; try { json = JsonNode.Parse(vpData.DiamondData); } catch { throw new Exception("DiamondData is invalid"); } if(json == null) throw new Exception("DiamondData is invalid"); try { List facets = new List(); if (json.AsObject()["facets"] != null) { JsonArray jsonArray = json.AsObject()["facets"].AsArray(); foreach (var item in jsonArray) { var value = CommonHelper.CreateByJsonStr(item.ToString()); facets.Add(value); } } else { throw new Exception("facets is invalid"); } if (json.AsObject()["positive_direction"] != null) { JsonObject positive = json.AsObject()["positive_direction"].AsObject(); ViewportManager.PositiveDirection.X = float.Parse(positive["x"]?.ToString() ?? "1.0"); ViewportManager.PositiveDirection.Y = float.Parse(positive["z"]?.ToString() ?? "0"); ViewportManager.PositiveDirection.Z = float.Parse(positive["y"]?.ToString() ?? "0"); } else { ViewportManager.PositiveDirection.X = 1.0f; ViewportManager.PositiveDirection.Y = 0f; ViewportManager.PositiveDirection.Z = 0; } var midZ = facets.SelectMany(e => new[] { e.Point1.X, e.Point2.X, e.Point3.X }).OrderBy(z => Math.Abs(z)) .First(); List facetsFinal = new List(); foreach (var item in facets) { var data = ViewportHelperPro.VectorClockwiseSort(new List { item.Point1, item.Point2, item.Point3 }); if (item.PlaneType == PlaneType.StarFacet || item.PlaneType == PlaneType.UpperGirdleFacet || item.PlaneType == PlaneType.UpperMainFacet || item.PlaneType == PlaneType.TableFacet) { item.Point1 = data[0]; item.Point2 = data[1]; item.Point3 = data[2]; } else if (item.PlaneType == PlaneType.Girdle) { var center = ViewportHelperPro.GetCentroid(data); data.Sort((v1, v2) => { double angle1 = Math.Atan2(v1.Y - center.Y, v1.X - center.X); double angle2 = Math.Atan2(v2.Y - center.Y, v2.X - center.X); return angle1.CompareTo(angle2); }); if (center.Z >= midZ) { item.Point1 = data[0]; item.Point2 = data[1]; item.Point3 = data[2]; } else { item.Point1 = data[2]; item.Point2 = data[1]; item.Point3 = data[0]; } } else { item.Point1 = data[2]; item.Point2 = data[1]; item.Point3 = data[0]; } item.TriangleCode = CommonHelper.GenerateTriangleCode(item.Point1, item.Point2, item.Point3); facetsFinal.Add(item); } // ViewportManager.ViewportTriangle.AddRange(facetsFinal); ViewportManager.LoadModelByEntities(facetsFinal); } catch (Exception ex) { throw new Exception(ex.Message); } } } public Viewport3D() { InitializeComponent(); DataContext = this; this.Viewport3Dx.EffectsManager = new DefaultEffectsManager(); ViewportManager.SetViewport3D(Viewport3Dx); } #region 菜单事件绑定 private void MenuItem_OnChecked(object sender, RoutedEventArgs e) { Growl.InfoGlobal("Viewport is checked" + e.OriginalSource); } private void MenuItem_OnUnchecked(object sender, RoutedEventArgs e) { Growl.InfoGlobal("Viewport is Unchecked" + e.OriginalSource); } private void MenuItem_OnClick(object sender, RoutedEventArgs e) { } #endregion #region 页面隐式交互 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; MainBorder.ContextMenu.IsOpen = false; return; } MainBorder.ContextMenu.Visibility = Visibility.Visible; // 未拖动时,显示右键菜单 MainBorder.ContextMenu.IsOpen = true; // e.Handled = true; // 阻止事件继续传播 } private void UIElement_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { _mouseDownPosition = e.GetPosition(Viewport3Dx); _isDragging = false; // 重置拖动状态 } #endregion private void Viewport3D_OnLoaded(object sender, RoutedEventArgs e) { //ViewportData.LoadData(); ViewportManager.LoadModelByEntities(new List()); } private void Viewport3Dx_OnPreviewMouseMove(object sender, MouseEventArgs e) { if (e.RightButton == MouseButtonState.Pressed) { // 计算鼠标移动距离 var currentPosition = e.GetPosition(Viewport3Dx); var distance = (currentPosition - _mouseDownPosition).Length; // 判断是否达到拖动的阈值 if (distance > 5) // 阈值可根据需要调整 { _isDragging = true; // 标记为拖动 } } } }