mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-12 11:32:33 +02:00
fa5073e68f
* (Add) Elapsed time to the Log list * (Add) Setting - Issues - Islands: Allow diagonal bonds with default to false (#22) * (Change) Tool - Repair Layers: Allow set both iterations to 0 to skip closing and opening operations and allow remove islands independently * (Change) Title - file open time from miliseconds to seconds * (Improvement) Tool - Repair Layers: Layer image will only read/save if required and if current layer got modified * (Fix) Setting - Issues - Islands: "Pixels below this value will turn black, otherwise white" (Threshold) was not using the set value and was forcing 1 * (Fix) Remove duplicated log for repair layers and issues
288 lines
8.7 KiB
C#
288 lines
8.7 KiB
C#
/*
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* Version 3, 19 November 2007
|
|
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
* Everyone is permitted to copy and distribute verbatim copies
|
|
* of this license document, but changing it is not allowed.
|
|
*/
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace UVtools.Core
|
|
{
|
|
#region LayerIssue Class
|
|
|
|
public class IslandDetectionConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Gets if the detection is enabled
|
|
/// </summary>
|
|
public bool Enabled { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a list of layers to check for islands, absent layers will not be checked.
|
|
/// Set to null to check every layer
|
|
/// </summary>
|
|
public List<uint> WhiteListLayers { get; set; } = null;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
|
|
/// Set to 0 to disable this operation
|
|
/// </summary>
|
|
public byte BinaryThreshold { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Gets the required area size (x*y) to consider process a island (0-255)
|
|
/// </summary>
|
|
public byte RequiredAreaToProcessCheck { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Gets the required brightness for check a pixel under a island (0-255)
|
|
/// </summary>
|
|
public byte RequiredPixelBrightnessToProcessCheck { get; set; } = 10;
|
|
|
|
/// <summary>
|
|
/// Gets the required number of pixels to support a island and discard it as a issue (0-255)
|
|
/// </summary>
|
|
public byte RequiredPixelsToSupport { get; set; } = 10;
|
|
|
|
/// <summary>
|
|
/// Gets the required brightness of supporting pixels to count as a valid support (0-255)
|
|
/// </summary>
|
|
public byte RequiredPixelBrightnessToSupport { get; set; } = 150;
|
|
|
|
/// <summary>
|
|
/// Gets the setting for whether or not diagonal bonds are considered when evaluation islands.
|
|
/// If true, all 8 neighbors of a pixel (including diagonals) will be considered when finding
|
|
/// individual components on the layer, if false only 4 neighbors (right, left, above, below)
|
|
/// will be considered..
|
|
/// </summary>
|
|
public bool AllowDiagonalBonds { get; set; } = false;
|
|
}
|
|
|
|
public class ResinTrapDetectionConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Gets if the detection is enabled
|
|
/// </summary>
|
|
public bool Enabled { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
|
|
/// Set to 0 to disable this operation
|
|
/// </summary>
|
|
public byte BinaryThreshold { get; set; } = 127;
|
|
|
|
/// <summary>
|
|
/// Gets the required area size (x*y) to consider process a hollow area (0-255)
|
|
/// </summary>
|
|
public byte RequiredAreaToProcessCheck { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Gets the number of black pixels required to consider a drain
|
|
/// </summary>
|
|
public byte RequiredBlackPixelsToDrain { get; set; } = 10;
|
|
|
|
/// <summary>
|
|
/// Gets the maximum pixel brightness to be a drain pixel (0-150)
|
|
/// </summary>
|
|
public byte MaximumPixelBrightnessToDrain { get; set; } = 30;
|
|
}
|
|
|
|
public class TouchingBoundDetectionConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Gets if the detection is enabled
|
|
/// </summary>
|
|
public bool Enabled { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Gets the maximum pixel brightness to be a touching bound
|
|
/// </summary>
|
|
public byte MaximumPixelBrightness { get; set; } = 200;
|
|
}
|
|
|
|
|
|
public class LayerIssue : IEnumerable<Point>
|
|
{
|
|
public enum IssueType : byte
|
|
{
|
|
Island,
|
|
ResinTrap,
|
|
TouchingBound,
|
|
EmptyLayer,
|
|
//HoleSandwich,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the parent layer
|
|
/// </summary>
|
|
public Layer Layer { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the layer index
|
|
/// </summary>
|
|
public uint LayerIndex => Layer.Index;
|
|
|
|
/// <summary>
|
|
/// Gets the issue type associated
|
|
/// </summary>
|
|
public IssueType Type { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the pixels points containing the issue
|
|
/// </summary>
|
|
public Point[] Pixels { get; }
|
|
|
|
public int PixelsCount => Pixels?.Length ?? 0;
|
|
|
|
/// <summary>
|
|
/// Gets the bounding rectangle of the pixel area
|
|
/// </summary>
|
|
public Rectangle BoundingRectangle { get; }
|
|
|
|
/// <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
|
|
{
|
|
get
|
|
{
|
|
if (Type == IssueType.ResinTrap && !BoundingRectangle.IsEmpty)
|
|
{
|
|
return (uint)(BoundingRectangle.Width * BoundingRectangle.Height);
|
|
}
|
|
|
|
if (ReferenceEquals(Pixels, null)) return 0;
|
|
return (uint)Pixels.Length;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if this issue have a valid start point to show
|
|
/// </summary>
|
|
public bool HaveValidPoint => !ReferenceEquals(Pixels, null) && Pixels.Length > 0;
|
|
|
|
public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Rectangle boundingRectangle = new Rectangle())
|
|
{
|
|
Layer = layer;
|
|
Type = type;
|
|
Pixels = pixels;
|
|
BoundingRectangle = boundingRectangle;
|
|
}
|
|
|
|
public Point this[uint index] => Pixels[index];
|
|
|
|
public Point this[int index] => Pixels[index];
|
|
|
|
public IEnumerator<Point> GetEnumerator()
|
|
{
|
|
return ((IEnumerable<Point>)Pixels).GetEnumerator();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(Size)}: {Size}";
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region LayerHollowArea
|
|
|
|
public class LayerHollowArea : IEnumerable<Point>
|
|
{
|
|
public enum AreaType : byte
|
|
{
|
|
Unknown = 0,
|
|
Trap,
|
|
Drain
|
|
}
|
|
/// <summary>
|
|
/// Gets area pixels
|
|
/// </summary>
|
|
public Point[] Contour { get; }
|
|
|
|
public Rectangle BoundingRectangle { get; }
|
|
|
|
public AreaType Type { get; set; } = AreaType.Unknown;
|
|
|
|
public bool Processed { get; set; }
|
|
|
|
#region Indexers
|
|
public Point this[uint index]
|
|
{
|
|
get => index < Contour.Length ? Contour[index] : Point.Empty;
|
|
set => Contour[index] = value;
|
|
}
|
|
|
|
public Point this[int index]
|
|
{
|
|
get => index < Contour.Length ? Contour[index] : Point.Empty;
|
|
set => Contour[index] = value;
|
|
}
|
|
|
|
public Point this[uint x, uint y]
|
|
{
|
|
get
|
|
{
|
|
for (uint i = 0; i < Contour.Length; i++)
|
|
{
|
|
if (Contour[i].X == x && Contour[i].Y == y) return Contour[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()
|
|
{
|
|
return ((IEnumerable<Point>)Contour).GetEnumerator();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
public LayerHollowArea()
|
|
{
|
|
}
|
|
|
|
public LayerHollowArea(Point[] contour, Rectangle boundingRectangle, AreaType type = AreaType.Unknown)
|
|
{
|
|
Contour = contour;
|
|
BoundingRectangle = boundingRectangle;
|
|
Type = type;
|
|
}
|
|
}
|
|
#endregion
|
|
}
|