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>2022-10-02 02:44:39 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2022-10-02 02:44:39 +0300
commitca6f623a9f0e994db30e7f37b84ab2c61d0cf3d8 (patch)
treec70ddc7c3ee26bdc87cebeb13e3347384403abae /UVtools.Core
parent46706f50a82e462b73a499a4100bb9e1ce629015 (diff)
v3.6.7v3.6.7
- **Layer:** - (Add) Property: `LayerMatBoundingRectangle` - (Add) Property: `LayerMatModelBoundingRectangle` - (Add) Method: `GetLayerMat(roi)` - **Issues:** - **Islands:** - (Improvement) Islands detection performance - (Improvement) Required area to consider an island is now real area instead of bounding box area - (Fix) Logic bug when combining with overhangs - **Overhangs:** - (Improvement) Overhangs detection performance - (Improvement) Overhangs are now split and identified as separately in the layer - (Improvement) Overhangs now shows the correct issue area and able to locate the problem region more precisely - (Improvement) Compress overhangs into contours instead of using whole pixels, resulting in better render performance and less memory to hold the issue - (Fix) Bug in overhang logic causing to detect the problem twice when combined with supports - (Improvement) Touching bounds check logic to spare cycles - **Tool - Raise platform on print finish:** - (Add) Preset "Minimum": Sets to the minimum position - (Add) Preset "Medium": Sets to half-way between minimum and maximum position - (Add) Preset "Maximum": Sets to the maximum position - (Add) Wait time: Sets the ensured wait time to stay still on the desired position. This is useful if the printer firmware always move to top and you want to stay still on the set position for at least the desired time. Note: The print time calculation will take this wait into consideration and display a longer print time. - (Add) FileFormat: AnyCubic custom machine (.pwc) - (Downgrade) OpenCV from 4.5.5 to 4.5.4 due a possible crash while detecting islands (Windows)
Diffstat (limited to 'UVtools.Core')
-rw-r--r--UVtools.Core/CoreSettings.cs6
-rw-r--r--UVtools.Core/EmguCV/EmguContour.cs4
-rw-r--r--UVtools.Core/EmguCV/EmguContours.cs24
-rw-r--r--UVtools.Core/EmguCV/MatRoi.cs49
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs27
-rw-r--r--UVtools.Core/Extensions/PointExtensions.cs4
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs1
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs196
-rw-r--r--UVtools.Core/Layers/Layer.cs50
-rw-r--r--UVtools.Core/Layers/LayerIssueConfiguration.cs4
-rw-r--r--UVtools.Core/Layers/MainIssue.cs1
-rw-r--r--UVtools.Core/Managers/IssueManager.cs251
-rw-r--r--UVtools.Core/Objects/KernelConfiguration.cs4
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs5
-rw-r--r--UVtools.Core/Operations/OperationCalibrateElephantFoot.cs3
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs12
-rw-r--r--UVtools.Core/Operations/OperationCalibrateStressTower.cs3
-rw-r--r--UVtools.Core/Operations/OperationCalibrateTolerance.cs7
-rw-r--r--UVtools.Core/Operations/OperationDoubleExposure.cs13
-rw-r--r--UVtools.Core/Operations/OperationDynamicLayerHeight.cs3
-rw-r--r--UVtools.Core/Operations/OperationInfill.cs4
-rw-r--r--UVtools.Core/Operations/OperationLithophane.cs6
-rw-r--r--UVtools.Core/Operations/OperationPixelArithmetic.cs9
-rw-r--r--UVtools.Core/Operations/OperationPixelDimming.cs4
-rw-r--r--UVtools.Core/Operations/OperationRaftRelief.cs11
-rw-r--r--UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs37
-rw-r--r--UVtools.Core/Operations/OperationRepairLayers.cs11
-rw-r--r--UVtools.Core/UVtools.Core.csproj9
28 files changed, 457 insertions, 301 deletions
diff --git a/UVtools.Core/CoreSettings.cs b/UVtools.Core/CoreSettings.cs
index 10246be..46e86f2 100644
--- a/UVtools.Core/CoreSettings.cs
+++ b/UVtools.Core/CoreSettings.cs
@@ -44,6 +44,12 @@ public static class CoreSettings
public static ParallelOptions ParallelOptions => new() {MaxDegreeOfParallelism = _maxDegreeOfParallelism};
/// <summary>
+ /// Gets the ParallelOptions with <see cref="MaxDegreeOfParallelism"/> set to 1 for debug purposes
+ /// </summary>
+ public static ParallelOptions ParallelDebugOptions => new() { MaxDegreeOfParallelism = 1 };
+
+
+ /// <summary>
/// Gets the ParallelOptions with <see cref="MaxDegreeOfParallelism"/> and the <see cref="CancellationToken"/> set
/// </summary>
public static ParallelOptions GetParallelOptions(CancellationToken token = default)
diff --git a/UVtools.Core/EmguCV/EmguContour.cs b/UVtools.Core/EmguCV/EmguContour.cs
index f7d3bd1..5e5bd10 100644
--- a/UVtools.Core/EmguCV/EmguContour.cs
+++ b/UVtools.Core/EmguCV/EmguContour.cs
@@ -224,9 +224,9 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
#region Static methods
public static Point GetCentroid(VectorOfPoint points)
{
- if (points is null || points.Length == 0) return new Point(-1, -1);
+ if (points is null || points.Length == 0) return EmguExtensions.AnchorCenter;
using var moments = CvInvoke.Moments(points);
- return moments.M00 == 0 ? new Point(-1, -1) :
+ return moments.M00 == 0 ? EmguExtensions.AnchorCenter :
new Point(
(int)Math.Round(moments.M10 / moments.M00),
(int)Math.Round(moments.M01 / moments.M00));
diff --git a/UVtools.Core/EmguCV/EmguContours.cs b/UVtools.Core/EmguCV/EmguContours.cs
index d0ac9a5..164fe64 100644
--- a/UVtools.Core/EmguCV/EmguContours.cs
+++ b/UVtools.Core/EmguCV/EmguContours.cs
@@ -322,30 +322,40 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
}
/// <summary>
- /// Checks if two contours intersects
+ /// Checks if two contours intersects and return the intersecting pixel count
/// </summary>
/// <param name="contour1">Contour 1</param>
/// <param name="contour2">Contour 2</param>
- /// <returns></returns>
- public static bool ContoursIntersect(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2)
+ /// <returns>Intersecting pixel count</returns>
+ public static int ContoursIntersectingPixels(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2)
{
var contour1Rect = CvInvoke.BoundingRectangle(contour1[0]);
var contour2Rect = CvInvoke.BoundingRectangle(contour2[0]);
/* early exit if the bounding rectangles don't intersect */
- if (!contour1Rect.IntersectsWith(contour2Rect)) return false;
+ if (!contour1Rect.IntersectsWith(contour2Rect)) return 0;
var totalRect = Rectangle.Union(contour1Rect, contour2Rect);
using var contour1Mat = EmguExtensions.InitMat(totalRect.Size);
using var contour2Mat = EmguExtensions.InitMat(totalRect.Size);
-
+
var inverseOffset = new Point(-totalRect.X, -totalRect.Y);
CvInvoke.DrawContours(contour1Mat, contour1, -1, EmguExtensions.WhiteColor, -1, LineType.EightConnected, null, int.MaxValue, inverseOffset);
CvInvoke.DrawContours(contour2Mat, contour2, -1, EmguExtensions.WhiteColor, -1, LineType.EightConnected, null, int.MaxValue, inverseOffset);
CvInvoke.BitwiseAnd(contour1Mat, contour2Mat, contour1Mat);
- //return !contour1Mat.IsZeroed();
- return CvInvoke.CountNonZero(contour1Mat) > 0;
+ return CvInvoke.CountNonZero(contour1Mat);
+ }
+
+ /// <summary>
+ /// Checks if two contours intersects
+ /// </summary>
+ /// <param name="contour1">Contour 1</param>
+ /// <param name="contour2">Contour 2</param>
+ /// <returns></returns>
+ public static bool ContoursIntersect(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2)
+ {
+ return ContoursIntersectingPixels(contour1, contour2) > 0;
}
} \ No newline at end of file
diff --git a/UVtools.Core/EmguCV/MatRoi.cs b/UVtools.Core/EmguCV/MatRoi.cs
new file mode 100644
index 0000000..6bd5b3f
--- /dev/null
+++ b/UVtools.Core/EmguCV/MatRoi.cs
@@ -0,0 +1,49 @@
+/*
+ * 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;
+using System.Drawing;
+using Emgu.CV;
+using UVtools.Core.Extensions;
+
+namespace UVtools.Core.EmguCV;
+
+/// <summary>
+/// A disposable Mat with associated ROI Mat
+/// </summary>
+public class MatRoi : IDisposable
+{
+ #region Properties
+ public Mat SourceMat { get; }
+ public Rectangle Roi { get; }
+ public Mat RoiMat { get; }
+
+ public Point RoiLocation => Roi.Location;
+ public Size RoiSize => Roi.Size;
+
+ #endregion
+
+ #region Constructor
+
+ public MatRoi(Mat sourceMat, Rectangle roi)
+ {
+ SourceMat = sourceMat;
+ Roi = roi;
+ RoiMat = sourceMat.Roi(roi);
+ }
+
+ #endregion
+
+
+ public void Dispose()
+ {
+ SourceMat.Dispose();
+ RoiMat.Dispose();
+ }
+} \ No newline at end of file
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index b39f829..eb74c44 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -35,7 +35,8 @@ public static class EmguExtensions
public static readonly MCvScalar BlackColor = new(0, 0, 0, 255);
//public static readonly MCvScalar TransparentColor = new();
- public static readonly Mat Kernel3x3Rectangle = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1));
+ public static readonly Point AnchorCenter = new (-1, -1);
+ public static readonly Mat Kernel3x3Rectangle = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), AnchorCenter);
#endregion
#region Initializers methods
@@ -209,13 +210,19 @@ public static class EmguExtensions
/// Gets the whole data span to manipulate or read pixels, use this when possibly using ROI
/// </summary>
/// <returns></returns>
- public static unsafe Span2D<byte> GetDataByteSpan2D(this Mat mat)
+ public static unsafe Span2D<T> GetDataSpan2D<T>(this Mat mat)
{
- if (!mat.IsSubmatrix) return new(mat.GetBytePointer(), mat.Height, mat.Step, 0);
var step = mat.GetRealStep();
- return new(mat.GetBytePointer(), mat.Height, step, mat.Step - step);
+ if (!mat.IsSubmatrix) return new(mat.DataPointer.ToPointer(), mat.Height, step, 0);
+ return new(mat.DataPointer.ToPointer(), mat.Height, step, mat.Step / mat.ElementSize - step);
}
-
+
+ /// <summary>
+ /// Gets the whole data span to manipulate or read pixels, use this when possibly using ROI
+ /// </summary>
+ /// <returns></returns>
+ public static Span2D<byte> GetDataByteSpan2D(this Mat mat) => mat.GetDataSpan2D<byte>();
+
/// <summary>
/// Gets the data span to manipulate or read pixels given a length and offset
@@ -1381,8 +1388,11 @@ public static class EmguExtensions
{
var contours = new VectorOfVectorOfPoint();
using var hierarchyMat = new Mat();
+
CvInvoke.FindContours(mat, contours, hierarchyMat, mode, method, offset);
+
hierarchy = new int[hierarchyMat.Cols, 4];
+ if (contours.Size == 0) return contours;
var gcHandle = GCHandle.Alloc(hierarchy, GCHandleType.Pinned);
using (var mat2 = new Mat(hierarchyMat.Rows, hierarchyMat.Cols, hierarchyMat.Depth, 4, gcHandle.AddrOfPinnedObject(), hierarchyMat.Step))
hierarchyMat.CopyTo(mat2);
@@ -1403,7 +1413,6 @@ public static class EmguExtensions
public static Mat Skeletonize(this Mat src, out int iterations, Size ksize = default, ElementShape elementShape = ElementShape.Rectangle)
{
if (ksize.IsEmpty) ksize = new Size(3, 3);
- Point anchor = new(-1, -1);
var skeleton = src.NewBlank();
var kernel = Kernel3x3Rectangle;
@@ -1416,8 +1425,8 @@ public static class EmguExtensions
// erode and dilate the image using the structuring element
using var eroded = new Mat();
- CvInvoke.Erode(image, eroded, kernel, anchor, 1, BorderType.Reflect101, default);
- CvInvoke.Dilate(eroded, temp, kernel, anchor, 1, BorderType.Reflect101, default);
+ CvInvoke.Erode(image, eroded, kernel, AnchorCenter, 1, BorderType.Reflect101, default);
+ CvInvoke.Dilate(eroded, temp, kernel, AnchorCenter, 1, BorderType.Reflect101, default);
// subtract the temporary image from the original, eroded
// image, then take the bitwise 'or' between the skeleton
@@ -1458,7 +1467,7 @@ public static class EmguExtensions
{
var size = Math.Max(iterations, 1) * 2 + 1;
iterations = 1;
- return CvInvoke.GetStructuringElement(elementShape, new Size(size, size), new Point(-1, -1));
+ return CvInvoke.GetStructuringElement(elementShape, new Size(size, size), AnchorCenter);
}
#endregion
diff --git a/UVtools.Core/Extensions/PointExtensions.cs b/UVtools.Core/Extensions/PointExtensions.cs
index 01c6c54..9d2dfb9 100644
--- a/UVtools.Core/Extensions/PointExtensions.cs
+++ b/UVtools.Core/Extensions/PointExtensions.cs
@@ -62,6 +62,10 @@ public static class PointExtensions
}
}
+ public static Point Invert(this Point point) => new(-point.X, -point.Y);
+
+ public static PointF Invert(this PointF point) => new(-point.X, -point.Y);
+
public static Point OffsetBy(this Point point, int value)=> new(point.X + value, point.Y + value);
public static Point OffsetBy(this Point point, int x, int y) => new(point.X + x, point.Y + y);
public static Point OffsetBy(this Point point, Point other) => new(point.X + other.X, point.Y + other.Y);
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 35ce5c8..f60faf6 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -2423,6 +2423,7 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
public bool CanUseLayerRetractHeight2 => HaveLayerParameterModifier(PrintParameterModifier.RetractHeight2);
public bool CanUseLayerRetractSpeed2 => HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed2);
public bool CanUseLayerLightOffDelay => HaveLayerParameterModifier(PrintParameterModifier.LightOffDelay);
+ public bool CanUseLayerAnyWaitTimeBeforeCure => CanUseLayerWaitTimeBeforeCure || CanUseLayerLightOffDelay;
public bool CanUseLayerLightPWM => HaveLayerParameterModifier(PrintParameterModifier.LightPWM);
public string ExposureRepresentation
diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
index 688795d..815d361 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -82,20 +82,20 @@ public class PhotonWorkshopFile : FileFormat
public enum AnyCubicMachine : byte
{
- AnyCubicPhotonS,
- AnyCubicPhotonZero,
- AnyCubicPhotonX,
- AnyCubicPhotonUltra,
- AnyCubicPhotonD2,
- AnyCubicPhotonMono,
- AnyCubicPhotonMonoSE,
- AnyCubicPhotonMono4K,
- AnyCubicPhotonMonoX,
- AnyCubicPhotonMonoX6KM3Plus,
- AnyCubicPhotonMonoSQ,
- AnyCubicPhotonM3,
- AnyCubicPhotonM3Max,
- AnyCubicCustom,
+ PhotonS,
+ PhotonZero,
+ PhotonX,
+ PhotonUltra,
+ PhotonD2,
+ PhotonMono,
+ PhotonMonoSE,
+ PhotonMono4K,
+ PhotonMonoX,
+ PhotonMonoX6KM3Plus,
+ PhotonMonoSQ,
+ PhotonM3,
+ PhotonM3Max,
+ Custom,
}
#endregion
@@ -1109,6 +1109,7 @@ public class PhotonWorkshopFile : FileFormat
new(typeof(PhotonWorkshopFile), "pmsq", "Photon Mono SQ (PMSQ)"),
new(typeof(PhotonWorkshopFile), "pm3", "Photon M3 (PM3)"),
new(typeof(PhotonWorkshopFile), "pm3m", "Photon M3 Max (PM3M)"),
+ new(typeof(PhotonWorkshopFile), "pwc", "Anycubic Custom Machine (PWC)"),
//new(typeof(PhotonWorkshopFile), "pwmb", "Photon M3 Plus (PWMB)"),
};
@@ -1217,19 +1218,19 @@ public class PhotonWorkshopFile : FileFormat
if (MachineSettings.DisplayWidth > 0) return MachineSettings.DisplayWidth;
return PrinterModel switch
{
- AnyCubicMachine.AnyCubicPhotonS => 68.04f,
- AnyCubicMachine.AnyCubicPhotonZero => 55.44f,
- AnyCubicMachine.AnyCubicPhotonX => 192,
- AnyCubicMachine.AnyCubicPhotonUltra => 102.40f,
- AnyCubicMachine.AnyCubicPhotonD2 => 130.56f,
- AnyCubicMachine.AnyCubicPhotonMono => 82.62f,
- AnyCubicMachine.AnyCubicPhotonMonoSE => 82.62f,
- AnyCubicMachine.AnyCubicPhotonMono4K => 134.40f,
- AnyCubicMachine.AnyCubicPhotonMonoX => 192,
- AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus => 198.15f,
- AnyCubicMachine.AnyCubicPhotonMonoSQ => 120,
- AnyCubicMachine.AnyCubicPhotonM3 => 163.84f,
- AnyCubicMachine.AnyCubicPhotonM3Max => 298.08f,
+ AnyCubicMachine.PhotonS => 68.04f,
+ AnyCubicMachine.PhotonZero => 55.44f,
+ AnyCubicMachine.PhotonX => 192,
+ AnyCubicMachine.PhotonUltra => 102.40f,
+ AnyCubicMachine.PhotonD2 => 130.56f,
+ AnyCubicMachine.PhotonMono => 82.62f,
+ AnyCubicMachine.PhotonMonoSE => 82.62f,
+ AnyCubicMachine.PhotonMono4K => 134.40f,
+ AnyCubicMachine.PhotonMonoX => 192,
+ AnyCubicMachine.PhotonMonoX6KM3Plus => 198.15f,
+ AnyCubicMachine.PhotonMonoSQ => 120,
+ AnyCubicMachine.PhotonM3 => 163.84f,
+ AnyCubicMachine.PhotonM3Max => 298.08f,
_ => 0
};
}
@@ -1246,19 +1247,19 @@ public class PhotonWorkshopFile : FileFormat
if (MachineSettings.DisplayHeight > 0) return MachineSettings.DisplayHeight;
return PrinterModel switch
{
- AnyCubicMachine.AnyCubicPhotonS => 120.96f,
- AnyCubicMachine.AnyCubicPhotonZero => 98.637f,
- AnyCubicMachine.AnyCubicPhotonX => 120,
- AnyCubicMachine.AnyCubicPhotonUltra => 57.60f,
- AnyCubicMachine.AnyCubicPhotonD2 => 73.44f,
- AnyCubicMachine.AnyCubicPhotonMono => 130.56f,
- AnyCubicMachine.AnyCubicPhotonMonoSE => 130.56f,
- AnyCubicMachine.AnyCubicPhotonMono4K => 84,
- AnyCubicMachine.AnyCubicPhotonMonoX => 120,
- AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus => 123.84f,
- AnyCubicMachine.AnyCubicPhotonMonoSQ => 128,
- AnyCubicMachine.AnyCubicPhotonM3 => 102.40f,
- AnyCubicMachine.AnyCubicPhotonM3Max => 165.60f,
+ AnyCubicMachine.PhotonS => 120.96f,
+ AnyCubicMachine.PhotonZero => 98.637f,
+ AnyCubicMachine.PhotonX => 120,
+ AnyCubicMachine.PhotonUltra => 57.60f,
+ AnyCubicMachine.PhotonD2 => 73.44f,
+ AnyCubicMachine.PhotonMono => 130.56f,
+ AnyCubicMachine.PhotonMonoSE => 130.56f,
+ AnyCubicMachine.PhotonMono4K => 84,
+ AnyCubicMachine.PhotonMonoX => 120,
+ AnyCubicMachine.PhotonMonoX6KM3Plus => 123.84f,
+ AnyCubicMachine.PhotonMonoSQ => 128,
+ AnyCubicMachine.PhotonM3 => 102.40f,
+ AnyCubicMachine.PhotonM3Max => 165.60f,
_ => 0
};
}
@@ -1276,19 +1277,19 @@ public class PhotonWorkshopFile : FileFormat
if (MachineSettings.MachineZ > 0) return MachineSettings.MachineZ;
return PrinterModel switch
{
- AnyCubicMachine.AnyCubicPhotonS => 165,
- AnyCubicMachine.AnyCubicPhotonZero => 150,
- AnyCubicMachine.AnyCubicPhotonX => 245,
- AnyCubicMachine.AnyCubicPhotonUltra => 165,
- AnyCubicMachine.AnyCubicPhotonD2 => 165,
- AnyCubicMachine.AnyCubicPhotonMono => 165,
- AnyCubicMachine.AnyCubicPhotonMonoSE => 160,
- AnyCubicMachine.AnyCubicPhotonMono4K => 165,
- AnyCubicMachine.AnyCubicPhotonMonoX => 245,
- AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus => 245,
- AnyCubicMachine.AnyCubicPhotonMonoSQ => 200,
- AnyCubicMachine.AnyCubicPhotonM3 => 180f,
- AnyCubicMachine.AnyCubicPhotonM3Max => 300f,
+ AnyCubicMachine.PhotonS => 165,
+ AnyCubicMachine.PhotonZero => 150,
+ AnyCubicMachine.PhotonX => 245,
+ AnyCubicMachine.PhotonUltra => 165,
+ AnyCubicMachine.PhotonD2 => 165,
+ AnyCubicMachine.PhotonMono => 165,
+ AnyCubicMachine.PhotonMonoSE => 160,
+ AnyCubicMachine.PhotonMono4K => 165,
+ AnyCubicMachine.PhotonMonoX => 245,
+ AnyCubicMachine.PhotonMonoX6KM3Plus => 245,
+ AnyCubicMachine.PhotonMonoSQ => 200,
+ AnyCubicMachine.PhotonM3 => 180f,
+ AnyCubicMachine.PhotonM3Max => 300f,
_ => 0
};
}
@@ -1573,20 +1574,20 @@ public class PhotonWorkshopFile : FileFormat
if (string.IsNullOrWhiteSpace(MachineSettings.MachineName)) return MachineSettings.MachineName;
return PrinterModel switch
{
- AnyCubicMachine.AnyCubicPhotonS => "Photon S",
- AnyCubicMachine.AnyCubicPhotonZero => "Photon Zero",
- AnyCubicMachine.AnyCubicPhotonX => "Photon X",
- AnyCubicMachine.AnyCubicPhotonUltra => "Photon Ultra",
- AnyCubicMachine.AnyCubicPhotonD2 => "Photon D2",
- AnyCubicMachine.AnyCubicPhotonMono => "Photon Mono",
- AnyCubicMachine.AnyCubicPhotonMonoSE => "Photon Mono SE",
- AnyCubicMachine.AnyCubicPhotonMono4K => "Photon Mono 4K",
- AnyCubicMachine.AnyCubicPhotonMonoX => "Photon Mono X",
- AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus => "Photon Mono X 6K / M3 Plus",
- AnyCubicMachine.AnyCubicPhotonMonoSQ => "Photon Mono SQ",
- AnyCubicMachine.AnyCubicPhotonM3 => "Photon M3",
- AnyCubicMachine.AnyCubicPhotonM3Max => "Photon M3 Max",
- AnyCubicMachine.AnyCubicCustom => "Custom",
+ AnyCubicMachine.PhotonS => "Photon S",
+ AnyCubicMachine.PhotonZero => "Photon Zero",
+ AnyCubicMachine.PhotonX => "Photon X",
+ AnyCubicMachine.PhotonUltra => "Photon Ultra",
+ AnyCubicMachine.PhotonD2 => "Photon D2",
+ AnyCubicMachine.PhotonMono => "Photon Mono",
+ AnyCubicMachine.PhotonMonoSE => "Photon Mono SE",
+ AnyCubicMachine.PhotonMono4K => "Photon Mono 4K",
+ AnyCubicMachine.PhotonMonoX => "Photon Mono X",
+ AnyCubicMachine.PhotonMonoX6KM3Plus => "Photon Mono X 6K / M3 Plus",
+ AnyCubicMachine.PhotonMonoSQ => "Photon Mono SQ",
+ AnyCubicMachine.PhotonM3 => "Photon M3",
+ AnyCubicMachine.PhotonM3Max => "Photon M3 Max",
+ AnyCubicMachine.Custom => "Custom",
_ => base.MachineName
};
}
@@ -1606,70 +1607,75 @@ public class PhotonWorkshopFile : FileFormat
{
if (FileEndsWith(".pws"))
{
- return AnyCubicMachine.AnyCubicPhotonS;
+ return AnyCubicMachine.PhotonS;
}
if (FileEndsWith(".pw0"))
{
- return AnyCubicMachine.AnyCubicPhotonZero;
+ return AnyCubicMachine.PhotonZero;
}
if (FileEndsWith(".pwx"))
{
- return AnyCubicMachine.AnyCubicPhotonX;
+ return AnyCubicMachine.PhotonX;
}
if (FileEndsWith(".dlp"))
{
- return AnyCubicMachine.AnyCubicPhotonUltra;
+ return AnyCubicMachine.PhotonUltra;
}
if (FileEndsWith(".dl2p"))
{
- return AnyCubicMachine.AnyCubicPhotonD2;
+ return AnyCubicMachine.PhotonD2;
}
if (FileEndsWith(".pwmo"))
{
- return AnyCubicMachine.AnyCubicPhotonMono;
+ return AnyCubicMachine.PhotonMono;
}
if (FileEndsWith(".pwms"))
{
- return AnyCubicMachine.AnyCubicPhotonMonoSE;
+ return AnyCubicMachine.PhotonMonoSE;
}
if (FileEndsWith(".pwma"))
{
- return AnyCubicMachine.AnyCubicPhotonMono4K;
+ return AnyCubicMachine.PhotonMono4K;
}
if (FileEndsWith(".pwmx"))
{
- return AnyCubicMachine.AnyCubicPhotonMonoX;
+ return AnyCubicMachine.PhotonMonoX;
}
if (FileEndsWith(".pwmb"))
{
- return AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus;
+ return AnyCubicMachine.PhotonMonoX6KM3Plus;
}
if (FileEndsWith(".pmsq"))
{
- return AnyCubicMachine.AnyCubicPhotonMonoSQ;
+ return AnyCubicMachine.PhotonMonoSQ;
}
if (FileEndsWith(".pm3"))
{
- return AnyCubicMachine.AnyCubicPhotonM3;
+ return AnyCubicMachine.PhotonM3;
}
if (FileEndsWith(".pm3m"))
{
- return AnyCubicMachine.AnyCubicPhotonM3Max;
+ return AnyCubicMachine.PhotonM3Max;
}
- return AnyCubicMachine.AnyCubicPhotonS;
+ if (FileEndsWith(".pwc"))
+ {
+ return AnyCubicMachine.Custom;
+ }
+
+ return AnyCubicMachine.PhotonS;
}
}
#endregion
@@ -2067,20 +2073,20 @@ public class PhotonWorkshopFile : FileFormat
HeaderSettings.PerLayerOverride = System.Convert.ToUInt32(AllLayersAreUsingGlobalParameters);
MachineSettings.MaxFileVersion = PrinterModel switch
{
- AnyCubicMachine.AnyCubicPhotonS => VERSION_1,
- AnyCubicMachine.AnyCubicPhotonZero => VERSION_1,
- AnyCubicMachine.AnyCubicPhotonX => VERSION_1,
- AnyCubicMachine.AnyCubicPhotonUltra => VERSION_515,
- AnyCubicMachine.AnyCubicPhotonD2 => VERSION_516,
- AnyCubicMachine.AnyCubicPhotonMono => VERSION_515,
- AnyCubicMachine.AnyCubicPhotonMonoSE => VERSION_515,
- AnyCubicMachine.AnyCubicPhotonMono4K => VERSION_516,
- AnyCubicMachine.AnyCubicPhotonMonoX => VERSION_516,
- AnyCubicMachine.AnyCubicPhotonMonoX6KM3Plus => VERSION_517,
- AnyCubicMachine.AnyCubicPhotonMonoSQ => VERSION_515,
- AnyCubicMachine.AnyCubicPhotonM3 => VERSION_516,
- AnyCubicMachine.AnyCubicPhotonM3Max => VERSION_516,
- AnyCubicMachine.AnyCubicCustom => VERSION_516,
+ AnyCubicMachine.PhotonS => VERSION_1,
+ AnyCubicMachine.PhotonZero => VERSION_1,
+ AnyCubicMachine.PhotonX => VERSION_1,
+ AnyCubicMachine.PhotonUltra => VERSION_515,
+ AnyCubicMachine.PhotonD2 => VERSION_516,
+ AnyCubicMachine.PhotonMono => VERSION_515,
+ AnyCubicMachine.PhotonMonoSE => VERSION_515,
+ AnyCubicMachine.PhotonMono4K => VERSION_516,
+ AnyCubicMachine.PhotonMonoX => VERSION_516,
+ AnyCubicMachine.PhotonMonoX6KM3Plus => VERSION_517,
+ AnyCubicMachine.PhotonMonoSQ => VERSION_515,
+ AnyCubicMachine.PhotonM3 => VERSION_516,
+ AnyCubicMachine.PhotonM3Max => VERSION_516,
+ AnyCubicMachine.Custom => VERSION_517,
_ => VERSION_517
};
}
diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs
index 2f2ea02..5b7ac72 100644
--- a/UVtools.Core/Layers/Layer.cs
+++ b/UVtools.Core/Layers/Layer.cs
@@ -18,6 +18,7 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
using K4os.Compression.LZ4;
+using UVtools.Core.EmguCV;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
@@ -814,7 +815,22 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
}
}
- //public Mat LayerMatBoundingRectangle => new(LayerMat, BoundingRectangle);
+ /// <summary>
+ /// Gets the layer mat with roi of it bounding rectangle
+ /// </summary>
+ public MatRoi LayerMatBoundingRectangle => new(LayerMat, BoundingRectangle);
+
+ /// <summary>
+ /// Gets the layer mat with roi of model bounding rectangle
+ /// </summary>
+ public MatRoi LayerMatModelBoundingRectangle => new(LayerMat, SlicerFile.BoundingRectangle);
+
+ /// <summary>
+ /// Gets the layer mat with a specified roi
+ /// </summary>
+ /// <param name="roi">Region of interest</param>
+ /// <returns></returns>
+ public MatRoi GetLayerMat(Rectangle roi) => new(LayerMat, roi);
/// <summary>
/// Gets a new Brg image instance
@@ -1215,8 +1231,19 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
needDispose = true;
}
- NonZeroPixelCount = (uint)CvInvoke.CountNonZero(mat);
- BoundingRectangle = _nonZeroPixelCount > 0 ? CvInvoke.BoundingRectangle(mat) : Rectangle.Empty;
+
+ //NonZeroPixelCount = (uint)CvInvoke.CountNonZero(mat);
+ //BoundingRectangle = _nonZeroPixelCount > 0 ? CvInvoke.BoundingRectangle(mat) : Rectangle.Empty;
+ BoundingRectangle = CvInvoke.BoundingRectangle(mat);
+ if (_boundingRectangle.IsEmpty)
+ {
+ NonZeroPixelCount = 0;
+ }
+ else
+ {
+ using var roiMat = mat.Roi(_boundingRectangle);
+ NonZeroPixelCount = (uint)CvInvoke.CountNonZero(roiMat);
+ }
if (needDispose) mat!.Dispose();
@@ -1590,6 +1617,23 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
#region Static Methods
+ /// <summary>
+ /// Gets the bounding rectangle that is the union of a collection of layers
+ /// </summary>
+ /// <param name="layers">Layer collection</param>
+ /// <returns></returns>
+ public static Rectangle GetBoundingRectangleUnion(params Layer[] layers)
+ {
+ var rect = Rectangle.Empty;
+ foreach (var layer in layers)
+ {
+ if(layer.BoundingRectangle.IsEmpty) continue;
+ rect = rect.IsEmpty ? layer.BoundingRectangle : Rectangle.Union(rect, layer.BoundingRectangle);
+ }
+
+ return rect;
+ }
+
public static float RoundHeight(float height) => (float) Math.Round(height, HeightPrecision);
public static double RoundHeight(double height) => Math.Round(height, HeightPrecision);
public static decimal RoundHeight(decimal height) => Math.Round(height, HeightPrecision);
diff --git a/UVtools.Core/Layers/LayerIssueConfiguration.cs b/UVtools.Core/Layers/LayerIssueConfiguration.cs
index 630b533..27caebd 100644
--- a/UVtools.Core/Layers/LayerIssueConfiguration.cs
+++ b/UVtools.Core/Layers/LayerIssueConfiguration.cs
@@ -53,7 +53,7 @@ public sealed class IslandDetectionConfiguration
/// <summary>
/// Combines the island and overhang detections for a better more realistic detection and to discard false-positives. (Slower)
/// If enabled, and when a island is found, it will check for overhangs on that same island, if no overhang found then the island will be discarded and considered safe, otherwise it will flag as an island issue.
- /// Note: Overhangs settings will be used to configure the detection.Enabling Overhangs is not required for this procedure to work.
+ /// Note: Overhangs settings will be used to configure the detection. Enabling Overhangs is not required for this procedure to work.
/// </summary>
public bool EnhancedDetection { get; set; } = true;
@@ -72,7 +72,7 @@ public sealed class IslandDetectionConfiguration
public byte BinaryThreshold { get; set; } = 1;
/// <summary>
- /// Gets the required area size (x*y) to consider process a island (0-65535)
+ /// Gets the required pixel area to consider process a island (0-65535)
/// </summary>
public ushort RequiredAreaToProcessCheck { get; set; } = 1;
diff --git a/UVtools.Core/Layers/MainIssue.cs b/UVtools.Core/Layers/MainIssue.cs
index be4435d..bc25d22 100644
--- a/UVtools.Core/Layers/MainIssue.cs
+++ b/UVtools.Core/Layers/MainIssue.cs
@@ -113,6 +113,7 @@ public class MainIssue : IReadOnlyList<Issue>
Childs = new[] { issue };
issue.Parent = this;
PixelCount = issue.PixelsCount;
+ if (issue is IssueOfPoints) Area = issue.PixelsCount;
}
public MainIssue(IssueType type, IEnumerable<Issue> issues) : this(type)
diff --git a/UVtools.Core/Managers/IssueManager.cs b/UVtools.Core/Managers/IssueManager.cs
index 14156c7..6ef1473 100644
--- a/UVtools.Core/Managers/IssueManager.cs
+++ b/UVtools.Core/Managers/IssueManager.cs
@@ -8,6 +8,7 @@ using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
+using CommunityToolkit.HighPerformance;
using UVtools.Core.EmguCV;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
@@ -216,36 +217,34 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
return;
}
- using (var image = layer.LayerMat)
+ using (var image = layer.GetLayerMat(layerIndex == 0 ? SlicerFile.BoundingRectangle : Layer.GetBoundingRectangleUnion(SlicerFile[layerIndex - 1], layer)))
{
- var step = image.GetRealStep();
- var span = image.GetDataByteSpan();
+ var sourceSpan = image.SourceMat.GetDataByteSpan2D();
+ var roiSpan = image.RoiMat.GetDataByteSpan2D();
if (touchBoundConfig.Enabled)
{
// TouchingBounds Checker
List<Point> pixels = new();
bool touchTop = layer.BoundingRectangle.Top <= touchBoundConfig.MarginTop;
- bool touchBottom = layer.BoundingRectangle.Bottom >= image.Height - touchBoundConfig.MarginBottom;
+ bool touchBottom = layer.BoundingRectangle.Bottom >= image.SourceMat.Height - touchBoundConfig.MarginBottom;
bool touchLeft = layer.BoundingRectangle.Left <= touchBoundConfig.MarginLeft;
- bool touchRight = layer.BoundingRectangle.Right >=
- image.Width - touchBoundConfig.MarginRight;
+ bool touchRight = layer.BoundingRectangle.Right >= image.SourceMat.Width - touchBoundConfig.MarginRight;
int minx = int.MaxValue;
int miny = int.MaxValue;
int maxx = 0;
int maxy = 0;
-
+
if (touchTop || touchBottom)
{
- for (int x = 0; x < image.Width; x++) // Check Top and Bottom bounds
+ for (int x = layer.BoundingRectangle.X; x < layer.BoundingRectangle.Right; x++) // Check Top and Bottom bounds
{
if (touchTop)
{
- for (int y = 0; y < touchBoundConfig.MarginTop; y++) // Top
+ for (int y = layer.BoundingRectangle.Y; y < touchBoundConfig.MarginTop; y++) // Top
{
- if (span[image.GetPixelPos(x, y)] >=
- touchBoundConfig.MinimumPixelBrightness)
+ if (sourceSpan.DangerousGetReferenceAt(y, x) >= touchBoundConfig.MinimumPixelBrightness)
{
pixels.Add(new Point(x, y));
minx = Math.Min(minx, x);
@@ -258,12 +257,11 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
if (touchBottom)
{
- for (int y = image.Height - touchBoundConfig.MarginBottom;
- y < image.Height;
+ for (int y = image.SourceMat.Height - touchBoundConfig.MarginBottom;
+ y < layer.BoundingRectangle.Bottom;
y++) // Bottom
{
- if (span[image.GetPixelPos(x, y)] >=
- touchBoundConfig.MinimumPixelBrightness)
+ if (sourceSpan.DangerousGetReferenceAt(y, x) >= touchBoundConfig.MinimumPixelBrightness)
{
pixels.Add(new Point(x, y));
minx = Math.Min(minx, x);
@@ -273,22 +271,20 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
}
}
}
-
}
}
if (touchLeft || touchRight)
{
- for (int y = touchBoundConfig.MarginTop;
- y < image.Height - touchBoundConfig.MarginBottom;
+ for (int y = layer.BoundingRectangle.Y + touchBoundConfig.MarginTop;
+ y < layer.BoundingRectangle.Bottom - touchBoundConfig.MarginBottom;
y++) // Check Left and Right bounds
{
if (touchLeft)
{
- for (int x = 0; x < touchBoundConfig.MarginLeft; x++) // Left
+ for (int x = layer.BoundingRectangle.X; x < touchBoundConfig.MarginLeft; x++) // Left
{
- if (span[image.GetPixelPos(x, y)] >=
- touchBoundConfig.MinimumPixelBrightness)
+ if (sourceSpan.DangerousGetReferenceAt(y, x) >= touchBoundConfig.MinimumPixelBrightness)
{
pixels.Add(new Point(x, y));
minx = Math.Min(minx, x);
@@ -301,12 +297,11 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
if (touchRight)
{
- for (int x = image.Width - touchBoundConfig.MarginRight;
- x < image.Width;
+ for (int x = layer.BoundingRectangle.Right - touchBoundConfig.MarginRight;
+ x < layer.BoundingRectangle.Right;
x++) // Right
{
- if (span[image.GetPixelPos(x, y)] >=
- touchBoundConfig.MinimumPixelBrightness)
+ if (sourceSpan.DangerousGetReferenceAt(y, x) >= touchBoundConfig.MinimumPixelBrightness)
{
pixels.Add(new Point(x, y));
minx = Math.Min(minx, x);
@@ -328,8 +323,59 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
if (layerIndex > 0 && layer.PositionZ > firstLayer!.PositionZ) // No islands nor overhangs for layer 0 or on plate
{
- Mat? previousImage = null;
- Span<byte> previousSpan = null;
+ MatRoi? previousImage = null;
+ Span2D<byte> previousSpan = null;
+ Mat? overhangImage = null;
+ var previousLayer = SlicerFile[layerIndex - 1];
+
+
+ // Overhangs
+ var overhangCount = 0;
+ //if (!islandConfig.Enabled && overhangConfig.Enabled ||
+ // (islandConfig.Enabled && overhangConfig.Enabled && overhangConfig.IndependentFromIslands))
+ if (overhangConfig.Enabled)
+ {
+ bool canProcessCheck = true;
+ if (overhangConfig.WhiteListLayers is not null) // Check white list
+ {
+ if (!overhangConfig.WhiteListLayers.Contains(layerIndex))
+ {
+ canProcessCheck = false;
+ }
+ }
+
+ if (canProcessCheck)
+ {
+ previousImage ??= previousLayer.GetLayerMat(Layer.GetBoundingRectangleUnion(previousLayer, layer));
+
+ overhangImage = new Mat();
+ using var vecPoints = new VectorOfPoint();
+
+ CvInvoke.Subtract(image.RoiMat, previousImage.RoiMat, overhangImage);
+ CvInvoke.Threshold(overhangImage, overhangImage, 127, 255, ThresholdType.Binary);
+
+ CvInvoke.Erode(overhangImage, overhangImage, EmguExtensions.Kernel3x3Rectangle,
+ EmguExtensions.AnchorCenter, overhangConfig.ErodeIterations, BorderType.Default, default);
+
+ //CvInvoke.MorphologyEx(subtractedImage, subtractedImage, MorphOp.Open, EmguExtensions.Kernel3x3Rectangle,
+ // EmguExtensions.AnchorCenter, 2, BorderType.Reflect101, default);
+
+ using var contours = overhangImage.FindContours(out var hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxSimple, image.RoiLocation);
+ var contoursInGroups = EmguContours.GetPositiveContoursInGroups(contours, hierarchy);
+
+ foreach (var contourGroup in contoursInGroups)
+ {
+ if (contourGroup[0].Size < 3) continue; // Single contour, single line, ignore
+ overhangCount++;
+ var area = EmguContours.GetContourArea(contourGroup);
+ if (area >= overhangConfig.RequiredPixelsToConsider)
+ {
+ var rect = CvInvoke.BoundingRectangle(contourGroup[0]);
+ AddIssue(new MainIssue(MainIssue.IssueType.Overhang, new IssueOfContours(layer, contourGroup.ToArrayOfArray(), rect, area)));
+ }
+ }
+ }
+ }
if (islandConfig.Enabled)
{
@@ -350,12 +396,11 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
{
needDispose = true;
islandImage = new();
- CvInvoke.Threshold(image, islandImage, islandConfig.BinaryThreshold, byte.MaxValue,
- ThresholdType.Binary);
+ CvInvoke.Threshold(image.RoiMat, islandImage, islandConfig.BinaryThreshold, byte.MaxValue, ThresholdType.Binary);
}
else
{
- islandImage = image;
+ islandImage = image.RoiMat;
}
using Mat labels = new();
@@ -373,48 +418,53 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
}
// Get array that contains details of each connected component
- var ccStats = stats.GetData();
+ //var ccStats = stats.GetData();
//stats[i][0]: Left Edge of Connected Component
//stats[i][1]: Top Edge of Connected Component
//stats[i][2]: Width of Connected Component
//stats[i][3]: Height of Connected Component
//stats[i][4]: Total Area (in pixels) in Connected Component
-
- var labelSpan = labels.GetDataSpan<int>();
+ var ccStats = stats.GetDataSpan<int>();
+ var labelSpan = labels.GetDataSpan2D<int>();
for (int i = 1; i < numLabels; i++)
{
+ int pos = i * stats.Cols;
Rectangle rect = new(
- (int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Left)!,
+ ccStats[pos + (int)ConnectedComponentsTypes.Left],
+ ccStats[pos + (int)ConnectedComponentsTypes.Top],
+ ccStats[pos + (int)ConnectedComponentsTypes.Width],
+ ccStats[pos + (int)ConnectedComponentsTypes.Height]
+ /*(int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Left)!,
(int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Top)!,
(int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Width)!,
- (int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Height)!);
+ (int)ccStats.GetValue(i, (int)ConnectedComponentsTypes.Height)!*/
+ );
- if (rect.Area() < islandConfig.RequiredAreaToProcessCheck)
+ if (ccStats[pos + (int)ConnectedComponentsTypes.Area] < islandConfig.RequiredAreaToProcessCheck)
continue;
- if (previousImage is null)
+ previousImage ??= previousLayer.GetLayerMat(Layer.GetBoundingRectangleUnion(previousLayer, layer));
+
+ if (previousSpan == null)
{
- previousImage = SlicerFile[layerIndex - 1].LayerMat;
- previousSpan = previousImage.GetDataByteSpan();
+ previousSpan = previousImage.RoiMat.GetDataByteSpan2D();
}
List<Point> points = new();
uint pixelsSupportingIsland = 0;
-
+
for (int y = rect.Y; y < rect.Bottom; y++)
for (int x = rect.X; x < rect.Right; x++)
{
- int pixel = step * y + x;
- if (
- labelSpan[pixel] !=
- i || // Background pixel or a pixel from another component within the bounding rectangle
- span[pixel] < islandConfig.RequiredPixelBrightnessToProcessCheck // Low brightness, ignore
+ if (labelSpan.DangerousGetReferenceAt(y, x) != i || // Background pixel or a pixel from another component within the bounding rectangle
+ roiSpan.DangerousGetReferenceAt(y, x) < islandConfig.RequiredPixelBrightnessToProcessCheck // Low brightness, ignore
) continue;
- points.Add(new Point(x, y));
+ points.Add(new Point(image.Roi.X + x, image.Roi.Y + y));
- if (previousSpan[pixel] >= islandConfig.RequiredPixelBrightnessToSupport)
+ //int pixel = roiStep * y + x;
+ if (previousSpan.DangerousGetReferenceAt(y, x) >= islandConfig.RequiredPixelBrightnessToSupport)
{
pixelsSupportingIsland++;
}
@@ -434,101 +484,58 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
IssueOfPoints? island = null;
if (pixelsSupportingIsland < requiredSupportingPixels)
{
- island = new IssueOfPoints(layer, points.ToArray(), rect);
+ island = new IssueOfPoints(layer, points.ToArray(), new Rectangle(rect.Location.OffsetBy(image.RoiLocation), rect.Size));
}
- // Check for overhangs
- if (overhangConfig.Enabled && !overhangConfig.IndependentFromIslands &&
- island is null
- || island is not null && islandConfig.EnhancedDetection &&
- pixelsSupportingIsland >= 10
- )
+ // Check for overhangs in islands
+ if (island is not null && islandConfig.EnhancedDetection && pixelsSupportingIsland >= 10 &&
+ (!overhangConfig.Enabled || (overhangConfig.Enabled && overhangCount > 0)))
{
- points.Clear();
- using var imageRoi = image.Roi(rect);
- using var previousImageRoi = previousImage.Roi(rect);
- using var subtractedImage = new Mat();
- var anchor = new Point(-1, -1);
- CvInvoke.Subtract(imageRoi, previousImageRoi, subtractedImage);
- CvInvoke.Threshold(subtractedImage, subtractedImage, 127, 255,
- ThresholdType.Binary);
-
- CvInvoke.Erode(subtractedImage, subtractedImage, EmguExtensions.Kernel3x3Rectangle,
- anchor, overhangConfig.ErodeIterations, BorderType.Default, default);
-
- var subtractedSpan = subtractedImage.GetDataByteSpan();
+ using var islandRoi = image.RoiMat.Roi(rect);
+ using var previousIslandRoi = previousImage.RoiMat.Roi(rect);
+
+ if (overhangImage is null)
+ {
+ overhangImage = new Mat();
+ CvInvoke.Subtract(islandRoi, previousIslandRoi, overhangImage);
+ CvInvoke.Threshold(overhangImage, overhangImage, 127, 255, ThresholdType.Binary);
+
+ CvInvoke.Erode(overhangImage, overhangImage, EmguExtensions.Kernel3x3Rectangle,
+ EmguExtensions.AnchorCenter, overhangConfig.ErodeIterations, BorderType.Default, default);
+ }
+
+ using var subtractedImage = overhangImage.Roi(rect);
+
+ var subtractedSpan = subtractedImage.GetDataByteSpan2D();
var subtractedStep = subtractedImage.GetRealStep();
- for (int y = 0; y < subtractedImage.Height; y++)
- for (int x = 0; x < subtractedStep; x++)
+ int overhangPixels = 0;
+
+ for (int y = 0; y < subtractedImage.Height && overhangPixels < overhangConfig.RequiredPixelsToConsider; y++)
+ for (int x = 0; x < subtractedStep && overhangPixels < overhangConfig.RequiredPixelsToConsider; x++)
{
int labelX = rect.X + x;
int labelY = rect.Y + y;
- int pixel = subtractedImage.GetPixelPos(x, y);
- int pixelLabel = labelY * step + labelX;
- if (labelSpan[pixelLabel] != i || subtractedSpan[pixel] == 0)
+ if (labelSpan[labelY, labelX] != i || subtractedSpan.DangerousGetReferenceAt(y, x) == 0)
continue;
- points.Add(new Point(labelX, labelY));
+ overhangPixels++;
}
- if (points.Count >= overhangConfig.RequiredPixelsToConsider
- ) // Overhang
- {
- AddIssue(new MainIssue(MainIssue.IssueType.Overhang, new IssueOfPoints(layer, points, rect)));
- }
- else if (islandConfig.EnhancedDetection) // No overhang
+ if (overhangPixels < overhangConfig.RequiredPixelsToConsider) // No overhang = no island
{
island = null;
}
- }
- if (island is not null)
- AddIssue(new MainIssue(MainIssue.IssueType.Island, island));
- }
- }
- }
-
- // Overhangs
- if (!islandConfig.Enabled && overhangConfig.Enabled ||
- (islandConfig.Enabled && overhangConfig.Enabled &&
- overhangConfig.IndependentFromIslands) )
- {
- bool canProcessCheck = true;
- if (overhangConfig.WhiteListLayers is not null) // Check white list
- {
- if (!overhangConfig.WhiteListLayers.Contains(layerIndex))
- {
- canProcessCheck = false;
- }
- }
-
- if (canProcessCheck)
- {
- previousImage ??= SlicerFile[layerIndex - 1].LayerMat;
-
- 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.Erode(subtractedImage, subtractedImage, EmguExtensions.Kernel3x3Rectangle,
- anchor, overhangConfig.ErodeIterations, BorderType.Default, default);
+ }
- CvInvoke.FindNonZero(subtractedImage, vecPoints);
- if (vecPoints.Size >= overhangConfig.RequiredPixelsToConsider)
- {
- AddIssue(new MainIssue(MainIssue.IssueType.Overhang, new IssueOfPoints(layer, vecPoints.ToArray(), layer.BoundingRectangle)
- ));
+ if (island is not null) AddIssue(new MainIssue(MainIssue.IssueType.Island, island));
}
}
}
previousImage?.Dispose();
+ overhangImage?.Dispose();
}
if (resinTrapConfig.Enabled)
@@ -541,12 +548,12 @@ public sealed class IssueManager : RangeObservableCollection<MainIssue>
if (resinTrapConfig.BinaryThreshold > 0)
{
resinTrapImage = new Mat();
- CvInvoke.Threshold(image, resinTrapImage, resinTrapConfig.BinaryThreshold, byte.MaxValue, ThresholdType.Binary);
+ CvInvoke.Threshold(image.SourceMat, resinTrapImage, resinTrapConfig.BinaryThreshold, byte.MaxValue, ThresholdType.Binary);
}
else
{
needDispose = true;
- resinTrapImage = image;
+ resinTrapImage = image.SourceMat;
}
var contourLayer = resinTrapImage.Roi(SlicerFile.BoundingRectangle);
diff --git a/UVtools.Core/Objects/KernelConfiguration.cs b/UVtools.Core/Objects/KernelConfiguration.cs
index 779450d..dac6fce 100644
--- a/UVtools.Core/Objects/KernelConfiguration.cs
+++ b/UVtools.Core/Objects/KernelConfiguration.cs
@@ -217,8 +217,8 @@ public sealed class KernelConfiguration : BindableBase, IDisposable
KernelMat = CvInvoke.GetStructuringElement(shape, size, anchor);
}
- public void SetKernel(ElementShape shape, Size size) => SetKernel(shape, size, new Point(-1, -1));
- public void SetKernel(ElementShape shape) => SetKernel(shape, new Size(3, 3), new Point(-1, -1));
+ public void SetKernel(ElementShape shape, Size size) => SetKernel(shape, size, EmguExtensions.AnchorCenter);
+ public void SetKernel(ElementShape shape) => SetKernel(shape, new Size(3, 3), EmguExtensions.AnchorCenter);
public Mat? GetKernel()
{
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index b7ae234..b9fc536 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -12,6 +12,7 @@ using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
+using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
@@ -147,9 +148,9 @@ public sealed class OperationBlur : Operation
{
Size size = new((int)Size, (int)Size);
Point anchor = Kernel.Anchor;
- if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (anchor.IsEmpty) anchor = EmguExtensions.AnchorCenter;
//if (size.IsEmpty) size = new Size(3, 3);
- //if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ //if (anchor.IsEmpty) anchor = EmguExtensions.AnchorCenter;
var target = GetRoiOrDefault(mat);
using var original = mat.Clone();
switch (BlurOperation)
diff --git a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
index 58c73d6..9ffc5e1 100644
--- a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
+++ b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs
@@ -436,7 +436,6 @@ public sealed class OperationCalibrateElephantFoot : Operation
public Mat[] GetLayers()
{
var layers = new Mat[3];
- var anchor = new Point(-1, -1);
layers[0] = EmguExtensions.InitMat(SlicerFile.Resolution);
layers[2] = layers[0].Clone();
@@ -655,7 +654,7 @@ public sealed class OperationCalibrateElephantFoot : Operation
mask.SetTo(new MCvScalar(byte.MaxValue-brightness));
int tempIterations = DimmingWallThickness;
var kernel = DimmingKernel.GetKernel(ref tempIterations);
- CvInvoke.Erode(shape, erode, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(shape, erode, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
//CvInvoke.Subtract(shape, erode, diff);
//CvInvoke.BitwiseAnd(diff, mask, target);
//CvInvoke.Add(erode, target, target);
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index efd6b15..45ba400 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -1766,8 +1766,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
CvInvoke.BitwiseAnd(layers[0], mat, layers[1], matMask);
- Point anchor = new Point(-1, -1);
- //CvInvoke.MorphologyEx(layers[1], layers[1], MorphOp.Open, CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3,3), anchor), anchor, 1, BorderType.Reflect101, default);
+ //CvInvoke.MorphologyEx(layers[1], layers[1], MorphOp.Open, CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3,3), EmguExtensions.AnchorCenter), EmguExtensions.AnchorCenter, 1, BorderType.Reflect101, default);
mat.Dispose();
matMask.Dispose();
@@ -1845,7 +1844,6 @@ public sealed class OperationCalibrateExposureFinder : Operation
int partMarginXPx = (int)(_partMargin * Xppmm);
int partMarginYPx = (int)(_partMargin * Yppmm);
- var anchor = new Point(-1, -1);
var kernel = EmguExtensions.Kernel3x3Rectangle;
if (_patternModel)
@@ -1921,14 +1919,14 @@ public sealed class OperationCalibrateExposureFinder : Operation
if (layerCountOnHeight < _chamferLayers)
{
- CvInvoke.Erode(newMatRoi, newMatRoi, kernel, anchor, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default);
+ CvInvoke.Erode(newMatRoi, newMatRoi, kernel, EmguExtensions.AnchorCenter, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default);
}
if (layer.IsBottomLayer)
{
if (_erodeBottomIterations > 0)
{
- CvInvoke.Erode(newMatRoi, newMatRoi, kernel, anchor, _erodeBottomIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(newMatRoi, newMatRoi, kernel, EmguExtensions.AnchorCenter, _erodeBottomIterations, BorderType.Reflect101, default);
}
if(_patternModelTextEnabled)
@@ -2114,12 +2112,12 @@ public sealed class OperationCalibrateExposureFinder : Operation
if (isBottomLayer && _erodeBottomIterations > 0)
{
- CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _erodeBottomIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(matRoi, matRoi, kernel, EmguExtensions.AnchorCenter, _erodeBottomIterations, BorderType.Reflect101, default);
}
if (layerCountOnHeight < _chamferLayers)
{
- CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default);
+ CvInvoke.Erode(matRoi, matRoi, kernel, EmguExtensions.AnchorCenter, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default);
}
if (_multipleBrightness && brightness < 255)
diff --git a/UVtools.Core/Operations/OperationCalibrateStressTower.cs b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
index 4ba78d6..ab14dec 100644
--- a/UVtools.Core/Operations/OperationCalibrateStressTower.cs
+++ b/UVtools.Core/Operations/OperationCalibrateStressTower.cs
@@ -331,8 +331,7 @@ public sealed class OperationCalibrateStressTower : Operation
const byte fontThickness = 2;
LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected;
- var anchor = new Point(-1, -1);
- var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);*/
+ var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), EmguExtensions.AnchorCenter);*/
Parallel.For(0, LayerCount, CoreSettings.ParallelOptions, layerIndex =>
{
layers[layerIndex] = EmguExtensions.InitMat(SlicerFile.Resolution);
diff --git a/UVtools.Core/Operations/OperationCalibrateTolerance.cs b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
index dd5d7ba..7179fa9 100644
--- a/UVtools.Core/Operations/OperationCalibrateTolerance.cs
+++ b/UVtools.Core/Operations/OperationCalibrateTolerance.cs
@@ -510,7 +510,6 @@ public sealed class OperationCalibrateTolerance : Operation
const byte fontThickness = 2;
LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected;
- var anchor = new Point(-1, -1);
var kernel = EmguExtensions.Kernel3x3Rectangle;
var pointTextList = new List<KeyValuePair<Point, string>>();
@@ -647,7 +646,7 @@ public sealed class OperationCalibrateTolerance : Operation
{
Parallel.For(0, _bottomLayers, CoreSettings.ParallelOptions, layerIndex =>
{
- CvInvoke.Erode(layers[layerIndex], layers[layerIndex], kernel, anchor, _erodeBottomIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(layers[layerIndex], layers[layerIndex], kernel, EmguExtensions.AnchorCenter, _erodeBottomIterations, BorderType.Reflect101, default);
});
}
@@ -656,10 +655,10 @@ public sealed class OperationCalibrateTolerance : Operation
Parallel.For(0, _chamferLayers, CoreSettings.ParallelOptions, layerIndexOffset =>
{
var iteration = _chamferLayers - layerIndexOffset;
- CvInvoke.Erode(layers[layerIndexOffset], layers[layerIndexOffset], kernel, anchor, iteration, BorderType.Reflect101, default);
+ CvInvoke.Erode(layers[layerIndexOffset], layers[layerIndexOffset], kernel, EmguExtensions.AnchorCenter, iteration, BorderType.Reflect101, default);
var layerIndex = layers.Length - 1 - layerIndexOffset;
- CvInvoke.Erode(layers[layerIndex], layers[layerIndex], kernel, anchor, iteration, BorderType.Reflect101, default);
+ CvInvoke.Erode(layers[layerIndex], layers[layerIndex], kernel, EmguExtensions.AnchorCenter, iteration, BorderType.Reflect101, default);
});
/*byte iterations = _chamferLayers;
var layerIndex = 0;
diff --git a/UVtools.Core/Operations/OperationDoubleExposure.cs b/UVtools.Core/Operations/OperationDoubleExposure.cs
index bdefe8c..0123d68 100644
--- a/UVtools.Core/Operations/OperationDoubleExposure.cs
+++ b/UVtools.Core/Operations/OperationDoubleExposure.cs
@@ -12,6 +12,7 @@ using System;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
+using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Layers;
using UVtools.Core.Objects;
@@ -273,8 +274,6 @@ public class OperationDoubleExposure : Operation
protected override bool ExecuteInternally(OperationProgress progress)
{
- var anchor = new Point(-1, -1);
-
var layers = new Layer[SlicerFile.LayerCount+LayerRangeCount];
// Untouched
@@ -308,7 +307,7 @@ public class OperationDoubleExposure : Operation
{
int tempIterations = firstErodeIterations;
var kernel = Kernel.GetKernel(ref tempIterations);
- CvInvoke.Erode(mat, mat, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(mat, mat, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
firstLayer.LayerMat = mat;
firstLayer.CopyImageTo(secondLayer);
@@ -317,7 +316,7 @@ public class OperationDoubleExposure : Operation
tempIterations = _secondLayerDifferenceOverlapErodeIterations;
kernel = Kernel.GetKernel(ref tempIterations);
using var matErode = new Mat();
- CvInvoke.Erode(mat, matErode, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(mat, matErode, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
//CvInvoke.Threshold(matErode, matErode, 127, 255, ThresholdType.Binary);
CvInvoke.Subtract(mat, matErode, mat);
secondLayer.LayerMat = mat;
@@ -336,7 +335,7 @@ public class OperationDoubleExposure : Operation
int tempIterations = firstErodeIterations;
var kernel = Kernel.GetKernel(ref tempIterations);
firstMat = new Mat();
- CvInvoke.Erode(mat, firstMat, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(mat, firstMat, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
firstLayer.LayerMat = firstMat;
}
@@ -345,7 +344,7 @@ public class OperationDoubleExposure : Operation
int tempIterations = secondErodeIterations;
var kernel = Kernel.GetKernel(ref tempIterations);
secondMat = new Mat();
- CvInvoke.Erode(mat, secondMat, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(mat, secondMat, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
}
if(firstMat is not null && _secondLayerDifference)
@@ -357,7 +356,7 @@ public class OperationDoubleExposure : Operation
{
int tempIterations = _secondLayerDifferenceOverlapErodeIterations;
var kernel = Kernel.GetKernel(ref tempIterations);
- CvInvoke.Erode(firstMat, firstMat, kernel, anchor, tempIterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(firstMat, firstMat, kernel, EmguExtensions.AnchorCenter, tempIterations, BorderType.Reflect101, default);
//CvInvoke.Threshold(firstMat, firstMat, 127, 255, ThresholdType.Binary);
}
diff --git a/UVtools.Core/Operations/OperationDynamicLayerHeight.cs b/UVtools.Core/Operations/OperationDynamicLayerHeight.cs
index 938f1f5..2d7e0ff 100644
--- a/UVtools.Core/Operations/OperationDynamicLayerHeight.cs
+++ b/UVtools.Core/Operations/OperationDynamicLayerHeight.cs
@@ -566,7 +566,6 @@ public sealed class OperationDynamicLayerHeight : Operation
OldPrintTime = SlicerFile.PrintTime
};
- var anchor = new Point(-1, -1);
var kernel = EmguExtensions.Kernel3x3Rectangle;
var matCache = new MatCacheManager(this, (ushort)CacheObjectCount, ObjectsPerCache)
@@ -729,7 +728,7 @@ public sealed class OperationDynamicLayerHeight : Operation
break;
}*/
//Debug.WriteLine($"{layerIndex} - {erodeCount}");
- CvInvoke.Erode(matXorSum, matXor, kernel, anchor, 1, BorderType.Reflect101, default);
+ CvInvoke.Erode(matXorSum, matXor, kernel, EmguExtensions.AnchorCenter, 1, BorderType.Reflect101, default);
//CvInvoke.Imshow("Render", erodeMatXor.Roi(SlicerFile.BoundingRectangle));
//CvInvoke.WaitKey();
if (CvInvoke.CountNonZero(matXor) == 0)
diff --git a/UVtools.Core/Operations/OperationInfill.cs b/UVtools.Core/Operations/OperationInfill.cs
index 9085ad3..9d0c4df 100644
--- a/UVtools.Core/Operations/OperationInfill.cs
+++ b/UVtools.Core/Operations/OperationInfill.cs
@@ -182,7 +182,7 @@ public sealed class OperationInfill : Operation
public override bool Execute(Mat mat, params object[]? arguments)
{
if (arguments is null || arguments.Length < 1) return false;
- var anchor = new Point(-1, -1);
+
var kernel = EmguExtensions.Kernel3x3Rectangle;
uint index = Convert.ToUInt32(arguments[0]);
uint layerIndex = index - LayerIndexStart;
@@ -465,7 +465,7 @@ public sealed class OperationInfill : Operation
//patternMask.Save("D:\\pattern.png");
- CvInvoke.Erode(target, erode, kernel, anchor, WallThickness, BorderType.Reflect101,
+ CvInvoke.Erode(target, erode, kernel, EmguExtensions.AnchorCenter, WallThickness, BorderType.Reflect101,
default);
CvInvoke.Subtract(target, erode, diff);
diff --git a/UVtools.Core/Operations/OperationLithophane.cs b/UVtools.Core/Operations/OperationLithophane.cs
index 86b36b7..9b076d0 100644
--- a/UVtools.Core/Operations/OperationLithophane.cs
+++ b/UVtools.Core/Operations/OperationLithophane.cs
@@ -371,8 +371,8 @@ public class OperationLithophane : Operation
CvInvoke.GaussianBlur(mat, mat, new Size(ksize, ksize), 0);
}
- if (_removeNoiseIterations > 0) CvInvoke.MorphologyEx(mat, mat, MorphOp.Open, EmguExtensions.Kernel3x3Rectangle, new Point(-1, -1), _removeNoiseIterations, BorderType.Reflect101, default);
- if (_gapClosingIterations > 0) CvInvoke.MorphologyEx(mat, mat, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, new Point(-1, -1), _gapClosingIterations, BorderType.Reflect101, default);
+ if (_removeNoiseIterations > 0) CvInvoke.MorphologyEx(mat, mat, MorphOp.Open, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter, _removeNoiseIterations, BorderType.Reflect101, default);
+ if (_gapClosingIterations > 0) CvInvoke.MorphologyEx(mat, mat, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter, _gapClosingIterations, BorderType.Reflect101, default);
if (_rotate != RotateDirection.None) CvInvoke.Rotate(mat, mat, (RotateFlags) _rotate);
if (_mirror)
@@ -496,7 +496,7 @@ public class OperationLithophane : Operation
{
using var dilatedMat = new Mat();
CvInvoke.Threshold(mat, dilatedMat, 1, byte.MaxValue, ThresholdType.Binary);
- CvInvoke.Dilate(dilatedMat, dilatedMat, EmguExtensions.Kernel3x3Rectangle, new Point(-1, -1), _baseMargin, BorderType.Reflect101, default);
+ CvInvoke.Dilate(dilatedMat, dilatedMat, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter, _baseMargin, BorderType.Reflect101, default);
dilatedMat.CopyToCenter(baseMat);
break;
}
diff --git a/UVtools.Core/Operations/OperationPixelArithmetic.cs b/UVtools.Core/Operations/OperationPixelArithmetic.cs
index 1613018..8690208 100644
--- a/UVtools.Core/Operations/OperationPixelArithmetic.cs
+++ b/UVtools.Core/Operations/OperationPixelArithmetic.cs
@@ -535,7 +535,6 @@ public class OperationPixelArithmetic : Operation
Mat? patternAlternateMat = null;
Mat patternMatMask = null!;
Mat patternAlternateMatMask = null!;
- var anchor = new Point(-1, -1);
if (_usePattern && IsUsePatternVisible)
{
@@ -639,7 +638,7 @@ public class OperationPixelArithmetic : Operation
using var erode = new Mat();
int iterations = 1;
var kernel = Kernel.GetKernel(ref iterations);
- CvInvoke.Erode(target, erode, kernel, anchor, iterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, erode, kernel, EmguExtensions.AnchorCenter, iterations, BorderType.Reflect101, default);
CvInvoke.Subtract(target, erode, erode);
CvInvoke.Add(applyMask, erode, applyMask);
@@ -649,7 +648,7 @@ public class OperationPixelArithmetic : Operation
{
iterations = wallThickness - 1;
kernel = Kernel.GetKernel(ref iterations);
- CvInvoke.Dilate(applyMask, erode, kernel, anchor, iterations, BorderType.Reflect101, default);
+ CvInvoke.Dilate(applyMask, erode, kernel, EmguExtensions.AnchorCenter, iterations, BorderType.Reflect101, default);
erode.CopyTo(applyMask, target);
}
}
@@ -666,7 +665,7 @@ public class OperationPixelArithmetic : Operation
applyMask = new Mat();
int iterations = wallThickness;
var kernel = Kernel.GetKernel(ref iterations);
- CvInvoke.Erode(target, applyMask, kernel, anchor, iterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, applyMask, kernel, EmguExtensions.AnchorCenter, iterations, BorderType.Reflect101, default);
break;
}
case PixelArithmeticApplyMethod.ModelWalls:
@@ -681,7 +680,7 @@ public class OperationPixelArithmetic : Operation
applyMask = target.Clone();
int iterations = wallThickness;
var kernel = Kernel.GetKernel(ref iterations);
- CvInvoke.Erode(target, erode, kernel, anchor, iterations, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, erode, kernel, EmguExtensions.AnchorCenter, iterations, BorderType.Reflect101, default);
applyMask.SetTo(EmguExtensions.BlackColor, erode);
break;
}
diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs
index 334f597..87465f8 100644
--- a/UVtools.Core/Operations/OperationPixelDimming.cs
+++ b/UVtools.Core/Operations/OperationPixelDimming.cs
@@ -665,7 +665,7 @@ public class OperationPixelDimming : Operation
public override bool Execute(Mat mat, params object[]? arguments)
{
if (arguments is null || arguments.Length < 2) return false;
- var anchor = new Point(-1, -1);
+
var kernel = EmguExtensions.Kernel3x3Rectangle;
uint layerIndex = Convert.ToUInt32(arguments[0]);
@@ -690,7 +690,7 @@ public class OperationPixelDimming : Operation
using var mask = GetMask(mat);
- CvInvoke.Erode(target, erode, kernel, anchor, wallThickness, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, erode, kernel, EmguExtensions.AnchorCenter, wallThickness, BorderType.Reflect101, default);
if (_lighteningPixels)
{
diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs
index 41d5e1a..5e9cb2f 100644
--- a/UVtools.Core/Operations/OperationRaftRelief.cs
+++ b/UVtools.Core/Operations/OperationRaftRelief.cs
@@ -273,7 +273,7 @@ public class OperationRaftRelief : Operation
const uint maxLayerCount = 1000;
Mat? supportsMat = null;
- var anchor = new Point(-1, -1);
+
var kernel = EmguExtensions.Kernel3x3Rectangle;
uint firstSupportLayerIndex = _maskLayerIndex;
@@ -305,9 +305,8 @@ public class OperationRaftRelief : Operation
if (_dilateIterations > 0)
{
- CvInvoke.Dilate(supportsMat, supportsMat,
- CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)),
- new Point(-1, -1), _dilateIterations, BorderType.Reflect101, new MCvScalar());
+ CvInvoke.Dilate(supportsMat, supportsMat, EmguExtensions.Kernel3x3Rectangle,
+ EmguExtensions.AnchorCenter, _dilateIterations, BorderType.Reflect101, new MCvScalar());
}
var color = new MCvScalar(255 - _lowBrightness);
@@ -386,7 +385,7 @@ public class OperationRaftRelief : Operation
}
// Close minor holes, round imperfections, stronger joints
- CvInvoke.MorphologyEx(supportsMat, supportsMat, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, new Point(-1, -1), 1, BorderType.Reflect101, default);
+ CvInvoke.MorphologyEx(supportsMat, supportsMat, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter, 1, BorderType.Reflect101, default);
break;
}
@@ -412,7 +411,7 @@ public class OperationRaftRelief : Operation
CvInvoke.Erode(mask, mask, kernel, anchor, operation.WallMargin, BorderType.Reflect101, new MCvScalar());
CvInvoke.Subtract(target, patternMat, target, mask);*/
- CvInvoke.Erode(target, mask, kernel, anchor, WallMargin, BorderType.Reflect101, default);
+ CvInvoke.Erode(target, mask, kernel, EmguExtensions.AnchorCenter, WallMargin, BorderType.Reflect101, default);
CvInvoke.Subtract(mask, supportsMat, mask);
CvInvoke.Subtract(target, patternMat, target, mask);
}
diff --git a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
index d8b083c..65c9e69 100644
--- a/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
+++ b/UVtools.Core/Operations/OperationRaiseOnPrintFinish.cs
@@ -22,8 +22,9 @@ public class OperationRaiseOnPrintFinish : Operation
#region Members
private decimal _positionZ;
-
+ private decimal _waitTime = 1200; // 20m
private bool _outputDummyPixel = true;
+
#endregion
#region Overrides
@@ -89,7 +90,7 @@ public class OperationRaiseOnPrintFinish : Operation
public override string ToString()
{
- var result = $"[Z={_positionZ}mm] [Dummy pixel: {_outputDummyPixel}]";
+ var result = $"[Z={_positionZ}mm] [Wait: {_waitTime}s] [Dummy pixel: {_outputDummyPixel}]";
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
@@ -98,9 +99,11 @@ public class OperationRaiseOnPrintFinish : Operation
#region Properties
public float MinimumPositionZ => Layer.RoundHeight(SlicerFile.PrintHeight + SlicerFile.LayerHeight);
+ public float MediumPositionZ => Layer.RoundHeight(MinimumPositionZ + (MaximumPositionZ - MinimumPositionZ) / 2);
+ public float MaximumPositionZ => Math.Max(MinimumPositionZ, Layer.RoundHeight(SlicerFile.MachineZ));
/// <summary>
- /// Sets or gets the Z position to raise to
+ /// Gets or sets the Z position to raise to
/// </summary>
public decimal PositionZ
{
@@ -109,6 +112,17 @@ public class OperationRaiseOnPrintFinish : Operation
}
/// <summary>
+ /// <para>Gets or sets the ensured wait time to stay still on the desired position.</para>
+ /// <para>This is useful if the printer firmware always move to top and you want to stay still on the set position for at least the desired time.</para>
+ /// <para>Note: The print time calculation will take this wait into consideration and display a longer print time.</para>
+ /// </summary>
+ public decimal WaitTime
+ {
+ get => _waitTime;
+ set => RaiseAndSetIfChanged(ref _waitTime, Math.Round(Math.Max(0, value), 2));
+ }
+
+ /// <summary>
/// True to output a dummy pixel on bounding rectangle position to avoid empty layer and blank image, otherwise set to false
/// </summary>
public bool OutputDummyPixel
@@ -125,7 +139,10 @@ public class OperationRaiseOnPrintFinish : Operation
//_outputDummyPixel = !SlicerFile.SupportsGCode;
}
- public OperationRaiseOnPrintFinish(FileFormat slicerFile) : base(slicerFile)
+ public OperationRaiseOnPrintFinish(FileFormat slicerFile) : base(slicerFile)
+ { }
+
+ public override void InitWithSlicerFile()
{
if (_positionZ <= 0) _positionZ = (decimal)SlicerFile.MachineZ;
}
@@ -136,7 +153,7 @@ public class OperationRaiseOnPrintFinish : Operation
protected bool Equals(OperationRaiseOnPrintFinish other)
{
- return _positionZ == other._positionZ && _outputDummyPixel == other._outputDummyPixel;
+ return _positionZ == other._positionZ && _outputDummyPixel == other._outputDummyPixel && _waitTime == other._waitTime;
}
public override bool Equals(object? obj)
@@ -149,13 +166,19 @@ public class OperationRaiseOnPrintFinish : Operation
public override int GetHashCode()
{
- return HashCode.Combine(_positionZ, _outputDummyPixel);
+ return HashCode.Combine(_positionZ, _outputDummyPixel, _waitTime);
}
#endregion
#region Methods
+ public void SetToMinimumPosition() => PositionZ = (decimal)MinimumPositionZ;
+ public void SetToMediumPosition() => PositionZ = (decimal)MediumPositionZ;
+ public void SetToMaximumPosition() => PositionZ = (decimal)MaximumPositionZ;
+
+ public void SetWaitTime(decimal time) => WaitTime = time;
+
protected override bool ExecuteInternally(OperationProgress progress)
{
var layer = SlicerFile.LastLayer!.Clone();
@@ -169,6 +192,8 @@ public class OperationRaiseOnPrintFinish : Operation
layer.LayerMat = newMat;
+ if(_waitTime > 0) layer.SetWaitTimeBeforeCureOrLightOffDelay((float)_waitTime);
+
SlicerFile.SuppressRebuildPropertiesWork(() =>
{
SlicerFile.Append(layer);
diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs
index e0e6abc..a3ac3ea 100644
--- a/UVtools.Core/Operations/OperationRepairLayers.cs
+++ b/UVtools.Core/Operations/OperationRepairLayers.cs
@@ -250,12 +250,12 @@ public class OperationRepairLayers : Operation
{
var layer = SlicerFile[group.Key];
var image = layer.LayerMat;
- var bytes = image.GetDataByteSpan();
+ var span = image.GetDataByteSpan();
foreach (IssueOfPoints issue in group)
{
foreach (var issuePixel in issue.Points)
{
- bytes[image.GetPixelPos(issuePixel)] = 0;
+ span[image.GetPixelPos(issuePixel)] = 0;
}
progress.LockAndIncrement();
@@ -435,17 +435,16 @@ public class OperationRepairLayers : Operation
if (_repairIslands && (_gapClosingIterations > 0 || _noiseRemovalIterations > 0))
{
InitImage();
- using var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3),
- new Point(-1, -1));
+
if (_gapClosingIterations > 0)
{
- CvInvoke.MorphologyEx(image, image, MorphOp.Close, kernel, new Point(-1, -1),
+ CvInvoke.MorphologyEx(image, image, MorphOp.Close, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter,
(int)_gapClosingIterations, BorderType.Default, default);
}
if (_noiseRemovalIterations > 0)
{
- CvInvoke.MorphologyEx(image, image, MorphOp.Open, kernel, new Point(-1, -1),
+ CvInvoke.MorphologyEx(image, image, MorphOp.Open, EmguExtensions.Kernel3x3Rectangle, EmguExtensions.AnchorCenter,
(int)_noiseRemovalIterations, BorderType.Default, default);
}
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 1be2e3a..020fa6a 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>3.6.6</Version>
+ <Version>3.6.7</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -31,16 +31,19 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DocumentationFile>..\documentation\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DocumentationFile>..\documentation\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DocumentationFile>..\documentation\$(AssemblyName).xml</DocumentationFile>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
@@ -69,10 +72,10 @@
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.0.0" />
<PackageReference Include="Emgu.CV" Version="4.5.5.4823" />
<PackageReference Include="Emgu.CV.runtime.ubuntu.20.04-x64" Version="4.5.4.4788" />
- <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
+ <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.4.4788" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
<PackageReference Include="KdTree" Version="1.4.1" />
- <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.3.0" />
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.3.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />