Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'UVtools.Core/Operations/OperationDynamicLifts.cs')
-rw-r--r--UVtools.Core/Operations/OperationDynamicLifts.cs344
1 files changed, 344 insertions, 0 deletions
diff --git a/UVtools.Core/Operations/OperationDynamicLifts.cs b/UVtools.Core/Operations/OperationDynamicLifts.cs
new file mode 100644
index 0000000..03c7412
--- /dev/null
+++ b/UVtools.Core/Operations/OperationDynamicLifts.cs
@@ -0,0 +1,344 @@
+/*
+ * 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.Linq;
+using System.Text;
+using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.Core.Operations
+{
+ [Serializable]
+ public sealed class OperationDynamicLifts : Operation
+ {
+ private float _minBottomLiftHeight;
+ private float _maxBottomLiftHeight;
+ private float _minLiftHeight;
+ private float _maxLiftHeight;
+ private float _minBottomLiftSpeed;
+ private float _maxBottomLiftSpeed;
+ private float _minLiftSpeed;
+ private float _maxLiftSpeed;
+ private bool _updateLightOffDelay = true;
+ private float _lightOffDelayBottomExtraTime = 3;
+ private float _lightOffDelayExtraTime = 2.5f;
+
+ #region Members
+
+ #endregion
+
+ #region Overrides
+
+ public override string Title => "Dynamic lifts";
+
+ public override string Description =>
+ "Generate dynamic lift height and speeds for each layer given it mass\n" +
+ "Larger masses requires more lift height and less speed while smaller masses can go with shorter lift height and more speed.\n" +
+ "If you have a raft, start after it layer number to not influence the calculations.\n" +
+ "Note: Only few printers support this. Running this on an unsupported printer will cause no harm.";
+
+ public override string ConfirmationText =>
+ $"generate dynamic lifts from layers {LayerIndexStart} through {LayerIndexEnd}?";
+
+ public override string ProgressTitle =>
+ $"Generating dynamic lifts from layers {LayerIndexStart} through {LayerIndexEnd}";
+
+ public override string ProgressAction => "Generated lifts";
+
+ public override string ValidateInternally()
+ {
+ var sb = new StringBuilder();
+
+ if (_minBottomLiftHeight > _maxBottomLiftHeight)
+ {
+ sb.AppendLine("Minimum bottom lift height can't be higher than the maximum.");
+ }
+ if (_minBottomLiftSpeed > _maxBottomLiftSpeed)
+ {
+ sb.AppendLine("Minimum bottom lift speed can't be higher than the maximum.");
+ }
+
+ if (_minLiftHeight > _maxLiftHeight)
+ {
+ sb.AppendLine("Minimum lift height can't be higher than the maximum.");
+ }
+ if (_minLiftSpeed > _maxLiftSpeed)
+ {
+ sb.AppendLine("Minimum lift speed can't be higher than the maximum.");
+ }
+
+ if (_minBottomLiftHeight == _maxBottomLiftHeight &&
+ _minBottomLiftSpeed == _maxBottomLiftSpeed &&
+ _minLiftHeight == _maxLiftHeight &&
+ _minLiftSpeed == _maxLiftSpeed)
+ {
+ sb.AppendLine("The selected min/max settings are all equal and will not produce a change.");
+ }
+
+ return sb.ToString();
+ }
+
+ public override string ToString()
+ {
+ var result =
+ $"[Bottom height: {_minBottomLiftHeight}/{_maxBottomLiftHeight}mm]" +
+ $" [Bottom speed: {_minBottomLiftSpeed}/{_maxBottomLiftSpeed}mm/min]" +
+ $" [Height: {_minLiftHeight}/{_maxLiftHeight}mm]" +
+ $" [Speed: {_minLiftSpeed}/{_maxLiftSpeed}mm/min]" +
+ $" [Light-off: {_updateLightOffDelay} {_lightOffDelayBottomExtraTime}/{_lightOffDelayExtraTime}s]" +
+ LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #endregion
+
+ #region Properties
+
+ public float MinBottomLiftHeight
+ {
+ get => _minBottomLiftHeight;
+ set => RaiseAndSetIfChanged(ref _minBottomLiftHeight, (float)Math.Round(value, 2));
+ }
+
+ public float MaxBottomLiftHeight
+ {
+ get => _maxBottomLiftHeight;
+ set => RaiseAndSetIfChanged(ref _maxBottomLiftHeight, (float)Math.Round(value, 2));
+ }
+
+ public float MinLiftHeight
+ {
+ get => _minLiftHeight;
+ set => RaiseAndSetIfChanged(ref _minLiftHeight, (float)Math.Round(value, 2));
+ }
+
+ public float MaxLiftHeight
+ {
+ get => _maxLiftHeight;
+ set => RaiseAndSetIfChanged(ref _maxLiftHeight, (float)Math.Round(value, 2));
+ }
+
+ public float MinBottomLiftSpeed
+ {
+ get => _minBottomLiftSpeed;
+ set => RaiseAndSetIfChanged(ref _minBottomLiftSpeed, (float)Math.Round(value, 2));
+ }
+
+ public float MaxBottomLiftSpeed
+ {
+ get => _maxBottomLiftSpeed;
+ set => RaiseAndSetIfChanged(ref _maxBottomLiftSpeed, (float)Math.Round(value, 2));
+ }
+
+ public float MinLiftSpeed
+ {
+ get => _minLiftSpeed;
+ set => RaiseAndSetIfChanged(ref _minLiftSpeed, (float)Math.Round(value, 2));
+ }
+
+ public float MaxLiftSpeed
+ {
+ get => _maxLiftSpeed;
+ set => RaiseAndSetIfChanged(ref _maxLiftSpeed, (float)Math.Round(value, 2));
+ }
+
+ public bool UpdateLightOffDelay
+ {
+ get => _updateLightOffDelay;
+ set => RaiseAndSetIfChanged(ref _updateLightOffDelay, value);
+ }
+
+ public float LightOffDelayBottomExtraTime
+ {
+ get => _lightOffDelayBottomExtraTime;
+ set => RaiseAndSetIfChanged(ref _lightOffDelayBottomExtraTime, (float)Math.Round(value, 2));
+ }
+
+ public float LightOffDelayExtraTime
+ {
+ get => _lightOffDelayExtraTime;
+ set => RaiseAndSetIfChanged(ref _lightOffDelayExtraTime, (float)Math.Round(value, 2));
+ }
+
+ //public uint MinBottomLayerPixels => SlicerFile.Where(layer => layer.IsBottomLayer && !layer.IsEmpty && layer.Index >= LayerIndexStart && layer.Index <= LayerIndexEnd).Max(layer => layer.NonZeroPixelCount);
+ public uint MinBottomLayerPixels => (from layer in SlicerFile
+ where layer.IsBottomLayer
+ where !layer.IsEmpty
+ where layer.Index >= LayerIndexStart
+ where layer.Index <= LayerIndexEnd
+ select layer.NonZeroPixelCount).Min();
+
+ //public uint MinNormalLayerPixels => SlicerFile.Where(layer => layer.IsNormalLayer && !layer.IsEmpty && layer.Index >= LayerIndexStart && layer.Index <= LayerIndexEnd).Max(layer => layer.NonZeroPixelCount);
+ public uint MinNormalLayerPixels => (from layer in SlicerFile
+ where layer.IsNormalLayer
+ where !layer.IsEmpty
+ where layer.Index >= LayerIndexStart
+ where layer.Index <= LayerIndexEnd
+ select layer.NonZeroPixelCount).Min();
+
+ //public uint MaxBottomLayerPixels => SlicerFile.Where(layer => layer.IsBottomLayer && layer.Index >= LayerIndexStart && layer.Index <= LayerIndexEnd).Max(layer => layer.NonZeroPixelCount);
+ public uint MaxBottomLayerPixels => (from layer in SlicerFile
+ where layer.IsBottomLayer
+ where !layer.IsEmpty
+ where layer.Index >= LayerIndexStart
+ where layer.Index <= LayerIndexEnd
+ select layer.NonZeroPixelCount).Max();
+ //public uint MaxNormalLayerPixels => SlicerFile.Where(layer => layer.IsNormalLayer && layer.Index >= LayerIndexStart && layer.Index <= LayerIndexEnd).Max(layer => layer.NonZeroPixelCount);
+ public uint MaxNormalLayerPixels => (from layer in SlicerFile
+ where layer.IsNormalLayer
+ where !layer.IsEmpty
+ where layer.Index >= LayerIndexStart
+ where layer.Index <= LayerIndexEnd
+ select layer.NonZeroPixelCount).Max();
+
+ public Layer MinBottomLayer => SlicerFile.Where(layer => layer.IsBottomLayer && !layer.IsEmpty).OrderBy(layer => layer.NonZeroPixelCount).First();
+ public Layer MaxBottomLayer => SlicerFile.Where(layer => layer.IsBottomLayer).OrderByDescending(layer => layer.NonZeroPixelCount).First();
+ public Layer MinLayer => SlicerFile.Where(layer => layer.IsNormalLayer && !layer.IsEmpty).OrderBy(layer => layer.NonZeroPixelCount).First();
+ public Layer MaxLayer => SlicerFile.Where(layer => layer.IsNormalLayer).OrderByDescending(layer => layer.NonZeroPixelCount).First();
+
+ #endregion
+
+ #region Constructor
+
+ public OperationDynamicLifts()
+ { }
+
+ public OperationDynamicLifts(FileFormat slicerFile) : base(slicerFile)
+ {
+ _minBottomLiftHeight = _maxBottomLiftHeight = SlicerFile.BottomLiftHeight;
+ _minLiftHeight = _maxLiftHeight = SlicerFile.LiftHeight;
+
+ _minBottomLiftSpeed = _maxBottomLiftSpeed = SlicerFile.BottomLiftSpeed;
+ _minLiftSpeed = _maxLiftSpeed = SlicerFile.LiftSpeed;
+ }
+
+ #endregion
+
+ #region Methods
+
+ protected override bool ExecuteInternally(OperationProgress progress)
+ {
+ uint minBottomPixels = 0;
+ uint minNormalPixels = 0;
+ uint maxBottomPixels = 0;
+ uint maxNormalPixels = 0;
+
+ try
+ {
+ minBottomPixels = MinBottomLayerPixels;
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ minNormalPixels = MinNormalLayerPixels;
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ maxBottomPixels = MaxBottomLayerPixels;
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ maxNormalPixels = MaxNormalLayerPixels;
+ }
+ catch
+ {
+ }
+
+ float liftHeight;
+ float liftSpeed;
+
+ uint max = (from layer in SlicerFile where !layer.IsBottomLayer where !layer.IsEmpty where layer.Index >= LayerIndexStart where layer.Index <= LayerIndexEnd select layer).Aggregate<Layer, uint>(0, (current, layer) => Math.Max(layer.NonZeroPixelCount, current));
+
+ for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
+ {
+ progress.Token.ThrowIfCancellationRequested();
+ var layer = SlicerFile[layerIndex];
+
+ // Height
+ // min - largestpixelcount
+ // x - pixelcount
+
+ // Speed
+ // max - minpixelCount
+ // x - pixelcount
+
+ if (layer.IsBottomLayer)
+ {
+ liftHeight = (_maxBottomLiftHeight * layer.NonZeroPixelCount / maxBottomPixels).Clamp(_minBottomLiftHeight, _maxBottomLiftHeight);
+ liftSpeed = (_maxBottomLiftSpeed - (_maxBottomLiftSpeed * layer.NonZeroPixelCount / maxNormalPixels)).Clamp(_minBottomLiftSpeed, _maxBottomLiftSpeed);
+ }
+ else
+ {
+ liftHeight = (_maxLiftHeight * layer.NonZeroPixelCount / maxNormalPixels).Clamp(_minLiftHeight, _maxLiftHeight);
+ liftSpeed = (_maxLiftSpeed - (_maxLiftSpeed * layer.NonZeroPixelCount / maxNormalPixels)).Clamp(_minLiftSpeed, _maxLiftSpeed);
+ }
+
+ layer.LiftHeight = (float) Math.Round(liftHeight, 2);
+ layer.LiftSpeed = (float) Math.Round(liftSpeed, 2);
+
+ if (_updateLightOffDelay)
+ {
+ layer.UpdateLightOffDelay(layer.IsBottomLayer ? _lightOffDelayBottomExtraTime : _lightOffDelayExtraTime);
+ }
+
+ progress++;
+ }
+
+ SlicerFile.UpdatePrintTime();
+
+ return !progress.Token.IsCancellationRequested;
+ }
+
+
+ #endregion
+
+ #region Equality
+
+ private bool Equals(OperationDynamicLifts other)
+ {
+ return _minBottomLiftHeight.Equals(other._minBottomLiftHeight) && _maxBottomLiftHeight.Equals(other._maxBottomLiftHeight) && _minLiftHeight.Equals(other._minLiftHeight) && _maxLiftHeight.Equals(other._maxLiftHeight) && _minBottomLiftSpeed.Equals(other._minBottomLiftSpeed) && _maxBottomLiftSpeed.Equals(other._maxBottomLiftSpeed) && _minLiftSpeed.Equals(other._minLiftSpeed) && _maxLiftSpeed.Equals(other._maxLiftSpeed) && _updateLightOffDelay == other._updateLightOffDelay && _lightOffDelayBottomExtraTime.Equals(other._lightOffDelayBottomExtraTime) && _lightOffDelayExtraTime.Equals(other._lightOffDelayExtraTime);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || obj is OperationDynamicLifts other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ var hashCode = new HashCode();
+ hashCode.Add(_minBottomLiftHeight);
+ hashCode.Add(_maxBottomLiftHeight);
+ hashCode.Add(_minLiftHeight);
+ hashCode.Add(_maxLiftHeight);
+ hashCode.Add(_minBottomLiftSpeed);
+ hashCode.Add(_maxBottomLiftSpeed);
+ hashCode.Add(_minLiftSpeed);
+ hashCode.Add(_maxLiftSpeed);
+ hashCode.Add(_updateLightOffDelay);
+ hashCode.Add(_lightOffDelayBottomExtraTime);
+ hashCode.Add(_lightOffDelayExtraTime);
+ return hashCode.ToHashCode();
+ }
+
+ #endregion
+ }
+}