diff --git a/CHANGELOG.md b/CHANGELOG.md index 600081d..e9ffca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 06/04/2022 - v3.2.2 + +- **Settings:** + - (Add) Remove source file after automatic conversion (#444) + - (Add) Remove source file after manual conversion (#444) + - (Add) **Average resin bottle cost:** The average cost per one resin bottle of 1000ml. + Used to calculate the material cost when the file lacks that information. + Use 0 to disable this feature and only show the cost if file have that information. + If this value is changed, you need to reload the current file to update the cost. + - (Change) Move "Expand and show tool descriptions by default" to From `General` to `Tools` tab (Setting will reset to default) +- **File formats:** + - (Add) Property `StartingMaterialMilliliters`: Gets the starting material milliliters when the file was loaded + - (Add) Property `StartingMaterialCost`: Gets the starting material cost when the file was loaded + - (Add) Property `MaterialMilliliterCost`: Gets the material cost per one milliliter + - (Improvement) Update `MaterialCost` when `MaterialMilliliters` changes (#449) +- **Raft relief:** + - (Add) Linked lines: Remove the raft, keep supports and link them with lines + - (Improvement) Change the supports detection parameters to be more effective and precise on detect the starting layer + - (Fix) Brightness percentage not getting updated + - (Fix) Remove anti-aliased edges from Tabs +- (Improvement) Core: Minor clean-up +- (Fix) Issue repair error when 'Auto repair layers and issues on file load' is enabled (#446) +- (Fix) UI: Selecting a object with ROI when flip is verically, will cause 1px up-shift on the preview +- (Fix) macOS permission error due loss of attributes on the build script, WSL have bug with mv, using ln&rm instead + ## 02/04/2022 - v3.2.1 - **AnyCubic file format:** diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000..1ebb05c --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,23 @@ +- **Settings:** + - (Add) Remove source file after automatic conversion (#444) + - (Add) Remove source file after manual conversion (#444) + - (Add) **Average resin bottle cost:** The average cost per one resin bottle of 1000ml. + Used to calculate the material cost when the file lacks that information. + Use 0 to disable this feature and only show the cost if file have that information. + If this value is changed, you need to reload the current file to update the cost. + - (Change) Move "Expand and show tool descriptions by default" to From `General` to `Tools` tab (Setting will reset to default) +- **File formats:** + - (Add) Property `StartingMaterialMilliliters`: Gets the starting material milliliters when the file was loaded + - (Add) Property `StartingMaterialCost`: Gets the starting material cost when the file was loaded + - (Add) Property `MaterialMilliliterCost`: Gets the material cost per one milliliter + - (Improvement) Update `MaterialCost` when `MaterialMilliliters` changes (#449) +- **Raft relief:** + - (Add) Linked lines: Remove the raft, keep supports and link them with lines + - (Improvement) Change the supports detection parameters to be more effective and precise on detect the starting layer + - (Fix) Brightness percentage not getting updated + - (Fix) Remove anti-aliased edges from Tabs +- (Improvement) Core: Minor clean-up +- (Fix) Issue repair error when 'Auto repair layers and issues on file load' is enabled (#446) +- (Fix) UI: Selecting a object with ROI when flip is verically, will cause 1px up-shift on the preview +- (Fix) macOS permission error due loss of attributes on the build script, WSL have bug with mv, using ln&rm instead + diff --git a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj index 676fb95..a3f8722 100644 --- a/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj +++ b/UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj @@ -2,7 +2,7 @@ net6.0 - Tiago Conceição + Tiago Conceição, sn4k3 PTRTECH Copyright © 2020 PTRTECH LICENSE diff --git a/UVtools.Cmd/UVtools.Cmd.csproj b/UVtools.Cmd/UVtools.Cmd.csproj index 9240a90..0f7493f 100644 --- a/UVtools.Cmd/UVtools.Cmd.csproj +++ b/UVtools.Cmd/UVtools.Cmd.csproj @@ -6,7 +6,7 @@ UVtoolsCmd UVtools.ico 1.0.0 - Tiago Conceição + Tiago Conceição, sn4k3 PTRTECH LICENSE https://github.com/sn4k3/UVtools diff --git a/UVtools.Core/About.cs b/UVtools.Core/About.cs index db116bf..b41c27b 100644 --- a/UVtools.Core/About.cs +++ b/UVtools.Core/About.cs @@ -7,27 +7,162 @@ */ using System; +using System.IO; +using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using UVtools.Core.Extensions; +using UVtools.Core.FileFormats; namespace UVtools.Core; public static class About { public const string Software = "UVtools"; + public static Version Version => CoreAssembly.GetName().Version!; + public static string VersionStr => Version.ToString(3); + public static string VersionArch => $"{VersionStr} {RuntimeInformation.ProcessArchitecture}"; public static string SoftwareWithVersion => $"{Software} v{VersionStr}"; + public static string SoftwareWithVersionArch => $"{Software} v{VersionArch}"; public const string Author = "Tiago Conceição"; - public const string Company = "PTRTECH"; public const string License = "GNU Affero General Public License v3.0 (AGPL)"; public const string LicenseUrl = "https://github.com/sn4k3/UVtools/blob/master/LICENSE"; public const string Website = "https://github.com/sn4k3/UVtools"; public const string Donate = "https://paypal.me/SkillTournament"; public const string Sponsor = "https://github.com/sponsors/sn4k3"; + #region Assembly properties + public static Assembly CoreAssembly => Assembly.GetExecutingAssembly(); + + public static string AssemblyVersion => CoreAssembly.GetName().Version?.ToString()!; + + public static string AssemblyName => Assembly.GetExecutingAssembly().GetName().Name!; + + public static string AssemblyTitle + { + get + { + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + var titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != string.Empty) + { + return titleAttribute.Title; + } + } + return Path.GetFileNameWithoutExtension(CoreAssembly.Location); + } + } + + public static string AssemblyDescription + { + get + { + var attributes = CoreAssembly.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return string.Empty; + } + + var description = ((AssemblyDescriptionAttribute)attributes[0]).Description + $"{Environment.NewLine}{Environment.NewLine}Available File Formats:"; + + return FileFormat.AvailableFormats.SelectMany(fileFormat => fileFormat.FileExtensions).Aggregate(description, (current, fileExtension) => current + $"{Environment.NewLine}- {fileExtension.Description} (.{fileExtension.Extension})"); + } + } + + public static string AssemblyProduct + { + get + { + var attributes = CoreAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public static string AssemblyCopyright + { + get + { + var attributes = CoreAssembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public static string AssemblyCompany + { + get + { + var attributes = CoreAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + + public static string SystemBits => Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; + + /// + /// Gets UVtools born date and time + /// + public static DateTime Born => new(2020, 4, 6, 20, 33, 14); + + /// + /// Gets UVtools years + /// + public static int YearsOld => Born.Age(); + + /// + /// Return full age in a readable string + /// + public static string AgeStr + { + get + { + var sb = new StringBuilder($"{YearsOld} years"); + var born = Born; + var now = DateTime.Now; + + var months = 12 + now.Month - born.Month + (now.Day >= born.Day ? 0 : -1); + if (months >= 12) months -= 12; + if (months > 0) sb.Append($", {months} month(s)"); + + + + var days = 31 + now.Day - born.Day; + if (days >= 31) days -= 31; + if (days > 0) sb.Append($", {days} day(s)"); + + var hours = 12 + now.Hour - born.Hour; + if (hours >= 12) hours -= 12; + if (hours > 0) sb.Append($", {hours} hour(s)"); + + var minutes = 60 + now.Minute - born.Minute; + if (minutes >= 60) minutes -= 60; + if (minutes > 0) sb.Append($", {minutes} minutes(s)"); + + var seconds = 60 + now.Second - born.Second; + if (seconds >= 60) seconds -= 60; + if (seconds > 0) sb.Append($", {seconds} seconds(s)"); + + + return sb.ToString(); + } + } + + /// + /// Checks if today is UVtools birthday + /// + public static bool IsBirthday + { + get + { + var born = Born; + var now = DateTime.Now; + return born.Month == now.Month && born.Day == now.Day; + } + } + public const string DemoFile = "UVtools_demo_file.sl1"; - public static Version Version => CoreAssembly.GetName().Version!; - public static string VersionStr => Version.ToString(3); - public static string Arch => Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; - - public static Assembly CoreAssembly => Assembly.GetExecutingAssembly(); } \ No newline at end of file diff --git a/UVtools.Core/CoreSettings.cs b/UVtools.Core/CoreSettings.cs index f048af2..10246be 100644 --- a/UVtools.Core/CoreSettings.cs +++ b/UVtools.Core/CoreSettings.cs @@ -71,7 +71,13 @@ public static class CoreSettings /// /// Gets or sets the default compression type for layers /// - public static Layer.LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = Layer.LayerCompressionCodec.Png; + public static LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = LayerCompressionCodec.Png; + + /// + /// The average resin 1000ml bottle cost, to use when bottle cost is not available. + /// Use 0 to disable. + /// + public static float AverageResin1000MlBottleCost = 60f; /// /// Gets the default folder to save the settings diff --git a/UVtools.Core/EmguCV/EmguContours.cs b/UVtools.Core/EmguCV/EmguContours.cs index 958cfd8..d8c0639 100644 --- a/UVtools.Core/EmguCV/EmguContours.cs +++ b/UVtools.Core/EmguCV/EmguContours.cs @@ -6,10 +6,13 @@ * of this license document, but changing it is not allowed. */ +using System; +using System.Collections; using Emgu.CV; using Emgu.CV.Util; using System.Collections.Generic; using System.Drawing; +using System.Linq; using System.Threading.Tasks; using UVtools.Core.Extensions; @@ -19,8 +22,71 @@ namespace UVtools.Core.EmguCV; /// Utility methods for contour handling. /// Use only with Tree type /// -public static class EmguContours +public class EmguContours : IReadOnlyList, IDisposable { + private readonly EmguContour[] _contours; + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)_contours).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _contours.GetEnumerator(); + } + + public int Count => _contours.Length; + + + + public EmguContour this[int index] => _contours[index]; + + public EmguContours(VectorOfVectorOfPoint vectorOfPointsOfPoints) + { + _contours = new EmguContour[vectorOfPointsOfPoints.Size]; + for (int i = 0; i < _contours.Length; i++) + { + _contours[i] = new EmguContour(vectorOfPointsOfPoints[i]); + } + } + + public (int Index, EmguContour Contour, double Distance)[][] CalculateCentroidDistances(bool includeOwn = false, bool sortByDistance = true) + { + var items = new (int Index, EmguContour Contour, double Distance)[Count][]; + for (int i = 0; i < Count; i++) + { + items[i] = new (int Index, EmguContour Contour, double Distance)[Count-1]; + int count = 0; + for (int x = 0; x < Count; x++) + { + if (x == i) + { + if (includeOwn) + { + items[i][count] = new(x, this[x], 0); + } + continue; + } + items[i][count] = new (x, this[x], PointExtensions.FindLength(this[i].Centroid, this[x].Centroid)); + + count++; + } + + if(sortByDistance) items[i] = items[i].OrderBy(tuple => tuple.Distance).ToArray(); + } + + return items; + } + + public void Dispose() + { + foreach (var contour in _contours) + { + contour.Dispose(); + } + } + /// /// Gets contours inside a point /// diff --git a/UVtools.Core/Extensions/DateTimeExtensions.cs b/UVtools.Core/Extensions/DateTimeExtensions.cs index ebb132e..9186d5d 100644 --- a/UVtools.Core/Extensions/DateTimeExtensions.cs +++ b/UVtools.Core/Extensions/DateTimeExtensions.cs @@ -47,4 +47,36 @@ public static class DateTimeExtensions { return DateTime.UnixEpoch.AddMinutes(minutes); } + + /// + /// Calculates the age in years of the current System.DateTime object today. + /// + /// The date of birth + /// Age in years today. 0 is returned for a future date of birth. + public static int Age(this DateTime birthDate) + { + return Age(birthDate, DateTime.Today); + } + + /// + /// Calculates the age in years of the current System.DateTime object on a later date. + /// + /// The date of birth + /// The date on which to calculate the age. + /// Age in years on a later day. 0 is returned as minimum. + public static int Age(this DateTime birthDate, DateTime laterDate) + { + var age = laterDate.Year - birthDate.Year; + + if (age > 0) + { + age -= Convert.ToInt32(laterDate.Date < birthDate.Date.AddYears(age)); + } + else + { + age = 0; + } + + return age; + } } \ No newline at end of file diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 12ad9e4..6102aef 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -2725,7 +2725,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable - /// Gets the starting material milliliters when the file loaded + /// Gets the starting material milliliters when the file was loaded /// public float StartingMaterialMilliliters { get; private set; } @@ -2749,7 +2749,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable 0 && StartingMaterialCost > 0) { - MaterialCost = _materialMilliliters * StartingMaterialCost / StartingMaterialMilliliters; + MaterialCost = GetMaterialCostPer(_materialMilliliters); } //RaisePropertyChanged(nameof(MaterialCost)); } @@ -2768,7 +2768,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable - /// Gets the starting material cost when the file loaded + /// Gets the starting material cost when the file was loaded /// public float StartingMaterialCost { get; private set; } @@ -2781,6 +2781,13 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable RaiseAndSetIfChanged(ref _materialCost, (float)Math.Round(value, 3)); } + /// + /// Gets the material cost per one milliliter + /// + public float MaterialMilliliterCost => StartingMaterialMilliliters > 0 ? StartingMaterialCost / StartingMaterialMilliliters : 0; + + public float GetMaterialCostPer(float milliliters, byte roundDigits = 3) => (float)Math.Round(MaterialMilliliterCost * milliliters, roundDigits); + /// /// Gets the material name /// @@ -3313,7 +3320,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable /// The new method to change to /// - public void ChangeLayersCompressionMethod(Layer.LayerCompressionCodec newCodec, OperationProgress? progress = null) + public void ChangeLayersCompressionMethod(LayerCompressionCodec newCodec, OperationProgress? progress = null) { progress ??= new OperationProgress($"Changing layers compression codec to {newCodec}"); progress.Reset("Layers", LayerCount); diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs index 98b224f..1cacb93 100644 --- a/UVtools.Core/GCode/GCodeBuilder.cs +++ b/UVtools.Core/GCode/GCodeBuilder.cs @@ -309,7 +309,7 @@ public class GCodeBuilder : BindableBase public void AppendUVtools() { - AppendComment($"Generated by {About.Software} v{About.VersionStr} {About.Arch} @ {DateTime.UtcNow}"); + AppendComment($"Generated by {About.Software} v{About.VersionStr} {About.SystemBits} @ {DateTime.UtcNow}"); } public void AppendStartGCode() diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs index 2015ac7..4db7a9e 100644 --- a/UVtools.Core/Layers/Layer.cs +++ b/UVtools.Core/Layers/Layer.cs @@ -25,29 +25,29 @@ using UVtools.Core.Operations; namespace UVtools.Core.Layers; +#region Enums + +public enum LayerCompressionCodec : byte +{ + [Description("PNG: Compression=High Speed=Slow (Use with low RAM)")] + Png, + [Description("GZip: Compression=Medium Speed=Medium (Optimal)")] + GZip, + [Description("Deflate: Compression=Medium Speed=Medium (Optimal)")] + Deflate, + [Description("LZ4: Compression=Low Speed=Fast (Use with high RAM)")] + Lz4, + //[Description("None: Compression=None Speed=Fastest (Your soul belongs to RAM)")] + //None +} + +#endregion + /// /// Represent a Layer /// public class Layer : BindableBase, IEquatable, IEquatable { - #region Enums - - public enum LayerCompressionCodec : byte - { - [Description("PNG: Compression=High Speed=Slow (Use with low RAM)")] - Png, - [Description("GZip: Compression=Medium Speed=Medium (Optimal)")] - GZip, - [Description("Deflate: Compression=Medium Speed=Medium (Optimal)")] - Deflate, - [Description("LZ4: Compression=Low Speed=Fast (Use with high RAM)")] - Lz4, - //[Description("None: Compression=None Speed=Fastest (Your soul belongs to RAM)")] - //None - } - - #endregion - #region Constants public const byte HeightPrecision = 3; public const decimal HeightPrecisionIncrement = 0.001M; diff --git a/UVtools.Core/Operations/OperationLayerExportImage.cs b/UVtools.Core/Operations/OperationLayerExportImage.cs index 918c66b..5fbc7ca 100644 --- a/UVtools.Core/Operations/OperationLayerExportImage.cs +++ b/UVtools.Core/Operations/OperationLayerExportImage.cs @@ -216,7 +216,7 @@ public sealed class OperationLayerExportImage : Operation using TextWriter tw = new StreamWriter(fileFullPath); tw.WriteLine(""); diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs index 9725317..3b4ccef 100644 --- a/UVtools.Core/Operations/OperationRaftRelief.cs +++ b/UVtools.Core/Operations/OperationRaftRelief.cs @@ -30,6 +30,9 @@ public class OperationRaftRelief : Operation [Description("Relief: Drill raft to relief pressure and remove some mass")] Relief, + [Description("Linked lines: Remove the raft, keep supports and link them with lines")] + LinkedLines, + [Description("Dimming: Darkens the raft to cure it less")] Dimming, @@ -45,12 +48,15 @@ public class OperationRaftRelief : Operation private RaftReliefTypes _reliefType = RaftReliefTypes.Relief; private uint _maskLayerIndex; private byte _ignoreFirstLayers; - private byte _brightness; + private byte _lowBrightness; private byte _dilateIterations = 15;// +/- 1.5mm radius private byte _wallMargin = 40; // +/- 2mm private byte _holeDiameter = 80; // +/- 4mm private byte _holeSpacing = 40; // +/- 2mm - private byte _tabBrightness = byte.MaxValue; + private byte _linkedLineThickness = 26; + private byte _linkedMinimumLinks = 4; + private bool _linkedExternalSupports = true; + private byte _highBrightness = byte.MaxValue; private ushort _tabTriangleBase = 200; private ushort _tabTriangleHeight = 250; @@ -60,7 +66,7 @@ public class OperationRaftRelief : Operation public override string IconClass => "fas fa-bowling-ball"; public override string Title => "Raft relief"; public override string Description => - "Relief raft by adding holes in between to reduce FEP suction, save resin and easier to remove the prints."; + "Relief raft with a strategy to remove mass, reduce FEP suction, spare resin and easier to remove the prints."; public override string ConfirmationText => $"relief the raft"; @@ -70,8 +76,7 @@ public class OperationRaftRelief : Operation public override string ProgressAction => "Relieved layers"; - public override LayerRangeSelection StartLayerRangeSelection => - LayerRangeSelection.None; + public override LayerRangeSelection StartLayerRangeSelection => LayerRangeSelection.None; public override string? ValidateInternally() { @@ -80,7 +85,11 @@ public class OperationRaftRelief : Operation { if(_tabTriangleHeight == 0) sb.AppendLine("The tab height can't be 0"); if(_tabTriangleBase == 0) sb.AppendLine("The tab base can't be 0"); - if(_tabBrightness == 0) sb.AppendLine("The tab brightness can't be 0"); + if(_highBrightness == 0) sb.AppendLine("The tab brightness can't be 0"); + } + else if (_reliefType == RaftReliefTypes.LinkedLines) + { + if(_linkedLineThickness < 4) sb.AppendLine("The link thickness can't be less than 4"); } return sb.ToString(); @@ -88,7 +97,7 @@ public class OperationRaftRelief : Operation public override string ToString() { - var result = $"[{_reliefType}] [Mask layer: {_maskLayerIndex}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]"; + var result = $"[{_reliefType}] [Mask layer: {_maskLayerIndex}] [Ignore: {_ignoreFirstLayers}] [B: {_lowBrightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]"; if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}"; return result; } @@ -110,6 +119,7 @@ public class OperationRaftRelief : Operation { if(!RaiseAndSetIfChanged(ref _reliefType, value)) return; RaisePropertyChanged(nameof(IsRelief)); + RaisePropertyChanged(nameof(IsLinkedLines)); RaisePropertyChanged(nameof(IsDimming)); RaisePropertyChanged(nameof(IsDecimate)); RaisePropertyChanged(nameof(IsTabs)); @@ -118,6 +128,7 @@ public class OperationRaftRelief : Operation } public bool IsRelief => _reliefType == RaftReliefTypes.Relief; + public bool IsLinkedLines => _reliefType == RaftReliefTypes.LinkedLines; public bool IsDimming => _reliefType == RaftReliefTypes.Dimming; public bool IsDecimate => _reliefType == RaftReliefTypes.Decimate; public bool IsTabs => _reliefType == RaftReliefTypes.Tabs; @@ -134,17 +145,27 @@ public class OperationRaftRelief : Operation set => RaiseAndSetIfChanged(ref _ignoreFirstLayers, value); } - public byte Brightness + public byte LowBrightness { - get => _brightness; + get => _lowBrightness; set { - if (!RaiseAndSetIfChanged(ref _brightness, value)) return; + if (!RaiseAndSetIfChanged(ref _lowBrightness, value)) return; RaisePropertyChanged(nameof(BrightnessPercent)); } } - public decimal BrightnessPercent => Math.Round((_reliefType == RaftReliefTypes.Tabs ? _tabBrightness : _brightness) * 100 / 255M, 2); + public byte HighBrightness + { + get => _highBrightness; + set + { + if(!RaiseAndSetIfChanged(ref _highBrightness, Math.Max((byte) 1, value))) return; + RaisePropertyChanged(nameof(BrightnessPercent)); + } + } + + public decimal BrightnessPercent => Math.Round((_reliefType is RaftReliefTypes.LinkedLines or RaftReliefTypes.Tabs ? _highBrightness : _lowBrightness) * 100 / 255M, 2); public byte DilateIterations { @@ -170,10 +191,22 @@ public class OperationRaftRelief : Operation set => RaiseAndSetIfChanged(ref _holeSpacing, value); } - public byte TabBrightness + public byte LinkedLineThickness { - get => _tabBrightness; - set => RaiseAndSetIfChanged(ref _tabBrightness, Math.Max((byte)1, value)); + get => _linkedLineThickness; + set => RaiseAndSetIfChanged(ref _linkedLineThickness, Math.Max((byte)4, value)); + } + + public byte LinkedMinimumLinks + { + get => _linkedMinimumLinks; + set => RaiseAndSetIfChanged(ref _linkedMinimumLinks, value); + } + + public bool LinkedExternalSupports + { + get => _linkedExternalSupports; + set => RaiseAndSetIfChanged(ref _linkedExternalSupports, value); } public ushort TabTriangleBase @@ -198,7 +231,7 @@ public class OperationRaftRelief : Operation protected bool Equals(OperationRaftRelief other) { - 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 && _tabTriangleBase == other._tabTriangleBase && _tabTriangleHeight == other._tabTriangleHeight; + return _reliefType == other._reliefType && _maskLayerIndex == other._maskLayerIndex && _ignoreFirstLayers == other._ignoreFirstLayers && _lowBrightness == other._lowBrightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing && _linkedLineThickness == other._linkedLineThickness && _linkedMinimumLinks == other._linkedMinimumLinks && _linkedExternalSupports == other._linkedExternalSupports && _highBrightness == other._highBrightness && _tabTriangleBase == other._tabTriangleBase && _tabTriangleHeight == other._tabTriangleHeight; } public override bool Equals(object? obj) @@ -215,11 +248,15 @@ public class OperationRaftRelief : Operation hashCode.Add((int) _reliefType); hashCode.Add(_maskLayerIndex); hashCode.Add(_ignoreFirstLayers); - hashCode.Add(_brightness); + hashCode.Add(_lowBrightness); hashCode.Add(_dilateIterations); hashCode.Add(_wallMargin); hashCode.Add(_holeDiameter); hashCode.Add(_holeSpacing); + hashCode.Add(_linkedLineThickness); + hashCode.Add(_linkedMinimumLinks); + hashCode.Add(_linkedExternalSupports); + hashCode.Add(_highBrightness); hashCode.Add(_tabTriangleBase); hashCode.Add(_tabTriangleHeight); return hashCode.ToHashCode(); @@ -248,7 +285,8 @@ public class OperationRaftRelief : Operation { progress.ThrowIfCancellationRequested(); supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat); - var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200); + //var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 255); // OLD + var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.GradientAlt, 1.5, 25, 300, 0.80, 5, 255); if (circles.Length >= minSupportsRequired) break; supportsMat.Dispose(); @@ -263,20 +301,21 @@ public class OperationRaftRelief : Operation if (supportsMat is null || /*firstSupportLayerIndex == 0 ||*/ _ignoreFirstLayers >= firstSupportLayerIndex) return false; Mat? patternMat = null; + using var supportsMatOriginal = supportsMat.Clone(); - if (DilateIterations > 0) + if (_dilateIterations > 0) { CvInvoke.Dilate(supportsMat, supportsMat, CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)), - new Point(-1, -1), DilateIterations, BorderType.Reflect101, new MCvScalar()); + new Point(-1, -1), _dilateIterations, BorderType.Reflect101, new MCvScalar()); } - var color = new MCvScalar(255 - Brightness); + var color = new MCvScalar(255 - _lowBrightness); switch (ReliefType) { case RaftReliefTypes.Relief: - patternMat = EmguExtensions.InitMat(supportsMat.Size); + patternMat = supportsMat.NewBlank(); int shapeSize = HoleDiameter + HoleSpacing; using (var shape = EmguExtensions.InitMat(new Size(shapeSize, shapeSize))) { @@ -296,6 +335,61 @@ public class OperationRaftRelief : Operation } break; + case RaftReliefTypes.LinkedLines: + { + using var contours = new EmguContours(supportsMatOriginal.FindContours()); + using var supportsRedraw = _linkedExternalSupports ? supportsMatOriginal.Clone() : null; + using var supportsBrightnessCorrection = _highBrightness < byte.MaxValue ? supportsMat.Clone() : null; + + var centroidDistance = contours.CalculateCentroidDistances(false, true); + + var links = Math.Min(_linkedMinimumLinks, contours.Count-1); + var linkColor = new MCvScalar(_highBrightness); + + //var listPoints = new List(); + + for (int i = 0; i < contours.Count; i++) + { + if(contours[i].Centroid.IsAnyNegative()) continue; + //listPoints.Add(contours[i].Centroid); + + // Link all centroids to each other to calculate the external contour + if (_linkedExternalSupports) + { + for (int x = 0; x < contours.Count; x++) + { + if (x == i) continue; + if (contours[x].Centroid.IsAnyNegative()) continue; + CvInvoke.Line(supportsRedraw, contours[i].Centroid, contours[x].Centroid, linkColor, 4); + } + } + + for (int link = 0; link < links; link++) + { + CvInvoke.Line(supportsMat, contours[i].Centroid, centroidDistance[i][link].Contour.Centroid, linkColor, _linkedLineThickness); + } + } + + + //CvInvoke.Polylines(supportsMat, listPoints.ToArray(), false, linkColor, _linkedLineThickness); + // Link external centroids + if (_linkedExternalSupports) + { + using var externalContours = supportsRedraw!.FindContours(RetrType.External); + CvInvoke.DrawContours(supportsMat, externalContours, -1, linkColor, _linkedLineThickness); + } + + // Fix original supports brightness + if (_highBrightness < byte.MaxValue) + { + supportsBrightnessCorrection!.CopyTo(supportsMat, supportsBrightnessCorrection); + } + + // Close minor holes, round imperfections, stronger joints + CvInvoke.MorphologyEx(supportsMat, supportsMat, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, new Point(-1, -1), 1, BorderType.Reflect101, default); + + break; + } case RaftReliefTypes.Dimming: patternMat = EmguExtensions.InitMat(supportsMat.Size, color); break; @@ -324,6 +418,7 @@ public class OperationRaftRelief : Operation } break; + case RaftReliefTypes.LinkedLines: case RaftReliefTypes.Decimate: supportsMat.CopyTo(target); break; @@ -348,7 +443,7 @@ public class OperationRaftRelief : Operation new Point(-1, 0), // Left }; - var color = new MCvScalar(_tabBrightness); + var color = new MCvScalar(_highBrightness); for (var i = 0; i < contours.Size; i++) { @@ -419,9 +514,9 @@ public class OperationRaftRelief : Operation break; } - CvInvoke.Ellipse(mat, new Point(x, y), new Size(triangleBaseRadius, (int)(triangleBaseRadius / 1.5)), 90 * dir, 0, 180, EmguExtensions.WhiteColor, -1, LineType.AntiAlias); + CvInvoke.Ellipse(mat, new Point(x, y), new Size(triangleBaseRadius, (int)(triangleBaseRadius / 1.5)), 90 * dir, 0, 180, EmguExtensions.WhiteColor, -1); using var vec = new VectorOfPoint(polygon); - CvInvoke.FillPoly(mat, vec, color, LineType.AntiAlias); + CvInvoke.FillPoly(mat, vec, color); } } diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs index f1b5bec..f839390 100644 --- a/UVtools.Core/Operations/OperationRepairLayers.cs +++ b/UVtools.Core/Operations/OperationRepairLayers.cs @@ -159,8 +159,7 @@ public class OperationRepairLayers : Operation set => RaiseAndSetIfChanged(ref _noiseRemovalIterations, value); } - [XmlIgnore] - public IslandDetectionConfiguration? IslandDetectionConfig { get; set; } + [XmlIgnore] public IslandDetectionConfiguration IslandDetectionConfig { get; set; } = new(); #endregion @@ -205,8 +204,8 @@ public class OperationRepairLayers : Operation var issues = SlicerFile.IssueManager.GetVisible().ToList(); // Remove islands if (//Issues is not null - IslandDetectionConfig is not null - && _repairIslands + //IslandDetectionConfig is not null + _repairIslands && _removeIslandsBelowEqualPixelCount > 0 && _removeIslandsRecursiveIterations != 1) { @@ -282,7 +281,7 @@ public class OperationRepairLayers : Operation if (islandsToProcess.Count == 0) { - var islandConfig = IslandDetectionConfig?.Clone() ?? new IslandDetectionConfiguration(); + var islandConfig = IslandDetectionConfig.Clone(); var overhangConfig = new OverhangDetectionConfiguration(false); var touchingBoundsConfig = new TouchingBoundDetectionConfiguration(false); var printHeightConfig = new PrintHeightDetectionConfiguration(false); @@ -292,12 +291,12 @@ public class OperationRepairLayers : Operation islandConfig.Enabled = true; islandsToProcess = SlicerFile.IssueManager.DetectIssues(islandConfig, overhangConfig, resinTrapsConfig, touchingBoundsConfig, printHeightConfig, emptyLayersConfig, progress); - islandsToProcess?.RemoveAll(mainIssue => SlicerFile.IssueManager.IgnoredIssues.Contains(mainIssue)); + islandsToProcess.RemoveAll(mainIssue => SlicerFile.IssueManager.IgnoredIssues.Contains(mainIssue)); } - var issuesGroup = IssueManager.GetIssuesBy(islandsToProcess!, MainIssue.IssueType.Island).GroupBy(issue => issue.LayerIndex); + var issuesGroup = IssueManager.GetIssuesBy(islandsToProcess, MainIssue.IssueType.Island).GroupBy(issue => issue.LayerIndex); - progress.Reset("Attempt to attach islands below", (uint) islandsToProcess!.Count); + progress.Reset("Attempt to attach islands below", (uint) islandsToProcess.Count); var sync = new object(); Parallel.ForEach(issuesGroup, CoreSettings.GetParallelOptions(progress), group => { @@ -310,7 +309,7 @@ public class OperationRepairLayers : Operation for (var layerIndex = startLayer+1; layerIndex >= lowestPossibleLayer; layerIndex--) { - Debug.WriteLine(layerIndex); + //Debug.WriteLine(layerIndex); Monitor.Enter(SlicerFile[layerIndex].Mutex); matCache.Add((uint) layerIndex, SlicerFile[layerIndex].LayerMat); matCacheModified.Add((uint) layerIndex, false); @@ -319,7 +318,7 @@ public class OperationRepairLayers : Operation foreach (IssueOfPoints issue in group) { int foundAt = startLayer == 0 ? 0 : - 1; - var requiredSupportingPixels = Math.Max(1, issue.PixelsCount * IslandDetectionConfig!.RequiredPixelsToSupportMultiplier); + var requiredSupportingPixels = Math.Max(1, issue.PixelsCount * IslandDetectionConfig.RequiredPixelsToSupportMultiplier); for (var layerIndex = startLayer; layerIndex >= lowestPossibleLayer && foundAt < 0; layerIndex--) { diff --git a/UVtools.Core/RELEASE_NOTES.md b/UVtools.Core/RELEASE_NOTES.md deleted file mode 100644 index 5efb19e..0000000 --- a/UVtools.Core/RELEASE_NOTES.md +++ /dev/null @@ -1,12 +0,0 @@ -- **AnyCubic file format:** - - (Fix) Lift height and speed are not being correctly set on old version, keeping a constant value (#441) - - (Fix) Retract speed getter was not return value from TSMC if using version 516 -- **Tool - Infill:** - - (Add) Waves infill type - - (Add) Concentric infill type - - (Add) Gyroid infill type (#443) - - (Change) Increase the default spacing from 200px to 300px - - (Improvement) Fastter infill processing by use the model bounds -- (Add) `FormatSpeedUnit` property to file formats to get the speed unit which the file use internally -- (Fix) UI: ROI rectangle can overlap scroll bars while selecting - diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 5321ef9..69928f1 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -5,12 +5,12 @@ true LICENSE PTRTECH - Tiago Conceição + Tiago Conceição, sn4k3 Git https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 3.2.1 + 3.2.2 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 @@ -50,7 +50,7 @@ True - \ + True @@ -74,7 +74,7 @@ - + diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs index cc40285..fb18481 100644 --- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs +++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs @@ -2,7 +2,7 @@ - + diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index 7003486..61f3b8b 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -330,10 +330,10 @@ public class App : Application #endregion - #region Assembly Attribute Accessors + #region Assembly properties + public static Assembly WpfAssembly => Assembly.GetExecutingAssembly(); - public static Version Version => Assembly.GetExecutingAssembly().GetName().Version!; - public static string VersionStr => Version.ToString(3); + public static string AssemblyVersion => WpfAssembly.GetName().Version?.ToString()!; public static string AssemblyName => Assembly.GetExecutingAssembly().GetName().Name!; @@ -341,32 +341,30 @@ public class App : Application { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + var attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); if (attributes.Length > 0) { - AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; - if (titleAttribute.Title != "") + var titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != string.Empty) { return titleAttribute.Title; } } - return Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location); + return Path.GetFileNameWithoutExtension(WpfAssembly.Location); } } - public static string AssemblyVersion => Assembly.GetExecutingAssembly().GetName().Version?.ToString()!; - public static string AssemblyDescription { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + var attributes = WpfAssembly.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); if (attributes.Length == 0) { - return ""; + return string.Empty; } - string description = ((AssemblyDescriptionAttribute)attributes[0]).Description + $"{Environment.NewLine}{Environment.NewLine}Available File Formats:"; + var description = ((AssemblyDescriptionAttribute)attributes[0]).Description + $"{Environment.NewLine}{Environment.NewLine}Available File Formats:"; return FileFormat.AvailableFormats.SelectMany(fileFormat => fileFormat.FileExtensions).Aggregate(description, (current, fileExtension) => current + $"{Environment.NewLine}- {fileExtension.Description} (.{fileExtension.Extension})"); } @@ -376,12 +374,8 @@ public class App : Application { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyProductAttribute)attributes[0]).Product; + var attributes = WpfAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyProductAttribute)attributes[0]).Product; } } @@ -389,12 +383,8 @@ public class App : Application { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + var attributes = WpfAssembly.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyCopyrightAttribute)attributes[0]).Copyright; } } @@ -402,14 +392,9 @@ public class App : Application { get { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCompanyAttribute)attributes[0]).Company; + var attributes = WpfAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + return attributes.Length == 0 ? string.Empty : ((AssemblyCompanyAttribute)attributes[0]).Company; } } - #endregion } \ No newline at end of file diff --git a/UVtools.WPF/Assets/Styles/Styles.xaml b/UVtools.WPF/Assets/Styles/Styles.xaml index bcfcfbd..05e5ccf 100644 --- a/UVtools.WPF/Assets/Styles/Styles.xaml +++ b/UVtools.WPF/Assets/Styles/Styles.xaml @@ -248,6 +248,14 @@ + + @@ -162,7 +164,7 @@ IsReadOnly="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" - Text="{Binding Description}"/> + Text="{Binding Source={x:Static core:About.AssemblyDescription}}"/> diff --git a/UVtools.WPF/Windows/AboutWindow.axaml.cs b/UVtools.WPF/Windows/AboutWindow.axaml.cs index c0c3919..a4a8966 100644 --- a/UVtools.WPF/Windows/AboutWindow.axaml.cs +++ b/UVtools.WPF/Windows/AboutWindow.axaml.cs @@ -13,14 +13,8 @@ namespace UVtools.WPF.Windows; public class AboutWindow : WindowEx { - public string Software => About.Software; - public string Version => $"Version: {App.VersionStr} {RuntimeInformation.ProcessArchitecture}"; - public string Copyright => App.AssemblyCopyright; - public string Company => App.AssemblyCompany; - public string License => About.License; - public string Description => App.AssemblyDescription; - public string OpenCVBuildInformation => CvInvoke.BuildInformation; - public string LoadedAssemblies + public static string OpenCVBuildInformation => CvInvoke.BuildInformation; + public static string LoadedAssemblies { get { @@ -36,14 +30,14 @@ public class AboutWindow : WindowEx } } - public string OSDescription => $"{RuntimeInformation.OSDescription} {RuntimeInformation.OSArchitecture}"; + public static string OSDescription => $"{RuntimeInformation.OSDescription} {RuntimeInformation.OSArchitecture}"; - public string RuntimeDescription => RuntimeInformation.RuntimeIdentifier; + public static string RuntimeDescription => RuntimeInformation.RuntimeIdentifier; - public string FrameworkDescription => RuntimeInformation.FrameworkDescription; - public string AvaloniaUIDescription => typeof(AvaloniaObject).Assembly.GetName().Version.ToString(3); + public static string FrameworkDescription => RuntimeInformation.FrameworkDescription; + public static string AvaloniaUIDescription => typeof(AvaloniaObject).Assembly.GetName().Version!.ToString(3); - public string OpenCVVersion + public static string OpenCVVersion { get { @@ -56,11 +50,11 @@ public class AboutWindow : WindowEx } } - public string ProcessorName => SystemAware.GetProcessorName(); + public static string ProcessorName => SystemAware.GetProcessorName(); - public int ProcessorCount => Environment.ProcessorCount; + public static int ProcessorCount => Environment.ProcessorCount; - public string MemoryRAMDescription + public static string MemoryRAMDescription { get { @@ -85,7 +79,7 @@ public class AboutWindow : WindowEx get { var result = new StringBuilder(); - for (int i = 0; i < Screens.All.Count; i++) + for (var i = 0; i < Screens.All.Count; i++) { var onScreen = Screens.ScreenFromVisual(App.MainWindow); var screen = Screens.All[i]; @@ -116,7 +110,7 @@ public class AboutWindow : WindowEx private string GetEssentialInformation() { var message = new StringBuilder(); - message.AppendLine($"{About.SoftwareWithVersion}"); + message.AppendLine($"{About.SoftwareWithVersionArch}"); message.AppendLine($"Operative system: {OSDescription}"); message.AppendLine($"Processor: {ProcessorName}"); message.AppendLine($"Processor cores: {ProcessorCount}"); @@ -129,24 +123,25 @@ public class AboutWindow : WindowEx message.AppendLine("Sreens, resolution, working area, usable area:"); message.AppendLine(ScreensDescription); message.AppendLine(); - message.AppendLine($"Path: {App.ApplicationPath}"); + message.AppendLine($"Path: {App.ApplicationPath}"); + message.AppendLine($"Executable: {App.AppExecutable}"); return message.ToString(); } public void CopyEssentialInformation() { - Application.Current.Clipboard.SetTextAsync(GetEssentialInformation()); + Application.Current?.Clipboard?.SetTextAsync(GetEssentialInformation()); } public void CopyOpenCVInformationToClipboard() { - Application.Current.Clipboard.SetTextAsync(CvInvoke.BuildInformation); + Application.Current?.Clipboard?.SetTextAsync(CvInvoke.BuildInformation); } public void CopyLoadedAssembliesToClipboard() { - Application.Current.Clipboard.SetTextAsync(LoadedAssemblies); + Application.Current?.Clipboard?.SetTextAsync(LoadedAssemblies); } public async void CopyInformationToClipboard() @@ -156,6 +151,6 @@ public class AboutWindow : WindowEx message.AppendLine(CvInvoke.BuildInformation); message.AppendLine("Loaded Assemblies:"); message.AppendLine(LoadedAssemblies); - await Application.Current.Clipboard.SetTextAsync(message.ToString()); + await Application.Current?.Clipboard?.SetTextAsync(message.ToString())!; } } \ No newline at end of file diff --git a/UVtools.WPF/Windows/BenchmarkWindow.axaml.cs b/UVtools.WPF/Windows/BenchmarkWindow.axaml.cs index 46ead58..b7686e6 100644 --- a/UVtools.WPF/Windows/BenchmarkWindow.axaml.cs +++ b/UVtools.WPF/Windows/BenchmarkWindow.axaml.cs @@ -526,7 +526,7 @@ public class BenchmarkWindow : WindowEx public void TestPNGCompress(BenchmarkResolution resolution) { - Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Png); + Layer.CompressMat(Mats[resolution], LayerCompressionCodec.Png); } public void TestPNGDecompress(BenchmarkResolution resolution) @@ -534,7 +534,7 @@ public class BenchmarkWindow : WindowEx public void TestGZipCompress(BenchmarkResolution resolution) { - Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.GZip); + Layer.CompressMat(Mats[resolution], LayerCompressionCodec.GZip); } public void TestGZipDecompress(BenchmarkResolution resolution) @@ -542,7 +542,7 @@ public class BenchmarkWindow : WindowEx public void TestDeflateCompress(BenchmarkResolution resolution) { - Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Deflate); + Layer.CompressMat(Mats[resolution], LayerCompressionCodec.Deflate); } public void TestDeflateDecompress(BenchmarkResolution resolution) @@ -550,7 +550,7 @@ public class BenchmarkWindow : WindowEx public void TestLZ4Compress(BenchmarkResolution resolution) { - Layer.CompressMat(Mats[resolution], Layer.LayerCompressionCodec.Lz4); + Layer.CompressMat(Mats[resolution], LayerCompressionCodec.Lz4); } public void TestLZ4Decompress(BenchmarkResolution resolution) diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml index 9740d8b..e5b44ab 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -50,8 +50,8 @@ - + + + + + + @@ -188,10 +211,6 @@ Increment="1" Value="{Binding Settings.General.WindowsVerticalMargin}"/> - - @@ -1848,8 +1867,12 @@ - + + + diff --git a/UVtools.WPF/Windows/ToolWindow.axaml b/UVtools.WPF/Windows/ToolWindow.axaml index 3ad837b..4f9a59f 100644 --- a/UVtools.WPF/Windows/ToolWindow.axaml +++ b/UVtools.WPF/Windows/ToolWindow.axaml @@ -20,7 +20,7 @@ Padding="10" IsVisible="{Binding Description, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">