From 6f9c92808e575b94a589d454c19b8cdcfd8dfcde Mon Sep 17 00:00:00 2001 From: tslater2006 Date: Mon, 13 Sep 2021 20:18:03 -0500 Subject: [PATCH] fix Airmap logic bug / suction cup bug Adjust airmap logic during 2nd pass to account for contours that were determined to be air-connected during first pass. Always move resolved resin traps to suction traps, and only conditionally report them as issues if configured to do so. Suction traps are used during a cleanup stage for resin traps, so needs to be populated no matter what, there is no additional processing penalty for this. --- UVtools.Core/Layer/LayerManager.cs | 54 ++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 6e44649..c4f86fd 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -763,6 +763,7 @@ namespace UVtools.Core var suctionTraps = new List[LayerCount]; var externalContours = new VectorOfVectorOfPoint[LayerCount]; var hollows = new List[LayerCount]; + var airContours = new List[LayerCount]; var resinTrapsContoursArea = new double[LayerCount][]; bool IsIgnored(LayerIssue issue) => ignoredIssues is not null && ignoredIssues.Count > 0 && ignoredIssues.Contains(issue); @@ -1264,7 +1265,10 @@ namespace UVtools.Core { if (overlapCount >= resinTrapConfig.RequiredBlackPixelsToDrain) { - /* this contour does overlap air, add it to the current air map */ + /* this contour does overlap air, add it to the current air map and remember this contour was air-connected for 2nd pass */ + airContours[layerIndex] ??= new List(); + airContours[layerIndex].Add(hollows[layerIndex][i]); + CvInvoke.BitwiseOr(currentContour, currentAirMap, currentAirMap); } else @@ -1303,6 +1307,15 @@ namespace UVtools.Core /* we still modify the airmap like normal, where we account for the air areas of the layer, and any contours that might overlap...*/ GenerateAirMap(curLayer, layerAirMap, externalContours[layerIndex]); + /* Update air map with any hollows that were found to be air-connected during first pass */ + if (airContours[layerIndex] != null) + { + for (var y = 0; y < airContours[layerIndex].Count; y++) + { + CvInvoke.DrawContours(layerAirMap, airContours[layerIndex][y], -1, EmguExtensions.WhiteColor, -1); + } + } + /* remove solid areas of current layer from the air map */ CvInvoke.Subtract(currentAirMap, curLayer, currentAirMap); @@ -1324,18 +1337,19 @@ namespace UVtools.Core CvInvoke.BitwiseAnd(currentAirMap, currentContour, airOverlap); var overlapCount = CvInvoke.CountNonZero(airOverlap); - if (overlapCount > resinTrapConfig.RequiredBlackPixelsToDrain) + if (overlapCount >= resinTrapConfig.RequiredBlackPixelsToDrain) { /* this contour does overlap air, add this it our air map */ CvInvoke.BitwiseOr(currentContour, currentAirMap, currentAirMap); - if (resinTrapConfig.DetectSuctionCups) - { - /* if we haven't defined a suctionTrap list for this layer, do so */ - suctionTraps[layerIndex] ??= new List(); + /* Always add the removed contour to suctionTraps (even if we aren't reporting suction traps) + * This is because contours that are placed on here get removed from resin traps in the next stage + * if you don't put them here, they never get removed even if they should :) */ - /* since we know it isn't a resin trap, it becomes a suction trap */ - suctionTraps[layerIndex].Add(resinTraps[layerIndex][x]); - } + /* if we haven't defined a suctionTrap list for this layer, do so */ + suctionTraps[layerIndex] ??= new List(); + + /* since we know it isn't a resin trap, it becomes a suction trap */ + suctionTraps[layerIndex].Add(resinTraps[layerIndex][x]); /* to keep things tidy while we iterate resin traps, it will be left in the list for now, and removed later */ } @@ -1408,17 +1422,21 @@ namespace UVtools.Core } } - var minimumSuctionArea = resinTrapConfig.RequiredAreaToConsiderSuctionCup; - for (var layerIndex = 0; layerIndex < suctionTraps.Length; layerIndex++) + /* only report suction cup issues if enabled */ + if (resinTrapConfig.DetectSuctionCups) { - if (suctionTraps[layerIndex] == null) continue; - - foreach (var trap in suctionTraps[layerIndex]) + var minimumSuctionArea = resinTrapConfig.RequiredAreaToConsiderSuctionCup; + for (var layerIndex = 0; layerIndex < suctionTraps.Length; layerIndex++) { - var suctionTrapArea = EmguContours.GetContourArea(trap); - if (suctionTrapArea < minimumSuctionArea) continue; - var rect = CvInvoke.BoundingRectangle(trap[0]); - AddIssue(new LayerIssue(this[layerIndex], LayerIssue.IssueType.SuctionCup, trap.ToArrayOfArray(), rect){Area = suctionTrapArea }); + if (suctionTraps[layerIndex] == null) continue; + + foreach (var trap in suctionTraps[layerIndex]) + { + var suctionTrapArea = EmguContours.GetContourArea(trap); + if (suctionTrapArea < minimumSuctionArea) continue; + var rect = CvInvoke.BoundingRectangle(trap[0]); + AddIssue(new LayerIssue(this[layerIndex], LayerIssue.IssueType.SuctionCup, trap.ToArrayOfArray(), rect) { Area = suctionTrapArea }); + } } } }