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:
tslater2006
2021-09-20 12:10:12 -05:00
parent 4b235ffb1d
commit 9b87bc8500
3 changed files with 71 additions and 86 deletions
+66
View File
@@ -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)
+4 -26
View File
@@ -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");