Skip to content

Commit

Permalink
v2.21.1
Browse files Browse the repository at this point in the history
- **(Add) Layer outline:**
   - Blob outline: Outline all separate blobs
   - Centroids: Draw a dot at the gemoetric center of a blob
- (Add) Adjust layer height: Allow to change exposure time on the dialog and inform that different layer thickness require different exposure times
- (Add) Resin trap detection: Allow to choose the starting layer index for resin trap detection which will also be considered a drain layer.
        Use this setting to bypass complicated rafts by selected the model first real layer (#221)
- (Improvement) Disable mirroed preview when loading a file that is not mirroed
  • Loading branch information
sn4k3 committed Sep 6, 2021
1 parent 6a2a52e commit 08a5797
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 43 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 06/09/2021 - v2.21.1

- **(Add) Layer outline:**
- Blob outline: Outline all separate blobs
- Centroids: Draw a dot at the gemoetric center of a blob
- (Add) Adjust layer height: Allow to change exposure time on the dialog and inform that different layer thickness require different exposure times
- (Add) Resin trap detection: Allow to choose the starting layer index for resin trap detection which will also be considered a drain layer.
Use this setting to bypass complicated rafts by selected the model first real layer (#221)
- (Improvement) Disable mirroed preview when loading a file that is not mirroed

## 03/09/2021 - v2.21.0

- **UI:**
Expand Down
14 changes: 13 additions & 1 deletion UVtools.Core/EmguCV/Contour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public double Perimeter
/// <summary>
/// Gets the centroid of the contour
/// </summary>
public Point Centroid => _centroid ??= Moments.M00 == 0 ? Point.Empty :
public Point Centroid => _centroid ??= Moments.M00 == 0 ? new Point(-1,-1) :
new Point(
(int)Math.Round(_moments.M10 / _moments.M00),
(int)Math.Round(_moments.M01 / _moments.M00));
Expand Down Expand Up @@ -211,6 +211,18 @@ public void FitCircle(Mat src, MCvScalar color, int thickness = 1, LineType line
}*/
#endregion

#region Static methods
public static Point GetCentroid(VectorOfPoint points)
{
if (points is null || points.Length == 0) return new Point(-1, -1);
using var moments = CvInvoke.Moments(points);
return moments.M00 == 0 ? new Point(-1, -1) :
new Point(
(int)Math.Round(moments.M10 / moments.M00),
(int)Math.Round(moments.M01 / moments.M00));
}
#endregion

#region Implementations

public IEnumerator<Point> GetEnumerator()
Expand Down
6 changes: 6 additions & 0 deletions UVtools.Core/Layer/LayerIssue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ public sealed class ResinTrapDetectionConfiguration
/// </summary>
public bool Enabled { get; set; } = true;

/// <summary>
/// Gets or sets the starting layer index for the detection which will also be considered a drain layer.
/// Use this setting to bypass complicated rafts by selected the model first real layer.
/// </summary>
public uint StartLayerIndex { get; set; }

/// <summary>
/// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
/// Set to 0 to disable this operation
Expand Down
4 changes: 2 additions & 2 deletions UVtools.Core/Layer/LayerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,7 @@ bool AddIssue(LayerIssue issue)
listHollowArea.Add(new LayerHollowArea(contours[i].ToArray(),
rect,
layer.Index == 0 ||
layer.Index <= resinTrapConfig.StartLayerIndex ||
layer.Index == LayerCount - 1 // First and Last layers, always drains
? LayerHollowArea.AreaType.Drain
: LayerHollowArea.AreaType.Unknown));
Expand All @@ -1410,7 +1410,7 @@ bool AddIssue(LayerIssue issue)

ResinTrapTree resinTrapTree = new();

for (uint layerIndex = 1; layerIndex < LayerCount - 1; layerIndex++) // First and Last layers, always drains
for (uint layerIndex = resinTrapConfig.StartLayerIndex+1; layerIndex < LayerCount - 1; layerIndex++) // First and Last layers, always drains
{
if (progress.Token.IsCancellationRequested) break;
if (!layerHollowAreas.TryGetValue(layerIndex, out var areas))
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/Operations/OperationDoubleExposure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class OperationDoubleExposure : Operation
"The double exposure method clones the selected layer range and print the same layer twice with different exposure times and strategies.\n" +
"Can be used to eliminate the elephant foot effect or to harden a layer in two steps.\n" +
"After this, do not apply any modification which reconstruct the z positions of the layers.\n" +
"Note: To eliminate the elephant foot effect, the use of wall dimming method recommended.";
"Note: To eliminate the elephant foot effect, the use of wall dimming method is recommended.";

public override string ConfirmationText =>
$"double exposure model layers {LayerIndexStart} through {LayerIndexEnd}";
Expand Down
34 changes: 30 additions & 4 deletions UVtools.Core/Operations/OperationLayerReHeight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public enum OperationLayerReHeightAntiAliasingType : byte
#region Members
private OperationLayerReHeightItem _selectedItem;
private OperationLayerReHeightAntiAliasingType _antiAliasingType;
private decimal _bottomExposure;
private decimal _normalExposure;

#endregion

Expand All @@ -49,7 +51,8 @@ public enum OperationLayerReHeightAntiAliasingType : byte
public override string Description =>
"Adjust the layer height of the model.\n\n" +
"Adjusting to values lower than current height will reduce layer lines, adjusting to values higher" +
" than current height will reduce model detail.\n\n" +
" than current height will reduce model detail.\n" +
"Different layer thickness will require different exposure times, adjust accordingly.\n\n" +
"Note: Using dedicated slicer software to re-slice will usually yeild better results.";
public override string ConfirmationText =>
$"adjust layer height to {SelectedItem.LayerHeight}mm?";
Expand Down Expand Up @@ -87,7 +90,9 @@ public override string ValidateInternally()

public override string ToString()
{
var result = $"[Layer Count: {SelectedItem.LayerCount}] [Layer Height: {SelectedItem.LayerHeight}]" + LayerRangeString;
var result = $"[Layer Count: {SelectedItem.LayerCount}] " +
$"[Layer Height: {SelectedItem.LayerHeight}] " +
$"[Exposure: {_bottomExposure}/{_normalExposure}s]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
Expand Down Expand Up @@ -115,6 +120,18 @@ public OperationLayerReHeightAntiAliasingType AntiAliasingType
set => RaiseAndSetIfChanged(ref _antiAliasingType, value);
}

public decimal BottomExposure
{
get => _bottomExposure;
set => RaiseAndSetIfChanged(ref _bottomExposure, Math.Round(value, 2));
}

public decimal NormalExposure
{
get => _normalExposure;
set => RaiseAndSetIfChanged(ref _normalExposure, Math.Round(value, 2));
}


public static OperationLayerReHeightItem[] GetItems(uint layerCount, decimal layerHeight)
{
Expand Down Expand Up @@ -158,6 +175,9 @@ public override void InitWithSlicerFile()
{
_selectedItem = Presets[0];
}

if (_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime;
if (_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime;
}

#endregion
Expand Down Expand Up @@ -297,8 +317,14 @@ protected override bool ExecuteInternally(OperationProgress progress)

progress.Token.ThrowIfCancellationRequested();

SlicerFile.LayerHeight = (float)SelectedItem.LayerHeight;
SlicerFile.LayerManager.Layers = layers;
SlicerFile.SuppressRebuildPropertiesWork(() =>
{
SlicerFile.LayerHeight = (float)SelectedItem.LayerHeight;
SlicerFile.BottomExposureTime = (float)_bottomExposure;
SlicerFile.ExposureTime = (float)_normalExposure;
SlicerFile.LayerManager.Layers = layers;
}, true);


return !progress.Token.IsCancellationRequested;
}
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/UVtools.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>2.21.0</Version>
<Version>2.21.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
Expand Down
2 changes: 1 addition & 1 deletion UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
IsEnabled="{Binding Operation.SecondLayerDifference}"
ToolTip.Tip="When the 'Exposure the difference between first and second layer for the second layer' is active,
this setting will further erode the layer producing a overlap of n pixel perimeters over the previous layer"
Text="Difference overlap margin:"/>
Text="Difference overlap by:"/>
<NumericUpDown
Grid.Row="0" Grid.Column="2"
VerticalAlignment="Center"
Expand Down
31 changes: 25 additions & 6 deletions UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,41 @@
<StackPanel Orientation="Vertical" Spacing="10">
<TextBlock VerticalAlignment="Center" Text="{Binding CurrentLayers}"/>

<Grid RowDefinitions="Auto,10,Auto"
ColumnDefinitions="Auto,10,Auto">
<Grid RowDefinitions="Auto,10,Auto,10,Auto"
ColumnDefinitions="Auto,10,Auto,5,Auto,20,Auto,10,Auto,5,Auto">

<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="Modifier:"/>
<ComboBox
Grid.Row="0" Grid.Column="2" Width="500"
Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="9"
Width="430"
SelectedItem="{Binding Operation.SelectedItem}"
Items="{Binding Operation.Presets}"
/>
Items="{Binding Operation.Presets}"/>

<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Text="Anti-Aliasing:"/>
<ComboBox Grid.Row="2" Grid.Column="2" Width="500"
<ComboBox Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="9"
Width="430"
IsEnabled="{Binding Operation.CanAntiAliasing}"
Items="{Binding Operation.AntiAliasingType, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
SelectedItem="{Binding Operation.AntiAliasingType, Converter={StaticResource FromValueDescriptionToEnumConverter}}">
</ComboBox>

<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Center" Text="Bottom exposure:"/>
<NumericUpDown Grid.Row="4" Grid.Column="2"
VerticalAlignment="Center"
Minimum="0.01"
Maximum="1000"
Increment="0.5"
Value="{Binding Operation.BottomExposure}"/>
<TextBlock Grid.Row="4" Grid.Column="4" VerticalAlignment="Center" Text="s"/>

<TextBlock Grid.Row="4" Grid.Column="6" VerticalAlignment="Center" Text="Normal exposure:"/>
<NumericUpDown Grid.Row="4" Grid.Column="8"
VerticalAlignment="Center"
Minimum="0.01"
Maximum="1000"
Increment="0.5"
Value="{Binding Operation.NormalExposure}"/>
<TextBlock Grid.Row="4" Grid.Column="10" VerticalAlignment="Center" Text="s"/>
</Grid>

</StackPanel>
Expand Down
25 changes: 24 additions & 1 deletion UVtools.WPF/MainWindow.Issues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,17 @@ public RangeObservableCollection<LayerIssue> Issues
}

public readonly List<LayerIssue> IgnoredIssues = new();
private uint _resinTrapDetectionStartLayer;

public bool IssueCanGoPrevious => Issues.Count > 0 && _issueSelectedIndex > 0;
public bool IssueCanGoNext => Issues.Count > 0 && _issueSelectedIndex < Issues.Count - 1;

public uint ResinTrapDetectionStartLayer
{
get => _resinTrapDetectionStartLayer;
set => RaiseAndSetIfChanged(ref _resinTrapDetectionStartLayer, value);
}

#endregion

#region Methods
Expand Down Expand Up @@ -526,7 +534,21 @@ public void IssuesClear(bool clearIgnored = true)
if(clearIgnored) IgnoredIssues.Clear();
}


public void SetResinTrapDetectionStartLayer(char which)
{
switch (which)
{
case 'N':
ResinTrapDetectionStartLayer = SlicerFile.FirstNormalLayer.Index;
break;
case 'C':
ResinTrapDetectionStartLayer = ActualLayer;
break;
}
}



public IslandDetectionConfiguration GetIslandDetectionConfiguration(bool enable)
{
return new()
Expand Down Expand Up @@ -561,6 +583,7 @@ public ResinTrapDetectionConfiguration GetResinTrapDetectionConfiguration(bool e
return new()
{
Enabled = enable,
StartLayerIndex = _resinTrapDetectionStartLayer,
BinaryThreshold = Settings.Issues.ResinTrapBinaryThreshold,
RequiredAreaToProcessCheck = Settings.Issues.ResinTrapRequiredAreaToProcessCheck,
RequiredBlackPixelsToDrain = Settings.Issues.ResinTrapRequiredBlackPixelsToDrain,
Expand Down
68 changes: 68 additions & 0 deletions UVtools.WPF/MainWindow.LayerPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Emgu.CV.Util;
using UVtools.AvaloniaControls;
using UVtools.Core;
using UVtools.Core.EmguCV;
using UVtools.Core.Extensions;
using UVtools.Core.PixelEditor;
using UVtools.WPF.Controls;
Expand Down Expand Up @@ -74,7 +75,9 @@ public enum ZoomToFitType : byte
private bool _isPixelEditorActive;
private bool _showLayerOutlinePrintVolumeBoundary;
private bool _showLayerOutlineLayerBoundary;
private bool _showLayerOutlineContourBoundary;
private bool _showLayerOutlineHollowAreas;
private bool _showLayerOutlineCentroids;
private bool _showLayerOutlineEdgeDetection;
private bool _showLayerOutlineDistanceDetection;
private bool _showLayerOutlineSkeletonize;
Expand Down Expand Up @@ -107,7 +110,9 @@ public void InitLayerPreview()
_showLayerImageDifference = Settings.LayerPreview.ShowLayerDifference;
_showLayerOutlinePrintVolumeBoundary = Settings.LayerPreview.VolumeBoundsOutline;
_showLayerOutlineLayerBoundary = Settings.LayerPreview.LayerBoundsOutline;
_showLayerOutlineContourBoundary = Settings.LayerPreview.ContourBoundsOutline;
_showLayerOutlineHollowAreas = Settings.LayerPreview.HollowOutline;
_showLayerOutlineCentroids = Settings.LayerPreview.CentroidOutline;

LayerImageBox.ZoomLevels = new AdvancedImageBox.ZoomLevelCollection(AppSettings.ZoomLevels);

Expand Down Expand Up @@ -370,6 +375,16 @@ public bool ShowLayerOutlineLayerBoundary
}
}

public bool ShowLayerOutlineContourBoundary
{
get => _showLayerOutlineContourBoundary;
set
{
if (!RaiseAndSetIfChanged(ref _showLayerOutlineContourBoundary, value)) return;
ShowLayer();
}
}

public bool ShowLayerOutlineHollowAreas
{
get => _showLayerOutlineHollowAreas;
Expand All @@ -380,6 +395,16 @@ public bool ShowLayerOutlineHollowAreas
}
}

public bool ShowLayerOutlineCentroids
{
get => _showLayerOutlineCentroids;
set
{
if (!RaiseAndSetIfChanged(ref _showLayerOutlineCentroids, value)) return;
ShowLayer();
}
}

public bool ShowLayerOutlineEdgeDetection
{
get => _showLayerOutlineEdgeDetection;
Expand Down Expand Up @@ -983,6 +1008,21 @@ unsafe void ShowLayer()
Settings.LayerPreview.LayerBoundsOutlineThickness);
}

if (_showLayerOutlineContourBoundary)
{
for (int i = 0; i < LayerCache.LayerContours.Size; i++)
{
if ((int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 2) == -1 &&
(int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 3) != -1) continue;
CvInvoke.Rectangle(LayerCache.ImageBgr, CvInvoke.BoundingRectangle(LayerCache.LayerContours[i]),
new MCvScalar(
Settings.LayerPreview.ContourBoundsOutlineColor.B,
Settings.LayerPreview.ContourBoundsOutlineColor.G,
Settings.LayerPreview.ContourBoundsOutlineColor.R),
Settings.LayerPreview.ContourBoundsOutlineThickness);
}
}

if (_showLayerOutlineHollowAreas)
{
//CvInvoke.Threshold(ActualLayerImage, grayscale, 1, 255, ThresholdType.Binary);
Expand All @@ -1009,6 +1049,34 @@ unsafe void ShowLayer()
}
}

