diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-09-06 03:34:58 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-09-06 03:34:58 +0300 |
commit | 08a5797f36867c9b4c9b58da94e61bbea6258ae1 (patch) | |
tree | 51bdf0a133dbdeff923a8566f67fdce000a93006 | |
parent | 6a2a52ebcb3bcd98476d13f24d562383fc8756b4 (diff) |
v2.21.1v2.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
-rw-r--r-- | CHANGELOG.md | 10 | ||||
-rw-r--r-- | UVtools.Core/EmguCV/Contour.cs | 14 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerIssue.cs | 6 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerManager.cs | 4 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationDoubleExposure.cs | 2 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationLayerReHeight.cs | 34 | ||||
-rw-r--r-- | UVtools.Core/UVtools.Core.csproj | 2 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml | 2 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml | 31 | ||||
-rw-r--r-- | UVtools.WPF/MainWindow.Issues.cs | 25 | ||||
-rw-r--r-- | UVtools.WPF/MainWindow.LayerPreview.cs | 68 | ||||
-rw-r--r-- | UVtools.WPF/MainWindow.axaml | 45 | ||||
-rw-r--r-- | UVtools.WPF/MainWindow.axaml.cs | 9 | ||||
-rw-r--r-- | UVtools.WPF/UVtools.WPF.csproj | 2 | ||||
-rw-r--r-- | UVtools.WPF/UserSettings.cs | 73 | ||||
-rw-r--r-- | UVtools.WPF/Windows/SettingsWindow.axaml | 97 |
16 files changed, 381 insertions, 43 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index c921ace..40444c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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:** diff --git a/UVtools.Core/EmguCV/Contour.cs b/UVtools.Core/EmguCV/Contour.cs index 20d216e..291cad8 100644 --- a/UVtools.Core/EmguCV/Contour.cs +++ b/UVtools.Core/EmguCV/Contour.cs @@ -90,7 +90,7 @@ namespace UVtools.Core.EmguCV /// <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)); @@ -211,6 +211,18 @@ namespace UVtools.Core.EmguCV }*/ #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() diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs index 8b46e51..598231f 100644 --- a/UVtools.Core/Layer/LayerIssue.cs +++ b/UVtools.Core/Layer/LayerIssue.cs @@ -159,6 +159,12 @@ namespace UVtools.Core 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 /// </summary> diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 678c298..ba1ed48 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -1389,7 +1389,7 @@ namespace UVtools.Core 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)); @@ -1410,7 +1410,7 @@ namespace UVtools.Core 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)) diff --git a/UVtools.Core/Operations/OperationDoubleExposure.cs b/UVtools.Core/Operations/OperationDoubleExposure.cs index 5de3e0e..96068d9 100644 --- a/UVtools.Core/Operations/OperationDoubleExposure.cs +++ b/UVtools.Core/Operations/OperationDoubleExposure.cs @@ -45,7 +45,7 @@ namespace UVtools.Core.Operations "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}"; diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs index 44f153d..f9a86a6 100644 --- a/UVtools.Core/Operations/OperationLayerReHeight.cs +++ b/UVtools.Core/Operations/OperationLayerReHeight.cs @@ -38,6 +38,8 @@ namespace UVtools.Core.Operations #region Members private OperationLayerReHeightItem _selectedItem; private OperationLayerReHeightAntiAliasingType _antiAliasingType; + private decimal _bottomExposure; + private decimal _normalExposure; #endregion @@ -49,7 +51,8 @@ namespace UVtools.Core.Operations 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?"; @@ -87,7 +90,9 @@ namespace UVtools.Core.Operations 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; } @@ -115,6 +120,18 @@ namespace UVtools.Core.Operations 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) { @@ -158,6 +175,9 @@ namespace UVtools.Core.Operations { _selectedItem = Presets[0]; } + + if (_bottomExposure <= 0) _bottomExposure = (decimal)SlicerFile.BottomExposureTime; + if (_normalExposure <= 0) _normalExposure = (decimal)SlicerFile.ExposureTime; } #endregion @@ -297,8 +317,14 @@ namespace UVtools.Core.Operations 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; } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index fc4b636..268f850 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -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> diff --git a/UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml b/UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml index 56dd8ef..063ff3c 100644 --- a/UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolDoubleExposureControl.axaml @@ -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" diff --git a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml index 168ac75..6a886f6 100644 --- a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml @@ -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> diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs index 1308b0e..8acfc62 100644 --- a/UVtools.WPF/MainWindow.Issues.cs +++ b/UVtools.WPF/MainWindow.Issues.cs @@ -44,9 +44,17 @@ namespace UVtools.WPF } 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 @@ -526,7 +534,21 @@ namespace UVtools.WPF 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() @@ -561,6 +583,7 @@ namespace UVtools.WPF return new() { Enabled = enable, + StartLayerIndex = _resinTrapDetectionStartLayer, BinaryThreshold = Settings.Issues.ResinTrapBinaryThreshold, RequiredAreaToProcessCheck = Settings.Issues.ResinTrapRequiredAreaToProcessCheck, RequiredBlackPixelsToDrain = Settings.Issues.ResinTrapRequiredBlackPixelsToDrain, diff --git a/UVtools.WPF/MainWindow.LayerPreview.cs b/UVtools.WPF/MainWindow.LayerPreview.cs index fd53e1d..06097c1 100644 --- a/UVtools.WPF/MainWindow.LayerPreview.cs +++ b/UVtools.WPF/MainWindow.LayerPreview.cs @@ -26,6 +26,7 @@ using Emgu.CV.Structure; 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; @@ -74,7 +75,9 @@ namespace UVtools.WPF 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; @@ -107,7 +110,9 @@ namespace UVtools.WPF _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); @@ -370,6 +375,16 @@ namespace UVtools.WPF } } + public bool ShowLayerOutlineContourBoundary + { + get => _showLayerOutlineContourBoundary; + set + { + if (!RaiseAndSetIfChanged(ref _showLayerOutlineContourBoundary, value)) return; + ShowLayer(); + } + } + public bool ShowLayerOutlineHollowAreas { get => _showLayerOutlineHollowAreas; @@ -380,6 +395,16 @@ namespace UVtools.WPF } } + public bool ShowLayerOutlineCentroids + { + get => _showLayerOutlineCentroids; + set + { + if (!RaiseAndSetIfChanged(ref _showLayerOutlineCentroids, value)) return; + ShowLayer(); + } + } + public bool ShowLayerOutlineEdgeDetection { get => _showLayerOutlineEdgeDetection; @@ -983,6 +1008,21 @@ namespace UVtools.WPF 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); @@ -1009,6 +1049,34 @@ namespace UVtools.WPF } } + 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()); diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml index 6c98575..35fe48c 100644 --- a/UVtools.WPF/MainWindow.axaml +++ b/UVtools.WPF/MainWindow.axaml @@ -786,9 +786,39 @@ <CheckBox IsChecked="{Binding Settings.Issues.ComputeOverhangs}" Content="Overhangs"/> - <CheckBox - IsChecked="{Binding Settings.Issues.ComputeResinTraps}" - Content="Resin traps"/> + <StackPanel Orientation="Horizontal"> + <CheckBox + VerticalAlignment="Center" + IsChecked="{Binding Settings.Issues.ComputeResinTraps}" + Content="Resin traps"/> + + <NumericUpDown + VerticalAlignment="Center" + Margin="10,0,0,0" + ToolTip.Tip="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." + Minimum="0" + Maximum="{Binding SlicerFile.LastLayerIndex}" + Increment="1" + Width="110" + Value="{Binding ResinTrapDetectionStartLayer}"/> + + <Button + VerticalAlignment="Center" + Margin="2,0,0,0" + ToolTip.Tip="Set to the first normal layer" + Content="N" + Command="{Binding SetResinTrapDetectionStartLayer}" + CommandParameter="N"/> + <Button + VerticalAlignment="Center" + Margin="2,0,0,0" + ToolTip.Tip="Set to the current layer" + Content="C" + Command="{Binding SetResinTrapDetectionStartLayer}" + CommandParameter="C"/> + </StackPanel> + <CheckBox IsChecked="{Binding Settings.Issues.ComputeTouchingBounds}" Content="Touching bounds"/> @@ -1948,8 +1978,7 @@ Command="{Binding OpenContextMenu}" CommandParameter="LayerPreviewOutline" VerticalAlignment="Stretch" - Margin="1,0,0,0" - > + Margin="1,0,0,0"> <Button.ContextMenu> <ContextMenu Name="LayerPreviewOutlineContextMenu" PlacementMode="Bottom"> <CheckBox @@ -1959,9 +1988,15 @@ IsChecked="{Binding ShowLayerOutlineLayerBoundary}" Content="Layer boundary"/> <CheckBox + IsChecked="{Binding ShowLayerOutlineContourBoundary}" + Content="Blob boundary"/> + <CheckBox IsChecked="{Binding ShowLayerOutlineHollowAreas}" Content="Hollow areas"/> <CheckBox + IsChecked="{Binding ShowLayerOutlineCentroids}" + Content="Centroids"/> + <CheckBox IsChecked="{Binding ShowLayerOutlineEdgeDetection}" Content="Edge detection"> <CheckBox.IsEnabled> diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 72ef210..efe024e 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -712,7 +712,7 @@ namespace UVtools.WPF { ProcessFile(Path.Combine(App.ApplicationPath, About.DemoFile)); } - + DispatcherTimer.Run(() => { UpdateTitle(); @@ -967,6 +967,7 @@ namespace UVtools.WPF _actualLayer = 0; LayerCache.Clear(); + _resinTrapDetectionStartLayer = 0; VisibleThumbnailIndex = 0; @@ -1389,7 +1390,11 @@ namespace UVtools.WPF _showLayerImageRotated = mat.Height > mat.Width; } - if (SlicerFile.DisplayMirror != Enumerations.FlipDirection.None) + if (SlicerFile.DisplayMirror == Enumerations.FlipDirection.None) + { + _showLayerImageFlipped = false; + } + else { _showLayerImageFlipped = true; _showLayerImageFlippedHorizontally = SlicerFile.DisplayMirror is Enumerations.FlipDirection.Horizontally or Enumerations.FlipDirection.Both; diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index fb90318..56a2dd8 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ <PackageLicenseFile>LICENSE</PackageLicenseFile> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryType>Git</RepositoryType> - <Version>2.21.0</Version> + <Version>2.21.1</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs index b76150e..a1aa260 100644 --- a/UVtools.WPF/UserSettings.cs +++ b/UVtools.WPF/UserSettings.cs @@ -183,12 +183,19 @@ namespace UVtools.WPF private Color _volumeBoundsOutlineColor = new(255, 0, 255, 0); private byte _volumeBoundsOutlineThickness = 3; private bool _volumeBoundsOutline = true; - private Color _layerBoundsOutlineColor = new(255, 0, 255, 0); + private Color _layerBoundsOutlineColor = new(255, 45, 150, 45); private byte _layerBoundsOutlineThickness = 3; private bool _layerBoundsOutline = false; + private Color _contourBoundsOutlineColor = new(255, 50, 100, 50); + private byte _contourBoundsOutlineThickness = 2; + private bool _contourBoundsOutline = false; private Color _hollowOutlineColor = new(255, 255, 165, 0); private sbyte _hollowOutlineLineThickness = 5; private bool _hollowOutline = false; + private Color _centroidOutlineColor = new(255, 255, 0, 0); + private byte _centroidOutlineDiameter = 8; + private bool _centroidOutlineHollow = false; + private bool _centroidOutline = true; private Color _maskOutlineColor = new(255, 42, 157, 244); private sbyte _maskOutlineLineThickness = 10; private bool _maskClearRoiAfterSet = true; @@ -298,6 +305,35 @@ namespace UVtools.WPF set => RaiseAndSetIfChanged(ref _layerBoundsOutline, value); } + public Color ContourBoundsOutlineColor + { + get => _contourBoundsOutlineColor; + set + { + RaiseAndSetIfChanged(ref _contourBoundsOutlineColor, value); + RaisePropertyChanged(nameof(ContourBoundsOutlineBrush)); + } + } + + [XmlIgnore] + public SolidColorBrush ContourBoundsOutlineBrush + { + get => new(_contourBoundsOutlineColor.ToAvalonia()); + set => ContourBoundsOutlineColor = new Color(value); + } + + public byte ContourBoundsOutlineThickness + { + get => _contourBoundsOutlineThickness; + set => RaiseAndSetIfChanged(ref _contourBoundsOutlineThickness, value); + } + + public bool ContourBoundsOutline + { + get => _contourBoundsOutline; + set => RaiseAndSetIfChanged(ref _contourBoundsOutline, value); + } + public Color HollowOutlineColor { get => _hollowOutlineColor; @@ -327,6 +363,41 @@ namespace UVtools.WPF set => RaiseAndSetIfChanged(ref _hollowOutline, value); } + public Color CentroidOutlineColor + { + get => _centroidOutlineColor; + set + { + RaiseAndSetIfChanged(ref _centroidOutlineColor, value); + RaisePropertyChanged(nameof(CentroidOutlineBrush)); + } + } + + [XmlIgnore] + public SolidColorBrush CentroidOutlineBrush + { + get => new(_centroidOutlineColor.ToAvalonia()); + set => CentroidOutlineColor = new Color(value); + } + + public byte CentroidOutlineDiameter + { + get => _centroidOutlineDiameter; + set => RaiseAndSetIfChanged(ref _centroidOutlineDiameter, value); + } + + public bool CentroidOutlineHollow + { + get => _centroidOutlineHollow; + set => RaiseAndSetIfChanged(ref _centroidOutlineHollow, value); + } + + public bool CentroidOutline + { + get => _centroidOutline; + set => RaiseAndSetIfChanged(ref _centroidOutline, value); + } + public Color MaskOutlineColor { get => _maskOutlineColor; diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml index 6389676..325cf21 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -345,7 +345,7 @@ <StackPanel Orientation="Vertical"> <TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Layer colors"/> - <Grid Margin="10" RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,Auto,Auto,Auto,*"> + <Grid Margin="10" RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,Auto,Auto,Auto,*"> <!--Tooltip overlay--> <TextBlock Grid.Row="0" Grid.Column="0" @@ -417,16 +417,14 @@ VerticalAlignment="Center" Background="{Binding Settings.LayerPreview.LayerBoundsOutlineBrush}" Command="{Binding SelectColor}" - CommandParameter="LayerBoundsOutlineColor" - /> + CommandParameter="LayerBoundsOutlineColor"/> <NumericUpDown Grid.Row="4" Grid.Column="2" Margin="10,0,0,0" VerticalAlignment="Center" Minimum="1" Maximum="50" - Value="{Binding Settings.LayerPreview.LayerBoundsOutlineThickness}" - /> + Value="{Binding Settings.LayerPreview.LayerBoundsOutlineThickness}"/> <TextBlock Grid.Row="4" Grid.Column="3" Margin="5,0,0,0" VerticalAlignment="Center" @@ -436,15 +434,44 @@ HorizontalAlignment="Right" VerticalAlignment="Center" Content="Show by default" - IsChecked="{Binding Settings.LayerPreview.LayerBoundsOutline}" - /> + IsChecked="{Binding Settings.LayerPreview.LayerBoundsOutline}"/> + + <!--Blob boundary--> + <TextBlock Grid.Row="6" Grid.Column="0" + VerticalAlignment="Center" + Text="Blob boundary:"/> + <Button Grid.Row="6" Grid.Column="1" + Margin="10,0,0,0" + Padding="10" + BorderBrush="Black" + BorderThickness="2" + VerticalAlignment="Center" + Background="{Binding Settings.LayerPreview.ContourBoundsOutlineBrush}" + Command="{Binding SelectColor}" + CommandParameter="LayerBoundsOutlineColor"/> + <NumericUpDown Grid.Row="6" Grid.Column="2" + Margin="10,0,0,0" + VerticalAlignment="Center" + Minimum="1" + Maximum="50" + Value="{Binding Settings.LayerPreview.ContourBoundsOutlineThickness}"/> + <TextBlock Grid.Row="6" Grid.Column="3" + Margin="5,0,0,0" + VerticalAlignment="Center" + Text="Line thickness"/> + <CheckBox Grid.Row="6" Grid.Column="4" + Margin="10,0,0,0" + HorizontalAlignment="Right" + VerticalAlignment="Center" + Content="Show by default" + IsChecked="{Binding Settings.LayerPreview.ContourBoundsOutline}"/> <!--Hallow area boundary--> - <TextBlock Grid.Row="6" Grid.Column="0" + <TextBlock Grid.Row="8" Grid.Column="0" VerticalAlignment="Center" Text="Hollow area outline:"/> - <Button Grid.Row="6" Grid.Column="1" + <Button Grid.Row="8" Grid.Column="1" Margin="10,0,0,0" Padding="10" BorderBrush="Black" @@ -453,29 +480,65 @@ Background="{Binding Settings.LayerPreview.HollowOutlineBrush}" Command="{Binding SelectColor}" CommandParameter="HollowOutlineColor"/> - <NumericUpDown Grid.Row="6" Grid.Column="2" + <NumericUpDown Grid.Row="8" Grid.Column="2" Margin="10,0,0,0" VerticalAlignment="Center" Minimum="-1" Maximum="127" Value="{Binding Settings.LayerPreview.HollowOutlineLineThickness}"/> - <TextBlock Grid.Row="6" Grid.Column="3" + <TextBlock Grid.Row="8" Grid.Column="3" Margin="5,0,0,0" VerticalAlignment="Center" ToolTip.Tip="Set -1 to fill the area" Text="Line thickness"/> - <CheckBox Grid.Row="6" Grid.Column="4" + <CheckBox Grid.Row="8" Grid.Column="4" Margin="10,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center" Content="Show by default" IsChecked="{Binding Settings.LayerPreview.HollowOutline}"/> + <!--Blob boundary--> + <TextBlock Grid.Row="10" Grid.Column="0" + VerticalAlignment="Center" + Text="Centroids:"/> + <Button Grid.Row="10" Grid.Column="1" + Margin="10,0,0,0" + Padding="10" + BorderBrush="Black" + BorderThickness="2" + VerticalAlignment="Center" + Background="{Binding Settings.LayerPreview.CentroidOutlineBrush}" + Command="{Binding SelectColor}" + CommandParameter="LayerBoundsOutlineColor"/> + <NumericUpDown Grid.Row="10" Grid.Column="2" + Margin="10,0,0,0" + VerticalAlignment="Center" + Minimum="1" + Maximum="50" + Value="{Binding Settings.LayerPreview.CentroidOutlineDiameter}"/> + <TextBlock Grid.Row="10" Grid.Column="3" + Margin="5,0,0,0" + VerticalAlignment="Center" + Text="Diameter"/> + + <StackPanel + HorizontalAlignment="Right" + VerticalAlignment="Center" + Grid.Row="10" Grid.Column="3" Grid.ColumnSpan="2" Orientation="Horizontal" Spacing="10"> + <CheckBox Content="Hollow centroids" + IsChecked="{Binding Settings.LayerPreview.CentroidOutlineHollow}"/> + + <CheckBox Content="Show by default" + IsChecked="{Binding Settings.LayerPreview.CentroidOutline}"/> + </StackPanel> + + <!--Masks--> - <TextBlock Grid.Row="8" Grid.Column="0" + <TextBlock Grid.Row="12" Grid.Column="0" VerticalAlignment="Center" Text="Mask area outline:"/> - <Button Grid.Row="8" Grid.Column="1" + <Button Grid.Row="12" Grid.Column="1" Margin="10,0,0,0" Padding="10" BorderBrush="Black" @@ -484,18 +547,18 @@ Background="{Binding Settings.LayerPreview.MaskOutlineBrush}" Command="{Binding SelectColor}" CommandParameter="MaskOutlineColor"/> - <NumericUpDown Grid.Row="8" Grid.Column="2" + <NumericUpDown Grid.Row="12" Grid.Column="2" Margin="10,0,0,0" VerticalAlignment="Center" Minimum="-1" Maximum="127" Value="{Binding Settings.LayerPreview.MaskOutlineLineThickness}"/> - <TextBlock Grid.Row="8" Grid.Column="3" + <TextBlock Grid.Row="12" Grid.Column="3" Margin="5,0,0,0" VerticalAlignment="Center" ToolTip.Tip="Set -1 to fill the area" Text="Line thickness"/> - <CheckBox Grid.Row="8" Grid.Column="4" + <CheckBox Grid.Row="12" Grid.Column="4" Margin="10,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center" |