mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-11 19:12:31 +02:00
2c7ad09dc0
- (Change) `Layer.IsBottomLayer` no longer calculate the value using the position of the layer, a new property `IsBottomLayerByHeight` is now used to get that result - (Improvement) Tool - Double exposure: Increase the bottom layer count per cloned bottom layer - (Improvement) Calibration - Exposure time finder: Set the absolute bottom layer count accordingly when also testing for bottom time - (Improvement) Goo: Enforce Wait times or Light-off-delay flag based on property set - (Fix) AnyCubic and Goo: `PerLayerSetting` flag was set inverted causing printer not to follow layer settings when it should and also the otherwise (#689) - (Fix) Tool - Scripting: Prevent from reload UI multiple times when using profiles (#694)
149 lines
4.5 KiB
C#
149 lines
4.5 KiB
C#
using Avalonia.Controls;
|
|
using Avalonia.Markup.Xaml;
|
|
using Emgu.CV;
|
|
using Emgu.CV.CvEnum;
|
|
using Emgu.CV.Structure;
|
|
using System;
|
|
using System.Drawing;
|
|
using UVtools.Core.Extensions;
|
|
using UVtools.Core.Operations;
|
|
using UVtools.WPF.Extensions;
|
|
using UVtools.WPF.Windows;
|
|
using Bitmap = Avalonia.Media.Imaging.Bitmap;
|
|
|
|
namespace UVtools.WPF.Controls.Tools;
|
|
|
|
public class ToolMaskControl : ToolControl
|
|
{
|
|
private bool _isMaskInverted;
|
|
private byte _genMinimumBrightness = 200;
|
|
private byte _genMaximumBrightness = byte.MaxValue;
|
|
private uint _genDiameter;
|
|
private Bitmap _maskImage;
|
|
public OperationMask Operation => BaseOperation as OperationMask;
|
|
|
|
public bool IsMaskInverted
|
|
{
|
|
get => _isMaskInverted;
|
|
set
|
|
{
|
|
if(!RaiseAndSetIfChanged(ref _isMaskInverted, value)) return;
|
|
if (!Operation.HaveInputMask) return;
|
|
Operation.InvertMask();
|
|
MaskImage = Operation.Mask.ToBitmapParallel();
|
|
}
|
|
}
|
|
|
|
public byte GenMinimumBrightness
|
|
{
|
|
get => _genMinimumBrightness;
|
|
set => RaiseAndSetIfChanged(ref _genMinimumBrightness, value);
|
|
}
|
|
|
|
public byte GenMaximumBrightness
|
|
{
|
|
get => _genMaximumBrightness;
|
|
set => RaiseAndSetIfChanged(ref _genMaximumBrightness, value);
|
|
}
|
|
|
|
public uint GenDiameter
|
|
{
|
|
get => _genDiameter;
|
|
set => RaiseAndSetIfChanged(ref _genDiameter, value);
|
|
}
|
|
|
|
public string InfoPrinterResolutionStr => $"Printer resolution: {App.SlicerFile.Resolution}";
|
|
public string InfoMaskResolutionStr => $"Mask resolution: "+ (Operation.HaveInputMask ? Operation.Mask.Size.ToString() : "(Unloaded)");
|
|
|
|
public Bitmap MaskImage
|
|
{
|
|
get => _maskImage;
|
|
set
|
|
{
|
|
if(!RaiseAndSetIfChanged(ref _maskImage, value)) return;
|
|
RaisePropertyChanged(nameof(InfoMaskResolutionStr));
|
|
ParentWindow.ButtonOkEnabled = Operation.HaveInputMask;
|
|
}
|
|
}
|
|
|
|
public ToolMaskControl()
|
|
{
|
|
BaseOperation = new OperationMask(SlicerFile);
|
|
if (!ValidateSpawn()) return;
|
|
InitializeComponent();
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
AvaloniaXamlLoader.Load(this);
|
|
}
|
|
|
|
public override void Callback(ToolWindow.Callbacks callback)
|
|
{
|
|
switch (callback)
|
|
{
|
|
case ToolWindow.Callbacks.Init:
|
|
ParentWindow.ButtonOkEnabled = false;
|
|
break;
|
|
case ToolWindow.Callbacks.AfterLoadProfile:
|
|
case ToolWindow.Callbacks.ClearROI:
|
|
Operation.Mask = null;
|
|
MaskImage = null;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public async void ImportImageMask()
|
|
{
|
|
var dialog = new OpenFileDialog
|
|
{
|
|
Filters = Helpers.ImagesFileFilter,
|
|
AllowMultiple = false
|
|
};
|
|
|
|
var result = await dialog.ShowAsync(ParentWindow);
|
|
if (result is null || result.Length == 0) return;
|
|
|
|
try
|
|
{
|
|
Operation.LoadFromFile(result[0], _isMaskInverted, App.MainWindow.ROI.Size.IsEmpty ? SlicerFile.Resolution : App.MainWindow.ROI.Size);
|
|
MaskImage = Operation.Mask.ToBitmapParallel();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
await ParentWindow.MessageBoxError(e.ToString(), "Error while trying to read the image");
|
|
}
|
|
}
|
|
|
|
public void GenerateMask()
|
|
{
|
|
var roi = App.MainWindow.ROI;
|
|
Operation.Mask = roi.IsEmpty ? App.MainWindow.LayerCache.Image.NewBlank() : new Mat(roi.Size, DepthType.Cv8U, 1);
|
|
|
|
int radius = (int)_genDiameter;
|
|
if (radius == 0)
|
|
{
|
|
radius = Math.Min(Operation.Mask.Width, Operation.Mask.Height) / 2;
|
|
}
|
|
else
|
|
{
|
|
radius = Math.Clamp(radius, 2, Math.Min(Operation.Mask.Width, Operation.Mask.Height)) / 2;
|
|
}
|
|
|
|
var maxScalar = new MCvScalar(_genMaximumBrightness);
|
|
Operation.Mask.SetTo(maxScalar);
|
|
|
|
var center = new Point(Operation.Mask.Width / 2, Operation.Mask.Height / 2);
|
|
var colorDifference = _genMinimumBrightness - _genMaximumBrightness;
|
|
//CvInvoke.Circle(Mask, center, radius, minScalar, -1);
|
|
|
|
for (decimal i = 1; i < radius; i++)
|
|
{
|
|
int color = (int)(_genMinimumBrightness - i / radius * colorDifference); //or some another color calculation
|
|
CvInvoke.Circle(Operation.Mask, center, (int)i, new MCvScalar(color), 2);
|
|
}
|
|
|
|
if (_isMaskInverted) Operation.InvertMask();
|
|
MaskImage = Operation.Mask.ToBitmapParallel();
|
|
}
|
|
} |