mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-09 01:52:32 +02:00
v2.6.1
* (Add) Setting: Auto repair layers and issues on file load * (Improvement) When ComputeIssuesOnLoad is enabled and issues are detected it will switch the view to the Issues tab * **(Improvement) Raft Relief:** * Add parameter "Mask layer index": Defines the mask layer to use and ignore the white blobs on the raft * Increase the automatic support detection allowance on more odd shapes * Prevent layer 0 to be used as a mask, if so it will quit * If the ignored layer number are set and equal or larger than mask layer index it will quit * Fix progress count when using ignored layers * Change supports dilate kernel from Elipse to Rectangle for a better coverage of the pad * Change the default values for a more conservative values * (Fix) When both ComputeIssuesOnLoad and ComputeIssuesOnClickTab are enabled, clicking the issues tab will rescan for issues * (Fix) Tools: Set a default profile insn't working * (Fix) Redoing the last operation was not recovering the custom ROI on the operation
This commit is contained in:
+18
-2
@@ -1,13 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## 25/02/2021 - v2.6.0
|
||||
## 03/03/2021 - v2.6.1
|
||||
|
||||
* (Add) Setting: Auto repair layers and issues on file load
|
||||
* (Improvement) When ComputeIssuesOnLoad is enabled and issues are detected it will switch the view to the Issues tab
|
||||
* **(Improvement) Raft Relief:**
|
||||
* Add parameter "Mask layer index": Defines the mask layer to use and ignore the white blobs on the raft
|
||||
* Increase the automatic support detection allowance on more odd shapes
|
||||
* Prevent layer 0 to be used as a mask, if so it will quit
|
||||
* If the ignored layer number are set and equal or larger than mask layer index it will quit
|
||||
* Fix progress count when using ignored layers
|
||||
* Change supports dilate kernel from Elipse to Rectangle for a better coverage of the pad
|
||||
* Change the default values for a more conservative values
|
||||
* (Fix) When both ComputeIssuesOnLoad and ComputeIssuesOnClickTab are enabled, clicking the issues tab will rescan for issues
|
||||
* (Fix) Tools: Set a default profile insn't working
|
||||
* (Fix) Redoing the last operation was not recovering the custom ROI on the operation
|
||||
|
||||
## 02/03/2021 - v2.6.0
|
||||
|
||||
* (Add) File format: Zcode (Uniz IBEE)
|
||||
* (Add) PrusaSlicer Printer: Uniz IBEE
|
||||
* (Add) Extract: Output an "Layer.ini" file containing per layer data and include the Configuration.ini for Zip file formats
|
||||
* (Improvement) Zip: Increase the GCode parsing performance
|
||||
* (Fix) File formats: Wasn't set bottom / light off delay per individual layer on generic formats, defaulting every layer to 0
|
||||
* (Fix) Edit print paramenters: When changing bottom layer count, layers didnt update thier properties
|
||||
* (Fix) Edit print parameters: When changing bottom layer count, layers didnt update thier properties
|
||||
|
||||
## 25/02/2021 - v2.5.1
|
||||
|
||||
|
||||
+2
-1
@@ -48,4 +48,5 @@
|
||||
* Andrew Griffiths
|
||||
* Abhinav Sinha
|
||||
* Randy Savell
|
||||
* Steve Clynes
|
||||
* Steve Clynes
|
||||
* Nicholas Taylor
|
||||
@@ -32,6 +32,6 @@ namespace UVtools.Core.Extensions
|
||||
return (T)Activator.CreateInstance(type);
|
||||
}
|
||||
|
||||
public static byte ToByte(this bool value) => value ? 1 : 0;
|
||||
public static byte ToByte(this bool value) => (byte)(value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,7 +1085,7 @@ namespace UVtools.Core.FileFormats
|
||||
get => HeaderSettings.ProjectorType > 0;
|
||||
set
|
||||
{
|
||||
HeaderSettings.ProjectorType = value ? 1 : 0;
|
||||
HeaderSettings.ProjectorType = value ? 1u : 0;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace UVtools.Core.FileFormats
|
||||
set
|
||||
{
|
||||
HeaderSettings.ProjectType = value ? "LCD_mirror" : "Normal";
|
||||
HeaderSettings.Mirror = value ? 1 : 0;
|
||||
HeaderSettings.Mirror = (byte)(value ? 1 : 0);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ namespace UVtools.Core.FileFormats
|
||||
get => HeaderSettings.ProjectorType > 0;
|
||||
set
|
||||
{
|
||||
HeaderSettings.ProjectorType = value ? 1 : 0;
|
||||
HeaderSettings.ProjectorType = value ? 1u : 0;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +775,7 @@ namespace UVtools.Core.FileFormats
|
||||
get => HeaderSettings.ProjectorType > 0;
|
||||
set
|
||||
{
|
||||
HeaderSettings.ProjectorType = value ? 1 : 0;
|
||||
HeaderSettings.ProjectorType = value ? 1u : 0;
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace UVtools.Core.FileFormats
|
||||
for (int i = 0; i < imageLength; i++)
|
||||
{
|
||||
//color = color <= 127 ? 0 : 255; // Sanitize no AA
|
||||
byte thisColor = spanMat[i] <= 127 ? 0 : 255; // Sanitize no AA
|
||||
byte thisColor = spanMat[i] <= 127 ? byte.MinValue : byte.MaxValue; // Sanitize no AA
|
||||
if (thisColor != color)
|
||||
{
|
||||
AddRep();
|
||||
|
||||
@@ -1318,7 +1318,7 @@ namespace UVtools.Core.FileFormats
|
||||
break;
|
||||
}
|
||||
|
||||
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1;
|
||||
HeaderSettings.PerLayerOverride = (byte)(LayerManager.AllLayersHaveGlobalParameters ? 0 : 1);
|
||||
|
||||
|
||||
uint currentOffset = FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings);
|
||||
@@ -1522,7 +1522,7 @@ namespace UVtools.Core.FileFormats
|
||||
FileFullPath = filePath;
|
||||
}
|
||||
|
||||
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1;
|
||||
HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1u;
|
||||
|
||||
using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
|
||||
outputFile.Seek(FileMarkSettings.HeaderAddress, SeekOrigin.Begin);
|
||||
|
||||
@@ -379,7 +379,7 @@ namespace UVtools.Core.FileFormats
|
||||
|
||||
public override byte AntiAliasing
|
||||
{
|
||||
get => (byte)PrinterSettings.GammaCorrection > 0 ? 4 : 1;
|
||||
get => (byte)(PrinterSettings.GammaCorrection > 0 ? 4 : 1);
|
||||
set => PrinterSettings.GammaCorrection = value > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -771,7 +771,7 @@ namespace UVtools.Core.FileFormats
|
||||
byte[] data = Encoding.UTF8.GetBytes(line);
|
||||
List<byte> padData = new(64) {0, 1, 0};
|
||||
padData.AddRange(data);
|
||||
|
||||
|
||||
if (padData.Count > 64)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Too long gcode line to encrypt, got: {padData.Count} bytes while expecting less than 64 bytes");
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
using System;
|
||||
/*
|
||||
* 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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
using System;
|
||||
/*
|
||||
* 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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.Text;
|
||||
|
||||
namespace UVtools.Core.Objects
|
||||
{
|
||||
public class GCodeBuilder : BindableBase
|
||||
{
|
||||
#region Enums
|
||||
|
||||
public enum GCodeTimeUnits : byte
|
||||
{
|
||||
Milliseconds,
|
||||
Seconds
|
||||
}
|
||||
|
||||
public enum GCodeSpeedUnits : byte
|
||||
{
|
||||
MillimetersPerSecond,
|
||||
MillimetersPerMinute,
|
||||
CentimetersPerMinute,
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Members
|
||||
private readonly StringBuilder _gcode = new();
|
||||
|
||||
private bool _appendComma = true;
|
||||
private bool _appendComment = true;
|
||||
private bool _useAbsoluteCommands = true;
|
||||
private GCodeTimeUnits _gCodeTimeUnit = GCodeTimeUnits.Milliseconds;
|
||||
private GCodeSpeedUnits _gCodeSpeedUnit = GCodeSpeedUnits.MillimetersPerMinute;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public bool UseAbsoluteCommands
|
||||
{
|
||||
get => _useAbsoluteCommands;
|
||||
set => RaiseAndSetIfChanged(ref _useAbsoluteCommands, value);
|
||||
}
|
||||
|
||||
public GCodeTimeUnits GCodeTimeUnit
|
||||
{
|
||||
get => _gCodeTimeUnit;
|
||||
set => RaiseAndSetIfChanged(ref _gCodeTimeUnit, value);
|
||||
}
|
||||
|
||||
public GCodeSpeedUnits GCodeSpeedUnit
|
||||
{
|
||||
get => _gCodeSpeedUnit;
|
||||
set => RaiseAndSetIfChanged(ref _gCodeSpeedUnit, value);
|
||||
}
|
||||
|
||||
public bool AppendComma
|
||||
{
|
||||
get => _appendComma;
|
||||
set => RaiseAndSetIfChanged(ref _appendComma, value);
|
||||
}
|
||||
|
||||
public bool AppendComment
|
||||
{
|
||||
get => _appendComment;
|
||||
set => RaiseAndSetIfChanged(ref _appendComment, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region StringBuilder
|
||||
public void AppendLine() => _gcode.AppendLine();
|
||||
public void AppendLine(string line) => _gcode.AppendLine(line);
|
||||
public void AppendFormat(string format, params object?[] args) => _gcode.AppendFormat(format, args);
|
||||
public void Clear() => _gcode.Clear();
|
||||
public override string ToString() => _gcode.ToString();
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public string FormatGCodeLine(string line, string comment)
|
||||
{
|
||||
if (_appendComma || _appendComment)
|
||||
line += ';';
|
||||
if (_appendComment)
|
||||
line += comment;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
public void AppendUnitsMmG21()
|
||||
{
|
||||
AppendLine(FormatGCodeLine("G21", "Set units to be mm"));
|
||||
}
|
||||
|
||||
public void AppendPositioningType()
|
||||
{
|
||||
if (_useAbsoluteCommands)
|
||||
{
|
||||
AppendLine(FormatGCodeLine("G90", "Absolute positioning"));
|
||||
}
|
||||
else
|
||||
{
|
||||
AppendLine(FormatGCodeLine("G91", "Partial positioning"));
|
||||
}
|
||||
}
|
||||
|
||||
public void AppendEnableMotors()
|
||||
{
|
||||
AppendLine(FormatGCodeLine("M17", "Enable motors"));
|
||||
}
|
||||
|
||||
public void AppendDisableMotors()
|
||||
{
|
||||
AppendLine(FormatGCodeLine("M18", "Disable motors"));
|
||||
}
|
||||
|
||||
public void AppendTurnMotors(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
AppendEnableMotors();
|
||||
else
|
||||
AppendDisableMotors();
|
||||
}
|
||||
|
||||
public void AppendHomeZG28()
|
||||
{
|
||||
AppendLine(FormatGCodeLine("G28 Z0", "Home Z"));
|
||||
}
|
||||
|
||||
|
||||
public void AppendMoveG0(float z, float feedRate)
|
||||
{
|
||||
AppendLine(FormatGCodeLine($"G0 Z{z} F{feedRate}", "Z Move"));
|
||||
}
|
||||
|
||||
public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate)
|
||||
{
|
||||
AppendLine(FormatGCodeLine($"G0 Z{upZ} F{upFeedRate}", "Z Lift"));
|
||||
AppendLine(FormatGCodeLine($"G0 Z{downZ} F{downFeedRate}", "Retract to layer height"));
|
||||
}
|
||||
|
||||
public void AppendWaitG4(float time)
|
||||
{
|
||||
AppendLine(FormatGCodeLine($"G4 P{time}", "Delay"));
|
||||
}
|
||||
|
||||
public void AppendTurnLightM106(ushort value)
|
||||
{
|
||||
AppendLine(FormatGCodeLine($"M106 S{value}", "Turn LED"));
|
||||
}
|
||||
|
||||
public void AppendLightOffM106() => AppendTurnLightM106(0);
|
||||
public void AppendLightFullM106() => AppendTurnLightM106(255);
|
||||
|
||||
public void AppendExposure(ushort value, float time)
|
||||
{
|
||||
if (time <= 0) return;
|
||||
|
||||
AppendTurnLightM106(value);
|
||||
AppendWaitG4(time);
|
||||
AppendLightOffM106();
|
||||
}
|
||||
|
||||
public void AppendShowImageM6054(string name)
|
||||
{
|
||||
AppendLine(FormatGCodeLine($"M6054 \"{name}\"","Show image"));
|
||||
}
|
||||
|
||||
public void AppendLineComment(string comment)
|
||||
{
|
||||
AppendLine($";{comment}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -31,12 +31,14 @@ namespace UVtools.Core.Operations
|
||||
|
||||
#region Members
|
||||
private RaftReliefTypes _reliefType = RaftReliefTypes.Relief;
|
||||
private uint _maskLayerIndex;
|
||||
private byte _ignoreFirstLayers;
|
||||
private byte _brightness;
|
||||
private byte _dilateIterations = 10;
|
||||
private byte _wallMargin = 20;
|
||||
private byte _holeDiameter = 50;
|
||||
private byte _holeSpacing = 20;
|
||||
private byte _dilateIterations = 15;// +/- 1.5mm radius
|
||||
private byte _wallMargin = 40; // +/- 2mm
|
||||
private byte _holeDiameter = 80; // +/- 4mm
|
||||
private byte _holeSpacing = 40; // +/- 2mm
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
@@ -57,7 +59,7 @@ namespace UVtools.Core.Operations
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var result = $"[{_reliefType}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
|
||||
var result = $"[{_reliefType}] [Mask layer: {_maskLayerIndex}] [Ignore: {_ignoreFirstLayers}] [B: {_brightness}] [Dilate: {_dilateIterations}] [Wall margin: {_wallMargin}] [Hole diameter: {_holeDiameter}] [Hole spacing: {_holeSpacing}]";
|
||||
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
|
||||
return result;
|
||||
}
|
||||
@@ -90,6 +92,12 @@ namespace UVtools.Core.Operations
|
||||
public bool IsDimming => _reliefType == RaftReliefTypes.Dimming;
|
||||
public bool IsDecimate => _reliefType == RaftReliefTypes.Decimate;
|
||||
|
||||
public uint MaskLayerIndex
|
||||
{
|
||||
get => _maskLayerIndex;
|
||||
set => RaiseAndSetIfChanged(ref _maskLayerIndex, value);
|
||||
}
|
||||
|
||||
public byte IgnoreFirstLayers
|
||||
{
|
||||
get => _ignoreFirstLayers;
|
||||
@@ -137,7 +145,7 @@ namespace UVtools.Core.Operations
|
||||
|
||||
protected bool Equals(OperationRaftRelief other)
|
||||
{
|
||||
return _reliefType == other._reliefType && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing;
|
||||
return _reliefType == other._reliefType && _maskLayerIndex == other._maskLayerIndex && _ignoreFirstLayers == other._ignoreFirstLayers && _brightness == other._brightness && _dilateIterations == other._dilateIterations && _wallMargin == other._wallMargin && _holeDiameter == other._holeDiameter && _holeSpacing == other._holeSpacing;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@@ -150,7 +158,7 @@ namespace UVtools.Core.Operations
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine((int) _reliefType, _ignoreFirstLayers, _brightness, _dilateIterations, _wallMargin, _holeDiameter, _holeSpacing);
|
||||
return HashCode.Combine((int) _reliefType, _maskLayerIndex, _ignoreFirstLayers, _brightness, _dilateIterations, _wallMargin, _holeDiameter, _holeSpacing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -160,33 +168,43 @@ namespace UVtools.Core.Operations
|
||||
protected override bool ExecuteInternally(OperationProgress progress)
|
||||
{
|
||||
progress.ItemCount = 0;
|
||||
const uint minLength = 5;
|
||||
const uint minSupportsRequired = 5;
|
||||
const uint maxLayerCount = 1000;
|
||||
|
||||
Mat supportsMat = null;
|
||||
var anchor = new Point(-1, -1);
|
||||
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
|
||||
|
||||
|
||||
uint firstSupportLayerIndex = 0;
|
||||
for (; firstSupportLayerIndex < SlicerFile.LayerCount; firstSupportLayerIndex++)
|
||||
uint firstSupportLayerIndex = _maskLayerIndex;
|
||||
if (firstSupportLayerIndex <= 0)
|
||||
{
|
||||
uint layerCount = Math.Min(SlicerFile.LayerCount, maxLayerCount);
|
||||
progress.Reset("Tracing raft", layerCount, firstSupportLayerIndex);
|
||||
for (; firstSupportLayerIndex < layerCount; firstSupportLayerIndex++)
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return false;
|
||||
progress++;
|
||||
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
|
||||
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 5, 80, 35, 5, 200);
|
||||
if (circles.Length >= minSupportsRequired) break;
|
||||
|
||||
supportsMat.Dispose();
|
||||
supportsMat = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
progress.Reset("Tracing raft", SlicerFile.LayerCount, firstSupportLayerIndex);
|
||||
if (progress.Token.IsCancellationRequested) return false;
|
||||
supportsMat = GetRoiOrDefault(SlicerFile[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 false;
|
||||
if (supportsMat is null || /*firstSupportLayerIndex == 0 ||*/ _ignoreFirstLayers >= firstSupportLayerIndex) return false;
|
||||
Mat patternMat = null;
|
||||
|
||||
if (DilateIterations > 0)
|
||||
{
|
||||
CvInvoke.Dilate(supportsMat, supportsMat,
|
||||
CvInvoke.GetStructuringElement(ElementShape.Ellipse, new Size(3, 3), new Point(-1, -1)),
|
||||
CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1)),
|
||||
new Point(-1, -1), DilateIterations, BorderType.Reflect101, new MCvScalar());
|
||||
}
|
||||
|
||||
@@ -220,8 +238,8 @@ namespace UVtools.Core.Operations
|
||||
break;
|
||||
}
|
||||
|
||||
progress.Reset(ProgressAction, firstSupportLayerIndex);
|
||||
Parallel.For(IgnoreFirstLayers, firstSupportLayerIndex, layerIndex =>
|
||||
progress.Reset(ProgressAction, firstSupportLayerIndex - _ignoreFirstLayers);
|
||||
Parallel.For(_ignoreFirstLayers, firstSupportLayerIndex, layerIndex =>
|
||||
{
|
||||
if (progress.Token.IsCancellationRequested) return;
|
||||
using (Mat dst = SlicerFile[layerIndex].LayerMat)
|
||||
@@ -238,7 +256,8 @@ namespace UVtools.Core.Operations
|
||||
CvInvoke.Erode(mask, mask, kernel, anchor, operation.WallMargin, BorderType.Reflect101, new MCvScalar());
|
||||
CvInvoke.Subtract(target, patternMat, target, mask);*/
|
||||
|
||||
CvInvoke.Erode(target, mask, kernel, anchor, WallMargin, BorderType.Reflect101, default);
|
||||
CvInvoke.Erode(target, mask, kernel, anchor, WallMargin, BorderType.Reflect101,
|
||||
default);
|
||||
CvInvoke.Subtract(mask, supportsMat, mask);
|
||||
CvInvoke.Subtract(target, patternMat, target, mask);
|
||||
}
|
||||
|
||||
@@ -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.6.0</Version>
|
||||
<Version>2.6.1</Version>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<Grid
|
||||
ColumnDefinitions="Auto,10,150,5,Auto"
|
||||
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
|
||||
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
|
||||
>
|
||||
|
||||
<TextBlock Text="Relief type:" VerticalAlignment="Center"/>
|
||||
@@ -18,107 +18,128 @@
|
||||
SelectedItem="{Binding Operation.ReliefType}"
|
||||
Items="{Binding Operation.RaftReliefItems}"/>
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Text="Ignore first:" VerticalAlignment="Center"/>
|
||||
ToolTip.Tip="Defines the mask layer to use and ignore it white blobs on the raft.
|
||||

Often this is the first layer where raft ends and supports starts.
|
||||

Use '0' to auto detect the mask layer, otherwise if it fails or if you have multiple rafts with different heights
|
||||
you must manually input the layer index of the last raft where it ends and supports starts."
|
||||
Text="Mask layer index:" VerticalAlignment="Center"/>
|
||||
|
||||
<NumericUpDown Grid.Row="2" Grid.Column="2"
|
||||
Minimum="0"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.IgnoreFirstLayers}"/>
|
||||
<TextBlock
|
||||
Grid.Row="2" Grid.Column="4"
|
||||
Text="layer(s)" VerticalAlignment="Center"/>
|
||||
Maximum="{Binding SlicerFile.LastLayerIndex}"
|
||||
Value="{Binding Operation.MaskLayerIndex}"/>
|
||||
<StackPanel Grid.Row="2" Grid.Column="4"
|
||||
Orientation="Horizontal" Spacing="5">
|
||||
|
||||
<Button Content="Use current layer" Command="{Binding UseCurrentLayerAsMask}" />
|
||||
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="(0 = Auto detect)" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Text="Ignore first:" VerticalAlignment="Center"/>
|
||||
|
||||
<NumericUpDown Grid.Row="4" Grid.Column="2"
|
||||
Minimum="0"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.IgnoreFirstLayers}"/>
|
||||
<TextBlock
|
||||
Grid.Row="4" Grid.Column="4"
|
||||
Text="layer(s)" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"
|
||||
Text="Pixel brightness:" VerticalAlignment="Center"/>
|
||||
|
||||
<NumericUpDown Grid.Row="4" Grid.Column="2"
|
||||
<NumericUpDown Grid.Row="6" Grid.Column="2"
|
||||
Minimum="0"
|
||||
Maximum="255"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"
|
||||
Value="{Binding Operation.Brightness}"/>
|
||||
<TextBlock
|
||||
Grid.Row="4" Grid.Column="4"
|
||||
Grid.Row="6" Grid.Column="4"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"
|
||||
Text="{Binding Operation.BrightnessPercent, StringFormat=\{0:0.00\}%}" VerticalAlignment="Center"/>
|
||||
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="8"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"
|
||||
Text="Supports margin:" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Row="8"
|
||||
IsVisible="{Binding Operation.IsDecimate}"
|
||||
ToolTip.Tip="Raft will be replaced by the present supports and then dilated by this value to thicken the supports and increase the adhesion.
|
||||

Use large numbers with tiny supports for best adhesion."
|
||||
Text="Dilate supports by:" VerticalAlignment="Center"/>
|
||||
|
||||
<NumericUpDown Grid.Row="6" Grid.Column="2"
|
||||
<NumericUpDown Grid.Row="8" Grid.Column="2"
|
||||
Minimum="0"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.DilateIterations}"/>
|
||||
<TextBlock
|
||||
Grid.Row="6" Grid.Column="4"
|
||||
Grid.Row="8" Grid.Column="4"
|
||||
Text="px" VerticalAlignment="Center"/>
|
||||
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Row="10"
|
||||
Text="Wall margin:" VerticalAlignment="Center"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"
|
||||
/>
|
||||
|
||||
<NumericUpDown Grid.Row="8" Grid.Column="2"
|
||||
<NumericUpDown Grid.Row="10" Grid.Column="2"
|
||||
Minimum="1"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.WallMargin}"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"/>
|
||||
<TextBlock
|
||||
Grid.Row="8" Grid.Column="4"
|
||||
Grid.Row="10" Grid.Column="4"
|
||||
Text="px" VerticalAlignment="Center"
|
||||
IsVisible="{Binding !Operation.IsDecimate}"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Text="Hole diameter:" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"
|
||||
/>
|
||||
|
||||
<NumericUpDown Grid.Row="10" Grid.Column="2"
|
||||
Minimum="10"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.HoleDiameter}"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
<TextBlock
|
||||
Grid.Row="10" Grid.Column="4"
|
||||
Text="px" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Text="Hole spacing:" VerticalAlignment="Center"
|
||||
Text="Hole diameter:" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"
|
||||
/>
|
||||
|
||||
<NumericUpDown Grid.Row="12" Grid.Column="2"
|
||||
Minimum="10"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.HoleSpacing}"
|
||||
Value="{Binding Operation.HoleDiameter}"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
<TextBlock
|
||||
Grid.Row="12" Grid.Column="4"
|
||||
Text="px" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="14"
|
||||
Text="Hole spacing:" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"
|
||||
/>
|
||||
|
||||
<NumericUpDown Grid.Row="14" Grid.Column="2"
|
||||
Minimum="10"
|
||||
Maximum="255"
|
||||
Value="{Binding Operation.HoleSpacing}"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
<TextBlock
|
||||
Grid.Row="14" Grid.Column="4"
|
||||
Text="px" VerticalAlignment="Center"
|
||||
IsVisible="{Binding Operation.IsRelief}"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -17,5 +17,10 @@ namespace UVtools.WPF.Controls.Tools
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void UseCurrentLayerAsMask()
|
||||
{
|
||||
Operation.MaskLayerIndex = App.MainWindow.ActualLayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,7 @@ namespace UVtools.WPF.Controls.Tools
|
||||
public ToolRepairLayersControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
BaseOperation = new OperationRepairLayers(SlicerFile)
|
||||
{
|
||||
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
|
||||
RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps,
|
||||
RemoveEmptyLayers = UserSettings.Instance.LayerRepair.RemoveEmptyLayers,
|
||||
RemoveIslandsBelowEqualPixelCount = UserSettings.Instance.LayerRepair.RemoveIslandsBelowEqualPixels,
|
||||
RemoveIslandsRecursiveIterations = UserSettings.Instance.LayerRepair.RemoveIslandsRecursiveIterations,
|
||||
GapClosingIterations = UserSettings.Instance.LayerRepair.ClosingIterations,
|
||||
NoiseRemovalIterations = UserSettings.Instance.LayerRepair.OpeningIterations,
|
||||
};
|
||||
BaseOperation = GetOperationRepairLayers();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
@@ -28,6 +19,17 @@ namespace UVtools.WPF.Controls.Tools
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public static OperationRepairLayers GetOperationRepairLayers() => new (App.SlicerFile)
|
||||
{
|
||||
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
|
||||
RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps,
|
||||
RemoveEmptyLayers = UserSettings.Instance.LayerRepair.RemoveEmptyLayers,
|
||||
RemoveIslandsBelowEqualPixelCount = UserSettings.Instance.LayerRepair.RemoveIslandsBelowEqualPixels,
|
||||
RemoveIslandsRecursiveIterations = UserSettings.Instance.LayerRepair.RemoveIslandsRecursiveIterations,
|
||||
GapClosingIterations = UserSettings.Instance.LayerRepair.ClosingIterations,
|
||||
NoiseRemovalIterations = UserSettings.Instance.LayerRepair.OpeningIterations,
|
||||
};
|
||||
|
||||
public override void Callback(ToolWindow.Callbacks callback)
|
||||
{
|
||||
switch (callback)
|
||||
|
||||
@@ -70,6 +70,10 @@ namespace UVtools.WPF
|
||||
return;
|
||||
}
|
||||
if (clip?.Operation is null) return;
|
||||
if (clip.Operation.HaveROI)
|
||||
{
|
||||
ROI = GetTransposedRectangle(clip.Operation.ROI);
|
||||
}
|
||||
var operation = await ShowRunOperation(clip.Operation.GetType(), clip.Operation);
|
||||
if (operation is null)
|
||||
{
|
||||
|
||||
@@ -420,10 +420,10 @@ namespace UVtools.WPF
|
||||
await ShowRunOperation(typeof(OperationRepairLayers));
|
||||
}
|
||||
|
||||
public void OnClickDetectIssues()
|
||||
public async Task OnClickDetectIssues()
|
||||
{
|
||||
if (!IsFileLoaded) return;
|
||||
ComputeIssues(
|
||||
await ComputeIssues(
|
||||
GetIslandDetectionConfiguration(),
|
||||
GetOverhangDetectionConfiguration(),
|
||||
GetResinTrapDetectionConfiguration(),
|
||||
@@ -431,7 +431,7 @@ namespace UVtools.WPF
|
||||
Settings.Issues.ComputeEmptyLayers);
|
||||
}
|
||||
|
||||
private async void ComputeIssues(IslandDetectionConfiguration islandConfig = null,
|
||||
private async Task ComputeIssues(IslandDetectionConfiguration islandConfig = null,
|
||||
OverhangDetectionConfiguration overhangConfig = null,
|
||||
ResinTrapDetectionConfiguration resinTrapConfig = null,
|
||||
TouchingBoundDetectionConfiguration touchingBoundConfig = null, bool emptyLayersConfig = true)
|
||||
|
||||
@@ -1120,7 +1120,14 @@ namespace UVtools.WPF
|
||||
|
||||
if (Settings.Issues.ComputeIssuesOnLoad)
|
||||
{
|
||||
OnClickDetectIssues();
|
||||
_firstTimeOnIssues = false;
|
||||
await OnClickDetectIssues();
|
||||
if (Issues.Count > 0)
|
||||
{
|
||||
SelectedTabItem = TabIssues;
|
||||
if(Settings.Issues.AutoRepairIssuesOnLoad)
|
||||
await RunOperation(ToolRepairLayersControl.GetOperationRepairLayers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<Version>2.6.0</Version>
|
||||
<Version>2.6.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@@ -572,7 +572,8 @@ namespace UVtools.WPF
|
||||
[Serializable]
|
||||
public sealed class IssuesUserSettings : BindableBase
|
||||
{
|
||||
private bool _computeIssuesOnLoad = false;
|
||||
private bool _computeIssuesOnLoad;
|
||||
private bool _autoRepairIssuesOnLoad;
|
||||
private bool _computeIssuesOnClickTab = true;
|
||||
private bool _computeIslands = true;
|
||||
private bool _computeOverhangs = true;
|
||||
@@ -580,8 +581,8 @@ namespace UVtools.WPF
|
||||
private bool _computeTouchingBounds = true;
|
||||
private bool _computeEmptyLayers = true;
|
||||
private bool _islandEnhancedDetection = true;
|
||||
private bool _islandAllowDiagonalBonds = false;
|
||||
private byte _islandBinaryThreshold = 0;
|
||||
private bool _islandAllowDiagonalBonds;
|
||||
private byte _islandBinaryThreshold;
|
||||
private byte _islandRequiredAreaToProcessCheck = 1;
|
||||
private byte _islandRequiredPixelBrightnessToProcessCheck = 1;
|
||||
private byte _islandRequiredPixelsToSupport = 10;
|
||||
@@ -606,6 +607,12 @@ namespace UVtools.WPF
|
||||
set => RaiseAndSetIfChanged(ref _computeIssuesOnLoad, value);
|
||||
}
|
||||
|
||||
public bool AutoRepairIssuesOnLoad
|
||||
{
|
||||
get => _autoRepairIssuesOnLoad;
|
||||
set => RaiseAndSetIfChanged(ref _autoRepairIssuesOnLoad, value);
|
||||
}
|
||||
|
||||
public bool ComputeIssuesOnClickTab
|
||||
{
|
||||
get => _computeIssuesOnClickTab;
|
||||
|
||||
@@ -692,9 +692,14 @@
|
||||
<TextBlock Padding="10" Background="LightBlue" FontWeight="Bold" Text="Common"/>
|
||||
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="20">
|
||||
<CheckBox Margin="10,10" Content="Compute issues on file load"
|
||||
IsChecked="{Binding Settings.Issues.ComputeIssuesOnLoad}"
|
||||
/>
|
||||
IsChecked="{Binding Settings.Issues.ComputeIssuesOnLoad}"/>
|
||||
|
||||
<CheckBox Margin="0,10" Content="Auto repair layers and issues on file load"
|
||||
IsEnabled="{Binding Settings.Issues.ComputeIssuesOnLoad}"
|
||||
IsChecked="{Binding Settings.Issues.AutoRepairIssuesOnLoad}"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Margin="10,0,10,0" Content="Auto compute issues when the Issues tab is opened for the first time"
|
||||
IsChecked="{Binding Settings.Issues.ComputeIssuesOnClickTab}"
|
||||
|
||||
@@ -535,7 +535,7 @@ namespace UVtools.WPF.Windows
|
||||
{
|
||||
if (operation.ProfileIsDefault)
|
||||
{
|
||||
_selectedProfileItem = operation;
|
||||
SelectedProfileItem = operation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user