mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-12 19:42:32 +02:00
774fe9d5d0
- (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)
213 lines
6.6 KiB
C#
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
|
|
}
|
|
}
|