mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-09 01:52:32 +02:00
Add UI for repair suction cups
This commit is contained in:
@@ -210,7 +210,7 @@ namespace UVtools.Core.EmguCV
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool CheckContoursIntersect(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2)
|
||||
public static bool ContoursIntersect(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2)
|
||||
{
|
||||
var contour1Rect = CvInvoke.BoundingRectangle(contour1[0]);
|
||||
var contour2Rect = CvInvoke.BoundingRectangle(contour2[0]);
|
||||
@@ -226,17 +226,17 @@ namespace UVtools.Core.EmguCV
|
||||
|
||||
var totalRect = new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
||||
|
||||
using Mat contour1Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
using Mat contour2Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
using Mat overlapCheck = EmguExtensions.InitMat(totalRect.Size);
|
||||
|
||||
using var contour1Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
using var contour2Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
using var overlapCheck = EmguExtensions.InitMat(totalRect.Size);
|
||||
|
||||
var inverseOffset = new Point(minX * -1, minY * -1);
|
||||
CvInvoke.DrawContours(contour1Mat, contour1, -1, EmguExtensions.WhiteColor, -1, Emgu.CV.CvEnum.LineType.EightConnected, null, int.MaxValue, inverseOffset);
|
||||
CvInvoke.DrawContours(contour2Mat, contour2, -1, EmguExtensions.WhiteColor, -1, Emgu.CV.CvEnum.LineType.EightConnected, null, int.MaxValue, inverseOffset);
|
||||
|
||||
CvInvoke.BitwiseAnd(contour1Mat, contour2Mat, overlapCheck);
|
||||
|
||||
return (CvInvoke.CountNonZero(overlapCheck) > 0);
|
||||
return CvInvoke.CountNonZero(overlapCheck) > 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ namespace UVtools.Core.Operations
|
||||
private bool _repairIslands = true;
|
||||
private bool _repairResinTraps = true;
|
||||
private bool _removeEmptyLayers = true;
|
||||
/* Suction Cup repair disabled by default, needs UI component to toggle */
|
||||
private bool _repairSuctionCups = false;
|
||||
private bool _repairSuctionCups;
|
||||
private ushort _removeIslandsBelowEqualPixelCount = 5;
|
||||
private ushort _removeIslandsRecursiveIterations = 4;
|
||||
private ushort _attachIslandsBelowLayers = 2;
|
||||
private byte _resinTrapsOverlapBy = 5;
|
||||
private byte _suctionCupsVentHole = 16;
|
||||
private uint _gapClosingIterations = 1;
|
||||
private uint _noiseRemovalIterations;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace UVtools.Core.Operations
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (!RepairIslands && !RemoveEmptyLayers && !RepairResinTraps)
|
||||
if (!_repairIslands && !_repairResinTraps && !_repairSuctionCups && !_removeEmptyLayers)
|
||||
{
|
||||
sb.AppendLine("You must select at least one repair operation.");
|
||||
}
|
||||
@@ -92,6 +92,12 @@ namespace UVtools.Core.Operations
|
||||
set => RaiseAndSetIfChanged(ref _repairResinTraps, value);
|
||||
}
|
||||
|
||||
public bool RepairSuctionCups
|
||||
{
|
||||
get => _repairSuctionCups;
|
||||
set => RaiseAndSetIfChanged(ref _repairSuctionCups, value);
|
||||
}
|
||||
|
||||
public bool RemoveEmptyLayers
|
||||
{
|
||||
get => _removeEmptyLayers;
|
||||
@@ -122,6 +128,12 @@ namespace UVtools.Core.Operations
|
||||
set => RaiseAndSetIfChanged(ref _resinTrapsOverlapBy, value);
|
||||
}
|
||||
|
||||
public byte SuctionCupsVentHole
|
||||
{
|
||||
get => _suctionCupsVentHole;
|
||||
set => RaiseAndSetIfChanged(ref _suctionCupsVentHole, value);
|
||||
}
|
||||
|
||||
public uint GapClosingIterations
|
||||
{
|
||||
get => _gapClosingIterations;
|
||||
@@ -193,9 +205,9 @@ namespace UVtools.Core.Operations
|
||||
Parallel.ForEach(issuesGroup, CoreSettings.ParallelOptions, group =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
Layer layer = SlicerFile[group.Key];
|
||||
Mat image = layer.LayerMat;
|
||||
Span<byte> bytes = image.GetDataSpan<byte>();
|
||||
var layer = SlicerFile[group.Key];
|
||||
var image = layer.LayerMat;
|
||||
var bytes = image.GetDataByteSpan();
|
||||
foreach (var issue in group)
|
||||
{
|
||||
foreach (var issuePixel in issue.Pixels)
|
||||
@@ -382,7 +394,7 @@ namespace UVtools.Core.Operations
|
||||
if (_repairIslands && (_gapClosingIterations > 0 || _noiseRemovalIterations > 0))
|
||||
{
|
||||
initImage();
|
||||
using Mat kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3),
|
||||
using var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3),
|
||||
new Point(-1, -1));
|
||||
if (_gapClosingIterations > 0)
|
||||
{
|
||||
@@ -408,13 +420,12 @@ namespace UVtools.Core.Operations
|
||||
}
|
||||
|
||||
|
||||
if (_repairSuctionCups)
|
||||
if (_repairSuctionCups && Issues is not null)
|
||||
{
|
||||
/* build out parent/child relationships between all detected suction cups */
|
||||
|
||||
ConcurrentBag<LayerIssue> bottomSuctionIssues = new();
|
||||
var bottomSuctionIssues = new ConcurrentBag<LayerIssue>();
|
||||
|
||||
var layerCount = SlicerFile.LayerCount;
|
||||
Parallel.ForEach(Issues.Where(issue => issue.Type == LayerIssue.IssueType.SuctionCup), issue => {
|
||||
|
||||
if (issue.LayerIndex == 0)
|
||||
@@ -422,11 +433,12 @@ namespace UVtools.Core.Operations
|
||||
bottomSuctionIssues.Add(issue);
|
||||
return;
|
||||
}
|
||||
|
||||
bool overlapFound = false;
|
||||
|
||||
foreach(var candidate in Issues.Where(candidate => candidate.LayerIndex == issue.LayerIndex - 1 && candidate.Type == LayerIssue.IssueType.SuctionCup))
|
||||
{
|
||||
if (EmguContours.CheckContoursIntersect(new VectorOfVectorOfPoint(issue.Contours), new VectorOfVectorOfPoint(candidate.Contours))) {
|
||||
if (EmguContours.ContoursIntersect(new VectorOfVectorOfPoint(issue.Contours), new VectorOfVectorOfPoint(candidate.Contours))) {
|
||||
overlapFound = true;
|
||||
break;
|
||||
}
|
||||
@@ -439,52 +451,42 @@ namespace UVtools.Core.Operations
|
||||
|
||||
(bool canDrill, Point location) GetDrillLocation(LayerIssue issue, int diameter)
|
||||
{
|
||||
var centroid = EmguCV.EmguContour.GetCentroid(new VectorOfPoint(issue.Contours[0]));
|
||||
using Mat circleCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using Mat contourMat = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
using Mat overlapCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size);
|
||||
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);
|
||||
|
||||
CvInvoke.DrawContours(contourMat, new VectorOfVectorOfPoint(issue.Contours), -1, EmguExtensions.WhiteColor, -1, Emgu.CV.CvEnum.LineType.EightConnected, null, int.MaxValue, inverseOffset);
|
||||
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);
|
||||
|
||||
if (CvInvoke.CountNonZero(overlapCheck) > 0)
|
||||
{
|
||||
|
||||
/* 5px centroid is inside layer! drill baby drill */
|
||||
return (true,centroid);
|
||||
|
||||
} else
|
||||
{
|
||||
/* centroid is not inside the actual contour, no drill */
|
||||
return (false, new Point());
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
List<PixelOperation> drillOps = new List<PixelOperation>();
|
||||
var suctionReliefSize = (int)Math.Max(SlicerFile.PpmmMax * .5, 15);
|
||||
|
||||
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, suctionReliefSize);
|
||||
if (drillPoint.canDrill)
|
||||
{
|
||||
drillOps.Add(new PixelDrainHole(issue.LayerIndex, drillPoint.location, (byte)suctionReliefSize));
|
||||
}
|
||||
var drillPoint = GetDrillLocation(issue, _suctionCupsVentHole);
|
||||
if (!drillPoint.canDrill) continue;
|
||||
drillOps.Add(new PixelDrainHole(issue.LayerIndex, drillPoint.location, _suctionCupsVentHole));
|
||||
}
|
||||
|
||||
SlicerFile.LayerManager.DrawModifications(drillOps, progress);
|
||||
|
||||
}
|
||||
|
||||
if (_removeEmptyLayers)
|
||||
{
|
||||
List<uint> removeLayers = new();
|
||||
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
|
||||
var removeLayers = new List<uint>();
|
||||
for (var layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
|
||||
{
|
||||
if (SlicerFile[layerIndex].NonZeroPixelCount == 0)
|
||||
{
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace UVtools.Core.PixelEditor
|
||||
{
|
||||
public class PixelDrainHole : PixelOperation
|
||||
{
|
||||
private byte _diameter = 50;
|
||||
private ushort _diameter = 50;
|
||||
public override PixelOperationType OperationType => PixelOperationType.DrainHole;
|
||||
|
||||
public byte Diameter
|
||||
public ushort Diameter
|
||||
{
|
||||
get => _diameter;
|
||||
set => RaiseAndSetIfChanged(ref _diameter, value);
|
||||
@@ -22,7 +22,7 @@ namespace UVtools.Core.PixelEditor
|
||||
|
||||
public PixelDrainHole(){ _pixelBrightness = 0; }
|
||||
|
||||
public PixelDrainHole(uint layerIndex, Point location, byte diameter) : base(layerIndex, location)
|
||||
public PixelDrainHole(uint layerIndex, Point location, ushort diameter) : base(layerIndex, location)
|
||||
{
|
||||
Diameter = diameter;
|
||||
Size = new Size(diameter, diameter);
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
<CheckBox
|
||||
IsChecked="{Binding Operation.RepairIslands}"
|
||||
ToolTip.Tip="If enabled, repair will first attempt to eliminate islands smaller than the pixel area removal threshold, and then runs the “gap closure” technique."
|
||||
Content="Repair islands"
|
||||
/>
|
||||
Content="Repair islands"/>
|
||||
|
||||
|
||||
<!-- Repair resin traps -->
|
||||
@@ -21,8 +20,13 @@
|
||||
IsChecked="{Binding Operation.RepairResinTraps}"
|
||||
ToolTip.Tip="If enabled, repair will fill black pixels found within a resin trap with white pixels.
|
||||

Hollow areas will become solid."
|
||||
Content="Repair resin traps"
|
||||
/>
|
||||
Content="Repair resin traps"/>
|
||||
|
||||
<!-- Repair resin traps -->
|
||||
<CheckBox
|
||||
IsChecked="{Binding Operation.RepairSuctionCups}"
|
||||
ToolTip.Tip="If enabled, repair will drill suction cup layers with a vertical hole at the specified size."
|
||||
Content="Repair suction cups"/>
|
||||
|
||||
|
||||
<!-- Remove empty layers -->
|
||||
@@ -30,12 +34,10 @@
|
||||
IsChecked="{Binding Operation.RemoveEmptyLayers}"
|
||||
ToolTip.Tip="If enabled, repair will remove all layers with no white pixels.
|
||||

The model will be recalculated to ensure the correct Z height is maintained."
|
||||
Content="Remove empty layers"
|
||||
/>
|
||||
Content="Remove empty layers"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid ColumnDefinitions="Auto,10,190,5,Auto"
|
||||
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto">
|
||||
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,10,190,5,Auto">
|
||||
|
||||
<!-- Remove islands equal or smaller than -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
@@ -137,6 +139,22 @@
|
||||

Use this field when you have aggressive blur on model and a visible margin between white pixels and the resin trap highlight area.
|
||||

(0 = Fill the found area without overlap nearby pixels)"
|
||||
Value="{Binding Operation.ResinTrapsOverlapBy}"/>
|
||||
|
||||
<!-- Suction cup vent hole -->
|
||||
<TextBlock Grid.Row="8" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
IsEnabled="{Binding Operation.RepairSuctionCups}"
|
||||
ToolTip.Tip="Hole diameter to drill the layers with"
|
||||
Text="Suction cup vent hole diameter:"/>
|
||||
|
||||
<NumericUpDown Grid.Row="8" Grid.Column="2"
|
||||
Classes="ValueLabel ValueLabel_px"
|
||||
Increment="1"
|
||||
Minimum="4"
|
||||
Maximum="255"
|
||||
IsEnabled="{Binding Operation.RepairSuctionCups}"
|
||||
ToolTip.Tip="Hole diameter to drill the layers with"
|
||||
Value="{Binding Operation.SuctionCupsVentHole}"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
@@ -24,11 +24,13 @@ namespace UVtools.WPF.Controls.Tools
|
||||
{
|
||||
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
|
||||
RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps,
|
||||
RepairSuctionCups = UserSettings.Instance.LayerRepair.RepairSuctionCups,
|
||||
RemoveEmptyLayers = UserSettings.Instance.LayerRepair.RemoveEmptyLayers,
|
||||
RemoveIslandsBelowEqualPixelCount = UserSettings.Instance.LayerRepair.RemoveIslandsBelowEqualPixels,
|
||||
RemoveIslandsRecursiveIterations = UserSettings.Instance.LayerRepair.RemoveIslandsRecursiveIterations,
|
||||
AttachIslandsBelowLayers = UserSettings.Instance.LayerRepair.AttachIslandsBelowLayers,
|
||||
ResinTrapsOverlapBy = UserSettings.Instance.LayerRepair.ResinTrapsOverlapBy,
|
||||
SuctionCupsVentHole = UserSettings.Instance.LayerRepair.SuctionCupsVentHole,
|
||||
GapClosingIterations = UserSettings.Instance.LayerRepair.ClosingIterations,
|
||||
NoiseRemovalIterations = UserSettings.Instance.LayerRepair.OpeningIterations,
|
||||
};
|
||||
@@ -37,11 +39,13 @@ namespace UVtools.WPF.Controls.Tools
|
||||
{
|
||||
Operation.RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands;
|
||||
Operation.RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps;
|
||||
Operation.RepairSuctionCups = UserSettings.Instance.LayerRepair.RepairSuctionCups;
|
||||
Operation.RemoveEmptyLayers = UserSettings.Instance.LayerRepair.RemoveEmptyLayers;
|
||||
Operation.RemoveIslandsBelowEqualPixelCount = UserSettings.Instance.LayerRepair.RemoveIslandsBelowEqualPixels;
|
||||
Operation.RemoveIslandsRecursiveIterations = UserSettings.Instance.LayerRepair.RemoveIslandsRecursiveIterations;
|
||||
Operation.AttachIslandsBelowLayers = UserSettings.Instance.LayerRepair.AttachIslandsBelowLayers;
|
||||
Operation.ResinTrapsOverlapBy = UserSettings.Instance.LayerRepair.ResinTrapsOverlapBy;
|
||||
Operation.SuctionCupsVentHole = UserSettings.Instance.LayerRepair.SuctionCupsVentHole;
|
||||
Operation.GapClosingIterations = UserSettings.Instance.LayerRepair.ClosingIterations;
|
||||
Operation.NoiseRemovalIterations = UserSettings.Instance.LayerRepair.OpeningIterations;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ using UVtools.Core.EmguCV;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Operations;
|
||||
using UVtools.WPF.Extensions;
|
||||
using static UVtools.Core.LayerIssue;
|
||||
using Brushes = Avalonia.Media.Brushes;
|
||||
|
||||
namespace UVtools.WPF
|
||||
@@ -87,18 +86,18 @@ namespace UVtools.WPF
|
||||
|
||||
public List<LayerIssue> GetOverlappingIssues(LayerIssue targetIssue, int indexOffset)
|
||||
{
|
||||
List<LayerIssue> retValue = new();
|
||||
var retValue = new List<LayerIssue>();
|
||||
|
||||
var targetLayerIndex = targetIssue.LayerIndex + indexOffset;
|
||||
if (targetLayerIndex > SlicerFile.LayerCount - 1 || targetLayerIndex < 0) return retValue;
|
||||
|
||||
foreach (var candidate in Issues.Where(candidate => candidate.LayerIndex == targetLayerIndex && candidate.Type == LayerIssue.IssueType.SuctionCup))
|
||||
{
|
||||
if (EmguContours.CheckContoursIntersect(new VectorOfVectorOfPoint(targetIssue.Contours), new VectorOfVectorOfPoint(candidate.Contours)))
|
||||
{
|
||||
retValue.Add(candidate);
|
||||
break;
|
||||
}
|
||||
using var vec1 = new VectorOfVectorOfPoint(targetIssue.Contours);
|
||||
using var vec2 = new VectorOfVectorOfPoint(candidate.Contours);
|
||||
if (!EmguContours.ContoursIntersect(vec1, vec2)) continue;
|
||||
retValue.Add(candidate);
|
||||
break;
|
||||
}
|
||||
|
||||
return retValue;
|
||||
@@ -242,8 +241,8 @@ namespace UVtools.WPF
|
||||
{
|
||||
if (issueRemoveList.Contains(issue)) continue;
|
||||
|
||||
Stack<LayerIssue> upDirection = new Stack<LayerIssue>();
|
||||
Stack<LayerIssue> downDirection = new Stack<LayerIssue>();
|
||||
var upDirection = new Stack<LayerIssue>();
|
||||
var downDirection = new Stack<LayerIssue>();
|
||||
upDirection.Push(issue);
|
||||
downDirection.Push(issue);
|
||||
|
||||
|
||||
@@ -788,7 +788,7 @@ namespace UVtools.WPF
|
||||
private byte _resinTrapRequiredAreaToProcessCheck = 17;
|
||||
private byte _resinTrapRequiredBlackPixelsToDrain = 10;
|
||||
private byte _resinTrapMaximumPixelBrightnessToDrain = 30;
|
||||
private uint _suctionCupRequiredAreaToConsider = 5000;
|
||||
private uint _suctionCupRequiredAreaToConsider = 10000;
|
||||
private byte _touchingBoundMinimumPixelBrightness = 127;
|
||||
private byte _touchingBoundMarginLeft = 5;
|
||||
private byte _touchingBoundMarginTop = 5;
|
||||
@@ -1219,11 +1219,13 @@ namespace UVtools.WPF
|
||||
{
|
||||
private bool _repairIslands = true;
|
||||
private bool _repairResinTraps = true;
|
||||
private bool _repairSuctionCups;
|
||||
private bool _removeEmptyLayers = true;
|
||||
private ushort _removeIslandsBelowEqualPixels = 5;
|
||||
private ushort _removeIslandsRecursiveIterations = 4;
|
||||
private ushort _attachIslandsBelowLayers = 2;
|
||||
private byte _resinTrapsOverlapBy = 0;
|
||||
private byte _suctionCupsVentHole = 16;
|
||||
private byte _closingIterations = 2;
|
||||
private byte _openingIterations = 0;
|
||||
|
||||
@@ -1239,6 +1241,12 @@ namespace UVtools.WPF
|
||||
set => RaiseAndSetIfChanged(ref _repairResinTraps, value);
|
||||
}
|
||||
|
||||
public bool RepairSuctionCups
|
||||
{
|
||||
get => _repairSuctionCups;
|
||||
set => RaiseAndSetIfChanged(ref _repairSuctionCups, value);
|
||||
}
|
||||
|
||||
public bool RemoveEmptyLayers
|
||||
{
|
||||
get => _removeEmptyLayers;
|
||||
@@ -1269,6 +1277,12 @@ namespace UVtools.WPF
|
||||
set => RaiseAndSetIfChanged(ref _resinTrapsOverlapBy, value);
|
||||
}
|
||||
|
||||
public byte SuctionCupsVentHole
|
||||
{
|
||||
get => _suctionCupsVentHole;
|
||||
set => RaiseAndSetIfChanged(ref _suctionCupsVentHole, value);
|
||||
}
|
||||
|
||||
public byte ClosingIterations
|
||||
{
|
||||
get => _closingIterations;
|
||||
|
||||
@@ -1596,11 +1596,13 @@
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Default values"/>
|
||||
|
||||
<CheckBox IsChecked="{Binding Settings.LayerRepair.RepairIslands}"
|
||||
Margin="10,0" Content="Attempt to repair islands by default"/>
|
||||
Margin="10,0" Content="Attempt to repair islands by default"/>
|
||||
<CheckBox IsChecked="{Binding Settings.LayerRepair.RepairResinTraps}"
|
||||
Margin="10,0" Content="Attempt to repair resin traps by default"/>
|
||||
Margin="10,0" Content="Attempt to repair resin traps by default"/>
|
||||
<CheckBox IsChecked="{Binding Settings.LayerRepair.RepairSuctionCups}"
|
||||
Margin="10,0" Content="Attempt to repair suction cups by default"/>
|
||||
<CheckBox IsChecked="{Binding Settings.LayerRepair.RemoveEmptyLayers}"
|
||||
Margin="10,0" Content="Remove empty layers by default"/>
|
||||
Margin="10,0" Content="Remove empty layers by default"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="10,0" Spacing="10">
|
||||
<NumericUpDown
|
||||
@@ -1640,6 +1642,15 @@
|
||||
<TextBlock VerticalAlignment="Center" Text="Resin traps: Overlap and expand resin trap area by this value in pixels (0 = Disabled)"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="10,0" Spacing="10">
|
||||
<NumericUpDown
|
||||
Value="{Binding Settings.LayerRepair.SuctionCupsVentHole}"
|
||||
Width="70"
|
||||
Minimum="4"
|
||||
Maximum="255"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="Suction cups: Hole diameter to drill the layers with"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="10,0" Spacing="10">
|
||||
<NumericUpDown
|
||||
Value="{Binding Settings.LayerRepair.ClosingIterations}"
|
||||
|
||||
Reference in New Issue
Block a user