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 diff --git a/CREDITS.md b/CREDITS.md index 3cb1d24..e29767e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -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 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. + * 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. + * 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. + * 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 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 2.6.0 + 2.6.1 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 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 @@ @@ -18,107 +18,128 @@ SelectedItem="{Binding Operation.ReliefType}" Items="{Binding Operation.RaftReliefItems}"/> - + 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"/> - + Maximum="{Binding SlicerFile.LastLayerIndex}" + Value="{Binding Operation.MaskLayerIndex}"/> + + +