- **(Improvement) CWS:**
   - Remove light-off delay from the format
   - Sync movements with a delay time
   - Auto convert the light-off delay time to wait before cure time when required
- **(Improvement) CTB:**
   - When positively set the 'Wait time before cure' property on a CTBv3 or lower, it will compute the right light-off delay with that extra time into consideration
   - When positively set any of the light-off delays on a CTBv4 it will auto zero the 'Wait times' properties and vice-versa
   - Automation to set light-off delay on file load, will no longer do when any of 'Wait times' are defined for a CTBv4
- (Improvement) PrusaSlicer printers that use .cws format, implement the wait times on printer notes
- (Fix) GCode parser: Commented commands were being parsed
- (Fix) Exposure time information on bottom status bar was inverted, showing normal/bottom time instead of bottom/normal
- (Fix) macOS: Installing libusb is no longer a requirement
This commit is contained in:
Tiago Conceição
2021-07-24 02:55:43 +01:00
parent f72a9de628
commit 2d79c6504f
17 changed files with 335 additions and 159 deletions
+15
View File
@@ -1,5 +1,20 @@
# Changelog
## 24/07/2021 - v2.15.1
- **(Improvement) CWS:**
- Remove light-off delay from the format
- Sync movements with a delay time
- Auto convert the light-off delay time to wait before cure time when required
- **(Improvement) CTB:**
- When positively set the 'Wait time before cure' property on a CTBv3 or lower, it will compute the right light-off delay with that extra time into consideration
- When positively set any of the light-off delays on a CTBv4 it will auto zero the 'Wait times' properties and vice-versa
- Automation to set light-off delay on file load, will no longer do when any of 'Wait times' are defined for a CTBv4
- (Improvement) PrusaSlicer printers that use .cws format, implement the wait times on printer notes
- (Fix) GCode parser: Commented commands were being parsed
- (Fix) Exposure time information on bottom status bar was inverted, showing normal/bottom time instead of bottom/normal
- (Fix) macOS: Installing libusb is no longer a requirement
## 16/07/2021 - v2.15.0
- **File formats:**
+5
View File
@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
IDList=
URL=https://www.facebook.com/Photonsters/posts/1198980267222618
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

