diff --git a/.gitignore b/.gitignore index fa47f94..9beca53 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,20 @@ *.idea **/__pycache__/ LoginDetails.txt +.vs/ + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ \ No newline at end of file diff --git a/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher.sln b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher.sln new file mode 100644 index 0000000..d572538 --- /dev/null +++ b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FolderWatcher", "FolderWatcher\FolderWatcher.csproj", "{C6242277-730C-4AC6-B162-503D5D093D1C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6242277-730C-4AC6-B162-503D5D093D1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6242277-730C-4AC6-B162-503D5D093D1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6242277-730C-4AC6-B162-503D5D093D1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6242277-730C-4AC6-B162-503D5D093D1C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {137C35CA-CBE2-4914-83A2-F306FC8D23B1} + EndGlobalSection +EndGlobal diff --git a/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.cs b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.cs new file mode 100644 index 0000000..5ab0bee --- /dev/null +++ b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.cs @@ -0,0 +1,123 @@ + +using Newtonsoft.Json; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace PiXYZDemo +{ + class FolderWatcher + { + private static void WatchFolder (string configFile) + { + var (inputFolder, outputFolder, extensions, optimization, publishToAssetmanager, orgid, projid, collectionPath, tags) = ReadConfig(configFile); + + using (FileSystemWatcher watcher = new FileSystemWatcher()) + { + watcher.Path = inputFolder; + watcher.Filter = "*.*"; + watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite; + + watcher.Created += (sender, e) => OnChanged(e.FullPath, inputFolder, outputFolder, extensions, optimization, publishToAssetmanager, orgid, projid, collectionPath, tags); + + watcher.EnableRaisingEvents = true; + + Console.WriteLine("\nWaiting for files to process...\n"); + Console.ReadLine(); // Keep the application running + } + + } + + private static void OnChanged(string filePath, string inputFolder, string outputFolder, string[] extensions, bool optimization, string publishToAssetmanager, string orgid, string projid, string collectionPath, string[] tags) + { + string fileExtension = GetFileExtension(filePath); + + if (extensions.Contains(fileExtension)) + { + Console.WriteLine($"Processing file: {filePath}"); + + // Add your processing logic here + ExecutePixyzSDK(filePath, outputFolder, extensions, optimization, publishToAssetmanager, orgid, projid, collectionPath, tags); + + // Remove the file after processing if needed: + File.Delete(filePath); + Console.WriteLine($"File deleted: {filePath}"); + } + } + + private static (string, string, string[], bool, string, string, string, string, string[]) ReadConfig(string configFile) + { + var configContent = File.ReadAllText("../../../"+configFile); + dynamic inputs = JsonConvert.DeserializeObject(configContent); + + string inputFolder = Path.GetFullPath((string)inputs.input_folder); + string outputFolder = Path.GetFullPath((string)inputs.output_folder); + string[] extensions = ((IEnumerable)inputs.extensions).Select(x => x.ToString()).ToArray(); + bool optimization = (bool)inputs.optimization; + string publishToAssetmanager = (string)inputs.publish_to_assetmanager; + string orgid = (string)inputs.orgid; + string projid = (string)inputs.projid; + string collectionPath = (string)inputs.collectionpath; + string[] tags = inputs.tags.ToObject(); + + Console.WriteLine("\n"); + Console.WriteLine($"Input folder: {inputFolder}\n"); + Console.WriteLine($"Output folder: {outputFolder}\n"); + Console.WriteLine($"Extensions: {string.Join(" ", extensions)}\n"); + Console.WriteLine($"Publish to Asset Manager: {publishToAssetmanager}\n"); + Console.WriteLine($"Organisation ID: {orgid}\n"); + Console.WriteLine($"Project ID: {projid}\n"); + Console.WriteLine($"Collection Path: {collectionPath}\n"); + Console.WriteLine($"Asset Tags: {string.Join(" ", tags)}\n"); + + return (inputFolder, outputFolder, extensions, optimization, publishToAssetmanager, orgid, projid, collectionPath, tags); + } + + private static void ExecutePixyzSDK(string inputFile, string outputFolder, string[] extensions, bool optimization, string publishToAssetmanager, string orgid, string projid, string collectionPath, string[] tags) + { + PixyzInit.GetPixyzLicense(); + + if (PixyzInit.api.Core.CheckLicense()) + { + ImportOptimiseExport.ConvertFile(inputFile, outputFolder, extensions.ToList(), optimization, orgid, projid, collectionPath, tags.ToList()); + } + else + { + Console.WriteLine("No License Available"); + } + + } + + private static string GetFileExtension(string file) + { + return Path.GetExtension(file); + } + + static void PrintLogo() + { + Console.WriteLine(""); + Console.WriteLine(" ####### %###### "); + Console.WriteLine(" ############## &#############& "); + Console.WriteLine("###### ###### ###### &#####"); + Console.WriteLine("#### &########### ####"); + Console.WriteLine("####% ###### ####"); + Console.WriteLine(" #####& &###### #### #####%"); + Console.WriteLine(" ###### ###### ###### &###### "); + Console.WriteLine(" ######& ### &########## "); + Console.WriteLine(" ####### ###### "); + Console.WriteLine(" &###########& #### &###### "); + Console.WriteLine(" ###### ###### &###### ######& "); + Console.WriteLine(" ##### ##% ###### &####%"); + Console.WriteLine("####% %####### ####"); + Console.WriteLine("####% ############& ####"); + Console.WriteLine(" #####& %#####% ######% #####%"); + Console.WriteLine(" ############ ############# "); + Console.WriteLine(" ####### %###### "); + } + static void Main(string[] args) + { + PixyzInit.InitPixyz(); + PrintLogo(); + WatchFolder("config.json"); + } + } +} \ No newline at end of file diff --git a/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.csproj b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.csproj new file mode 100644 index 0000000..c9c6a27 --- /dev/null +++ b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/FolderWatcher.csproj @@ -0,0 +1,25 @@ + + + + Exe + net8.0 + enable + enable + PiXYZDemo.FolderWatcher + + + + + + + + + + + + + + + + + diff --git a/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/config.json b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/config.json new file mode 100644 index 0000000..6c9f863 --- /dev/null +++ b/csharp/Windows/FolderWatcher/FolderWatcher/FolderWatcher/config.json @@ -0,0 +1,18 @@ +{ + "input_folder": "_input/", + "output_folder": "_output/", + "extensions": + [ + ".pxz", + ".fbx", + ".glb", + ".obj", + ".3dxml" + ], + "optimization": "True", + "publish_to_assetmanager": "False", + "orgid": "ORG_ID", + "projid": "PROJ_ID", + "collectionpath": "COLLECTION_PATH", + "tags": ["TAG"] +} diff --git a/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.cs b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.cs new file mode 100644 index 0000000..133d75a --- /dev/null +++ b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace PiXYZDemo +{ + using UnityEngine.Pixyz.Algo; + using UnityEngine.Pixyz.Scene; + using UnityEngine.Pixyz.IO; + + using static System.Formats.Asn1.AsnWriter; + using System.Xml.Linq; + using UnityEngine.Pixyz.API; + + class ImportOptimiseExport + { + static void OptimiseModel(uint root, string fileName) + { + var stats = PixyzUtils.GetStats(root); + var t0 = stats.Item1; + var n_triangles = stats.Item2; + var n_vertices = stats.Item3; + var n_parts = stats.Item4; + + var occurrences = new OccurrenceList((int)root); + + Console.WriteLine("Removing Holes..."); + double diameter = 10; + PixyzInit.api.Algo.RemoveHoles(occurrences, true, false, false, diameter, 0); + + Console.WriteLine("Delete Patches..."); + PixyzInit.api.Algo.DeletePatches(occurrences, true); + + Console.WriteLine("Decimating..."); + PixyzInit.api.Algo.Decimate(occurrences, 1, 0.1, 3, -1, false); + + Console.WriteLine("Removing Hidden Geometries..."); + PixyzInit.api.Algo.RemoveOccludedGeometries(occurrences, SelectionLevel.Polygons, 1024, 16, 90, false, 1); + + var newStats = PixyzUtils.GetStats(root); + var t1 = newStats.Item1; + PixyzUtils.PrintStats(fileName, t1 - t0, n_triangles, newStats.Item2, n_vertices, newStats.Item3, n_parts, newStats.Item4); + } + + public static void ConvertFile(string inputFile, string outputFolder, List extensions, bool optimization, string orgId, string projId, string collectionPath, List tags) + { + var modelFiles = new List(); + var fileName = Path.GetFileNameWithoutExtension(inputFile); + + PixyzInit.api.Core.SetLogFile(Path.Combine(outputFolder, fileName + ".log")); + + var root = ImportModel(inputFile); + + PrepareModel(root); + + if (optimization) + { + OptimiseModel(root, fileName); + } + + foreach (var extension in extensions) + { + Console.WriteLine($"Exporting {extension}..."); + PixyzInit.api.IO.ExportScene(Path.Combine(outputFolder, fileName + extension)); + modelFiles.Add(Path.Combine(outputFolder, fileName + extension)); + } + } + + static uint ImportModel(string filepath) + { + Console.WriteLine($"Importing {filepath}..."); + return PixyzInit.api.IO.ImportScene(filepath); + } + + static void PrepareModel(uint root) + { + var occurrences = new OccurrenceList((int)root); + + Console.WriteLine("Calculating Tolerances... "); + double tolerance = Math.Min(MathUtils.AabbDiagLength(PixyzInit.api.Scene.GetAABB(occurrences)) / 1000, 0.1); + + Console.WriteLine("Repairing CAD... "); + PixyzInit.api.Algo.RepairCAD(occurrences, tolerance, false); + + Console.WriteLine("Repairing Meshes... "); + PixyzInit.api.Algo.RepairMesh(occurrences, tolerance, true, false); + + Console.WriteLine("Tessellating Meshes... "); + PixyzInit.api.Algo.Tessellate(occurrences, tolerance, -1, -1); + } + + static void ExportModel(string filepath, string extension, uint root) + { + var finalPath = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath) + extension); + Console.WriteLine($"Exporting {finalPath}..."); + PixyzInit.api.IO.ExportScene(finalPath, root); + } + + static void Main(string[] args) + { + + string modelFilePath = "../../../../../../../python/Windows/shared/shared_models/SkidLoaderSolidworks/Skid Loader ASSM 11-4-21.SLDASM"; + + PixyzInit.InitPixyz(); + PixyzInit.GetPixyzLicense(); + + if (PixyzInit.api.Core.CheckLicense()) + { + var root = ImportModel(modelFilePath); + PixyzUtils.SaveScreenshot((int)root, Path.Combine(Path.GetDirectoryName(modelFilePath), "before.png"), Orientation.LEFT); + PrepareModel(root); + PixyzUtils.SaveScreenshot((int)root, Path.Combine(Path.GetDirectoryName(modelFilePath), "after.png"), Orientation.FRONT); + PixyzUtils.ExtractHierarchyToJson(root, Path.Combine(Path.GetDirectoryName(modelFilePath), $"{Path.GetFileNameWithoutExtension(modelFilePath)}.json")); + ExportModel(modelFilePath, "_new.glb", root); + } + else + { + Console.WriteLine("No License Available"); + } + } + } +} \ No newline at end of file diff --git a/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.csproj b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.csproj new file mode 100644 index 0000000..74c7ce2 --- /dev/null +++ b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.sln b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.sln new file mode 100644 index 0000000..0fef07d --- /dev/null +++ b/csharp/Windows/ImportOptimiseExport/ImportOptimiseExport/ImportOptimiseExport.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportOptimiseExport", "ImportOptimiseExport.csproj", "{17025DAA-A491-4612-B9FE-EC84A85436F1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17025DAA-A491-4612-B9FE-EC84A85436F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17025DAA-A491-4612-B9FE-EC84A85436F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17025DAA-A491-4612-B9FE-EC84A85436F1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17025DAA-A491-4612-B9FE-EC84A85436F1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {89105A4A-78D1-4B36-B961-639B2216DFBD} + EndGlobalSection +EndGlobal diff --git a/csharp/Windows/shared/shared_utils/MathUtils.cs b/csharp/Windows/shared/shared_utils/MathUtils.cs new file mode 100644 index 0000000..57bf3af --- /dev/null +++ b/csharp/Windows/shared/shared_utils/MathUtils.cs @@ -0,0 +1,96 @@ +using System; +using static System.Formats.Asn1.AsnWriter; +using System.Xml.Linq; +using System.Xml; + +namespace PiXYZDemo +{ + using Newtonsoft.Json; + using System.Drawing; + using UnityEngine.Pixyz.API; + using UnityEngine.Pixyz.Geom; + using UnityEngine.Pixyz.Scene; + using UnityEngine.Pixyz.View; + + + public static class MathUtils + { + public static Point3 PointAdd(Point3 pt1, Point3 pt2) + { + return new Point3 + { + x = pt1.x + pt2.x, + y = pt1.y + pt2.y, + z = pt1.z + pt2.z + }; + } + + public static Point3 PointSub(Point3 pt1, Point3 pt2) + { + return new Point3 + { + x = pt1.x - pt2.x, + y = pt1.y - pt2.y, + z = pt1.z - pt2.z + }; + } + + public static double DotProduct(Point3 pt1, Point3 pt2) + { + return pt1.x * pt2.x + pt1.y * pt2.y + pt1.z * pt2.z; + } + + public static Point3 CrossProduct(Point3 pt1, Point3 pt2) + { + return new Point3 + { + x = pt1.y * pt2.z - pt1.z * pt2.y, + y = pt1.z * pt2.x - pt1.x * pt2.z, + z = pt1.z * pt2.z - pt1.z * pt2.z + }; + } + + public static double VectorLength(Point3 v) + { + return Math.Sqrt(DotProduct(v, v)); + } + + public static double AabbDiagLength(AABB aabb) + { + return VectorLength(PointSub(aabb.high, aabb.low)); + } + + public static Point3 Center(Point3 pt1, Point3 pt2) + { + return new Point3 + { + x = (pt1.x + pt2.x) / 2, + y = (pt1.y + pt2.y) / 2, + z = (pt1.z + pt2.z) / 2 + }; + } + + public static Point3 Normalize(Point3 v) + { + double length = VectorLength(v); + return new Point3 + { + x = v.x / length, + y = v.y / length, + z = v.z / length + }; + } + + public static bool PointInAABB(AABB aabb, Point3 pt) + { + if (pt.x < aabb.low.x) return false; + if (pt.y < aabb.low.y) return false; + if (pt.z < aabb.low.z) return false; + if (pt.x > aabb.high.x) return false; + if (pt.y > aabb.high.y) return false; + if (pt.z > aabb.high.z) return false; + return true; + } + } +} + diff --git a/csharp/Windows/shared/shared_utils/PixyzInit.cs b/csharp/Windows/shared/shared_utils/PixyzInit.cs new file mode 100644 index 0000000..3e794a5 --- /dev/null +++ b/csharp/Windows/shared/shared_utils/PixyzInit.cs @@ -0,0 +1,102 @@ +namespace PiXYZDemo +{ + using Newtonsoft.Json; + using System.Runtime.InteropServices; + using UnityEngine.Pixyz.API; + using UnityEngine.Pixyz.Geom; + using UnityEngine.Pixyz.Scene; + using UnityEngine.Pixyz.View; + + + public static class PixyzInit + { + public static PiXYZAPI api; + + private static int currentProgress = 0; + + static string serverName = "Server Name"; + static ushort serverPort = 27005; + + public static void InitPixyz() + { + Console.WriteLine("Initializing pixyz sdk"); + + api = PiXYZAPI.Initialize(); + + Console.WriteLine("Adding available tokens."); + foreach (var token in api.Core.ListTokens().list) + { + try + { + api.Core.AddWantedToken(token); + Console.WriteLine($"Token {token} added successfully."); + } + catch (Exception e) + { + Console.WriteLine($"Failed to add token {token}: {e.Message}"); + } + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + InitializeDedicatedGraphics(); + } + + api.Core.AddProgressChangedCallback(OnProgressChangedCallback, 0); + api.Core.AddOnSessionResetCallback(OnSessionResetCallback, 0); + + } + + public static void GetPixyzLicense() + { + if (!api.Core.CheckLicense()) + { + api.Core.ConfigureLicenseServer(serverName, serverPort, true); + Console.WriteLine("Configured license server."); + } + + } + + private static void InitializeDedicatedGraphics() + { + // Force program to be executed on discrete GPU in case of a dual integrated/discrete architecture + try + { + var is64Bit = RuntimeInformation.ProcessArchitecture == Architecture.X64; + var dllName = is64Bit ? "nvapi64.dll" : "nvapi.dll"; + var nvapi = NativeLibrary.Load(dllName); + + // Simulate a call to a nonexistent method as a placeholder + // If there are specific functions to be called, replace 'Fake' with them + var fakeMethod = NativeLibrary.GetExport(nvapi, "fake"); + // fakeMethod.DynamicInvoke(); // Assumes handle to 'fake' method for demonstration + + NativeLibrary.Free(nvapi); + } + catch (Exception) + { + // Ignore any exceptions since the 'fake' entry point doesn't exist + } + } + private static void OnProgressChangedCallback(nint userdata, int progress) + { + if (progress != -1) + { + if (progress % 5 == 0) + { + if (progress != currentProgress) + { + Console.WriteLine($"Progress: {progress}"); + currentProgress = progress; + } + } + } + } + + private static void OnSessionResetCallback(nint userdata) + { + Console.WriteLine("Session reset"); + } + } +} + diff --git a/csharp/Windows/shared/shared_utils/PixyzUtils.cs b/csharp/Windows/shared/shared_utils/PixyzUtils.cs new file mode 100644 index 0000000..8fbc8bf --- /dev/null +++ b/csharp/Windows/shared/shared_utils/PixyzUtils.cs @@ -0,0 +1,147 @@ +namespace PiXYZDemo +{ + using Newtonsoft.Json; + using UnityEngine.Pixyz.API; + using UnityEngine.Pixyz.Geom; + using UnityEngine.Pixyz.Scene; + using UnityEngine.Pixyz.View; + + + public enum Orientation + { + FRONT = 0, + BACK = 1, + TOP = 2, + BOTTOM = 3, + LEFT = 4, + RIGHT = 5 + } + + public static class PixyzUtils + { + public static (double, int, int, int) GetStats(uint root) + { + PixyzInit.api.Core.ConfigureInterfaceLogger(false, false, false); + + double t = DateTime.Now.TimeOfDay.TotalSeconds; + var occurrences = new OccurrenceList((int)root); + + int n_triangles = (int)PixyzInit.api.Scene.GetPolygonCount(occurrences, true, false, false); + int n_vertices = (int)PixyzInit.api.Scene.GetVertexCount(occurrences, false, false, false); + int n_parts = PixyzInit.api.Scene.GetPartOccurrences((uint)root).length; + PixyzInit.api.Core.ConfigureInterfaceLogger(true, true, true); + + return (t, n_triangles, n_vertices, n_parts); + } + + public static void SaveScreenshot(int occurrence, string path, Orientation orientation = Orientation.FRONT, + CameraType type = CameraType.Perspective, int resolution = 1024, + int fov = 60, bool showEdges = false, bool showLines = false) + { + Console.WriteLine("Taking Screenshot..."); + + Point3 direction = orientation switch + { + Orientation.FRONT => new Point3 { x = 0, y = 0, z = -1 }, + Orientation.BACK => new Point3 { x = 0, y = 0, z = 1 }, + Orientation.TOP => new Point3 { x = 0, y = -1, z = 0 }, + Orientation.BOTTOM => new Point3 { x = 0, y = 1, z = 0 }, + Orientation.LEFT => new Point3 { x = 1, y = 0, z = 0 }, + Orientation.RIGHT => new Point3 { x = -1, y = 0, z = 0 }, + _ => new Point3 { x = 0, y = 0, z = 0 } + }; + + var occurrences = new OccurrenceList(occurrence); + + var viewer = PixyzInit.api.View.CreateViewer(resolution, resolution); + var gpuScene = PixyzInit.api.View.CreateGPUScene(occurrences, showEdges); + PixyzInit.api.View.AddGPUScene(gpuScene, viewer); + PixyzInit.api.View.FitCamera(direction, type, fov, viewer, occurrences); + + PixyzInit.api.View.SetViewerProperty("ShowEdges", showEdges ? "True" : "False", viewer); + PixyzInit.api.View.SetViewerProperty("ShowLines", showLines ? "True" : "False", viewer); + + PixyzInit.api.View.TakeScreenshot(path, viewer); + Console.WriteLine("Screenshot saved at: " + path); + PixyzInit.api.View.DestroyViewer(viewer); + PixyzInit.api.View.DestroyGPUScene(gpuScene); + } + + public static void PrintStats(string fileName, double t, int n_triangles, int _n_triangles, + int n_vertices, int _n_vertices, int n_parts, int _n_parts) + { + Console.WriteLine("\n"); + Console.WriteLine($"{"file",-20}{fileName}\n"); + Console.WriteLine($"{"optimization",-20}{t:0.000} s\n"); + Console.WriteLine($"{"triangles",-20}{n_triangles} -> {_n_triangles}\n"); + Console.WriteLine($"{"vertices",-20}{n_vertices} -> {_n_vertices}\n"); + Console.WriteLine($"{"parts",-20}{n_parts} -> {_n_parts}\n"); + } + + static Dictionary GetMetadataDict(PropertyValue propertyValue) + { + return new Dictionary + { + { "name", propertyValue.name }, + { "value", propertyValue.value } + }; + } + + static Dictionary GetHierarchyDict(uint occurrence) + { + var hierarchyDict = new Dictionary + { + { "name", PixyzInit.api.Core.GetProperty(occurrence, "Name") } + }; + + var matrix = PixyzInit.api.Scene.GetLocalMatrix(occurrence); + var vector3lst = PixyzInit.api.Geom.ToTRS(matrix); + hierarchyDict.Add("translation", new List { vector3lst[0]._base.x, vector3lst[0]._base.y, vector3lst[0]._base.z }); + hierarchyDict.Add("rotation", new List { vector3lst[1]._base.x, vector3lst[1]._base.y, vector3lst[1]._base.z }); + hierarchyDict.Add("scale", new List { vector3lst[2]._base.x, vector3lst[2]._base.y, vector3lst[2]._base.z }); + + var children = new List>(); + foreach (var child in PixyzInit.api.Scene.GetChildren(occurrence).list) + { + children.Add(GetHierarchyDict(child)); + } + hierarchyDict.Add("children", children); + + if (PixyzInit.api.Scene.HasComponent(occurrence, ComponentType.Metadata)) + { + + var metadataComponent = PixyzInit.api.Scene.GetComponent(occurrence, ComponentType.Metadata); + var occurrences = new MetadataList(1); + occurrences[0] = metadataComponent; + + MetadataDefinitionList metadataDefinitions = PixyzInit.api.Scene.GetMetadatasDefinitions(occurrences); + + + MetadataDefinition metadataDefinition = metadataDefinitions[0]; + + var metadataList = new List>(); + + foreach (PropertyValue propertyValue in metadataDefinition._base.list) + { + metadataList.Add(GetMetadataDict(propertyValue)); + } + + hierarchyDict.Add("metadata", metadataList); + } + + return hierarchyDict; + } + + public static void ExtractHierarchyToJson(uint root, string filePath) + { + var hierarchyDict = GetHierarchyDict(root); + using (var writer = new StreamWriter(filePath)) + { + var json = JsonConvert.SerializeObject(hierarchyDict, Formatting.Indented); + writer.Write(json); + } + Console.WriteLine("\nDone: structure tree exported at " + filePath); + } + } +} +