* (Add) Tool - Layer repair: Allow remove islands recursively (#74)
* (Fix) Pixel Editor: Cursor dimentions when using brushes with thickness > 1 (#73)
This commit is contained in:
Tiago Conceição
2020-10-13 02:04:05 +01:00
parent 4721a52565
commit 1a0229a654
19 changed files with 420 additions and 103 deletions
+5
View File
@@ -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
+7 -1
View File
@@ -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:
+38
View File
@@ -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;
}
}
+78 -3
View File
@@ -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)
@@ -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; }
+3 -3
View File
@@ -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'">
+5 -1
View File
@@ -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>
+53 -9
View File
@@ -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;
}
}
@@ -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;
@@ -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>
+6 -3
View File
@@ -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
{
+2 -2
View File
@@ -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")]
+12
View File
@@ -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;
}
}
}
}
+3
View File
@@ -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>
@@ -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.
&#x0a;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.
&#x0a;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.
&#x0a;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.
&#x0a;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.
&#x0a;
&#x0a;NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand.
&#x0a; 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.
&#x0a;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.
&#x0a;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.
&#x0a;
&#x0a;NOTE: Use with caution as this can remove large portions of your model if proper supports have not been added beforehand.
&#x0a; 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
@@ -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,
};
+1
View File
@@ -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:
+28 -21
View File
@@ -841,30 +841,13 @@ 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;
public byte ClosingIterations
{
get => _closingIterations;
set => this.RaiseAndSetIfChanged(ref _closingIterations, value);
}
public byte OpeningIterations
{
get => _openingIterations;
set => this.RaiseAndSetIfChanged(ref _openingIterations, value);
}
public byte RemoveIslandsBelowEqualPixels
{
get => _removeIslandsBelowEqualPixels;
set => this.RaiseAndSetIfChanged(ref _removeIslandsBelowEqualPixels, value);
}
private byte _removeIslandsBelowEqualPixels = 10;
private ushort _removeIslandsRecursiveIterations = 4;
private byte _closingIterations = 2;
private byte _openingIterations = 0;
public bool RepairIslands
{
@@ -884,6 +867,30 @@ namespace UVtools.WPF
set => this.RaiseAndSetIfChanged(ref _removeEmptyLayers, value);
}
public byte RemoveIslandsBelowEqualPixels
{
get => _removeIslandsBelowEqualPixels;
set => this.RaiseAndSetIfChanged(ref _removeIslandsBelowEqualPixels, value);
}
public ushort RemoveIslandsRecursiveIterations
{
get => _removeIslandsRecursiveIterations;
set => this.RaiseAndSetIfChanged(ref _removeIslandsRecursiveIterations, value);
}
public byte ClosingIterations
{
get => _closingIterations;
set => this.RaiseAndSetIfChanged(ref _closingIterations, value);
}
public byte OpeningIterations
{
get => _openingIterations;
set => this.RaiseAndSetIfChanged(ref _openingIterations, value);
}
public LayerRepairUserSettings Clone()
{
return MemberwiseClone() as LayerRepairUserSettings;
+40 -34
View File
@@ -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">
<NumericUpDown
Value="{Binding Settings.LayerRepair.ClosingIterations}"
Width="60"
Minimum="0"
Maximum="255"
/>
<TextBlock VerticalAlignment="Center" Text="Default 'Gap Closing' iterations"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown
Value="{Binding Settings.LayerRepair.OpeningIterations}"
Width="60"
Minimum="0"
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"/>
Margin="15,0" Content="Remove empty layers by default"/>
<CheckBox IsChecked="{Binding Settings.LayerRepair.RemoveEmptyLayers}"
Margin="15" Content="Attempt to repair resin traps by default"/>
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="70"
Minimum="0"
Maximum="255"/>
<TextBlock VerticalAlignment="Center" Text="Default 'Gap Closing' iterations"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown
Value="{Binding Settings.LayerRepair.OpeningIterations}"
Width="70"
Minimum="0"
Maximum="255"/>
<TextBlock VerticalAlignment="Center" Text="Default 'Noise Removal' iterations"/>
</StackPanel>
</StackPanel>
</Border>