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>2020-11-14 08:26:49 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2020-11-14 08:26:49 +0300
commit6d661821b522c6c8cc2c5b645693e8dd3dab76b4 (patch)
treeab5b947f47baf1a9c51bf84f6e365461c86d6215
parent3455f09c24daa26c12346a7e0cd451e6d947e8a7 (diff)
v1.3.0v1.3.0
* (Add) Changelog description to the new version update dialog * (Add) Tool - Infill: Proper configurable infills * (Add) Pixel area as "px²" to the layer bounds and ROI at layer bottom information bar * (Add) Pixel dimming: Alternate pattern every x layers * (Add) Pixel dimming: Lattice infill * (Add) Solidify: Required minimum/maximum area to solidify found areas (Default values will produce the old behaviour) * (Add) Issues: Allow to hide and ignore selected issues * (Add) Issue - Touch boundary: Allow to configure Left, Top, Right, Bottom margins in pixels, defaults to 5px (#94) * (Add) UVJ: Allow convert to another formats (#96) * (Add) Setters to some internal Core properties for more abstraction * (Improvement) Issue - Touch boundary: Only check boundary pixels if layer bounds overlap the set margins, otherwise, it will not waste cycles on check individual rows of pixels when not need to * (Change) Place .ctb extension show first than .cbddlp due more popular this days * (Change) Pixel dimming: Text "Borders" to "Walls" * (Change) Issues: Remove "Remove" text from button, keep only the icon to free up space * (Change) Ungroup extensions on "covert to" menu (#97) * (Fix) Issues: Detect button has a incorrect "save" icon * (Fix) SL1: Increase NumSlow property limit * (Fix) UVJ: not decoding nor showing preview images * (Fix) "Convert to" menu shows same options than previous loaded file when current file dont support convertions (#96) * (Fix) Hides "Convert to" menu when unable to convert to another format (#96) * (Fix) Program crash when demo file is disabled and tries to load a file in * (Fix) Rare crash on startup when mouse dont move in startup period and user types a key in meanwhile * (Fix) On a slow startup on progress window it will show "Decoded layers" as default text, changed to "Initializing"
-rw-r--r--CHANGELOG.md28
-rw-r--r--UVtools.Cmd/Program.cs2
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs1
-rw-r--r--UVtools.Core/Extensions/PointExtensions.cs24
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs6
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs53
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs53
-rw-r--r--UVtools.Core/FileFormats/FileExtension.cs8
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs25
-rw-r--r--UVtools.Core/FileFormats/IFileFormat.cs15
-rw-r--r--UVtools.Core/FileFormats/ImageFile.cs5
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs8
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs47
-rw-r--r--UVtools.Core/FileFormats/PWSFile.cs29
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs16
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs50
-rw-r--r--UVtools.Core/FileFormats/UVJFile.cs341
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs44
-rw-r--r--UVtools.Core/Layer/Layer.cs240
-rw-r--r--UVtools.Core/Layer/LayerIssue.cs73
-rw-r--r--UVtools.Core/Layer/LayerManager.cs146
-rw-r--r--UVtools.Core/Operations/OperationInfill.cs94
-rw-r--r--UVtools.Core/Operations/OperationPixelDimming.cs63
-rw-r--r--UVtools.Core/Operations/OperationProgress.cs2
-rw-r--r--UVtools.Core/Operations/OperationSolidify.cs32
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.cs8
-rw-r--r--UVtools.GUI/FrmMain.cs4
-rw-r--r--UVtools.WPF/Assets/Icons/eye-slash-16x16.pngbin0 -> 250 bytes
-rw-r--r--UVtools.WPF/Assets/Icons/stroopwafel-16x16.pngbin0 -> 249 bytes
-rw-r--r--UVtools.WPF/Controls/Helpers.cs8
-rw-r--r--UVtools.WPF/Controls/Tools/ToolInfillControl.axaml119
-rw-r--r--UVtools.WPF/Controls/Tools/ToolInfillControl.axaml.cs21
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml31
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs63
-rw-r--r--UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml32
-rw-r--r--UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml.cs20
-rw-r--r--UVtools.WPF/MainWindow.Issues.cs43
-rw-r--r--UVtools.WPF/MainWindow.LayerPreview.cs10
-rw-r--r--UVtools.WPF/MainWindow.axaml15
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs52
-rw-r--r--UVtools.WPF/Structures/AppVersionChecker.cs15
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj4
-rw-r--r--UVtools.WPF/UserSettings.cs83
-rw-r--r--UVtools.WPF/Windows/SettingsWindow.axaml160
-rw-r--r--UVtools.WPF/Windows/SettingsWindow.axaml.cs2
46 files changed, 1867 insertions, 230 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 582fc37..d1910c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,32 @@
# Changelog
-## 07/11/2020 - v1.2.1
+## 14/11/2020 - v1.3.0
+
+* (Add) Changelog description to the new version update dialog
+* (Add) Tool - Infill: Proper configurable infills
+* (Add) Pixel area as "px²" to the layer bounds and ROI at layer bottom information bar
+* (Add) Pixel dimming: Alternate pattern every x layers
+* (Add) Pixel dimming: Lattice infill
+* (Add) Solidify: Required minimum/maximum area to solidify found areas (Default values will produce the old behaviour)
+* (Add) Issues: Allow to hide and ignore selected issues
+* (Add) Issue - Touch boundary: Allow to configure Left, Top, Right, Bottom margins in pixels, defaults to 5px (#94)
+* (Add) UVJ: Allow convert to another formats (#96)
+* (Add) Setters to some internal Core properties for more abstraction
+* (Improvement) Issue - Touch boundary: Only check boundary pixels if layer bounds overlap the set margins, otherwise, it will not waste cycles on check individual rows of pixels when not need to
+* (Change) Place .ctb extension show first than .cbddlp due more popular this days
+* (Change) Pixel dimming: Text "Borders" to "Walls"
+* (Change) Issues: Remove "Remove" text from button, keep only the icon to free up space
+* (Change) Ungroup extensions on "covert to" menu (#97)
+* (Fix) Issues: Detect button has a incorrect "save" icon
+* (Fix) SL1: Increase NumSlow property limit
+* (Fix) UVJ: not decoding nor showing preview images
+* (Fix) "Convert to" menu shows same options than previous loaded file when current file dont support convertions (#96)
+* (Fix) Hides "Convert to" menu when unable to convert to another format (#96)
+* (Fix) Program crash when demo file is disabled and tries to load a file in
+* (Fix) Rare crash on startup when mouse dont move in startup period and user types a key in meanwhile
+* (Fix) On a slow startup on progress window it will show "Decoded layers" as default text, changed to "Initializing"
+
+## 08/11/2020 - v1.2.1
* (Add) IsModified property to current layer information, indicates if layer have unsaved changes
* (Add) Splitter between preview image and properties to resize the vertical space between that two controls
diff --git a/UVtools.Cmd/Program.cs b/UVtools.Cmd/Program.cs
index 744d463..e19e5ef 100644
--- a/UVtools.Cmd/Program.cs
+++ b/UVtools.Cmd/Program.cs
@@ -187,7 +187,7 @@ namespace UVtools.Cmd
{
Console.WriteLine("Computing Issues, please wait.");
sw.Restart();
- var issueList = fileFormat.LayerManager.GetAllIssues(null, null, null, null, true, progress);
+ var issueList = fileFormat.LayerManager.GetAllIssues(null, null, null, null, true, null, progress);
sw.Stop();
Console.WriteLine("Issues:");
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index 0791ec4..a1a2436 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -17,6 +17,7 @@ namespace UVtools.Core.Extensions
{
public static class EmguExtensions
{
+ public static readonly MCvScalar WhiteByte = new MCvScalar(255);
public static readonly MCvScalar BlackByte = new MCvScalar(0);
public static readonly MCvScalar Black3Byte = new MCvScalar(0, 0, 0);
public static readonly MCvScalar Transparent4Byte = new MCvScalar(0, 0, 0, 0);
diff --git a/UVtools.Core/Extensions/PointExtensions.cs b/UVtools.Core/Extensions/PointExtensions.cs
new file mode 100644
index 0000000..4703ca5
--- /dev/null
+++ b/UVtools.Core/Extensions/PointExtensions.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace UVtools.Core.Extensions
+{
+ public static class PointExtensions
+ {
+ public static Point Rotate(this Point point, double angleDegree, Point pivot = default)
+ {
+ double angle = angleDegree * Math.PI / 180;
+ double cos = Math.Cos(angle);
+ double sin = Math.Sin(angle);
+ int dx = point.X - pivot.X;
+ int dy = point.Y - pivot.Y;
+ double x = cos * dx - sin * dy + pivot.X;
+ double y = sin * dx + cos * dy + pivot.X;
+
+ Point rotated = new Point((int)Math.Round(x), (int)Math.Round(y));
+ return rotated;
+ }
+ }
+}
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index c57af3a..3dcbb25 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -126,7 +126,7 @@ namespace UVtools.Core.FileFormats
public PrinterType Printer { get; set; } = PrinterType.Unknown;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("cws", "NovaMaker CWS Files"),
+ new FileExtension("cws", "NovaMaker CWS"),
//new FileExtension("cws", "NovaMaker Bene Mono CWS Files", "Bene")
};
@@ -306,7 +306,7 @@ namespace UVtools.Core.FileFormats
}
- public override float PrintTime => 0;
+ /*public override float PrintTime => 0;
public override float UsedMaterial => 0;
@@ -314,7 +314,7 @@ namespace UVtools.Core.FileFormats
public override string MaterialName => string.Empty;
- public override string MachineName => "Unknown";
+ public override string MachineName => "Unknown";*/
public override object[] Configs => new object[] { SliceSettings, OutputSettings};
#endregion
diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index 1b5a19a..2561172 100644
--- a/UVtools.Core/FileFormats/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -957,17 +957,17 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("cbddlp", "Chitubox DLP Files"),
- new FileExtension("ctb", "Chitubox CTB Files"),
- new FileExtension("photon", "Chitubox Photon Files"),
+ new FileExtension("ctb", "Chitubox CTB"),
+ new FileExtension("cbddlp", "Chitubox CBDDLP"),
+ new FileExtension("photon", "Chitubox Photon"),
};
public override Type[] ConvertToFormats { get; } =
{
typeof(ChituboxFile),
typeof(ChituboxZipFile),
- typeof(PWSFile),
typeof(PHZFile),
+ typeof(PWSFile),
typeof(ZCodexFile),
typeof(CWSFile),
typeof(UVJFile),
@@ -1209,15 +1209,48 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => HeaderSettings.PrintTime;
+ public override float PrintTime
+ {
+ get => HeaderSettings.PrintTime;
+ set
+ {
+ HeaderSettings.PrintTime = (uint) value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float UsedMaterial
+ {
+ get => (float) Math.Round(PrintParametersSettings.VolumeMl, 2);
+ set
+ {
+ PrintParametersSettings.VolumeMl = (float) Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override float UsedMaterial => (float) Math.Round(PrintParametersSettings.VolumeMl, 2);
+ public override float MaterialCost
+ {
+ get => (float) Math.Round(PrintParametersSettings.CostDollars, 2);
+ set
+ {
+ PrintParametersSettings.CostDollars = (float) Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override float MaterialCost => (float) Math.Round(PrintParametersSettings.CostDollars, 2);
+ public override string MachineName
+ {
+ get => SlicerInfoSettings.MachineName;
+ set
+ {
+ SlicerInfoSettings.MachineName = value;
+ SlicerInfoSettings.MachineNameSize = (uint) SlicerInfoSettings.MachineName.Length;
+ RequireFullEncode = true;
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => "Unknown";
- public override string MachineName => SlicerInfoSettings.MachineName;
-
public override object[] Configs => new[] { (object)HeaderSettings, PrintParametersSettings, SlicerInfoSettings };
public bool IsCbddlpFile => HeaderSettings.Magic == MAGIC_CBDDLP;
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index 9e37497..bdb8fe5 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -93,7 +93,7 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("zip", "Chitubox Zip Files")
+ new FileExtension("zip", "Chitubox Zip")
};
public override Type[] ConvertToFormats { get; } = {
@@ -317,15 +317,56 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => HeaderSettings.EstimatedPrintTime;
+ public override float PrintTime
+ {
+ get => HeaderSettings.EstimatedPrintTime;
+ set
+ {
+ HeaderSettings.EstimatedPrintTime = value;
+ RaisePropertyChanged();
+ }
+ }
- public override float UsedMaterial => HeaderSettings.Weight;
+ public override float UsedMaterial
+ {
+ get => HeaderSettings.Weight;
+ set
+ {
+ HeaderSettings.Weight = value;
+ RaisePropertyChanged();
+ }
+ }
- public override float MaterialCost => HeaderSettings.Price;
+ public override float MaterialCost
+ {
+ get => HeaderSettings.Price;
+ set
+ {
+ HeaderSettings.Price = value;
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => HeaderSettings.Resin;
+ public override string MaterialName
+ {
+ get => HeaderSettings.Resin;
+ set
+ {
+ HeaderSettings.Resin = value;
+ RaisePropertyChanged();
+ }
+ }
- public override string MachineName => HeaderSettings.MachineType;
+ public override string MachineName
+ {
+ get => HeaderSettings.MachineType;
+ set
+ {
+ HeaderSettings.MachineType = value;
+ RequireFullEncode = true;
+ RaisePropertyChanged();
+ }
+ }
public override object[] Configs => new object[] { HeaderSettings };
diff --git a/UVtools.Core/FileFormats/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs
index 8f72fb5..4d15556 100644
--- a/UVtools.Core/FileFormats/FileExtension.cs
+++ b/UVtools.Core/FileFormats/FileExtension.cs
@@ -94,5 +94,13 @@ namespace UVtools.Core.FileFormats
public static IEqualityComparer<FileExtension> ExtensionComparer { get; } = new ExtensionEqualityComparer();
#endregion
+
+ #region Methods
+
+ public FileFormat GetFileFormat()
+ {
+ return FileFormat.FindByExtension(Extension);
+ }
+ #endregion
}
}
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index fe0f667..6f0b41c 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -7,15 +7,12 @@
*/
using System;
-using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
@@ -193,8 +190,8 @@ namespace UVtools.Core.FileFormats
new SL1File(), // Prusa SL1
new ChituboxZipFile(), // Zip
new ChituboxFile(), // cbddlp, cbt, photon
- new PhotonSFile(), // photons
new PHZFile(), // phz
+ new PhotonSFile(), // photons
new PWSFile(), // PSW
new ZCodexFile(), // zcodex
new CWSFile(), // CWS
@@ -330,6 +327,8 @@ namespace UVtools.Core.FileFormats
}
}
+ public bool SuppressRebuildProperties { get; set; }
+
public string FileFullPath { get; set; }
public abstract byte ThumbnailsCount { get; }
@@ -439,7 +438,7 @@ namespace UVtools.Core.FileFormats
public virtual byte LightPWM { get; set; } = DefaultLightPWM;
- public abstract float PrintTime { get; }
+ public virtual float PrintTime { get; set; }
//(header.numberOfLayers - header.bottomLayers) * (double) header.exposureTimeSeconds + (double) header.bottomLayers * (double) header.exposureBottomTimeSeconds + (double) header.offTimeSeconds * (double) header.numberOfLayers);
public virtual float PrintTimeOrComputed
{
@@ -455,13 +454,13 @@ namespace UVtools.Core.FileFormats
public float PrintTimeHours => (float) Math.Round(PrintTimeOrComputed / 3600, 2);
- public abstract float UsedMaterial { get; }
+ public virtual float UsedMaterial { get; set; }
- public abstract float MaterialCost { get; }
+ public virtual float MaterialCost { get; set; }
- public abstract string MaterialName { get; }
-
- public abstract string MachineName { get; }
+ public virtual string MaterialName { get; set; }
+
+ public virtual string MachineName { get; set; } = "Unknown";
public StringBuilder GCode { get; set; }
@@ -482,7 +481,7 @@ namespace UVtools.Core.FileFormats
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
- Debug.WriteLine(e.PropertyName);
+ if (SuppressRebuildProperties) return;
if (e.PropertyName == nameof(LayerCount))
{
if (this[LayerCount - 1] is null) return; // Not initialized
@@ -1084,9 +1083,7 @@ namespace UVtools.Core.FileFormats
public abstract bool Convert(Type to, string fileFullPath, OperationProgress progress = null);
public bool Convert(FileFormat to, string fileFullPath, OperationProgress progress = null)
- {
- return Convert(to.GetType(), fileFullPath, progress);
- }
+ => Convert(to.GetType(), fileFullPath, progress);
public byte ValidateAntiAliasingLevel()
{
diff --git a/UVtools.Core/FileFormats/IFileFormat.cs b/UVtools.Core/FileFormats/IFileFormat.cs
index 6329e9b..91893e1 100644
--- a/UVtools.Core/FileFormats/IFileFormat.cs
+++ b/UVtools.Core/FileFormats/IFileFormat.cs
@@ -57,6 +57,11 @@ namespace UVtools.Core.FileFormats
string FileFilterExtensionsOnly { get; }
/// <summary>
+ /// Gets or sets if change a global property should rebuild every layer data based on them
+ /// </summary>
+ bool SuppressRebuildProperties { get; set; }
+
+ /// <summary>
/// Gets the input file path loaded into this <see cref="FileFormat"/>
/// </summary>
string FileFullPath { get; set; }
@@ -216,7 +221,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the estimate print time in seconds
/// </summary>
- float PrintTime { get; }
+ float PrintTime { get; set; }
/// <summary>
/// Gets the estimate print time in seconds, if print doesn't support it it will be calculated
@@ -231,22 +236,22 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the estimate used material in ml
/// </summary>
- float UsedMaterial { get; }
+ float UsedMaterial { get; set; }
/// <summary>
/// Gets the estimate material cost
/// </summary>
- float MaterialCost { get; }
+ float MaterialCost { get; set; }
/// <summary>
/// Gets the material name
/// </summary>
- string MaterialName { get; }
+ string MaterialName { get; set; }
/// <summary>
/// Gets the machine name
/// </summary>
- string MachineName { get; }
+ string MachineName { get; set; }
/// <summary>
/// Gets the GCode, returns null if not supported
diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs
index 9517be0..3331d44 100644
--- a/UVtools.Core/FileFormats/ImageFile.cs
+++ b/UVtools.Core/FileFormats/ImageFile.cs
@@ -1,5 +1,4 @@
using System;
-using System.IO;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Operations;
@@ -59,11 +58,11 @@ namespace UVtools.Core.FileFormats
public override byte AntiAliasing { get; } = 1;
public override float LayerHeight { get; set; } = 0;
- public override float PrintTime { get; } = 0;
+ /*public override float PrintTime { get; } = 0;
public override float UsedMaterial { get; } = 0;
public override float MaterialCost { get; } = 0;
public override string MaterialName { get; } = null;
- public override string MachineName { get; } = null;
+ public override string MachineName { get; } = null;*/
public override object[] Configs { get; } = null;
private Mat ImageMat { get; set; }
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index 82ec363..cf98191 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -207,8 +207,8 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("lgs", "Longer Orange 10 Files"),
- new FileExtension("lgs30", "Longer Orange 30 Files"),
+ new FileExtension("lgs", "Longer Orange 10"),
+ new FileExtension("lgs30", "Longer Orange 30"),
};
public override Type[] ConvertToFormats { get; } =
@@ -378,14 +378,14 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => 0;
+ /*public override float PrintTime => 0;
public override float UsedMaterial => 0;
public override float MaterialCost => 0;
public override string MaterialName => "Unknown";
- public override string MachineName => null;
+ public override string MachineName => null;*/
public override object[] Configs => new object[] { HeaderSettings };
diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index bb28b78..4f72f58 100644
--- a/UVtools.Core/FileFormats/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -679,7 +679,7 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("phz", "Chitubox PHZ Files"),
+ new FileExtension("phz", "Chitubox PHZ"),
};
public override Type[] ConvertToFormats { get; } =
@@ -903,15 +903,48 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => HeaderSettings.PrintTime;
+ public override float PrintTime
+ {
+ get => HeaderSettings.PrintTime;
+ set
+ {
+ HeaderSettings.PrintTime = (uint) value;
+ RaisePropertyChanged();
+ }
+ }
- public override float UsedMaterial => (float) Math.Round(HeaderSettings.VolumeMl, 2);
+ public override float UsedMaterial
+ {
+ get => (float) Math.Round(HeaderSettings.VolumeMl, 2);
+ set
+ {
+ HeaderSettings.VolumeMl = (float)Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override float MaterialCost => (float) Math.Round(HeaderSettings.CostDollars, 2);
+ public override float MaterialCost
+ {
+ get => (float) Math.Round(HeaderSettings.CostDollars, 2);
+ set
+ {
+ HeaderSettings.CostDollars = (float)Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
+
+ public override string MachineName
+ {
+ get => HeaderSettings.MachineName;
+ set
+ {
+ HeaderSettings.MachineName = value;
+ HeaderSettings.MachineNameSize = (uint)HeaderSettings.MachineName.Length;
+ RequireFullEncode = true;
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => "Unknown";
- public override string MachineName => HeaderSettings.MachineName;
-
public override object[] Configs => new object[] { HeaderSettings };
#endregion
diff --git a/UVtools.Core/FileFormats/PWSFile.cs b/UVtools.Core/FileFormats/PWSFile.cs
index c055f63..7f27959 100644
--- a/UVtools.Core/FileFormats/PWSFile.cs
+++ b/UVtools.Core/FileFormats/PWSFile.cs
@@ -769,9 +769,9 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("pws", "Photon Workshop PWS Files"),
- new FileExtension("pw0", "Photon Workshop PW0 Files"),
- new FileExtension("pwmx", "Photon Workshop PWMX Files")
+ new FileExtension("pws", "Photon Workshop PWS"),
+ new FileExtension("pw0", "Photon Workshop PW0"),
+ new FileExtension("pwmx", "Photon Workshop PWMX")
};
public override Type[] ConvertToFormats { get; } =
@@ -931,13 +931,26 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => 0;
-
- public override float UsedMaterial => (float) Math.Round(HeaderSettings.Volume, 2);
+ public override float UsedMaterial
+ {
+ get => (float) Math.Round(HeaderSettings.Volume, 2);
+ set
+ {
+ HeaderSettings.Volume = (float)Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override float MaterialCost => (float) Math.Round(HeaderSettings.Price, 2);
+ public override float MaterialCost
+ {
+ get => (float) Math.Round(HeaderSettings.Price, 2);
+ set
+ {
+ HeaderSettings.Price = (float)Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => null;
public override string MachineName => LayerFormat == LayerRleFormat.PWS ? "AnyCubic Photon S" : "AnyCubic Photon Zero";
public override object[] Configs => new object[] { FileMarkSettings, HeaderSettings, PreviewSettings, LayersDefinition };
diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs
index 1d092ef..f4a671a 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -162,7 +162,7 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("photons", "Chitubox PhotonS Files"),
+ new FileExtension("photons", "Chitubox PhotonS"),
};
public override Type[] ConvertToFormats { get; } =
@@ -340,13 +340,17 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => 0;
- public override float UsedMaterial => (float) HeaderSettings.Volume;
-
- public override float MaterialCost => 0;
+ public override float UsedMaterial
+ {
+ get => (float) HeaderSettings.Volume;
+ set
+ {
+ HeaderSettings.Volume = Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => "Unknown";
public override string MachineName => "Anycubic Photon S";
public override object[] Configs => new object[] { HeaderSettings };
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 9584766..0034082 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -255,7 +255,7 @@ namespace UVtools.Core.FileFormats
public string MaterialName { get; set; }
public ushort NumFade { get; set; }
public ushort NumFast { get; set; }
- public byte NumSlow { get; set; }
+ public ushort NumSlow { get; set; }
public string PrintProfile { get; set; }
public float PrintTime { get; set; }
public string PrinterModel { get; set; }
@@ -289,15 +289,15 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("sl1", "PrusaSlicer SL1 Files")
+ new FileExtension("sl1", "PrusaSlicer SL1")
};
public override Type[] ConvertToFormats { get; } =
{
typeof(ChituboxFile),
typeof(ChituboxZipFile),
- typeof(PWSFile),
typeof(PHZFile),
+ typeof(PWSFile),
typeof(ZCodexFile),
typeof(CWSFile),
typeof(LGSFile),
@@ -407,15 +407,47 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => OutputConfigSettings.PrintTime;
+ public override float PrintTime
+ {
+ get => OutputConfigSettings.PrintTime;
+ set
+ {
+ OutputConfigSettings.PrintTime = value;
+ RaisePropertyChanged();
+ }
+ }
- public override float UsedMaterial => OutputConfigSettings.UsedMaterial;
+ public override float UsedMaterial
+ {
+ get => OutputConfigSettings.UsedMaterial;
+ set
+ {
+ OutputConfigSettings.UsedMaterial = value;
+ RaisePropertyChanged();
+ }
+ }
public override float MaterialCost => (float) Math.Round(OutputConfigSettings.UsedMaterial * MaterialSettings.BottleCost / MaterialSettings.BottleVolume, 2);
- public override string MaterialName => OutputConfigSettings.MaterialName;
+ public override string MaterialName
+ {
+ get => OutputConfigSettings.MaterialName;
+ set
+ {
+ OutputConfigSettings.MaterialName = value;
+ RaisePropertyChanged();
+ }
+ }
- public override string MachineName => PrinterSettings.PrinterSettingsId;
+ public override string MachineName
+ {
+ get => PrinterSettings.PrinterSettingsId;
+ set
+ {
+ PrinterSettings.PrinterSettingsId = value;
+ RaisePropertyChanged();
+ }
+ }
public override object[] Configs => new object[] { PrinterSettings, MaterialSettings, PrintSettings, OutputConfigSettings };
#endregion
@@ -569,14 +601,18 @@ namespace UVtools.Core.FileFormats
var fieldName = IniKeyToMemberName(keyValue[0]);
bool foundMember = false;
+
foreach (var obj in Configs)
{
var attribute = obj.GetType().GetProperty(fieldName);
if (ReferenceEquals(attribute, null)) continue;
Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
+
Statistics.ImplementedKeys.Add(keyValue[0]);
foundMember = true;
}
+
+
if (!foundMember)
{
diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs
index 7baa21a..c9235c0 100644
--- a/UVtools.Core/FileFormats/UVJFile.cs
+++ b/UVtools.Core/FileFormats/UVJFile.cs
@@ -130,10 +130,19 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("uvj", "UVJ Files")
+ new FileExtension("uvj", "UVJ")
};
- public override Type[] ConvertToFormats { get; } = null;
+ public override Type[] ConvertToFormats { get; } =
+ {
+ typeof(ChituboxFile),
+ typeof(ChituboxZipFile),
+ typeof(PHZFile),
+ typeof(PWSFile),
+ typeof(ZCodexFile),
+ typeof(CWSFile),
+ //typeof(LGSFile)
+ };
public override PrintParameterModifier[] PrintParameterModifiers { get; } = {
PrintParameterModifier.BottomLayerCount,
@@ -340,16 +349,6 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => 0;
-
- public override float UsedMaterial => 0;
-
- public override float MaterialCost => 0;
-
- public override string MaterialName => null;
-
- public override string MachineName => null;
-
public override object[] Configs => new[] {(object) JsonSettings.Properties.Size, JsonSettings.Properties.Size.Millimeter, JsonSettings.Properties.Bottom, JsonSettings.Properties.Exposure};
#endregion
@@ -456,7 +455,9 @@ namespace UVtools.Core.FileFormats
{
using (Stream stream = entry.Open())
{
- CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
+ Mat image = new Mat();
+ CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
+ Thumbnails[0] = image;
stream.Close();
}
}
@@ -466,7 +467,9 @@ namespace UVtools.Core.FileFormats
{
using (Stream stream = entry.Open())
{
- CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[1]);
+ Mat image = new Mat();
+ CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
+ Thumbnails[1] = image;
stream.Close();
}
}
@@ -523,7 +526,315 @@ namespace UVtools.Core.FileFormats
public override bool Convert(Type to, string fileFullPath, OperationProgress progress = null)
{
- throw new NotImplementedException();
+ if (to == typeof(ChituboxFile))
+ {
+ ChituboxFile file = new ChituboxFile
+ {
+
+ LayerManager = LayerManager,
+ HeaderSettings
+ =
+ {
+ BedSizeX = DisplayWidth,
+ BedSizeY = DisplayHeight,
+ BedSizeZ = TotalHeight,
+ OverallHeightMilimeter = TotalHeight,
+ BottomExposureSeconds = BottomExposureTime,
+ BottomLayersCount = BottomLayerCount,
+ BottomLightPWM = BottomLightPWM,
+ LayerCount = LayerCount,
+ LayerExposureSeconds = ExposureTime,
+ LayerHeightMilimeter = LayerHeight,
+ LayerOffTime = LayerOffTime,
+ LightPWM = LightPWM,
+ PrintTime = (uint) PrintTimeOrComputed,
+ ProjectorType = 0,
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ AntiAliasLevel = ValidateAntiAliasingLevel()
+ },
+ PrintParametersSettings =
+ {
+ BottomLayerCount = BottomLayerCount,
+ BottomLiftHeight = BottomLiftHeight,
+ BottomLiftSpeed = BottomLiftSpeed,
+ BottomLightOffDelay = BottomLayerOffTime,
+ CostDollars = MaterialCost,
+ LiftHeight = LiftHeight,
+ LiftSpeed = LiftSpeed,
+ LightOffDelay = LayerOffTime,
+ RetractSpeed = RetractSpeed,
+ VolumeMl = UsedMaterial,
+ WeightG = 0
+ },
+ SlicerInfoSettings = { MachineName = MachineName, MachineNameSize = (uint)MachineName.Length }
+ };
+
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
+ if (to == typeof(ChituboxZipFile))
+ {
+ ChituboxZipFile file = new ChituboxZipFile
+ {
+ LayerManager = LayerManager,
+ HeaderSettings =
+ {
+ Filename = Path.GetFileName(FileFullPath),
+
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ MachineX = DisplayWidth,
+ MachineY = DisplayHeight,
+ MachineZ = TotalHeight,
+ MachineType = MachineName,
+ ProjectType = "Normal",
+
+ Resin = MaterialName,
+ Price = MaterialCost,
+ Weight = 0,
+ Volume = UsedMaterial,
+ Mirror = 0,
+
+
+ BottomLiftHeight = BottomLiftHeight,
+ LiftHeight = LiftHeight,
+ BottomLiftSpeed = BottomLiftSpeed,
+ LiftSpeed = LiftSpeed,
+ RetractSpeed = RetractSpeed,
+ BottomLayCount = BottomLayerCount,
+ BottomLayerCount = BottomLayerCount,
+ BottomLightOffTime = BottomLayerOffTime,
+ LightOffTime = LayerOffTime,
+ BottomLayExposureTime = BottomExposureTime,
+ BottomLayerExposureTime = BottomExposureTime,
+ LayerExposureTime = ExposureTime,
+ LayerHeight = LayerHeight,
+ LayerCount = LayerCount,
+ AntiAliasing = ValidateAntiAliasingLevel(),
+ BottomLightPWM = BottomLightPWM,
+ LightPWM = LightPWM,
+
+ EstimatedPrintTime = PrintTime
+ },
+ };
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
+ if (to == typeof(PHZFile))
+ {
+ PHZFile file = new PHZFile
+ {
+ LayerManager = LayerManager,
+ HeaderSettings =
+ {
+ Version = 2,
+ BedSizeX = DisplayWidth,
+ BedSizeY = DisplayHeight,
+ BedSizeZ = TotalHeight,
+ OverallHeightMilimeter = TotalHeight,
+ BottomExposureSeconds = BottomExposureTime,
+ BottomLayersCount = BottomLayerCount,
+ BottomLightPWM = BottomLightPWM,
+ LayerCount = LayerCount,
+ LayerExposureSeconds = ExposureTime,
+ LayerHeightMilimeter = LayerHeight,
+ LayerOffTime = LayerOffTime,
+ LightPWM = LightPWM,
+ PrintTime = (uint) PrintTimeOrComputed,
+ ProjectorType = 0,
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ BottomLayerCount = BottomLayerCount,
+ BottomLiftHeight = BottomLiftHeight,
+ BottomLiftSpeed = BottomLiftSpeed,
+ BottomLightOffDelay = BottomLayerOffTime,
+ CostDollars = MaterialCost,
+ LiftHeight = LiftHeight,
+ LiftSpeed = LiftSpeed,
+ RetractSpeed = RetractSpeed,
+ VolumeMl = UsedMaterial,
+ AntiAliasLevelInfo = ValidateAntiAliasingLevel(),
+ WeightG = 0,
+ MachineName = MachineName,
+ MachineNameSize = (uint)MachineName.Length
+ }
+ };
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
+ if (to == typeof(PWSFile))
+ {
+ PWSFile file = new PWSFile
+ {
+ LayerManager = LayerManager,
+ HeaderSettings =
+ {
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ LayerHeight = LayerHeight,
+ LayerExposureTime = ExposureTime,
+ LiftHeight = LiftHeight,
+ LiftSpeed = LiftSpeed / 60,
+ RetractSpeed = RetractSpeed / 60,
+ LayerOffTime = LayerOffTime,
+ BottomLayersCount = BottomLayerCount,
+ BottomExposureSeconds = BottomExposureTime,
+ Price = MaterialCost,
+ Volume = UsedMaterial,
+ Weight = 0,
+ AntiAliasing = ValidateAntiAliasingLevel()
+ }
+ };
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
+ if (to == typeof(ZCodexFile))
+ {
+ TimeSpan ts = new TimeSpan(0, 0, (int)PrintTime);
+ ZCodexFile file = new ZCodexFile
+ {
+ ResinMetadataSettings = new ZCodexFile.ResinMetadata
+ {
+ MaterialId = 2,
+ Material = MaterialName,
+ AdditionalSupportLayerTime = 0,
+ BottomLayersNumber = BottomLayerCount,
+ BottomLayersTime = (uint)(BottomExposureTime * 1000),
+ LayerTime = (uint)(ExposureTime * 1000),
+ DisableSettingsChanges = false,
+ LayerThickness = LayerHeight,
+ PrintTime = (uint)PrintTime,
+ TotalLayersCount = LayerCount,
+ TotalMaterialVolumeUsed = UsedMaterial,
+ TotalMaterialWeightUsed = UsedMaterial,
+ },
+ UserSettings = new ZCodexFile.UserSettingsdata
+ {
+ Printer = MachineName,
+ BottomLayersCount = BottomLayerCount,
+ PrintTime = $"{ts.Hours}h {ts.Minutes}m",
+ LayerExposureTime = (uint)(ExposureTime * 1000),
+ BottomLayerExposureTime = (uint)(BottomExposureTime * 1000),
+ MaterialId = 2,
+ LayerThickness = $"{LayerHeight} mm",
+ AntiAliasing = (byte)(AntiAliasing > 1 ? 1 : 0),
+ CrossSupportEnabled = 1,
+ ExposureOffTime = (uint)LayerOffTime,
+ HollowEnabled = 0,
+ HollowThickness = 0,
+ InfillDensity = 0,
+ IsAdvanced = 0,
+ MaterialType = MaterialName,
+ MaterialVolume = UsedMaterial,
+ MaxLayer = LayerCount - 1,
+ ModelLiftEnabled = 0,
+ ModelLiftHeight = 0,
+ RaftEnabled = 0,
+ RaftHeight = 0,
+ RaftOffset = 0,
+ SupportAdditionalExposureEnabled = 0,
+ SupportAdditionalExposureTime = 0,
+ XCorrection = 0,
+ YCorrection = 0,
+ ZLiftDistance = LiftHeight,
+ ZLiftFeedRate = LiftSpeed,
+ ZLiftRetractRate = RetractSpeed,
+ },
+ ZCodeMetadataSettings = new ZCodexFile.ZCodeMetadata
+ {
+ PrintTime = (uint)PrintTime,
+ PrinterName = MachineName,
+ Materials = new List<ZCodexFile.ZCodeMetadata.MaterialsData>
+ {
+ new ZCodexFile.ZCodeMetadata.MaterialsData
+ {
+ Name = MaterialName,
+ ExtruderType = "MAIN",
+ Id = 0,
+ Usage = 0,
+ Temperature = 0
+ }
+ },
+ },
+ LayerManager = LayerManager
+ };
+
+ float usedMaterial = UsedMaterial / LayerCount;
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ file.ResinMetadataSettings.Layers.Add(new ZCodexFile.ResinMetadata.LayerData
+ {
+ Layer = layerIndex,
+ UsedMaterialVolume = usedMaterial
+ });
+ }
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+ return true;
+ }
+
+ if (to == typeof(CWSFile))
+ {
+ CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile));
+ CWSFile file = new CWSFile { LayerManager = LayerManager };
+
+ file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = (float)Math.Round(ResolutionX / DisplayWidth, 3);
+ file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float)Math.Round(ResolutionY / DisplayHeight, 3);
+ file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX;
+ file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY;
+ file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight;
+ file.SliceSettings.LayersNum = file.OutputSettings.LayersNum = LayerCount;
+ file.SliceSettings.HeadLayersNum = file.OutputSettings.NumberBottomLayers = BottomLayerCount;
+ file.SliceSettings.LayersExpoMs = file.OutputSettings.LayerTime = (uint)ExposureTime * 1000;
+ file.SliceSettings.HeadLayersExpoMs = file.OutputSettings.BottomLayersTime = (uint)BottomExposureTime * 1000;
+ file.SliceSettings.WaitBeforeExpoMs = (uint)(LayerOffTime * 1000);
+ file.SliceSettings.LiftDistance = file.OutputSettings.LiftDistance = LiftHeight;
+ file.SliceSettings.LiftUpSpeed = file.OutputSettings.ZLiftFeedRate = LiftSpeed;
+ file.SliceSettings.LiftDownSpeed = file.OutputSettings.ZLiftRetractRate = RetractSpeed;
+ file.SliceSettings.LiftWhenFinished = defaultFormat.SliceSettings.LiftWhenFinished;
+
+ file.OutputSettings.BlankingLayerTime = (uint)(LayerOffTime * 1000);
+ //file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.OutlineWidthInset = 0;
+ //file.OutputSettings.OutlineWidthOutset = 0;
+ file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.TiltValue = 0;
+ //file.OutputSettings.UseMainliftGCodeTab = false;
+ //file.OutputSettings.AntiAliasing = 0;
+ //file.OutputSettings.AntiAliasingValue = 0;
+ file.OutputSettings.FlipX = false;
+ file.OutputSettings.FlipY = file.OutputSettings.FlipX;
+ file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel();
+ file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1;
+
+ file.Printer = MachineName.Contains("Bene4 Mono") ||
+ FileFullPath.Contains("bene4_mono")
+ ? CWSFile.PrinterType.BeneMono : CWSFile.PrinterType.Elfin;
+
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
+ return false;
}
#endregion
diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index 682d3f0..944a694 100644
--- a/UVtools.Core/FileFormats/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -148,7 +148,7 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Archive;
public override FileExtension[] FileExtensions { get; } = {
- new FileExtension("zcodex", "Z-Suite ZCodex Files")
+ new FileExtension("zcodex", "Z-Suite ZCodex")
};
public override Type[] ConvertToFormats { get; } = null;
@@ -281,15 +281,45 @@ namespace UVtools.Core.FileFormats
}
}
- public override float PrintTime => ResinMetadataSettings.PrintTime;
-
- public override float UsedMaterial => ResinMetadataSettings.TotalMaterialVolumeUsed;
+ public override float PrintTime
+ {
+ get => ResinMetadataSettings.PrintTime;
+ set
+ {
+ ResinMetadataSettings.PrintTime = (uint) value;
+ RaisePropertyChanged();
+ }
+ }
- public override float MaterialCost => 0;
+ public override float UsedMaterial
+ {
+ get => ResinMetadataSettings.TotalMaterialVolumeUsed;
+ set
+ {
+ ResinMetadataSettings.TotalMaterialVolumeUsed = (float) Math.Round(value, 2);
+ RaisePropertyChanged();
+ }
+ }
- public override string MaterialName => ResinMetadataSettings.Material;
+ public override string MaterialName
+ {
+ get => ResinMetadataSettings.Material;
+ set
+ {
+ ResinMetadataSettings.Material = value;
+ RaisePropertyChanged();
+ }
+ }
- public override string MachineName => ZCodeMetadataSettings.PrinterName;
+ public override string MachineName
+ {
+ get => ZCodeMetadataSettings.PrinterName;
+ set
+ {
+ ZCodeMetadataSettings.PrinterName = value;
+ RaisePropertyChanged();
+ }
+ }
public override object[] Configs => new[] {(object) ResinMetadataSettings, UserSettings, ZCodeMetadataSettings};
#endregion
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index cb5bf2b..d75b2bd 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -730,6 +730,20 @@ namespace UVtools.Core
for (int i = 0; i < contours.Size; i++)
{
if ((int)arr.GetValue(0, i, 2) != -1 || (int)arr.GetValue(0, i, 3) == -1) continue;
+ if (operation.MinimumArea > 1)
+ {
+ var rectangle = CvInvoke.BoundingRectangle(contours[i]);
+ if (operation.AreaCheckType == OperationSolidify.AreaCheckTypes.More)
+ {
+ if (rectangle.GetArea() < operation.MinimumArea) continue;
+ }
+ else
+ {
+ if (rectangle.GetArea() > operation.MinimumArea) continue;
+ }
+
+ }
+
CvInvoke.DrawContours(target, contours, i, new MCvScalar(255), -1);
}
}
@@ -751,7 +765,7 @@ namespace UVtools.Core
}
}
- public void MutatePixelDimming(Matrix<byte> evenPattern = null, Matrix<byte> oddPattern = null, ushort borderSize = 5)
+ /*public void MutatePixelDimming(Matrix<byte> evenPattern = null, Matrix<byte> oddPattern = null, ushort borderSize = 5)
{
var anchor = new Point(-1, -1);
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
@@ -808,16 +822,16 @@ namespace UVtools.Core
}
}
}
- }
+ }*/
- public void PixelDimming(OperationPixelDimming operation, Mat evenPatternMask, Mat oddPatternMask = null)
+ public void PixelDimming(OperationPixelDimming operation, Mat patternMask, Mat alternatePatternMask = null)
{
var anchor = new Point(-1, -1);
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
- if (ReferenceEquals(oddPatternMask, null))
+ if (ReferenceEquals(alternatePatternMask, null))
{
- oddPatternMask = evenPatternMask;
+ alternatePatternMask = patternMask;
}
using (Mat dst = LayerMat)
@@ -826,16 +840,18 @@ namespace UVtools.Core
{
Mat target = operation.GetRoiOrDefault(dst);
- CvInvoke.Erode(target, erode, kernel, anchor, (int) operation.BorderSize, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, erode, kernel, anchor, (int) operation.WallThickness, BorderType.Reflect101, default);
CvInvoke.Subtract(target, erode, diff);
- if (operation.BordersOnly)
+
+
+ if (operation.WallsOnly)
{
- CvInvoke.BitwiseAnd(diff, Index % 2 == 0 ? evenPatternMask : oddPatternMask, target);
+ CvInvoke.BitwiseAnd(diff, operation.IsNormalPattern(Index) ? patternMask : alternatePatternMask, target);
CvInvoke.Add(erode, target, target);
}
else
{
- CvInvoke.BitwiseAnd(erode, Index % 2 == 0 ? evenPatternMask : oddPatternMask, target);
+ CvInvoke.BitwiseAnd(erode, operation.IsNormalPattern(Index) ? patternMask : alternatePatternMask, target);
CvInvoke.Add(target, diff, target);
}
@@ -843,6 +859,210 @@ namespace UVtools.Core
}
}
+ public void Infill(OperationInfill operation)
+ {
+ var anchor = new Point(-1, -1);
+ var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+
+ uint layerIndex = Index - operation.LayerIndexStart;
+ var infillColor = new MCvScalar(operation.InfillBrightness);
+
+ Mat patternMask = null;
+ using (Mat dst = LayerMat)
+ using (Mat erode = new Mat())
+ using (Mat diff = new Mat())
+ {
+ Mat target = operation.GetRoiOrDefault(dst);
+
+ /*if (operation.InfillType == OperationInfill.InfillAlgorithm.Rhombus)
+ {
+ const double rotationAngle = 55;
+ patternMask = target.CloneBlank();
+ int offsetLayerPos = (int)(layerIndex % operation.InfillSpacing);
+ var pivot = new Point( operation.InfillThickness / 2, operation.InfillThickness / 2);
+
+ Point[] points1 = {
+ new Point(operation.InfillThickness / 4, operation.InfillThickness / 2), // Left
+ new Point(operation.InfillThickness / 2, 0), // Top
+ new Point((int) (operation.InfillThickness / 1.25), operation.InfillThickness / 2), // Right
+ new Point(operation.InfillThickness / 2, operation.InfillThickness) // Bottom
+ };
+ var vec1 = new VectorOfPoint(points1);
+
+
+ Point[] points2 = {
+ points1[0].Rotate(rotationAngle, pivot),
+ points1[1].Rotate(rotationAngle, pivot),
+ points1[2].Rotate(rotationAngle, pivot),
+ points1[3].Rotate(rotationAngle, pivot),
+ };
+ var vec2 = new VectorOfPoint(points2);
+
+ Point[] points3 = {
+ points1[0].Rotate(-rotationAngle, pivot),
+ points1[1].Rotate(-rotationAngle, pivot),
+ points1[2].Rotate(-rotationAngle, pivot),
+ points1[3].Rotate(-rotationAngle, pivot),
+ };
+ var vec3 = new VectorOfPoint(points3);
+
+
+ /*int halfPos = (operation.InfillThickness + offsetPos) / 2;
+
+ Point[] points = {
+ new Point(0+offsetPos, halfPos), // Left
+ new Point(halfPos, 0+offsetPos), // Top
+ new Point(operation.InfillThickness+offsetPos, halfPos), // Right
+ new Point(halfPos, operation.InfillThickness+offsetPos) // Bottom
+ }; */
+ /* for (int y = 0; y < patternMask.Height; y += operation.InfillSpacing)
+ {
+ for (int x = 0; x < patternMask.Width; x+=operation.InfillSpacing)
+ {
+ CvInvoke.FillPoly(patternMask, vec1, infillColor, LineType.EightConnected, default, new Point(x, y+offsetLayerPos));
+ CvInvoke.FillPoly(patternMask, vec2, infillColor, LineType.EightConnected, default, new Point(x- offsetLayerPos, y+ offsetLayerPos));
+ CvInvoke.FillPoly(patternMask, vec3, infillColor, LineType.EightConnected, default, new Point(x+ offsetLayerPos, y+ offsetLayerPos));
+ }
+ }
+
+ patternMask.Save("D:\\mask.png");
+
+
+ }
+ else*/ if (operation.InfillType == OperationInfill.InfillAlgorithm.CubicSimple ||
+ operation.InfillType == OperationInfill.InfillAlgorithm.CubicCenterLink ||
+ operation.InfillType == OperationInfill.InfillAlgorithm.CubicInterlinked)
+ {
+ using (var infillPattern = EmguExtensions.InitMat(new Size(operation.InfillSpacing, operation.InfillSpacing)))
+ using (Mat matPattern = dst.CloneBlank())
+ {
+ bool firstPattern = true;
+ uint accumulator = 0;
+ uint step = 0;
+ while (accumulator < layerIndex)
+ {
+ firstPattern = true;
+ accumulator += operation.InfillSpacing;
+
+ if (accumulator >= layerIndex) break;
+ firstPattern = false;
+ accumulator += operation.InfillThickness;
+ }
+
+ if (firstPattern)
+ {
+ int thickness = operation.InfillThickness / 2;
+ // Top Left
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(0, 0, thickness, thickness),
+ infillColor, -1);
+
+ // Top Right
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(infillPattern.Width - thickness, 0, thickness, thickness),
+ infillColor, -1);
+
+ // Bottom Left
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(0, infillPattern.Height - thickness, thickness, thickness),
+ infillColor, -1);
+
+ // Bottom Right
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(infillPattern.Width - thickness, infillPattern.Height - thickness,
+ thickness, thickness),
+ infillColor, -1);
+
+ if (operation.InfillType == OperationInfill.InfillAlgorithm.CubicCenterLink ||
+ operation.InfillType == OperationInfill.InfillAlgorithm.CubicInterlinked)
+ {
+ // Center cross
+ int margin = (int) (operation.InfillSpacing - accumulator + layerIndex) - thickness;
+ int marginInv = (int) (accumulator - layerIndex) - thickness;
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(margin, margin, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(marginInv, marginInv, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(margin, marginInv, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(marginInv, margin, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ if (operation.InfillType == OperationInfill.InfillAlgorithm.CubicInterlinked)
+ {
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(margin, -thickness, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(marginInv, -thickness, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(-thickness, margin, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(-thickness, marginInv, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(operation.InfillSpacing - thickness, margin, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(operation.InfillSpacing - thickness, marginInv, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(margin, operation.InfillSpacing - thickness, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(marginInv, operation.InfillSpacing - thickness, operation.InfillThickness, operation.InfillThickness),
+ infillColor, -1);
+ }
+ }
+
+
+ }
+ else
+ {
+ CvInvoke.Rectangle(infillPattern,
+ new Rectangle(0, 0, operation.InfillSpacing, operation.InfillSpacing),
+ infillColor, operation.InfillThickness);
+ }
+
+
+ {
+ CvInvoke.Repeat(infillPattern, target.Rows / infillPattern.Rows + 1,
+ target.Cols / infillPattern.Cols + 1, matPattern);
+ patternMask = new Mat(matPattern, new Rectangle(0, 0, target.Width, target.Height));
+ }
+ }
+ }
+
+
+ CvInvoke.Erode(target, erode, kernel, anchor, operation.WallThickness, BorderType.Reflect101,
+ default);
+ CvInvoke.Subtract(target, erode, diff);
+
+
+ CvInvoke.BitwiseAnd(erode, patternMask, target);
+ CvInvoke.Add(target, diff, target);
+ patternMask?.Dispose();
+
+ LayerMat = dst;
+ }
+ }
+
public void Morph(OperationMorph operation, int iterations = 1, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
{
if (iterations == 0)
@@ -1033,6 +1253,6 @@ namespace UVtools.Core
#endregion
-
+
}
}
diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs
index 3c1dfdd..58c086e 100644
--- a/UVtools.Core/Layer/LayerIssue.cs
+++ b/UVtools.Core/Layer/LayerIssue.cs
@@ -5,16 +5,18 @@
* 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.Drawing;
-using System.Runtime.CompilerServices;
+using System.Linq;
namespace UVtools.Core
{
#region LayerIssue Class
- public class IssuesDetectionConfiguration
+ public sealed class IssuesDetectionConfiguration
{
public IslandDetectionConfiguration IslandConfig { get; }
public OverhangDetectionConfiguration OverhangConfig { get; }
@@ -32,7 +34,7 @@ namespace UVtools.Core
}
}
- public class IslandDetectionConfiguration
+ public sealed class IslandDetectionConfiguration
{
/// <summary>
/// Gets or sets if the detection is enabled
@@ -93,7 +95,7 @@ namespace UVtools.Core
/// <summary>
/// Overhang configuration
/// </summary>
- public class OverhangDetectionConfiguration
+ public sealed class OverhangDetectionConfiguration
{
/// <summary>
/// Gets or sets if the detection is enabled
@@ -128,7 +130,7 @@ namespace UVtools.Core
}
}
- public class ResinTrapDetectionConfiguration
+ public sealed class ResinTrapDetectionConfiguration
{
/// <summary>
/// Gets or sets if the detection is enabled
@@ -163,7 +165,7 @@ namespace UVtools.Core
}
- public class TouchingBoundDetectionConfiguration
+ public sealed class TouchingBoundDetectionConfiguration
{
/// <summary>
/// Gets if the detection is enabled
@@ -171,9 +173,30 @@ namespace UVtools.Core
public bool Enabled { get; set; } = true;
/// <summary>
- /// Gets the maximum pixel brightness to be a touching bound
+ /// Gets the minimum pixel brightness to be a touching bound
+ /// </summary>
+ public byte MinimumPixelBrightness { get; set; } = 127;
+
+ /// <summary>
+ /// Gets or sets the margin in pixels from left edge to check for touching white pixels
+ /// </summary>
+ public byte MarginLeft { get; set; } = 5;
+
+ /// <summary>
+ /// Gets or sets the margin in pixels from top to check for touching white pixels
+ /// </summary>
+ public byte MarginTop { get; set; } = 5;
+
+ /// <summary>
+ /// Gets or sets the margin in pixels from right edge to check for touching white pixels
+ /// </summary>
+ public byte MarginRight { get; set; } = 5;
+
+ /// <summary>
+ /// Gets or sets the margin in pixels from bottom edge to check for touching white pixels
/// </summary>
- public byte MaximumPixelBrightness { get; set; } = 200;
+ public byte MarginBottom { get; set; } = 5;
+
public TouchingBoundDetectionConfiguration(bool enabled = true)
{
@@ -182,7 +205,7 @@ namespace UVtools.Core
}
- public class LayerIssue : IEnumerable<Point>
+ public class LayerIssue : IEquatable<LayerIssue>, IEnumerable<Point>
{
public enum IssueType : byte
{
@@ -285,6 +308,38 @@ namespace UVtools.Core
{
return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(Size)}: {Size}";
}
+
+ public bool Equals(LayerIssue other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Layer.Index == other.Layer.Index
+ && Type == other.Type
+ && PixelsCount == other.PixelsCount
+ && !(Pixels is null) && !(other.Pixels is null) && Pixels.SequenceEqual(other.Pixels)
+ //&& BoundingRectangle.Equals(other.BoundingRectangle)
+ ;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((LayerIssue) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = (Layer != null ? Layer.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ (int) Type;
+ hashCode = (hashCode * 397) ^ (Pixels != null ? Pixels.GetHashCode() : 0);
+ hashCode = (hashCode * 397) ^ BoundingRectangle.GetHashCode();
+ return hashCode;
+ }
+ }
}
#endregion
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index 06f2a72..02e4988 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -426,17 +426,17 @@ namespace UVtools.Core
if (progress is null) progress = new OperationProgress();
progress.Reset(operation.ProgressAction, operation.LayerRangeCount);
- if (operation.EvenPattern is null)
+ if (operation.Pattern is null)
{
- operation.EvenPattern = new Matrix<byte>(2, 2)
+ operation.Pattern = new Matrix<byte>(2, 2)
{
[0, 0] = 127, [0, 1] = 255,
[1, 0] = 255, [1, 1] = 127,
};
- if (operation.OddPattern is null)
+ if (operation.AlternatePattern is null)
{
- operation.OddPattern = new Matrix<byte>(2, 2)
+ operation.AlternatePattern = new Matrix<byte>(2, 2)
{
[0, 0] = 255, [0, 1] = 127,
[1, 0] = 127, [1, 1] = 255,
@@ -444,29 +444,29 @@ namespace UVtools.Core
}
}
- if (operation.OddPattern is null)
+ if (operation.AlternatePattern is null)
{
- operation.OddPattern = operation.EvenPattern;
+ operation.AlternatePattern = operation.Pattern;
}
using (Mat mat = this[0].LayerMat)
- using (Mat matEven = mat.CloneBlank())
- using (Mat matOdd = mat.CloneBlank())
+ using (Mat matPattern = mat.CloneBlank())
+ using (Mat matAlternatePattern = mat.CloneBlank())
{
Mat target = operation.GetRoiOrDefault(mat);
- CvInvoke.Repeat(operation.EvenPattern, target.Rows / operation.EvenPattern.Rows + 1,
- target.Cols / operation.EvenPattern.Cols + 1, matEven);
- CvInvoke.Repeat(operation.OddPattern, target.Rows / operation.OddPattern.Rows + 1,
- target.Cols / operation.OddPattern.Cols + 1, matOdd);
+ CvInvoke.Repeat(operation.Pattern, target.Rows / operation.Pattern.Rows + 1,
+ target.Cols / operation.Pattern.Cols + 1, matPattern);
+ CvInvoke.Repeat(operation.AlternatePattern, target.Rows / operation.AlternatePattern.Rows + 1,
+ target.Cols / operation.AlternatePattern.Cols + 1, matAlternatePattern);
- using (var evenPatternMask = new Mat(matEven, new Rectangle(0, 0, target.Width, target.Height)))
- using (var oddPatternMask = new Mat(matOdd, new Rectangle(0, 0, target.Width, target.Height)))
+ using (var patternMask = new Mat(matPattern, new Rectangle(0, 0, target.Width, target.Height)))
+ using (var alternatePatternMask = new Mat(matAlternatePattern, new Rectangle(0, 0, target.Width, target.Height)))
{
Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- this[layerIndex].PixelDimming(operation, evenPatternMask, oddPatternMask);
+ this[layerIndex].PixelDimming(operation, patternMask, alternatePatternMask);
lock (progress.Mutex)
{
progress++;
@@ -478,6 +478,22 @@ namespace UVtools.Core
progress.Token.ThrowIfCancellationRequested();
}
+ public void Infill(OperationInfill operation, OperationProgress progress)
+ {
+ if (progress is null) progress = new OperationProgress();
+ progress.Reset(operation.ProgressAction, operation.LayerRangeCount);
+
+ Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ this[layerIndex].Infill(operation);
+ lock (progress.Mutex)
+ {
+ progress++;
+ }
+ });
+ }
+
private void MutateGetVarsIterationFade(uint startLayerIndex, uint endLayerIndex, int iterationsStart, int iterationsEnd, ref bool isFade, out float iterationSteps, out int maxIteration)
{
iterationSteps = 0;
@@ -780,19 +796,30 @@ namespace UVtools.Core
ResinTrapDetectionConfiguration resinTrapConfig = null,
TouchingBoundDetectionConfiguration touchBoundConfig = null,
bool emptyLayersConfig = true,
+ List<LayerIssue> ignoredIssues = null,
OperationProgress progress = null)
{
- if(islandConfig is null) islandConfig = new IslandDetectionConfiguration();
+
+ if (islandConfig is null) islandConfig = new IslandDetectionConfiguration();
if(overhangConfig is null) overhangConfig = new OverhangDetectionConfiguration();
if(resinTrapConfig is null) resinTrapConfig = new ResinTrapDetectionConfiguration();
if(touchBoundConfig is null) touchBoundConfig = new TouchingBoundDetectionConfiguration();
if(progress is null) progress = new OperationProgress();
-
+
var result = new ConcurrentBag<LayerIssue>();
var layerHollowAreas = new ConcurrentDictionary<uint, List<LayerHollowArea>>();
bool islandsFinished = false;
+ bool IsIgnored(LayerIssue issue) => !(ignoredIssues is null) && ignoredIssues.Count > 0 && ignoredIssues.Contains(issue);
+
+ bool AddIssue(LayerIssue issue)
+ {
+ if (IsIgnored(issue)) return false;
+ result.Add(issue);
+ return true;
+ }
+
progress.Reset(OperationProgress.StatusIslands, Count);
Parallel.Invoke(() =>
@@ -813,7 +840,7 @@ namespace UVtools.Core
{
if (emptyLayersConfig)
{
- result.Add(new LayerIssue(layer, LayerIssue.IssueType.EmptyLayer));
+ AddIssue(new LayerIssue(layer, LayerIssue.IssueType.EmptyLayer));
}
lock (progress.Mutex)
@@ -851,41 +878,75 @@ namespace UVtools.Core
{
// TouchingBounds Checker
List<Point> pixels = new List<Point>();
- for (int x = 0; x < image.Width; x++) // Check Top and Bottom bounds
+ bool touchTop = layer.BoundingRectangle.Top <= touchBoundConfig.MarginTop;
+ bool touchBottom = layer.BoundingRectangle.Bottom >= image.Height - touchBoundConfig.MarginBottom;
+ bool touchLeft = layer.BoundingRectangle.Left <= touchBoundConfig.MarginLeft;
+ bool touchRight = layer.BoundingRectangle.Right >= image.Width - touchBoundConfig.MarginRight;
+ if (touchTop || touchBottom)
{
- if (span[x] >= touchBoundConfig.MaximumPixelBrightness) // Top
+ for (int x = 0; x < image.Width; x++) // Check Top and Bottom bounds
{
- pixels.Add(new Point(x, 0));
- }
+ if (touchTop)
+ {
+ for (int y = 0; y < touchBoundConfig.MarginTop; y++) // Top
+ {
+ if (span[image.GetPixelPos(x, y)] >=
+ touchBoundConfig.MinimumPixelBrightness)
+ {
+ pixels.Add(new Point(x, y));
+ }
+ }
+ }
+
+ if (touchBottom)
+ {
+ for (int y = image.Height - touchBoundConfig.MarginBottom; y < image.Height; y++) // Bottom
+ {
+ if (span[image.GetPixelPos(x, y)] >=
+ touchBoundConfig.MinimumPixelBrightness)
+ {
+ pixels.Add(new Point(x, y));
+ }
+ }
+ }
- if (span[step * image.Height - step + x] >=
- touchBoundConfig.MaximumPixelBrightness) // Bottom
- {
- pixels.Add(new Point(x, image.Height - 1));
}
}
- for (int y = 0; y < image.Height; y++) // Check Left and Right bounds
+ if (touchLeft || touchRight)
{
- if (span[y * step] >= touchBoundConfig.MaximumPixelBrightness) // Left
+ for (int y = touchBoundConfig.MarginTop; y < image.Height - touchBoundConfig.MarginBottom; y++) // Check Left and Right bounds
{
- pixels.Add(new Point(0, y));
- }
+ if (touchLeft)
+ {
+ for (int x = 0; x < touchBoundConfig.MarginLeft; x++) // Left
+ {
+ if (span[image.GetPixelPos(x, y)] >=
+ touchBoundConfig.MinimumPixelBrightness)
+ {
+ pixels.Add(new Point(x, y));
+ }
+ }
+ }
- if (span[y * step + step - 1] >= touchBoundConfig.MaximumPixelBrightness) // Right
- {
- pixels.Add(new Point(step - 1, y));
+ if (touchRight)
+ {
+ for (int x = image.Width - touchBoundConfig.MarginRight; x < image.Width; x++) // Right
+ {
+ if (span[image.GetPixelPos(x, y)] >=
+ touchBoundConfig.MinimumPixelBrightness)
+ {
+ pixels.Add(new Point(x, y));
+ }
+ }
+ }
}
}
if (pixels.Count > 0)
{
- result.Add(new LayerIssue(layer, LayerIssue.IssueType.TouchingBound,
+ AddIssue(new LayerIssue(layer, LayerIssue.IssueType.TouchingBound,
pixels.ToArray()));
- /*result.TryAdd(layer.Index, new List<LayerIssue>
- {
- new LayerIssue(layer, LayerIssue.IssueType.TouchingBound, pixels.ToArray())
- });*/
}
}
@@ -998,7 +1059,7 @@ namespace UVtools.Core
if (pixelsSupportingIsland < requiredSupportingPixels)
{
- result.Add(new LayerIssue(layer, LayerIssue.IssueType.Island,
+ AddIssue(new LayerIssue(layer, LayerIssue.IssueType.Island,
points.ToArray(),
rect));
}
@@ -1036,7 +1097,7 @@ namespace UVtools.Core
if (points.Count >= overhangConfig.RequiredPixelsToConsider)
{
- result.Add(new LayerIssue(
+ AddIssue(new LayerIssue(
layer, LayerIssue.IssueType.Overhang, points.ToArray(), rect
));
}
@@ -1091,7 +1152,7 @@ namespace UVtools.Core
if (vecPoints.Size >= overhangConfig.RequiredPixelsToConsider)
{
//subtractedImage.Save("D:\\subtracted_image\\subtracted_erroded.png");
- result.Add(new LayerIssue(
+ AddIssue(new LayerIssue(
layer, LayerIssue.IssueType.Overhang, vecPoints.ToArray(), layer.BoundingRectangle
));
}
@@ -1367,7 +1428,7 @@ namespace UVtools.Core
where area.Type == LayerHollowArea.AreaType.Trap
select new LayerIssue(this[layerIndex], LayerIssue.IssueType.ResinTrap, area.Contour, area.BoundingRectangle))
{
- result.Add(issue);
+ AddIssue(issue);
}
}
@@ -2077,6 +2138,7 @@ namespace UVtools.Core
#endregion
+
}
}
diff --git a/UVtools.Core/Operations/OperationInfill.cs b/UVtools.Core/Operations/OperationInfill.cs
new file mode 100644
index 0000000..7f0ec58
--- /dev/null
+++ b/UVtools.Core/Operations/OperationInfill.cs
@@ -0,0 +1,94 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+
+namespace UVtools.Core.Operations
+{
+ [Serializable]
+ public sealed class OperationInfill : Operation
+ {
+ private InfillAlgorithm _infillType = InfillAlgorithm.CubicCenterLink;
+ private ushort _wallThickness = 64;
+ private ushort _infillThickness = 45;
+ private ushort _infillSpacing = 160;
+ private ushort _infillBrightness = 255;
+
+ #region Overrides
+
+ public override string Title => "Infill";
+
+ public override string Description =>
+ $"Generate infill patterns in the model\n\nNOTES:\n1) You must exclude floor and ceil layers from the range.\n2) You must take care of drain holes after the operation.";
+
+ public override string ConfirmationText =>
+ $"infill model with {InfillType} from layers {LayerIndexStart} through {LayerIndexEnd}?";
+
+ public override string ProgressTitle =>
+ $"Infill model with {InfillType} from layers {LayerIndexStart} through {LayerIndexEnd}";
+
+ public override string ProgressAction => "Infilled layers";
+
+ #endregion
+
+ #region Enums
+ public enum InfillAlgorithm
+ {
+ //Rhombus,
+ CubicSimple,
+ CubicCenterLink,
+ CubicInterlinked,
+ }
+ #endregion
+
+ #region Properties
+ public static Array InfillAlgorithmTypes => Enum.GetValues(typeof(InfillAlgorithm));
+ public InfillAlgorithm InfillType
+ {
+ get => _infillType;
+ set => RaiseAndSetIfChanged(ref _infillType, value);
+ }
+
+ public ushort WallThickness
+ {
+ get => _wallThickness;
+ set => RaiseAndSetIfChanged(ref _wallThickness, value);
+ }
+
+ public ushort InfillBrightness
+ {
+ get => _infillBrightness;
+ set => RaiseAndSetIfChanged(ref _infillBrightness, value);
+ }
+
+ public ushort InfillThickness
+ {
+ get => _infillThickness;
+ set => RaiseAndSetIfChanged(ref _infillThickness, value);
+ }
+
+ public ushort InfillSpacing
+ {
+ get => _infillSpacing;
+ set => RaiseAndSetIfChanged(ref _infillSpacing, value);
+ }
+
+ public override string ToString()
+ {
+ var result = $"[{_infillType}] [Wall: {_wallThickness}px] [B: {_infillBrightness}px] [T: {_infillThickness}px] [S: {_infillSpacing}px]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #endregion
+
+ #region Equality
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs
index 24bbeaa..c099e15 100644
--- a/UVtools.Core/Operations/OperationPixelDimming.cs
+++ b/UVtools.Core/Operations/OperationPixelDimming.cs
@@ -17,10 +17,11 @@ namespace UVtools.Core.Operations
[Serializable]
public class OperationPixelDimming : Operation
{
- private uint _borderSize = 5;
- private bool _bordersOnly;
- private Matrix<byte> _evenPattern;
- private Matrix<byte> _oddPattern;
+ private uint _wallThickness = 5;
+ private bool _wallsOnly;
+ private Matrix<byte> _pattern;
+ private Matrix<byte> _alternatePattern;
+ private ushort _alternatePatternPerLayers = 1;
#region Overrides
public override string Title => "Pixel dimming";
@@ -43,12 +44,12 @@ namespace UVtools.Core.Operations
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
- if (BorderSize == 0 && BordersOnly)
+ if (WallThickness == 0 && WallsOnly)
{
sb.AppendLine("Border size must be positive in order to use \"Dim only borders\" function.");
}
- if (EvenPattern is null && OddPattern is null)
+ if (Pattern is null && AlternatePattern is null)
{
sb.AppendLine("Either even or odd pattern must contain a valid matrix.");
}
@@ -59,46 +60,66 @@ namespace UVtools.Core.Operations
#region Properties
- public uint BorderSize
+ public uint WallThickness
{
- get => _borderSize;
- set => RaiseAndSetIfChanged(ref _borderSize, value);
+ get => _wallThickness;
+ set => RaiseAndSetIfChanged(ref _wallThickness, value);
}
- public bool BordersOnly
+ public bool WallsOnly
{
- get => _bordersOnly;
- set => RaiseAndSetIfChanged(ref _bordersOnly, value);
+ get => _wallsOnly;
+ set => RaiseAndSetIfChanged(ref _wallsOnly, value);
+ }
+
+ /// <summary>
+ /// Use the alternate pattern every <see cref="AlternatePatternPerLayers"/> layers
+ /// </summary>
+ public ushort AlternatePatternPerLayers
+ {
+ get => _alternatePatternPerLayers;
+ set => RaiseAndSetIfChanged(ref _alternatePatternPerLayers, Math.Max((ushort)1, value));
}
[XmlIgnore]
- public Matrix<byte> EvenPattern
+ public Matrix<byte> Pattern
{
- get => _evenPattern;
- set => RaiseAndSetIfChanged(ref _evenPattern, value);
+ get => _pattern;
+ set => RaiseAndSetIfChanged(ref _pattern, value);
}
[XmlIgnore]
- public Matrix<byte> OddPattern
+ public Matrix<byte> AlternatePattern
{
- get => _oddPattern;
- set => RaiseAndSetIfChanged(ref _oddPattern, value);
+ get => _alternatePattern;
+ set => RaiseAndSetIfChanged(ref _alternatePattern, value);
}
#endregion
+ #region Methods
+
+ public bool IsNormalPattern(uint layerIndex)
+ {
+ return layerIndex / AlternatePatternPerLayers % 2 == 0;
+ }
+
+ public bool IsAlternatePattern(uint layerIndex) => !IsNormalPattern(layerIndex);
+
public override string ToString()
{
- var result = $"[Border: {_borderSize}px] [Only borders: {_bordersOnly}]" + LayerRangeString;
+ var result = $"[Border: {_wallThickness}px] [Only borders: {_wallsOnly}] [Alternate every: {_alternatePatternPerLayers}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
+ #endregion
+
#region Equality
protected bool Equals(OperationPixelDimming other)
{
- return _borderSize == other._borderSize && _bordersOnly == other._bordersOnly;
+ return _wallThickness == other._wallThickness && _wallsOnly == other._wallsOnly;
}
public override bool Equals(object obj)
@@ -113,7 +134,7 @@ namespace UVtools.Core.Operations
{
unchecked
{
- return ((int) _borderSize * 397) ^ _bordersOnly.GetHashCode();
+ return ((int) _wallThickness * 397) ^ _wallsOnly.GetHashCode();
}
}
diff --git a/UVtools.Core/Operations/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs
index 85a9971..077c4ba 100644
--- a/UVtools.Core/Operations/OperationProgress.cs
+++ b/UVtools.Core/Operations/OperationProgress.cs
@@ -38,7 +38,7 @@ namespace UVtools.Core.Operations
private bool _canCancel = true;
private string _title = "Operation";
- private string _itemName = StatusDecodeLayers;
+ private string _itemName = "Initializing";
private uint _processedItems;
private uint _itemCount;
diff --git a/UVtools.Core/Operations/OperationSolidify.cs b/UVtools.Core/Operations/OperationSolidify.cs
index af9474c..4dc4088 100644
--- a/UVtools.Core/Operations/OperationSolidify.cs
+++ b/UVtools.Core/Operations/OperationSolidify.cs
@@ -13,6 +13,14 @@ namespace UVtools.Core.Operations
[Serializable]
public sealed class OperationSolidify : Operation
{
+ public enum AreaCheckTypes
+ {
+ More,
+ Less
+ }
+ private uint _minimumArea = 1;
+ private AreaCheckTypes _areaCheckType = AreaCheckTypes.More;
+
#region Overrides
public override string Title => "Solidify";
@@ -29,7 +37,29 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Solidified layers";
- public override bool CanHaveProfiles => false;
+ /// <summary>
+ /// Gets the minimum required area to solidify it
+ /// </summary>
+ public uint MinimumArea
+ {
+ get => _minimumArea;
+ set => RaiseAndSetIfChanged(ref _minimumArea, Math.Max(1, value));
+ }
+
+ public AreaCheckTypes AreaCheckType
+ {
+ get => _areaCheckType;
+ set => RaiseAndSetIfChanged(ref _areaCheckType, value);
+ }
+
+ public static Array AreaCheckTypeItems => Enum.GetValues(typeof(AreaCheckTypes));
+
+ public override string ToString()
+ {
+ var result = $"[Area: ={_areaCheckType} than {_minimumArea}px²]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
#endregion
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 176522d..9d3c379 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
- <Version>1.2.1</Version>
+ <Version>1.3.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.cs b/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.cs
index 576e3f4..f9cfbf3 100644
--- a/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.cs
+++ b/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.cs
@@ -43,8 +43,8 @@ namespace UVtools.GUI.Controls.Tools
public override bool UpdateOperation()
{
base.UpdateOperation();
- Operation.BorderSize = (uint) nmBorderSize.Value;
- Operation.BordersOnly = cbDimsOnlyBorders.Checked;
+ Operation.WallThickness = (uint) nmBorderSize.Value;
+ Operation.WallsOnly = cbDimsOnlyBorders.Checked;
var matrixTextbox = new[]
@@ -95,8 +95,8 @@ namespace UVtools.GUI.Controls.Tools
}
}
- Operation.EvenPattern = matrixTextbox[0].Pattern;
- Operation.OddPattern = matrixTextbox[1].Pattern;
+ Operation.Pattern = matrixTextbox[0].Pattern;
+ Operation.AlternatePattern = matrixTextbox[1].Pattern;
return true;
}
diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs
index f5f0ffb..5ce71fd 100644
--- a/UVtools.GUI/FrmMain.cs
+++ b/UVtools.GUI/FrmMain.cs
@@ -3625,7 +3625,7 @@ namespace UVtools.GUI
try
{
Issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig, touchingBoundConfig,
- emptyLayersConfig, FrmLoading.RestartProgress());
+ emptyLayersConfig, null, FrmLoading.RestartProgress());
}
catch (OperationCanceledException)
{
@@ -4061,7 +4061,7 @@ namespace UVtools.GUI
try
{
var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig,
- touchingBoundConfig, false,
+ touchingBoundConfig, false, null,
FrmLoading.RestartProgress());
issues.RemoveAll(issue => issue.Type != LayerIssue.IssueType.Island && issue.Type != LayerIssue.IssueType.Overhang); // Remove all non islands
diff --git a/UVtools.WPF/Assets/Icons/eye-slash-16x16.png b/UVtools.WPF/Assets/Icons/eye-slash-16x16.png
new file mode 100644
index 0000000..de4683b
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/eye-slash-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Assets/Icons/stroopwafel-16x16.png b/UVtools.WPF/Assets/Icons/stroopwafel-16x16.png
new file mode 100644
index 0000000..4fc0de6
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/stroopwafel-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Controls/Helpers.cs b/UVtools.WPF/Controls/Helpers.cs
index efcd8cd..9530e78 100644
--- a/UVtools.WPF/Controls/Helpers.cs
+++ b/UVtools.WPF/Controls/Helpers.cs
@@ -71,5 +71,13 @@ namespace UVtools.WPF.Controls
result.AddRange(data.Select(kv => new FileDialogFilter {Name = kv.Key, Extensions = kv.Value}));
return result;
}
+
+ public static List<FileDialogFilter> ToAvaloniaFilter(string name, string extension)
+ {
+ return new List<FileDialogFilter>(1)
+ {
+ new FileDialogFilter {Name = name, Extensions = new List<string>(1) {extension}}
+ };
+ }
}
}
diff --git a/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml
new file mode 100644
index 0000000..f09dc61
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml
@@ -0,0 +1,119 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="300"
+ x:Class="UVtools.WPF.Controls.Tools.ToolInfillControl">
+ <Grid
+ RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,200,5,Auto"
+ >
+
+ <!--Pattern-->
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Pattern:"
+ />
+
+ <ComboBox
+ Grid.Column="2"
+ Items="{Binding Operation.InfillAlgorithmTypes}"
+ SelectedItem="{Binding Operation.InfillType}"
+ />
+
+ <!--Wall thickness-->
+ <TextBlock
+ Grid.Row="2"
+ Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Wall thickness:"
+ />
+
+ <NumericUpDown
+ Grid.Row="2"
+ Grid.Column="2"
+ Minimum="0"
+ Maximum="65535"
+ Increment="1"
+ ClipValueToMinMax="True"
+ Value="{Binding Operation.WallThickness}"
+ />
+
+ <TextBlock
+ Grid.Row="2"
+ Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"
+ />
+
+ <!--Infill brightness-->
+ <TextBlock
+ Grid.Row="4"
+ Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Infill brightness:"
+ />
+
+ <NumericUpDown
+ Grid.Row="4"
+ Grid.Column="2"
+ Minimum="0"
+ Maximum="255"
+ Increment="1"
+ ClipValueToMinMax="True"
+ Value="{Binding Operation.InfillBrightness}"
+ />
+
+ <!--Infill thickness-->
+ <TextBlock
+ Grid.Row="6"
+ Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Infill thickness:"
+ />
+
+ <NumericUpDown
+ Grid.Row="6"
+ Grid.Column="2"
+ Name="InfillThickness"
+ Minimum="0"
+ Maximum="65535"
+ Increment="1"
+ ClipValueToMinMax="True"
+ Value="{Binding Operation.InfillThickness}"
+ />
+
+ <TextBlock
+ Grid.Row="6"
+ Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"
+ />
+
+ <!--Infill spacing-->
+ <TextBlock
+ Grid.Row="8"
+ Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Infill spacing:"
+ />
+
+ <NumericUpDown
+ Grid.Row="8"
+ Grid.Column="2"
+ Minimum="{Binding #InfillThickness.Value}"
+ Maximum="65535"
+ Increment="1"
+ ClipValueToMinMax="True"
+ Value="{Binding Operation.InfillSpacing}"
+ />
+
+ <TextBlock
+ Grid.Row="8"
+ Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="px"
+ />
+
+ </Grid>
+</UserControl>
diff --git a/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml.cs
new file mode 100644
index 0000000..a710a9e
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolInfillControl.axaml.cs
@@ -0,0 +1,21 @@
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public class ToolInfillControl : ToolControl
+ {
+ public OperationInfill Operation => BaseOperation as OperationInfill;
+
+ public ToolInfillControl()
+ {
+ InitializeComponent();
+ BaseOperation = new OperationInfill();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
index c9e7ee4..2dd9dbe 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
@@ -8,13 +8,13 @@
<StackPanel Spacing="10" Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
- Text="Border size:"
+ Text="Wall thickness:"
/>
<NumericUpDown
Minimum="0"
Maximum="1000"
Width="80"
- Value="{Binding Operation.BorderSize}"
+ Value="{Binding Operation.WallThickness}"
/>
<TextBlock
VerticalAlignment="Center"
@@ -23,8 +23,24 @@
<CheckBox
Margin="20,0,0,0"
- Content="Dim only borders"
- IsChecked="{Binding Operation.BordersOnly}"
+ Content="Dim only walls"
+ IsChecked="{Binding Operation.WallsOnly}"
+ />
+
+ <TextBlock
+ Margin="20,0,0,0"
+ VerticalAlignment="Center"
+ Text="Alternate the pattern every:"
+ />
+ <NumericUpDown
+ Minimum="1"
+ Maximum="{Binding ushort.MaxValue}"
+ Width="80"
+ Value="{Binding Operation.AlternatePatternPerLayers}"
+ />
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="layers"
/>
@@ -222,6 +238,13 @@
Command="{Binding GenerateInfill}"
CommandParameter="Waves"
/>
+ <Button
+ Padding="10"
+ Content="Lattice"
+ Width="100"
+ Command="{Binding GenerateInfill}"
+ CommandParameter="Lattice"
+ />
</StackPanel>
</StackPanel>
</Border>
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
index 36499a2..e4d35bf 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
@@ -1,4 +1,5 @@
using System;
+using System.Drawing;
using Avalonia.Markup.Xaml;
using Emgu.CV;
using UVtools.Core.Extensions;
@@ -116,8 +117,8 @@ namespace UVtools.WPF.Controls.Tools
}
}
- Operation.EvenPattern = stringMatrix[0].Pattern;
- Operation.OddPattern = stringMatrix[1].Pattern;
+ Operation.Pattern = stringMatrix[0].Pattern;
+ Operation.AlternatePattern = stringMatrix[1].Pattern;
return true;
}
@@ -331,6 +332,64 @@ namespace UVtools.WPF.Controls.Tools
AlternatePatternText = null;
return;
}
+
+ if (pattern == "Lattice")
+ {
+ var p1 = string.Empty;
+ var p2 = string.Empty;
+
+ var zeros = Math.Max(0, _infillGenSpacing - _infillGenThickness * 2);
+
+ // Pillar
+ for (int i = 0; i < _infillGenThickness; i++)
+ {
+ p1 += "255 ".Repeat(_infillGenThickness);
+ p1 += "0 ".Repeat(zeros);
+ p1 += "255 ".Repeat(_infillGenThickness);
+ p1 = p1.Trim() + '\n';
+ }
+
+ for (int i = 0; i < zeros; i++)
+ {
+ p1 += "0 ".Repeat(_infillGenSpacing);
+ p1 = p1.Trim() + '\n';
+ }
+
+ for (int i = 0; i < _infillGenThickness; i++)
+ {
+ p1 += "255 ".Repeat(_infillGenThickness);
+ p1 += "0 ".Repeat(zeros);
+ p1 += "255 ".Repeat(_infillGenThickness);
+ p1 = p1.Trim() + '\n';
+ }
+
+ // Square
+ for (int i = 0; i < _infillGenThickness; i++)
+ {
+ p2 += "255 ".Repeat(_infillGenSpacing);
+ p2 = p2.Trim() + '\n';
+ }
+
+ for (int i = 0; i < zeros; i++)
+ {
+ p2 += "255 ".Repeat(_infillGenThickness);
+ p2 += "0 ".Repeat(zeros);
+ p2 += "255 ".Repeat(_infillGenThickness);
+ p2 = p2.Trim() + '\n';
+ }
+
+ for (int i = 0; i < _infillGenThickness; i++)
+ {
+ p2 += "255 ".Repeat(_infillGenSpacing);
+ p2 = p2.Trim() + '\n';
+ }
+
+
+
+ PatternText = p1.Trim('\n', '\r');
+ AlternatePatternText = p2.Trim('\n', '\r'); ;
+ return;
+ }
}
}
diff --git a/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml b/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml
new file mode 100644
index 0000000..fe7cc24
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml
@@ -0,0 +1,32 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="100"
+ x:Class="UVtools.WPF.Controls.Tools.ToolSolidifyControl">
+ <StackPanel Orientation="Horizontal" Spacing="5">
+ <TextBlock
+ Text="Solidifies areas with or"
+ VerticalAlignment="Center" />
+
+ <ComboBox
+ Items="{Binding Operation.AreaCheckTypeItems}"
+ SelectedItem="{Binding Operation.AreaCheckType}"
+ Width="70"
+ VerticalAlignment="Center" />
+
+ <TextBlock
+ Text="than:"
+ VerticalAlignment="Center" />
+
+ <NumericUpDown
+ Width="100"
+ Minimum="1"
+ Maximum="4294967295"
+ Value="{Binding Operation.MinimumArea}"
+ />
+ <TextBlock
+ Text="px²"
+ VerticalAlignment="Center" />
+ </StackPanel>
+</UserControl>
diff --git a/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml.cs
new file mode 100644
index 0000000..e851ee9
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolSolidifyControl.axaml.cs
@@ -0,0 +1,20 @@
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public class ToolSolidifyControl : ToolControl
+ {
+ public OperationSolidify Operation => BaseOperation as OperationSolidify;
+ public ToolSolidifyControl()
+ {
+ InitializeComponent();
+ BaseOperation = new OperationSolidify();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs
index 3785ebb..6542e25 100644
--- a/UVtools.WPF/MainWindow.Issues.cs
+++ b/UVtools.WPF/MainWindow.Issues.cs
@@ -52,6 +52,8 @@ namespace UVtools.WPF
private set => RaiseAndSetIfChanged(ref _issues, value);
}
+ public readonly List<LayerIssue> IgnoredIssues = new List<LayerIssue>();
+
public bool IssueCanGoPrevious => Issues.Count > 0 && _issueSelectedIndex > 0;
public bool IssueCanGoNext => Issues.Count > 0 && _issueSelectedIndex < Issues.Count - 1;
#endregion
@@ -84,7 +86,7 @@ namespace UVtools.WPF
if (await this.MessageBoxQuestion($"Are you sure you want to remove all selected {IssuesGrid.SelectedItems.Count} issues?\n\n" +
"Warning: Removing an island can cause other issues to appear if there is material present in the layers above it.\n" +
- "Always check previous and next layers before performing an island removal.", "Remove Issues?") != ButtonResult.Yes) return;
+ "Always check previous and next layers before performing an island removal.", $"Remove {IssuesGrid.SelectedItems.Count} Issues?") != ButtonResult.Yes) return;
Dictionary<uint, List<LayerIssue>> processIssues = new Dictionary<uint, List<LayerIssue>>();
List<uint> layersRemove = new List<uint>();
@@ -222,6 +224,35 @@ namespace UVtools.WPF
CanSave = true;
}
+ public async void OnClickIssueIgnore()
+ {
+ if ((_globalModifiers & KeyModifiers.Alt) != 0)
+ {
+ if(IgnoredIssues.Count == 0) return;
+ if (await this.MessageBoxQuestion(
+ $"Are you sure you want to re-enable {IgnoredIssues.Count} ignored issues?\n" +
+ "A full re-detect will be required to get the ignored issues.\n", $"Re-enable {IgnoredIssues.Count} Issues?") !=
+ ButtonResult.Yes) return;
+
+ IgnoredIssues.Clear();
+
+ return;
+ }
+
+ if (IssuesGrid.SelectedItems.Count == 0) return;
+
+ if (await this.MessageBoxQuestion(
+ $"Are you sure you want to hide and ignore all selected {IssuesGrid.SelectedItems.Count} issues?\n" +
+ "The ignored issues won't be re-detected.\n", $"Ignore {IssuesGrid.SelectedItems.Count} Issues?") !=
+ ButtonResult.Yes) return;
+
+ var list = IssuesGrid.SelectedItems.Cast<LayerIssue>().ToArray();
+ IgnoredIssues.AddRange(list);
+ IssuesGrid.SelectedItems.Clear();
+ Issues.RemoveMany(list);
+ ShowLayer();
+ }
+
private async Task UpdateIslandsOverhangs(List<uint> whiteListLayers)
{
if (whiteListLayers.Count == 0) return;
@@ -254,7 +285,7 @@ namespace UVtools.WPF
try
{
var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig,
- touchingBoundConfig, false,
+ touchingBoundConfig, false, IgnoredIssues,
ProgressWindow.RestartProgress());
issues.RemoveAll(issue => issue.Type != LayerIssue.IssueType.Island && issue.Type != LayerIssue.IssueType.Overhang); // Remove all non islands and overhangs
@@ -414,7 +445,7 @@ namespace UVtools.WPF
try
{
var issues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapConfig, touchingBoundConfig,
- emptyLayersConfig, ProgressWindow.RestartProgress());
+ emptyLayersConfig, IgnoredIssues, ProgressWindow.RestartProgress());
return issues;
}
catch (OperationCanceledException)
@@ -529,7 +560,11 @@ namespace UVtools.WPF
return new TouchingBoundDetectionConfiguration
{
Enabled = Settings.Issues.ComputeTouchingBounds,
- //MaximumPixelBrightness = 100
+ MinimumPixelBrightness = UserSettings.Instance.Issues.TouchingBoundMinimumPixelBrightness,
+ MarginLeft = UserSettings.Instance.Issues.TouchingBoundMarginLeft,
+ MarginTop = UserSettings.Instance.Issues.TouchingBoundMarginTop,
+ MarginRight = UserSettings.Instance.Issues.TouchingBoundMarginRight,
+ MarginBottom = UserSettings.Instance.Issues.TouchingBoundMarginBottom,
};
}
diff --git a/UVtools.WPF/MainWindow.LayerPreview.cs b/UVtools.WPF/MainWindow.LayerPreview.cs
index 0073f3c..984bd60 100644
--- a/UVtools.WPF/MainWindow.LayerPreview.cs
+++ b/UVtools.WPF/MainWindow.LayerPreview.cs
@@ -309,13 +309,13 @@ namespace UVtools.WPF
}
}
- public string LayerBoundsStr => LayerCache.Layer is null ? "NS" : LayerCache.Layer.BoundingRectangle.ToString();
+ public string LayerBoundsStr => LayerCache.Layer is null ? "NS" : $"{LayerCache.Layer.BoundingRectangle} ({LayerCache.Layer.BoundingRectangle.GetArea()}px²)";
public string LayerROIStr
{
get
{
var roi = ROI;
- return roi.IsEmpty ? "NS" : roi.ToString();
+ return roi.IsEmpty ? "NS" : $"{roi} ({roi.GetArea()}px²)";
}
}
@@ -540,7 +540,7 @@ namespace UVtools.WPF
if (issue.Type == LayerIssue.IssueType.ResinTrap)
{
- color = selectedIssues.Contains(issue)
+ color = selectedIssues.Count > 0 && selectedIssues.Contains(issue)
? Settings.LayerPreview.ResinTrapHighlightColor
: Settings.LayerPreview.ResinTrapColor;
@@ -564,7 +564,7 @@ namespace UVtools.WPF
switch (issue.Type)
{
case LayerIssue.IssueType.Island:
- color = selectedIssues.Contains(issue)
+ color = selectedIssues.Count > 0 && selectedIssues.Contains(issue)
? Settings.LayerPreview.IslandHighlightColor
: Settings.LayerPreview.IslandColor;
if (_showLayerImageCrosshairs &&
@@ -576,7 +576,7 @@ namespace UVtools.WPF
break;
case LayerIssue.IssueType.Overhang:
- color = selectedIssues.Contains(issue)
+ color = selectedIssues.Count > 0 && selectedIssues.Contains(issue)
? Settings.LayerPreview.OverhangHighlightColor
: Settings.LayerPreview.OverhangColor;
if (_showLayerImageCrosshairs &&
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 7f2ac69..76e33b2 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -89,6 +89,7 @@
Name="MainMenu.File.Convert"
Header="_Convert to"
IsEnabled="{Binding IsFileLoaded}"
+ IsVisible="{Binding MenuFileConvertItems, Converter={x:Static ObjectConverters.IsNotNull}}"
Items="{Binding MenuFileConvertItems}">
<MenuItem.Icon>
<Image Source="\Assets\Icons\convert-16x16.png"/>
@@ -631,6 +632,14 @@
</RepeatButton>
<Button
+ ToolTip.Tip="Hides and ignores the selected issues, they won't be re-detected.
+&#x0a;ALT + Click to re-enable the ignored issues."
+ IsEnabled="{Binding #IssuesGrid.SelectedItem, Converter={x:Static ObjectConverters.IsNotNull}}"
+ Command="{Binding OnClickIssueIgnore}">
+ <Image Source="/Assets/Icons/eye-slash-16x16.png" />
+ </Button>
+
+ <Button
ToolTip.Tip="Remove selected issue when possible.
&#x0a;Islands: All pixels are removed (turn black).
&#x0a;ResinTrap: All trap areas are filled with white pixels.
@@ -639,7 +648,7 @@
Command="{Binding OnClickIssueRemove}">
<StackPanel Orientation="Horizontal" Spacing="5">
<Image Source="/Assets/Icons/trash-16x16.png" />
- <TextBlock VerticalAlignment="Center" Text="Remove"/>
+ <!--<TextBlock VerticalAlignment="Center" Text="Remove"/>!-->
</StackPanel>
</Button>
@@ -688,7 +697,7 @@
</Button.ContextMenu>
<StackPanel Orientation="Horizontal" Spacing="5">
- <Image Source="/Assets/Icons/save-16x16.png" />
+ <Image Source="/Assets/Icons/refresh-16x16.png" />
<TextBlock Text="Detect ⮟"/>
</StackPanel>
@@ -1716,7 +1725,7 @@
<Grid
IsEnabled="{Binding IsFileLoaded}"
Grid.Row="2"
- ColumnDefinitions="*,*" RowDefinitions="Auto" Margin="5">
+ ColumnDefinitions="4*,2*" RowDefinitions="Auto" Margin="5">
<WrapPanel Orientation="Horizontal">
<StackPanel
ToolTip.Tip="Number of pixels to cure on this layer image and the percentage of them against total lcd pixels"
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index e91f678..c82ce00 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -152,6 +152,14 @@ namespace UVtools.WPF
},
new MenuItem
{
+ Tag = new OperationInfill(),
+ Icon = new Avalonia.Controls.Image
+ {
+ Source = new Bitmap(App.GetAsset("/Assets/Icons/stroopwafel-16x16.png"))
+ }
+ },
+ new MenuItem
+ {
Tag = new OperationBlur(),
Icon = new Avalonia.Controls.Image
{
@@ -230,7 +238,7 @@ namespace UVtools.WPF
#region Members
- public Stopwatch LastStopWatch;
+ public Stopwatch LastStopWatch = new Stopwatch();
private bool _isGUIEnabled = true;
private uint _savesCount;
@@ -479,7 +487,7 @@ namespace UVtools.WPF
|| LayerImageBox.SelectionMode == AdvancedImageBox.SelectionModes.Rectangle
) return;
- var imageBoxMousePosition = _globalPointerEventArgs.GetPosition(LayerImageBox);
+ var imageBoxMousePosition = _globalPointerEventArgs?.GetPosition(LayerImageBox) ?? new Point(-1, -1);
if (imageBoxMousePosition.X < 0 || imageBoxMousePosition.Y < 0) return;
// Pixel Edit is active, Shift is down, and the cursor is over the image region.
@@ -621,6 +629,8 @@ namespace UVtools.WPF
{
if (SlicerFile is null) return;
+ MenuFileConvertItems = null;
+
ClipboardManager.Instance.Reset();
SlicerFile?.Dispose();
@@ -628,6 +638,7 @@ namespace UVtools.WPF
SlicerProperties.Clear();
Issues.Clear();
+ IgnoredIssues.Clear();
_issuesSliderCanvas.Children.Clear();
Drawings.Clear();
@@ -703,10 +714,12 @@ namespace UVtools.WPF
{
var result =
await this.MessageBoxQuestion(
- $"Do you like to auto-update {About.Software} v{App.Version} to v{VersionChecker.Version}?\n\n" +
+ $"Do you like to auto-update {About.Software} v{App.Version} to v{VersionChecker.Version}?\n" +
"Yes: Auto update\n" +
"No: Manual update\n" +
- "Cancel: No action", "Update UVtools?", ButtonEnum.YesNoCancel);
+ "Cancel: No action\n\n" +
+ "Changelog:\n" +
+ $"{VersionChecker.Changelog}", $"Update UVtools to v{VersionChecker.Version}?", ButtonEnum.YesNoCancel);
if (result == ButtonResult.Yes)
{
@@ -749,9 +762,9 @@ namespace UVtools.WPF
private void UpdateTitle()
{
- Title = (SlicerFile is null
- ? $"{About.Software} Version: {App.VersionStr}"
- : $"{About.Software} File: {Path.GetFileName(SlicerFile.FileFullPath)} ({Math.Round(LastStopWatch.ElapsedMilliseconds / 1000m, 2)}s) Version: {App.VersionStr}")
+ Title = SlicerFile is null
+ ? $"{About.Software} Version: {App.VersionStr}"
+ : $"{About.Software} File: {Path.GetFileName(SlicerFile.FileFullPath)} ({Math.Round(LastStopWatch.ElapsedMilliseconds / 1000m, 2)}s) Version: {App.VersionStr}"
;
Title += $" RAM: {SizeExtensions.SizeSuffix(Environment.WorkingSet)}";
@@ -846,8 +859,20 @@ namespace UVtools.WPF
foreach (var fileFormatType in SlicerFile.ConvertToFormats)
{
FileFormat fileFormat = FileFormat.FindByType(fileFormatType);
+ if(fileFormat.FileExtensions is null) continue;
+ foreach (var fileExtension in fileFormat.FileExtensions)
+ {
+ var menuItem = new MenuItem
+ {
+ Header = fileExtension.Description,
+ Tag = fileExtension
+ };
- string extensions = fileFormat.FileExtensions.Length > 0
+ menuItem.Tapped += ConvertToOnTapped;
+
+ menuItems.Add(menuItem);
+ }
+ /*string extensions = fileFormat.FileExtensions.Length > 0
? $" ({fileFormat.GetFileExtensions()})"
: string.Empty;
@@ -859,7 +884,7 @@ namespace UVtools.WPF
menuItem.Tapped += ConvertToOnTapped;
- menuItems.Add(menuItem);
+ menuItems.Add(menuItem);*/
}
MenuFileConvertItems = menuItems.ToArray();
@@ -920,12 +945,12 @@ namespace UVtools.WPF
private async void ConvertToOnTapped(object? sender, RoutedEventArgs e)
{
if (!(sender is MenuItem item)) return;
- if (!(item.Tag is FileFormat fileFormat)) return;
+ if (!(item.Tag is FileExtension fileExtension)) return;
SaveFileDialog dialog = new SaveFileDialog
{
InitialFileName = Path.GetFileNameWithoutExtension(SlicerFile.FileFullPath),
- Filters = Helpers.ToAvaloniaFileFilter(fileFormat.FileFilterAvalonia),
+ Filters = Helpers.ToAvaloniaFilter(fileExtension.Description, fileExtension.Extension),
Directory = string.IsNullOrEmpty(Settings.General.DefaultDirectoryConvertFile)
? Path.GetDirectoryName(SlicerFile.FileFullPath)
: Settings.General.DefaultDirectoryConvertFile
@@ -942,7 +967,7 @@ namespace UVtools.WPF
ShowProgressWindow($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {Path.GetExtension(result)}");
try
{
- return SlicerFile.Convert(fileFormat, result, ProgressWindow.RestartProgress());
+ return SlicerFile.Convert(fileExtension.GetFileFormat(), result, ProgressWindow.RestartProgress());
}
catch (OperationCanceledException)
{
@@ -1249,6 +1274,9 @@ namespace UVtools.WPF
case OperationPixelDimming operation:
SlicerFile.LayerManager.PixelDimming(operation, ProgressWindow.RestartProgress(operation.CanCancel));
break;
+ case OperationInfill operation:
+ SlicerFile.LayerManager.Infill(operation, ProgressWindow.RestartProgress(operation.CanCancel));
+ break;
case OperationBlur operation:
SlicerFile.LayerManager.Blur(operation, ProgressWindow.RestartProgress(operation.CanCancel));
break;
diff --git a/UVtools.WPF/Structures/AppVersionChecker.cs b/UVtools.WPF/Structures/AppVersionChecker.cs
index 57d9ba0..79e6903 100644
--- a/UVtools.WPF/Structures/AppVersionChecker.cs
+++ b/UVtools.WPF/Structures/AppVersionChecker.cs
@@ -6,15 +6,12 @@
* of this license document, but changing it is not allowed.
*/
using System;
-using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
-using System.Threading.Tasks;
-using ABI.Windows.Data.Json;
using Avalonia.Threading;
using Newtonsoft.Json;
using UVtools.Core;
@@ -29,6 +26,7 @@ namespace UVtools.WPF.Structures
public const string GitHubReleaseApi = "https://api.github.com/repos/sn4k3/UVtools/releases/latest";
private string _version;
private string _url;
+ private string _changelog;
public string Filename
{
@@ -83,6 +81,12 @@ namespace UVtools.WPF.Structures
}
}
+ public string Changelog
+ {
+ get => _changelog;
+ set => RaiseAndSetIfChanged(ref _changelog, value);
+ }
+
public string VersionAnnouncementText => $"New version v{_version} is available!";
public string UrlLatestRelease => $"{About.Website}/releases/latest";
@@ -113,12 +117,15 @@ namespace UVtools.WPF.Structures
tag_name = tag_name.Trim(' ', 'v', 'V');
Debug.WriteLine($"Version checker: v{App.VersionStr} <=> v{tag_name}");
+ Changelog = json.body;
+
if (string.Compare(tag_name, App.VersionStr, StringComparison.OrdinalIgnoreCase) > 0)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
Version = tag_name;
- Debug.WriteLine($"New version detected: {DownloadLink}");
+ Debug.WriteLine($"New version detected: {DownloadLink}\n" +
+ $"{_changelog}");
});
return true;
}
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 62df3bd..ac1ac0e 100644
--- a/UVtools.WPF/UVtools.WPF.csproj
+++ b/UVtools.WPF/UVtools.WPF.csproj
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
- <Version>1.2.1</Version>
+ <Version>1.3.0</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -42,8 +42,10 @@
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Icons\clipboard-32x32.png" />
+ <None Remove="Assets\Icons\eye-slash-16x16.png" />
<None Remove="Assets\Icons\layers-alt-32x32.png" />
<None Remove="Assets\Icons\redo-16x16.png" />
+ <None Remove="Assets\Icons\stroopwafel-16x16.png" />
<None Remove="Assets\Icons\UVtools.ico" />
</ItemGroup>
<ItemGroup>
diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs
index f0f9d4f..6f6e3d3 100644
--- a/UVtools.WPF/UserSettings.cs
+++ b/UVtools.WPF/UserSettings.cs
@@ -14,12 +14,13 @@ using Avalonia.Media;
using JetBrains.Annotations;
using ReactiveUI;
using UVtools.Core;
+using UVtools.Core.Objects;
using Color=UVtools.WPF.Structures.Color;
namespace UVtools.WPF
{
[Serializable]
- public sealed class UserSettings : ReactiveObject
+ public sealed class UserSettings : BindableBase
{
#region Constants
public const ushort SETTINGS_VERSION = 1;
@@ -29,7 +30,7 @@ namespace UVtools.WPF
#region General
[Serializable]
- public sealed class GeneralUserSettings : ReactiveObject
+ public sealed class GeneralUserSettings : BindableBase
{
private bool _startMaximized = true;
private bool _checkForUpdatesOnStartup = true;
@@ -133,7 +134,7 @@ namespace UVtools.WPF
#region Layer Preview
[Serializable]
- public sealed class LayerPreviewUserSettings : ReactiveObject
+ public sealed class LayerPreviewUserSettings : BindableBase
{
private Color _tooltipOverlayBackgroundColor = new Color(210, 255, 255, 192);
private bool _tooltipOverlay = true;
@@ -541,7 +542,7 @@ namespace UVtools.WPF
#region Issues
[Serializable]
- public sealed class IssuesUserSettings : ReactiveObject
+ public sealed class IssuesUserSettings : BindableBase
{
private bool _computeIssuesOnLoad = false;
private bool _computeIssuesOnClickTab = true;
@@ -563,6 +564,12 @@ namespace UVtools.WPF
private byte _resinTrapRequiredAreaToProcessCheck = 17;
private byte _resinTrapRequiredBlackPixelsToDrain = 10;
private byte _resinTrapMaximumPixelBrightnessToDrain = 30;
+ private byte _touchingBoundMinimumPixelBrightness = 127;
+ private byte _touchingBoundMarginLeft = 5;
+ private byte _touchingBoundMarginTop = 5;
+ private byte _touchingBoundMarginRight = 5;
+ private byte _touchingBoundMarginBottom = 5;
+ private bool _touchingBoundSyncMargins = true;
public bool ComputeIssuesOnLoad
{
@@ -684,6 +691,70 @@ namespace UVtools.WPF
set => this.RaiseAndSetIfChanged(ref _resinTrapMaximumPixelBrightnessToDrain, value);
}
+ public byte TouchingBoundMinimumPixelBrightness
+ {
+ get => _touchingBoundMinimumPixelBrightness;
+ set => RaiseAndSetIfChanged(ref _touchingBoundMinimumPixelBrightness, value);
+ }
+
+ public byte TouchingBoundMarginLeft
+ {
+ get => _touchingBoundMarginLeft;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _touchingBoundMarginLeft, value)) return;
+ if (_touchingBoundSyncMargins)
+ {
+ TouchingBoundMarginRight = value;
+ }
+ }
+ }
+
+ public byte TouchingBoundMarginTop
+ {
+ get => _touchingBoundMarginTop;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _touchingBoundMarginTop, value)) return;
+ if (_touchingBoundSyncMargins)
+ {
+ TouchingBoundMarginBottom = value;
+ }
+ }
+ }
+
+ public byte TouchingBoundMarginRight
+ {
+ get => _touchingBoundMarginRight;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _touchingBoundMarginRight, value)) return;
+ if (_touchingBoundSyncMargins)
+ {
+ TouchingBoundMarginLeft = value;
+ }
+ }
+ }
+
+ public byte TouchingBoundMarginBottom
+ {
+ get => _touchingBoundMarginBottom;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _touchingBoundMarginBottom, value)) return;
+ if (_touchingBoundSyncMargins)
+ {
+ TouchingBoundMarginTop = value;
+ }
+ }
+ }
+
+ public bool TouchingBoundSyncMargins
+ {
+ get => _touchingBoundSyncMargins;
+ set => RaiseAndSetIfChanged(ref _touchingBoundSyncMargins, value);
+ }
+
public IssuesUserSettings Clone()
{
return MemberwiseClone() as IssuesUserSettings;
@@ -694,7 +765,7 @@ namespace UVtools.WPF
#region Pixel Editor
[Serializable]
- public sealed class PixelEditorUserSettings : ReactiveObject
+ public sealed class PixelEditorUserSettings : BindableBase
{
private Color _addPixelColor = new Color(255, 144, 238, 144);
private Color _addPixelHighlightColor = new Color(255, 0, 255, 0);
@@ -882,7 +953,7 @@ namespace UVtools.WPF
#region Layer Repair
[Serializable]
- public sealed class LayerRepairUserSettings : ReactiveObject
+ public sealed class LayerRepairUserSettings : BindableBase
{
private bool _repairIslands = true;
private bool _repairResinTraps = true;
diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml
index 74595a9..4182b2b 100644
--- a/UVtools.WPF/Windows/SettingsWindow.axaml
+++ b/UVtools.WPF/Windows/SettingsWindow.axaml
@@ -202,6 +202,7 @@
<NumericUpDown Grid.Row="2" Grid.Column="2"
Margin="10,0,0,0"
VerticalAlignment="Center"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="50"
Value="{Binding Settings.LayerPreview.VolumeBoundsOutlineThickness}"
@@ -235,6 +236,7 @@
<NumericUpDown Grid.Row="4" Grid.Column="2"
Margin="10,0,0,0"
VerticalAlignment="Center"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="50"
Value="{Binding Settings.LayerPreview.LayerBoundsOutlineThickness}"
@@ -269,6 +271,7 @@
<NumericUpDown Grid.Row="6" Grid.Column="2"
Margin="10,0,0,0"
VerticalAlignment="Center"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="50"
Value="{Binding Settings.LayerPreview.HollowOutlineLineThickness}"
@@ -528,6 +531,7 @@
<NumericUpDown Grid.Row="0" Grid.Column="3"
Margin="10,0,0,0"
VerticalAlignment="Center"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="1000000"
Width="70"
@@ -558,6 +562,7 @@
<NumericUpDown Grid.Row="2" Grid.Column="3"
Margin="10,0,0,0"
VerticalAlignment="Center"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Width="70"
@@ -664,6 +669,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="0"
Maximum="254"
Value="{Binding Settings.Issues.IslandBinaryThreshold}"
@@ -679,6 +685,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Value="{Binding Settings.Issues.IslandRequiredAreaToProcessCheck}"
@@ -692,6 +699,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Value="{Binding Settings.Issues.IslandRequiredPixelBrightnessToProcessCheck}"
@@ -705,6 +713,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="0.05"
Maximum="0.95"
Increment="0.05"
@@ -721,6 +730,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="50"
Maximum="255"
Value="{Binding Settings.Issues.IslandRequiredPixelBrightnessToSupport}"
@@ -735,6 +745,7 @@
<!--
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Value="{Binding Settings.Issues.IslandRequiredPixelsToSupport}"
@@ -750,6 +761,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="50"
Maximum="255"
Value="{Binding Settings.Issues.IslandRequiredPixelBrightnessToSupport}"
@@ -782,6 +794,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="2"
Maximum="255"
Value="{Binding Settings.Issues.OverhangErodeIterations}"
@@ -806,6 +819,7 @@
<StackPanel Orientation="Horizontal" Margin="15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="254"
Value="{Binding Settings.Issues.ResinTrapBinaryThreshold}"
@@ -822,6 +836,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Value="{Binding Settings.Issues.ResinTrapRequiredAreaToProcessCheck}"
@@ -835,6 +850,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="255"
Value="{Binding Settings.Issues.ResinTrapRequiredBlackPixelsToDrain}"
@@ -848,6 +864,7 @@
<StackPanel Orientation="Horizontal" Margin="15,0,15,15" Spacing="10">
<NumericUpDown Width="60"
+ ClipValueToMinMax="True"
Minimum="1"
Maximum="150"
Value="{Binding Settings.Issues.ResinTrapMaximumPixelBrightnessToDrain}"
@@ -861,6 +878,145 @@
</StackPanel>
</Border>
+ <Border
+ Margin="5"
+ BorderBrush="LightBlue"
+ BorderThickness="4">
+
+ <StackPanel Orientation="Vertical">
+ <TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Touching boundary"/>
+
+ <StackPanel Orientation="Horizontal" Margin="15" Spacing="10">
+ <NumericUpDown Width="60"
+ ClipValueToMinMax="True"
+ Minimum="1"
+ Maximum="255"
+ Value="{Binding Settings.Issues.TouchingBoundMinimumPixelBrightness}"
+ />
+ <TextBlock
+ VerticalAlignment="Center"
+ Text="Minimum pixel intensity for a pixel to be considered a touching boundary"
+ ToolTip.Tip="Pixels below this values won't flag a issue when inside the dangerous boundary margin.
+&#x0a;Pixels equal or above this values will flag a issue when inside the dangerous boundary margin."
+ />
+ </StackPanel>
+
+
+ <Grid
+ ColumnDefinitions="Auto,Auto,Auto,Auto,Auto"
+ RowDefinitions="Auto,Auto,Auto,Auto,Auto"
+ Margin="15,0,15,15"
+ >
+ <TextBlock
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Grid.Row="1"
+ Grid.Column="1"
+ FontWeight="Bold"
+ Text="Margin" />
+
+ <TextBlock
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Grid.Row="3"
+ Grid.Column="1"
+ FontWeight="Bold"
+ Text="Margin" />
+
+ <TextBlock
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Grid.Row="1"
+ Grid.Column="3"
+ FontWeight="Bold"
+ Text="Margin" />
+
+ <TextBlock
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Grid.Row="3"
+ Grid.Column="3"
+ FontWeight="Bold"
+ Text="Margin" />
+
+ <TextBlock
+ Grid.Column="0"
+ Grid.Row="2"
+ VerticalAlignment="Center"
+ Text="Left " />
+ <NumericUpDown
+ Grid.Column="1"
+ Grid.Row="2"
+ Width="70"
+ Minimum="1"
+ Maximum="255"
+ Margin="0,0,5,0"
+ ClipValueToMinMax="True"
+ Value="{Binding Settings.Issues.TouchingBoundMarginLeft}" />
+
+
+ <TextBlock
+ Grid.Column="2"
+ Grid.Row="0"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Margin="0,0,0,2"
+ Text="Top" />
+ <NumericUpDown
+ Grid.Column="2"
+ Grid.Row="1"
+ Width="70"
+ Minimum="1"
+ Maximum="255"
+ Margin="0,0,0,5"
+ ClipValueToMinMax="True"
+ Value="{Binding Settings.Issues.TouchingBoundMarginTop}" />
+
+ <TextBlock
+ Grid.Column="4"
+ Grid.Row="2"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Text=" Right" />
+ <NumericUpDown
+ Grid.Column="3"
+ Grid.Row="2"
+ Width="70"
+ Minimum="1"
+ Maximum="255"
+ Margin="5,0,0,0"
+ ClipValueToMinMax="True"
+ Value="{Binding Settings.Issues.TouchingBoundMarginRight}" />
+
+ <TextBlock
+ Grid.Column="2"
+ Grid.Row="4"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ Margin="0,2,0,0"
+ Text="Bottom" />
+ <NumericUpDown
+ Grid.Column="2"
+ Grid.Row="3"
+ Width="70"
+ Minimum="1"
+ Maximum="255"
+ Margin="0,5,0,0"
+ ClipValueToMinMax="True"
+ Value="{Binding Settings.Issues.TouchingBoundMarginBottom}" />
+
+ <CheckBox
+ Grid.Row="2"
+ Grid.Column="2"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Center"
+ IsChecked="{Binding Settings.Issues.TouchingBoundSyncMargins}"
+ Content="Sync"/>
+ </Grid>
+
+ </StackPanel>
+ </Border>
+
</StackPanel>
</ScrollViewer>
</TabItem>
@@ -1024,6 +1180,7 @@
<NumericUpDown
Value="{Binding Settings.LayerRepair.RemoveIslandsBelowEqualPixels}"
Width="70"
+ ClipValueToMinMax="True"
Minimum="0"
Maximum="255"/>
<TextBlock VerticalAlignment="Center" Text="Default maximum pixel area for Island removal (0 = disable)"/>
@@ -1033,6 +1190,7 @@
<NumericUpDown
Value="{Binding Settings.LayerRepair.RemoveIslandsRecursiveIterations}"
Width="70"
+ ClipValueToMinMax="True"
Minimum="0"
Maximum="65535"/>
<TextBlock VerticalAlignment="Center" Text="Default maximum layers for recursive island removal (0 = All)"/>
@@ -1042,6 +1200,7 @@
<NumericUpDown
Value="{Binding Settings.LayerRepair.ClosingIterations}"
Width="70"
+ ClipValueToMinMax="True"
Minimum="0"
Maximum="255"/>
<TextBlock VerticalAlignment="Center" Text="Default 'Gap Closing' iterations"/>
@@ -1051,6 +1210,7 @@
<NumericUpDown
Value="{Binding Settings.LayerRepair.OpeningIterations}"
Width="70"
+ ClipValueToMinMax="True"
Minimum="0"
Maximum="255"/>
<TextBlock VerticalAlignment="Center" Text="Default 'Noise Removal' iterations"/>
diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
index cd767ee..f3522d5 100644
--- a/UVtools.WPF/Windows/SettingsWindow.axaml.cs
+++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
@@ -61,7 +61,7 @@ namespace UVtools.WPF.Windows
//MaxHeight = Screens.Primary.WorkingArea.Height - 50;
- ScrollViewerMaxHeight = Screens.Primary.WorkingArea.Height / Screens.Primary.PixelDensity - 200;
+ ScrollViewerMaxHeight = Screens.Primary.WorkingArea.Height / Screens.Primary.PixelDensity - 300;
DataContext = this;