mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-09 01:52:32 +02:00
LayerIssue to support contours
This commit is contained in:
@@ -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
|
||||
/// <summary>
|
||||
/// Gets the parent layer
|
||||
/// </summary>
|
||||
public Layer Layer { get; }
|
||||
public Layer Layer { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer index
|
||||
@@ -286,66 +288,89 @@ namespace UVtools.Core
|
||||
/// <summary>
|
||||
/// Gets the issue type associated
|
||||
/// </summary>
|
||||
public IssueType Type { get; }
|
||||
public IssueType Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixels points containing the issue
|
||||
/// </summary>
|
||||
public Point[] Pixels { get; }
|
||||
|
||||
public int PixelsCount => Pixels?.Length ?? 0;
|
||||
public Point[] Pixels { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding rectangle of the pixel area
|
||||
/// Gets the contours containing the issue
|
||||
/// </summary>
|
||||
public Rectangle BoundingRectangle { get; }
|
||||
public Point[][] Contours { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X coordinate for the first point, -1 if doesn't exists
|
||||
/// </summary>
|
||||
public int X => HaveValidPoint ? Pixels[0].X : -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y coordinate for the first point, -1 if doesn't exists
|
||||
/// </summary>
|
||||
public int Y => HaveValidPoint ? Pixels[0].Y : -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XY point for first point
|
||||
/// </summary>
|
||||
public Point FirstPoint => HaveValidPoint ? Pixels[0] : new Point(-1, -1);
|
||||
public string FirstPointStr => $"{FirstPoint.X}, {FirstPoint.Y}";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of pixels on this issue
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding rectangle of the pixel area
|
||||
/// </summary>
|
||||
public Rectangle BoundingRectangle { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the area of the issue
|
||||
/// </summary>
|
||||
public double Area { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X coordinate for the first point, -1 if doesn't exists
|
||||
/// </summary>
|
||||
public int X => FirstPoint.X;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y coordinate for the first point, -1 if doesn't exists
|
||||
/// </summary>
|
||||
public int Y => FirstPoint.Y;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XY point for first point
|
||||
/// </summary>
|
||||
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}";
|
||||
|
||||
/// <summary>
|
||||
/// Check if this issue have a valid start point to show
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets area pixels
|
||||
/// Gets contours
|
||||
/// </summary>
|
||||
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<Point[]> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<LayerHollowArea>();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user