feat: 3D模型数值优化

master
Tongg 7 months ago
parent 1879f3c5c2
commit 10bca8e310
  1. 1
      SparkClient.sln.DotSettings.user
  2. 2
      Views/UserControl/Viewport3D.xaml
  3. 129
      Views/UserControl/Viewport3D.xaml.cs
  4. 2
      Views/UserControl/ViewportData/Entity/ColorConfigEntity.cs
  5. 157
      Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs
  6. 6
      Views/UserControl/ViewportData/Helper/ViewportManager.cs

@ -39,6 +39,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARoutedEventArgs_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F1a88b4a860176dd5f825206bbebf3ee3d44ff3f058ceed9eb693c1eaa018_003FRoutedEventArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002ECoreCLR_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F955ec549fe664629353c3b5424b6ad6c7dfcec4ab59bae709ab962c228cf45_003FRuntimeType_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeType_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5147b10c5a8c4522b56fba0a889139cfc8f908_003F45_003F2a5f113e_003FRuntimeType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AScreenSpacedNode_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F68d37d16685244cf9996bf767117a771210200_003Ff9_003F61fd6f6c_003FScreenSpacedNode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASqliteCommand_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc7a59cb727594ed7a94648b2d66dbf702aa28_003F2f_003Fdc5f3094_003FSqliteCommand_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATaskCompletionSource_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5147b10c5a8c4522b56fba0a889139cfc8f908_003Ffc_003Fe9092391_003FTaskCompletionSource_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATextInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Ftongg_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F68d37d16685244cf9996bf767117a771210200_003F3a_003Ff14dd285_003FTextInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>

@ -139,7 +139,7 @@
<!-- TextChanged="TbCustomizeRevolve_OnTextChanged" -->
<!-- -->
<!-- /> -->
<hc:NumericUpDown Grid.Column="1" Grid.Row="1" Padding="0" HorizontalContentAlignment="Center" Maximum="360" x:Name="TbCustomizeRevolve"/>
<hc:NumericUpDown Grid.Column="1" Grid.Row="1" Padding="0" HorizontalContentAlignment="Center" Value="10" Maximum="360" MouseDoubleClick="TbCustomizeRevolve_OnMouseDoubleClick" x:Name="TbCustomizeRevolve"/>
</Grid>
</Grid>
</Grid>

@ -202,58 +202,144 @@ public partial class Viewport3D
private void BtnDirection_OnClick(object sender, RoutedEventArgs e)
{
var directionName = ((Button)sender).Name.ToString();
var directionValue = (int)TbCustomizeRevolve.Value; // 旋转角度(单位:度)
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 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; // 仰角(垂直方向的角度)
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 范围内循环
if (elevation >= 90)
{
elevation = 89.9f;
azimuth += 180.0f;
}
else if (elevation <= -90)
{
elevation = -89.9f;
azimuth += 180.0f;
}
azimuth = (azimuth + 360) % 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 轴为上方向
var rightDirection = Vector3D.CrossProduct(camera.LookDirection, new Vector3D(0, 1, 0)); // 计算右方向
if (rightDirection.Length < 0.027)
{
rightDirection = Vector3D.CrossProduct(camera.LookDirection, new Vector3D(-1, 0, 0)); // 计算右方向
}
camera.UpDirection = Vector3D.CrossProduct(camera.LookDirection, rightDirection);
}
// 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 右键菜单事件绑定
/// <summary>
@ -495,5 +581,12 @@ public partial class Viewport3D
#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;
}
}

@ -11,7 +11,7 @@ public class ColorConfigEntity
private string _mainFacetColor = "#FFBDD2ED";
private string _mainBorderColor = "#FF6959CC";
private string _selFacetColor = "#FFBDB759";
private string _selFacetColor = "#FFE8E187";
private string _selBorderColor = "#FF000000";
private string _selTypeColor = "#FFFCFCD1";
private string _selFontColor = "#FFFF0000";

