diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-03-04 02:48:55 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-03-04 02:48:55 +0300 |
commit | 93d038128098bb4ea91f3e8e97d89c30c6736b12 (patch) | |
tree | 8df2f6808388112e64d06294c90bbb112f1f7f3c | |
parent | 5fc722e203ad7dfbee29b8348f698f665b23aafc (diff) |
v2.6.1v2.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
26 files changed, 360 insertions, 79 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 3edddee..74f3b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -48,4 +48,5 @@ * Andrew Griffiths * Abhinav Sinha * Randy Savell -* Steve Clynes
\ No newline at end of file +* Steve Clynes +* Nicholas Taylor
\ No newline at end of file diff --git a/UVtools.Core/Extensions/TypeExtensions.cs b/UVtools.Core/Extensions/TypeExtensions.cs index 5b982dc..d46e2cf 100644 --- a/UVtools.Core/Extensions/TypeExtensions.cs +++ b/UVtools.Core/Extensions/TypeExtensions.cs @@ -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); } } diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index d682425..de24c76 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -1085,7 +1085,7 @@ namespace UVtools.Core.FileFormats get => HeaderSettings.ProjectorType > 0; set { - HeaderSettings.ProjectorType = value ? 1 : 0; + HeaderSettings.ProjectorType = value ? 1u : 0; RaisePropertyChanged(); } } diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs index 66c6f9c..b5ce0fb 100644 --- a/UVtools.Core/FileFormats/ChituboxZipFile.cs +++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs @@ -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(); } } diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs index 10f96a1..5f4c04f 100644 --- a/UVtools.Core/FileFormats/FDGFile.cs +++ b/UVtools.Core/FileFormats/FDGFile.cs @@ -757,7 +757,7 @@ namespace UVtools.Core.FileFormats get => HeaderSettings.ProjectorType > 0; set { - HeaderSettings.ProjectorType = value ? 1 : 0; + HeaderSettings.ProjectorType = value ? 1u : 0; RaisePropertyChanged(); } } diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs index bad77d1..ac28db9 100644 --- a/UVtools.Core/FileFormats/PHZFile.cs +++ b/UVtools.Core/FileFormats/PHZFile.cs @@ -775,7 +775,7 @@ namespace UVtools.Core.FileFormats get => HeaderSettings.ProjectorType > 0; set { - HeaderSettings.ProjectorType = value ? 1 : 0; + HeaderSettings.ProjectorType = value ? 1u : 0; RaisePropertyChanged(); } } diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs index 0a1af1c..27fb6fa 100644 --- a/UVtools.Core/FileFormats/PhotonSFile.cs +++ b/UVtools.Core/FileFormats/PhotonSFile.cs @@ -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(); diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index 7f5efd2..67f295f 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -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); diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs index 3cfbd5f..e33b4e7 100644 --- a/UVtools.Core/FileFormats/SL1File.cs +++ b/UVtools.Core/FileFormats/SL1File.cs @@ -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; } diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs index 2e0dea1..1dcb2fe 100644 --- a/UVtools.Core/FileFormats/ZCodeFile.cs +++ b/UVtools.Core/FileFormats/ZCodeFile.cs @@ -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"); diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs index 364d5be..d27c512 100644 --- a/UVtools.Core/Managers/ClipboardManager.cs +++ b/UVtools.Core/Managers/ClipboardManager.cs @@ -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; diff --git a/UVtools.Core/Managers/MaterialManager.cs b/UVtools.Core/Managers/MaterialManager.cs index bd0446b..461e7b3 100644 --- a/UVtools.Core/Managers/MaterialManager.cs +++ b/UVtools.Core/Managers/MaterialManager.cs @@ -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; diff --git a/UVtools.Core/Objects/GCodeBuilder.cs b/UVtools.Core/Objects/GCodeBuilder.cs new file mode 100644 index 0000000..bf11994 --- /dev/null +++ b/UVtools.Core/Objects/GCodeBuilder.cs @@ -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 +} diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs index d5634c6..c19bd91 100644 --- a/UVtools.Core/Operations/OperationRaftRelief.cs +++ b/UVtools.Core/Operations/OperationRaftRelief.cs @@ -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); } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 081889b..d180d78 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -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> diff --git a/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml b/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml index 7f1e337..b9d3020 100644 --- a/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml @@ -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,104 +18,125 @@ 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. +
Often this is the first layer where raft ends and supports starts. +
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="{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="2" Grid.Column="4" + Grid.Row="4" Grid.Column="4" Text="layer(s)" VerticalAlignment="Center"/> <TextBlock - Grid.Row="4" + 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. 
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" + Grid.Row="12" Text="Hole diameter:" VerticalAlignment="Center" IsVisible="{Binding Operation.IsRelief}" /> - <NumericUpDown Grid.Row="10" Grid.Column="2" + <NumericUpDown Grid.Row="12" Grid.Column="2" Minimum="10" Maximum="255" Value="{Binding Operation.HoleDiameter}" IsVisible="{Binding Operation.IsRelief}"/> <TextBlock - Grid.Row="10" Grid.Column="4" + Grid.Row="12" Grid.Column="4" Text="px" VerticalAlignment="Center" IsVisible="{Binding Operation.IsRelief}"/> <TextBlock - Grid.Row="12" + Grid.Row="14" Text="Hole spacing:" VerticalAlignment="Center" IsVisible="{Binding Operation.IsRelief}" /> - <NumericUpDown Grid.Row="12" Grid.Column="2" + <NumericUpDown Grid.Row="14" Grid.Column="2" Minimum="10" Maximum="255" Value="{Binding Operation.HoleSpacing}" IsVisible="{Binding Operation.IsRelief}"/> <TextBlock - Grid.Row="12" Grid.Column="4" + Grid.Row="14" Grid.Column="4" Text="px" VerticalAlignment="Center" IsVisible="{Binding Operation.IsRelief}"/> diff --git a/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml.cs index 58606b9..5d61417 100644 --- a/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolRaftReliefControl.axaml.cs @@ -17,5 +17,10 @@ namespace UVtools.WPF.Controls.Tools { AvaloniaXamlLoader.Load(this); } + + public void UseCurrentLayerAsMask() + { + Operation.MaskLayerIndex = App.MainWindow.ActualLayer; + } } } diff --git a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs index 14ed006..0cefc50 100644 --- a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs @@ -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) diff --git a/UVtools.WPF/MainWindow.Clipboard.cs b/UVtools.WPF/MainWindow.Clipboard.cs index bf8435d..7c536e5 100644 --- a/UVtools.WPF/MainWindow.Clipboard.cs +++ b/UVtools.WPF/MainWindow.Clipboard.cs @@ -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) { diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs index e1b2f76..87abea6 100644 --- a/UVtools.WPF/MainWindow.Issues.cs +++ b/UVtools.WPF/MainWindow.Issues.cs @@ -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) diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 8553b3b..ba6d224 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -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()); + } } } diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 7dc6c97..4356ed6 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -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'"> diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs index 53296cd..fd06445 100644 --- a/UVtools.WPF/UserSettings.cs +++ b/UVtools.WPF/UserSettings.cs @@ -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; diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml index 2d87662..86bfb5b 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -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}" diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs index e3936d3..14a1fb7 100644 --- a/UVtools.WPF/Windows/ToolWindow.axaml.cs +++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs @@ -535,7 +535,7 @@ namespace UVtools.WPF.Windows { if (operation.ProfileIsDefault) { - _selectedProfileItem = operation; + SelectedProfileItem = operation; break; } } |