diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-02-16 01:30:26 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-02-16 01:30:26 +0300 |
commit | f69a0f1175603e87558e0587e5a29ea882ef7e9b (patch) | |
tree | cd8534e3c6188c0cb5727697d8699bfc419b9d45 | |
parent | a78703662ec6bfb575df283c1e1b4e4776723b43 (diff) |
v2.4.6v2.4.6
* **(Improvement) Calibration - Elephant Foot:** (#145)
* Remove text from bottom layers to prevent islands from not adhering to plate
* Add a option to extrude text up to a height
* **(Improvement) Calibration - Exposure time finder:** (#144)
* Increase the left and right margin to 10mm
* Allow to iterate over pixel brightness and generate dimmed objects to test multiple times at once
* **(Fix) File format PWS:**
* Some files would produce black layers if pixels are not full whites, Antialiasing level was not inherit from source
* Antialiasing level was forced 1 and not read the value from file properties
* Antialiasing threshold pixel math was producing the wrong pixel value
* **(Fix) Raw images (jpg, png, etc):** (#146)
* Set layer height to be 0.01mm by default to allow the use of some tools
* When add layers by clone or other tool it don't update layers height, positions, indexes, leading to crashes
* **(Fix) Actions - Import Layers:** (#146, #147)
* ROI calculation error leading to not process images that can potential fit inside the volumes
* Out-of-bounds calculation for Stack type
* Replace type was calculating out-of-bounds calculation like Stack type when is not required to and can lead to skip images
* Better image ROI colection for Insert and Replace types instead of capture the center most
* (Fix) Settings window: Force a redraw on open to fix auto sizes
19 files changed, 619 insertions, 185 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 392e1a7..59f1166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 15/02/2021 - v2.4.6 + +* **(Improvement) Calibration - Elephant Foot:** (#145) + * Remove text from bottom layers to prevent islands from not adhering to plate + * Add a option to extrude text up to a height +* **(Improvement) Calibration - Exposure time finder:** (#144) + * Increase the left and right margin to 10mm + * Allow to iterate over pixel brightness and generate dimmed objects to test multiple times at once +* **(Fix) File format PWS:** + * Some files would produce black layers if pixels are not full whites, Antialiasing level was not inherit from source + * Antialiasing level was forced 1 and not read the value from file properties + * Antialiasing threshold pixel math was producing the wrong pixel value +* **(Fix) Raw images (jpg, png, etc):** (#146) + * Set layer height to be 0.01mm by default to allow the use of some tools + * When add layers by clone or other tool it don't update layers height, positions, indexes, leading to crashes +* **(Fix) Actions - Import Layers:** (#146, #147) + * ROI calculation error leading to not process images that can potential fit inside the volumes + * Out-of-bounds calculation for Stack type + * Replace type was calculating out-of-bounds calculation like Stack type when is not required to and can lead to skip images + * Better image ROI colection for Insert and Replace types instead of capture the center most +* (Fix) Settings window: Force a redraw on open to fix auto sizes + ## 12/02/2021 - v2.4.5 * (Add) Setting: Expand and show tool descriptions by default @@ -46,4 +46,5 @@ * Claus Pfeilschifter * Chris Taatgen * Andrew Griffiths -* Abhinav Sinha
\ No newline at end of file +* Abhinav Sinha +* Randy Savell
\ No newline at end of file diff --git a/CreateRelease.WPF.ps1 b/CreateRelease.WPF.ps1 index 607d0f4..ded2d46 100644 --- a/CreateRelease.WPF.ps1 +++ b/CreateRelease.WPF.ps1 @@ -29,9 +29,9 @@ class FixedEncoder : System.Text.UTF8Encoding { #################################### ### Configuration ### #################################### -$enableMSI = $true +$enableMSI = $false $buildOnly = $null -#$buildOnly = ""#"win-x64" +#$buildOnly = "osx-x64"#"win-x64" # Profilling $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index b5ed369..2eaa12a 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -8,6 +8,7 @@ using System; using System.Drawing; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Emgu.CV; using Emgu.CV.CvEnum; @@ -275,15 +276,25 @@ namespace UVtools.Core.Extensions return mat; } - public static Mat RoiFromCenter(this Mat mat, Size size) + public static Mat RoiFromCenter(this Mat mat, Size targetSize, Rectangle roi) { - if (size == mat.Size) return mat; - return new Mat(mat, new Rectangle( - mat.Size.Width / 2 - size.Width / 2, - mat.Size.Height / 2 - size.Height / 2, - size.Width, - size.Height - )); + if (targetSize == mat.Size) return mat; + var newMat = InitMat(targetSize); + + var roiMat = new Mat(mat, roi); + + + //int xStart = mat.Width / 2 - targetSize.Width / 2; + //int yStart = mat.Height / 2 - targetSize.Height / 2; + + var newMatRoi = new Mat(newMat, new Rectangle( + targetSize.Width / 2 - roi.Width / 2, + targetSize.Height / 2 - roi.Height / 2, + roi.Width, + roi.Height + )); + roiMat.CopyTo(newMatRoi); + return newMat; } } diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 074070f..69cb349 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -37,9 +37,14 @@ namespace UVtools.Core.FileFormats private const string ExtractConfigFileName = "Configuration"; private const string ExtractConfigFileExtension = "ini"; + public const ushort DefaultBottomLayerCount = 4; + + public const float DefaultBottomExposureTime = 30; public const float DefaultBottomLiftHeight = 5; public const float DefaultLiftHeight = 5; public const float DefaultBottomLiftSpeed = 100; + + public const float DefaultExposureTime = 3; public const float DefaultLiftSpeed = 100; public const float DefaultRetractSpeed = 100; public const float DefaultBottomLightOffDelay = 0; @@ -639,7 +644,10 @@ namespace UVtools.Core.FileFormats public virtual uint LayerCount { get => LayerManager?.Count ?? 0; - set { } + set { + RaisePropertyChanged(); + RaisePropertyChanged(nameof(NormalLayerCount)); + } } #region Universal Properties @@ -647,7 +655,7 @@ namespace UVtools.Core.FileFormats /// <summary> /// Gets or sets the number of initial layer count /// </summary> - public virtual ushort BottomLayerCount { get; set; } + public virtual ushort BottomLayerCount { get; set; } = DefaultBottomLayerCount; /// <summary> /// Gets the number of normal layer count @@ -657,12 +665,12 @@ namespace UVtools.Core.FileFormats /// <summary> /// Gets or sets the initial exposure time for <see cref="BottomLayerCount"/> in seconds /// </summary> - public virtual float BottomExposureTime { get; set; } + public virtual float BottomExposureTime { get; set; } = DefaultBottomExposureTime; /// <summary> /// Gets or sets the normal layer exposure time in seconds /// </summary> - public virtual float ExposureTime { get; set; } + public virtual float ExposureTime { get; set; } = DefaultExposureTime; /// <summary> /// Gets or sets the bottom layer off time in seconds @@ -1074,6 +1082,7 @@ namespace UVtools.Core.FileFormats for (var i = 0; i < ThumbnailsCount; i++) { Thumbnails[i] = image.Clone(); + if (ThumbnailsOriginalSize is null || i >= ThumbnailsOriginalSize.Length) continue; if (Thumbnails[i].Size != ThumbnailsOriginalSize[i]) { CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]); diff --git a/UVtools.Core/FileFormats/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs index c97ff1d..da2cec9 100644 --- a/UVtools.Core/FileFormats/ImageFile.cs +++ b/UVtools.Core/FileFormats/ImageFile.cs @@ -66,7 +66,7 @@ namespace UVtools.Core.FileFormats set { } } - public override float LayerHeight { get; set; } = 0; + public override float LayerHeight { get; set; } = 0.01f; /*public override float PrintTime { get; } = 0; public override float UsedMaterial { get; } = 0; public override float MaterialCost { get; } = 0; diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index 610b6a7..5447c13 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -505,7 +505,7 @@ namespace UVtools.Core.FileFormats rawData.Add(by); } - for (byte aalevel = 0; aalevel < Parent.AntiAliasing; aalevel++) + for (byte aalevel = 1; aalevel <= Parent.AntiAliasing; aalevel++) { obit = false; rep = 0; @@ -516,7 +516,9 @@ namespace UVtools.Core.FileFormats // aa 2: 255 127 // aa 4: 255 191 127 63 // aa 8: 255 223 191 159 127 95 63 31 - byte threshold = (byte)(256 / Parent.AntiAliasing * aalevel - 1); + //byte threshold = (byte)(256 / Parent.AntiAliasing * aalevel - 1); + // threshold := byte(int(255 * (level + 1) / (levels + 1))) + 1 + byte threshold = (byte) (255 * aalevel / (Parent.AntiAliasing + 1) + 1); for (int pixel = 0; pixel < imageLength; pixel++) @@ -845,8 +847,13 @@ namespace UVtools.Core.FileFormats public override byte AntiAliasing { - get => 4; - set { } + get => (byte) HeaderSettings.AntiAliasing; + set + { + HeaderSettings.AntiAliasing = value.Clamp(1, 16); + ValidateAntiAliasingLevel(); + RaisePropertyChanged(); + } } public override float LayerHeight diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs index 74ca871..6da632c 100644 --- a/UVtools.Core/Layer/Layer.cs +++ b/UVtools.Core/Layer/Layer.cs @@ -205,26 +205,13 @@ namespace UVtools.Core { _compressedBytes = value; IsModified = true; - if (!ReferenceEquals(ParentLayerManager, null)) + if (ParentLayerManager is not null) ParentLayerManager.BoundingRectangle = Rectangle.Empty; + RaisePropertyChanged(); } } /// <summary> - /// Gets a computed layer filename, padding zeros are equal to layer count digits - /// </summary> - public string Filename => FormatFileName("layer"); - - /// <summary> - /// Gets if layer has been modified - /// </summary> - public bool IsModified - { - get => _isModified; - set => RaiseAndSetIfChanged(ref _isModified, value); - } - - /// <summary> /// Gets or sets a new image instance /// </summary> public Mat LayerMat @@ -232,7 +219,7 @@ namespace UVtools.Core get { Mat mat = new(); - CvInvoke.Imdecode(CompressedBytes, ImreadModes.Grayscale, mat); + CvInvoke.Imdecode(_compressedBytes, ImreadModes.Grayscale, mat); return mat; } set @@ -252,26 +239,34 @@ namespace UVtools.Core { get { - Mat mat = LayerMat; + var mat = LayerMat; CvInvoke.CvtColor(mat, mat, ColorConversion.Gray2Bgr); return mat; } } + /// <summary> + /// Gets a computed layer filename, padding zeros are equal to layer count digits + /// </summary> + public string Filename => FormatFileName("layer"); + + /// <summary> + /// Gets if layer has been modified + /// </summary> + public bool IsModified + { + get => _isModified; + set => RaiseAndSetIfChanged(ref _isModified, value); + } + #endregion #region Constructor - public Layer(uint index, byte[] compressedBytes, LayerManager parentLayerManager) + + public Layer(uint index, LayerManager parentLayerManager) { ParentLayerManager = parentLayerManager; - Index = index; - //Filename = filename ?? $"Layer{index}.png"; - CompressedBytes = compressedBytes; - IsModified = false; - /*if (compressedBytes.Length > 0) - { - GetBoundingRectangle(); - }*/ + _index = index; if (parentLayerManager is null) return; _positionZ = SlicerFile.GetHeightFromLayer(index); @@ -282,13 +277,23 @@ namespace UVtools.Core _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); } + public Layer(uint index, byte[] compressedBytes, LayerManager parentLayerManager) : this(index, parentLayerManager) + { + CompressedBytes = compressedBytes; + _isModified = false; + /*if (compressedBytes.Length > 0) + { + GetBoundingRectangle(); + }*/ + } + public Layer(uint index, byte[] compressedBytes, FileFormat slicerFile) : this(index, compressedBytes, slicerFile.LayerManager) {} - public Layer(uint index, Mat layerMat, LayerManager parentLayerManager) : this(index, new byte[0], parentLayerManager) + public Layer(uint index, Mat layerMat, LayerManager parentLayerManager) : this(index, parentLayerManager) { LayerMat = layerMat; - IsModified = false; + _isModified = false; } public Layer(uint index, Mat layerMat, FileFormat slicerFile) : this(index, layerMat, slicerFile.LayerManager) { } diff --git a/UVtools.Core/Objects/ExposureItem.cs b/UVtools.Core/Objects/ExposureItem.cs index 374a567..817ee78 100644 --- a/UVtools.Core/Objects/ExposureItem.cs +++ b/UVtools.Core/Objects/ExposureItem.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace UVtools.Core.Objects { @@ -12,7 +8,7 @@ namespace UVtools.Core.Objects private decimal _layerHeight; private decimal _bottomExposure; private decimal _exposure; - + private byte _brightness = byte.MaxValue; /// <summary> /// Gets or sets the layer height in millimeters @@ -42,25 +38,41 @@ namespace UVtools.Core.Objects set => RaiseAndSetIfChanged(ref _exposure, Math.Round(value, 2)); } - public bool IsValid => _layerHeight > 0 && _bottomExposure > 0 && _exposure > 0; + /// <summary> + /// Gets or sets the brightness level + /// </summary> + public byte Brightness + { + get => _brightness; + set + { + if(!RaiseAndSetIfChanged(ref _brightness, value)) return; + RaisePropertyChanged(nameof(BrightnessPercent)); + } + } + + public decimal BrightnessPercent => Math.Round(_brightness * 100m / byte.MaxValue, 2); + + public bool IsValid => _layerHeight > 0 && _bottomExposure > 0 && _exposure > 0 && _brightness > 0; public ExposureItem() { } - public ExposureItem(decimal layerHeight, decimal bottomExposure = 0, decimal exposure = 0) + public ExposureItem(decimal layerHeight, decimal bottomExposure = 0, decimal exposure = 0, byte brightness = 255) { _layerHeight = Math.Round(layerHeight, 2); _bottomExposure = Math.Round(bottomExposure, 2); _exposure = Math.Round(exposure, 2); + _brightness = brightness; } public override string ToString() { - return $"{nameof(LayerHeight)}: {LayerHeight}mm, {nameof(BottomExposure)}: {BottomExposure}s, {nameof(Exposure)}: {Exposure}s"; + return $"{nameof(LayerHeight)}: {_layerHeight}mm, {nameof(BottomExposure)}: {_bottomExposure}s, {nameof(Exposure)}: {_exposure}s, {nameof(Brightness)}: {_brightness} ({BrightnessPercent} %)"; } private bool Equals(ExposureItem other) { - return _layerHeight == other._layerHeight && _bottomExposure == other._bottomExposure && _exposure == other._exposure; + return _layerHeight == other._layerHeight && _bottomExposure == other._bottomExposure && _exposure == other._exposure && _brightness == other._brightness; } public override bool Equals(object obj) @@ -70,7 +82,7 @@ namespace UVtools.Core.Objects public override int GetHashCode() { - return HashCode.Combine(_layerHeight, _bottomExposure, _exposure); + return HashCode.Combine(_layerHeight, _bottomExposure, _exposure, _brightness); } public int CompareTo(ExposureItem other) @@ -81,7 +93,9 @@ namespace UVtools.Core.Objects if (layerHeightComparison != 0) return layerHeightComparison; var bottomExposureComparison = _bottomExposure.CompareTo(other._bottomExposure); if (bottomExposureComparison != 0) return bottomExposureComparison; - return _exposure.CompareTo(other._exposure); + var exposureComparison = _exposure.CompareTo(other._exposure); + if (exposureComparison != 0) return exposureComparison; + return _brightness.CompareTo(other._brightness); } } } diff --git a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs index 0b3f789..3b77e81 100644 --- a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs +++ b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs @@ -34,6 +34,8 @@ namespace UVtools.Core.Operations private decimal _normalExposure = 12; private decimal _partScale = 1; private byte _margin = 30; + private bool _extrudeText = true; + private decimal _textHeight = 1; private bool _enableAntiAliasing = true; private bool _mirrorOutput; private bool _isErodeEnabled = true; @@ -46,6 +48,7 @@ namespace UVtools.Core.Operations private byte _dimmingEndBrightness = 200; private byte _dimmingBrightnessSteps = 20; private bool _outputOriginalPart = true; + #endregion @@ -99,6 +102,7 @@ namespace UVtools.Core.Operations var result = $"[Layer Height: {_layerHeight}] " + $"[Layers: {_bottomLayers}/{_normalLayers}] " + $"[Exposure: {_bottomExposure}/{_normalExposure}] " + + $"[Extrude: {_extrudeText} {_textHeight}mm]" + $"[Scale: {_partScale}] [Margin: {_margin}] [ORI: {_outputOriginalPart}]" + $"[E: {_erodeStartIteration}-{_erodeEndIteration} S{_erodeIterationSteps}] " + $"[D: W{_dimmingWallThickness} B{_dimmingStartBrightness}-{_dimmingEndBrightness} S{_dimmingBrightnessSteps}] " + @@ -170,7 +174,7 @@ namespace UVtools.Core.Operations } } - public uint LayerCount => (uint)(_bottomLayers + _normalLayers); + public uint LayerCount => (uint)(_bottomLayers + _normalLayers + (_extrudeText ? Math.Floor(_textHeight / _layerHeight) : 0)); public decimal BottomHeight => Math.Round(LayerHeight * BottomLayers, 2); public decimal NormalHeight => Math.Round(LayerHeight * NormalLayers, 2); @@ -201,6 +205,18 @@ namespace UVtools.Core.Operations set => RaiseAndSetIfChanged(ref _margin, value); } + public bool ExtrudeText + { + get => _extrudeText; + set => RaiseAndSetIfChanged(ref _extrudeText, value); + } + + public decimal TextHeight + { + get => _textHeight; + set => RaiseAndSetIfChanged(ref _textHeight, value); + } + public bool OutputOriginalPart { get => _outputOriginalPart; @@ -354,10 +370,10 @@ namespace UVtools.Core.Operations #endregion #region Equality - + private bool Equals(OperationCalibrateElephantFoot other) { - return _layerHeight == other._layerHeight && _syncLayers == other._syncLayers && _bottomLayers == other._bottomLayers && _normalLayers == other._normalLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _partScale == other._partScale && _margin == other._margin && _isErodeEnabled == other._isErodeEnabled && _erodeStartIteration == other._erodeStartIteration && _erodeEndIteration == other._erodeEndIteration && _erodeIterationSteps == other._erodeIterationSteps && _isDimmingEnabled == other._isDimmingEnabled && _dimmingWallThickness == other._dimmingWallThickness && _dimmingStartBrightness == other._dimmingStartBrightness && _dimmingEndBrightness == other._dimmingEndBrightness && _dimmingBrightnessSteps == other._dimmingBrightnessSteps && _outputOriginalPart == other._outputOriginalPart && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput; + return _layerHeight == other._layerHeight && _syncLayers == other._syncLayers && _bottomLayers == other._bottomLayers && _normalLayers == other._normalLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _partScale == other._partScale && _margin == other._margin && _extrudeText == other._extrudeText && _textHeight == other._textHeight && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _isErodeEnabled == other._isErodeEnabled && _erodeStartIteration == other._erodeStartIteration && _erodeEndIteration == other._erodeEndIteration && _erodeIterationSteps == other._erodeIterationSteps && _isDimmingEnabled == other._isDimmingEnabled && _dimmingWallThickness == other._dimmingWallThickness && _dimmingStartBrightness == other._dimmingStartBrightness && _dimmingEndBrightness == other._dimmingEndBrightness && _dimmingBrightnessSteps == other._dimmingBrightnessSteps && _outputOriginalPart == other._outputOriginalPart; } public override bool Equals(object obj) @@ -376,8 +392,9 @@ namespace UVtools.Core.Operations hashCode.Add(_normalExposure); hashCode.Add(_partScale); hashCode.Add(_margin); + hashCode.Add(_extrudeText); + hashCode.Add(_textHeight); hashCode.Add(_enableAntiAliasing); - hashCode.Add(_outputOriginalPart); hashCode.Add(_mirrorOutput); hashCode.Add(_isErodeEnabled); hashCode.Add(_erodeStartIteration); @@ -388,7 +405,7 @@ namespace UVtools.Core.Operations hashCode.Add(_dimmingStartBrightness); hashCode.Add(_dimmingEndBrightness); hashCode.Add(_dimmingBrightnessSteps); - + hashCode.Add(_outputOriginalPart); return hashCode.ToHashCode(); } @@ -402,11 +419,12 @@ namespace UVtools.Core.Operations /// <returns></returns> public Mat[] GetLayers() { - Mat[] layers = new Mat[2]; + Mat[] layers = new Mat[3]; var anchor = new Point(-1, -1); var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor); layers[0] = EmguExtensions.InitMat(SlicerFile.Resolution); + layers[2] = layers[0].Clone(); LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected; int length = (int) (250 * _partScale); int triangleLength = (int) (50 * _partScale); @@ -488,26 +506,41 @@ namespace UVtools.Core.Operations void addText(Mat mat, ushort number, params string[] text) { - CvInvoke.PutText(mat, number.ToString(), new Point((int) (100 * _partScale), (int) (55 * _partScale)), font, 1.5 * (double) _partScale, EmguExtensions.BlackByte, (int) (4 * _partScale), lineType); - CvInvoke.PutText(mat, "UVtools EP", new Point(fontStartX, fontStartY), font, 0.8 * (double) _partScale, EmguExtensions.BlackByte, (int) (2 * _partScale), lineType); - CvInvoke.PutText(mat, $"{Microns}um", new Point(fontStartX, fontStartY + fontMargin), font, fontScale, EmguExtensions.BlackByte, fontThickness, lineType); - CvInvoke.PutText(mat, $"{BottomExposure}|{NormalExposure}s", new Point(fontStartX, fontStartY + fontMargin * 2), font, fontScale, EmguExtensions.BlackByte, fontThickness, lineType); + var color = _extrudeText ? EmguExtensions.WhiteByte : EmguExtensions.BlackByte; + CvInvoke.PutText(mat, number.ToString(), new Point((int) (100 * _partScale), (int) (55 * _partScale)), font, 1.5 * (double) _partScale, color, (int) (4 * _partScale), lineType); + CvInvoke.PutText(mat, "UVtools EP", new Point(fontStartX, fontStartY), font, 0.8 * (double) _partScale, color, (int) (2 * _partScale), lineType); + CvInvoke.PutText(mat, $"{Microns}um", new Point(fontStartX, fontStartY + fontMargin), font, fontScale, color, fontThickness, lineType); + CvInvoke.PutText(mat, $"{BottomExposure}|{NormalExposure}s", new Point(fontStartX, fontStartY + fontMargin * 2), font, fontScale, color, fontThickness, lineType); if (text is null) return; for (var i = 0; i < text.Length; i++) { CvInvoke.PutText(mat, text[i], new Point(fontStartX, fontStartY + fontMargin * (i + 3)), font, - fontScale, EmguExtensions.BlackByte, fontThickness, lineType); + fontScale, color, fontThickness, lineType); } } ushort count = 0; + layers[1] = layers[0].Clone(); + if (OutputOriginalPart) { - using var roi = new Mat(layers[0], new Rectangle(new Point(currentX, currentY), shape.Size)); - shape.CopyTo(roi); - addText(roi, ++count, "ORI"); + using var roi0 = new Mat(layers[0], new Rectangle(new Point(currentX, currentY), shape.Size)); + shape.CopyTo(roi0); + + using var roi1 = new Mat(layers[1], new Rectangle(new Point(currentX, currentY), shape.Size)); + shape.CopyTo(roi1); + + if (_extrudeText) + { + using var roi2 = new Mat(layers[2], new Rectangle(new Point(currentX, currentY), shape.Size)); + addText(roi2, ++count, "ORI"); + } + else + { + addText(roi1, ++count, "ORI"); + } } else { @@ -515,7 +548,7 @@ namespace UVtools.Core.Operations } - layers[1] = layers[0].Clone(); + if (IsErodeEnabled) { @@ -541,7 +574,16 @@ namespace UVtools.Core.Operations using (var roi = new Mat(layers[1], new Rectangle(new Point(currentX, currentY), shape.Size))) { shape.CopyTo(roi); - addText(roi, count, $"E: {iteration}i"); + if (_extrudeText) + { + using var roi1 = new Mat(layers[2], new Rectangle(new Point(currentX, currentY), shape.Size)); + addText(roi1, count, $"E: {iteration}i"); + } + else + { + addText(roi, count, $"E: {iteration}i"); + } + } using (var roi = new Mat(layers[0], @@ -550,7 +592,7 @@ namespace UVtools.Core.Operations { CvInvoke.Erode(shape, erode, ErodeKernel.Matrix, ErodeKernel.Anchor, iteration, BorderType.Reflect101, default); erode.CopyTo(roi); - addText(roi, count, $"E: {iteration}i"); + //addText(roi, count, $"E: {iteration}i"); } } } @@ -578,7 +620,15 @@ namespace UVtools.Core.Operations using (var roi = new Mat(layers[1], new Rectangle(new Point(currentX, currentY), shape.Size))) { shape.CopyTo(roi); - addText(roi, count, $"W: {DimmingWallThickness}", $"B: {brightness}"); + if (_extrudeText) + { + using var roi1 = new Mat(layers[2], new Rectangle(new Point(currentX, currentY), shape.Size)); + addText(roi1, count, $"W: {DimmingWallThickness}", $"B: {brightness}"); + } + else + { + addText(roi, count, $"W: {DimmingWallThickness}", $"B: {brightness}"); + } } using (var roi = new Mat(layers[0], @@ -595,7 +645,7 @@ namespace UVtools.Core.Operations CvInvoke.BitwiseAnd(diff, mask, target); CvInvoke.Add(erode, target, target); target.CopyTo(roi); - addText(roi, count, $"W: {DimmingWallThickness}", $"B: {brightness}"); + //addText(roi, count, $"W: {DimmingWallThickness}", $"B: {brightness}"); } } } @@ -649,30 +699,46 @@ namespace UVtools.Core.Operations progress++; - var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager) - { - IsModified = true - }; + var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager); + + Layer extrudeLayer = null; + var moveOp = new OperationMove(SlicerFile, bottomLayer.BoundingRectangle); + moveOp.Execute(layers[0]); + moveOp.Execute(layers[1]); + var layer = new Layer(0, layers[1], SlicerFile.LayerManager) { IsModified = true }; - var moveOp = new OperationMove(SlicerFile, bottomLayer.BoundingRectangle); - moveOp.Execute(layers[0]); - moveOp.Execute(layers[1]); + if (_extrudeText) + { + moveOp.Execute(layers[2]); + extrudeLayer = new Layer(0, layers[2], SlicerFile.LayerManager) + { + IsModified = true + }; + + } bottomLayer.LayerMat = layers[0]; - layer.LayerMat = layers[1]; progress++; for (uint layerIndex = 0; - layerIndex < LayerCount; + layerIndex < _bottomLayers + _normalLayers; layerIndex++) { newLayers[layerIndex] = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone()); } + if (_extrudeText) + { + for (uint layerIndex = (uint) (_bottomLayers + _normalLayers); layerIndex < LayerCount; layerIndex++) + { + newLayers[layerIndex] = extrudeLayer.Clone(); + } + } + foreach (var mat in layers) { mat.Dispose(); diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs index f66a3e7..9fd4d25 100644 --- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs +++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Drawing; using System.Linq; using System.Text; @@ -45,7 +44,7 @@ namespace UVtools.Core.Operations private decimal _bottomExposure = 60; private decimal _normalExposure = 12; private decimal _topBottomMargin = 5; - private decimal _leftRightMargin = 5; + private decimal _leftRightMargin = 10; private byte _chamferLayers = 5; private byte _erodeBottomIterations = 0; private decimal _partMargin = 0; @@ -67,9 +66,16 @@ namespace UVtools.Core.Operations private byte _textThickness = 2; private string _text = "ABGHJKLMQRSTUVWXZ%&#"; + private bool _multipleBrightness; + private CalibrateExposureFinderMultipleBrightnessExcludeFrom _multipleBrightnessExcludeFrom = CalibrateExposureFinderMultipleBrightnessExcludeFrom.BottomAndBase; + private string _multipleBrightnessValues = "255, 242, 230, 217, 204, 191"; + private decimal _multipleBrightnessGenExposureTime; + + private bool _multipleLayerHeight; private decimal _multipleLayerHeightMaximum = 0.1m; private decimal _multipleLayerHeightStep = 0.01m; + private bool _multipleExposures; private ExposureGenTypes _exposureGenType = ExposureGenTypes.Linear; private bool _exposureGenIgnoreBaseExposure; @@ -82,7 +88,6 @@ namespace UVtools.Core.Operations private ObservableCollection<ExposureItem> _exposureTable = new(); private CalibrateExposureFinderShapes _holeShape = CalibrateExposureFinderShapes.Square; - #endregion #region Overrides @@ -147,6 +152,14 @@ namespace UVtools.Core.Operations } } + if (_multipleBrightness) + { + if (MultipleBrightnessValuesArray.Length == 0) + { + sb.AppendLine($"[MB]: Multiple brightness tests are enabled but no valid values are set, use from 1 to 255."); + } + } + return new StringTag(sb.ToString()); } @@ -220,13 +233,21 @@ namespace UVtools.Core.Operations public decimal BottomExposure { get => _bottomExposure; - set => RaiseAndSetIfChanged(ref _bottomExposure, Math.Round(value, 2)); + set + { + if(!RaiseAndSetIfChanged(ref _bottomExposure, Math.Round(value, 2))) return; + RaisePropertyChanged(nameof(MultipleBrightnessTable)); + } } public decimal NormalExposure { get => _normalExposure; - set => RaiseAndSetIfChanged(ref _normalExposure, Math.Round(value, 2)); + set + { + if(!RaiseAndSetIfChanged(ref _normalExposure, Math.Round(value, 2))) return; + RaisePropertyChanged(nameof(MultipleBrightnessTable)); + } } public decimal TopBottomMargin @@ -337,9 +358,9 @@ namespace UVtools.Core.Operations { if (string.IsNullOrWhiteSpace(mmStr)) continue; if (!decimal.TryParse(mmStr, out var mm)) continue; - if(mm <= 0) continue; - var mmPx = (int) Math.Floor(mm * Ppmm); - if(holes.Contains(mmPx) || mmPx > 500) continue; + var mmPx = (int)Math.Floor(mm * Ppmm); + if (mmPx <= 0 || mmPx > 500) continue; + if(holes.Contains(mmPx)) continue; holes.Add((int)Math.Floor(mm * Ppmm)); } } @@ -350,8 +371,8 @@ namespace UVtools.Core.Operations { if (string.IsNullOrWhiteSpace(pxStr)) continue; if (!int.TryParse(pxStr, out var px)) continue; - if (px <= 0) continue; - if (holes.Contains(px) || px > 500) continue; + if (px <= 0 || px > 500) continue; + if (holes.Contains(px)) continue; holes.Add(px); } } @@ -411,9 +432,9 @@ namespace UVtools.Core.Operations { if (string.IsNullOrWhiteSpace(mmStr)) continue; if (!decimal.TryParse(mmStr, out var mm)) continue; - if (mm <= 0) continue; var mmPx = (int)Math.Floor(mm * Xppmm); - if (bars.Contains(mmPx) || mmPx > 500) continue; + if (mmPx <= 0 || mmPx > 500) continue; + if (bars.Contains(mmPx)) continue; bars.Add((int)Math.Floor(mm * Xppmm)); } } @@ -424,8 +445,8 @@ namespace UVtools.Core.Operations { if (string.IsNullOrWhiteSpace(pxStr)) continue; if (!int.TryParse(pxStr, out var px)) continue; - if (px <= 0) continue; - if (bars.Contains(px) || px > 500) continue; + if (px <= 0 || px > 500) continue; + if (bars.Contains(px)) continue; bars.Add(px); } } @@ -475,6 +496,72 @@ namespace UVtools.Core.Operations } } + public bool MultipleBrightness + { + get => _multipleBrightness; + set => RaiseAndSetIfChanged(ref _multipleBrightness, value); + } + + public CalibrateExposureFinderMultipleBrightnessExcludeFrom MultipleBrightnessExcludeFrom + { + get => _multipleBrightnessExcludeFrom; + set => RaiseAndSetIfChanged(ref _multipleBrightnessExcludeFrom, value); + } + + public string MultipleBrightnessValues + { + get => _multipleBrightnessValues; + set + { + if(!RaiseAndSetIfChanged(ref _multipleBrightnessValues, value)) return; + RaisePropertyChanged(nameof(MultipleBrightnessTable)); + } + } + + public List<ExposureItem> MultipleBrightnessTable + { + get + { + var brightnesses = MultipleBrightnessValuesArray; + return brightnesses.Select(brightness => (ExposureItem) + new( + _layerHeight, + Math.Round(brightness * _bottomExposure / byte.MaxValue, 2), + Math.Round(brightness * _normalExposure / byte.MaxValue, 2), + brightness)).ToList(); + } + } + + public decimal MultipleBrightnessGenExposureTime + { + get => _multipleBrightnessGenExposureTime; + set => RaiseAndSetIfChanged(ref _multipleBrightnessGenExposureTime, value); + } + + /// <summary> + /// Gets all holes in pixels and ordered + /// </summary> + public byte[] MultipleBrightnessValuesArray + { + get + { + List<byte> values = new(); + + var split = _multipleBrightnessValues.Split(',', StringSplitOptions.TrimEntries); + foreach (var brightnessStr in split) + { + if (string.IsNullOrWhiteSpace(brightnessStr)) continue; + if (!byte.TryParse(brightnessStr, out var brightness)) continue; + if (brightness <= 0 || brightness > 255) continue; + if (values.Contains(brightness)) continue; + values.Add(brightness); + } + + return values.OrderByDescending(brightness => brightness).ToArray(); + } + } + + public bool MultipleLayerHeight { get => _multipleLayerHeight; @@ -611,6 +698,10 @@ namespace UVtools.Core.Operations _exposureGenManualBottom = (decimal) SlicerFile.BottomExposureTime; if (_exposureGenManualNormal == 0) _exposureGenManualNormal = (decimal)SlicerFile.ExposureTime; + if (_multipleBrightnessGenExposureTime == 0) + { + _multipleBrightnessGenExposureTime = (decimal)SlicerFile.ExposureTime; + } if (!SlicerFile.HavePrintParameterPerLayerModifier(FileFormat.PrintParameterModifier.ExposureSeconds)) { @@ -638,6 +729,14 @@ namespace UVtools.Core.Operations public static Array MeasuresItems => Enum.GetValues(typeof(Measures)); + public enum CalibrateExposureFinderMultipleBrightnessExcludeFrom : byte + { + None, + Bottom, + BottomAndBase + } + public static Array MultipleBrightnessExcludeFromItems => Enum.GetValues(typeof(CalibrateExposureFinderMultipleBrightnessExcludeFrom)); + public enum ExposureGenTypes : byte { Linear, @@ -649,11 +748,9 @@ namespace UVtools.Core.Operations #region Equality - - private bool Equals(OperationCalibrateExposureFinder other) { - return _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _unitOfMeasure == other._unitOfMeasure && _holeDiametersMm == other._holeDiametersMm && _holeDiametersPx == other._holeDiametersPx && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _holeShape == other._holeShape; + return _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && Equals(_exposureTable, other._exposureTable) && _holeShape == other._holeShape; } public override bool Equals(object obj) @@ -679,8 +776,8 @@ namespace UVtools.Core.Operations hashCode.Add(_featuresHeight); hashCode.Add(_featuresMargin); hashCode.Add((int) _unitOfMeasure); - hashCode.Add(_holeDiametersMm); hashCode.Add(_holeDiametersPx); + hashCode.Add(_holeDiametersMm); hashCode.Add(_barSpacing); hashCode.Add(_barLength); hashCode.Add(_barVerticalSplitter); @@ -690,6 +787,9 @@ namespace UVtools.Core.Operations hashCode.Add(_textScale); hashCode.Add(_textThickness); hashCode.Add(_text); + hashCode.Add(_multipleBrightness); + hashCode.Add((int) _multipleBrightnessExcludeFrom); + hashCode.Add(_multipleBrightnessValues); hashCode.Add(_multipleLayerHeight); hashCode.Add(_multipleLayerHeightMaximum); hashCode.Add(_multipleLayerHeightStep); @@ -699,9 +799,6 @@ namespace UVtools.Core.Operations hashCode.Add(_exposureGenBottomStep); hashCode.Add(_exposureGenNormalStep); hashCode.Add(_exposureGenTests); - hashCode.Add(_exposureGenManualLayerHeight); - hashCode.Add(_exposureGenManualBottom); - hashCode.Add(_exposureGenManualNormal); hashCode.Add(_exposureTable); hashCode.Add((int) _holeShape); return hashCode.ToHashCode(); @@ -1039,6 +1136,10 @@ namespace UVtools.Core.Operations var anchor = new Point(-1, -1); using var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor); + var brightnesses = MultipleBrightnessValuesArray; + + if (brightnesses.Length == 0 || !_multipleBrightness) brightnesses = new[] {byte.MaxValue}; + void AddLayer(decimal currentHeight, decimal layerHeight, decimal bottomExposure, decimal normalExposure) { var layerDifference = currentHeight / layerHeight; @@ -1046,59 +1147,96 @@ namespace UVtools.Core.Operations if (!layerDifference.IsInteger()) return; // Not at right height to process with layer height //Debug.WriteLine($"{currentHeight} / {layerHeight} = {layerDifference}, Floor={Math.Floor(layerDifference)}"); + using Mat mat = EmguExtensions.InitMat(SlicerFile.Resolution); + int layerCountOnHeight = (int)Math.Floor(currentHeight / layerHeight); + bool isBottomLayer = layerCountOnHeight <= _bottomLayers; + bool isBaseLayer = currentHeight <= _baseHeight; + ushort microns = (ushort)Math.Floor(layerHeight * 1000); Point position; - ExposureItem key = new(layerHeight, bottomExposure, normalExposure); + bool addSomething = false; - if (table.TryGetValue(key, out var pos)) - { - position = pos; - } - else + foreach(var brightness in brightnesses) { - if (currentX + layers[0].Width + sideMarginPx > SlicerFile.ResolutionX) + var bottomExposureTemp = bottomExposure; + var normalExposureTemp = normalExposure; + ExposureItem key = new(layerHeight, bottomExposure, normalExposure, brightness); + + if (table.TryGetValue(key, out var pos)) { - currentX = sideMarginPx; - currentY += layers[0].Height + (int)Math.Floor(_partMargin * Yppmm); + position = pos; } - - if (currentY + layers[0].Height + topBottomMarginPx > SlicerFile.ResolutionY) + else { - return; // Reach the end + if (currentX + layers[0].Width + sideMarginPx > SlicerFile.ResolutionX) + { + currentX = sideMarginPx; + currentY += layers[0].Height + (int)Math.Floor(_partMargin * Yppmm); + } + + if (currentY + layers[0].Height + topBottomMarginPx > SlicerFile.ResolutionY) + { + break; // Reach the end + } + + position = new Point(currentX, currentY); + table.Add(key, new Point(currentX, currentY)); + + currentX += layers[0].Width + (int)Math.Floor(_partMargin * Xppmm); } - position = new Point(currentX, currentY); - table.Add(key, new Point(currentX, currentY)); + + Mat matRoi = new(mat, new Rectangle(position, layers[0].Size)); - currentX += layers[0].Width + (int)Math.Floor(_partMargin * Xppmm); - } + layers[isBaseLayer ? 0 : 1].CopyTo(matRoi); - ushort microns = (ushort)Math.Floor(layerHeight * 1000); + if (isBottomLayer && _erodeBottomIterations > 0) + { + CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _erodeBottomIterations, BorderType.Reflect101, default); + } - Mat mat = EmguExtensions.InitMat(SlicerFile.Resolution); - Mat matRoi = new(mat, new Rectangle(position, layers[0].Size)); + if (layerCountOnHeight < _chamferLayers) + { + CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default); + } - int layerCountOnHeight = (int)Math.Floor(currentHeight / layerHeight); - bool isBottomLayer = layerCountOnHeight <= _bottomLayers; - bool isBaseLayer = currentHeight <= _baseHeight; - layers[isBaseLayer ? 0 : 1].CopyTo(matRoi); + if (_multipleBrightness && brightness < 255) + { + // normalExposure - 255 + // x - brightness + normalExposureTemp = Math.Round(normalExposure * brightness / byte.MaxValue, 2); + if (_multipleBrightnessExcludeFrom == CalibrateExposureFinderMultipleBrightnessExcludeFrom.None) + { + bottomExposureTemp = Math.Round(bottomExposure * brightness / byte.MaxValue, 2); + } + } - if (isBottomLayer && _erodeBottomIterations > 0) - { - CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _erodeBottomIterations, BorderType.Reflect101, default); - } + var textHeightStart = matRoi.Height - featuresMarginY - TextMarkingSpacing; + CvInvoke.PutText(matRoi, $"{microns}u", new Point(TextMarkingStartX, textHeightStart), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + CvInvoke.PutText(matRoi, $"{bottomExposureTemp}s", new Point(TextMarkingStartX, textHeightStart + TextMarkingLineBreak), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + CvInvoke.PutText(matRoi, $"{normalExposureTemp}s", new Point(TextMarkingStartX, textHeightStart + TextMarkingLineBreak * 2), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + CvInvoke.PutText(matRoi, $"{microns}u", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + CvInvoke.PutText(matRoi, $"{bottomExposureTemp}s", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart + TextMarkingLineBreak), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + CvInvoke.PutText(matRoi, $"{normalExposureTemp}s", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart + TextMarkingLineBreak * 2), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - if (layerCountOnHeight < _chamferLayers) - { - CvInvoke.Erode(matRoi, matRoi, kernel, anchor, _chamferLayers - layerCountOnHeight, BorderType.Reflect101, default); + if(_multipleBrightness) + { + CvInvoke.PutText(matRoi, brightness.ToString(), new Point(matRoi.Width / 3, 35), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + if (brightness < 255 && + (_multipleBrightnessExcludeFrom == CalibrateExposureFinderMultipleBrightnessExcludeFrom.None || + _multipleBrightnessExcludeFrom == CalibrateExposureFinderMultipleBrightnessExcludeFrom.Bottom && !isBottomLayer || + _multipleBrightnessExcludeFrom == CalibrateExposureFinderMultipleBrightnessExcludeFrom.BottomAndBase && !isBottomLayer && !isBaseLayer) + ) + { + using var pattern = matRoi.CloneBlank(); + pattern.SetTo(new MCvScalar(brightness)); + CvInvoke.BitwiseAnd(matRoi, pattern, matRoi, matRoi); + } + } + + addSomething = true; } - var textHeightStart = matRoi.Height - featuresMarginY - TextMarkingSpacing; - CvInvoke.PutText(matRoi, $"{microns}u", new Point(TextMarkingStartX, textHeightStart), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - CvInvoke.PutText(matRoi, $"{bottomExposure}s", new Point(TextMarkingStartX, textHeightStart + TextMarkingLineBreak), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - CvInvoke.PutText(matRoi, $"{normalExposure}s", new Point(TextMarkingStartX, textHeightStart + TextMarkingLineBreak * 2), TextMarkingFontFace, TextMarkingScale, EmguExtensions.WhiteByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - CvInvoke.PutText(matRoi, $"{microns}u", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - CvInvoke.PutText(matRoi, $"{bottomExposure}s", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart + TextMarkingLineBreak), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); - CvInvoke.PutText(matRoi, $"{normalExposure}s", new Point(matRoi.Width - featuresMarginX * 2 - holes[^1] + TextMarkingStartX, textHeightStart + TextMarkingLineBreak * 2), TextMarkingFontFace, TextMarkingScale, EmguExtensions.BlackByte, TextMarkingThickness, _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected); + if (!addSomething) return; Layer layer = new(layerIndex++, mat, SlicerFile) { @@ -1112,7 +1250,6 @@ namespace UVtools.Core.Operations IsModified = true }; newLayers.Add(layer); - mat.Dispose(); progress++; } diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs index 86b2b94..c85273d 100644 --- a/UVtools.Core/Operations/OperationLayerImport.cs +++ b/UVtools.Core/Operations/OperationLayerImport.cs @@ -11,6 +11,7 @@ using System.Collections.ObjectModel; using System.Drawing; using System.IO; using System.Linq; +using System.Runtime.InteropServices.ComTypes; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; @@ -304,37 +305,43 @@ namespace UVtools.Core.Operations { case ImportTypes.Insert: if (SlicerFile.Resolution != fileFormat.Resolution && - (SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || - SlicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; + (SlicerFile.Resolution.Width < fileFormatBoundingRectangle.Width || + SlicerFile.Resolution.Height < fileFormatBoundingRectangle.Height)) continue; SlicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount); break; case ImportTypes.Replace: case ImportTypes.Stack: if (SlicerFile.Resolution != fileFormat.Resolution && - (SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || - SlicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; + (SlicerFile.Resolution.Width < fileFormatBoundingRectangle.Width || + SlicerFile.Resolution.Height < fileFormatBoundingRectangle.Height)) continue; - if(fileFormatBoundingRectangle.Width >= SlicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= SlicerFile.ResolutionY) - continue; + //if(fileFormatBoundingRectangle.Width >= SlicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= SlicerFile.ResolutionY) + // continue; - int x = 0; - int y = 0; - - if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width < - SlicerFile.ResolutionX) - { - x = boundingRectangle.Right + _stackMargin; - } - else + if (_importType == ImportTypes.Stack) { - y = boundingRectangle.Bottom + _stackMargin; - } + int x = 0; + int y = 0; + + if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width < + SlicerFile.ResolutionX) + { + x = boundingRectangle.Right + _stackMargin; + } + else + { + y = boundingRectangle.Bottom + _stackMargin; + } - if (y >= SlicerFile.ResolutionY) - continue; + if (x + fileFormatBoundingRectangle.Width >= SlicerFile.ResolutionX) + continue; + if (y + fileFormatBoundingRectangle.Height >= SlicerFile.ResolutionY) + continue; - roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height); + roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, + fileFormatBoundingRectangle.Height); + } if (_extendBeyondLayerCount) { @@ -385,7 +392,7 @@ namespace UVtools.Core.Operations } using var layer = fileFormat[i].LayerMat; - using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution); + using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution, fileFormatBoundingRectangle); SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile); break; @@ -400,7 +407,7 @@ namespace UVtools.Core.Operations } using var layer = fileFormat[i].LayerMat; - using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution); + using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution, fileFormatBoundingRectangle); SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile); break; } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index de882cc..e9bad39 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl> <Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description> - <Version>2.4.5</Version> + <Version>2.4.6</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml index c424156..badccba 100644 --- a/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml +++ b/UVtools.WPF/Controls/Calibrators/CalibrateElephantFootControl.axaml @@ -9,7 +9,7 @@ <Grid ColumnDefinitions="Auto,10,350"> <StackPanel Spacing="10"> <Grid - RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto" + RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto" ColumnDefinitions="Auto,10,150,5,Auto,20,Auto,10,150,5,Auto" > @@ -21,8 +21,7 @@ Minimum="0.01" Maximum="0.30" FormatString="F02" - Value="{Binding Operation.LayerHeight}" - /> + Value="{Binding Operation.LayerHeight}"/> <TextBlock Grid.Row="0" Grid.Column="4" VerticalAlignment="Center" Text="mm"/> @@ -110,7 +109,6 @@ VerticalAlignment="Center" Text="Margin:"/> <NumericUpDown Grid.Row="6" Grid.Column="8" - Increment="1" Minimum="0" Maximum="255" @@ -119,7 +117,35 @@ VerticalAlignment="Center" Text="px"/> - <StackPanel Grid.Row="8" Grid.Column="0" + <TextBlock Grid.Row="8" Grid.Column="0" + VerticalAlignment="Center" + Text="Markings:"/> + + <ToggleSwitch Grid.Row="8" Grid.Column="2" + Grid.ColumnSpan="2" + OffContent="Intrude text" OnContent="Extrude text" + IsChecked="{Binding Operation.ExtrudeText}"/> + + <TextBlock Grid.Row="8" Grid.Column="6" + VerticalAlignment="Center" + IsEnabled="{Binding Operation.ExtrudeText}" + Text="Text height:"/> + + <NumericUpDown Grid.Row="8" Grid.Column="8" + Increment="0.5" + Minimum="0.5" + Maximum="10" + FormatString="F2" + IsEnabled="{Binding Operation.ExtrudeText}" + Value="{Binding Operation.TextHeight}"/> + + <TextBlock Grid.Row="8" Grid.Column="10" + VerticalAlignment="Center" + IsEnabled="{Binding Operation.ExtrudeText}" + Text="mm"/> + + + <StackPanel Grid.Row="10" Grid.Column="0" VerticalAlignment="Center" Spacing="0"> <TextBlock @@ -132,7 +158,7 @@ </StackPanel> - <StackPanel Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="9" + <StackPanel Grid.Row="10" Grid.Column="2" Grid.ColumnSpan="9" VerticalAlignment="Center" Spacing="0"> <TextBlock FontWeight="Bold"> @@ -149,17 +175,17 @@ Text="{Binding Operation.ObjectCount}"/> </StackPanel> - <CheckBox Grid.Row="8" Grid.Column="6" + <CheckBox Grid.Row="10" Grid.Column="6" Grid.ColumnSpan="5" IsChecked="{Binding Operation.EnableAntiAliasing}" Content="Enable Anti-Aliasing" /> - - <CheckBox Grid.Row="10" Grid.Column="0" + + <CheckBox Grid.Row="12" Grid.Column="0" Grid.ColumnSpan="6" IsChecked="{Binding Operation.OutputOriginalPart}" Content="Output an unmodified part (The original)" /> - <CheckBox Grid.Row="10" Grid.Column="6" + <CheckBox Grid.Row="12" Grid.Column="6" Grid.ColumnSpan="5" ToolTip.Tip="Most of the printers requires a mirror output to print with the correct orientation" IsChecked="{Binding Operation.MirrorOutput}" diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml index f375bff..507a922 100644 --- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml +++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml @@ -415,6 +415,119 @@ </Expander> </Border> + <Border BorderBrush="Black" + BorderThickness="1" + Padding="5"> + <Expander IsExpanded="True"> + <Expander.Header> + <TextBlock Text="Multiple brightness" + FontWeight="Bold" + Cursor="Hand"/> + + </Expander.Header> + + <StackPanel Spacing="10"> + + <TextBlock Text="Only printers able to do Anti-Aliasing and enabled on file can support this, make sure your is supported or else it can print a full white or full black model. +
Also take into consideration some printers/formats have fixed usable AA levels and all in between will be threshold, study this first. +
If your printer is able to do 'Multiple exposures times per layer', please use that method instead of this (More accurate and AA threshold free)."/> + + <CheckBox + Content="Enable - For advanced users only!" + IsChecked="{Binding Operation.MultipleBrightness}"/> + + <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto" + ColumnDefinitions="Auto,10,200,5,Auto,20,Auto,10,Auto,5,Auto,5,Auto" + IsEnabled="{Binding Operation.MultipleBrightness}"> + + <TextBlock Grid.Row="0" Grid.Column="0" + ToolTip.Tip="Do not change brightness from the selected layers. Full brightness of 255 is applied to the skip layers." + Text="Exclude from:" + VerticalAlignment="Center"/> + <ComboBox Grid.Row="0" Grid.Column="2" + VerticalAlignment="Center" + HorizontalAlignment="Stretch" + Items="{Binding Operation.MultipleBrightnessExcludeFromItems}" + SelectedItem="{Binding Operation.MultipleBrightnessExcludeFrom}"/> + <TextBlock Grid.Row="0" Grid.Column="4" + Text="layers" + VerticalAlignment="Center"/> + + <TextBlock Grid.Row="0" Grid.Column="6" + ToolTip.Tip="Append a brightness level to the list by giving a desired exposure time. Supplied time must be lower than the commun exposure time or you need to increase it on the commun 'Normal Exposure'." + Text="Generate by exposure time:" + VerticalAlignment="Center"/> + + <NumericUpDown Grid.Row="0" Grid.Column="8" + Increment="0.10" + Minimum="0.10" + Maximum="{Binding Operation.NormalExposure}" + FormatString="F02" + Value="{Binding Operation.MultipleBrightnessGenExposureTime}"/> + + <TextBlock Grid.Row="0" Grid.Column="10" + Text="s" + VerticalAlignment="Center"/> + + <Button + Grid.Row="0" Grid.Column="12" VerticalContentAlignment="Center" + HorizontalContentAlignment="Center" + VerticalAlignment="Stretch" + Command="{Binding BrightnessExposureGenAdd}"> + <StackPanel Orientation="Horizontal" Spacing="10"> + <Image Source="/Assets/Icons/plus-16x16.png"/> + <TextBlock + VerticalAlignment="Center" + Text="Add"/> + </StackPanel> + </Button> + + <TextBlock Grid.Row="2" Grid.Column="0" + Text="Brightnesses:" + ToolTip.Tip="From 1-255, where 1 is almost black and 255 is full white. No half numbers are allowed." + VerticalAlignment="Center"/> + + <TextBox Grid.Row="2" Grid.Column="2" + Grid.ColumnSpan="11" + Text="{Binding Operation.MultipleBrightnessValues}"/> + </Grid> + + + <DataGrid + Name="BrightnessTable" + CanUserReorderColumns="True" + CanUserResizeColumns="True" + CanUserSortColumns="True" + GridLinesVisibility="Horizontal" + IsReadOnly="True" + ClipboardCopyMode="IncludeHeader" + VerticalAlignment="Stretch" + Margin="0,-10,0,0" + IsEnabled="{Binding Operation.MultipleBrightness}" + Items="{Binding Operation.MultipleBrightnessTable}"> + <DataGrid.Columns> + <DataGridTextColumn Header="Brightness" + Binding="{Binding Brightness}" + Width="Auto" /> + <DataGridTextColumn Header="Percent (%)" + Binding="{Binding BrightnessPercent}" + Width="Auto" /> + <DataGridTextColumn Header="Bottom exposure (s)" + Binding="{Binding BottomExposure}" + Width="Auto" /> + <DataGridTextColumn Header="Exposure (s)" + Binding="{Binding Exposure}" + Width="Auto" /> + </DataGrid.Columns> + + </DataGrid> + + + + </StackPanel> + </Expander> + </Border> + <Border BorderBrush="Black" BorderThickness="1" Padding="5" diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs index e92c190..4a901ed 100644 --- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs +++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Timers; using Avalonia; @@ -7,6 +8,7 @@ using Avalonia.Media.Imaging; using Avalonia.Threading; using DynamicData; using MessageBox.Avalonia.Enums; +using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Objects; using UVtools.Core.Operations; @@ -83,6 +85,18 @@ namespace UVtools.WPF.Controls.Calibrators } } + public void BrightnessExposureGenAdd() + { + var values = Operation.MultipleBrightnessValuesArray.ToList(); + // normal exposure - 255 + // wanted - x + byte brightness = (byte)Math.Round(Operation.MultipleBrightnessGenExposureTime * byte.MaxValue / Operation.NormalExposure).Clamp(1, byte.MaxValue); + if (values.Contains(brightness)) return; + values.Add(brightness); + values.Sort((b, b1) => b1.CompareTo(b)); + Operation.MultipleBrightnessValues = string.Join(", ", values); + } + public async void GenerateExposureTable() { if (Operation.ExposureTable.Count > 0) diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs index 2045a79..26e70d7 100644 --- a/UVtools.WPF/Program.cs +++ b/UVtools.WPF/Program.cs @@ -22,8 +22,7 @@ namespace UVtools.WPF // Add the event handler for handling non-UI thread exceptions to the event. AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException; - BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } private static async void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -45,8 +44,8 @@ namespace UVtools.WPF public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure<App>() .UsePlatformDetect() - .With(new Win32PlatformOptions { AllowEglInitialization = true}) - .With(new X11PlatformOptions { UseGpu = true, UseEGL = true }) + .With(new Win32PlatformOptions { AllowEglInitialization = true/*, UseWgl = true*/}) + .With(new X11PlatformOptions { UseGpu = true/*, UseEGL = true*/ }) .With(new MacOSPlatformOptions { ShowInDock = true }) .With(new AvaloniaNativePlatformOptions { UseGpu = true }) .UseSkia() diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index ddc666e..170a4a5 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ <PackageLicenseFile>LICENSE</PackageLicenseFile> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryType>Git</RepositoryType> - <Version>2.4.5</Version> + <Version>2.4.6</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs index 8cbcd29..edc4bc4 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml.cs +++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs @@ -86,12 +86,15 @@ namespace UVtools.WPF.Windows protected override void OnOpened(EventArgs e) { base.OnOpened(e); - SizeToContent = SizeToContent.Manual; + //SizeToContent = SizeToContent.Manual; Position = new PixelPoint( (int)(App.MainWindow.Position.X + App.MainWindow.Width / 2 - Width / 2), App.MainWindow.Position.Y + 20 ); + + SelectedTabIndex = 1; + SelectedTabIndex = 0; } protected override void OnClosed(EventArgs e) |