Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2021-08-13 01:19:47 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-08-13 01:19:47 +0300
commit80a9adbcd0d80a62eec3f2714ee902af6fb562f1 (patch)
tree54e5d6b0eb55a963a24ee743fd1c5406349d3c62
parentb8e05db1133b98ae3c023318b963962834c842eb (diff)
v2.18.0v2.18.0
- **Command line arguments:** - (Add) Convert files: UVtools.exe -c \<inputfile\> \<outputfile1/ext1\> [outputfile2/ext2] - (Add) Extract files: UVtools.exe -e \<inputfile\> [output_folder] - https://github.com/sn4k3/UVtools#command-line-arguments - **File formats:** - (Add) Implement TSMC (Two Stage Motor Control) for the supported formats - (Add) Implement 'Bottom retract speed' for the supported formats - (Add) LGS: Support for lgs120 and lg4k (#218) - (Add) CTB: Special/virtual file extensions .v2.ctb, .v3.ctb, .v4.ctb to force a convertion to the set version (2 to 4). The .ctb is Version 3 by default when creating/converting files - (Improvement) Better performance for file formats that decode images in sequential pixels groups - **GCode:** - (Improvement) Better parsing of the movements / lifts - (Improvement) Better handling of lifts performed after cure the layer - (Improvement) More fail-safe checks and sanitize of gcode while parsing - (Improvement) CTBv3: Enable per layer settings if disabled when fast save without reencode - (Upgrade) .NET from 5.0.8 to 5.0.9 - (Fix) PrusaSlicer printer: Longer Orange 4k with correct resolution and display size - (Fix) Odd error when changing properties too fast in multi-thread
-rw-r--r--CHANGELOG.md21
-rw-r--r--Documentation/osla.md2
-rw-r--r--PrusaSlicer/printer/Longer Orange 4K.ini12
-rw-r--r--Scripts/010 Editor/lgs.bt18
-rw-r--r--Scripts/010 Editor/osla.bt23
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs55
-rw-r--r--UVtools.Core/Extensions/SizeExtensions.cs2
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs18
-rw-r--r--UVtools.Core/FileFormats/CXDLPFile.cs2
-rw-r--r--UVtools.Core/FileFormats/CXDLPv1File.cs2
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs183
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs17
-rw-r--r--UVtools.Core/FileFormats/FDGFile.cs2
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs680
-rw-r--r--UVtools.Core/FileFormats/GR1File.cs2
-rw-r--r--UVtools.Core/FileFormats/LGSFile.cs143
-rw-r--r--UVtools.Core/FileFormats/OSLAFile.cs150
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs2
-rw-r--r--UVtools.Core/FileFormats/PhotonSFile.cs44
-rw-r--r--UVtools.Core/FileFormats/PhotonWorkshopFile.cs2
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs4
-rw-r--r--UVtools.Core/FileFormats/UVJFile.cs7
-rw-r--r--UVtools.Core/FileFormats/VDTFile.cs118
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs20
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs5
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs169
-rw-r--r--UVtools.Core/GCode/GCodeLayer.cs164
-rw-r--r--UVtools.Core/Layer/Layer.cs176
-rw-r--r--UVtools.Core/Layer/LayerManager.cs38
-rw-r--r--UVtools.Core/Operations/OperationCalculator.cs45
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs11
-rw-r--r--UVtools.Core/Operations/OperationDynamicLifts.cs7
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.InstallerMM/UVtools.InstallerMM.wxs4
-rw-r--r--UVtools.WPF/ConsoleArguments.cs152
-rw-r--r--UVtools.WPF/MainWindow.Information.cs7
-rw-r--r--UVtools.WPF/Program.cs10
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj2
-rw-r--r--build/CreateRelease.WPF.ps16
39 files changed, 1958 insertions, 369 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16e1e67..316c0ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,26 @@
# Changelog
+## 12/08/2021 - v2.18.0
+
+- **Command line arguments:**
+ - (Add) Convert files: UVtools.exe -c \<inputfile\> \<outputfile1/ext1\> [outputfile2/ext2]
+ - (Add) Extract files: UVtools.exe -e \<inputfile\> [output_folder]
+ - https://github.com/sn4k3/UVtools#command-line-arguments
+- **File formats:**
+ - (Add) Implement TSMC (Two Stage Motor Control) for the supported formats
+ - (Add) Implement 'Bottom retract speed' for the supported formats
+ - (Add) LGS: Support for lgs120 and lg4k (#218)
+ - (Add) CTB: Special/virtual file extensions .v2.ctb, .v3.ctb, .v4.ctb to force a convertion to the set version (2 to 4). The .ctb is Version 3 by default when creating/converting files
+ - (Improvement) Better performance for file formats that decode images in sequential pixels groups
+- **GCode:**
+ - (Improvement) Better parsing of the movements / lifts
+ - (Improvement) Better handling of lifts performed after cure the layer
+ - (Improvement) More fail-safe checks and sanitize of gcode while parsing
+- (Improvement) CTBv3: Enable per layer settings if disabled when fast save without reencode
+- (Upgrade) .NET from 5.0.8 to 5.0.9
+- (Fix) PrusaSlicer printer: Longer Orange 4k with correct resolution and display size
+- (Fix) Odd error when changing properties too fast in multi-thread
+
## 08/08/2021 - v2.17.0
- **Windows MSI:**
diff --git a/Documentation/osla.md b/Documentation/osla.md
index be765c8..2a5c432 100644
--- a/Documentation/osla.md
+++ b/Documentation/osla.md
@@ -198,9 +198,9 @@ LiftSpeed=100 (float) Speed in mm/min
LiftHeight2=0 (float) Extra distance in mm to raise from current position
LiftSpeed2=50 (float) Speed in mm/min
WaitTimeAfterLift=0 (float) Time to wait in seconds after lift / before retract
+RetractSpeed=100 (float) Speed in mm/min
RetractHeight2=0 (float) Offset retract distance in mm to perform
RetractSpeed2=150 (float) Speed in mm/min
-RetractSpeed=100 (float) Speed in mm/min
WaitTimeBeforeCure=2.5 (float) Time to wait in seconds before cure the layer / turn on LED
ExposureTime=2.8 (float) Time in seconds while curing the layer
WaitTimeAfterCure=1 (float) Time to wait in seconds after cure the layer / turn off LED
diff --git a/PrusaSlicer/printer/Longer Orange 4K.ini b/PrusaSlicer/printer/Longer Orange 4K.ini
index b41bded..9de296c 100644
--- a/PrusaSlicer/printer/Longer Orange 4K.ini
+++ b/PrusaSlicer/printer/Longer Orange 4K.ini
@@ -1,18 +1,18 @@
-# generated by PrusaSlicer 2.3.1+win64 on 2021-06-28 at 08:59:40 UTC
+# generated by PrusaSlicer 2.3.1+win64 on 2021-08-12 at 03:59:08 UTC
absolute_correction = 0
area_fill = 50
bed_custom_model =
bed_custom_texture =
-bed_shape = 0x0,68.04x0,68.04x120.96,0x120.96
+bed_shape = 0x0,120.96x0,120.96x68.04,0x68.04
default_sla_material_profile = Prusa Orange Tough 0.05
default_sla_print_profile = 0.05 Normal
-display_height = 120.96
+display_height = 68.04
display_mirror_x = 1
display_mirror_y = 0
display_orientation = landscape
-display_pixels_x = 6480
-display_pixels_y = 3840
-display_width = 68.04
+display_pixels_x = 3840
+display_pixels_y = 6480
+display_width = 120.96
elefant_foot_compensation = 0.2
elefant_foot_min_width = 0.2
fast_tilt_time = 5
diff --git a/Scripts/010 Editor/lgs.bt b/Scripts/010 Editor/lgs.bt
index 1f9e630..7b917b8 100644
--- a/Scripts/010 Editor/lgs.bt
+++ b/Scripts/010 Editor/lgs.bt
@@ -12,9 +12,6 @@ typedef struct() {
BYTE LayerRLE[DataSize] <fgcolor=cBlack, bgcolor=cRed>;
} layerData;
-typedef struct(int size) {
- BYTE layerDataBlock[size] <fgcolor=cBlack, bgcolor=0x00FF00>;
-} rgbPreviewImageRawData;
struct HEADER {
char Name[8] <fgcolor=cBlack, bgcolor=cWhite>;
@@ -62,15 +59,20 @@ struct HEADER {
uint32 Uint_a8 <fgcolor=cBlack, bgcolor=cRed>;
uint32 PreviewSizeX <fgcolor=cBlack, bgcolor=cRed>;
uint32 PreviewSizeY <fgcolor=cBlack, bgcolor=cRed>;
+} header;
+
- rgbPreviewImageRawData preview(PreviewSizeX*PreviewSizeY*2);
+byte preview_data[header.PreviewSizeX*header.PreviewSizeY*2];
- if(PrinterModel == 120) // .lgs120
- {
+if(header.PrinterModel == 120) // .lgs120
+{
+ struct PNG_PREVIEW {
uint32 pngLength <fgcolor=cBlack, bgcolor=cRed>;
byte png[pngLength] <fgcolor=cBlack, bgcolor=cYellow>;
- }
-} header;
+ ushort padding <fgcolor=cBlack, bgcolor=cRed>;
+ } png_preview;
+}
+
struct LAYERS {
local int i;
diff --git a/Scripts/010 Editor/osla.bt b/Scripts/010 Editor/osla.bt
index c56b8e3..355ac8a 100644
--- a/Scripts/010 Editor/osla.bt
+++ b/Scripts/010 Editor/osla.bt
@@ -25,7 +25,7 @@ struct HEADER {
float MachineZ <fgcolor=cBlack, bgcolor=cRed>;
float DisplayWidth <fgcolor=cBlack, bgcolor=cRed>;
float DisplayHeight <fgcolor=cBlack, bgcolor=cRed>;
- byte DisplayMirror <fgcolor=cBlack, bgcolor=cRed>;
+ ubyte DisplayMirror <fgcolor=cBlack, bgcolor=cRed>;
char PreviewDataType[16] <fgcolor=cBlack, bgcolor=cRed>;
char LayerDataType[16] <fgcolor=cBlack, bgcolor=cRed>;
@@ -66,16 +66,33 @@ struct PREVIEW {
ushort ResolutionX <fgcolor=cBlack, bgcolor=cPurple>;
ushort ResolutionY <fgcolor=cBlack, bgcolor=cPurple>;
uint ImageLength <fgcolor=cBlack, bgcolor=cPurple>;
- byte ImageData[ImageLength] <fgcolor=cWhite, bgcolor=cBlack>;
+ ubyte ImageData[ImageLength] <fgcolor=cWhite, bgcolor=cBlack>;
};
struct LAYER_DEF {
uint DataAddress <fgcolor=cBlack, bgcolor=cPurple>;
+ float PositionZ <fgcolor=cBlack, bgcolor=cPurple>;
+ float LiftHeight <fgcolor=cBlack, bgcolor=cPurple>;
+ float LiftSpeed <fgcolor=cBlack, bgcolor=cPurple>;
+ float LiftHeight2 <fgcolor=cBlack, bgcolor=cPurple>;
+ float LiftSpeed2 <fgcolor=cBlack, bgcolor=cPurple>;
+ float WaitTimeAfterLift <fgcolor=cBlack, bgcolor=cPurple>;
+ float RetractSpeed <fgcolor=cBlack, bgcolor=cPurple>;
+ float RetractHeight2 <fgcolor=cBlack, bgcolor=cPurple>;
+ float RetractSpeed2 <fgcolor=cBlack, bgcolor=cPurple>;
+ float WaitTimeBeforeCure <fgcolor=cBlack, bgcolor=cPurple>;
+ float ExposureTime <fgcolor=cBlack, bgcolor=cPurple>;
+ float WaitTimeAfterCure <fgcolor=cBlack, bgcolor=cPurple>;
+ ubyte LightPWM <fgcolor=cBlack, bgcolor=cPurple>;
+ uint BoundingRectangleX <fgcolor=cBlack, bgcolor=cPurple>;
+ uint BoundingRectangleY <fgcolor=cBlack, bgcolor=cPurple>;
+ uint BoundingRectangleWidth <fgcolor=cBlack, bgcolor=cPurple>;
+ uint BoundingRectangleHeight <fgcolor=cBlack, bgcolor=cPurple>;
};
struct LAYER_DATA{
uint ImageLength <fgcolor=cWhite, bgcolor=cBlack>;
- byte ImageData[ImageLength] <fgcolor=cWhite, bgcolor=cBlack>;
+ ubyte ImageData[ImageLength] <fgcolor=cWhite, bgcolor=cBlack>;
};
struct GCODE{
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index d53b283..5968786 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -149,6 +149,11 @@ namespace UVtools.Core.Extensions
return mat.GetDataSpan<byte>();
}
+ public static unsafe Span<byte> GetDataByteSpan(this Mat mat, int length, int offset = 0)
+ {
+ return new(IntPtr.Add(mat.DataPointer, offset).ToPointer(), length <= 0 ? mat.GetLength() : length);
+ }
+
/// <summary>
/// Gets the data span to manipulate or read pixels given a length and offset
/// </summary>
@@ -217,6 +222,56 @@ namespace UVtools.Core.Extensions
}
#endregion
+ #region Memory Fill
+
+ /// <summary>
+ /// Fill a mat span with a color
+ /// </summary>
+ /// <param name="mat">Mat to fill</param>
+ /// <param name="startPosition">Start position, this reference will increment by the <see cref="length"/></param>
+ /// <param name="length">Length to fill</param>
+ /// <param name="color">Color to fill with</param>
+ /// <param name="colorFillMinThreshold">Ignore and sum <see cref="startPosition"/> to <see cref="length"/> if <see cref="color"/> is less than the threshold value</param>
+ public static void FillSpan(this Mat mat, ref int startPosition, int length, byte color, byte colorFillMinThreshold = 1)
+ {
+ if (length <= 0) return;
+ if (color < colorFillMinThreshold) // Ignore threshold (mostly if blacks), spare cycles
+ {
+ startPosition += length;
+ return;
+ }
+
+ mat.GetDataByteSpan(length, startPosition).Fill(color);
+ startPosition += length;
+ }
+
+ /// <summary>
+ /// Fill a mat span with a color
+ /// </summary>
+ /// <param name="mat">Mat to fill</param>
+ /// <param name="x"></param>
+ /// <param name="y"></param>
+ /// <param name="length">Length to fill</param>
+ /// <param name="color">Color to fill with</param>
+ /// <param name="colorFillMinThreshold">Ignore and sum <see cref="startPosition"/> to <see cref="length"/> if <see cref="color"/> is less than the threshold value</param>
+ public static void FillSpan(this Mat mat, int x, int y, int length, byte color, byte colorFillMinThreshold = 1)
+ {
+ if (length <= 0 || color < colorFillMinThreshold) return; // Ignore threshold (mostly if blacks), spare cycles
+ mat.GetDataByteSpan(length, mat.GetPixelPos(x, y)).Fill(color);
+ }
+
+ /// <summary>
+ /// Fill a mat span with a color
+ /// </summary>
+ /// <param name="mat">Mat to fill</param>
+ /// <param name="position"></param>
+ /// <param name="length">Length to fill</param>
+ /// <param name="color">Color to fill with</param>
+ /// <param name="colorFillMinThreshold">Ignore and sum <see cref="startPosition"/> to <see cref="length"/> if <see cref="color"/> is less than the threshold value</param>
+ public static void FillSpan(this Mat mat, Point position, int length, byte color, byte colorFillMinThreshold = 1)
+ => mat.FillSpan(position.X, position.Y, length, color, colorFillMinThreshold);
+ #endregion
+
#region Get/Set methods
/// <summary>
/// Gets the total length of this <see cref="Mat"/></param>
diff --git a/UVtools.Core/Extensions/SizeExtensions.cs b/UVtools.Core/Extensions/SizeExtensions.cs
index 8bbc547..6be074e 100644
--- a/UVtools.Core/Extensions/SizeExtensions.cs
+++ b/UVtools.Core/Extensions/SizeExtensions.cs
@@ -60,7 +60,7 @@ namespace UVtools.Core.Extensions
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
- public static Size Invert(this Size size) => new(size.Height, size.Width);
+ public static Size Exchange(this Size size) => new(size.Height, size.Width);
public static int Area(this Rectangle rect) => rect.Width * rect.Height;
diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index 40f4ca1..0145ba4 100644
--- a/UVtools.Core/FileFormats/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -309,9 +309,6 @@ namespace UVtools.Core.FileFormats
public override PrintParameterModifier[] PrintParameterModifiers { get; } = {
PrintParameterModifier.BottomLayerCount,
- //PrintParameterModifier.BottomLightOffDelay,
- //PrintParameterModifier.LightOffDelay,
-
PrintParameterModifier.BottomWaitTimeBeforeCure,
PrintParameterModifier.WaitTimeBeforeCure,
@@ -326,11 +323,22 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
+
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
};
@@ -341,8 +349,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.LightPWM,
};
diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs
index f6f9d6d..0d8b5f0 100644
--- a/UVtools.Core/FileFormats/CXDLPFile.cs
+++ b/UVtools.Core/FileFormats/CXDLPFile.cs
@@ -548,6 +548,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)value;
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => SlicerInfoSettings.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/CXDLPv1File.cs b/UVtools.Core/FileFormats/CXDLPv1File.cs
index 752cebc..81a845f 100644
--- a/UVtools.Core/FileFormats/CXDLPv1File.cs
+++ b/UVtools.Core/FileFormats/CXDLPv1File.cs
@@ -497,6 +497,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)value;
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => SlicerInfoSettings.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index d2fdc78..9c4d346 100644
--- a/UVtools.Core/FileFormats/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -27,6 +27,8 @@ namespace UVtools.Core.FileFormats
{
#region Constants
+ public const byte USED_VERSION = 3; // 318570521
+
public const uint MAGIC_CBDDLP = 0x12FD0019; // 318570521
public const uint MAGIC_CBT = 0x12FD0086; // 318570630
public const uint MAGIC_CBTv4 = 0x12FD0106; // 318570758
@@ -69,7 +71,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Gets the software version
/// </summary>
- [FieldOrder(1)] public uint Version { get; set; } = 3;
+ [FieldOrder(1)] public uint Version { get; set; } = USED_VERSION;
/// <summary>
/// Gets dimensions of the printer’s X output volume, in millimeters.
@@ -285,7 +287,7 @@ namespace UVtools.Core.FileFormats
public class SlicerInfo
{
private string _machineName;
- [FieldOrder(0)] public float BottomLiftDistance2 { get; set; }
+ [FieldOrder(0)] public float BottomLiftHeight2 { get; set; }
[FieldOrder(1)] public float BottomLiftSpeed2 { get; set; }
[FieldOrder(2)] public float LiftHeight2 { get; set; }
[FieldOrder(3)] public float LiftSpeed2 { get; set; }
@@ -352,7 +354,7 @@ namespace UVtools.Core.FileFormats
public override string ToString()
{
- return $"{nameof(BottomLiftDistance2)}: {BottomLiftDistance2}, {nameof(BottomLiftSpeed2)}: {BottomLiftSpeed2}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift2)}: {RestTimeAfterLift2}, {nameof(TransitionLayerCount)}: {TransitionLayerCount}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(MachineName)}: {MachineName}";
+ return $"{nameof(BottomLiftHeight2)}: {BottomLiftHeight2}, {nameof(BottomLiftSpeed2)}: {BottomLiftSpeed2}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(MachineNameAddress)}: {MachineNameAddress}, {nameof(MachineNameSize)}: {MachineNameSize}, {nameof(EncryptionMode)}: {EncryptionMode}, {nameof(MysteriousId)}: {MysteriousId}, {nameof(AntiAliasLevel)}: {AntiAliasLevel}, {nameof(SoftwareVersion)}: {SoftwareVersion}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(RestTimeAfterLift2)}: {RestTimeAfterLift2}, {nameof(TransitionLayerCount)}: {TransitionLayerCount}, {nameof(Padding1)}: {Padding1}, {nameof(Padding2)}: {Padding2}, {nameof(Padding3)}: {Padding3}, {nameof(MachineName)}: {MachineName}";
}
}
@@ -706,10 +708,10 @@ namespace UVtools.Core.FileFormats
return image;
}
- private unsafe Mat DecodeCbtImage(uint layerIndex)
+ private Mat DecodeCbtImage(uint layerIndex)
{
- var image = EmguExtensions.InitMat(Parent.Resolution);
- var span = image.GetBytePointer();
+ var mat = EmguExtensions.InitMat(Parent.Resolution);
+ //var span = mat.GetBytePointer();
if (Parent.HeaderSettings.EncryptionKey > 0)
{
@@ -751,7 +753,7 @@ namespace UVtools.Core.FileFormats
}
else
{
- image.Dispose();
+ mat.Dispose();
throw new FileLoadException("Corrupted RLE data");
}
}
@@ -762,22 +764,24 @@ namespace UVtools.Core.FileFormats
code = (byte)((code << 1) | 1);
}
- if (stride == 0) continue; // Nothing to do
+ mat.FillSpan(ref pixel, stride, code);
- if (code == 0) // Ignore blacks, spare cycles
+ //if (stride <= 0) continue; // Nothing to do
+
+ /*if (code == 0) // Ignore blacks, spare cycles
{
pixel += stride;
continue;
- }
+ }*/
- for (; stride > 0; stride--)
+ /*for (; stride > 0; stride--)
{
span[pixel] = code;
pixel++;
- }
+ }*/
}
- return image;
+ return mat;
}
public byte[] Encode(Mat image, byte aaIndex, uint layerIndex)
@@ -950,7 +954,7 @@ namespace UVtools.Core.FileFormats
public class LayerDataEx
{
/// <summary>
- /// Gets a copy of layer data defenition
+ /// Gets a copy of layer data definition
/// </summary>
[FieldOrder(0)] public LayerData LayerData { get; set; } = new();
@@ -986,6 +990,12 @@ namespace UVtools.Core.FileFormats
if (layerData.Parent.HeaderSettings.Version >= 4)
{
+ LiftHeight2 = layerData.Parent[layerIndex].LiftHeight2;
+ LiftSpeed2 = layerData.Parent[layerIndex].LiftSpeed2;
+
+ RetractHeight2 = layerData.Parent[layerIndex].RetractHeight2;
+ RetractSpeed2 = layerData.Parent[layerIndex].RetractSpeed2;
+
RestTimeAfterRetract = layerData.Parent[layerIndex].WaitTimeBeforeCure;
RestTimeBeforeLift = layerData.Parent[layerIndex].WaitTimeAfterCure;
RestTimeAfterLift = layerData.Parent[layerIndex].WaitTimeAfterLift;
@@ -1075,7 +1085,11 @@ namespace UVtools.Core.FileFormats
public override FileFormatType FileType => FileFormatType.Binary;
public override FileExtension[] FileExtensions { get; } = {
- new("ctb", "Chitubox CTB"),
+ new("ctb", $"Chitubox CTBv{USED_VERSION}"),
+ //new("v2.ctb", "Chitubox CTBv2"),
+ //new("v3.ctb", "Chitubox CTBv3"),
+ new("v4.ctb", "Chitubox CTBv4"),
+ //new("encrypted.ctb", "Chitubox encrypted CTB"),
new("cbddlp", "Chitubox CBDDLP"),
new("photon", "Chitubox Photon"),
};
@@ -1107,11 +1121,20 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.BottomLiftSpeed,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
//PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
@@ -1169,8 +1192,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.LightPWM,
};
}
@@ -1421,6 +1448,46 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = PrintParametersSettings.LiftSpeed = (float)Math.Round(value, 2);
}
+ public override float BottomLiftHeight2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.BottomLiftHeight2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.BottomLiftHeight2 = SlicerInfoSettings.BottomLiftHeight2 = (float)Math.Round(value, 2);
+ }
+ }
+
+ public override float LiftHeight2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.LiftHeight2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.LiftHeight2 = SlicerInfoSettings.LiftHeight2 = (float)Math.Round(value, 2);
+ }
+ }
+
+ public override float BottomLiftSpeed2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.BottomLiftSpeed2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.BottomLiftSpeed2 = SlicerInfoSettings.BottomLiftSpeed2 = (float)Math.Round(value, 2);
+ }
+ }
+
+ public override float LiftSpeed2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.LiftSpeed2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.LiftSpeed2 = SlicerInfoSettings.LiftSpeed2 = (float)Math.Round(value, 2);
+ }
+ }
+
public override float BottomWaitTimeAfterLift => WaitTimeAfterLift;
public override float WaitTimeAfterLift
{
@@ -1437,10 +1504,52 @@ namespace UVtools.Core.FileFormats
}
}
+ public override float BottomRetractSpeed
+ {
+ get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.BottomRetractSpeed : RetractSpeed;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.BottomRetractSpeed = PrintParametersV4Settings.BottomRetractSpeed = (float)Math.Round(value, 2);
+ }
+ }
+
public override float RetractSpeed
{
get => PrintParametersSettings.RetractSpeed;
- set => base.RetractSpeed = PrintParametersV4Settings.BottomRetractSpeed = PrintParametersSettings.RetractSpeed = (float)Math.Round(value, 2);
+ set => base.RetractSpeed = PrintParametersSettings.RetractSpeed = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomRetractHeight2
+ {
+ get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.BottomRetractHeight2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.BottomRetractSpeed2 = PrintParametersV4Settings.BottomRetractHeight2 = (float)Math.Round(value, 2);
+ }
+ }
+
+ public override float RetractHeight2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.RetractHeight2 : 0;
+ set => base.RetractSpeed2 = SlicerInfoSettings.RetractHeight2 = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomRetractSpeed2
+ {
+ get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.BottomRetractSpeed2 : 0;
+ set
+ {
+ if (HeaderSettings.Version < 4) return;
+ base.BottomRetractSpeed2 = PrintParametersV4Settings.BottomRetractSpeed2 = (float)Math.Round(value, 2);
+ }
+ }
+
+ public override float RetractSpeed2
+ {
+ get => HeaderSettings.Version >= 4 ? SlicerInfoSettings.RetractSpeed2 : 0;
+ set => base.RetractSpeed2 = SlicerInfoSettings.RetractSpeed2 = (float)Math.Round(value, 2);
}
public override byte BottomLightPWM
@@ -1537,13 +1646,8 @@ namespace UVtools.Core.FileFormats
LayerDefinitions = null;
}
- protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
+ public void SanitizeProperties()
{
- LayersHash.Clear();
-
- HeaderSettings.Magic = FileEndsWith(".ctb") ? MAGIC_CBT : MAGIC_CBDDLP;
- HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
-
if (IsCbtFile)
{
if (SlicerInfoSettings.AntiAliasLevel <= 1)
@@ -1555,30 +1659,52 @@ namespace UVtools.Core.FileFormats
if (HeaderSettings.Version <= 2)
{
- //if (SlicerInfoSettings.RestTimeAfterRetract == 0)
- //SlicerInfoSettings.RestTimeAfterRetract = 0x200; // 512 for v2 | 0 for v3
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CTBv2;
PrintParametersSettings.Padding4 = 0x1234; // 4660
if (SlicerInfoSettings.MysteriousId == 0)
SlicerInfoSettings.MysteriousId = 305419896;
}
- else if(HeaderSettings.Version == 3)
+ else if (HeaderSettings.Version == 3)
{
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CTBv3;
if (SlicerInfoSettings.MysteriousId == 0)
SlicerInfoSettings.MysteriousId = 305419896;
}
- else
+ else if (HeaderSettings.Version >= 4)
{
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CTBv4;
if (SlicerInfoSettings.MysteriousId == 0)
SlicerInfoSettings.MysteriousId = 27087820;
}
+ }
+ }
+ protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
+ {
+ LayersHash.Clear();
+ HeaderSettings.Magic = FileEndsWith(".ctb") ? MAGIC_CBT : MAGIC_CBDDLP;
+ HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
+
+ if (FileEndsWith(".v2.ctb"))
+ {
+ HeaderSettings.Version = 2;
+ }
+ else if (FileEndsWith(".v3.ctb"))
+ {
+ HeaderSettings.Version = 3;
+ }
+ else if (FileEndsWith(".v4.ctb"))
+ {
+ HeaderSettings.Version = 4;
+ }
+
+ SanitizeProperties();
+ if (IsCbtFile)
+ {
if (HeaderSettings.EncryptionKey == 0)
{
var rnd = new Random();
@@ -1883,6 +2009,10 @@ namespace UVtools.Core.FileFormats
if (HeaderSettings.Version >= 4)
{
+ layer.LiftHeight2 = LayerDefinitionsEx[layerIndex].LiftHeight2;
+ layer.LiftSpeed2 = LayerDefinitionsEx[layerIndex].LiftSpeed2;
+ layer.RetractHeight2 = LayerDefinitionsEx[layerIndex].RetractHeight2;
+ layer.RetractSpeed2 = LayerDefinitionsEx[layerIndex].RetractSpeed2;
layer.WaitTimeBeforeCure = LayerDefinitionsEx[layerIndex].RestTimeAfterRetract;
layer.WaitTimeAfterCure = LayerDefinitionsEx[layerIndex].RestTimeBeforeLift;
layer.WaitTimeAfterLift = LayerDefinitionsEx[layerIndex].RestTimeAfterLift;
@@ -1915,6 +2045,7 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
+ SanitizeProperties();
using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index 7d663e8..1039758 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -96,11 +96,22 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
-
+
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
+
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
};
@@ -111,8 +122,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.LightPWM,
};
diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs
index a80e0c1..2d601d2 100644
--- a/UVtools.Core/FileFormats/FDGFile.cs
+++ b/UVtools.Core/FileFormats/FDGFile.cs
@@ -867,6 +867,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = HeaderSettings.LiftSpeed = (float)Math.Round(value, 2);
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => HeaderSettings.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 465e68a..4b49fb0 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -44,15 +44,26 @@ namespace UVtools.Core.FileFormats
public const ushort DefaultBottomLayerCount = 4;
public const float DefaultBottomExposureTime = 30;
+ public const float DefaultExposureTime = 3;
+
public const float DefaultBottomLiftHeight = 5;
public const float DefaultLiftHeight = 5;
public const float DefaultBottomLiftSpeed = 100;
-
- public const float DefaultExposureTime = 3;
public const float DefaultLiftSpeed = 100;
+
+ public const float DefaultBottomLiftHeight2 = 0;
+ public const float DefaultLiftHeight2 = 0;
+ public const float DefaultBottomLiftSpeed2 = 300;
+ public const float DefaultLiftSpeed2 = 300;
+
+
+ public const float DefaultBottomRetractSpeed = 100;
public const float DefaultRetractSpeed = 100;
- public const float DefaultBottomLightOffDelay = 0;
- public const float DefaultLightOffDelay = 0;
+ public const float DefaultBottomRetractHeight2 = 0;
+ public const float DefaultRetractHeight2 = 0;
+ public const float DefaultBottomRetractSpeed2 = 300;
+ public const float DefaultRetractSpeed2 = 300;
+
public const byte DefaultBottomLightPWM = 255;
public const byte DefaultLightPWM = 255;
@@ -61,7 +72,7 @@ namespace UVtools.Core.FileFormats
public const float MinimumLayerHeight = 0.01f;
public const float MaximumLayerHeight = 0.20f;
- private const ushort QueueTimerPrintTime = 250;
+ private const ushort QueueTimerPrintTime = 250; // ms
#endregion
#region Enums
@@ -108,16 +119,28 @@ namespace UVtools.Core.FileFormats
public static PrintParameterModifier WaitTimeAfterCure { get; } = new("Wait after cure", "Time to wait/rest after cure a new bottom layer\nChitubox: Rest before lift\nLychee: Wait after print", "s", 0, 1000, 2);
public static PrintParameterModifier BottomLiftHeight { get; } = new ("Bottom lift height", "Bottom lift/peel height between layers", "mm", 1);
- public static PrintParameterModifier LiftHeight { get; } = new ("Lift height", @"Lift/peel height between layers", "mm");
+ public static PrintParameterModifier LiftHeight { get; } = new ("Lift height", @"Lift/peel height between layers", "mm", 1);
public static PrintParameterModifier BottomLiftSpeed { get; } = new ("Bottom lift speed", null, "mm/min", 10, 5000, 2);
public static PrintParameterModifier LiftSpeed { get; } = new ("Lift speed", null, "mm/min", 10, 5000, 2);
-
+
+ public static PrintParameterModifier BottomLiftHeight2 { get; } = new("2) Bottom lift height", "Bottom second lift/peel height between layers", "mm");
+ public static PrintParameterModifier LiftHeight2 { get; } = new("2) Lift height", @"Second lift/peel height between layers", "mm");
+
+ public static PrintParameterModifier BottomLiftSpeed2 { get; } = new("2) Bottom lift speed", null, "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier LiftSpeed2 { get; } = new("2) Lift speed", null, "mm/min", 10, 5000, 2);
+
public static PrintParameterModifier BottomWaitTimeAfterLift { get; } = new("Bottom wait after lift", "Time to wait/rest after a lift/peel sequence at bottom layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s", 0, 1000, 2);
public static PrintParameterModifier WaitTimeAfterLift { get; } = new("Wait after lift", "Time to wait/rest after a lift/peel sequence at layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s", 0, 1000, 2);
+ public static PrintParameterModifier BottomRetractSpeed { get; } = new ("Bottom retract speed", "Bottom down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
public static PrintParameterModifier RetractSpeed { get; } = new ("Retract speed", "Down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier BottomRetractHeight2 { get; } = new("2) Bottom retract height", "Second extra bottom retract height ", "mm");
+ public static PrintParameterModifier RetractHeight2 { get; } = new("2) Retract height", @"Second extra retract height", "mm");
+ public static PrintParameterModifier BottomRetractSpeed2 { get; } = new("2) Bottom retract speed", "Bottom second down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier RetractSpeed2 { get; } = new("2) Retract speed", "Second down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
+
public static PrintParameterModifier BottomLightPWM { get; } = new ("Bottom light PWM", "UV LED power for bottom layers", "☀", 1, byte.MaxValue, 0);
public static PrintParameterModifier LightPWM { get; } = new ("Light PWM", "UV LED power for layers", "☀", 1, byte.MaxValue, 0);
@@ -360,21 +383,48 @@ namespace UVtools.Core.FileFormats
#region Members
private bool _haveModifiedLayers;
private LayerManager _layerManager;
- private float _printTime;
- private float _materialMilliliters;
- private float _machineZ;
+
private ushort _bottomLayerCount = DefaultBottomLayerCount;
+
+ private float _bottomLightOffDelay;
+ private float _lightOffDelay;
+
+ private float _bottomWaitTimeBeforeCure;
+ private float _waitTimeBeforeCure;
+
private float _bottomExposureTime = DefaultBottomExposureTime;
private float _exposureTime = DefaultExposureTime;
+
+ private float _bottomWaitTimeAfterCure;
+ private float _waitTimeAfterCure;
+
private float _bottomLiftHeight = DefaultBottomLiftHeight;
private float _liftHeight = DefaultLiftHeight;
private float _bottomLiftSpeed = DefaultBottomLiftSpeed;
private float _liftSpeed = DefaultLiftSpeed;
+
+ private float _bottomLiftHeight2 = DefaultBottomLiftHeight2;
+ private float _liftHeight2 = DefaultLiftHeight2;
+ private float _bottomLiftSpeed2 = DefaultBottomLiftSpeed2;
+ private float _liftSpeed2 = DefaultLiftSpeed2;
+
+ private float _bottomWaitTimeAfterLift;
+ private float _waitTimeAfterLift;
+
+ private float _bottomRetractHeight2 = DefaultBottomRetractHeight2;
+ private float _retractHeight2 = DefaultRetractHeight2;
+ private float _bottomRetractSpeed2 = DefaultBottomRetractSpeed2;
+ private float _retractSpeed2 = DefaultRetractSpeed2;
+ private float _bottomRetractSpeed = DefaultBottomRetractSpeed;
private float _retractSpeed = DefaultRetractSpeed;
- private float _bottomLightOffDelay = DefaultBottomLightOffDelay;
- private float _lightOffDelay = DefaultLightOffDelay;
+
+
private byte _bottomLightPwm = DefaultBottomLightPWM;
private byte _lightPwm = DefaultLightPWM;
+
+ private float _printTime;
+ private float _materialMilliliters;
+ private float _machineZ;
private string _machineName = "Unknown";
private string _materialName;
private float _materialGrams;
@@ -382,17 +432,12 @@ namespace UVtools.Core.FileFormats
private bool _suppressRebuildGCode;
private readonly Timer _queueTimerPrintTime = new(QueueTimerPrintTime){AutoReset = false};
- private float _bottomWaitTimeBeforeCure;
- private float _waitTimeBeforeCure;
- private float _bottomWaitTimeAfterCure;
- private float _waitTimeAfterCure;
- private float _bottomWaitTimeAfterLift;
- private float _waitTimeAfterLift;
-
#endregion
#region Properties
+ public object Mutex = new();
+
/// <summary>
/// Gets the file format type
/// </summary>
@@ -857,6 +902,9 @@ namespace UVtools.Core.FileFormats
}
}
+ /// <summary>
+ /// Gets or sets the bottom time in seconds to wait before cure the layer
+ /// </summary>
public virtual float BottomWaitTimeBeforeCure
{
get => _bottomWaitTimeBeforeCure;
@@ -868,6 +916,9 @@ namespace UVtools.Core.FileFormats
}
+ /// <summary>
+ /// Gets or sets the time in seconds to wait after cure the layer
+ /// </summary>
public virtual float WaitTimeBeforeCure
{
get => _waitTimeBeforeCure;
@@ -904,6 +955,9 @@ namespace UVtools.Core.FileFormats
}
}
+ /// <summary>
+ /// Gets or sets the bottom time in seconds to wait after cure the layer
+ /// </summary>
public virtual float BottomWaitTimeAfterCure
{
get => _bottomWaitTimeAfterCure;
@@ -914,6 +968,9 @@ namespace UVtools.Core.FileFormats
}
}
+ /// <summary>
+ /// Gets or sets the time in seconds to wait after cure the layer
+ /// </summary>
public virtual float WaitTimeAfterCure
{
get => _waitTimeAfterCure;
@@ -925,6 +982,34 @@ namespace UVtools.Core.FileFormats
}
/// <summary>
+ /// Gets: Total bottom lift height (lift1 + lift2)
+ /// Sets: Bottom lift1 with value and lift2 with 0
+ /// </summary>
+ public float BottomLiftHeightTotal
+ {
+ get => (float)Math.Round(_bottomLiftHeight + _bottomLiftHeight2);
+ set
+ {
+ BottomLiftHeight = value;
+ BottomLiftHeight2 = 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets: Total lift height (lift1 + lift2)
+ /// Sets: Lift1 with value and lift2 with 0
+ /// </summary>
+ public float LiftHeightTotal
+ {
+ get => (float)Math.Round(_liftHeight + _liftHeight2);
+ set
+ {
+ LiftHeight = value;
+ LiftHeight2 = 0;
+ }
+ }
+
+ /// <summary>
/// Gets or sets the bottom lift height in mm
/// </summary>
public virtual float BottomLiftHeight
@@ -933,36 +1018,42 @@ namespace UVtools.Core.FileFormats
set
{
RaiseAndSet(ref _bottomLiftHeight, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(BottomLiftHeightTotal));
RaisePropertyChanged(nameof(LiftRepresentation));
+ BottomRetractHeight2 = _bottomRetractHeight2; // Sanitize
}
}
/// <summary>
- /// Gets or sets the lift height in mm
+ /// Gets or sets the bottom lift speed in mm/min
/// </summary>
- public virtual float LiftHeight
+ public virtual float BottomLiftSpeed
{
- get => _liftHeight;
+ get => _bottomLiftSpeed;
set
{
- RaiseAndSet(ref _liftHeight, (float)Math.Round(value, 2));
+ RaiseAndSet(ref _bottomLiftSpeed, (float)Math.Round(value, 2));
RaisePropertyChanged(nameof(LiftRepresentation));
}
}
/// <summary>
- /// Gets or sets the bottom lift speed in mm/min
+ /// Gets or sets the lift height in mm
/// </summary>
- public virtual float BottomLiftSpeed
+ public virtual float LiftHeight
{
- get => _bottomLiftSpeed;
+ get => _liftHeight;
set
{
- RaiseAndSet(ref _bottomLiftSpeed, (float)Math.Round(value, 2));
+ RaiseAndSet(ref _liftHeight, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(LiftHeightTotal));
RaisePropertyChanged(nameof(LiftRepresentation));
+ RetractHeight2 = _retractHeight2; // Sanitize
}
}
+
+
/// <summary>
/// Gets or sets the speed in mm/min
/// </summary>
@@ -976,6 +1067,66 @@ namespace UVtools.Core.FileFormats
}
}
+ /// <summary>
+ /// Gets or sets the second bottom lift height in mm
+ /// </summary>
+ public virtual float BottomLiftHeight2
+ {
+ get => _bottomLiftHeight2;
+ set
+ {
+ RaiseAndSet(ref _bottomLiftHeight2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(BottomLiftHeightTotal));
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ BottomRetractHeight2 = _bottomRetractHeight2; // Sanitize
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the second bottom lift speed in mm/min
+ /// </summary>
+ public virtual float BottomLiftSpeed2
+ {
+ get => _bottomLiftSpeed2;
+ set
+ {
+ RaiseAndSet(ref _bottomLiftSpeed2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the second lift height in mm
+ /// </summary>
+ public virtual float LiftHeight2
+ {
+ get => _liftHeight2;
+ set
+ {
+ RaiseAndSet(ref _liftHeight2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(LiftHeightTotal));
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ RetractHeight2 = _retractHeight2; // Sanitize
+ }
+ }
+
+
+ /// <summary>
+ /// Gets or sets the second speed in mm/min
+ /// </summary>
+ public virtual float LiftSpeed2
+ {
+ get => _liftSpeed2;
+ set
+ {
+ RaiseAndSet(ref _liftSpeed2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(LiftRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the bottom time in seconds to wait after lift / before retract
+ /// </summary>
public virtual float BottomWaitTimeAfterLift
{
get => _bottomWaitTimeAfterLift;
@@ -986,6 +1137,9 @@ namespace UVtools.Core.FileFormats
}
}
+ /// <summary>
+ /// Gets or sets the time in seconds to wait after lift / before retract
+ /// </summary>
public virtual float WaitTimeAfterLift
{
get => _waitTimeAfterLift;
@@ -997,6 +1151,39 @@ namespace UVtools.Core.FileFormats
}
/// <summary>
+ /// Gets: Total bottom retract height (retract1 + retract2) alias of <see cref="BottomLiftHeightTotal"/>
+ /// </summary>
+ public float BottomRetractHeightTotal => BottomLiftHeightTotal;
+
+ /// <summary>
+ /// Gets: Total retract height (retract1 + retract2) alias of <see cref="LiftHeightTotal"/>
+ /// </summary>
+ public float RetractHeightTotal => LiftHeightTotal;
+
+ /// <summary>
+ /// Gets the bottom retract height in mm
+ /// </summary>
+ public float BottomRetractHeight => (float)Math.Round(BottomLiftHeightTotal - _bottomRetractHeight2);
+
+ /// <summary>
+ /// Gets the speed in mm/min for the bottom retracts
+ /// </summary>
+ public virtual float BottomRetractSpeed
+ {
+ get => _bottomRetractSpeed;
+ set
+ {
+ RaiseAndSet(ref _bottomRetractSpeed, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets the retract height in mm
+ /// </summary>
+ public float RetractHeight => (float)Math.Round(LiftHeightTotal - _retractHeight2);
+
+ /// <summary>
/// Gets the speed in mm/min for the retracts
/// </summary>
public virtual float RetractSpeed
@@ -1010,6 +1197,64 @@ namespace UVtools.Core.FileFormats
}
/// <summary>
+ /// Gets or sets the second bottom retract height in mm
+ /// </summary>
+ public virtual float BottomRetractHeight2
+ {
+ get => _bottomRetractHeight2;
+ set
+ {
+ value = Math.Clamp((float)Math.Round(value, 2), 0, BottomRetractHeightTotal);
+ RaiseAndSet(ref _bottomRetractHeight2, value);
+ RaisePropertyChanged(nameof(BottomRetractHeight));
+ RaisePropertyChanged(nameof(BottomRetractHeightTotal));
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets the speed in mm/min for the retracts
+ /// </summary>
+ public virtual float BottomRetractSpeed2
+ {
+ get => _bottomRetractSpeed2;
+ set
+ {
+ RaiseAndSet(ref _bottomRetractSpeed2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the second retract height in mm
+ /// </summary>
+ public virtual float RetractHeight2
+ {
+ get => _retractHeight2;
+ set
+ {
+ value = Math.Clamp((float)Math.Round(value, 2), 0, RetractHeightTotal);
+ RaiseAndSet(ref _retractHeight2, value);
+ RaisePropertyChanged(nameof(RetractHeight));
+ RaisePropertyChanged(nameof(RetractHeightTotal));
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
+ }
+
+ /// <summary>
+ /// Gets the speed in mm/min for the retracts
+ /// </summary>
+ public virtual float RetractSpeed2
+ {
+ get => _retractSpeed2;
+ set
+ {
+ RaiseAndSet(ref _retractSpeed2, (float)Math.Round(value, 2));
+ RaisePropertyChanged(nameof(RetractRepresentation));
+ }
+ }
+
+ /// <summary>
/// Gets or sets the bottom pwm value from 0 to 255
/// </summary>
public virtual byte BottomLightPWM
@@ -1053,11 +1298,28 @@ namespace UVtools.Core.FileFormats
public bool CanUseLiftSpeed => HavePrintParameterModifier(PrintParameterModifier.LiftSpeed);
public bool CanUseAnyLiftSpeed => CanUseBottomLiftSpeed || CanUseLiftSpeed;
+ public bool CanUseBottomLiftHeight2 => HavePrintParameterModifier(PrintParameterModifier.BottomLiftHeight2);
+ public bool CanUseLiftHeight2 => HavePrintParameterModifier(PrintParameterModifier.LiftHeight2);
+ public bool CanUseAnyLiftHeight2 => CanUseBottomLiftHeight2 || CanUseLiftHeight2;
+
+ public bool CanUseBottomLiftSpeed2 => HavePrintParameterModifier(PrintParameterModifier.BottomLiftSpeed2);
+ public bool CanUseLiftSpeed2 => HavePrintParameterModifier(PrintParameterModifier.LiftSpeed2);
+ public bool CanUseAnyLiftSpeed2 => CanUseBottomLiftSpeed2 || CanUseLiftSpeed2;
+
public bool CanUseBottomWaitTimeAfterLift => HavePrintParameterModifier(PrintParameterModifier.BottomWaitTimeAfterLift);
public bool CanUseWaitTimeAfterLift => HavePrintParameterModifier(PrintParameterModifier.WaitTimeAfterLift);
public bool CanUseAnyWaitTimeAfterLift => CanUseBottomWaitTimeAfterLift || CanUseWaitTimeAfterLift;
+ public bool CanUseBottomRetractSpeed => HavePrintParameterModifier(PrintParameterModifier.BottomRetractSpeed);
public bool CanUseRetractSpeed => HavePrintParameterModifier(PrintParameterModifier.RetractSpeed);
+ public bool CanUseAnyRetractSpeed => CanUseBottomRetractSpeed || CanUseRetractSpeed;
+
+ public bool CanUseBottomRetractHeight2 => HavePrintParameterModifier(PrintParameterModifier.BottomRetractHeight2);
+ public bool CanUseRetractHeight2 => HavePrintParameterModifier(PrintParameterModifier.RetractHeight2);
+ public bool CanUseAnyRetractHeight2 => CanUseBottomRetractHeight2 || CanUseRetractHeight2;
+ public bool CanUseBottomRetractSpeed2 => HavePrintParameterModifier(PrintParameterModifier.BottomRetractSpeed2);
+ public bool CanUseRetractSpeed2 => HavePrintParameterModifier(PrintParameterModifier.RetractSpeed2);
+ public bool CanUseAnyRetractSpeed2 => CanUseBottomRetractSpeed2 || CanUseRetractSpeed2;
public bool CanUseAnyWaitTime => CanUseBottomWaitTimeBeforeCure || CanUseBottomWaitTimeAfterCure || CanUseBottomWaitTimeAfterLift ||
CanUseWaitTimeBeforeCure || CanUseWaitTimeAfterCure || CanUseWaitTimeAfterLift;
@@ -1071,8 +1333,12 @@ namespace UVtools.Core.FileFormats
public bool CanUseLayerWaitTimeAfterCure => HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterCure);
public bool CanUseLayerLiftHeight => HaveLayerParameterModifier(PrintParameterModifier.LiftHeight);
public bool CanUseLayerLiftSpeed => HaveLayerParameterModifier(PrintParameterModifier.LiftSpeed);
+ public bool CanUseLayerLiftHeight2 => HaveLayerParameterModifier(PrintParameterModifier.LiftHeight2);
+ public bool CanUseLayerLiftSpeed2 => HaveLayerParameterModifier(PrintParameterModifier.LiftSpeed2);
public bool CanUseLayerWaitTimeAfterLift => HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterLift);
public bool CanUseLayerRetractSpeed => HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed);
+ public bool CanUseLayerRetractHeight2 => HaveLayerParameterModifier(PrintParameterModifier.RetractHeight2);
+ public bool CanUseLayerRetractSpeed2 => HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed2);
public bool CanUseLayerLightOffDelay => HaveLayerParameterModifier(PrintParameterModifier.LightOffDelay);
public bool CanUseLayerLightPWM => HaveLayerParameterModifier(PrintParameterModifier.LightPWM);
@@ -1106,9 +1372,12 @@ namespace UVtools.Core.FileFormats
var haveBottomLiftHeight = CanUseBottomLiftHeight;
var haveLiftHeight = CanUseLiftHeight;
+ var haveBottomLiftHeight2 = CanUseBottomLiftHeight2;
+ var haveLiftHeight2 = CanUseLiftHeight2;
- if (!haveBottomLiftHeight && !haveLiftHeight) return str;
+ if (!haveBottomLiftHeight && !haveLiftHeight && !haveBottomLiftHeight2 && !haveLiftHeight2) return str;
+ // Sequence 1
if (haveBottomLiftHeight)
{
str += BottomLiftHeight.ToString(CultureInfo.InvariantCulture);
@@ -1137,6 +1406,35 @@ namespace UVtools.Core.FileFormats
str += "mm/min";
+ // Sequence 2
+ if (haveBottomLiftHeight2)
+ {
+ str += $"\n2th: {BottomLiftHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
+ if (haveLiftHeight2)
+ {
+ str += str.EndsWith("mm/min") ? "\n2th: " : '/';
+ str += LiftHeight2.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (str.EndsWith("mm/min")) return str;
+
+ str += "mm @ ";
+
+ var haveBottomLiftSpeed2 = CanUseBottomLiftSpeed2;
+ var haveLiftSpeed2 = CanUseLiftSpeed2;
+ if (haveBottomLiftSpeed2)
+ {
+ str += BottomLiftSpeed2.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveLiftSpeed2)
+ {
+ if (haveBottomLiftSpeed2) str += '/';
+ str += LiftSpeed2.ToString(CultureInfo.InvariantCulture);
+ }
+
+ str += "mm/min";
+
return str;
}
}
@@ -1147,12 +1445,71 @@ namespace UVtools.Core.FileFormats
{
var str = string.Empty;
- if (CanUseRetractSpeed)
+ var haveBottomRetractHeight = CanUseLiftHeight;
+ var haveRetractHeight = CanUseBottomLiftHeight;
+ var haveBottomRetractSpeed = CanUseBottomRetractSpeed;
+ var haveRetractSpeed = CanUseRetractSpeed;
+ var haveBottomRetractHeight2 = CanUseBottomRetractHeight2;
+ var haveRetractHeight2 = CanUseRetractHeight2;
+ var haveBottomRetractSpeed2 = CanUseBottomRetractSpeed2;
+ var haveRetractSpeed2 = CanUseRetractSpeed2;
+
+ if (!haveBottomRetractSpeed && !haveRetractSpeed && !haveBottomRetractHeight2 && !haveRetractHeight2) return str;
+
+ // Sequence 1
+ if (haveBottomRetractHeight)
{
+ str += BottomRetractHeight.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveRetractHeight)
+ {
+ if (!string.IsNullOrEmpty(str)) str += '/';
+ str += RetractHeight.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (string.IsNullOrEmpty(str)) return str;
+
+ str += "mm @ ";
+
+
+ if (haveBottomRetractSpeed)
+ {
+ str += BottomRetractSpeed.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveRetractSpeed)
+ {
+ if (haveBottomRetractSpeed) str += '/';
str += RetractSpeed.ToString(CultureInfo.InvariantCulture);
}
- if (!string.IsNullOrEmpty(str)) str += "mm/min";
+ str += "mm/min";
+
+ // Sequence 2
+ if (haveBottomRetractHeight2)
+ {
+ str += $"\n2th: {BottomRetractHeight2.ToString(CultureInfo.InvariantCulture)}";
+ }
+ if (haveRetractHeight2)
+ {
+ str += str.EndsWith("mm/min") ? "\n2th: " : '/';
+ str += RetractHeight2.ToString(CultureInfo.InvariantCulture);
+ }
+
+ if (str.EndsWith("mm/min")) return str;
+
+ str += "mm @ ";
+
+ if (haveBottomRetractSpeed2)
+ {
+ str += BottomRetractSpeed2.ToString(CultureInfo.InvariantCulture);
+ }
+ if (haveRetractSpeed2)
+ {
+ if (haveBottomRetractSpeed2) str += '/';
+ str += RetractSpeed2.ToString(CultureInfo.InvariantCulture);
+ }
+
+ str += "mm/min";
return str;
}
@@ -1461,12 +1818,21 @@ namespace UVtools.Core.FileFormats
or nameof(BottomWaitTimeAfterCure)
or nameof(WaitTimeAfterCure)
or nameof(BottomLiftHeight)
+ or nameof(BottomLiftSpeed)
or nameof(LiftHeight)
- or nameof(BottomLiftSpeed)
or nameof(LiftSpeed)
+ or nameof(BottomLiftHeight2)
+ or nameof(BottomLiftSpeed2)
+ or nameof(LiftHeight2)
+ or nameof(LiftSpeed2)
or nameof(BottomWaitTimeAfterLift)
or nameof(WaitTimeAfterLift)
- or nameof(RetractSpeed)
+ or nameof(BottomRetractSpeed)
+ or nameof(RetractSpeed)
+ or nameof(BottomRetractHeight2)
+ or nameof(BottomRetractSpeed2)
+ or nameof(RetractHeight2)
+ or nameof(RetractSpeed2)
or nameof(BottomLightPWM)
or nameof(LightPWM)
)
@@ -1579,7 +1945,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Checks if a extension is valid under the <see cref="FileFormat"/>
/// </summary>
- /// <param name="extension">Extension to check</param>
+ /// <param name="extension">Extension to check without the dot (.)</param>
/// <param name="isFilePath">True if <see cref="extension"/> is a full file path, otherwise false for extension only</param>
/// <returns>True if valid, otherwise false</returns>
public bool IsExtensionValid(string extension, bool isFilePath = false)
@@ -1865,24 +2231,36 @@ namespace UVtools.Core.FileFormats
tw.WriteLine($"{nameof(layer.LayerHeight)}: {layer.LayerHeight}");
tw.WriteLine($"{nameof(layer.PositionZ)}: {layer.PositionZ}");
- if (HaveLayerParameterModifier(PrintParameterModifier.LightOffDelay))
+ if (CanUseLayerLightOffDelay)
tw.WriteLine($"{nameof(layer.LightOffDelay)}: {layer.LightOffDelay}");
- if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeBeforeCure))
+ if (CanUseLayerWaitTimeBeforeCure)
tw.WriteLine($"{nameof(layer.WaitTimeBeforeCure)}: {layer.WaitTimeBeforeCure}");
tw.WriteLine($"{nameof(layer.ExposureTime)}: {layer.ExposureTime}");
- if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterCure))
+ if (CanUseLayerWaitTimeAfterCure)
tw.WriteLine($"{nameof(layer.WaitTimeAfterCure)}: {layer.WaitTimeAfterCure}");
- if (HaveLayerParameterModifier(PrintParameterModifier.LiftHeight))
+ if (CanUseLayerLiftHeight)
tw.WriteLine($"{nameof(layer.LiftHeight)}: {layer.LiftHeight}");
- if (HaveLayerParameterModifier(PrintParameterModifier.LiftSpeed))
+ if (CanUseLayerLiftSpeed)
tw.WriteLine($"{nameof(layer.LiftSpeed)}: {layer.LiftSpeed}");
- if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterLift))
+ if (CanUseLayerLiftHeight2)
+ tw.WriteLine($"{nameof(layer.LiftHeight2)}: {layer.LiftHeight2}");
+ if (CanUseLayerLiftSpeed2)
+ tw.WriteLine($"{nameof(layer.LiftSpeed2)}: {layer.LiftSpeed2}");
+ if (CanUseLayerWaitTimeAfterLift)
tw.WriteLine($"{nameof(layer.WaitTimeAfterLift)}: {layer.WaitTimeAfterLift}");
- if (HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed))
+ if (CanUseLayerRetractSpeed)
+ {
+ tw.WriteLine($"{nameof(layer.RetractHeight)}: {layer.RetractHeight}");
tw.WriteLine($"{nameof(layer.RetractSpeed)}: {layer.RetractSpeed}");
- if (HaveLayerParameterModifier(PrintParameterModifier.LightPWM))
+ }
+ if (CanUseLayerRetractHeight2)
+ tw.WriteLine($"{nameof(layer.RetractHeight2)}: {layer.RetractHeight2}");
+ if (CanUseLayerRetractSpeed2)
+ tw.WriteLine($"{nameof(layer.RetractSpeed2)}: {layer.RetractSpeed2}");
+
+ if (CanUseLayerLightPWM)
tw.WriteLine($"{nameof(layer.LightPWM)}: {layer.LightPWM}");
var materialMillilitersPercent = layer.MaterialMillilitersPercent;
@@ -2025,14 +2403,14 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.BottomLiftHeight.Value = (decimal)BottomLiftHeight;
}
- if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftHeight))
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftSpeed))
{
- PrintParameterModifier.LiftHeight.Value = (decimal)LiftHeight;
+ PrintParameterModifier.BottomLiftSpeed.Value = (decimal)BottomLiftSpeed;
}
- if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftSpeed))
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftHeight))
{
- PrintParameterModifier.BottomLiftSpeed.Value = (decimal)BottomLiftSpeed;
+ PrintParameterModifier.LiftHeight.Value = (decimal)LiftHeight;
}
if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftSpeed))
@@ -2040,6 +2418,26 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftSpeed.Value = (decimal)LiftSpeed;
}
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftHeight2))
+ {
+ PrintParameterModifier.BottomLiftHeight2.Value = (decimal)BottomLiftHeight2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftSpeed2))
+ {
+ PrintParameterModifier.BottomLiftSpeed2.Value = (decimal)BottomLiftSpeed2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftHeight2))
+ {
+ PrintParameterModifier.LiftHeight2.Value = (decimal)LiftHeight2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftSpeed2))
+ {
+ PrintParameterModifier.LiftSpeed2.Value = (decimal)LiftSpeed2;
+ }
+
if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomWaitTimeAfterLift))
{
PrintParameterModifier.BottomWaitTimeAfterLift.Value = (decimal)BottomWaitTimeAfterLift;
@@ -2050,11 +2448,36 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterLift.Value = (decimal)WaitTimeAfterLift;
}
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomRetractSpeed))
+ {
+ PrintParameterModifier.BottomRetractSpeed.Value = (decimal)BottomRetractSpeed;
+ }
+
if (PrintParameterModifiers.Contains(PrintParameterModifier.RetractSpeed))
{
PrintParameterModifier.RetractSpeed.Value = (decimal)RetractSpeed;
}
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomRetractHeight2))
+ {
+ PrintParameterModifier.BottomRetractHeight2.Value = (decimal)BottomRetractHeight2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomRetractSpeed2))
+ {
+ PrintParameterModifier.BottomRetractSpeed2.Value = (decimal)BottomRetractSpeed2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.RetractHeight2))
+ {
+ PrintParameterModifier.RetractHeight2.Value = (decimal)RetractHeight2;
+ }
+
+ if (PrintParameterModifiers.Contains(PrintParameterModifier.RetractSpeed2))
+ {
+ PrintParameterModifier.RetractSpeed2.Value = (decimal)RetractSpeed2;
+ }
+
if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLightPWM))
{
PrintParameterModifier.BottomLightPWM.Value = BottomLightPWM;
@@ -2104,6 +2527,16 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftSpeed.Value = (decimal)layer.LiftSpeed;
}
+ if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LiftHeight2))
+ {
+ PrintParameterModifier.LiftHeight2.Value = (decimal)layer.LiftHeight2;
+ }
+
+ if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LiftSpeed2))
+ {
+ PrintParameterModifier.LiftSpeed2.Value = (decimal)layer.LiftSpeed2;
+ }
+
if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.WaitTimeAfterLift))
{
PrintParameterModifier.WaitTimeAfterLift.Value = (decimal)layer.WaitTimeAfterLift;
@@ -2114,6 +2547,16 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.RetractSpeed.Value = (decimal)layer.RetractSpeed;
}
+ if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.RetractHeight2))
+ {
+ PrintParameterModifier.RetractHeight2.Value = (decimal)layer.RetractHeight2;
+ }
+
+ if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.RetractSpeed2))
+ {
+ PrintParameterModifier.RetractSpeed2.Value = (decimal)layer.RetractSpeed2;
+ }
+
if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LightPWM))
{
PrintParameterModifier.LightPWM.Value = layer.LightPWM;
@@ -2159,14 +2602,36 @@ namespace UVtools.Core.FileFormats
if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed))
return LiftSpeed;
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftHeight2))
+ return BottomLiftHeight2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.LiftHeight2))
+ return LiftHeight2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftSpeed2))
+ return BottomLiftSpeed2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed2))
+ return LiftSpeed2;
+
if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterLift))
return BottomWaitTimeAfterLift;
if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeAfterLift))
return WaitTimeAfterLift;
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractSpeed))
+ return BottomRetractSpeed;
if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed))
return RetractSpeed;
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractHeight2))
+ return BottomRetractHeight2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.RetractHeight2))
+ return RetractHeight2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractSpeed2))
+ return BottomRetractSpeed2;
+ if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed2))
+ return RetractSpeed2;
+
+
+
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightPWM))
return BottomLightPWM;
if (ReferenceEquals(modifier, PrintParameterModifier.LightPWM))
@@ -2254,6 +2719,27 @@ namespace UVtools.Core.FileFormats
return true;
}
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftHeight2))
+ {
+ BottomLiftHeight2 = (float)value;
+ return true;
+ }
+ if (ReferenceEquals(modifier, PrintParameterModifier.LiftHeight2))
+ {
+ LiftHeight2 = (float)value;
+ return true;
+ }
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftSpeed2))
+ {
+ BottomLiftSpeed2 = (float)value;
+ return true;
+ }
+ if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed2))
+ {
+ LiftSpeed2 = (float)value;
+ return true;
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterLift))
{
BottomWaitTimeAfterLift = (float)value;
@@ -2265,12 +2751,41 @@ namespace UVtools.Core.FileFormats
return true;
}
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractSpeed))
+ {
+ BottomRetractSpeed = (float)value;
+ return true;
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed))
{
RetractSpeed = (float) value;
return true;
}
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractHeight2))
+ {
+ BottomRetractHeight2 = (float)value;
+ return true;
+ }
+
+ if (ReferenceEquals(modifier, PrintParameterModifier.RetractHeight2))
+ {
+ RetractHeight2 = (float)value;
+ return true;
+ }
+ if (ReferenceEquals(modifier, PrintParameterModifier.BottomRetractSpeed2))
+ {
+ BottomRetractSpeed2 = (float)value;
+ return true;
+ }
+
+ if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed2))
+ {
+ RetractSpeed2 = (float)value;
+ return true;
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightPWM))
{
BottomLightPWM = (byte)value;
@@ -2315,17 +2830,15 @@ namespace UVtools.Core.FileFormats
public float CalculateMotorMovementTime(bool isBottomLayer, float extraTime = 0)
{
return isBottomLayer
- ? OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, RetractSpeed, extraTime)
- : OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed, extraTime);
+ ? OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, BottomRetractSpeed, extraTime, BottomLiftHeight2, BottomLiftSpeed2, BottomRetractHeight2, BottomRetractSpeed2)
+ : OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed, extraTime, LiftHeight2, LiftSpeed2, RetractHeight2, RetractSpeed2);
}
public float CalculateLightOffDelay(bool isBottomLayer, float extraTime = 0)
{
extraTime = (float)Math.Round(extraTime, 2);
if (SupportsGCode) return extraTime;
- return isBottomLayer
- ? OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, RetractSpeed, extraTime)
- : OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed, extraTime);
+ return CalculateMotorMovementTime(isBottomLayer, extraTime);
}
public bool SetLightOffDelay(bool isBottomLayer, float extraTime = 0)
@@ -2415,13 +2928,23 @@ namespace UVtools.Core.FileFormats
// Lift
slicerFile.BottomLiftHeight = BottomLiftHeight;
- slicerFile.LiftHeight = LiftHeight;
-
slicerFile.BottomLiftSpeed = BottomLiftSpeed;
+ slicerFile.LiftHeight = LiftHeight;
slicerFile.LiftSpeed = LiftSpeed;
-
+
+ slicerFile.BottomLiftHeight2 = BottomLiftHeight2;
+ slicerFile.BottomLiftSpeed2 = BottomLiftSpeed2;
+ slicerFile.LiftHeight2 = LiftHeight2;
+ slicerFile.LiftSpeed2 = LiftSpeed2;
+
+ slicerFile.BottomRetractSpeed = BottomRetractSpeed;
slicerFile.RetractSpeed = RetractSpeed;
+ slicerFile.BottomRetractHeight2 = BottomRetractHeight2;
+ slicerFile.BottomRetractSpeed2 = BottomRetractSpeed2;
+ slicerFile.RetractHeight2 = RetractHeight2;
+ slicerFile.RetractSpeed2 = RetractSpeed2;
+
// Wait times
slicerFile.BottomLightOffDelay = BottomLightOffDelay;
slicerFile.LightOffDelay = LightOffDelay;
@@ -2526,6 +3049,50 @@ namespace UVtools.Core.FileFormats
return result;
}
+ public void UpdateGlobalPropertiesFromLayers()
+ {
+ if (LayerCount == 0) return;
+
+ SuppressRebuildPropertiesWork(() =>
+ {
+ var bottomLayer = FirstLayer;
+ if (bottomLayer is not null)
+ {
+ if (bottomLayer.LightOffDelay > 0) BottomLightOffDelay = bottomLayer.LightOffDelay;
+ if (bottomLayer.WaitTimeBeforeCure > 0) BottomWaitTimeBeforeCure = bottomLayer.WaitTimeBeforeCure;
+ if (bottomLayer.ExposureTime > 0) BottomExposureTime = bottomLayer.ExposureTime;
+ if (bottomLayer.WaitTimeAfterCure > 0) BottomWaitTimeAfterCure = bottomLayer.WaitTimeAfterCure;
+ if (bottomLayer.LiftHeight > 0) BottomLiftHeight = bottomLayer.LiftHeight;
+ if (bottomLayer.LiftSpeed > 0) BottomLiftSpeed = bottomLayer.LiftSpeed;
+ if (bottomLayer.LiftHeight2 > 0) BottomLiftHeight2 = bottomLayer.LiftHeight2;
+ if (bottomLayer.LiftSpeed2 > 0) BottomLiftSpeed2 = bottomLayer.LiftSpeed2;
+ if (bottomLayer.WaitTimeAfterLift > 0) BottomWaitTimeAfterLift = bottomLayer.WaitTimeAfterLift;
+ if (bottomLayer.RetractSpeed > 0) BottomRetractSpeed = bottomLayer.RetractSpeed;
+ if (bottomLayer.RetractHeight2 > 0) BottomRetractHeight2 = bottomLayer.RetractHeight2;
+ if (bottomLayer.RetractSpeed2 > 0) BottomRetractSpeed2 = bottomLayer.RetractSpeed2;
+ if (bottomLayer.LightPWM > 0) BottomLightPWM = bottomLayer.LightPWM;
+ }
+
+ var normalLayer = LastLayer;
+ if (normalLayer is not null)
+ {
+ if (normalLayer.LightOffDelay > 0) LightOffDelay = normalLayer.LightOffDelay;
+ if (normalLayer.WaitTimeBeforeCure > 0) WaitTimeBeforeCure = normalLayer.WaitTimeBeforeCure;
+ if (normalLayer.ExposureTime > 0) ExposureTime = normalLayer.ExposureTime;
+ if (normalLayer.WaitTimeAfterCure > 0) WaitTimeAfterCure = normalLayer.WaitTimeAfterCure;
+ if (normalLayer.LiftHeight > 0) LiftHeight = normalLayer.LiftHeight;
+ if (normalLayer.LiftSpeed > 0) LiftSpeed = normalLayer.LiftSpeed;
+ if (normalLayer.LiftHeight2 > 0) LiftHeight2 = normalLayer.LiftHeight2;
+ if (normalLayer.LiftSpeed2 > 0) LiftSpeed2 = normalLayer.LiftSpeed2;
+ if (normalLayer.WaitTimeAfterLift > 0) WaitTimeAfterLift = normalLayer.WaitTimeAfterLift;
+ if (normalLayer.RetractSpeed > 0) RetractSpeed = normalLayer.RetractSpeed;
+ if (normalLayer.RetractHeight2 > 0) RetractHeight2 = normalLayer.RetractHeight2;
+ if (normalLayer.RetractSpeed2 > 0) RetractSpeed2 = normalLayer.RetractSpeed2;
+ if (normalLayer.LightPWM > 0) LightPWM = normalLayer.LightPWM;
+ }
+ });
+ }
+
public void UpdatePrintTime()
{
PrintTime = PrintTimeComputed;
@@ -2534,8 +3101,11 @@ namespace UVtools.Core.FileFormats
public void UpdatePrintTimeQueued()
{
- _queueTimerPrintTime.Stop();
- _queueTimerPrintTime.Start();
+ lock (Mutex)
+ {
+ _queueTimerPrintTime.Stop();
+ _queueTimerPrintTime.Start();
+ }
}
#endregion
diff --git a/UVtools.Core/FileFormats/GR1File.cs b/UVtools.Core/FileFormats/GR1File.cs
index fdf8ef2..4e977eb 100644
--- a/UVtools.Core/FileFormats/GR1File.cs
+++ b/UVtools.Core/FileFormats/GR1File.cs
@@ -332,6 +332,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = SlicerInfoSettings.LiftSpeed = (ushort)value;
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => SlicerInfoSettings.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs
index 5ecbe22..78e09b1 100644
--- a/UVtools.Core/FileFormats/LGSFile.cs
+++ b/UVtools.Core/FileFormats/LGSFile.cs
@@ -92,28 +92,32 @@ namespace UVtools.Core.FileFormats
[FieldOrder(1)]
[FieldLength(nameof(DataSize))]
- public byte[] EncodedRle { get; set; }
+ public byte[] PngBytes { get; set; }
+
+ [FieldOrder(2)] public ushort Padding { get; set; }
public void Encode(Mat mat)
{
+ mat ??= EmguExtensions.InitMat(new Size(ResolutionX, ResolutionY), 3);
+
if (mat.Width != ResolutionX || mat.Height != ResolutionY)
{
using var resizeMat = new Mat();
CvInvoke.Resize(mat, resizeMat, new Size(ResolutionX, ResolutionY));
- EncodedRle = resizeMat.GetPngByes();
+ PngBytes = resizeMat.GetPngByes();
}
else
{
- EncodedRle = mat.GetPngByes();
+ PngBytes = mat.GetPngByes();
}
}
public Mat Decode(bool consumeRle = true)
{
var mat = new Mat();
- CvInvoke.Imdecode(EncodedRle, ImreadModes.AnyColor, mat);
+ CvInvoke.Imdecode(PngBytes, ImreadModes.AnyColor, mat);
if (consumeRle)
- EncodedRle = null;
+ PngBytes = null;
return mat;
}
}
@@ -133,10 +137,23 @@ namespace UVtools.Core.FileFormats
[FieldLength(nameof(DataSize))]
public byte[] EncodedRle { get; set; }
+ public LayerData() { }
+
+ public LayerData(LGSFile parent)
+ {
+ Parent = parent;
+ }
+
public unsafe byte[] Encode(Mat mat)
{
List<byte> rawData = new();
List<byte> chunk = new();
+
+ if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
+ {
+ CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90Clockwise);
+ }
+
var spanMat = mat.GetBytePointer();
var imageLength = mat.GetLength();
@@ -171,65 +188,66 @@ namespace UVtools.Core.FileFormats
addSpan();
EncodedRle = rawData.ToArray();
DataSize = (uint) EncodedRle.Length;
+
+ if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
+ {
+ CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90CounterClockwise);
+ }
+
return EncodedRle;
}
- public unsafe Mat Decode(bool consumeRle = true)
+ public Mat Decode(bool consumeRle = true)
{
- var mat = EmguExtensions.InitMat(Parent.Resolution);
- var matSpan = mat.GetBytePointer();
+ // lgs10/30 -------->
+ // lgs120/4k From Y bottom to top Y
+ var mat = EmguExtensions.InitMat(Parent.HeaderSettings.PrinterModel is 4000 or 4500 ? Parent.Resolution.Exchange() : Parent.Resolution);
+ //var matSpan = mat.GetBytePointer();
var imageLength = mat.GetLength();
+
+ int pixelPos = 0;
- byte last = 0;
- int span = 0;
- int index = 0;
-
- foreach (var b in EncodedRle)
+ for (var i = 0; i < EncodedRle.Length; i++)
{
- byte color = (byte) ((b & 0xf0) | (b >> 4));
+ var b = EncodedRle[i];
+ byte colorNibble = (byte)(b >> 4);
+ byte color = (byte)(colorNibble << 0x4 | colorNibble);
+ int repeat = b & 0xf;
- if (color == last)
+ while (i + 1 < EncodedRle.Length && (EncodedRle[i + 1] >> 4) == colorNibble)
{
- span = (span << 4) | (b & 0xf);
+ i++;
+ repeat = (repeat << 4) | (EncodedRle[i] & 0xf);
}
- else
- {
- for(; span > 0; span--)
- {
- if (index >= imageLength)
- {
- throw new FileLoadException($"'{span}' bytes to many");
- }
-
- matSpan[index++] = last;
- }
-
- span = b & 0xf;
+ if (pixelPos >= imageLength)
+ {
+ throw new FileLoadException($"Too much buffer, expected: {imageLength}, got: {pixelPos}");
}
- last = color;
- }
+ mat.FillSpan(ref pixelPos, repeat, color);
- for (; span > 0; span--)
- {
- if (index >= imageLength)
+ //if (repeat <= 0) continue;
+ /*while (repeat-- > 0)
{
- throw new FileLoadException($"'{span}' bytes to many");
- }
+ matSpan[pixel++] = color;
+ }*/
- matSpan[index++] = last;
}
- if (index != imageLength)
+ if (pixelPos != imageLength)
{
- throw new FileLoadException($"Incomplete buffer, expected: {imageLength}, got: {index}");
+ throw new FileLoadException($"Incomplete buffer, expected: {imageLength}, got: {pixelPos}");
}
-
if (consumeRle)
EncodedRle = null;
+ if (Parent.HeaderSettings.PrinterModel is 4000 or 4500)
+ {
+ CvInvoke.Rotate(mat, mat, RotateFlags.Rotate90CounterClockwise);
+ }
+
return mat;
}
}
@@ -245,8 +263,8 @@ namespace UVtools.Core.FileFormats
public override FileExtension[] FileExtensions { get; } = {
new ("lgs", "Longer Orange 10"),
new ("lgs30", "Longer Orange 30"),
- //new ("lgs120", "Longer Orange 120"),
- //new ("lgs4k", "Longer Orange 4k"),
+ new ("lgs120", "Longer Orange 120"),
+ new ("lgs4k", "Longer Orange 4k"),
};
public override PrintParameterModifier[] PrintParameterModifiers { get; } =
@@ -448,6 +466,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = HeaderSettings.LiftSpeed = HeaderSettings.LiftSpeed_ = value;
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed => LiftSpeed;
/*public override float PrintTime => 0;
@@ -548,6 +568,15 @@ namespace UVtools.Core.FileFormats
outputFile.WriteSerialize(HeaderSettings);
outputFile.WriteBytes(PreviewEncode(Thumbnails[0]));
+ if (HeaderSettings.PrinterModel == 120)
+ {
+ // Insert PNG here
+ var mat = GetThumbnail(true);
+ var pngPreview = new LGS120PngPreview();
+ pngPreview.Encode(mat);
+ outputFile.WriteSerialize(pngPreview);
+ }
+
var layerData = new LayerData[LayerCount];
Parallel.For(0, LayerCount, layerIndex =>
@@ -555,7 +584,7 @@ namespace UVtools.Core.FileFormats
if (progress.Token.IsCancellationRequested) return;
using (var mat = this[layerIndex].LayerMat)
{
- layerData[layerIndex] = new LayerData();
+ layerData[layerIndex] = new LayerData(this);
layerData[layerIndex].Encode(mat);
}
@@ -587,13 +616,14 @@ namespace UVtools.Core.FileFormats
throw new FileLoadException("Not a valid LGS file!", fileFullPath);
}
- // Fix inconsistencies found of different version of plugin and slicers
- if (ResolutionX > ResolutionY)
- {
- var oldX = ResolutionX;
- ResolutionX = ResolutionY;
- ResolutionY = oldX;
- }
+ //if (HeaderSettings.PrinterModel is 10 or 30 or 120)
+ //{
+ // Fix inconsistencies found of different version of plugin and slicers
+ if (ResolutionX > ResolutionY)
+ {
+ (ResolutionX, ResolutionY) = (ResolutionY, ResolutionX);
+ }
+ //}
int previewSize = (int) (HeaderSettings.PreviewSizeX * HeaderSettings.PreviewSizeY * 2);
byte[] previewData = new byte[previewSize];
@@ -603,13 +633,13 @@ namespace UVtools.Core.FileFormats
currentOffset += inputFile.ReadBytes(previewData);
Thumbnails[0] = PreviewDecode(previewData);
- if (FileEndsWith(".lgs120"))
+ if (HeaderSettings.PrinterModel == 120)
{
var pngPreview = Helpers.Deserialize<LGS120PngPreview>(inputFile);
}
- LayerData[] layerData = new LayerData[HeaderSettings.LayerCount];
+ var layerData = new LayerData[HeaderSettings.LayerCount];
progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.LayerCount);
for (int layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
@@ -656,12 +686,9 @@ namespace UVtools.Core.FileFormats
FileFullPath = filePath;
}
- using (var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write))
- {
-
- outputFile.Seek(0, SeekOrigin.Begin);
- Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- }
+ using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write);
+ outputFile.Seek(0, SeekOrigin.Begin);
+ Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
}
#endregion
diff --git a/UVtools.Core/FileFormats/OSLAFile.cs b/UVtools.Core/FileFormats/OSLAFile.cs
index 94d956d..d513036 100644
--- a/UVtools.Core/FileFormats/OSLAFile.cs
+++ b/UVtools.Core/FileFormats/OSLAFile.cs
@@ -98,7 +98,7 @@ namespace UVtools.Core.FileFormats
[FieldOrder(11)] public float LayerHeight { get; set; } = 0.05f;
[FieldOrder(12)] public ushort BottomLayersCount { get; set; } = 4;
[FieldOrder(13)] public uint LayerCount { get; set; }
- [FieldOrder(14)] public uint LayerTableSize { get; set; } = 4;
+ [FieldOrder(14)] public uint LayerTableSize { get; set; } = 69;
[FieldOrder(15)] public uint LayerDefinitionsAddress { get; set; }
[FieldOrder(16)] public uint GCodeAddress { get; set; }
[FieldOrder(17)] public uint PrintTime { get; set; }
@@ -107,6 +107,7 @@ namespace UVtools.Core.FileFormats
[FieldOrder(20)] [FieldLength(50)] [SerializeAs(SerializedType.TerminatedString)] public string MaterialName { get; set; }
[FieldOrder(21)] [FieldLength(50)] [SerializeAs(SerializedType.TerminatedString)] public string MachineName { get; set; } = "Unknown";
+
public override string ToString()
{
return $"{nameof(TableSize)}: {TableSize}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(MachineZ)}: {MachineZ}, {nameof(DisplayWidth)}: {DisplayWidth}, {nameof(DisplayHeight)}: {DisplayHeight}, {nameof(DisplayMirror)}: {DisplayMirror}, {nameof(PreviewDataType)}: {PreviewDataType}, {nameof(LayerDataType)}: {LayerDataType}, {nameof(PreviewTableSize)}: {PreviewTableSize}, {nameof(PreviewCount)}: {PreviewCount}, {nameof(LayerTableSize)}: {LayerTableSize}, {nameof(BottomLayersCount)}: {BottomLayersCount}, {nameof(LayerCount)}: {LayerCount}, {nameof(LayerDefinitionsAddress)}: {LayerDefinitionsAddress}, {nameof(GCodeAddress)}: {GCodeAddress}, {nameof(PrintTime)}: {PrintTime}, {nameof(MaterialMilliliters)}: {MaterialMilliliters}, {nameof(MaterialCost)}: {MaterialCost}, {nameof(MaterialName)}: {MaterialName}, {nameof(MachineName)}: {MachineName}";
@@ -161,17 +162,68 @@ namespace UVtools.Core.FileFormats
#region Layer
public class LayerDef
{
- [FieldOrder(0)] public uint DataAddress { get; set; }
-
- [Ignore] public byte[] ImageData { get; set; }
+ //[FieldOrder(0)] public uint DataAddress { get; set; }
+
+ [FieldOrder(1)] public float PositionZ { get; set; }
+ [FieldOrder(2)] public float LiftHeight { get; set; }
+ [FieldOrder(3)] public float LiftSpeed { get; set; }
+ [FieldOrder(4)] public float LiftHeight2 { get; set; }
+ [FieldOrder(5)] public float LiftSpeed2 { get; set; }
+ [FieldOrder(6)] public float WaitTimeAfterLift { get; set; }
+ [FieldOrder(7)] public float RetractSpeed { get; set; }
+ [FieldOrder(8)] public float RetractHeight2 { get; set; }
+ [FieldOrder(9)] public float RetractSpeed2 { get; set; }
+ [FieldOrder(10)] public float WaitTimeBeforeCure { get; set; }
+ [FieldOrder(11)] public float ExposureTime { get; set; }
+ [FieldOrder(12)] public float WaitTimeAfterCure { get; set; }
+ [FieldOrder(13)] public byte LightPWM { get; set; }
+ [FieldOrder(14)] public uint BoundingRectangleX { get; set; }
+ [FieldOrder(15)] public uint BoundingRectangleY { get; set; }
+ [FieldOrder(16)] public uint BoundingRectangleWidth { get; set; }
+ [FieldOrder(17)] public uint BoundingRectangleHeight { get; set; }
+
+ //[Ignore] public byte[] ImageData { get; set; }
public LayerDef()
{
}
- public override string ToString()
+ public LayerDef(Layer layer)
{
- return $"{nameof(DataAddress)}: {DataAddress}, {nameof(ImageData)}: {ImageData.Length}";
+ PositionZ = layer.PositionZ;
+ LiftHeight = layer.LiftHeight;
+ LiftSpeed = layer.LiftSpeed;
+ LiftHeight2 = layer.LiftHeight2;
+ LiftSpeed2 = layer.LiftSpeed2;
+ WaitTimeAfterLift = layer.WaitTimeAfterLift;
+ RetractSpeed = layer.RetractSpeed;
+ RetractHeight2 = layer.RetractHeight2;
+ RetractSpeed2 = layer.RetractSpeed2;
+ WaitTimeBeforeCure = layer.WaitTimeBeforeCure;
+ ExposureTime = layer.ExposureTime;
+ WaitTimeAfterCure = layer.WaitTimeAfterCure;
+ LightPWM = layer.LightPWM;
+ BoundingRectangleX = (uint)layer.BoundingRectangle.X;
+ BoundingRectangleY = (uint)layer.BoundingRectangle.Y;
+ BoundingRectangleWidth = (uint)layer.BoundingRectangle.Width;
+ BoundingRectangleHeight = (uint)layer.BoundingRectangle.Height;
+ }
+
+ public void SetTo(Layer layer)
+ {
+ layer.PositionZ = PositionZ;
+ layer.LiftHeight = LiftHeight;
+ layer.LiftSpeed = LiftSpeed;
+ layer.LiftHeight2 = LiftHeight2;
+ layer.LiftSpeed2 = LiftSpeed2;
+ layer.WaitTimeAfterLift = WaitTimeAfterLift;
+ layer.RetractSpeed = RetractSpeed;
+ layer.RetractHeight2 = RetractHeight2;
+ layer.RetractSpeed2 = RetractSpeed2;
+ layer.WaitTimeBeforeCure = WaitTimeBeforeCure;
+ layer.ExposureTime = ExposureTime;
+ layer.WaitTimeAfterCure = WaitTimeAfterCure;
+ layer.LightPWM = LightPWM;
}
}
#endregion
@@ -205,8 +257,7 @@ namespace UVtools.Core.FileFormats
//new ("odlp", "Open DLP universal binary file"),
};
- public override PrintParameterModifier[] PrintParameterModifiers { get; } =
- {
+ public override PrintParameterModifier[] PrintParameterModifiers { get; } = {
PrintParameterModifier.BottomLayerCount,
PrintParameterModifier.BottomWaitTimeBeforeCure,
@@ -223,11 +274,21 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
-
+
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
@@ -239,8 +300,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.LightPWM,
};
@@ -464,7 +529,7 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(HeaderSettings.LayerTableSize * LayerCount, SeekOrigin.Current); // Start of layer data
var layerHash = new Dictionary<string, uint>();
-
+
var range = Enumerable.Range(0, (int)LayerCount);
foreach (var batch in range.Batch(Environment.ProcessorCount * 10))
{
@@ -496,23 +561,30 @@ namespace UVtools.Core.FileFormats
layerHash.Add(hash, layerDataAddresses[layerIndex]);
}
-
-
layerBytes[layerIndex] = null; // Clean
}
}
HeaderSettings.GCodeAddress = (uint)outputFile.Position;
+ uint layerTableSize = 0;
outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
- for (int i = 0; i < layerDataAddresses.Length; i++)
+ for (int layerIndex = 0; layerIndex < layerDataAddresses.Length; layerIndex++)
{
progress.Token.ThrowIfCancellationRequested();
- outputFile.WriteUIntLittleEndian(layerDataAddresses[i]);
- // Need to fill what we don't know
- if (HeaderSettings.LayerTableSize > 4)
+
+ var layer = this[layerIndex];
+ var layerdef = new LayerDef(layer);
+
+ outputFile.WriteUIntLittleEndian(layerDataAddresses[layerIndex]);
+ Helpers.SerializeWriteFileStream(outputFile, layerdef);
+ if (layerTableSize == 0)
{
- outputFile.Seek(HeaderSettings.LayerTableSize - 4, SeekOrigin.Current);
+ layerTableSize = 4 + (uint)Helpers.Serializer.SizeOf(layerdef);
+ }
+ if (HeaderSettings.LayerTableSize > layerTableSize)
+ {
+ outputFile.Seek(HeaderSettings.LayerTableSize - layerTableSize, SeekOrigin.Current);
}
}
@@ -581,15 +653,25 @@ namespace UVtools.Core.FileFormats
inputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
LayerManager.Init(HeaderSettings.LayerCount);
+ var layerDef = new LayerDef[LayerCount];
+
+
progress.Reset(OperationProgress.StatusGatherLayers, HeaderSettings.LayerCount);
uint[] layerDataAddresses = new uint[LayerCount];
+ uint layerTableSize = 0;
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
progress.Token.ThrowIfCancellationRequested();
layerDataAddresses[layerIndex] = inputFile.ReadUIntLittleEndian();
- if (HeaderSettings.LayerTableSize > 4)
+
+ layerDef[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
+ if (layerTableSize == 0)
{
- inputFile.Seek(HeaderSettings.LayerTableSize - 4, SeekOrigin.Current);
+ layerTableSize = 4 + (uint)Helpers.Serializer.SizeOf(layerDef[layerIndex]);
+ }
+ if (HeaderSettings.LayerTableSize > layerTableSize)
+ {
+ inputFile.Seek(HeaderSettings.LayerTableSize - layerTableSize, SeekOrigin.Current);
}
progress++;
@@ -615,7 +697,9 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
using var mat = DecodeImage(layerBytes[layerIndex], HeaderSettings.LayerDataType, Resolution);
- this[layerIndex] = new Layer((uint)layerIndex, mat, this);
+ var layer = new Layer((uint)layerIndex, mat, this);
+ layerDef[layerIndex].SetTo(layer);
+ this[layerIndex] = layer;
layerBytes[layerIndex] = null; // Clean
progress.LockAndIncrement();
@@ -626,7 +710,9 @@ namespace UVtools.Core.FileFormats
inputFile.Seek(HeaderSettings.GCodeAddress, SeekOrigin.Begin);
var gcodeDef = Helpers.Deserialize<GCodeDef>(inputFile);
GCodeStr = gcodeDef.GCodeText;
- GCode.ParseLayersFromGCode(this);
+ //GCode.ParseLayersFromGCode(this);
+
+ UpdateGlobalPropertiesFromLayers();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
@@ -653,13 +739,23 @@ namespace UVtools.Core.FileFormats
Helpers.SerializeWriteFileStream(outputFile, FileSettings);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
- outputFile.Seek(HeaderSettings.GCodeAddress, SeekOrigin.Begin);
- outputFile.SetLength(HeaderSettings.GCodeAddress);
+ outputFile.Seek(HeaderSettings.LayerDefinitionsAddress, SeekOrigin.Begin);
+ foreach (var layer in this)
+ {
+ outputFile.Seek(4, SeekOrigin.Current); // skip address
+ Helpers.SerializeWriteFileStream(outputFile, new LayerDef(layer)); // Update layer values
+ }
- RebuildGCode();
- var gcodeSettings = new GCodeDef {GCodeText = GCodeStr};
- gcodeSettings.GCodeSize = (uint) gcodeSettings.GCodeText.Length;
- Helpers.SerializeWriteFileStream(outputFile, gcodeSettings);
+ if (HeaderSettings.GCodeAddress > 0)
+ {
+ outputFile.Seek(HeaderSettings.GCodeAddress, SeekOrigin.Begin);
+ outputFile.SetLength(HeaderSettings.GCodeAddress);
+
+ RebuildGCode();
+ var gcodeSettings = new GCodeDef { GCodeText = GCodeStr };
+ gcodeSettings.GCodeSize = (uint)gcodeSettings.GCodeText.Length;
+ Helpers.SerializeWriteFileStream(outputFile, gcodeSettings);
+ }
}
#endregion
diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index 65e7819..9f7f063 100644
--- a/UVtools.Core/FileFormats/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -891,6 +891,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = HeaderSettings.LiftSpeed = (float)Math.Round(value, 2);
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => HeaderSettings.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs
index 21436be..429cdf2 100644
--- a/UVtools.Core/FileFormats/PhotonSFile.cs
+++ b/UVtools.Core/FileFormats/PhotonSFile.cs
@@ -165,44 +165,52 @@ namespace UVtools.Core.FileFormats
public unsafe Mat Decode(bool consumeRle = true)
{
var mat = EmguExtensions.InitMat(new Size((int) ResolutionX, (int) ResolutionY));
- var matSpan = mat.GetBytePointer();
+ //var matSpan = mat.GetBytePointer();
var imageLength = mat.GetLength();
- uint pixel = 0;
+ int pixelPos = 0;
foreach (var run in EncodedRle)
{
+ if (pixelPos > imageLength)
+ {
+ mat.Dispose();
+ throw new FileLoadException($"Error image ran off the end, expecting {imageLength} pixels.");
+ }
+
byte brightness = (byte) ((run & 0x01) * 255);
- uint numPixelsInRun =
- (uint) ((((run & 128) > 0 ? 1 : 0) |
- ((run & 64) > 0 ? 2 : 0) |
- ((run & 32) > 0 ? 4 : 0) |
- ((run & 16) > 0 ? 8 : 0) |
- ((run & 8) > 0 ? 16 : 0) |
- ((run & 4) > 0 ? 32 : 0) |
- ((run & 2) > 0 ? 64 : 0)) + 1);
+ int numPixelsInRun =
+ (((run & 128) > 0 ? 1 : 0) |
+ ((run & 64) > 0 ? 2 : 0) |
+ ((run & 32) > 0 ? 4 : 0) |
+ ((run & 16) > 0 ? 8 : 0) |
+ ((run & 8) > 0 ? 16 : 0) |
+ ((run & 4) > 0 ? 32 : 0) |
+ ((run & 2) > 0 ? 64 : 0)) + 1;
- if (brightness == 0) // Don't fill black pixels
+ mat.FillSpan(ref pixelPos, numPixelsInRun, brightness);
+
+ /*if (brightness == 0) // Don't fill black pixels
{
- pixel += numPixelsInRun;
+ pixelPos += numPixelsInRun;
continue;
}
for (; numPixelsInRun > 0; numPixelsInRun--)
{
- if (pixel > imageLength)
+ if (pixelPos > imageLength)
{
mat.Dispose();
throw new FileLoadException($"Error image ran off the end, expecting {imageLength} pixels.");
}
- matSpan[pixel++] = brightness;
- }
+ matSpan[pixelPos++] = brightness;
+ }*/
}
- if (pixel != imageLength && pixel-1 != imageLength)
+ if (pixelPos != imageLength && pixelPos-1 != imageLength)
{
mat.Dispose();
- throw new FileLoadException($"Error image ran shortly or off the end, expecting {imageLength} pixels, got {pixel} pixels.");
+ throw new FileLoadException($"Error image ran shortly or off the end, expecting {imageLength} pixels, got {pixelPos} pixels.");
}
// Not required as mat is all black by default
@@ -369,6 +377,8 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = (float) (HeaderSettings.LiftSpeed = Math.Round(value / 60.0, 2));
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => (float)Math.Round(HeaderSettings.RetractSpeed * 60.0, 2);
diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
index b442a57..5fcf0bb 100644
--- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
+++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs
@@ -1142,6 +1142,8 @@ namespace UVtools.Core.FileFormats
}
}
+ public override float BottomRetractSpeed => RetractSpeed;
+
public override float RetractSpeed
{
get => (float)Math.Round(HeaderSettings.RetractSpeed * 60, 2);
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 763d021..4481200 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -637,8 +637,8 @@ namespace UVtools.Core.FileFormats
SuppressRebuildPropertiesWork(() =>
{
- BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, DefaultBottomLightOffDelay);
- LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, DefaultLightOffDelay);
+ BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, 0f);
+ LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, 0f);
BottomWaitTimeBeforeCure = LookupCustomValue(Keyword_BottomWaitTimeBeforeCure, 0f);
WaitTimeBeforeCure = LookupCustomValue(Keyword_WaitTimeBeforeCure, 0f);
diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs
index 24e160f..b7cefd5 100644
--- a/UVtools.Core/FileFormats/UVJFile.cs
+++ b/UVtools.Core/FileFormats/UVJFile.cs
@@ -146,6 +146,7 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.BottomLiftSpeed,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
PrintParameterModifier.BottomLightPWM,
@@ -313,6 +314,12 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = JsonSettings.Properties.Exposure.LiftSpeed = (float)Math.Round(value, 2);
}
+ public override float BottomRetractSpeed
+ {
+ get => JsonSettings.Properties.Bottom.RetractSpeed;
+ set => base.BottomRetractSpeed = JsonSettings.Properties.Bottom.RetractSpeed = (float)Math.Round(value, 2);
+ }
+
public override float RetractSpeed
{
get => JsonSettings.Properties.Exposure.RetractSpeed;
diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs
index 9dfc917..ae4c366 100644
--- a/UVtools.Core/FileFormats/VDTFile.cs
+++ b/UVtools.Core/FileFormats/VDTFile.cs
@@ -97,22 +97,30 @@ namespace UVtools.Core.FileFormats
{
[JsonProperty("layer_thickness")] public float LayerHeight { get; set; }
[JsonProperty("bottom_layers")] public ushort BottomLayers { get; set; } = DefaultBottomLayerCount;
- [JsonProperty("bottom_light_off_delay")] public float BottomLightOffDelay { get; set; } = DefaultBottomLightOffDelay;
- [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; } = DefaultLightOffDelay;
- [JsonProperty("bottom_wait_time_before_cure")] public float BottomWaitTimeBeforeCure { get; set; } = DefaultBottomLightOffDelay;
- [JsonProperty("wait_time_before_cure")] public float WaitTimeBeforeCure { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("bottom_light_off_delay")] public float BottomLightOffDelay { get; set; }
+ [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; }
+ [JsonProperty("bottom_wait_time_before_cure")] public float BottomWaitTimeBeforeCure { get; set; }
+ [JsonProperty("wait_time_before_cure")] public float WaitTimeBeforeCure { get; set; }
[JsonProperty("bottom_exposure_time")] public float BottomExposureTime { get; set; } = DefaultBottomExposureTime;
[JsonProperty("exposure_time")] public float ExposureTime { get; set; } = DefaultExposureTime;
- [JsonProperty("bottom_wait_time_after_cure")] public float BottomWaitTimeAfterCure { get; set; } = DefaultBottomLightOffDelay;
- [JsonProperty("wait_time_after_cure")] public float WaitTimeAfterCure { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("bottom_wait_time_after_cure")] public float BottomWaitTimeAfterCure { get; set; }
+ [JsonProperty("wait_time_after_cure")] public float WaitTimeAfterCure { get; set; }
[JsonProperty("bottom_lift_distance")] public float BottomLiftHeight { get; set; } = DefaultBottomLiftHeight;
- [JsonProperty("lift_distance")] public float LiftHeight { get; set; } = DefaultLiftHeight;
[JsonProperty("bottom_lift_speed")] public float BottomLiftSpeed { get; set; } = DefaultBottomLiftSpeed;
+ [JsonProperty("lift_distance")] public float LiftHeight { get; set; } = DefaultLiftHeight;
[JsonProperty("lift_speed")] public float LiftSpeed { get; set; } = DefaultLiftSpeed;
- [JsonProperty("bottom_retract_speed")] public float BottomRetractSpeed { get; set; } = DefaultRetractSpeed;
- [JsonProperty("bottom_wait_time_after_lift")] public float BottomWaitTimeAfterLift { get; set; } = DefaultBottomLightOffDelay;
- [JsonProperty("wait_time_after_lift")] public float WaitTimeAfterLift { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("bottom_lift_distance2")] public float BottomLiftHeight2 { get; set; } = DefaultBottomLiftHeight2;
+ [JsonProperty("bottom_lift_speed2")] public float BottomLiftSpeed2 { get; set; } = DefaultBottomLiftSpeed2;
+ [JsonProperty("lift_distance2")] public float LiftHeight2 { get; set; } = DefaultLiftHeight2;
+ [JsonProperty("lift_speed2")] public float LiftSpeed2 { get; set; } = DefaultLiftSpeed2;
+ [JsonProperty("bottom_wait_time_after_lift")] public float BottomWaitTimeAfterLift { get; set; }
+ [JsonProperty("wait_time_after_lift")] public float WaitTimeAfterLift { get; set; }
+ [JsonProperty("bottom_retract_speed")] public float BottomRetractSpeed { get; set; } = DefaultBottomRetractSpeed;
[JsonProperty("retract_speed")] public float RetractSpeed { get; set; } = DefaultRetractSpeed;
+ [JsonProperty("bottom_retract_height2")] public float BottomRetractHeight2 { get; set; } = DefaultBottomRetractHeight2;
+ [JsonProperty("bottom_retract_speed2")] public float BottomRetractSpeed2 { get; set; } = DefaultBottomRetractSpeed2;
+ [JsonProperty("retract_height2")] public float RetractHeight2 { get; set; } = DefaultRetractHeight2;
+ [JsonProperty("retract_speed2")] public float RetractSpeed2 { get; set; } = DefaultRetractSpeed2;
}
public sealed class VDTPrintStatistics
@@ -127,14 +135,18 @@ namespace UVtools.Core.FileFormats
public sealed class VDTLayer
{
[JsonProperty("height")] public float PositionZ { get; set; }
- [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; } = DefaultLightOffDelay;
- [JsonProperty("wait_time_before_cure")] public float WaitTimeBeforeCure { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; }
+ [JsonProperty("wait_time_before_cure")] public float WaitTimeBeforeCure { get; set; }
[JsonProperty("exposure_time")] public float ExposureTime { get; set; } = DefaultExposureTime;
- [JsonProperty("wait_time_after_cure")] public float WaitTimeAfterCure { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("wait_time_after_cure")] public float WaitTimeAfterCure { get; set; }
[JsonProperty("lift_distance")] public float LiftHeight { get; set; } = DefaultLiftHeight;
[JsonProperty("lift_speed")] public float LiftSpeed { get; set; } = DefaultLiftSpeed;
- [JsonProperty("wait_time_after_lift")] public float WaitTimeAfterLift { get; set; } = DefaultLightOffDelay;
+ [JsonProperty("lift_distance2")] public float LiftHeight2 { get; set; } = DefaultLiftHeight2;
+ [JsonProperty("lift_speed2")] public float LiftSpeed2 { get; set; } = DefaultLiftSpeed2;
+ [JsonProperty("wait_time_after_lift")] public float WaitTimeAfterLift { get; set; }
[JsonProperty("retract_speed")] public float RetractSpeed { get; set; } = DefaultRetractSpeed;
+ [JsonProperty("retract_distance2")] public float RetractHeight2 { get; set; } = DefaultRetractHeight2;
+ [JsonProperty("retract_speed2")] public float RetractSpeed2 { get; set; } = DefaultRetractSpeed2;
[JsonProperty("light_pwm")] public byte LightPWM { get; set; } = DefaultLightPWM;
}
@@ -169,10 +181,20 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
@@ -186,8 +208,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.BottomWaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
@@ -362,6 +388,30 @@ namespace UVtools.Core.FileFormats
set => base.LiftSpeed = ManifestFile.Print.LiftSpeed = (float)Math.Round(value, 2);
}
+ public override float BottomLiftHeight2
+ {
+ get => ManifestFile.Print.BottomLiftHeight2;
+ set => base.BottomLiftHeight2 = ManifestFile.Print.BottomLiftHeight2 = (float)Math.Round(value, 2);
+ }
+
+ public override float LiftHeight2
+ {
+ get => ManifestFile.Print.LiftHeight2;
+ set => base.LiftHeight2 = ManifestFile.Print.LiftHeight2 = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomLiftSpeed2
+ {
+ get => ManifestFile.Print.BottomLiftSpeed2;
+ set => base.BottomLiftSpeed2 = ManifestFile.Print.BottomLiftSpeed2 = (float)Math.Round(value, 2);
+ }
+
+ public override float LiftSpeed2
+ {
+ get => ManifestFile.Print.LiftSpeed2;
+ set => base.LiftSpeed2 = ManifestFile.Print.LiftSpeed2 = (float)Math.Round(value, 2);
+ }
+
public override float BottomWaitTimeAfterLift
{
get => ManifestFile.Print.BottomWaitTimeAfterLift;
@@ -373,10 +423,40 @@ namespace UVtools.Core.FileFormats
set => base.WaitTimeAfterLift = ManifestFile.Print.WaitTimeAfterLift = (float)Math.Round(value, 2);
}
+ public override float BottomRetractSpeed
+ {
+ get => ManifestFile.Print.BottomRetractSpeed;
+ set => base.BottomRetractSpeed = ManifestFile.Print.BottomRetractSpeed = (float)Math.Round(value, 2);
+ }
+
public override float RetractSpeed
{
get => ManifestFile.Print.RetractSpeed;
- set => base.RetractSpeed = ManifestFile.Print.RetractSpeed = ManifestFile.Print.BottomRetractSpeed = (float)Math.Round(value, 2);
+ set => base.RetractSpeed = ManifestFile.Print.RetractSpeed = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomRetractHeight2
+ {
+ get => ManifestFile.Print.BottomRetractHeight2;
+ set => base.BottomRetractHeight2 = ManifestFile.Print.BottomRetractHeight2 = (float)Math.Round(value, 2);
+ }
+
+ public override float RetractHeight2
+ {
+ get => ManifestFile.Print.RetractHeight2;
+ set => base.RetractHeight2 = ManifestFile.Print.RetractHeight2 = (float)Math.Round(value, 2);
+ }
+
+ public override float BottomRetractSpeed2
+ {
+ get => ManifestFile.Print.BottomRetractSpeed2;
+ set => base.BottomRetractSpeed2 = ManifestFile.Print.BottomRetractSpeed2 = (float)Math.Round(value, 2);
+ }
+
+ public override float RetractSpeed2
+ {
+ get => ManifestFile.Print.RetractSpeed2;
+ set => base.RetractSpeed2 = ManifestFile.Print.RetractSpeed2 = (float)Math.Round(value, 2);
}
public override byte BottomLightPWM
@@ -456,8 +536,12 @@ namespace UVtools.Core.FileFormats
WaitTimeAfterCure = layer.WaitTimeAfterCure,
LiftHeight = layer.LiftHeight,
LiftSpeed = layer.LiftSpeed,
+ LiftHeight2 = layer.LiftHeight2,
+ LiftSpeed2 = layer.LiftSpeed2,
WaitTimeAfterLift = layer.WaitTimeAfterLift,
RetractSpeed = layer.RetractSpeed,
+ RetractHeight2 = layer.RetractHeight2,
+ RetractSpeed2 = layer.RetractSpeed2,
LightPWM = layer.LightPWM
};
}
@@ -540,8 +624,12 @@ namespace UVtools.Core.FileFormats
WaitTimeAfterCure = manifestLayer.WaitTimeAfterCure,
LiftHeight = manifestLayer.LiftHeight,
LiftSpeed = manifestLayer.LiftSpeed,
+ LiftHeight2 = manifestLayer.LiftHeight2,
+ LiftSpeed2 = manifestLayer.LiftSpeed2,
WaitTimeAfterLift = manifestLayer.WaitTimeAfterLift,
RetractSpeed = manifestLayer.RetractSpeed,
+ RetractHeight2 = manifestLayer.RetractHeight2,
+ RetractSpeed2 = manifestLayer.RetractSpeed2,
LightPWM = manifestLayer.LightPWM,
};
}
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index 643f14d..f0cb407 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -8,7 +8,6 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
@@ -84,10 +83,10 @@ namespace UVtools.Core.FileFormats
public float LiftSpeed { get; set; } = FileFormat.DefaultLiftSpeed;
[XmlAttribute("cooldown_bottom")]
- public uint BottomLightOffDelay { get; set; } = (uint) (FileFormat.DefaultBottomLightOffDelay * 1000);
+ public uint BottomLightOffDelay { get; set; }
[XmlAttribute("cooldown")]
- public uint LightOffDelay { get; set; } = (uint) (FileFormat.DefaultLightOffDelay * 1000);
+ public uint LightOffDelay { get; set; }
[XmlAttribute("thickness")]
public float LayerHeight { get; set; } = FileFormat.DefaultLayerHeight;
@@ -209,11 +208,22 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomLiftHeight2,
+ PrintParameterModifier.BottomLiftSpeed2,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
+
PrintParameterModifier.BottomWaitTimeAfterLift,
PrintParameterModifier.WaitTimeAfterLift,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.BottomRetractHeight2,
+ PrintParameterModifier.BottomRetractSpeed2,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
+
PrintParameterModifier.BottomLightPWM,
PrintParameterModifier.LightPWM,
};
@@ -224,8 +234,12 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.WaitTimeAfterCure,
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.LiftHeight2,
+ PrintParameterModifier.LiftSpeed2,
PrintParameterModifier.WaitTimeAfterLift,
PrintParameterModifier.RetractSpeed,
+ PrintParameterModifier.RetractHeight2,
+ PrintParameterModifier.RetractSpeed2,
PrintParameterModifier.LightPWM,
};
diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index a268d32..56ec300 100644
--- a/UVtools.Core/FileFormats/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -11,12 +11,9 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
-using System.Text;
using System.Text.RegularExpressions;
using Emgu.CV;
using Emgu.CV.CvEnum;
-using Emgu.CV.Stitching;
-using Emgu.CV.Util;
using Newtonsoft.Json;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
@@ -174,6 +171,7 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LiftHeight,
PrintParameterModifier.LiftSpeed,
+ PrintParameterModifier.BottomRetractSpeed,
PrintParameterModifier.RetractSpeed,
};
@@ -609,6 +607,7 @@ M106 S0
}
}
+ BottomRetractSpeed = RetractSpeed; // Compability
LayerManager.GetBoundingRectangle(progress);
}
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index e53faa2..9d5d156 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Globalization;
@@ -390,12 +391,12 @@ namespace UVtools.Core.GCode
AppendMoveG1(z, feedRate);
}
- public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
+ public void AppendLiftMoveGx(float upZ, float upFeedRate, float upZ2, float upFeedRate2, float downZ, float downFeedRate, float downZ2, float downFeedRate2, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
if (_layerMoveCommand == GCodeMoveCommands.G0)
- AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
+ AppendLiftMoveG0(upZ, upFeedRate, upZ2, upFeedRate2, downZ, downFeedRate, downZ2, downFeedRate2, waitAfterLift, waitAfterRetract, layer);
else
- AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
+ AppendLiftMoveG1(upZ, upFeedRate, upZ2, upFeedRate2, downZ, downFeedRate, downZ2, downFeedRate2, waitAfterLift, waitAfterRetract, layer);
}
@@ -405,14 +406,15 @@ namespace UVtools.Core.GCode
AppendLine(CommandMoveG0, z, feedRate);
}
- public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
+ public void AppendLiftMoveG0(float upZ, float upFeedRate, float upZ2 = 0, float upFeedRate2 = 0, float downZ = 0, float downFeedRate = 0, float downZ2 = 0, float downFeedRate2 = 0, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
- if (upZ == 0 || upFeedRate <= 0) return;
- AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift
+ if ((upZ == 0 || upFeedRate <= 0) && (upZ2 == 0 || upFeedRate2 <= 0)) return;
+
+ if(upZ > 0 && upFeedRate > 0) AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift
+ if(upZ2 > 0 && upFeedRate2 > 0) AppendLineOverrideComment(CommandMoveG0, "Z Lift (2)", upZ2, upFeedRate2); // Z Lift2
if (_syncMovementsWithDelay && layer is not null)
{
- // Finish this
- var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
@@ -422,13 +424,17 @@ namespace UVtools.Core.GCode
AppendWaitG4(waitAfterLift, "Wait after lift");
}
- if (downZ != 0 && downFeedRate > 0)
+ if ((downZ != 0 && downFeedRate > 0) || (downZ2 != 0 && downFeedRate2 > 0))
{
- AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate);
+ if(downZ2 != 0 && downFeedRate2 > 0)
+ AppendLineOverrideComment(CommandMoveG0, "Retract (2)", downZ2, downFeedRate2);
+ if (downZ != 0 && downFeedRate > 0)
+ AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate);
+
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
- var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
@@ -446,19 +452,17 @@ namespace UVtools.Core.GCode
AppendLine(CommandMoveG1, z, feedRate);
}
- public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
+ public void AppendLiftMoveG1(float upZ, float upFeedRate, float upZ2 = 0, float upFeedRate2 = 0, float downZ = 0, float downFeedRate = 0, float downZ2 = 0, float downFeedRate2 = 0, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
- if (upZ == 0 || upFeedRate <= 0) return;
- AppendLineOverrideComment(CommandMoveG1, "Lift Z", upZ, upFeedRate); // Z Lift
+ if ((upZ == 0 || upFeedRate <= 0) && (upZ2 == 0 || upFeedRate2 <= 0)) return;
+
+ if (upZ > 0 && upFeedRate > 0) AppendLineOverrideComment(CommandMoveG1, "Z Lift", upZ, upFeedRate); // Z Lift
+ if (upZ2 > 0 && upFeedRate2 > 0) AppendLineOverrideComment(CommandMoveG1, "Z Lift (2)", upZ2, upFeedRate2); // Z Lift2
if (_syncMovementsWithDelay && layer is not null)
{
- // Finish this
- var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
- if (seconds > layer.WaitTimeAfterLift) // Fix if wait time already include this
- {
- var time = ConvertFromSeconds(seconds);
- AppendWaitG4($"0{time}", "Sync movement");
- }
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
+ var time = ConvertFromSeconds(seconds);
+ AppendWaitG4($"0{time}", "Sync movement");
}
if (waitAfterLift > 0)
@@ -466,18 +470,19 @@ namespace UVtools.Core.GCode
AppendWaitG4(waitAfterLift, "Wait after lift");
}
- if (downZ != 0 && downFeedRate > 0)
+ if ((downZ != 0 && downFeedRate > 0) || (downZ2 != 0 && downFeedRate2 > 0))
{
- AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate);
+ if (downZ2 != 0 && downFeedRate2 > 0)
+ AppendLineOverrideComment(CommandMoveG1, "Retract (2)", downZ2, downFeedRate2);
+ if (downZ != 0 && downFeedRate > 0)
+ AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate);
+
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
- var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
- if (seconds > layer.WaitTimeBeforeCure) // Fix if wait time already include this
- {
- var time = ConvertFromSeconds(seconds);
- AppendWaitG4($"0{time}", "Sync movement");
- }
+ var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
+ var time = ConvertFromSeconds(seconds);
+ AppendWaitG4($"0{time}", "Sync movement");
}
}
@@ -569,7 +574,7 @@ namespace UVtools.Core.GCode
float lastZPosition = 0;
- // Defaults for: Absolute, mm/m and s
+ // Defaults for: Absolute, mm/min and s
for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++)
{
var layer = slicerFile[layerIndex];
@@ -578,23 +583,64 @@ namespace UVtools.Core.GCode
float exposureTime = ConvertFromSeconds(layer.ExposureTime);
float waitAfterCure = ConvertFromSeconds(layer.WaitTimeAfterCure);
float liftHeight = layer.LiftHeight;
- float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
- float liftZPosAbs = liftZPos;
+ //float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
+ //float liftZPosAbs = liftZPos;
float liftSpeed = ConvertFromMillimetersPerMinute(layer.LiftSpeed);
+ float liftHeight2 = layer.LiftHeight2;
+ float liftSpeed2 = ConvertFromMillimetersPerMinute(layer.LiftSpeed2);
float waitAfterLift = ConvertFromSeconds(layer.WaitTimeAfterLift);
- float retractPos = layer.PositionZ;
+ float retractHeight = layer.RetractHeight;
float retractSpeed = ConvertFromMillimetersPerMinute(layer.RetractSpeed);
+ float retractHeight2 = layer.RetractHeight2;
+ float retractSpeed2 = ConvertFromMillimetersPerMinute(layer.RetractSpeed2);
+ float liftHeightTotal = layer.LiftHeightTotal;
ushort pwmValue = layer.LightPWM;
if (_maxLedPower != byte.MaxValue)
{
pwmValue = (ushort)(_maxLedPower * pwmValue / byte.MaxValue);
}
+ float liftPos = 0;
+ float liftPos2 = 0;
+ float retractPos = 0;
+ float retractPos2 = 0;
+
switch (GCodePositioningType)
{
+ case GCodePositioningTypes.Absolute:
+ var absLiftPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
+ var absLiftPos2 = Layer.RoundHeight(absLiftPos + liftHeight2);
+ var absRetractPos2 = Layer.RoundHeight(absLiftPos2 - retractHeight2);
+ if (liftHeight > 0) liftPos = absLiftPos;
+ if (liftHeight2 > 0) liftPos2 = absLiftPos2;
+ if (retractHeight2 > 0) retractPos2 = absRetractPos2;
+ if (retractHeight > 0) retractPos = layer.PositionZ;
+ if (retractPos > 0 && retractPos > retractPos2) retractPos2 = 0; // Fail-safe
+ break;
case GCodePositioningTypes.Partial:
- liftZPos = liftHeight;
- retractPos = Layer.RoundHeight(layer.PositionZ - lastZPosition - liftHeight);
+ var partialLiftPos = Layer.RoundHeight(layer.PositionZ - lastZPosition + liftHeight);
+ var partialLiftPosTotal = Layer.RoundHeight(partialLiftPos + liftHeight2);
+ var partialRetractPosTotal = Layer.RoundHeight(partialLiftPos + liftHeight2);
+ if (liftHeight > 0)
+ {
+ liftPos = partialLiftPos;
+ if (liftHeight2 > 0) liftPos2 = liftHeight2;
+ }
+ else
+ {
+ if (liftHeight2 > 0) liftPos2 = Layer.RoundHeight(partialLiftPos + liftHeight2);
+ }
+
+ if (retractHeight2 > 0) retractPos2 = -retractHeight2;
+ if (retractHeight > 0) retractPos = -retractHeight;
+
+ // Assert
+ if (Layer.RoundHeight(Math.Abs(retractPos + retractPos2)) != liftHeightTotal) // Fail-safe
+ {
+ retractPos2 = 0;
+ retractPos = -liftHeightTotal;
+ }
+
break;
}
@@ -605,9 +651,9 @@ namespace UVtools.Core.GCode
AppendShowImageM6054(GetShowImageString(layerIndex));
//}
- if (liftHeight > 0 && liftZPosAbs > layer.PositionZ)
+ if (liftHeightTotal > 0 && Layer.RoundHeight(liftHeightTotal + layer.PositionZ) > layer.PositionZ)
{
- AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift, 0, layer);
+ AppendLiftMoveGx(liftPos, liftSpeed, liftPos2, liftSpeed2, retractPos, retractSpeed, retractPos2, retractSpeed2, waitAfterLift, 0, layer);
}
else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position
{
@@ -759,10 +805,7 @@ namespace UVtools.Core.GCode
}
// Propagate values before switch to the new layer
- layerBlock.PositionZ ??= positionZ;
- layerBlock.SetLayer();
-
- layerBlock.Init();
+ layerBlock.SetLayer(true);
layerBlock.LayerIndex = layerIndex;
continue;
@@ -782,12 +825,16 @@ namespace UVtools.Core.GCode
RegexOptions.IgnoreCase);
match = moveG0Regex.Success && moveG0Regex.Groups.Count >= 2 ? moveG0Regex : moveG1Regex;
- if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed.HasValue)
+ if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed2.HasValue && layerBlock.LightOffCount < 2)
{
float pos = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
float speed = ConvertToMillimetersPerMinute(float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture));
- if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now
+
+ layerBlock.Movements.Add(new(pos, speed));
+ layerBlock.AssignMovements(positionType);
+
+ /*if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now
{
switch (positionType)
{
@@ -817,7 +864,7 @@ namespace UVtools.Core.GCode
layerBlock.LiftHeight = layerBlock.PositionZ - positionZ;
layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + pos);
break;
- }
+ }*/
continue;
}
@@ -897,7 +944,7 @@ namespace UVtools.Core.GCode
if (pwm == 0 && layerBlock.LightPWM.HasValue)
{
- layerBlock.IsAfterLightOff = true;
+ layerBlock.LightOffCount++;
}
else if (!layerBlock.IsAfterLightOff)
{
@@ -910,7 +957,6 @@ namespace UVtools.Core.GCode
}
// Propagate values of left over layer
- layerBlock.PositionZ ??= positionZ;
layerBlock.SetLayer();
@@ -1016,36 +1062,7 @@ namespace UVtools.Core.GCode
if (rebuildGlobalTable)
{
- slicerFile.SuppressRebuildPropertiesWork(() =>
- {
- var bottomLayer = slicerFile.FirstLayer;
- if (bottomLayer is not null)
- {
- if (bottomLayer.LightOffDelay > 0) slicerFile.BottomLightOffDelay = bottomLayer.LightOffDelay;
- if (bottomLayer.WaitTimeBeforeCure > 0) slicerFile.BottomWaitTimeBeforeCure = bottomLayer.WaitTimeBeforeCure;
- if (bottomLayer.ExposureTime > 0) slicerFile.BottomExposureTime = bottomLayer.ExposureTime;
- if (bottomLayer.WaitTimeAfterCure > 0) slicerFile.BottomWaitTimeAfterCure = bottomLayer.WaitTimeAfterCure;
- if (bottomLayer.LiftHeight > 0) slicerFile.BottomLiftHeight = bottomLayer.LiftHeight;
- if (bottomLayer.LiftSpeed > 0) slicerFile.BottomLiftSpeed = bottomLayer.LiftSpeed;
- if (bottomLayer.WaitTimeAfterLift > 0) slicerFile.BottomWaitTimeAfterLift = bottomLayer.WaitTimeAfterLift;
- if (bottomLayer.RetractSpeed > 0) slicerFile.RetractSpeed = bottomLayer.RetractSpeed;
- if (bottomLayer.LightPWM > 0) slicerFile.BottomLightPWM = bottomLayer.LightPWM;
- }
-
- var normalLayer = slicerFile.LastLayer;
- if (normalLayer is not null)
- {
- if (normalLayer.LightOffDelay > 0) slicerFile.LightOffDelay = normalLayer.LightOffDelay;
- if (normalLayer.WaitTimeBeforeCure > 0) slicerFile.WaitTimeBeforeCure = normalLayer.WaitTimeBeforeCure;
- if (normalLayer.ExposureTime > 0) slicerFile.ExposureTime = normalLayer.ExposureTime;
- if (normalLayer.WaitTimeAfterCure > 0) slicerFile.WaitTimeAfterCure = normalLayer.WaitTimeAfterCure;
- if (normalLayer.LiftHeight > 0) slicerFile.LiftHeight = normalLayer.LiftHeight;
- if (normalLayer.LiftSpeed > 0) slicerFile.LiftSpeed = normalLayer.LiftSpeed;
- if (normalLayer.WaitTimeAfterLift > 0) slicerFile.WaitTimeAfterLift = normalLayer.WaitTimeAfterLift;
- if (normalLayer.RetractSpeed > 0) slicerFile.RetractSpeed = normalLayer.RetractSpeed;
- if (normalLayer.LightPWM > 0) slicerFile.LightPWM = normalLayer.LightPWM;
- }
- });
+ slicerFile.UpdateGlobalPropertiesFromLayers();
}
}
diff --git a/UVtools.Core/GCode/GCodeLayer.cs b/UVtools.Core/GCode/GCodeLayer.cs
index 9f3c36b..cbd0fab 100644
--- a/UVtools.Core/GCode/GCodeLayer.cs
+++ b/UVtools.Core/GCode/GCodeLayer.cs
@@ -7,6 +7,7 @@
*/
using System;
+using System.Collections.Generic;
using UVtools.Core.FileFormats;
using UVtools.Core.Operations;
@@ -14,13 +15,18 @@ namespace UVtools.Core.GCode
{
public class GCodeLayer
{
+ private float? _positionZ;
private float? _waitTimeBeforeCure;
private float? _exposureTime;
private float? _waitTimeAfterCure;
private float? _liftHeight;
private float? _liftSpeed;
+ private float? _liftHeight2;
+ private float? _liftSpeed2;
private float? _waitTimeAfterLift;
private float? _retractSpeed;
+ private float? _retractHeight2;
+ private float? _retractSpeed2;
public enum GCodeLastParsedLine : byte
{
@@ -30,8 +36,16 @@ namespace UVtools.Core.GCode
public bool IsValid => LayerIndex.HasValue;
public FileFormat SlicerFile { get; }
+ public List<(float Pos, float Speed)> Movements = new();
public uint? LayerIndex { get; set; }
- public float? PositionZ { get; set; }
+
+ public float? PositionZ
+ {
+ get => _positionZ;
+ set => _positionZ = value;
+ }
+
+ public float PreviousPositionZ { get; set; }
public float? WaitTimeBeforeCure
{
@@ -54,7 +68,7 @@ namespace UVtools.Core.GCode
public float? LiftHeight
{
get => _liftHeight;
- set => _liftHeight = value is null ? null : (float)Math.Round(value.Value, 2);
+ set => _liftHeight = value is null ? null : Layer.RoundHeight(value.Value);
}
public float? LiftSpeed
@@ -63,6 +77,20 @@ namespace UVtools.Core.GCode
set => _liftSpeed = value is null ? null : (float)Math.Round(value.Value, 2);
}
+ public float LiftHeightTotal => Layer.RoundHeight((LiftHeight ?? 0) + (LiftHeight2 ?? 0));
+
+ public float? LiftHeight2
+ {
+ get => _liftHeight2;
+ set => _liftHeight2 = value is null ? null : Layer.RoundHeight(value.Value);
+ }
+
+ public float? LiftSpeed2
+ {
+ get => _liftSpeed2;
+ set => _liftSpeed2 = value is null ? null : (float)Math.Round(value.Value, 2);
+ }
+
public float? WaitTimeAfterLift
{
get => _waitTimeAfterLift;
@@ -75,11 +103,25 @@ namespace UVtools.Core.GCode
set => _retractSpeed = value is null ? null : (float)Math.Round(value.Value, 2);
}
+ public float? RetractHeight2
+ {
+ get => _retractHeight2;
+ set => _retractHeight2 = value is null ? null : Layer.RoundHeight(value.Value);
+ }
+
+ public float? RetractSpeed2
+ {
+ get => _retractSpeed2;
+ set => _retractSpeed2 = value is null ? null : (float)Math.Round(value.Value, 2);
+ }
+
public byte? LightPWM { get; set; }
public bool IsExposing => LightPWM.HasValue && !IsAfterLightOff;
+ public bool IsExposed => LightPWM.HasValue && IsAfterLightOff;
- public bool IsAfterLightOff { get; set; }
+ public byte LightOffCount { get; set; }
+ public bool IsAfterLightOff => LightOffCount > 0;
public GCodeLayer(FileFormat slicerFile)
{
@@ -88,6 +130,9 @@ namespace UVtools.Core.GCode
public void Init()
{
+ PreviousPositionZ = PositionZ ?? 0;
+
+ Movements.Clear();
LayerIndex = null;
PositionZ = null;
WaitTimeBeforeCure = null;
@@ -95,39 +140,142 @@ namespace UVtools.Core.GCode
WaitTimeAfterCure = null;
LiftHeight = null;
LiftSpeed = null;
+ LiftHeight2 = null;
+ LiftSpeed2 = null;
WaitTimeAfterLift = null;
RetractSpeed = null;
+ RetractHeight2 = null;
+ RetractSpeed2 = null;
LightPWM = null;
- IsAfterLightOff = false;
+ LightOffCount = 0;
+ }
+
+ public void AssignMovements(GCodeBuilder.GCodePositioningTypes positionType)
+ {
+ if (Movements.Count == 0) return;
+ var currentZ = PreviousPositionZ;
+
+ PositionZ = null;
+ LiftHeight = null;
+ LiftSpeed = null;
+ LiftHeight2 = null;
+ LiftSpeed2 = null;
+ RetractSpeed = null;
+ RetractHeight2 = null;
+ RetractSpeed2 = null;
+
+ for (int i = 0; i < Movements.Count; i++)
+ {
+ var (pos, speed) = Movements[i];
+ float heightRaw;
+ switch (positionType)
+ {
+ case GCodeBuilder.GCodePositioningTypes.Absolute:
+ heightRaw = Layer.RoundHeight(pos - currentZ);
+ currentZ = pos;
+ break;
+ case GCodeBuilder.GCodePositioningTypes.Partial:
+ heightRaw = pos;
+ currentZ = Layer.RoundHeight(currentZ + pos);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(positionType));
+ }
+
+ // Fail-safe check
+ if (currentZ < PreviousPositionZ)
+ throw new NotSupportedException("GCode parsing error: Attempting to crash the print on the LCD with negative position.\n" +
+ "Do not attempt to print this file!");
+
+ // Is position Z
+ if (i == Movements.Count - 1)
+ {
+ PositionZ = currentZ;
+ if (LiftHeight.HasValue) RetractSpeed = speed; // A lift exists, set to retract speed of this move
+ continue;
+ }
+
+ if (heightRaw == 0) continue;
+ var height = Math.Abs(heightRaw);
+
+ if (heightRaw > 0) // Is a lift
+ {
+ if (!LiftHeight.HasValue)
+ {
+ LiftHeight = height;
+ LiftSpeed = speed;
+ continue;
+ }
+
+ LiftHeight2 ??= 0;
+ LiftHeight2 += height;
+ LiftSpeed2 = speed;
+
+ continue;
+ }
+
+ if(!LiftHeight.HasValue) continue; // Fail-safe: Retract without a lift? Skip
+
+ // Is a extra retract (2)
+ RetractHeight2 ??= 0;
+ RetractHeight2 += height;
+ RetractSpeed2 = speed;
+ }
+
+ if (Movements.Count == 1) // Only 1 move, this is the PositionZ only
+ {
+ LiftSpeed = Movements[0].Speed;
+ return;
+ }
+
+ // Sanitize
+ if (PositionZ.HasValue && LiftHeight.HasValue && !IsExposed) // Lift before exposure order, need to remove layer height as offset
+ {
+ var liftHeight = Layer.RoundHeight(LiftHeight.Value - (PositionZ.Value - PreviousPositionZ));
+ if(liftHeight <= 0) return; // Something not right or not the correct moment, skip
+ LiftHeight = liftHeight;
+ }
+
+ if (LiftHeight.HasValue && RetractHeight2.HasValue) // Sanitize RetractHeight2 value
+ {
+ RetractHeight2 = Math.Clamp(RetractHeight2.Value, 0, LiftHeightTotal);
+ }
}
/// <summary>
/// Set gathered data to the layer
/// </summary>
- public void SetLayer()
+ public void SetLayer(bool reinit = false)
{
if (!IsValid) return;
uint layerIndex = LayerIndex.Value;
var layer = SlicerFile[layerIndex];
- if(PositionZ.HasValue) layer.PositionZ = PositionZ.Value;
+ if (!PositionZ.HasValue) PositionZ = PreviousPositionZ;
+ layer.PositionZ = PositionZ.Value;
layer.WaitTimeBeforeCure = WaitTimeBeforeCure ?? 0;
layer.ExposureTime = ExposureTime ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
layer.WaitTimeAfterCure = WaitTimeAfterCure ?? 0;
layer.LiftHeight = LiftHeight ?? 0;
layer.LiftSpeed = LiftSpeed ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
+ layer.LiftHeight2 = LiftHeight2 ?? 0;
+ layer.LiftSpeed2 = LiftSpeed2 ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
layer.WaitTimeAfterLift = WaitTimeAfterLift ?? 0;
- layer.RetractSpeed = RetractSpeed ?? SlicerFile.RetractSpeed;
+ layer.RetractSpeed = RetractSpeed ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed, SlicerFile.RetractSpeed);
+ layer.RetractHeight2 = RetractHeight2 ?? 0;
+ layer.RetractSpeed2 = RetractSpeed2 ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed2, SlicerFile.RetractSpeed2);
layer.LightPWM = LightPWM ?? 0;//SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
if (SlicerFile.GCode.SyncMovementsWithDelay) // Dirty fix of the value
{
- var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, 1.5f);
+ var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer, 1.5f);
if (syncTime < layer.WaitTimeBeforeCure)
{
layer.WaitTimeBeforeCure = (float) Math.Round(layer.WaitTimeBeforeCure - syncTime, 2);
}
}
+
+ if(reinit) Init();
}
}
}
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index 7ae01d0..456cec5 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -7,6 +7,7 @@
*/
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Drawing;
using System.Linq;
using Emgu.CV;
@@ -40,14 +41,18 @@ namespace UVtools.Core
private bool _isModified;
private uint _index;
private float _positionZ;
+ private float _lightOffDelay;
private float _waitTimeBeforeCure;
private float _exposureTime;
private float _waitTimeAfterCure;
- private float _lightOffDelay = FileFormat.DefaultLightOffDelay;
private float _liftHeight = FileFormat.DefaultLiftHeight;
private float _liftSpeed = FileFormat.DefaultLiftSpeed;
+ private float _liftHeight2 = FileFormat.DefaultLiftHeight2;
+ private float _liftSpeed2 = FileFormat.DefaultLiftSpeed2;
private float _waitTimeAfterLift;
private float _retractSpeed = FileFormat.DefaultRetractSpeed;
+ private float _retractHeight2 = FileFormat.DefaultRetractHeight2;
+ private float _retractSpeed2 = FileFormat.DefaultRetractSpeed2;
private byte _lightPwm = FileFormat.DefaultLightPWM;
private float _materialMilliliters;
#endregion
@@ -132,6 +137,19 @@ namespace UVtools.Core
}
/// <summary>
+ /// Gets or sets the layer position on Z in mm
+ /// </summary>
+ public float PositionZ
+ {
+ get => _positionZ;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _positionZ, value)) return;
+ RaisePropertyChanged(nameof(LayerHeight));
+ }
+ }
+
+ /// <summary>
/// Gets or sets the wait time in seconds before cure the layer
/// AKA: Light-off delay
/// Chitubox: Rest time after retract
@@ -191,6 +209,20 @@ namespace UVtools.Core
}
/// <summary>
+ /// Gets: Total lift height (lift1 + lift2)
+ /// Sets: Lift1 with value and lift2 with 0
+ /// </summary>
+ public float LiftHeightTotal
+ {
+ get => (float)Math.Round(_liftHeight + _liftHeight2);
+ set
+ {
+ LiftHeight = value;
+ LiftHeight2 = 0;
+ }
+ }
+
+ /// <summary>
/// Gets or sets the lift height in mm
/// </summary>
public float LiftHeight
@@ -200,6 +232,8 @@ namespace UVtools.Core
{
if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
if(!RaiseAndSetIfChanged(ref _liftHeight, value)) return;
+ RaisePropertyChanged(nameof(LiftHeightTotal));
+ RetractHeight2 = _retractHeight2; // Sanitize
SlicerFile?.UpdatePrintTimeQueued();
}
}
@@ -218,6 +252,36 @@ namespace UVtools.Core
}
}
+ /// <summary>
+ /// Gets or sets the lift height in mm
+ /// </summary>
+ public float LiftHeight2
+ {
+ get => _liftHeight2;
+ set
+ {
+ if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftHeight2, SlicerFile.LiftHeight2);
+ if (!RaiseAndSetIfChanged(ref _liftHeight2, value)) return;
+ RaisePropertyChanged(nameof(LiftHeightTotal));
+ RetractHeight2 = _retractHeight2; // Sanitize
+ SlicerFile?.UpdatePrintTimeQueued();
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the speed in mm/min
+ /// </summary>
+ public float LiftSpeed2
+ {
+ get => _liftSpeed2;
+ set
+ {
+ if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
+ if (!RaiseAndSetIfChanged(ref _liftSpeed2, value)) return;
+ SlicerFile?.UpdatePrintTimeQueued();
+ }
+ }
+
public float WaitTimeAfterLift
{
get => _waitTimeAfterLift;
@@ -229,6 +293,16 @@ namespace UVtools.Core
}
/// <summary>
+ /// Gets: Total retract height (retract1 + retract2) alias of <see cref="LiftHeightTotal"/>
+ /// </summary>
+ public float RetractHeightTotal => LiftHeightTotal;
+
+ /// <summary>
+ /// Gets the retract height in mm
+ /// </summary>
+ public float RetractHeight => (float)Math.Round(LiftHeightTotal - _retractHeight2);
+
+ /// <summary>
/// Gets the speed in mm/min for the retracts
/// </summary>
public float RetractSpeed
@@ -243,38 +317,49 @@ namespace UVtools.Core
}
/// <summary>
- /// Gets or sets the pwm value from 0 to 255
+ /// Gets or sets the second retract height in mm
/// </summary>
- public byte LightPWM
+ public virtual float RetractHeight2
{
- get => _lightPwm;
+ get => _retractHeight2;
set
{
- //if (value == 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
- //if (value == 0) value = FileFormat.DefaultLightPWM;
- RaiseAndSetIfChanged(ref _lightPwm, value);
+ value = Math.Clamp((float)Math.Round(value, 2), 0, RetractHeightTotal);
+ RaiseAndSetIfChanged(ref _retractHeight2, value);
+ RaisePropertyChanged(nameof(RetractHeight));
+ RaisePropertyChanged(nameof(RetractHeightTotal));
}
}
/// <summary>
- /// Gets if this layer can be exposed to UV light
+ /// Gets the speed in mm/min for the retracts
/// </summary>
- public bool CanExpose => _exposureTime > 0 && _lightPwm > 0;
+ public virtual float RetractSpeed2
+ {
+ get => _retractSpeed2;
+ set => RaiseAndSetIfChanged(ref _retractSpeed2, (float)Math.Round(value, 2));
+ }
/// <summary>
- /// Gets or sets the layer position on Z in mm
+ /// Gets or sets the pwm value from 0 to 255
/// </summary>
- public float PositionZ
+ public byte LightPWM
{
- get => _positionZ;
+ get => _lightPwm;
set
{
- if(!RaiseAndSetIfChanged(ref _positionZ, value)) return;
- RaisePropertyChanged(nameof(LayerHeight));
+ //if (value == 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
+ //if (value == 0) value = FileFormat.DefaultLightPWM;
+ RaiseAndSetIfChanged(ref _lightPwm, value);
}
}
/// <summary>
+ /// Gets if this layer can be exposed to UV light
+ /// </summary>
+ public bool CanExpose => _exposureTime > 0 && _lightPwm > 0;
+
+ /// <summary>
/// Gets the layer height in millimeters of this layer
/// </summary>
public float LayerHeight
@@ -406,7 +491,12 @@ namespace UVtools.Core
WaitTimeBeforeCure != SlicerFile.BottomWaitTimeBeforeCure ||
LiftHeight != SlicerFile.BottomLiftHeight ||
LiftSpeed != SlicerFile.BottomLiftSpeed ||
+ LiftHeight2 != SlicerFile.BottomLiftHeight2 ||
+ LiftSpeed2 != SlicerFile.BottomLiftSpeed2 ||
WaitTimeAfterLift != SlicerFile.BottomWaitTimeAfterLift ||
+ RetractSpeed != SlicerFile.BottomRetractSpeed ||
+ RetractHeight2 != SlicerFile.BottomRetractHeight2 ||
+ RetractSpeed2 != SlicerFile.BottomRetractSpeed2 ||
LightPWM != SlicerFile.BottomLightPWM
) return false;
}
@@ -419,13 +509,16 @@ namespace UVtools.Core
WaitTimeAfterCure != SlicerFile.WaitTimeAfterCure ||
LiftHeight != SlicerFile.LiftHeight ||
LiftSpeed != SlicerFile.LiftSpeed ||
+ LiftHeight2 != SlicerFile.LiftHeight2 ||
+ LiftSpeed2 != SlicerFile.LiftSpeed2 ||
WaitTimeAfterLift != SlicerFile.WaitTimeAfterLift ||
+ RetractSpeed != SlicerFile.RetractSpeed ||
+ RetractHeight2 != SlicerFile.RetractHeight2 ||
+ RetractSpeed2 != SlicerFile.RetractSpeed2 ||
LightPWM != SlicerFile.LightPWM
) return false;
}
- if (RetractSpeed != SlicerFile.RetractSpeed) return false;
-
return true;
}
}
@@ -447,8 +540,12 @@ namespace UVtools.Core
_waitTimeAfterCure = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomWaitTimeAfterCure, SlicerFile.WaitTimeAfterCure);
_liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
_liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
+ _liftHeight2 = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight2, SlicerFile.LiftHeight2);
+ _liftSpeed2 = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
_waitTimeAfterLift = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomWaitTimeAfterLift, SlicerFile.WaitTimeAfterLift);
- _retractSpeed = SlicerFile.RetractSpeed;
+ _retractSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomRetractSpeed, SlicerFile.RetractSpeed);
+ _retractHeight2 = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomRetractHeight2, SlicerFile.RetractHeight2);
+ _retractSpeed2 = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomRetractSpeed2, SlicerFile.RetractSpeed2);
_lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
}
@@ -569,8 +666,13 @@ namespace UVtools.Core
$"{nameof(WaitTimeAfterCure)}: {WaitTimeAfterCure}s, " +
$"{nameof(LiftHeight)}: {LiftHeight}mm, " +
$"{nameof(LiftSpeed)}: {LiftSpeed}mm/mim, " +
+ $"{nameof(LiftHeight2)}: {LiftHeight2}mm, " +
+ $"{nameof(LiftSpeed2)}: {LiftSpeed2}mm/mim, " +
$"{nameof(WaitTimeAfterLift)}: {WaitTimeAfterLift}s, " +
+ $"{nameof(RetractHeight)}: {RetractHeight}mm, " +
$"{nameof(RetractSpeed)}: {RetractSpeed}mm/mim, " +
+ $"{nameof(RetractHeight2)}: {RetractHeight2}mm, " +
+ $"{nameof(RetractSpeed2)}: {RetractSpeed2}mm/mim, " +
$"{nameof(LightPWM)}: {LightPWM}, " +
$"{nameof(IsModified)}: {IsModified}, " +
$"{nameof(HaveGlobalParameters)}: {HaveGlobalParameters}";
@@ -581,13 +683,13 @@ namespace UVtools.Core
public float CalculateMotorMovementTime(float extraTime = 0)
{
- return OperationCalculator.LightOffDelayC.CalculateSeconds(_liftHeight, _liftSpeed, _retractSpeed, extraTime);
+ return OperationCalculator.LightOffDelayC.CalculateSeconds(this, extraTime);
}
public float CalculateLightOffDelay(float extraTime = 0)
{
- if (SlicerFile is null) return OperationCalculator.LightOffDelayC.CalculateSeconds(_liftHeight, _liftSpeed, _retractSpeed, extraTime);
- return SlicerFile.SupportsGCode ? extraTime : OperationCalculator.LightOffDelayC.CalculateSeconds(_liftHeight, _liftSpeed, _retractSpeed, extraTime);
+ if (SlicerFile is null) return OperationCalculator.LightOffDelayC.CalculateSeconds(this, extraTime);
+ return SlicerFile.SupportsGCode ? extraTime : OperationCalculator.LightOffDelayC.CalculateSeconds(this, extraTime);
}
public void SetLightOffDelay(float extraTime = 0)
@@ -702,6 +804,18 @@ namespace UVtools.Core
return true;
}
+ if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.LiftHeight2))
+ {
+ LiftHeight2 = (float)value;
+ return true;
+ }
+
+ if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.LiftSpeed2))
+ {
+ LiftSpeed2 = (float)value;
+ return true;
+ }
+
if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.WaitTimeAfterLift))
{
WaitTimeAfterLift = (float)value;
@@ -714,6 +828,18 @@ namespace UVtools.Core
return true;
}
+ if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.RetractHeight2))
+ {
+ RetractHeight2 = (float)value;
+ return true;
+ }
+
+ if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.RetractSpeed2))
+ {
+ RetractSpeed2 = (float)value;
+ return true;
+ }
+
if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.LightPWM))
{
LightPWM = (byte)value;
@@ -898,7 +1024,11 @@ namespace UVtools.Core
public Layer Clone()
{
- return new(_index, CompressedBytes.ToArray(), ParentLayerManager)
+ //var layer = (Layer)MemberwiseClone();
+ //layer.CompressedBytes = _compressedBytes.ToArray();
+ //Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes));
+ //return layer;
+ return new (_index, CompressedBytes.ToArray(), ParentLayerManager)
{
PositionZ = _positionZ,
LightOffDelay = _lightOffDelay,
@@ -907,8 +1037,12 @@ namespace UVtools.Core
WaitTimeAfterCure = _waitTimeAfterCure,
LiftHeight = _liftHeight,
LiftSpeed = _liftSpeed,
+ LiftHeight2 = _liftHeight2,
+ LiftSpeed2 = _liftSpeed2,
WaitTimeAfterLift = _waitTimeAfterLift,
RetractSpeed = _retractSpeed,
+ RetractHeight2 = _retractHeight2,
+ RetractSpeed2 = _retractSpeed2,
LightPWM = _lightPwm,
BoundingRectangle = _boundingRectangle,
NonZeroPixelCount = _nonZeroPixelCount,
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index 4d4c2a4..d17c7f8 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -505,8 +505,12 @@ namespace UVtools.Core
layer.WaitTimeAfterCure = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomWaitTimeAfterCure, SlicerFile.WaitTimeAfterCure);
layer.LiftHeight = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
layer.LiftSpeed = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
+ layer.LiftHeight2 = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftHeight2, SlicerFile.LiftHeight2);
+ layer.LiftSpeed2 = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
layer.WaitTimeAfterLift = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomWaitTimeAfterLift, SlicerFile.WaitTimeAfterLift);
- layer.RetractSpeed = SlicerFile.RetractSpeed;
+ layer.RetractSpeed = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed, SlicerFile.RetractSpeed);
+ layer.RetractHeight2 = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractHeight2, SlicerFile.RetractHeight2);
+ layer.RetractSpeed2 = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed2, SlicerFile.RetractSpeed2);
layer.LightPWM = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
}
else
@@ -533,13 +537,25 @@ namespace UVtools.Core
case nameof(SlicerFile.BottomLiftSpeed):
layer.LiftSpeed = SlicerFile.BottomLiftSpeed;
break;
+ case nameof(SlicerFile.BottomLiftHeight2):
+ layer.LiftHeight2 = SlicerFile.BottomLiftHeight2;
+ break;
+ case nameof(SlicerFile.BottomLiftSpeed2):
+ layer.LiftSpeed2 = SlicerFile.BottomLiftSpeed2;
+ break;
case nameof(SlicerFile.BottomWaitTimeAfterLift):
layer.WaitTimeAfterLift = SlicerFile.BottomWaitTimeAfterLift;
break;
- case nameof(SlicerFile.RetractSpeed):
- layer.RetractSpeed = SlicerFile.RetractSpeed;
+ case nameof(SlicerFile.BottomRetractSpeed):
+ layer.RetractSpeed = SlicerFile.BottomRetractSpeed;
+ break;
+ case nameof(SlicerFile.BottomRetractHeight2):
+ layer.RetractHeight2 = SlicerFile.BottomRetractHeight2;
+ break;
+ case nameof(SlicerFile.BottomRetractSpeed2):
+ layer.RetractSpeed2 = SlicerFile.BottomRetractSpeed2;
break;
-
+
case nameof(SlicerFile.BottomLightPWM):
layer.LightPWM = SlicerFile.BottomLightPWM;
break;
@@ -567,12 +583,24 @@ namespace UVtools.Core
case nameof(SlicerFile.LiftSpeed):
layer.LiftSpeed = SlicerFile.LiftSpeed;
break;
+ case nameof(SlicerFile.LiftHeight2):
+ layer.LiftHeight2 = SlicerFile.LiftHeight2;
+ break;
+ case nameof(SlicerFile.LiftSpeed2):
+ layer.LiftSpeed2 = SlicerFile.LiftSpeed2;
+ break;
case nameof(SlicerFile.WaitTimeAfterLift):
layer.WaitTimeAfterLift = SlicerFile.WaitTimeAfterLift;
break;
case nameof(SlicerFile.RetractSpeed):
layer.RetractSpeed = SlicerFile.RetractSpeed;
break;
+ case nameof(SlicerFile.RetractHeight2):
+ layer.RetractHeight2 = SlicerFile.RetractHeight2;
+ break;
+ case nameof(SlicerFile.RetractSpeed2):
+ layer.RetractSpeed2 = SlicerFile.RetractSpeed2;
+ break;
case nameof(SlicerFile.LightPWM):
layer.LightPWM = SlicerFile.LightPWM;
break;
@@ -603,7 +631,7 @@ namespace UVtools.Core
{
var layer = this[layerIndex];
if (this[layerIndex - 1].PositionZ != layer.PositionZ) continue;
- layer.LiftHeight = liftHeight;
+ layer.LiftHeightTotal = liftHeight;
layer.WaitTimeAfterLift = 0;
if (zeroLightOffDelay)
{
diff --git a/UVtools.Core/Operations/OperationCalculator.cs b/UVtools.Core/Operations/OperationCalculator.cs
index 6cf526b..a5e9216 100644
--- a/UVtools.Core/Operations/OperationCalculator.cs
+++ b/UVtools.Core/Operations/OperationCalculator.cs
@@ -286,35 +286,58 @@ namespace UVtools.Core.Operations
return Math.Round(time, 2);
}
- public static float CalculateSeconds(float liftHeight, float liftSpeed, float retractSpeed, float extraWaitTime = 0)
+ public static float CalculateSeconds(float liftHeight, float liftSpeed, float retractSpeed, float extraWaitTime = 0,
+ float liftHeight2 = 0, float liftSpeed2 = 0, float retractHeight2 = 0, float retractSpeed2 = 0)
{
var time = extraWaitTime;
- if (liftSpeed > 0)
- {
+ if (liftHeight > 0 && liftSpeed > 0)
time += liftHeight / (liftSpeed / 60f);
- }
- if (retractSpeed > 0)
+
+ if (liftHeight2 > 0 && liftSpeed2 > 0)
+ time += liftHeight2 / (liftSpeed2 / 60f);
+
+ if (retractHeight2 > 0 && retractSpeed2 > 0)
+ time += retractHeight2 / (retractSpeed2 / 60f);
+
+ var remainingRetractHeight = liftHeight + liftHeight2 - retractHeight2;
+
+ if (remainingRetractHeight > 0 && retractSpeed > 0)
{
- time += liftHeight / (retractSpeed / 60f);
+ time += remainingRetractHeight / (retractSpeed / 60f);
}
return (float)Math.Round(time, 2);
}
+ public static float CalculateSeconds(Layer layer, float extraTime)
+ => CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, extraTime,
+ layer.LiftHeight2, layer.LiftSpeed2, layer.RetractHeight2, layer.RetractSpeed2);
+
+ public static uint CalculateMilliseconds(Layer layer, float extraTime)
+ => (uint)(CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, extraTime,
+ layer.LiftHeight2, layer.LiftSpeed2, layer.RetractHeight2, layer.RetractSpeed2) * 1000);
+
public static uint CalculateMilliseconds(float liftHeight, float liftSpeed, float retract, float extraWaitTime = 0) =>
(uint)(CalculateSeconds(liftHeight, liftSpeed, retract, extraWaitTime) * 1000);
- public static float CalculateSecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0)
+ public static float CalculateSecondsLiftOnly(float liftHeight, float liftSpeed, float liftHeight2 = 0, float liftSpeed2 = 0, float extraWaitTime = 0)
{
- if (liftSpeed <= 0) return extraWaitTime;
- return (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2);
+ var time = extraWaitTime;
+ if (liftHeight > 0 && liftSpeed > 0) time += (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2);
+ if (liftHeight2 > 0 && liftSpeed2 > 0) time += (float)Math.Round(liftHeight2 / (liftSpeed2 / 60f) + extraWaitTime, 2);
+ return time;
}
- public static uint CalculateMillisecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0) =>
- (uint)(CalculateSecondsLiftOnly(liftHeight, liftSpeed, extraWaitTime) * 1000);
+ public static uint CalculateMillisecondsLiftOnly(float liftHeight, float liftSpeed, float liftHeight2 = 0, float liftSpeed2 = 0, float extraWaitTime = 0) =>
+ (uint)(CalculateSecondsLiftOnly(liftHeight, liftSpeed, liftHeight2, liftSpeed2, extraWaitTime) * 1000);
+
+ public static float CalculateSecondsLiftOnly(Layer layer, float extraWaitTime = 0) =>
+ CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, layer.LiftHeight2, layer.LiftSpeed2, extraWaitTime);
+ public static uint CalculateMillisecondsLiftOnly(Layer layer, float extraWaitTime = 0) =>
+ (uint)(CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, layer.LiftHeight2, layer.LiftSpeed2, extraWaitTime) * 1000);
}
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index 608b8ec..ccd1305 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -2170,15 +2170,10 @@ namespace UVtools.Core.Operations
}
else
{
- Layer layer = new(layerIndex++, mat, SlicerFile)
+ var layer = new Layer(layerIndex++, mat, SlicerFile)
{
PositionZ = (float)currentHeight,
ExposureTime = isBottomLayer ? (float)bottomExposure : (float)normalExposure,
- LiftHeight = isBottomLayer ? SlicerFile.BottomLiftHeight : SlicerFile.LiftHeight,
- LiftSpeed = isBottomLayer ? SlicerFile.BottomLiftSpeed : SlicerFile.LiftSpeed,
- RetractSpeed = SlicerFile.RetractSpeed,
- LightOffDelay = isBottomLayer ? SlicerFile.BottomLightOffDelay : SlicerFile.LightOffDelay,
- LightPWM = isBottomLayer ? SlicerFile.BottomLightPWM : SlicerFile.LightPWM,
IsModified = true
};
newLayers.Add(layer);
@@ -2249,8 +2244,8 @@ namespace UVtools.Core.Operations
var layers = SlicerFile.LayerManager.GetSamePositionedLayers();
foreach (var layer in layers)
{
- if(_samePositionedLayersLiftHeightEnabled) layer.LiftHeight = (float) _samePositionedLayersLiftHeight;
- if(_samePositionedLayersLightOffDelayEnabled) layer.LightOffDelay = (float) _samePositionedLayersLightOffDelay;
+ if(_samePositionedLayersLiftHeightEnabled) layer.LiftHeightTotal = (float) _samePositionedLayersLiftHeight;
+ if(_samePositionedLayersLightOffDelayEnabled) layer.LightOffDelay = (float) _samePositionedLayersLightOffDelay;
}
}
diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs
index 739c485..ea82e3d 100644
--- a/UVtools.Core/Operations/OperationDynamicLifts.cs
+++ b/UVtools.Core/Operations/OperationDynamicLifts.cs
@@ -252,10 +252,10 @@ namespace UVtools.Core.Operations
{
base.InitWithSlicerFile();
- if(_minBottomLiftHeight <= 0) _minBottomLiftHeight = SlicerFile.BottomLiftHeight;
+ if(_minBottomLiftHeight <= 0) _minBottomLiftHeight = SlicerFile.BottomLiftHeightTotal;
if (_maxBottomLiftHeight <= 0 || _maxBottomLiftHeight < _minBottomLiftHeight) _maxBottomLiftHeight = _minBottomLiftHeight;
- if (_minLiftHeight <= 0) _minLiftHeight = SlicerFile.LiftHeight;
+ if (_minLiftHeight <= 0) _minLiftHeight = SlicerFile.LiftHeightTotal;
if (_maxLiftHeight <= 0 || _maxLiftHeight < _minLiftHeight) _maxLiftHeight = _minLiftHeight;
if (_minBottomLiftSpeed <= 0) _minBottomLiftSpeed = SlicerFile.BottomLiftSpeed;
@@ -340,7 +340,8 @@ namespace UVtools.Core.Operations
liftSpeed = (_maxLiftSpeed - (_maxLiftSpeed * layer.NonZeroPixelCount / maxNormalPixels)).Clamp(_minLiftSpeed, _maxLiftSpeed);
}
- layer.LiftHeight = (float) Math.Round(liftHeight, 1);
+ layer.RetractHeight2 = 0;
+ layer.LiftHeightTotal = (float) Math.Round(liftHeight, 1);
layer.LiftSpeed = (float) Math.Round(liftSpeed, 1);
switch (_lightOffDelaySetMode)
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index b2d41a2..42df498 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.17.0</Version>
+ <Version>2.18.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
index e762ac3..543738a 100644
--- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs
+++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
@@ -311,8 +311,8 @@
<Component Id="owc6F31DEF09608AA645959666A4CB7FBBC" Guid="c94570a5-5bb4-a53f-e12f-9581bddf7d08" Win64="yes">
<File Id="owf6F31DEF09608AA645959666A4CB7FBBC" Source="$(var.SourceDir)\mscordaccore.dll" KeyPath="yes" />
</Component>
- <Component Id="owc0365879AFD7A138F231419745CD7CD56" Guid="419f9e5f-a09c-aa5d-379f-f6b5994c509d" Win64="yes">
- <File Id="owf0365879AFD7A138F231419745CD7CD56" Source="$(var.SourceDir)\mscordaccore_amd64_amd64_5.0.821.31504.dll" KeyPath="yes" />
+ <Component Id="owc428BBD3686267EBE46F26528F46752D2" Guid="51ee2d87-3a8b-16e2-c5e8-4523e0869c04" Win64="yes">
+ <File Id="owf428BBD3686267EBE46F26528F46752D2" Source="$(var.SourceDir)\mscordaccore_amd64_amd64_5.0.921.35908.dll" KeyPath="yes" />
</Component>
<Component Id="owc5FC34571A1AE47A011FC6C2A95B00DA6" Guid="2591451e-0fe5-ccad-abf6-1d1097251253" Win64="yes">
<File Id="owf5FC34571A1AE47A011FC6C2A95B00DA6" Source="$(var.SourceDir)\mscordbi.dll" KeyPath="yes" />
diff --git a/UVtools.WPF/ConsoleArguments.cs b/UVtools.WPF/ConsoleArguments.cs
new file mode 100644
index 0000000..7839392
--- /dev/null
+++ b/UVtools.WPF/ConsoleArguments.cs
@@ -0,0 +1,152 @@
+/*
+ * 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.Generic;
+using System.IO;
+using MoreLinq;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.WPF
+{
+ public static class ConsoleArguments
+ {
+ /// <summary>
+ /// Parse arguments from command line
+ /// </summary>
+ /// <param name="args"></param>
+ /// <returns>True if is a valid argument, otherwise false</returns>
+ public static bool ParseArgs(string[] args)
+ {
+ if(args is null || args.Length == 0) return false;
+
+ // Convert to other file
+ if (args[0] is "-c" or "--convert")
+ {
+ if (args.Length < 3)
+ {
+ Console.WriteLine("Invalid syntax: <input_file> <output_file1/ext1> [output_file2/ext2]");
+ return true;
+ }
+ if (!File.Exists(args[1]))
+ {
+ Console.WriteLine($"Input file does not exists: {args[1]}");
+ return true;
+ }
+
+ var slicerFile = FileFormat.FindByExtension(args[1], true, true);
+ if (slicerFile is null)
+ {
+ Console.WriteLine($"Invalid input file: {args[1]}");
+ return true;
+ }
+
+
+ var filenameNoExt = FileFormat.GetFileNameStripExtensions(args[1], out _);
+
+ var filesToConvert = new List<KeyValuePair<FileFormat, string>>();
+
+ for (int i = 2; i < args.Length; i++)
+ {
+ var outputFile = args[i];
+ var targetFormat = FileFormat.FindByExtension(args[i]);
+ if (targetFormat is not null)
+ {
+ outputFile = $"{filenameNoExt}.{args[i]}";
+ }
+ else
+ {
+ targetFormat = FileFormat.FindByExtension(args[i], true);
+ }
+
+ if (targetFormat is null)
+ {
+ Console.WriteLine($"Invalid output file/extension: {args[i]}");
+ continue;
+ }
+
+ filesToConvert.Add(new KeyValuePair<FileFormat, string>(targetFormat, outputFile));
+ }
+
+ if (filesToConvert.Count == 0)
+ {
+ return true;
+ }
+
+ //var workingDir = Path.GetDirectoryName(args[1]);
+ //if(!string.IsNullOrWhiteSpace(workingDir)) Directory.SetCurrentDirectory(workingDir);
+
+ Console.WriteLine($"Loading file: {args[1]}");
+ slicerFile.Decode(args[1]);
+
+ foreach (var (outputSlicerFile, outputFile) in filesToConvert.DistinctBy(pair => pair.Value))
+ {
+ Console.WriteLine($"Converting to: {outputFile}");
+ slicerFile.Convert(outputSlicerFile, outputFile);
+ Console.WriteLine("Converted");
+
+ }
+
+ Console.WriteLine("OK");
+
+ return true;
+ }
+
+ // Extract the file
+ if (args[0] is "-e" or "--extract")
+ {
+ if (args.Length < 2)
+ {
+ Console.WriteLine("Invalid syntax: <input_file> [output_folder]");
+ return true;
+ }
+ if (!File.Exists(args[1]))
+ {
+ Console.WriteLine($"Input file does not exists: {args[1]}");
+ return true;
+ }
+
+ var slicerFile = FileFormat.FindByExtension(args[1], true, true);
+ if (slicerFile is null)
+ {
+ Console.WriteLine($"Invalid input file: {args[1]}");
+ return true;
+ }
+
+ var outputFolder = FileFormat.GetFileNameStripExtensions(args[1], out _);
+
+ if (args.Length >= 3 && !string.IsNullOrWhiteSpace(args[2]))
+ {
+ try
+ {
+ Path.GetFullPath(outputFolder);
+ outputFolder = args[2];
+ }
+ catch (Exception)
+ {
+ Console.WriteLine($"Invalid output directory: {args[2]}");
+ return true;
+ }
+ }
+
+ //var workingDir = Path.GetDirectoryName(args[1]);
+ //if(!string.IsNullOrWhiteSpace(workingDir)) Directory.SetCurrentDirectory(workingDir);
+
+ Console.WriteLine($"Loading file: {args[1]}");
+ slicerFile.Decode(args[1]);
+ Console.WriteLine($"Extracting to: {outputFolder}");
+ slicerFile.Extract(outputFolder);
+ Console.WriteLine("Extracted");
+ Console.WriteLine("OK");
+ return true;
+ }
+
+
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/UVtools.WPF/MainWindow.Information.cs b/UVtools.WPF/MainWindow.Information.cs
index 3efc701..60563ce 100644
--- a/UVtools.WPF/MainWindow.Information.cs
+++ b/UVtools.WPF/MainWindow.Information.cs
@@ -348,8 +348,13 @@ namespace UVtools.WPF
if (SlicerFile.CanUseLayerLiftHeight)
CurrentLayerProperties.Add(new ValueDescription($"{layer.LiftHeight.ToString(CultureInfo.InvariantCulture)}mm @ {layer.LiftSpeed.ToString(CultureInfo.InvariantCulture)}mm/min", nameof(layer.LiftHeight)));
+ if (SlicerFile.CanUseLayerLiftHeight2)
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.LiftHeight2.ToString(CultureInfo.InvariantCulture)}mm @ {layer.LiftSpeed2.ToString(CultureInfo.InvariantCulture)}mm/min", nameof(layer.LiftHeight2)));
+
if (SlicerFile.CanUseLayerRetractSpeed)
- CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractSpeed}mm/min", nameof(layer.RetractSpeed)));
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractHeight.ToString(CultureInfo.InvariantCulture)}mm @ {layer.RetractSpeed}mm/min", nameof(layer.RetractHeight)));
+ if (SlicerFile.CanUseLayerRetractHeight2)
+ CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractHeight2.ToString(CultureInfo.InvariantCulture)}mm @ {layer.RetractSpeed2}mm/min", nameof(layer.RetractHeight2)));
if (SlicerFile.CanUseLayerLightOffDelay)
CurrentLayerProperties.Add(new ValueDescription($"{layer.LightOffDelay}s", nameof(layer.LightOffDelay)));
diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs
index 48a070b..b3ee62d 100644
--- a/UVtools.WPF/Program.cs
+++ b/UVtools.WPF/Program.cs
@@ -20,6 +20,16 @@ namespace UVtools.WPF
ProgramStartupTime = Stopwatch.StartNew();
Args = args;
+ try
+ {
+ if (ConsoleArguments.ParseArgs(args)) return;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ return;
+ }
+
/*Slicer slicer = new(Size.Empty, SizeF.Empty, "D:\\Cube100x100x100.stl");
var slices = slicer.SliceModel(0.05f);
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 35bb601..42cae7b 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.17.0</Version>
+ <Version>2.18.0</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1
index 4985e72..218e9b5 100644
--- a/build/CreateRelease.WPF.ps1
+++ b/build/CreateRelease.WPF.ps1
@@ -32,10 +32,10 @@ Set-Location $PSScriptRoot\..
####################################
### Configuration ###
####################################
-$enableMSI = $true
-#$buildOnly = 'win-x64'
+#$enableMSI = $true
+$buildOnly = 'win-x64'
#$buildOnly = 'linux-x64'
-$enableNugetPublish = $true
+#$enableNugetPublish = $true
# Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
$deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch