diff --git a/Language/zh_CN.xaml b/Language/zh_CN.xaml
index 74e12bd..34bacec 100644
--- a/Language/zh_CN.xaml
+++ b/Language/zh_CN.xaml
@@ -105,7 +105,7 @@
正面视角
截图当前视角到PNG
显示模型面
- 显示模型面
+ 显示模型面分类标记
显示模型边框
显示光照
双击选择面
diff --git a/SparkClient.sln.DotSettings.user b/SparkClient.sln.DotSettings.user
index e3f03b5..5c02844 100644
--- a/SparkClient.sln.DotSettings.user
+++ b/SparkClient.sln.DotSettings.user
@@ -1,4 +1,5 @@
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -6,10 +7,13 @@
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
diff --git a/ViewModel/Grading/GradingResultVM.cs b/ViewModel/Grading/GradingResultVM.cs
index d29af69..a868392 100644
--- a/ViewModel/Grading/GradingResultVM.cs
+++ b/ViewModel/Grading/GradingResultVM.cs
@@ -571,12 +571,13 @@ public class GradingResultVM : BaseViewModel
}
}
}
- private void ExportFile(string filePath)
+ private async void ExportFile(string filePath)
{
TxtFile(filePath);
ExcelFile(filePath);
- DatFile(filePath);
- STLFile(filePath);
+ await DatFile(filePath);
+ STLFile(filePath);
+ DataConver(filePath);
}
private void TxtFile(string filePath)
@@ -801,13 +802,20 @@ public class GradingResultVM : BaseViewModel
{
return (Math.Floor(value * 10) / 10).ToString(digitsFormat);
}
- private void DatFile(string filePath)
+ private async Task DatFile(string filePath)
{
- File.Create(filePath + ".dat").Close();
+ //File.Create(filePath + ".dat").Close();
+ await ViewportData.SaveAsToVedioFile(filePath + ".mp4");
}
private void STLFile(string filePath)
{
- File.Create(filePath + ".stl").Close();
+ //File.Create(filePath + ".stl").Close();
+ ViewportData.SaveAsToStlFile(filePath + ".stl");
+ }
+ private void DataConver(string filePath)
+ {
+ //File.Create(filePath + ".stl").Close();
+ ViewportData.ConvertMp4ToDat(filePath + ".mp4",filePath + ".dat");
}
#endregion
diff --git a/Views/UserControl/Viewport3D.xaml.cs b/Views/UserControl/Viewport3D.xaml.cs
index b164436..c003abc 100644
--- a/Views/UserControl/Viewport3D.xaml.cs
+++ b/Views/UserControl/Viewport3D.xaml.cs
@@ -258,10 +258,13 @@ public partial class Viewport3D
case "ViewportRightMenuShowModelFace":
//显示模型面
ViewportManager.ShowMainModel3D(checkResult);
+ // ViewportRightMenuShowModelFace.IsChecked = !checkResult;
+ // ViewportManager.ShowMainModel3DByType(!checkResult);
break;
case "ViewportRightMenuShowModelFaceByType":
//显示模型面
- ViewportManager.ShowMainModel3D(!checkResult);
+ // ViewportManager.ShowMainModel3D(!checkResult);
+ // ViewportRightMenuShowModelFaceByType.IsChecked = !checkResult;
ViewportManager.ShowMainModel3DByType(checkResult);
break;
case "ViewportRightMenuShowModelFrame":
diff --git a/Views/UserControl/ViewportData/Helper/VideoHelper.cs b/Views/UserControl/ViewportData/Helper/VideoHelper.cs
new file mode 100644
index 0000000..6e744f8
--- /dev/null
+++ b/Views/UserControl/ViewportData/Helper/VideoHelper.cs
@@ -0,0 +1,159 @@
+
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Media.Media3D;
+using HelixToolkit.Wpf.SharpDX;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Windows.Media.Imaging;
+using System.Drawing;
+using System.Windows;
+
+namespace SparkClient.Views.UserControl.ViewportData.Helper;
+
+public class VideoHelper
+{
+ public static async void CreateVideoFromPngList(List pngEncoders, string outputPath)
+ {
+ string tempDirectory = Path.Combine(System.Environment.CurrentDirectory, "PngFrames");
+ Directory.CreateDirectory(tempDirectory);
+ await Task.Delay(1);
+ try
+ {
+ // Save each PNG frame to a temporary directory
+ for (int i = 0; i < pngEncoders.Count; i++)
+ {
+ string framePath = Path.Combine(tempDirectory, $"frame_{i:D5}.png");
+ using (FileStream fs = new FileStream(framePath, FileMode.Create))
+ {
+ pngEncoders[i].Save(fs);
+ }
+ }
+
+ // Use FFmpeg to create a video from the PNG frames
+ string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); // Assuming ffmpeg.exe is in the same directory as the application
+ if (!File.Exists(ffmpegPath))
+ {
+ throw new FileNotFoundException("FFmpeg executable not found.", ffmpegPath);
+ }
+
+ string framePattern = Path.Combine(tempDirectory, "frame_%05d.png").Replace("\\", "/"); // Replace backslashes with forward slashes for FFmpeg compatibility
+ string arguments = $"-framerate 30 -i \"{framePattern}\" -vf \"scale=640:480\" -c:v libx264 -pix_fmt yuv420p \"{outputPath}\"";
+
+ var processInfo = new System.Diagnostics.ProcessStartInfo
+ {
+ FileName = ffmpegPath,
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+
+ using (var process = System.Diagnostics.Process.Start(processInfo))
+ {
+ string error = process.StandardError.ReadToEnd();
+ process.WaitForExit();
+
+ if (process.ExitCode != 0)
+ {
+ throw new Exception($"FFmpeg error: {error}");
+ }
+ }
+
+ var dicName = Path.GetDirectoryName(outputPath);
+ var fileName =Path.GetFileNameWithoutExtension(outputPath);
+ Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(outputPath, fileName+".dat");
+ }
+ finally
+ {
+ // Clean up temporary frames
+ Directory.Delete(tempDirectory, true);
+ }
+ }
+
+ public static void ConvertMp4ToDat(string inputFilePath, string outputFilePath)
+ {
+ string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); // Assuming ffmpeg.exe is in the same directory as the application
+ if (!File.Exists(ffmpegPath))
+ {
+ throw new FileNotFoundException("FFmpeg executable not found.", ffmpegPath);
+ }
+
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = ffmpegPath,
+ Arguments = $"-i \"{outputFilePath}\" \"{inputFilePath}\"",
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+
+ File.Delete(outputFilePath);
+
+ }
+
+ public static async Task> StartGenerationAndRotation(Viewport3DX viewport)
+ {
+
+
+ var genPngTask = Task.Run(() => GenPng(viewport));
+
+ var rotateModelTask = Task.Run(() => RotateModel());
+
+ await Task.WhenAll(genPngTask, rotateModelTask);
+
+ return genPngTask.Result;
+ }
+
+ public static List GenPng(Viewport3DX viewport)
+ {
+ List result = new List();
+
+ for (int i = 0; i < 10000; i += 50)
+ {
+ // 使用 Dispatcher.Invoke 来确保 UI 操作在主线程中执行
+ var encoder = Application.Current.Dispatcher.Invoke(() => CutPng(viewport));
+ result.Add(encoder);
+ Thread.Sleep(50); // 模拟处理过程
+ }
+
+ return result;
+ }
+
+
+ public static async void RotateModel()
+ {
+ await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ var center = ViewportManager.ModelBounds.Center;
+ var maxDimension = ViewportManager.ModelBounds.Size.Length();
+ var distance = maxDimension *1.2; // 调整相机到模型的距离,保证视野范围内
+ var camera = ViewportManager.GetViewport3D().Camera as HelixToolkit.Wpf.SharpDX.PerspectiveCamera;
+ 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);
+ ViewportHelperPro.RotateModel(new Vector3D(0,-1,0));
+
+ });
+ await Task.Delay(5000);
+ await Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ ViewportHelperPro.RotateModel(new Vector3D(-1, 0, 0));
+ });
+
+ }
+
+ public static PngBitmapEncoder CutPng(Viewport3DX viewport)
+ {
+ int width = (int)viewport.ActualWidth;
+ int height = (int)viewport.ActualHeight;
+ var renderTargetBitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
+ renderTargetBitmap.Render(viewport);
+ var encoder = new PngBitmapEncoder();
+ encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
+ return encoder;
+ }
+}
\ No newline at end of file
diff --git a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs
index ba11257..aa31041 100644
--- a/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs
+++ b/Views/UserControl/ViewportData/Helper/ViewportHelperPro.cs
@@ -1,5 +1,6 @@
using System.Collections.Frozen;
using System.Collections.ObjectModel;
+using System.Drawing.Text;
using System.IO;
using System.Windows;
using System.Windows.Media;
@@ -99,7 +100,7 @@ public class ViewportHelperPro
foreach (var group in groupedDict)
{
var key = group.Key;
-
+ result.Add(GenerateModelByEntity(group.Value, GenFaceColor4(key)));
}
return result;
@@ -110,10 +111,21 @@ public class ViewportHelperPro
switch (planeType)
{
case PlaneType.Girdle:
- return ViewportManager.LightGray;
- case PlaneType.Crown :
- return new Color4(1, 1, 1, 1);
-
+ return new Color4(0, 0.74901f, 1, 0.2f);
+ case PlaneType.TableFacet :
+ return new Color4(0.52941f, 0.80734f, 0.98039f, 1);
+ case PlaneType.UpperMainFacet:
+ return new Color4(30/255f, 144/255f, 1, 1f);
+ case PlaneType.StarFacet:
+ return new Color4(0, 0, 1, 1f);
+ case PlaneType.UpperGirdleFacet:
+ return new Color4(100/255f, 149/255f, 237/255f, 1f);
+ case PlaneType.PavilionMainFacet:
+ return new Color4(106/255f, 90/255f, 205/255f, 1f);
+ case PlaneType.LowerGirdleFact:
+ return new Color4(175/255f, 238/255f, 238/255f, 1f);
+ case PlaneType.Culet:
+ return new Color4(255/255f, 255/255f, 255/255f, 1f);
}
return null;
@@ -144,6 +156,19 @@ public class ViewportHelperPro
}
}
+
+ public static async Task ExportModelsToVideo(Viewport3DX viewport, string filePath)
+ {
+ if (viewport == null)
+ viewport = ViewportManager.GetViewport3D();
+
+ var generationTask = VideoHelper.StartGenerationAndRotation(viewport);
+
+ List pngList = await generationTask;
+
+ VideoHelper.CreateVideoFromPngList(pngList, filePath);
+ }
+
///
/// 导出模型
///
diff --git a/Views/UserControl/ViewportData/Helper/ViewportManager.cs b/Views/UserControl/ViewportData/Helper/ViewportManager.cs
index 6e2b91a..a376140 100644
--- a/Views/UserControl/ViewportData/Helper/ViewportManager.cs
+++ b/Views/UserControl/ViewportData/Helper/ViewportManager.cs
@@ -46,6 +46,8 @@ public class ViewportManager
/// 模型光照
///
public static List MainModelLighting = new List();
+
+ public static List MainModelMeshes = new List();
///
/// 模型控件对象映射
///
@@ -159,6 +161,7 @@ public class ViewportManager
MainModel3D = ViewportHelperPro.GenerateModelByEntity(_viewport, entities);
MainModelLines = ViewportHelperPro.GentrateLineByEntity(_viewport, entities);
MainModelLighting = ViewportHelperPro.GenerateLightingForModel(_viewport);
+ MainModelMeshes = ViewportHelperPro.GenerateModelByEntityGroupByType(entities);
//切换相机视角
_viewport.Camera = ViewportHelperPro.CalculateCamera(PositiveDirection, ModelBounds);
_viewport.Camera.UpDirection = new Vector3D(0, -1, 0);
@@ -196,14 +199,18 @@ public class ViewportManager
if (_viewport == null) return;
if (isShow)
{
- if(_viewport.Items.Contains(MainModel3D))
- return;
- else
- _viewport.Items.Add(MainModel3D);
+ MainModelMeshes.ForEach(e =>
+ {
+ if(!_viewport.Items.Contains(e))
+ _viewport.Items.Add(e);
+ });
}
else
{
- _viewport.Items.Remove(MainModel3D);
+ MainModelMeshes.ForEach(e =>
+ {
+ _viewport.Items.Remove(e);
+ });
}
}
diff --git a/Views/UserControl/ViewportData/ViewportData.cs b/Views/UserControl/ViewportData/ViewportData.cs
index 54a3448..5c1fa6e 100644
--- a/Views/UserControl/ViewportData/ViewportData.cs
+++ b/Views/UserControl/ViewportData/ViewportData.cs
@@ -153,11 +153,25 @@ public class ViewportData
}
}
- public bool SaveAsToVedioFile(string filename)
+ public async Task SaveAsToVedioFile(string filename)
{
try
{
- ViewportHelperPro.ExportModelsToStl(null, filename);
+ await ViewportHelperPro.ExportModelsToVideo(null, filename);
+
+ }
+ catch
+ {
+ return ;
+ }
+ }
+
+ public bool ConvertMp4ToDat(string mp4FilePath, string datFilePath)
+ {
+
+ try
+ {
+ VideoHelper.ConvertMp4ToDat(datFilePath, mp4FilePath);
return true;
}
catch