diff options
47 files changed, 1776 insertions, 501 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f6e184c..4b80220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## 16/07/2021 - v2.15.0 + +- **File formats:** + - (Add) Wait time before cure: The time to rest/wait in seconds before cure a new layer + - (Add) Wait time before after: The time to rest/wait in seconds after cure a new layer + - (Add) Wait time after lift: The time to rest/wait in seconds after a lift/peel move + - (Change) All gcode file formats dropped light-off delay field in favor of new 'Wait time before cure' field, setting light-off delay still valid but it redirects to the new field + - (Change) Reorder 'Light-off delay' before 'Exposure time' + - (Improvement) Recalculate the print time when a related property changes + - (Fix) Generic time estimation calculation was ignoring exposure times + - (Fix) Unable to load files with uppercase extensions + - (Fix) ZIP: Use G1 at end of gcode instead of G0 + - (Fix) CWS: Use G1 for movements + - **(Fix) CXDLP:** (#240) + - Layer area calculation + - Validation checksum + - **(Fix) ZCODE:** + - Use G1 at end of gcode instead of G0 to prevent crash to top bug on firmware + - Put back the M18 motors off at end of gcode +- **GCode Builder/Parser:** + - (Add) Allow to choose between G0 and G1 for layer movements and end gcode + - (Fix) Safe guard: If the total print height is larger than set machine Z, do not raise/lower print on completeness + - (Fix) Light-off delay is the real delay time and not the calculated movement of the lifts plus the extra time + - (Improvement) Parse gcode line by line instead searching on a group of layers to allow a better control and identification +- **Tools:** + - **Change print parameters:** + - (Add) Tooltips to labels + - (Add) Sun UTF-8 to the Light PWM value unit to describe intensity + - (Improvement) Dynamic lifts: Round lift height and speed to 1 decimal + - (Fix) Exposure time finder: Time estimation when using 'Use different settings for layers with same Z positioning' +- **Prusa Slicer:** + - (Add) Note keyword: BottomWaitBeforeCure_xxx + - (Add) Note keyword: WaitBeforeCure_xxx + - (Add) Note keyword: BottomWaitAfterCure_xxx + - (Add) Note keyword: WaitAfterCure_xxx + - (Add) Note keyword: BottomWaitAfterLift_xxx + - (Add) Note keyword: WaitAfterLift_xxx + - (Change) Uniz IBEE: Remove light-off delay and implement wait time keywords +- **macOS:** (#236) + - (Remove) osx legacy packages from build and downloads + - (Fix) macOS: Simplify the libcvextern.dylib and remove libtesseract dependency + - (Fix) macOS: Include libusb-1.0.0.dylib + - Note: `brew install libusb` still required +- **UI:** + - (Fix) Refresh gcode does not update text on UI for ZIP, CWS, ZCODEX files + - (Fix) Operations: Import a .uvtop file by drag and drop into the UI would not load the layer range + - (Change) When convert a file, the result dialog will have Yes, No and Cancel actions, where No will open the converted file on current window, while Cancel will not perform any action (The old No behaviour) + ## 12/07/2021 - v2.14.3 - (Add) Exposure time finder: Base layers print modes, a option to speed up the print process and merge all base layers in the same height diff --git a/PrusaSlicer/printer/Uniz IBEE.ini b/PrusaSlicer/printer/Uniz IBEE.ini index 2a7d1ca..3f8cc9f 100644 --- a/PrusaSlicer/printer/Uniz IBEE.ini +++ b/PrusaSlicer/printer/Uniz IBEE.ini @@ -1,4 +1,4 @@ -# generated by PrusaSlicer 2.3.0+win64 on 2021-03-02 at 01:39:35 UTC +# generated by PrusaSlicer 2.3.1+win64 on 2021-07-16 at 02:35:15 UTC absolute_correction = 0 area_fill = 50 bed_custom_model = @@ -26,7 +26,7 @@ min_exposure_time = 1 min_initial_exposure_time = 1 print_host = printer_model = SL1 -printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_UNIZ\nPRINTER_MODEL_IBEE\nFILEFORMAT_ZCODE\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_15\nLiftHeight_7\nBottomLiftSpeed_20\nLiftSpeed_80\nRetractSpeed_80\nEND_CUSTOM_VALUES +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_UNIZ\nPRINTER_MODEL_IBEE\nFILEFORMAT_ZCODE\n\nSTART_CUSTOM_VALUES\nBottomWaitBeforeCure_3\nWaitBeforeCure_2.5\nBottomWaitAfterCure_3\nWaitAfterCure_1\nBottomLiftHeight_7\nLiftHeight_5\nBottomLiftSpeed_80\nLiftSpeed_150\nBottomWaitAfterLift_0\nWaitAfterLift_0\nRetractSpeed_150\nEND_CUSTOM_VALUES printer_settings_id = printer_technology = SLA printer_variant = default @@ -184,16 +184,22 @@ Complete guide: https://github.com/sn4k3/UVtools/wiki/Setup-PrusaSlicer Note that some variables will only work if the target format supports them, otherwise they will be ignored. Replace the "xxx" by your desired value in the correct units -* **BottomLightOffDelay_xxx:** Sets the bottom light off delay time in seconds -* **LightOffDelay_xxx:** Sets the light off delay time in seconds -* **BottomLiftHeight_xxx:** Sets the bottom lift height in millimeters -* **BottomLiftSpeed_xxx:** Sets the bottom lift speed in millimeters/minute -* **LiftHeight_xxx:** Sets the lift height in millimeters -* **LiftSpeed_xxx:** Sets the lift speed in millimeters/minute -* **RetractSpeed_xxx:** Sets the retract speed in millimeters/minute -* **BottomLightPWM_xxx:** Sets the bottom LED light power (0-255) -* **LightPWM_xxx:** Sets the LED light power (0-255) -* **FILEFORMAT_xxx:** Sets the output file format extension to be auto converted once open on UVtools +- **BottomLightOffDelay_xxx:** Sets the bottom light off delay time in seconds +- **LightOffDelay_xxx:** Sets the light off delay time in seconds +- **BottomWaitBeforeCure_xxx:** Sets the bottom wait time before cure in seconds +- **WaitBeforeCure_xxx:** Sets the wait time before cure in seconds +- **BottomWaitAfterCure_xxx:** Sets the bottom wait time after cure in seconds +- **WaitAfterCure_xxx:** Sets the wait time after cure in seconds +- **BottomLiftHeight_xxx:** Sets the bottom lift height in millimeters +- **BottomLiftSpeed_xxx:** Sets the bottom lift speed in millimeters/minute +- **LiftHeight_xxx:** Sets the lift height in millimeters +- **LiftSpeed_xxx:** Sets the lift speed in millimeters/minute +- **BottomWaitAfterLift_xxx:** Sets the bottom wait time after lift in seconds +- **WaitAfterLift_xxx:** Sets the wait time after lift in seconds +- **RetractSpeed_xxx:** Sets the retract speed in millimeters/minute +- **BottomLightPWM_xxx:** Sets the bottom LED light power (0-255) +- **LightPWM_xxx:** Sets the LED light power (0-255) +- **FILEFORMAT_xxx:** Sets the output file format extension to be auto converted once open on UVtools # File Convertion diff --git a/Scripts/010 Editor/ctb.bt b/Scripts/010 Editor/ctb.bt index 88ddc4b..e45a4d5 100644 --- a/Scripts/010 Editor/ctb.bt +++ b/Scripts/010 Editor/ctb.bt @@ -88,7 +88,7 @@ struct SLICER_INFO { uint EncryptionMode <fgcolor=cBlack, bgcolor=cRed>; // 0/8 for cbddlp files, 0xF (15) for ctb files, 0x2000000F (536870927) for v3 ctb and 1073741839 for v4 ctb files to allow per layer parameters uint MysteriousId <fgcolor=cBlack, bgcolor=cRed>; // v3 = 305419896 | v4 lightoff? = 27093086 | v4 rest? = 27093090 uint AntiAliasLevel <fgcolor=cBlack, bgcolor=cRed>; - uint SoftwareVersion <fgcolor=cBlack, bgcolor=cRed>; // ctb v3 = 17171200 | ctb v4 = 16777216 + uint SoftwareVersion <fgcolor=cBlack, bgcolor=cRed>; // ctb v3 = 17171200 | ctb v4 pro = 16777216 float RestTimeAfterRetract <fgcolor=cBlack, bgcolor=cRed>; float RestTimeAfterLift2 <fgcolor=cBlack, bgcolor=cRed>; uint TransitionLayerCount <fgcolor=cBlack, bgcolor=cRed>; diff --git a/Scripts/010 Editor/cxdlp_v1.bt b/Scripts/010 Editor/cxdlp_v1.bt index bc43eda..e1f85db 100644 --- a/Scripts/010 Editor/cxdlp_v1.bt +++ b/Scripts/010 Editor/cxdlp_v1.bt @@ -87,5 +87,5 @@ struct FOOTER { uint32 footerSize <fgcolor=cBlack, bgcolor=cWhite>; BYTE str[footer.footerSize] <fgcolor=cBlack, bgcolor=cRed>; - uint32 unknown <fgcolor=cBlack, bgcolor=cWhite>; + uint32 checkSum <fgcolor=cBlack, bgcolor=cWhite>; } footer;
\ No newline at end of file diff --git a/Scripts/010 Editor/cxdlp_v2.bt b/Scripts/010 Editor/cxdlp_v2.bt index 3a33f30..91322ed 100644 --- a/Scripts/010 Editor/cxdlp_v2.bt +++ b/Scripts/010 Editor/cxdlp_v2.bt @@ -18,14 +18,14 @@ typedef struct { } layerPointsData; typedef struct { - uint32 unknown <fgcolor=cBlack, bgcolor=cWhite>; + uint32 layerArea <fgcolor=cBlack, bgcolor=cWhite>; } layerDef; typedef struct() { - uint32 unknown <fgcolor=cBlack, bgcolor=cWhite>; - uint32 LayerPointNum <fgcolor=cBlack, bgcolor=cWhite>; + uint32 layerArea <fgcolor=cBlack, bgcolor=cWhite>; + uint32 layerPointNum <fgcolor=cBlack, bgcolor=cWhite>; - layerPointsData pD()[LayerPointNum]; + layerPointsData pD()[layerPointNum]; BYTE CR_LF2[2] <fgcolor=cBlack, bgcolor=cRed>; } layerData; @@ -37,7 +37,7 @@ struct HEADER { uint32 headerSize <fgcolor=cBlack, bgcolor=cWhite>; BYTE header[headerSize] <fgcolor=cBlack, bgcolor=cRed>; - uint16 unknown <fgcolor=cBlack, bgcolor=cWhite>; + uint16 version <fgcolor=cBlack, bgcolor=cWhite>; uint32 modelSize <fgcolor=cBlack, bgcolor=cWhite>; BYTE model[modelSize] <fgcolor=cBlack, bgcolor=cRed>; @@ -66,8 +66,8 @@ struct HEADER { uint32 layerThicknessLength <fgcolor=cBlack, bgcolor=cWhite>; wchar_t layerThickness[layerThicknessLength/2]; - uint16 turnOffTime <fgcolor=cBlack, bgcolor=cWhite>; uint16 exposureTime <fgcolor=cBlack, bgcolor=cWhite>; + uint16 turnOffTime <fgcolor=cBlack, bgcolor=cWhite>; uint16 bottomExposure <fgcolor=cBlack, bgcolor=cWhite>; uint16 bottomLayers <fgcolor=cBlack, bgcolor=cWhite>; uint16 bottomRaise <fgcolor=cBlack, bgcolor=cWhite>; @@ -99,5 +99,6 @@ struct FOOTER { uint32 footerSize <fgcolor=cBlack, bgcolor=cWhite>; BYTE str[footer.footerSize] <fgcolor=cBlack, bgcolor=cRed>; - uint32 unknown <fgcolor=cBlack, bgcolor=cWhite>; + byte checkSumControl[3] <fgcolor=cBlack, bgcolor=cWhite>; + unsigned byte checkSumByte <fgcolor=cBlack, bgcolor=cWhite>; } footer;
\ No newline at end of file diff --git a/UVtools.Core/Extensions/BitExtensions.cs b/UVtools.Core/Extensions/BitExtensions.cs index 8cb7dbd..252062c 100644 --- a/UVtools.Core/Extensions/BitExtensions.cs +++ b/UVtools.Core/Extensions/BitExtensions.cs @@ -83,6 +83,36 @@ namespace UVtools.Core.Extensions buffer[offset + 3] = (byte)value; } + public static byte[] ToBytesLittleEndian(int value) + { + var bytes = new byte[4]; + ToBytesLittleEndian(value, bytes); + return bytes; + } + + public static void ToBytesLittleEndian(int value, byte[] buffer, uint offset = 0) + { + buffer[offset] = (byte)value; + buffer[offset + 1] = (byte)(value >> 8); + buffer[offset + 2] = (byte)(value >> 16); + buffer[offset + 3] = (byte)(value >> 24); + } + + public static byte[] ToBytesBigEndian(int value) + { + var bytes = new byte[4]; + ToBytesBigEndian(value, bytes); + return bytes; + } + + public static void ToBytesBigEndian(int value, byte[] buffer, uint offset = 0) + { + buffer[offset] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)value; + } + } } diff --git a/UVtools.Core/Extensions/PathExtensions.cs b/UVtools.Core/Extensions/PathExtensions.cs index 1b3be72..223b8c1 100644 --- a/UVtools.Core/Extensions/PathExtensions.cs +++ b/UVtools.Core/Extensions/PathExtensions.cs @@ -29,7 +29,7 @@ namespace UVtools.Core.Extensions foreach (var extension in extensions) { var dotExtension = $".{extension}"; - if (!path.EndsWith(dotExtension)) continue; + if (!path.EndsWith(dotExtension, StringComparison.OrdinalIgnoreCase)) continue; strippedExtension = extension; return path.Remove(path.Length - dotExtension.Length); } diff --git a/UVtools.Core/FileFormats/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs index 86e5e31..6a22b78 100644 --- a/UVtools.Core/FileFormats/CWSFile.cs +++ b/UVtools.Core/FileFormats/CWSFile.cs @@ -9,13 +9,11 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml.Serialization; using Emgu.CV; @@ -311,27 +309,41 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomWaitTimeBeforeCure, + PrintParameterModifier.WaitTimeBeforeCure, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomWaitTimeAfterCure, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.BottomLiftHeight, - PrintParameterModifier.LiftHeight, PrintParameterModifier.BottomLiftSpeed, + PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + + PrintParameterModifier.BottomWaitTimeAfterLift, + PrintParameterModifier.WaitTimeAfterLift, + PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + PrintParameterModifier.WaitTimeAfterLift, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.LightPWM, }; @@ -431,6 +443,34 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = SliceSettings.HeadLayersNum = value; } + public override float BottomLightOffDelay + { + get => BottomWaitTimeBeforeCure; + set => BottomWaitTimeBeforeCure = value; + } + + public override float LightOffDelay + { + get => WaitTimeBeforeCure; + set => WaitTimeBeforeCure = value; + } + + public override float BottomWaitTimeBeforeCure + { + get => base.BottomWaitTimeBeforeCure; + set => base.BottomWaitTimeBeforeCure = base.BottomLightOffDelay = value; + } + + public override float WaitTimeBeforeCure + { + get => TimeExtensions.MillisecondsToSeconds(SliceSettings.WaitBeforeExpoMs); + set + { + SliceSettings.WaitBeforeExpoMs = TimeExtensions.SecondsToMillisecondsUint(value); + base.WaitTimeBeforeCure = base.LightOffDelay = value; + } + } + public override float BottomExposureTime { get => TimeExtensions.MillisecondsToSeconds(OutputSettings.BottomLayersTime); @@ -481,16 +521,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = OutputSettings.ZLiftRetractRate = SliceSettings.LiftDownSpeed = (float)Math.Round(value, 2); } - public override float LightOffDelay - { - get => TimeExtensions.MillisecondsToSeconds(SliceSettings.WaitBeforeExpoMs); - set - { - SliceSettings.WaitBeforeExpoMs = TimeExtensions.SecondsToMillisecondsUint(value); - base.LightOffDelay = value; - } - } - public override byte BottomLightPWM { get => OutputSettings.BottomLightPWM; @@ -507,6 +537,7 @@ namespace UVtools.Core.FileFormats public override object[] Configs => Printer == PrinterType.Wanhao ? new object[] { SliceBuildConfig, OutputSettings } : new object[] { SliceSettings, OutputSettings}; #endregion + #region Constructor public CWSFile() { GCode = new GCodeBuilder @@ -515,11 +546,14 @@ namespace UVtools.Core.FileFormats GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial, GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute, GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds, - GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndexZero + GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndexZero, + LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G1, + EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1 }; GCode.CommandShowImageM6054.Set(";<Slice>", "{0}"); GCode.CommandWaitG4.Set(";<Delay>", "{0}"); } + #endregion #region Methods @@ -837,6 +871,7 @@ namespace UVtools.Core.FileFormats public override void RebuildGCode() { + if (!SupportsGCode || SuppressRebuildGCode) return; //string arch = Environment.Is64BitOperatingSystem ? "64-bits" : "32-bits"; //GCode.Clear(); //GCode.AppendLine($"; {About.Website} {About.Software} {Assembly.GetExecutingAssembly().GetName().Version} {arch} {DateTime.Now}"); @@ -938,6 +973,7 @@ namespace UVtools.Core.FileFormats } GCode.AppendFormat(Printer == PrinterType.Wanhao ? WanhaoGCodeEnd : GCodeEnd, Environment.NewLine, SliceSettings.LiftWhenFinished);*/ + RaisePropertyChanged(nameof(GCodeStr)); } public override void SaveAs(string filePath = null, OperationProgress progress = null) diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs index aaabbbf..3692231 100644 --- a/UVtools.Core/FileFormats/CXDLPFile.cs +++ b/UVtools.Core/FileFormats/CXDLPFile.cs @@ -55,7 +55,7 @@ namespace UVtools.Core.FileFormats [FieldOrder(2)] [FieldEndianness(Endianness.Big)] - public ushort Unknown { get; set; } = 2; + public ushort Version { get; set; } = 2; /// <summary> /// Gets the size of the printer model @@ -130,7 +130,7 @@ namespace UVtools.Core.FileFormats public override string ToString() { - return $"{nameof(HeaderSize)}: {HeaderSize}, {nameof(HeaderValue)}: {HeaderValue}, {nameof(Unknown)}: {Unknown}, {nameof(PrinterModelSize)}: {PrinterModelSize}, {nameof(PrinterModelArray)}: {PrinterModelArray}, {nameof(PrinterModel)}: {PrinterModel}, {nameof(LayerCount)}: {LayerCount}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Offset)}: {Offset}"; + return $"{nameof(HeaderSize)}: {HeaderSize}, {nameof(HeaderValue)}: {HeaderValue}, {nameof(Version)}: {Version}, {nameof(PrinterModelSize)}: {PrinterModelSize}, {nameof(PrinterModelArray)}: {PrinterModelArray}, {nameof(PrinterModel)}: {PrinterModel}, {nameof(LayerCount)}: {LayerCount}, {nameof(ResolutionX)}: {ResolutionX}, {nameof(ResolutionY)}: {ResolutionY}, {nameof(Offset)}: {Offset}"; } } @@ -221,38 +221,38 @@ namespace UVtools.Core.FileFormats { [FieldOrder(0)] [FieldEndianness(Endianness.Big)] - public uint Unknown { get; set; } + public uint LayerArea { get; set; } public PreLayer() { } - public PreLayer(uint unknown) + public PreLayer(uint layerArea) { - Unknown = unknown; + LayerArea = layerArea; } } public sealed class LayerDef { - [FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint Unknown { get; set; } + [FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint LayerArea { get; set; } [FieldOrder(1)] [FieldEndianness(Endianness.Big)] public uint LineCount { get; set; } [FieldOrder(2)] [FieldCount(nameof(LineCount))] public LayerLine[] Lines { get; set; } [FieldOrder(3)] public PageBreak PageBreak { get; set; } = new(); - public static byte[] GetHeaderBytes(uint unknown, uint lineCount) + public static byte[] GetHeaderBytes(uint layerArea, uint lineCount) { var bytes = new byte[8]; - BitExtensions.ToBytesBigEndian(unknown, bytes); + BitExtensions.ToBytesBigEndian(layerArea, bytes); BitExtensions.ToBytesBigEndian(lineCount, bytes, 4); return bytes; } public LayerDef() { } - public LayerDef(uint unknown, uint lineCount, LayerLine[] lines) + public LayerDef(uint layerArea, uint lineCount, LayerLine[] lines) { - Unknown = unknown; + LayerArea = layerArea; LineCount = lineCount; Lines = lines; } @@ -335,9 +335,9 @@ namespace UVtools.Core.FileFormats [SerializeAs(SerializedType.TerminatedString)] public string FooterValue { get; set; } = HEADER_VALUE; - [FieldOrder(2)] + /*[FieldOrder(2)] [FieldEndianness(Endianness.Big)] - public uint Unknown { get; set; } = 7; + public uint CheckSum { get; set; }*/ public void Validate() { @@ -366,15 +366,17 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, @@ -413,6 +415,7 @@ namespace UVtools.Core.FileFormats set { string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture); + //string str = Math.Round(value, 2).ToString("0.000000"); SlicerInfoSettings.DisplayWidthDataSize = (uint)(str.Length * 2); var data = new byte[SlicerInfoSettings.DisplayWidthDataSize]; for (var i = 0; i < str.Length; i++) @@ -431,6 +434,7 @@ namespace UVtools.Core.FileFormats set { string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture); + //string str = Math.Round(value, 2).ToString("0.000000"); SlicerInfoSettings.DisplayHeightDataSize = (uint)(str.Length * 2); var data = new byte[SlicerInfoSettings.DisplayHeightDataSize]; for (var i = 0; i < str.Length; i++) @@ -455,6 +459,7 @@ namespace UVtools.Core.FileFormats set { string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture); + //string str = Layer.RoundHeight(value).ToString("0.000000"); SlicerInfoSettings.LayerHeightDataSize = (uint)(str.Length * 2); var data = new byte[SlicerInfoSettings.LayerHeightDataSize]; for (var i = 0; i < str.Length; i++) @@ -479,6 +484,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = SlicerInfoSettings.BottomLayers = value; } + public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; + + public override float LightOffDelay + { + get => SlicerInfoSettings.LightOffDelay; + set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; + } + public override float BottomExposureTime { get => SlicerInfoSettings.BottomExposureTime; @@ -521,14 +534,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)value; } - public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; - - public override float LightOffDelay - { - get => SlicerInfoSettings.LightOffDelay; - set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; - } - public override byte BottomLightPWM { get => (byte) SlicerInfoSettings.BottomLightPWM; @@ -558,7 +563,7 @@ namespace UVtools.Core.FileFormats protected override void EncodeInternally(string fileFullPath, OperationProgress progress) { - using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write); + using var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.ReadWrite); if (ResolutionX == 1620 && ResolutionY == 2560) { @@ -624,7 +629,7 @@ namespace UVtools.Core.FileFormats for (int layerIndex = 0; layerIndex < LayerCount; layerIndex++) { //var layer = this[layerIndex]; - outputFile.WriteBytes(BitExtensions.ToBytesBigEndian(this[layerIndex].NonZeroPixelCount)); + outputFile.WriteBytes(BitExtensions.ToBytesBigEndian((uint)Math.Round(this[layerIndex].BoundingRectangleMillimeters.Area()*1000))); //preLayers[layerIndex] = new(layer.NonZeroPixelCount); } //Helpers.SerializeWriteFileStream(outputFile, preLayers); @@ -679,7 +684,9 @@ namespace UVtools.Core.FileFormats } } - layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes(layer.NonZeroPixelCount, lineCount)); + layerBytes[layerIndex].InsertRange(0, LayerDef.GetHeaderBytes( + (uint)Math.Round(layer.BoundingRectangleMillimeters.Area()*1000), + lineCount)); layerBytes[layerIndex].AddRange(pageBreak); progress.LockAndIncrement(); @@ -765,6 +772,10 @@ namespace UVtools.Core.FileFormats Helpers.SerializeWriteFileStream(outputFile, FooterSettings); + uint checkSum = CalculateCheckSum(outputFile, false); + + outputFile.Write(BitExtensions.ToBytesBigEndian(checkSum)); + Debug.WriteLine("Encode Results:"); Debug.WriteLine(HeaderSettings); Debug.WriteLine("-End-"); @@ -773,11 +784,28 @@ namespace UVtools.Core.FileFormats protected override void DecodeInternally(string fileFullPath, OperationProgress progress) { using var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read); + + inputFile.Seek(0, SeekOrigin.Begin); + HeaderSettings = Helpers.Deserialize<Header>(inputFile); + Debug.WriteLine(HeaderSettings); HeaderSettings.Validate(); - Debug.WriteLine(HeaderSettings); + var position = inputFile.Position; + + var expectedCheckSum = CalculateCheckSum(inputFile, false, -4); + inputFile.Seek(3, SeekOrigin.Current); + byte checkSum = (byte) inputFile.ReadByte(); + + inputFile.Seek(position, SeekOrigin.Begin); + + if (expectedCheckSum != checkSum) + { + throw new FileLoadException($"Checksum fails, expecting: {expectedCheckSum} but got: {checkSum}.\n" + + $"Try to reslice the file.", fileFullPath); + } + byte[][] previews = new byte[ThumbnailsOriginalSize.Length][]; for (int i = 0; i < ThumbnailsOriginalSize.Length; i++) { @@ -925,11 +953,40 @@ namespace UVtools.Core.FileFormats offset += size.Area() * 2 + 2; // + page break } - using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); + using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.ReadWrite); outputFile.Seek(offset, SeekOrigin.Begin); Helpers.SerializeWriteFileStream(outputFile, SlicerInfoSettings); + + uint checkSum = CalculateCheckSum(outputFile, false, -4); + outputFile.WriteBytes(BitExtensions.ToBytesBigEndian(checkSum)); } - #endregion + private byte CalculateCheckSum(FileStream fs, bool restorePosition = true, int offsetSize = 0) + { + byte checkSum = 0; + var position = fs.Position; + var dataSize = fs.Length + offsetSize; + const int bufferSize = 50 * 1024 * 1024; + + fs.Seek(0, SeekOrigin.Begin); + + for ( + int chunkSize = (int)Math.Min(bufferSize, dataSize - fs.Position); + chunkSize > 0; + chunkSize = (int)Math.Min(chunkSize, dataSize - fs.Position)) + { + var bytes = fs.ReadBytes(chunkSize); + for (int i = 0; i < bytes.Length; i++) + { + checkSum ^= bytes[i]; + } + } + + if (restorePosition) fs.Seek(position, SeekOrigin.Begin); + + return checkSum; + } + + #endregion } } diff --git a/UVtools.Core/FileFormats/CXDLPv1File.cs b/UVtools.Core/FileFormats/CXDLPv1File.cs index cf3a2a9..0e96f5a 100644 --- a/UVtools.Core/FileFormats/CXDLPv1File.cs +++ b/UVtools.Core/FileFormats/CXDLPv1File.cs @@ -318,15 +318,17 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, @@ -431,6 +433,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = SlicerInfoSettings.BottomLayers = value; } + public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; + + public override float LightOffDelay + { + get => SlicerInfoSettings.LightOffDelay; + set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; + } + public override float BottomExposureTime { get => SlicerInfoSettings.BottomExposureTime; @@ -473,14 +483,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)value; } - public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; - - public override float LightOffDelay - { - get => SlicerInfoSettings.LightOffDelay; - set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; - } - public override byte BottomLightPWM { get => (byte)SlicerInfoSettings.BottomLightPWM; diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index bc22593..db930c6 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -973,6 +973,13 @@ namespace UVtools.Core.FileFormats LiftSpeed = layerData.Parent[layerIndex].LiftSpeed; RetractSpeed = layerData.Parent[layerIndex].RetractSpeed; LightPWM = layerData.Parent[layerIndex].LightPWM; + + if (layerData.Parent.HeaderSettings.Version >= 4) + { + RestTimeAfterRetract = layerData.Parent[layerIndex].WaitTimeBeforeCure; + RestTimeBeforeLift = layerData.Parent[layerIndex].WaitTimeAfterCure; + RestTimeAfterLift = layerData.Parent[layerIndex].WaitTimeAfterLift; + } } if (layerData.DataSize > 0) @@ -1063,41 +1070,101 @@ namespace UVtools.Core.FileFormats new("photon", "Chitubox Photon"), }; - public override PrintParameterModifier[] PrintParameterModifiers { get; } = + public override PrintParameterModifier[] PrintParameterModifiers { - PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, - - PrintParameterModifier.BottomLiftHeight, - PrintParameterModifier.BottomLiftSpeed, - PrintParameterModifier.LiftHeight, - PrintParameterModifier.LiftSpeed, - PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, - - PrintParameterModifier.BottomLightPWM, - PrintParameterModifier.LightPWM, - }; + get + { + if (HeaderSettings.Version >= 4) + { + return new[] + { + + PrintParameterModifier.BottomLayerCount, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, + + //PrintParameterModifier.BottomWaitTimeBeforeCure, + PrintParameterModifier.WaitTimeBeforeCure, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + //PrintParameterModifier.BottomWaitTimeAfterCure, + PrintParameterModifier.WaitTimeAfterCure, + + PrintParameterModifier.BottomLiftHeight, + PrintParameterModifier.BottomLiftSpeed, + PrintParameterModifier.LiftHeight, + PrintParameterModifier.LiftSpeed, + + //PrintParameterModifier.BottomWaitTimeAfterLift, + PrintParameterModifier.WaitTimeAfterLift, + + PrintParameterModifier.RetractSpeed, + + PrintParameterModifier.BottomLightPWM, + PrintParameterModifier.LightPWM, + }; + } + + return new[] + { + + PrintParameterModifier.BottomLayerCount, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomLiftHeight, + PrintParameterModifier.BottomLiftSpeed, + PrintParameterModifier.LiftHeight, + PrintParameterModifier.LiftSpeed, + PrintParameterModifier.RetractSpeed, + + + PrintParameterModifier.BottomLightPWM, + PrintParameterModifier.LightPWM, + }; + } + } + + public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get { if (!IsCbtFile) return null; // Only ctb files - if (HeaderSettings.Version >= 3) + if (HeaderSettings.Version == 3) { return new[] { - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.LightOffDelay, + PrintParameterModifier.ExposureTime, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, + PrintParameterModifier.LightPWM, + }; + } + if (HeaderSettings.Version >= 4) + { + return new[] + { PrintParameterModifier.LightOffDelay, + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.WaitTimeAfterCure, + PrintParameterModifier.LiftHeight, + PrintParameterModifier.LiftSpeed, + PrintParameterModifier.WaitTimeAfterLift, + PrintParameterModifier.RetractSpeed, PrintParameterModifier.LightPWM, }; } - + /* Disable for v2 beside the fields on format they are not used if (HeaderSettings.Version <= 2) { @@ -1224,18 +1291,6 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = (ushort) (HeaderSettings.BottomLayersCount = value); } - public override float BottomExposureTime - { - get => HeaderSettings.BottomExposureSeconds; - set => base.BottomExposureTime = HeaderSettings.BottomExposureSeconds = (float) Math.Round(value, 2); - } - - public override float ExposureTime - { - get => HeaderSettings.LayerExposureSeconds; - set => base.ExposureTime = HeaderSettings.LayerExposureSeconds = (float)Math.Round(value, 2); - } - public override float BottomLightOffDelay { get => PrintParametersSettings.BottomLightOffDelay; @@ -1248,6 +1303,40 @@ namespace UVtools.Core.FileFormats set => base.LightOffDelay = HeaderSettings.LightOffDelay = PrintParametersSettings.LightOffDelay = (float)Math.Round(value, 2); } + public override float BottomWaitTimeBeforeCure => WaitTimeBeforeCure; + public override float WaitTimeBeforeCure + { + get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.RestTimeAfterRetract : 0; + set + { + if (HeaderSettings.Version < 4) return; + base.WaitTimeBeforeCure = SlicerInfoSettings.RestTimeAfterRetract = PrintParametersV4Settings.RestTimeAfterRetract = (float)Math.Round(value, 2); + } + } + + public override float BottomExposureTime + { + get => HeaderSettings.BottomExposureSeconds; + set => base.BottomExposureTime = HeaderSettings.BottomExposureSeconds = (float) Math.Round(value, 2); + } + + public override float BottomWaitTimeAfterCure => WaitTimeAfterCure; + public override float WaitTimeAfterCure + { + get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.RestTimeBeforeLift : 0; + set + { + if (HeaderSettings.Version < 4) return; + base.WaitTimeAfterCure = PrintParametersV4Settings.RestTimeBeforeLift = (float)Math.Round(value, 2); + } + } + + public override float ExposureTime + { + get => HeaderSettings.LayerExposureSeconds; + set => base.ExposureTime = HeaderSettings.LayerExposureSeconds = (float)Math.Round(value, 2); + } + public override float BottomLiftHeight { get => PrintParametersSettings.BottomLiftHeight; @@ -1272,6 +1361,17 @@ namespace UVtools.Core.FileFormats set => base.LiftSpeed = PrintParametersSettings.LiftSpeed = (float)Math.Round(value, 2); } + public override float BottomWaitTimeAfterLift => WaitTimeAfterLift; + public override float WaitTimeAfterLift + { + get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.RestTimeAfterLift : 0; + set + { + if (HeaderSettings.Version < 4) return; + base.WaitTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift2 = PrintParametersV4Settings.RestTimeAfterLift = (float)Math.Round(value, 2); + } + } + public override float RetractSpeed { get => PrintParametersSettings.RetractSpeed; @@ -1715,6 +1815,13 @@ namespace UVtools.Core.FileFormats layer.LiftSpeed = LayerDefinitionsEx[layerIndex].LiftSpeed; layer.RetractSpeed = LayerDefinitionsEx[layerIndex].RetractSpeed; layer.LightPWM = (byte) LayerDefinitionsEx[layerIndex].LightPWM; + + if (HeaderSettings.Version >= 4) + { + layer.WaitTimeBeforeCure = LayerDefinitionsEx[layerIndex].RestTimeAfterRetract; + layer.WaitTimeAfterCure = LayerDefinitionsEx[layerIndex].RestTimeBeforeLift; + layer.WaitTimeAfterLift = LayerDefinitionsEx[layerIndex].RestTimeAfterLift; + } } this[layerIndex] = layer; diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs index 4f5c972..e997adb 100644 --- a/UVtools.Core/FileFormats/ChituboxZipFile.cs +++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs @@ -16,10 +16,8 @@ using System.Reflection; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Util; -using Microsoft.CodeAnalysis.CSharp.Syntax; using UVtools.Core.Extensions; using UVtools.Core.GCode; -using UVtools.Core.Objects; using UVtools.Core.Operations; namespace UVtools.Core.FileFormats @@ -83,27 +81,38 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.BottomWaitTimeBeforeCure, + PrintParameterModifier.WaitTimeBeforeCure, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomWaitTimeAfterCure, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, - PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomWaitTimeAfterLift, + PrintParameterModifier.WaitTimeAfterLift, + + PrintParameterModifier.RetractSpeed, + PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + PrintParameterModifier.WaitTimeAfterLift, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.LightPWM, }; @@ -202,6 +211,30 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = HeaderSettings.BottomLayerCount = HeaderSettings.BottomLayCount = value; } + public override float BottomLightOffDelay + { + get => BottomWaitTimeBeforeCure; + set => BottomWaitTimeBeforeCure = value; + } + + public override float LightOffDelay + { + get => WaitTimeBeforeCure; + set => WaitTimeBeforeCure = value; + } + + public override float BottomWaitTimeBeforeCure + { + get => HeaderSettings.BottomLightOffDelay; + set => base.BottomWaitTimeBeforeCure = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); + } + + public override float WaitTimeBeforeCure + { + get => HeaderSettings.LightOffDelay; + set => base.WaitTimeBeforeCure = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => HeaderSettings.BottomExposureTime; @@ -244,18 +277,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = HeaderSettings.RetractSpeed = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay - { - get => HeaderSettings.BottomLightOffDelay; - set => base.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); - } - - public override float LightOffDelay - { - get => HeaderSettings.LightOffDelay; - set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); - } - public override byte BottomLightPWM { get => HeaderSettings.BottomLightPWM; @@ -339,7 +360,9 @@ namespace UVtools.Core.FileFormats GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Absolute, GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute, GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds, - GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.FilenameNonZeroPNG + GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.FilenameNonZeroPNG, + LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G0, + EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1 }; } @@ -503,8 +526,9 @@ namespace UVtools.Core.FileFormats public override void RebuildGCode() { - if (IsPHZZip) return; + if (!SupportsGCode || SuppressRebuildGCode) return; GCode.RebuildGCode(this, new object[]{ HeaderSettings }); + RaisePropertyChanged(nameof(GCodeStr)); } public override void SaveAs(string filePath = null, OperationProgress progress = null) diff --git a/UVtools.Core/FileFormats/FDGFile.cs b/UVtools.Core/FileFormats/FDGFile.cs index 82c8422..cab1b55 100644 --- a/UVtools.Core/FileFormats/FDGFile.cs +++ b/UVtools.Core/FileFormats/FDGFile.cs @@ -677,24 +677,25 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, PrintParameterModifier.LightOffDelay, + PrintParameterModifier.ExposureTime, }; public override Size[] ThumbnailsOriginalSize { get; } = @@ -798,6 +799,18 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = (ushort) (HeaderSettings.BottomLayersCount2 = HeaderSettings.BottomLayersCount = value); } + public override float BottomLightOffDelay + { + get => HeaderSettings.BottomLightOffDelay; + set => base.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); + } + + public override float LightOffDelay + { + get => HeaderSettings.LightOffDelay; + set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => HeaderSettings.BottomExposureSeconds; @@ -840,18 +853,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = HeaderSettings.RetractSpeed = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay - { - get => HeaderSettings.BottomLightOffDelay; - set => base.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); - } - - public override float LightOffDelay - { - get => HeaderSettings.LightOffDelay; - set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); - } - public override byte BottomLightPWM { get => (byte) HeaderSettings.BottomLightPWM; diff --git a/UVtools.Core/FileFormats/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs index 39d4ff5..fe05b52 100644 --- a/UVtools.Core/FileFormats/FileExtension.cs +++ b/UVtools.Core/FileFormats/FileExtension.cs @@ -63,12 +63,12 @@ namespace UVtools.Core.FileFormats public bool Equals(FileExtension other) { - return Extension.Equals(other.Extension, StringComparison.InvariantCultureIgnoreCase); + return Extension.Equals(other.Extension, StringComparison.OrdinalIgnoreCase); } public bool Equals(string other) { - return Extension.Equals(other, StringComparison.InvariantCultureIgnoreCase); + return Extension.Equals(other, StringComparison.OrdinalIgnoreCase); } public override bool Equals(object obj) diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 53ac4c2..ae96149 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -17,6 +17,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; +using System.Timers; using Emgu.CV; using Emgu.CV.CvEnum; using UVtools.Core.Extensions; @@ -59,6 +60,8 @@ namespace UVtools.Core.FileFormats public const float MinimumLayerHeight = 0.01f; public const float MaximumLayerHeight = 0.20f; + + private const ushort QueueTimerPrintTime = 250; #endregion #region Enums @@ -90,25 +93,43 @@ namespace UVtools.Core.FileFormats { #region Instances - public static PrintParameterModifier BottomLayerCount { get; } = new ("Bottom layer count", null, "layers",0, ushort.MaxValue, 0); - public static PrintParameterModifier BottomExposureSeconds { get; } = new ("Bottom exposure time", null, "s", 0.1M, 1000, 2); - public static PrintParameterModifier ExposureSeconds { get; } = new ("Exposure time", null, "s", 0.1M, 1000, 2); + public static PrintParameterModifier BottomLayerCount { get; } = new ("Bottom layers count", "Number of bottom/burn-in layers", "layers",0, ushort.MaxValue, 0); + + public static PrintParameterModifier BottomLightOffDelay { get; } = new("Bottom light-off seconds", "Total motor movement time + rest time to wait before cure a new bottom layer", "s"); + public static PrintParameterModifier LightOffDelay { get; } = new("Light-off seconds", "Total motor movement time + rest time to wait before cure a new layer", "s"); + + public static PrintParameterModifier BottomWaitTimeBeforeCure { get; } = new ("Bottom wait before cure", "Time to wait/rest before cure a new bottom layer\nChitubox: Rest after retract\nLychee: Wait before print", "s", 0, 1000, 2); + public static PrintParameterModifier WaitTimeBeforeCure { get; } = new ("Wait before cure", "Time to wait/rest before cure a new layer\nChitubox: Rest after retract\nLychee: Wait before print", "s", 0, 1000, 2); - public static PrintParameterModifier BottomLightOffDelay { get; } = new ("Bottom light-off seconds", null, "s"); - public static PrintParameterModifier LightOffDelay { get; } = new ("Light-off seconds", null, "s"); - public static PrintParameterModifier BottomLiftHeight { get; } = new ("Bottom lift height", @"Modify 'Bottom lift height' millimeters between bottom layers", "mm", 1); - public static PrintParameterModifier LiftHeight { get; } = new ("Lift height", @"Modify 'Lift height' millimeters between layers", "mm"); - public static PrintParameterModifier BottomLiftSpeed { get; } = new ("Bottom lift Speed", @"Modify 'Bottom lift Speed' mm/min between bottom layers", "mm/min", 10); - public static PrintParameterModifier LiftSpeed { get; } = new ("Lift speed", @"Modify 'Lift speed' mm/min between layers", "mm/min", 10, 5000, 2); - public static PrintParameterModifier RetractSpeed { get; } = new ("Retract speed", @"Modify 'Retract speed' mm/min between layer", "mm/min", 10, 5000, 2); + public static PrintParameterModifier BottomExposureTime { get; } = new ("Bottom exposure time", "Bottom layers cure time", "s", 0.1M, 1000, 2); + public static PrintParameterModifier ExposureTime { get; } = new ("Exposure time", "Layers cure time", "s", 0.1M, 1000, 2); + + public static PrintParameterModifier BottomWaitTimeAfterCure { get; } = new("Bottom 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 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 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 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 RetractSpeed { get; } = new ("Retract speed", "Down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2); - public static PrintParameterModifier BottomLightPWM { get; } = new ("Bottom light PWM", @"Modify 'Bottom light PWM' value", null, 1, byte.MaxValue, 0); - public static PrintParameterModifier LightPWM { get; } = new ("Light PWM", @"Modify 'Light PWM' value", null, 1, byte.MaxValue, 0); + 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); public static PrintParameterModifier[] Parameters = { BottomLayerCount, - BottomExposureSeconds, - ExposureSeconds, + + BottomWaitTimeBeforeCure, + WaitTimeBeforeCure, + BottomExposureTime, + ExposureTime, + BottomWaitTimeAfterCure, + WaitTimeAfterCure, BottomLightOffDelay, LightOffDelay, @@ -116,6 +137,8 @@ namespace UVtools.Core.FileFormats BottomLiftSpeed, LiftHeight, LiftSpeed, + BottomWaitTimeAfterLift, + WaitTimeAfterLift, RetractSpeed, BottomLightPWM, @@ -299,6 +322,8 @@ namespace UVtools.Core.FileFormats { GetFileNameStripExtensions(extension, out extension); } + + if (string.IsNullOrWhiteSpace(extension)) return null; return (from fileFormat in AvailableFormats where fileFormat.IsExtensionValid(extension) select createNewInstance ? (FileFormat) Activator.CreateInstance(fileFormat.GetType()) : fileFormat).FirstOrDefault(); } @@ -355,6 +380,14 @@ namespace UVtools.Core.FileFormats private float _materialCost; 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 @@ -794,6 +827,26 @@ namespace UVtools.Core.FileFormats /// </summary> public uint NormalLayerCount => LayerCount - BottomLayerCount; + public virtual float BottomWaitTimeBeforeCure + { + get => _bottomWaitTimeBeforeCure; + set + { + RaiseAndSet(ref _bottomWaitTimeBeforeCure, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + + public virtual float WaitTimeBeforeCure + { + get => _waitTimeBeforeCure; + set + { + RaiseAndSet(ref _waitTimeBeforeCure, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + /// <summary> /// Gets or sets the initial exposure time for <see cref="BottomLayerCount"/> in seconds /// </summary> @@ -820,6 +873,26 @@ namespace UVtools.Core.FileFormats } } + public virtual float BottomWaitTimeAfterCure + { + get => _bottomWaitTimeAfterCure; + set + { + RaiseAndSet(ref _bottomWaitTimeAfterCure, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + + public virtual float WaitTimeAfterCure + { + get => _waitTimeAfterCure; + set + { + RaiseAndSet(ref _waitTimeAfterCure, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + /// <summary> /// Gets or sets the bottom lift height in mm /// </summary> @@ -872,6 +945,26 @@ namespace UVtools.Core.FileFormats } } + public virtual float BottomWaitTimeAfterLift + { + get => _bottomWaitTimeAfterLift; + set + { + RaiseAndSet(ref _bottomWaitTimeAfterLift, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + + public virtual float WaitTimeAfterLift + { + get => _waitTimeAfterLift; + set + { + RaiseAndSet(ref _waitTimeAfterLift, value); + RaisePropertyChanged(nameof(WaitTimeRepresentation)); + } + } + /// <summary> /// Gets the speed in mm/min for the retracts /// </summary> @@ -931,10 +1024,22 @@ namespace UVtools.Core.FileFormats public bool CanUseBottomLayerCount => HavePrintParameterModifier(PrintParameterModifier.BottomLayerCount); - public bool CanUseBottomExposureTime => HavePrintParameterModifier(PrintParameterModifier.BottomExposureSeconds); - public bool CanUseExposureTime => HavePrintParameterModifier(PrintParameterModifier.ExposureSeconds); + public bool CanUseBottomLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.BottomLightOffDelay); + public bool CanUseLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.LightOffDelay); + public bool CanUseAnyLightOffDelay => CanUseBottomLightOffDelay || CanUseLightOffDelay; + + public bool CanUseBottomWaitTimeBeforeCure => HavePrintParameterModifier(PrintParameterModifier.BottomWaitTimeBeforeCure); + public bool CanUseWaitTimeBeforeCure => HavePrintParameterModifier(PrintParameterModifier.WaitTimeBeforeCure); + public bool CanUseAnyWaitTimeBeforeCure => CanUseBottomWaitTimeBeforeCure || CanUseWaitTimeBeforeCure; + + public bool CanUseBottomExposureTime => HavePrintParameterModifier(PrintParameterModifier.BottomExposureTime); + public bool CanUseExposureTime => HavePrintParameterModifier(PrintParameterModifier.ExposureTime); public bool CanUseAnyExposureTime => CanUseBottomExposureTime || CanUseExposureTime; + public bool CanUseBottomWaitTimeAfterCure => HavePrintParameterModifier(PrintParameterModifier.BottomWaitTimeAfterCure); + public bool CanUseWaitTimeAfterCure => HavePrintParameterModifier(PrintParameterModifier.WaitTimeAfterCure); + public bool CanUseAnyWaitTimeAfterCure => CanUseBottomWaitTimeAfterCure || CanUseWaitTimeAfterCure; + public bool CanUseBottomLiftHeight => HavePrintParameterModifier(PrintParameterModifier.BottomLiftHeight); public bool CanUseLiftHeight => HavePrintParameterModifier(PrintParameterModifier.LiftHeight); public bool CanUseAnyLiftHeight => CanUseBottomLiftHeight || CanUseLiftHeight; @@ -943,19 +1048,25 @@ namespace UVtools.Core.FileFormats public bool CanUseLiftSpeed => HavePrintParameterModifier(PrintParameterModifier.LiftSpeed); public bool CanUseAnyLiftSpeed => CanUseBottomLiftSpeed || CanUseLiftSpeed; + public bool CanUseBottomWaitTimeAfterLift => HavePrintParameterModifier(PrintParameterModifier.BottomWaitTimeAfterLift); + public bool CanUseWaitTimeAfterLift => HavePrintParameterModifier(PrintParameterModifier.WaitTimeAfterLift); + public bool CanUseAnyWaitTimeAfterLift => CanUseBottomWaitTimeAfterLift || CanUseWaitTimeAfterLift; + public bool CanUseRetractSpeed => HavePrintParameterModifier(PrintParameterModifier.RetractSpeed); - public bool CanUseBottomLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.BottomLightOffDelay); - public bool CanUseLightOffDelay => HavePrintParameterModifier(PrintParameterModifier.LightOffDelay); - public bool CanUseAnyLightOffDelay => CanUseBottomLightOffDelay || CanUseLightOffDelay; + public bool CanUseAnyWaitTime => CanUseBottomWaitTimeBeforeCure || CanUseBottomWaitTimeAfterCure || CanUseBottomWaitTimeAfterLift || + CanUseWaitTimeBeforeCure || CanUseWaitTimeAfterCure || CanUseWaitTimeAfterLift; public bool CanUseBottomLightPWM => HavePrintParameterModifier(PrintParameterModifier.BottomLightPWM); public bool CanUseLightPWM => HavePrintParameterModifier(PrintParameterModifier.LightPWM); public bool CanUseAnyLightPWM => CanUseBottomLightPWM || CanUseLightPWM; - public bool CanUseLayerExposureTime => HaveLayerParameterModifier(PrintParameterModifier.ExposureSeconds); + public bool CanUseLayerWaitTimeBeforeCure => HaveLayerParameterModifier(PrintParameterModifier.WaitTimeBeforeCure); + public bool CanUseLayerExposureTime => HaveLayerParameterModifier(PrintParameterModifier.ExposureTime); + public bool CanUseLayerWaitTimeAfterCure => HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterCure); public bool CanUseLayerLiftHeight => HaveLayerParameterModifier(PrintParameterModifier.LiftHeight); public bool CanUseLayerLiftSpeed => HaveLayerParameterModifier(PrintParameterModifier.LiftSpeed); + public bool CanUseLayerWaitTimeAfterLift => HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterLift); public bool CanUseLayerRetractSpeed => HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed); public bool CanUseLayerLightOffDelay => HaveLayerParameterModifier(PrintParameterModifier.LightOffDelay); public bool CanUseLayerLightPWM => HaveLayerParameterModifier(PrintParameterModifier.LightPWM); @@ -1064,6 +1175,26 @@ namespace UVtools.Core.FileFormats } } + public string WaitTimeRepresentation + { + get + { + var str = string.Empty; + + if (CanUseBottomWaitTimeBeforeCure || CanUseBottomWaitTimeAfterCure || CanUseBottomWaitTimeAfterLift) + { + str += $"{BottomWaitTimeBeforeCure}/{BottomWaitTimeAfterCure}/{BottomWaitTimeAfterLift}s"; + } + if (!string.IsNullOrEmpty(str)) str += "|"; + if (CanUseWaitTimeBeforeCure || CanUseWaitTimeAfterCure || CanUseWaitTimeAfterLift) + { + str += $"{WaitTimeBeforeCure}/{WaitTimeAfterCure}/{WaitTimeAfterLift}s"; + } + + return str; + } + } + #endregion /// <summary> @@ -1111,8 +1242,20 @@ namespace UVtools.Core.FileFormats break; } - var lightOffDelay = layer.CalculateLightOffDelay(); - time += layer.ExposureTime + (lightOffDelay > layer.LightOffDelay ? lightOffDelay : layer.LightOffDelay); + var motorTime = layer.CalculateMotorMovementTime(); + time += layer.WaitTimeBeforeCure + layer.ExposureTime + layer.WaitTimeAfterCure + layer.WaitTimeAfterLift; + if (SupportsGCode) + { + time += motorTime; + if (layer.WaitTimeBeforeCure <= 0) + { + time += layer.LightOffDelay; + } + } + else + { + time += motorTime > layer.LightOffDelay ? motorTime : layer.LightOffDelay; + } /*if (lightOffDelay >= layer.LightOffDelay) time += lightOffDelay; else @@ -1122,11 +1265,38 @@ namespace UVtools.Core.FileFormats if (computeGeneral) { - time = ExtraPrintTime + + var bottomMotorTime = CalculateMotorMovementTime(true); + var motorTime = CalculateMotorMovementTime(false); + time = ExtraPrintTime + BottomLightOffDelay * BottomLayerCount + LightOffDelay * NormalLayerCount + - OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, RetractSpeed) * BottomLayerCount + - OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed) * NormalLayerCount; + BottomWaitTimeBeforeCure * BottomLayerCount + + WaitTimeBeforeCure * NormalLayerCount + + BottomExposureTime * BottomLayerCount + + ExposureTime * NormalLayerCount + + BottomWaitTimeAfterCure * BottomLayerCount + + WaitTimeAfterCure * NormalLayerCount + + BottomWaitTimeAfterLift * BottomLayerCount + + WaitTimeAfterLift * NormalLayerCount; + + if (SupportsGCode) + { + time += bottomMotorTime * BottomLayerCount + motorTime * NormalLayerCount; + + if (BottomWaitTimeBeforeCure <= 0) + { + time += BottomLightOffDelay * BottomLayerCount; + } + if (WaitTimeBeforeCure <= 0) + { + time += LightOffDelay * NormalLayerCount; + } + } + else + { + time += motorTime > BottomLightOffDelay ? bottomMotorTime * BottomLayerCount : BottomLightOffDelay * BottomLayerCount; + time += motorTime > LightOffDelay ? motorTime * NormalLayerCount : LightOffDelay * NormalLayerCount; + } } return (float) Math.Round(time, 2); @@ -1141,7 +1311,14 @@ namespace UVtools.Core.FileFormats /// <summary> /// Gets the estimate print time in hours and minutes formatted /// </summary> - public string PrintTimeString => TimeSpan.FromSeconds(PrintTime).ToString("hh\\hmm\\m"); + public string PrintTimeString + { + get + { + var printTime = PrintTime; + return TimeSpan.FromSeconds(printTime >= float.PositiveInfinity ? 0 : printTime).ToString("hh\\hmm\\m"); + } + } /// <summary> /// Gets the estimate used material in ml @@ -1261,6 +1438,7 @@ namespace UVtools.Core.FileFormats LayerManager = new(this); Thumbnails = new Mat[ThumbnailsCount]; PropertyChanged += OnPropertyChanged; + _queueTimerPrintTime.Elapsed += (sender, e) => UpdatePrintTime(); } private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) @@ -1268,15 +1446,21 @@ namespace UVtools.Core.FileFormats if (SuppressRebuildProperties) return; if ( e.PropertyName - is nameof(BottomLayerCount) - or nameof(BottomExposureTime) - or nameof(ExposureTime) + is nameof(BottomLayerCount) or nameof(BottomLightOffDelay) or nameof(LightOffDelay) + or nameof(BottomWaitTimeBeforeCure) + or nameof(WaitTimeBeforeCure) + or nameof(BottomExposureTime) + or nameof(ExposureTime) + or nameof(BottomWaitTimeAfterCure) + or nameof(WaitTimeAfterCure) or nameof(BottomLiftHeight) or nameof(LiftHeight) or nameof(BottomLiftSpeed) - or nameof(LiftSpeed) + or nameof(LiftSpeed) + or nameof(BottomWaitTimeAfterLift) + or nameof(WaitTimeAfterLift) or nameof(RetractSpeed) or nameof(BottomLightPWM) or nameof(LightPWM) @@ -1285,7 +1469,7 @@ namespace UVtools.Core.FileFormats LayerManager?.RebuildLayersProperties(false, e.PropertyName); if(e.PropertyName != nameof(BottomLightPWM) && e.PropertyName != nameof(LightPWM)) - PrintTime = PrintTimeComputed; + UpdatePrintTimeQueued(); return; } } @@ -1345,6 +1529,7 @@ namespace UVtools.Core.FileFormats public void Dispose() { GC.SuppressFinalize(this); + _queueTimerPrintTime.Dispose(); Clear(); } @@ -1398,7 +1583,7 @@ namespace UVtools.Core.FileFormats { GetFileNameStripExtensions(extension, out extension); } - return FileExtensions.Any(fileExtension => fileExtension.Equals(extension)); + return !string.IsNullOrWhiteSpace(extension) && FileExtensions.Any(fileExtension => fileExtension.Equals(extension)); } /// <summary> @@ -1674,14 +1859,22 @@ namespace UVtools.Core.FileFormats tw.WriteLine($"{nameof(layer.IsBottomLayer)}: {layer.IsBottomLayer}"); tw.WriteLine($"{nameof(layer.LayerHeight)}: {layer.LayerHeight}"); tw.WriteLine($"{nameof(layer.PositionZ)}: {layer.PositionZ}"); - tw.WriteLine($"{nameof(layer.ExposureTime)}: {layer.ExposureTime}"); if (HaveLayerParameterModifier(PrintParameterModifier.LightOffDelay)) tw.WriteLine($"{nameof(layer.LightOffDelay)}: {layer.LightOffDelay}"); + if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeBeforeCure)) + tw.WriteLine($"{nameof(layer.WaitTimeBeforeCure)}: {layer.WaitTimeBeforeCure}"); + tw.WriteLine($"{nameof(layer.ExposureTime)}: {layer.ExposureTime}"); + if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterCure)) + tw.WriteLine($"{nameof(layer.WaitTimeAfterCure)}: {layer.WaitTimeAfterCure}"); + + if (HaveLayerParameterModifier(PrintParameterModifier.LiftHeight)) tw.WriteLine($"{nameof(layer.LiftHeight)}: {layer.LiftHeight}"); if (HaveLayerParameterModifier(PrintParameterModifier.LiftSpeed)) tw.WriteLine($"{nameof(layer.LiftSpeed)}: {layer.LiftSpeed}"); + if (HaveLayerParameterModifier(PrintParameterModifier.WaitTimeAfterLift)) + tw.WriteLine($"{nameof(layer.WaitTimeAfterLift)}: {layer.WaitTimeAfterLift}"); if (HaveLayerParameterModifier(PrintParameterModifier.RetractSpeed)) tw.WriteLine($"{nameof(layer.RetractSpeed)}: {layer.RetractSpeed}"); if (HaveLayerParameterModifier(PrintParameterModifier.LightPWM)) @@ -1782,24 +1975,44 @@ namespace UVtools.Core.FileFormats PrintParameterModifier.BottomLayerCount.Value = BottomLayerCount; } - if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomExposureSeconds)) + if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLightOffDelay)) { - PrintParameterModifier.BottomExposureSeconds.Value = (decimal) BottomExposureTime; + PrintParameterModifier.BottomLightOffDelay.Value = (decimal)BottomLightOffDelay; } - if (PrintParameterModifiers.Contains(PrintParameterModifier.ExposureSeconds)) + if (PrintParameterModifiers.Contains(PrintParameterModifier.LightOffDelay)) { - PrintParameterModifier.ExposureSeconds.Value = (decimal)ExposureTime; + PrintParameterModifier.LightOffDelay.Value = (decimal)LightOffDelay; } - if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLightOffDelay)) + if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomWaitTimeBeforeCure)) { - PrintParameterModifier.BottomLightOffDelay.Value = (decimal)BottomLightOffDelay; + PrintParameterModifier.BottomWaitTimeBeforeCure.Value = (decimal)BottomWaitTimeBeforeCure; } - if (PrintParameterModifiers.Contains(PrintParameterModifier.LightOffDelay)) + if (PrintParameterModifiers.Contains(PrintParameterModifier.WaitTimeBeforeCure)) { - PrintParameterModifier.LightOffDelay.Value = (decimal)LightOffDelay; + PrintParameterModifier.WaitTimeBeforeCure.Value = (decimal)WaitTimeBeforeCure; + } + + if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomExposureTime)) + { + PrintParameterModifier.BottomExposureTime.Value = (decimal) BottomExposureTime; + } + + if (PrintParameterModifiers.Contains(PrintParameterModifier.ExposureTime)) + { + PrintParameterModifier.ExposureTime.Value = (decimal)ExposureTime; + } + + if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomWaitTimeAfterCure)) + { + PrintParameterModifier.BottomWaitTimeAfterCure.Value = (decimal)BottomWaitTimeAfterCure; + } + + if (PrintParameterModifiers.Contains(PrintParameterModifier.WaitTimeAfterCure)) + { + PrintParameterModifier.WaitTimeAfterCure.Value = (decimal)WaitTimeAfterCure; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftHeight)) @@ -1822,6 +2035,16 @@ namespace UVtools.Core.FileFormats PrintParameterModifier.LiftSpeed.Value = (decimal)LiftSpeed; } + if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomWaitTimeAfterLift)) + { + PrintParameterModifier.BottomWaitTimeAfterLift.Value = (decimal)BottomWaitTimeAfterLift; + } + + if (PrintParameterModifiers.Contains(PrintParameterModifier.WaitTimeAfterLift)) + { + PrintParameterModifier.WaitTimeAfterLift.Value = (decimal)WaitTimeAfterLift; + } + if (PrintParameterModifiers.Contains(PrintParameterModifier.RetractSpeed)) { PrintParameterModifier.RetractSpeed.Value = (decimal)RetractSpeed; @@ -1846,14 +2069,24 @@ namespace UVtools.Core.FileFormats if (PrintParameterPerLayerModifiers is null) return; var layer = this[layerIndex]; - if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.ExposureSeconds)) + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LightOffDelay)) { - PrintParameterModifier.ExposureSeconds.Value = (decimal)layer.ExposureTime; + PrintParameterModifier.LightOffDelay.Value = (decimal)layer.LightOffDelay; } - if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LightOffDelay)) + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.WaitTimeBeforeCure)) { - PrintParameterModifier.LightOffDelay.Value = (decimal)layer.LightOffDelay; + PrintParameterModifier.WaitTimeBeforeCure.Value = (decimal)layer.WaitTimeBeforeCure; + } + + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.ExposureTime)) + { + PrintParameterModifier.ExposureTime.Value = (decimal)layer.ExposureTime; + } + + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.WaitTimeAfterCure)) + { + PrintParameterModifier.WaitTimeAfterCure.Value = (decimal)layer.WaitTimeAfterCure; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LiftHeight)) @@ -1866,6 +2099,11 @@ namespace UVtools.Core.FileFormats PrintParameterModifier.LiftSpeed.Value = (decimal)layer.LiftSpeed; } + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.WaitTimeAfterLift)) + { + PrintParameterModifier.WaitTimeAfterLift.Value = (decimal)layer.WaitTimeAfterLift; + } + if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.RetractSpeed)) { PrintParameterModifier.RetractSpeed.Value = (decimal)layer.RetractSpeed; @@ -1886,16 +2124,27 @@ namespace UVtools.Core.FileFormats { if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount)) return BottomLayerCount; - if (ReferenceEquals(modifier, PrintParameterModifier.BottomExposureSeconds)) - return BottomExposureTime; - if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds)) - return ExposureTime; if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightOffDelay)) return BottomLightOffDelay; if (ReferenceEquals(modifier, PrintParameterModifier.LightOffDelay)) return LightOffDelay; + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeBeforeCure)) + return BottomWaitTimeBeforeCure; + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeBeforeCure)) + return WaitTimeBeforeCure; + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomExposureTime)) + return BottomExposureTime; + if (ReferenceEquals(modifier, PrintParameterModifier.ExposureTime)) + return ExposureTime; + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterCure)) + return BottomWaitTimeAfterCure; + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeAfterCure)) + return WaitTimeAfterCure; + if (ReferenceEquals(modifier, PrintParameterModifier.BottomLiftHeight)) return BottomLiftHeight; if (ReferenceEquals(modifier, PrintParameterModifier.LiftHeight)) @@ -1904,6 +2153,12 @@ namespace UVtools.Core.FileFormats return BottomLiftSpeed; if (ReferenceEquals(modifier, PrintParameterModifier.LiftSpeed)) return LiftSpeed; + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterLift)) + return BottomWaitTimeAfterLift; + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeAfterLift)) + return WaitTimeAfterLift; + if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed)) return RetractSpeed; @@ -1928,25 +2183,48 @@ namespace UVtools.Core.FileFormats BottomLayerCount = (ushort)value; return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.BottomExposureSeconds)) + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightOffDelay)) + { + BottomLightOffDelay = (float)value; + return true; + } + if (ReferenceEquals(modifier, PrintParameterModifier.LightOffDelay)) + { + LightOffDelay = (float)value; + return true; + } + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeBeforeCure)) + { + BottomWaitTimeBeforeCure = (float)value; + return true; + } + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeBeforeCure)) + { + WaitTimeBeforeCure = (float)value; + return true; + } + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomExposureTime)) { BottomExposureTime = (float) value; return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds)) + if (ReferenceEquals(modifier, PrintParameterModifier.ExposureTime)) { ExposureTime = (float) value; return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.BottomLightOffDelay)) + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterCure)) { - BottomLightOffDelay = (float) value; + BottomWaitTimeAfterCure = (float)value; return true; } - if (ReferenceEquals(modifier, PrintParameterModifier.LightOffDelay)) + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeAfterCure)) { - LightOffDelay = (float) value; + WaitTimeAfterCure = (float)value; return true; } @@ -1970,6 +2248,18 @@ namespace UVtools.Core.FileFormats LiftSpeed = (float) value; return true; } + + if (ReferenceEquals(modifier, PrintParameterModifier.BottomWaitTimeAfterLift)) + { + BottomWaitTimeAfterLift = (float)value; + return true; + } + if (ReferenceEquals(modifier, PrintParameterModifier.WaitTimeAfterLift)) + { + WaitTimeAfterLift = (float)value; + return true; + } + if (ReferenceEquals(modifier, PrintParameterModifier.RetractSpeed)) { RetractSpeed = (float) value; @@ -2017,8 +2307,16 @@ namespace UVtools.Core.FileFormats public bool SetNormalLightOffDelay(float extraTime = 0) => SetLightOffDelay(false, extraTime); + public float CalculateMotorMovementTime(bool isBottomLayer, float extraTime = 0) + { + return isBottomLayer + ? OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, RetractSpeed, extraTime) + : OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed, extraTime); + } + public float CalculateLightOffDelay(bool isBottomLayer, float extraTime = 0) { + if (SupportsGCode) return extraTime; return isBottomLayer ? OperationCalculator.LightOffDelayC.CalculateSeconds(BottomLiftHeight, BottomLiftSpeed, RetractSpeed, extraTime) : OperationCalculator.LightOffDelayC.CalculateSeconds(LiftHeight, LiftSpeed, RetractSpeed, extraTime); @@ -2104,18 +2402,29 @@ namespace UVtools.Core.FileFormats slicerFile.DisplayHeight = DisplayHeight; slicerFile.MachineZ = MachineZ; slicerFile.MirrorDisplay = MirrorDisplay; + + slicerFile.BottomLightOffDelay = BottomLightOffDelay; + slicerFile.LightOffDelay = LightOffDelay; + + slicerFile.BottomWaitTimeBeforeCure = BottomWaitTimeBeforeCure; + slicerFile.WaitTimeBeforeCure = WaitTimeBeforeCure; + slicerFile.BottomExposureTime = BottomExposureTime; slicerFile.ExposureTime = ExposureTime; + slicerFile.BottomWaitTimeAfterCure = BottomWaitTimeAfterCure; + slicerFile.WaitTimeAfterCure = WaitTimeAfterCure; + slicerFile.BottomLiftHeight = BottomLiftHeight; slicerFile.LiftHeight = LiftHeight; slicerFile.BottomLiftSpeed = BottomLiftSpeed; slicerFile.LiftSpeed = LiftSpeed; - slicerFile.RetractSpeed = RetractSpeed; - slicerFile.BottomLightOffDelay = BottomLightOffDelay; - slicerFile.LightOffDelay = LightOffDelay; + slicerFile.BottomWaitTimeAfterLift = BottomWaitTimeAfterLift; + slicerFile.WaitTimeAfterLift = WaitTimeAfterLift; + + slicerFile.RetractSpeed = RetractSpeed; slicerFile.BottomLightPWM = BottomLightPWM; slicerFile.LightPWM = LightPWM; @@ -2210,6 +2519,13 @@ namespace UVtools.Core.FileFormats public void UpdatePrintTime() { PrintTime = PrintTimeComputed; + Debug.WriteLine($"Time updated: {_printTime}s"); + } + + public void UpdatePrintTimeQueued() + { + _queueTimerPrintTime.Stop(); + _queueTimerPrintTime.Start(); } #endregion diff --git a/UVtools.Core/FileFormats/GR1File.cs b/UVtools.Core/FileFormats/GR1File.cs index b9b64ec..34993bf 100644 --- a/UVtools.Core/FileFormats/GR1File.cs +++ b/UVtools.Core/FileFormats/GR1File.cs @@ -154,10 +154,10 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, - PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, @@ -268,6 +268,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = SlicerInfoSettings.BottomLayers = value; } + public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; + + public override float LightOffDelay + { + get => SlicerInfoSettings.LightOffDelay; + set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; + } + public override float BottomExposureTime { get => SlicerInfoSettings.BottomExposureTime; @@ -310,14 +318,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = SlicerInfoSettings.RetractSpeed = (ushort)value; } - public override float BottomLightOffDelay => SlicerInfoSettings.LightOffDelay; - - public override float LightOffDelay - { - get => SlicerInfoSettings.LightOffDelay; - set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; - } - public override byte BottomLightPWM { get => (byte)SlicerInfoSettings.BottomLightPWM; diff --git a/UVtools.Core/FileFormats/LGSFile.cs b/UVtools.Core/FileFormats/LGSFile.cs index ecffe6e..b5dc348 100644 --- a/UVtools.Core/FileFormats/LGSFile.cs +++ b/UVtools.Core/FileFormats/LGSFile.cs @@ -252,15 +252,18 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, + }; public override Size[] ThumbnailsOriginalSize { get; } = {new(120, 150)}; @@ -361,6 +364,26 @@ namespace UVtools.Core.FileFormats } } + public override float BottomLightOffDelay + { + get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.BottomLightOffDelayMs); + set + { + HeaderSettings.BottomLightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value); + base.BottomLightOffDelay = value; + } + } + + public override float LightOffDelay + { + get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.LightOffDelayMs); + set + { + HeaderSettings.LightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value); + base.LightOffDelay = value; + } + } + public override float BottomExposureTime { get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.BottomExposureTimeMs); @@ -407,26 +430,6 @@ namespace UVtools.Core.FileFormats public override float RetractSpeed => LiftSpeed; - public override float BottomLightOffDelay - { - get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.BottomLightOffDelayMs); - set - { - HeaderSettings.BottomLightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value); - base.BottomLightOffDelay = value; - } - } - - public override float LightOffDelay - { - get => TimeExtensions.MillisecondsToSeconds(HeaderSettings.LightOffDelayMs); - set - { - HeaderSettings.LightOffDelayMs = TimeExtensions.SecondsToMilliseconds(value); - base.LightOffDelay = value; - } - } - /*public override float PrintTime => 0; public override float UsedMaterial => 0; diff --git a/UVtools.Core/FileFormats/MDLPFile.cs b/UVtools.Core/FileFormats/MDLPFile.cs index 21b61cd..2899843 100644 --- a/UVtools.Core/FileFormats/MDLPFile.cs +++ b/UVtools.Core/FileFormats/MDLPFile.cs @@ -157,11 +157,11 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, //PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, /*PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, @@ -272,6 +272,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = SlicerInfoSettings.BottomLayers = value; } + public override float BottomLightOffDelay => LightOffDelay; + + public override float LightOffDelay + { + get => SlicerInfoSettings.LightOffDelay; + set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; + } + public override float BottomExposureTime { get => SlicerInfoSettings.BottomExposureTime; @@ -284,18 +292,6 @@ namespace UVtools.Core.FileFormats set => base.ExposureTime = SlicerInfoSettings.ExposureTime = (ushort)value; } - public override float BottomLightOffDelay - { - get => LightOffDelay; - set { } - } - - public override float LightOffDelay - { - get => SlicerInfoSettings.LightOffDelay; - set => base.LightOffDelay = SlicerInfoSettings.LightOffDelay = (ushort)value; - } - public override object[] Configs => new[] { (object)HeaderSettings, SlicerInfoSettings }; #endregion diff --git a/UVtools.Core/FileFormats/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs index 59c9eb7..c9a34ab 100644 --- a/UVtools.Core/FileFormats/PHZFile.cs +++ b/UVtools.Core/FileFormats/PHZFile.cs @@ -695,16 +695,19 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.BottomLightOffDelay, + PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, @@ -820,6 +823,18 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = (ushort) (HeaderSettings.BottomLayersCount2 = HeaderSettings.BottomLayersCount = value); } + public override float BottomLightOffDelay + { + get => HeaderSettings.BottomLightOffDelay; + set => base.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); + } + + public override float LightOffDelay + { + get => HeaderSettings.LightOffDelay; + set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => HeaderSettings.BottomExposureSeconds; @@ -862,18 +877,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = HeaderSettings.RetractSpeed = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay - { - get => HeaderSettings.BottomLightOffDelay; - set => base.BottomLightOffDelay = HeaderSettings.BottomLightOffDelay = (float)Math.Round(value, 2); - } - - public override float LightOffDelay - { - get => HeaderSettings.LightOffDelay; - set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); - } - public override byte BottomLightPWM { get => (byte) HeaderSettings.BottomLightPWM; diff --git a/UVtools.Core/FileFormats/PhotonSFile.cs b/UVtools.Core/FileFormats/PhotonSFile.cs index 40e2602..2195e9d 100644 --- a/UVtools.Core/FileFormats/PhotonSFile.cs +++ b/UVtools.Core/FileFormats/PhotonSFile.cs @@ -231,11 +231,14 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, - //PrintParameterModifier.BottomLightOffDelay, PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + //PrintParameterModifier.BottomLightOffDelay, + //PrintParameterModifier.BottomLiftHeight, //PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, @@ -310,6 +313,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = (ushort) (HeaderSettings.BottomLayerCount = value); } + public override float BottomLightOffDelay => LightOffDelay; + + public override float LightOffDelay + { + get => (float)HeaderSettings.LightOffDelay; + set => base.LightOffDelay = (float)(HeaderSettings.LightOffDelay = Math.Round(value, 2)); + } + public override float BottomExposureTime { get => (float) HeaderSettings.BottomExposureSeconds; @@ -344,14 +355,6 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = (float) (HeaderSettings.RetractSpeed = (float) Math.Round(value / 60.0, 2)); } - public override float BottomLightOffDelay => LightOffDelay; - - public override float LightOffDelay - { - get => (float)HeaderSettings.LightOffDelay; - set => base.LightOffDelay = (float)(HeaderSettings.LightOffDelay = Math.Round(value, 2)); - } - public override float MaterialMilliliters { diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index 88a0a80..0c733b9 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -925,11 +925,13 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, - //PrintParameterModifier.BottomLightOffDelay, PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + //PrintParameterModifier.BottomLightOffDelay, //PrintParameterModifier.BottomLiftHeight, //PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, @@ -938,7 +940,7 @@ namespace UVtools.Core.FileFormats }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.ExposureTime, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, }; @@ -1080,6 +1082,14 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = (ushort) (HeaderSettings.BottomLayersCount = value); } + public override float BottomLightOffDelay => LightOffDelay; + + public override float LightOffDelay + { + get => HeaderSettings.LightOffDelay; + set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => HeaderSettings.BottomExposureSeconds; @@ -1092,14 +1102,6 @@ namespace UVtools.Core.FileFormats set => base.ExposureTime = HeaderSettings.LayerExposureTime = (float) Math.Round(value, 2); } - public override float BottomLightOffDelay => LightOffDelay; - - public override float LightOffDelay - { - get => HeaderSettings.LightOffDelay; - set => base.LightOffDelay = HeaderSettings.LightOffDelay = (float) Math.Round(value, 2); - } - public override float BottomLiftHeight => LiftHeight; public override float LiftHeight diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs index c377f1b..c4580cd 100644 --- a/UVtools.Core/FileFormats/SL1File.cs +++ b/UVtools.Core/FileFormats/SL1File.cs @@ -31,11 +31,17 @@ namespace UVtools.Core.FileFormats public const string Keyword_FileFormat = "FILEFORMAT"; public const string Keyword_BottomLightOffDelay = "BottomLightOffDelay"; - public const string Keyword_LightOffDelay = "LightOffDelay"; + public const string Keyword_LightOffDelay = "LightOffDelay"; + public const string Keyword_BottomWaitTimeBeforeCure = "BottomWaitBeforeCure"; + public const string Keyword_WaitTimeBeforeCure = "WaitBeforeCure"; + public const string Keyword_BottomWaitTimeAfterCure = "BottomWaitAfterCure"; + public const string Keyword_WaitTimeAfterCure = "WaitAfterCure"; public const string Keyword_BottomLiftHeight = "BottomLiftHeight"; public const string Keyword_BottomLiftSpeed = "BottomLiftSpeed"; public const string Keyword_LiftHeight = "LiftHeight"; public const string Keyword_LiftSpeed = "LiftSpeed"; + public const string Keyword_BottomWaitTimeAfterLift = "BottomWaitAfterLift"; + public const string Keyword_WaitTimeAfterLift = "WaitAfterLift"; public const string Keyword_RetractSpeed = "RetractSpeed"; public const string Keyword_BottomLightPWM = "BottomLightPWM"; public const string Keyword_LightPWM = "LightPWM"; @@ -309,8 +315,8 @@ namespace UVtools.Core.FileFormats }; public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, }; public override System.Drawing.Size[] ThumbnailsOriginalSize { get; } = @@ -631,13 +637,25 @@ namespace UVtools.Core.FileFormats SuppressRebuildPropertiesWork(() => { + BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, DefaultBottomLightOffDelay); + LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, DefaultLightOffDelay); + + BottomWaitTimeBeforeCure = LookupCustomValue(Keyword_BottomWaitTimeBeforeCure, 0f); + WaitTimeBeforeCure = LookupCustomValue(Keyword_WaitTimeBeforeCure, 0f); + + BottomWaitTimeAfterCure = LookupCustomValue(Keyword_BottomWaitTimeAfterCure, 0f); + WaitTimeAfterCure = LookupCustomValue(Keyword_WaitTimeAfterCure, 0f); + BottomLiftHeight = LookupCustomValue(Keyword_BottomLiftHeight, DefaultBottomLiftHeight); BottomLiftSpeed = LookupCustomValue(Keyword_BottomLiftSpeed, DefaultBottomLiftSpeed); + LiftHeight = LookupCustomValue(Keyword_LiftHeight, DefaultLiftHeight); LiftSpeed = LookupCustomValue(Keyword_LiftSpeed, DefaultLiftSpeed); + + BottomWaitTimeAfterLift = LookupCustomValue(Keyword_BottomWaitTimeAfterLift, 0f); + WaitTimeAfterLift = LookupCustomValue(Keyword_WaitTimeAfterLift, 0f); + RetractSpeed = LookupCustomValue(Keyword_RetractSpeed, DefaultRetractSpeed); - BottomLightOffDelay = LookupCustomValue(Keyword_BottomLightOffDelay, DefaultBottomLightOffDelay); - LightOffDelay = LookupCustomValue(Keyword_LightOffDelay, DefaultLightOffDelay); BottomLightPWM = LookupCustomValue(Keyword_BottomLightPWM, DefaultLightPWM); LightPWM = LookupCustomValue(Keyword_LightPWM, DefaultBottomLightPWM); }); diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs index feb22c1..f6e96ab 100644 --- a/UVtools.Core/FileFormats/UVJFile.cs +++ b/UVtools.Core/FileFormats/UVJFile.cs @@ -135,11 +135,13 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, PrintParameterModifier.BottomLightOffDelay, PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, @@ -151,11 +153,12 @@ namespace UVtools.Core.FileFormats }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, + PrintParameterModifier.LightOffDelay, + PrintParameterModifier.ExposureTime, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, + PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, @@ -242,6 +245,18 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = JsonSettings.Properties.Bottom.Count = value; } + public override float LightOffDelay + { + get => JsonSettings.Properties.Exposure.LightOffTime; + set => base.LightOffDelay = JsonSettings.Properties.Exposure.LightOffTime = (float)Math.Round(value, 2); + } + + public override float BottomLiftHeight + { + get => JsonSettings.Properties.Bottom.LiftHeight; + set => base.BottomLiftHeight = JsonSettings.Properties.Bottom.LiftHeight = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => JsonSettings.Properties.Bottom.LightOnTime; @@ -260,18 +275,6 @@ namespace UVtools.Core.FileFormats set => base.BottomLightOffDelay = JsonSettings.Properties.Bottom.LightOffTime = (float)Math.Round(value, 2); } - public override float LightOffDelay - { - get => JsonSettings.Properties.Exposure.LightOffTime; - set => base.LightOffDelay = JsonSettings.Properties.Exposure.LightOffTime = (float)Math.Round(value, 2); - } - - public override float BottomLiftHeight - { - get => JsonSettings.Properties.Bottom.LiftHeight; - set => base.BottomLiftHeight = JsonSettings.Properties.Bottom.LiftHeight = (float)Math.Round(value, 2); - } - public override float LiftHeight { get => JsonSettings.Properties.Exposure.LiftHeight; diff --git a/UVtools.Core/FileFormats/VDAFile.cs b/UVtools.Core/FileFormats/VDAFile.cs index ab6ab3a..126c325 100644 --- a/UVtools.Core/FileFormats/VDAFile.cs +++ b/UVtools.Core/FileFormats/VDAFile.cs @@ -8,24 +8,16 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.IO.Compression; using System.Linq; -using System.Text; using System.Xml.Serialization; -using Emgu.CV; -using Emgu.CV.CvEnum; -using Emgu.CV.Util; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.OpenSsl; using UVtools.Core.Extensions; -using UVtools.Core.GCode; using UVtools.Core.Operations; namespace UVtools.Core.FileFormats { + #region Sub Classes [Serializable] [XmlRoot(ElementName = "root")] public class VDARoot @@ -146,6 +138,7 @@ namespace UVtools.Core.FileFormats public VDAMachines Machines { get; set; } = new(); public List<VDALayer> Layers { get; set; } = new(); } + #endregion public class VDAFile : FileFormat { diff --git a/UVtools.Core/FileFormats/VDTFile.cs b/UVtools.Core/FileFormats/VDTFile.cs index 00008cc..7657917 100644 --- a/UVtools.Core/FileFormats/VDTFile.cs +++ b/UVtools.Core/FileFormats/VDTFile.cs @@ -11,7 +11,6 @@ using System.IO; using System.IO.Compression; using Emgu.CV; using Emgu.CV.CvEnum; -using Emgu.CV.Util; using Newtonsoft.Json; using UVtools.Core.Extensions; using UVtools.Core.Operations; @@ -98,16 +97,22 @@ 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_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_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_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("retract_speed")] public float RetractSpeed { get; set; } = DefaultRetractSpeed; - [JsonProperty("bottom_light_off_delay")] public float BottomLightOffDelay { get; set; } = DefaultBottomLightOffDelay; - [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; } = DefaultLightOffDelay; } public sealed class VDTPrintStatistics @@ -122,11 +127,14 @@ 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("exposure_time")] public float ExposureTime { get; set; } = DefaultExposureTime; + [JsonProperty("wait_time_after_cure")] public float WaitTimeAfterCure { get; set; } = DefaultLightOffDelay; [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("retract_speed")] public float RetractSpeed { get; set; } = DefaultRetractSpeed; - [JsonProperty("light_off_delay")] public float LightOffDelay { get; set; } = DefaultLightOffDelay; [JsonProperty("light_pwm")] public byte LightPWM { get; set; } = DefaultLightPWM; } @@ -143,15 +151,27 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, PrintParameterModifier.BottomLightOffDelay, PrintParameterModifier.LightOffDelay, + + PrintParameterModifier.BottomWaitTimeBeforeCure, + PrintParameterModifier.WaitTimeBeforeCure, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomWaitTimeAfterCure, + PrintParameterModifier.WaitTimeAfterCure, + PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + + PrintParameterModifier.BottomWaitTimeAfterLift, + PrintParameterModifier.WaitTimeAfterLift, + PrintParameterModifier.RetractSpeed, PrintParameterModifier.BottomLightPWM, @@ -159,11 +179,15 @@ namespace UVtools.Core.FileFormats }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.LightOffDelay, + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.BottomWaitTimeAfterCure, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + PrintParameterModifier.WaitTimeAfterLift, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, @@ -268,6 +292,29 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = ManifestFile.Print.BottomLayers = value; } + public override float BottomLightOffDelay + { + get => ManifestFile.Print.BottomLightOffDelay; + set => base.BottomLightOffDelay = ManifestFile.Print.BottomLightOffDelay = (float)Math.Round(value, 2); + } + + public override float LightOffDelay + { + get => ManifestFile.Print.LightOffDelay; + set => base.LightOffDelay = ManifestFile.Print.LightOffDelay = (float)Math.Round(value, 2); + } + + public override float BottomWaitTimeBeforeCure + { + get => ManifestFile.Print.BottomWaitTimeBeforeCure; + set => base.BottomWaitTimeBeforeCure = ManifestFile.Print.BottomWaitTimeBeforeCure = (float)Math.Round(value, 2); + } + public override float WaitTimeBeforeCure + { + get => ManifestFile.Print.WaitTimeBeforeCure; + set => base.WaitTimeBeforeCure = ManifestFile.Print.WaitTimeBeforeCure = (float)Math.Round(value, 2); + } + public override float BottomExposureTime { get => ManifestFile.Print.BottomExposureTime; @@ -280,16 +327,15 @@ namespace UVtools.Core.FileFormats set => base.ExposureTime = ManifestFile.Print.ExposureTime = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay + public override float BottomWaitTimeAfterCure { - get => ManifestFile.Print.BottomLightOffDelay; - set => base.BottomLightOffDelay = ManifestFile.Print.BottomLightOffDelay = (float)Math.Round(value, 2); + get => ManifestFile.Print.BottomWaitTimeAfterCure; + set => base.BottomWaitTimeAfterCure = ManifestFile.Print.BottomWaitTimeAfterCure = (float)Math.Round(value, 2); } - - public override float LightOffDelay + public override float WaitTimeAfterCure { - get => ManifestFile.Print.LightOffDelay; - set => base.LightOffDelay = ManifestFile.Print.LightOffDelay = (float)Math.Round(value, 2); + get => ManifestFile.Print.WaitTimeAfterCure; + set => base.WaitTimeAfterCure = ManifestFile.Print.WaitTimeAfterCure = (float)Math.Round(value, 2); } public override float BottomLiftHeight @@ -316,6 +362,17 @@ namespace UVtools.Core.FileFormats set => base.LiftSpeed = ManifestFile.Print.LiftSpeed = (float)Math.Round(value, 2); } + public override float BottomWaitTimeAfterLift + { + get => ManifestFile.Print.BottomWaitTimeAfterLift; + set => base.BottomWaitTimeAfterLift = ManifestFile.Print.BottomWaitTimeAfterLift = (float)Math.Round(value, 2); + } + public override float WaitTimeAfterLift + { + get => ManifestFile.Print.WaitTimeAfterLift; + set => base.WaitTimeAfterLift = ManifestFile.Print.WaitTimeAfterLift = (float)Math.Round(value, 2); + } + public override float RetractSpeed { get => ManifestFile.Print.RetractSpeed; @@ -393,11 +450,14 @@ namespace UVtools.Core.FileFormats layers[layerIndex] = new VDTLayer { PositionZ = layer.PositionZ, + LightOffDelay = layer.LightOffDelay, + WaitTimeBeforeCure = layer.WaitTimeBeforeCure, ExposureTime = layer.ExposureTime, + WaitTimeAfterCure = layer.WaitTimeAfterCure, LiftHeight = layer.LiftHeight, LiftSpeed = layer.LiftSpeed, + WaitTimeAfterLift = layer.WaitTimeAfterLift, RetractSpeed = layer.RetractSpeed, - LightOffDelay = layer.LightOffDelay, LightPWM = layer.LightPWM }; } @@ -474,11 +534,14 @@ namespace UVtools.Core.FileFormats this[layerIndex] = new Layer(layerIndex, stream, LayerManager) { PositionZ = manifestLayer.PositionZ, + LightOffDelay = manifestLayer.LightOffDelay, + WaitTimeBeforeCure = manifestLayer.WaitTimeBeforeCure, ExposureTime = manifestLayer.ExposureTime, + WaitTimeAfterCure = manifestLayer.WaitTimeAfterCure, LiftHeight = manifestLayer.LiftHeight, LiftSpeed = manifestLayer.LiftSpeed, + WaitTimeAfterLift = manifestLayer.WaitTimeAfterLift, RetractSpeed = manifestLayer.RetractSpeed, - LightOffDelay = manifestLayer.LightOffDelay, LightPWM = manifestLayer.LightPWM, }; } diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs index b02e816..8cd42a2 100644 --- a/UVtools.Core/FileFormats/ZCodeFile.cs +++ b/UVtools.Core/FileFormats/ZCodeFile.cs @@ -193,26 +193,37 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, + + PrintParameterModifier.BottomWaitTimeBeforeCure, + PrintParameterModifier.WaitTimeBeforeCure, + + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + + PrintParameterModifier.BottomWaitTimeAfterCure, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.BottomLiftHeight, PrintParameterModifier.BottomLiftSpeed, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + + PrintParameterModifier.BottomWaitTimeAfterLift, + PrintParameterModifier.WaitTimeAfterLift, + PrintParameterModifier.RetractSpeed, - PrintParameterModifier.BottomLightOffDelay, - PrintParameterModifier.LightOffDelay, PrintParameterModifier.BottomLightPWM, PrintParameterModifier.LightPWM, }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { - PrintParameterModifier.ExposureSeconds, - PrintParameterModifier.LightOffDelay, + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.WaitTimeAfterCure, PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, + PrintParameterModifier.WaitTimeAfterLift, PrintParameterModifier.RetractSpeed, PrintParameterModifier.LightPWM, }; @@ -295,6 +306,38 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = ManifestFile.Profile.Slice.BottomLayerCount = value; } + public override float BottomLightOffDelay + { + get => BottomWaitTimeBeforeCure; + set => BottomWaitTimeBeforeCure = value; + } + + public override float LightOffDelay + { + get => WaitTimeBeforeCure; + set => WaitTimeBeforeCure = value; + } + + public override float BottomWaitTimeBeforeCure + { + get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomLightOffDelay); + set + { + ManifestFile.Profile.Slice.BottomLightOffDelay = TimeExtensions.SecondsToMillisecondsUint(value); + base.BottomWaitTimeBeforeCure = base.BottomLightOffDelay = value; + } + } + + public override float WaitTimeBeforeCure + { + get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.LightOffDelay); + set + { + ManifestFile.Profile.Slice.LightOffDelay = TimeExtensions.SecondsToMillisecondsUint(value); + base.WaitTimeBeforeCure = base.LightOffDelay = value; + } + } + public override float BottomExposureTime { get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomExposureTime); @@ -339,26 +382,6 @@ namespace UVtools.Core.FileFormats set => base.LiftSpeed = ManifestFile.Profile.Slice.LiftSpeed = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay - { - get => TimeExtensions.MillisecondsToSeconds(ManifestFile.Profile.Slice.BottomLightOffDelay); - set - { - ManifestFile.Profile.Slice.BottomLightOffDelay = TimeExtensions.SecondsToMillisecondsUint(value); - base.BottomLightOffDelay = value; - } - } - - public override float LightOffDelay - { - get => (float)Math.Round(ManifestFile.Profile.Slice.LightOffDelay / 1000f, 2); - set - { - ManifestFile.Profile.Slice.LightOffDelay = (uint)(value * 1000); - base.LightOffDelay = value; - } - } - public override byte LightPWM { get => (byte)(byte.MaxValue * ManifestFile.Profile.Slice.LedPower / MaxLEDPower); @@ -433,9 +456,10 @@ namespace UVtools.Core.FileFormats GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.CentimetersPerMinute, GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds, GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.FilenameNonZeroPNG, + LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G0, + EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1, MaxLEDPower = MaxLEDPower, CommandClearImage = {Enabled = false}, - CommandMotorsOffM18 = {Enabled = false}, }; } #endregion diff --git a/UVtools.Core/FileFormats/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs index bf7aeaf..0239e4d 100644 --- a/UVtools.Core/FileFormats/ZCodexFile.cs +++ b/UVtools.Core/FileFormats/ZCodexFile.cs @@ -19,6 +19,7 @@ using Emgu.CV.Stitching; using Emgu.CV.Util; using Newtonsoft.Json; using UVtools.Core.Extensions; +using UVtools.Core.GCode; using UVtools.Core.Operations; namespace UVtools.Core.FileFormats @@ -165,14 +166,15 @@ namespace UVtools.Core.FileFormats public override PrintParameterModifier[] PrintParameterModifiers { get; } = { PrintParameterModifier.BottomLayerCount, - PrintParameterModifier.BottomExposureSeconds, - PrintParameterModifier.ExposureSeconds, - + + PrintParameterModifier.WaitTimeBeforeCure, + PrintParameterModifier.BottomExposureTime, + PrintParameterModifier.ExposureTime, + PrintParameterModifier.LiftHeight, PrintParameterModifier.LiftSpeed, PrintParameterModifier.RetractSpeed, - PrintParameterModifier.LightOffDelay }; public override PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = { @@ -252,6 +254,20 @@ namespace UVtools.Core.FileFormats set => base.BottomLayerCount = ResinMetadataSettings.BottomLayersNumber = UserSettings.BottomLayersCount = value; } + public override float BottomLightOffDelay => BottomWaitTimeBeforeCure; + + public override float LightOffDelay => WaitTimeBeforeCure; + public override float BottomWaitTimeBeforeCure => WaitTimeBeforeCure; + public override float WaitTimeBeforeCure + { + get => TimeExtensions.MillisecondsToSeconds(ResinMetadataSettings.BlankingLayerTime); + set + { + UserSettings.ExposureOffTime = ResinMetadataSettings.BlankingLayerTime = TimeExtensions.SecondsToMillisecondsUint(value); + base.WaitTimeBeforeCure = base.LightOffDelay = value; + } + } + public override float BottomExposureTime { get => TimeExtensions.MillisecondsToSeconds(UserSettings.BottomLayerExposureTime); @@ -294,19 +310,7 @@ namespace UVtools.Core.FileFormats set => base.RetractSpeed = UserSettings.ZLiftRetractRate = (float)Math.Round(value, 2); } - public override float BottomLightOffDelay => LightOffDelay; - - public override float LightOffDelay - { - get => TimeExtensions.MillisecondsToSeconds(ResinMetadataSettings.BlankingLayerTime); - set - { - UserSettings.ExposureOffTime = ResinMetadataSettings.BlankingLayerTime = TimeExtensions.SecondsToMillisecondsUint(value); - base.LightOffDelay = value; - } - } - - + public override float PrintTime { get => ResinMetadataSettings.PrintTime; @@ -354,7 +358,16 @@ namespace UVtools.Core.FileFormats public ZCodexFile() { - GCode = new(); + GCode = new() + { + UseComments = true, + GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial, + GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute, + GCodeTimeUnit = GCodeBuilder.GCodeTimeUnits.Milliseconds, + GCodeShowImageType = GCodeBuilder.GCodeShowImageTypes.LayerIndexZero, + LayerMoveCommand = GCodeBuilder.GCodeMoveCommands.G1, + EndGCodeMoveCommand = GCodeBuilder.GCodeMoveCommands.G1 + }; } #endregion @@ -610,6 +623,8 @@ M106 S0 GCode.Clear(); GCode.Append(gcode); + + RaisePropertyChanged(nameof(GCodeStr)); } public override void SaveAs(string filePath = null, OperationProgress progress = null) diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs index 5e3d8a2..8bdbfff 100644 --- a/UVtools.Core/GCode/GCodeBuilder.cs +++ b/UVtools.Core/GCode/GCodeBuilder.cs @@ -80,6 +80,12 @@ namespace UVtools.Core.GCode CentimetersPerMinute, } + public enum GCodeMoveCommands : byte + { + G0, // Fast + G1 // Interpolated + } + public enum GCodeShowImageTypes : byte { FilenameZeroPNG, @@ -100,6 +106,8 @@ namespace UVtools.Core.GCode private GCodeShowImageTypes _gCodeShowImageType = GCodeShowImageTypes.FilenameNonZeroPNG; private ushort _maxLedPower = byte.MaxValue; private uint _lineCount; + private GCodeMoveCommands _layerMoveCommand; + private GCodeMoveCommands _endGCodeMoveCommand; #endregion @@ -129,6 +137,18 @@ namespace UVtools.Core.GCode set => RaiseAndSetIfChanged(ref _gCodeShowImageType, value); } + public GCodeMoveCommands LayerMoveCommand + { + get => _layerMoveCommand; + set => RaiseAndSetIfChanged(ref _layerMoveCommand, value); + } + + public GCodeMoveCommands EndGCodeMoveCommand + { + get => _endGCodeMoveCommand; + set => RaiseAndSetIfChanged(ref _endGCodeMoveCommand, value); + } + public bool UseTailComma { get => _useTailComma; @@ -303,7 +323,10 @@ namespace UVtools.Core.GCode AppendLightOffM106(); if (raiseZ > 0) { - AppendMoveG0(raiseZ, feedRate); + if (_endGCodeMoveCommand == GCodeMoveCommands.G0) + AppendMoveG0(raiseZ, feedRate); + else + AppendMoveG1(raiseZ, feedRate); } AppendMotorsOff(); @@ -353,6 +376,22 @@ namespace UVtools.Core.GCode AppendLine(CommandHomeG28); } + public void AppendMoveGx(float z, float feedRate) + { + if(_layerMoveCommand == GCodeMoveCommands.G0) + AppendMoveG0(z, feedRate); + else + AppendMoveG1(z, feedRate); + } + + public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) + { + if (_layerMoveCommand == GCodeMoveCommands.G0) + AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract); + else + AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract); + } + public void AppendMoveG0(float z, float feedRate) { @@ -360,18 +399,24 @@ namespace UVtools.Core.GCode AppendLine(CommandMoveG0, z, feedRate); } - public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float stabilizationDelay = 0) + public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) { if (upZ == 0 || upFeedRate <= 0) return; AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift + + if (waitAfterLift > 0) + { + AppendWaitG4(waitAfterLift, "Wait after lift"); + } + if (downZ != 0 && downFeedRate > 0) { AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate); } - if (stabilizationDelay > 0) + if (waitAfterRetract > 0) { - AppendWaitG4(stabilizationDelay); + AppendWaitG4(waitAfterRetract, "Wait after retract"); } } @@ -381,18 +426,24 @@ namespace UVtools.Core.GCode AppendLine(CommandMoveG1, z, feedRate); } - public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float stabilizationDelay = 0) + public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) { if (upZ == 0 || upFeedRate <= 0) return; AppendLineOverrideComment(CommandMoveG1, "Lift Z", upZ, upFeedRate); // Z Lift + + if (waitAfterLift > 0) + { + AppendWaitG4(waitAfterLift, "Wait after lift"); + } + if (downZ != 0 && downFeedRate > 0) { AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate); } - if (stabilizationDelay > 0) + if (waitAfterRetract > 0) { - AppendWaitG4(stabilizationDelay); + AppendWaitG4(waitAfterRetract, "Wait after retract"); } } @@ -444,6 +495,15 @@ namespace UVtools.Core.GCode _ => throw new InvalidExpressionException($"Unhandled image type for {_gCodeShowImageType}") }; + public string GetShowImageString(string value) => _gCodeShowImageType switch + { + GCodeShowImageTypes.FilenameZeroPNG => $"{value}.png", + GCodeShowImageTypes.FilenameNonZeroPNG => $"{value}.png", + GCodeShowImageTypes.LayerIndexZero => $"{value}", + GCodeShowImageTypes.LayerIndexNonZero => $"{value}", + _ => throw new InvalidExpressionException($"Unhandled image type for {_gCodeShowImageType}") + }; + public void RebuildGCode(FileFormat slicerFile, StringBuilder header) => RebuildGCode(slicerFile, header?.ToString()); public void RebuildGCode(FileFormat slicerFile, string header = null) { @@ -466,14 +526,17 @@ namespace UVtools.Core.GCode for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++) { var layer = slicerFile[layerIndex]; + + float waitBeforeCure = ConvertFromSeconds(layer.WaitTimeBeforeCure); 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 liftSpeed = ConvertFromMillimetersPerMinute(layer.LiftSpeed); + float waitAfterLift = ConvertFromSeconds(layer.WaitTimeAfterLift); float retractPos = layer.PositionZ; float retractSpeed = ConvertFromMillimetersPerMinute(layer.RetractSpeed); - float lightOffDelay = ConvertFromSeconds(layer.LightOffDelay); ushort pwmValue = layer.LightPWM; if (_maxLedPower != byte.MaxValue) { @@ -497,24 +560,25 @@ namespace UVtools.Core.GCode if (liftHeight > 0 && liftZPosAbs > layer.PositionZ) { - AppendLiftMoveG0(liftZPos, liftSpeed, retractPos, retractSpeed); + AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift); } else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position { switch (GCodePositioningType) { case GCodePositioningTypes.Absolute: - AppendMoveG0(layer.PositionZ, liftSpeed); + AppendMoveGx(layer.PositionZ, liftSpeed); break; case GCodePositioningTypes.Partial: - AppendMoveG0(Layer.RoundHeight(layer.PositionZ - lastZPosition), liftSpeed); + AppendMoveGx(Layer.RoundHeight(layer.PositionZ - lastZPosition), liftSpeed); break; } } - AppendWaitG4(lightOffDelay, "Stabilization delay"); + AppendWaitG4(waitBeforeCure, "Wait before cure"); // Safer to parse if present AppendExposure(exposureTime, pwmValue); + if(waitAfterCure > 0) AppendWaitG4(waitAfterCure, "Wait after cure"); AppendLineIfCanComment(EndLayerComments, layerIndex, layer.PositionZ); AppendLine(); @@ -522,7 +586,7 @@ namespace UVtools.Core.GCode lastZPosition = layer.PositionZ; } - float finalRaiseZPosition = slicerFile.MachineZ; + float finalRaiseZPosition = Math.Max(lastZPosition, slicerFile.MachineZ); switch (GCodePositioningType) { @@ -590,11 +654,190 @@ namespace UVtools.Core.GCode if (string.IsNullOrWhiteSpace(gcode)) return; } - var positionType = ParsePositioningTypeFromGCode(gcode); + var positionType = GCodePositioningTypes.Absolute; + // test + /*gcode = + "G90\r\n" + + "M6054 \"1.png\";\r\n" + + "G4 P0;\r\n" + + "M106 S300;\r\n" + + "G4 P36000;\r\n" + + "M106 S0;\r\n" + + "G4 P5000;\r\n" + + "\r\n" + ;*/ float positionZ = 0; - for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++) + var layerBlock = new GCodeLayer(slicerFile); + + using var reader = new StringReader(gcode); + string line; + while ((line = reader.ReadLine()) != null) + { + if(string.IsNullOrWhiteSpace(line)) continue; + + // Search for and switch position type when needed + if (line.StartsWith(CommandPositioningAbsoluteG90.Command)) + { + positionType = GCodePositioningTypes.Absolute; + continue; + } + + if (line.StartsWith(CommandPositioningPartialG91.Command)) + { + positionType = GCodePositioningTypes.Partial; + continue; + } + + var match = Regex.Match(line, CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(@"(\d+)")), RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) // Begin new layer + { + var layerIndex = uint.Parse(match.Groups[1].Value); + if (_gCodeShowImageType is GCodeShowImageTypes.FilenameNonZeroPNG or GCodeShowImageTypes.LayerIndexNonZero) layerIndex--; + if (layerIndex > slicerFile.LayerCount) + { + throw new FileLoadException($"GCode parser detected the layer {layerIndex}, but the file was sliced to {slicerFile.LayerCount} layers.", slicerFile.FileFullPath); + } + + // Propagate values before switch to the new layer + layerBlock.PositionZ ??= positionZ; + layerBlock.SetLayer(); + + layerBlock.Init(); + layerBlock.LayerIndex = layerIndex; + + continue; + } + + if (!layerBlock.IsValid) continue; // No layer yet found to work on, skip + + + // Check moves + var moveG0Regex = Regex.Match(line, CommandMoveG0.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); + var moveG1Regex = Regex.Match(line, CommandMoveG1.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); + match = moveG0Regex.Success && moveG0Regex.Groups.Count >= 2 ? moveG0Regex : moveG1Regex; + + if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed.HasValue) + { + 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 + { + switch (positionType) + { + case GCodePositioningTypes.Absolute: + layerBlock.PositionZ = pos; + break; + case GCodePositioningTypes.Partial: + layerBlock.PositionZ = Layer.RoundHeight(positionZ + pos); + break; + } + + layerBlock.LiftSpeed = speed; + continue; + } + + + // ~90% sure its retract here, still is possible to bug this with 2 lifts + layerBlock.RetractSpeed = speed; + + switch (positionType) + { + case GCodePositioningTypes.Absolute: + layerBlock.LiftHeight = Layer.RoundHeight(layerBlock.PositionZ.Value - pos); + layerBlock.PositionZ = positionZ = pos; + break; + case GCodePositioningTypes.Partial: + layerBlock.LiftHeight = layerBlock.PositionZ - positionZ; + layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + pos); + break; + } + + continue; + } + + // Check for waits + match = Regex.Match(line, CommandWaitG4.ToStringWithoutComments(@"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) + { + var waitTime = float.Parse(match.Groups[1].Value); + + if (layerBlock.PositionZ.HasValue && !layerBlock.RetractSpeed.HasValue) // Must be wait time after lift, if not, don't blame me! + { + layerBlock.WaitTimeAfterLift ??= 0; + layerBlock.WaitTimeAfterLift += ConvertToSeconds(waitTime); + continue; + } + + if (!layerBlock.LightPWM.HasValue) // Before cure + { + layerBlock.WaitTimeBeforeCure ??= 0; + layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime); + continue; + } + + if (layerBlock.IsExposing) // Must be exposure time, if not, don't blame me! + { + layerBlock.ExposureTime ??= 0; + layerBlock.ExposureTime += ConvertToSeconds(waitTime); + continue; + } + + if (layerBlock.IsAfterLightOff) + { + if (!layerBlock.WaitTimeBeforeCure.HasValue) // Novamaker fix, delay on last line, broke logic but safer + { + layerBlock.WaitTimeBeforeCure ??= 0; + layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime); + } + else + { + layerBlock.WaitTimeAfterCure ??= 0; + layerBlock.WaitTimeAfterCure += ConvertToSeconds(waitTime); + } + + continue; + } + + continue; + } + + // Check LightPWM + match = Regex.Match(line, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"), RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) + { + byte pwm; + if (_maxLedPower == byte.MaxValue) + { + pwm = byte.Parse(match.Groups[1].Value); + } + else + { + ushort pwmValue = ushort.Parse(match.Groups[1].Value); + pwm = (byte)(pwmValue * byte.MaxValue / _maxLedPower); + } + + if (pwm == 0 && layerBlock.LightPWM.HasValue) + { + layerBlock.IsAfterLightOff = true; + } + else if(!layerBlock.IsAfterLightOff) + { + layerBlock.LightPWM = pwm; + } + + continue; + } + } + + // Propagate values of left over layer + layerBlock.PositionZ ??= positionZ; + layerBlock.SetLayer(); + + + /*for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++) { var layer = slicerFile[layerIndex]; if(layer is null) continue; @@ -602,7 +845,7 @@ namespace UVtools.Core.GCode var endStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex+1)); gcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length + 1); var endStrIndex = gcode.IndexOf(endStr, StringComparison.Ordinal); - var stripGcode = endStrIndex > 0 ? gcode[..endStrIndex] : gcode;/*.Trim(' ', '\n', '\r', '\t');*/ + var stripGcode = endStrIndex > 0 ? gcode[..endStrIndex] : gcode;//.Trim(' ', '\n', '\r', '\t'); float liftHeight = 0;// this allow read back no lifts slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftHeight, slicerFile.LiftHeight); float liftSpeed = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftSpeed, slicerFile.LiftSpeed); @@ -692,6 +935,7 @@ namespace UVtools.Core.GCode layer.LightOffDelay = lightOffDelay; layer.LightPWM = pwm; } + */ if (rebuildGlobalTable) { @@ -700,22 +944,28 @@ namespace UVtools.Core.GCode 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.LightOffDelay > 0) slicerFile.BottomLightOffDelay = bottomLayer.LightOffDelay; 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.LightOffDelay > 0) slicerFile.LightOffDelay = normalLayer.LightOffDelay; if (normalLayer.LightPWM > 0) slicerFile.LightPWM = normalLayer.LightPWM; } }); diff --git a/UVtools.Core/GCode/GCodeLayer.cs b/UVtools.Core/GCode/GCodeLayer.cs new file mode 100644 index 0000000..a2bdfe4 --- /dev/null +++ b/UVtools.Core/GCode/GCodeLayer.cs @@ -0,0 +1,123 @@ +/* + * 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 UVtools.Core.FileFormats; + +namespace UVtools.Core.GCode +{ + public class GCodeLayer + { + private float? _waitTimeBeforeCure; + private float? _exposureTime; + private float? _waitTimeAfterCure; + private float? _liftHeight; + private float? _liftSpeed; + private float? _waitTimeAfterLift; + private float? _retractSpeed; + + public enum GCodeLastParsedLine : byte + { + LayerIndex, + } + + public bool IsValid => LayerIndex.HasValue; + + public FileFormat SlicerFile { get; } + public uint? LayerIndex { get; set; } + public float? PositionZ { get; set; } + + public float? WaitTimeBeforeCure + { + get => _waitTimeBeforeCure; + set => _waitTimeBeforeCure = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? ExposureTime + { + get => _exposureTime; + set => _exposureTime = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? WaitTimeAfterCure + { + get => _waitTimeAfterCure; + set => _waitTimeAfterCure = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? LiftHeight + { + get => _liftHeight; + set => _liftHeight = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? LiftSpeed + { + get => _liftSpeed; + set => _liftSpeed = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? WaitTimeAfterLift + { + get => _waitTimeAfterLift; + set => _waitTimeAfterLift = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public float? RetractSpeed + { + get => _retractSpeed; + set => _retractSpeed = value is null ? null : (float)Math.Round(value.Value, 2); + } + + public byte? LightPWM { get; set; } + + public bool IsExposing => LightPWM.HasValue && !IsAfterLightOff; + + public bool IsAfterLightOff { get; set; } + + public GCodeLayer(FileFormat slicerFile) + { + SlicerFile = slicerFile; + } + + public void Init() + { + LayerIndex = null; + PositionZ = null; + WaitTimeBeforeCure = null; + ExposureTime = null; + WaitTimeAfterCure = null; + LiftHeight = null; + LiftSpeed = null; + WaitTimeAfterLift = null; + RetractSpeed = null; + LightPWM = null; + IsAfterLightOff = false; + } + + /// <summary> + /// Set gathered data to the layer + /// </summary> + public void SetLayer() + { + if (!IsValid) return; + uint layerIndex = LayerIndex.Value; + var layer = SlicerFile[layerIndex]; + + if(PositionZ.HasValue) 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.WaitTimeAfterLift = WaitTimeAfterLift ?? 0; + layer.RetractSpeed = RetractSpeed ?? SlicerFile.RetractSpeed; + layer.LightPWM = LightPWM ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); + } + } +} diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs index c7aca95..7b87948 100644 --- a/UVtools.Core/Layer/Layer.cs +++ b/UVtools.Core/Layer/Layer.cs @@ -11,7 +11,6 @@ using System.Drawing; using System.Linq; using Emgu.CV; using Emgu.CV.CvEnum; -using Emgu.CV.Util; using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Objects; @@ -33,16 +32,21 @@ namespace UVtools.Core #endregion #region Members + + public object Mutex = new(); private byte[] _compressedBytes; private uint _nonZeroPixelCount; private Rectangle _boundingRectangle = Rectangle.Empty; private bool _isModified; private uint _index; private float _positionZ; + 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 _waitTimeAfterLift; private float _retractSpeed = FileFormat.DefaultRetractSpeed; private byte _lightPwm = FileFormat.DefaultLightPWM; private float _materialMilliliters; @@ -50,8 +54,6 @@ namespace UVtools.Core #region Properties - public object Mutex = new(); - /// <summary> /// Gets the parent layer manager /// </summary> @@ -130,7 +132,23 @@ namespace UVtools.Core } /// <summary> - /// Gets or sets the normal layer exposure time in seconds + /// Gets or sets the wait time in seconds before cure the layer + /// AKA: Light-off delay + /// Chitubox: Rest time after retract + /// Lychee: Wait before print + /// </summary> + public float WaitTimeBeforeCure + { + get => _waitTimeBeforeCure; + set + { + if (!RaiseAndSetIfChanged(ref _waitTimeBeforeCure, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); + } + } + + /// <summary> + /// Gets or sets the exposure time in seconds /// </summary> public float ExposureTime { @@ -138,7 +156,23 @@ namespace UVtools.Core set { if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime); - RaiseAndSetIfChanged(ref _exposureTime, value); + if(!RaiseAndSetIfChanged(ref _exposureTime, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); + } + } + + /// <summary> + /// Gets or sets the wait time in seconds after cure the layer + /// Chitubox: Rest time before lift + /// Lychee: Wait after print + /// </summary> + public float WaitTimeAfterCure + { + get => _waitTimeAfterCure; + set + { + if (!RaiseAndSetIfChanged(ref _waitTimeAfterCure, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); } } @@ -151,7 +185,8 @@ namespace UVtools.Core set { if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay); - RaiseAndSetIfChanged(ref _lightOffDelay, value); + if(!RaiseAndSetIfChanged(ref _lightOffDelay, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); } } @@ -164,7 +199,8 @@ namespace UVtools.Core set { if (value < 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight); - RaiseAndSetIfChanged(ref _liftHeight, value); + if(!RaiseAndSetIfChanged(ref _liftHeight, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); } } @@ -177,7 +213,18 @@ namespace UVtools.Core set { if (value <= 0) value = SlicerFile.GetInitialLayerValueOrNormal(Index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed); - RaiseAndSetIfChanged(ref _liftSpeed, value); + if(!RaiseAndSetIfChanged(ref _liftSpeed, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); + } + } + + public float WaitTimeAfterLift + { + get => _waitTimeAfterLift; + set + { + if (!RaiseAndSetIfChanged(ref _waitTimeAfterLift, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); } } @@ -190,7 +237,8 @@ namespace UVtools.Core set { if (value <= 0) value = SlicerFile.RetractSpeed; - RaiseAndSetIfChanged(ref _retractSpeed, value); + if(!RaiseAndSetIfChanged(ref _retractSpeed, value)) return; + SlicerFile?.UpdatePrintTimeQueued(); } } @@ -351,19 +399,27 @@ namespace UVtools.Core if (SlicerFile is null) return false; // Cant verify if (IsBottomLayer) { - if (ExposureTime != SlicerFile.BottomExposureTime || + if ( + LightOffDelay != SlicerFile.BottomLightOffDelay || + WaitTimeBeforeCure != SlicerFile.BottomWaitTimeBeforeCure || + ExposureTime != SlicerFile.BottomExposureTime || + WaitTimeBeforeCure != SlicerFile.BottomWaitTimeBeforeCure || LiftHeight != SlicerFile.BottomLiftHeight || LiftSpeed != SlicerFile.BottomLiftSpeed || - LightOffDelay != SlicerFile.BottomLightOffDelay || + WaitTimeAfterLift != SlicerFile.BottomWaitTimeAfterLift || LightPWM != SlicerFile.BottomLightPWM ) return false; } else { - if (ExposureTime != SlicerFile.ExposureTime || + if ( + LightOffDelay != SlicerFile.LightOffDelay || + WaitTimeBeforeCure != SlicerFile.WaitTimeBeforeCure || + ExposureTime != SlicerFile.ExposureTime || + WaitTimeAfterCure != SlicerFile.WaitTimeAfterCure || LiftHeight != SlicerFile.LiftHeight || LiftSpeed != SlicerFile.LiftSpeed || - LightOffDelay != SlicerFile.LightOffDelay || + WaitTimeAfterLift != SlicerFile.WaitTimeAfterLift || LightPWM != SlicerFile.LightPWM ) return false; } @@ -385,10 +441,13 @@ namespace UVtools.Core if (parentLayerManager is null) return; _positionZ = SlicerFile.GetHeightFromLayer(index); + _lightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay); + _waitTimeBeforeCure = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomWaitTimeBeforeCure, SlicerFile.WaitTimeBeforeCure); _exposureTime = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime); + _waitTimeAfterCure = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomWaitTimeAfterCure, SlicerFile.WaitTimeAfterCure); _liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight); _liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed); - _lightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay); + _waitTimeAfterLift = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomWaitTimeAfterLift, SlicerFile.WaitTimeAfterLift); _retractSpeed = SlicerFile.RetractSpeed; _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); } @@ -496,17 +555,41 @@ namespace UVtools.Core public override string ToString() { - return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(IsBottomLayer)}: {IsBottomLayer}, {nameof(IsNormalLayer)}: {IsNormalLayer}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(LightPWM)}: {LightPWM}, {nameof(IsModified)}: {IsModified}, {nameof(HaveGlobalParameters)}: {HaveGlobalParameters}"; + return $"{nameof(Index)}: {Index}, " + + $"{nameof(Filename)}: {Filename}, " + + $"{nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, " + + $"{nameof(BoundingRectangle)}: {BoundingRectangle}, " + + $"{nameof(IsBottomLayer)}: {IsBottomLayer}, " + + $"{nameof(IsNormalLayer)}: {IsNormalLayer}, " + + $"{nameof(LayerHeight)}: {LayerHeight}, " + + $"{nameof(PositionZ)}: {PositionZ}, " + + $"{nameof(LightOffDelay)}: {LightOffDelay}, " + + $"{nameof(WaitTimeBeforeCure)}: {WaitTimeBeforeCure}, " + + $"{nameof(ExposureTime)}: {ExposureTime}, " + + $"{nameof(WaitTimeAfterCure)}: {WaitTimeAfterCure}, " + + $"{nameof(LiftHeight)}: {LiftHeight}, " + + $"{nameof(LiftSpeed)}: {LiftSpeed}, " + + $"{nameof(WaitTimeAfterLift)}: {WaitTimeAfterLift}, " + + $"{nameof(RetractSpeed)}: {RetractSpeed}, " + + $"{nameof(LightPWM)}: {LightPWM}, " + + $"{nameof(IsModified)}: {IsModified}, " + + $"{nameof(HaveGlobalParameters)}: {HaveGlobalParameters}"; } #endregion #region Methods - public float CalculateLightOffDelay(float extraTime = 0) + public float CalculateMotorMovementTime(float extraTime = 0) { return OperationCalculator.LightOffDelayC.CalculateSeconds(_liftHeight, _liftSpeed, _retractSpeed, 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); + } + public void SetLightOffDelay(float extraTime = 0) { LightOffDelay = CalculateLightOffDelay(extraTime); @@ -572,15 +655,27 @@ namespace UVtools.Core public bool SetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier, decimal value) { - if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.ExposureSeconds)) + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.LightOffDelay)) + { + LightOffDelay = (float)value; + return true; + } + + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.WaitTimeBeforeCure)) + { + WaitTimeBeforeCure = (float)value; + return true; + } + + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.ExposureTime)) { ExposureTime = (float)value; return true; } - if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.LightOffDelay)) + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.WaitTimeAfterCure)) { - LightOffDelay = (float)value; + WaitTimeAfterCure = (float)value; return true; } @@ -596,6 +691,12 @@ namespace UVtools.Core return true; } + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.WaitTimeAfterLift)) + { + WaitTimeAfterLift = (float)value; + return true; + } + if (ReferenceEquals(modifier, FileFormat.PrintParameterModifier.RetractSpeed)) { RetractSpeed = (float)value; @@ -789,11 +890,14 @@ namespace UVtools.Core return new(_index, CompressedBytes.ToArray(), ParentLayerManager) { PositionZ = _positionZ, + LightOffDelay = _lightOffDelay, + WaitTimeBeforeCure = _waitTimeBeforeCure, ExposureTime = _exposureTime, + WaitTimeAfterCure = _waitTimeAfterCure, LiftHeight = _liftHeight, LiftSpeed = _liftSpeed, + WaitTimeAfterLift = _waitTimeAfterLift, RetractSpeed = _retractSpeed, - LightOffDelay = _lightOffDelay, LightPWM = _lightPwm, BoundingRectangle = _boundingRectangle, NonZeroPixelCount = _nonZeroPixelCount, diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 08d342c..307b1df 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -497,62 +497,84 @@ namespace UVtools.Core if (property != string.Empty) { - if (property is null || property == nameof(SlicerFile.BottomLayerCount)) + if (property is null or nameof(SlicerFile.BottomLayerCount)) { + layer.LightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay); + layer.WaitTimeBeforeCure = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomWaitTimeBeforeCure, SlicerFile.WaitTimeBeforeCure); layer.ExposureTime = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime); + 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.WaitTimeAfterLift = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomWaitTimeAfterLift, SlicerFile.WaitTimeAfterLift); layer.RetractSpeed = SlicerFile.RetractSpeed; layer.LightPWM = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); - layer.LightOffDelay = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightOffDelay, SlicerFile.LightOffDelay); } else { - if (layer.IsNormalLayer) + if (layer.IsBottomLayer) { switch (property) { - case nameof(SlicerFile.ExposureTime): - layer.ExposureTime = SlicerFile.ExposureTime; + case nameof(SlicerFile.BottomLightOffDelay): + layer.LightOffDelay = SlicerFile.BottomLightOffDelay; break; - case nameof(SlicerFile.LiftHeight): - layer.LiftHeight = SlicerFile.LiftHeight; + case nameof(SlicerFile.BottomWaitTimeBeforeCure): + layer.WaitTimeBeforeCure = SlicerFile.BottomWaitTimeBeforeCure; break; - case nameof(SlicerFile.LiftSpeed): - layer.LiftSpeed = SlicerFile.LiftSpeed; + case nameof(SlicerFile.BottomExposureTime): + layer.ExposureTime = SlicerFile.BottomExposureTime; + break; + case nameof(SlicerFile.BottomWaitTimeAfterCure): + layer.WaitTimeAfterCure = SlicerFile.BottomWaitTimeAfterCure; + break; + case nameof(SlicerFile.BottomLiftHeight): + layer.LiftHeight = SlicerFile.BottomLiftHeight; + break; + case nameof(SlicerFile.BottomLiftSpeed): + layer.LiftSpeed = SlicerFile.BottomLiftSpeed; + break; + case nameof(SlicerFile.BottomWaitTimeAfterLift): + layer.WaitTimeAfterLift = SlicerFile.BottomWaitTimeAfterLift; break; case nameof(SlicerFile.RetractSpeed): layer.RetractSpeed = SlicerFile.RetractSpeed; break; - case nameof(SlicerFile.LightOffDelay): - layer.LightOffDelay = SlicerFile.LightOffDelay; - break; - case nameof(SlicerFile.LightPWM): - layer.LightPWM = SlicerFile.LightPWM; + + case nameof(SlicerFile.BottomLightPWM): + layer.LightPWM = SlicerFile.BottomLightPWM; break; } } - else // Bottom layers + else // Normal layers { switch (property) { - case nameof(SlicerFile.BottomExposureTime): - layer.ExposureTime = SlicerFile.BottomExposureTime; + case nameof(SlicerFile.LightOffDelay): + layer.LightOffDelay = SlicerFile.LightOffDelay; break; - case nameof(SlicerFile.BottomLiftHeight): - layer.LiftHeight = SlicerFile.BottomLiftHeight; + case nameof(SlicerFile.WaitTimeBeforeCure): + layer.WaitTimeBeforeCure = SlicerFile.WaitTimeBeforeCure; break; - case nameof(SlicerFile.BottomLiftSpeed): - layer.LiftSpeed = SlicerFile.BottomLiftSpeed; + case nameof(SlicerFile.ExposureTime): + layer.ExposureTime = SlicerFile.ExposureTime; + break; + case nameof(SlicerFile.WaitTimeAfterCure): + layer.WaitTimeAfterCure = SlicerFile.WaitTimeAfterCure; + break; + case nameof(SlicerFile.LiftHeight): + layer.LiftHeight = SlicerFile.LiftHeight; + break; + case nameof(SlicerFile.LiftSpeed): + layer.LiftSpeed = SlicerFile.LiftSpeed; + break; + case nameof(SlicerFile.WaitTimeAfterLift): + layer.WaitTimeAfterLift = SlicerFile.WaitTimeAfterLift; break; case nameof(SlicerFile.RetractSpeed): layer.RetractSpeed = SlicerFile.RetractSpeed; break; - case nameof(SlicerFile.BottomLightOffDelay): - layer.LightOffDelay = SlicerFile.BottomLightOffDelay; - break; - case nameof(SlicerFile.BottomLightPWM): - layer.LightPWM = SlicerFile.BottomLightPWM; + case nameof(SlicerFile.LightPWM): + layer.LightPWM = SlicerFile.LightPWM; break; } } @@ -579,10 +601,15 @@ namespace UVtools.Core var layer = this[layerIndex]; if (this[layerIndex - 1].PositionZ != layer.PositionZ) continue; layer.LiftHeight = 0; - if(zeroLightOffDelay) layer.LightOffDelay = 0; + layer.WaitTimeAfterLift = 0; + if (zeroLightOffDelay) + { + layer.LightOffDelay = 0; + layer.WaitTimeBeforeCure = 0; + layer.WaitTimeAfterCure = 0; + } } SlicerFile?.RebuildGCode(); - SlicerFile?.UpdatePrintTime(); } public IEnumerable<Layer> GetSamePositionedLayers() diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs index f24a6fe..5ba5bd5 100644 --- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs +++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs @@ -1165,7 +1165,7 @@ namespace UVtools.Core.Operations if (_multipleExposuresBaseLayersCustomExposure <= 0) _multipleExposuresBaseLayersCustomExposure = (decimal)SlicerFile.ExposureTime; - if (!SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureSeconds)) + if (!SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureTime)) { _multipleLayerHeight = false; _multipleExposures = false; diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs index 37d8253..4eed766 100644 --- a/UVtools.Core/Operations/OperationDynamicLifts.cs +++ b/UVtools.Core/Operations/OperationDynamicLifts.cs @@ -329,8 +329,8 @@ namespace UVtools.Core.Operations liftSpeed = (_maxLiftSpeed - (_maxLiftSpeed * layer.NonZeroPixelCount / maxNormalPixels)).Clamp(_minLiftSpeed, _maxLiftSpeed); } - layer.LiftHeight = (float) Math.Round(liftHeight, 2); - layer.LiftSpeed = (float) Math.Round(liftSpeed, 2); + layer.LiftHeight = (float) Math.Round(liftHeight, 1); + layer.LiftSpeed = (float) Math.Round(liftSpeed, 1); switch (_lightOffDelaySetMode) { @@ -351,8 +351,6 @@ namespace UVtools.Core.Operations progress++; } - SlicerFile.UpdatePrintTime(); - return !progress.Token.IsCancellationRequested; } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 30fcd60..d1da60f 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.14.3</Version> + <Version>2.15.0</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.Platforms/osx-x64/libcvextern.dylib b/UVtools.Platforms/osx-x64/libcvextern.dylib Binary files differindex d2c3c07..938daae 100644 --- a/UVtools.Platforms/osx-x64/libcvextern.dylib +++ b/UVtools.Platforms/osx-x64/libcvextern.dylib diff --git a/UVtools.Platforms/osx-x64/libusb-1.0.0.dylib b/UVtools.Platforms/osx-x64/libusb-1.0.0.dylib Binary files differnew file mode 100644 index 0000000..cc2b506 --- /dev/null +++ b/UVtools.Platforms/osx-x64/libusb-1.0.0.dylib diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index 20c37ca..ba3231c 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -67,6 +67,13 @@ namespace UVtools.WPF } }*/ + if (!CvInvoke.Init()) + { + Console.WriteLine("UVtools can not init OpenCV library\n" + + "Please build or install this dependencies in order to run UVtools\n" + + "Check manual or page at 'Requirements' section for help"); + } + MainWindow = new MainWindow(); try { diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs index 205f874..5fc920d 100644 --- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs +++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs @@ -31,7 +31,7 @@ namespace UVtools.WPF.Controls.Calibrators set => RaiseAndSetIfChanged(ref _previewImage, value); } - public bool CanSupportPerLayerSettings => SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureSeconds); + public bool CanSupportPerLayerSettings => SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureTime); public CalibrateExposureFinderControl() { diff --git a/UVtools.WPF/Controls/Tools/ToolDynamicLayerHeightControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolDynamicLayerHeightControl.axaml.cs index 040ef78..28a1599 100644 --- a/UVtools.WPF/Controls/Tools/ToolDynamicLayerHeightControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolDynamicLayerHeightControl.axaml.cs @@ -44,7 +44,7 @@ namespace UVtools.WPF.Controls.Tools return; } - if (!SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureSeconds)) + if (!SlicerFile.HaveLayerParameterModifier(FileFormat.PrintParameterModifier.ExposureTime)) { App.MainWindow.MessageBoxWaring($"Your printer seems to not support this tool, still you are allowed to run it for analyze, packing layers or simulation.\n" + $"Do not print this file after run this tool on a not compatible printer, it will result in malformed model and height violation.\n" + diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs index 2ab8826..58107ad 100644 --- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; +using System.ComponentModel; using System.Globalization; using Avalonia; using Avalonia.Controls; @@ -38,7 +35,7 @@ namespace UVtools.WPF.Controls.Tools Modifier = modifier; modifier.NewValue = modifier.OldValue.Clamp(modifier.Minimum, modifier.Maximum); - + Name = new TextBlock { Text = $"{modifier.Name}:", @@ -47,6 +44,8 @@ namespace UVtools.WPF.Controls.Tools Tag = this, }; + if(!string.IsNullOrWhiteSpace(modifier.Description)) ToolTip.SetTip(Name, modifier.Description); + OldValue = new TextBlock { Text = modifier.OldValue.ToString(CultureInfo.InvariantCulture), diff --git a/UVtools.WPF/MainWindow.Information.cs b/UVtools.WPF/MainWindow.Information.cs index 71d6a5f..3efc701 100644 --- a/UVtools.WPF/MainWindow.Information.cs +++ b/UVtools.WPF/MainWindow.Information.cs @@ -342,21 +342,22 @@ namespace UVtools.WPF CurrentLayerProperties.Add(new ValueDescription(layer.IsBottomLayer.ToString(), nameof(layer.IsBottomLayer))); CurrentLayerProperties.Add(new ValueDescription(layer.IsModified.ToString(), nameof(layer.IsModified))); CurrentLayerProperties.Add(new ValueDescription($"{layer.ExposureTime:F2}s", nameof(layer.ExposureTime))); - - if (SlicerFile.PrintParameterPerLayerModifiers is not null) + + if (SlicerFile.SupportPerLayerSettings) { - if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LiftHeight)) + 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.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.RetractSpeed)) - CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractSpeed}mm/min", - nameof(layer.RetractSpeed))); - - if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LightOffDelay)) - CurrentLayerProperties.Add(new ValueDescription($"{layer.LightOffDelay}s", - nameof(layer.LightOffDelay))); - - if (SlicerFile.PrintParameterPerLayerModifiers.Contains(FileFormat.PrintParameterModifier.LightPWM)) + if (SlicerFile.CanUseLayerRetractSpeed) + CurrentLayerProperties.Add(new ValueDescription($"{layer.RetractSpeed}mm/min", nameof(layer.RetractSpeed))); + + if (SlicerFile.CanUseLayerLightOffDelay) + CurrentLayerProperties.Add(new ValueDescription($"{layer.LightOffDelay}s", nameof(layer.LightOffDelay))); + + if (SlicerFile.CanUseLayerWaitTimeBeforeCure) + CurrentLayerProperties.Add(new ValueDescription($"{layer.WaitTimeBeforeCure}/{layer.WaitTimeAfterCure}/{layer.WaitTimeAfterLift}s", "WaitTimes:")); + + if (SlicerFile.CanUseLayerLightPWM) CurrentLayerProperties.Add(new ValueDescription(layer.LightPWM.ToString(), nameof(layer.LightPWM))); } var materialMillilitersPercent = layer.MaterialMillilitersPercent; diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml index 3507618..1d0d098 100644 --- a/UVtools.WPF/MainWindow.axaml +++ b/UVtools.WPF/MainWindow.axaml @@ -314,6 +314,11 @@ <TextBlock IsVisible="{Binding SlicerFile.CanUseAnyLightOffDelay}" Text="{Binding SlicerFile.LightOffDelayRepresentation, StringFormat=Light-off: {0}}"/> + <TextBlock IsVisible="{Binding SlicerFile.CanUseAnyWaitTime}" Text=" | "/> + <TextBlock IsVisible="{Binding SlicerFile.CanUseAnyWaitTime}" + ToolTip.Tip="Wait time: Before cure / After cure / After lift" + Text="{Binding SlicerFile.WaitTimeRepresentation, StringFormat=Wait time: {0}}"/> + <TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}" Text=" | "/> <TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}" Text="{Binding SlicerFile.PrintTimeString, StringFormat=Print time: \{0\}}"/> diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 4052fc3..3b8bb8a 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -1309,7 +1309,7 @@ namespace UVtools.WPF if (sender is not MenuItem item) return; if (item.Tag is not FileExtension fileExtension) return; - SaveFileDialog dialog = new() + SaveFileDialog saveDialog = new() { InitialFileName = Path.GetFileNameWithoutExtension(SlicerFile.FileFullPath), Filters = Helpers.ToAvaloniaFilter(fileExtension.Description, fileExtension.Extension), @@ -1318,7 +1318,7 @@ namespace UVtools.WPF : Settings.General.DefaultDirectoryConvertFile }; - var result = await dialog.ShowAsync(this); + var result = await saveDialog.ShowAsync(this); if (string.IsNullOrEmpty(result)) return; @@ -1354,12 +1354,21 @@ namespace UVtools.WPF if (task) { - if (await this.MessageBoxQuestion( + var question = await this.MessageBoxQuestion( $"Conversion completed in {LastStopWatch.ElapsedMilliseconds / 1000}s\n\n" + - $"Do you want to open {Path.GetFileName(result)} in a new window?", - "Conversion complete") == ButtonResult.Yes) - { - App.NewInstance(result); + $"Do you want to open '{Path.GetFileName(result)}' in a new window?\n" + + "Yes: Open in a new window.\n" + + "No: Open in this window.\n" + + "Cancel: Do not perform any action.\n", + "Conversion complete", ButtonEnum.YesNoCancel); + switch (question) + { + case ButtonResult.No: + ProcessFile(result, _actualLayer); + break; + case ButtonResult.Yes: + App.NewInstance(result); + break; } } else @@ -1547,11 +1556,12 @@ namespace UVtools.WPF control.IsVisible = false; } - var window = new ToolWindow(control); + if (loadOperation is not null) { control.BaseOperation = loadOperation; } + var window = new ToolWindow(control); await window.ShowDialog(this); if (window.DialogResult != DialogResults.OK) return null; var operation = control.BaseOperation; diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 917c2f0..e2a8f43 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.14.3</Version> + <Version>2.15.0</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs index 2d1da9c..f7ffdfa 100644 --- a/UVtools.WPF/Windows/ToolWindow.axaml.cs +++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs @@ -611,7 +611,7 @@ namespace UVtools.WPF.Windows } if (toolControl.BaseOperation.HaveExecuted - || toolControl.BaseOperation.ImportedFrom is not Operation.OperationImportFrom.None) // Loaded from something + || toolControl.BaseOperation.ImportedFrom != Operation.OperationImportFrom.None) // Loaded from something { if (toolControl.BaseOperation.HaveROI) { @@ -645,7 +645,7 @@ namespace UVtools.WPF.Windows var profiles = OperationProfiles.GetOperations(ToolControl.BaseOperation.GetType()); _profiles.AddRange(profiles); - if (toolControl.BaseOperation.ImportedFrom is Operation.OperationImportFrom.None || + if (toolControl.BaseOperation.ImportedFrom == Operation.OperationImportFrom.None || (loadedFromSession && !Settings.Tools.LastUsedSettingsPriorityOverDefaultProfile)) { //Operation profile = _profiles.FirstOrDefault(operation => operation.ProfileIsDefault); diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1 index f3d3827..79d12b1 100644 --- a/build/CreateRelease.WPF.ps1 +++ b/build/CreateRelease.WPF.ps1 @@ -32,10 +32,10 @@ Set-Location $PSScriptRoot\.. #################################### ### Configuration ### #################################### -$enableMSI = $true +#$enableMSI = $true #$buildOnly = 'linux-x64' -#$buildOnly = 'win-x64' -$enableNugetPublish = $true +$buildOnly = 'osx-x64' +#$enableNugetPublish = $true # Profilling $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch @@ -122,7 +122,7 @@ $runtimes = "osx-x64" = @{ "extraCmd" = "-p:PublishReadyToRun=true" "exclude" = @() - "include" = @("libcvextern.dylib") + "include" = @("libcvextern.dylib", "libusb-1.0.0.dylib") } } @@ -212,7 +212,7 @@ Building: $runtime" wsl cp -a "$publishFolder/$runtime/." "$macPublishFolder/Contents/MacOS" wsl cd "$publishFolder/" `&`& pwd `&`& zip -r "../$targetZip" "$macAppFolder/*" - wsl cd "$publishFolder/$runtime" `&`& pwd `&`& zip -r "../../$macTargetZipLegacy" . + #wsl cd "$publishFolder/$runtime" `&`& pwd `&`& zip -r "../../$macTargetZipLegacy" . } else { |