* (Add) Setting: Auto repair layers and issues on file load
* (Improvement) When ComputeIssuesOnLoad is enabled and issues are detected it will switch the view to the Issues tab
* **(Improvement) Raft Relief:**
   * Add parameter "Mask layer index": Defines the mask layer to use and ignore the white blobs on the raft
   * Increase the automatic support detection allowance on more odd shapes
   * Prevent layer 0 to be used as a mask, if so it will quit
   * If the ignored layer number are set and equal or larger than mask layer index it will quit
   * Fix progress count when using ignored layers
   * Change supports dilate kernel from Elipse to Rectangle for a better coverage of the pad
   * Change the default values for a more conservative values
* (Fix) When both ComputeIssuesOnLoad and ComputeIssuesOnClickTab are enabled, clicking the issues tab will rescan for issues
* (Fix) Tools: Set a default profile insn't working
* (Fix) Redoing the last operation was not recovering the custom ROI on the operation
This commit is contained in:
Tiago Conceição
2021-03-03 23:48:55 +00:00
parent 5fc722e203
commit 93d0381280
26 changed files with 375 additions and 94 deletions
+18 -2
View File
@@ -1,13 +1,29 @@
# Changelog
## 25/02/2021 - v2.6.0
## 03/03/2021 - v2.6.1
* (Add) Setting: Auto repair layers and issues on file load
* (Improvement) When ComputeIssuesOnLoad is enabled and issues are detected it will switch the view to the Issues tab
* **(Improvement) Raft Relief:**
* Add parameter "Mask layer index": Defines the mask layer to use and ignore the white blobs on the raft
* Increase the automatic support detection allowance on more odd shapes
* Prevent layer 0 to be used as a mask, if so it will quit
* If the ignored layer number are set and equal or larger than mask layer index it will quit
* Fix progress count when using ignored layers
* Change supports dilate kernel from Elipse to Rectangle for a better coverage of the pad
* Change the default values for a more conservative values
* (Fix) When both ComputeIssuesOnLoad and ComputeIssuesOnClickTab are enabled, clicking the issues tab will rescan for issues
* (Fix) Tools: Set a default profile insn't working
* (Fix) Redoing the last operation was not recovering the custom ROI on the operation
## 02/03/2021 - v2.6.0
* (Add) File format: Zcode (Uniz IBEE)
* (Add) PrusaSlicer Printer: Uniz IBEE
* (Add) Extract: Output an "Layer.ini" file containing per layer data and include the Configuration.ini for Zip file formats
* (Improvement) Zip: Increase the GCode parsing performance
* (Fix) File formats: Wasn't set bottom / light off delay per individual layer on generic formats, defaulting every layer to 0
* (Fix) Edit print paramenters: When changing bottom layer count, layers didnt update thier properties
* (Fix) Edit print parameters: When changing bottom layer count, layers didnt update thier properties
## 25/02/2021 - v2.5.1
+2 -1
View File
@@ -48,4 +48,5 @@
* Andrew Griffiths
* Abhinav Sinha
* Randy Savell
* Steve Clynes
* Steve Clynes
* Nicholas Taylor
+1 -1
View File
@@ -32,6 +32,6 @@ namespace UVtools.Core.Extensions
return (T)Activator.CreateInstance(type);
}
public static byte ToByte(this bool value) => value ? 1 : 0;
public static byte ToByte(this bool value) => (byte)(value ? 1 : 0);
}
}
+1 -1
View File
@@ -1085,7 +1085,7 @@ namespace UVtools.Core.FileFormats
get => HeaderSettings.ProjectorType > 0;
set
{
HeaderSettings.ProjectorType = value ? 1 : 0;
HeaderSettings.ProjectorType = value ? 1u : 0;
RaisePropertyChanged();
}
}
+1 -1
View File
@@ -181,7 +181,7 @@ namespace UVtools.Core.FileFormats
set
{
HeaderSettings.ProjectType = value ? "LCD_mirror" : "Normal";
HeaderSettings.Mirror = value ? 1 : 0;
HeaderSettings.Mirror = (byte)(value ? 1 : 0);
RaisePropertyChanged();
}
}
+1 -1
View File
@@ -757,7 +757,7 @@ namespace UVtools.Core.FileFormats
get => HeaderSettings.ProjectorType > 0;
set
{
HeaderSettings.ProjectorType = value ? 1 : 0;
HeaderSettings.ProjectorType = value ? 1u : 0;
RaisePropertyChanged();
}
}
+1 -1
View File
@@ -775,7 +775,7 @@ namespace UVtools.Core.FileFormats
get => HeaderSettings.ProjectorType > 0;
set
{
HeaderSettings.ProjectorType = value ? 1 : 0;
HeaderSettings.ProjectorType = value ? 1u : 0;
RaisePropertyChanged();
}
}
+1 -1
View File
@@ -126,7 +126,7 @@ namespace UVtools.Core.FileFormats
for (int i = 0; i < imageLength; i++)
{
//color = color <= 127 ? 0 : 255; // Sanitize no AA
byte thisColor = spanMat[i] <= 127 ? 0 : 255; // Sanitize no AA
byte thisColor = spanMat[i] <= 127 ? byte.MinValue : byte.MaxValue; // Sanitize no AA
if (thisColor != color)
{
AddRep();
@@ -1318,7 +1318,7 @@ namespace UVtools.Core.FileFormats
break;
}
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1;
HeaderSettings.PerLayerOverride = (byte)(LayerManager.AllLayersHaveGlobalParameters ? 0 : 1);
uint currentOffset = FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings);
@@ -1522,7 +1522,7 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1;
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1u;
using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(FileMarkSettings.HeaderAddress, SeekOrigin.Begin);
+1 -1
View File
@@ -379,7 +379,7 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing
{
get => (byte)PrinterSettings.GammaCorrection > 0 ? 4 : 1;
get => (byte)(PrinterSettings.GammaCorrection > 0 ? 4 : 1);
set => PrinterSettings.GammaCorrection = value > 0 ? 1 : 0;
}
+1 -1
View File
@@ -771,7 +771,7 @@ namespace UVtools.Core.FileFormats
byte[] data = Encoding.UTF8.GetBytes(line);
List<byte> padData = new(64) {0, 1, 0};
padData.AddRange(data);
if (padData.Count > 64)
{
throw new ArgumentOutOfRangeException($"Too long gcode line to encrypt, got: {padData.Count} bytes while expecting less than 64 bytes");
+8 -1
View File
@@ -1,4 +1,11 @@
using System;
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+8 -1
View File
@@ -1,4 +1,11 @@
using System;
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+180
View File
@@ -0,0 +1,180 @@
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System.Text;
namespace UVtools.Core.Objects
{
public class GCodeBuilder : BindableBase
{
#region Enums
public enum GCodeTimeUnits : byte
{
Milliseconds,
Seconds
}
public enum GCodeSpeedUnits : byte
{
MillimetersPerSecond,
MillimetersPerMinute,
CentimetersPerMinute,
}
#endregion
#region Members
private readonly StringBuilder _gcode = new();
private bool _appendComma = true;
private bool _appendComment = true;
private bool _useAbsoluteCommands = true;
private GCodeTimeUnits _gCodeTimeUnit = GCodeTimeUnits.Milliseconds;
private GCodeSpeedUnits _gCodeSpeedUnit = GCodeSpeedUnits.MillimetersPerMinute;
#endregion
#region Properties
public bool UseAbsoluteCommands
{
get => _useAbsoluteCommands;
set => RaiseAndSetIfChanged(ref _useAbsoluteCommands, value);
}
public GCodeTimeUnits GCodeTimeUnit
{
get => _gCodeTimeUnit;
set => RaiseAndSetIfChanged(ref _gCodeTimeUnit, value);
}
public GCodeSpeedUnits GCodeSpeedUnit
{
get => _gCodeSpeedUnit;
set => RaiseAndSetIfChanged(ref _gCodeSpeedUnit, value);
}
public bool AppendComma
{
get => _appendComma;
set => RaiseAndSetIfChanged(ref _appendComma, value);
}
public bool AppendComment
{
get => _appendComment;
set => RaiseAndSetIfChanged(ref _appendComment, value);
}
#endregion
#region StringBuilder
public void AppendLine() => _gcode.AppendLine();
public void AppendLine(string line) => _gcode.AppendLine(line);
public void AppendFormat(string format, params object?[] args) => _gcode.AppendFormat(format, args);
public void Clear() => _gcode.Clear();
public override string ToString() => _gcode.ToString();
#endregion
#region Methods
public string FormatGCodeLine(string line, string comment)
{
if (_appendComma || _appendComment)
line += ';';
if (_appendComment)
line += comment;
return line;
}
public void AppendUnitsMmG21()
{
AppendLine(FormatGCodeLine("G21", "Set units to be mm"));
}
public void AppendPositioningType()
{
if (_useAbsoluteCommands)
{
AppendLine(FormatGCodeLine("G90", "Absolute positioning"));
}
else
{
AppendLine(FormatGCodeLine("G91", "Partial positioning"));
}
}
public void AppendEnableMotors()
{
AppendLine(FormatGCodeLine("M17", "Enable motors"));
}
public void AppendDisableMotors()
{
AppendLine(FormatGCodeLine("M18", "Disable motors"));
}
public void AppendTurnMotors(bool enable)
{
if (enable)
AppendEnableMotors();
else
AppendDisableMotors();
}
public void AppendHomeZG28()
{
AppendLine(FormatGCodeLine("G28 Z0", "Home Z"));
}
public void AppendMoveG0(float z, float feedRate)
{
AppendLine(FormatGCodeLine($"G0 Z{z} F{feedRate}", "Z Move"));
}
public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate)
{
AppendLine(FormatGCodeLine($"G0 Z{upZ} F{upFeedRate}", "Z Lift"));
AppendLine(FormatGCodeLine($"G0 Z{downZ} F{downFeedRate}", "Retract to layer height"));
}
public void AppendWaitG4(float time)
{
AppendLine(FormatGCodeLine($"G4 P{time}", "Delay"));
}
public void AppendTurnLightM106(ushort value)
{
AppendLine(FormatGCodeLine($"M106 S{value}", "Turn LED"));
}
public void AppendLightOffM106() => AppendTurnLightM106(0);
public void AppendLightFullM106() => AppendTurnLightM106(255);
public void AppendExposure(ushort value, float time)
{
if (time <= 0) return;
AppendTurnLightM106(value);
AppendWaitG4(time);
AppendLightOffM106();
}
public void AppendShowImageM6054(string name)
{
AppendLine(FormatGCodeLine($"M6054 \"{name}\"","Show image"));
}
public void AppendLineComment(string comment)
{
AppendLine($";{comment}");
}
}
#endregion
}
+41 -22
View File
@@ -31,12 +31,14 @@ namespace UVtools.Core.Operations
#region Members
private RaftReliefTypes _reliefType = RaftReliefTypes.Relief;
private uint _maskLayerIndex;
private byte _ignoreFirstLayers;
private byte _brightness;
private byte _dilateIterations = 10;
private byte _wallMargin = 20;
private byte _holeDiameter = 50;
private byte _holeSpacing = 20;
private byte _dilateIterations = 15;// +/- 1.5mm radius
private byte _wallMargin = 40; // +/- 2mm
private byte _holeDiameter = 80; // +/- 4mm
private byte _holeSpacing = 40; // +/- 2mm
#endregion
#region Overrides
@@ -57,7 +59,7 @@ namespace UVtools.Core.Operations
public override string ToString()
{
var result = $"[{_reliefType}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
var result = $"[{_reliefType}] [Mask layer: {_maskLayerIndex}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -90,6 +92,12 @@ namespace UVtools.Core.Operations
public bool IsDimming => _reliefType == RaftReliefTypes.Dimming;
public bool IsDecimate => _reliefType == RaftReliefTypes.Decimate;
public uint MaskLayerIndex
{
get => _maskLayerIndex;
set => RaiseAndSetIfChanged(ref _maskLayerIndex, value);
}
public byte IgnoreFirstLayers
{
get => _ignoreFirstLayers;
@@ -137,7 +145,7 @@ namespace UVtools.Core.Operations
protected bool Equals(OperationRaftRelief other)
{
return _reliefType == other._reliefType && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing;
return _reliefType == other._reliefType && _maskLayerIndex == other._maskLayerIndex && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing;
}
public override bool Equals(object obj)
@@ -150,7 +158,7 @@ namespace UVtools.Core.Operations
public override int GetHashCode()
{
return HashCode.Combine((int) _reliefType, _ignoreFirstLayers, _brightness, _dilateIterations, _wallMargin, _holeDiameter, _holeSpacing);
return HashCode.Combine((int) _reliefType, _maskLayerIndex, _ignoreFirstLayers, _brightness, _dilateIterations, _wallMargin, _holeDiameter, _holeSpacing);
}
#endregion
@@ -160,33 +168,43 @@ namespace UVtools.Core.Operations
protected override bool ExecuteInternally(OperationProgress progress)
{
progress.ItemCount = 0;
const uint minLength = 5;
const uint minSupportsRequired = 5;
const uint maxLayerCount = 1000;
Mat supportsMat = null;
var anchor = new Point(-1, -1);
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
uint firstSupportLayerIndex = 0;
for (; firstSupportLayerIndex < SlicerFile.LayerCount; firstSupportLayerIndex++)
uint firstSupportLayerIndex = _maskLayerIndex;
if (firstSupportLayerIndex <= 0)
{
uint layerCount = Math.Min(SlicerFile.LayerCount, maxLayerCount);
progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex);
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
{
if (progress.Token.IsCancellationRequested) return false;
progress++;
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200);
if (circles.Length >= minSupportsRequired) break;
supportsMat.Dispose();
supportsMat = null;
}
}
else
{
progress.Reset("Tracing raft", SlicerFile.LayerCount, firstSupportLayerIndex);
if (progress.Token.IsCancellationRequested) return false;
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 20, 100, 30, 5, 200);
if (circles.Length >= minLength) break;
supportsMat.Dispose();
supportsMat = null;
}
if (supportsMat is null) return false;
if (supportsMat is null || /*firstSupportLayerIndex == 0 ||*/ _ignoreFirstLayers >= firstSupportLayerIndex) return false;
Mat patternMat = null;
if (DilateIterations > 0)
{
CvInvoke.Dilate(supportsMat, supportsMat,
CvInvoke.GetStructuringElement(ElementShape.Ellipse, new Size(3, 3), new Point(-1, -1)),
CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)),
new Point(-1, -1), DilateIterations, BorderType.Reflect101, new MCvScalar());
}
@@ -220,8 +238,8 @@ namespace UVtools.Core.Operations
break;
}
progress.Reset(ProgressAction, firstSupportLayerIndex);
Parallel.For(IgnoreFirstLayers, firstSupportLayerIndex, layerIndex =>
progress.Reset(ProgressAction, firstSupportLayerIndex - _ignoreFirstLayers);
Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using (Mat dst = SlicerFile[layerIndex].LayerMat)
@@ -238,7 +256,8 @@ namespace UVtools.Core.Operations
CvInvoke.Erode(mask, mask, kernel, anchor, operation.WallMargin, BorderType.Reflect101, new MCvScalar());
CvInvoke.Subtract(target, patternMat, target, mask);*/
CvInvoke.Erode(target, mask, kernel, anchor, WallMargin, BorderType.Reflect101, default);
CvInvoke.Erode(target, mask, kernel, anchor, WallMargin, BorderType.Reflect101,
default);
CvInvoke.Subtract(mask, supportsMat, mask);
CvInvoke.Subtract(target, patternMat, target, mask);
}
+1 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>2.6.0</Version>
<Version>2.6.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -8,7 +8,7 @@
<Grid
ColumnDefinitions="Auto,10,150,5,Auto"
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
>
<TextBlock Text="Relief type:" VerticalAlignment="Center"/>
@@ -18,107 +18,128 @@
SelectedItem="{Binding Operation.ReliefType}"
Items="{Binding Operation.RaftReliefItems}"/>
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="Ignore first:" VerticalAlignment="Center"/>
ToolTip.Tip="Defines the mask layer to use and ignore it white blobs on the raft.
&#x0a;Often this is the first layer where raft ends and supports starts.
&#x0a;Use '0' to auto detect the mask layer, otherwise if it fails or if you have multiple rafts with different heights
you must manually input the layer index of the last raft where it ends and supports starts."
Text="Mask layer index:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="2" Grid.Column="2"
Minimum="0"
Maximum="255"
Value="{Binding Operation.IgnoreFirstLayers}"/>
<TextBlock
Grid.Row="2" Grid.Column="4"
Text="layer(s)" VerticalAlignment="Center"/>
Maximum="{Binding SlicerFile.LastLayerIndex}"
Value="{Binding Operation.MaskLayerIndex}"/>
<StackPanel Grid.Row="2" Grid.Column="4"
Orientation="Horizontal" Spacing="5">
<Button Content="Use current layer" Command="{Binding UseCurrentLayerAsMask}" />
<TextBlock VerticalAlignment="Center"
Text="(0 = Auto detect)" />
</StackPanel>
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="Ignore first:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="4" Grid.Column="2"
Minimum="0"
Maximum="255"
Value="{Binding Operation.IgnoreFirstLayers}"/>
<TextBlock
Grid.Row="4" Grid.Column="4"
Text="layer(s)" VerticalAlignment="Center"/>
<TextBlock
Grid.Row="6"
Grid.Column="0"
IsVisible="{Binding !Operation.IsDecimate}"
Text="Pixel brightness:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="4" Grid.Column="2"
<NumericUpDown Grid.Row="6" Grid.Column="2"
Minimum="0"
Maximum="255"
IsVisible="{Binding !Operation.IsDecimate}"
Value="{Binding Operation.Brightness}"/>
<TextBlock
Grid.Row="4" Grid.Column="4"
Grid.Row="6" Grid.Column="4"
IsVisible="{Binding !Operation.IsDecimate}"
Text="{Binding Operation.BrightnessPercent, StringFormat=\{0:0.00\}%}" VerticalAlignment="Center"/>
<TextBlock
Grid.Row="6"
Grid.Row="8"
IsVisible="{Binding !Operation.IsDecimate}"
Text="Supports margin:" VerticalAlignment="Center"/>
<TextBlock
Grid.Row="6"
Grid.Row="8"
IsVisible="{Binding Operation.IsDecimate}"
ToolTip.Tip="Raft will be replaced by the present supports and then dilated by this value to thicken the supports and increase the adhesion.
&#x0a;Use large numbers with tiny supports for best adhesion."
Text="Dilate supports by:" VerticalAlignment="Center"/>
<NumericUpDown Grid.Row="6" Grid.Column="2"
<NumericUpDown Grid.Row="8" Grid.Column="2"
Minimum="0"
Maximum="255"
Value="{Binding Operation.DilateIterations}"/>
<TextBlock
Grid.Row="6" Grid.Column="4"
Grid.Row="8" Grid.Column="4"
Text="px" VerticalAlignment="Center"/>
<TextBlock
Grid.Row="8"
Grid.Row="10"
Text="Wall margin:" VerticalAlignment="Center"
IsVisible="{Binding !Operation.IsDecimate}"
/>
<NumericUpDown Grid.Row="8" Grid.Column="2"
<NumericUpDown Grid.Row="10" Grid.Column="2"
Minimum="1"
Maximum="255"
Value="{Binding Operation.WallMargin}"
IsVisible="{Binding !Operation.IsDecimate}"/>
<TextBlock
Grid.Row="8" Grid.Column="4"
Grid.Row="10" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding !Operation.IsDecimate}"/>
<TextBlock
Grid.Row="10"
Text="Hole diameter:" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"
/>
<NumericUpDown Grid.Row="10" Grid.Column="2"
Minimum="10"
Maximum="255"
Value="{Binding Operation.HoleDiameter}"
IsVisible="{Binding Operation.IsRelief}"/>
<TextBlock
Grid.Row="10" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"/>
<TextBlock
Grid.Row="12"
Text="Hole spacing:" VerticalAlignment="Center"
Text="Hole diameter:" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"
/>
<NumericUpDown Grid.Row="12" Grid.Column="2"
Minimum="10"
Maximum="255"
Value="{Binding Operation.HoleSpacing}"
Value="{Binding Operation.HoleDiameter}"
IsVisible="{Binding Operation.IsRelief}"/>
<TextBlock
Grid.Row="12" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"/>
<TextBlock
Grid.Row="14"
Text="Hole spacing:" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"
/>
<NumericUpDown Grid.Row="14" Grid.Column="2"
Minimum="10"
Maximum="255"
Value="{Binding Operation.HoleSpacing}"
IsVisible="{Binding Operation.IsRelief}"/>
<TextBlock
Grid.Row="14" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding Operation.IsRelief}"/>
</Grid>
</UserControl>
@@ -17,5 +17,10 @@ namespace UVtools.WPF.Controls.Tools
{
AvaloniaXamlLoader.Load(this);
}
public void UseCurrentLayerAsMask()
{
Operation.MaskLayerIndex = App.MainWindow.ActualLayer;
}
}
}
@@ -11,16 +11,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolRepairLayersControl()
{
InitializeComponent();
BaseOperation = new OperationRepairLayers(SlicerFile)
{
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
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,
};
BaseOperation = GetOperationRepairLayers();
}
private void InitializeComponent()
@@ -28,6 +19,17 @@ namespace UVtools.WPF.Controls.Tools
AvaloniaXamlLoader.Load(this);
}
public static OperationRepairLayers GetOperationRepairLayers() => new (App.SlicerFile)
{
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
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,
};
public override void Callback(ToolWindow.Callbacks callback)
{
switch (callback)
+4
View File
@@ -70,6 +70,10 @@ namespace UVtools.WPF
return;
}
if (clip?.Operation is null) return;
if (clip.Operation.HaveROI)
{
ROI = GetTransposedRectangle(clip.Operation.ROI);
}
var operation = await ShowRunOperation(clip.Operation.GetType(), clip.Operation);
if (operation is null)
{
+3 -3
View File
@@ -420,10 +420,10 @@ namespace UVtools.WPF
await ShowRunOperation(typeof(OperationRepairLayers));
}
public void OnClickDetectIssues()
public async Task OnClickDetectIssues()
{
if (!IsFileLoaded) return;
ComputeIssues(
await ComputeIssues(
GetIslandDetectionConfiguration(),
GetOverhangDetectionConfiguration(),
GetResinTrapDetectionConfiguration(),
@@ -431,7 +431,7 @@ namespace UVtools.WPF
Settings.Issues.ComputeEmptyLayers);
}
private async void ComputeIssues(IslandDetectionConfiguration islandConfig = null,
private async Task ComputeIssues(IslandDetectionConfiguration islandConfig = null,
OverhangDetectionConfiguration overhangConfig = null,
ResinTrapDetectionConfiguration resinTrapConfig = null,
TouchingBoundDetectionConfiguration touchingBoundConfig = null, bool emptyLayersConfig = true)
+8 -1
View File
@@ -1120,7 +1120,14 @@ namespace UVtools.WPF
if (Settings.Issues.ComputeIssuesOnLoad)
{
OnClickDetectIssues();
_firstTimeOnIssues = false;
await OnClickDetectIssues();
if (Issues.Count > 0)
{
SelectedTabItem = TabIssues;
if(Settings.Issues.AutoRepairIssuesOnLoad)
await RunOperation(ToolRepairLayersControl.GetOperationRepairLayers());
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>2.6.0</Version>
<Version>2.6.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+10 -3
View File
@@ -572,7 +572,8 @@ namespace UVtools.WPF
[Serializable]
public sealed class IssuesUserSettings : BindableBase
{
private bool _computeIssuesOnLoad = false;
private bool _computeIssuesOnLoad;
private bool _autoRepairIssuesOnLoad;
private bool _computeIssuesOnClickTab = true;
private bool _computeIslands = true;
private bool _computeOverhangs = true;
@@ -580,8 +581,8 @@ namespace UVtools.WPF
private bool _computeTouchingBounds = true;
private bool _computeEmptyLayers = true;
private bool _islandEnhancedDetection = true;
private bool _islandAllowDiagonalBonds = false;
private byte _islandBinaryThreshold = 0;
private bool _islandAllowDiagonalBonds;
private byte _islandBinaryThreshold;
private byte _islandRequiredAreaToProcessCheck = 1;
private byte _islandRequiredPixelBrightnessToProcessCheck = 1;
private byte _islandRequiredPixelsToSupport = 10;
@@ -606,6 +607,12 @@ namespace UVtools.WPF
set => RaiseAndSetIfChanged(ref _computeIssuesOnLoad, value);
}
public bool AutoRepairIssuesOnLoad
{
get => _autoRepairIssuesOnLoad;
set => RaiseAndSetIfChanged(ref _autoRepairIssuesOnLoad, value);
}
public bool ComputeIssuesOnClickTab
{
get => _computeIssuesOnClickTab;
+7 -2
View File
@@ -692,9 +692,14 @@
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Common"/>
<StackPanel Orientation="Horizontal" Spacing="20">
<CheckBox Margin="10,10" Content="Compute issues on file load"
IsChecked="{Binding Settings.Issues.ComputeIssuesOnLoad}"
/>
IsChecked="{Binding Settings.Issues.ComputeIssuesOnLoad}"/>
<CheckBox Margin="0,10" Content="Auto repair layers and issues on file load"
IsEnabled="{Binding Settings.Issues.ComputeIssuesOnLoad}"
IsChecked="{Binding Settings.Issues.AutoRepairIssuesOnLoad}"/>
</StackPanel>
<CheckBox Margin="10,0,10,0" Content="Auto compute issues when the Issues tab is opened for the first time"
IsChecked="{Binding Settings.Issues.ComputeIssuesOnClickTab}"
+1 -1
View File
@@ -535,7 +535,7 @@ namespace UVtools.WPF.Windows
{
if (operation.ProfileIsDefault)
{
_selectedProfileItem = operation;
SelectedProfileItem = operation;
break;
}
}