mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-10 10:32:32 +02:00
1e787ba11b
- Issues: - (Add) Suction cups: Add a auto repair feature for this issues by drill a vertical vent hole (#296) - (Add) Layer issue track bar: Colorize the issue tracker map with it own colors (Configurable) - (Add) Allow to group issues by type and/or layer - (Improvement) Order issues by area in descending order - (Improvement) Always bring the selected issue into view on the list - (Fix) When manually removing a issue from the list, it will no longer reselect other and make the user lost track of the remove issue - (Fix) Allow to ignore all issue type - (Fix) Material ml calculation was calculating a bad value for PhotonWorkshop files
292 lines
10 KiB
C#
292 lines
10 KiB
C#
/*
|
|
* GNU AFFERO GENERAL PUBLIC LICENSE
|
|
* Version 3, 19 November 2007
|
|
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
* Everyone is permitted to copy and distribute verbatim copies
|
|
* of this license document, but changing it is not allowed.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UVtools.Core.FileFormats;
|
|
using UVtools.Core.Layers;
|
|
using UVtools.Core.Operations;
|
|
|
|
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
|
|
{
|
|
LayerIndex,
|
|
}
|
|
|
|
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 => _positionZ;
|
|
set => _positionZ = value;
|
|
}
|
|
|
|
public float PreviousPositionZ { get; set; }
|
|
|
|
public float? WaitTimeBeforeCure
|
|
{
|
|
get => _waitTimeBeforeCure;
|
|
set => _waitTimeBeforeCure = value is null ? null : (float)Math.Round(value.Value, 2);
|
|
}
|
|
|
|
public float? ExposureTime
|
|
{
|
|
get => _exposureTime;
|
|
set => _exposureTime = value is null ? null : (float)Math.Round(value.Value, 2);
|
|
}
|
|
|
|
public float? WaitTimeAfterCure
|
|
{
|
|
get => _waitTimeAfterCure;
|
|
set => _waitTimeAfterCure = value is null ? null : (float)Math.Round(value.Value, 2);
|
|
}
|
|
|
|
public float? LiftHeight
|
|
{
|
|
get => _liftHeight;
|
|
set => _liftHeight = value is null ? null : Layer.RoundHeight(value.Value);
|
|
}
|
|
|
|
public float? LiftSpeed
|
|
{
|
|
get => _liftSpeed;
|
|
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;
|
|
set => _waitTimeAfterLift = value is null ? null : (float)Math.Round(value.Value, 2);
|
|
}
|
|
|
|
public float? RetractSpeed
|
|
{
|
|
get => _retractSpeed;
|
|
set => _retractSpeed = value is null ? null : (float)Math.Round(value.Value, 2);
|
|
}
|
|
|
|
public 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 byte LightOffCount { get; set; }
|
|
public bool IsAfterLightOff => LightOffCount > 0;
|
|
|
|
public GCodeLayer(FileFormat slicerFile)
|
|
{
|
|
SlicerFile = slicerFile;
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
PreviousPositionZ = PositionZ ?? 0;
|
|
|
|
Movements.Clear();
|
|
LayerIndex = null;
|
|
PositionZ = null;
|
|
WaitTimeBeforeCure = null;
|
|
ExposureTime = null;
|
|
WaitTimeAfterCure = null;
|
|
LiftHeight = null;
|
|
LiftSpeed = null;
|
|
LiftHeight2 = null;
|
|
LiftSpeed2 = null;
|
|
WaitTimeAfterLift = null;
|
|
RetractSpeed = null;
|
|
RetractHeight2 = null;
|
|
RetractSpeed2 = null;
|
|
LightPWM = null;
|
|
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 (RetractHeight2.HasValue) // Need to fix the propose of this value
|
|
{
|
|
RetractHeight2 = Layer.RoundHeight(LiftHeightTotal - RetractHeight2.Value);
|
|
(RetractSpeed, RetractSpeed2) = (RetractSpeed2, RetractSpeed);
|
|
}
|
|
|
|
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(bool reinit = false)
|
|
{
|
|
if (!IsValid) return;
|
|
uint layerIndex = LayerIndex.Value;
|
|
var layer = SlicerFile[layerIndex];
|
|
|
|
PositionZ ??= PreviousPositionZ;
|
|
layer.PositionZ = PositionZ.Value;
|
|
layer.WaitTimeBeforeCure = WaitTimeBeforeCure ?? 0;
|
|
layer.ExposureTime = ExposureTime ?? SlicerFile.GetBottomOrNormalValue(layer, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
|
|
layer.WaitTimeAfterCure = WaitTimeAfterCure ?? 0;
|
|
layer.LiftHeight = LiftHeight ?? 0;
|
|
layer.LiftSpeed = LiftSpeed ?? SlicerFile.GetBottomOrNormalValue(layer, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
|
|
layer.LiftHeight2 = LiftHeight2 ?? 0;
|
|
layer.LiftSpeed2 = LiftSpeed2 ?? SlicerFile.GetBottomOrNormalValue(layer, SlicerFile.BottomLiftSpeed2, SlicerFile.LiftSpeed2);
|
|
layer.WaitTimeAfterLift = WaitTimeAfterLift ?? 0;
|
|
layer.RetractSpeed = RetractSpeed ?? SlicerFile.GetBottomOrNormalValue(layer, SlicerFile.BottomRetractSpeed, SlicerFile.RetractSpeed);
|
|
layer.RetractHeight2 = RetractHeight2 ?? 0;
|
|
layer.RetractSpeed2 = RetractSpeed2 ?? SlicerFile.GetBottomOrNormalValue(layer, 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, 1.5f);
|
|
if (syncTime < layer.WaitTimeBeforeCure)
|
|
{
|
|
layer.WaitTimeBeforeCure = (float) Math.Round(layer.WaitTimeBeforeCure - syncTime, 2);
|
|
}
|
|
}
|
|
|
|
if(reinit) Init();
|
|
}
|
|
}
|
|
}
|