mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-11 19:12:31 +02:00
0ba61780b7
* (Upgrade) EmguCV/OpenCV to v4.5.1
* (Upgrade) AvaloniaUI to 1.0
* (Improvement) GUI re-touched
* (Improvement) Make pixel editor tab to disappear when pixel editor is disabled
* (Improvement) Simplify the output filename from PrusaSlicer profiles
* (Improvement) All operations require a slicer file at constructor rather than on execute, this allow exposure the open file to the operation before run it
* (Improvement) Calibrations: Auto set "Mirror Output" if open file have MirrorDisplay set
* (Change) Tool - Redraw model/supports icon
* (Change) photon and cbddlp to use version 3 by default
* (Add) Tool - Dynamic layer height: Analyze and optimize the model with dynamic layer heights, larger angles will slice at lower layer height
while more straight angles will slice larger layer height. (#131)
* (Add) Calibration - Exposure time finder: Generates test models with various strategies and increments to verify the best exposure time for a given layer height
* (Add) File load checks, trigger error when a file have critical errors and attempt to fix non-critical errors
* Layers must have an valid image, otherwise trigger an error
* Layers must have a incremental or equal position Z than it previous, otherwise trigger an error
* If layer 0 starts at 0mm it will auto fix all layers, it will add Layer Height to the current z at every layer
* (Add) Tool - Edit print parameters: Allow set parameters to each x layers and skip n layers inside the given range.
This allow the use of optimizations in a layer pattern, for example, to set 3s for a layer but 2.5s for the next.
* (Add) Layer height property to "Layer Data" table: Shows layer height for the slice
* (Fix) When automations applied and file is saved, it will not warn user about file overwrite for the first time save
* (Fix) Tool - Redraw model/supports: Disable apply button when no file selected
* (Fix) Tool - Infill: Lack of equality member to test if same infill profile already exists
* (Fix) Auto converted files from SL1 where clipping filename at first dot (.), now it only strips known extensions
* (Fix) SL1 encoded files wasn't generating the right information and lead to printer crash
* (Fix) PrusaSlicer printer "Anycubic Photon S" LiftSpeed was missing and contains a typo (#135)
* (Fix) PrusaSlicer profile manager wasnt marking missing profiles to be installed (#135)
* (Fix) PrusaSlicer folder search on linux to also look at %HOME%/.config/PrusaSlicer (#135, #136)
* (Fix) Operations were revised and some bug fixed, most about can't cancel the progress
* (Fix) Some typos on tooltips
* (Fix) Prevent PhotonS from enconding, it will trigger error now as this format is read-only
* **(Fix) Ctrl + Shift + Z to redo the last operation:**
* The layer range is reseted instead of pull the used values
* Tool - Arithmetic always disabled
* Action - Layer import didn't generate info and always disabled
228 lines
8.4 KiB
C#
228 lines
8.4 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.Drawing;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Emgu.CV;
|
|
using UVtools.Core.FileFormats;
|
|
using UVtools.Core.Objects;
|
|
|
|
namespace UVtools.Core.Operations
|
|
{
|
|
[Serializable]
|
|
public sealed class OperationChangeResolution : Operation
|
|
{
|
|
#region Members
|
|
private uint _newResolutionX;
|
|
private uint _newResolutionY;
|
|
#endregion
|
|
|
|
#region Subclasses
|
|
public class Resolution
|
|
{
|
|
public uint ResolutionX { get; }
|
|
public uint ResolutionY { get; }
|
|
public string Name { get; }
|
|
public bool IsEmpty => ResolutionX == 0 && ResolutionY == 0;
|
|
|
|
public Resolution(uint resolutionX, uint resolutionY, string name = null)
|
|
{
|
|
ResolutionX = resolutionX;
|
|
ResolutionY = resolutionY;
|
|
Name = name;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
if(IsEmpty) return string.Empty;
|
|
var str = $"{ResolutionX} x {ResolutionY}";
|
|
if (!string.IsNullOrEmpty(Name))
|
|
{
|
|
str += $" ({Name})";
|
|
}
|
|
return str;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Overrides
|
|
|
|
public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
|
|
public override bool CanROI => false;
|
|
public override string Title => "Change print resolution";
|
|
public override string Description =>
|
|
"Crops or resizes all layer images to fit an alternate print area\n\n" +
|
|
"Useful to make files printable on a different printer than they were originally sliced for without the need to re-slice.\n\n" +
|
|
"NOTE: Please ensure that the actual model will fit within the new print resolution. The operation will be aborted if it will result in any of the actual model being clipped.";
|
|
|
|
public override string ConfirmationText =>
|
|
"change print resolution " +
|
|
$"from {SlicerFile.ResolutionX}x{SlicerFile.ResolutionY} " +
|
|
$"to {NewResolutionX}x{NewResolutionY}?";
|
|
|
|
public override string ProgressTitle =>
|
|
$"Changing print resolution from ({SlicerFile.ResolutionX}x{SlicerFile.ResolutionY}) to ({NewResolutionX}x{NewResolutionY})";
|
|
|
|
public override string ProgressAction => "Changed layers";
|
|
|
|
public override StringTag Validate(params object[] parameters)
|
|
{
|
|
var sb = new StringBuilder();
|
|
if (SlicerFile.ResolutionX == NewResolutionX && SlicerFile.ResolutionY == NewResolutionY)
|
|
{
|
|
sb.AppendLine($"The new resolution must be different from current resolution ({SlicerFile.ResolutionX} x {SlicerFile.ResolutionY}).");
|
|
}
|
|
|
|
if (NewResolutionX < SlicerFile.BoundingRectangle.Width || NewResolutionY < SlicerFile.BoundingRectangle.Height)
|
|
{
|
|
sb.AppendLine($"The new resolution ({NewResolutionX} x {NewResolutionY}) is not large enough to hold the model volume ({SlicerFile.BoundingRectangle.Width} x {SlicerFile.BoundingRectangle.Height}), continuing operation would clip the model");
|
|
sb.AppendLine("To fix this, try to rotate the object and/or resize to fit on this new resolution.");
|
|
}
|
|
|
|
return new StringTag(sb.ToString());
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
var result = $"{_newResolutionX} x {_newResolutionY}";
|
|
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
public uint NewResolutionX
|
|
{
|
|
get => _newResolutionX;
|
|
set => RaiseAndSetIfChanged(ref _newResolutionX, value);
|
|
}
|
|
|
|
public uint NewResolutionY
|
|
{
|
|
get => _newResolutionY;
|
|
set => RaiseAndSetIfChanged(ref _newResolutionY, value);
|
|
}
|
|
|
|
public Size VolumeBondsSize => SlicerFile.BoundingRectangle.Size;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public OperationChangeResolution() { }
|
|
|
|
public OperationChangeResolution(FileFormat slicerFile) : base(slicerFile)
|
|
{
|
|
NewResolutionX = SlicerFile.ResolutionX;
|
|
NewResolutionY = SlicerFile.ResolutionY;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
public static Resolution[] GetResolutions()
|
|
{
|
|
return new [] {
|
|
//new Resolution(0, 0, string.Empty),
|
|
new Resolution(854, 480, "FWVGA"),
|
|
new Resolution(960, 1708),
|
|
new Resolution(1080, 1920, "FHD"),
|
|
new Resolution(1440, 2560, "QHD"),
|
|
new Resolution(1600, 2560, "WQXGA"),
|
|
new Resolution(1620, 2560, "WQXGA"),
|
|
new Resolution(1920, 1080, "FHD"),
|
|
new Resolution(2160, 3840, "4K UHD"),
|
|
new Resolution(2531, 1410, "QHD"),
|
|
new Resolution(2560, 1440, "QHD"),
|
|
new Resolution(2560, 1600, "WQXGA"),
|
|
new Resolution(2560, 1620, "WQXGA"),
|
|
new Resolution(3840, 2160, "4K UHD"),
|
|
new Resolution(3840, 2400, "WQUXGA"),
|
|
};
|
|
}
|
|
|
|
public static Resolution[] Presets => GetResolutions();
|
|
|
|
|
|
protected override bool ExecuteInternally(OperationProgress progress)
|
|
{
|
|
progress.ItemCount = SlicerFile.LayerCount;
|
|
|
|
Parallel.For(0, SlicerFile.LayerCount, layerIndex =>
|
|
{
|
|
if (progress.Token.IsCancellationRequested) return;
|
|
|
|
using var mat = SlicerFile[layerIndex].LayerMat;
|
|
using var matRoi = new Mat(mat, SlicerFile.BoundingRectangle);
|
|
using var matDst = new Mat(new Size((int)NewResolutionX, (int)NewResolutionY), mat.Depth, mat.NumberOfChannels);
|
|
using var matDstRoi = new Mat(matDst,
|
|
new Rectangle((int)(NewResolutionX / 2 - SlicerFile.BoundingRectangle.Width / 2),
|
|
(int)NewResolutionY / 2 - SlicerFile.BoundingRectangle.Height / 2,
|
|
SlicerFile.BoundingRectangle.Width, SlicerFile.BoundingRectangle.Height));
|
|
matRoi.CopyTo(matDstRoi);
|
|
//Execute(mat);
|
|
SlicerFile[layerIndex].LayerMat = matDst;
|
|
|
|
lock (progress.Mutex)
|
|
{
|
|
progress++;
|
|
}
|
|
});
|
|
|
|
progress.Token.ThrowIfCancellationRequested();
|
|
|
|
SlicerFile.ResolutionX = NewResolutionX;
|
|
SlicerFile.ResolutionY = NewResolutionY;
|
|
|
|
return !progress.Token.IsCancellationRequested;
|
|
}
|
|
|
|
/*public override bool Execute(Mat mat, params object[] arguments)
|
|
{
|
|
//mat.Transform(1, 1, newResolutionX-mat.Width+roi.Width, newResolutionY-mat.Height - roi.Height/2, new Size((int) newResolutionX, (int) newResolutionY));
|
|
using var matRoi = new Mat(mat, VolumeBonds);
|
|
using var matDst = new Mat(new Size((int)NewResolutionX, (int)NewResolutionY), mat.Depth, mat.NumberOfChannels);
|
|
using var matDstRoi = new Mat(matDst,
|
|
new Rectangle((int)(NewResolutionX / 2 - VolumeBonds.Width / 2),
|
|
(int)NewResolutionY / 2 - VolumeBonds.Height / 2,
|
|
VolumeBonds.Width, VolumeBonds.Height));
|
|
matRoi.CopyTo(matDstRoi);
|
|
|
|
return true;
|
|
}*/
|
|
|
|
#endregion
|
|
|
|
#region Equality
|
|
|
|
private bool Equals(OperationChangeResolution other)
|
|
{
|
|
return _newResolutionX == other._newResolutionX && _newResolutionY == other._newResolutionY;
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
return ReferenceEquals(this, obj) || obj is OperationChangeResolution other && Equals(other);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked
|
|
{
|
|
return ((int) _newResolutionX * 397) ^ (int) _newResolutionY;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|