From b7425b8e3b637af41e81b9ec5663ae98bf57ff7a Mon Sep 17 00:00:00 2001 From: unitycoder Date: Sun, 15 Sep 2024 20:44:24 +0300 Subject: [PATCH 01/83] fix json progress output for all files, #BUILD beta --- MainWindow.xaml.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index bd98bb1..26b2372 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -499,14 +499,11 @@ static void InitProgressBars(ImportSettings importSettings) int threadCount = importSettings.maxThreads; // clamp to max files - threadCount = Math.Min(threadCount, importSettings.maxFiles); + threadCount = Math.Min(threadCount, importSettings.inputFiles.Count); threadCount = Math.Max(threadCount, 1); //Log.WriteLine("Creating progress bars: " + threadCount); - bool useJsonLog = importSettings.useJSONLog; - - //Log.WriteLine("Creating progress bars: " + threadCount); progressInfos.Clear(); for (int i = 0; i < threadCount; i++) From fb1bdc31f182c2af44acd765e251c2bfad4b286f Mon Sep 17 00:00:00 2001 From: mika Date: Mon, 16 Sep 2024 18:13:49 +0300 Subject: [PATCH 02/83] Update main.yml, #BUILD beta --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66d4716..69f2575 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,9 @@ name: CI on: # Triggers the workflow on push or pull request events but only for the master branch push: - branches: [ master ] + branches: + - master + - plugintest # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 550561aef89ce688d584aeb9bc79637c8db34e6b Mon Sep 17 00:00:00 2001 From: mika Date: Mon, 16 Sep 2024 18:14:14 +0300 Subject: [PATCH 03/83] Update main.yml --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 69f2575..a29907b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,6 @@ on: push: branches: - master - - plugintest # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 02e602388cb00e6918458feff942ad0e879ef8cd Mon Sep 17 00:00:00 2001 From: mika Date: Mon, 16 Sep 2024 18:16:19 +0300 Subject: [PATCH 04/83] #BUILD beta --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 32665a4..a4ca901 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,4 @@ Pull requests to improve this converter are welcome! (please create Issue first, + From e2401b7c999da26f29208f161fce5bf8943ccf0b Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 16 Sep 2024 19:51:42 +0300 Subject: [PATCH 05/83] fix json progressbar value (now reaches 100%), #BUILD beta --- MainWindow.xaml.cs | 32 ++++++++++++++++++++------------ Writers/PCROOT.cs | 5 +++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 020497f..f847b45 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -527,7 +527,7 @@ static void StartProgressTimer() //Log.Write("Starting progress timer..*-*************************"); progressTimerThread = new DispatcherTimer(DispatcherPriority.Background, Application.Current.Dispatcher); progressTimerThread.Tick += ProgressTick; - progressTimerThread.Interval = TimeSpan.FromSeconds(0.1); + progressTimerThread.Interval = TimeSpan.FromSeconds(1); progressTimerThread.Start(); Application.Current.Dispatcher.Invoke(new Action(() => @@ -625,7 +625,7 @@ static void ProgressTick(object sender, EventArgs e) { progressBar.Maximum = maxValue; progressBar.Value = currentValue; - progressBar.Foreground = (currentValue + 1 >= maxValue ? Brushes.Lime : Brushes.Red); //+1 hack fix + progressBar.Foreground = ((currentValue + 1 >= maxValue) ? Brushes.Lime : Brushes.Red); //+1 hack fix //progressBar.ToolTip = $"Thread {index} - {currentValue} / {maxValue}"; // not visible, because modal dialog //Log.Write("ProgressTick: " + index + " " + currentValue + " / " + maxValue); @@ -637,7 +637,7 @@ static void ProgressTick(object sender, EventArgs e) "\"thread\": " + index + "," + "\"currentPoint\": " + currentValue + "," + "\"totalPoints\": " + maxValue + "," + - "\"percentage\": " + (int)((currentValue / (float)maxValue) * 100) + "," + + "\"percentage\": " + (int)((currentValue / (float)maxValue) * 100.0) + "," + "\"file\": " + System.Text.Json.JsonSerializer.Serialize(progressInfo.FilePath) + "}"; Log.Write(jsonString, LogEvent.Progress); @@ -686,7 +686,7 @@ static void ProgressTick(object sender, EventArgs e) // process single file static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, CancellationToken cancellationToken) { - progressTotalPoints = 1; // FIXME dummy for progress bar + progressTotalPoints = 0; Log.Write("Started processing file: " + importSettings.inputFiles[fileIndex]); @@ -697,7 +697,7 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, IReader taskReader = importSettings.GetOrCreateReader(taskId); ProgressInfo progressInfo = null; - lock (lockObject) + //lock (lockObject) { //Log.Write(progressInfos.Count + " : " + fileIndex, LogEvent.Info); progressInfo = progressInfos[fileIndex % progressInfos.Count]; @@ -800,8 +800,6 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, //progressPoint = 0; progressInfo.CurrentValue = 0; progressInfo.MaxValue = importSettings.useLimit ? pointCount : fullPointCount; - //progressTotalPoints = importSettings.useLimit ? pointCount : fullPointCount; - progressInfo.FilePath = importSettings.inputFiles[fileIndex]; lastStatusMessage = "Processing points.."; @@ -816,14 +814,19 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, Log.Write(jsonString, LogEvent.File); - int checkCancelEvery = fullPointCount / 100; + int checkCancelEvery = fullPointCount / 128; // Loop all points - for (int i = 0; i < fullPointCount; i++) + + int maxPointIterations = importSettings.useLimit ? pointCount : fullPointCount; + + //for (int i = 0; i < fullPointCount; i++) + for (int i = 0; i < maxPointIterations; i++) //for (int i = 0; i < 1000; i++) { + // stop at limit count - if (importSettings.useLimit == true && i > pointCount) break; + //if (importSettings.useLimit == true && i > pointCount) break; // check for cancel every 1% of points if (i % checkCancelEvery == 0) @@ -839,7 +842,7 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, // get point XYZ Float3 point = taskReader.GetXYZ(); - if (point.hasError == true) break; + if (point.hasError == true) break; // TODO display errors // add offsets (its 0 if not used) point.x -= importSettings.offsetX; @@ -915,8 +918,12 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, taskWriter.AddPoint(i, (float)point.x, (float)point.y, (float)point.z, rgb.r, rgb.g, rgb.b, importSettings.importIntensity, intensity.r, importSettings.averageTimestamp, time); //progressPoint = i; progressInfo.CurrentValue = i; + } // for all points + // hack for missing 100% progress + progressInfo.CurrentValue = maxPointIterations; + lastStatusMessage = "Saving files.."; //importSettings.writer.Save(fileIndex); taskWriter.Save(fileIndex); @@ -1446,7 +1453,7 @@ void SaveSettings() Properties.Settings.Default.customintensityrange = (bool)chkCustomIntensityRange.IsChecked; Properties.Settings.Default.openOutputFolder = (bool)chkOpenOutputFolder.IsChecked; Properties.Settings.Default.useManualOffset = (bool)chkManualOffset.IsChecked; - float.TryParse(txtOffsetX.Text.Replace(",","."), NumberStyles.Float, CultureInfo.InvariantCulture, out float offsetX); + float.TryParse(txtOffsetX.Text.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float offsetX); Properties.Settings.Default.manualOffsetX = offsetX; float.TryParse(txtOffsetY.Text.Replace(",", "."), NumberStyles.Float, CultureInfo.InvariantCulture, out float offsetY); Properties.Settings.Default.manualOffsetY = offsetY; @@ -1642,6 +1649,7 @@ private void btnImportSettings_Click(object sender, RoutedEventArgs e) var dialog = new OpenFileDialog(); dialog.Title = "Select settings file"; dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; + //dialog.DefaultDirectory = "configs/"; if (dialog.ShowDialog() == true) { diff --git a/Writers/PCROOT.cs b/Writers/PCROOT.cs index 23bfd80..9eb74de 100644 --- a/Writers/PCROOT.cs +++ b/Writers/PCROOT.cs @@ -231,6 +231,8 @@ void IWriter.Close() for (int i = 0, len = nodeBounds.Count; i < len; i++) { var tilerow = nodeBounds[i].fileName + sep + nodeBounds[i].totalPoints + sep + nodeBounds[i].minX + sep + nodeBounds[i].minY + sep + nodeBounds[i].minZ + sep + nodeBounds[i].maxX + sep + nodeBounds[i].maxY + sep + nodeBounds[i].maxZ + sep + nodeBounds[i].cellX + sep + nodeBounds[i].cellY + sep + nodeBounds[i].cellZ + sep + nodeBounds[i].averageTimeStamp + sep + nodeBounds[i].overlapRatio; + // force dot as decimal separator + tilerow = tilerow.Replace(",", "."); tilerootdata.Add(tilerow); totalPointCount += nodeBounds[i].totalPoints; } @@ -266,6 +268,9 @@ void IWriter.Close() string globalData = versionID + sep + importSettings.gridSize.ToString() + sep + totalPointCount + sep + cloudMinX + sep + cloudMinY + sep + cloudMinZ + sep + cloudMaxX + sep + cloudMaxY + sep + cloudMaxZ; // autoOffsetX, globalOffsetY, globalOffsetZ, packMagic globalData += sep + importSettings.offsetX + sep + importSettings.offsetY + sep + importSettings.offsetZ + sep + importSettings.packMagicValue; + // force dot as decimal separator + globalData = globalData.Replace(",", "."); + if (addComments) { tilerootdata.Insert(2, globalData); From 69cb22208e6fae251afcdaf7524c6f6a8a9fb19f Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 17 Sep 2024 09:04:30 +0300 Subject: [PATCH 06/83] fix plugin handling #BUILD beta --- Interfaces/ILogger.cs | 2 +- MainWindow.xaml.cs | 57 +++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Interfaces/ILogger.cs b/Interfaces/ILogger.cs index 1f3659d..86ebaa0 100644 --- a/Interfaces/ILogger.cs +++ b/Interfaces/ILogger.cs @@ -61,7 +61,7 @@ public static class LoggerFactory { public static ILogger CreateLogger(bool isJSON) { - Trace.WriteLine($"Creating logger with JSON: {isJSON}"); + //Trace.WriteLine($"Creating logger with JSON: {isJSON}"); if (isJSON) { return new LogJSON(); diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index f847b45..187104c 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -28,7 +28,7 @@ namespace PointCloudConverter { public partial class MainWindow : Window { - static readonly string version = "16.09.2024"; + static readonly string version = "17.09.2024"; static readonly string appname = "PointCloud Converter - " + version; static readonly string rootFolder = AppDomain.CurrentDomain.BaseDirectory; @@ -100,43 +100,42 @@ private async void Main() var pluginsDirectory = "plugins"; - if (!Directory.Exists(pluginsDirectory)) + if (Directory.Exists(pluginsDirectory)) { - Log.Write("Plugins directory not found."); - return; - } + //Log.Write("Plugins directory not found."); - // Get all DLL files in the plugins directory - var pluginFiles = Directory.GetFiles(pluginsDirectory, "*.dll"); + // Get all DLL files in the plugins directory + var pluginFiles = Directory.GetFiles(pluginsDirectory, "*.dll"); - foreach (var pluginDLL in pluginFiles) - { - try + foreach (var pluginDLL in pluginFiles) { - // Load the DLL file as an assembly - var assembly = Assembly.LoadFrom(pluginDLL); + try + { + // Load the DLL file as an assembly + var assembly = Assembly.LoadFrom(pluginDLL); - // Find all types in the assembly that implement IWriter - var writerTypes = assembly.GetTypes().Where(type => typeof(IWriter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract); + // Find all types in the assembly that implement IWriter + var writerTypes = assembly.GetTypes().Where(type => typeof(IWriter).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract); - foreach (var writerType in writerTypes) - { - // Derive a unique key for the writer (e.g., from its name or class name) - string writerName = writerType.Name;//.Replace("Writer", ""); // Customize the key generation logic - if (!externalWriters.ContainsKey(writerName)) + foreach (var writerType in writerTypes) { - // Add the writer type to the dictionary for later use - externalWriters.Add(writerName, writerType); - //Log.Write($"Found writer: {writerType.FullName} in {pluginDLL}"); + // Derive a unique key for the writer (e.g., from its name or class name) + string writerName = writerType.Name;//.Replace("Writer", ""); // Customize the key generation logic + if (!externalWriters.ContainsKey(writerName)) + { + // Add the writer type to the dictionary for later use + externalWriters.Add(writerName, writerType); + //Log.Write($"Found writer: {writerType.FullName} in {pluginDLL}"); - // TODO take extensions from plugin? has 2: .glb and .gltf - externalFileFormats += "|" + writerName + " (" + writerType.FullName + ")|*." + writerName.ToLower(); + // TODO take extensions from plugin? has 2: .glb and .gltf + externalFileFormats += "|" + writerName + " (" + writerType.FullName + ")|*." + writerName.ToLower(); + } } } - } - catch (Exception ex) - { - Console.WriteLine($"Error loading plugin {pluginDLL}: {ex.Message}"); + catch (Exception ex) + { + Console.WriteLine($"Error loading plugin {pluginDLL}: {ex.Message}"); + } } } @@ -413,7 +412,7 @@ private static async Task ProcessAllFiles(object workerParamsObject) Interlocked.Increment(ref errorCounter); // thread-safe error counter increment if (importSettings.useJSONLog) { - Trace.WriteLine("useJSONLoguseJSONLoguseJSONLoguseJSONLog"); + //Trace.WriteLine("useJSONLoguseJSONLoguseJSONLoguseJSONLog"); Log.Write("{\"event\": \"" + LogEvent.File + "\", \"path\": " + System.Text.Json.JsonSerializer.Serialize(importSettings.inputFiles[i]) + ", \"status\": \"" + LogStatus.Processing + "\"}", LogEvent.Error); } else From 0b3ddc6381a0c497378c50cecb5a6fe8008f23c5 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 23 Sep 2024 23:30:23 +0300 Subject: [PATCH 07/83] save last used config folder, improve skipping (in main loop) fixes #38, fix GUI auto-offset+manual duplicated argument, fix import settings format type (was object, needs to be string), --- App.config | 3 ++ MainWindow.xaml | 2 +- MainWindow.xaml.cs | 65 ++++++++++++++++++++++----------- Properties/Settings.Designer.cs | 12 ++++++ Properties/Settings.settings | 3 ++ Tools/ArgParser.cs | 5 +-- Writers/PCROOT.cs | 8 ++-- Writers/UCPC.cs | 8 ++-- 8 files changed, 73 insertions(+), 33 deletions(-) diff --git a/App.config b/App.config index 51e82ea..184f694 100644 --- a/App.config +++ b/App.config @@ -148,6 +148,9 @@ True + + + diff --git a/MainWindow.xaml b/MainWindow.xaml index f982f02..65a6d4f 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -81,7 +81,7 @@ - + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 187104c..dffff85 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -28,7 +28,7 @@ namespace PointCloudConverter { public partial class MainWindow : Window { - static readonly string version = "17.09.2024"; + static readonly string version = "23.09.2024"; static readonly string appname = "PointCloud Converter - " + version; static readonly string rootFolder = AppDomain.CurrentDomain.BaseDirectory; @@ -816,17 +816,10 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, int checkCancelEvery = fullPointCount / 128; // Loop all points - + // FIXME: would be nicer, if use different STEP value for skip, keep and limit..(to collect points all over the file, not just start) int maxPointIterations = importSettings.useLimit ? pointCount : fullPointCount; - - //for (int i = 0; i < fullPointCount; i++) for (int i = 0; i < maxPointIterations; i++) - //for (int i = 0; i < 1000; i++) { - - // stop at limit count - //if (importSettings.useLimit == true && i > pointCount) break; - // check for cancel every 1% of points if (i % checkCancelEvery == 0) { @@ -837,21 +830,23 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, } } - // FIXME: need to add skip and keep point skipper here, to make skipping faster! - // get point XYZ Float3 point = taskReader.GetXYZ(); if (point.hasError == true) break; // TODO display errors + // skip points + if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; + + // keep points + if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; + + // add offsets (its 0 if not used) point.x -= importSettings.offsetX; point.y -= importSettings.offsetY; point.z -= importSettings.offsetZ; // scale if enabled - //point.x = importSettings.useScale ? point.x * importSettings.scale : point.x; - //point.y = importSettings.useScale ? point.y * importSettings.scale : point.y; - //point.z = importSettings.useScale ? point.z * importSettings.scale : point.z; if (importSettings.useScale == true) { point.x *= importSettings.scale; @@ -917,7 +912,6 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, taskWriter.AddPoint(i, (float)point.x, (float)point.y, (float)point.z, rgb.r, rgb.g, rgb.b, importSettings.importIntensity, intensity.r, importSettings.averageTimestamp, time); //progressPoint = i; progressInfo.CurrentValue = i; - } // for all points // hack for missing 100% progress @@ -1025,7 +1019,15 @@ void StartProcess(bool doProcess = true) } args.Add("-output=" + txtOutput.Text); - args.Add("-offset=" + (bool)chkAutoOffset.IsChecked); + // check if using autooffset + if ((bool)chkAutoOffset.IsChecked && !(bool)chkManualOffset.IsChecked) + { + args.Add("-offset=" + (bool)chkAutoOffset.IsChecked); + } + + // or manual offset, TODO later should allow using both (first autooffset, then add manual) + if ((bool)chkManualOffset.IsChecked) args.Add("-offset=" + txtOffsetX.Text + "," + txtOffsetY.Text + "," + txtOffsetZ.Text); + args.Add("-rgb=" + (bool)chkImportRGB.IsChecked); args.Add("-intensity=" + (bool)chkImportIntensity.IsChecked); @@ -1046,7 +1048,6 @@ void StartProcess(bool doProcess = true) if ((bool)chkUseSkip.IsChecked) args.Add("-skip=" + txtSkipEvery.Text); if ((bool)chkUseKeep.IsChecked) args.Add("-keep=" + txtKeepEvery.Text); if ((bool)chkUseMaxFileCount.IsChecked) args.Add("-maxfiles=" + txtMaxFileCount.Text); - if ((bool)chkManualOffset.IsChecked) args.Add("-offset=" + txtOffsetX.Text + "," + txtOffsetY.Text + "," + txtOffsetZ.Text); args.Add("-randomize=" + (bool)chkRandomize.IsChecked); if ((bool)chkSetRandomSeed.IsChecked) args.Add("-seed=" + txtRandomSeed.Text); if ((bool)chkUseJSONLog.IsChecked) args.Add("-json=true"); @@ -1061,7 +1062,7 @@ void StartProcess(bool doProcess = true) if (((bool)chkImportIntensity.IsChecked) && ((bool)chkCustomIntensityRange.IsChecked)) args.Add("-customintensityrange=True"); // check input files - Trace.WriteLine("loggeris:" + Log.GetType().ToString()); + //Trace.WriteLine("loggeris:" + Log.GetType().ToString()); var importSettings = ArgParser.Parse(args.ToArray(), rootFolder, Log); @@ -1140,6 +1141,8 @@ void ImportArgs(string rawArgs) string key = parts[0].ToLower().TrimStart('-'); string value = parts[1]; + // FIXME, if value is not saved, need to use default value + // Apply the key-value pairs to the GUI elements switch (key) { @@ -1360,7 +1363,7 @@ private void LoadSettings() { if ((ExportFormat)item == ExportFormat.Unknown) continue; if ((ExportFormat)item == ExportFormat.External) continue; - cmbExportFormat.Items.Add(item); + cmbExportFormat.Items.Add(item.ToString()); } // Add dynamic export formats discovered from plugins @@ -1646,9 +1649,18 @@ private void btnCopyToClipboard_Click(object sender, RoutedEventArgs e) private void btnImportSettings_Click(object sender, RoutedEventArgs e) { var dialog = new OpenFileDialog(); - dialog.Title = "Select settings file"; + dialog.Title = "Import settings file"; dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; - //dialog.DefaultDirectory = "configs/"; + + // if have previously used config dir use that, if not, use local config dir if exists, if neither, use default.. + if (string.IsNullOrEmpty(Properties.Settings.Default.lastImportFolder) == false) + { + dialog.InitialDirectory = Properties.Settings.Default.lastImportFolder; + } + else if (Directory.Exists("configs/")) + { + dialog.InitialDirectory = "configs/"; + } if (dialog.ShowDialog() == true) { @@ -1656,6 +1668,7 @@ private void btnImportSettings_Click(object sender, RoutedEventArgs e) { var contents = File.ReadAllText(dialog.FileName); ImportArgs(contents); + Properties.Settings.Default.lastImportFolder = Path.GetDirectoryName(dialog.FileName); } } } @@ -1666,10 +1679,20 @@ private void btnExportSettings_Click(object sender, RoutedEventArgs e) dialog.Title = "Save settings file"; dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; + if (string.IsNullOrEmpty(Properties.Settings.Default.lastImportFolder) == false) + { + dialog.InitialDirectory = Properties.Settings.Default.lastImportFolder; + } + else if (Directory.Exists("configs/")) + { + dialog.InitialDirectory = "configs/"; + } + if (dialog.ShowDialog() == true) { StartProcess(false); File.WriteAllText(dialog.FileName, txtConsole.Text); + Properties.Settings.Default.lastImportFolder = Path.GetDirectoryName(dialog.FileName); } } diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index f5bcac6..4e3df17 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -574,5 +574,17 @@ public bool useGrid { this["useGrid"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string lastUsedConfigFolder { + get { + return ((string)(this["lastUsedConfigFolder"])); + } + set { + this["lastUsedConfigFolder"] = value; + } + } } } diff --git a/Properties/Settings.settings b/Properties/Settings.settings index 64c244a..44a7c93 100644 --- a/Properties/Settings.settings +++ b/Properties/Settings.settings @@ -140,5 +140,8 @@ True + + + \ No newline at end of file diff --git a/Tools/ArgParser.cs b/Tools/ArgParser.cs index 1b1d010..5a61bba 100644 --- a/Tools/ArgParser.cs +++ b/Tools/ArgParser.cs @@ -595,16 +595,15 @@ public static ImportSettings Parse(string[] args, string rootFolder, ILogger log case "-offset": Log.Write("offset = " + param); - // check if its true or false + // check if its true or false (for automatic offset) if (param != "false" && param != "true") { - // check if its valid integer x,z + // check if have x,y,z values, NOTE should be in this format: -offset=10.5,-123,0 if (param.IndexOf(',') > -1) { var temp = param.Split(','); if (temp.Length == 3) { - float xOff, yOff, zOff; if (float.TryParse(temp[0].Trim(), out xOff) && float.TryParse(temp[1].Trim(), out yOff) && float.TryParse(temp[2].Trim(), out zOff)) { diff --git a/Writers/PCROOT.cs b/Writers/PCROOT.cs index 9eb74de..c8d7f4d 100644 --- a/Writers/PCROOT.cs +++ b/Writers/PCROOT.cs @@ -585,11 +585,11 @@ void IWriter.Save(int fileIndex) // loop and output all points within that node/tile for (int i = 0, len = nodeTempX.Count; i < len; i++) { - // skip points - if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; + //// skip points + //if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; - // keep points - if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; + //// keep points + //if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; // get original world positions float px = nodeTempX[i]; diff --git a/Writers/UCPC.cs b/Writers/UCPC.cs index 96e6a7c..921e768 100644 --- a/Writers/UCPC.cs +++ b/Writers/UCPC.cs @@ -252,11 +252,11 @@ void IWriter.Randomize() void IWriter.AddPoint(int index, float x, float y, float z, float r, float g, float b, bool hasIntensity, float i, bool hasTime, double time) { - // skip points - if (importSettings.skipPoints == true && (index % importSettings.skipEveryN == 0)) return; + //// skip points + //if (importSettings.skipPoints == true && (index % importSettings.skipEveryN == 0)) return; - // keep points - if (importSettings.keepPoints == true && (index % importSettings.keepEveryN != 0)) return; + //// keep points + //if (importSettings.keepPoints == true && (index % importSettings.keepEveryN != 0)) return; // get bounds if (x < cloudMinX) cloudMinX = x; From e469103ce68986d63cf2466c3df97cd284087917 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 24 Sep 2024 20:50:01 +0300 Subject: [PATCH 08/83] fix autooffset value bug, fixed crash for cancel process with 1 thread, import/export settings, now properly sets all fields, tilerows: dont replace comma in filenames, rename GLTF plugin to GLB, #BUILD beta --- MainWindow.xaml.cs | 62 ++++++++++++++++++++++++++++++++++--------- Tools/ArgParser.cs | 9 +++++-- Tools/PluginLoader.cs | 2 +- Tools/Tools.cs | 2 +- Writers/PCROOT.cs | 5 ++-- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index dffff85..989217d 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -23,12 +23,13 @@ using PointCloudConverter.Writers; using System.Reflection; using System.Globalization; +using System.Windows.Media; namespace PointCloudConverter { public partial class MainWindow : Window { - static readonly string version = "23.09.2024"; + static readonly string version = "24.09.2024"; static readonly string appname = "PointCloud Converter - " + version; static readonly string rootFolder = AppDomain.CurrentDomain.BaseDirectory; @@ -310,7 +311,7 @@ private static async Task ProcessAllFiles(object workerParamsObject) if (boundsListTemp[iii].z < lowestZ) lowestZ = (float)boundsListTemp[iii].z; } - //Console.WriteLine("Lowest bounds: " + lowestX + " " + lowestY + " " + lowestZ); + //Log.Write("Lowest bounds: " + lowestX + " " + lowestY + " " + lowestZ); // TODO could take center for XZ, and lowest for Y? importSettings.offsetX = lowestX; importSettings.offsetY = lowestY; @@ -382,11 +383,18 @@ private static async Task ProcessAllFiles(object workerParamsObject) } finally { - //// Ensure the semaphore is released, if needed - //if (semaphore.CurrentCount == 0) // Make sure we don't release more times than we acquire - //{ - // semaphore.Release(); - //} + // Ensure the semaphore is released safely + if (semaphore.CurrentCount == 0) // Make sure we don't release more times than we acquire + { + try + { + semaphore.Release(); + } + catch (SemaphoreFullException ex) + { + //Log.Write($"Semaphore was already fully released. Exception: {ex.Message}"); + } + } } //int? taskId = Task.CurrentId; // Get the current task ID @@ -768,13 +776,18 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, importSettings.offsetY = importSettings.manualOffsetY; importSettings.offsetZ = importSettings.manualOffsetZ; } - else // neither + else // no autooffset either { - importSettings.offsetX = 0; - importSettings.offsetY = 0; - importSettings.offsetZ = 0; + if (importSettings.useAutoOffset == false) + { + importSettings.offsetX = 0; + importSettings.offsetY = 0; + importSettings.offsetZ = 0; + } } + //Log.Write("************** Offsets: " + importSettings.offsetX + " " + importSettings.offsetY + " " + importSettings.offsetZ); + var taskWriter = importSettings.GetOrCreateWriter(taskId); // for saving pcroot header, we need this writer @@ -1020,7 +1033,8 @@ void StartProcess(bool doProcess = true) args.Add("-output=" + txtOutput.Text); // check if using autooffset - if ((bool)chkAutoOffset.IsChecked && !(bool)chkManualOffset.IsChecked) + //if ((bool)chkAutoOffset.IsChecked && !(bool)chkManualOffset.IsChecked) + if (!(bool)chkManualOffset.IsChecked) { args.Add("-offset=" + (bool)chkAutoOffset.IsChecked); } @@ -1123,6 +1137,9 @@ void ImportArgs(string rawArgs) bool isFirstArgExe = args[0].EndsWith(".exe", StringComparison.OrdinalIgnoreCase); int startIndex = isFirstArgExe ? 1 : 0; + // reset all checkboxes to false + UncheckAllCheckboxes(this); + for (int i = startIndex; i < args.Length; i++) { string arg = args[i]; @@ -1246,6 +1263,27 @@ void ImportArgs(string rawArgs) } // for all args } // ImportArgs() + private void UncheckAllCheckboxes(DependencyObject parent) + { + // Loop through all the child elements + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + + // If the child is a CheckBox, set it to unchecked + if (child is CheckBox checkBox) + { + checkBox.IsChecked = false; + } + + // If the child is a container, recursively call the function to check its children + if (VisualTreeHelper.GetChildrenCount(child) > 0) + { + UncheckAllCheckboxes(child); + } + } + } + private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { SaveSettings(); diff --git a/Tools/ArgParser.cs b/Tools/ArgParser.cs index 5a61bba..72b6043 100644 --- a/Tools/ArgParser.cs +++ b/Tools/ArgParser.cs @@ -867,7 +867,12 @@ public static ImportSettings Parse(string[] args, string rootFolder, ILogger log if (importSettings.batch == true && importSettings.exportFormat == ExportFormat.UCPC && Path.GetExtension(importSettings.outputFile).ToLower() == ".ucpc") { - importSettings.errors.Add("With UCPC batching, do not set output filename - set ONLY output folder (each ucpc file will be saved separately)"); + importSettings.errors.Add("With batch processing whole input folder, do not set output filename - Set output folder (each .UCPP file will be saved separately)"); + } + + if (importSettings.batch == true && importSettings.exportFormat == ExportFormat.External && Path.GetExtension(importSettings.outputFile).ToLower() == ".glb") + { + importSettings.errors.Add("With batch processing whole input folder, do not set output filename - Set output folder (each .GLB file will be saved separately)"); } if (importSettings.skipPoints == true && importSettings.keepPoints == true) @@ -885,7 +890,7 @@ public static ImportSettings Parse(string[] args, string rootFolder, ILogger log if (importSettings.exportFormat == ExportFormat.PCROOT && importSettings.useGrid == false) { //importSettings.errors.Add("V3 pcroot export format requires -usegrid=true to use grid"); - Log.Write("V3 pcroot export format requires -usegrid=true to use grid, enabling it.."); + Log.Write("V3 pcroot export format requires -usegrid=true to use grid, enabling it now."); importSettings.useGrid = true; } diff --git a/Tools/PluginLoader.cs b/Tools/PluginLoader.cs index 1cdf17a..2e1acc0 100644 --- a/Tools/PluginLoader.cs +++ b/Tools/PluginLoader.cs @@ -30,7 +30,7 @@ public static IWriter LoadWriter(string pluginName) var pluginAssembly = Assembly.LoadFrom(pluginPath); // Find the specific type 'PointCloudConverter.Writers.GLTF' - var writerType = pluginAssembly.GetType("PointCloudConverter.Writers.GLTF"); + var writerType = pluginAssembly.GetType("PointCloudConverter.Writers.GLB"); if (writerType == null) throw new InvalidOperationException($"No valid implementation of IWriter found in {pluginPath}"); diff --git a/Tools/Tools.cs b/Tools/Tools.cs index e7f04b9..f611311 100644 --- a/Tools/Tools.cs +++ b/Tools/Tools.cs @@ -289,7 +289,7 @@ public static void PrintHelpAndExit(char argSeparator, bool waitEnter = false) // TODO Console.WriteLine("-decimate" + separator + "50\t\t\tRemoves 50% of the points (by skipping every x point)\tDefault is off"); //Console.WriteLine("-version" + argSeparator + "2\t\t2=v2 .ucpc, 3=v3 .pcroot tiles\tDefault is 2"); Console.WriteLine("-randomize" + argSeparator + "true\t\tRandomize point indexes, to use Dynamic resolution\tDefault is true (Always enabled for v3)"); - Console.WriteLine("-seed" + argSeparator + "42\t\tSet random seed\tDefault is random value"); + Console.WriteLine("-seed" + argSeparator + "42\t\tSet random seed\tDefault is some random value"); Console.WriteLine("-json" + argSeparator + "false\t\tOutput console log in JSON format\tDefault is false"); Console.WriteLine("-customintensityrange" + argSeparator + "false\t\tCustom intensity range (0-65535)\tDefault is false"); Console.WriteLine("-metadata" + argSeparator + "false\t\tRead metadata from header, outputs into json file\tDefault is false"); diff --git a/Writers/PCROOT.cs b/Writers/PCROOT.cs index c8d7f4d..47c412a 100644 --- a/Writers/PCROOT.cs +++ b/Writers/PCROOT.cs @@ -230,9 +230,10 @@ void IWriter.Close() // add to tileroot list for (int i = 0, len = nodeBounds.Count; i < len; i++) { - var tilerow = nodeBounds[i].fileName + sep + nodeBounds[i].totalPoints + sep + nodeBounds[i].minX + sep + nodeBounds[i].minY + sep + nodeBounds[i].minZ + sep + nodeBounds[i].maxX + sep + nodeBounds[i].maxY + sep + nodeBounds[i].maxZ + sep + nodeBounds[i].cellX + sep + nodeBounds[i].cellY + sep + nodeBounds[i].cellZ + sep + nodeBounds[i].averageTimeStamp + sep + nodeBounds[i].overlapRatio; - // force dot as decimal separator + var tilerow = nodeBounds[i].totalPoints + sep + nodeBounds[i].minX + sep + nodeBounds[i].minY + sep + nodeBounds[i].minZ + sep + nodeBounds[i].maxX + sep + nodeBounds[i].maxY + sep + nodeBounds[i].maxZ + sep + nodeBounds[i].cellX + sep + nodeBounds[i].cellY + sep + nodeBounds[i].cellZ + sep + nodeBounds[i].averageTimeStamp + sep + nodeBounds[i].overlapRatio; + // force dot as decimal separator for values tilerow = tilerow.Replace(",", "."); + tilerow = nodeBounds[i].fileName + sep + tilerow; tilerootdata.Add(tilerow); totalPointCount += nodeBounds[i].totalPoints; } From ecfe5e8281a6cd9b08fe01a55f2326ae51b2ce33 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Tue, 24 Sep 2024 23:52:14 +0300 Subject: [PATCH 09/83] fix config last used folder, fix skipping points for pcroot, add -offsetmode: min= all cloud min bounds, legacy= first cloud min bounds, #BUILD beta --- App.config | 3 ++ MainWindow.xaml | 5 +- MainWindow.xaml.cs | 48 +++++++++++-------- Properties/Settings.Designer.cs | 12 +++++ Properties/Settings.settings | 3 ++ Structs/ImportSettings.cs | 15 +++--- Tools/ArgParser.cs | 13 ++++++ Tools/Tools.cs | 1 + Writers/PCROOT.cs | 82 ++++++++++++++++----------------- 9 files changed, 112 insertions(+), 70 deletions(-) diff --git a/App.config b/App.config index 184f694..5506e12 100644 --- a/App.config +++ b/App.config @@ -151,6 +151,9 @@ + + min + diff --git a/MainWindow.xaml b/MainWindow.xaml index 65a6d4f..7a76610 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -41,7 +41,10 @@ - + + + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 989217d..5698436 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -262,7 +262,6 @@ private static async Task ProcessAllFiles(object workerParamsObject) // get all file bounds, if in batch mode and RGB+INT+PACK // TODO: check what happens if its too high? over 128/256? //if (importSettings.useAutoOffset == true && importSettings.importIntensity == true && importSettings.importRGB == true && importSettings.packColors == true && importSettings.importMetadataOnly == false) - //Log.Write(importSettings.useAutoOffset + " && " + importSettings.importMetadataOnly + " || (" + importSettings.importIntensity + " && " + importSettings.importRGB + " && " + importSettings.packColors + " && " + importSettings.importMetadataOnly + ")"); //bool istrue1 = (importSettings.useAutoOffset == true && importSettings.importMetadataOnly == false); //bool istrue2 = (importSettings.importIntensity == true && importSettings.importRGB == true && importSettings.packColors == true && importSettings.importMetadataOnly == false); @@ -271,7 +270,9 @@ private static async Task ProcessAllFiles(object workerParamsObject) if ((importSettings.useAutoOffset == true && importSettings.importMetadataOnly == false) || (importSettings.importIntensity == true && importSettings.importRGB == true && importSettings.packColors == true && importSettings.importMetadataOnly == false)) { - for (int i = 0, len = importSettings.maxFiles; i < len; i++) + int iterations = importSettings.offsetMode == "min" ? importSettings.maxFiles : 1; // 1 for legacy mode + + for (int i = 0, len = iterations; i < len; i++) { if (cancellationToken.IsCancellationRequested) { @@ -768,6 +769,7 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, // dont use these bounds, in this case if (importSettings.useAutoOffset == true || (importSettings.importIntensity == true && importSettings.importRGB == true && importSettings.packColors == true)) { + // TODO add manual offset here still? // we use global bounds or Y offset to fix negative Y } else if (importSettings.useManualOffset == true) @@ -847,13 +849,21 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, Float3 point = taskReader.GetXYZ(); if (point.hasError == true) break; // TODO display errors + // get point color + Color rgb = (default); + + if (importSettings.importRGB == true) + { + rgb = taskReader.GetRGB(); + } + + // skip points if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; // keep points if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; - // add offsets (its 0 if not used) point.x -= importSettings.offsetX; point.y -= importSettings.offsetY; @@ -887,16 +897,10 @@ static bool ParseFile(ImportSettings importSettings, int fileIndex, int? taskId, point.x = -point.x; } - // get point color - Color rgb = (default); + Color intensity = (default); double time = 0; - if (importSettings.importRGB == true) - { - rgb = taskReader.GetRGB(); - } - // TODO get intensity as separate value, TODO is this float or rgb? if (importSettings.importIntensity == true) { @@ -1039,6 +1043,8 @@ void StartProcess(bool doProcess = true) args.Add("-offset=" + (bool)chkAutoOffset.IsChecked); } + args.Add("-offsetmode=" + txtOffsetMode.Text.ToLower()); + // or manual offset, TODO later should allow using both (first autooffset, then add manual) if ((bool)chkManualOffset.IsChecked) args.Add("-offset=" + txtOffsetX.Text + "," + txtOffsetY.Text + "," + txtOffsetZ.Text); @@ -1460,6 +1466,7 @@ private void LoadSettings() chkCalculateOverlappingTiles.IsChecked = Properties.Settings.Default.calculateOverlappingTiles; txtMaxThreads.Text = Properties.Settings.Default.maxThreads; chkUseGrid.IsChecked = Properties.Settings.Default.useGrid; + txtOffsetMode.Text = Properties.Settings.Default.offsetMode; isInitialiazing = false; } @@ -1510,6 +1517,7 @@ void SaveSettings() Properties.Settings.Default.calculateOverlappingTiles = (bool)chkCalculateOverlappingTiles.IsChecked; Properties.Settings.Default.maxThreads = txtMaxThreads.Text; Properties.Settings.Default.useGrid = (bool)chkUseGrid.IsChecked; + Properties.Settings.Default.offsetMode = txtOffsetMode.Text; Properties.Settings.Default.Save(); } @@ -1691,13 +1699,13 @@ private void btnImportSettings_Click(object sender, RoutedEventArgs e) dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; // if have previously used config dir use that, if not, use local config dir if exists, if neither, use default.. - if (string.IsNullOrEmpty(Properties.Settings.Default.lastImportFolder) == false) + if (string.IsNullOrEmpty(Properties.Settings.Default.lastUsedConfigFolder) == false) { - dialog.InitialDirectory = Properties.Settings.Default.lastImportFolder; + dialog.InitialDirectory = Properties.Settings.Default.lastUsedConfigFolder; } - else if (Directory.Exists("configs/")) + else if (Directory.Exists(Path.Combine(Directory.GetCurrentDirectory(), "configs"))) { - dialog.InitialDirectory = "configs/"; + dialog.InitialDirectory = Path.Combine(Directory.GetCurrentDirectory(), "configs"); } if (dialog.ShowDialog() == true) @@ -1706,7 +1714,7 @@ private void btnImportSettings_Click(object sender, RoutedEventArgs e) { var contents = File.ReadAllText(dialog.FileName); ImportArgs(contents); - Properties.Settings.Default.lastImportFolder = Path.GetDirectoryName(dialog.FileName); + Properties.Settings.Default.lastUsedConfigFolder = Path.GetDirectoryName(dialog.FileName); } } } @@ -1717,20 +1725,20 @@ private void btnExportSettings_Click(object sender, RoutedEventArgs e) dialog.Title = "Save settings file"; dialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; - if (string.IsNullOrEmpty(Properties.Settings.Default.lastImportFolder) == false) + if (string.IsNullOrEmpty(Properties.Settings.Default.lastUsedConfigFolder) == false) { - dialog.InitialDirectory = Properties.Settings.Default.lastImportFolder; + dialog.InitialDirectory = Properties.Settings.Default.lastUsedConfigFolder; } - else if (Directory.Exists("configs/")) + else if (Directory.Exists(Path.Combine(Directory.GetCurrentDirectory(), "configs"))) { - dialog.InitialDirectory = "configs/"; + dialog.InitialDirectory = Path.Combine(Directory.GetCurrentDirectory(), "configs"); } if (dialog.ShowDialog() == true) { StartProcess(false); File.WriteAllText(dialog.FileName, txtConsole.Text); - Properties.Settings.Default.lastImportFolder = Path.GetDirectoryName(dialog.FileName); + Properties.Settings.Default.lastUsedConfigFolder = Path.GetDirectoryName(dialog.FileName); } } diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 4e3df17..540e5b0 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -586,5 +586,17 @@ public string lastUsedConfigFolder { this["lastUsedConfigFolder"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("min")] + public string offsetMode { + get { + return ((string)(this["offsetMode"])); + } + set { + this["offsetMode"] = value; + } + } } } diff --git a/Properties/Settings.settings b/Properties/Settings.settings index 44a7c93..62b8962 100644 --- a/Properties/Settings.settings +++ b/Properties/Settings.settings @@ -143,5 +143,8 @@ + + min + \ No newline at end of file diff --git a/Structs/ImportSettings.cs b/Structs/ImportSettings.cs index 9b5a0bb..e30f8fc 100644 --- a/Structs/ImportSettings.cs +++ b/Structs/ImportSettings.cs @@ -203,12 +203,13 @@ public void ReleaseReader(int? taskId) public int seed { get; set; } = -1; // random seed for shuffling public int maxThreads { get; set; } - public bool useJSONLog = false; - public bool importMetadata = false; - public bool importMetadataOnly = false; - public bool averageTimestamp = false; // calculate average timestamp for all points for this tile - public bool checkoverlap = false; // check if tile overlaps with other tiles (save into pcroot) - public bool useGrid = true; // required for PCROOT format + public bool useJSONLog { get; set; } = false; + public bool importMetadata { get; set; } = false; + public bool importMetadataOnly { get; set; } = false; + public bool averageTimestamp { get; set; } = false; // calculate average timestamp for all points for this tile + public bool checkoverlap { get; set; } = false; // check if tile overlaps with other tiles (save into pcroot) + public bool useGrid { get; set; } = true; // required for PCROOT format + public string offsetMode { get; set; } = "min"; // TODO use enum: "min" or "legacy" now (legacy is first bounds min only) public override string ToString() { @@ -251,6 +252,8 @@ public override string ToString() t += "\n importMetadataOnly=" + importMetadataOnly; t += "\n averageTimestamp=" + averageTimestamp; t += "\n checkoverlap=" + checkoverlap; + t += "\n useGrid=" + useGrid; + t += "\n offsetMode=" + offsetMode; return t; } diff --git a/Tools/ArgParser.cs b/Tools/ArgParser.cs index 72b6043..efacf77 100644 --- a/Tools/ArgParser.cs +++ b/Tools/ArgParser.cs @@ -727,6 +727,19 @@ public static ImportSettings Parse(string[] args, string rootFolder, ILogger log importSettings.importIntensity = (param == "true"); } break; + + case "-offsetmode": + Log.Write("offsetmode = " + param); + + if (param != "legacy" && param != "min") + { + importSettings.errors.Add("Invalid offsetmode parameter: " + param); + } + else + { + importSettings.offsetMode = param; + } + break; // TODO load whole commandline args list from text file case "-config": diff --git a/Tools/Tools.cs b/Tools/Tools.cs index f611311..4c4dced 100644 --- a/Tools/Tools.cs +++ b/Tools/Tools.cs @@ -296,6 +296,7 @@ public static void PrintHelpAndExit(char argSeparator, bool waitEnter = false) Console.WriteLine("-metadataonly" + argSeparator + "false\t\tRead metadata only (dont process points)\tDefault is false"); Console.WriteLine("-averagetimestamp" + argSeparator + "false\t\tGet Average timestamp per Tile\tDefault is false"); Console.WriteLine("-checkoverlap" + argSeparator + "false\t\tCalculate overlapping tiles\tDefault is false"); + Console.WriteLine("-offsetmode" + argSeparator + "min\t\tGet auto-offset bounds, min=min from all bounds, legacy= first cloud min bounds\tDefault is min"); Console.WriteLine(""); Console.WriteLine("? /? -? help -help /help"); Console.ForegroundColor = ConsoleColor.White; diff --git a/Writers/PCROOT.cs b/Writers/PCROOT.cs index 47c412a..ec8c18b 100644 --- a/Writers/PCROOT.cs +++ b/Writers/PCROOT.cs @@ -43,7 +43,7 @@ public class PCROOT : IWriter, IDisposable //int? taskID; static int skippedNodesCounter = 0; - static int skippedPointsCounter = 0; + static int skippedPointsCounter = 0; // FIXME, not used in regular mode, only for lossy filtering, TODO can calculate from importsetting values static bool useLossyFiltering = false; //not used, for testing only public void Dispose() @@ -507,6 +507,7 @@ void IWriter.Save(int fileIndex) } + // randomize points in this node if (importSettings.randomize == true) { @@ -693,7 +694,7 @@ void IWriter.Save(int fileIndex) } reservedGridCells[reservedTileLocalCellIndex] = true; - } + } // if packed or lossy if (useLossyFiltering == true) { @@ -739,7 +740,6 @@ void IWriter.Save(int fileIndex) //} //writerPoints.Write(pz); - FloatToBytes(px, pointBuffer, 0); if (importSettings.packColors == true && importSettings.importRGB == true && importSettings.importIntensity == true) @@ -750,12 +750,9 @@ void IWriter.Save(int fileIndex) { FloatToBytes(py, pointBuffer, 4); // Convert float to bytes manually } - FloatToBytes(pz, pointBuffer, 8); - writerPoints.Write(pointBuffer); - - } + } // wrote packed or unpacked xyz if (importSettings.averageTimestamp == true) { @@ -774,45 +771,44 @@ void IWriter.Save(int fileIndex) // not packed if (importSettings.packColors == false && useLossyFiltering == false) { - try + //try + //{ + // save separate RGB + using (var writerColors = new BinaryWriter(new BufferedStream(new FileStream(fullpath + ".rgb", FileMode.Create)))) { + //bool skipPoints = importSettings.skipPoints; + //bool keepPoints = importSettings.keepPoints; + //int skipEveryN = importSettings.skipEveryN; + //int keepEveryN = importSettings.keepEveryN; + + int len = nodeTempX.Count; + byte[] colorBuffer = new byte[12]; // Buffer to hold the RGB values as bytes - // save separate RGB - using (var writerColors = new BinaryWriter(new BufferedStream(new FileStream(fullpath + ".rgb", FileMode.Create)))) + //unsafe void FloatToBytes(float value, byte[] buffer, int offset) + //{ + // fixed (byte* b = &buffer[offset]) + // { + // *(float*)b = value; + // } + //} + + for (int i = 0; i < len; i++) { - bool skipPoints = importSettings.skipPoints; - bool keepPoints = importSettings.keepPoints; - int skipEveryN = importSettings.skipEveryN; - int keepEveryN = importSettings.keepEveryN; - - int len = nodeTempX.Count; - byte[] colorBuffer = new byte[12]; // Buffer to hold the RGB values as bytes - - //unsafe void FloatToBytes(float value, byte[] buffer, int offset) - //{ - // fixed (byte* b = &buffer[offset]) - // { - // *(float*)b = value; - // } - //} - - for (int i = 0; i < len; i++) - { - if ((skipPoints && (i % skipEveryN == 0)) || (keepPoints && (i % keepEveryN != 0))) continue; + //if ((skipPoints && (i % skipEveryN == 0)) || (keepPoints && (i % keepEveryN != 0))) continue; - FloatToBytes(nodeTempR[i], colorBuffer, 0); - FloatToBytes(nodeTempG[i], colorBuffer, 4); - FloatToBytes(nodeTempB[i], colorBuffer, 8); + FloatToBytes(nodeTempR[i], colorBuffer, 0); + FloatToBytes(nodeTempG[i], colorBuffer, 4); + FloatToBytes(nodeTempB[i], colorBuffer, 8); - writerColors.Write(colorBuffer); - } + writerColors.Write(colorBuffer); } } - catch (Exception e) - { - Trace.WriteLine("Error writing RGB file: " + e.Message); - throw; - } + //} + //catch (Exception e) + //{ + // Trace.WriteLine("Error writing RGB file: " + e.Message); + // throw; + //} // TESTING save separate Intensity, if both rgb and intensity are enabled if (importSettings.importRGB == true && importSettings.importIntensity == true) @@ -824,11 +820,11 @@ void IWriter.Save(int fileIndex) // output all points within that node cell for (int i = 0, len = nodeTempX.Count; i < len; i++) { - // skip points - if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; + //// skip points + //if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0)) continue; - // keep points - if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; + //// keep points + //if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0)) continue; // TODO write as byte (not RGB floats) writerIntensity.Write(nodeTempIntensity[i]); From 5108d47c3c47e832210fbf6db268c1e58a533b64 Mon Sep 17 00:00:00 2001 From: unitycoder Date: Mon, 21 Oct 2024 22:14:18 +0300 Subject: [PATCH 10/83] update help output, add browse plugins folder, #BUILD beta --- MainWindow.xaml | 40 +++++++++++++++++++++++---------------- MainWindow.xaml.cs | 15 ++++++++++++--- Structs/ImportSettings.cs | 2 +- Tools/Tools.cs | 4 +++- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/MainWindow.xaml b/MainWindow.xaml index 7a76610..be7ed89 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:PointCloudConverter" mc:Ignorable="d" - Title="PointCloudConverter" Height="720" Width="907" Background="#FF252222" Closing="Window_Closing" Loaded="Window_Loaded"> + Title="PointCloudConverter" Height="720" Width="907" Background="#FF252222" Closing="Window_Closing" Loaded="Window_Loaded" MinWidth="920">