diff --git a/CHANGELOG.md b/CHANGELOG.md index c67036f..e1d1a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,18 @@ # Changelog +## 05/04/2021 - v2.8.2 + +* **Operations:** + * Force validate all operations on execute if they haven't been before, if validation fails it will show the message error + * Add some utility functions to ease layer and mat allocation in the file + * Layer remove: Disallow to select and remove all layers + * Tool - Edit print parameters: Retract speed wasn't propagating the value to normal layers +* File formats: Better control, set and checking for null/empty thumbnails + ## 04/04/2021 - v2.8.1 * Clipboard Manager: As now full backups are made when removing or adding layers, the undo and redo no longer rebuilds layer properties nor Z heights -* Resin traps: Improved the detection to group areas with cross paths and process them as one whole area, this also increase the detection speed and performance (#179, #13 ) +* Resin traps: Improved the detection to group areas with cross paths and process them as one whole area, this also increase the detection speed and performance (#179, #13) * Action - Layer import: Fix a bug preventing to import layers of any kind ## 28/03/2021 - v2.8.0 diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index a6aa974..48a9da8 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -298,5 +298,29 @@ namespace UVtools.Core.Extensions return newMat; } + /// + /// Allocates a new array of mat 's + /// + /// Array size + /// + public static Mat[] Allocate(uint count) => Allocate(count, Size.Empty); + + /// + /// Allocates a new array of mat 's + /// + /// Array size + /// Image size to create, use to create a empty Mat + /// New mat array + public static Mat[] Allocate(uint count, Size size) + { + var layers = new Mat[count]; + for (var i = 0; i < layers.Length; i++) + { + layers[i] = size == Size.Empty ? new Mat() : InitMat(size); + } + + return layers; + } + } } diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index 2e4949a..f317809 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -1302,7 +1302,7 @@ namespace UVtools.Core.FileFormats if (HeaderSettings.EncryptionKey == 0) { - Random rnd = new Random(); + Random rnd = new(); HeaderSettings.EncryptionKey = (uint)rnd.Next(byte.MaxValue, int.MaxValue); } } @@ -1322,8 +1322,9 @@ namespace UVtools.Core.FileFormats for (byte i = 0; i < thumbnails.Length; i++) { var image = thumbnails[i]; + if(image is null) continue; - Preview preview = new Preview + Preview preview = new() { ResolutionX = (uint)image.Width, ResolutionY = (uint)image.Height, diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 86690fe..c36790d 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -458,7 +458,7 @@ namespace UVtools.Core.FileFormats foreach (var thumbnail in Thumbnails) { - if (thumbnail is null) continue; + if (thumbnail is null || thumbnail.IsEmpty) continue; count++; } @@ -1194,7 +1194,7 @@ namespace UVtools.Core.FileFormats { for (int i = 0; i < ThumbnailsCount; i++) { - if(ReferenceEquals(Thumbnails[i], null)) continue; + if(Thumbnails[i] is null) continue; if (Thumbnails[i].Height <= maxHeight) return Thumbnails[i]; } @@ -1232,9 +1232,18 @@ namespace UVtools.Core.FileFormats /// public void SetThumbnails(Mat[] images) { - for (var i = 0; i < ThumbnailsCount; i++) + byte imageIndex = 0; + for (int i = 0; i < ThumbnailsCount; i++) { - Thumbnails[i] = images[Math.Min(i, images.Length - 1)].Clone(); + var image = images[Math.Min(imageIndex++, images.Length - 1)]; + if (image is null || image.IsEmpty) + { + if (imageIndex >= images.Length) break; + i--; + continue; + } + + Thumbnails[i] = image.Clone(); if (Thumbnails[i].Size != ThumbnailsOriginalSize[i]) { CvInvoke.Resize(Thumbnails[i], Thumbnails[i], ThumbnailsOriginalSize[i]); @@ -1248,6 +1257,7 @@ namespace UVtools.Core.FileFormats /// Image to set public void SetThumbnails(Mat image) { + if (image is null || image.IsEmpty) return; for (var i = 0; i < ThumbnailsCount; i++) { Thumbnails[i] = image.Clone(); @@ -1299,7 +1309,7 @@ namespace UVtools.Core.FileFormats for (var i = 0; i < Thumbnails.Length; i++) { - if (Thumbnails[i] is null) continue; + if (Thumbnails[i] is null || Thumbnails[i].IsEmpty) continue; if(Thumbnails[i].Size == ThumbnailsOriginalSize[i]) continue; CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height)); } diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs index 222ded1..bc45523 100644 --- a/UVtools.Core/FileFormats/UVJFile.cs +++ b/UVtools.Core/FileFormats/UVJFile.cs @@ -163,7 +163,7 @@ namespace UVtools.Core.FileFormats public override byte ThumbnailsCount { get; } = 2; - public override System.Drawing.Size[] ThumbnailsOriginalSize { get; } = {new System.Drawing.Size(400, 400), new System.Drawing.Size(800, 480) }; + public override System.Drawing.Size[] ThumbnailsOriginalSize { get; } = {new(400, 400), new(800, 480) }; public override uint ResolutionX { @@ -346,28 +346,20 @@ namespace UVtools.Core.FileFormats if (CreatedThumbnailsCount > 0) { - using (Stream stream = outputFile.CreateEntry(FilePreviewTinyName).Open()) - { - using (var vec = new VectorOfByte()) - { - CvInvoke.Imencode(".png", Thumbnails[0], vec); - stream.WriteBytes(vec.ToArray()); - stream.Close(); - } - } + using var stream = outputFile.CreateEntry(FilePreviewTinyName).Open(); + using var vec = new VectorOfByte(); + CvInvoke.Imencode(".png", Thumbnails[0], vec); + stream.WriteBytes(vec.ToArray()); + stream.Close(); } if (CreatedThumbnailsCount > 1) { - using (Stream stream = outputFile.CreateEntry(FilePreviewHugeName).Open()) - { - using (var vec = new VectorOfByte()) - { - CvInvoke.Imencode(".png", Thumbnails[1], vec); - stream.WriteBytes(vec.ToArray()); - stream.Close(); - } - } + using Stream stream = outputFile.CreateEntry(FilePreviewHugeName).Open(); + using var vec = new VectorOfByte(); + CvInvoke.Imencode(".png", Thumbnails[1], vec); + stream.WriteBytes(vec.ToArray()); + stream.Close(); } for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index f64330b..e601878 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -431,6 +431,9 @@ namespace UVtools.Core case nameof(SlicerFile.LiftSpeed): layer.LiftSpeed = SlicerFile.LiftSpeed; break; + case nameof(SlicerFile.RetractSpeed): + layer.RetractSpeed = SlicerFile.RetractSpeed; + break; case nameof(SlicerFile.LightOffDelay): layer.LightOffDelay = SlicerFile.LightOffDelay; break; @@ -477,13 +480,16 @@ namespace UVtools.Core /// /// Set LiftHeight to 0 if previous and current have same PositionZ + /// If true also set light off to 0, otherwise current value will be kept. /// - public void SetNoLiftForSamePositionedLayers() + public void SetNoLiftForSamePositionedLayers(bool zeroLightOffDelay = false) { for (int layerIndex = 1; layerIndex < LayerCount; layerIndex++) { - if (this[layerIndex - 1].PositionZ != this[layerIndex].PositionZ) continue; - this[layerIndex].LiftHeight = 0; + var layer = this[layerIndex]; + if (this[layerIndex - 1].PositionZ != layer.PositionZ) continue; + layer.LiftHeight = 0; + //if(zeroLightOffDelay) layer.LightOffDelay = 0; } SlicerFile?.RebuildGCode(); } @@ -1762,6 +1768,34 @@ namespace UVtools.Core /// public void ReallocateEnd(uint layerCount, bool initBlack = false) => ReallocateInsert(LayerCount, layerCount, initBlack); + /// + /// Allocate layers from a Mat array + /// + /// + /// The new Layer array + public Layer[] AllocateFromMat(Mat[] mats) + { + var layers = new Layer[mats.Length]; + Parallel.For(0L, mats.Length, i => + { + layers[i] = new Layer((uint)i, mats[i], this); + }); + + return layers; + } + + /// + /// Allocate layers from a Mat array and set them to the current file + /// + /// + /// /// The new Layer array + public Layer[] AllocateAndSetFromMat(Mat[] mats) + { + var layers = AllocateFromMat(mats); + Layers = layers; + return layers; + } + /// /// Clone this object /// @@ -1800,5 +1834,7 @@ namespace UVtools.Core } #endregion + + } } diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs index f64f4c7..fc7de71 100644 --- a/UVtools.Core/Operations/Operation.cs +++ b/UVtools.Core/Operations/Operation.cs @@ -8,7 +8,6 @@ using System; using System.Drawing; -using System.Threading.Tasks; using System.Xml.Serialization; using Emgu.CV; using Emgu.CV.Util; @@ -210,6 +209,12 @@ namespace UVtools.Core.Operations /// [XmlIgnore] public bool HaveExecuted { get; private set; } + + /// + /// Gets if this operation have validated at least once + /// + [XmlIgnore] + public bool IsValidated { get; private set; } #endregion #region Constructor @@ -224,16 +229,22 @@ namespace UVtools.Core.Operations #endregion #region Methods + + public virtual string ValidateInternally() => null; + /// /// Validates the operation /// /// null or empty if validates, otherwise return a string with error message - public virtual StringTag Validate(params object[] parameters) => null; - - public bool CanValidate(params object[] parameters) + public string Validate() { - var result = Validate(parameters); - return result is null || string.IsNullOrEmpty(result.Content); + IsValidated = true; + return ValidateInternally(); + } + + public bool CanValidate() + { + return string.IsNullOrWhiteSpace(Validate()); } public void SelectAllLayers() @@ -383,7 +394,13 @@ namespace UVtools.Core.Operations public bool Execute(OperationProgress progress = null) { - if (_slicerFile is null) throw new InvalidOperationException($"{Title} can't execute due the lacking of file parent."); + if (_slicerFile is null) throw new InvalidOperationException($"{Title} can't execute due the lacking of a file parent."); + if (!IsValidated) + { + var msg = Validate(); + if(!string.IsNullOrWhiteSpace(msg)) throw new InvalidOperationException($"{Title} can't execute due some errors:\n{msg}"); + } + progress ??= new OperationProgress(); progress.Reset(ProgressAction, LayerRangeCount); HaveExecuted = true; diff --git a/UVtools.Core/Operations/OperationArithmetic.cs b/UVtools.Core/Operations/OperationArithmetic.cs index 75edfad..fd29f51 100644 --- a/UVtools.Core/Operations/OperationArithmetic.cs +++ b/UVtools.Core/Operations/OperationArithmetic.cs @@ -75,7 +75,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Calculated layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); if (string.IsNullOrWhiteSpace(_sentence)) @@ -87,7 +87,7 @@ namespace UVtools.Core.Operations else if (Operations.Count == 0) sb.AppendLine("No operations to perform."); - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs index b68f447..ed65ac8 100644 --- a/UVtools.Core/Operations/OperationBlur.cs +++ b/UVtools.Core/Operations/OperationBlur.cs @@ -39,7 +39,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Blured layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -60,7 +60,7 @@ namespace UVtools.Core.Operations } } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs index 5da95f4..e9c2a03 100644 --- a/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs +++ b/UVtools.Core/Operations/OperationCalibrateElephantFoot.cs @@ -75,7 +75,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -94,7 +94,7 @@ namespace UVtools.Core.Operations sb.AppendLine("No objects to output, please adjust the settings."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs index c57a03b..e9bdbb0 100644 --- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs +++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs @@ -114,7 +114,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -162,7 +162,7 @@ namespace UVtools.Core.Operations } } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationCalibrateGrayscale.cs b/UVtools.Core/Operations/OperationCalibrateGrayscale.cs index 215bccd..ec4e624 100644 --- a/UVtools.Core/Operations/OperationCalibrateGrayscale.cs +++ b/UVtools.Core/Operations/OperationCalibrateGrayscale.cs @@ -70,7 +70,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -83,7 +83,7 @@ namespace UVtools.Core.Operations sb.AppendLine("No divisions to output."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationCalibrateStressTower.cs b/UVtools.Core/Operations/OperationCalibrateStressTower.cs index db0490e..4d9bcb8 100644 --- a/UVtools.Core/Operations/OperationCalibrateStressTower.cs +++ b/UVtools.Core/Operations/OperationCalibrateStressTower.cs @@ -64,7 +64,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -78,7 +78,7 @@ namespace UVtools.Core.Operations sb.AppendLine("Display height must be a positive value."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationCalibrateTolerance.cs b/UVtools.Core/Operations/OperationCalibrateTolerance.cs index e73314a..2cc4d3a 100644 --- a/UVtools.Core/Operations/OperationCalibrateTolerance.cs +++ b/UVtools.Core/Operations/OperationCalibrateTolerance.cs @@ -76,7 +76,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -100,7 +100,7 @@ namespace UVtools.Core.Operations sb.AppendLine("No objects to output."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs b/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs index 40756dd..454bbbc 100644 --- a/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs +++ b/UVtools.Core/Operations/OperationCalibrateXYZAccuracy.cs @@ -77,7 +77,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Generated"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -96,7 +96,7 @@ namespace UVtools.Core.Operations sb.AppendLine("No objects to output."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs index c021753..e89aeab 100644 --- a/UVtools.Core/Operations/OperationChangeResolution.cs +++ b/UVtools.Core/Operations/OperationChangeResolution.cs @@ -74,7 +74,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Changed layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); if (SlicerFile.ResolutionX == NewResolutionX && SlicerFile.ResolutionY == NewResolutionY) @@ -88,7 +88,7 @@ namespace UVtools.Core.Operations sb.AppendLine("To fix this, try to rotate the object and/or resize to fit on this new resolution."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationDynamicLayerHeight.cs b/UVtools.Core/Operations/OperationDynamicLayerHeight.cs index 24930d6..9d123b4 100644 --- a/UVtools.Core/Operations/OperationDynamicLayerHeight.cs +++ b/UVtools.Core/Operations/OperationDynamicLayerHeight.cs @@ -95,7 +95,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Processed layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -141,7 +141,7 @@ namespace UVtools.Core.Operations } } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs index b6da2c2..cb4ab3d 100644 --- a/UVtools.Core/Operations/OperationEditParameters.cs +++ b/UVtools.Core/Operations/OperationEditParameters.cs @@ -72,7 +72,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); var changed = Modifiers.Any(modifier => modifier.HasChanged); @@ -83,7 +83,7 @@ namespace UVtools.Core.Operations } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationIPrintedThisFile.cs b/UVtools.Core/Operations/OperationIPrintedThisFile.cs index c743aa7..76c1348 100644 --- a/UVtools.Core/Operations/OperationIPrintedThisFile.cs +++ b/UVtools.Core/Operations/OperationIPrintedThisFile.cs @@ -45,7 +45,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Consumed"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -62,7 +62,7 @@ namespace UVtools.Core.Operations sb.AppendLine("Print time must be higher than 0s."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationLayerClone.cs b/UVtools.Core/Operations/OperationLayerClone.cs index 9d12ab5..3b6fd8a 100644 --- a/UVtools.Core/Operations/OperationLayerClone.cs +++ b/UVtools.Core/Operations/OperationLayerClone.cs @@ -46,7 +46,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); if (Clones <= 0) @@ -54,7 +54,7 @@ namespace UVtools.Core.Operations sb.AppendLine("Clones must be a positive number"); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs index 438cff4..fb69546 100644 --- a/UVtools.Core/Operations/OperationLayerImport.cs +++ b/UVtools.Core/Operations/OperationLayerImport.cs @@ -72,7 +72,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { /*var result = new ConcurrentBag(); Parallel.ForEach(Files, file => @@ -112,7 +112,7 @@ namespace UVtools.Core.Operations sb.AppendLine("No files to import."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs index 9d214f2..7b26095 100644 --- a/UVtools.Core/Operations/OperationLayerReHeight.cs +++ b/UVtools.Core/Operations/OperationLayerReHeight.cs @@ -44,7 +44,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -54,7 +54,7 @@ namespace UVtools.Core.Operations } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationLayerRemove.cs b/UVtools.Core/Operations/OperationLayerRemove.cs index 653eef7..8ca7e3c 100644 --- a/UVtools.Core/Operations/OperationLayerRemove.cs +++ b/UVtools.Core/Operations/OperationLayerRemove.cs @@ -8,8 +8,10 @@ using System; using System.Collections.Generic; +using System.Text; using System.Threading.Tasks; using UVtools.Core.FileFormats; +using UVtools.Core.Objects; namespace UVtools.Core.Operations { @@ -39,6 +41,18 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; + public override string ValidateInternally() + { + var sb = new StringBuilder(); + + if (LayerRangeCount == SlicerFile.LayerCount) + { + sb.AppendLine("You can't remove all layers from the file. Keep at least one."); + } + + return sb.ToString(); + } + #endregion #region Properties diff --git a/UVtools.Core/Operations/OperationMask.cs b/UVtools.Core/Operations/OperationMask.cs index 4b43b5a..f3571fb 100644 --- a/UVtools.Core/Operations/OperationMask.cs +++ b/UVtools.Core/Operations/OperationMask.cs @@ -38,7 +38,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); if (Mask is null) @@ -46,7 +46,7 @@ namespace UVtools.Core.Operations sb.AppendLine("The mask can not be empty."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs index b2cbacf..5c84b1e 100644 --- a/UVtools.Core/Operations/OperationMove.cs +++ b/UVtools.Core/Operations/OperationMove.cs @@ -40,7 +40,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -49,7 +49,7 @@ namespace UVtools.Core.Operations sb.AppendLine("Your parameters will put the model outside of build plate. Please adjust the location and margins."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs index 22398b3..15ac44d 100644 --- a/UVtools.Core/Operations/OperationPattern.cs +++ b/UVtools.Core/Operations/OperationPattern.cs @@ -49,7 +49,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -63,7 +63,7 @@ namespace UVtools.Core.Operations sb.AppendLine("Your parameters will put the object outside of the build plate, please adjust the margins."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs index 6f92bf0..f441064 100644 --- a/UVtools.Core/Operations/OperationPixelDimming.cs +++ b/UVtools.Core/Operations/OperationPixelDimming.cs @@ -70,7 +70,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Dimmed layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); /*if (WallThicknessStart == 0 && WallsOnly) @@ -100,7 +100,7 @@ namespace UVtools.Core.Operations if (item.Pattern.Cols != bytes.Length) { sb.AppendLine($"Row {row + 1} have invalid number of pixels, the pattern must have equal pixel count per line, per defined on line 1"); - return new StringTag(sb.ToString()); + return sb.ToString(); } } @@ -113,7 +113,7 @@ namespace UVtools.Core.Operations else { sb.AppendLine($"{bytes[col]} is a invalid number, use values from 0 to 255"); - return new StringTag(sb.ToString()); + return sb.ToString(); } } } @@ -125,10 +125,10 @@ namespace UVtools.Core.Operations if (Pattern is null && AlternatePattern is null) { sb.AppendLine("Either even or odd pattern must contain a valid matrix."); - return new StringTag(sb.ToString()); + return sb.ToString(); } - return new StringTag(sb.ToString()); + return sb.ToString(); } public override string ToString() @@ -149,6 +149,16 @@ namespace UVtools.Core.Operations #region Properties + public uint WallThickness + { + get => _wallThicknessStart; + set + { + WallThicknessStart = value; + WallThicknessEnd = value; + } + } + public uint WallThicknessStart { get => _wallThicknessStart; diff --git a/UVtools.Core/Operations/OperationRedrawModel.cs b/UVtools.Core/Operations/OperationRedrawModel.cs index 26e6630..06f2c77 100644 --- a/UVtools.Core/Operations/OperationRedrawModel.cs +++ b/UVtools.Core/Operations/OperationRedrawModel.cs @@ -50,7 +50,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Redraw layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -59,7 +59,7 @@ namespace UVtools.Core.Operations sb.AppendLine("The selected file is not valid."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs index fc37c87..ab0a5e5 100644 --- a/UVtools.Core/Operations/OperationRepairLayers.cs +++ b/UVtools.Core/Operations/OperationRepairLayers.cs @@ -50,7 +50,7 @@ namespace UVtools.Core.Operations public override bool CanHaveProfiles => false; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -59,7 +59,7 @@ namespace UVtools.Core.Operations sb.AppendLine("You must select at least one repair operation."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationResize.cs b/UVtools.Core/Operations/OperationResize.cs index ec81b4d..0565437 100644 --- a/UVtools.Core/Operations/OperationResize.cs +++ b/UVtools.Core/Operations/OperationResize.cs @@ -44,7 +44,7 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Resized layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { var sb = new StringBuilder(); @@ -53,7 +53,7 @@ namespace UVtools.Core.Operations sb.AppendLine("X and Y can't both be 100%."); } - return new StringTag(sb.ToString()); + return sb.ToString(); } #endregion diff --git a/UVtools.Core/Operations/OperationScripting.cs b/UVtools.Core/Operations/OperationScripting.cs index 7807d16..661daad 100644 --- a/UVtools.Core/Operations/OperationScripting.cs +++ b/UVtools.Core/Operations/OperationScripting.cs @@ -48,15 +48,15 @@ namespace UVtools.Core.Operations public override string ProgressAction => "Scripted layers"; - public override StringTag Validate(params object[] parameters) + public override string ValidateInternally() { if (!CanExecute) { - return new StringTag("Script is not loaded."); + return "Script is not loaded."; } var scriptValidation = _scriptState.ContinueWithAsync("return ScriptValidate();").Result; - return new StringTag(scriptValidation.ReturnValue); + return scriptValidation.ReturnValue; } #endregion diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 9d550de..6893a21 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 2.8.1 + 2.8.2 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 diff --git a/UVtools.ScriptSample/ScriptTestPerLayerSettingsSample.cs b/UVtools.ScriptSample/ScriptTestPerLayerSettingsSample.cs new file mode 100644 index 0000000..70e283c --- /dev/null +++ b/UVtools.ScriptSample/ScriptTestPerLayerSettingsSample.cs @@ -0,0 +1,144 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. + * 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 Emgu.CV; +using Emgu.CV.CvEnum; +using UVtools.Core.Extensions; +using UVtools.Core.Operations; +using UVtools.Core.Scripting; + +namespace UVtools.ScriptSample +{ + /// + /// Change layer properties to random values + /// + public class ScriptTestPerLayerSettingsSample : ScriptGlobals + { + private ScriptCheckBoxInput InputDoNotUseLift = new() + { + Label = "Do not perform the lift sequence for same height layers", + ToolTip = "Not all printers are compatible with this even if they can maintain same Z position, some will require a obligatory lift/retract", + Value = true + }; + + /// + /// Set configurations here, this function trigger just after load a script + /// + public void ScriptInit() + { + Script.Name = "Test per layer settings capability with a print"; + Script.Description = "Print this file to check if your printer is able to have per layer independent settings.\n" + + "1) Load a file that you previous printed into UVtools\n" + + "2) Run this script\n" + + "3) Go to File -> Save As, and give it a new name\n" + + "4) Remove printer VAT and head/plate\n" + + "5) Print the created file and observe the printer LCD and movements:\n" + + "- First layer must show the whole face and do the normal lift sequence and raise to the next layer.\n" + + "- Then all the renaming layers should print one object per layer at same height, if not, then your printer is not able.\n" + + "Note: Look at printer screen to confirm the layer position, exposure time is set to 5s.\n" + + "If you find yours compatible and not on the official list, please report to us.\n" + + "https://github.com/sn4k3/UVtools/wiki/Printer-compability-with-per-layer-settings-and-advanced-tools"; + Script.Author = "Tiago Conceição"; + Script.Version = new Version(0, 1); + Script.UserInputs.Add(InputDoNotUseLift); + } + + /// + /// Validate user inputs here, this function trigger when user click on execute + /// + /// A error message, empty or null if validation passes. + public string ScriptValidate() + { + return null; + } + + /// + /// Execute the script, this function trigger when when user click on execute and validation passes + /// + /// True if executes successfully to the end, otherwise false. + public bool ScriptExecute() + { + const byte layerCount = 5; + const ushort eyeDiameter = 300; + const ushort noseHeight = eyeDiameter; + const ushort noseThickness = 100; + const ushort mouthHeight = 300; + const ushort faceSpacing = 150; + const LineType lineType = LineType.AntiAlias; + Progress.Reset("Generating layers", layerCount); // Sets the progress name and number of items to process + + // Layer 0 = Whole face + // Layer 1 = Left eye + // Layer 2 = Nose + // Layer 3 = Right eye + // Layer 4 = Mouth + // Exercise for you: Do eyebrows + var mats = EmguExtensions.Allocate(layerCount, SlicerFile.Resolution); // Allocate x images with file resolution + + int x, y; + int xCenter = (int) (SlicerFile.ResolutionX / 2); + //int yCenter = (int) (SlicerFile.ResolutionY / 2); + + // Do the left eye + x = xCenter - noseThickness/2 - faceSpacing - eyeDiameter/2; + y = faceSpacing; + CvInvoke.Circle(mats[0], new Point(x, y), eyeDiameter/2, EmguExtensions.WhiteByte, -1, lineType); + CvInvoke.Circle(mats[1], new Point(x, y), eyeDiameter/2, EmguExtensions.WhiteByte, -1, lineType); + Progress++; + + // Do the right eye, the mirror of left... + x = (int)(SlicerFile.ResolutionX - x); + CvInvoke.Circle(mats[0], new Point(x, y), eyeDiameter / 2, EmguExtensions.WhiteByte, -1, lineType); + CvInvoke.Circle(mats[3], new Point(x, y), eyeDiameter / 2, EmguExtensions.WhiteByte, -1, lineType); + Progress++; + + // Do the noose + x = xCenter - noseThickness / 2; + CvInvoke.Rectangle(mats[0], new Rectangle(x, y, noseThickness, noseHeight), EmguExtensions.WhiteByte, -1, lineType); + CvInvoke.Rectangle(mats[2], new Rectangle(x, y, noseThickness, noseHeight), EmguExtensions.WhiteByte, -1, lineType); + Progress++; + + // Do the mouth + x = xCenter; + y += noseHeight + faceSpacing; + CvInvoke.Ellipse(mats[0], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteByte, -1, lineType); + CvInvoke.Ellipse(mats[4], new Point(x, y), new Size(eyeDiameter+faceSpacing+noseThickness/2, mouthHeight), 0, 0, 180, EmguExtensions.WhiteByte, -1, lineType); + + SlicerFile.LayerManager.AllocateAndSetFromMat(mats); // Replace layers and rebuild properties + + SlicerFile.BottomLayerCount = 1; // Set one bottom layer, the whole face + SlicerFile.BottomExposureTime = 5; // Set exposure to be fixed at 5s + SlicerFile.ExposureTime = 5; // Set exposure to be fixed at 5s + + // Set layers 2-4 all same z height as layer 1 + for (int layerIndex = 2; layerIndex < mats.Length; layerIndex++) + { + SlicerFile[layerIndex].PositionZ = SlicerFile[1].PositionZ; + } + + if (InputDoNotUseLift.Value) + { + SlicerFile.LayerManager.SetNoLiftForSamePositionedLayers(); + } + Progress++; + + // Move me to the middle + new OperationMove(SlicerFile).Execute(Progress); + + // Generate a cool waves pattern, just because i can :) + var pdOp = new OperationPixelDimming(SlicerFile) {WallThickness = 25}; + pdOp.GenerateInfill("Waves"); + pdOp.Execute(Progress); + + // return true if not cancelled by user + return !Progress.Token.IsCancellationRequested; + } + } +} diff --git a/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs index eaa58db..eaff935 100644 --- a/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolScriptingControl.axaml.cs @@ -103,9 +103,9 @@ namespace UVtools.WPF.Controls.Tools TextBox tbScriptName = new() { IsReadOnly = true, - Text = $"{Operation.ScriptGlobals.Script.Name} v{Operation.ScriptGlobals.Script.Version} by {Operation.ScriptGlobals.Script.Author}", + Text = $"{Operation.ScriptGlobals.Script.Name} | Version: {Operation.ScriptGlobals.Script.Version} by {Operation.ScriptGlobals.Script.Author}", UseFloatingWatermark = true, - Watermark = "Script name, Version and Author" + Watermark = "Script name, version and author" }; TextBox tbScriptDescription = new() diff --git a/UVtools.WPF/MainWindow.Information.cs b/UVtools.WPF/MainWindow.Information.cs index 7e35a3c..3822b94 100644 --- a/UVtools.WPF/MainWindow.Information.cs +++ b/UVtools.WPF/MainWindow.Information.cs @@ -128,7 +128,7 @@ namespace UVtools.WPF if (!IsFileLoaded) return; var index = value - 1; if (index >= SlicerFile.CreatedThumbnailsCount) return; - if (SlicerFile.Thumbnails[index] is null) return; + if (SlicerFile.Thumbnails[index] is null || SlicerFile.Thumbnails[index].IsEmpty) return; if (!RaiseAndSetIfChanged(ref _visibleThumbnailIndex, value)) return; VisibleThumbnailImage = SlicerFile.Thumbnails[index].ToBitmap(); diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs index 57293c9..2261565 100644 --- a/UVtools.WPF/Program.cs +++ b/UVtools.WPF/Program.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.ExceptionServices; using Avalonia; +using UVtools.WPF.Extensions; namespace UVtools.WPF { @@ -31,12 +32,12 @@ namespace UVtools.WPF } - private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) + private static async void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) { Exception ex = (Exception)e.ExceptionObject; ErrorLog.AppendLine("Fatal Non-UI Error", ex.ToString()); - - /*try + + try { string errorMsg = "An application error occurred. Please contact the administrator with the following information:\n\n" + $"{ex}"; @@ -46,7 +47,7 @@ namespace UVtools.WPF catch (Exception exception) { Debug.WriteLine(exception); - }*/ + } } // Avalonia configuration, don't remove; also used by visual designer. diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 4e847ca..e6a7ed6 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ LICENSE https://github.com/sn4k3/UVtools Git - 2.8.1 + 2.8.2