diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-04-04 08:00:40 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-04-04 08:00:40 +0300 |
commit | 8b2f5b2e33981a73de89577cc67f9d37fc1aeb3b (patch) | |
tree | 3129bd4d7d06ea06f37430bdeae02ae175e7256e /UVtools.Core | |
parent | 7b44ea73a98537c485b03c52f7f26733a30ba589 (diff) |
v2.8.1
* Clipboard Manager: As now full backups are made when removing or adding layers, the undo and redo no longer rebuilds layer properties nor Z heights
* Resin traps: Improved the detection to group areas with cross paths and process them as one whole area, this also increase the detection speed and performance (#179, #13 )
* Action - Layer import: Fix a bug preventing to import layers of any kind
Diffstat (limited to 'UVtools.Core')
-rw-r--r-- | UVtools.Core/Layer/LayerIssue.cs | 173 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerManager.cs | 73 | ||||
-rw-r--r-- | UVtools.Core/Managers/ClipboardManager.cs | 6 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationLayerImport.cs | 6 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationScripting.cs | 2 |
5 files changed, 212 insertions, 48 deletions
diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs index 15f9cff..812479f 100644 --- a/UVtools.Core/Layer/LayerIssue.cs +++ b/UVtools.Core/Layer/LayerIssue.cs @@ -11,6 +11,8 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; +using System.Runtime.InteropServices.ComTypes; +using UVtools.Core.Objects; namespace UVtools.Core { @@ -453,11 +455,128 @@ namespace UVtools.Core #region ResinTrapGround - public sealed class ResinTrapGroup + public sealed class ResinTrapGroup : BindableBase, IList<LayerHollowArea> { - public List<List<LayerHollowArea>> Groups { get; } = new(); + #region List Implementation + private readonly List<LayerHollowArea> hollowAreaList = new(); + private LayerHollowArea.AreaType _currentAreaType = LayerHollowArea.AreaType.Trap; - public int FindHollowArea(LayerHollowArea hollowArea) + public IEnumerator<LayerHollowArea> GetEnumerator() + { + return hollowAreaList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) hollowAreaList).GetEnumerator(); + } + + public void Add(LayerHollowArea item) + { + if (item.Type == LayerHollowArea.AreaType.Drain) + { + CurrentAreaType = LayerHollowArea.AreaType.Drain; + } + else if (_currentAreaType == LayerHollowArea.AreaType.Drain) + { + item.Type = LayerHollowArea.AreaType.Drain; + } + hollowAreaList.Add(item); + } + + public void Add(ResinTrapGroup group) + { + foreach (var area in group) + { + Add(area); + } + } + + public void Clear() + { + CurrentAreaType = LayerHollowArea.AreaType.Trap; + hollowAreaList.Clear(); + } + + public bool Contains(LayerHollowArea item) + { + return hollowAreaList.Contains(item); + } + + public void CopyTo(LayerHollowArea[] array, int arrayIndex) + { + hollowAreaList.CopyTo(array, arrayIndex); + } + + public bool Remove(LayerHollowArea item) + { + var result = hollowAreaList.Remove(item); + if (Count == 0) CurrentAreaType = LayerHollowArea.AreaType.Trap; + return result; + } + + public int Count => hollowAreaList.Count; + + public bool IsReadOnly => false; + + public int IndexOf(LayerHollowArea item) + { + return hollowAreaList.IndexOf(item); + } + + public void Insert(int index, LayerHollowArea item) + { + if (item.Type == LayerHollowArea.AreaType.Drain) + { + CurrentAreaType = LayerHollowArea.AreaType.Drain; + } + else if (_currentAreaType == LayerHollowArea.AreaType.Drain) + { + item.Type = LayerHollowArea.AreaType.Drain; + } + hollowAreaList.Insert(index, item); + } + + public void RemoveAt(int index) + { + hollowAreaList.RemoveAt(index); + if (Count == 0) CurrentAreaType = LayerHollowArea.AreaType.Trap; + } + + public LayerHollowArea this[int index] + { + get => hollowAreaList[index]; + set => hollowAreaList[index] = value; + } + #endregion + + #region Properties + public LayerHollowArea.AreaType CurrentAreaType + { + get => _currentAreaType; + set + { + if(!RaiseAndSetIfChanged(ref _currentAreaType, value)) return; + foreach (var area in this) // Update previous items + { + area.Type = _currentAreaType; + } + } + } + #endregion + } + + public sealed class ResinTrapTree + { + public List<ResinTrapGroup> Groups { get; } = new(); + + public ResinTrapGroup FindHollowGroup(LayerHollowArea hollowArea) + { + var i = FindHollowGroupIndex(hollowArea); + return i >= 0 ? Groups[i] : null; + } + + public int FindHollowGroupIndex(LayerHollowArea hollowArea) { for (var i = 0; i < Groups.Count; i++) { @@ -470,20 +589,54 @@ namespace UVtools.Core return -1; } - public int Add(LayerHollowArea hollowArea) + public ResinTrapGroup AddRoot(LayerHollowArea hollowArea) => AddRoot(hollowArea, out _); + public ResinTrapGroup AddRoot(LayerHollowArea hollowArea, out int index) { - var index = FindHollowArea(hollowArea); + index = FindHollowGroupIndex(hollowArea); if (index < 0) // Not found { index = Groups.Count; - Groups.Add(new List<LayerHollowArea>{hollowArea}); - return index; + Groups.Add(new(){hollowArea}); + } + else // Exists + { + Groups[index].Add(hollowArea); } - // Exists - Groups[index].Add(hollowArea); + return Groups[index]; + } + + public ResinTrapGroup AddChild(ResinTrapGroup group, LayerHollowArea hollowArea) + { + // This will find if the area exists in any other group, + // If yes then the groups are merged, otherwise it will be added to the parent group - return index; + var findGroup = FindHollowGroup(hollowArea); + if (findGroup is not null && !ReferenceEquals(group, findGroup)) + { + return MergeGroups(group, findGroup, true); + } + if(group.IndexOf(hollowArea) == -1) group.Add(hollowArea); + return group; + } + + /// <summary> + /// Merges two groups + /// </summary> + /// <param name="group1"></param> + /// <param name="group2"></param> + /// <param name="manageGroups">True to remove old groups and add the new to group list</param> + /// <returns>A new group instance holding group1 and group2 items</returns> + public ResinTrapGroup MergeGroups(ResinTrapGroup group1, ResinTrapGroup group2, bool manageGroups = false) + { + ResinTrapGroup newGroup = new (){group1, group2}; + if (manageGroups) + { + Groups.Remove(group1); + Groups.Remove(group2); + Groups.Add(newGroup); + } + return newGroup; } } #endregion diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index ae4c9a0..f64330b 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -10,9 +10,11 @@ using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Emgu.CV; using Emgu.CV.CvEnum; @@ -1005,9 +1007,9 @@ namespace UVtools.Core islandImage = image; } - using (Mat labels = new Mat()) - using (Mat stats = new Mat()) - using (Mat centroids = new Mat()) + using (Mat labels = new()) + using (Mat stats = new()) + using (Mat centroids = new()) { var numLabels = CvInvoke.ConnectedComponentsWithStats(islandImage, labels, stats, centroids, @@ -1028,7 +1030,7 @@ namespace UVtools.Core //stats[i][3]: Height of Connected Component //stats[i][4]: Total Area (in pixels) in Connected Component - Span<int> labelSpan = labels.GetPixelSpan<int>(); + var labelSpan = labels.GetPixelSpan<int>(); for (int i = 1; i < numLabels; i++) { @@ -1169,35 +1171,30 @@ namespace UVtools.Core if (canProcessCheck) { - if (previousImage is null) - { - previousImage = this[layer.Index - 1].LayerMat; - } + previousImage ??= this[layer.Index - 1].LayerMat; - using (var subtractedImage = new Mat()) - using (var vecPoints = new VectorOfPoint()) - { - var anchor = new Point(-1, -1); + using var subtractedImage = new Mat(); + using var vecPoints = new VectorOfPoint(); + var anchor = new Point(-1, -1); - CvInvoke.Subtract(image, previousImage, subtractedImage); - CvInvoke.Threshold(subtractedImage, subtractedImage, 127, 255, - ThresholdType.Binary); + CvInvoke.Subtract(image, previousImage, subtractedImage); + CvInvoke.Threshold(subtractedImage, subtractedImage, 127, 255, + ThresholdType.Binary); - CvInvoke.Erode(subtractedImage, subtractedImage, - CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), - anchor), - anchor, overhangConfig.ErodeIterations, BorderType.Default, - new MCvScalar()); + CvInvoke.Erode(subtractedImage, subtractedImage, + CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), + anchor), + anchor, overhangConfig.ErodeIterations, BorderType.Default, + new MCvScalar()); - CvInvoke.FindNonZero(subtractedImage, vecPoints); - if (vecPoints.Size >= overhangConfig.RequiredPixelsToConsider) - { - AddIssue(new LayerIssue( - layer, LayerIssue.IssueType.Overhang, vecPoints.ToArray(), - layer.BoundingRectangle - )); - } + CvInvoke.FindNonZero(subtractedImage, vecPoints); + if (vecPoints.Size >= overhangConfig.RequiredPixelsToConsider) + { + AddIssue(new LayerIssue( + layer, LayerIssue.IssueType.Overhang, vecPoints.ToArray(), + layer.BoundingRectangle + )); } } } @@ -1268,7 +1265,7 @@ namespace UVtools.Core { progress.Reset(OperationProgress.StatusResinTraps, LayerCount); - + ResinTrapTree resinTrapTree = new(); for (uint layerIndex = 1; layerIndex < LayerCount - 1; layerIndex++) // First and Last layers, always drains { @@ -1290,7 +1287,9 @@ namespace UVtools.Core areaCount++; - List<LayerHollowArea> linkedAreas = new(); + var trapGroup = resinTrapTree.AddRoot(area); + + //List<LayerHollowArea> linkedAreas = new(); for (sbyte dir = 1; dir >= -1 && area.Type != LayerHollowArea.AreaType.Drain; dir -= 2) //Parallel.ForEach(new sbyte[] {1, -1}, new ParallelOptions {MaxDegreeOfParallelism = 2}, dir => @@ -1386,7 +1385,9 @@ namespace UVtools.Core queue.Enqueue(intersectingAreas[i]); } - linkedAreas.Add(intersectingAreas[i]); + + trapGroup = resinTrapTree.AddChild(trapGroup, intersectingAreas[i]); + //linkedAreas.Add(intersectingAreas[i]); intersectingAreas.Remove(i); if (intersectingAreas.Count == 0 ) // Intersection areas sweep end, quit this path @@ -1433,7 +1434,8 @@ namespace UVtools.Core resinTrapConfig.RequiredBlackPixelsToDrain) ) // Black pixel without next areas = Drain { - area.Type = LayerHollowArea.AreaType.Drain; + trapGroup.CurrentAreaType = LayerHollowArea.AreaType.Drain; + //area.Type = LayerHollowArea.AreaType.Drain; exitPixelLoop = true; break; } @@ -1443,7 +1445,8 @@ namespace UVtools.Core if (queue.Count == 0 && blackCount > Math.Min(checkArea.Contour.Length / 2, resinTrapConfig.RequiredBlackPixelsToDrain)) { - area.Type = LayerHollowArea.AreaType.Drain; + trapGroup.CurrentAreaType = LayerHollowArea.AreaType.Drain; + //area.Type = LayerHollowArea.AreaType.Drain; } } // Dispose intersecting image @@ -1452,10 +1455,10 @@ namespace UVtools.Core } // Areas loop } // Dir layer loop - foreach (var linkedArea in linkedAreas) // Update linked areas + /*foreach (var linkedArea in linkedAreas) // Update linked areas { linkedArea.Type = area.Type; - } + }*/ }//); } } diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs index a436625..6577f6b 100644 --- a/UVtools.Core/Managers/ClipboardManager.cs +++ b/UVtools.Core/Managers/ClipboardManager.cs @@ -130,7 +130,11 @@ namespace UVtools.Core.Managers SlicerFile.LayerHeight = clip.LayerHeight; } - SlicerFile.LayerManager.Layers = Layer.CloneLayers(layers); + SlicerFile.SuppressRebuildPropertiesWork(() => + { + SlicerFile.LayerManager.Layers = Layer.CloneLayers(layers); + }); + if (i == _currentIndex) break; } } diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs index e77fc49..438cff4 100644 --- a/UVtools.Core/Operations/OperationLayerImport.cs +++ b/UVtools.Core/Operations/OperationLayerImport.cs @@ -469,7 +469,11 @@ namespace UVtools.Core.Operations } - progress.LockAndIncrement(); + lock (progress.Mutex) + { + lastProcessedLayerIndex = Math.Max(lastProcessedLayerIndex, (int)layerIndex); + progress++; + } }); fileFormat.Dispose(); diff --git a/UVtools.Core/Operations/OperationScripting.cs b/UVtools.Core/Operations/OperationScripting.cs index ea95c47..7807d16 100644 --- a/UVtools.Core/Operations/OperationScripting.cs +++ b/UVtools.Core/Operations/OperationScripting.cs @@ -41,7 +41,7 @@ namespace UVtools.Core.Operations $"Make sure to run only the scripts you trust! Or run UVtools in a sandbox while executing this."; public override string ConfirmationText => - $"Run script from layers {LayerIndexStart} through {LayerIndexEnd}?"; + $"run the {ScriptGlobals.Script.Name} script from layers {LayerIndexStart} through {LayerIndexEnd}?"; public override string ProgressTitle => $"Scripting from layers {LayerIndexStart} through {LayerIndexEnd}"; |