mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
b4504f83a5
- (Improvement) Increase `PixelSize`, `PixelWdith` and `PixelHeight` precision from 3 to 4 decimals (#684) - (Improvement) Suggestion wait time before/after cure: When unable to set time per layer and/or per bottom and normal layers it will show a simpler message with just one time that it can apply - (Fix) Unable to apply the wait time before cure suggestion in some formats due incorrectly check for the wait time after cure availability (#686)
329 lines
13 KiB
C#
329 lines
13 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.ComponentModel;
|
|
using System.Text;
|
|
using UVtools.Core.Operations;
|
|
|
|
namespace UVtools.Core.Suggestions;
|
|
|
|
public sealed class SuggestionWaitTimeAfterCure : Suggestion
|
|
{
|
|
#region Enums
|
|
public enum SuggestionWaitTimeAfterCureSetType
|
|
{
|
|
[Description("Fixed: Use a fixed time")]
|
|
Fixed,
|
|
[Description("Proportional: Proportional to an exposure time")]
|
|
ProportionalExposure
|
|
}
|
|
#endregion
|
|
|
|
#region Members
|
|
private SuggestionWaitTimeAfterCureSetType _setType = SuggestionWaitTimeAfterCureSetType.Fixed;
|
|
private decimal _fixedBottomWaitTimeAfterCure = 7;
|
|
private decimal _fixedWaitTimeAfterCure = 1;
|
|
private decimal _proportionalWaitTimeAfterCure = 1;
|
|
private decimal _proportionalExposureTime = 3;
|
|
private decimal _minimumBottomWaitTimeAfterCure = 3;
|
|
private decimal _minimumWaitTimeAfterCure = 1;
|
|
private decimal _maximumBottomWaitTimeAfterCure = 20;
|
|
private decimal _maximumWaitTimeAfterCure = 12;
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public override bool IsAvailable
|
|
{
|
|
get
|
|
{
|
|
if (SlicerFile is null) return false;
|
|
return SlicerFile.CanUseAnyWaitTimeAfterCure || SlicerFile.CanUseLayerWaitTimeAfterCure;
|
|
}
|
|
}
|
|
|
|
public override bool IsApplied
|
|
{
|
|
get
|
|
{
|
|
if (SlicerFile is null) return false;
|
|
|
|
switch (_applyWhen)
|
|
{
|
|
case SuggestionApplyWhen.OutsideLimits:
|
|
if (SlicerFile.CanUseBottomWaitTimeAfterCure)
|
|
{
|
|
if ((decimal)SlicerFile.BottomWaitTimeAfterCure < _minimumWaitTimeAfterCure ||
|
|
(decimal)SlicerFile.BottomWaitTimeAfterCure > _maximumWaitTimeAfterCure) return false;
|
|
}
|
|
if (SlicerFile.CanUseWaitTimeAfterCure)
|
|
{
|
|
if ((decimal)SlicerFile.WaitTimeAfterCure < _minimumWaitTimeAfterCure ||
|
|
(decimal)SlicerFile.WaitTimeAfterCure > _maximumWaitTimeAfterCure) return false;
|
|
}
|
|
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure)
|
|
{
|
|
foreach (var layer in SlicerFile)
|
|
{
|
|
if (layer.IsDummy)
|
|
{
|
|
if (layer.WaitTimeAfterCure > 0.1) return false;
|
|
}
|
|
else
|
|
{
|
|
if ((decimal) layer.WaitTimeAfterCure < _minimumWaitTimeAfterCure ||
|
|
(decimal) layer.WaitTimeAfterCure > _maximumWaitTimeAfterCure) return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
case SuggestionApplyWhen.Different:
|
|
if (SlicerFile.CanUseBottomWaitTimeAfterCure)
|
|
{
|
|
if (Math.Abs(SlicerFile.BottomWaitTimeAfterCure - CalculateWaitTime(true, (decimal)SlicerFile.BottomExposureTime)) > 0.1) return false;
|
|
}
|
|
if (SlicerFile.CanUseWaitTimeAfterCure)
|
|
{
|
|
if (Math.Abs(SlicerFile.WaitTimeAfterCure - CalculateWaitTime(false, (decimal)SlicerFile.ExposureTime)) > 0.1) return false;
|
|
}
|
|
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure)
|
|
{
|
|
foreach (var layer in SlicerFile)
|
|
{
|
|
if (layer.IsDummy)
|
|
{
|
|
if (layer.WaitTimeAfterCure > 0.1) return false;
|
|
}
|
|
else
|
|
{
|
|
if (Math.Abs(layer.WaitTimeAfterCure - CalculateWaitTime(layer.IsBottomLayer, (decimal)layer.ExposureTime)) > 0.1) return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override string Title => "Wait time after cure";
|
|
public override string Description => "Rest some time after curing the layer and before the lift sequence may allow the resin reaction to settle, harden and cool down a bit to detach more easily from the FEP, then yields less tension on the model, better print quality and easier lift's.";
|
|
|
|
public override string Message
|
|
{
|
|
get
|
|
{
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure || SlicerFile is {CanUseBottomWaitTimeAfterCure: true, CanUseWaitTimeAfterCure: true})
|
|
{
|
|
return IsApplied
|
|
? $"{GlobalAppliedMessage}: {SlicerFile.BottomWaitTimeAfterCure}/{SlicerFile.WaitTimeAfterCure}s"
|
|
: $"{GlobalNotAppliedMessage} of {SlicerFile.BottomWaitTimeAfterCure}/{SlicerFile.WaitTimeAfterCure}s " +
|
|
$"is out of the recommended {CalculateWaitTime(true, (decimal) SlicerFile.BottomExposureTime)}/{CalculateWaitTime(false, (decimal) SlicerFile.ExposureTime)}s";
|
|
}
|
|
|
|
// Single property
|
|
return IsApplied
|
|
? $"{GlobalAppliedMessage}: {SlicerFile.WaitTimeAfterCure}s"
|
|
: $"{GlobalNotAppliedMessage} of {SlicerFile.WaitTimeAfterCure}s " +
|
|
$"is out of the recommended {CalculateWaitTime(false, (decimal)SlicerFile.ExposureTime)}s";
|
|
}
|
|
}
|
|
|
|
public override string ToolTip
|
|
{
|
|
get
|
|
{
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure || SlicerFile is {CanUseBottomWaitTimeAfterCure: true, CanUseWaitTimeAfterCure: true})
|
|
{
|
|
return (_setType == SuggestionWaitTimeAfterCureSetType.Fixed
|
|
? $"The recommended wait time must be {_fixedBottomWaitTimeAfterCure}/{_fixedWaitTimeAfterCure}s"
|
|
: $"The recommended wait time is a ratio of (wait time){_proportionalWaitTimeAfterCure}s to (exposure time){_proportionalExposureTime}s") +
|
|
$" constrained from [Bottoms={_minimumBottomWaitTimeAfterCure}s to {_maximumBottomWaitTimeAfterCure}s] and [Normals={_minimumWaitTimeAfterCure}s to {_maximumWaitTimeAfterCure}s].\n" +
|
|
$"Explanation: {Description}";
|
|
}
|
|
|
|
return (_setType == SuggestionWaitTimeAfterCureSetType.Fixed
|
|
? $"The recommended wait time must be {_fixedWaitTimeAfterCure}s"
|
|
: $"The recommended wait time is a ratio of (wait time){_proportionalWaitTimeAfterCure}s to (exposure time){_proportionalExposureTime}s") +
|
|
$" constrained from {_minimumWaitTimeAfterCure}s to {_maximumWaitTimeAfterCure}s.\n" +
|
|
$"Explanation: {Description}";
|
|
}
|
|
}
|
|
|
|
public override string? ConfirmationMessage
|
|
{
|
|
get
|
|
{
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure || SlicerFile is {CanUseBottomWaitTimeAfterCure: true, CanUseWaitTimeAfterCure: true})
|
|
{
|
|
return $"{Title}: {SlicerFile.BottomWaitTimeAfterCure}/{SlicerFile.WaitTimeAfterCure}s » {CalculateWaitTime(true, (decimal) SlicerFile.BottomWaitTimeAfterCure)}/{CalculateWaitTime(false, (decimal) SlicerFile.WaitTimeAfterCure)}s";
|
|
}
|
|
|
|
// Single property
|
|
return $"{Title}: {SlicerFile.WaitTimeAfterCure}s » {CalculateWaitTime(false, (decimal)SlicerFile.WaitTimeAfterCure)}s";
|
|
}
|
|
}
|
|
|
|
public SuggestionWaitTimeAfterCureSetType SetType
|
|
{
|
|
get => _setType;
|
|
set
|
|
{
|
|
if(!RaiseAndSetIfChanged(ref _setType, value)) return;
|
|
RaisePropertyChanged(nameof(IsSetTypeFixed));
|
|
RaisePropertyChanged(nameof(IsSetTypeProportionalExposure));
|
|
}
|
|
}
|
|
|
|
public bool IsSetTypeFixed => _setType == SuggestionWaitTimeAfterCureSetType.Fixed;
|
|
public bool IsSetTypeProportionalExposure => _setType == SuggestionWaitTimeAfterCureSetType.ProportionalExposure;
|
|
|
|
public decimal FixedBottomWaitTimeAfterCure
|
|
{
|
|
get => _fixedBottomWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _fixedBottomWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal FixedWaitTimeAfterCure
|
|
{
|
|
get => _fixedWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _fixedWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal ProportionalWaitTimeAfterCure
|
|
{
|
|
get => _proportionalWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _proportionalWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal ProportionalExposureTime
|
|
{
|
|
get => _proportionalExposureTime;
|
|
set => RaiseAndSetIfChanged(ref _proportionalExposureTime, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal MinimumBottomWaitTimeAfterCure
|
|
{
|
|
get => _minimumBottomWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _minimumBottomWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal MinimumWaitTimeAfterCure
|
|
{
|
|
get => _minimumWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _minimumWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal MaximumBottomWaitTimeAfterCure
|
|
{
|
|
get => _maximumBottomWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _maximumBottomWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
public decimal MaximumWaitTimeAfterCure
|
|
{
|
|
get => _maximumWaitTimeAfterCure;
|
|
set => RaiseAndSetIfChanged(ref _maximumWaitTimeAfterCure, Math.Round(value, 2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public SuggestionWaitTimeAfterCure()
|
|
{
|
|
_applyWhen = SuggestionApplyWhen.Different;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Overrides
|
|
|
|
public override string? Validate()
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
if (_minimumBottomWaitTimeAfterCure > _maximumBottomWaitTimeAfterCure)
|
|
{
|
|
sb.AppendLine("Minimum bottom limit can't be higher than maximum bottom limit");
|
|
}
|
|
|
|
if (_minimumWaitTimeAfterCure > _maximumWaitTimeAfterCure)
|
|
{
|
|
sb.AppendLine("Minimum normal limit can't be higher than maximum normal limit");
|
|
}
|
|
|
|
if (_setType == SuggestionWaitTimeAfterCureSetType.ProportionalExposure)
|
|
{
|
|
if (_proportionalWaitTimeAfterCure <= 0)
|
|
{
|
|
sb.AppendLine("The proportional wait time must be higher than 0s");
|
|
}
|
|
|
|
if (_proportionalExposureTime <= 0)
|
|
{
|
|
sb.AppendLine("The proportional exposure time must be higher than 0s");
|
|
}
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
protected override bool ExecuteInternally(OperationProgress progress)
|
|
{
|
|
if (SlicerFile.CanUseBottomWaitTimeAfterCure)
|
|
{
|
|
SlicerFile.BottomWaitTimeAfterCure = CalculateWaitTime(true, (decimal)SlicerFile.BottomExposureTime);
|
|
}
|
|
if (SlicerFile.CanUseWaitTimeAfterCure)
|
|
{
|
|
SlicerFile.WaitTimeAfterCure = CalculateWaitTime(false, (decimal)SlicerFile.ExposureTime);
|
|
}
|
|
|
|
if (SlicerFile.CanUseLayerWaitTimeAfterCure)
|
|
{
|
|
foreach (var layer in SlicerFile)
|
|
{
|
|
layer.WaitTimeAfterCure = layer.IsDummy ? 0 : CalculateWaitTime(layer.IsBottomLayer, (decimal) layer.ExposureTime);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
public float CalculateWaitTime(bool isBottomLayer, decimal exposureTime)
|
|
{
|
|
return _setType switch
|
|
{
|
|
SuggestionWaitTimeAfterCureSetType.Fixed => (float) (isBottomLayer
|
|
? _fixedBottomWaitTimeAfterCure
|
|
: _fixedWaitTimeAfterCure),
|
|
SuggestionWaitTimeAfterCureSetType.ProportionalExposure =>
|
|
(float)Math.Clamp(
|
|
Math.Round(exposureTime * _proportionalWaitTimeAfterCure / _proportionalExposureTime, 2),
|
|
isBottomLayer ? _minimumBottomWaitTimeAfterCure : _minimumWaitTimeAfterCure,
|
|
isBottomLayer ? _maximumBottomWaitTimeAfterCure : _maximumWaitTimeAfterCure
|
|
),
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
};
|
|
}
|
|
|
|
#endregion
|
|
} |