diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2020-10-13 04:04:05 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2020-10-13 04:04:05 +0300 |
commit | 1a0229a654c49385d9c757383d30f0d38882d3d7 (patch) | |
tree | 66deae60c2715c3c59df2e39a667f772fe9654cf | |
parent | 4721a525653789f44615c7fe19433c570077a352 (diff) |
v0.8.4.3v0.8.4.3
* (Add) Tool - Layer repair: Allow remove islands recursively (#74)
* (Fix) Pixel Editor: Cursor dimentions when using brushes with thickness > 1 (#73)
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerIssue.cs | 38 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerManager.cs | 81 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationRepairLayers.cs | 56 | ||||
-rw-r--r-- | UVtools.Core/UVtools.Core.csproj | 6 | ||||
-rw-r--r-- | UVtools.GUI/App.config | 6 | ||||
-rw-r--r-- | UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.Designer.cs | 62 | ||||
-rw-r--r-- | UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs | 2 | ||||
-rw-r--r-- | UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.resx | 14 | ||||
-rw-r--r-- | UVtools.GUI/FrmMain.cs | 9 | ||||
-rw-r--r-- | UVtools.GUI/Properties/AssemblyInfo.cs | 4 | ||||
-rw-r--r-- | UVtools.GUI/Properties/Settings.Designer.cs | 12 | ||||
-rw-r--r-- | UVtools.GUI/Properties/Settings.settings | 3 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml | 89 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs | 4 | ||||
-rw-r--r-- | UVtools.WPF/MainWindow.axaml.cs | 1 | ||||
-rw-r--r-- | UVtools.WPF/UserSettings.cs | 43 | ||||
-rw-r--r-- | UVtools.WPF/Windows/SettingsWindow.axaml | 58 |
19 files changed, 409 insertions, 92 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6121d9f..85ae86c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ * (Improvement) GUI is now scalable * (Fix) Some bug found and fixed during convertion +## 13/10/2020 - v0.8.4.3 + +* (Add) Tool - Layer repair: Allow remove islands recursively (#74) +* (Fix) Pixel Editor: Cursor dimentions when using brushes with thickness > 1 (#73) + ## 10/10/2020 - v0.8.4.2 * (Fix) pws and pw0: Error when try to save or copy to clipboard the slicer information / properties @@ -190,15 +190,21 @@ The current public build will only work in windows.** <!--- * Donwload and install: https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.402-macos-x64-installer +brew install libjpeg libpng libgeotiff libdc1394 ffmpeg openexr tbb --> ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" brew analytics off -brew install libjpeg libpng libgeotiff libdc1394 ffmpeg openexr tbb brew cask install dotnet ``` +To run UVtools open it folder on a terminal and call one of: + +* `dotnet UVtools.dll` +* `sh UVtools.sh` +* As a pratical alternative you can create a shortcut on Desktop + ## How to use There are multiple ways to open your file: diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs index bba9c2c..ef93c20 100644 --- a/UVtools.Core/Layer/LayerIssue.cs +++ b/UVtools.Core/Layer/LayerIssue.cs @@ -14,6 +14,24 @@ namespace UVtools.Core { #region LayerIssue Class + public class IssuesDetectionConfiguration + { + public IslandDetectionConfiguration IslandConfig { get; } + public OverhangDetectionConfiguration OverhangConfig { get; } + public ResinTrapDetectionConfiguration ResinTrapConfig { get; } + public TouchingBoundDetectionConfiguration TouchingBoundConfig { get; } + public bool EmptyLayerConfig { get; } + + public IssuesDetectionConfiguration(IslandDetectionConfiguration islandConfig, OverhangDetectionConfiguration overhangConfig, ResinTrapDetectionConfiguration resinTrapConfig, TouchingBoundDetectionConfiguration touchingBoundConfig, bool emptyLayerConfig) + { + IslandConfig = islandConfig; + OverhangConfig = overhangConfig; + ResinTrapConfig = resinTrapConfig; + TouchingBoundConfig = touchingBoundConfig; + EmptyLayerConfig = emptyLayerConfig; + } + } + public class IslandDetectionConfiguration { /// <summary> @@ -60,6 +78,11 @@ namespace UVtools.Core /// will be considered.. /// </summary> public bool AllowDiagonalBonds { get; set; } = false; + + public IslandDetectionConfiguration(bool enabled = true) + { + Enabled = enabled; + } } /// <summary> @@ -93,6 +116,11 @@ namespace UVtools.Core /// The survived pixels are potential overhangs. /// </summary> public byte ErodeIterations { get; set; } = 40; + + public OverhangDetectionConfiguration(bool enabled = true) + { + Enabled = enabled; + } } public class ResinTrapDetectionConfiguration @@ -122,6 +150,11 @@ namespace UVtools.Core /// Gets the maximum pixel brightness to be a drain pixel (0-150) /// </summary> public byte MaximumPixelBrightnessToDrain { get; set; } = 30; + + public ResinTrapDetectionConfiguration(bool enabled = true) + { + Enabled = enabled; + } } @@ -136,6 +169,11 @@ namespace UVtools.Core /// Gets the maximum pixel brightness to be a touching bound /// </summary> public byte MaximumPixelBrightness { get; set; } = 200; + + public TouchingBoundDetectionConfiguration(bool enabled = true) + { + Enabled = enabled; + } } diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index e4d3faa..5e7d5c7 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -1348,10 +1348,85 @@ namespace UVtools.Core public void RepairLayers(OperationRepairLayers operation, OperationProgress progress = null) { if(ReferenceEquals(progress, null)) progress = new OperationProgress(); - progress.Reset(operation.ProgressAction, operation.LayerRangeCount); + var issues = operation.Issues; + // Remove islands + if (!ReferenceEquals(issues, null) + && !ReferenceEquals(operation.IslandDetectionConfig, null) + && operation.RepairIslands + && operation.RemoveIslandsBelowEqualPixelCount > 0 + && operation.RemoveIslandsRecursiveIterations != 1) + { + progress.Reset("Removed recursive islands", 0); + ushort limit = operation.RemoveIslandsRecursiveIterations == 0 + ? ushort.MaxValue + : operation.RemoveIslandsRecursiveIterations; + + var recursiveIssues = issues; + ConcurrentBag<uint> islandsToRecompute = null; + + var islandConfig = operation.IslandDetectionConfig; + var overhangConfig = new OverhangDetectionConfiguration(false); + var touchingBoundsConfig = new TouchingBoundDetectionConfiguration(false); + var resinTrapsConfig = new ResinTrapDetectionConfiguration(false); + var emptyLayersConfig = false; + + islandConfig.Enabled = true; + islandConfig.RequiredAreaToProcessCheck = (byte) Math.Ceiling(operation.RemoveIslandsBelowEqualPixelCount/2m); + + for (uint i = 0; i < limit; i++) + { + if (i > 0) + { + /*var whiteList = islandsToRecompute.GroupBy(u => u) + .Select(grp => grp.First()) + .ToList();*/ + islandConfig.WhiteListLayers = islandsToRecompute.ToList(); + recursiveIssues = GetAllIssues(islandConfig, overhangConfig, resinTrapsConfig, touchingBoundsConfig, emptyLayersConfig); + //Debug.WriteLine(i); + } + + var issuesGroup = + recursiveIssues + .Where(issue => issue.Type == LayerIssue.IssueType.Island && + issue.Pixels.Length <= operation.RemoveIslandsBelowEqualPixelCount) + .GroupBy(issue => issue.LayerIndex); + + if (!issuesGroup.Any()) break; // Nothing to process + islandsToRecompute = new ConcurrentBag<uint>(); + Parallel.ForEach(issuesGroup, group => + { + if (progress.Token.IsCancellationRequested) return; + Layer layer = this[group.Key]; + Mat image = layer.LayerMat; + Span<byte> bytes = image.GetPixelSpan<byte>(); + foreach (var issue in group) + { + foreach (var issuePixel in issue.Pixels) + { + bytes[image.GetPixelPos(issuePixel)] = 0; + } + + lock (progress.Mutex) + { + progress++; + } + } + + var nextLayerIndex = group.Key + 1; + if(nextLayerIndex < Count) + islandsToRecompute.Add(nextLayerIndex); + + layer.LayerMat = image; + }); + + if (islandsToRecompute.IsEmpty) break; // No more leftovers + } + } + + progress.Reset(operation.ProgressAction, operation.LayerRangeCount); if (operation.RepairIslands || operation.RepairResinTraps) { Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd, layerIndex => @@ -1362,13 +1437,13 @@ namespace UVtools.Core void initImage() { - if(ReferenceEquals(image, null)) + if(image is null) image = layer.LayerMat; } if (!ReferenceEquals(issues, null)) { - if (operation.RepairIslands && operation.RemoveIslandsBelowEqualPixelCount > 0) + if (operation.RepairIslands && operation.RemoveIslandsBelowEqualPixelCount > 0 && operation.RemoveIslandsRecursiveIterations == 1) { Span<byte> bytes = null; foreach (var issue in issues) diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs index 4291576..e004682 100644 --- a/UVtools.Core/Operations/OperationRepairLayers.cs +++ b/UVtools.Core/Operations/OperationRepairLayers.cs @@ -14,6 +14,13 @@ namespace UVtools.Core.Operations { public class OperationRepairLayers : Operation { + private bool _repairIslands = true; + private bool _repairResinTraps = true; + private bool _removeEmptyLayers = true; + private byte _removeIslandsBelowEqualPixelCount = 5; + private ushort _removeIslandsRecursiveIterations = 4; + private uint _gapClosingIterations = 1; + private uint _noiseRemovalIterations = 0; public override bool CanROI { get; set; } = false; public override string Title => "Repair layers and issues"; public override string Description => null; @@ -37,12 +44,49 @@ namespace UVtools.Core.Operations return new StringTag(sb.ToString()); } - public bool RepairIslands { get; set; } = true; - public bool RepairResinTraps { get; set; } = true; - public bool RemoveEmptyLayers { get; set; } = true; - public byte RemoveIslandsBelowEqualPixelCount { get; set; } = 5; - public uint GapClosingIterations { get; set; } = 1; - public uint NoiseRemovalIterations { get; set; } = 0; + public bool RepairIslands + { + get => _repairIslands; + set => RaiseAndSetIfChanged(ref _repairIslands, value); + } + + public bool RepairResinTraps + { + get => _repairResinTraps; + set => RaiseAndSetIfChanged(ref _repairResinTraps, value); + } + + public bool RemoveEmptyLayers + { + get => _removeEmptyLayers; + set => RaiseAndSetIfChanged(ref _removeEmptyLayers, value); + } + + public byte RemoveIslandsBelowEqualPixelCount + { + get => _removeIslandsBelowEqualPixelCount; + set => RaiseAndSetIfChanged(ref _removeIslandsBelowEqualPixelCount, value); + } + + public ushort RemoveIslandsRecursiveIterations + { + get => _removeIslandsRecursiveIterations; + set => RaiseAndSetIfChanged(ref _removeIslandsRecursiveIterations, value); + } + + public uint GapClosingIterations + { + get => _gapClosingIterations; + set => RaiseAndSetIfChanged(ref _gapClosingIterations, value); + } + + public uint NoiseRemovalIterations + { + get => _noiseRemovalIterations; + set => RaiseAndSetIfChanged(ref _noiseRemovalIterations, value); + } + + public IslandDetectionConfiguration IslandDetectionConfig { get; set; } public List<LayerIssue> Issues { get; set; } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 786f667..3e9ed20 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,12 +10,12 @@ <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl> <Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description> - <Version>0.8.4.2</Version> + <Version>0.8.4.3</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> - <AssemblyVersion>0.8.4.2</AssemblyVersion> - <FileVersion>0.8.4.2</FileVersion> + <AssemblyVersion>0.8.4.3</AssemblyVersion> + <FileVersion>0.8.4.3</FileVersion> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/UVtools.GUI/App.config b/UVtools.GUI/App.config index cea47d0..cc2e5e9 100644 --- a/UVtools.GUI/App.config +++ b/UVtools.GUI/App.config @@ -216,7 +216,8 @@ <setting name="LayerRepairRemoveEmptyLayers" serializeAs="String"> <value>True</value> </setting> - <setting name="LayerRepairRemoveIslandsBelowEqualPixelsDefault" serializeAs="String"> + <setting name="LayerRepairRemoveIslandsBelowEqualPixelsDefault" + serializeAs="String"> <value>10</value> </setting> <setting name="PartialUpdateIslandsOnEditing" serializeAs="String"> @@ -267,6 +268,9 @@ <setting name="OverhangIndependentFromIslands" serializeAs="String"> <value>True</value> </setting> + <setting name="LayerRepairRemoveIslandsRecursiveIterations" serializeAs="String"> + <value>4</value> + </setting> </UVtools.GUI.Properties.Settings> </userSettings> </configuration> diff --git a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.Designer.cs index cd08105..24b0fe2 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.Designer.cs @@ -40,10 +40,14 @@ this.cbRemoveEmptyLayers = new System.Windows.Forms.CheckBox(); this.cbRepairResinTraps = new System.Windows.Forms.CheckBox(); this.cbRepairIslands = new System.Windows.Forms.CheckBox(); + this.label4 = new System.Windows.Forms.Label(); + this.nmRemoveIslandsRecursiveIterations = new System.Windows.Forms.NumericUpDown(); + this.label5 = new System.Windows.Forms.Label(); this.groupAdvancedSettings.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nmOpeningIterations)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nmClosingIterations)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.nmRemoveIslandsBelowEqualPixels)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.nmRemoveIslandsRecursiveIterations)).BeginInit(); this.SuspendLayout(); // // groupAdvancedSettings @@ -52,7 +56,7 @@ this.groupAdvancedSettings.Controls.Add(this.label1); this.groupAdvancedSettings.Controls.Add(this.nmClosingIterations); this.groupAdvancedSettings.Controls.Add(this.lbIterationsStart); - this.groupAdvancedSettings.Location = new System.Drawing.Point(3, 87); + this.groupAdvancedSettings.Location = new System.Drawing.Point(3, 111); this.groupAdvancedSettings.Name = "groupAdvancedSettings"; this.groupAdvancedSettings.Size = new System.Drawing.Size(601, 110); this.groupAdvancedSettings.TabIndex = 31; @@ -106,7 +110,7 @@ // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(319, 46); + this.label3.Location = new System.Drawing.Point(341, 46); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(25, 20); this.label3.TabIndex = 30; @@ -117,15 +121,16 @@ this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(3, 46); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(250, 20); + this.label2.Size = new System.Drawing.Size(276, 20); this.label2.TabIndex = 29; - this.label2.Text = "Do not remove islands larger than:"; + this.label2.Text = "Remove islands equal or smaller than:"; this.toolTip.SetToolTip(this.label2, "The pixel area theshold above which islands will not be removed by this repair. " + - " Islands remaining after repair will require supports to be added manually."); + " Islands remaining after repair will require supports to be added manually.\r\n0 =" + + " Disable: Do not remove any island"); // // nmRemoveIslandsBelowEqualPixels // - this.nmRemoveIslandsBelowEqualPixels.Location = new System.Drawing.Point(259, 43); + this.nmRemoveIslandsBelowEqualPixels.Location = new System.Drawing.Point(281, 43); this.nmRemoveIslandsBelowEqualPixels.Maximum = new decimal(new int[] { 255, 0, @@ -135,7 +140,8 @@ this.nmRemoveIslandsBelowEqualPixels.Size = new System.Drawing.Size(58, 26); this.nmRemoveIslandsBelowEqualPixels.TabIndex = 28; this.toolTip.SetToolTip(this.nmRemoveIslandsBelowEqualPixels, "The pixel area theshold above which islands will not be removed by this repair. " + - " Islands remaining after repair will require supports to be added manually."); + " Islands remaining after repair will require supports to be added manually.\r\n0 =" + + " Disable: Do not remove any island\r\n"); // // cbRemoveEmptyLayers // @@ -179,12 +185,46 @@ " area removal threshold, and then runs the “gap closure” technique.\r\n"); this.cbRepairIslands.UseVisualStyleBackColor = true; // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 77); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(265, 20); + this.label4.TabIndex = 32; + this.label4.Text = "Recursively remove islands for up to:"; + this.toolTip.SetToolTip(this.label4, resources.GetString("label4.ToolTip")); + // + // nmRemoveIslandsRecursiveIterations + // + this.nmRemoveIslandsRecursiveIterations.Location = new System.Drawing.Point(281, 74); + this.nmRemoveIslandsRecursiveIterations.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.nmRemoveIslandsRecursiveIterations.Name = "nmRemoveIslandsRecursiveIterations"; + this.nmRemoveIslandsRecursiveIterations.Size = new System.Drawing.Size(58, 26); + this.nmRemoveIslandsRecursiveIterations.TabIndex = 33; + this.toolTip.SetToolTip(this.nmRemoveIslandsRecursiveIterations, resources.GetString("nmRemoveIslandsRecursiveIterations.ToolTip")); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(341, 77); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(50, 20); + this.label5.TabIndex = 34; + this.label5.Text = "layers"; + // // CtrlToolRepairLayers // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.label5); + this.Controls.Add(this.nmRemoveIslandsRecursiveIterations); + this.Controls.Add(this.label4); this.Controls.Add(this.groupAdvancedSettings); this.Controls.Add(this.label3); this.Controls.Add(this.label2); @@ -197,12 +237,13 @@ this.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.LayerRangeVisible = false; this.Name = "CtrlToolRepairLayers"; - this.Size = new System.Drawing.Size(607, 200); + this.Size = new System.Drawing.Size(607, 224); this.groupAdvancedSettings.ResumeLayout(false); this.groupAdvancedSettings.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.nmOpeningIterations)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nmClosingIterations)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nmRemoveIslandsBelowEqualPixels)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.nmRemoveIslandsRecursiveIterations)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -221,5 +262,8 @@ private System.Windows.Forms.CheckBox cbRemoveEmptyLayers; private System.Windows.Forms.CheckBox cbRepairResinTraps; private System.Windows.Forms.CheckBox cbRepairIslands; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.NumericUpDown nmRemoveIslandsRecursiveIterations; + private System.Windows.Forms.Label label5; } } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs index c8fe8a9..f63bd8d 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs @@ -25,6 +25,7 @@ namespace UVtools.GUI.Controls.Tools cbRepairResinTraps.Checked = Properties.Settings.Default.LayerRepairResinTraps; cbRemoveEmptyLayers.Checked = Properties.Settings.Default.LayerRepairRemoveEmptyLayers; nmRemoveIslandsBelowEqualPixels.Value = Properties.Settings.Default.LayerRepairRemoveIslandsBelowEqualPixelsDefault; + nmRemoveIslandsRecursiveIterations.Value = Properties.Settings.Default.LayerRepairRemoveIslandsRecursiveIterations; nmClosingIterations.Value = Properties.Settings.Default.LayerRepairDefaultClosingIterations; nmOpeningIterations.Value = Properties.Settings.Default.LayerRepairDefaultOpeningIterations; @@ -39,6 +40,7 @@ namespace UVtools.GUI.Controls.Tools Operation.RepairResinTraps = cbRepairResinTraps.Checked; Operation.RemoveEmptyLayers = cbRemoveEmptyLayers.Checked; Operation.RemoveIslandsBelowEqualPixelCount = (byte) nmRemoveIslandsBelowEqualPixels.Value; + Operation.RemoveIslandsRecursiveIterations = (ushort) nmRemoveIslandsRecursiveIterations.Value; Operation.GapClosingIterations = (uint) nmClosingIterations.Value; Operation.NoiseRemovalIterations = (uint) nmOpeningIterations.Value; diff --git a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.resx b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.resx index 866a61d..e083b02 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.resx +++ b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.resx @@ -131,4 +131,18 @@ WARNING: Even at low settings this operation has the potential to introduce new Set iterations to 0 to disable. WARNING: Using high iteration values can destroy your model. Low values recomended.</value> </data> + <data name="label4.ToolTip" xml:space="preserve"> + <value>If the removal of an island in the current layer results in a new island being introduce in the layer above, the island in the layer above will also be automatically removed. +This process will repeat for up to the number of layers specified. Set to 0 to repeat until there are no more valid islands to remove. + +NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand. + Using this function with high values can be extremely slow depending on resolution and issue count.</value> + </data> + <data name="nmRemoveIslandsRecursiveIterations.ToolTip" xml:space="preserve"> + <value>If the removal of an island in the current layer results in a new island being introduce in the layer above, the island in the layer above will also be automatically removed. +This process will repeat for up to the number of layers specified. Set to 0 to repeat until there are no more valid islands to remove. + +NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand. + Using this function with high values can be extremely slow depending on resolution and issue count.</value> + </data> </root>
\ No newline at end of file diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs index 0f6cd03..e6240de 100644 --- a/UVtools.GUI/FrmMain.cs +++ b/UVtools.GUI/FrmMain.cs @@ -4259,6 +4259,7 @@ namespace UVtools.GUI { // Tools case OperationRepairLayers operation: + operation.IslandDetectionConfig = GetIslandDetectionConfiguration(); SlicerFile.LayerManager.RepairLayers(operation, FrmLoading.RestartProgress(operation.CanCancel)); break; case OperationMove operation: @@ -4378,7 +4379,9 @@ namespace UVtools.GUI ? 1 : nmPixelEditorDrawingThickness.Value); - int diameter = (brushSize * pbLayer.Zoom / 100); + + var cursorSize = thickness > 1 ? brushSize + thickness : brushSize; + int diameter = (int) (cursorSize * pbLayer.ZoomFactor); if (brushSize > 1 && diameter >= _pixelEditorCursorMinDiamater) { bitmap = new Bitmap(diameter, diameter, PixelFormat.Format32bppArgb); @@ -4392,7 +4395,7 @@ namespace UVtools.GUI case PixelDrawing.BrushShapeType.Rectangle: if (thickness >= 1) { - gr.DrawRectangle(new Pen(_pixelEditorCursorBrush, thickness), 0, 0, diameter, diameter); + gr.DrawRectangle(new Pen(_pixelEditorCursorBrush, (int)(thickness * 2 * pbLayer.ZoomFactor)), 0, 0, diameter, diameter); } else { @@ -4402,7 +4405,7 @@ namespace UVtools.GUI case PixelDrawing.BrushShapeType.Circle: if (thickness >= 1) { - gr.DrawEllipse(new Pen(_pixelEditorCursorBrush, thickness), 0, 0, diameter, diameter); + gr.DrawEllipse(new Pen(_pixelEditorCursorBrush, (int)(thickness * 2 * pbLayer.ZoomFactor)), 0, 0, diameter, diameter); } else { diff --git a/UVtools.GUI/Properties/AssemblyInfo.cs b/UVtools.GUI/Properties/AssemblyInfo.cs index 20c38ad..36d551e 100644 --- a/UVtools.GUI/Properties/AssemblyInfo.cs +++ b/UVtools.GUI/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.4.2")] -[assembly: AssemblyFileVersion("0.8.4.2")] +[assembly: AssemblyVersion("0.8.4.3")] +[assembly: AssemblyFileVersion("0.8.4.3")] diff --git a/UVtools.GUI/Properties/Settings.Designer.cs b/UVtools.GUI/Properties/Settings.Designer.cs index 1e56ae5..1f91fc8 100644 --- a/UVtools.GUI/Properties/Settings.Designer.cs +++ b/UVtools.GUI/Properties/Settings.Designer.cs @@ -970,5 +970,17 @@ namespace UVtools.GUI.Properties { this["OverhangIndependentFromIslands"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("4")] + public short LayerRepairRemoveIslandsRecursiveIterations { + get { + return ((short)(this["LayerRepairRemoveIslandsRecursiveIterations"])); + } + set { + this["LayerRepairRemoveIslandsRecursiveIterations"] = value; + } + } } } diff --git a/UVtools.GUI/Properties/Settings.settings b/UVtools.GUI/Properties/Settings.settings index 5cf1017..e25f334 100644 --- a/UVtools.GUI/Properties/Settings.settings +++ b/UVtools.GUI/Properties/Settings.settings @@ -239,5 +239,8 @@ <Setting Name="OverhangIndependentFromIslands" Type="System.Boolean" Scope="User"> <Value Profile="(Default)">True</Value> </Setting> + <Setting Name="LayerRepairRemoveIslandsRecursiveIterations" Type="System.Int16" Scope="User"> + <Value Profile="(Default)">4</Value> + </Setting> </Settings> </SettingsFile>
\ No newline at end of file diff --git a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml index 489fb41..e176d9d 100644 --- a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml @@ -49,40 +49,93 @@ </CheckBox> </StackPanel> - <StackPanel Orientation="Horizontal" Spacing="10"> + <Grid ColumnDefinitions="Auto,10,Auto,5,Auto" + RowDefinitions="Auto,10,Auto"> - <!-- Do not remove islands larger than --> + <!-- Remove islands equal or smaller than --> <TextBlock - VerticalAlignment="Center" - Text="Do not remove islands larger than:"> + Grid.Row="0" + Grid.Column="0" + VerticalAlignment="Center" + Text="Remove islands equal or smaller than:"> + <ToolTip.Tip> + <StackPanel> + <TextBlock FontWeight="Bold" Text="Remove islands equal or smaller than:"/> + <TextBlock Text="The pixel area theshold above which islands will not be removed by this repair. + 
Islands remaining after repair will require supports to be added manually."/> + </StackPanel> + </ToolTip.Tip> + </TextBlock> + + <NumericUpDown + Grid.Row="0" + Grid.Column="2" + Increment="1" + Minimum="0" + Maximum="255" + Width="70" + Value="{Binding Operation.RemoveIslandsBelowEqualPixelCount}" + > + <ToolTip.Tip> + <StackPanel> + <TextBlock FontWeight="Bold" Text="Remove islands equal or smaller than:"/> + <TextBlock Text="The pixel area theshold above which islands will not be removed by this repair. +
Islands remaining after repair will require supports to be added manually."/> + </StackPanel> + </ToolTip.Tip> + </NumericUpDown> + <TextBlock + Grid.Row="0" + Grid.Column="4" + VerticalAlignment="Center" + Text="px"/> + + + <!-- Recursively remove islands for up to --> + <TextBlock + Grid.Row="2" + Grid.Column="0" + VerticalAlignment="Center" + Text="Recursively remove islands for up to:"> <ToolTip.Tip> <StackPanel> - <TextBlock FontWeight="Bold" Text="Do not remove islands larger than:"/> - <TextBlock Text="The pixel area theshold above which islands will not be removed by this repair. -
Islands remaining after repair will require supports to be added manually."/> + <TextBlock FontWeight="Bold" Text="Recursively remove islands for up to:"/> + <TextBlock Text="If the removal of an island in the current layer results in a new island being introduce in the layer above, the island in the layer above will also be automatically removed. +
This process will repeat for up to the number of layers specified. Set to 0 to repeat until there are no more valid islands to remove. +
 +
NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand. +
 Using this function with high values can be extremely slow depending on resolution and issue count."/> </StackPanel> </ToolTip.Tip> - </TextBlock> - + </TextBlock> + <NumericUpDown + Grid.Row="2" + Grid.Column="2" Increment="1" Minimum="0" - Maximum="255" + Maximum="65535" Width="70" - Value="{Binding Operation.RemoveIslandsBelowEqualPixelCount}" - > + Value="{Binding Operation.RemoveIslandsRecursiveIterations}" + > <ToolTip.Tip> <StackPanel> - <TextBlock FontWeight="Bold" Text="Do not remove islands larger than:"/> - <TextBlock Text="The pixel area theshold above which islands will not be removed by this repair. -
Islands remaining after repair will require supports to be added manually."/> + <TextBlock FontWeight="Bold" Text="Recursively remove islands for up to:"/> + <TextBlock Text="If the removal of an island in the current layer results in a new island being introduce in the layer above, the island in the layer above will also be automatically removed. +
This process will repeat for up to the number of layers specified. Set to 0 to repeat until there are no more valid islands to remove. +
 +
NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand. +
 Using this function with high values can be extremely slow depending on resolution and issue count."/> </StackPanel> </ToolTip.Tip> </NumericUpDown> <TextBlock - VerticalAlignment="Center" - Text="px"/> - </StackPanel> + Grid.Row="2" + Grid.Column="4" + VerticalAlignment="Center" + Text="layers"/> + + </Grid> <Grid diff --git a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs index 70fcabe..843c096 100644 --- a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs @@ -1,5 +1,4 @@ -using System.Diagnostics; -using Avalonia.Markup.Xaml; +using Avalonia.Markup.Xaml; using UVtools.Core.Operations; using UVtools.WPF.Windows; @@ -18,6 +17,7 @@ namespace UVtools.WPF.Controls.Tools RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps, RemoveEmptyLayers = UserSettings.Instance.LayerRepair.RemoveEmptyLayers, RemoveIslandsBelowEqualPixelCount = UserSettings.Instance.LayerRepair.RemoveIslandsBelowEqualPixels, + RemoveIslandsRecursiveIterations = UserSettings.Instance.LayerRepair.RemoveIslandsRecursiveIterations, GapClosingIterations = UserSettings.Instance.LayerRepair.ClosingIterations, NoiseRemovalIterations = UserSettings.Instance.LayerRepair.OpeningIterations, }; diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index fe78532..1863f08 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -1108,6 +1108,7 @@ namespace UVtools.WPF { // Tools case OperationRepairLayers operation: + operation.IslandDetectionConfig = GetIslandDetectionConfiguration(); SlicerFile.LayerManager.RepairLayers(operation, ProgressWindow.RestartProgress(operation.CanCancel)); break; case OperationMove operation: diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs index 1607311..a5e5ca3 100644 --- a/UVtools.WPF/UserSettings.cs +++ b/UVtools.WPF/UserSettings.cs @@ -841,23 +841,30 @@ namespace UVtools.WPF [Serializable] public sealed class LayerRepairUserSettings : ReactiveObject { - private byte _closingIterations = 2; - private byte _openingIterations = 0; - private byte _removeIslandsBelowEqualPixels = 10; private bool _repairIslands = true; private bool _repairResinTraps = true; private bool _removeEmptyLayers = true; + private byte _removeIslandsBelowEqualPixels = 10; + private ushort _removeIslandsRecursiveIterations = 4; + private byte _closingIterations = 2; + private byte _openingIterations = 0; - public byte ClosingIterations + public bool RepairIslands { - get => _closingIterations; - set => this.RaiseAndSetIfChanged(ref _closingIterations, value); + get => _repairIslands; + set => this.RaiseAndSetIfChanged(ref _repairIslands, value); } - public byte OpeningIterations + public bool RepairResinTraps { - get => _openingIterations; - set => this.RaiseAndSetIfChanged(ref _openingIterations, value); + get => _repairResinTraps; + set => this.RaiseAndSetIfChanged(ref _repairResinTraps, value); + } + + public bool RemoveEmptyLayers + { + get => _removeEmptyLayers; + set => this.RaiseAndSetIfChanged(ref _removeEmptyLayers, value); } public byte RemoveIslandsBelowEqualPixels @@ -866,22 +873,22 @@ namespace UVtools.WPF set => this.RaiseAndSetIfChanged(ref _removeIslandsBelowEqualPixels, value); } - public bool RepairIslands + public ushort RemoveIslandsRecursiveIterations { - get => _repairIslands; - set => this.RaiseAndSetIfChanged(ref _repairIslands, value); + get => _removeIslandsRecursiveIterations; + set => this.RaiseAndSetIfChanged(ref _removeIslandsRecursiveIterations, value); } - public bool RepairResinTraps + public byte ClosingIterations { - get => _repairResinTraps; - set => this.RaiseAndSetIfChanged(ref _repairResinTraps, value); + get => _closingIterations; + set => this.RaiseAndSetIfChanged(ref _closingIterations, value); } - public bool RemoveEmptyLayers + public byte OpeningIterations { - get => _removeEmptyLayers; - set => this.RaiseAndSetIfChanged(ref _removeEmptyLayers, value); + get => _openingIterations; + set => this.RaiseAndSetIfChanged(ref _openingIterations, value); } public LayerRepairUserSettings Clone() diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml index b65d4c9..21a4ca9 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -951,46 +951,52 @@ BorderBrush="LightBlue" BorderThickness="4"> - <StackPanel Orientation="Vertical"> + <StackPanel Orientation="Vertical" Spacing="15"> <TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Default values"/> - <StackPanel Orientation="Horizontal" Margin="15" Spacing="10"> + <CheckBox IsChecked="{Binding Settings.LayerRepair.RepairIslands}" + Margin="15,0" Content="Attempt to repair islands by default"/> + <CheckBox IsChecked="{Binding Settings.LayerRepair.RepairResinTraps}" + Margin="15,0" Content="Remove empty layers by default"/> + <CheckBox IsChecked="{Binding Settings.LayerRepair.RemoveEmptyLayers}" + Margin="15,0" Content="Attempt to repair resin traps by default"/> + + <StackPanel Orientation="Horizontal" Margin="15,0" Spacing="10"> + <NumericUpDown + Value="{Binding Settings.LayerRepair.RemoveIslandsBelowEqualPixels}" + Width="70" + Minimum="0" + Maximum="255"/> + <TextBlock VerticalAlignment="Center" Text="Default maximum pixel area for Island removal (0 = disable)"/> + </StackPanel> + + <StackPanel Orientation="Horizontal" Margin="15,0" Spacing="10"> + <NumericUpDown + Value="{Binding Settings.LayerRepair.RemoveIslandsRecursiveIterations}" + Width="70" + Minimum="0" + Maximum="65535"/> + <TextBlock VerticalAlignment="Center" Text="Default maximum layers for recursive island removal (0 = All)"/> + </StackPanel> + + <StackPanel Orientation="Horizontal" Margin="15,0" Spacing="10"> <NumericUpDown Value="{Binding Settings.LayerRepair.ClosingIterations}" - Width="60" + Width="70" Minimum="0" - Maximum="255" - /> + Maximum="255"/> <TextBlock VerticalAlignment="Center" Text="Default 'Gap Closing' iterations"/> </StackPanel> <StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10"> - <NumericUpDown + <NumericUpDown Value="{Binding Settings.LayerRepair.OpeningIterations}" - Width="60" + Width="70" Minimum="0" - Maximum="255" - /> + Maximum="255"/> <TextBlock VerticalAlignment="Center" Text="Default 'Noise Removal' iterations"/> </StackPanel> - <StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10"> - <NumericUpDown - Value="{Binding Settings.LayerRepair.RemoveIslandsBelowEqualPixels}" - Width="60" - Minimum="0" - Maximum="255" - /> - <TextBlock VerticalAlignment="Center" Text="Default maximum pixel area for Island removal (0 = disable)"/> - </StackPanel> - - <CheckBox IsChecked="{Binding Settings.LayerRepair.RepairIslands}" - Margin="15,0" Content="Attempt to repair islands by default"/> - <CheckBox IsChecked="{Binding Settings.LayerRepair.RepairResinTraps}" - Margin="15,15,15,0" Content="Remove empty layers by default"/> - <CheckBox IsChecked="{Binding Settings.LayerRepair.RemoveEmptyLayers}" - Margin="15" Content="Attempt to repair resin traps by default"/> - </StackPanel> </Border> |