* (Add) Tool - Raft relief: Relief raft by adding holes in between to reduce FEP suction, save resin and easier to remove the prints.
This commit is contained in:
Tiago Conceição
2020-12-08 03:30:02 +00:00
parent 5c5670f0b1
commit de3d15f4c9
10 changed files with 350 additions and 4 deletions
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## 04/11/2020 - v1.4.0
* (Add) Tool - Raft relief: Relief raft by adding holes in between to reduce FEP suction, save resin and easier to remove the prints.
## 04/11/2020 - v1.3.5
* (Add) Pixel Dimming: Chamfer - Allow the number of walls pixels to be gradually varied as the operation progresses from the starting layer to the ending layer (#106)
+100 -2
View File
@@ -540,8 +540,6 @@ namespace UVtools.Core
out var maxIteration
);
Debug.WriteLine($"Steps: {iterationSteps}, Max iteration: {maxIteration}");
Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1,
//new ParallelOptions {MaxDegreeOfParallelism = 1},
layerIndex =>
@@ -709,6 +707,106 @@ namespace UVtools.Core
progress.Token.ThrowIfCancellationRequested();
}*/
public void RaftRelief(OperationRaftRelief operation, OperationProgress progress)
{
const uint minLength = 5;
if (progress is null) progress = new OperationProgress();
//progress.Reset(operation.ProgressAction);
Mat supportsMat = null;
uint firstSupportLayerIndex = 0;
for (; firstSupportLayerIndex < Count; firstSupportLayerIndex++)
{
progress.Reset("Tracing raft", Count, firstSupportLayerIndex);
if (progress.Token.IsCancellationRequested) return;
supportsMat = operation.GetRoiOrDefault(this[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 20, 100, 30, 5, 200);
if (circles.Length >= minLength) break;
supportsMat.Dispose();
supportsMat = null;
}
if (supportsMat is null) return;
Mat patternMat = null;
switch (operation.ReliefType)
{
case OperationRaftRelief.RaftReliefTypes.Relief:
patternMat = EmguExtensions.InitMat(supportsMat.Size);
int shapeSize = operation.HoleDiameter + operation.HoleSpacing;
using (var shape = EmguExtensions.InitMat(new Size(shapeSize, shapeSize)))
{
int center = operation.HoleDiameter / 2;
int centerTwo = operation.HoleDiameter + operation.HoleSpacing + operation.HoleDiameter / 2;
int radius = center;
CvInvoke.Circle(shape, new Point(shapeSize / 2, shapeSize / 2), radius, EmguExtensions.WhiteByte, -1);
CvInvoke.Circle(shape, new Point(0, 0), radius / 2, EmguExtensions.WhiteByte, -1);
CvInvoke.Circle(shape, new Point(0, shapeSize), radius / 2, EmguExtensions.WhiteByte, -1);
CvInvoke.Circle(shape, new Point(shapeSize, 0), radius / 2, EmguExtensions.WhiteByte, -1);
CvInvoke.Circle(shape, new Point(shapeSize, shapeSize), radius / 2, EmguExtensions.WhiteByte, -1);
//shape.Save("D:\\shape.png");
CvInvoke.Repeat(shape, supportsMat.Height / shape.Height + 1, supportsMat.Width / shape.Width + 1, patternMat);
patternMat = new Mat(patternMat, new Rectangle(0, 0, supportsMat.Width, supportsMat.Height));
}
break;
case OperationRaftRelief.RaftReliefTypes.Decimate:
if (operation.DilateIterations <= 0) break;
CvInvoke.Dilate(supportsMat, supportsMat,
CvInvoke.GetStructuringElement(ElementShape.Ellipse, new Size(3, 3), new Point(-1, -1)),
new Point(-1, -1), operation.DilateIterations, BorderType.Reflect101, new MCvScalar());
break;
}
progress.Reset(operation.ProgressAction, firstSupportLayerIndex);
Parallel.For(0, firstSupportLayerIndex, layerIndex =>
{
using (Mat dst = this[layerIndex].LayerMat)
{
var target = operation.GetRoiOrDefault(dst);
switch (operation.ReliefType)
{
case OperationRaftRelief.RaftReliefTypes.Relief:
using (Mat mask = new Mat())
{
CvInvoke.Subtract(target, supportsMat, mask);
//target.CopyTo(mask);
CvInvoke.Erode(mask, mask,
CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3),
new Point(-1, -1)),
new Point(-1, -1), operation.WallMargin, BorderType.Reflect101, new MCvScalar());
CvInvoke.Subtract(target, patternMat, target, mask);
}
break;
case OperationRaftRelief.RaftReliefTypes.Decimate:
supportsMat.CopyTo(target);
break;
}
this[layerIndex].LayerMat = dst;
}
lock (progress.Mutex)
{
progress++;
}
});
supportsMat.Dispose();
patternMat?.Dispose();
}
public void Arithmetic(OperationArithmetic operation, OperationProgress progress = null)
{
if (!operation.IsValid) return;
@@ -0,0 +1,116 @@
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
namespace UVtools.Core.Operations
{
[Serializable]
public class OperationRaftRelief : Operation
{
private RaftReliefTypes _reliefType = RaftReliefTypes.Relief;
private byte _dilateIterations = 10;
private byte _wallMargin = 10;
private byte _holeDiameter = 50;
private byte _holeSpacing = 20;
public override string Title => "Raft relief";
public override string Description =>
"Relief raft by adding holes in between to reduce FEP suction, save resin and easier to remove the prints.";
public override string ConfirmationText =>
$"relief the raft";
public override string ProgressTitle =>
$"Relieving raft";
public override string ProgressAction => "Relieved layers";
public override Enumerations.LayerRangeSelection StartLayerRangeSelection =>
Enumerations.LayerRangeSelection.None;
public OperationRaftRelief()
{
}
public override string ToString()
{
var result = $"[{_reliefType}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
public enum RaftReliefTypes : byte
{
Relief,
Decimate
}
public static Array RaftReliefItems => Enum.GetValues(typeof(RaftReliefTypes));
public RaftReliefTypes ReliefType
{
get => _reliefType;
set => RaiseAndSetIfChanged(ref _reliefType, value);
}
public byte DilateIterations
{
get => _dilateIterations;
set => RaiseAndSetIfChanged(ref _dilateIterations, value);
}
public byte WallMargin
{
get => _wallMargin;
set => RaiseAndSetIfChanged(ref _wallMargin, value);
}
public byte HoleDiameter
{
get => _holeDiameter;
set => RaiseAndSetIfChanged(ref _holeDiameter, value);
}
public byte HoleSpacing
{
get => _holeSpacing;
set => RaiseAndSetIfChanged(ref _holeSpacing, value);
}
#region Equality
protected bool Equals(OperationRaftRelief other)
{
return _reliefType == other._reliefType && _dilateIterations == other._dilateIterations && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing && _wallMargin == other._wallMargin;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((OperationRaftRelief) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) _reliefType;
hashCode = (hashCode * 397) ^ _dilateIterations.GetHashCode();
hashCode = (hashCode * 397) ^ _holeDiameter.GetHashCode();
hashCode = (hashCode * 397) ^ _holeSpacing.GetHashCode();
hashCode = (hashCode * 397) ^ _wallMargin.GetHashCode();
return hashCode;
}
}
#endregion
}
}
+1 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
<Version>1.3.5</Version>
<Version>1.4.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

@@ -0,0 +1,95 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="UVtools.WPF.Controls.Tools.ToolRaftReliefControl">
<Grid
ColumnDefinitions="Auto,10,Auto,5,Auto"
RowDefinitions="Auto,10,Auto,Auto,10,Auto,10,Auto"
>
<TextBlock Text="Relief type:" VerticalAlignment="Center"/>
<ComboBox
Name="ReliefType"
Grid.Column="2"
Width="100"
SelectedItem="{Binding Operation.ReliefType}"
Items="{Binding Operation.RaftReliefItems}"/>
<TextBlock
Grid.Row="2"
ToolTip.Tip="Raft will be replaced by the present supports and then dilated by this value.
&#x0a;Use large numbers with tiny supports for best adhesion."
Text="Dilate supports by:" VerticalAlignment="Center"
IsVisible="{Binding #ReliefType.SelectedIndex}"
/>
<NumericUpDown Grid.Row="2" Grid.Column="2"
Width="100"
Minimum="0"
Maximum="255"
Value="{Binding Operation.DilateIterations}"
IsVisible="{Binding #ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="2" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding #ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="3"
Text="Wall margin:" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"
/>
<NumericUpDown Grid.Row="3" Grid.Column="2"
Width="100"
Minimum="1"
Maximum="255"
Value="{Binding Operation.WallMargin}"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="3" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="5"
Text="Hole diameter:" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"
/>
<NumericUpDown Grid.Row="5" Grid.Column="2"
Width="100"
Minimum="10"
Maximum="255"
Value="{Binding Operation.HoleDiameter}"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="5" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="7"
Text="Hole spacing:" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"
/>
<NumericUpDown Grid.Row="7" Grid.Column="2"
Width="100"
Minimum="10"
Maximum="255"
Value="{Binding Operation.HoleSpacing}"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
<TextBlock
Grid.Row="7" Grid.Column="4"
Text="px" VerticalAlignment="Center"
IsVisible="{Binding !#ReliefType.SelectedIndex}"/>
</Grid>
</UserControl>
@@ -0,0 +1,21 @@
using Avalonia.Markup.Xaml;
using UVtools.Core.Operations;
namespace UVtools.WPF.Controls.Tools
{
public class ToolRaftReliefControl : ToolControl
{
public OperationRaftRelief Operation => BaseOperation as OperationRaftRelief;
public ToolRaftReliefControl()
{
this.InitializeComponent();
BaseOperation = new OperationRaftRelief();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
+11
View File
@@ -119,6 +119,14 @@ namespace UVtools.WPF
}
},
new MenuItem
{
Tag = new OperationRaftRelief(),
Icon = new Avalonia.Controls.Image
{
Source = new Bitmap(App.GetAsset("/Assets/Icons/dot-circle-16x16.png"))
}
},
new MenuItem
{
Tag = new OperationThreshold(),
Icon = new Avalonia.Controls.Image
@@ -1268,6 +1276,9 @@ namespace UVtools.WPF
case OperationMorph operation:
SlicerFile.LayerManager.Morph(operation, BorderType.Default, new MCvScalar(), ProgressWindow.RestartProgress(operation.CanCancel));
break;
case OperationRaftRelief operation:
SlicerFile.LayerManager.RaftRelief(operation, ProgressWindow.RestartProgress(operation.CanCancel));
break;
case OperationThreshold operation:
SlicerFile.LayerManager.ThresholdPixels(operation, ProgressWindow.RestartProgress(operation.CanCancel));
break;
@@ -30,6 +30,7 @@ namespace UVtools.WPF.Structures
//[XmlElement(typeof(OperationLayerRemove))]
//[XmlElement(typeof(OperationMask))]
[XmlElement(typeof(OperationMorph))]
[XmlElement(typeof(OperationRaftRelief))]
//[XmlElement(typeof(OperationMove))]
//[XmlElement(typeof(OperationPattern))]
[XmlElement(typeof(OperationPixelDimming))]
+1 -1
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>1.3.5</Version>
<Version>1.4.0</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">