@ -3,12 +3,14 @@ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Text;
using System.IO;
using System.Text.Json.Nodes;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Threading;
using HandyControl.Controls;
using HelixToolkit.Wpf.SharpDX;
using log4net;
using NPOI.OpenXmlFormats.Vml.Office;
@ -415,8 +417,8 @@ public class ViewportHelperPro
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));
// result.Add(DisplayLineModel3D( VectorClockwiseSort(ViewportManager.GirdleBottomLines), color??ViewportManager.ColorConfig.MainBorderColor, thickness));
// result.Add(DisplayLineModel3D( VectorClockwiseSort(ViewportManager.GirdleTopLines), color??ViewportManager.ColorConfig.MainBorderColor, thickness));
}
@ -474,24 +476,99 @@ public class ViewportHelperPro
var groupedDic = facetTypeAll.GroupBy(entity => entity.PlaneCode)
.ToDictionary(group => group.Key, group => group.ToList());
Logger.Info($"【面文本生成】 腰由{groupedDic.Count}个面组成");
foreach (var kv in groupedDic)
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)
{
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); });
/***
* 0 1 2 3
* 4 5 6 7
* id-loop4 = 0 - 线 - -
* id-loop4 = 1 - 线 -
* id-loop4 = 2 - 线 -
* id-loop4 = 3 - 线 -
*/
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, textColor));
// 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
{
@ -515,7 +592,12 @@ public class ViewportHelperPro
{
Logger.Info($"【面文本生成】 钻石数据有效,Index有效");
facetIndex += 1;
var param = ViewportManager.DicFacetToValueParam[selFacetType];
var param = ViewportManager.DicFacetToValueParam.ContainsKey(selFacetType) ? ViewportManager.DicFacetToValueParam[selFacetType] : null;
if (param == null)
{ continue;
}
var detail = ViewportManager.DiamondData[$"{param}_DETAIL"];
if (detail == null)
{
@ -531,10 +613,10 @@ public class ViewportHelperPro
}
Logger.Info($"【面文本生成】 {param}_DETAIL.{param}_{facetIndex} ==={paramValue}");
var valueFloat = Math.Round(float.Parse(paramValue.ToString()), MidpointRounding.ToZero);
var valueFloat = float.Parse(paramValue.ToString()).ToString("F1");
Logger.Info($"【面文本生成】 {valueFloat} -- {facetIndex}");
var facetTextPoint = GetOffsetCenter(facetPoints, ViewportManager.CenterVector);
result.Add(DisplayText3D($" {facetIndex} \r\n {valueFloat}", facetTextPoint, textColor));
result.Add(DisplayText3D($" {facetIndex} \r\n {valueFloat}", facetTextPoint, textColor));
}
}
@ -1213,6 +1295,41 @@ public class ViewportHelperPro
}
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,

@ -95,7 +95,7 @@ public class ViewportManager
//选中边框夹角文字
public static bool DoubleClickSelectShowBorderAngle = false;
public static bool DoubleClickSelectShowInfoText = false;
public static bool DoubleClickSelectShowInfoText = true;
//选中同类面
public static bool DoubleClickSelectShowPlaneType = true;
//选中三角形代码
@ -140,13 +140,13 @@ public class ViewportManager
public static Dictionary<PlaneType, string> DicFacetToValueParam = new Dictionary<PlaneType, string>()
{
{ PlaneType.UpperMainFacet,"CROWN_ANGLE"},
{ PlaneType.LowerGirdleFact, "PAV_ANGLE"},
{ PlaneType.PavilionMainFacet, "PAV_ANGLE"},
};
// 数据 -> 面
public static Dictionary<string, PlaneType> DicValueParamToFacet = new Dictionary<string, PlaneType>()
{
{"CROWN_ANGLE", PlaneType.UpperMainFacet},
{"PAV_ANGLE", PlaneType.LowerGirdleFact},
{"PAV_ANGLE", PlaneType.PavilionMainFacet},
};
#endregion
#endregion

Loading…
Cancel
Save