mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-09 01:52:32 +02:00
v2.18.0
- **Command line arguments:** - (Add) Convert files: UVtools.exe -c \<inputfile\> \<outputfile1/ext1\> [outputfile2/ext2] - (Add) Extract files: UVtools.exe -e \<inputfile\> [output_folder] - https://github.com/sn4k3/UVtools#command-line-arguments - **File formats:** - (Add) Implement TSMC (Two Stage Motor Control) for the supported formats - (Add) Implement 'Bottom retract speed' for the supported formats - (Add) LGS: Support for lgs120 and lg4k (#218) - (Add) CTB: Special/virtual file extensions .v2.ctb, .v3.ctb, .v4.ctb to force a convertion to the set version (2 to 4). The .ctb is Version 3 by default when creating/converting files - (Improvement) Better performance for file formats that decode images in sequential pixels groups - **GCode:** - (Improvement) Better parsing of the movements / lifts - (Improvement) Better handling of lifts performed after cure the layer - (Improvement) More fail-safe checks and sanitize of gcode while parsing - (Improvement) CTBv3: Enable per layer settings if disabled when fast save without reencode - (Upgrade) .NET from 5.0.8 to 5.0.9 - (Fix) PrusaSlicer printer: Longer Orange 4k with correct resolution and display size - (Fix) Odd error when changing properties too fast in multi-thread
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
@@ -390,12 +391,12 @@ namespace UVtools.Core.GCode
|
||||
AppendMoveG1(z, feedRate);
|
||||
}
|
||||
|
||||
public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
public void AppendLiftMoveGx(float upZ, float upFeedRate, float upZ2, float upFeedRate2, float downZ, float downFeedRate, float downZ2, float downFeedRate2, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
{
|
||||
if (_layerMoveCommand == GCodeMoveCommands.G0)
|
||||
AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
|
||||
AppendLiftMoveG0(upZ, upFeedRate, upZ2, upFeedRate2, downZ, downFeedRate, downZ2, downFeedRate2, waitAfterLift, waitAfterRetract, layer);
|
||||
else
|
||||
AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer);
|
||||
AppendLiftMoveG1(upZ, upFeedRate, upZ2, upFeedRate2, downZ, downFeedRate, downZ2, downFeedRate2, waitAfterLift, waitAfterRetract, layer);
|
||||
}
|
||||
|
||||
|
||||
@@ -405,14 +406,15 @@ namespace UVtools.Core.GCode
|
||||
AppendLine(CommandMoveG0, z, feedRate);
|
||||
}
|
||||
|
||||
public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
public void AppendLiftMoveG0(float upZ, float upFeedRate, float upZ2 = 0, float upFeedRate2 = 0, float downZ = 0, float downFeedRate = 0, float downZ2 = 0, float downFeedRate2 = 0, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
{
|
||||
if (upZ == 0 || upFeedRate <= 0) return;
|
||||
AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift
|
||||
if ((upZ == 0 || upFeedRate <= 0) && (upZ2 == 0 || upFeedRate2 <= 0)) return;
|
||||
|
||||
if(upZ > 0 && upFeedRate > 0) AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift
|
||||
if(upZ2 > 0 && upFeedRate2 > 0) AppendLineOverrideComment(CommandMoveG0, "Z Lift (2)", upZ2, upFeedRate2); // Z Lift2
|
||||
if (_syncMovementsWithDelay && layer is not null)
|
||||
{
|
||||
// Finish this
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
@@ -422,13 +424,17 @@ namespace UVtools.Core.GCode
|
||||
AppendWaitG4(waitAfterLift, "Wait after lift");
|
||||
}
|
||||
|
||||
if (downZ != 0 && downFeedRate > 0)
|
||||
if ((downZ != 0 && downFeedRate > 0) || (downZ2 != 0 && downFeedRate2 > 0))
|
||||
{
|
||||
AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate);
|
||||
if(downZ2 != 0 && downFeedRate2 > 0)
|
||||
AppendLineOverrideComment(CommandMoveG0, "Retract (2)", downZ2, downFeedRate2);
|
||||
if (downZ != 0 && downFeedRate > 0)
|
||||
AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate);
|
||||
|
||||
if (_syncMovementsWithDelay && layer is not null)
|
||||
{
|
||||
// Finish this
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
@@ -446,19 +452,17 @@ namespace UVtools.Core.GCode
|
||||
AppendLine(CommandMoveG1, z, feedRate);
|
||||
}
|
||||
|
||||
public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
public void AppendLiftMoveG1(float upZ, float upFeedRate, float upZ2 = 0, float upFeedRate2 = 0, float downZ = 0, float downFeedRate = 0, float downZ2 = 0, float downFeedRate2 = 0, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null)
|
||||
{
|
||||
if (upZ == 0 || upFeedRate <= 0) return;
|
||||
AppendLineOverrideComment(CommandMoveG1, "Lift Z", upZ, upFeedRate); // Z Lift
|
||||
if ((upZ == 0 || upFeedRate <= 0) && (upZ2 == 0 || upFeedRate2 <= 0)) return;
|
||||
|
||||
if (upZ > 0 && upFeedRate > 0) AppendLineOverrideComment(CommandMoveG1, "Z Lift", upZ, upFeedRate); // Z Lift
|
||||
if (upZ2 > 0 && upFeedRate2 > 0) AppendLineOverrideComment(CommandMoveG1, "Z Lift (2)", upZ2, upFeedRate2); // Z Lift2
|
||||
if (_syncMovementsWithDelay && layer is not null)
|
||||
{
|
||||
// Finish this
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f);
|
||||
if (seconds > layer.WaitTimeAfterLift) // Fix if wait time already include this
|
||||
{
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer, 0.75f);
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
|
||||
if (waitAfterLift > 0)
|
||||
@@ -466,18 +470,19 @@ namespace UVtools.Core.GCode
|
||||
AppendWaitG4(waitAfterLift, "Wait after lift");
|
||||
}
|
||||
|
||||
if (downZ != 0 && downFeedRate > 0)
|
||||
if ((downZ != 0 && downFeedRate > 0) || (downZ2 != 0 && downFeedRate2 > 0))
|
||||
{
|
||||
AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate);
|
||||
if (downZ2 != 0 && downFeedRate2 > 0)
|
||||
AppendLineOverrideComment(CommandMoveG1, "Retract (2)", downZ2, downFeedRate2);
|
||||
if (downZ != 0 && downFeedRate > 0)
|
||||
AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate);
|
||||
|
||||
if (_syncMovementsWithDelay && layer is not null)
|
||||
{
|
||||
// Finish this
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f);
|
||||
if (seconds > layer.WaitTimeBeforeCure) // Fix if wait time already include this
|
||||
{
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.RetractHeight, layer.RetractSpeed, layer.RetractHeight2, layer.RetractSpeed2, 0.75f);
|
||||
var time = ConvertFromSeconds(seconds);
|
||||
AppendWaitG4($"0{time}", "Sync movement");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +574,7 @@ namespace UVtools.Core.GCode
|
||||
|
||||
float lastZPosition = 0;
|
||||
|
||||
// Defaults for: Absolute, mm/m and s
|
||||
// Defaults for: Absolute, mm/min and s
|
||||
for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++)
|
||||
{
|
||||
var layer = slicerFile[layerIndex];
|
||||
@@ -578,23 +583,64 @@ namespace UVtools.Core.GCode
|
||||
float exposureTime = ConvertFromSeconds(layer.ExposureTime);
|
||||
float waitAfterCure = ConvertFromSeconds(layer.WaitTimeAfterCure);
|
||||
float liftHeight = layer.LiftHeight;
|
||||
float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
|
||||
float liftZPosAbs = liftZPos;
|
||||
//float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
|
||||
//float liftZPosAbs = liftZPos;
|
||||
float liftSpeed = ConvertFromMillimetersPerMinute(layer.LiftSpeed);
|
||||
float liftHeight2 = layer.LiftHeight2;
|
||||
float liftSpeed2 = ConvertFromMillimetersPerMinute(layer.LiftSpeed2);
|
||||
float waitAfterLift = ConvertFromSeconds(layer.WaitTimeAfterLift);
|
||||
float retractPos = layer.PositionZ;
|
||||
float retractHeight = layer.RetractHeight;
|
||||
float retractSpeed = ConvertFromMillimetersPerMinute(layer.RetractSpeed);
|
||||
float retractHeight2 = layer.RetractHeight2;
|
||||
float retractSpeed2 = ConvertFromMillimetersPerMinute(layer.RetractSpeed2);
|
||||
float liftHeightTotal = layer.LiftHeightTotal;
|
||||
ushort pwmValue = layer.LightPWM;
|
||||
if (_maxLedPower != byte.MaxValue)
|
||||
{
|
||||
pwmValue = (ushort)(_maxLedPower * pwmValue / byte.MaxValue);
|
||||
}
|
||||
|
||||
float liftPos = 0;
|
||||
float liftPos2 = 0;
|
||||
float retractPos = 0;
|
||||
float retractPos2 = 0;
|
||||
|
||||
switch (GCodePositioningType)
|
||||
{
|
||||
case GCodePositioningTypes.Absolute:
|
||||
var absLiftPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
|
||||
var absLiftPos2 = Layer.RoundHeight(absLiftPos + liftHeight2);
|
||||
var absRetractPos2 = Layer.RoundHeight(absLiftPos2 - retractHeight2);
|
||||
if (liftHeight > 0) liftPos = absLiftPos;
|
||||
if (liftHeight2 > 0) liftPos2 = absLiftPos2;
|
||||
if (retractHeight2 > 0) retractPos2 = absRetractPos2;
|
||||
if (retractHeight > 0) retractPos = layer.PositionZ;
|
||||
if (retractPos > 0 && retractPos > retractPos2) retractPos2 = 0; // Fail-safe
|
||||
break;
|
||||
case GCodePositioningTypes.Partial:
|
||||
liftZPos = liftHeight;
|
||||
retractPos = Layer.RoundHeight(layer.PositionZ - lastZPosition - liftHeight);
|
||||
var partialLiftPos = Layer.RoundHeight(layer.PositionZ - lastZPosition + liftHeight);
|
||||
var partialLiftPosTotal = Layer.RoundHeight(partialLiftPos + liftHeight2);
|
||||
var partialRetractPosTotal = Layer.RoundHeight(partialLiftPos + liftHeight2);
|
||||
if (liftHeight > 0)
|
||||
{
|
||||
liftPos = partialLiftPos;
|
||||
if (liftHeight2 > 0) liftPos2 = liftHeight2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (liftHeight2 > 0) liftPos2 = Layer.RoundHeight(partialLiftPos + liftHeight2);
|
||||
}
|
||||
|
||||
if (retractHeight2 > 0) retractPos2 = -retractHeight2;
|
||||
if (retractHeight > 0) retractPos = -retractHeight;
|
||||
|
||||
// Assert
|
||||
if (Layer.RoundHeight(Math.Abs(retractPos + retractPos2)) != liftHeightTotal) // Fail-safe
|
||||
{
|
||||
retractPos2 = 0;
|
||||
retractPos = -liftHeightTotal;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -605,9 +651,9 @@ namespace UVtools.Core.GCode
|
||||
AppendShowImageM6054(GetShowImageString(layerIndex));
|
||||
//}
|
||||
|
||||
if (liftHeight > 0 && liftZPosAbs > layer.PositionZ)
|
||||
if (liftHeightTotal > 0 && Layer.RoundHeight(liftHeightTotal + layer.PositionZ) > layer.PositionZ)
|
||||
{
|
||||
AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift, 0, layer);
|
||||
AppendLiftMoveGx(liftPos, liftSpeed, liftPos2, liftSpeed2, retractPos, retractSpeed, retractPos2, retractSpeed2, waitAfterLift, 0, layer);
|
||||
}
|
||||
else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position
|
||||
{
|
||||
@@ -759,10 +805,7 @@ namespace UVtools.Core.GCode
|
||||
}
|
||||
|
||||
// Propagate values before switch to the new layer
|
||||
layerBlock.PositionZ ??= positionZ;
|
||||
layerBlock.SetLayer();
|
||||
|
||||
layerBlock.Init();
|
||||
layerBlock.SetLayer(true);
|
||||
layerBlock.LayerIndex = layerIndex;
|
||||
|
||||
continue;
|
||||
@@ -782,12 +825,16 @@ namespace UVtools.Core.GCode
|
||||
RegexOptions.IgnoreCase);
|
||||
match = moveG0Regex.Success && moveG0Regex.Groups.Count >= 2 ? moveG0Regex : moveG1Regex;
|
||||
|
||||
if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed.HasValue)
|
||||
if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed2.HasValue && layerBlock.LightOffCount < 2)
|
||||
{
|
||||
float pos = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
float speed = ConvertToMillimetersPerMinute(float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture));
|
||||
|
||||
if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now
|
||||
|
||||
layerBlock.Movements.Add(new(pos, speed));
|
||||
layerBlock.AssignMovements(positionType);
|
||||
|
||||
/*if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now
|
||||
{
|
||||
switch (positionType)
|
||||
{
|
||||
@@ -817,7 +864,7 @@ namespace UVtools.Core.GCode
|
||||
layerBlock.LiftHeight = layerBlock.PositionZ - positionZ;
|
||||
layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + pos);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -897,7 +944,7 @@ namespace UVtools.Core.GCode
|
||||
|
||||
if (pwm == 0 && layerBlock.LightPWM.HasValue)
|
||||
{
|
||||
layerBlock.IsAfterLightOff = true;
|
||||
layerBlock.LightOffCount++;
|
||||
}
|
||||
else if (!layerBlock.IsAfterLightOff)
|
||||
{
|
||||
@@ -910,7 +957,6 @@ namespace UVtools.Core.GCode
|
||||
}
|
||||
|
||||
// Propagate values of left over layer
|
||||
layerBlock.PositionZ ??= positionZ;
|
||||
layerBlock.SetLayer();
|
||||
|
||||
|
||||
@@ -1016,36 +1062,7 @@ namespace UVtools.Core.GCode
|
||||
|
||||
if (rebuildGlobalTable)
|
||||
{
|
||||
slicerFile.SuppressRebuildPropertiesWork(() =>
|
||||
{
|
||||
var bottomLayer = slicerFile.FirstLayer;
|
||||
if (bottomLayer is not null)
|
||||
{
|
||||
if (bottomLayer.LightOffDelay > 0) slicerFile.BottomLightOffDelay = bottomLayer.LightOffDelay;
|
||||
if (bottomLayer.WaitTimeBeforeCure > 0) slicerFile.BottomWaitTimeBeforeCure = bottomLayer.WaitTimeBeforeCure;
|
||||
if (bottomLayer.ExposureTime > 0) slicerFile.BottomExposureTime = bottomLayer.ExposureTime;
|
||||
if (bottomLayer.WaitTimeAfterCure > 0) slicerFile.BottomWaitTimeAfterCure = bottomLayer.WaitTimeAfterCure;
|
||||
if (bottomLayer.LiftHeight > 0) slicerFile.BottomLiftHeight = bottomLayer.LiftHeight;
|
||||
if (bottomLayer.LiftSpeed > 0) slicerFile.BottomLiftSpeed = bottomLayer.LiftSpeed;
|
||||
if (bottomLayer.WaitTimeAfterLift > 0) slicerFile.BottomWaitTimeAfterLift = bottomLayer.WaitTimeAfterLift;
|
||||
if (bottomLayer.RetractSpeed > 0) slicerFile.RetractSpeed = bottomLayer.RetractSpeed;
|
||||
if (bottomLayer.LightPWM > 0) slicerFile.BottomLightPWM = bottomLayer.LightPWM;
|
||||
}
|
||||
|
||||
var normalLayer = slicerFile.LastLayer;
|
||||
if (normalLayer is not null)
|
||||
{
|
||||
if (normalLayer.LightOffDelay > 0) slicerFile.LightOffDelay = normalLayer.LightOffDelay;
|
||||
if (normalLayer.WaitTimeBeforeCure > 0) slicerFile.WaitTimeBeforeCure = normalLayer.WaitTimeBeforeCure;
|
||||
if (normalLayer.ExposureTime > 0) slicerFile.ExposureTime = normalLayer.ExposureTime;
|
||||
if (normalLayer.WaitTimeAfterCure > 0) slicerFile.WaitTimeAfterCure = normalLayer.WaitTimeAfterCure;
|
||||
if (normalLayer.LiftHeight > 0) slicerFile.LiftHeight = normalLayer.LiftHeight;
|
||||
if (normalLayer.LiftSpeed > 0) slicerFile.LiftSpeed = normalLayer.LiftSpeed;
|
||||
if (normalLayer.WaitTimeAfterLift > 0) slicerFile.WaitTimeAfterLift = normalLayer.WaitTimeAfterLift;
|
||||
if (normalLayer.RetractSpeed > 0) slicerFile.RetractSpeed = normalLayer.RetractSpeed;
|
||||
if (normalLayer.LightPWM > 0) slicerFile.LightPWM = normalLayer.LightPWM;
|
||||
}
|
||||
});
|
||||
slicerFile.UpdateGlobalPropertiesFromLayers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UVtools.Core.FileFormats;
|
||||
using UVtools.Core.Operations;
|
||||
|
||||
@@ -14,13 +15,18 @@ namespace UVtools.Core.GCode
|
||||
{
|
||||
public class GCodeLayer
|
||||
{
|
||||
private float? _positionZ;
|
||||
private float? _waitTimeBeforeCure;
|
||||
private float? _exposureTime;
|
||||
private float? _waitTimeAfterCure;
|
||||
private float? _liftHeight;
|
||||
private float? _liftSpeed;
|
||||
private float? _liftHeight2;
|
||||
private float? _liftSpeed2;
|
||||
private float? _waitTimeAfterLift;
|
||||
private float? _retractSpeed;
|
||||
private float? _retractHeight2;
|
||||
private float? _retractSpeed2;
|
||||
|
||||
public enum GCodeLastParsedLine : byte
|
||||
{
|
||||
@@ -30,8 +36,16 @@ namespace UVtools.Core.GCode
|
||||
public bool IsValid => LayerIndex.HasValue;
|
||||
|
||||
public FileFormat SlicerFile { get; }
|
||||
public List<(float Pos, float Speed)> Movements = new();
|
||||
public uint? LayerIndex { get; set; }
|
||||
public float? PositionZ { get; set; }
|
||||
|
||||
public float? PositionZ
|
||||
{
|
||||
get => _positionZ;
|
||||
set => _positionZ = value;
|
||||
}
|
||||
|
||||
public float PreviousPositionZ { get; set; }
|
||||
|
||||
public float? WaitTimeBeforeCure
|
||||
{
|
||||
@@ -54,7 +68,7 @@ namespace UVtools.Core.GCode
|
||||
public float? LiftHeight
|
||||
{
|
||||
get => _liftHeight;
|
||||
set => _liftHeight = value is null ? null : (float)Math.Round(value.Value, 2);
|
||||
set => _liftHeight = value is null ? null : Layer.RoundHeight(value.Value);
|
||||
}
|
||||
|
||||
public float? LiftSpeed
|
||||
@@ -63,6 +77,20 @@ namespace UVtools.Core.GCode
|
||||
set => _liftSpeed = value is null ? null : (float)Math.Round(value.Value, 2);
|
||||
}
|
||||
|
||||
public float LiftHeightTotal => Layer.RoundHeight((LiftHeight ?? 0) + (LiftHeight2 ?? 0));
|
||||
|
||||
public float? LiftHeight2
|
||||
{
|
||||
get => _liftHeight2;
|
||||
set => _liftHeight2 = value is null ? null : Layer.RoundHeight(value.Value);
|
||||
}
|
||||
|
||||
public float? LiftSpeed2
|
||||
{
|
||||
get => _liftSpeed2;
|
||||
set => _liftSpeed2 = value is null ? null : (float)Math.Round(value.Value, 2);
|
||||
}
|
||||
|
||||
public float? WaitTimeAfterLift
|
||||
{
|
||||
get => _waitTimeAfterLift;
|
||||
@@ -75,11 +103,25 @@ namespace UVtools.Core.GCode
|
||||
set => _retractSpeed = value is null ? null : (float)Math.Round(value.Value, 2);
|
||||
}
|
||||
|
||||
public float? RetractHeight2
|
||||
{
|
||||
get => _retractHeight2;
|
||||
set => _retractHeight2 = value is null ? null : Layer.RoundHeight(value.Value);
|
||||
}
|
||||
|
||||
public float? RetractSpeed2
|
||||
{
|
||||
get => _retractSpeed2;
|
||||
set => _retractSpeed2 = value is null ? null : (float)Math.Round(value.Value, 2);
|
||||
}
|
||||
|
||||
public byte? LightPWM { get; set; }
|
||||
|
||||
public bool IsExposing => LightPWM.HasValue && !IsAfterLightOff;
|
||||
public bool IsExposed => LightPWM.HasValue && IsAfterLightOff;
|
||||
|
||||
public bool IsAfterLightOff { get; set; }
|
||||
public byte LightOffCount { get; set; }
|
||||
public bool IsAfterLightOff => LightOffCount > 0;
|
||||
|
||||
public GCodeLayer(FileFormat slicerFile)
|
||||
{
|
||||
@@ -88,6 +130,9 @@ namespace UVtools.Core.GCode
|
||||
|
||||
public void Init()
|
||||
{
|
||||
PreviousPositionZ = PositionZ ?? 0;
|
||||
|
||||
Movements.Clear();
|
||||
LayerIndex = null;
|
||||
PositionZ = null;
|
||||
WaitTimeBeforeCure = null;
|
||||
@@ -95,39 +140,142 @@ namespace UVtools.Core.GCode
|
||||
WaitTimeAfterCure = null;
|
||||
LiftHeight = null;
|
||||
LiftSpeed = null;
|
||||
LiftHeight2 = null;
|
||||
LiftSpeed2 = null;
|
||||
WaitTimeAfterLift = null;
|
||||
RetractSpeed = null;
|
||||
RetractHeight2 = null;
|
||||
RetractSpeed2 = null;
|
||||
LightPWM = null;
|
||||
IsAfterLightOff = false;
|
||||
LightOffCount = 0;
|
||||
}
|
||||
|
||||
public void AssignMovements(GCodeBuilder.GCodePositioningTypes positionType)
|
||||
{
|
||||
if (Movements.Count == 0) return;
|
||||
var currentZ = PreviousPositionZ;
|
||||
|
||||
PositionZ = null;
|
||||
LiftHeight = null;
|
||||
LiftSpeed = null;
|
||||
LiftHeight2 = null;
|
||||
LiftSpeed2 = null;
|
||||
RetractSpeed = null;
|
||||
RetractHeight2 = null;
|
||||
RetractSpeed2 = null;
|
||||
|
||||
for (int i = 0; i < Movements.Count; i++)
|
||||
{
|
||||
var (pos, speed) = Movements[i];
|
||||
float heightRaw;
|
||||
switch (positionType)
|
||||
{
|
||||
case GCodeBuilder.GCodePositioningTypes.Absolute:
|
||||
heightRaw = Layer.RoundHeight(pos - currentZ);
|
||||
currentZ = pos;
|
||||
break;
|
||||
case GCodeBuilder.GCodePositioningTypes.Partial:
|
||||
heightRaw = pos;
|
||||
currentZ = Layer.RoundHeight(currentZ + pos);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(positionType));
|
||||
}
|
||||
|
||||
// Fail-safe check
|
||||
if (currentZ < PreviousPositionZ)
|
||||
throw new NotSupportedException("GCode parsing error: Attempting to crash the print on the LCD with negative position.\n" +
|
||||
"Do not attempt to print this file!");
|
||||
|
||||
// Is position Z
|
||||
if (i == Movements.Count - 1)
|
||||
{
|
||||
PositionZ = currentZ;
|
||||
if (LiftHeight.HasValue) RetractSpeed = speed; // A lift exists, set to retract speed of this move
|
||||
continue;
|
||||
}
|
||||
|
||||
if (heightRaw == 0) continue;
|
||||
var height = Math.Abs(heightRaw);
|
||||
|
||||
if (heightRaw > 0) // Is a lift
|
||||
{
|
||||
if (!LiftHeight.HasValue)
|
||||
{
|
||||
LiftHeight = height;
|
||||
LiftSpeed = speed;
|
||||
continue;
|
||||
}
|
||||
|
||||
LiftHeight2 ??= 0;
|
||||
LiftHeight2 += height;
|
||||
LiftSpeed2 = speed;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!LiftHeight.HasValue) continue; // Fail-safe: Retract without a lift? Skip
|
||||
|
||||
// Is a extra retract (2)
|
||||
RetractHeight2 ??= 0;
|
||||
RetractHeight2 += height;
|
||||
RetractSpeed2 = speed;
|
||||
}
|
||||
|
||||
if (Movements.Count == 1) // Only 1 move, this is the PositionZ only
|
||||
{
|
||||
LiftSpeed = Movements[0].Speed;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize
|
||||
if (PositionZ.HasValue && LiftHeight.HasValue && !IsExposed) // Lift before exposure order, need to remove layer height as offset
|
||||
{
|
||||
var liftHeight = Layer.RoundHeight(LiftHeight.Value - (PositionZ.Value - PreviousPositionZ));
|
||||
if(liftHeight <= 0) return; // Something not right or not the correct moment, skip
|
||||
LiftHeight = liftHeight;
|
||||
}
|
||||
|
||||
if (LiftHeight.HasValue && RetractHeight2.HasValue) // Sanitize RetractHeight2 value
|
||||
{
|
||||
RetractHeight2 = Math.Clamp(RetractHeight2.Value, 0, LiftHeightTotal);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set gathered data to the layer
|
||||
/// </summary>
|
||||
public void SetLayer()
|
||||
public void SetLayer(bool reinit = false)
|
||||
{
|
||||
if (!IsValid) return;
|
||||
uint layerIndex = LayerIndex.Value;
|
||||
var layer = SlicerFile[layerIndex];
|
||||
|
||||
if(PositionZ.HasValue) layer.PositionZ = PositionZ.Value;
|
||||
if (!PositionZ.HasValue) PositionZ = PreviousPositionZ;
|
||||
layer.PositionZ = PositionZ.Value;
|
||||
layer.WaitTimeBeforeCure = WaitTimeBeforeCure ?? 0;
|
||||
layer.ExposureTime = ExposureTime ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
|
||||
layer.WaitTimeAfterCure = WaitTimeAfterCure ?? 0;
|
||||
layer.LiftHeight = LiftHeight ?? 0;
|
||||
layer.LiftSpeed = LiftSpeed ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
|
||||
layer.LiftHeight2 = LiftHeight2 ?? 0;
|
||||
layer.LiftSpeed2 = LiftSpeed2 ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
|
||||
layer.WaitTimeAfterLift = WaitTimeAfterLift ?? 0;
|
||||
layer.RetractSpeed = RetractSpeed ?? SlicerFile.RetractSpeed;
|
||||
layer.RetractSpeed = RetractSpeed ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed, SlicerFile.RetractSpeed);
|
||||
layer.RetractHeight2 = RetractHeight2 ?? 0;
|
||||
layer.RetractSpeed2 = RetractSpeed2 ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomRetractSpeed2, SlicerFile.RetractSpeed2);
|
||||
layer.LightPWM = LightPWM ?? 0;//SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
|
||||
|
||||
if (SlicerFile.GCode.SyncMovementsWithDelay) // Dirty fix of the value
|
||||
{
|
||||
var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, 1.5f);
|
||||
var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer, 1.5f);
|
||||
if (syncTime < layer.WaitTimeBeforeCure)
|
||||
{
|
||||
layer.WaitTimeBeforeCure = (float) Math.Round(layer.WaitTimeBeforeCure - syncTime, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if(reinit) Init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user