diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2020-09-12 06:05:32 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2020-09-12 06:05:32 +0300 |
commit | 5cfd62d36e6ad9193a044bfca2a0e2dd4ae71928 (patch) | |
tree | a0516c7bfc3ad8098283be6f3bab7b358b0ff5b0 | |
parent | 67c9d7139d19f8356b21a19f2b8062a5c107beab (diff) |
v0.8.1.0v0.8.1.0
* (Add) Tools can now run inside a ROI (#49)
* (Add) Layer preview: Hold-Shift + Left-drag to select an ROI (Region of interest) on image, that region will be used instead of whole image when running some tools
* (Add) Layer preview: Hold-Shift + Hold-Alt + Left-drag to select and auto adjust the ROI to the contained objects, that region will be used instead of whole image when running some tools
* (Add) Layer preview: Hold-Shift + Right-click on a object to select its bounding area, that region will be used instead of whole image when running some tools
* (Add) Layer preview: ESC key to clear ROI
* (Add) Layer preview: Overlay text with hints for current action
* (Add) Tool - Move: Now possible to do a copy move instead of a cut move
* (Add) Arrow wait cursor to progress loadings
* (Change) Layer preview: Hold-Shift key to select issues and pick pixel position/brightness changed to Hold-Control key
* (Change) Layer preview: Shift+click combination to zoom-in changed to Alt+click
* (Fix) CTB v3: Bad file when re-encoding
36 files changed, 845 insertions, 217 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d01576c..2726bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,20 @@ # Changelog -## /08/2020 - v0.8.1.0 +## 12/09/2020 - v0.8.1.0 -* (Add) Layer preview: Hold-Shift key to select an ROI (Region of interest) on image, that region will be used instead of whole image when running some tools +* (Add) Tools can now run inside a ROI (#49) +* (Add) Layer preview: Hold-Shift + Left-drag to select an ROI (Region of interest) on image, that region will be used instead of whole image when running some tools +* (Add) Layer preview: Hold-Shift + Hold-Alt + Left-drag to select and auto adjust the ROI to the contained objects, that region will be used instead of whole image when running some tools +* (Add) Layer preview: Hold-Shift + Right-click on a object to select its bounding area, that region will be used instead of whole image when running some tools * (Add) Layer preview: ESC key to clear ROI * (Add) Layer preview: Overlay text with hints for current action +* (Add) Tool - Move: Now possible to do a copy move instead of a cut move +* (Add) Arrow wait cursor to progress loadings * (Change) Layer preview: Hold-Shift key to select issues and pick pixel position/brightness changed to Hold-Control key * (Change) Layer preview: Shift+click combination to zoom-in changed to Alt+click +* (Fix) CTB v3: Bad file when re-encoding -## 11/08/2020 - v0.8.0.0 +## 11/09/2020 - v0.8.0.0 * (Add) LGS and LGS30 file format for Longer Orange 10 and 30 (ezrec/uv3dp#105) * (Add) CWS: Support the GRAY2RGB and RBG2GRAY encoding for Bene Mono @@ -50,7 +56,7 @@ Less frequently used settings for gap and noise removal iterations have been mov * (Fix) Mask: A crash when check "Invert" when mask is not loaded * (Fix) Some text and phrases -## 04/08/2020 - v0.7.0.0 +## 04/09/2020 - v0.7.0.0 * (Add) "Rebuild GCode" button * (Add) Issues: Touching Bounds and Empty Layers to the detect button diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index 6ff4e23..7880abc 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -1218,7 +1218,9 @@ namespace UVtools.Core.FileFormats if (HeaderSettings.Version >= 3) { var layerDataEx = new LayerDataEx(layerData, layerIndex); - layerData.DataAddress = layerDataCurrentOffset += Helpers.SerializeWriteFileStream(outputFile, layerDataEx); + layerDataCurrentOffset += (uint)Helpers.Serializer.SizeOf(layerDataEx); + layerData.DataAddress = layerDataCurrentOffset; + Helpers.SerializeWriteFileStream(outputFile, layerDataEx); } layerDataCurrentOffset += outputFile.WriteBytes(layerData.EncodedRle); diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs index b0d8b95..4bbad16 100644 --- a/UVtools.Core/Layer/Layer.cs +++ b/UVtools.Core/Layer/Layer.cs @@ -444,35 +444,44 @@ namespace UVtools.Core return result; } - public void MutateMove(OperationMove operation) + public void Move(OperationMove operation) { - using (var layer = LayerMat) + using (var mat = LayerMat) { - if (operation.ImageWidth == 0) operation.ImageWidth = (uint)layer.Width; - if (operation.ImageHeight == 0) operation.ImageHeight = (uint)layer.Height; + if (operation.ImageWidth == 0) operation.ImageWidth = (uint)mat.Width; + if (operation.ImageHeight == 0) operation.ImageHeight = (uint)mat.Height; /*layer.Transform(1.0, 1.0, move.MarginLeft - move.MarginRight, move.MarginTop-move.MarginBottom); LayerMat = layer;*/ - using (var layerRoi = new Mat(layer, operation.SrcRoi)) + /*using (var layerRoi = new Mat(layer, operation.SrcRoi)) + using (var dstLayer = layer.CloneBlank()) + using (var dstRoi = new Mat(dstLayer, operation.DstRoi)) { - using (var dstLayer = layer.CloneBlank()) + layerRoi.CopyTo(dstRoi); + LayerMat = dstLayer; + }*/ + + using (var srcRoi = new Mat(mat, operation.ROI)) + using (var dstRoi = new Mat(mat, operation.DstRoi)) + { + srcRoi.CopyTo(dstRoi); + if (operation.IsCutMove) { - using (var dstRoi = new Mat(dstLayer, operation.DstRoi)) - { - layerRoi.CopyTo(dstRoi); - LayerMat = dstLayer; - } + srcRoi.SetTo(new MCvScalar(0)); } + + LayerMat = mat; } } } - public void Resize(double xScale, double yScale) + public void Resize(double xScale, double yScale, OperationResize operation) { using (var mat = LayerMat) { - mat.TransformFromCenter(xScale, yScale); + Mat target = operation.GetRoiOrDefault(mat); + target.TransformFromCenter(xScale, yScale); LayerMat = mat; } } @@ -481,33 +490,20 @@ namespace UVtools.Core { using (var mat = LayerMat) { + Mat target = operation.GetRoiOrDefault(mat); + if (operation.MakeCopy) { using (Mat dst = new Mat()) { - CvInvoke.Flip(mat, dst, operation.FlipTypeOpenCV); - CvInvoke.Add(mat, dst, mat); - /*var spanSrc = mat.GetPixelSpan<byte>(); - var spanDst = dst.GetPixelSpan<byte>(); - for (int i = 0; i < spanSrc.Length; i++) - { - if (spanDst[i] == 0) continue; - spanSrc[i] = spanDst[i]; - }*/ - - - - LayerMat = mat; + CvInvoke.Flip(target, dst, operation.FlipTypeOpenCV); + CvInvoke.Add(target, dst, target); } } else { - CvInvoke.Flip(mat, mat, operation.FlipTypeOpenCV); - /*GpuMat gpumat = new GpuMat(); - gpumat.Upload(mat); - CudaInvoke.Flip(gpumat, gpumat, flipType); - gpumat.Download(mat);*/ + CvInvoke.Flip(target, target, operation.FlipTypeOpenCV); } LayerMat = mat; @@ -518,8 +514,10 @@ namespace UVtools.Core { using (var mat = LayerMat) { - var halfWidth = mat.Width / 2.0f; - var halfHeight = mat.Height / 2.0f; + Mat target = operation.GetRoiOrDefault(mat); + + var halfWidth = target.Width / 2.0f; + var halfHeight = target.Height / 2.0f; using (var translateTransform = new Matrix<double>(2, 3)) { CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), (double) operation.AngleDegrees, 1.0, translateTransform); @@ -537,20 +535,23 @@ namespace UVtools.Core translateTransform[1, 2] += bound_h / 2 - halfHeight;*/ - CvInvoke.WarpAffine(mat, mat, translateTransform, mat.Size); + CvInvoke.WarpAffine(target, target, translateTransform, target.Size); } LayerMat = mat; } } - public void MutateSolidify() + public void Solidify(OperationSolidify operation) { using (Mat mat = LayerMat) { using (Mat filteredMat = new Mat()) { - CvInvoke.Threshold(mat, filteredMat, 254, 255, ThresholdType.Binary); // Clean AA + Mat target = operation.GetRoiOrDefault(mat); + + + CvInvoke.Threshold(target, filteredMat, 254, 255, ThresholdType.Binary); // Clean AA using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { @@ -561,7 +562,7 @@ namespace UVtools.Core for (int i = 0; i < contours.Size; i++) { if ((int)arr.GetValue(0, i, 2) != -1 || (int)arr.GetValue(0, i, 3) == -1) continue; - CvInvoke.DrawContours(mat, contours, i, new MCvScalar(255), -1); + CvInvoke.DrawContours(target, contours, i, new MCvScalar(255), -1); } } } @@ -571,13 +572,13 @@ namespace UVtools.Core } } - public void Mask(OperationMask mask) => Mask(mask.Mask); - - public void Mask(Mat mask) + public void Mask(OperationMask operation) { using (var mat = LayerMat) { - CvInvoke.BitwiseAnd(mat, mask, mat); + Mat target = operation.GetRoiOrDefault(mat); + if(operation.Mask.Size != target.Size) return; + CvInvoke.BitwiseAnd(target, operation.Mask, target); LayerMat = mat; } } @@ -655,17 +656,19 @@ namespace UVtools.Core using (Mat erode = new Mat()) using (Mat diff = new Mat()) { - CvInvoke.Erode(dst, erode, kernel, anchor, (int) operation.BorderSize, BorderType.Reflect101, default); - CvInvoke.Subtract(dst, erode, diff); + Mat target = operation.GetRoiOrDefault(dst); + + CvInvoke.Erode(target, erode, kernel, anchor, (int) operation.BorderSize, BorderType.Reflect101, default); + CvInvoke.Subtract(target, erode, diff); if (operation.BordersOnly) { - CvInvoke.BitwiseAnd(diff, Index % 2 == 0 ? evenPatternMask : oddPatternMask, dst); - CvInvoke.Add(erode, dst, dst); + CvInvoke.BitwiseAnd(diff, Index % 2 == 0 ? evenPatternMask : oddPatternMask, target); + CvInvoke.Add(erode, target, target); } else { - CvInvoke.BitwiseAnd(erode, Index % 2 == 0 ? evenPatternMask : oddPatternMask, dst); - CvInvoke.Add(dst, diff, dst); + CvInvoke.BitwiseAnd(erode, Index % 2 == 0 ? evenPatternMask : oddPatternMask, target); + CvInvoke.Add(target, diff, target); } LayerMat = dst; @@ -679,7 +682,8 @@ namespace UVtools.Core using (Mat dst = LayerMat) { - CvInvoke.MorphologyEx(dst, dst, operation.MorphOperation, operation.Kernel.Matrix, operation.Kernel.Anchor, iterations, borderType, borderValue); + Mat target = operation.GetRoiOrDefault(dst); + CvInvoke.MorphologyEx(target, target, operation.MorphOperation, operation.Kernel.Matrix, operation.Kernel.Anchor, iterations, borderType, borderValue); LayerMat = dst; } } @@ -758,7 +762,8 @@ namespace UVtools.Core { using (Mat dst = LayerMat) { - CvInvoke.Threshold(dst, dst, operation.Threshold, operation.Maximum, operation.Type); + Mat target = operation.GetRoiOrDefault(dst); + CvInvoke.Threshold(target, target, operation.Threshold, operation.Maximum, operation.Type); LayerMat = dst; } } @@ -772,23 +777,24 @@ namespace UVtools.Core //if (anchor.IsEmpty) anchor = new Point(-1, -1); using (Mat dst = LayerMat) { + Mat target = operation.GetRoiOrDefault(dst); switch (operation.BlurOperation) { case OperationBlur.BlurAlgorithm.Blur: - CvInvoke.Blur(dst, dst, size, operation.Kernel.Anchor); + CvInvoke.Blur(target, target, size, operation.Kernel.Anchor); break; case OperationBlur.BlurAlgorithm.Pyramid: - CvInvoke.PyrDown(dst, dst); - CvInvoke.PyrUp(dst, dst); + CvInvoke.PyrDown(target, target); + CvInvoke.PyrUp(target, target); break; case OperationBlur.BlurAlgorithm.MedianBlur: - CvInvoke.MedianBlur(dst, dst, (int) operation.Size); + CvInvoke.MedianBlur(target, target, (int) operation.Size); break; case OperationBlur.BlurAlgorithm.GaussianBlur: - CvInvoke.GaussianBlur(dst, dst, size, 0); + CvInvoke.GaussianBlur(target, target, size, 0); break; case OperationBlur.BlurAlgorithm.Filter2D: - CvInvoke.Filter2D(dst, dst, operation.Kernel.Matrix, anchor); + CvInvoke.Filter2D(target, target, operation.Kernel.Matrix, anchor); break; default: throw new ArgumentOutOfRangeException(); @@ -824,7 +830,7 @@ namespace UVtools.Core public void Pattern(OperationPattern operation) { using (var layer = LayerMat) - using (var layerRoi = new Mat(layer, operation.SrcRoi)) + using (var layerRoi = new Mat(layer, operation.ROI)) using (var dstLayer = layer.CloneBlank()) { for (ushort col = 0; col < operation.Cols; col++) diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index 24cbbf3..0370ac1 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -247,13 +247,13 @@ namespace UVtools.Core if (ReferenceEquals(progress, null)) progress = new OperationProgress(); progress.Reset(operation.ProgressAction, operation.LayerRangeCount); - if (operation.SrcRoi == Rectangle.Empty) operation.SrcRoi = GetBoundingRectangle(progress); + if (operation.ROI == Rectangle.Empty) operation.ROI = GetBoundingRectangle(progress); Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1, layerIndex => { if (progress.Token.IsCancellationRequested) return; - this[layerIndex].MutateMove(operation); + this[layerIndex].Move(operation); lock (progress.Mutex) { @@ -322,7 +322,7 @@ namespace UVtools.Core if (newX == 1.0m && newY == 1.0m) return; - this[layerIndex].Resize((double) (newX / 100m), (double) (newY / 100m)); + this[layerIndex].Resize((double) (newX / 100m), (double) (newY / 100m), operation); }); progress.Token.ThrowIfCancellationRequested(); } @@ -366,7 +366,7 @@ namespace UVtools.Core Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1, layerIndex => { if (progress.Token.IsCancellationRequested) return; - this[layerIndex].MutateSolidify(); + this[layerIndex].Solidify(operation); lock (progress.Mutex) { progress++; @@ -425,13 +425,15 @@ namespace UVtools.Core using (Mat matEven = mat.CloneBlank()) using (Mat matOdd = mat.CloneBlank()) { - CvInvoke.Repeat(operation.EvenPattern, mat.Rows / operation.EvenPattern.Rows + 1, - mat.Cols / operation.EvenPattern.Cols + 1, matEven); - CvInvoke.Repeat(operation.OddPattern, mat.Rows / operation.OddPattern.Rows + 1, - mat.Cols / operation.OddPattern.Cols + 1, matOdd); + Mat target = operation.GetRoiOrDefault(mat); - using (var evenPatternMask = new Mat(matEven, new Rectangle(0, 0, mat.Width, mat.Height))) - using (var oddPatternMask = new Mat(matOdd, new Rectangle(0, 0, mat.Width, mat.Height))) + CvInvoke.Repeat(operation.EvenPattern, target.Rows / operation.EvenPattern.Rows + 1, + target.Cols / operation.EvenPattern.Cols + 1, matEven); + CvInvoke.Repeat(operation.OddPattern, target.Rows / operation.OddPattern.Rows + 1, + target.Cols / operation.OddPattern.Cols + 1, matOdd); + + using (var evenPatternMask = new Mat(matEven, new Rectangle(0, 0, target.Width, target.Height))) + using (var oddPatternMask = new Mat(matOdd, new Rectangle(0, 0, target.Width, target.Height))) { Parallel.For(operation.LayerIndexStart, operation.LayerIndexEnd + 1, layerIndex => { diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs index 3f656c0..1ed1cfb 100644 --- a/UVtools.Core/Operations/Operation.cs +++ b/UVtools.Core/Operations/Operation.cs @@ -6,7 +6,9 @@ * of this license document, but changing it is not allowed. */ +using System.Drawing; using System.Runtime.CompilerServices; +using Emgu.CV; using UVtools.Core.Objects; namespace UVtools.Core.Operations @@ -78,5 +80,17 @@ namespace UVtools.Core.Operations public virtual uint LayerIndexEnd { get; set; } public uint LayerRangeCount => LayerIndexEnd - LayerIndexStart + 1; + + /// <summary> + /// Gets or sets an ROI to process this operation + /// </summary> + public Rectangle ROI { get; set; } = Rectangle.Empty; + + public bool HaveROI => !ROI.IsEmpty; + + public Mat GetRoiOrDefault(Mat defaultMat) + { + return HaveROI ? new Mat(defaultMat, ROI) : defaultMat; + } } } diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs index 77401ea..c663514 100644 --- a/UVtools.Core/Operations/OperationMove.cs +++ b/UVtools.Core/Operations/OperationMove.cs @@ -16,17 +16,17 @@ namespace UVtools.Core.Operations { public override string Title => "Move"; public override string Description => - "Change the position of the model on the build plate."; + "Change or copy the position of the model on the build plate."; public override string ConfirmationText => - $"move model layers {LayerIndexStart} through {LayerIndexEnd} from " + - $"location {{X={SrcRoi.X},Y={SrcRoi.Y}}} to " + + (IsCutMove ? "move" : "copy") + $" model layers {LayerIndexStart} through {LayerIndexEnd} from " + + $"location {{X={ROI.X},Y={ROI.Y}}} to " + $"location {{X={DstRoi.X},Y={DstRoi.Y}}}?"; public override string ProgressTitle => - $"Moving model to {{X={DstRoi.X},Y={DstRoi.Y}}}"; + (IsCutMove ? "Moving" : "Copying") +$" model to {{X={DstRoi.X},Y={DstRoi.Y}}}"; - public override string ProgressAction => "Moved layers"; + public override string ProgressAction => (IsCutMove ? "Moved" : "Copied")+" layers"; public override StringTag Validate(params object[] parameters) { @@ -34,15 +34,12 @@ namespace UVtools.Core.Operations if (!ValidateBounds()) { - sb.AppendLine("Your parameters will put the model outside of build plate. Please adjust the location and margins."); + sb.AppendLine("Your parameters will put the model outside of build plate. Please adjust the location and margins."); } return new StringTag(sb.ToString()); } - - public Rectangle SrcRoi { get; set; } - private Rectangle _dstRoi = Rectangle.Empty; public Rectangle DstRoi { @@ -57,7 +54,7 @@ namespace UVtools.Core.Operations public void CalculateDstRoi() { - _dstRoi.Size = SrcRoi.Size; + _dstRoi.Size = ROI.Size; switch (Anchor) { @@ -65,29 +62,29 @@ namespace UVtools.Core.Operations _dstRoi.Location = new Point(0, 0); break; case Enumerations.Anchor.TopCenter: - _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), 0); + _dstRoi.Location = new Point((int)(ImageWidth / 2 - ROI.Width / 2), 0); break; case Enumerations.Anchor.TopRight: - _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), 0); + _dstRoi.Location = new Point((int)(ImageWidth - ROI.Width), 0); break; case Enumerations.Anchor.MiddleLeft: - _dstRoi.Location = new Point(0, (int)(ImageHeight / 2 - SrcRoi.Height / 2)); + _dstRoi.Location = new Point(0, (int)(ImageHeight / 2 - ROI.Height / 2)); break; case Enumerations.Anchor.MiddleCenter: //case Anchor.None: - _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), (int)(ImageHeight / 2 - SrcRoi.Height / 2)); + _dstRoi.Location = new Point((int)(ImageWidth / 2 - ROI.Width / 2), (int)(ImageHeight / 2 - ROI.Height / 2)); break; case Enumerations.Anchor.MiddleRight: - _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), (int)(ImageHeight / 2 - SrcRoi.Height / 2)); + _dstRoi.Location = new Point((int)(ImageWidth - ROI.Width), (int)(ImageHeight / 2 - ROI.Height / 2)); break; case Enumerations.Anchor.BottomLeft: - _dstRoi.Location = new Point(0, (int)(ImageHeight - SrcRoi.Height)); + _dstRoi.Location = new Point(0, (int)(ImageHeight - ROI.Height)); break; case Enumerations.Anchor.BottomCenter: - _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), (int)(ImageHeight - SrcRoi.Height)); + _dstRoi.Location = new Point((int)(ImageWidth / 2 - ROI.Width / 2), (int)(ImageHeight - ROI.Height)); break; case Enumerations.Anchor.BottomRight: - _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), (int)(ImageHeight - SrcRoi.Height)); + _dstRoi.Location = new Point((int)(ImageWidth - ROI.Width), (int)(ImageHeight - ROI.Height)); break; default: throw new ArgumentOutOfRangeException(); @@ -110,13 +107,15 @@ namespace UVtools.Core.Operations public int MarginRight { get; set; } = 0; public int MarginBottom { get; set; } = 0; + public bool IsCutMove { get; set; } = true; + public OperationMove() { } public OperationMove(Rectangle srcRoi, uint imageWidth = 0, uint imageHeight = 0, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) { - SrcRoi = srcRoi; + ROI = srcRoi; ImageWidth = imageWidth; ImageHeight = imageHeight; Anchor = anchor; diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs index 039c0dd..e5d0e69 100644 --- a/UVtools.Core/Operations/OperationPattern.cs +++ b/UVtools.Core/Operations/OperationPattern.cs @@ -46,7 +46,6 @@ namespace UVtools.Core.Operations #endregion public Enumerations.Anchor Anchor { get; set; } - public Rectangle SrcRoi { get; } public uint ImageWidth { get; } public uint ImageHeight { get; } @@ -54,16 +53,16 @@ namespace UVtools.Core.Operations public ushort MarginCol { get; set; } public ushort MarginRow { get; set; } - public ushort MaxMarginCol { get; } - public ushort MaxMarginRow { get; } + public ushort MaxMarginCol { get; set; } + public ushort MaxMarginRow { get; set; } public ushort Cols { get; set; } = 1; public ushort Rows { get; set; } = 1; - public ushort MaxCols { get; } - public ushort MaxRows { get; } + public ushort MaxCols { get; set; } + public ushort MaxRows { get; set; } - public Size GetPatternVolume => new Size(Cols * SrcRoi.Width + (Cols - 1) * MarginCol, Rows * SrcRoi.Height + (Rows - 1) * MarginRow); + public Size GetPatternVolume => new Size(Cols * ROI.Width + (Cols - 1) * MarginCol, Rows * ROI.Height + (Rows - 1) * MarginRow); public OperationPattern() { @@ -71,12 +70,18 @@ namespace UVtools.Core.Operations public OperationPattern(Rectangle srcRoi, Size resolution) { - SrcRoi = srcRoi; ImageWidth = (uint) resolution.Width; ImageHeight = (uint) resolution.Height; - MaxCols = (ushort) (ImageWidth / srcRoi.Width); - MaxRows = (ushort) (ImageHeight / srcRoi.Height); + SetRoi(srcRoi); + } + + public void SetRoi(Rectangle srcRoi) + { + ROI = srcRoi; + + MaxCols = (ushort)(ImageWidth / srcRoi.Width); + MaxRows = (ushort)(ImageHeight / srcRoi.Height); MaxMarginCol = CalculateMarginCol(MaxCols); MaxMarginRow = CalculateMarginRow(MaxRows); @@ -141,13 +146,13 @@ namespace UVtools.Core.Operations public ushort CalculateMarginCol(ushort cols) { if (cols <= 1) return 0; - return (ushort)((ImageWidth - SrcRoi.Width * cols) / cols); + return (ushort)((ImageWidth - ROI.Width * cols) / cols); } public ushort CalculateMarginRow(ushort rows) { if (rows <= 1) return 0; - return (ushort)((ImageHeight - SrcRoi.Height * rows) / rows); + return (ushort)((ImageHeight - ROI.Height * rows) / rows); } public Rectangle GetRoi(ushort col, ushort row) @@ -155,8 +160,8 @@ namespace UVtools.Core.Operations var patternVolume = GetPatternVolume; return new Rectangle(new Point( - (int) (col * SrcRoi.Width + col * MarginCol + (ImageWidth - patternVolume.Width) / 2), - (int) (row * SrcRoi.Height + row * MarginRow + (ImageHeight - patternVolume.Height) / 2)), SrcRoi.Size); + (int) (col * ROI.Width + col * MarginCol + (ImageWidth - patternVolume.Width) / 2), + (int) (row * ROI.Height + row * MarginRow + (ImageHeight - patternVolume.Height) / 2)), ROI.Size); } public bool ValidateBounds() diff --git a/UVtools.GUI/Controls/CtrlToolWindowContent.cs b/UVtools.GUI/Controls/CtrlToolWindowContent.cs index e096821..bfaf348 100644 --- a/UVtools.GUI/Controls/CtrlToolWindowContent.cs +++ b/UVtools.GUI/Controls/CtrlToolWindowContent.cs @@ -81,6 +81,11 @@ namespace UVtools.GUI.Controls [SettingsBindable(true)] public bool CanRun { get; set; } = true; + /// <summary> + /// Gets or sets if this control can make use of ROI + /// </summary> + [SettingsBindable(true)] public bool CanROI { get; set; } = false; + [Editor("System.ComponentModel.Design.MultilineStringEditor", typeof(UITypeEditor))] [SettingsBindable(true)] public string Description { get; set; } @@ -161,6 +166,11 @@ namespace UVtools.GUI.Controls if (ParentToolWindow is null) return true; BaseOperation.LayerIndexStart = ParentToolWindow.LayerRangeStart; BaseOperation.LayerIndexEnd = ParentToolWindow.LayerRangeEnd; + if (CanROI) + { + BaseOperation.ROI = Program.FrmMain.ROI; + } + return true; } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolBlur.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolBlur.Designer.cs index ffe07fd..a70eeb9 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolBlur.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolBlur.Designer.cs @@ -101,6 +101,7 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoSize = true; + this.CanROI = true; this.Controls.Add(this.label1); this.Controls.Add(this.cbBlurOperation); this.Controls.Add(this.nmSize); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolEditEditParameters.cs b/UVtools.GUI/Controls/Tools/CtrlToolEditEditParameters.cs index c0e49f6..228fcf0 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolEditEditParameters.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolEditEditParameters.cs @@ -159,7 +159,7 @@ namespace UVtools.GUI.Controls.Tools public override void ExtraActionCall(object sender) { - if (sender is Button button) + if (ReferenceEquals(sender, ParentToolWindow.btnActionExtra)) { foreach (var rowControl in RowControls) { diff --git a/UVtools.GUI/Controls/Tools/CtrlToolFlip.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolFlip.Designer.cs index 6d34da4..f319c53 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolFlip.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolFlip.Designer.cs @@ -69,6 +69,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; + this.CanROI = true; this.Controls.Add(this.cbMakeCopy); this.Controls.Add(this.cbFlipDirection); this.Controls.Add(this.lbX); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMask.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolMask.Designer.cs index c5ea3cf..0ef38f2 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMask.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMask.Designer.cs @@ -225,8 +225,8 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.ButtonOkEnabled = false; + this.CanROI = true; this.Controls.Add(this.groupBox2); this.Controls.Add(this.cbInvertMask); this.Controls.Add(this.lbMaskResolution); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMask.cs b/UVtools.GUI/Controls/Tools/CtrlToolMask.cs index d5d8499..0a7009f 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMask.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMask.cs @@ -30,6 +30,18 @@ namespace UVtools.GUI.Controls.Tools lbPrinterResolution.Text = $"Printer Resolution: {Program.FrmMain.ActualLayerImage.Size}"; } + public override void ExtraActionCall(object sender) + { + if (ReferenceEquals(sender, ParentToolWindow.btnClearRoi)) + { + Operation.Mask = null; + pbMask.Image = null; + lbMaskResolution.Text = "Mask resolution: (Unloaded)"; + ButtonOkEnabled = false; + return; + } + } + private void EventClick(object sender, EventArgs e) { if (ReferenceEquals(sender, btnImportImageMask)) @@ -44,9 +56,20 @@ namespace UVtools.GUI.Controls.Tools Operation.Mask = CvInvoke.Imread(fileOpen.FileName, ImreadModes.Grayscale); - if (Operation.Mask.Size != Program.FrmMain.ActualLayerImage.Size) + var roi = Program.FrmMain.ROI; + if (roi.IsEmpty) + { + if (Operation.Mask.Size != Program.FrmMain.ActualLayerImage.Size) + { + CvInvoke.Resize(Operation.Mask, Operation.Mask, Program.FrmMain.ActualLayerImage.Size); + } + } + else { - CvInvoke.Resize(Operation.Mask, Operation.Mask, Program.FrmMain.ActualLayerImage.Size); + if (Operation.Mask.Size != roi.Size) + { + CvInvoke.Resize(Operation.Mask, Operation.Mask, roi.Size); + } } if (cbInvertMask.Checked) @@ -72,7 +95,9 @@ namespace UVtools.GUI.Controls.Tools if (ReferenceEquals(sender, btnMaskGenerate)) { - Operation.Mask = Program.FrmMain.ActualLayerImage.CloneBlank(); + var roi = Program.FrmMain.ROI; + Operation.Mask = roi.IsEmpty ? Program.FrmMain.ActualLayerImage.CloneBlank() : new Mat(roi.Size, DepthType.Cv8U, 1); + lbMaskResolution.Text = $"Mask Resolution: {Operation.Mask.Size}"; int radius = (int)nmGeneratorDiameter.Value; diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMorph.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolMorph.Designer.cs index 229e215..59aeccf 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMorph.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMorph.Designer.cs @@ -145,6 +145,7 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoSize = true; + this.CanROI = true; this.Controls.Add(this.label1); this.Controls.Add(this.cbMorphOperation); this.Controls.Add(this.ctrlKernel); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMorph.cs b/UVtools.GUI/Controls/Tools/CtrlToolMorph.cs index 72b34eb..991f382 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMorph.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMorph.cs @@ -45,9 +45,9 @@ namespace UVtools.GUI.Controls.Tools public override void ExtraActionCall(object sender) { - if (sender is CheckBox checkbox) + if (ReferenceEquals(sender, ParentToolWindow.cbActionExtra)) { - ctrlKernel.Visible = checkbox.Checked; + ctrlKernel.Visible = ParentToolWindow.cbActionExtra.Checked; return; } } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMove.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolMove.Designer.cs index c142242..3d10a55 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMove.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMove.Designer.cs @@ -29,6 +29,8 @@ private void InitializeComponent() { this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cbMoveType = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); this.lbInsideBounds = new System.Windows.Forms.Label(); this.lbPlacementY = new System.Windows.Forms.Label(); this.lbPlacementX = new System.Windows.Forms.Label(); @@ -64,6 +66,8 @@ // this.groupBox1.AutoSize = true; this.groupBox1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.groupBox1.Controls.Add(this.cbMoveType); + this.groupBox1.Controls.Add(this.label1); this.groupBox1.Controls.Add(this.lbInsideBounds); this.groupBox1.Controls.Add(this.lbPlacementY); this.groupBox1.Controls.Add(this.lbPlacementX); @@ -81,11 +85,33 @@ this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill; this.groupBox1.Location = new System.Drawing.Point(0, 0); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(570, 214); + this.groupBox1.Size = new System.Drawing.Size(570, 260); this.groupBox1.TabIndex = 24; this.groupBox1.TabStop = false; this.groupBox1.Text = "Location && Margins"; // + // cbMoveType + // + this.cbMoveType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbMoveType.FormattingEnabled = true; + this.cbMoveType.Items.AddRange(new object[] { + "Cut", + "Copy"}); + this.cbMoveType.Location = new System.Drawing.Point(99, 207); + this.cbMoveType.Name = "cbMoveType"; + this.cbMoveType.Size = new System.Drawing.Size(101, 28); + this.cbMoveType.TabIndex = 30; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 211); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(85, 20); + this.label1.TabIndex = 29; + this.label1.Text = "Move type:"; + // // lbInsideBounds // this.lbInsideBounds.AutoSize = true; @@ -392,12 +418,13 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; + this.CanROI = true; this.Controls.Add(this.groupBox1); this.Description = ""; this.ExtraButtonVisible = true; this.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "CtrlToolMove"; - this.Size = new System.Drawing.Size(570, 214); + this.Size = new System.Drawing.Size(570, 260); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.tableAnchor.ResumeLayout(false); @@ -437,5 +464,7 @@ private System.Windows.Forms.Label label4; private System.Windows.Forms.NumericUpDown nmMarginRight; private System.Windows.Forms.NumericUpDown nmMarginLeft; + private System.Windows.Forms.ComboBox cbMoveType; + private System.Windows.Forms.Label label1; } } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolMove.cs b/UVtools.GUI/Controls/Tools/CtrlToolMove.cs index 2ddda86..e9746e4 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolMove.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolMove.cs @@ -21,26 +21,39 @@ namespace UVtools.GUI.Controls.Tools public CtrlToolMove() { InitializeComponent(); - Operation = new OperationMove(Program.SlicerFile.LayerManager.BoundingRectangle, (uint)Program.FrmMain.ActualLayerImage.Width, + + var roi = Program.FrmMain.ROI; + + Operation = new OperationMove(roi.IsEmpty ? Program.SlicerFile.LayerManager.BoundingRectangle : roi, (uint)Program.FrmMain.ActualLayerImage.Width, (uint)Program.FrmMain.ActualLayerImage.Height); SetOperation(Operation); - lbVolumeWidth.Text = $"Width: {Operation.SrcRoi.Width} / {Operation.ImageWidth}"; - lbVolumeHeight.Text = $"Height: {Operation.SrcRoi.Height} / {Operation.ImageHeight}"; - + cbMoveType.SelectedIndex = 0; ExtraActionCall(this); } public override void ExtraActionCall(object sender) { - if (sender is Button || ReferenceEquals(sender, this)) + if (ReferenceEquals(sender, this) || ReferenceEquals(sender, ParentToolWindow.btnActionExtra)) { + lbVolumeWidth.Text = $"Width: {Operation.ROI.Width} / {Operation.ImageWidth}"; + lbVolumeHeight.Text = $"Height: {Operation.ROI.Height} / {Operation.ImageHeight}"; + nmMarginLeft.Value = 0; nmMarginTop.Value = 0; nmMarginRight.Value = 0; nmMarginBottom.Value = 0; rbAnchorMiddleCenter.Checked = true; EventValueChanged(this, EventArgs.Empty); + + return; + } + + if (ReferenceEquals(sender, ParentToolWindow.btnClearRoi)) + { + Operation.ROI = Program.SlicerFile.LayerManager.BoundingRectangle; + ExtraActionCall(this); + return; } } @@ -49,8 +62,8 @@ namespace UVtools.GUI.Controls.Tools UpdateOperation(); var insideBounds = ButtonOkEnabled = Operation.ValidateBounds(); lbInsideBounds.Text = "Model within boundary: " + (insideBounds ? "Yes" : "No"); - lbPlacementX.Text = $"X: {Operation.DstRoi.X} / {Operation.ImageWidth - Operation.SrcRoi.Width}"; - lbPlacementY.Text = $"Y: {Operation.DstRoi.Y} / {Operation.ImageHeight - Operation.SrcRoi.Height}"; + lbPlacementX.Text = $"X: {Operation.DstRoi.X} / {Operation.ImageWidth - Operation.ROI.Width}"; + lbPlacementY.Text = $"Y: {Operation.DstRoi.Y} / {Operation.ImageHeight - Operation.ROI.Height}"; } public override bool UpdateOperation() @@ -77,6 +90,7 @@ namespace UVtools.GUI.Controls.Tools Operation.MarginTop = (int)nmMarginTop.Value; Operation.MarginRight = (int)nmMarginRight.Value; Operation.MarginBottom = (int)nmMarginBottom.Value; + Operation.IsCutMove = cbMoveType.SelectedIndex == 0; return true; } } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolPattern.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolPattern.Designer.cs index ac20b66..7d26dd5 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolPattern.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolPattern.Designer.cs @@ -397,8 +397,8 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.ButtonOkEnabled = false; + this.CanROI = true; this.Controls.Add(this.groupBox1); this.Controls.Add(this.btnAutoMarginRow); this.Controls.Add(this.btnAutoMarginCol); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs b/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs index 240f6ef..3519d2b 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs @@ -22,7 +22,9 @@ namespace UVtools.GUI.Controls.Tools public CtrlToolPattern() { InitializeComponent(); - Operation = new OperationPattern(Program.SlicerFile.LayerManager.BoundingRectangle, Program.FrmMain.ActualLayerImage.Size); + + var roi = Program.FrmMain.ROI; + Operation = new OperationPattern(roi.IsEmpty ? Program.SlicerFile.LayerManager.BoundingRectangle : roi, Program.FrmMain.ActualLayerImage.Size); SetOperation(Operation); if (Operation.MaxRows < 2 && Operation.MaxCols < 2) @@ -34,22 +36,31 @@ namespace UVtools.GUI.Controls.Tools return; } - nmCols.Maximum = Operation.MaxCols; - nmRows.Maximum = Operation.MaxRows; - ExtraActionCall(this); } public override void ExtraActionCall(object sender) { - if (sender is Button || ReferenceEquals(sender, this)) + if (ReferenceEquals(sender, this) || ReferenceEquals(sender, ParentToolWindow.btnActionExtra)) { + nmCols.Maximum = Operation.MaxCols; + nmRows.Maximum = Operation.MaxRows; + nmMarginCol.Value = Operation.MaxMarginCol; nmMarginRow.Value = Operation.MaxMarginRow; nmCols.Value = Operation.MaxCols; nmRows.Value = Operation.MaxRows; Operation.Fill(); EventValueChanged(this, EventArgs.Empty); + + return; + } + + if (ReferenceEquals(sender, ParentToolWindow.btnClearRoi)) + { + Operation.SetRoi(Program.SlicerFile.LayerManager.BoundingRectangle); + ExtraActionCall(this); + return; } } @@ -91,8 +102,8 @@ namespace UVtools.GUI.Controls.Tools ButtonOkEnabled = insideBounds && (Operation.Cols > 1 || Operation.Rows > 1); lbInsideBounds.Text = "Model within boundary: " + (insideBounds ? "Yes" : "No"); - lbVolumeWidth.Text = $"Width: {Operation.GetPatternVolume.Width} (Min:{Operation.SrcRoi.Width}, Max:{Operation.ImageWidth})"; - lbVolumeHeight.Text = $"Height: {Operation.GetPatternVolume.Height} (Min:{Operation.SrcRoi.Height}, Max:{Operation.ImageHeight})"; + lbVolumeWidth.Text = $"Width: {Operation.GetPatternVolume.Width} (Min:{Operation.ROI.Width}, Max:{Operation.ImageWidth})"; + lbVolumeHeight.Text = $"Height: {Operation.GetPatternVolume.Height} (Min:{Operation.ROI.Height}, Max:{Operation.ImageHeight})"; lbCols.Text = $"Columns: {nmCols.Value} / {Operation.MaxCols}"; lbRows.Text = $"Rows: {nmRows.Value} / {Operation.MaxRows}"; diff --git a/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.Designer.cs index 0a175b7..ee58e5e 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolPixelDimming.Designer.cs @@ -508,7 +508,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CanROI = true; this.Controls.Add(this.cbDimsOnlyBorders); this.Controls.Add(this.groupBox2); this.Controls.Add(this.label5); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs index 8f6aae9..c8fe8a9 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolRepairLayers.cs @@ -47,9 +47,9 @@ namespace UVtools.GUI.Controls.Tools public override void ExtraActionCall(object sender) { - if (sender is CheckBox checkbox) + if (ReferenceEquals(sender, ParentToolWindow.cbActionExtra)) { - LayerRangeVisible = groupAdvancedSettings.Visible = checkbox.Checked; + LayerRangeVisible = groupAdvancedSettings.Visible = ParentToolWindow.cbActionExtra.Checked; return; } } diff --git a/UVtools.GUI/Controls/Tools/CtrlToolResize.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolResize.Designer.cs index 226becd..3a3f35d 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolResize.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolResize.Designer.cs @@ -166,6 +166,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.ButtonOkEnabled = false; + this.CanROI = true; this.Controls.Add(this.cbFade); this.Controls.Add(this.label2); this.Controls.Add(this.label1); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolRotate.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolRotate.Designer.cs index 135276c..94737a0 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolRotate.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolRotate.Designer.cs @@ -52,8 +52,8 @@ this.nmDegrees.Name = "nmDegrees"; this.nmDegrees.Size = new System.Drawing.Size(101, 26); this.nmDegrees.TabIndex = 23; - this.toolTip.SetToolTip(this.nmDegrees, "Number of degrees to rotate the layers, where postive values are clockwise and" + - " negative values are counter-clockwise."); + this.toolTip.SetToolTip(this.nmDegrees, "Number of degrees to rotate the layers, where postive values are clockwise and ne" + + "gative values are counter-clockwise."); this.nmDegrees.Value = new decimal(new int[] { 90, 0, @@ -85,7 +85,7 @@ // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CanROI = true; this.Controls.Add(this.label1); this.Controls.Add(this.nmDegrees); this.Controls.Add(this.lbX); diff --git a/UVtools.GUI/Controls/Tools/CtrlToolSolidify.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.Designer.cs new file mode 100644 index 0000000..9820f01 --- /dev/null +++ b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.Designer.cs @@ -0,0 +1,48 @@ +namespace UVtools.GUI.Controls.Tools +{ + partial class CtrlToolSolidify + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + this.SuspendLayout(); + // + // CtrlToolSolidify + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.CanROI = true; + this.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Name = "CtrlToolSolidify"; + this.Size = new System.Drawing.Size(540, 0); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/UVtools.GUI/Controls/Tools/CtrlToolSolidify.cs b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.cs new file mode 100644 index 0000000..3f4b609 --- /dev/null +++ b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.cs @@ -0,0 +1,23 @@ +/* + * GNU AFFERO GENERAL PUBLIC LICENSE + * Version 3, 19 November 2007 + * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. + */ +using System.Windows.Forms; +using UVtools.Core.Operations; + +namespace UVtools.GUI.Controls.Tools +{ + public partial class CtrlToolSolidify : CtrlToolWindowContent + { + private OperationSolidify Operation { get; } + public CtrlToolSolidify() + { + InitializeComponent(); + Operation = new OperationSolidify(); + SetOperation(Operation); + } + } +} diff --git a/UVtools.GUI/Controls/Tools/CtrlToolSolidify.resx b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.resx new file mode 100644 index 0000000..8766f29 --- /dev/null +++ b/UVtools.GUI/Controls/Tools/CtrlToolSolidify.resx @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>17, 17</value> + </metadata> +</root>
\ No newline at end of file diff --git a/UVtools.GUI/Controls/Tools/CtrlToolThreshold.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolThreshold.Designer.cs index 9e5ee5d..b1abf20 100644 --- a/UVtools.GUI/Controls/Tools/CtrlToolThreshold.Designer.cs +++ b/UVtools.GUI/Controls/Tools/CtrlToolThreshold.Designer.cs @@ -132,6 +132,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; + this.CanROI = true; this.Controls.Add(this.label3); this.Controls.Add(this.cbPresetHelpers); this.Controls.Add(this.nmMaximum); diff --git a/UVtools.GUI/Forms/FrmLoading.cs b/UVtools.GUI/Forms/FrmLoading.cs index fb4204a..61cd510 100644 --- a/UVtools.GUI/Forms/FrmLoading.cs +++ b/UVtools.GUI/Forms/FrmLoading.cs @@ -66,6 +66,8 @@ namespace UVtools.GUI.Forms btnCancel.Enabled = CanCancel; btnCancel.Text = "Cancel"; + + Cursor = Cursors.AppStarting; } protected override void OnClosed(EventArgs e) @@ -75,6 +77,7 @@ namespace UVtools.GUI.Forms StopWatch.Stop(); Progress = null; OperationLog.ElapsedTime = (uint) StopWatch.ElapsedMilliseconds / 1000m; + Cursor = Cursors.Arrow; } public OperationProgress RestartProgress(bool canCancel = true) diff --git a/UVtools.GUI/Forms/FrmToolWindow.Designer.cs b/UVtools.GUI/Forms/FrmToolWindow.Designer.cs index 469b5e9..fe732e0 100644 --- a/UVtools.GUI/Forms/FrmToolWindow.Designer.cs +++ b/UVtools.GUI/Forms/FrmToolWindow.Designer.cs @@ -41,7 +41,6 @@ namespace UVtools.GUI.Forms this.lbLayerRangeFromMM = new System.Windows.Forms.Label(); this.lbLayerRangeToMM = new System.Windows.Forms.Label(); this.nmLayerRangeEnd = new System.Windows.Forms.NumericUpDown(); - this.btnLayerRangeSelect = new UVtools.GUI.Controls.SplitButton(); this.cmLayerRange = new System.Windows.Forms.ContextMenuStrip(this.components); this.btnLayerRangeAllLayers = new System.Windows.Forms.ToolStripMenuItem(); this.btnLayerRangeCurrentLayer = new System.Windows.Forms.ToolStripMenuItem(); @@ -60,6 +59,13 @@ namespace UVtools.GUI.Forms this.btnActionExtra = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.btnOk = new System.Windows.Forms.Button(); + this.pnROI = new System.Windows.Forms.Panel(); + this.gbROI = new System.Windows.Forms.GroupBox(); + this.lbRoi = new System.Windows.Forms.Label(); + this.btnClearRoi = new System.Windows.Forms.Button(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.cbClearRoiAfterOperation = new System.Windows.Forms.CheckBox(); + this.btnLayerRangeSelect = new UVtools.GUI.Controls.SplitButton(); this.pnDescription.SuspendLayout(); this.pnLayerRange.SuspendLayout(); this.gbLayerRange.SuspendLayout(); @@ -68,6 +74,8 @@ namespace UVtools.GUI.Forms ((System.ComponentModel.ISupportInitialize)(this.nmLayerRangeStart)).BeginInit(); this.table.SuspendLayout(); this.pnActions.SuspendLayout(); + this.pnROI.SuspendLayout(); + this.gbROI.SuspendLayout(); this.SuspendLayout(); // // pnDescription @@ -102,7 +110,7 @@ namespace UVtools.GUI.Forms this.pnContent.BackColor = System.Drawing.Color.White; this.pnContent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pnContent.Dock = System.Windows.Forms.DockStyle.Fill; - this.pnContent.Location = new System.Drawing.Point(3, 191); + this.pnContent.Location = new System.Drawing.Point(3, 312); this.pnContent.Name = "pnContent"; this.pnContent.Size = new System.Drawing.Size(548, 2); this.pnContent.TabIndex = 9; @@ -185,16 +193,6 @@ namespace UVtools.GUI.Forms this.nmLayerRangeEnd.TabIndex = 14; this.nmLayerRangeEnd.ValueChanged += new System.EventHandler(this.EventValueChanged); // - // btnLayerRangeSelect - // - this.btnLayerRangeSelect.Location = new System.Drawing.Point(359, 31); - this.btnLayerRangeSelect.Menu = this.cmLayerRange; - this.btnLayerRangeSelect.Name = "btnLayerRangeSelect"; - this.btnLayerRangeSelect.Size = new System.Drawing.Size(180, 26); - this.btnLayerRangeSelect.TabIndex = 18; - this.btnLayerRangeSelect.Text = "Select"; - this.btnLayerRangeSelect.UseVisualStyleBackColor = true; - // // cmLayerRange // this.cmLayerRange.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -314,18 +312,20 @@ namespace UVtools.GUI.Forms this.table.ColumnCount = 1; this.table.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.table.Controls.Add(this.pnDescription, 0, 0); - this.table.Controls.Add(this.pnActions, 0, 3); - this.table.Controls.Add(this.pnContent, 0, 2); + this.table.Controls.Add(this.pnActions, 0, 4); + this.table.Controls.Add(this.pnContent, 0, 3); this.table.Controls.Add(this.pnLayerRange, 0, 1); + this.table.Controls.Add(this.pnROI, 0, 2); this.table.Dock = System.Windows.Forms.DockStyle.Fill; this.table.Location = new System.Drawing.Point(0, 0); this.table.Name = "table"; - this.table.RowCount = 4; + this.table.RowCount = 5; this.table.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.table.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.table.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.table.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.table.Size = new System.Drawing.Size(554, 281); + this.table.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.table.Size = new System.Drawing.Size(554, 404); this.table.TabIndex = 10; // // pnActions @@ -338,16 +338,15 @@ namespace UVtools.GUI.Forms this.pnActions.Controls.Add(this.btnCancel); this.pnActions.Controls.Add(this.btnOk); this.pnActions.Dock = System.Windows.Forms.DockStyle.Fill; - this.pnActions.Location = new System.Drawing.Point(3, 199); + this.pnActions.Location = new System.Drawing.Point(3, 320); this.pnActions.Name = "pnActions"; - this.pnActions.Size = new System.Drawing.Size(548, 85); + this.pnActions.Size = new System.Drawing.Size(548, 86); this.pnActions.TabIndex = 8; // // cbActionExtra // - this.cbActionExtra.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.cbActionExtra.AutoSize = true; - this.cbActionExtra.Location = new System.Drawing.Point(10, 31); + this.cbActionExtra.Location = new System.Drawing.Point(10, 30); this.cbActionExtra.Name = "cbActionExtra"; this.cbActionExtra.Size = new System.Drawing.Size(202, 24); this.cbActionExtra.TabIndex = 26; @@ -358,11 +357,10 @@ namespace UVtools.GUI.Forms // // btnActionExtra // - this.btnActionExtra.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.btnActionExtra.AutoSize = true; this.btnActionExtra.Image = global::UVtools.GUI.Properties.Resources.undo_alt_16x16; this.btnActionExtra.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.btnActionExtra.Location = new System.Drawing.Point(4, 19); + this.btnActionExtra.Location = new System.Drawing.Point(4, 18); this.btnActionExtra.Name = "btnActionExtra"; this.btnActionExtra.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); this.btnActionExtra.Size = new System.Drawing.Size(177, 48); @@ -375,11 +373,12 @@ namespace UVtools.GUI.Forms // // btnCancel // - this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.AutoSize = true; this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Image = global::UVtools.GUI.Properties.Resources.Cancel_24x24; this.btnCancel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.btnCancel.Location = new System.Drawing.Point(430, 19); + this.btnCancel.Location = new System.Drawing.Point(430, 18); this.btnCancel.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.btnCancel.Name = "btnCancel"; this.btnCancel.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); @@ -393,20 +392,98 @@ namespace UVtools.GUI.Forms // // btnOk // - this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnOk.AutoSize = true; this.btnOk.Image = global::UVtools.GUI.Properties.Resources.Ok_24x24; this.btnOk.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; - this.btnOk.Location = new System.Drawing.Point(330, 19); + this.btnOk.Location = new System.Drawing.Point(340, 18); this.btnOk.Name = "btnOk"; this.btnOk.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.btnOk.Size = new System.Drawing.Size(93, 48); + this.btnOk.Size = new System.Drawing.Size(83, 48); this.btnOk.TabIndex = 5; this.btnOk.Text = "&Ok"; this.btnOk.TextAlign = System.Drawing.ContentAlignment.MiddleRight; this.btnOk.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; this.btnOk.Click += new System.EventHandler(this.EventClick); // + // pnROI + // + this.pnROI.AutoSize = true; + this.pnROI.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.pnROI.Controls.Add(this.gbROI); + this.pnROI.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnROI.Location = new System.Drawing.Point(3, 191); + this.pnROI.Name = "pnROI"; + this.pnROI.Size = new System.Drawing.Size(548, 115); + this.pnROI.TabIndex = 10; + this.pnROI.Visible = false; + // + // gbROI + // + this.gbROI.AutoSize = true; + this.gbROI.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.gbROI.Controls.Add(this.cbClearRoiAfterOperation); + this.gbROI.Controls.Add(this.lbRoi); + this.gbROI.Controls.Add(this.btnClearRoi); + this.gbROI.Dock = System.Windows.Forms.DockStyle.Fill; + this.gbROI.Location = new System.Drawing.Point(0, 0); + this.gbROI.Name = "gbROI"; + this.gbROI.Size = new System.Drawing.Size(548, 115); + this.gbROI.TabIndex = 0; + this.gbROI.TabStop = false; + this.gbROI.Text = "ROI - Region of interest"; + this.toolTip.SetToolTip(this.gbROI, "The impact of the operation will be limited to the ROI, which can be set directly" + + " from the layer preview window."); + // + // lbRoi + // + this.lbRoi.AutoSize = true; + this.lbRoi.Location = new System.Drawing.Point(7, 33); + this.lbRoi.Name = "lbRoi"; + this.lbRoi.Size = new System.Drawing.Size(151, 20); + this.lbRoi.TabIndex = 2; + this.lbRoi.Text = "Region: (Rectangle)"; + this.toolTip.SetToolTip(this.lbRoi, "The impact of the operation will be limited to the ROI, which can be set directly" + + " from the layer preview window."); + // + // btnClearRoi + // + this.btnClearRoi.Location = new System.Drawing.Point(309, 57); + this.btnClearRoi.Name = "btnClearRoi"; + this.btnClearRoi.Size = new System.Drawing.Size(103, 33); + this.btnClearRoi.TabIndex = 1; + this.btnClearRoi.Text = "Clear ROI"; + this.btnClearRoi.UseVisualStyleBackColor = true; + this.btnClearRoi.Click += new System.EventHandler(this.EventClick); + // + // toolTip + // + this.toolTip.AutoPopDelay = 32767; + this.toolTip.InitialDelay = 500; + this.toolTip.ReshowDelay = 100; + this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info; + this.toolTip.ToolTipTitle = "Information"; + // + // cbClearRoiAfterOperation + // + this.cbClearRoiAfterOperation.AutoSize = true; + this.cbClearRoiAfterOperation.Location = new System.Drawing.Point(11, 61); + this.cbClearRoiAfterOperation.Name = "cbClearRoiAfterOperation"; + this.cbClearRoiAfterOperation.Size = new System.Drawing.Size(292, 24); + this.cbClearRoiAfterOperation.TabIndex = 3; + this.cbClearRoiAfterOperation.Text = "Clear ROI after perform the operation"; + this.cbClearRoiAfterOperation.UseVisualStyleBackColor = true; + // + // btnLayerRangeSelect + // + this.btnLayerRangeSelect.Location = new System.Drawing.Point(359, 31); + this.btnLayerRangeSelect.Menu = this.cmLayerRange; + this.btnLayerRangeSelect.Name = "btnLayerRangeSelect"; + this.btnLayerRangeSelect.Size = new System.Drawing.Size(180, 26); + this.btnLayerRangeSelect.TabIndex = 18; + this.btnLayerRangeSelect.Text = "Select"; + this.btnLayerRangeSelect.UseVisualStyleBackColor = true; + // // FrmToolWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); @@ -415,7 +492,7 @@ namespace UVtools.GUI.Forms this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.BackColor = System.Drawing.Color.White; this.CancelButton = this.btnCancel; - this.ClientSize = new System.Drawing.Size(554, 281); + this.ClientSize = new System.Drawing.Size(554, 404); this.Controls.Add(this.table); this.DoubleBuffered = true; this.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -444,6 +521,10 @@ namespace UVtools.GUI.Forms this.table.PerformLayout(); this.pnActions.ResumeLayout(false); this.pnActions.PerformLayout(); + this.pnROI.ResumeLayout(false); + this.pnROI.PerformLayout(); + this.gbROI.ResumeLayout(false); + this.gbROI.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -477,6 +558,12 @@ namespace UVtools.GUI.Forms private System.Windows.Forms.ToolStripMenuItem btnLayerRangeFirstLayer; private System.Windows.Forms.ToolStripMenuItem btnLayerRangeLastLayer; public System.Windows.Forms.Button btnActionExtra; - private System.Windows.Forms.CheckBox cbActionExtra; + private System.Windows.Forms.Panel pnROI; + private System.Windows.Forms.GroupBox gbROI; + private System.Windows.Forms.Label lbRoi; + public System.Windows.Forms.ToolTip toolTip; + public System.Windows.Forms.CheckBox cbActionExtra; + public System.Windows.Forms.Button btnClearRoi; + public System.Windows.Forms.CheckBox cbClearRoiAfterOperation; } }
\ No newline at end of file diff --git a/UVtools.GUI/Forms/FrmToolWindow.cs b/UVtools.GUI/Forms/FrmToolWindow.cs index f6e6502..f9a3875 100644 --- a/UVtools.GUI/Forms/FrmToolWindow.cs +++ b/UVtools.GUI/Forms/FrmToolWindow.cs @@ -149,6 +149,17 @@ namespace UVtools.GUI.Forms pnContent.Visible = false; } + var ROI = Program.FrmMain.ROI; + if (ROI != Rectangle.Empty) + { + pnROI.Visible = true; + lbRoi.Text = ROI.ToString(); + + /*lbDescription.Text += + "\n\nNOTE: The operation will only be applied to the selected Region of Interest indicated below.\n" + + "The Region of Interest can be set directly from the layer preview window prior to running this tool.";*/ + } + EventValueChanged(nmLayerRangeStart, EventArgs.Empty); EventValueChanged(nmLayerRangeEnd, EventArgs.Empty); } @@ -172,6 +183,12 @@ namespace UVtools.GUI.Forms ExtraCheckboxText = content.ExtraCheckboxText; btnOk.Enabled = content.ButtonOkEnabled; //content.AutoSize = true; + + if (!content.CanROI) + { + pnROI.Visible = false; + } + Content = content; content.PropertyChanged += ContentOnPropertyChanged; @@ -318,6 +335,18 @@ namespace UVtools.GUI.Forms return; } + if (ReferenceEquals(sender, btnClearRoi)) + { + if (MessageQuestionBox("Are you sure you want to clear the current ROI?\n" + + "This action can not be reverted, to select another ROI you must quit this window and select it on layer preview.", + "Clear the current ROI?") != DialogResult.Yes) return; + Program.FrmMain.pbLayer.SelectNone(); + cbClearRoiAfterOperation.Checked = false; + pnROI.Visible = false; + ExtraActionCall(btnClearRoi); + return; + } + if (ReferenceEquals(sender, btnActionExtra) || ReferenceEquals(sender, cbActionExtra)) { ExtraActionCall(sender); @@ -351,6 +380,11 @@ namespace UVtools.GUI.Forms DialogResult.Yes) return; } + if (cbClearRoiAfterOperation.Checked) + { + Program.FrmMain.pbLayer.SelectNone(); + } + DialogResult = DialogResult.OK; Close(); diff --git a/UVtools.GUI/Forms/FrmToolWindow.resx b/UVtools.GUI/Forms/FrmToolWindow.resx index 83a57f5..fa91044 100644 --- a/UVtools.GUI/Forms/FrmToolWindow.resx +++ b/UVtools.GUI/Forms/FrmToolWindow.resx @@ -120,6 +120,9 @@ <metadata name="cmLayerRange.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <value>17, 17</value> </metadata> + <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>107, 17</value> + </metadata> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <value> diff --git a/UVtools.GUI/FrmMain.Designer.cs b/UVtools.GUI/FrmMain.Designer.cs index 8a22929..627849f 100644 --- a/UVtools.GUI/FrmMain.Designer.cs +++ b/UVtools.GUI/FrmMain.Designer.cs @@ -247,6 +247,7 @@ namespace UVtools.GUI this.panelLayerNavigation = new System.Windows.Forms.Panel(); this.pbTrackerIssues = new System.Windows.Forms.PictureBox(); this.lbActualLayer = new System.Windows.Forms.Label(); + this.tbLayer = new UVtools.GUI.Controls.TrackBarEx(); this.lbInitialLayer = new System.Windows.Forms.Label(); this.panel2 = new System.Windows.Forms.Panel(); this.btnFindLayer = new System.Windows.Forms.Button(); @@ -257,7 +258,6 @@ namespace UVtools.GUI this.toolTipInformation = new System.Windows.Forms.ToolTip(this.components); this.layerScrollTimer = new System.Windows.Forms.Timer(this.components); this.mouseHoldTimer = new System.Windows.Forms.Timer(this.components); - this.tbLayer = new UVtools.GUI.Controls.TrackBarEx(); this.menu.SuspendLayout(); this.mainTable.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.scCenter)).BeginInit(); @@ -316,8 +316,8 @@ namespace UVtools.GUI this.tlRight.SuspendLayout(); this.panelLayerNavigation.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pbTrackerIssues)).BeginInit(); - this.panel2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).BeginInit(); + this.panel2.SuspendLayout(); this.SuspendLayout(); // // menu @@ -2737,6 +2737,18 @@ namespace UVtools.GUI this.lbActualLayer.TabIndex = 9; this.lbActualLayer.Text = "?"; // + // tbLayer + // + this.tbLayer.Dock = System.Windows.Forms.DockStyle.Right; + this.tbLayer.Location = new System.Drawing.Point(93, 0); + this.tbLayer.Margin = new System.Windows.Forms.Padding(0); + this.tbLayer.Name = "tbLayer"; + this.tbLayer.Orientation = System.Windows.Forms.Orientation.Vertical; + this.tbLayer.Size = new System.Drawing.Size(45, 557); + this.tbLayer.TabIndex = 8; + this.tbLayer.TickStyle = System.Windows.Forms.TickStyle.TopLeft; + this.tbLayer.ValueChanged += new System.EventHandler(this.ValueChanged); + // // lbInitialLayer // this.lbInitialLayer.Dock = System.Windows.Forms.DockStyle.Fill; @@ -2827,18 +2839,6 @@ namespace UVtools.GUI this.mouseHoldTimer.Interval = 1000; this.mouseHoldTimer.Tick += new System.EventHandler(this.EventTimerTick); // - // tbLayer - // - this.tbLayer.Dock = System.Windows.Forms.DockStyle.Right; - this.tbLayer.Location = new System.Drawing.Point(93, 0); - this.tbLayer.Margin = new System.Windows.Forms.Padding(0); - this.tbLayer.Name = "tbLayer"; - this.tbLayer.Orientation = System.Windows.Forms.Orientation.Vertical; - this.tbLayer.Size = new System.Drawing.Size(45, 557); - this.tbLayer.TabIndex = 8; - this.tbLayer.TickStyle = System.Windows.Forms.TickStyle.TopLeft; - this.tbLayer.ValueChanged += new System.EventHandler(this.ValueChanged); - // // FrmMain // this.AllowDrop = true; @@ -2945,8 +2945,8 @@ namespace UVtools.GUI this.panelLayerNavigation.ResumeLayout(false); this.panelLayerNavigation.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pbTrackerIssues)).EndInit(); - this.panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.tbLayer)).EndInit(); + this.panel2.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -3000,7 +3000,6 @@ namespace UVtools.GUI private System.Windows.Forms.ToolStripButton btnLayerImageRotate; private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; private System.Windows.Forms.ToolStripButton btnLayerImageLayerDifference; - private Cyotek.Windows.Forms.ImageBox pbLayer; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; private System.Windows.Forms.ToolStripButton btnLayerImagePixelEdit; private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; @@ -3180,6 +3179,7 @@ namespace UVtools.GUI private System.Windows.Forms.ToolStripSeparator toolStripSeparator26; private System.Windows.Forms.ToolStripButton btnLogVerbose; private System.Windows.Forms.Label lbLayerImageOverlay; + public Cyotek.Windows.Forms.ImageBox pbLayer; } } diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs index 8ea093d..0d23959 100644 --- a/UVtools.GUI/FrmMain.cs +++ b/UVtools.GUI/FrmMain.cs @@ -15,6 +15,7 @@ using System.IO; using System.Linq; using System.Net; using System.Reflection; +using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -71,12 +72,24 @@ namespace UVtools.GUI public FrmLoading FrmLoading { get; } + public Rectangle ROI + { + get + { + var rectangleF = pbLayer.SelectionRegion; + return rectangleF.IsEmpty ? Rectangle.Empty : GetTransposedRectangle(rectangleF, false); + } + set => pbLayer.SelectionRegion = value; + } + public static FileFormat SlicerFile { get => Program.SlicerFile; set => Program.SlicerFile = value; } + public LayerCache LayerCache { get; set; } = new LayerCache(); + public uint ActualLayer { get; set; } public Mat ActualLayerImage { get; private set; } @@ -1338,6 +1351,14 @@ namespace UVtools.GUI ShowLayer(); if (ReferenceEquals(sender, btnLayerImageRotate)) { + // Arrange selection rotation + var rectangleF = pbLayer.SelectionRegion; + if (!rectangleF.IsEmpty) + { + var rectangle = Rectangle.Round(rectangleF); + pbLayer.SelectionRegion = GetTransposedRectangle(rectangle, btnLayerImageRotate.Checked, true); + } + ZoomToFit(); } @@ -1715,6 +1736,8 @@ namespace UVtools.GUI // GUI CLEAN pbThumbnail.Image = null; pbLayer.Image = null; + pbLayer.SelectNone(); + lbLayerImageOverlay.Visible = false; pbThumbnail.Image = null; tbGCode.Clear(); tabPageIssues.Tag = null; @@ -2245,19 +2268,6 @@ namespace UVtools.GUI var layer = SlicerFile[ActualLayer]; - VectorOfVectorOfPoint layerContours = null; - Mat layerHierarchy = null; - Array layerHierarchyJagged = null; - - void initContours() - { - if (!ReferenceEquals(layerContours, null)) return; - layerContours = new VectorOfVectorOfPoint(); - layerHierarchy = new Mat(); - CvInvoke.FindContours(ActualLayerImage, layerContours, layerHierarchy, RetrType.Ccomp, - ChainApproxMethod.ChainApproxSimple); - layerHierarchyJagged = layerHierarchy.GetData(); - } try { @@ -2273,6 +2283,7 @@ namespace UVtools.GUI ActualLayerImage?.Dispose(); ActualLayerImage = SlicerFile[layerNum].LayerMat; + LayerCache.Image = ActualLayerImage; CvInvoke.CvtColor(ActualLayerImage, ActualLayerImageBgr, ColorConversion.Gray2Bgr); @@ -2475,7 +2486,6 @@ namespace UVtools.GUI if (btnLayerImageLayerOutlineHollowAreas.Checked) { //CvInvoke.Threshold(ActualLayerImage, grayscale, 1, 255, ThresholdType.Binary); - initContours(); /* * hierarchy[i][0]: the index of the next contour of the same level @@ -2483,14 +2493,14 @@ namespace UVtools.GUI * hierarchy[i][2]: the index of the first child * hierarchy[i][3]: the index of the parent */ - for (int i = 0; i < layerContours.Size; i++) + for (int i = 0; i < LayerCache.LayerContours.Size; i++) { - if ((int) layerHierarchyJagged.GetValue(0, i, 2) == -1 && - (int) layerHierarchyJagged.GetValue(0, i, 3) != -1) + if ((int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 2) == -1 && + (int)LayerCache.LayerHierarchyJagged.GetValue(0, i, 3) != -1) { //var r = CvInvoke.BoundingRectangle(contours[i]); //CvInvoke.Rectangle(ActualLayerImageBgr, r, new MCvScalar(0, 0, 255), 2); - CvInvoke.DrawContours(ActualLayerImageBgr, layerContours, i, + CvInvoke.DrawContours(ActualLayerImageBgr, LayerCache.LayerContours, i, new MCvScalar(Settings.Default.OutlineHollowAreasColor.B, Settings.Default.OutlineHollowAreasColor.G, Settings.Default.OutlineHollowAreasColor.R), @@ -2563,16 +2573,15 @@ namespace UVtools.GUI } else if (operation.OperationType == PixelOperation.PixelOperationType.Eraser) { - initContours(); if (imageSpan[ActualLayerImage.GetPixelPos(operation.Location)] < 10) continue; var color = flvPixelHistory.SelectedObjects.Contains(operation) ? Settings.Default.PixelEditorRemovePixelHLColor : Settings.Default.PixelEditorRemovePixelColor; - for (int i = 0; i < layerContours.Size; i++) + for (int i = 0; i < LayerCache.LayerContours.Size; i++) { - if (CvInvoke.PointPolygonTest(layerContours[i], operation.Location, false) >= 0) + if (CvInvoke.PointPolygonTest(LayerCache.LayerContours[i], operation.Location, false) >= 0) { - CvInvoke.DrawContours(ActualLayerImageBgr, layerContours, i, + CvInvoke.DrawContours(ActualLayerImageBgr, LayerCache.LayerContours, i, new MCvScalar(color.B, color.G, color.R), -1); break; } @@ -2627,6 +2636,11 @@ namespace UVtools.GUI if (btnLayerImageRotate.Checked) { CvInvoke.Rotate(ActualLayerImageBgr, ActualLayerImageBgr, RotateFlags.Rotate90Clockwise); + /*var roi = Rectangle.Round(pbLayer.SelectionRegion); + if (roi != Rectangle.Empty) + { + pbLayer.SelectionRegion = G + }*/ } @@ -2650,10 +2664,6 @@ namespace UVtools.GUI tsLayerInfo.Update(); tsLayerInfo.Refresh(); - layerContours?.Dispose(); - layerHierarchy?.Dispose(); - - watch.Stop(); tsLayerPreviewTime.Text = $"{watch.ElapsedMilliseconds}ms"; //lbLayers.Text = $"{SlicerFile.GetHeightFromLayer(layerNum)} / {SlicerFile.TotalHeight}mm\n{layerNum} / {SlicerFile.LayerCount-1}\n{percent}%"; @@ -2794,14 +2804,17 @@ namespace UVtools.GUI { pbLayer.Cursor = Cursors.Cross; pbLayer.PanMode = ImageBoxPanMode.None; - lbLayerImageOverlay.Text = "Pixel editing is on\n" + - "Click to over a pixel to draw"; + lbLayerImageOverlay.Text = "Pixel editing is on:\n" + + "» Click to over a pixel to draw"; } else { + pbLayer.Cursor = Cursors.Cross; pbLayer.SelectionMode = ImageBoxSelectionMode.Rectangle; - lbLayerImageOverlay.Text = "ROI selection mode\n" + - "Click and drag to select an ROI\n" + + lbLayerImageOverlay.Text = "ROI selection mode:\n" + + "» Left-click and drag to select an ROI\n" + + "» Left-click + Alt and drag to select contained objects\n" + + "» Right click on an object to select its area\n" + "Press Esc to clear the ROI"; } @@ -2813,8 +2826,8 @@ namespace UVtools.GUI { pbLayer.Cursor = Cursors.Hand; pbLayer.PanMode = ImageBoxPanMode.None; - lbLayerImageOverlay.Text = "Issue selection mode\n" + - "Click over a issue to select it"; + lbLayerImageOverlay.Text = "Issue selection mode:\n" + + "» Click over a issue to select it"; lbLayerImageOverlay.Visible = true; return; @@ -3039,11 +3052,34 @@ namespace UVtools.GUI // unconditionally stop any pending mouse timer here. mouseHoldTimer.Stop(); + if (!pbLayer.IsPointInImage(e.Location)) return; + Point location = pbLayer.PointToImage(e.Location); + if (pbLayer.SelectionMode == ImageBoxSelectionMode.Rectangle) + { + if (e.Button == MouseButtons.Left) + { + if ((ModifierKeys & Keys.Alt) != 0) + { + if (SelectObjectRoi(ROI) == 0) SelectObjectRoi(location); + return; + } + return; + } + + if (e.Button == MouseButtons.Right) + { + if (!pbLayer.IsPointInImage(e.Location)) return; + SelectObjectRoi(location); + + return; + } + } + // Shift must be pressed for any pixel edit action, middle button is ignored. if (!btnLayerImagePixelEdit.Checked || (e.Button & MouseButtons.Middle) != 0 || (ModifierKeys & Keys.Shift) == 0) return; - if (!pbLayer.IsPointInImage(e.Location)) return; - var location = pbLayer.PointToImage(e.Location); + //if (!pbLayer.IsPointInImage(e.Location)) return; + //location = pbLayer.PointToImage(e.Location); _lastPixelMouseLocation = Point.Empty; // Left or Alt-Right Adds pixel, Right or Alt-Left removes pixel @@ -3053,6 +3089,53 @@ namespace UVtools.GUI } } + public bool SelectObjectRoi(Point location) + { + var point = GetTransposedPoint(location); + var brightness = ActualLayerImage.GetByte(point); + + if (brightness == 0) return false; + for (int i = 0; i < LayerCache.LayerContours.Size; i++) + { + if (CvInvoke.PointPolygonTest(LayerCache.LayerContours[i], point, false) >= 0) + { + var rectangle = + GetTransposedRectangle(CvInvoke.BoundingRectangle(LayerCache.LayerContours[i])); + ROI = rectangle; + + return true; + } + } + + return false; + } + + public uint SelectObjectRoi(Rectangle roiRectangle) + { + if (roiRectangle.IsEmpty) return 0; + List<Rectangle> rectangles = new List<Rectangle>(); + for (int i = 0; i < LayerCache.LayerContours.Size; i++) + { + var rectangle = CvInvoke.BoundingRectangle(LayerCache.LayerContours[i]); + //roi.Intersect(rectangle); + if (roiRectangle.IntersectsWith(rectangle)) + { + rectangles.Add(rectangle); + } + + } + roiRectangle = rectangles.Count == 0 ? Rectangle.Empty : rectangles[0]; + for (var i = 1; i < rectangles.Count; i++) + { + var rectangle = rectangles[i]; + roiRectangle = Rectangle.Union(roiRectangle, rectangle); + } + + ROI = GetTransposedRectangle(roiRectangle); + + return (uint) rectangles.Count; + } + private void EventMouseLeave(object sender, EventArgs e) { // Toolstrip Buttons do not register mouseup events if the mouse is no longer over @@ -3506,12 +3589,19 @@ namespace UVtools.GUI : new Point(ActualLayerImage.Height - 1 - point.Y, point.X); } - public Rectangle GetTransposedRectangle(Rectangle rectangle) + public Rectangle GetTransposedRectangle(RectangleF rectangleF, bool clockWise = true, bool ignoreLayerRotation = false) => + GetTransposedRectangle(Rectangle.Round(rectangleF), clockWise, ignoreLayerRotation); + + public Rectangle GetTransposedRectangle(Rectangle rectangle, bool clockWise = true, bool ignoreLayerRotation = false) { - return btnLayerImageRotate.Checked + if (rectangle.IsEmpty || (!ignoreLayerRotation && !btnLayerImageRotate.Checked)) return rectangle; + return clockWise ? new Rectangle(ActualLayerImage.Height - rectangle.Bottom, - rectangle.X, rectangle.Height, rectangle.Width) - : rectangle; + rectangle.Left, rectangle.Height, rectangle.Width) + //: new Rectangle(ActualLayerImage.Width - rectangle.Bottom, rectangle.Left, rectangle.Width, rectangle.Height); + //: new Rectangle(ActualLayerImage.Width - rectangle.Bottom, ActualLayerImage.Height-rectangle.Right, rectangle.Width, rectangle.Height); // Rotate90FlipX: // = Rotate270FlipY + //: new Rectangle(rectangle.Top, rectangle.Left, rectangle.Width, rectangle.Height); // Rotate270FlipX: // = Rotate90FlipY + : new Rectangle(rectangle.Top, ActualLayerImage.Height - rectangle.Right, rectangle.Height, rectangle.Width); // Rotate90FlipNone: // = Rotate270FlipXY } /// <summary> diff --git a/UVtools.GUI/FrmMain.resx b/UVtools.GUI/FrmMain.resx index 881eac7..c0d3023 100644 --- a/UVtools.GUI/FrmMain.resx +++ b/UVtools.GUI/FrmMain.resx @@ -174,7 +174,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABk - FAAAAk1TRnQBSQFMAgEBBgEAATABCwEwAQsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + FAAAAk1TRnQBSQFMAgEBBgEAATgBCwE4AQsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIC4AAxgBIgMwAUsDMAFMAzIBUDMAAQEDJAE2AysBQqwAAyIBMQNWAbkDXQHi AwAB/wMAAf8BKgEtASgB/gNTAawDTQGVAwABARgAAwkBDAMzAVIDUAGdA1cB6AMAAf4DKwH8Ay8BSqQA AyEBMANZAewBKwEuASkB+gNRAfcDUgH0A1MB8QNIAfYDQQH5AwAB/wNPAZsDAAEBCAADFQEdAz8BbgNV diff --git a/UVtools.GUI/LayerCache.cs b/UVtools.GUI/LayerCache.cs new file mode 100644 index 0000000..07ef491 --- /dev/null +++ b/UVtools.GUI/LayerCache.cs @@ -0,0 +1,79 @@ +using System; +using Emgu.CV; +using Emgu.CV.CvEnum; +using Emgu.CV.Util; + +namespace UVtools.GUI +{ + public sealed class LayerCache + { + private Mat _image; + private Array _layerHierarchyJagged; + private VectorOfVectorOfPoint _layerContours; + private Mat _layerHierarchy; + + public Mat Image + { + get => _image; + set + { + Clear(); + _image = value; + } + } + + public VectorOfVectorOfPoint LayerContours + { + get + { + if (_layerContours is null) CacheContours(); + return _layerContours; + } + private set => _layerContours = value; + } + + public Mat LayerHierarchy + { + get + { + if (_layerHierarchy is null) CacheContours(); + return _layerHierarchy; + } + private set => _layerHierarchy = value; + } + + public Array LayerHierarchyJagged + { + get + { + if(_layerHierarchyJagged is null) CacheContours(); + return _layerHierarchyJagged; + } + private set => _layerHierarchyJagged = value; + } + + public void CacheContours(bool refresh = false) + { + if(refresh) Clear(); + if (!ReferenceEquals(_layerContours, null)) return; + _layerContours = new VectorOfVectorOfPoint(); + _layerHierarchy = new Mat(); + CvInvoke.FindContours(Image, _layerContours, _layerHierarchy, RetrType.Ccomp, + ChainApproxMethod.ChainApproxSimple); + _layerHierarchyJagged = _layerHierarchy.GetData(); + } + + + /// <summary> + /// Clears the cache + /// </summary> + public void Clear() + { + _layerContours?.Dispose(); + _layerContours = null; + _layerHierarchy?.Dispose(); + _layerHierarchy = null; + _layerHierarchyJagged = null; + } + } +} diff --git a/UVtools.GUI/UVtools.GUI.csproj b/UVtools.GUI/UVtools.GUI.csproj index 85bfe97..636d9ce 100644 --- a/UVtools.GUI/UVtools.GUI.csproj +++ b/UVtools.GUI/UVtools.GUI.csproj @@ -188,6 +188,12 @@ <Compile Include="Controls\Tools\CtrlToolRepairLayers.Designer.cs"> <DependentUpon>CtrlToolRepairLayers.cs</DependentUpon> </Compile> + <Compile Include="Controls\Tools\CtrlToolSolidify.cs"> + <SubType>UserControl</SubType> + </Compile> + <Compile Include="Controls\Tools\CtrlToolSolidify.Designer.cs"> + <DependentUpon>CtrlToolSolidify.cs</DependentUpon> + </Compile> <Compile Include="Controls\Tools\CtrlToolThreshold.cs"> <SubType>UserControl</SubType> </Compile> @@ -327,6 +333,7 @@ <DependentUpon>FrmMain.cs</DependentUpon> </Compile> <Compile Include="Forms\PEProfileFolder.cs" /> + <Compile Include="LayerCache.cs" /> <Compile Include="Program.cs" /> <Compile Include="Properties\Annotations.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> @@ -345,6 +352,9 @@ <EmbeddedResource Include="Controls\Tools\CtrlToolRepairLayers.resx"> <DependentUpon>CtrlToolRepairLayers.cs</DependentUpon> </EmbeddedResource> + <EmbeddedResource Include="Controls\Tools\CtrlToolSolidify.resx"> + <DependentUpon>CtrlToolSolidify.cs</DependentUpon> + </EmbeddedResource> <EmbeddedResource Include="Controls\Tools\CtrlToolThreshold.resx"> <DependentUpon>CtrlToolThreshold.cs</DependentUpon> </EmbeddedResource> |