You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
8.1 KiB

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<Viewport3DTriangleEntity> facets = new List<Viewport3DTriangleEntity>();
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<Viewport3DTriangleEntity> facetsFinal = new List<Viewport3DTriangleEntity>();
foreach (var item in facets)
{
var data = ViewportHelperPro.VectorClockwiseSort(new List<Vector3>
{ 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<Viewport3DTriangleEntity>());
}
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; // 标记为拖动
}
}
}
}