mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-09 01:52:32 +02:00
Extract suction cup drilling to common function
Both the repair operation as well as the deletion of an issue will now leverage common code for executing a repair. Repair operation will repair all suction cups, and deleting a specific suction cup will only repair that one.
This commit is contained in:
@@ -14,6 +14,7 @@ using UVtools.Core.Extensions;
|
||||
using UVtools.Core.FileFormats;
|
||||
using UVtools.Core.Layers;
|
||||
using UVtools.Core.Operations;
|
||||
using UVtools.Core.PixelEditor;
|
||||
|
||||
namespace UVtools.Core.Managers
|
||||
{
|
||||
@@ -970,5 +971,70 @@ namespace UVtools.Core.Managers
|
||||
|
||||
return GetResult();
|
||||
}
|
||||
|
||||
public void DrillSuctionCupsForIssues(MainIssue[] issues, int ventHoleDiameter, OperationProgress progress)
|
||||
{
|
||||
List<Issue> combinedIssues = issues.SelectMany(issue => issue.Childs).ToList();
|
||||
List<IssueOfContours> bottomSuctionIssues = new();
|
||||
Parallel.ForEach(combinedIssues, issue =>
|
||||
{
|
||||
var issueOfContours = (IssueOfContours)issue;
|
||||
if (issue.LayerIndex == 0)
|
||||
{
|
||||
bottomSuctionIssues.Add(issueOfContours);
|
||||
return;
|
||||
}
|
||||
|
||||
bool overlapFound = false;
|
||||
|
||||
foreach (IssueOfContours candidate in combinedIssues.Where(candidate => candidate.LayerIndex == issue.LayerIndex - 1))
|
||||
{
|
||||
using var vec1 = new VectorOfVectorOfPoint(issueOfContours.Contours);
|
||||
using var vec2 = new VectorOfVectorOfPoint(candidate.Contours);
|
||||
if (EmguContours.ContoursIntersect(vec1, vec2))
|
||||
{
|
||||
overlapFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!overlapFound)
|
||||
{
|
||||
bottomSuctionIssues.Add(issueOfContours);
|
||||
}
|
||||
});
|
||||
|
||||
(bool canDrill, Point location) GetDrillLocation(IssueOfContours issue, int diameter)
|
||||
{
|
||||
using var vecCentroid = new VectorOfPoint(issue.Contours[0]);
|
||||
var centroid = EmguContour.GetCentroid(vecCentroid);
|
||||
using var circleCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using var contourMat = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using var overlapCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
|
||||
var inverseOffset = new Point(issue.BoundingRectangle.X * -1, issue.BoundingRectangle.Y * -1);
|
||||
using var vec = new VectorOfVectorOfPoint(issue.Contours);
|
||||
CvInvoke.DrawContours(contourMat, vec, -1, EmguExtensions.WhiteColor, -1, LineType.EightConnected, null, int.MaxValue, inverseOffset);
|
||||
|
||||
CvInvoke.Circle(circleCheck, new(centroid.X + inverseOffset.X, centroid.Y + inverseOffset.Y), diameter, EmguExtensions.WhiteColor, -1);
|
||||
|
||||
CvInvoke.BitwiseAnd(circleCheck, contourMat, overlapCheck);
|
||||
|
||||
return CvInvoke.CountNonZero(overlapCheck) > 0
|
||||
? (true, centroid) /* 5px centroid is inside layer! drill baby drill */
|
||||
: (false, new Point()); /* centroid is not inside the actual contour, no drill */
|
||||
}
|
||||
|
||||
var drillOps = new List<PixelOperation>();
|
||||
//var suctionReliefSize = (ushort)Math.Max(SlicerFile.PpmmMax * 0.8, 17);
|
||||
/* for each suction cup issue that is an initial layer */
|
||||
foreach (var issue in bottomSuctionIssues)
|
||||
{
|
||||
var drillPoint = GetDrillLocation(issue, ventHoleDiameter);
|
||||
if (!drillPoint.canDrill) continue;
|
||||
drillOps.Add(new PixelDrainHole(issue.LayerIndex, drillPoint.location, (ushort)ventHoleDiameter));
|
||||
}
|
||||
|
||||
SlicerFile.LayerManager.DrawModifications(drillOps, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,68 +417,9 @@ namespace UVtools.Core.Operations
|
||||
|
||||
if (_repairSuctionCups && SlicerFile.IssueManager.Count > 0)
|
||||
{
|
||||
/* build out parent/child relationships between all detected suction cups */
|
||||
|
||||
var bottomSuctionIssues = new ConcurrentBag<IssueOfContours>();
|
||||
var suctionCups = SlicerFile.IssueManager.GetIssuesBy(MainIssue.IssueType.SuctionCup);
|
||||
Parallel.ForEach(suctionCups, issue =>
|
||||
{
|
||||
var issueOfContours = (IssueOfContours)issue;
|
||||
if (issue.LayerIndex == 0)
|
||||
{
|
||||
bottomSuctionIssues.Add(issueOfContours);
|
||||
return;
|
||||
}
|
||||
|
||||
bool overlapFound = false;
|
||||
|
||||
foreach(IssueOfContours candidate in suctionCups.Where(candidate => candidate.LayerIndex == issue.LayerIndex - 1))
|
||||
{
|
||||
using var vec1 = new VectorOfVectorOfPoint(issueOfContours.Contours);
|
||||
using var vec2 = new VectorOfVectorOfPoint(candidate.Contours);
|
||||
if (EmguContours.ContoursIntersect(vec1, vec2)) {
|
||||
overlapFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!overlapFound)
|
||||
{
|
||||
bottomSuctionIssues.Add(issueOfContours);
|
||||
}
|
||||
});
|
||||
|
||||
(bool canDrill, Point location) GetDrillLocation(IssueOfContours issue, int diameter)
|
||||
{
|
||||
using var vecCentroid = new VectorOfPoint(issue.Contours[0]);
|
||||
var centroid = EmguContour.GetCentroid(vecCentroid);
|
||||
using var circleCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using var contourMat = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using var overlapCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
|
||||
var inverseOffset = new Point(issue.BoundingRectangle.X * -1, issue.BoundingRectangle.Y * -1);
|
||||
using var vec = new VectorOfVectorOfPoint(issue.Contours);
|
||||
CvInvoke.DrawContours(contourMat, vec, -1, EmguExtensions.WhiteColor, -1, LineType.EightConnected, null, int.MaxValue, inverseOffset);
|
||||
|
||||
CvInvoke.Circle(circleCheck, new(centroid.X + inverseOffset.X, centroid.Y + inverseOffset.Y), diameter, EmguExtensions.WhiteColor, -1);
|
||||
|
||||
CvInvoke.BitwiseAnd(circleCheck, contourMat, overlapCheck);
|
||||
|
||||
return CvInvoke.CountNonZero(overlapCheck) > 0
|
||||
? (true,centroid) /* 5px centroid is inside layer! drill baby drill */
|
||||
: (false, new Point()); /* centroid is not inside the actual contour, no drill */
|
||||
}
|
||||
|
||||
var drillOps = new List<PixelOperation>();
|
||||
//var suctionReliefSize = (ushort)Math.Max(SlicerFile.PpmmMax * 0.8, 17);
|
||||
/* for each suction cup issue that is an initial layer */
|
||||
foreach (var issue in bottomSuctionIssues)
|
||||
{
|
||||
var drillPoint = GetDrillLocation(issue, _suctionCupsVentHole);
|
||||
if (!drillPoint.canDrill) continue;
|
||||
drillOps.Add(new PixelDrainHole(issue.LayerIndex, drillPoint.location, _suctionCupsVentHole));
|
||||
}
|
||||
|
||||
SlicerFile.LayerManager.DrawModifications(drillOps, progress);
|
||||
SlicerFile.IssueManager.DrillSuctionCupsForIssues(SlicerFile.IssueManager.Where(issue => issue.Type == MainIssue.IssueType.SuctionCup).ToArray(), _suctionCupsVentHole, progress);
|
||||
}
|
||||
|
||||
if (_removeEmptyLayers)
|
||||
|
||||
@@ -222,6 +222,7 @@ namespace UVtools.WPF
|
||||
|
||||
// Update GUI
|
||||
var issueRemoveList = new List<MainIssue>();
|
||||
var suctionCupList = new List<MainIssue>();
|
||||
foreach (MainIssue issue in IssuesGrid.SelectedItems)
|
||||
{
|
||||
if (issue.Type != MainIssue.IssueType.Island &&
|
||||
@@ -239,32 +240,7 @@ namespace UVtools.WPF
|
||||
|
||||
if (issue.Type == MainIssue.IssueType.SuctionCup)
|
||||
{
|
||||
// Need redo
|
||||
/*if (issueRemoveList.Contains(issue)) continue;
|
||||
|
||||
var upDirection = new Stack<LayerIssue>();
|
||||
var downDirection = new Stack<LayerIssue>();
|
||||
upDirection.Push(issue);
|
||||
downDirection.Push(issue);
|
||||
|
||||
while (upDirection.Count > 0)
|
||||
{
|
||||
var current = upDirection.Pop();
|
||||
foreach(var iss in GetOverlappingIssues(current,1))
|
||||
{
|
||||
upDirection.Push(iss);
|
||||
issueRemoveList.Add(iss);
|
||||
}
|
||||
}
|
||||
while(downDirection.Count > 0)
|
||||
{
|
||||
var current = downDirection.Pop();
|
||||
foreach (var iss in GetOverlappingIssues(current, -1))
|
||||
{
|
||||
downDirection.Push(iss);
|
||||
issueRemoveList.Add(iss);
|
||||
}
|
||||
}*/
|
||||
suctionCupList.Add(issue);
|
||||
|
||||
}
|
||||
|
||||
@@ -272,6 +248,8 @@ namespace UVtools.WPF
|
||||
//Issues.Remove(issue);
|
||||
|
||||
}
|
||||
|
||||
SlicerFile.IssueManager.DrillSuctionCupsForIssues(suctionCupList.ToArray(), UserSettings.Instance.LayerRepair.SuctionCupsVentHole, Progress);
|
||||
|
||||
Clipboard.Clip($"Manually removed {issueRemoveList.Count} issues");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user