Files
UVtools/UVtools.Core/Operations/OperationResize.cs
T
Tiago Conceição 774fe9d5d0 v2.20.5
- (Add) Setting - Max degree of parallelism: Sets the maximum number of concurrent tasks/threads/operations enabled to run by parallel method calls.
   If your computer lags and freeze during operations you can reduce this number to reduce the workload and keep some cores available to other tasks as well.
   <= 0: Will utilize however many threads the underlying scheduler provides, mostly this is the processor count.
   1: Single thread. (#279)
2021-08-31 17:06:46 +01:00

213 lines
6.6 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.Text;
using System.Threading.Tasks;
using Emgu.CV;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
namespace UVtools.Core.Operations
{
[Serializable]
public class OperationResize : Operation
{
#region Members
private decimal _x = 100;
private decimal _y = 100;
private bool _constrainXy;
private bool _isFade;
#endregion
#region Overrides
public override string Title => "Resize";
public override string Description =>
"Resize the model by a percentage in the X/Y plane.\n\n" +
"NOTE: This operation is applied based on the original orientation of the layers in the model file. " +
"If the image is rotated 90° in the Layer Preview, you will need to compensate by inverting " +
"the X and Y values. The print bounds will also not be validated as part of this operation, so please " +
"ensure that the scaling factor does not result in the model being clipped.";
public override string ConfirmationText =>
$"resize model layers {LayerIndexStart} through {LayerIndexEnd} by " +
$"X={X}% and Y={Y}%";
public override string ProgressTitle =>
$"Resizing from layers {LayerIndexStart} to {LayerIndexEnd} at X:{X}% Y:{Y}% ";
public override string ProgressAction => "Resized layers";
public override string ValidateInternally()
{
var sb = new StringBuilder();
if (X == 100m && Y == 100m)
{
sb.AppendLine("X and Y can't both be 100%.");
}
return sb.ToString();
}
public override string ToString()
{
var result = $"[X: {_x}%, Y: {_y}%] [Fade: {_isFade}] [Constrain: {_constrainXy}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
#endregion
#region Properties
public decimal X
{
get => _x;
set
{
RaiseAndSetIfChanged(ref _x, value);
if (_constrainXy)
Y = value;
RaisePropertyChanged(nameof(XScale));
}
}
public decimal XScale => _x / 100m;
public decimal YScale => _y / 100m;
public decimal Y
{
get => _y;
set
{
if(!RaiseAndSetIfChanged(ref _y, value)) return;
RaisePropertyChanged(nameof(YScale));
}
}
public bool ConstrainXY
{
get => _constrainXy;
set
{
if (!RaiseAndSetIfChanged(ref _constrainXy, value)) return;
if (_constrainXy)
{
Y = _x;
}
}
}
public bool IsFade
{
get => _isFade;
set => RaiseAndSetIfChanged(ref _isFade, value);
}
#endregion
#region Constructor
public OperationResize() { }
public OperationResize(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality
protected bool Equals(OperationResize other)
{
return _x == other._x && _y == other._y && _constrainXy == other._constrainXy && _isFade == other._isFade;
}
public override bool Equals(object obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((OperationResize) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = _x.GetHashCode();
hashCode = (hashCode * 397) ^ _y.GetHashCode();
hashCode = (hashCode * 397) ^ _constrainXy.GetHashCode();
hashCode = (hashCode * 397) ^ _isFade.GetHashCode();
return hashCode;
}
}
#endregion
#region Methods
protected override bool ExecuteInternally(OperationProgress progress)
{
if (_x <= 0 || _y <= 0) return false;
if (_x == 100 && _y == 100) return false;
decimal xSteps = Math.Abs(100 - _x) / (LayerIndexEnd - LayerIndexStart + 1);
decimal ySteps = Math.Abs(100 - _y) / (LayerIndexEnd - LayerIndexStart + 1);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.ParallelOptions, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
var newX = _x;
var newY = _y;
if (IsFade)
{
if (newX != 100)
{
newX = newX < 100
? newX + (layerIndex - LayerIndexStart) * xSteps
: newX - (layerIndex - LayerIndexStart) * xSteps;
}
if (newY != 100)
{
newY = newY < 100
? newY + (layerIndex - LayerIndexStart) * ySteps
: newY - (layerIndex - LayerIndexStart) * ySteps;
}
}
progress.LockAndIncrement();
if (newX == 100 && newY == 100) return;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, newX / 100, newY / 100);
SlicerFile[layerIndex].LayerMat = mat;
});
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
{
var xScale = XScale;
var yScale = YScale;
if (arguments is not null && arguments.Length >= 2)
{
xScale = (decimal) arguments[0];
yScale = (decimal) arguments[1];
}
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
target.TransformFromCenter((double) xScale, (double) yScale);
ApplyMask(original, target);
return true;
}
#endregion
}
}