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-03-28 06:26:01 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-03-28 06:26:01 +0300
commit1e9bbf9562357f1c53db91f0148cfc01e9db2d62 (patch)
treeca763c375807ae8243c23438aac301d90f8046d5
parent2231fdaca309cec03bb02e59a52ed6685a906cf4 (diff)
v2.7.2v2.7.2
* **Core:** * Fix some improper locks for progress counter and change to Interlocked instead * Fix a bug when chaging layer count by remove or add layers it will malform the file after save and crash the program with some tools and/or clipboard * Fix when a operation fails by other reason different from cancelation it was not restoring the backup * When manually delete/fix issues it will also backup the layers * **LayerManager:** * LayerManager is now readonly and no longer used to transpose layers, each FileFormat have now a unique `LayerManager` instance which is set on the generic constructor * Implemented `List<Layer>` methods to easy modify the layers array * Changing the `Layers` instance will now recompute some properties, call the properties rebuild and forced sanitize of the structure * Better reallocation methods * **Clipboard Manager:** * Add the hability to do full backups, they will be marked with an asterisk (*) at clipboard items list * When a partial backup is made and it backups all the layers it will be converted to full backup * Clipboard can now restore a snapshot directly with `RestoreSnapshot` * Prevent restore the initial backup upon file load and when clearing the clipboard * Clip's that change the layer count will perform a full backup and also do a fail-safe backup behind if previous clip is not a full backup * **Pixel dimming:** * Allow to load an image file as a pattern (Do not use very large files or it will take much time to dump the data into the textbox) * Empty lines on patterns will be discarded and not trigger validation error
-rw-r--r--CHANGELOG.md22
-rw-r--r--CREDITS.md4
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs5
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs155
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs14
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs4
-rw-r--r--UVtools.Core/FileFormats/FDGFile.cs12
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs39
-rw-r--r--UVtools.Core/FileFormats/ImageFile.cs3
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs12
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs12
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs12
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs12
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs2
-rw-r--r--UVtools.Core/FileFormats/UVJFile.cs2
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs2
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs2
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs4
-rw-r--r--UVtools.Core/Layer/Layer.cs12
-rw-r--r--UVtools.Core/Layer/LayerManager.cs477
-rw-r--r--UVtools.Core/Managers/ClipboardManager.cs274
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs5
-rw-r--r--UVtools.Core/Operations/OperationCalibrateStressTower.cs5
-rw-r--r--UVtools.Core/Operations/OperationCalibrateTolerance.cs5
-rw-r--r--UVtools.Core/Operations/OperationChangeResolution.cs5
-rw-r--r--UVtools.Core/Operations/OperationFlip.cs5
-rw-r--r--UVtools.Core/Operations/OperationInfill.cs7
-rw-r--r--UVtools.Core/Operations/OperationLayerClone.cs25
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs15
-rw-r--r--UVtools.Core/Operations/OperationLayerReHeight.cs20
-rw-r--r--UVtools.Core/Operations/OperationLayerRemove.cs16
-rw-r--r--UVtools.Core/Operations/OperationMask.cs5
-rw-r--r--UVtools.Core/Operations/OperationMorph.cs7
-rw-r--r--UVtools.Core/Operations/OperationMove.cs5
-rw-r--r--UVtools.Core/Operations/OperationPattern.cs5
-rw-r--r--UVtools.Core/Operations/OperationPixelDimming.cs56
-rw-r--r--UVtools.Core/Operations/OperationProgress.cs12
-rw-r--r--UVtools.Core/Operations/OperationRaftRelief.cs5
-rw-r--r--UVtools.Core/Operations/OperationRedrawModel.cs5
-rw-r--r--UVtools.Core/Operations/OperationRepairLayers.cs10
-rw-r--r--UVtools.Core/Operations/OperationResize.cs5
-rw-r--r--UVtools.Core/Operations/OperationRotate.cs5
-rw-r--r--UVtools.Core/Operations/OperationSolidify.cs7
-rw-r--r--UVtools.Core/Operations/OperationThreshold.cs5
-rw-r--r--UVtools.Core/UVtools.Core.csproj4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml37
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs13
-rw-r--r--UVtools.WPF/MainWindow.Issues.cs14
-rw-r--r--UVtools.WPF/MainWindow.PixelEditor.cs10
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs13
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj2
51 files changed, 753 insertions, 661 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf60600..68b0ffa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,27 @@
# Changelog
+## 28/03/2021 - v2.7.2
+
+* **Core:**
+ * Fix some improper locks for progress counter and change to Interlocked instead
+ * Fix a bug when chaging layer count by remove or add layers it will malform the file after save and crash the program with some tools and/or clipboard
+ * Fix when a operation fails by other reason different from cancelation it was not restoring the backup
+ * When manually delete/fix issues it will also backup the layers
+* **LayerManager:**
+ * LayerManager is now readonly and no longer used to transpose layers, each FileFormat have now a unique `LayerManager` instance which is set on the generic constructor
+ * Implemented `List<Layer>` methods to easy modify the layers array
+ * Changing the `Layers` instance will now recompute some properties, call the properties rebuild and forced sanitize of the structure
+ * Better reallocation methods
+* **Clipboard Manager:**
+ * Add the hability to do full backups, they will be marked with an asterisk (*) at clipboard items list
+ * When a partial backup is made and it backups all the layers it will be converted to full backup
+ * Clipboard can now restore a snapshot directly with `RestoreSnapshot`
+ * Prevent restore the initial backup upon file load and when clearing the clipboard
+ * Clip's that change the layer count will perform a full backup and also do a fail-safe backup behind if previous clip is not a full backup
+* **Pixel dimming:**
+ * Allow to load an image file as a pattern (Do not use very large files or it will take much time to dump the data into the textbox)
+ * Empty lines on patterns will be discarded and not trigger validation error
+
## 24/03/2021 - v2.7.1
* **File formats:**
diff --git a/CREDITS.md b/CREDITS.md
index ab77ebd..7bb93fa 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -49,4 +49,6 @@
* Nicholas Taylor
* Nadine Maillard
* Sidney Cheng
-* Ben Ford \ No newline at end of file
+* Ben Ford
+* Mario Molero
+* Dennis Hansen \ No newline at end of file
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index 2eaa12a..a6aa974 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -252,7 +252,8 @@ namespace UVtools.Core.Extensions
public static Mat InitMat(Size size, int channels = 1, DepthType depthType = DepthType.Cv8U)
{
- var mat = new Mat(size, depthType, channels);
+ return Mat.Zeros(size.Height, size.Width, depthType, channels);
+ /*var mat = new Mat(size, depthType, channels);
switch (channels)
{
case 1:
@@ -266,7 +267,7 @@ namespace UVtools.Core.Extensions
break;
}
- return mat;
+ return mat;*/
}
public static Mat InitMat(Size size, MCvScalar scalar, int channels = 1, DepthType depthType = DepthType.Cv8U)
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index d620337..f8863bb 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -770,7 +770,7 @@ namespace UVtools.Core.FileFormats
tr.Close();
}
- LayerManager = new LayerManager(OutputSettings.LayersNum, this);
+ LayerManager.Init(OutputSettings.LayersNum);
progress.ItemCount = OutputSettings.LayersNum;
@@ -832,159 +832,6 @@ namespace UVtools.Core.FileFormats
}
}
- /*inputFile.Entries.AsParallel().ForAllInApproximateOrder(zipArchiveEntry =>
- //foreach (var zipArchiveEntry in inputFile.Entries)
- {
- if (!zipArchiveEntry.Name.EndsWith(".png") || progress.Token.IsCancellationRequested) return;
-
- var layerIndexStr = string.Empty;
- var layerStr = zipArchiveEntry.Name.Substring(0, zipArchiveEntry.Name.Length - 4);
- for (int i = layerStr.Length-1; i >= 0; i--)
- {
- if(layerStr[i] < '0' || layerStr[i] > '9') break;
- layerIndexStr = $"{layerStr[i]}{layerIndexStr}";
- }
-
- if (string.IsNullOrEmpty(layerIndexStr)) return;
-
- // - .png - 4 numbers
- // string layerStr = zipArchiveEntry.Name.Substring(zipArchiveEntry.Name.Length - 4 - layerSize, layerSize);
- uint layerIndex = uint.Parse(layerIndexStr);
-
- var startStr = $"{GCodeKeywordSlice} {layerIndex}";
- var stripGcode =
- gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) +
- startStr.Length);
-
- var endStr = $"{GCodeKeywordSlice} {layerIndex + 1}";
- var endIndex = stripGcode.IndexOf(endStr, StringComparison.InvariantCulture);
- if (endIndex < 0) endIndex = stripGcode.Length;
- stripGcode = stripGcode
- .Substring(0, endIndex)
- .Trim(' ', '\n', '\r', '\t');
- //var startCurrPos = stripGcode.Remove(0, ";currPos:".Length);
-
- float liftHeight = 0;
- float liftSpeed = GetInitialLayerValueOrNormal(layerIndex, BottomLiftSpeed, LiftSpeed);
- float retractSpeed = RetractSpeed;
- float lightOffDelay = GetInitialLayerValueOrNormal(layerIndex, BottomLightOffDelay, LightOffDelay);
- byte pwm = GetInitialLayerValueOrNormal(layerIndex, BottomLightPWM, LightPWM); ;
- float exposureTime = GetInitialLayerValueOrNormal(layerIndex, BottomExposureTime, ExposureTime);
-
- //var currPos = Regex.Match(stripGcode, "G1 Z([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase);
- var moveG1Regex = Regex.Match(stripGcode, @"G1 Z([+-]?([0-9]*[.])?[0-9]+) F(\d+)", RegexOptions.IgnoreCase);
- var pwmM106Regex = Regex.Match(stripGcode, @"M106 S(\d+)", RegexOptions.IgnoreCase);
- var waitRegex = Regex.Match(stripGcode, ";<Delay> (\\d+)", RegexOptions.IgnoreCase);
-
- if (moveG1Regex.Success)
- {
- var liftHeightTemp = float.Parse(moveG1Regex.Groups[1].Value, CultureInfo.InvariantCulture);
- var liftSpeedTemp = float.Parse(moveG1Regex.Groups[3].Value, CultureInfo.InvariantCulture);
- moveG1Regex = moveG1Regex.NextMatch();
- if (moveG1Regex.Success)
- {
- liftHeight = liftHeightTemp;
- liftSpeed = liftSpeedTemp;
- retractSpeed = float.Parse(moveG1Regex.Groups[3].Value, CultureInfo.InvariantCulture);
- }
- }
-
- if (pwmM106Regex.Success)
- {
- pwm = byte.Parse(pwmM106Regex.Groups[1].Value);
- }
- if (layerIndex == 0)
- {
- OutputSettings.BottomLightPWM = pwm;
- }
-
- if (waitRegex.Success)
- {
- exposureTime = (float)Math.Round(float.Parse(waitRegex.Groups[1].Value, CultureInfo.InvariantCulture) / 1000f, 2);
- waitRegex = waitRegex.NextMatch();
- if (waitRegex.Success)
- {
- lightOffDelay = (float)Math.Round(float.Parse(waitRegex.Groups[1].Value, CultureInfo.InvariantCulture) / 1000f, 2);
- }
- else // Only one match, meaning light off delay is not present
- {
- lightOffDelay = GetInitialLayerValueOrNormal(layerIndex, BottomLightOffDelay, LightOffDelay);
- }
- }
-
- byte[] buffer;
-
- lock (progress.Mutex)
- {
- using (var stream = zipArchiveEntry.Open())
- {
- buffer = stream.ToArray();
- if (Printer == PrinterType.Unknown)
- {
- using (Mat mat = new Mat())
- {
- CvInvoke.Imdecode(buffer, ImreadModes.AnyColor, mat);
- Printer = mat.NumberOfChannels == 1 ? PrinterType.Elfin : PrinterType.BeneMono;
- }
- }
-
- stream.Close();
- }
- }
-
-
- if (Printer == PrinterType.BeneMono)
- {
- using (Mat mat = new Mat())
- {
- CvInvoke.Imdecode(buffer, ImreadModes.Color, mat);
- using (Mat matDecode = new Mat(mat.Height, mat.Step, DepthType.Cv8U, 1))
- {
- var span = mat.GetPixelSpan<byte>();
- var spanDecode = matDecode.GetPixelSpan<byte>();
- for (int i = 0; i < span.Length; i++)
- {
- spanDecode[i] = span[i];
- }
-
- this[layerIndex] =
- new Layer(layerIndex, matDecode, LayerManager)
- {
- ExposureTime = exposureTime,
- LiftHeight = liftHeight,
- LiftSpeed = liftSpeed,
- RetractSpeed = retractSpeed,
- LightOffDelay = lightOffDelay,
- LightPWM = pwm,
- };
- }
- }
- }
- else
- {
- this[layerIndex] =
- new Layer(layerIndex, buffer, LayerManager)
- {
- ExposureTime = exposureTime,
- LiftHeight = liftHeight,
- LiftSpeed = liftSpeed,
- RetractSpeed = retractSpeed,
- LightOffDelay = lightOffDelay,
- LightPWM = pwm,
- };
- }
-
- progress++;
- });
-
- // Fix missing values from configuration
- if (LayerCount > 0 && this[0] is not null)
- {
- SuppressRebuildProperties = true;
- BottomLiftHeight = this[0].LiftHeight;
- BottomLightOffDelay = this[0].LightOffDelay;
- SuppressRebuildProperties = false;
- }*/
LayerManager.GetBoundingRectangle(progress);
}
diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index 070d08f..2e4949a 100644
--- a/UVtools.Core/FileFormats/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -1384,10 +1384,7 @@ namespace UVtools.Core.FileFormats
LayerDefinitions[aaIndex, layerIndex] = layerData;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
@@ -1559,7 +1556,7 @@ namespace UVtools.Core.FileFormats
}
}
- LayerManager = new LayerManager(HeaderSettings.LayerCount, this);
+ LayerManager.Init(HeaderSettings.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
@@ -1589,11 +1586,8 @@ namespace UVtools.Core.FileFormats
this[layerIndex] = layer;
-
- lock (progress.Mutex)
- {
- progress++;
- }
+
+ progress.LockAndIncrement();
});
}
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index 7e90511..ed8a707 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -438,7 +438,7 @@ namespace UVtools.Core.FileFormats
}
}
- LayerManager = new LayerManager(HeaderSettings.LayerCount, this);
+ LayerManager.Init(HeaderSettings.LayerCount);
progress.ItemCount = LayerCount;
@@ -487,7 +487,7 @@ namespace UVtools.Core.FileFormats
}
entry = inputFile.GetEntry("preview_cropping.png");
- if (!ReferenceEquals(entry, null))
+ if (entry is not null)
{
var count = CreatedThumbnailsCount;
Thumbnails[count] = new Mat();
diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs
index 2febaf6..9aa0eda 100644
--- a/UVtools.Core/FileFormats/FDGFile.cs
+++ b/UVtools.Core/FileFormats/FDGFile.cs
@@ -995,10 +995,7 @@ namespace UVtools.Core.FileFormats
LayersDefinitions[layerIndex] = layer;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
@@ -1129,7 +1126,7 @@ namespace UVtools.Core.FileFormats
progress.Token.ThrowIfCancellationRequested();
}
- LayerManager = new LayerManager(HeaderSettings.LayerCount, this);
+ LayerManager.Init(HeaderSettings.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
@@ -1150,10 +1147,7 @@ namespace UVtools.Core.FileFormats
};
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
}
}
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index a99f567..86690fe 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -482,7 +482,8 @@ namespace UVtools.Core.FileFormats
public LayerManager LayerManager
{
get => _layerManager;
- set
+ private init => _layerManager = value;
+ /*set
{
var oldLayerManager = _layerManager;
if (!RaiseAndSetIfChanged(ref _layerManager, value) || value is null) return;
@@ -499,14 +500,14 @@ namespace UVtools.Core.FileFormats
if (oldLayerManager is null) return; // Init
- if (oldLayerManager.Count != LayerCount)
+ if (oldLayerManager.LayerCount != LayerCount)
{
- LayerCount = _layerManager.Count;
+ LayerCount = _layerManager.LayerCount;
if (SuppressRebuildProperties) return;
- if (LayerCount == 0 || this[LayerCount - 1] is null) return; // Not initialized
+ if (LayerCount == 0 || this[LastLayerIndex] is null) return; // Not initialized
LayerManager.RebuildLayersProperties();
}
- }
+ }*/
}
/// <summary>
@@ -722,7 +723,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the last layer index
/// </summary>
- public uint LastLayerIndex => LayerCount - 1;
+ public uint LastLayerIndex => LayerManager?.LastLayerIndex ?? 0;
/// <summary>
/// Checks if this file format supports per layer settings
@@ -734,7 +735,7 @@ namespace UVtools.Core.FileFormats
/// </summary>
public virtual uint LayerCount
{
- get => LayerManager?.Count ?? 0;
+ get => LayerManager?.LayerCount ?? 0;
set {
RaisePropertyChanged();
RaisePropertyChanged(nameof(NormalLayerCount));
@@ -1027,6 +1028,7 @@ namespace UVtools.Core.FileFormats
#region Constructor
protected FileFormat()
{
+ LayerManager = new(this);
Thumbnails = new Mat[ThumbnailsCount];
PropertyChanged += OnPropertyChanged;
}
@@ -1082,7 +1084,7 @@ namespace UVtools.Core.FileFormats
#region Numerators
public IEnumerator<Layer> GetEnumerator()
{
- return ((IEnumerable<Layer>)LayerManager.Layers).GetEnumerator();
+ return LayerManager.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
@@ -1123,7 +1125,7 @@ namespace UVtools.Core.FileFormats
public virtual void Clear()
{
FileFullPath = null;
- LayerManager = null;
+ LayerManager.Clear();
GCode.Clear();
if (Thumbnails is not null)
@@ -1491,16 +1493,11 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
var byteArr = layer.CompressedBytes;
- using (FileStream stream = File.Create(Path.Combine(path, layer.Filename),
- byteArr.Length))
- {
- stream.Write(byteArr, 0, byteArr.Length);
- stream.Close();
- lock (progress.Mutex)
- {
- progress++;
- }
- }
+ using var stream = File.Create(Path.Combine(path, layer.Filename),
+ byteArr.Length);
+ stream.Write(byteArr, 0, byteArr.Length);
+ stream.Close();
+ progress.LockAndIncrement();
});
}
}
@@ -1813,9 +1810,9 @@ namespace UVtools.Core.FileFormats
slicerFile.SuppressRebuildPropertiesWork(() =>
{
- slicerFile.LayerManager = _layerManager.Clone();
+ slicerFile.LayerManager.Init(_layerManager.CloneLayers());
slicerFile.AntiAliasing = ValidateAntiAliasingLevel();
- slicerFile.LayerCount = _layerManager.Count;
+ slicerFile.LayerCount = _layerManager.LayerCount;
slicerFile.BottomLayerCount = BottomLayerCount;
slicerFile.LayerHeight = LayerHeight;
slicerFile.ResolutionX = ResolutionX;
diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs
index da2cec9..668e2a8 100644
--- a/UVtools.Core/FileFormats/ImageFile.cs
+++ b/UVtools.Core/FileFormats/ImageFile.cs
@@ -97,8 +97,7 @@ namespace UVtools.Core.FileFormats
{
CvInvoke.CvtColor(ImageMat, ImageMat, ColorConversion.Bgr2Gray);
}*/
-
- LayerManager = new LayerManager(1, this);
+ LayerManager.Init(1);
this[0] = new Layer(0, ImageMat, LayerManager);
}
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index da5a3e4..03143e3 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -457,10 +457,7 @@ namespace UVtools.Core.FileFormats
layerData[layerIndex].Encode(mat);
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.ItemName = "Saving layers";
@@ -536,7 +533,7 @@ namespace UVtools.Core.FileFormats
layerData[layerIndex].Parent = this;
}
- LayerManager = new LayerManager(HeaderSettings.LayerCount, this);
+ LayerManager.Init(HeaderSettings.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
Parallel.For(0, LayerCount,
@@ -548,10 +545,7 @@ namespace UVtools.Core.FileFormats
using var image = layerData[layerIndex].Decode();
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
LayerManager.RebuildLayersProperties();
diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index 861d163..2a6491f 100644
--- a/UVtools.Core/FileFormats/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -1020,10 +1020,7 @@ namespace UVtools.Core.FileFormats
LayersDefinitions[layerIndex] = layer;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.Reset(OperationProgress.StatusWritingFile, LayerCount);
@@ -1151,7 +1148,7 @@ namespace UVtools.Core.FileFormats
progress.Token.ThrowIfCancellationRequested();
}
- LayerManager = new LayerManager(HeaderSettings.LayerCount, this);
+ LayerManager.Init(HeaderSettings.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, HeaderSettings.LayerCount);
@@ -1172,10 +1169,7 @@ namespace UVtools.Core.FileFormats
};
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
}
}
diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs
index 50e99c6..d881a4f 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -406,10 +406,7 @@ namespace UVtools.Core.FileFormats
layerData[layerIndex].Encode(mat);
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.ItemName = "Saving layers";
@@ -491,7 +488,7 @@ namespace UVtools.Core.FileFormats
Debug.WriteLine($"Layer {layerIndex} -> {layerData[layerIndex]}");
}
- LayerManager = new LayerManager(LayerSettings.LayerCount, this);
+ LayerManager.Init(LayerSettings.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
Parallel.For(0, LayerCount,
@@ -502,10 +499,7 @@ namespace UVtools.Core.FileFormats
using var image = layerData[layerIndex].Decode();
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
LayerManager.RebuildLayersProperties();
diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
index 7ef1934..00e9670 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -1301,10 +1301,7 @@ namespace UVtools.Core.FileFormats
layer.Encode(image);
LayersDefinition.Layers[layerIndex] = layer;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
uint offsetLayerRle = FileMarkSettings.LayerImageAddress = (uint) (currentOffset + Helpers.Serializer.SizeOf(LayersDefinition.Section) + LayersDefinition.Section.Length);
@@ -1396,7 +1393,7 @@ namespace UVtools.Core.FileFormats
Debug.Write("LayersDefinition -> ");
Debug.WriteLine(LayersDefinition);
- LayerManager = new LayerManager(LayersDefinition.LayerCount, this);
+ LayerManager.Init(LayersDefinition.LayerCount);
LayersDefinition.Layers = new LayerData[LayerCount];
@@ -1443,10 +1440,7 @@ namespace UVtools.Core.FileFormats
};
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
// Fix position z height values
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 7f854f1..05e32ae 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -641,7 +641,7 @@ namespace UVtools.Core.FileFormats
LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM);
});
- LayerManager = new LayerManager((uint) (OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast), this);
+ LayerManager.Init(OutputConfigSettings.NumSlow + OutputConfigSettings.NumFast);
progress.ItemCount = LayerCount;
diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs
index e30f5da..222ded1 100644
--- a/UVtools.Core/FileFormats/UVJFile.cs
+++ b/UVtools.Core/FileFormats/UVJFile.cs
@@ -397,7 +397,7 @@ namespace UVtools.Core.FileFormats
JsonSettings = Helpers.JsonDeserializeObject<Settings>(entry.Open());
- LayerManager = new LayerManager(JsonSettings.Properties.Size.Layers, this);
+ LayerManager.Init(JsonSettings.Properties.Size.Layers);
entry = inputFile.GetEntry(FilePreviewTinyName);
if (!ReferenceEquals(entry, null))
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index bb113a2..86e08e3 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -528,7 +528,7 @@ namespace UVtools.Core.FileFormats
tr.Close();
}
- LayerManager = new LayerManager(ManifestFile.Job.LayerCount, this);
+ LayerManager.Init(ManifestFile.Job.LayerCount);
progress.Reset(OperationProgress.StatusDecodeLayers, LayerCount);
//var gcode = GCode.ToString();
diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index 16cdcd7..e0137a4 100644
--- a/UVtools.Core/FileFormats/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -485,7 +485,7 @@ namespace UVtools.Core.FileFormats
throw new FileLoadException("ResinGCodeData not found", fileFullPath);
}
- LayerManager = new LayerManager(ResinMetadataSettings.TotalLayersCount, this);
+ LayerManager.Init(ResinMetadataSettings.TotalLayersCount);
GCode.Clear();
using (TextReader tr = new StreamReader(entry.Open()))
{
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index 33b5cc0..211832d 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -450,11 +450,11 @@ namespace UVtools.Core.GCode
public void RebuildGCode(FileFormat slicerFile, StringBuilder header) => RebuildGCode(slicerFile, header?.ToString());
public void RebuildGCode(FileFormat slicerFile, string header = null)
{
- if (slicerFile.LayerCount == 0) return;
Clear();
-
AppendUVtools();
+ if (slicerFile.LayerCount == 0) return;
+
if (!string.IsNullOrWhiteSpace(header))
{
Append(header);
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index a202ccf..b01fc52 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -537,7 +537,7 @@ namespace UVtools.Core
public Layer NextLayer()
{
- if (ParentLayerManager is null || _index >= ParentLayerManager.Count - 1)
+ if (ParentLayerManager is null || _index >= ParentLayerManager.LayerCount - 1)
return null;
return ParentLayerManager[_index + 1];
@@ -802,6 +802,16 @@ namespace UVtools.Core
public static string ShowHeight(double height) => string.Format($"{{0:F{HeightPrecision}}}", height);
public static string ShowHeight(decimal height) => string.Format($"{{0:F{HeightPrecision}}}", height);
+ public static Layer[] CloneLayers(Layer[] layers)
+ {
+ var clonedLayers = new Layer[layers.Length];
+ for (uint layerIndex = 0; layerIndex < layers.Length; layerIndex++)
+ {
+ clonedLayers[layerIndex] = layers[layerIndex]?.Clone();
+ }
+ return clonedLayers;
+ }
+
#endregion
}
}
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index 9a60479..49a6730 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -26,7 +26,7 @@ using UVtools.Core.PixelEditor;
namespace UVtools.Core
{
- public class LayerManager : BindableBase, IEnumerable<Layer>, IDisposable
+ public class LayerManager : BindableBase, IList<Layer>, IDisposable
{
#region Properties
public FileFormat SlicerFile { get; set; }
@@ -39,21 +39,53 @@ namespace UVtools.Core
public Layer[] Layers
{
get => _layers;
- protected internal set
+ set
{
+ //if (ReferenceEquals(_layers, value)) return;
+
+ var rebuildProperties = false;
+ var oldLayerCount = LayerCount;
+ var oldLayers = _layers;
_layers = value;
BoundingRectangle = Rectangle.Empty;
- if (SlicerFile.LayerCount != Count)
+ if (LayerCount != oldLayerCount)
{
- SlicerFile.LayerCount = Count;
+ SlicerFile.LayerCount = LayerCount;
}
SlicerFile.RequireFullEncode = true;
- if (value is null) return;
- SetAllIsModified(true);
+ SlicerFile.PrintHeight = SlicerFile.PrintHeight;
SlicerFile.PrintTime = SlicerFile.PrintTimeComputed;
- SlicerFile.RebuildGCode();
+
+ if (value is not null && LayerCount > 0)
+ {
+ SlicerFile.MaterialMilliliters = 0;
+ //SetAllIsModified(true);
+
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) // Forced sanitize
+ {
+ if (_layers[layerIndex] is null) continue;
+ _layers[layerIndex].Index = layerIndex;
+ _layers[layerIndex].ParentLayerManager = this;
+
+ if (layerIndex >= oldLayerCount || layerIndex < oldLayerCount && !_layers[layerIndex].Equals(oldLayers[layerIndex]))
+ {
+ // Marks as modified only if layer image changed on this index
+ _layers[layerIndex].IsModified = true;
+ }
+ }
+
+ if (LayerCount != oldLayerCount && !SlicerFile.SuppressRebuildProperties && LastLayer is not null)
+ {
+ RebuildLayersProperties();
+ rebuildProperties = true;
+ }
+ }
+
+ if(!rebuildProperties) SlicerFile.RebuildGCode();
+
+ RaisePropertyChanged();
}
}
@@ -68,6 +100,11 @@ namespace UVtools.Core
public Layer LastLayer => _layers?[^1];
/// <summary>
+ /// Gets the last layer index
+ /// </summary>
+ public uint LastLayerIndex => LayerCount - 1;
+
+ /// <summary>
/// Gets the bounding rectangle of the object
/// </summary>
private Rectangle _boundingRectangle = Rectangle.Empty;
@@ -101,14 +138,135 @@ namespace UVtools.Core
(float)Math.Round(_boundingRectangle.Height * pixelSize.Height, 2));
}
}
+
+ public void Init(uint layerCount)
+ {
+ _layers = new Layer[layerCount];
+ }
+
+ public void Init(Layer[] layers)
+ {
+ _layers = layers;
+ }
+
+ public void Add(Layer layer)
+ {
+ Layers = _layers.Append(layer).ToArray();
+ }
+
+ public void Add(IEnumerable<Layer> layers)
+ {
+ var list = _layers.ToList();
+ list.AddRange(layers);
+ Layers = list.ToArray();
+ }
+
+ public void Clear()
+ {
+ //Layers = Array.Empty<Layer>();
+ Layers = null;
+ }
+
+ public bool Contains(Layer layer)
+ {
+ return _layers.Contains(layer);
+ }
+
+ public void CopyTo(Layer[] array, int arrayIndex)
+ {
+ _layers.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(Layer layer)
+ {
+ var list = _layers.ToList();
+ var result = list.Remove(layer);
+ if (result)
+ {
+ Layers = list.ToArray();
+ }
+
+ return result;
+ }
+
+ public int IndexOf(Layer layer)
+ {
+ for (int layerIndex = 0; layerIndex < Count; layerIndex++)
+ {
+ if (_layers[layerIndex].Equals(layer)) return layerIndex;
+ }
+
+ return -1;
+ }
+
+ public void Prepend(Layer layer) => Insert(0, layer);
+ public void Prepend(IEnumerable<Layer> layers) => InsertRange(0, layers);
+ public void Append(Layer layer) => Add(layer);
+ public void AppendRange(IEnumerable<Layer> layers) => Add(layers);
+
+ public void Insert(int index, Layer layer)
+ {
+ if (index < 0) return;
+ if (index > Count)
+ {
+ Add(layer); // Append
+ return;
+ }
+
+ var list = _layers.ToList();
+ list.Insert(index, layer);
+ Layers = list.ToArray();
+ }
+
+ public void InsertRange(int index, IEnumerable<Layer> layers)
+ {
+ if (index < 0) return;
+ if (index > Count)
+ {
+ Add(layers);
+ return;
+ }
+
+ var list = _layers.ToList();
+ list.InsertRange(index, layers);
+ Layers = list.ToArray();
+ }
+
+ public void RemoveAt(int index)
+ {
+ if (index >= LastLayerIndex) return;
+ var list = _layers.ToList();
+ list.RemoveAt(index);
+ Layers = list.ToArray();
+ }
+
+ public void RemoveRange(int index, int count)
+ {
+ if (count <= 0 || index >= LastLayerIndex) return;
+ var list = _layers.ToList();
+ list.RemoveRange(index, count);
+ Layers = list.ToArray();
+ }
+
+ /// <summary>
+ /// Removes all null layers in the collection
+ /// </summary>
+ public void RemoveNulls()
+ {
+ Layers = _layers.Where(layer => layer is not null).ToArray();
+ }
+
+ public int Count => _layers?.Length ?? 0;
+
+ public bool IsReadOnly => false;
/// <summary>
/// Gets the layers count
/// </summary>
- public uint Count => (uint) Layers.Length;
+ public uint LayerCount => (uint)(_layers?.Length ?? 0);
- public byte LayerDigits => (byte)Count.ToString().Length;
+ public byte LayerDigits => (byte)LayerCount.ToString().Length;
/// <summary>
/// Gets if any layer got modified, otherwise false
@@ -117,9 +275,9 @@ namespace UVtools.Core
{
get
{
- for (uint i = 0; i < Count; i++)
+ for (uint i = 0; i < LayerCount; i++)
{
- if (Layers[i].IsModified) return true;
+ if (_layers[i].IsModified) return true;
}
return false;
}
@@ -128,14 +286,19 @@ namespace UVtools.Core
/// <summary>
/// Gets if all layers have same value parameters as global settings
/// </summary>
- public bool AllLayersHaveGlobalParameters => Layers.Where(layer => layer is not null).All(layer => layer.HaveGlobalParameters);
+ public bool AllLayersHaveGlobalParameters => _layers.Where(layer => layer is not null).All(layer => layer.HaveGlobalParameters);
//public float LayerHeight => Layers[0].PositionZ;
#endregion
#region Constructors
- public LayerManager(uint layerCount, FileFormat slicerFile)
+ public LayerManager(FileFormat slicerFile)
+ {
+ SlicerFile = slicerFile;
+ }
+
+ public LayerManager(uint layerCount, FileFormat slicerFile) : this(slicerFile)
{
SlicerFile = slicerFile;
_layers = new Layer[layerCount];
@@ -145,20 +308,20 @@ namespace UVtools.Core
#region Indexers
public Layer this[uint index]
{
- get => Layers[index];
- set => AddLayer(index, value);
+ get => _layers[index];
+ set => SetLayer(index, value);
}
public Layer this[int index]
{
- get => Layers[index];
- set => AddLayer((uint) index, value);
+ get => _layers[index];
+ set => SetLayer((uint) index, value);
}
public Layer this[long index]
{
- get => Layers[index];
- set => AddLayer((uint) index, value);
+ get => _layers[index];
+ set => SetLayer((uint) index, value);
}
#endregion
@@ -234,65 +397,69 @@ namespace UVtools.Core
public void RebuildLayersProperties(bool recalculateZPos = true, string property = null)
{
//var layerHeight = SlicerFile.LayerHeight;
- for (uint layerIndex = 0; layerIndex < Count; layerIndex++)
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var layer = this[layerIndex];
layer.Index = layerIndex;
+ layer.ParentLayerManager = this;
- if (property is null || property == nameof(SlicerFile.BottomLayerCount))
- {
- layer.ExposureTime = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
- layer.LiftHeight = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
- layer.LiftSpeed = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
- layer.RetractSpeed = SlicerFile.RetractSpeed;
- layer.LightPWM = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
- layer.LightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay);
- }
- else
+ if (property != string.Empty)
{
- if (layer.IsNormalLayer)
+ if (property is null || property == nameof(SlicerFile.BottomLayerCount))
{
- switch (property)
- {
- case nameof(SlicerFile.ExposureTime):
- layer.ExposureTime = SlicerFile.ExposureTime;
- break;
- case nameof(SlicerFile.LiftHeight):
- layer.LiftHeight = SlicerFile.LiftHeight;
- break;
- case nameof(SlicerFile.LiftSpeed):
- layer.LiftSpeed = SlicerFile.LiftSpeed;
- break;
- case nameof(SlicerFile.LightOffDelay):
- layer.LightOffDelay = SlicerFile.LightOffDelay;
- break;
- case nameof(SlicerFile.LightPWM):
- layer.LightPWM = SlicerFile.LightPWM;
- break;
- }
+ layer.ExposureTime = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
+ layer.LiftHeight = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
+ layer.LiftSpeed = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
+ layer.RetractSpeed = SlicerFile.RetractSpeed;
+ layer.LightPWM = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
+ layer.LightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay);
}
- else // Bottom layers
+ else
{
- switch (property)
+ if (layer.IsNormalLayer)
{
- case nameof(SlicerFile.BottomExposureTime):
- layer.ExposureTime = SlicerFile.BottomExposureTime;
- break;
- case nameof(SlicerFile.BottomLiftHeight):
- layer.LiftHeight = SlicerFile.BottomLiftHeight;
- break;
- case nameof(SlicerFile.BottomLiftSpeed):
- layer.LiftSpeed = SlicerFile.BottomLiftSpeed;
- break;
- case nameof(SlicerFile.RetractSpeed):
- layer.RetractSpeed = SlicerFile.RetractSpeed;
- break;
- case nameof(SlicerFile.BottomLightOffDelay):
- layer.LightOffDelay = SlicerFile.BottomLightOffDelay;
- break;
- case nameof(SlicerFile.BottomLightPWM):
- layer.LightPWM = SlicerFile.BottomLightPWM;
- break;
+ switch (property)
+ {
+ case nameof(SlicerFile.ExposureTime):
+ layer.ExposureTime = SlicerFile.ExposureTime;
+ break;
+ case nameof(SlicerFile.LiftHeight):
+ layer.LiftHeight = SlicerFile.LiftHeight;
+ break;
+ case nameof(SlicerFile.LiftSpeed):
+ layer.LiftSpeed = SlicerFile.LiftSpeed;
+ break;
+ case nameof(SlicerFile.LightOffDelay):
+ layer.LightOffDelay = SlicerFile.LightOffDelay;
+ break;
+ case nameof(SlicerFile.LightPWM):
+ layer.LightPWM = SlicerFile.LightPWM;
+ break;
+ }
+ }
+ else // Bottom layers
+ {
+ switch (property)
+ {
+ case nameof(SlicerFile.BottomExposureTime):
+ layer.ExposureTime = SlicerFile.BottomExposureTime;
+ break;
+ case nameof(SlicerFile.BottomLiftHeight):
+ layer.LiftHeight = SlicerFile.BottomLiftHeight;
+ break;
+ case nameof(SlicerFile.BottomLiftSpeed):
+ layer.LiftSpeed = SlicerFile.BottomLiftSpeed;
+ break;
+ case nameof(SlicerFile.RetractSpeed):
+ layer.RetractSpeed = SlicerFile.RetractSpeed;
+ break;
+ case nameof(SlicerFile.BottomLightOffDelay):
+ layer.LightOffDelay = SlicerFile.BottomLightOffDelay;
+ break;
+ case nameof(SlicerFile.BottomLightPWM):
+ layer.LightPWM = SlicerFile.BottomLightPWM;
+ break;
+ }
}
}
}
@@ -311,7 +478,7 @@ namespace UVtools.Core
/// </summary>
public void SetNoLiftForSamePositionedLayers()
{
- for (int layerIndex = 1; layerIndex < Count; layerIndex++)
+ for (int layerIndex = 1; layerIndex < LayerCount; layerIndex++)
{
if (this[layerIndex - 1].PositionZ != this[layerIndex].PositionZ) continue;
this[layerIndex].LiftHeight = 0;
@@ -321,23 +488,20 @@ namespace UVtools.Core
public Rectangle GetBoundingRectangle(OperationProgress progress = null)
{
- if (!_boundingRectangle.IsEmpty || Count == 0 || this[0] is null) return _boundingRectangle;
- progress ??= new OperationProgress(OperationProgress.StatusOptimizingBounds, Count - 1);
+ if (!_boundingRectangle.IsEmpty || LayerCount == 0 || this[0] is null) return _boundingRectangle;
+ progress ??= new OperationProgress(OperationProgress.StatusOptimizingBounds, LayerCount - 1);
_boundingRectangle = this[0].BoundingRectangle;
if (_boundingRectangle.IsEmpty) // Safe checking
{
- progress.Reset(OperationProgress.StatusOptimizingBounds, Count-1);
- Parallel.For(0, Count, layerIndex =>
+ progress.Reset(OperationProgress.StatusOptimizingBounds, LayerCount-1);
+ Parallel.For(0, LayerCount, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
this[layerIndex].GetBoundingRectangle();
if (progress is null) return;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
_boundingRectangle = this[0].BoundingRectangle;
@@ -348,10 +512,10 @@ namespace UVtools.Core
}
}
- progress.Reset(OperationProgress.StatusCalculatingBounds, Count-1);
- for (int i = 1; i < Count; i++)
+ progress.Reset(OperationProgress.StatusCalculatingBounds, LayerCount-1);
+ for (int i = 1; i < LayerCount; i++)
{
- if(this[i].BoundingRectangle.IsEmpty) continue;
+ if(this[i] is null || this[i].BoundingRectangle.IsEmpty) continue;
_boundingRectangle = Rectangle.Union(_boundingRectangle, this[i].BoundingRectangle);
progress++;
}
@@ -360,19 +524,18 @@ namespace UVtools.Core
}
/// <summary>
- /// Add a layer
+ /// Sets a layer
/// </summary>
/// <param name="index">Layer index</param>
/// <param name="layer">Layer to add</param>
/// <param name="makeClone">True to add a clone of the layer</param>
- public void AddLayer(uint index, Layer layer, bool makeClone = false)
+ public void SetLayer(uint index, Layer layer, bool makeClone = false)
{
- if (Layers[index] is not null && layer is not null) layer.IsModified = true;
- Layers[index] = makeClone && layer is not null ? layer.Clone() : layer;
- if (layer is not null)
- {
- layer.ParentLayerManager = this;
- }
+ if (_layers[index] is not null && layer is not null) layer.IsModified = true;
+ _layers[index] = makeClone && layer is not null ? layer.Clone() : layer;
+ if (layer is null) return;
+ layer.Index = index;
+ layer.ParentLayerManager = this;
}
/// <summary>
@@ -380,13 +543,11 @@ namespace UVtools.Core
/// </summary>
/// <param name="layers">Layers to add</param>
/// <param name="makeClone">True to add a clone of layers</param>
- public void AddLayers(IEnumerable<Layer> layers, bool makeClone = false)
+ public void SetLayers(IEnumerable<Layer> layers, bool makeClone = false)
{
- //layer.Index = index;
foreach (var layer in layers)
{
- layer.ParentLayerManager = this;
- Layers[layer.Index] = makeClone ? layer.Clone() : layer;
+ SetLayer(layer.Index, layer, makeClone);
}
}
@@ -397,7 +558,7 @@ namespace UVtools.Core
/// <returns></returns>
public Layer GetLayer(uint index)
{
- return Layers[index];
+ return _layers[index];
}
public static void MutateGetVarsIterationChamfer(uint startLayerIndex, uint endLayerIndex, int iterationsStart, int iterationsEnd, ref bool isFade, out float iterationSteps, out int maxIteration)
@@ -452,7 +613,7 @@ namespace UVtools.Core
List<uint> actionLayers = new();
bool checkedEmptyLayers = false;
Mat emptyMat = new ();
- Mat[] cachedLayers = new Mat[Count];
+ Mat[] cachedLayers = new Mat[LayerCount];
const uint cacheCount = 300;
bool IsIgnored(LayerIssue issue) => !(ignoredIssues is null) && ignoredIssues.Count > 0 && ignoredIssues.Contains(issue);
@@ -466,7 +627,7 @@ namespace UVtools.Core
Mat GetCachedMat(uint layerIndex)
{
if (cachedLayers[layerIndex] is not null) return cachedLayers[layerIndex];
- Parallel.For(layerIndex, Math.Min(layerIndex + cacheCount, Count), i =>
+ Parallel.For(layerIndex, Math.Min(layerIndex + cacheCount, LayerCount), i =>
{
if (this[i].IsEmpty) return; // empty layers
cachedLayers[i] = this[i].LayerMat;
@@ -481,7 +642,7 @@ namespace UVtools.Core
)
{
checkedEmptyLayers = true;
- for (uint layerIndex = 0; layerIndex < Count; layerIndex++)
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var layer = this[layerIndex];
if (layer.IsEmpty)
@@ -500,7 +661,7 @@ namespace UVtools.Core
if (!checkedEmptyLayers && emptyLayersConfig)
{
checkedEmptyLayers = true;
- for (uint layerIndex = 0; layerIndex < Count; layerIndex++)
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
var layer = this[layerIndex];
if (layer.IsEmpty)
@@ -522,11 +683,8 @@ namespace UVtools.Core
var layer = this[layerIndex];
if (layer.IsEmpty)
{
- lock (progress.Mutex)
- {
- progress++;
- }
-
+ progress.LockAndIncrement();
+
return; // Empty layer
}
@@ -614,10 +772,7 @@ namespace UVtools.Core
}
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
for (; i < layerAdvance - 1; i++)
@@ -673,7 +828,7 @@ namespace UVtools.Core
if (islandConfig.Enabled || overhangConfig.Enabled || resinTrapConfig.Enabled || touchBoundConfig.Enabled || emptyLayersConfig)
{
- progress.Reset(OperationProgress.StatusIslands, Count);
+ progress.Reset(OperationProgress.StatusIslands, LayerCount);
// Detect contours
Parallel.ForEach(this,
@@ -1071,7 +1226,7 @@ namespace UVtools.Core
listHollowArea.Add(new LayerHollowArea(contours[i].ToArray(),
rect,
layer.Index == 0 ||
- layer.Index == Count - 1 // First and Last layers, always drains
+ layer.Index == LayerCount - 1 // First and Last layers, always drains
? LayerHollowArea.AreaType.Drain
: LayerHollowArea.AreaType.Unknown));
@@ -1087,11 +1242,11 @@ namespace UVtools.Core
if (resinTrapConfig.Enabled)
{
- progress.Reset(OperationProgress.StatusResinTraps, Count);
+ progress.Reset(OperationProgress.StatusResinTraps, LayerCount);
- for (uint layerIndex = 1; layerIndex < Count - 1; layerIndex++) // First and Last layers, always drains
+ for (uint layerIndex = 1; layerIndex < LayerCount - 1; layerIndex++) // First and Last layers, always drains
{
if (progress.Token.IsCancellationRequested) break;
if (!layerHollowAreas.TryGetValue(layerIndex, out var areas))
@@ -1130,13 +1285,13 @@ namespace UVtools.Core
checkArea.Processed = true;
nextLayerIndex += dir;
- if (nextLayerIndex < 0 || nextLayerIndex >= Count)
+ if (nextLayerIndex < 0 || nextLayerIndex >= LayerCount)
break; // Exhausted layers
bool haveNextAreas =
layerHollowAreas.TryGetValue((uint) nextLayerIndex, out var nextAreas);
Dictionary<int, LayerHollowArea> intersectingAreas = new();
- progress.Reset(OperationProgress.StatusResinTraps, Count, (uint) nextLayerIndex);
+ progress.Reset(OperationProgress.StatusResinTraps, LayerCount, (uint) nextLayerIndex);
using (var image = this[nextLayerIndex].LayerMat)
{
@@ -1289,7 +1444,7 @@ namespace UVtools.Core
});*/
if (progress.Token.IsCancellationRequested) return result.OrderBy(issue => issue.Type).ThenBy(issue => issue.LayerIndex).ThenBy(issue => issue.PixelsCount).ToList();
- for (uint layerIndex = 0; layerIndex < Count; layerIndex++)
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
if (!layerHollowAreas.TryGetValue(layerIndex, out var list)) continue;
if (list.Count == 0) continue;
@@ -1454,34 +1609,22 @@ namespace UVtools.Core
}
progress.Reset("Saving", (uint) modifiedLayers.Count);
- Parallel.ForEach(modifiedLayers, (modfiedLayer, state) =>
+ Parallel.ForEach(modifiedLayers, (modifiedLayer, state) =>
{
- this[modfiedLayer.Key].LayerMat = modfiedLayer.Value;
- modfiedLayer.Value.Dispose();
+ this[modifiedLayer.Key].LayerMat = modifiedLayer.Value;
+ modifiedLayer.Value.Dispose();
- lock (progress)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
- /*foreach (var modfiedLayer in modfiedLayers)
- {
- this[modfiedLayer.Key].LayerMat = modfiedLayer.Value;
- modfiedLayer.Value.Dispose();
- progress++;
- }*/
- //pixelHistory.Clear();
}
-
-
/// <summary>
/// Set the IsModified property for all layers
/// </summary>
public void SetAllIsModified(bool isModified)
{
- for (uint i = 0; i < Count; i++)
+ for (uint i = 0; i < LayerCount; i++)
{
if(Layers[i] is null) continue;
Layers[i].IsModified = isModified;
@@ -1492,27 +1635,46 @@ namespace UVtools.Core
/// Reallocate with new size
/// </summary>
/// <returns></returns>
- public LayerManager ReallocateNew(uint newLayerCount, bool makeClone = false)
+ public Layer[] ReallocateNew(uint newLayerCount, bool makeClone = false)
{
- LayerManager layerManager = new LayerManager(newLayerCount, SlicerFile);
- foreach (var layer in this)
+ var layers = new Layer[newLayerCount];
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
- if (layer.Index >= newLayerCount) break;
- layerManager[layer.Index] = makeClone ? layer.Clone() : layer;
+ if (layerIndex >= newLayerCount) break;
+ var layer = this[layerIndex];
+ layers[layerIndex] = makeClone && layer is not null ? layer.Clone() : layer;
}
- layerManager.BoundingRectangle = Rectangle.Empty;
+ return layers;
+ }
- return layerManager;
+ /// <summary>
+ /// Reallocate layer count with a new size
+ /// </summary>
+ /// <param name="newLayerCount">New layer count</param>
+ /// <param name="initBlack"></param>
+ public void Reallocate(uint newLayerCount, bool initBlack = false)
+ {
+ var oldLayerCount = LayerCount;
+ int differenceLayerCount = (int)newLayerCount - Count;
+ if (differenceLayerCount == 0) return;
+ Array.Resize(ref _layers, (int) newLayerCount);
+ if (differenceLayerCount > 0 && initBlack)
+ {
+ Parallel.For(oldLayerCount, newLayerCount, layerIndex =>
+ {
+ this[layerIndex] = new Layer((uint)layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this);
+ });
+ }
}
/// <summary>
- /// Reallocate with add size
+ /// Reallocate at given index
/// </summary>
/// <returns></returns>
- public void Reallocate(uint insertAtLayerIndex, uint layerCount, bool initBlack = false)
+ public void ReallocateInsert(uint insertAtLayerIndex, uint layerCount, bool initBlack = false)
{
- var newLayers = new Layer[Count + layerCount];
+ var newLayers = new Layer[LayerCount + layerCount];
// Rearrange
for (uint layerIndex = 0; layerIndex < insertAtLayerIndex; layerIndex++)
@@ -1539,9 +1701,14 @@ namespace UVtools.Core
{
Layers[layerIndex] = initBlack ? new Layer(layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this) : null;
}*/
- Layers = newLayers;
+ _layers = newLayers;
}
+ /// <summary>
+ /// Reallocate at a kept range
+ /// </summary>
+ /// <param name="startLayerIndex"></param>
+ /// <param name="endLayerIndex"></param>
public void ReallocateRange(uint startLayerIndex, uint endLayerIndex)
{
if ((int)(endLayerIndex - startLayerIndex) < 0) return;
@@ -1553,20 +1720,20 @@ namespace UVtools.Core
newLayers[currentLayerIndex++] = _layers[layerIndex];
}
- Layers = newLayers;
+ _layers = newLayers;
}
/// <summary>
/// Reallocate at start
/// </summary>
/// <returns></returns>
- public void ReallocateStart(uint layerCount, bool initBlack = false) => Reallocate(0, layerCount, initBlack);
+ public void ReallocateStart(uint layerCount, bool initBlack = false) => ReallocateInsert(0, layerCount, initBlack);
/// <summary>
/// Reallocate at end
/// </summary>
/// <returns></returns>
- public void ReallocateEnd(uint layerCount, bool initBlack = false) => Reallocate(Count, layerCount, initBlack);
+ public void ReallocateEnd(uint layerCount, bool initBlack = false) => ReallocateInsert(LayerCount, layerCount, initBlack);
/// <summary>
/// Clone this object
@@ -1574,16 +1741,26 @@ namespace UVtools.Core
/// <returns></returns>
public LayerManager Clone()
{
- LayerManager layerManager = new LayerManager(Count, SlicerFile);
- foreach (var layer in this)
+ LayerManager layerManager = new(SlicerFile);
+ layerManager.Init(CloneLayers());
+ /*foreach (var layer in this)
{
layerManager[layer.Index] = layer.Clone();
- }
+ }*/
layerManager.BoundingRectangle = BoundingRectangle;
return layerManager;
}
+ /// <summary>
+ /// Clone layers
+ /// </summary>
+ /// <returns></returns>
+ public Layer[] CloneLayers()
+ {
+ return Layer.CloneLayers(_layers);
+ }
+
public void Dispose() { }
#endregion
@@ -1592,11 +1769,9 @@ namespace UVtools.Core
public override string ToString()
{
- return $"{nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(Count)}: {Count}, {nameof(IsModified)}: {IsModified}";
+ return $"{nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(LayerCount)}: {LayerCount}, {nameof(IsModified)}: {IsModified}";
}
#endregion
-
-
}
}
diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs
index cb851fa..a436625 100644
--- a/UVtools.Core/Managers/ClipboardManager.cs
+++ b/UVtools.Core/Managers/ClipboardManager.cs
@@ -9,17 +9,17 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Drawing;
+using System.Diagnostics;
+using System.Linq;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
namespace UVtools.Core.Managers
{
- public sealed class ClipboardItem : IList<Layer>
+ public sealed class ClipboardItem : List<Layer>
{
#region Properties
- private readonly List<Layer> _layers = new();
-
+
/// <summary>
/// Gets the LayerCount for this clip
/// </summary>
@@ -32,62 +32,36 @@ namespace UVtools.Core.Managers
/// </summary>
public string Description { get; set; }
+ public bool IsFullBackup { get; set; }
+
public Operations.Operation Operation { get; set; }
#endregion
#region Constructor
- public ClipboardItem(FileFormat slicerFile, Operations.Operation operation) : this(slicerFile)
+ public ClipboardItem(FileFormat slicerFile, Operations.Operation operation, bool isFullBackup = false) : this(slicerFile)
{
Operation = operation;
string description = operation.ToString();
if (!description.StartsWith(operation.Title)) description = $"{operation.Title}: {description}";
Description = description;
+ IsFullBackup = isFullBackup;
}
- public ClipboardItem(FileFormat slicerFile, string description = null)
+ public ClipboardItem(FileFormat slicerFile, string description = null, bool isFullBackup = false)
{
LayerCount = slicerFile.LayerCount;
LayerHeight = slicerFile.LayerHeight;
Description = description;
- }
- #endregion
-
- #region List Implementation
- public IEnumerator<Layer> GetEnumerator() => _layers.GetEnumerator();
-
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public void Add(Layer item) => _layers.Add(item);
-
- public void Clear() => _layers.Clear();
-
- public bool Contains(Layer item) => _layers.Contains(item);
-
- public void CopyTo(Layer[] array, int arrayIndex) => _layers.CopyTo(array, arrayIndex);
-
- public bool Remove(Layer item) => _layers.Remove(item);
-
- public int Count => _layers.Count;
- public bool IsReadOnly => false;
- public int IndexOf(Layer item) => _layers.IndexOf(item);
-
- public void Insert(int index, Layer item) => _layers.Insert(index, item);
-
- public void RemoveAt(int index) => _layers.RemoveAt(index);
-
- public Layer this[int index]
- {
- get => _layers[index];
- set => _layers[index] = value;
+ IsFullBackup = isFullBackup;
}
#endregion
#region Methods
public override string ToString()
{
- return $"{Description} ({Count})";
+ return $"{(IsFullBackup ? "* " : "")}{Description} ({Count})";
}
#endregion
}
@@ -96,12 +70,12 @@ namespace UVtools.Core.Managers
{
#region Properties
- public ObservableCollection<ClipboardItem> Items { get; } = new ObservableCollection<ClipboardItem>();
+ public ObservableCollection<ClipboardItem> Items { get; } = new();
public FileFormat SlicerFile { get; set; }
private int _currentIndex = -1;
- private LayerManager _snapshotLayerManager;
+ private Layer[] _snapshotLayers;
private bool _reallocatedLayerCount;
private bool _suppressRestore;
@@ -121,27 +95,42 @@ namespace UVtools.Core.Managers
if (value >= 0 && !SuppressRestore)
{
+ ReallocatedLayerCount = false;
int dir = oldIndex < _currentIndex ? 1 : -1;
for (int i = oldIndex + dir; i >= 0 && i < Count; i += dir)
{
- var layerManager = SlicerFile.LayerManager;
var clip = this[i];
- if (layerManager.Count != clip.LayerCount) // Need resize layer manager
+
+ Layer[] layers;
+ if (clip.IsFullBackup)
{
- layerManager = layerManager.ReallocateNew(clip.LayerCount);
- ReallocatedLayerCount = true;
+ if(!_reallocatedLayerCount && SlicerFile.LayerCount != clip.Count) ReallocatedLayerCount = true;
+ layers = clip.ToArray();
+ }
+ else
+ {
+ layers = SlicerFile.LayerManager.Layers.ToArray();
+
+ if (SlicerFile.LayerCount != clip.LayerCount) // Need resize layer manager
+ {
+ //layers = SlicerFile.LayerManager.ReallocateNew(clip.LayerCount);
+ layers = SlicerFile.LayerManager.ReallocateNew(clip.LayerCount);
+ ReallocatedLayerCount = true;
+ }
+
+ foreach (var layer in clip)
+ {
+ layers[layer.Index] = layer;
+ }
}
- layerManager.AddLayers(clip);
-
- layerManager.BoundingRectangle = Rectangle.Empty;
if (SlicerFile.LayerHeight != clip.LayerHeight)
{
SlicerFile.LayerHeight = clip.LayerHeight;
}
- SlicerFile.LayerManager = layerManager.Clone();
+ SlicerFile.LayerManager.Layers = Layer.CloneLayers(layers);
if (i == _currentIndex) break;
}
}
@@ -168,10 +157,10 @@ namespace UVtools.Core.Managers
set => RaiseAndSetIfChanged(ref _reallocatedLayerCount, value);
}
- public LayerManager SnapshotLayerManager
+ public Layer[] SnapshotLayers
{
- get => _snapshotLayerManager;
- private set => RaiseAndSetIfChanged(ref _snapshotLayerManager, value);
+ get => _snapshotLayers;
+ private set => RaiseAndSetIfChanged(ref _snapshotLayers, value);
}
public ClipboardItem CurrentClip => _currentIndex < 0 || _currentIndex >= Count ? null : this[_currentIndex];
@@ -183,7 +172,7 @@ namespace UVtools.Core.Managers
#region Singleton
private static readonly Lazy<ClipboardManager> InstanceHolder =
- new Lazy<ClipboardManager>(() => new ClipboardManager());
+ new(() => new ClipboardManager());
public static ClipboardManager Instance => InstanceHolder.Value;
#endregion
@@ -241,6 +230,24 @@ namespace UVtools.Core.Managers
#region Methods
+ public void SuppressRestoreWork(Action action)
+ {
+ try
+ {
+ SuppressRestore = true;
+ action.Invoke();
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ throw;
+ }
+ finally
+ {
+ SuppressRestore = false;
+ }
+ }
+
/// <summary>
/// Clears the manager
/// </summary>
@@ -252,57 +259,91 @@ namespace UVtools.Core.Managers
/// <param name="slicerFile"></param>
public void Init(FileFormat slicerFile)
{
- Clear();
- SlicerFile = slicerFile;
- if(slicerFile is null) return;
- var clip = new ClipboardItem(SlicerFile, "Original layers");
- for (int layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
+ SuppressRestoreWork(() =>
{
- clip.Add(SlicerFile[layerIndex].Clone());
- }
-
- Add(clip);
- slicerFile.SuppressRebuildPropertiesWork(() => CurrentIndex = 0);
+ Clear();
+ SlicerFile = slicerFile;
+ if (slicerFile is null) return;
+ var clip = new ClipboardItem(SlicerFile, "Original layers", true);
+ clip.AddRange(SlicerFile.LayerManager.CloneLayers());
+ Add(clip);
+ slicerFile.SuppressRebuildPropertiesWork(() => CurrentIndex = 0);
+ });
}
/// <summary>
/// Snapshot layers and prepare manager to collect modified layers with <see cref="Clip"/>
/// </summary>
- public void Snapshot(LayerManager layerManager = null)
+ public void Snapshot(Layer[] layers = null)
+ {
+ SnapshotLayers = layers ?? SlicerFile.LayerManager.CloneLayers();
+ }
+
+ public void RestoreSnapshot()
{
- SnapshotLayerManager = layerManager ?? SlicerFile.LayerManager.Clone();
+ if (_snapshotLayers is null) return;
+ SlicerFile.LayerManager.Layers = _snapshotLayers;
+ SnapshotLayers = null;
}
/// <summary>
/// Collect differences and create a clip
/// </summary>
- public ClipboardItem Clip(string description = null, LayerManager layerManagerSnapshot = null)
+ public ClipboardItem Clip(string description = null, Layer[] layers = null, bool doFullBackup = false)
{
- if(!(layerManagerSnapshot is null)) Snapshot(layerManagerSnapshot);
- if (SnapshotLayerManager is null) throw new InvalidOperationException("A snapshot is required before perform a clip");
- var clip = new ClipboardItem(SlicerFile, description);
-
- int layerIndex = 0;
- for (;
- layerIndex < SlicerFile.LayerCount
- && layerIndex < SnapshotLayerManager.Count
- ; layerIndex++)
+ ClipboardItem safeClip = null;
+ if (!doFullBackup)
{
- //if(SnapshotLayerManager.Count - 1 < layerIndex) break;
- if(SnapshotLayerManager[layerIndex].Equals(SlicerFile[layerIndex])) continue;
-
- clip.Add(SlicerFile[layerIndex].Clone());
+ if (layers is not null) Snapshot(layers);
+ if (_snapshotLayers is null) throw new InvalidOperationException("A snapshot is required before perform a clip");
+
+ if (_snapshotLayers.Length != SlicerFile.LayerCount)
+ {
+ doFullBackup = true; // Force full backup when layer count changes
+ if (Count > 0 && !this[0].IsFullBackup)
+ {
+ safeClip = new ClipboardItem(SlicerFile, "Fail-safe full backup", true);
+ safeClip.AddRange(_snapshotLayers);
+ }
+
+ //Insert(0, safeClip);
+ }
}
- // Collect leftovers from snapshot
- // This happens when current layer manager has less layers then the snapshot/previous
- // So we need to preserve them
- for (; layerIndex < SlicerFile.LayerCount; layerIndex++)
+ var clip = new ClipboardItem(SlicerFile, description, doFullBackup);
+
+ if (doFullBackup)
{
- clip.Add(SlicerFile[layerIndex].Clone());
+ clip.AddRange(SlicerFile.LayerManager.CloneLayers());
}
+ else
+ {
+ int layerIndex = 0;
+ for (;
+ layerIndex < SlicerFile.LayerCount
+ && layerIndex < _snapshotLayers.Length;
+ layerIndex++)
+ {
+ //if(SnapshotLayers.Count - 1 < layerIndex) break;
+ if (_snapshotLayers[layerIndex].Equals(SlicerFile[layerIndex])) continue;
+ clip.Add(SlicerFile[layerIndex].Clone());
+ }
- SnapshotLayerManager = null;
+ // Collect leftovers from snapshot
+ // This happens when current state has less layers then the snapshot/previous
+ // So we need to preserve them
+ for (; layerIndex < SlicerFile.LayerCount; layerIndex++)
+ {
+ clip.Add(SlicerFile[layerIndex].Clone());
+ }
+
+ if (clip.Count == SlicerFile.LayerCount)
+ {
+ clip.IsFullBackup = true;
+ }
+ }
+
+ SnapshotLayers = null;
if (clip.Count == 0)
{
@@ -310,33 +351,38 @@ namespace UVtools.Core.Managers
return null;
}
- SuppressRestore = true;
- var oldCurrentIndex = _currentIndex;
- CurrentIndex = -1;
-
- // Remove all redo's for integrity
- for (int i = oldCurrentIndex - 1; i >= 0; i--)
+ SuppressRestoreWork(() =>
{
- RemoveAt(i);
- }
+ var oldCurrentIndex = _currentIndex;
+ CurrentIndex = -1;
-
- Insert(0, clip);
-
- CurrentIndex = 0;
- SuppressRestore = false;
+ // Remove all redo's for integrity
+ for (int i = oldCurrentIndex - 1; i >= 0; i--)
+ {
+ //if(this[i].IsFullBackup) continue; // Full backups can survive
+ RemoveAt(i);
+ }
+
+ if (safeClip is not null)
+ {
+ Insert(0, safeClip);
+ }
+ Insert(0, clip);
+ CurrentIndex = 0;
+ });
+
return clip;
}
/// <summary>
/// Collect differences and create a clip
/// </summary>
- public ClipboardItem Clip(Operations.Operation operation, LayerManager layerManagerSnapshot = null)
+ public ClipboardItem Clip(Operations.Operation operation, Layer[] layersSnapshot = null, bool doFullBackup = false)
{
string description = operation.ToString();
if (!description.StartsWith(operation.Title)) description = $"{operation.Title}: {description}";
- var clip = Clip(description, layerManagerSnapshot);
+ var clip = Clip(description, layersSnapshot, doFullBackup);
if (clip is null) return null;
clip.Operation = operation;
return clip;
@@ -357,38 +403,6 @@ namespace UVtools.Core.Managers
public void SetToOldest() => CurrentIndex = Count-1;
public void SetToNewest() => CurrentIndex = 0;
- /*public bool SetTo(int index)
- {
- if (index == _currentIndex || index < 0 || index >= Count) return false;
- bool changed = false;
- int dir = _currentIndex < index ? 1 : -1;
-
- for (int i = _currentIndex+dir; i >= 0 && i < Count; i+=dir)
- {
- var layerManager = SlicerFile.LayerManager;
- var clip = this[i];
- if (layerManager.Count != clip.LayerCount) // Need resize layer manager
- {
- layerManager = layerManager.Reallocate(clip.LayerCount);
- ReallocatedLayerCount = true;
- }
-
- layerManager.AddLayers(clip);
-
- layerManager.BoundingRectangle = Rectangle.Empty;
- SlicerFile.LayerManager = layerManager.Clone();
- changed = true;
- if (i == index) break;
- }
-
- if (changed)
- {
- CurrentIndex = index;
- }
-
- return changed;
- }*/
-
#endregion
}
}
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index ff0acaf..b68f447 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -144,10 +144,7 @@ namespace UVtools.Core.Operations
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationCalibrateStressTower.cs b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
index e588b19..db0490e 100644
--- a/UVtools.Core/Operations/OperationCalibrateStressTower.cs
+++ b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
@@ -420,10 +420,7 @@ namespace UVtools.Core.Operations
{
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile.LayerManager) {IsModified = true};
layers[layerIndex].Dispose();
- lock (progress)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
diff --git a/UVtools.Core/Operations/OperationCalibrateTolerance.cs b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
index 13ad30d..e73314a 100644
--- a/UVtools.Core/Operations/OperationCalibrateTolerance.cs
+++ b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
@@ -732,10 +732,7 @@ namespace UVtools.Core.Operations
{
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile.LayerManager) {IsModified = true};
layers[layerIndex].Dispose();
- lock (progress)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
if (SlicerFile.ThumbnailsCount > 0)
diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs
index 31a1883..c021753 100644
--- a/UVtools.Core/Operations/OperationChangeResolution.cs
+++ b/UVtools.Core/Operations/OperationChangeResolution.cs
@@ -173,10 +173,7 @@ namespace UVtools.Core.Operations
//Execute(mat);
SlicerFile[layerIndex].LayerMat = matDst;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.Token.ThrowIfCancellationRequested();
diff --git a/UVtools.Core/Operations/OperationFlip.cs b/UVtools.Core/Operations/OperationFlip.cs
index e2c55bb..2badeca 100644
--- a/UVtools.Core/Operations/OperationFlip.cs
+++ b/UVtools.Core/Operations/OperationFlip.cs
@@ -130,10 +130,7 @@ namespace UVtools.Core.Operations
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationInfill.cs b/UVtools.Core/Operations/OperationInfill.cs
index 745750e..b07ba06 100644
--- a/UVtools.Core/Operations/OperationInfill.cs
+++ b/UVtools.Core/Operations/OperationInfill.cs
@@ -135,11 +135,8 @@ namespace UVtools.Core.Operations
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex);
SlicerFile[layerIndex].LayerMat = mat;
-
- lock (progress.Mutex)
- {
- progress++;
- }
+
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationLayerClone.cs b/UVtools.Core/Operations/OperationLayerClone.cs
index 9eca95c..5e82593 100644
--- a/UVtools.Core/Operations/OperationLayerClone.cs
+++ b/UVtools.Core/Operations/OperationLayerClone.cs
@@ -7,7 +7,9 @@
*/
using System;
+using System.Collections.Generic;
using System.Drawing;
+using System.Linq;
using System.Text;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
@@ -88,13 +90,30 @@ namespace UVtools.Core.Operations
protected override bool ExecuteInternally(OperationProgress progress)
{
- var oldLayers = SlicerFile.LayerManager.Layers;
+ uint totalClones = (LayerIndexEnd - LayerIndexStart + 1) * Clones;
+ progress.Reset(ProgressAction, totalClones);
+
+ var newLayers = new Layer[SlicerFile.LayerCount + totalClones];
+ uint newLayerIndex = 0;
+ for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
+ {
+ newLayers[newLayerIndex++] = SlicerFile[layerIndex];
+ if (layerIndex < LayerIndexStart || layerIndex > LayerIndexEnd) continue;
+ for (uint i = 0; i < Clones; i++)
+ {
+ newLayers[newLayerIndex++] = SlicerFile[layerIndex].Clone();
+ progress++;
+ }
+ }
+
+ SlicerFile.LayerManager.Layers = newLayers;
+
+ /*var oldLayers = SlicerFile.LayerManager.Layers;
uint totalClones = (LayerIndexEnd - LayerIndexStart + 1) * Clones;
uint newLayerCount = (uint) (oldLayers.Length + totalClones);
var layers = new Layer[newLayerCount];
- progress.Reset(ProgressAction, totalClones);
uint newLayerIndex = 0;
for (uint layerIndex = 0; layerIndex < oldLayers.Length; layerIndex++)
@@ -115,7 +134,7 @@ namespace UVtools.Core.Operations
newLayerIndex++;
}
- SlicerFile.LayerManager.Layers = layers;
+ SlicerFile.LayerManager.Layers = layers;*/
return !progress.Token.IsCancellationRequested;
}
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index c3be204..e77fc49 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -245,7 +245,7 @@ namespace UVtools.Core.Operations
{
progress.Reset("Packing images", (uint)keyImage.Count);
SL1File format = new();
- format.LayerManager = new LayerManager((uint)keyImage.Count, format);
+ format.LayerManager.Init((uint)keyImage.Count);
Parallel.ForEach(keyImage, pair =>
{
@@ -254,10 +254,7 @@ namespace UVtools.Core.Operations
if (pair.Key == 0) format.Resolution = mat.Size;
format[pair.Key] = new Layer(pair.Key, mat, format);
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
progress.Token.ThrowIfCancellationRequested();
@@ -306,7 +303,7 @@ namespace UVtools.Core.Operations
if (SlicerFile.Resolution != fileFormat.Resolution &&
(SlicerFile.Resolution.Width < fileFormatBoundingRectangle.Width ||
SlicerFile.Resolution.Height < fileFormatBoundingRectangle.Height)) continue;
- SlicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount);
+ SlicerFile.LayerManager.ReallocateInsert(_startLayerIndex, fileFormat.LayerCount);
break;
case ImportTypes.Replace:
case ImportTypes.Stack:
@@ -472,11 +469,7 @@ namespace UVtools.Core.Operations
}
- lock (progress.Mutex)
- {
- lastProcessedLayerIndex = Math.Max(lastProcessedLayerIndex, (int)layerIndex);
- progress++;
- }
+ progress.LockAndIncrement();
});
fileFormat.Dispose();
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index fd45ac4..17b70db 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -136,23 +136,21 @@ namespace UVtools.Core.Operations
{
progress.ItemCount = Item.LayerCount;
- var oldLayers = SlicerFile.LayerManager.Layers;
-
var layers = new Layer[Item.LayerCount];
uint newLayerIndex = 0;
- for (uint layerIndex = 0; layerIndex < oldLayers.Length; layerIndex++)
+ for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
{
progress.Token.ThrowIfCancellationRequested();
- var oldLayer = oldLayers[layerIndex];
+ var oldLayer = SlicerFile[layerIndex];
if (Item.IsDivision)
{
for (byte i = 0; i < Item.Modifier; i++)
{
var newLayer = oldLayer.Clone();
- newLayer.Index = newLayerIndex;
- newLayer.PositionZ = (float)(Item.LayerHeight * (newLayerIndex + 1));
+ //newLayer.Index = newLayerIndex;
+ //newLayer.PositionZ = (float)(Item.LayerHeight * (newLayerIndex + 1));
layers[newLayerIndex] = newLayer;
newLayerIndex++;
progress++;
@@ -160,16 +158,16 @@ namespace UVtools.Core.Operations
}
else
{
- using var mat = oldLayers[layerIndex++].LayerMat;
+ using var mat = SlicerFile[layerIndex++].LayerMat;
for (byte i = 1; i < Item.Modifier; i++)
{
- using var nextMat = oldLayers[layerIndex++].LayerMat;
+ using var nextMat = SlicerFile[layerIndex++].LayerMat;
CvInvoke.Add(mat, nextMat, mat);
}
var newLayer = oldLayer.Clone();
- newLayer.Index = newLayerIndex;
- newLayer.PositionZ = (float)(Item.LayerHeight * (newLayerIndex + 1));
+ //newLayer.Index = newLayerIndex;
+ //newLayer.PositionZ = (float)(Item.LayerHeight * (newLayerIndex + 1));
newLayer.LayerMat = mat;
layers[newLayerIndex] = newLayer;
newLayerIndex++;
@@ -178,8 +176,8 @@ namespace UVtools.Core.Operations
}
}
- SlicerFile.LayerManager.Layers = layers;
SlicerFile.LayerHeight = (float)Item.LayerHeight;
+ SlicerFile.LayerManager.Layers = layers;
return !progress.Token.IsCancellationRequested;
}
diff --git a/UVtools.Core/Operations/OperationLayerRemove.cs b/UVtools.Core/Operations/OperationLayerRemove.cs
index 406a24f..b815c7f 100644
--- a/UVtools.Core/Operations/OperationLayerRemove.cs
+++ b/UVtools.Core/Operations/OperationLayerRemove.cs
@@ -73,9 +73,17 @@ namespace UVtools.Core.Operations
progress ??= new OperationProgress(false);
- progress.Reset("removed layers", (uint)layersRemove.Count);
+ progress.Reset("Removed layers", (uint)layersRemove.Count);
- var oldLayers = slicerFile.LayerManager.Layers;
+ foreach (var layerIndex in layersRemove)
+ {
+ slicerFile[layerIndex] = null;
+ progress++;
+ }
+
+ slicerFile.LayerManager.RemoveNulls();
+
+ /*var oldLayers = slicerFile.LayerManager.Layers;
var layerHeight = slicerFile.LayerHeight;
var layers = new Layer[oldLayers.Length - layersRemove.Count];
@@ -109,7 +117,9 @@ namespace UVtools.Core.Operations
progress++;
}
- slicerFile.LayerManager.Layers = layers;
+ slicerFile.LayerManager.Layers = layers;*/
+
+
return true;
}
diff --git a/UVtools.Core/Operations/OperationMask.cs b/UVtools.Core/Operations/OperationMask.cs
index 809fdbb..4b43b5a 100644
--- a/UVtools.Core/Operations/OperationMask.cs
+++ b/UVtools.Core/Operations/OperationMask.cs
@@ -81,10 +81,7 @@ namespace UVtools.Core.Operations
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationMorph.cs b/UVtools.Core/Operations/OperationMorph.cs
index bc5845b..c3120cf 100644
--- a/UVtools.Core/Operations/OperationMorph.cs
+++ b/UVtools.Core/Operations/OperationMorph.cs
@@ -168,11 +168,8 @@ namespace UVtools.Core.Operations
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, iterations);
SlicerFile[layerIndex].LayerMat = mat;
-
- lock (progress.Mutex)
- {
- progress++;
- }
+
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index 27ed2c2..b2cbacf 100644
--- a/UVtools.Core/Operations/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -287,10 +287,7 @@ namespace UVtools.Core.Operations
SlicerFile[layerIndex].LayerMat = mat;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
SlicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs
index 432aa95..22398b3 100644
--- a/UVtools.Core/Operations/OperationPattern.cs
+++ b/UVtools.Core/Operations/OperationPattern.cs
@@ -293,10 +293,7 @@ namespace UVtools.Core.Operations
//Execute(mat);
SlicerFile[layerIndex].LayerMat = dstLayer;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
SlicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs
index 95341a3..6f92bf0 100644
--- a/UVtools.Core/Operations/OperationPixelDimming.cs
+++ b/UVtools.Core/Operations/OperationPixelDimming.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
@@ -58,7 +59,8 @@ namespace UVtools.Core.Operations
"1) Reduced layer expansion for large layer objects\n" +
"2) Reduced cross layer exposure\n" +
"3) Extended pixel life of the LCD\n\n" +
- "NOTE: Run this tool only after repairs and all other transformations.";
+ "NOTE: Run this tool only after repairs and all other transformations.\n" +
+ "To create your own patterns: www.piskelapp.com";
public override string ConfirmationText =>
$"dim pixels from layers {LayerIndexStart} through {LayerIndexEnd}?";
@@ -85,11 +87,10 @@ namespace UVtools.Core.Operations
foreach (var item in stringMatrix)
{
if (string.IsNullOrWhiteSpace(item.Text)) continue;
- var lines = item.Text.Split('\n');
+ var lines = item.Text.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
for (var row = 0; row < lines.Length; row++)
{
-
- var bytes = lines[row].Trim().Split(' ');
+ var bytes = lines[row].Split(' ');
if (row == 0)
{
item.Pattern = new Matrix<byte>(lines.Length, bytes.Length);
@@ -272,7 +273,52 @@ namespace UVtools.Core.Operations
public bool IsAlternatePattern(uint layerIndex) => !IsNormalPattern(layerIndex);
-
+ public unsafe void LoadPatternFromImage(Mat mat, bool isAlternatePattern = false)
+ {
+ var result = new string[mat.Height];
+ var span = mat.GetBytePointer();
+ Parallel.For(0, mat.Height, y =>
+ {
+ result[y] = string.Empty;
+ for (int x = 0; x < mat.Width; x++)
+ {
+ result[y] += $"{span[mat.GetPixelPos(x, y)]} ";
+ }
+
+ result[y] = result[y].Trim();
+ });
+
+ StringBuilder sb = new();
+ foreach (var s in result)
+ {
+ sb.AppendLine(s);
+ }
+
+ if (isAlternatePattern)
+ {
+ AlternatePatternText = sb.ToString();
+ }
+ else
+ {
+ PatternText = sb.ToString();
+ }
+ }
+
+ public void LoadPatternFromImage(string filepath, bool isAlternatePattern = false)
+ {
+ try
+ {
+ using var mat = CvInvoke.Imread(filepath, ImreadModes.Grayscale);
+ LoadPatternFromImage(mat, isAlternatePattern);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ }
+
+ }
+
+
public void GeneratePixelDimming(string pattern)
{
if (pattern == "Chessboard")
diff --git a/UVtools.Core/Operations/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs
index 027243e..0da2586 100644
--- a/UVtools.Core/Operations/OperationProgress.cs
+++ b/UVtools.Core/Operations/OperationProgress.cs
@@ -32,7 +32,7 @@ namespace UVtools.Core.Operations
public const string StatusResinTraps = "Layers processed (Resin traps)";
public const string StatusRepairLayers = "Repaired Layers";
- public object Mutex = new();
+ public readonly object Mutex = new();
public CancellationTokenSource TokenSource { get; } = new();
public CancellationToken Token => TokenSource.Token;
@@ -104,7 +104,7 @@ namespace UVtools.Core.Operations
set
{
//_processedItems = value;
- RaiseAndSetIfChanged(ref _processedItems, value);
+ if(!RaiseAndSetIfChanged(ref _processedItems, value)) return;
RaisePropertyChanged(nameof(ProgressPercent));
RaisePropertyChanged(nameof(Description));
}
@@ -189,10 +189,14 @@ $"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_item
public void LockAndIncrement()
{
- lock (Mutex)
+ /*lock (Mutex)
{
ProcessedItems++;
- }
+ }*/
+ Interlocked.Increment(ref _processedItems);
+ RaisePropertyChanged(nameof(ProcessedItems));
+ RaisePropertyChanged(nameof(ProgressPercent));
+ RaisePropertyChanged(nameof(Description));
}
}
}
diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs
index 8a7c3f1..ffbfe6e 100644
--- a/UVtools.Core/Operations/OperationRaftRelief.cs
+++ b/UVtools.Core/Operations/OperationRaftRelief.cs
@@ -271,10 +271,7 @@ namespace UVtools.Core.Operations
ApplyMask(original, result);
SlicerFile[layerIndex].LayerMat = result;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
diff --git a/UVtools.Core/Operations/OperationRedrawModel.cs b/UVtools.Core/Operations/OperationRedrawModel.cs
index 06ae5ff..26e6630 100644
--- a/UVtools.Core/Operations/OperationRedrawModel.cs
+++ b/UVtools.Core/Operations/OperationRedrawModel.cs
@@ -244,10 +244,7 @@ namespace UVtools.Core.Operations
SlicerFile[fullMatLayerIndex].LayerMat = fullMat;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs
index 68c84b0..f1824b6 100644
--- a/UVtools.Core/Operations/OperationRepairLayers.cs
+++ b/UVtools.Core/Operations/OperationRepairLayers.cs
@@ -182,10 +182,7 @@ namespace UVtools.Core.Operations
bytes[image.GetPixelPos(issuePixel)] = 0;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
}
var nextLayerIndex = group.Key + 1;
@@ -287,10 +284,7 @@ namespace UVtools.Core.Operations
image.Dispose();
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
}
diff --git a/UVtools.Core/Operations/OperationResize.cs b/UVtools.Core/Operations/OperationResize.cs
index 1cc1105..ec81b4d 100644
--- a/UVtools.Core/Operations/OperationResize.cs
+++ b/UVtools.Core/Operations/OperationResize.cs
@@ -190,10 +190,7 @@ namespace UVtools.Core.Operations
}
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
if (newX == 1.0m && newY == 1.0m) return;
diff --git a/UVtools.Core/Operations/OperationRotate.cs b/UVtools.Core/Operations/OperationRotate.cs
index e8641c9..9498246 100644
--- a/UVtools.Core/Operations/OperationRotate.cs
+++ b/UVtools.Core/Operations/OperationRotate.cs
@@ -90,10 +90,7 @@ namespace UVtools.Core.Operations
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationSolidify.cs b/UVtools.Core/Operations/OperationSolidify.cs
index 566cc5b..9a97e1b 100644
--- a/UVtools.Core/Operations/OperationSolidify.cs
+++ b/UVtools.Core/Operations/OperationSolidify.cs
@@ -68,7 +68,7 @@ namespace UVtools.Core.Operations
public override string ToString()
{
- var result = $"[Area: ={_areaCheckType} than {_minimumArea}px²]" + LayerRangeString;
+ var result = $"[Area: {_areaCheckType} than {_minimumArea}px²]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -93,10 +93,7 @@ namespace UVtools.Core.Operations
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/Operations/OperationThreshold.cs b/UVtools.Core/Operations/OperationThreshold.cs
index 9768b23..d516b8e 100644
--- a/UVtools.Core/Operations/OperationThreshold.cs
+++ b/UVtools.Core/Operations/OperationThreshold.cs
@@ -90,10 +90,7 @@ namespace UVtools.Core.Operations
SlicerFile[layerIndex].LayerMat = mat;
}
- lock (progress.Mutex)
- {
- progress++;
- }
+ progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 67e3169..5f4d166 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.7.1</Version>
+ <Version>2.7.2</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -46,7 +46,7 @@
<ItemGroup>
<PackageReference Include="BinarySerializer" Version="8.6.0" />
<PackageReference Include="Emgu.CV" Version="4.5.1.4349" />
- <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
index 8ec27a5..6128e4f 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml
@@ -68,28 +68,43 @@
</StackPanel>
<Grid
- RowDefinitions="200,10,Auto"
- ColumnDefinitions="450,10,450"
- >
+ RowDefinitions="Auto,200,10,Auto"
+ ColumnDefinitions="450,10,450">
+
+ <Button Grid.Row="0" Grid.Column="0"
+ Content="Load pattern from image"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Command="{Binding LoadPatternFromImage}"
+ CommandParameter="False"/>
+
<TextBox
+ Grid.Row="1" Grid.Column="0"
AcceptsReturn="True"
Watermark="Pattern"
UseFloatingWatermark="True"
TextWrapping="NoWrap"
- Text="{Binding Operation.PatternText}"
- />
+ Text="{Binding Operation.PatternText}"/>
+
+ <Button Grid.Row="0" Grid.Column="2"
+ Content="Load alternate pattern from image"
+ HorizontalContentAlignment="Center"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Command="{Binding LoadPatternFromImage}"
+ CommandParameter="True"/>
<TextBox
- Grid.Column="2"
+ Grid.Row="1" Grid.Column="2"
AcceptsReturn="True"
Watermark="Alternate pattern (Optional)"
UseFloatingWatermark="True"
TextWrapping="NoWrap"
- Text="{Binding Operation.AlternatePatternText}"
- />
+ Text="{Binding Operation.AlternatePatternText}"/>
<Border
- Grid.Row="3"
- BorderBrush="LightGray"
+ Grid.Row="3" Grid.Column="0"
+ BorderBrush="LightGray"
BorderThickness="1"
Padding="5"
>
@@ -195,7 +210,7 @@
</Border>
<Border
- Grid.Row="2"
+ Grid.Row="3"
Grid.Column="2"
BorderBrush="LightGray"
BorderThickness="1"
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
index 4d09bb6..2d32651 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
@@ -1,4 +1,5 @@
using System;
+using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Emgu.CV;
using UVtools.Core.Extensions;
@@ -23,7 +24,17 @@ namespace UVtools.WPF.Controls.Tools
{
AvaloniaXamlLoader.Load(this);
}
-
+ public async void LoadPatternFromImage(bool isAlternatePattern = false)
+ {
+ var dialog = new OpenFileDialog
+ {
+ AllowMultiple = false,
+ Filters = Helpers.ImagesFileFilter,
+ };
+ var files = await dialog.ShowAsync(ParentWindow);
+ if (files is null || files.Length == 0) return;
+ Operation.LoadPatternFromImage(files[0], isAlternatePattern);
+ }
}
}
diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs
index 2971ea6..5e9c513 100644
--- a/UVtools.WPF/MainWindow.Issues.cs
+++ b/UVtools.WPF/MainWindow.Issues.cs
@@ -111,7 +111,9 @@ namespace UVtools.WPF
IsGUIEnabled = false;
-
+
+ Clipboard.Snapshot();
+
var task = await Task.Factory.StartNew(() =>
{
ShowProgressWindow("Removing selected issues");
@@ -160,7 +162,7 @@ namespace UVtools.WPF
}
}
- progress++;
+ progress.LockAndIncrement();
});
if (layersRemove.Count > 0)
@@ -181,7 +183,11 @@ namespace UVtools.WPF
IsGUIEnabled = true;
- if (!task) return;
+ if (!task)
+ {
+ Clipboard.RestoreSnapshot();
+ return;
+ }
var whiteListLayers = new List<uint>();
@@ -207,6 +213,8 @@ namespace UVtools.WPF
}
+ Clipboard.Clip($"Manually removed {issueRemoveList.Count} issues");
+
Issues.RemoveMany(issueRemoveList);
if (layersRemove.Count > 0)
diff --git a/UVtools.WPF/MainWindow.PixelEditor.cs b/UVtools.WPF/MainWindow.PixelEditor.cs
index ea23b9a..e7984cd 100644
--- a/UVtools.WPF/MainWindow.PixelEditor.cs
+++ b/UVtools.WPF/MainWindow.PixelEditor.cs
@@ -387,6 +387,7 @@ namespace UVtools.WPF
try
{
SlicerFile.LayerManager.DrawModifications(Drawings, ProgressWindow.RestartProgress());
+ return true;
}
catch (OperationCanceledException)
{
@@ -405,11 +406,18 @@ namespace UVtools.WPF
IsGUIEnabled = true;
+ if (!task.Result)
+ {
+ Clipboard.RestoreSnapshot();
+ ShowLayer();
+ return;
+ }
+
Clipboard.Clip($"Draw {Drawings.Count} modifications");
if (Settings.PixelEditor.PartialUpdateIslandsOnEditing)
{
- List<uint> whiteListLayers = new List<uint>();
+ List<uint> whiteListLayers = new();
foreach (var item in Drawings)
{
/*if (item.OperationType != PixelOperation.PixelOperationType.Drawing &&
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index bc680e6..6512bea 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -1060,7 +1060,7 @@ namespace UVtools.WPF
}
}
- ClipboardManager.Instance.Init(SlicerFile);
+ Clipboard.Init(SlicerFile);
if (SlicerFile is not ImageFile)
{
@@ -1466,11 +1466,11 @@ namespace UVtools.WPF
IsGUIEnabled = false;
- LayerManager backup = null;
+ Clipboard.Snapshot();
+
var result = await Task.Factory.StartNew(() =>
{
ShowProgressWindow(baseOperation.ProgressTitle);
- backup = SlicerFile.LayerManager.Clone();
try
{
@@ -1478,7 +1478,6 @@ namespace UVtools.WPF
}
catch (OperationCanceledException)
{
- SlicerFile.LayerManager = backup;
}
catch (Exception ex)
{
@@ -1494,7 +1493,7 @@ namespace UVtools.WPF
if (result)
{
- ClipboardManager.Instance.Clip(baseOperation, backup);
+ Clipboard.Clip(baseOperation);
ShowLayer();
RefreshProperties();
@@ -1510,6 +1509,10 @@ namespace UVtools.WPF
break;
}
}
+ else
+ {
+ Clipboard.RestoreSnapshot();
+ }
if (baseOperation.Tag is not null)
{
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index f6ff058..bd98a45 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>2.7.1</Version>
+ <Version>2.7.2</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">