diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs index 6ccc644..c4b742d 100644 --- a/UVtools.Core/Layer/LayerIssue.cs +++ b/UVtools.Core/Layer/LayerIssue.cs @@ -11,6 +11,7 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; +using UVtools.Core.Extensions; using UVtools.Core.Objects; namespace UVtools.Core @@ -267,6 +268,7 @@ namespace UVtools.Core Island, Overhang, ResinTrap, + SuctionCup, TouchingBound, PrintHeight, EmptyLayer, @@ -276,7 +278,7 @@ namespace UVtools.Core /// /// Gets the parent layer /// - public Layer Layer { get; } + public Layer Layer { get; init; } /// /// Gets the layer index @@ -286,66 +288,89 @@ namespace UVtools.Core /// /// Gets the issue type associated /// - public IssueType Type { get; } + public IssueType Type { get; init; } /// /// Gets the pixels points containing the issue /// - public Point[] Pixels { get; } - - public int PixelsCount => Pixels?.Length ?? 0; + public Point[] Pixels { get; init; } /// - /// Gets the bounding rectangle of the pixel area + /// Gets the contours containing the issue /// - public Rectangle BoundingRectangle { get; } + public Point[][] Contours { get; init; } - /// - /// Gets the X coordinate for the first point, -1 if doesn't exists - /// - public int X => HaveValidPoint ? Pixels[0].X : -1; - - /// - /// Gets the Y coordinate for the first point, -1 if doesn't exists - /// - public int Y => HaveValidPoint ? Pixels[0].Y : -1; - - /// - /// Gets the XY point for first point - /// - public Point FirstPoint => HaveValidPoint ? Pixels[0] : new Point(-1, -1); - public string FirstPointStr => $"{FirstPoint.X}, {FirstPoint.Y}"; - - /// - /// Gets the number of pixels on this issue - /// - public uint Size + public int PixelsCount { get { - if (Type == IssueType.ResinTrap && !BoundingRectangle.IsEmpty) - { - return (uint)(BoundingRectangle.Width * BoundingRectangle.Height); - } - - if (Pixels is null) return 0; - return (uint)Pixels.Length; + if (Pixels is not null) return Pixels.Length; + if (Contours is not null) return (int)Area; + return 0; } } + /// + /// Gets the bounding rectangle of the pixel area + /// + public Rectangle BoundingRectangle { get; init; } + + /// + /// Gets the area of the issue + /// + public double Area { get; init; } + + /// + /// Gets the X coordinate for the first point, -1 if doesn't exists + /// + public int X => FirstPoint.X; + + /// + /// Gets the Y coordinate for the first point, -1 if doesn't exists + /// + public int Y => FirstPoint.Y; + + /// + /// Gets the XY point for first point + /// + public Point FirstPoint + { + get + { + if (Pixels?.Length > 0) return Pixels[0]; + if (Contours?.Length > 0) return Contours[0][0]; + return new Point(-1, -1); + } + } + + public string FirstPointStr => $"{FirstPoint.X}, {FirstPoint.Y}"; + /// /// Check if this issue have a valid start point to show /// - public bool HaveValidPoint => Pixels?.Length > 0; + public bool HaveValidPoint => Pixels?.Length > 0 || Contours?.Length > 0; - public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Rectangle boundingRectangle = default) + public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Point[][] contours = null, Rectangle boundingRectangle = default) { Layer = layer; Type = type; + Contours = contours; Pixels = pixels; BoundingRectangle = boundingRectangle; + Area = (uint)boundingRectangle.Area(); } + public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Rectangle boundingRectangle = default) : + this(layer, type, pixels, null, boundingRectangle) { } + + + public LayerIssue(Layer layer, IssueType type, Point[][] contours, Rectangle boundingRectangle = default) : + this(layer, type, null, contours, boundingRectangle) { } + + public LayerIssue(Layer layer, IssueType type) : + this(layer, type, null, null, default) + { } + public Point this[uint index] => Pixels[index]; public Point this[int index] => Pixels[index]; @@ -362,9 +387,10 @@ namespace UVtools.Core public override string ToString() { - return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(Size)}: {Size}"; + return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(PixelsCount)}: {PixelsCount}"; } + public bool Equals(LayerIssue other) { if (other is null) return false; @@ -373,6 +399,7 @@ namespace UVtools.Core && Type == other.Type && PixelsCount == other.PixelsCount && Pixels is not null && other.Pixels is not null && Pixels.SequenceEqual(other.Pixels) + && Contours is not null && other.Contours is not null && Contours.SequenceEqual(other.Contours) //&& BoundingRectangle.Equals(other.BoundingRectangle) ; } @@ -392,6 +419,7 @@ namespace UVtools.Core var hashCode = (Layer != null ? Layer.GetHashCode() : 0); hashCode = (hashCode * 397) ^ (int) Type; hashCode = (hashCode * 397) ^ (Pixels != null ? Pixels.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (Contours != null ? Contours.GetHashCode() : 0); hashCode = (hashCode * 397) ^ BoundingRectangle.GetHashCode(); return hashCode; } @@ -410,12 +438,14 @@ namespace UVtools.Core Drain } /// - /// Gets area pixels + /// Gets contours /// public Point[][] Contours { get; } public Rectangle BoundingRectangle { get; } + public double Area { get; set; } + public AreaType Type { get; set; } = AreaType.Unknown; public bool Processed { get; set; } @@ -433,22 +463,6 @@ namespace UVtools.Core set => Contours[index] = value; } - /*public Point[] this[uint x, uint y] - { - get - { - for (uint i = 0; i < Contours.Length; i++) - { - if (Contours[i].X == x && Contours[i].Y == y) return Contours[i]; - } - return Point.Empty; - } - } - - public Point this[int x, int y] => this[(uint)x, (uint)y]; - - public Point this[Point point] => this[point.X, point.Y];*/ - #endregion public IEnumerator GetEnumerator() @@ -461,14 +475,13 @@ namespace UVtools.Core return GetEnumerator(); } - public LayerHollowArea() - { - } + public LayerHollowArea() { } - public LayerHollowArea(Point[][] contours, Rectangle boundingRectangle, AreaType type = AreaType.Unknown) + public LayerHollowArea(Point[][] contours, Rectangle boundingRectangle, double area, AreaType type = AreaType.Unknown) { Contours = contours; BoundingRectangle = boundingRectangle; + Area = area; Type = type; } } diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 325ebc0..ce5e935 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -904,8 +904,7 @@ namespace UVtools.Core if (pixels.Count > 0) { - AddIssue(new LayerIssue(layer, LayerIssue.IssueType.TouchingBound, - pixels.ToArray())); + AddIssue(new LayerIssue(layer, LayerIssue.IssueType.TouchingBound, pixels.ToArray(), null)); } } @@ -1168,13 +1167,15 @@ namespace UVtools.Core // var listHollowArea = new List(); var hollowGroups = EmguContours.GetNegativeContoursInGroups(contours, hierarchy); + var areas = EmguContours.GetContoursArea(hollowGroups); - foreach (var group in hollowGroups) + for (var i = 0; i < hollowGroups.Count; i++) { - if(CvInvoke.ContourArea(group[0]) < resinTrapConfig.RequiredAreaToProcessCheck) continue; - var rect = CvInvoke.BoundingRectangle(group[0]); - listHollowArea.Add(new LayerHollowArea(group.ToArrayOfArray(), + if (areas[i] < resinTrapConfig.RequiredAreaToProcessCheck) continue; + var rect = CvInvoke.BoundingRectangle(hollowGroups[i][0]); + listHollowArea.Add(new LayerHollowArea(hollowGroups[i].ToArrayOfArray(), rect, + areas[i], layer.Index <= resinTrapConfig.StartLayerIndex || layer.Index == LayerCount - 1 // First and Last layers, always drains ? LayerHollowArea.AreaType.Drain @@ -1415,7 +1416,7 @@ namespace UVtools.Core int ret = issue.Type.CompareTo(layerIssue.Type); return ret != 0 ? ret : issue.LayerIndex.CompareTo(layerIssue.LayerIndex); });*/ - if (progress.Token.IsCancellationRequested) return result.OrderBy(issue => issue.Type).ThenBy(issue => issue.LayerIndex).ThenBy(issue => issue.PixelsCount).ToList(); + if (progress.Token.IsCancellationRequested) return result.OrderBy(issue => issue.Type).ThenBy(issue => issue.LayerIndex).ThenBy(issue => issue.Area).ToList(); for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) { @@ -1425,13 +1426,13 @@ namespace UVtools.Core from area in list where area.Type == LayerHollowArea.AreaType.Trap - select new LayerIssue(this[layerIndex], LayerIssue.IssueType.ResinTrap, area.Contours[0], area.BoundingRectangle)) + select new LayerIssue(this[layerIndex], LayerIssue.IssueType.ResinTrap, area.Contours, area.BoundingRectangle){Area = area.Area}) { AddIssue(issue); } } - return result.OrderBy(issue => issue.Type).ThenBy(issue => issue.LayerIndex).ThenBy(issue => issue.PixelsCount).ToList(); + return result.OrderBy(issue => issue.Type).ThenBy(issue => issue.LayerIndex).ThenBy(issue => issue.Area).ToList(); } diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs index c554e26..425e1f2 100644 --- a/UVtools.Core/Operations/OperationRepairLayers.cs +++ b/UVtools.Core/Operations/OperationRepairLayers.cs @@ -358,12 +358,8 @@ namespace UVtools.Core.Operations foreach (var issue in Issues.Where(issue => issue.LayerIndex == layerIndex && issue.Type == LayerIssue.IssueType.ResinTrap)) { initImage(); - using var vec = new VectorOfVectorOfPoint(new VectorOfPoint(issue.Pixels)); - CvInvoke.DrawContours(image, - vec, - -1, - EmguExtensions.WhiteColor, - -1); + using var vec = new VectorOfVectorOfPoint(issue.Contours); + CvInvoke.DrawContours(image, vec, -1, EmguExtensions.WhiteColor, -1); } } } diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs index c9612a8..f0dfd4e 100644 --- a/UVtools.WPF/MainWindow.Issues.cs +++ b/UVtools.WPF/MainWindow.Issues.cs @@ -146,15 +146,11 @@ namespace UVtools.WPF } else if (issue.Type == LayerIssue.IssueType.ResinTrap) { - using (var contours = - new VectorOfVectorOfPoint(new VectorOfPoint(issue.Pixels))) - { - CvInvoke.DrawContours(image, contours, -1, new MCvScalar(255), -1); - } - + using var contours = new VectorOfVectorOfPoint(issue.Contours); + CvInvoke.DrawContours(image, contours, -1, EmguExtensions.WhiteColor, -1); edited = true; } - + } if (edited) @@ -351,11 +347,12 @@ namespace UVtools.WPF return; } - if (issue.Type is LayerIssue.IssueType.TouchingBound or LayerIssue.IssueType.EmptyLayer || (issue.X == -1 && issue.Y == -1)) + var firstPoint = issue.FirstPoint; + if (issue.Type is LayerIssue.IssueType.TouchingBound or LayerIssue.IssueType.EmptyLayer || (firstPoint.X == -1 && firstPoint.Y == -1)) { ZoomToFit(); } - else if (issue.X >= 0 && issue.Y >= 0) + else if (firstPoint.X >= 0 && firstPoint.Y >= 0) { if (Settings.LayerPreview.ZoomIssues ^ (_globalModifiers & KeyModifiers.Alt) != 0) diff --git a/UVtools.WPF/MainWindow.LayerPreview.cs b/UVtools.WPF/MainWindow.LayerPreview.cs index f1306e4..05a2364 100644 --- a/UVtools.WPF/MainWindow.LayerPreview.cs +++ b/UVtools.WPF/MainWindow.LayerPreview.cs @@ -963,10 +963,9 @@ namespace UVtools.WPF : Settings.LayerPreview.ResinTrapColor; - using (var vec = new VectorOfVectorOfPoint(new VectorOfPoint(issue.Pixels))) + using (var vec = new VectorOfVectorOfPoint(issue.Contours)) { - CvInvoke.DrawContours(LayerCache.ImageBgr, vec, -1, - new MCvScalar(color.B, color.G, color.R), -1); + CvInvoke.DrawContours(LayerCache.ImageBgr, vec, -1, new MCvScalar(color.B, color.G, color.R), -1); } if (_showLayerImageCrosshairs && @@ -1496,7 +1495,7 @@ namespace UVtools.WPF /// private Rectangle GetTransposedIssueBounds(LayerIssue issue) { - if (issue.X >= 0 && issue.Y >= 0 && (issue.BoundingRectangle.IsEmpty || issue.Size == 1)) + if (issue.X >= 0 && issue.Y >= 0 && (issue.BoundingRectangle.IsEmpty || issue.PixelsCount == 1)) return new Rectangle(GetTransposedPoint(issue.FirstPoint, true), new Size(1, 1)); //return new Rectangle(LayerCache.Image.Height - 1 - issue.Y, issue.X, 1, 1);