if (_showLayerOutlineCentroids)
{
for (int i = 0; i < LayerCache.LayerContours.Size; i++)
{
if ((int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 2) == -1 &&
(int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 3) != -1)
{
if (Settings.LayerPreview.CentroidOutlineHollow)
{
CvInvoke.Circle(LayerCache.ImageBgr, Contour.GetCentroid(LayerCache.LayerContours[i]),
Settings.LayerPreview.CentroidOutlineDiameter / 2, new MCvScalar(
Settings.LayerPreview.HollowOutlineColor.B,
Settings.LayerPreview.HollowOutlineColor.G,
Settings.LayerPreview.HollowOutlineColor.R), 1, LineType.AntiAlias);
}
}
else
{
CvInvoke.Circle(LayerCache.ImageBgr, Contour.GetCentroid(LayerCache.LayerContours[i]),
Settings.LayerPreview.CentroidOutlineDiameter / 2, new MCvScalar(
Settings.LayerPreview.CentroidOutlineColor.B,
Settings.LayerPreview.CentroidOutlineColor.G,
Settings.LayerPreview.CentroidOutlineColor.R), -1, LineType.AntiAlias);
}

}
}

if (_maskPoints is not null && _maskPoints.Count > 0)
{
using var vec = new VectorOfVectorOfPoint(_maskPoints.ToArray());
Expand Down
Loading

0 comments on commit 08a5797

Please sign in to comment.