diff --git a/UVtools.Core/Managers/IssueManager.cs b/UVtools.Core/Managers/IssueManager.cs index 80abd1e..4ba52ac 100644 --- a/UVtools.Core/Managers/IssueManager.cs +++ b/UVtools.Core/Managers/IssueManager.cs @@ -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 combinedIssues = issues.SelectMany(issue => issue.Childs).ToList(); + List 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(); + //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); + } } } diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs index 9d057ae..ed66089 100644 --- a/UVtools.Core/Operations/OperationRepairLayers.cs +++ b/UVtools.Core/Operations/OperationRepairLayers.cs @@ -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(); 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(); - //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) diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs index e882614..eacdfdb 100644 --- a/UVtools.WPF/MainWindow.Issues.cs +++ b/UVtools.WPF/MainWindow.Issues.cs @@ -222,6 +222,7 @@ namespace UVtools.WPF // Update GUI var issueRemoveList = new List(); + var suctionCupList = new List(); 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(); - var downDirection = new Stack(); - 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");