Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2022-04-06 20:17:48 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2022-04-06 20:17:48 +0300
commit331d37be7c8e3dfcbf08a4896fff1103b519d977 (patch)
tree8ad40f70b9e1943ea5c1fbf8a86f28e696e887a5 /UVtools.Core
parent7538d49acafb7667efd3f38fd84e7c5f7de8f241 (diff)
v3.2.2 - Birthday release 🎁 (2 years old) 🥳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
Diffstat (limited to 'UVtools.Core')
-rw-r--r--UVtools.Core/About.cs147
-rw-r--r--UVtools.Core/CoreSettings.cs8
-rw-r--r--UVtools.Core/EmguCV/EmguContours.cs68
-rw-r--r--UVtools.Core/Extensions/DateTimeExtensions.cs32
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs21
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs2
-rw-r--r--UVtools.Core/Layers/Layer.cs36
-rw-r--r--UVtools.Core/Operations/OperationLayerExportImage.cs2
-rw-r--r--UVtools.Core/Operations/OperationRaftRelief.cs143
-rw-r--r--UVtools.Core/Operations/OperationRepairLayers.cs19
-rw-r--r--UVtools.Core/RELEASE_NOTES.md12
-rw-r--r--UVtools.Core/UVtools.Core.csproj8
12 files changed, 415 insertions, 83 deletions
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";
- public const string DemoFile = "UVtools_demo_file.sl1";
+ #region Assembly properties
+ public static Assembly CoreAssembly => Assembly.GetExecutingAssembly();
- 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 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";
+
+ /// <summary>
+ /// Gets UVtools born date and time
+ /// </summary>
+ public static DateTime Born => new(2020, 4, 6, 20, 33, 14);
+
+ /// <summary>
+ /// Gets UVtools years
+ /// </summary>
+ public static int YearsOld => Born.Age();
+
+ /// <summary>
+ /// Return full age in a readable string
+ /// </summary>
+ 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();
+ }
+ }
+
+ /// <summary>
+ /// Checks if today is UVtools birthday
+ /// </summary>
+ 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 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
/// <summary>
/// Gets or sets the default compression type for layers
/// </summary>
- public static Layer.LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = Layer.LayerCompressionCodec.Png;
+ public static LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = LayerCompressionCodec.Png;
+
+ /// <summary>
+ /// <para>The average resin 1000ml bottle cost, to use when bottle cost is not available.</para>
+ /// <para>Use 0 to disable.</para>
+ /// </summary>
+ public static float AverageResin1000MlBottleCost = 60f;
/// <summary>
/// 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
/// </summary>
-public static class EmguContours
+public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
{
+ private readonly EmguContour[] _contours;
+
+ public IEnumerator<EmguContour> GetEnumerator()
+ {
+ return ((IEnumerable<EmguContour>)_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();
+ }
+ }
+
/// <summary>
/// Gets contours inside a point
/// </summary>
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);
}
+
+ /// <summary>
+ /// Calculates the age in years of the current System.DateTime object today.
+ /// </summary>
+ /// <param name="birthDate">The date of birth</param>
+ /// <returns>Age in years today. 0 is returned for a future date of birth.</returns>
+ public static int Age(this DateTime birthDate)
+ {
+ return Age(birthDate, DateTime.Today);
+ }
+
+ /// <summary>
+ /// Calculates the age in years of the current System.DateTime object on a later date.
+ /// </summary>
+ /// <param name="birthDate">The date of birth</param>
+ /// <param name="laterDate">The date on which to calculate the age.</param>
+ /// <returns>Age in years on a later day. 0 is returned as minimum.</returns>
+ 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<FileFor
}
/// <summary>
- /// Gets the starting material milliliters when the file loaded
+ /// Gets the starting material milliliters when the file was loaded
/// </summary>
public float StartingMaterialMilliliters { get; private set; }
@@ -2749,7 +2749,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
if (StartingMaterialMilliliters > 0 && StartingMaterialCost > 0)
{
- MaterialCost = _materialMilliliters * StartingMaterialCost / StartingMaterialMilliliters;
+ MaterialCost = GetMaterialCostPer(_materialMilliliters);
}
//RaisePropertyChanged(nameof(MaterialCost));
}
@@ -2768,7 +2768,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
}
/// <summary>
- /// Gets the starting material cost when the file loaded
+ /// Gets the starting material cost when the file was loaded
/// </summary>
public float StartingMaterialCost { get; private set; }
@@ -2782,6 +2782,13 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
}
/// <summary>
+ /// Gets the material cost per one milliliter
+ /// </summary>
+ public float MaterialMilliliterCost => StartingMaterialMilliliters > 0 ? StartingMaterialCost / StartingMaterialMilliliters : 0;
+
+ public float GetMaterialCostPer(float milliliters, byte roundDigits = 3) => (float)Math.Round(MaterialMilliliterCost * milliliters, roundDigits);
+
+ /// <summary>
/// Gets the material name
/// </summary>
public virtual string? MaterialName
@@ -3313,7 +3320,11 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
IsModified = false;
StartingMaterialMilliliters = MaterialMilliliters;
StartingMaterialCost = MaterialCost;
-
+ if (StartingMaterialCost <= 0)
+ {
+ StartingMaterialCost = StartingMaterialMilliliters * CoreSettings.AverageResin1000MlBottleCost / 1000f;
+ MaterialCost = StartingMaterialCost;
+ }
progress.ThrowIfCancellationRequested();
@@ -4629,7 +4640,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
/// </summary>
/// <param name="newCodec">The new method to change to</param>
/// <param name="progress"></param>
- 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
+
/// <summary>
/// Represent a Layer
/// </summary>
public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
{
- #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("<!--");
- tw.WriteLine($"# Generated by {About.Software} v{About.VersionStr} {About.Arch} @ {DateTime.UtcNow} #");
+ tw.WriteLine($"# Generated by {About.Software} v{About.VersionStr} {About.SystemBits} @ {DateTime.UtcNow} #");
tw.WriteLine($"File: {SlicerFile.Filename}");
tw.WriteLine($"{SlicerFile[layerIndex].ToString().Replace(", ", "\n")}");
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<Point>();
+
+ 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 @@
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Company>PTRTECH</Company>
- <Authors>Tiago Conceição</Authors>
+ <Authors>Tiago Conceição, sn4k3</Authors>
<RepositoryType>Git</RepositoryType>
<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>3.2.1</Version>
+ <Version>3.2.2</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -50,7 +50,7 @@
</None>
<None Include="..\README.md">
<Pack>True</Pack>
- <PackagePath>\</PackagePath>
+ <PackagePath></PackagePath>
</None>
<None Include="..\UVtools.CAD\UVtools.png">
<Pack>True</Pack>
@@ -74,7 +74,7 @@
</ItemGroup>
<Target Name="PreparePackageReleaseNotesFromFile" BeforeTargets="GenerateNuspec">
- <ReadLinesFromFile File="RELEASE_NOTES.md">
+ <ReadLinesFromFile File="..\RELEASE_NOTES.md">
<Output TaskParameter="Lines" ItemName="ReleaseNoteLines" />
</ReadLinesFromFile>
<PropertyGroup>