+2 -2
View File
@@ -1,4 +1,4 @@
# generated by PrusaSlicer 2.3.1+win64 on 2021-04-29 at 17:56:19 UTC
# generated by PrusaSlicer 2.3.1+win64 on 2021-07-24 at 01:01:47 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_NOVA3D\nPRINTER_MODEL_BENE4_MONO\nFILEFORMAT_RGB.CWS\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_120\nLiftSpeed_120\nRetractSpeed_120\nBottomLightPWM_255\nLightPWM_255\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_NOVA3D\nPRINTER_MODEL_BENE4_MONO\nFILEFORMAT_RGB.CWS\n\nSTART_CUSTOM_VALUES\nBottomWaitBeforeCure_3\nWaitBeforeCure_2.5\nBottomWaitAfterCure_3\nWaitAfterCure_1\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_120\nLiftSpeed_120\nBottomWaitAfterLift_0\nWaitAfterLift_0\nRetractSpeed_120\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
+2 -2
View File
@@ -1,4 +1,4 @@
# generated by PrusaSlicer 2.3.0+win64 on 2021-01-13 at 02:35:32 UTC
# generated by PrusaSlicer 2.3.1+win64 on 2021-07-24 at 01:02:10 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_NOVA3D\nPRINTER_MODEL_ELFIN\nFILEFORMAT_CWS\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_120\nLiftSpeed_120\nRetractSpeed_120\nBottomLightPWM_255\nLightPWM_255\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_NOVA3D\nPRINTER_MODEL_ELFIN\nFILEFORMAT_CWS\n\nSTART_CUSTOM_VALUES\nBottomWaitBeforeCure_3\nWaitBeforeCure_2.5\nBottomWaitAfterCure_3\nWaitAfterCure_1\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_120\nLiftSpeed_120\nBottomWaitAfterLift_0\nWaitAfterLift_0\nRetractSpeed_120\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
+2 -2
View File
@@ -1,4 +1,4 @@
# generated by PrusaSlicer 2.3.0+win64 on 2021-03-21 at 18:54:48 UTC
# generated by PrusaSlicer 2.3.1+win64 on 2021-07-21 at 02:49:31 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_PHROZEN\nPRINTER_MODEL_SONIC_MINI\nFILEFORMAT_PHZ\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_8\nLiftHeight_6\nBottomLiftSpeed_100\nLiftSpeed_100\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\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_PHROZEN\nPRINTER_MODEL_SONIC_MINI\nFILEFORMAT_PHZ\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_100\nLiftSpeed_150\nRetractSpeed_200\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
+2 -2
View File
@@ -1,4 +1,4 @@
# generated by PrusaSlicer 2.3.0+win64 on 2021-04-09 at 19:00:09 UTC
# generated by PrusaSlicer 2.3.1+win64 on 2021-07-24 at 01:02:43 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_WANHAO\nPRINTER_MODEL_D7\nFILEFORMAT_XML.CWS\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_60\nLiftSpeed_60\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\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_WANHAO\nPRINTER_MODEL_D7\nFILEFORMAT_XML.CWS\n\nSTART_CUSTOM_VALUES\nBottomWaitBeforeCure_3\nWaitBeforeCure_2.5\nBottomWaitAfterCure_3\nWaitAfterCure_1\nBottomLiftHeight_5\nLiftHeight_5\nBottomLiftSpeed_60\nLiftSpeed_60\nBottomWaitAfterLift_0\nWaitAfterLift_0\nRetractSpeed_150\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
+4 -4
View File
@@ -18,7 +18,6 @@ using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
using UVtools.Core.GCode;
using UVtools.Core.Operations;
@@ -310,8 +309,8 @@ namespace UVtools.Core.FileFormats
public override PrintParameterModifier[] PrintParameterModifiers { get; } = {
PrintParameterModifier.BottomLayerCount,
PrintParameterModifier.BottomLightOffDelay,
PrintParameterModifier.LightOffDelay,
//PrintParameterModifier.BottomLightOffDelay,
//PrintParameterModifier.LightOffDelay,
PrintParameterModifier.BottomWaitTimeBeforeCure,
PrintParameterModifier.WaitTimeBeforeCure,
@@ -347,7 +346,7 @@ namespace UVtools.Core.FileFormats
PrintParameterModifier.LightPWM,
};
public override System.Drawing.Size[] ThumbnailsOriginalSize { get; } = null;
public override System.Drawing.Size[] ThumbnailsOriginalSize => null;
public override uint ResolutionX
{
@@ -542,6 +541,7 @@ namespace UVtools.Core.FileFormats
{
GCode = new GCodeBuilder
{
SyncMovementsWithDelay = true,
UseComments = true,
GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial,
GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute,
+46 -4
View File
@@ -1294,13 +1294,31 @@ namespace UVtools.Core.FileFormats
public override float BottomLightOffDelay
{
get => PrintParametersSettings.BottomLightOffDelay;
set => base.BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay = (float)Math.Round(value, 2);
set
{
base.BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay = (float) Math.Round(value, 2);
if (HeaderSettings.Version >= 4 && value > 0)
{
WaitTimeBeforeCure = 0;
WaitTimeAfterCure = 0;
WaitTimeAfterLift = 0;
}
}
}
public override float LightOffDelay
{
get => PrintParametersSettings.LightOffDelay;
set => base.LightOffDelay = HeaderSettings.LightOffDelay = PrintParametersSettings.LightOffDelay = (float)Math.Round(value, 2);
set
{
base.LightOffDelay = HeaderSettings.LightOffDelay = PrintParametersSettings.LightOffDelay = (float) Math.Round(value, 2);
if (HeaderSettings.Version >= 4 && value > 0)
{
WaitTimeBeforeCure = 0;
WaitTimeAfterCure = 0;
WaitTimeAfterLift = 0;
}
}
}
public override float BottomWaitTimeBeforeCure => WaitTimeBeforeCure;
@@ -1309,8 +1327,22 @@ namespace UVtools.Core.FileFormats
get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.RestTimeAfterRetract : 0;
set
{
if (HeaderSettings.Version < 4) return;
if (HeaderSettings.Version < 4)
{
if (value > 0)
{
SetBottomLightOffDelay(value);
SetNormalLightOffDelay(value);
}
return;
}
base.WaitTimeBeforeCure = SlicerInfoSettings.RestTimeAfterRetract = PrintParametersV4Settings.RestTimeAfterRetract = (float)Math.Round(value, 2);
if (value > 0)
{
BottomLightOffDelay = 0;
LightOffDelay = 0;
}
}
}
@@ -1327,7 +1359,12 @@ namespace UVtools.Core.FileFormats
set
{
if (HeaderSettings.Version < 4) return;
base.WaitTimeAfterCure = PrintParametersV4Settings.RestTimeBeforeLift = (float)Math.Round(value, 2);
base.WaitTimeAfterCure = PrintParametersV4Settings.RestTimeBeforeLift = (float) Math.Round(value, 2);
if (value > 0)
{
BottomLightOffDelay = 0;
LightOffDelay = 0;
}
}
}
@@ -1369,6 +1406,11 @@ namespace UVtools.Core.FileFormats
{
if (HeaderSettings.Version < 4) return;
base.WaitTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift2 = PrintParametersV4Settings.RestTimeAfterLift = (float)Math.Round(value, 2);
if (value > 0)
{
BottomLightOffDelay = 0;
LightOffDelay = 0;
}
}
}
+2 -2
View File
@@ -1079,12 +1079,12 @@ namespace UVtools.Core.FileFormats
if (CanUseBottomExposureTime)
{
str += ExposureTime.ToString(CultureInfo.InvariantCulture);
str += BottomExposureTime.ToString(CultureInfo.InvariantCulture);
}
if (CanUseExposureTime)
{
if (!string.IsNullOrEmpty(str)) str += '/';
str += BottomExposureTime.ToString(CultureInfo.InvariantCulture);
str += ExposureTime.ToString(CultureInfo.InvariantCulture);
}
if (!string.IsNullOrEmpty(str)) str += 's';
+184 -104
View File
@@ -19,6 +19,7 @@ using Org.BouncyCastle.Asn1.Cms;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
using UVtools.Core.Operations;
namespace UVtools.Core.GCode
{
@@ -98,12 +99,14 @@ namespace UVtools.Core.GCode
#region Members
private readonly StringBuilder _gcode = new();
private bool _useTailComma = true;
private bool _useComments = true;
private GCodePositioningTypes _gCodePositioningType = GCodePositioningTypes.Absolute;
private GCodeTimeUnits _gCodeTimeUnit = GCodeTimeUnits.Milliseconds;
private GCodeSpeedUnits _gCodeSpeedUnit = GCodeSpeedUnits.MillimetersPerMinute;
private GCodeShowImageTypes _gCodeShowImageType = GCodeShowImageTypes.FilenameNonZeroPNG;
private bool _syncMovementsWithDelay;
private bool _useTailComma = true;
private bool _useComments = true;
private ushort _maxLedPower = byte.MaxValue;
private uint _lineCount;
private GCodeMoveCommands _layerMoveCommand;
@@ -149,6 +152,12 @@ namespace UVtools.Core.GCode
set => RaiseAndSetIfChanged(ref _endGCodeMoveCommand, value);
}
public bool SyncMovementsWithDelay
{
get => _syncMovementsWithDelay;
set => RaiseAndSetIfChanged(ref _syncMovementsWithDelay, value);
}
public bool UseTailComma
{
get => _useTailComma;
@@ -384,12 +393,12 @@ namespace UVtools.Core.GCode
AppendMoveG1(z, feedRate);
}
public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0)
public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
if (_layerMoveCommand == GCodeMoveCommands.G0)
AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract);
AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
else
AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract);
AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
}
@@ -399,10 +408,17 @@ namespace UVtools.Core.GCode
AppendLine(CommandMoveG0, z, feedRate);
}
public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0)
public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
if (upZ == 0 || upFeedRate <= 0) return;
AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
if (waitAfterLift > 0)
{
@@ -412,6 +428,13 @@ namespace UVtools.Core.GCode
if (downZ != 0 && downFeedRate > 0)
{
AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate);
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
}
if (waitAfterRetract > 0)
@@ -426,10 +449,20 @@ namespace UVtools.Core.GCode
AppendLine(CommandMoveG1, z, feedRate);
}
public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0)
public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
{
if (upZ == 0 || upFeedRate <= 0) return;
AppendLineOverrideComment(CommandMoveG1, "Lift Z", upZ, upFeedRate); // Z Lift
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
if (seconds > layer.WaitTimeAfterLift) // Fix if wait time already include this
{
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
}
if (waitAfterLift > 0)
{
@@ -439,6 +472,16 @@ namespace UVtools.Core.GCode
if (downZ != 0 && downFeedRate > 0)
{
AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate);
if (_syncMovementsWithDelay && layer is not null)
{
// Finish this
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
if (seconds > layer.WaitTimeBeforeCure) // Fix if wait time already include this
{
var time = ConvertFromSeconds(seconds);
AppendWaitG4($"0{time}", "Sync movement");
}
}
}
if (waitAfterRetract > 0)
@@ -453,6 +496,13 @@ namespace UVtools.Core.GCode
AppendLineOverrideComment(CommandWaitG4, comment, time);
}
public void AppendWaitG4(string timeStr, string comment = null)
{
if (!float.TryParse(timeStr, out var time)) return;
if (time < 0) return;
AppendLineOverrideComment(CommandWaitG4, comment, timeStr);
}
public void AppendTurnLightM106(ushort value)
{
AppendLineOverrideComment(CommandTurnLEDM106, "Turn LED " + (value == 0 ? "OFF" : "ON"), value);
@@ -560,7 +610,7 @@ namespace UVtools.Core.GCode
if (liftHeight > 0 && liftZPosAbs > layer.PositionZ)
{
AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift);
AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift, 0, layer);
}
else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position
{
@@ -675,7 +725,8 @@ namespace UVtools.Core.GCode
string line;
while ((line = reader.ReadLine()) != null)
{
if(string.IsNullOrWhiteSpace(line)) continue;
line = line.Trim();
if (string.IsNullOrWhiteSpace(line)) continue;
// Search for and switch position type when needed
if (line.StartsWith(CommandPositioningAbsoluteG90.Command))
@@ -690,145 +741,174 @@ namespace UVtools.Core.GCode
continue;
}
var match = Regex.Match(line, CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(@"(\d+)")), RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2) // Begin new layer
Match match = null;
// Display image
if (line.StartsWith(CommandShowImageM6054.Command))
{
var layerIndex = uint.Parse(match.Groups[1].Value);
if (_gCodeShowImageType is GCodeShowImageTypes.FilenameNonZeroPNG or GCodeShowImageTypes.LayerIndexNonZero) layerIndex--;
if (layerIndex > slicerFile.LayerCount)
match = Regex.Match(line,
CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(@"(\d+)")),
RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2) // Begin new layer
{
throw new FileLoadException($"GCode parser detected the layer {layerIndex}, but the file was sliced to {slicerFile.LayerCount} layers.", slicerFile.FileFullPath);
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;
}
// 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)
if (line.StartsWith(CommandMoveG0.Command) || line.StartsWith(CommandMoveG1.Command))
{
float pos = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
float speed = ConvertToMillimetersPerMinute(float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture));
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 (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now
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.PositionZ = pos;
layerBlock.LiftHeight = Layer.RoundHeight(layerBlock.PositionZ.Value - pos);
layerBlock.PositionZ = positionZ = pos;
break;
case GCodePositioningTypes.Partial:
layerBlock.PositionZ = Layer.RoundHeight(positionZ + pos);
layerBlock.LiftHeight = layerBlock.PositionZ - positionZ;
layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + 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)
if (line.StartsWith(CommandWaitG4.Command))
{
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!
match = Regex.Match(line, CommandWaitG4.ToStringWithoutComments(@"(([0-9]*[.])?[0-9]+)"),
RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2)
{
layerBlock.WaitTimeAfterLift ??= 0;
layerBlock.WaitTimeAfterLift += ConvertToSeconds(waitTime);
continue;
}
if (_syncMovementsWithDelay && match.Groups[1].Value.StartsWith('0')) continue; // Sync movement delay, skip
if (!layerBlock.LightPWM.HasValue) // Before cure
{
layerBlock.WaitTimeBeforeCure ??= 0;
layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime);
continue;
}
var waitTime = float.Parse(match.Groups[1].Value);
if (layerBlock.IsExposing) // Must be exposure time, if not, don't blame me!
{
layerBlock.ExposureTime ??= 0;
layerBlock.ExposureTime += ConvertToSeconds(waitTime);
continue;
}
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.IsAfterLightOff)
{
if (!layerBlock.WaitTimeBeforeCure.HasValue) // Novamaker fix, delay on last line, broke logic but safer
if (!layerBlock.LightPWM.HasValue) // Before cure
{
layerBlock.WaitTimeBeforeCure ??= 0;
layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime);
continue;
}
else
if (layerBlock.IsExposing) // Must be exposure time, if not, don't blame me!
{
layerBlock.WaitTimeAfterCure ??= 0;
layerBlock.WaitTimeAfterCure += ConvertToSeconds(waitTime);
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;
}
continue;
}
// Check LightPWM
match = Regex.Match(line, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"), RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2)
if (line.StartsWith(CommandTurnLEDM106.Command))
{
byte pwm;
if (_maxLedPower == byte.MaxValue)
match = Regex.Match(line, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"),
RegexOptions.IgnoreCase);
if (match.Success && match.Groups.Count >= 2)
{
pwm = byte.Parse(match.Groups[1].Value);
}
else
{
ushort pwmValue = ushort.Parse(match.Groups[1].Value);
pwm = (byte)(pwmValue * byte.MaxValue / _maxLedPower);
}
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;
}
if (pwm == 0 && layerBlock.LightPWM.HasValue)
{
layerBlock.IsAfterLightOff = true;
}
else if (!layerBlock.IsAfterLightOff)
{
layerBlock.LightPWM = pwm;
}
continue;
continue;
}
}
}
+10
View File
@@ -8,6 +8,7 @@
using System;
using UVtools.Core.FileFormats;
using UVtools.Core.Operations;
namespace UVtools.Core.GCode
{
@@ -118,6 +119,15 @@ namespace UVtools.Core.GCode
layer.WaitTimeAfterLift = WaitTimeAfterLift ?? 0;
layer.RetractSpeed = RetractSpeed ?? SlicerFile.RetractSpeed;
layer.LightPWM = LightPWM ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
if (SlicerFile.GCode.SyncMovementsWithDelay) // Dirty fix of the value
{
var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, 1.5f);
if (syncTime < layer.WaitTimeBeforeCure)
{
layer.WaitTimeBeforeCure = (float) Math.Round(layer.WaitTimeBeforeCure - syncTime, 2);
}
}
}
}
}
+23 -18
View File
@@ -271,23 +271,35 @@ namespace UVtools.Core.Operations
_bottomWaitTime = bottomWaitTime;
}
public static decimal CalculateSeconds(decimal liftHeight, decimal liftSpeed, decimal retract, decimal waitTime = 0)
public static decimal CalculateSeconds(decimal liftHeight, decimal liftSpeed, decimal retractSpeed, decimal extraWaitTime = 0)
{
try
var time = extraWaitTime;
if (liftSpeed > 0)
{
return Math.Round(liftHeight / (liftSpeed / 60m) + liftHeight / (retract / 60m) + waitTime, 2);
time += liftHeight / (liftSpeed / 60m);
}
catch (Exception)
if (retractSpeed > 0)
{
return 0;
time += liftHeight / (retractSpeed / 60m);
}
return Math.Round(time, 2);
}
public static float CalculateSeconds(float liftHeight, float liftSpeed, float retract, float extraWaitTime = 0)
public static float CalculateSeconds(float liftHeight, float liftSpeed, float retractSpeed, float extraWaitTime = 0)
{
if (liftSpeed == 0 || retract == 0) return extraWaitTime;
return (float) Math.Round(liftHeight / (liftSpeed / 60f) + liftHeight / (retract / 60f) + extraWaitTime, 2);
var time = extraWaitTime;
if (liftSpeed > 0)
{
time += liftHeight / (liftSpeed / 60f);
}
if (retractSpeed > 0)
{
time += liftHeight / (retractSpeed / 60f);
}
return (float)Math.Round(time, 2);
}
public static uint CalculateMilliseconds(float liftHeight, float liftSpeed, float retract, float extraWaitTime = 0) =>
@@ -296,15 +308,8 @@ namespace UVtools.Core.Operations
public static float CalculateSecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0)
{
try
{
return (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2);
}
catch (Exception)
{
return 0;
}
if (liftSpeed <= 0) return extraWaitTime;
return (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2);
}
public static uint CalculateMillisecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0) =>
+1 -1
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>2.15.0</Version>
<Version>2.15.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
+36 -17
View File
@@ -1125,33 +1125,52 @@ namespace UVtools.WPF
SlicerFile.CanUseBottomLightOffDelay &&
(Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.BottomLightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero))
{
float lightOff = Settings.Automations.LightOffDelaySetMode switch
if (SlicerFile is ChituboxFile chituboxFile &&
chituboxFile.HeaderSettings.Version >= 4 &&
(chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0))
{
Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateBottomLightOffDelay((float) Settings.Automations.BottomLightOffDelay),
Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateBottomLightOffDelay(),
_ => 0
};
if (lightOff != SlicerFile.BottomLightOffDelay)
{
modified = true;
SlicerFile.BottomLightOffDelay = lightOff;
// Ignore this automation
}
else
{
float lightOff = Settings.Automations.LightOffDelaySetMode switch
{
Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateBottomLightOffDelay((float)Settings.Automations.BottomLightOffDelay),
Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateBottomLightOffDelay(),
_ => 0
};
if (lightOff != SlicerFile.BottomLightOffDelay)
{
modified = true;
SlicerFile.BottomLightOffDelay = lightOff;
}
}
}
if (Settings.Automations.LightOffDelaySetMode != Enumerations.LightOffDelaySetMode.NoAction &&
SlicerFile.CanUseLightOffDelay &&
(Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.LightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero))
{
float lightOff = Settings.Automations.LightOffDelaySetMode switch
if (SlicerFile is ChituboxFile chituboxFile &&
chituboxFile.HeaderSettings.Version >= 4 &&
(chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0))
{
Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateNormalLightOffDelay((float)Settings.Automations.LightOffDelay),
Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateNormalLightOffDelay(),
_ => 0
};
if (lightOff != SlicerFile.LightOffDelay)
// Ignore this automation
}
else
{
modified = true;
SlicerFile.LightOffDelay = lightOff;
float lightOff = Settings.Automations.LightOffDelaySetMode switch
{
Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateNormalLightOffDelay((float)Settings.Automations.LightOffDelay),
Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateNormalLightOffDelay(),
_ => 0
};
if (lightOff != SlicerFile.LightOffDelay)
{
modified = true;
SlicerFile.LightOffDelay = lightOff;
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<Version>2.15.0</Version>
<Version>2.15.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">