diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-07-11 03:09:43 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-07-11 03:09:43 +0300 |
commit | 683a6f4fb4ba0942cb141245c7eff8afb7e43cea (patch) | |
tree | 045f1148096bf095df9002d298c7055af6407c0d | |
parent | 29c485458ce300e0085d9af01ce2ecc87fd0cbd5 (diff) |
v2.14.2v2.14.2
- **Exposure time finder:**
- (Add) [ME] Option: 'Use different settings for layers with same Z positioning'
- (Add) [ME] Option: 'Lift height' for same Z positioned layers
- (Add) [ME] Option: 'Light-off delay' for same Z positioned layers
- (Improvement) Auto-detect and optimize the 'multiple exposures' test to decrease the print time, by set a minimal lift to almost none
- (Improvement) Better information on the thumbnail
- (Fix) Importing a profile would crash the application
- (Fix) Error with 'Pattern loaded model' fails when generating more models than build plate can afford (#239)
- **GCode:**
- (Fix) When the last layer have no lifts and a move to top command is set on end, that value were being set incorrectly as last layer position
- (Fix) Layer parsing from mm/s to mm/m bad convertion
- (Add) File formats: Setter `SuppressRebuildGCode` to disable or enable the gcode auto rebuild when needed, set this to false to manually write your own gcode
- (Fix) ZCode: Some test files come with layer height of 0mm on a property, in that case lookup layer height on the second property as fallback
23 files changed, 512 insertions, 177 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index b3f2ca7..69d5756 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 11/06/2021 - v2.14.2 + +- **Exposure time finder:** + - (Add) [ME] Option: 'Use different settings for layers with same Z positioning' + - (Add) [ME] Option: 'Lift height' for same Z positioned layers + - (Add) [ME] Option: 'Light-off delay' for same Z positioned layers + - (Improvement) Auto-detect and optimize the 'multiple exposures' test to decrease the print time, by set a minimal lift to almost none + - (Improvement) Better information on the thumbnail + - (Fix) Importing a profile would crash the application + - (Fix) Error with 'Pattern loaded model' fails when generating more models than build plate can afford (#239) +- **GCode:** + - (Fix) When the last layer have no lifts and a move to top command is set on end, that value were being set incorrectly as last layer position + - (Fix) Layer parsing from mm/s to mm/m bad convertion +- (Add) File formats: Setter `SuppressRebuildGCode` to disable or enable the gcode auto rebuild when needed, set this to false to manually write your own gcode +- (Add) UVtools version to error logs +- (Fix) ZCode: Some test files come with layer height of 0mm on a property, in that case lookup layer height on the second property as fallback + ## 07/06/2021 - v2.14.1 - (Upgrade) EmguCV from 4.5.1 to 4.5.2 @@ -11,7 +28,7 @@ - (Fix) Division by 0 when start layer is equal to end layer - (Fix) Calculations when using the option "Increase or decrease towards 100%" - (Add) About window: OpenCV build number and a button to copy build information to clipboard -- (Improvement) Exposure exposure finder: Improve the **Multiple brightness** section to auto fill with correct values for file formats that use time fractions to emulate AntiAliasing, this can be used to replace the **Multiple exposures** section +- (Improvement) Exposure time finder: Improve the **Multiple brightness** section to auto fill with correct values for file formats that use time fractions to emulate AntiAliasing, this can be used to replace the **Multiple exposures** section - (Fix) UVJ: Error when using a null or empty layer array on manifest `config.json` file (#232) - (Fix) GCode parser: When only a G4/wait command is present on a layer it was setting the global exposure time and discard the this value per layer @@ -56,4 +56,5 @@ - James Kao - Finn Newick - Thomas Wilbert -- Gary Kyle
\ No newline at end of file +- Gary Kyle +- Peter Csaki
\ No newline at end of file diff --git a/Scripts/ctb.bt b/Scripts/010 Editor/ctb.bt index 88ddc4b..88ddc4b 100644 --- a/Scripts/ctb.bt +++ b/Scripts/010 Editor/ctb.bt diff --git a/Scripts/cxdlp_v1.bt b/Scripts/010 Editor/cxdlp_v1.bt index bc43eda..bc43eda 100644 --- a/Scripts/cxdlp_v1.bt +++ b/Scripts/010 Editor/cxdlp_v1.bt diff --git a/Scripts/cxdlp_v2.bt b/Scripts/010 Editor/cxdlp_v2.bt index 3a33f30..3a33f30 100644 --- a/Scripts/cxdlp_v2.bt +++ b/Scripts/010 Editor/cxdlp_v2.bt diff --git a/Scripts/gr1.bt b/Scripts/010 Editor/gr1.bt index c55b088..c55b088 100644 --- a/Scripts/gr1.bt +++ b/Scripts/010 Editor/gr1.bt diff --git a/Scripts/lgs.bt b/Scripts/010 Editor/lgs.bt index 1f9e630..1f9e630 100644 --- a/Scripts/lgs.bt +++ b/Scripts/010 Editor/lgs.bt diff --git a/Scripts/mdlp.bt b/Scripts/010 Editor/mdlp.bt index 501b06e..501b06e 100644 --- a/Scripts/mdlp.bt +++ b/Scripts/010 Editor/mdlp.bt diff --git a/Scripts/photons.bt b/Scripts/010 Editor/photons.bt index bc04d37..bc04d37 100644 --- a/Scripts/photons.bt +++ b/Scripts/010 Editor/photons.bt diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index 1a6cd42..d53b283 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -681,6 +681,8 @@ namespace UVtools.Core.Extensions } public static Size GetTextSizeExtended(string text, FontFace fontFace, double fontScale, int thickness, ref int baseLine, PutTextLineAlignment lineAlignment = default) + => GetTextSizeExtended(text, fontFace, fontScale, thickness, 0, ref baseLine, lineAlignment); + public static Size GetTextSizeExtended(string text, FontFace fontFace, double fontScale, int thickness, int lineGapOffset, ref int baseLine, PutTextLineAlignment lineAlignment = default) { text = text.TrimEnd('\n', '\r', ' '); var lines = text.Split(StaticObjects.LineBreakCharacters, StringSplitOptions.None); @@ -688,7 +690,7 @@ namespace UVtools.Core.Extensions if (lines.Length is 0 or 1) return textSize; - var lineGap = textSize.Height / 3; + var lineGap = textSize.Height / 3 + lineGapOffset; var width = 0; var height = lines.Length * (lineGap + textSize.Height) - lineGap; @@ -706,11 +708,16 @@ namespace UVtools.Core.Extensions return new(width, height); } - /// <summary> - /// Extended OpenCV PutText to accepting line breaks and line alignment - /// </summary> public static void PutTextExtended(this Mat src, string text, Point org, FontFace fontFace, double fontScale, - MCvScalar color, int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default) + MCvScalar color, int thickness = 1, LineType lineType = LineType.EightConnected, + bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default) + => src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, 0, lineType, bottomLeftOrigin, lineAlignment); + + /// <summary> + /// Extended OpenCV PutText to accepting line breaks and line alignment + /// </summary> + public static void PutTextExtended(this Mat src, string text, Point org, FontFace fontFace, double fontScale, + MCvScalar color, int thickness = 1, int lineGapOffset = 0, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default) { text = text.TrimEnd('\n', '\r', ' '); var lines = text.Split(StaticObjects.LineBreakCharacters, StringSplitOptions.None); @@ -727,7 +734,7 @@ namespace UVtools.Core.Extensions // Get height of text lines in pixels (height of all lines is the same) int baseLine = 0; var textSize = CvInvoke.GetTextSize(text, fontFace, fontScale, thickness, ref baseLine); - var lineGap = textSize.Height / 3; + var lineGap = textSize.Height / 3 + lineGapOffset; var linesSize = new Size[lines.Length]; int width = 0; @@ -769,15 +776,25 @@ namespace UVtools.Core.Extensions } } + /// <summary> + /// Extended OpenCV PutText to accepting line breaks, line alignment and rotation + /// </summary> + public static void PutTextRotated(this Mat src, string text, Point org, FontFace fontFace, double fontScale, + MCvScalar color, + int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, + PutTextLineAlignment lineAlignment = default, double angle = 0) + => src.PutTextRotated(text, org, fontFace, fontScale, color, thickness, 0, lineType, bottomLeftOrigin, + lineAlignment, angle); + /// <summary> /// Extended OpenCV PutText to accepting line breaks, line alignment and rotation /// </summary> public static void PutTextRotated(this Mat src, string text, Point org, FontFace fontFace, double fontScale, MCvScalar color, - int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default, double angle = 0) + int thickness = 1, int lineGapOffset = 0, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default, double angle = 0) { if (angle % 360 == 0) // No rotation needed, cheaper cycle { - src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin, lineAlignment); + src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment); return; } @@ -786,10 +803,10 @@ namespace UVtools.Core.Extensions var sizeDifference = (rotatedSrc.Size - src.Size).Half(); org.Offset(sizeDifference.ToPoint()); org = org.Rotate(-angle, new Point(rotatedSrc.Size.Width / 2, rotatedSrc.Size.Height / 2)); - rotatedSrc.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin, lineAlignment); + rotatedSrc.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment); using var mask = rotatedSrc.NewBlank(); - mask.PutTextExtended(text, org, fontFace, fontScale, WhiteColor, thickness, lineType, bottomLeftOrigin, lineAlignment); + mask.PutTextExtended(text, org, fontFace, fontScale, WhiteColor, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment); rotatedSrc.Rotate(angle, src.Size); mask.Rotate(angle, src.Size); diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs index a3bd7bb..4f5c972 100644 --- a/UVtools.Core/FileFormats/ChituboxZipFile.cs +++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs @@ -349,7 +349,7 @@ namespace UVtools.Core.FileFormats { using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create)) { - if (Thumbnails.Length > 0 && !ReferenceEquals(Thumbnails[0], null)) + if (Thumbnails.Length > 0 && Thumbnails[0] is not null) { using (Stream stream = outputFile.CreateEntry("preview.png").Open()) { @@ -358,7 +358,7 @@ namespace UVtools.Core.FileFormats } } - if (Thumbnails.Length > 1 && !ReferenceEquals(Thumbnails[1], null)) + if (Thumbnails.Length > 1 && Thumbnails[1] is not null) { using (Stream stream = outputFile.CreateEntry("preview_cropping.png").Open()) { diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index e10e4e7..3b271b8 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -39,7 +39,7 @@ namespace UVtools.Core.FileFormats private const string ExtractConfigFileExtension = "ini"; - public const float DefaultLayerHeight = 0.5f; + public const float DefaultLayerHeight = 0.05f; public const ushort DefaultBottomLayerCount = 4; public const float DefaultBottomExposureTime = 30; @@ -1217,6 +1217,11 @@ namespace UVtools.Core.FileFormats public bool HaveGCode => SupportsGCode && !GCode.IsEmpty; /// <summary> + /// Disable or enable the gcode auto rebuild when needed, set this to false to manually write your own gcode + /// </summary> + public bool SuppressRebuildGCode { get; set; } + + /// <summary> /// Get all configuration objects with properties and values /// </summary> public abstract object[] Configs { get; } @@ -2024,7 +2029,7 @@ namespace UVtools.Core.FileFormats /// </summary> public virtual void RebuildGCode() { - if (!SupportsGCode) return; + if (!SupportsGCode || SuppressRebuildGCode) return; GCode.RebuildGCode(this); } diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs index ffff100..417ecc1 100644 --- a/UVtools.Core/FileFormats/ZCodeFile.cs +++ b/UVtools.Core/FileFormats/ZCodeFile.cs @@ -125,7 +125,7 @@ namespace UVtools.Core.FileFormats public float VolumeMl { get; set; } [XmlElement("thickness")] - public float LayerHeight { get; set; } + public float LayerHeight { get; set; } = FileFormat.DefaultLayerHeight; [XmlElement("price")] public float Price { get; set; } @@ -276,7 +276,7 @@ namespace UVtools.Core.FileFormats public override float LayerHeight { - get => ManifestFile.Job.LayerHeight; + get => ManifestFile.Job.LayerHeight > 0 ? ManifestFile.Job.LayerHeight : ManifestFile.Profile.Slice.LayerHeight; set { ManifestFile.Job.LayerHeight = ManifestFile.Profile.Slice.LayerHeight = Layer.RoundHeight(value); diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs index 03c1d75..5e3d8a2 100644 --- a/UVtools.Core/GCode/GCodeBuilder.cs +++ b/UVtools.Core/GCode/GCodeBuilder.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; +using Org.BouncyCastle.Asn1.Cms; using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Objects; @@ -29,8 +30,8 @@ namespace UVtools.Core.GCode public GCodeCommand CommandPositioningAbsoluteG90 { get; } = new("G90", null, "Absolute positioning"); public GCodeCommand CommandPositioningPartialG91 { get; } = new("G91", null, "Partial positioning"); - public GCodeCommand CommandTurnMotorsOnM17 { get; } = new("M17", null, "Enable motors"); - public GCodeCommand CommandTurnMotorsOffM18 { get; } = new("M18", null, "Disable motors"); + public GCodeCommand CommandMotorsOnM17 { get; } = new("M17", null, "Enable motors"); + public GCodeCommand CommandMotorsOffM18 { get; } = new("M18", null, "Disable motors"); public GCodeCommand CommandHomeG28 { get; } = new("G28", "Z0", "Home Z"); @@ -289,7 +290,7 @@ namespace UVtools.Core.GCode AppendUnitsMmG21(); AppendPositioningType(); AppendLightOffM106(); - AppendEnableMotors(); + AppendMotorsOn(); AppendClearImage(); AppendHomeZG28(); AppendLineIfCanComment(EndStartGCodeComments); @@ -305,7 +306,7 @@ namespace UVtools.Core.GCode AppendMoveG0(raiseZ, feedRate); } - AppendDisableMotors(); + AppendMotorsOff(); AppendLineIfCanComment(EndEndGCodeComments); } @@ -329,22 +330,22 @@ namespace UVtools.Core.GCode } } - public void AppendEnableMotors() + public void AppendMotorsOn() { - AppendLine(CommandTurnMotorsOnM17); + AppendLine(CommandMotorsOnM17); } - public void AppendDisableMotors() + public void AppendMotorsOff() { - AppendLine(CommandTurnMotorsOffM18); + AppendLine(CommandMotorsOffM18); } public void AppendTurnMotors(bool enable) { if (enable) - AppendEnableMotors(); + AppendMotorsOn(); else - AppendDisableMotors(); + AppendMotorsOff(); } public void AppendHomeZG28() @@ -434,18 +435,13 @@ namespace UVtools.Core.GCode AppendLine(CommandShowImageM6054, layerIndex); } - /*public void AppendLayer(Layer layer) - { - - }*/ - public string GetShowImageString(uint layerIndex) => _gCodeShowImageType switch { GCodeShowImageTypes.FilenameZeroPNG => $"{layerIndex}.png", GCodeShowImageTypes.FilenameNonZeroPNG => $"{layerIndex + 1}.png", GCodeShowImageTypes.LayerIndexZero => $"{layerIndex}", GCodeShowImageTypes.LayerIndexNonZero => $"{layerIndex + 1}", - _ => throw new ArgumentOutOfRangeException() + _ => throw new InvalidExpressionException($"Unhandled image type for {_gCodeShowImageType}") }; public void RebuildGCode(FileFormat slicerFile, StringBuilder header) => RebuildGCode(slicerFile, header?.ToString()); @@ -470,14 +466,14 @@ namespace UVtools.Core.GCode for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++) { var layer = slicerFile[layerIndex]; - float exposureTime = layer.ExposureTime; + float exposureTime = ConvertFromSeconds(layer.ExposureTime); float liftHeight = layer.LiftHeight; float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ); float liftZPosAbs = liftZPos; - float liftSpeed = layer.LiftSpeed; + float liftSpeed = ConvertFromMillimetersPerMinute(layer.LiftSpeed); float retractPos = layer.PositionZ; - float retractSpeed = layer.RetractSpeed; - float lightOffDelay = layer.LightOffDelay; + float retractSpeed = ConvertFromMillimetersPerMinute(layer.RetractSpeed); + float lightOffDelay = ConvertFromSeconds(layer.LightOffDelay); ushort pwmValue = layer.LightPWM; if (_maxLedPower != byte.MaxValue) { @@ -492,26 +488,6 @@ namespace UVtools.Core.GCode break; } - switch (GCodeTimeUnit) - { - case GCodeTimeUnits.Milliseconds: - exposureTime *= 1000; - lightOffDelay *= 1000; - break; - } - - switch (GCodeSpeedUnit) - { - case GCodeSpeedUnits.MillimetersPerSecond: - liftSpeed = (float)Math.Round(liftSpeed / 60, 2); - retractSpeed = (float)Math.Round(retractSpeed / 60, 2); - break; - case GCodeSpeedUnits.CentimetersPerMinute: - liftSpeed = (float)Math.Round(liftSpeed / 10, 2); - retractSpeed = (float)Math.Round(retractSpeed / 10); - break; - } - AppendLineIfCanComment(BeginLayerComments, layerIndex, layer.PositionZ); //if (layer.CanExpose) @@ -555,15 +531,8 @@ namespace UVtools.Core.GCode break; } - float endFeedRate = GCodeSpeedUnit switch - { - GCodeSpeedUnits.MillimetersPerMinute => slicerFile.RetractSpeed, - GCodeSpeedUnits.MillimetersPerSecond => (float) Math.Round(slicerFile.RetractSpeed / 60, 2), - GCodeSpeedUnits.CentimetersPerMinute => (float) Math.Round(slicerFile.RetractSpeed / 10, 2), - _ => throw new InvalidExpressionException($"Unhandled feedrate unit for {GCodeSpeedUnit}") - }; - AppendEndGCode(finalRaiseZPosition, endFeedRate); + AppendEndGCode(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.RetractSpeed)); } public void RebuildGCode(FileFormat slicerFile, object[] configs, string separator = ":") @@ -633,7 +602,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.Substring(0, 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); @@ -650,26 +619,12 @@ namespace UVtools.Core.GCode if (moveRegex.Count >= 1 && moveRegex[0].Success) { float liftPosTemp = float.Parse(moveRegex[0].Groups[1].Value, CultureInfo.InvariantCulture); - float liftSpeedTemp = float.Parse(moveRegex[0].Groups[3].Value, CultureInfo.InvariantCulture); - - switch (GCodeSpeedUnit) - { - case GCodeSpeedUnits.MillimetersPerSecond: - liftSpeedTemp = (float) Math.Round(liftSpeedTemp / 60, 2); - break; - case GCodeSpeedUnits.MillimetersPerMinute: - break; - case GCodeSpeedUnits.CentimetersPerMinute: - liftSpeedTemp *= 10; - break; - default: - throw new ArgumentOutOfRangeException(); - } + float liftSpeedTemp = ConvertToMillimetersPerMinute(float.Parse(moveRegex[0].Groups[3].Value, CultureInfo.InvariantCulture)); if (moveRegex.Count >= 2 && moveRegex[1].Success) { float retractPos = float.Parse(moveRegex[1].Groups[1].Value, CultureInfo.InvariantCulture); - retractSpeed = float.Parse(moveRegex[1].Groups[3].Value, CultureInfo.InvariantCulture); + retractSpeed = ConvertToMillimetersPerMinute(float.Parse(moveRegex[1].Groups[3].Value, CultureInfo.InvariantCulture)); liftSpeed = liftSpeedTemp; switch (positionType) @@ -683,33 +638,21 @@ namespace UVtools.Core.GCode positionZ = Layer.RoundHeight(positionZ + liftPosTemp + retractPos); break; } - - switch (GCodeSpeedUnit) - { - case GCodeSpeedUnits.MillimetersPerSecond: - retractSpeed = (float)Math.Round(retractSpeed / 60, 2); - break; - case GCodeSpeedUnits.MillimetersPerMinute: - break; - case GCodeSpeedUnits.CentimetersPerMinute: - retractSpeed *= 10; - break; - default: - throw new ArgumentOutOfRangeException(); - } } else { - switch (positionType) + if (liftPosTemp - positionZ <= FileFormat.MaximumLayerHeight) { - case GCodePositioningTypes.Absolute: - positionZ = liftPosTemp; - break; - case GCodePositioningTypes.Partial: - positionZ = Layer.RoundHeight(positionZ + liftPosTemp); - break; + switch (positionType) + { + case GCodePositioningTypes.Absolute: + positionZ = liftPosTemp; + break; + case GCodePositioningTypes.Partial: + positionZ = Layer.RoundHeight(positionZ + liftPosTemp); + break; + } } - } } @@ -728,23 +671,11 @@ namespace UVtools.Core.GCode if (waitG4Regex.Count >= 1 && waitG4Regex[0].Success) { - lightOffDelay = float.Parse(waitG4Regex[0].Groups[1].Value, CultureInfo.InvariantCulture); - switch (GCodeTimeUnit) - { - case GCodeTimeUnits.Milliseconds: - lightOffDelay = TimeExtensions.MillisecondsToSeconds(lightOffDelay); - break; - } + lightOffDelay = ConvertToSeconds(float.Parse(waitG4Regex[0].Groups[1].Value, CultureInfo.InvariantCulture)); if (waitG4Regex.Count >= 2 && waitG4Regex[1].Success) { - exposureTime = float.Parse(waitG4Regex[1].Groups[1].Value, CultureInfo.InvariantCulture); - switch (GCodeTimeUnit) - { - case GCodeTimeUnits.Milliseconds: - exposureTime = TimeExtensions.MillisecondsToSeconds(exposureTime); - break; - } + exposureTime = ConvertToSeconds(float.Parse(waitG4Regex[1].Groups[1].Value, CultureInfo.InvariantCulture)); } else // Only one match, meaning light off delay is not present and the only time is the cure time { @@ -766,7 +697,7 @@ namespace UVtools.Core.GCode { slicerFile.SuppressRebuildPropertiesWork(() => { - var bottomLayer = slicerFile[0]; + var bottomLayer = slicerFile.FirstLayer; if (bottomLayer is not null) { if (bottomLayer.ExposureTime > 0) slicerFile.BottomExposureTime = bottomLayer.ExposureTime; @@ -795,6 +726,68 @@ namespace UVtools.Core.GCode { return new(_gcode.ToString()); } + + /// <summary> + /// Converts seconds to current gcode norm + /// </summary> + /// <param name="seconds"></param> + /// <returns></returns> + public float ConvertFromSeconds(float seconds) + { + return _gCodeTimeUnit switch + { + GCodeTimeUnits.Seconds => seconds, + GCodeTimeUnits.Milliseconds => TimeExtensions.SecondsToMilliseconds(seconds), + _ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}") + }; + } + + /// <summary> + /// Converts speed in mm/min to current gcode norm + /// </summary> + /// <param name="mmMin">Millimeters per minute</param> + /// <returns></returns> + public float ConvertFromMillimetersPerMinute(float mmMin) + { + return _gCodeSpeedUnit switch + { + GCodeSpeedUnits.MillimetersPerMinute => mmMin, + GCodeSpeedUnits.MillimetersPerSecond => (float) Math.Round(mmMin / 60, 2), + GCodeSpeedUnits.CentimetersPerMinute => (float) Math.Round(mmMin / 10, 2), + _ => throw new InvalidExpressionException($"Unhandled speed unit for {_gCodeSpeedUnit}") + }; + } + + /// <summary> + /// Converts time from current gcode norm in <see cref="GCodeTimeUnit"/> to s + /// </summary> + /// <param name="time">Time in <see cref="GCodeTimeUnit"/></param> + /// <returns></returns> + public float ConvertToSeconds(float time) + { + return _gCodeTimeUnit switch + { + GCodeTimeUnits.Seconds => time, + GCodeTimeUnits.Milliseconds => TimeExtensions.MillisecondsToSeconds(time), + _ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}") + }; + } + + /// <summary> + /// Converts speed from current gcode norm in <see cref="GCodeSpeedUnit"/> to mm/min + /// </summary> + /// <param name="speed">Speed in <see cref="GCodeSpeedUnit"/></param> + /// <returns></returns> + public float ConvertToMillimetersPerMinute(float speed) + { + return _gCodeSpeedUnit switch + { + GCodeSpeedUnits.MillimetersPerMinute => speed, + GCodeSpeedUnits.MillimetersPerSecond => (float)Math.Round(speed * 60, 2), + GCodeSpeedUnits.CentimetersPerMinute => (float)Math.Round(speed * 10, 2), + _ => throw new InvalidExpressionException($"Unhandled speed unit for {_gCodeSpeedUnit}") + }; + } } #endregion } diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index b9585c3..08d342c 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -585,6 +585,19 @@ namespace UVtools.Core SlicerFile?.UpdatePrintTime(); } + public IEnumerable<Layer> GetSamePositionedLayers() + { + var layers = new List<Layer>(); + for (int layerIndex = 1; layerIndex < LayerCount; layerIndex++) + { + var layer = this[layerIndex]; + if (this[layerIndex - 1].PositionZ != layer.PositionZ) continue; + layers.Add(layer); + } + + return layers; + } + public Rectangle GetBoundingRectangle(OperationProgress progress = null) { if (!_boundingRectangle.IsEmpty || LayerCount == 0 || this[0] is null) return _boundingRectangle; diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs index c515538..72ba3d7 100644 --- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs +++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs @@ -110,8 +110,11 @@ namespace UVtools.Core.Operations private decimal _multipleLayerHeightMaximum = 0.1m; private decimal _multipleLayerHeightStep = 0.01m; - private bool _dontLiftSamePositionedLayers; - private bool _zeroLightOffSamePositionedLayers; + private bool _differentSettingsForSamePositionedLayers; + private bool _samePositionedLayersLiftHeightEnabled = true; + private decimal _samePositionedLayersLiftHeight; + private bool _samePositionedLayersLightOffDelayEnabled = true; + private decimal _samePositionedLayersLightOffDelay; private bool _multipleExposures; private ExposureGenTypes _exposureGenType = ExposureGenTypes.Linear; private bool _exposureGenIgnoreBaseExposure; @@ -136,7 +139,6 @@ namespace UVtools.Core.Operations private byte _bullsEyeFenceThickness = 10; private sbyte _bullsEyeFenceOffset; private bool _patternModelGlueBottomLayers = true; - #endregion #region Overrides @@ -755,15 +757,17 @@ namespace UVtools.Core.Operations get { List<byte> values = new(); - - var split = _multipleBrightnessValues.Split(',', StringSplitOptions.TrimEntries); - foreach (var brightnessStr in split) + if (!string.IsNullOrWhiteSpace(_multipleBrightnessValues)) { - if (string.IsNullOrWhiteSpace(brightnessStr)) continue; - if (!byte.TryParse(brightnessStr, out var brightness)) continue; - if (brightness is <= 0 or > 255) continue; - if (values.Contains(brightness)) continue; - values.Add(brightness); + var split = _multipleBrightnessValues.Split(',', StringSplitOptions.TrimEntries); + foreach (var brightnessStr in split) + { + if (string.IsNullOrWhiteSpace(brightnessStr)) continue; + if (!byte.TryParse(brightnessStr, out var brightness)) continue; + if (brightness is <= 0 or > 255) continue; + if (values.Contains(brightness)) continue; + values.Add(brightness); + } } return values.OrderByDescending(brightness => brightness).ToArray(); @@ -801,16 +805,34 @@ namespace UVtools.Core.Operations } } - public bool DontLiftSamePositionedLayers + public bool DifferentSettingsForSamePositionedLayers + { + get => _differentSettingsForSamePositionedLayers; + set => RaiseAndSetIfChanged(ref _differentSettingsForSamePositionedLayers, value); + } + + public bool SamePositionedLayersLiftHeightEnabled + { + get => _samePositionedLayersLiftHeightEnabled; + set => RaiseAndSetIfChanged(ref _samePositionedLayersLiftHeightEnabled, value); + } + + public decimal SamePositionedLayersLiftHeight + { + get => _samePositionedLayersLiftHeight; + set => RaiseAndSetIfChanged(ref _samePositionedLayersLiftHeight, Math.Round(value, 2)); + } + + public bool SamePositionedLayersLightOffDelayEnabled { - get => _dontLiftSamePositionedLayers; - set => RaiseAndSetIfChanged(ref _dontLiftSamePositionedLayers, value); + get => _samePositionedLayersLightOffDelayEnabled; + set => RaiseAndSetIfChanged(ref _samePositionedLayersLightOffDelayEnabled, value); } - public bool ZeroLightOffSamePositionedLayers + public decimal SamePositionedLayersLightOffDelay { - get => _zeroLightOffSamePositionedLayers; - set => RaiseAndSetIfChanged(ref _zeroLightOffSamePositionedLayers, value); + get => _samePositionedLayersLightOffDelay; + set => RaiseAndSetIfChanged(ref _samePositionedLayersLightOffDelay, Math.Round(value, 2)); } public bool MultipleExposures @@ -1027,7 +1049,23 @@ namespace UVtools.Core.Operations public OperationCalibrateExposureFinder() { } public OperationCalibrateExposureFinder(FileFormat slicerFile) : base(slicerFile) - { } + { + if (SlicerFile.SupportPerLayerSettings) + { + _differentSettingsForSamePositionedLayers = true; + if (SlicerFile.SupportsGCode) + { + _samePositionedLayersLiftHeight = 0; + _samePositionedLayersLightOffDelay = 2; + } + else + { + _samePositionedLayersLiftHeight = 0.1m; + _samePositionedLayersLightOffDelay = 0; + } + } + + } public override void InitWithSlicerFile() { @@ -1107,7 +1145,7 @@ namespace UVtools.Core.Operations private bool Equals(OperationCalibrateExposureFinder other) { - return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThickness == other._staircaseThickness && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _dontLiftSamePositionedLayers == other._dontLiftSamePositionedLayers && _zeroLightOffSamePositionedLayers == other._zeroLightOffSamePositionedLayers && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers; + return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThickness == other._staircaseThickness && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleBrightnessGenEmulatedAALevel == other._multipleBrightnessGenEmulatedAALevel && _multipleBrightnessGenExposureFractions == other._multipleBrightnessGenExposureFractions && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _differentSettingsForSamePositionedLayers == other._differentSettingsForSamePositionedLayers && _samePositionedLayersLiftHeightEnabled == other._samePositionedLayersLiftHeightEnabled && _samePositionedLayersLiftHeight == other._samePositionedLayersLiftHeight && _samePositionedLayersLightOffDelayEnabled == other._samePositionedLayersLightOffDelayEnabled && _samePositionedLayersLightOffDelay == other._samePositionedLayersLightOffDelay && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers; } public override bool Equals(object obj) @@ -1157,11 +1195,16 @@ namespace UVtools.Core.Operations hashCode.Add((int) _multipleBrightnessExcludeFrom); hashCode.Add(_multipleBrightnessValues); hashCode.Add(_multipleBrightnessGenExposureTime); + hashCode.Add(_multipleBrightnessGenEmulatedAALevel); + hashCode.Add(_multipleBrightnessGenExposureFractions); hashCode.Add(_multipleLayerHeight); hashCode.Add(_multipleLayerHeightMaximum); hashCode.Add(_multipleLayerHeightStep); - hashCode.Add(_dontLiftSamePositionedLayers); - hashCode.Add(_zeroLightOffSamePositionedLayers); + hashCode.Add(_differentSettingsForSamePositionedLayers); + hashCode.Add(_samePositionedLayersLiftHeightEnabled); + hashCode.Add(_samePositionedLayersLiftHeight); + hashCode.Add(_samePositionedLayersLightOffDelayEnabled); + hashCode.Add(_samePositionedLayersLightOffDelay); hashCode.Add(_multipleExposures); hashCode.Add((int) _exposureGenType); hashCode.Add(_exposureGenIgnoreBaseExposure); @@ -1681,8 +1724,43 @@ namespace UVtools.Core.Operations CvInvoke.Line(thumbnail, new Point(xSpacing, 0), new Point(xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3); CvInvoke.Line(thumbnail, new Point(xSpacing, ySpacing + 5), new Point(thumbnail.Width - xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3); CvInvoke.Line(thumbnail, new Point(thumbnail.Width - xSpacing, 0), new Point(thumbnail.Width - xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3); - CvInvoke.PutText(thumbnail, "Exposure Time Cal.", new Point(xSpacing, ySpacing * 2), fontFace, fontScale, new MCvScalar(0, 255, 255), fontThickness); - CvInvoke.PutText(thumbnail, $"{Microns}um @ {BottomExposure}s/{NormalExposure}s", new Point(xSpacing, ySpacing * 3), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness); + CvInvoke.PutText(thumbnail, "Exposure Time Cal.", new Point(xSpacing, ySpacing * 2 - 10), fontFace, fontScale, new MCvScalar(0, 255, 255), fontThickness); + + + string text = string.Empty; + + if (_multipleLayerHeight) + { + text += $"{Microns}um-{(ushort)(_multipleLayerHeightMaximum *1000)}um/{(ushort)(_multipleLayerHeightStep *1000)}um\n"; + } + else + { + text += $"Layer height: {Microns}um\n"; + } + + if (_multipleExposures) + { + text += $"{_exposureTable[0].Exposure}s-{_exposureTable[^1].Exposure}s/{_exposureGenNormalStep}s"; + if (!_patternModel) + { + text += $"\nObjects: {_exposureTable.Count}"; + } + } + else + { + text += $"{_bottomExposure}s/{_normalExposure}s"; + } + + if (_patternModel) + { + text += "\nPatterned Model"; + } + + + thumbnail.PutTextExtended(text, new Point(xSpacing, ySpacing * 3 - 20), fontFace, 0.8, EmguExtensions.WhiteColor, 2, 10); + + + /*CvInvoke.PutText(thumbnail, $"{Microns}um @ {BottomExposure}s/{NormalExposure}s", new Point(xSpacing, ySpacing * 3), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness); if (_patternModel) { CvInvoke.PutText(thumbnail, $"Patterned Model", new Point(xSpacing, ySpacing * 4), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness); @@ -1690,7 +1768,7 @@ namespace UVtools.Core.Operations else { CvInvoke.PutText(thumbnail, $"Features: {(_staircaseThickness > 0 ? 1 : 0) + Holes.Length + Bars.Length + BullsEyes.Length + (_counterTrianglesEnabled ? 1 : 0)}", new Point(xSpacing, ySpacing * 4), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness); - } + }*/ return thumbnail; @@ -1732,7 +1810,7 @@ namespace UVtools.Core.Operations currentY += boundingRectangle.Height + partMarginYPx; } - if (currentY + topBottomMarginPx >= SlicerFile.ResolutionY) break; + if (currentY + boundingRectangle.Height + topBottomMarginPx >= SlicerFile.ResolutionY) break; var item = multipleExposure.Clone(); item.Brightness = brightness; @@ -2098,9 +2176,14 @@ namespace UVtools.Core.Operations if (SlicerFile.ThumbnailsCount > 0) SlicerFile.SetThumbnails(GetThumbnail()); - if (_dontLiftSamePositionedLayers) + if (_differentSettingsForSamePositionedLayers) { - SlicerFile.LayerManager.SetNoLiftForSamePositionedLayers(_zeroLightOffSamePositionedLayers); + var layers = SlicerFile.LayerManager.GetSamePositionedLayers(); + foreach (var layer in layers) + { + if(_samePositionedLayersLiftHeightEnabled) layer.LiftHeight = (float) _samePositionedLayersLiftHeight; + if(_samePositionedLayersLightOffDelayEnabled) layer.LightOffDelay = (float) _samePositionedLayersLightOffDelay; + } } new OperationMove(SlicerFile).Execute(progress); diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index b9b9c4f..0f89f35 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.1</Version> + <Version>2.14.2</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs index 4e2602a..ee8d38e 100644 --- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs +++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs @@ -341,8 +341,8 @@ <Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b"> <File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" /> </Component> - <Component Id="owc29161E83FC02784120326979FF285358" Guid="a8d30e75-1063-4d27-60b6-13d4bd4f52eb"> - <File Id="owf29161E83FC02784120326979FF285358" Source="$(var.SourceDir)\opencv_videoio_ffmpeg451_64.dll" KeyPath="yes" /> + <Component Id="owcC8F0982CA6FC282C6992A07EAF832954" Guid="eca80656-9710-cdb8-cb7f-c54f35b4b913"> + <File Id="owfC8F0982CA6FC282C6992A07EAF832954" Source="$(var.SourceDir)\opencv_videoio_ffmpeg452_64.dll" KeyPath="yes" /> </Component> <Component Id="owc363CAFE6342F1E71AB07D13BAEEE5FF0" Guid="8e946fdc-ea52-7c4b-a8b3-69e1ecf51086"> <File Id="owf363CAFE6342F1E71AB07D13BAEEE5FF0" Source="$(var.SourceDir)\SkiaSharp.dll" KeyPath="yes" /> @@ -867,9 +867,6 @@ <Component Id="owc1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Guid="545300b7-5398-2ce2-788f-02287a83e8a7"> <File Id="owf1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Source="$(var.SourceDir)\UVtools_demo_file.sl1" KeyPath="yes" /> </Component> - <Component Id="owc507468650B23000B702AAAE48E658343" Guid="dba8edf4-02a3-c04a-50fc-896025548077"> - <File Id="owf507468650B23000B702AAAE48E658343" Source="$(var.SourceDir)\vccorlib140.dll" KeyPath="yes" /> - </Component> <Component Id="owcEB2D9343E9BF3366381E9864468EFB9A" Guid="c4f85169-dfa6-1369-3b95-34e28199fa0f"> <File Id="owfEB2D9343E9BF3366381E9864468EFB9A" Source="$(var.SourceDir)\vcruntime140.dll" KeyPath="yes" /> </Component> diff --git a/UVtools.ScriptSample/ScriptCustomGCode.cs b/UVtools.ScriptSample/ScriptCustomGCode.cs new file mode 100644 index 0000000..c5e7565 --- /dev/null +++ b/UVtools.ScriptSample/ScriptCustomGCode.cs @@ -0,0 +1,154 @@ +/* + * 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.Scripting; +using System.IO; +using UVtools.Core; +using UVtools.Core.Extensions; +using UVtools.Core.FileFormats; + +namespace UVtools.ScriptSample +{ + /// <summary> + /// Change layer properties to random values + /// </summary> + public class ScriptCustomGCode : ScriptGlobals + { + /// <summary> + /// Set configurations here, this function trigger just after load a script + /// </summary> + public void ScriptInit() + { + Script.Name = "Custo gcode generator"; + Script.Description = "Generates custom gcode and saves the file"; + Script.Author = "Tiago Conceição"; + Script.Version = new Version(0, 1); + } + + /// <summary> + /// Validate user inputs here, this function trigger when user click on execute + /// </summary> + /// <returns>A error message, empty or null if validation passes.</returns> + public string ScriptValidate() + { + return SlicerFile.SupportsGCode ? null : "GCode is not supported on this file"; + } + + /// <summary> + /// Execute the script, this function trigger when when user click on execute and validation passes + /// </summary> + /// <returns>True if executes successfully to the end, otherwise false.</returns> + public bool ScriptExecute() + { + var gcode = SlicerFile.GCode; + gcode.Clear(); + + float pos = 1; + float layerHeight = 0.025f; + float liftHeight = 4.5f; + float feedrate = gcode.ConvertFromMillimetersPerMinute(150); + float lightoff = gcode.ConvertFromSeconds(1f); + + gcode.AppendStartGCode(); + //gcode.AppendShowImageM6054(gcode.GetShowImageString(0)); + //gcode.AppendWaitG4(gcode.ConvertFromSeconds(2)); + //gcode.AppendTurnLightM106(255); + gcode.AppendWaitG4(gcode.ConvertFromSeconds(1)); + //gcode.AppendTurnLightM106(0); + gcode.AppendLiftMoveG0(20, feedrate, pos, feedrate); + gcode.AppendWaitG4(gcode.ConvertFromSeconds(5)); + + // 0.025 test + /*gcode.AppendComment("0.025 layer height simulated print test"); + for (int i = 0; i < 50; i++) + { + pos = Layer.RoundHeight(pos + layerHeight); + var liftPos = Layer.RoundHeight(pos + liftHeight); + gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff); + }*/ + + // 0.01 test + gcode.AppendComment("0.01 layer height simulated print test"); + pos = 1; + layerHeight = 0.01f; + + + gcode.AppendMoveG0(pos, feedrate); + gcode.AppendWaitG4(gcode.ConvertFromSeconds(5)); + for (int i = 0; i < 50; i++) + { + pos = Layer.RoundHeight(pos + layerHeight); + var liftPos = Layer.RoundHeight(pos + liftHeight); + gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff); + } + + // 0.001 test + /*gcode.AppendComment("0.001 layer height simulated print test"); + pos = 1; + layerHeight = 0.001f; + liftHeight = 1; + + gcode.AppendMoveG0(pos, feedrate); + gcode.AppendWaitG4(gcode.ConvertFromSeconds(5)); + for (int i = 0; i < 50; i++) + { + pos = Layer.RoundHeight(pos + layerHeight); + var liftPos = Layer.RoundHeight(pos + liftHeight); + gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff); + }*/ + + + /*// 0.05 backlash test + gcode.AppendComment("0.05 backlash test"); + pos = 1; + layerHeight = 0.02f; + + gcode.AppendMoveG0(pos, feedrate); + //gcode.AppendWaitG4(gcode.ConvertFromSeconds(5)); + for (int i = 0; i < 50; i++) + { + var liftPos = Layer.RoundHeight(pos + layerHeight); + gcode.AppendMoveG0(liftPos, feedrate); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(pos, feedrate); + gcode.AppendWaitG4(lightoff); + } + */ + + /*gcode.AppendMoveG0(2, gcode.ConvertFromMillimetersPerMinute(150)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(2.5f, gcode.ConvertFromMillimetersPerMinute(160)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(3f, gcode.ConvertFromMillimetersPerMinute(170)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(3.5f, gcode.ConvertFromMillimetersPerMinute(180)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(4.0f, gcode.ConvertFromMillimetersPerMinute(190)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(4.5f, gcode.ConvertFromMillimetersPerMinute(195)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(5f, gcode.ConvertFromMillimetersPerMinute(199)); + gcode.AppendWaitG4(lightoff); + gcode.AppendMoveG0(5.5f, gcode.ConvertFromMillimetersPerMinute(205)); + gcode.AppendWaitG4(lightoff);*/ + + gcode.AppendMoveG0(100, feedrate); + //gcode.AppendTurnMotors(false); + + + + SlicerFile.SuppressRebuildGCode = true; + SlicerFile.Save(Progress); + SlicerFile.SuppressRebuildGCode = false; + + // return true if not cancelled by user + return !Progress.Token.IsCancellationRequested; + } + } +}
\ No newline at end of file diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml index dd221a6..f15720a 100644 --- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml +++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml @@ -896,24 +896,6 @@ Content="Enable - For advanced users only!" IsChecked="{Binding Operation.MultipleExposures}"/> - <StackPanel Orientation="Horizontal" Spacing="20" - IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}"> - - <CheckBox - ToolTip.Tip="The lift height will be set to 0 for sequential layers that share same z position, saving moves and time. -
Some printers may not support this and always require a lift after each layer, in that case turning this on will not affect the print." - Content="Do not perform the lifting sequence for layers with same Z positioning" - IsEnabled="{Binding Operation.MultipleExposures}" - IsChecked="{Binding Operation.DontLiftSamePositionedLayers}"/> - - <CheckBox - ToolTip.Tip="Sets the light-off delay to zero for each sequential layers with no lift's to save that additional time. -
Note that without a lift and a delay the UV LED and LCD will be almost always ON, that can lead to overheat and wear the LCD faster." - Content="Also set light-off delay to zero" - IsEnabled="{Binding Operation.DontLiftSamePositionedLayers}" - IsChecked="{Binding Operation.ZeroLightOffSamePositionedLayers}"/> - </StackPanel> - <TextBlock Text="Automatic exposure generation:" IsEnabled="{Binding Operation.MultipleExposures}" FontWeight="Bold"/> @@ -1114,6 +1096,79 @@ </DataGrid> + + <StackPanel Orientation="Vertical" Spacing="10" + IsEnabled="{Binding Operation.MultipleExposures}" + IsVisible="{Binding SlicerFile.SupportPerLayerSettings}"> + + <CheckBox + ToolTip.Tip="Change some defined settings for sequential layers that share same z position" + Content="Use different settings for layers with same Z positioning:" + FontWeight="Bold" + IsChecked="{Binding Operation.DifferentSettingsForSamePositionedLayers}"/> + + <Grid RowDefinitions="Auto,10,Auto" ColumnDefinitions="Auto,10,Auto,5,Auto" IsEnabled="{Binding Operation.DifferentSettingsForSamePositionedLayers}"> + <CheckBox Grid.Row="0" Grid.Column="0" + ToolTip.Tip="Use a low value to speed up layers with same Z position, lift is not really required here. +
Set no lift height (0mm) will not work on most of the printers, so far, only gcode printers are known/able to use no lifts. +
However set 0mm on a not compatible printer will cause no harm, value will be contained inside a min-max inside firmware." + Content="Lift height:" + IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}" + IsChecked="{Binding Operation.SamePositionedLayersLiftHeightEnabled}" + VerticalAlignment="Center"/> + <NumericUpDown Grid.Row="0" Grid.Column="2" + Increment="0.5" + Minimum="0" + Maximum="1000" + FormatString="F2" + IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}" + IsEnabled="{Binding Operation.SamePositionedLayersLiftHeightEnabled}" + Value="{Binding Operation.SamePositionedLayersLiftHeight}"/> + <TextBlock Grid.Row="0" Grid.Column="4" + Text="mm" + IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}" + VerticalAlignment="Center"/> + + <CheckBox Grid.Row="2" Grid.Column="0" + ToolTip.Tip="Use a low value to speed up layers with same Z position, a delay is not really required here. +
Set no delay (0s) is not recommended for gcode printers, as most need some time to render the image before move to the next command, 2s is recommended as a safe-guard." + Content="Light-off delay:" + IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}" + IsChecked="{Binding Operation.SamePositionedLayersLightOffDelayEnabled}" + VerticalAlignment="Center"/> + <NumericUpDown Grid.Row="2" Grid.Column="2" + Increment="0.5" + Minimum="0" + Maximum="1000" + FormatString="F2" + IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}" + IsEnabled="{Binding Operation.SamePositionedLayersLightOffDelayEnabled}" + Value="{Binding Operation.SamePositionedLayersLightOffDelay}"/> + <TextBlock Grid.Row="2" Grid.Column="4" + Text="s" + IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}" + VerticalAlignment="Center"/> + + </Grid> + + + <!-- + <CheckBox + ToolTip.Tip="The lift height will be set to 0 for sequential layers that share same z position, saving moves and time. +
Some printers may not support this and always require a lift after each layer, in that case turning this on will not affect the print." + Content="Do not perform the lifting sequence for layers with same Z positioning" + IsEnabled="{Binding Operation.MultipleExposures}" + IsChecked="{Binding Operation.DontLiftSamePositionedLayers}"/> + + <CheckBox + ToolTip.Tip="Sets the light-off delay to zero for each sequential layers with no lift's to save that additional time. +
Note that without a lift and a delay the UV LED and LCD will be almost always ON, that can lead to overheat and wear the LCD faster." + Content="Also set light-off delay to zero" + IsEnabled="{Binding Operation.DontLiftSamePositionedLayers}" + IsChecked="{Binding Operation.ZeroLightOffSamePositionedLayers}"/> + !--> + </StackPanel> + </StackPanel> </Expander> diff --git a/UVtools.WPF/ErrorLog.cs b/UVtools.WPF/ErrorLog.cs index d918064..7e2f229 100644 --- a/UVtools.WPF/ErrorLog.cs +++ b/UVtools.WPF/ErrorLog.cs @@ -15,7 +15,7 @@ namespace UVtools.WPF try { File.AppendAllText(FullPath, - $"({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}"); + $"[v{App.VersionStr}] ({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}"); } catch (Exception exception) { @@ -23,7 +23,7 @@ namespace UVtools.WPF } } - public static StreamWriter AppendText() + public static StreamWriter GetStreamWriter() { return File.AppendText(FullPath); } diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index d78fbe3..37b9bfc 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.1</Version> + <Version>2.14.2</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1 index f3d3827..422a593 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 = 'win-x64' +#$enableNugetPublish = $true # Profilling $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch |