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>2021-05-17 05:34:31 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-05-17 05:34:31 +0300
commit51c82318cf27b8e0d3425aa2ea1b093fc5b7d23f (patch)
tree1059ece01344eec934792d72bf8b0ed9aad4a06d /UVtools.Core
parentedd9984a31a90791edf3bcf594855d08507428b5 (diff)
v2.12.0v2.12.0
- **Layer arithmetic:** - (Add) Allow to use ':' to define a layer range to set, eg, 0:20 to select from 0 to 20 layers - (Improvement) Modifications with set ROI and/or Mask(s) are only applied to target layer on that same regions - (Improvement) Disallow set one layer to the same layer without any modification - (Improvement) Clear and sanitize non-existing layers indexes - (Improvement) Disable the layer range selector from dialog - (Fix) Prevent error when using non-existing layers indexes - (Fix) Allow use only a mask for operations - (Fix) Implement the progress bar - **File formats:** - (Add) VDA.ZIP (Voxeldance Additive) - (Improvement) Add a check to global `LightPWM` if 0 it will force to 255 - (Improvement) Add a check to layer `LightPWM` if 0 it will force to 255 - (Add) Allow to save the selected region (ROI) to a image file - (Update) .NET 5.0.5 to 5.0.6 - (Fix) Getting the transposed rectangle in fliped images are offseting the position by -1 - (Fix) Tools: Hide ROI Region text when empty/not selected
Diffstat (limited to 'UVtools.Core')
-rw-r--r--UVtools.Core/About.cs5
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs34
-rw-r--r--UVtools.Core/FileFormats/VDAFile.cs432
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs4
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs10
-rw-r--r--UVtools.Core/Layer/Layer.cs25
-rw-r--r--UVtools.Core/Layer/LayerManager.cs43
-rw-r--r--UVtools.Core/Objects/BindableBase.cs5
-rw-r--r--UVtools.Core/Operations/Operation.cs2
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs2
-rw-r--r--UVtools.Core/Operations/OperationLayerArithmetic.cs57
-rw-r--r--UVtools.Core/UVtools.Core.csproj4
12 files changed, 560 insertions, 63 deletions
diff --git a/UVtools.Core/About.cs b/UVtools.Core/About.cs
index b6c740d..35373a1 100644
--- a/UVtools.Core/About.cs
+++ b/UVtools.Core/About.cs
@@ -6,7 +6,9 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.IO;
+using System.Reflection;
namespace UVtools.Core
{
@@ -19,5 +21,8 @@ namespace UVtools.Core
public static string Donate = "https://paypal.me/SkillTournament";
public static string DemoFile = "UVtools_demo_file.sl1";
+
+ public static Version Version => Assembly.GetExecutingAssembly().GetName().Version;
+ public static string VersionStr => Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
}
}
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 0f0ade7..c667d84 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -216,6 +216,7 @@ namespace UVtools.Core.FileFormats
new GR1File(), // GR1 Workshop
new CXDLPFile(), // Creality Box
new LGSFile(), // LGS, LGS30
+ new VDAFile(), // VDA
new VDTFile(), // VDT
new UVJFile(), // UVJ
new ImageFile(), // images
@@ -367,12 +368,12 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
- public abstract PrintParameterModifier[] PrintParameterModifiers { get; }
+ public virtual PrintParameterModifier[] PrintParameterModifiers => null;
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/> per layer
/// </summary>
- public virtual PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = null;
+ public virtual PrintParameterModifier[] PrintParameterPerLayerModifiers => null;
/// <summary>
/// Checks if a <see cref="PrintParameterModifier"/> exists on print parameters
@@ -476,7 +477,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the original thumbnail sizes
/// </summary>
- public abstract Size[] ThumbnailsOriginalSize { get; }
+ public virtual Size[] ThumbnailsOriginalSize => null;
/// <summary>
/// Gets the thumbnails for this <see cref="FileFormat"/>
@@ -587,12 +588,12 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets or sets the display width in millimeters
/// </summary>
- public abstract float DisplayWidth { get; set; }
+ public virtual float DisplayWidth { get; set; }
/// <summary>
/// Gets or sets the display height in millimeters
/// </summary>
- public abstract float DisplayHeight { get; set; }
+ public virtual float DisplayHeight { get; set; }
/// <summary>
/// Gets or sets if images need to be mirrored on lcd to print on the correct orientation
@@ -904,6 +905,8 @@ namespace UVtools.Core.FileFormats
set => RaiseAndSet(ref _lightPwm, value);
}
+ public bool CanUseBottomLayerCount => HavePrintParameterModifier(PrintParameterModifier.BottomLayerCount);
+
public bool CanUseBottomExposureTime => HavePrintParameterModifier(PrintParameterModifier.BottomExposureSeconds);
public bool CanUseExposureTime => HavePrintParameterModifier(PrintParameterModifier.ExposureSeconds);
public bool CanUseAnyExposureTime => CanUseBottomExposureTime || CanUseExposureTime;
@@ -1528,26 +1531,7 @@ namespace UVtools.Core.FileFormats
"Lower and fix your layer height on slicer to avoid precision errors.", fileFullPath);
}
- bool reSaveFile = false;
-
- if(ResolutionX == 0 || ResolutionY == 0)
- {
- var layer = FirstLayer;
- if (layer is not null)
- {
- using var mat = layer.LayerMat;
-
- if (mat.Size.HaveZero())
- {
- throw new FileLoadException($"File resolution ({Resolution}) is invalid and can't be auto fixed due invalid layers with same problem ({mat.Size}).", fileFullPath);
- }
-
- Resolution = mat.Size;
- reSaveFile = true;
- }
- }
-
- reSaveFile |= _layerManager.Sanitize();
+ bool reSaveFile = _layerManager.Sanitize();
if (reSaveFile)
{
diff --git a/UVtools.Core/FileFormats/VDAFile.cs b/UVtools.Core/FileFormats/VDAFile.cs
new file mode 100644
index 0000000..ab6ab3a
--- /dev/null
+++ b/UVtools.Core/FileFormats/VDAFile.cs
@@ -0,0 +1,432 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Text;
+using System.Xml.Serialization;
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Util;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.OpenSsl;
+using UVtools.Core.Extensions;
+using UVtools.Core.GCode;
+using UVtools.Core.Operations;
+
+namespace UVtools.Core.FileFormats
+{
+ [Serializable]
+ [XmlRoot(ElementName = "root")]
+ public class VDARoot
+ {
+ [Serializable]
+ public class VDAFileInfo
+ {
+ [Serializable]
+ public class VDAVersion
+ {
+ public ushort Major { get; set; } = 1;
+ public ushort Minor { get; set; } = 2;
+
+ }
+
+ [Serializable]
+ public class VDAWritten
+ {
+ [Serializable]
+ [XmlRoot(ElementName = "By")]
+ public class VDABy
+ {
+ [XmlAttribute]
+ public string ApplicationName { get; set; } = About.Software;
+
+ [XmlAttribute]
+ public string ApplicationVersion { get; set; } = About.VersionStr;
+
+ public override string ToString()
+ {
+ return $"{ApplicationName} v{ApplicationVersion}";
+ }
+
+ public void Reset()
+ {
+ ApplicationName = About.Software;
+ ApplicationVersion = About.VersionStr;
+ }
+ }
+
+ public VDABy By { get; set; } = new();
+
+ public string When { get; set; } = DateTime.Now.ToString("u");
+
+ public void Reset()
+ {
+ When = DateTime.Now.ToString("u");
+ By.Reset();
+ }
+ }
+
+
+ public VDAVersion Version { get; set; } = new();
+
+ public VDAWritten Written { get; set; } = new();
+ }
+
+ [Serializable]
+ public class VDASlices
+ {
+ public ushort Count { get; set; } = 1;
+
+ [XmlElement("thickness")]
+ public float LayerHeight { get; set; }
+
+ [XmlElement("startHeight")]
+ public float StartHeight { get; set; }
+
+ [XmlElement("endHeight")]
+ public float EndHeight { get; set; }
+
+ [XmlElement("layersCount")]
+ public uint LayerCount { get; set; }
+ }
+
+ [Serializable]
+ public class VDAMachines
+ {
+ public string FileType { get; set; } = "ZIP File";
+ public string Resolution { get; set; } = "1920*1080P";
+ public string PixelXSize { get; set; } = "50um";
+ public string PixelYSize { get; set; } = "50um";
+
+ [XmlElement("Anti-Aliasing")]
+ public byte AntiAliasing { get; set; } = 1;
+
+ public float XLength { get; set; }
+ public float YWidth { get; set; }
+ public float ZHeight { get; set; }
+ }
+
+ public class VDALayer
+ {
+ [XmlElement("Index")]
+ public uint Index { get; set; }
+
+ [XmlElement("zvalue")]
+ public float ZPosition { get; set; }
+
+ [XmlElement("filename")]
+ public string Filename { get; set; }
+
+ public VDALayer()
+ {
+ }
+
+ public VDALayer(uint index, float zPosition, string filename)
+ {
+ Index = index;
+ ZPosition = zPosition;
+ Filename = filename;
+ }
+ }
+
+
+ public VDAFileInfo FileInfo { get; set; } = new();
+ public VDASlices Slices { get; set; } = new();
+ public VDAMachines Machines { get; set; } = new();
+ public List<VDALayer> Layers { get; set; } = new();
+ }
+
+ public class VDAFile : FileFormat
+ {
+ #region Constants
+
+ #endregion
+
+ #region Properties
+ public VDARoot ManifestFile { get; set; } = new ();
+
+ public override FileFormatType FileType => FileFormatType.Archive;
+
+ public override FileExtension[] FileExtensions { get; } = {
+ new("vda.zip", "Voxeldance Additive Zip")
+ };
+
+ public override uint ResolutionX
+ {
+ get
+ {
+ var resolution = ManifestFile.Machines.Resolution.Split('*', StringSplitOptions.TrimEntries);
+ if (resolution.Length < 2) return 0;
+ uint.TryParse(resolution[0], out var xRes);
+ return xRes;
+ }
+ set
+ {
+ ManifestFile.Machines.Resolution = $"{value}*{ResolutionY}P";
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint ResolutionY
+ {
+ get
+ {
+ var resolution = ManifestFile.Machines.Resolution.Split('*', StringSplitOptions.TrimEntries);
+ if (resolution.Length < 2) return 0;
+ resolution[1] = resolution[1].TrimEnd('P');
+ uint.TryParse(resolution[1], out var yRes);
+ return yRes;
+ }
+ set
+ {
+ ManifestFile.Machines.Resolution = $"{ResolutionX}*{value}P";
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float DisplayWidth
+ {
+ get
+ {
+ if (ManifestFile.Machines.XLength > 0) return ManifestFile.Machines.XLength;
+
+ var umStr= ManifestFile.Machines.PixelXSize.Replace("um", string.Empty, StringComparison.OrdinalIgnoreCase);
+
+ if (ushort.TryParse(umStr, out var um) && um > 0)
+ {
+ return (float) Math.Round(ResolutionX * um / 1000f, 2);
+ }
+
+ return ManifestFile.Machines.XLength;
+ }
+ set
+ {
+ ManifestFile.Machines.XLength = (float) Math.Round(value, 2);
+ ManifestFile.Machines.PixelXSize = $"{Math.Round(value / ResolutionX * 1000, 2)}um";
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float DisplayHeight
+ {
+ get
+ {
+ if (ManifestFile.Machines.YWidth > 0) return ManifestFile.Machines.YWidth;
+
+ var umStr = ManifestFile.Machines.PixelYSize.Replace("um", string.Empty, StringComparison.OrdinalIgnoreCase);
+
+ if (ushort.TryParse(umStr, out var um) && um > 0)
+ {
+ return (float)Math.Round(ResolutionY * um / 1000f, 2);
+ }
+
+ return ManifestFile.Machines.YWidth;
+ }
+ set
+ {
+ ManifestFile.Machines.YWidth = (float)Math.Round(value, 2);
+ ManifestFile.Machines.PixelYSize = $"{Math.Round(value / ResolutionY * 1000, 2)}um";
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float MachineZ
+ {
+ get => ManifestFile.Machines.ZHeight > 0 ? ManifestFile.Machines.ZHeight : base.MachineZ;
+ set
+ {
+ ManifestFile.Machines.ZHeight = value;
+ RaisePropertyChanged();
+ }
+ }
+
+ public override byte AntiAliasing
+ {
+ get => ManifestFile.Machines.AntiAliasing;
+ set
+ {
+ ManifestFile.Machines.AntiAliasing = value.Clamp(1, 16);
+ RaisePropertyChanged();
+ }
+ }
+
+ public override float LayerHeight
+ {
+ get => ManifestFile.Slices.LayerHeight;
+ set
+ {
+ ManifestFile.Slices.LayerHeight = Layer.RoundHeight(value);
+ RaisePropertyChanged();
+ }
+ }
+
+ public override uint LayerCount
+ {
+ get => base.LayerCount;
+ set => base.LayerCount = ManifestFile.Slices.LayerCount = base.LayerCount;
+ }
+
+
+ public override object[] Configs => new object[] {
+ ManifestFile.FileInfo.Version,
+ ManifestFile.FileInfo.Written,
+ ManifestFile.Machines,
+ ManifestFile.Slices };
+
+ #endregion
+
+ #region Constructor
+ public VDAFile()
+ { }
+ #endregion
+
+ #region Methods
+
+ protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
+ {
+ using var outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create);
+ var manifestFilename = Path.GetFileName(fileFullPath).
+ Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml").
+ Replace($".{FileExtensions[0].Extension}", ".xml");
+
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ var layer = this[layerIndex];
+ var filename = $"{layerIndex + 1}".PadLeft(4, '0') + ".png";
+ outputFile.PutFileContent(filename, layer.CompressedBytes, ZipArchiveMode.Create);
+ progress++;
+ }
+
+ UpdateManifest();
+
+ XmlSerializer serializer = new(ManifestFile.GetType());
+ XmlSerializerNamespaces ns = new();
+ ns.Add("", "");
+ var entry = outputFile.CreateEntry(manifestFilename);
+ using var stream = entry.Open();
+ serializer.Serialize(stream, ManifestFile, ns);
+ }
+
+ protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
+ {
+ using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
+ {
+ var entry = inputFile.Entries.FirstOrDefault(zipEntry => zipEntry.Name.EndsWith(".xml"));
+ if (entry is null)
+ {
+ Clear();
+ throw new FileLoadException($".xml manifest not found", fileFullPath);
+ }
+
+ try
+ {
+ var serializer = new XmlSerializer(ManifestFile.GetType());
+ using var stream = entry.Open();
+ ManifestFile = (VDARoot)serializer.Deserialize(stream);
+ }
+ catch (Exception e)
+ {
+ Clear();
+ throw new FileLoadException($"Unable to deserialize '{entry.Name}'\n{e}", fileFullPath);
+ }
+
+
+ LayerManager.Init(ManifestFile.Slices.LayerCount);
+ progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
+
+
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ if (progress.Token.IsCancellationRequested) break;
+ var filename = $"{layerIndex + 1}".PadLeft(4, '0')+".png";
+ entry = inputFile.GetEntry(filename);
+ if (entry is null)
+ {
+ Clear();
+ throw new FileLoadException($"Layer {filename} not found", fileFullPath);
+ }
+
+ using var stream = entry.Open();
+ this[layerIndex] = new Layer(layerIndex, stream, LayerManager);
+
+ progress++;
+ }
+ }
+
+ LayerManager.GetBoundingRectangle(progress);
+ }
+
+ public override void SaveAs(string filePath = null, OperationProgress progress = null)
+ {
+ if (RequireFullEncode)
+ {
+ if (!string.IsNullOrEmpty(filePath))
+ {
+ FileFullPath = filePath;
+ }
+ Encode(FileFullPath, progress);
+ return;
+ }
+
+ if (!string.IsNullOrEmpty(filePath))
+ {
+ File.Copy(FileFullPath, filePath, true);
+ FileFullPath = filePath;
+ }
+
+ using var outputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Update);
+ bool deleted;
+
+ do
+ {
+ deleted = false;
+ foreach (var zipEntry in outputFile.Entries)
+ {
+ if (!zipEntry.Name.EndsWith(".xml")) continue;
+ zipEntry.Delete();
+ deleted = true;
+ break;
+ }
+ } while (deleted);
+
+ var manifestFilename = Path.GetFileName(FileFullPath).
+ Replace($".{FileExtensions[0].Extension}{TemporaryFileAppend}", ".xml").
+ Replace($".{FileExtensions[0].Extension}", ".xml");
+
+ UpdateManifest();
+
+ XmlSerializer serializer = new(ManifestFile.GetType());
+ XmlSerializerNamespaces ns = new();
+ ns.Add("", "");
+ var entry = outputFile.CreateEntry(manifestFilename);
+ using var stream = entry.Open();
+ serializer.Serialize(stream, ManifestFile, ns);
+ }
+
+ public void UpdateManifest()
+ {
+ ManifestFile.FileInfo.Written.Reset();
+ ManifestFile.Slices.StartHeight = FirstLayer.PositionZ;
+ ManifestFile.Slices.EndHeight = LastLayer.PositionZ;
+ ManifestFile.Layers.Clear();
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ var layer = this[layerIndex];
+ ManifestFile.Layers.Add(new VDARoot.VDALayer(layerIndex, layer.PositionZ, layer.FormatFileName(4, false)));
+ }
+ }
+ #endregion
+ }
+}
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index 412adb5..698e87f 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -35,7 +35,7 @@ namespace UVtools.Core.FileFormats
public class ZcodePrintDevice
{
[XmlAttribute("z")]
- public ushort MachineZ { get; set; } = 220;
+ public float MachineZ { get; set; } = 220;
[XmlAttribute("height")]
public uint ResolutionY { get; set; } = 2400;
@@ -257,7 +257,7 @@ namespace UVtools.Core.FileFormats
get => ManifestFile.Device.MachineZ > 0 ? ManifestFile.Device.MachineZ : base.MachineZ;
set
{
- ManifestFile.Device.MachineZ = (ushort) value;
+ ManifestFile.Device.MachineZ = value;
RaisePropertyChanged();
}
}
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index 18d5c51..97b4667 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -514,10 +514,10 @@ namespace UVtools.Core.GCode
AppendLineIfCanComment(BeginLayerComments, layerIndex, layer.PositionZ);
- if (layer.CanExpose)
- {
- AppendShowImageM6054(GetShowImageString(layerIndex));
- }
+ //if (layer.CanExpose)
+ //{ Dont check this for compability
+ AppendShowImageM6054(GetShowImageString(layerIndex));
+ //}
if (liftHeight > 0 && liftZPosAbs > layer.PositionZ)
{
@@ -627,7 +627,7 @@ namespace UVtools.Core.GCode
float positionZ = 0;
for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++)
{
- var layer = slicerFile[layerIndex];
+ var layer = slicerFile[layerIndex];
if(layer is null) continue;
var startStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex));
var endStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex+1));
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index f9f9695..c1e2fc9 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -202,7 +202,8 @@ namespace UVtools.Core
get => _lightPwm;
set
{
- if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
+ if (value == 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
+ if (value == 0) value = FileFormat.DefaultLightPWM;
RaiseAndSetIfChanged(ref _lightPwm, value);
}
}
@@ -511,11 +512,23 @@ namespace UVtools.Core
LightOffDelay = CalculateLightOffDelay(extraTime);
}
- public string FormatFileName(string name)
+ public string FormatFileName(string prepend, byte padDigits, bool layerIndexZeroStarted = true)
{
- return $"{name}{Index.ToString().PadLeft(ParentLayerManager.LayerDigits, '0')}.png";
+ var index = Index;
+ if (!layerIndexZeroStarted)
+ {
+ index++;
+ }
+ return $"{prepend}{index.ToString().PadLeft(padDigits, '0')}.png";
}
+ public string FormatFileName(string prepend = "", bool layerIndexZeroStarted = true)
+ => FormatFileName(prepend, ParentLayerManager.LayerDigits, layerIndexZeroStarted);
+
+ public string FormatFileName(byte padDigits, bool layerIndexZeroStarted = true)
+ => FormatFileName(string.Empty, padDigits, layerIndexZeroStarted);
+
+
public Rectangle GetBoundingRectangle(Mat mat = null, bool reCalculate = false)
{
if (_nonZeroPixelCount > 0 && !reCalculate)
@@ -625,8 +638,8 @@ namespace UVtools.Core
// These arrays are used to
// get row and column numbers
// of 8 neighbors of a given cell
- List<LayerIssue> result = new List<LayerIssue>();
- List<Point> pixels = new List<Point>();
+ List<LayerIssue> result = new();
+ List<Point> pixels = new();
@@ -700,7 +713,7 @@ namespace UVtools.Core
int y2;
- Queue<Point> queue = new Queue<Point>();
+ Queue<Point> queue = new();
queue.Enqueue(new Point(x, y));
// Mark this cell as visited
visited[x, y] = true;
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index df3a950..e7b9c7d 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -441,6 +441,23 @@ namespace UVtools.Core
if (this[layerIndex - 1].PositionZ > this[layerIndex].PositionZ) throw new InvalidDataException($"Layer {layerIndex - 1} ({this[layerIndex - 1].PositionZ}mm) have a higher Z position than the successor layer {layerIndex} ({this[layerIndex].PositionZ}mm).\n");
}
+ if (SlicerFile.ResolutionX == 0 || SlicerFile.ResolutionY == 0)
+ {
+ var layer = FirstLayer;
+ if (layer is not null)
+ {
+ using var mat = layer.LayerMat;
+
+ if (mat.Size.HaveZero())
+ {
+ throw new FileLoadException($"File resolution ({SlicerFile.Resolution}) is invalid and can't be auto fixed due invalid layers with same problem ({mat.Size}).", SlicerFile.FileFullPath);
+ }
+
+ SlicerFile.Resolution = mat.Size;
+ appliedCorrections = true;
+ }
+ }
+
// Fix 0mm positions at layer 0
if (this[0].PositionZ == 0)
{
@@ -452,6 +469,18 @@ namespace UVtools.Core
appliedCorrections = true;
}
+ // Fix LightPWM of 0
+ if (SlicerFile.LightPWM == 0)
+ {
+ SlicerFile.LightPWM = FileFormat.DefaultLightPWM;
+ appliedCorrections = true;
+ }
+ if (SlicerFile.BottomLightPWM == 0)
+ {
+ SlicerFile.BottomLightPWM = FileFormat.DefaultBottomLightPWM;
+ appliedCorrections = true;
+ }
+
return appliedCorrections;
}
@@ -779,7 +808,7 @@ namespace UVtools.Core
if (touchBoundConfig.Enabled)
{
// TouchingBounds Checker
- List<Point> pixels = new List<Point>();
+ List<Point> pixels = new();
bool touchTop = layer.BoundingRectangle.Top <= touchBoundConfig.MarginTop;
bool touchBottom = layer.BoundingRectangle.Bottom >= image.Height - touchBoundConfig.MarginBottom;
bool touchLeft = layer.BoundingRectangle.Left <= touchBoundConfig.MarginLeft;
@@ -1113,7 +1142,7 @@ namespace UVtools.Core
for (int i = 1; i < numLabels; i++)
{
- Rectangle rect = new Rectangle(
+ Rectangle rect = new(
(int) ccStats.GetValue(i, (int) ConnectedComponentsTypes.Left),
(int) ccStats.GetValue(i, (int) ConnectedComponentsTypes.Top),
(int) ccStats.GetValue(i, (int) ConnectedComponentsTypes.Width),
@@ -1128,7 +1157,7 @@ namespace UVtools.Core
previousSpan = previousImage.GetPixelSpan<byte>();
}
- List<Point> points = new List<Point>();
+ List<Point> points = new();
uint pixelsSupportingIsland = 0;
for (int y = rect.Y; y < rect.Bottom; y++)
@@ -1573,7 +1602,7 @@ namespace UVtools.Core
progress ??= new OperationProgress();
progress.Reset("Drawings", (uint) drawings.Count);
- ConcurrentDictionary<uint, Mat> modifiedLayers = new ConcurrentDictionary<uint, Mat>();
+ ConcurrentDictionary<uint, Mat> modifiedLayers = new();
for (var i = 0; i < drawings.Count; i++)
{
var operation = drawings[i];
@@ -1648,7 +1677,7 @@ namespace UVtools.Core
int yStart = Math.Max(0, operation.Location.Y - operationSupport.TipDiameter / 2);
int xStart = Math.Max(0, operation.Location.X - operationSupport.TipDiameter / 2);
- using (Mat matCircleRoi = new Mat(mat, new Rectangle(xStart, yStart, operationSupport.TipDiameter, operationSupport.TipDiameter)))
+ using (Mat matCircleRoi = new(mat, new Rectangle(xStart, yStart, operationSupport.TipDiameter, operationSupport.TipDiameter)))
{
using (Mat matCircleMask = matCircleRoi.CloneBlank())
{
@@ -1683,9 +1712,9 @@ namespace UVtools.Core
int yStart = Math.Max(0, operation.Location.Y - radius);
int xStart = Math.Max(0, operation.Location.X - radius);
- using (Mat matCircleRoi = new Mat(mat, new Rectangle(xStart, yStart, operationDrainHole.Diameter, operationDrainHole.Diameter)))
+ using (Mat matCircleRoi = new(mat, new Rectangle(xStart, yStart, operationDrainHole.Diameter, operationDrainHole.Diameter)))
{
- using (Mat matCircleRoiInv = new Mat())
+ using (Mat matCircleRoiInv = new())
{
CvInvoke.Threshold(matCircleRoi, matCircleRoiInv, 100, 255, ThresholdType.BinaryInv);
using (Mat matCircleMask = matCircleRoi.CloneBlank())
diff --git a/UVtools.Core/Objects/BindableBase.cs b/UVtools.Core/Objects/BindableBase.cs
index 68a7611..9e63a1f 100644
--- a/UVtools.Core/Objects/BindableBase.cs
+++ b/UVtools.Core/Objects/BindableBase.cs
@@ -21,12 +21,11 @@ namespace UVtools.Core.Objects
/// Multicast event for property change notifications.
/// </summary>
private PropertyChangedEventHandler _propertyChanged;
- private List<string> events = new List<string>();
public event PropertyChangedEventHandler PropertyChanged
{
- add { _propertyChanged += value; events.Add("added"); }
- remove { _propertyChanged -= value; events.Add("removed"); }
+ add => _propertyChanged += value;
+ remove => _propertyChanged -= value;
}
/// <summary>
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index b7f7955..5cb7cad 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -235,6 +235,8 @@ namespace UVtools.Core.Operations
public bool HaveMask => _maskPoints is not null && _maskPoints.Length > 0;
+ public bool HaveROIorMask => HaveROI || HaveMask;
+
/// <summary>
/// Gets if this operation have been executed once
/// </summary>
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index 9109e29..9fb8d6b 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -128,7 +128,7 @@ namespace UVtools.Core.Operations
private bool _bullsEyeInvertQuadrants = true;
private bool _counterTrianglesEnabled = true;
- private sbyte _counterTrianglesTipOffset = 1;
+ private sbyte _counterTrianglesTipOffset = 3;
private bool _counterTrianglesFence = false;
private bool _patternModel;
diff --git a/UVtools.Core/Operations/OperationLayerArithmetic.cs b/UVtools.Core/Operations/OperationLayerArithmetic.cs
index 2ea9bc8..721f8c9 100644
--- a/UVtools.Core/Operations/OperationLayerArithmetic.cs
+++ b/UVtools.Core/Operations/OperationLayerArithmetic.cs
@@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
@@ -53,6 +54,8 @@ namespace UVtools.Core.Operations
#endregion
#region Overrides
+
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
public override string Title => "Layer arithmetic";
public override string Description =>
"Perform arithmetic operations over the layers\n" +
@@ -63,7 +66,7 @@ namespace UVtools.Core.Operations
"Syntax: <set_to_layer_indexes> = <layer_index> <operator> <layer_index>\n" +
"When: \"<set_to_layer_indexes> =\" is omitted, the result will assign to the first layer on the sentence.\n\n" +
"Example 1: 10+11\n" +
- "Example 2: 10,11,12 = 11+12-10*5\n" +
+ "Example 2: 10,11,12 = 11+12-10*5 Same as: 10:12 = 11+12-10*5\n" +
"On example 1 the layer 10 will be set with the result of layer 10 plus layer 11.\n" +
"On example 2 the layers 10,11,12 will be set with the result of layer 11 plus 12 minus 10 all multiplied by layer 5.\n\n" +
"Note: Calculation are made sequential, math order rules wont apply here.";
@@ -87,13 +90,15 @@ namespace UVtools.Core.Operations
sb.AppendLine("No layers to assign.");
else if (Operations.Count == 0)
sb.AppendLine("No operations to perform.");
+ else if (!IsValid)
+ sb.AppendLine("The operation will have no impact and will not be performed.");
return sb.ToString();
}
public override string ToString()
{
- var result = $"{_sentence}" + LayerRangeString;
+ var result = $"{_sentence}";
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -106,12 +111,13 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _sentence, value);
}
[XmlIgnore]
- public List<ArithmeticOperation> Operations { get; } = new();
+ public List<ArithmeticOperation> Operations { get; private set; } = new();
[XmlIgnore]
- public List<uint> SetLayers { get; } = new List<uint>();
+ public List<uint> SetLayers { get; private set; } = new();
- public bool IsValid => SetLayers.Count > 0 & Operations.Count > 0;
+ public bool IsValid => SetLayers.Count > 0 && Operations.Count > 0 &&
+ !(SetLayers.Count == 1 && Operations.Count == 1 && SetLayers[0] == Operations[0].LayerIndex);
#endregion
#region Constructor
@@ -135,15 +141,31 @@ namespace UVtools.Core.Operations
if (splitSentence.Length >= 2)
{
operations = splitSentence[1];
- var setLayers = splitSentence[0].Replace(" ", string.Empty).Split(',');
+ var setLayers = splitSentence[0].Replace(" ", string.Empty).Split(',', StringSplitOptions.TrimEntries);
foreach (var layer in setLayers)
{
+ var rangeSplit = layer.Split(':', StringSplitOptions.TrimEntries);
+ if (rangeSplit.Length > 1)
+ {
+ uint.TryParse(rangeSplit[0].Trim(), out var startLayer);
+ if (!uint.TryParse(rangeSplit[1].Trim(), out var endLayer)) endLayer = SlicerFile.LastLayerIndex;
+ for (var index = startLayer; index <= endLayer; index++)
+ {
+ if (SetLayers.Contains(index)) continue;
+ SetLayers.Add(index);
+ }
+ continue;
+ }
+
if (!uint.TryParse(layer.Trim(), out var layerIndex)) continue;
if (SetLayers.Contains(layerIndex)) continue;
SetLayers.Add(layerIndex);
}
}
+ SetLayers = SetLayers.Where(layerIndex => layerIndex <= SlicerFile.LastLayerIndex).ToList();
+ SetLayers.Sort();
+
operations = operations.Replace(" ", string.Empty);
if (string.IsNullOrWhiteSpace(operations)) return false;
@@ -208,8 +230,10 @@ namespace UVtools.Core.Operations
}
}
- if (Operations.Count == 0) return false;
- if (SetLayers.Count == 0)
+ Operations = Operations.Where(op => op.LayerIndex <= SlicerFile.LastLayerIndex).ToList();
+
+ //if (Operations.Count == 0) return false;
+ if (SetLayers.Count == 0 && Operations.Count > 0)
{
SetLayers.Add(Operations[0].LayerIndex);
}
@@ -223,12 +247,15 @@ namespace UVtools.Core.Operations
using var result = SlicerFile[Operations[0].LayerIndex].LayerMat;
using var resultRoi = GetRoiOrDefault(result);
+ using var imageMask = GetMask(resultRoi);
+
+ progress.ItemCount = (uint) Operations.Count;
for (int i = 1; i < Operations.Count; i++)
{
progress.Token.ThrowIfCancellationRequested();
using var image = SlicerFile[Operations[i].LayerIndex].LayerMat;
var imageRoi = GetRoiOrDefault(image);
- using var imageMask = GetMask(image);
+
switch (Operations[i - 1].Operator)
{
case LayerArithmeticOperators.Add:
@@ -256,20 +283,26 @@ namespace UVtools.Core.Operations
CvInvoke.AbsDiff(resultRoi, imageRoi, resultRoi);
break;
}
+
+ progress++;
}
+ progress.Reset("Applied layers", (uint) SetLayers.Count);
Parallel.ForEach(SetLayers, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
- if (Operations.Count == 1 && HaveROI)
+ progress.LockAndIncrement();
+ if (Operations.Count == 1 || HaveROIorMask)
{
- var mat = SlicerFile[layerIndex].LayerMat;
+ using var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = GetRoiOrDefault(mat);
- using var imageMask = GetMask(mat);
resultRoi.CopyTo(matRoi, imageMask);
SlicerFile[layerIndex].LayerMat = mat;
return;
}
+
+ //ApplyMask(mat, resultRoi, imageMask);
+
SlicerFile[layerIndex].LayerMat = result;
});
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index d3eac6a..46b05c3 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
- <Version>2.11.2</Version>
+ <Version>2.12.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -49,7 +49,7 @@
<PackageReference Include="AnimatedGif" Version="1.0.5" />
<PackageReference Include="BinarySerializer" Version="8.6.0" />
<PackageReference Include="Emgu.CV" Version="4.5.1.4349" />
- <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0-2.final" />
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.10.0-3.final" />
<PackageReference Include="morelinq" Version="3.3.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />