fix: 部署调整(3/3)

master
Tongg 4 months ago
parent 1c61cf83e1
commit b47f1e83ae
  1. 5
      ViewModel/Grading/DiamondSelectVM.cs
  2. 162
      Views/UserControl/ViewportData/Helper/ObjExporter.cs
  3. 2
      Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs
  4. 8
      Views/UserControl/ViewportData/Helper/ViewportManager.cs

@ -171,7 +171,7 @@ public class DiamondSelectVM : BaseViewModel
}
// 模拟耗时操作
//System.Threading.Thread.Sleep(50); // 休眠50毫秒
await Task.Delay(710);
await Task.Delay(515);
loading.setValue(i);
progress = i;
}
@ -537,7 +537,8 @@ public class DiamondSelectVM : BaseViewModel
{
//WindowManager.mainViewModel.Content = WindowManager.PreviousVM();
BaseControlVM vm = new BaseControlVM(new GradingResultVM(param), MultilingualHelper.getString("DetectionResult"));
vm.WindowTitle = string.IsNullOrWhiteSpace(param.DiamondCode) ? vm.WindowTitle : $"{vm.WindowTitle} - {param.DiamondCode}";
var ct = param.measurements.VOLUME / 57;
vm.WindowTitle = string.IsNullOrWhiteSpace(param.DiamondCode) ? vm.WindowTitle : $"{vm.WindowTitle} - {param.DiamondCode}({ct.ToString("F3")}ct)";
vm.ShowFunctionButton = System.Windows.Visibility.Visible;
WindowManager.mainViewModel.Content = vm;
WindowManager.openContent.Add(vm);

@ -10,92 +10,120 @@ namespace SparkClient.Views.UserControl.ViewportData.Helper;
public class ObjExporter
{
public static void ExportToObj2(List<Viewport3DTriangleEntity> entities, string outputPath)
{
// 分组:按面代码 PlaneCode 分组
var faceGroups = entities
.GroupBy(e => e.PlaneCode)
.ToDictionary(g => g.Key, g => g.ToList());
{
string obj = GenerateObj(entities);
// Step 2: 写入 OBJ 文件
using (var writer = new StreamWriter(outputPath))
{
writer.Write(obj);
}
}
public static string GenerateObj(IEnumerable<Viewport3DTriangleEntity> triangles)
{
var groups = triangles.GroupBy(t => t.PlaneCode);
// 存储每个面的顶点和法线
var faceData = new Dictionary<string, FaceData>();
List<Vector3> allVertices = new List<Vector3>();
List<Vector3> allNormals = new List<Vector3>();
List<string> faceLines = new List<string>();
// Step 1: 处理每个面,生成顶点列表并计算法线
foreach (var group in faceGroups)
{
// 合并所有顶点并去重
var vertices = group.Value
.SelectMany(e => new[] { e.Point1, e.Point2, e.Point3 })
.Distinct()
.ToList();
foreach (var group in groups)
{
// Step 1: 组内顶点去重
var localVertices = new Dictionary<Vector3, int>();
var groupVertices = new List<Vector3>();
// 按凸包算法排序顶点(避免交叉)
var sortedVertices = ConvexHullSort(vertices);
foreach (var triangle in group)
{
AddVertex(triangle.Point1);
AddVertex(triangle.Point2);
AddVertex(triangle.Point3);
}
// 计算面的法线(基于排序后的顶点)
var normal = CalculateFaceNormal(sortedVertices, ViewportManager.CenterVector);
void AddVertex(Vector3 v)
{
if (!localVertices.ContainsKey(v))
{
localVertices[v] = groupVertices.Count;
groupVertices.Add(v);
}
}
// 存储面数据
faceData[group.Key] = new FaceData
{
Vertices = sortedVertices,
Normal = normal
};
}
// 映射组内索引到全局索引
var vertexMap = new Dictionary<int, int>();
foreach (var v in groupVertices)
{
allVertices.Add(v);
vertexMap[localVertices[v]] = allVertices.Count; // OBJ索引从1开始
}
// Step 2: 写入 OBJ 文件
using (var writer = new StreamWriter(outputPath))
{
// 写入顶点
var vertexIndexMap = new Dictionary<Vector3, int>();
int index = 1;
foreach (var face in faceData.Values)
{
foreach (var vertex in face.Vertices)
{
if (!vertexIndexMap.ContainsKey(vertex))
// Step 2: 处理法线和面
Vector3 baseNormal = Vector3.Zero;
bool isFirstTriangle = true;
int vnIndex = 0;
foreach (var triangle in group)
{
vertexIndexMap[vertex] = index++;
writer.WriteLine($"v {vertex.X} {vertex.Y} {vertex.Z}");
Vector3 p1 = triangle.Point1;
Vector3 p2 = triangle.Point2;
Vector3 p3 = triangle.Point3;
int localI1 = localVertices[p1];
int localI2 = localVertices[p2];
int localI3 = localVertices[p3];
int globalI1 = vertexMap[localI1];
int globalI2 = vertexMap[localI2];
int globalI3 = vertexMap[localI3];
// 计算法线
Vector3 edge1 = p2 - p1;
Vector3 edge2 = p3 - p1;
Vector3 normal = Vector3.Cross(edge1, edge2);
normal.Normalize();
if (isFirstTriangle)
{
baseNormal = normal;
isFirstTriangle = false;
allNormals.Add(baseNormal);
vnIndex = allNormals.Count;
}
// 调整法线方向
float dot = Vector3.Dot(normal, baseNormal);
if (dot < 0)
{
(globalI2, globalI3) = (globalI3, globalI2);
}
faceLines.Add($"f {globalI1}//{vnIndex} {globalI2}//{vnIndex} {globalI3}//{vnIndex}");
}
}
}
// 写入法线(每个面一个法线)
var normalIndexMap = new Dictionary<Vector3, int>();
index = 1;
foreach (var face in faceData.Values)
{
if (!normalIndexMap.ContainsKey(face.Normal))
// 构建OBJ内容
StringBuilder objBuilder = new StringBuilder();
// 顶点
foreach (var v in allVertices)
{
normalIndexMap[face.Normal] = index++;
// writer.WriteLine($"vn {face.Normal.X} {face.Normal.Y} {face.Normal.Z}");
objBuilder.AppendLine($"v {v.X:F6} {v.Y:F6} {v.Z:F6}");
}
}
// 写入面
foreach (var faceEntry in faceData)
{
var face = faceEntry.Value;
var normalIndex = normalIndexMap[face.Normal];
// 正面(顺时针)
writer.Write("f ");
foreach (var vertex in face.Vertices)
// 法线
foreach (var vn in allNormals)
{
writer.Write($"{vertexIndexMap[vertex]}//{normalIndex} ");
objBuilder.AppendLine($"vn {vn.X:F6} {vn.Y:F6} {vn.Z:F6}");
}
writer.WriteLine();
// 反面(逆时针)
writer.Write("f ");
foreach (var vertex in face.Vertices.AsEnumerable().Reverse())
// 面
foreach (var face in faceLines)
{
writer.Write($"{vertexIndexMap[vertex]}//{normalIndex} ");
objBuilder.AppendLine(face);
}
writer.WriteLine();
return objBuilder.ToString();
}
}
}
/// <summary>
/// 凸包排序(Andrew's Monotone Chain 算法)

@ -375,7 +375,7 @@ public class ViewportHelperPro
var facetPoints = VectorClockwiseSort(uniqueVectors.ToList());
Vector3 center = GetCentroid(uniqueVectors.ToList());
Console.WriteLine($"{yaoFace.Key} \t {center.X} \t {center.Y} \t {center.Z}");
// Console.WriteLine($"{yaoFace.Key} \t {center.X} \t {center.Y} \t {center.Z}");
List<Vector3> leftLine = new List<Vector3>();
List<Vector3> rightLine = new List<Vector3>();

@ -361,6 +361,14 @@ public class ViewportManager
//切换相机视角
_viewport.Camera = ViewportHelperPro.CalculateCamera(PositiveDirection, ModelBounds);
_viewport.Camera.UpDirection = new Vector3D(0, -1, 0);
var center = ViewportManager.ModelBounds.Center;
var maxDimension = ViewportManager.ModelBounds.Size.Length();
var distance = maxDimension * 1.2; // 调整相机到模型的距离,保证视野范围内
var camera = _viewport.Camera as HelixToolkit.Wpf.SharpDX.OrthographicCamera;
camera.Position = new Point3D(center.X, center.Y - distance, center.Z); // 从底部看,Y轴负方向
camera.UpDirection = new Vector3D(0, 0, -1);
camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z);
_viewport.RenderHost.MSAA = MSAALevel.Maximum;
// TODO:
InitMeshLines();

Loading…
Cancel
Save