Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2020-07-04 23:29:58 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2020-07-04 23:29:58 +0300
commit2c514fe260b7939f372c745b5e600ee877b88e12 (patch)
treeb0c7b92f8a3fbf30c3a983efb17c5ac0ebae0657
parent08fe746dac81d2311978427ebf44f06f10601186 (diff)
v0.6.1.1v0.6.1.1
* (Add) Allow chitubox, phz, pws, pw0 files convert to cws * (Add) Allow convert between cbddlp, ctb and photon * (Add) Allow convert between pws and pw0 * (Improvement) Layers can now have modified heights and independent parameters (#9) * (Improvement) UVtools now generate better gcode and detect the lack of Lift and same z position and optimize the commands * (Fix) zcodex: Wasn't reporting layer decoding progress
-rw-r--r--CHANGELOG.md10
-rw-r--r--UVtools.Cmd/Program.cs1
-rw-r--r--UVtools.Core/FileFormats/CWSFile.cs (renamed from UVtools.Core/CWSFile.cs)96
-rw-r--r--UVtools.Core/FileFormats/ChituboxFile.cs (renamed from UVtools.Core/ChituboxFile.cs)139
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs (renamed from UVtools.Core/ChituboxZipFile.cs)80
-rw-r--r--UVtools.Core/FileFormats/FileExtension.cs (renamed from UVtools.Core/FileExtension.cs)2
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs (renamed from UVtools.Core/FileFormat.cs)6
-rw-r--r--UVtools.Core/FileFormats/IFileFormat.cs (renamed from UVtools.Core/IFileFormat.cs)3
-rw-r--r--UVtools.Core/FileFormats/ImageFile.cs (renamed from UVtools.Core/ImageFile.cs)4
-rw-r--r--UVtools.Core/FileFormats/PHZFile.cs (renamed from UVtools.Core/PHZFile.cs)67
-rw-r--r--UVtools.Core/FileFormats/PWSFile.cs (renamed from UVtools.Core/PWSFile.cs)96
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs (renamed from UVtools.Core/SL1File.cs)34
-rw-r--r--UVtools.Core/FileFormats/ZCodexFile.cs (renamed from UVtools.Core/ZCodexFile.cs)100
-rw-r--r--UVtools.Core/Layer/Layer.cs692
-rw-r--r--UVtools.Core/Layer/LayerIssue.cs245
-rw-r--r--UVtools.Core/Layer/LayerManager.cs (renamed from UVtools.Core/LayerManager.cs)922
-rw-r--r--UVtools.Core/MatBytes.cs84
-rw-r--r--UVtools.Core/Operations/OperationMove.cs (renamed from UVtools.Core/OperationMove.cs)4
-rw-r--r--UVtools.Core/Operations/OperationPattern.cs (renamed from UVtools.Core/OperationPattern.cs)2
-rw-r--r--UVtools.Core/Operations/OperationProgress.cs (renamed from UVtools.Core/OperationProgress.cs)2
-rw-r--r--UVtools.Core/UVtools.Core.csproj7
-rw-r--r--UVtools.GUI/Forms/FrmAbout.cs1
-rw-r--r--UVtools.GUI/Forms/FrmInputBox.cs1
-rw-r--r--UVtools.GUI/Forms/FrmLoading.cs1
-rw-r--r--UVtools.GUI/Forms/FrmMutationMove.cs1
-rw-r--r--UVtools.GUI/Forms/FrmSettings.cs1
-rw-r--r--UVtools.GUI/Forms/FrmToolPattern.cs1
-rw-r--r--UVtools.GUI/FrmMain.Designer.cs20
-rw-r--r--UVtools.GUI/FrmMain.cs32
-rw-r--r--UVtools.GUI/Program.cs1
-rw-r--r--UVtools.GUI/Properties/AssemblyInfo.cs4
31 files changed, 1547 insertions, 1112 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3db33d3..4cc4018 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Changelog
+## 02/07/2020 - v0.6.1.1
+
+* (Add) Allow chitubox, phz, pws, pw0 files convert to cws
+* (Add) Allow convert between cbddlp, ctb and photon
+* (Add) Allow convert between pws and pw0
+* (Improvement) Layers can now have modified heights and independent parameters (#9)
+* (Improvement) UVtools now generate better gcode and detect the lack of Lift and same z position and optimize the commands
+* (Fix) zcodex: Wasn't reporting layer decoding progress
+
+
## 02/07/2020 - v0.6.1.0
* (Add) Thumbnail image can now saved to clipboard
diff --git a/UVtools.Cmd/Program.cs b/UVtools.Cmd/Program.cs
index b1224f7..15cbff0 100644
--- a/UVtools.Cmd/Program.cs
+++ b/UVtools.Cmd/Program.cs
@@ -10,6 +10,7 @@ using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using UVtools.Core;
+using UVtools.Core.FileFormats;
namespace UVtools.Cmd
{
diff --git a/UVtools.Core/CWSFile.cs b/UVtools.Core/FileFormats/CWSFile.cs
index 4dcfa76..f6a1ddb 100644
--- a/UVtools.Core/CWSFile.cs
+++ b/UVtools.Core/FileFormats/CWSFile.cs
@@ -13,10 +13,11 @@ using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
-using System.Threading.Tasks;
+using System.Text.RegularExpressions;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class CWSFile : FileFormat
{
@@ -290,6 +291,9 @@ namespace UVtools.Core
LayerManager = new LayerManager(OutputSettings.LayersNum);
+ var gcode = GCode.ToString();
+ float currentHeight = 0;
+
foreach (var zipArchiveEntry in inputFile.Entries)
{
if (!zipArchiveEntry.Name.EndsWith(".png")) continue;
@@ -297,8 +301,55 @@ namespace UVtools.Core
// - .png - 4 numbers
int layerSize = OutputSettings.LayersNum.ToString().Length;
string layerStr = zipArchiveEntry.Name.Substring(zipArchiveEntry.Name.Length - 4 - layerSize, layerSize);
- uint iLayer = uint.Parse(layerStr);
- LayerManager[iLayer] = new Layer(iLayer, zipArchiveEntry.Open(), zipArchiveEntry.Name);
+ uint layerIndex = uint.Parse(layerStr);
+
+ var startStr = $"{GCodeKeywordSlice} {layerIndex}";
+ var stripGcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length);
+ stripGcode = stripGcode.Substring(0, stripGcode.IndexOf(GCodeKeywordDelay, stripGcode.IndexOf(GCodeKeywordSlice))).Trim(' ', '\n', '\r', '\t');
+ //var startCurrPos = stripGcode.Remove(0, ";currPos:".Length);
+
+ /*
+ *
+;<Slice> 0
+M106 S255
+;<Delay> 45000
+M106 S0
+;<Slice> Blank
+G1 Z4 F120
+G1 Z-3.9 F120
+;<Delay> 45000
+ */
+
+ var currPos = Regex.Match(stripGcode, "G1 Z([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase);
+ var exposureTime = Regex.Match(stripGcode, ";<Delay> (\\d+)", RegexOptions.IgnoreCase);
+ /*var pwm = Regex.Match(stripGcode, "M106 S(\\d+)", RegexOptions.IgnoreCase);
+ if (layerIndex < InitialLayerCount)
+ {
+ OutputSettings.BottomLayerLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }
+ else
+ {
+ OutputSettings.LayerLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }*/
+
+ if (currPos.Success)
+ {
+ var nextMatch = currPos.NextMatch();
+ if (nextMatch.Success)
+ {
+ currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value) + float.Parse(currPos.NextMatch().Groups[1].Value), 2);
+ }
+ else
+ {
+ currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value), 2);
+ }
+ }
+
+ LayerManager[layerIndex] = new Layer(layerIndex, zipArchiveEntry.Open(), zipArchiveEntry.Name)
+ {
+ PositionZ = currentHeight,
+ ExposureTime = float.Parse(exposureTime.Groups[1].Value) / 1000f
+ };
}
}
@@ -318,10 +369,19 @@ namespace UVtools.Core
public override bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, string value)
{
+ void UpdateLayers()
+ {
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ this[layerIndex].ExposureTime = GetInitialLayerValueOrNormal(layerIndex, InitialExposureTime, LayerExposureTime);
+ }
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.InitialLayerCount))
{
SliceSettings.HeadLayersNum =
OutputSettings.NumberBottomLayers = value.Convert<ushort>();
+ UpdateLayers();
UpdateGCode();
return true;
}
@@ -329,6 +389,7 @@ namespace UVtools.Core
{
SliceSettings.HeadLayersExpoMs =
OutputSettings.BottomLayersTime = value.Convert<uint>()*1000;
+ UpdateLayers();
UpdateGCode();
return true;
}
@@ -336,6 +397,7 @@ namespace UVtools.Core
{
SliceSettings.LayersExpoMs =
OutputSettings.LayerTime = value.Convert<uint>() * 1000;
+ UpdateLayers();
UpdateGCode();
return true;
}
@@ -453,17 +515,33 @@ namespace UVtools.Core
GCode.AppendLine();
GCode.AppendFormat(GCodeStart, Environment.NewLine);
+ float lastZPosition = 0;
+
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
- //Layer layer = this[layerIndex];
+ Layer layer = this[layerIndex];
GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}");
GCode.AppendLine($"M106 S{GetInitialLayerValueOrNormal(layerIndex, OutputSettings.BottomLayerLightPWM, OutputSettings.LayerLightPWM)}");
- GCode.AppendLine($"{GCodeKeywordDelay} {GetInitialLayerValueOrNormal(layerIndex, SliceSettings.HeadLayersExpoMs, SliceSettings.LayersExpoMs)}");
+ GCode.AppendLine($"{GCodeKeywordDelay} {layer.ExposureTime}");
GCode.AppendLine("M106 S0");
GCode.AppendLine(GCodeKeywordSliceBlank);
- GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}");
- GCode.AppendLine($"G1 Z-{LiftHeight - LayerHeight} F{RetractSpeed}");
- GCode.AppendLine($"{GCodeKeywordDelay} {GetInitialLayerValueOrNormal(layerIndex, SliceSettings.HeadLayersExpoMs, SliceSettings.LayersExpoMs)}");
+
+ if (lastZPosition != layer.PositionZ)
+ {
+ if (LiftHeight > 0)
+ {
+ GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}");
+ GCode.AppendLine($"G1 Z-{LiftHeight - layer.PositionZ + lastZPosition} F{RetractSpeed}");
+ }
+ else
+ {
+ GCode.AppendLine($"G1 Z{layer.PositionZ - lastZPosition} F{LiftSpeed}");
+ }
+ }
+
+ GCode.AppendLine($"{GCodeKeywordDelay} {layer.ExposureTime}");
+
+ lastZPosition = layer.PositionZ;
}
GCode.AppendFormat(GCodeEnd, Environment.NewLine, SliceSettings.LiftWhenFinished);
diff --git a/UVtools.Core/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs
index a011dd0..2ad10d1 100644
--- a/UVtools.Core/ChituboxFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxFile.cs
@@ -19,8 +19,9 @@ using BinarySerialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class ChituboxFile : FileFormat
{
@@ -508,15 +509,16 @@ namespace UVtools.Core
public LayerData(ChituboxFile parent, uint layerIndex)
{
Parent = parent;
- LayerPositionZ = parent.GetHeightFromLayer(layerIndex);
+ LayerPositionZ = parent[layerIndex].PositionZ;
+ LayerExposure = parent[layerIndex].ExposureTime;
- LayerOffTimeSeconds = layerIndex < parent.HeaderSettings.BottomLayersCount
- ? parent.PrintParametersSettings.BottomLightOffDelay
- : parent.PrintParametersSettings.LightOffDelay;
+ LayerOffTimeSeconds = parent.GetInitialLayerValueOrNormal(layerIndex,
+ parent.PrintParametersSettings.BottomLightOffDelay,
+ parent.PrintParametersSettings.LightOffDelay);
- LayerExposure = layerIndex < parent.HeaderSettings.BottomLayersCount
+ /*LayerExposure = layerIndex < parent.HeaderSettings.BottomLayersCount
? parent.HeaderSettings.BottomExposureSeconds
- : parent.HeaderSettings.LayerExposureSeconds;
+ : parent.HeaderSettings.LayerExposureSeconds;*/
}
public Mat Decode(uint layerIndex, bool consumeData = true)
@@ -531,9 +533,6 @@ namespace UVtools.Core
public static Mat DecodeCbddlpImage(ChituboxFile parent, uint layerIndex)
{
- //Mat image = new Mat(new Size((int)parent.HeaderSettings.ResolutionX, (int)parent.HeaderSettings.ResolutionY), DepthType.Cv8U, 1);
- //var bytes = image.GetBytesBlank();
- //var image = EmguExtensions.CreateMat(out var bytes, new Size((int)parent.HeaderSettings.ResolutionX, (int)parent.HeaderSettings.ResolutionY));
var image = new Mat(new Size((int)parent.HeaderSettings.ResolutionX, (int)parent.HeaderSettings.ResolutionY), DepthType.Cv8U, 1);
var span = image.GetPixelSpan<byte>();
@@ -909,10 +908,12 @@ namespace UVtools.Core
public override Type[] ConvertToFormats { get; } =
{
+ typeof(ChituboxFile),
typeof(ChituboxZipFile),
typeof(PWSFile),
typeof(PHZFile),
typeof(ZCodexFile),
+ typeof(CWSFile),
};
public override PrintParameterModifier[] PrintParameterModifiers { get; } =
@@ -1013,6 +1014,10 @@ namespace UVtools.Core
HeaderSettings.EncryptionKey = (uint)rnd.Next(byte.MaxValue, int.MaxValue);
}
}
+ else
+ {
+ HeaderSettings.EncryptionKey = 0;
+ }
uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
LayersDefinitions = new LayerData[HeaderSettings.AntiAliasLevel, HeaderSettings.LayerCount];
@@ -1099,7 +1104,7 @@ namespace UVtools.Core
var layerData = LayersDefinitions[aaIndex, layerIndex];
LayerData layerDataHash = null;
- if (!IsCbtFile && HeaderSettings.EncryptionKey == 0)
+ if (!IsCbtFile /*&& HeaderSettings.EncryptionKey == 0*/)
{
string hash = Helpers.ComputeSHA1Hash(layerData.EncodedRle);
if (LayersHash.TryGetValue(hash, out layerDataHash))
@@ -1258,7 +1263,12 @@ namespace UVtools.Core
using (var image = LayersDefinitions[0, layerIndex].Decode((uint) layerIndex))
{
- this[layerIndex] = new Layer((uint) layerIndex, image);
+ this[layerIndex] = new Layer((uint) layerIndex, image)
+ {
+ PositionZ = LayersDefinitions[0, layerIndex].LayerPositionZ,
+ ExposureTime = LayersDefinitions[0, layerIndex].LayerExposure
+ };
+
lock (progress.Mutex)
{
progress++;
@@ -1299,8 +1309,10 @@ namespace UVtools.Core
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
// Bottom : others
- LayersDefinitions[aaIndex, layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds;
- LayersDefinitions[aaIndex, layerIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? PrintParametersSettings.BottomLightOffDelay : PrintParametersSettings.LightOffDelay;
+ this[layerIndex].ExposureTime =
+ LayersDefinitions[aaIndex, layerIndex].LayerExposure = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomExposureSeconds, HeaderSettings.LayerExposureSeconds);
+
+ LayersDefinitions[aaIndex, layerIndex].LayerOffTimeSeconds = GetInitialLayerValueOrNormal(layerIndex, PrintParametersSettings.BottomLightOffDelay, HeaderSettings.LayerOffTime);
}
}
}
@@ -1427,6 +1439,66 @@ namespace UVtools.Core
public override bool Convert(Type to, string fileFullPath, OperationProgress progress = null)
{
+ if (to == typeof(ChituboxFile))
+ {
+ if (Path.GetExtension(FileFullPath).Equals(Path.GetExtension(fileFullPath)))
+ {
+ return false;
+ }
+ ChituboxFile file = new ChituboxFile
+ {
+ LayerManager = LayerManager,
+ HeaderSettings =
+ {
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ BedSizeX = HeaderSettings.BedSizeX,
+ BedSizeY = HeaderSettings.BedSizeY,
+ BedSizeZ = HeaderSettings.BedSizeZ,
+ ProjectorType = HeaderSettings.ProjectorType,
+ LayerCount = LayerCount,
+ AntiAliasLevel = ValidateAntiAliasingLevel(),
+ BottomLightPWM = (byte) HeaderSettings.BottomLightPWM,
+ LightPWM = (byte) HeaderSettings.LightPWM,
+ LayerOffTime = HeaderSettings.LayerOffTime,
+ PrintTime = HeaderSettings.PrintTime,
+ BottomExposureSeconds = HeaderSettings.BottomExposureSeconds,
+ BottomLayersCount = HeaderSettings.BottomLayersCount,
+ //EncryptionKey = HeaderSettings.EncryptionKey,
+ LayerExposureSeconds = HeaderSettings.LayerExposureSeconds,
+ LayerHeightMilimeter = HeaderSettings.LayerHeightMilimeter,
+ OverallHeightMilimeter = HeaderSettings.OverallHeightMilimeter,
+ },
+ PrintParametersSettings =
+ {
+ LiftSpeed = PrintParametersSettings.LiftSpeed,
+ LiftHeight = PrintParametersSettings.LiftHeight,
+ BottomLiftSpeed = PrintParametersSettings.BottomLiftSpeed,
+ RetractSpeed = PrintParametersSettings.RetractSpeed,
+ BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay,
+ LightOffDelay = PrintParametersSettings.BottomLightOffDelay,
+ BottomLayerCount = PrintParametersSettings.BottomLayerCount,
+ VolumeMl = PrintParametersSettings.VolumeMl,
+ BottomLiftHeight = PrintParametersSettings.BottomLiftHeight,
+ CostDollars = PrintParametersSettings.CostDollars,
+ WeightG = PrintParametersSettings.WeightG
+ },
+ SlicerInfoSettings =
+ {
+ AntiAliasLevel = SlicerInfoSettings.AntiAliasLevel,
+ MachineName = SlicerInfoSettings.MachineName,
+ //EncryptionMode = SlicerInfoSettings.EncryptionMode,
+ MachineNameSize = SlicerInfoSettings.MachineNameSize,
+ },
+ Thumbnails = Thumbnails,
+ };
+
+ //file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
if (to == typeof(ChituboxZipFile))
{
ChituboxZipFile file = new ChituboxZipFile
@@ -1643,6 +1715,45 @@ namespace UVtools.Core
return true;
}
+ if (to == typeof(CWSFile))
+ {
+ CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile));
+ CWSFile file = new CWSFile { LayerManager = LayerManager };
+
+ file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = (float)Math.Round(ResolutionX / HeaderSettings.BedSizeX, 3);
+ file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float)Math.Round(ResolutionY / HeaderSettings.BedSizeY, 3);
+ file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX;
+ file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY;
+ file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight;
+ file.SliceSettings.LayersNum = file.OutputSettings.LayersNum = LayerCount;
+ file.SliceSettings.HeadLayersNum = file.OutputSettings.NumberBottomLayers = InitialLayerCount;
+ file.SliceSettings.LayersExpoMs = file.OutputSettings.LayerTime = (uint)LayerExposureTime * 1000;
+ file.SliceSettings.HeadLayersExpoMs = file.OutputSettings.BottomLayersTime = (uint)InitialExposureTime * 1000;
+ file.SliceSettings.WaitBeforeExpoMs = (uint)(PrintParametersSettings.LightOffDelay * 1000);
+ file.SliceSettings.LiftDistance = file.OutputSettings.LiftDistance = LiftHeight;
+ file.SliceSettings.LiftUpSpeed = file.OutputSettings.ZLiftFeedRate = LiftSpeed;
+ file.SliceSettings.LiftDownSpeed = file.OutputSettings.ZLiftRetractRate = RetractSpeed;
+ file.SliceSettings.LiftWhenFinished = defaultFormat.SliceSettings.LiftWhenFinished;
+
+ file.OutputSettings.BlankingLayerTime = (uint) (PrintParametersSettings.LightOffDelay * 1000);
+ //file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.OutlineWidthInset = 0;
+ //file.OutputSettings.OutlineWidthOutset = 0;
+ file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.TiltValue = 0;
+ //file.OutputSettings.UseMainliftGCodeTab = false;
+ //file.OutputSettings.AntiAliasing = 0;
+ //file.OutputSettings.AntiAliasingValue = 0;
+ file.OutputSettings.FlipX = HeaderSettings.ProjectorType != 0;
+ file.OutputSettings.FlipY = file.OutputSettings.FlipX;
+ file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel();
+ file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1;
+
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
return false;
}
#endregion
diff --git a/UVtools.Core/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index 5fea234..07749a7 100644
--- a/UVtools.Core/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -14,12 +14,14 @@ using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
+using System.Text.RegularExpressions;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class ChituboxZipFile : FileFormat
{
@@ -242,6 +244,8 @@ namespace UVtools.Core
progress.ItemCount = LayerCount;
+ var gcode = GCode.ToString();
+
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
entry = inputFile.GetEntry($"{layerIndex+1}.png");
@@ -251,7 +255,28 @@ namespace UVtools.Core
throw new FileLoadException($"Layer {layerIndex+1} not found", fileFullPath);
}
- LayerManager[layerIndex] = new Layer(layerIndex, entry.Open(), entry.Name);
+ var startStr = $";LAYER_START:{layerIndex}";
+ var stripGcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length);
+ stripGcode = stripGcode.Substring(0, stripGcode.IndexOf(";LAYER_END")).Trim(' ', '\n', '\r', '\t');
+ //var startCurrPos = stripGcode.Remove(0, ";currPos:".Length);
+
+ var currPos = Regex.Match(stripGcode, ";currPos:([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase);
+ var exposureTime = Regex.Match(stripGcode, "G4 P(\\d+)", RegexOptions.IgnoreCase);
+ var pwm = Regex.Match(stripGcode, "M106 S(\\d+)", RegexOptions.IgnoreCase);
+ if (layerIndex < InitialLayerCount)
+ {
+ HeaderSettings.BottomLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }
+ else
+ {
+ HeaderSettings.LayerLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }
+
+ LayerManager[layerIndex] = new Layer(layerIndex, entry.Open(), entry.Name)
+ {
+ PositionZ = float.Parse(currPos.Groups[1].Value),
+ ExposureTime = float.Parse(exposureTime.NextMatch().Groups[1].Value) / 1000f
+ };
progress++;
}
@@ -293,16 +318,26 @@ namespace UVtools.Core
public override bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, string value)
{
+ void UpdateLayers()
+ {
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ this[layerIndex].ExposureTime = GetInitialLayerValueOrNormal(layerIndex, InitialExposureTime, LayerExposureTime);
+ }
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.InitialLayerCount))
{
HeaderSettings.BottomLayerCount =
HeaderSettings.BottomLayCount = value.Convert<ushort>();
+ UpdateLayers();
UpdateGCode();
return true;
}
if (ReferenceEquals(modifier, PrintParameterModifier.InitialExposureSeconds))
{
HeaderSettings.BottomLayerExposureTime = value.Convert<float>();
+ UpdateLayers();
UpdateGCode();
return true;
}
@@ -310,6 +345,7 @@ namespace UVtools.Core
if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds))
{
HeaderSettings.LayerExposureTime = value.Convert<float>();
+ UpdateLayers();
UpdateGCode();
return true;
}
@@ -426,19 +462,47 @@ namespace UVtools.Core
GCode.AppendLine();
GCode.AppendFormat(GCodeStart, Environment.NewLine);
+ float lastZPosition = 0;
+
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
+ var liftHeight = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomLayerLiftHeight,
+ HeaderSettings.LayerLiftHeight);
+
+ var liftZHeight = liftHeight + this[layerIndex].PositionZ;
+
+ var liftZSpeed = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomLayerLiftSpeed,
+ HeaderSettings.LayerLiftSpeed);
+
+ var lightOffDelay = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomLightOffTime,
+ HeaderSettings.LayerLightOffTime) * 1000;
+
+ var pwmValue = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomLightPWM, HeaderSettings.LayerLightPWM);
+ var exposureTime = GetInitialLayerValueOrNormal(layerIndex, InitialExposureTime, LayerExposureTime) * 1000;
+
GCode.AppendLine($";LAYER_START:{layerIndex}");
- GCode.AppendLine($";currPos:{GetHeightFromLayer(layerIndex, false)}");
+ GCode.AppendLine($";currPos:{this[layerIndex].PositionZ}");
GCode.AppendLine($"M6054 \"{layerIndex+1}.png\";show Image");
- GCode.AppendLine($"G0 Z{(layerIndex < InitialLayerCount ? HeaderSettings.BottomLayerLiftHeight : HeaderSettings.LayerLiftHeight) +GetHeightFromLayer(layerIndex, false)} F{(layerIndex < InitialLayerCount ? HeaderSettings.BottomLayerLiftSpeed : HeaderSettings.LayerLiftSpeed)};Z Lift");
- GCode.AppendLine($"G0 Z{GetHeightFromLayer(layerIndex)} F{HeaderSettings.RetractSpeed};Layer position");
- GCode.AppendLine($"G4 P{(layerIndex < InitialLayerCount ? HeaderSettings.BottomLightOffTime : HeaderSettings.LayerLightOffTime)*1000};Before cure delay");
- GCode.AppendLine($"M106 S{(layerIndex < InitialLayerCount ? HeaderSettings.BottomLightPWM : HeaderSettings.LayerLightPWM)};light on");
- GCode.AppendLine($"G4 P{(layerIndex < InitialLayerCount ? HeaderSettings.BottomLayerExposureTime : HeaderSettings.LayerExposureTime) * 1000};Cure time");
+
+ // Absolute gcode
+ if (liftHeight > 0 && liftZHeight > this[layerIndex].PositionZ)
+ {
+ GCode.AppendLine($"G0 Z{liftZHeight} F{liftZSpeed};Z Lift");
+ }
+
+ if (lastZPosition < this[layerIndex].PositionZ)
+ {
+ GCode.AppendLine($"G0 Z{this[layerIndex].PositionZ} F{HeaderSettings.RetractSpeed};Layer position");
+ }
+
+ GCode.AppendLine($"G4 P{lightOffDelay};Before cure delay");
+ GCode.AppendLine($"M106 S{pwmValue};light on");
+ GCode.AppendLine($"G4 P{exposureTime};Cure time");
GCode.AppendLine("M106 S0;light off");
GCode.AppendLine(";LAYER_END");
GCode.AppendLine();
+
+ lastZPosition = this[layerIndex].PositionZ;
}
GCode.AppendFormat(GCodeEnd, Environment.NewLine, HeaderSettings.MachineZ);
diff --git a/UVtools.Core/FileExtension.cs b/UVtools.Core/FileFormats/FileExtension.cs
index 7838211..904da8c 100644
--- a/UVtools.Core/FileExtension.cs
+++ b/UVtools.Core/FileFormats/FileExtension.cs
@@ -8,7 +8,7 @@
using System.Collections.Generic;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
/// <summary>
/// Represents a file extension for slicer file formats
diff --git a/UVtools.Core/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 018de42..89235cc 100644
--- a/UVtools.Core/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -12,13 +12,13 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
/// <summary>
/// Slicer <see cref="FileFormat"/> representation
@@ -274,7 +274,7 @@ namespace UVtools.Core
public abstract float LayerHeight { get; }
- public float TotalHeight => (float)Math.Round(LayerCount * LayerHeight, 2);
+ public float TotalHeight => LayerCount == 0 ? 0 : this[LayerCount - 1].PositionZ; //(float)Math.Round(LayerCount * LayerHeight, 2);
public uint LayerCount => LayerManager?.Count ?? 0;
diff --git a/UVtools.Core/IFileFormat.cs b/UVtools.Core/FileFormats/IFileFormat.cs
index 058298d..8b88602 100644
--- a/UVtools.Core/IFileFormat.cs
+++ b/UVtools.Core/FileFormats/IFileFormat.cs
@@ -9,8 +9,9 @@
using System;
using System.Text;
using Emgu.CV;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
/// <summary>
/// Slicer file format representation interface
diff --git a/UVtools.Core/ImageFile.cs b/UVtools.Core/FileFormats/ImageFile.cs
index a9c6ac5..5e2761e 100644
--- a/UVtools.Core/ImageFile.cs
+++ b/UVtools.Core/FileFormats/ImageFile.cs
@@ -1,11 +1,11 @@
using System;
using System.IO;
-using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
+using UVtools.Core.Operations;
using Size = System.Drawing.Size;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class ImageFile : FileFormat
{
diff --git a/UVtools.Core/PHZFile.cs b/UVtools.Core/FileFormats/PHZFile.cs
index bf1b791..c921493 100644
--- a/UVtools.Core/PHZFile.cs
+++ b/UVtools.Core/FileFormats/PHZFile.cs
@@ -14,15 +14,15 @@ using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using BinarySerialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class PHZFile : FileFormat
{
@@ -453,9 +453,12 @@ namespace UVtools.Core
public LayerData(PHZFile parent, uint layerIndex)
{
Parent = parent;
- LayerOffTimeSeconds = layerIndex < parent.HeaderSettings.BottomLayersCount ? parent.HeaderSettings.BottomLightOffDelay : parent.HeaderSettings.LayerOffTime;
- LayerExposure = layerIndex < Parent.InitialLayerCount ? Parent.HeaderSettings.BottomExposureSeconds : Parent.HeaderSettings.LayerExposureSeconds;
- LayerPositionZ = Parent.GetHeightFromLayer(layerIndex);
+ LayerPositionZ = parent[layerIndex].PositionZ;
+ LayerExposure = parent[layerIndex].ExposureTime;
+
+ LayerOffTimeSeconds = parent.GetInitialLayerValueOrNormal(layerIndex,
+ parent.HeaderSettings.BottomLightOffDelay,
+ parent.HeaderSettings.LayerOffTime);
}
public Mat Decode(uint layerIndex, bool consumeData = true)
@@ -682,6 +685,7 @@ namespace UVtools.Core
typeof(ChituboxZipFile),
typeof(PWSFile),
typeof(ZCodexFile),
+ typeof(CWSFile),
};
public override PrintParameterModifier[] PrintParameterModifiers { get; } =
@@ -819,7 +823,7 @@ namespace UVtools.Core
Parallel.For(0, LayerCount, /*new ParallelOptions{MaxDegreeOfParallelism = 1},*/ layerIndex =>
{
if(progress.Token.IsCancellationRequested) return;
- LayerData layer = new LayerData(this, (uint)layerIndex);
+ LayerData layer = new LayerData(this, (uint) layerIndex);
using (var image = this[layerIndex].LayerMat)
{
layer.Encode(image, (uint) layerIndex);
@@ -975,7 +979,11 @@ namespace UVtools.Core
using (var image = LayersDefinitions[layerIndex].Decode((uint) layerIndex, true))
{
- this[layerIndex] = new Layer((uint) layerIndex, image);
+ this[layerIndex] = new Layer((uint) layerIndex, image)
+ {
+ PositionZ = LayersDefinitions[layerIndex].LayerPositionZ,
+ ExposureTime = LayersDefinitions[layerIndex].LayerExposure
+ };
}
lock (progress.Mutex)
@@ -1015,8 +1023,10 @@ namespace UVtools.Core
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
{
// Bottom : others
- LayersDefinitions[layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomExposureSeconds : HeaderSettings.LayerExposureSeconds;
- LayersDefinitions[layerIndex].LayerOffTimeSeconds = layerIndex < HeaderSettings.BottomLayersCount ? HeaderSettings.BottomLightOffDelay : HeaderSettings.LayerOffTime;
+ this[layerIndex].ExposureTime =
+ LayersDefinitions[layerIndex].LayerExposure = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomExposureSeconds, HeaderSettings.LayerExposureSeconds);
+
+ LayersDefinitions[layerIndex].LayerOffTimeSeconds = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomLightOffDelay, HeaderSettings.LayerOffTime);
}
}
@@ -1360,6 +1370,45 @@ namespace UVtools.Core
return true;
}
+ if (to == typeof(CWSFile))
+ {
+ CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile));
+ CWSFile file = new CWSFile { LayerManager = LayerManager };
+
+ file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = (float)Math.Round(ResolutionX / HeaderSettings.BedSizeX, 3);
+ file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float)Math.Round(ResolutionY / HeaderSettings.BedSizeY, 3);
+ file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX;
+ file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY;
+ file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight;
+ file.SliceSettings.LayersNum = file.OutputSettings.LayersNum = LayerCount;
+ file.SliceSettings.HeadLayersNum = file.OutputSettings.NumberBottomLayers = InitialLayerCount;
+ file.SliceSettings.LayersExpoMs = file.OutputSettings.LayerTime = (uint)LayerExposureTime * 1000;
+ file.SliceSettings.HeadLayersExpoMs = file.OutputSettings.BottomLayersTime = (uint)InitialExposureTime * 1000;
+ file.SliceSettings.WaitBeforeExpoMs = (uint)(HeaderSettings.LayerOffTime * 1000);
+ file.SliceSettings.LiftDistance = file.OutputSettings.LiftDistance = LiftHeight;
+ file.SliceSettings.LiftUpSpeed = file.OutputSettings.ZLiftFeedRate = LiftSpeed;
+ file.SliceSettings.LiftDownSpeed = file.OutputSettings.ZLiftRetractRate = RetractSpeed;
+ file.SliceSettings.LiftWhenFinished = defaultFormat.SliceSettings.LiftWhenFinished;
+
+ file.OutputSettings.BlankingLayerTime = (uint)(HeaderSettings.LayerOffTime * 1000);
+ //file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.OutlineWidthInset = 0;
+ //file.OutputSettings.OutlineWidthOutset = 0;
+ file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.TiltValue = 0;
+ //file.OutputSettings.UseMainliftGCodeTab = false;
+ //file.OutputSettings.AntiAliasing = 0;
+ //file.OutputSettings.AntiAliasingValue = 0;
+ file.OutputSettings.FlipX = HeaderSettings.ProjectorType != 0;
+ file.OutputSettings.FlipY = file.OutputSettings.FlipX;
+ file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel();
+ file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1;
+
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
return false;
}
#endregion
diff --git a/UVtools.Core/PWSFile.cs b/UVtools.Core/FileFormats/PWSFile.cs
index 45eb55b..c4c4fce 100644
--- a/UVtools.Core/PWSFile.cs
+++ b/UVtools.Core/FileFormats/PWSFile.cs
@@ -16,8 +16,9 @@ using BinarySerialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class PWSFile : FileFormat
{
@@ -403,8 +404,9 @@ namespace UVtools.Core
Parent = parent;
LiftHeight = Parent.HeaderSettings.LiftHeight;
LiftSpeed = Parent.HeaderSettings.LiftSpeed;
- LayerExposure = layerIndex < Parent.InitialLayerCount ? Parent.HeaderSettings.BottomExposureSeconds : Parent.HeaderSettings.LayerExposureTime;
- LayerPositionZ = Parent.GetHeightFromLayer(layerIndex);
+
+ LayerPositionZ = parent[layerIndex].PositionZ;
+ LayerExposure = parent[layerIndex].ExposureTime;
}
public Mat Decode(bool consumeData = true)
@@ -754,7 +756,8 @@ namespace UVtools.Core
{
//typeof(ChituboxZipFile)
//typeof(PHZFile),
- //typeof(ZCodexFile),
+ typeof(PWSFile),
+ typeof(CWSFile),
};
public override PrintParameterModifier[] PrintParameterModifiers { get; } =
@@ -1007,7 +1010,11 @@ namespace UVtools.Core
using (var image = LayersDefinition[(uint) layerIndex].Decode())
{
- this[layerIndex] = new Layer((uint) layerIndex, image);
+ this[layerIndex] = new Layer((uint) layerIndex, image)
+ {
+ PositionZ = LayersDefinition[(uint)layerIndex].LayerPositionZ,
+ ExposureTime = LayersDefinition[(uint)layerIndex].LayerExposure
+ };
}
lock (progress.Mutex)
@@ -1035,9 +1042,9 @@ namespace UVtools.Core
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
// Bottom : others
- LayersDefinition[layerIndex].LayerExposure = layerIndex < HeaderSettings.BottomLayersCount
- ? HeaderSettings.BottomExposureSeconds
- : HeaderSettings.LayerExposureTime;
+
+ this[layerIndex].ExposureTime =
+ LayersDefinition[layerIndex].LayerExposure = GetInitialLayerValueOrNormal(layerIndex, HeaderSettings.BottomExposureSeconds, HeaderSettings.LayerExposureTime);
}
}
@@ -1129,6 +1136,39 @@ namespace UVtools.Core
public override bool Convert(Type to, string fileFullPath, OperationProgress progress = null)
{
+ if (to == typeof(PWSFile))
+ {
+ if (Path.GetExtension(FileFullPath).Equals(Path.GetExtension(fileFullPath)))
+ {
+ return false;
+ }
+ PWSFile file = new PWSFile
+ {
+ LayerManager = LayerManager,
+ HeaderSettings =
+ {
+ ResolutionX = ResolutionX,
+ ResolutionY = ResolutionY,
+ LayerHeight = LayerHeight,
+ LayerExposureTime = LayerExposureTime,
+ LiftHeight = LiftHeight,
+ LiftSpeed = LiftSpeed / 60,
+ RetractSpeed = RetractSpeed / 60,
+ LayerOffTime = HeaderSettings.LayerOffTime,
+ BottomLayersCount = InitialLayerCount,
+ BottomExposureSeconds = InitialExposureTime,
+ Price = MaterialCost,
+ Volume = UsedMaterial,
+ Weight = HeaderSettings.Weight,
+ AntiAliasing = ValidateAntiAliasingLevel()
+ }
+ };
+
+ file.SetThumbnails(Thumbnails);
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
/*if (to == typeof(PHZFile))
{
PHZFile file = new PHZFile
@@ -1262,6 +1302,46 @@ namespace UVtools.Core
return true;
}
*/
+
+ if (to == typeof(CWSFile))
+ {
+ CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile));
+ CWSFile file = new CWSFile { LayerManager = LayerManager };
+
+ //file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = defaultFormat.OutputSettings.
+ //file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float)Math.Round(ResolutionY / HeaderSettings.BedSizeY, 3);
+ file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX;
+ file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY;
+ file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight;
+ file.SliceSettings.LayersNum = file.OutputSettings.LayersNum = LayerCount;
+ file.SliceSettings.HeadLayersNum = file.OutputSettings.NumberBottomLayers = InitialLayerCount;
+ file.SliceSettings.LayersExpoMs = file.OutputSettings.LayerTime = (uint)LayerExposureTime * 1000;
+ file.SliceSettings.HeadLayersExpoMs = file.OutputSettings.BottomLayersTime = (uint)InitialExposureTime * 1000;
+ file.SliceSettings.WaitBeforeExpoMs = (uint)(HeaderSettings.LayerOffTime * 1000);
+ file.SliceSettings.LiftDistance = file.OutputSettings.LiftDistance = LiftHeight;
+ file.SliceSettings.LiftUpSpeed = file.OutputSettings.ZLiftFeedRate = LiftSpeed;
+ file.SliceSettings.LiftDownSpeed = file.OutputSettings.ZLiftRetractRate = RetractSpeed;
+ file.SliceSettings.LiftWhenFinished = defaultFormat.SliceSettings.LiftWhenFinished;
+
+ file.OutputSettings.BlankingLayerTime = (uint)(HeaderSettings.LayerOffTime * 1000);
+ //file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.OutlineWidthInset = 0;
+ //file.OutputSettings.OutlineWidthOutset = 0;
+ file.OutputSettings.RenderOutlines = false;
+ //file.OutputSettings.TiltValue = 0;
+ //file.OutputSettings.UseMainliftGCodeTab = false;
+ //file.OutputSettings.AntiAliasing = 0;
+ //file.OutputSettings.AntiAliasingValue = 0;
+ //file.OutputSettings.FlipX = HeaderSettings. != 0;
+ //file.OutputSettings.FlipY = file.OutputSettings.FlipX;
+ file.OutputSettings.AntiAliasingValue = ValidateAntiAliasingLevel();
+ file.OutputSettings.AntiAliasing = file.OutputSettings.AntiAliasingValue > 1;
+
+ file.Encode(fileFullPath, progress);
+
+ return true;
+ }
+
return false;
}
#endregion
diff --git a/UVtools.Core/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index e92f193..3f88b2c 100644
--- a/UVtools.Core/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -13,12 +13,12 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
-using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class SL1File : FileFormat
{
@@ -476,7 +476,11 @@ namespace UVtools.Core
// - .png - 5 numbers
string layerStr = entity.Name.Substring(entity.Name.Length - 4 - 5, 5);
uint iLayer = uint.Parse(layerStr);
- LayerManager[iLayer] = new Layer(iLayer, entity.Open(), entity.Name);
+ LayerManager[iLayer] = new Layer(iLayer, entity.Open(), entity.Name)
+ {
+ PositionZ = GetHeightFromLayer(iLayer),
+ ExposureTime = GetInitialLayerValueOrNormal(iLayer, InitialExposureTime, LayerExposureTime)
+ };
progress.ProcessedItems++;
}
}
@@ -501,22 +505,37 @@ namespace UVtools.Core
public override bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, string value)
{
+ void UpdateLayers()
+ {
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ this[layerIndex].ExposureTime = GetInitialLayerValueOrNormal(layerIndex, InitialExposureTime, LayerExposureTime);
+ }
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.InitialLayerCount))
{
PrintSettings.FadedLayers =
OutputConfigSettings.NumFade = value.Convert<byte>();
+ UpdateLayers();
return true;
}
if (ReferenceEquals(modifier, PrintParameterModifier.InitialExposureSeconds))
{
MaterialSettings.InitialExposureTime =
OutputConfigSettings.ExpTimeFirst = value.Convert<float>();
+
+ UpdateLayers();
+
return true;
}
if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds))
{
MaterialSettings.ExposureTime =
OutputConfigSettings.ExpTime = value.Convert<float>();
+
+ UpdateLayers();
+
return true;
}
@@ -890,13 +909,10 @@ namespace UVtools.Core
if (to == typeof(CWSFile))
{
CWSFile defaultFormat = (CWSFile)FindByType(typeof(CWSFile));
- CWSFile file = new CWSFile
- {
- LayerManager = LayerManager
- };
+ CWSFile file = new CWSFile {LayerManager = LayerManager};
- file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = (float) Math.Round(LookupCustomValue<float>("Xppm", file.SliceSettings.Xppm), 3);
- file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float) Math.Round(LookupCustomValue<float>("Yppm", file.SliceSettings.Xppm), 3);
+ file.SliceSettings.Xppm = file.OutputSettings.PixPermmX = (float) Math.Round(LookupCustomValue<float>("Xppm", defaultFormat.SliceSettings.Xppm), 3);
+ file.SliceSettings.Yppm = file.OutputSettings.PixPermmY = (float) Math.Round(LookupCustomValue<float>("Yppm", defaultFormat.SliceSettings.Xppm), 3);
file.SliceSettings.Xres = file.OutputSettings.XResolution = (ushort)ResolutionX;
file.SliceSettings.Yres = file.OutputSettings.YResolution = (ushort)ResolutionY;
file.SliceSettings.Thickness = file.OutputSettings.LayerThickness = LayerHeight;
diff --git a/UVtools.Core/ZCodexFile.cs b/UVtools.Core/FileFormats/ZCodexFile.cs
index cf7803e..c5a28bd 100644
--- a/UVtools.Core/ZCodexFile.cs
+++ b/UVtools.Core/FileFormats/ZCodexFile.cs
@@ -17,8 +17,9 @@ using Emgu.CV.CvEnum;
using Emgu.CV.Util;
using Newtonsoft.Json;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
-namespace UVtools.Core
+namespace UVtools.Core.FileFormats
{
public class ZCodexFile : FileFormat
{
@@ -175,9 +176,9 @@ namespace UVtools.Core
public override ushort InitialLayerCount => ResinMetadataSettings.BottomLayersNumber;
- public override float InitialExposureTime => UserSettings.BottomLayerExposureTime / 1000;
+ public override float InitialExposureTime => UserSettings.BottomLayerExposureTime / 1000f;
- public override float LayerExposureTime => UserSettings.LayerExposureTime / 1000;
+ public override float LayerExposureTime => UserSettings.LayerExposureTime / 1000f;
public override float LiftHeight => UserSettings.ZLiftDistance;
public override float LiftSpeed => UserSettings.ZLiftFeedRate;
@@ -227,13 +228,34 @@ namespace UVtools.Core
GCode = new StringBuilder(GCodeStart);
+ float lastZPosition = 0;
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.Token.ThrowIfCancellationRequested();
+ Layer layer = this[layerIndex];
GCode.AppendLine($"{GCodeKeywordSlice} {layerIndex}");
- GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}");
- GCode.AppendLine($"G1 Z-{LiftHeight - LayerHeight} F{RetractSpeed}");
+
+ if (lastZPosition != layer.PositionZ)
+ {
+ if (LiftHeight > 0)
+ {
+ GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}");
+ GCode.AppendLine($"G1 Z-{LiftHeight - layer.PositionZ + lastZPosition} F{RetractSpeed}");
+ }
+ else
+ {
+ GCode.AppendLine($"G1 Z{layer.PositionZ- lastZPosition} F{LiftSpeed}");
+ }
+ }
+ /*else
+ {
+ //GCode.AppendLine($";G1 Z{LiftHeight} F{LiftSpeed}; Already here");
+ //GCode.AppendLine($";G1 Z-{LiftHeight - layer.PositionZ + lastZPosition} F{RetractSpeed}; Already here");
+ }*/
+
+ //GCode.AppendLine($"G1 Z{LiftHeight} F{LiftSpeed}");
+ //GCode.AppendLine($"G1 Z-{LiftHeight - LayerHeight} F{RetractSpeed}");
GCode.AppendLine(GCodeKeywordDelayBlank);
GCode.AppendLine("M106 S255");
GCode.AppendLine(GCodeKeywordDelayModel);
@@ -249,6 +271,8 @@ namespace UVtools.Core
stream.Close();
}
+ lastZPosition = layer.PositionZ;
+
progress++;
}
@@ -308,6 +332,7 @@ namespace UVtools.Core
int layerIndex = 0;
int layerFileIndex = 0;
string layerimagePath = null;
+ float currentHeight = 0;
while (!ReferenceEquals(line = tr.ReadLine(), null))
{
GCode.AppendLine(line);
@@ -326,13 +351,59 @@ namespace UVtools.Core
continue;
}
+ /*
+ *
+<Slice> 0
+G1 Z5.0 F100.0
+G1 Z-4.9 F100.0
+<Delay_blank>
+M106 S255
+<Delay_support_full>
+M106 S0
+ */
+
+ var gcode = GCode.ToString();
+
if (line.StartsWith(GCodeKeywordDelaySupportFull) || line.StartsWith(GCodeKeywordDelayModel))
{
+ var startStr = $"{GCodeKeywordSlice} {layerIndex}";
+ var stripGcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length).Trim(' ', '\n', '\r', '\t');
+
+ var currPos = Regex.Match(stripGcode, "G1 Z([+-]?([0-9]*[.])?[0-9]+)", RegexOptions.IgnoreCase);
+ //var exposureTime = Regex.Match(stripGcode, ";<Delay> (\\d+)", RegexOptions.IgnoreCase);
+ /*var pwm = Regex.Match(stripGcode, "M106 S(\\d+)", RegexOptions.IgnoreCase);
+ if (layerIndex < InitialLayerCount)
+ {
+ OutputSettings.BottomLayerLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }
+ else
+ {
+ OutputSettings.LayerLightPWM = byte.Parse(pwm.Groups[1].Value);
+ }*/
+ if (currPos.Success)
+ {
+ var nextMatch = currPos.NextMatch();
+ if (nextMatch.Success)
+ {
+ currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value) + float.Parse(currPos.NextMatch().Groups[1].Value), 2);
+ }
+ else
+ {
+ currentHeight = (float)Math.Round(currentHeight + float.Parse(currPos.Groups[1].Value), 2);
+ }
+
+ }
+
LayersSettings[layerIndex].LayerFileIndex = layerFileIndex;
LayersSettings[layerIndex].LayerEntry = inputFile.GetEntry(layerimagePath);
- this[layerIndex] = new Layer((uint) layerIndex, LayersSettings[layerIndex].LayerEntry.Open(), LayersSettings[layerIndex].LayerEntry.Name);
+ this[layerIndex] = new Layer((uint) layerIndex, LayersSettings[layerIndex].LayerEntry.Open(), LayersSettings[layerIndex].LayerEntry.Name)
+ {
+ PositionZ = currentHeight,
+ ExposureTime = GetInitialLayerValueOrNormal((uint) layerIndex, InitialExposureTime, LayerExposureTime)
+ };
layerIndex++;
- continue;
+
+ progress++;
}
}
@@ -356,22 +427,37 @@ namespace UVtools.Core
public override bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, string value)
{
+ void UpdateLayers()
+ {
+ for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
+ {
+ this[layerIndex].ExposureTime = GetInitialLayerValueOrNormal(layerIndex, InitialExposureTime, LayerExposureTime);
+ }
+ }
+
if (ReferenceEquals(modifier, PrintParameterModifier.InitialLayerCount))
{
UserSettings.BottomLayersCount =
ResinMetadataSettings.BottomLayersNumber = value.Convert<ushort>();
+ UpdateLayers();
return true;
}
if (ReferenceEquals(modifier, PrintParameterModifier.InitialExposureSeconds))
{
ResinMetadataSettings.BottomLayersTime =
UserSettings.BottomLayerExposureTime = value.Convert<uint>()*1000;
+
+ UpdateLayers();
+
return true;
}
if (ReferenceEquals(modifier, PrintParameterModifier.ExposureSeconds))
{
ResinMetadataSettings.LayerTime =
UserSettings.LayerExposureTime = value.Convert<uint>()*1000;
+
+ UpdateLayers();
+
return true;
}
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
new file mode 100644
index 0000000..1842d73
--- /dev/null
+++ b/UVtools.Core/Layer/Layer.cs
@@ -0,0 +1,692 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
+using Emgu.CV.Util;
+using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
+
+namespace UVtools.Core
+{
+ /// <summary>
+ /// Represent a Layer
+ /// </summary>
+ public class Layer : IEquatable<Layer>, IEquatable<uint>
+ {
+ #region Properties
+
+ /// <summary>
+ /// Gets the parent layer manager
+ /// </summary>
+ public LayerManager ParentLayerManager { get; set; }
+
+ /// <summary>
+ /// Gets the number of non zero pixels on this layer image
+ /// </summary>
+ public uint NonZeroPixelCount { get; private protected set; }
+
+ /// <summary>
+ /// Gets the bounding rectangle for the image area
+ /// </summary>
+ public Rectangle BoundingRectangle { get; private protected set; } = Rectangle.Empty;
+
+ /// <summary>
+ /// Gets the layer index
+ /// </summary>
+ public uint Index { get; }
+
+ /// <summary>
+ /// Gets or sets the exposure time in seconds
+ /// </summary>
+ public float ExposureTime { get; set; }
+
+ /// <summary>
+ /// Gets or sets the layer position on Z in mm
+ /// </summary>
+ public float PositionZ { get; set; }
+
+ private byte[] _compressedBytes;
+ /// <summary>
+ /// Gets or sets layer image compressed data
+ /// </summary>
+ public byte[] CompressedBytes
+ {
+ get => LayerManager.DecompressLayer(_compressedBytes);
+ set
+ {
+ _compressedBytes = LayerManager.CompressLayer(value);
+ IsModified = true;
+ if (!ReferenceEquals(ParentLayerManager, null))
+ ParentLayerManager.BoundingRectangle = Rectangle.Empty;
+ }
+ }
+
+ /// <summary>
+ /// Gets the original filename, null if no filename attached with layer
+ /// </summary>
+ public string Filename { get; set; }
+
+ /// <summary>
+ /// Gets if layer has been modified
+ /// </summary>
+ public bool IsModified { get; set; }
+
+ /// <summary>
+ /// Gets or sets a new image instance
+ /// </summary>
+ public Mat LayerMat
+ {
+ get
+ {
+ Mat mat = new Mat();
+ CvInvoke.Imdecode(CompressedBytes, ImreadModes.Grayscale, mat);
+ return mat;
+ }
+ set
+ {
+ using (var vector = new VectorOfByte())
+ {
+ CvInvoke.Imencode(".png", value, vector);
+ CompressedBytes = vector.ToArray();
+
+ GetBoundingRectangle(value, true);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets a new Brg image instance
+ /// </summary>
+ public Mat BrgMat
+ {
+ get
+ {
+ Mat mat = LayerMat;
+ CvInvoke.CvtColor(mat, mat, ColorConversion.Gray2Bgr);
+ return mat;
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+ public Layer(uint index, byte[] compressedBytes, string filename = null, LayerManager pararentLayerManager = null)
+ {
+ ParentLayerManager = pararentLayerManager;
+ Index = index;
+ Filename = filename ?? $"Layer{index}.png";
+ CompressedBytes = compressedBytes;
+ IsModified = false;
+ /*if (compressedBytes.Length > 0)
+ {
+ GetBoundingRectangle();
+ }*/
+ }
+
+ public Layer(uint index, Mat layerMat, string filename = null, LayerManager pararentLayerManager = null) : this(index, new byte[0], filename, pararentLayerManager)
+ {
+ LayerMat = layerMat;
+ IsModified = false;
+ }
+
+
+ public Layer(uint index, Stream stream, string filename = null, LayerManager pararentLayerManager = null) : this(index, stream.ToArray(), filename, pararentLayerManager)
+ { }
+ #endregion
+
+ #region Equatables
+
+ public static bool operator ==(Layer obj1, Layer obj2)
+ {
+ return obj1.Equals(obj2);
+ }
+
+ public static bool operator !=(Layer obj1, Layer obj2)
+ {
+ return !obj1.Equals(obj2);
+ }
+
+ public static bool operator >(Layer obj1, Layer obj2)
+ {
+ return obj1.Index > obj2.Index;
+ }
+
+ public static bool operator <(Layer obj1, Layer obj2)
+ {
+ return obj1.Index < obj2.Index;
+ }
+
+ public static bool operator >=(Layer obj1, Layer obj2)
+ {
+ return obj1.Index >= obj2.Index;
+ }
+
+ public static bool operator <=(Layer obj1, Layer obj2)
+ {
+ return obj1.Index <= obj2.Index;
+ }
+
+ public bool Equals(uint other)
+ {
+ return Index == other;
+ }
+
+ public bool Equals(Layer other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(_compressedBytes, other._compressedBytes);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Layer)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return (_compressedBytes != null ? _compressedBytes.GetHashCode() : 0);
+ }
+
+ private sealed class IndexRelationalComparer : IComparer<Layer>
+ {
+ public int Compare(Layer x, Layer y)
+ {
+ if (ReferenceEquals(x, y)) return 0;
+ if (ReferenceEquals(null, y)) return 1;
+ if (ReferenceEquals(null, x)) return -1;
+ return x.Index.CompareTo(y.Index);
+ }
+ }
+
+ public static IComparer<Layer> IndexComparer { get; } = new IndexRelationalComparer();
+ #endregion
+
+ #region Formaters
+ public override string ToString()
+ {
+ return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(IsModified)}: {IsModified}";
+ }
+ #endregion
+
+ #region Methods
+
+ public Rectangle GetBoundingRectangle(Mat mat = null, bool reCalculate = false)
+ {
+ if (NonZeroPixelCount > 0 && !reCalculate)
+ {
+ return BoundingRectangle;
+ }
+ bool needDispose = false;
+ if (ReferenceEquals(mat, null))
+ {
+ mat = LayerMat;
+ needDispose = true;
+ }
+
+ using (var nonZeroMat = new Mat())
+ {
+ CvInvoke.FindNonZero(mat, nonZeroMat);
+ NonZeroPixelCount = (uint)nonZeroMat.Rows / 2;
+ BoundingRectangle = CvInvoke.BoundingRectangle(nonZeroMat);
+ }
+
+
+ if (needDispose) mat.Dispose();
+
+ return BoundingRectangle;
+ }
+
+ public Layer PreviousLayer()
+ {
+ if (ReferenceEquals(ParentLayerManager, null) || Index == 0)
+ return null;
+
+ return ParentLayerManager[Index - 1];
+ }
+
+ public Layer NextLayer()
+ {
+ if (ReferenceEquals(ParentLayerManager, null) || Index >= ParentLayerManager.Count - 1)
+ return null;
+
+ return ParentLayerManager[Index + 1];
+ }
+
+ /// <summary>
+ /// Gets all islands start pixel location for this layer
+ /// https://www.geeksforgeeks.org/find-number-of-islands/
+ /// </summary>
+ /// <returns><see cref="List{T}"/> holding all islands coordinates</returns>
+ public List<LayerIssue> GetIssues(uint requiredPixelsToSupportIsland = 5)
+ {
+ if (requiredPixelsToSupportIsland == 0)
+ requiredPixelsToSupportIsland = 1;
+
+ // These arrays are used to
+ // get row and column numbers
+ // of 8 neighbors of a given cell
+ List<LayerIssue> result = new List<LayerIssue>();
+ List<Point> pixels = new List<Point>();
+
+
+
+ var mat = LayerMat;
+ var bytes = mat.GetPixelSpan<byte>();
+
+
+
+ var previousLayerImage = PreviousLayer()?.LayerMat;
+ var previousBytes = previousLayerImage?.GetBytes();
+
+
+ /*var nextLayerImage = NextLayer()?.Image;
+ byte[] nextBytes = null;
+ if (!ReferenceEquals(nextLayerImage, null))
+ {
+ if (nextLayerImage.TryGetSinglePixelSpan(out var nextPixelSpan))
+ {
+ nextBytes = MemoryMarshal.AsBytes(nextPixelSpan).ToArray();
+ }
+ }*/
+
+ // Make a bool array to
+ // mark visited cells.
+ // Initially all cells
+ // are unvisited
+ bool[,] visited = new bool[mat.Width, mat.Height];
+
+ // Initialize count as 0 and
+ // traverse through the all
+ // cells of given matrix
+ //uint count = 0;
+
+ // Island checker
+ sbyte[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 };
+ sbyte[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 };
+ const uint minPixel = 10;
+ const uint minPixelForSupportIsland = 200;
+ int pixelIndex;
+ uint islandSupportingPixels;
+ if (Index > 0)
+ {
+ for (int y = 0; y < mat.Height; y++)
+ {
+ for (int x = 0; x < mat.Width; x++)
+ {
+ pixelIndex = y * mat.Width + x;
+
+ /*if (bytes[pixelIndex] == 0 && previousBytes?[pixelIndex] == byte.MaxValue &&
+ nextBytes?[pixelIndex] == byte.MaxValue)
+ {
+ result.Add(new LayerIssue(this, LayerIssue.IssueType.HoleSandwich, new []{new Point(x, y)}));
+ }*/
+
+ if (bytes[pixelIndex] > minPixel && !visited[x, y])
+ {
+ // If a cell with value 1 is not
+ // visited yet, then new island
+ // found, Visit all cells in this
+ // island and increment island count
+ pixels.Clear();
+ pixels.Add(new Point(x, y));
+ islandSupportingPixels = previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0;
+
+ int minX = x;
+ int maxX = x;
+ int minY = y;
+ int maxY = y;
+
+ int x2;
+ int y2;
+
+
+ Queue<Point> queue = new Queue<Point>();
+ queue.Enqueue(new Point(x, y));
+ // Mark this cell as visited
+ visited[x, y] = true;
+
+ while (queue.Count > 0)
+ {
+ var point = queue.Dequeue();
+ y2 = point.Y;
+ x2 = point.X;
+ for (byte k = 0; k < 8; k++)
+ {
+ //if (isSafe(y2 + rowNbr[k], x2 + colNbr[k]))
+ var tempy2 = y2 + rowNbr[k];
+ var tempx2 = x2 + colNbr[k];
+ pixelIndex = tempy2 * mat.Width + tempx2;
+ if (tempy2 >= 0 &&
+ tempy2 < mat.Height &&
+ tempx2 >= 0 && tempx2 < mat.Width &&
+ bytes[pixelIndex] >= minPixel &&
+ !visited[tempx2, tempy2])
+ {
+ visited[tempx2, tempy2] = true;
+ point = new Point(tempx2, tempy2);
+ pixels.Add(point);
+ queue.Enqueue(point);
+
+ minX = Math.Min(minX, tempx2);
+ maxX = Math.Max(maxX, tempx2);
+ minY = Math.Min(minY, tempy2);
+ maxY = Math.Max(maxY, tempy2);
+
+ islandSupportingPixels += previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0;
+ }
+ }
+ }
+ //count++;
+
+ if (islandSupportingPixels >= requiredPixelsToSupportIsland)
+ continue; // Not a island, bounding is strong
+ if (islandSupportingPixels > 0 && pixels.Count < requiredPixelsToSupportIsland &&
+ islandSupportingPixels >= Math.Max(1, pixels.Count / 2)) continue; // Not a island
+ result.Add(new LayerIssue(this, LayerIssue.IssueType.Island, pixels.ToArray(), new Rectangle(minX, minY, maxX - minX, maxY - minY)));
+ }
+ }
+ }
+ }
+
+ pixels.Clear();
+
+ // TouchingBounds Checker
+ for (int x = 0; x < mat.Width; x++) // Check Top and Bottom bounds
+ {
+ if (bytes[x] >= 200) // Top
+ {
+ pixels.Add(new Point(x, 0));
+ }
+
+ if (bytes[mat.Width * mat.Height - mat.Width + x] >= 200) // Bottom
+ {
+ pixels.Add(new Point(x, mat.Height - 1));
+ }
+ }
+
+ for (int y = 0; y < mat.Height; y++) // Check Left and Right bounds
+ {
+ if (bytes[y * mat.Width] >= 200) // Left
+ {
+ pixels.Add(new Point(0, y));
+ }
+
+ if (bytes[y * mat.Width + mat.Width - 1] >= 200) // Right
+ {
+ pixels.Add(new Point(mat.Width - 1, y));
+ }
+ }
+
+ if (pixels.Count > 0)
+ {
+ result.Add(new LayerIssue(this, LayerIssue.IssueType.TouchingBound, pixels.ToArray()));
+ }
+
+ pixels.Clear();
+
+ return result;
+ }
+
+ public void MutateMove(OperationMove move)
+ {
+ using (var layer = LayerMat)
+ {
+ if (move.ImageWidth == 0) move.ImageWidth = (uint)layer.Width;
+ if (move.ImageHeight == 0) move.ImageHeight = (uint)layer.Height;
+
+ /*layer.Transform(1.0, 1.0, move.MarginLeft - move.MarginRight, move.MarginTop-move.MarginBottom);
+ LayerMat = layer;*/
+ using (var layerRoi = new Mat(layer, move.SrcRoi))
+ {
+ using (var dstLayer = layer.CloneBlank())
+ {
+ using (var dstRoi = new Mat(dstLayer, move.DstRoi))
+ {
+ layerRoi.CopyTo(dstRoi);
+ LayerMat = dstLayer;
+ }
+ }
+ }
+ }
+ }
+
+
+ public void MutateResize(double xScale, double yScale)
+ {
+ using (var mat = LayerMat)
+ {
+ mat.TransformFromCenter(xScale, yScale);
+ LayerMat = mat;
+ }
+ }
+
+ public void MutateFlip(FlipType flipType, bool makeCopy = true)
+ {
+ using (var mat = LayerMat)
+ {
+ if (makeCopy)
+ {
+ using (Mat dst = new Mat())
+ {
+ CvInvoke.Flip(mat, dst, flipType);
+ 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;
+
+ }
+ }
+ else
+ {
+ CvInvoke.Flip(mat, mat, flipType);
+ }
+
+ LayerMat = mat;
+ }
+ }
+
+ public void MutateRotate(double angle = 90.0, Inter interpolation = Inter.Linear)
+ {
+ using (var mat = LayerMat)
+ {
+ var halfWidth = mat.Width / 2.0f;
+ var halfHeight = mat.Height / 2.0f;
+ using (var translateTransform = new Matrix<double>(2, 3))
+ {
+ CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), angle, 1.0, translateTransform);
+ /*var rect = new RotatedRect(PointF.Empty, mat.Size, (float) angle).MinAreaRect();
+ translateTransform[0, 2] += rect.Width / 2.0 - mat.Cols / 2.0;
+ translateTransform[0, 2] += rect.Height / 2.0 - mat.Rows / 2.0;*/
+
+ /* var abs_cos = Math.Abs(translateTransform[0, 0]);
+ var abs_sin = Math.Abs(translateTransform[0, 1]);
+
+ var bound_w = mat.Height * abs_sin + mat.Width * abs_cos;
+ var bound_h = mat.Height * abs_cos + mat.Width * abs_sin;
+
+ translateTransform[0, 2] += bound_w / 2 - halfWidth;
+ translateTransform[1, 2] += bound_h / 2 - halfHeight;*/
+
+
+ CvInvoke.WarpAffine(mat, mat, translateTransform, mat.Size, interpolation);
+ }
+
+ LayerMat = mat;
+ }
+ }
+
+ public void MutateSolidify()
+ {
+ using (Mat mat = LayerMat)
+ {
+ using (Mat filteredMat = new Mat())
+ {
+ CvInvoke.Threshold(mat, filteredMat, 254, 255, ThresholdType.Binary); // Clean AA
+
+ using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
+ {
+ using (Mat hierarchy = new Mat())
+ {
+ CvInvoke.FindContours(filteredMat, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
+ var arr = hierarchy.GetData();
+ 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);
+ }
+ }
+ }
+ }
+
+ LayerMat = mat;
+ }
+ }
+
+ public void MutateErode(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
+ {
+ if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (ReferenceEquals(kernel, null))
+ {
+ kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+ }
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.Erode(dst, dst, kernel, anchor, iterations, borderType, borderValue);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateDilate(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
+ {
+ if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (ReferenceEquals(kernel, null))
+ {
+ kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+ }
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.Dilate(dst, dst, kernel, anchor, iterations, borderType, borderValue);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateOpen(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
+ {
+ if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (ReferenceEquals(kernel, null))
+ {
+ kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+ }
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.MorphologyEx(dst, dst, MorphOp.Open, kernel, anchor, iterations, borderType, borderValue);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateClose(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
+ {
+ if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (ReferenceEquals(kernel, null))
+ {
+ kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
+ }
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.MorphologyEx(dst, dst, MorphOp.Close, kernel, anchor, iterations, borderType, borderValue);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateGradient(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
+ {
+ if (anchor.IsEmpty) anchor = new Point(-1, -1);
+ if (ReferenceEquals(kernel, null))
+ {
+ kernel = CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), anchor);
+ }
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.MorphologyEx(dst, dst, MorphOp.Gradient, kernel, anchor, iterations, borderType, borderValue);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutatePyrDownUp(BorderType borderType = BorderType.Reflect101)
+ {
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.PyrDown(dst, dst, borderType);
+ CvInvoke.PyrUp(dst, dst, borderType);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateMedianBlur(int aperture = 1)
+ {
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.MedianBlur(dst, dst, aperture);
+ LayerMat = dst;
+ }
+ }
+
+ public void MutateGaussianBlur(Size size = default, int sigmaX = 0, int sigmaY = 0, BorderType borderType = BorderType.Reflect101)
+ {
+ if (size.IsEmpty) size = new Size(5, 5);
+
+ using (Mat dst = LayerMat)
+ {
+ CvInvoke.GaussianBlur(dst, dst, size, sigmaX, sigmaY, borderType);
+ LayerMat = dst;
+ }
+ }
+
+ public void ToolPattern(OperationPattern settings)
+ {
+ using (var layer = LayerMat)
+ {
+ using (var layerRoi = new Mat(layer, settings.SrcRoi))
+ {
+ using (var dstLayer = layer.CloneBlank())
+ {
+ for (ushort col = 0; col < settings.Cols; col++)
+ {
+ for (ushort row = 0; row < settings.Rows; row++)
+ {
+ using (var dstRoi = new Mat(dstLayer, settings.GetRoi(col, row)))
+ {
+ layerRoi.CopyTo(dstRoi);
+ }
+ }
+ }
+
+ LayerMat = dstLayer;
+ }
+ }
+ }
+ }
+
+
+
+ public Layer Clone()
+ {
+ return new Layer(Index, CompressedBytes, Filename, ParentLayerManager);
+ }
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Layer/LayerIssue.cs b/UVtools.Core/Layer/LayerIssue.cs
new file mode 100644
index 0000000..8618d89
--- /dev/null
+++ b/UVtools.Core/Layer/LayerIssue.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace UVtools.Core
+{
+ #region LayerIssue Class
+
+ public class IslandDetectionConfiguration
+ {
+ /// <summary>
+ /// Gets if the detection is enabled
+ /// </summary>
+ public bool Enabled { get; set; } = true;
+
+ /// <summary>
+ /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
+ /// Set to 0 to disable this operation
+ /// </summary>
+ public byte BinaryThreshold { get; set; } = 1;
+
+ /// <summary>
+ /// Gets the required area size (x*y) to consider process a island (0-255)
+ /// </summary>
+ public byte RequiredAreaToProcessCheck { get; set; } = 1;
+
+ /// <summary>
+ /// Gets the required brightness for check a pixel under a island (0-255)
+ /// </summary>
+ public byte RequiredPixelBrightnessToProcessCheck { get; set; } = 10;
+
+ /// <summary>
+ /// Gets the required number of pixels to support a island and discard it as a issue (0-255)
+ /// </summary>
+ public byte RequiredPixelsToSupport { get; set; } = 10;
+
+ /// <summary>
+ /// Gets the required brightness of supporting pixels to count as a valid support (0-255)
+ /// </summary>
+ public byte RequiredPixelBrightnessToSupport { get; set; } = 150;
+ }
+
+ public class ResinTrapDetectionConfiguration
+ {
+ /// <summary>
+ /// Gets if the detection is enabled
+ /// </summary>
+ public bool Enabled { get; set; } = true;
+
+ /// <summary>
+ /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
+ /// Set to 0 to disable this operation
+ /// </summary>
+ public byte BinaryThreshold { get; set; } = 127;
+
+ /// <summary>
+ /// Gets the required area size (x*y) to consider process a hollow area (0-255)
+ /// </summary>
+ public byte RequiredAreaToProcessCheck { get; set; } = 1;
+
+ /// <summary>
+ /// Gets the number of black pixels required to consider a drain
+ /// </summary>
+ public byte RequiredBlackPixelsToDrain { get; set; } = 10;
+
+ /// <summary>
+ /// Gets the maximum pixel brightness to be a drain pixel (0-150)
+ /// </summary>
+ public byte MaximumPixelBrightnessToDrain { get; set; } = 30;
+ }
+
+
+ public class LayerIssue : IEnumerable<Point>
+ {
+ public enum IssueType : byte
+ {
+ Island,
+ ResinTrap,
+ TouchingBound,
+ //HoleSandwich,
+ }
+
+ /// <summary>
+ /// Gets the parent layer
+ /// </summary>
+ public Layer Layer { get; }
+
+ /// <summary>
+ /// Gets the issue type associated
+ /// </summary>
+ public IssueType Type { get; }
+
+ /// <summary>
+ /// Gets the pixels containing the issue
+ /// </summary>
+ public Point[] Pixels { get; }
+
+ /// <summary>
+ /// Gets the bounding rectangle of the pixel area
+ /// </summary>
+ public Rectangle BoundingRectangle { get; }
+
+ /// <summary>
+ /// Gets the X coordinate for the first point, -1 if doesn't exists
+ /// </summary>
+ public int X => HaveValidPoint ? Pixels[0].X : -1;
+
+ /// <summary>
+ /// Gets the Y coordinate for the first point, -1 if doesn't exists
+ /// </summary>
+ public int Y => HaveValidPoint ? Pixels[0].Y : -1;
+
+ /// <summary>
+ /// Gets the XY point for first point
+ /// </summary>
+ public Point Point => HaveValidPoint ? Pixels[0] : new Point(-1, -1);
+
+ /// <summary>
+ /// Gets the number of pixels on this issue
+ /// </summary>
+ public uint Size
+ {
+ get
+ {
+ if (Type == IssueType.ResinTrap && !BoundingRectangle.IsEmpty)
+ {
+ return (uint)(BoundingRectangle.Width * BoundingRectangle.Height);
+ }
+
+ if (ReferenceEquals(Pixels, null)) return 0;
+ return (uint)Pixels.Length;
+ }
+ }
+
+ /// <summary>
+ /// Check if this issue have a valid start point to show
+ /// </summary>
+ public bool HaveValidPoint => !ReferenceEquals(Pixels, null) && Pixels.Length > 0;
+
+ public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Rectangle boundingRectangle = new Rectangle())
+ {
+ Layer = layer;
+ Type = type;
+ Pixels = pixels;
+ BoundingRectangle = boundingRectangle;
+ }
+
+ public Point this[uint index] => Pixels[index];
+
+ public Point this[int index] => Pixels[index];
+
+ public IEnumerator<Point> GetEnumerator()
+ {
+ return ((IEnumerable<Point>)Pixels).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public override string ToString()
+ {
+ return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(Size)}: {Size}";
+ }
+ }
+ #endregion
+
+ #region LayerHollowArea
+
+ public class LayerHollowArea : IEnumerable<Point>
+ {
+ public enum AreaType : byte
+ {
+ Unknown = 0,
+ Trap,
+ Drain
+ }
+ /// <summary>
+ /// Gets area pixels
+ /// </summary>
+ public Point[] Contour { get; }
+
+ public Rectangle BoundingRectangle { get; }
+
+ public AreaType Type { get; set; } = AreaType.Unknown;
+
+ public bool Processed { get; set; }
+
+ #region Indexers
+ public Point this[uint index]
+ {
+ get => index < Contour.Length ? Contour[index] : Point.Empty;
+ set => Contour[index] = value;
+ }
+
+ public Point this[int index]
+ {
+ get => index < Contour.Length ? Contour[index] : Point.Empty;
+ set => Contour[index] = value;
+ }
+
+ public Point this[uint x, uint y]
+ {
+ get
+ {
+ for (uint i = 0; i < Contour.Length; i++)
+ {
+ if (Contour[i].X == x && Contour[i].Y == y) return Contour[i];
+ }
+ return Point.Empty;
+ }
+ }
+
+ public Point this[int x, int y] => this[(uint)x, (uint)y];
+
+ public Point this[Point point] => this[point.X, point.Y];
+
+ #endregion
+
+ public IEnumerator<Point> GetEnumerator()
+ {
+ return ((IEnumerable<Point>)Contour).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public LayerHollowArea()
+ {
+ }
+
+ public LayerHollowArea(Point[] contour, Rectangle boundingRectangle, AreaType type = AreaType.Unknown)
+ {
+ Contour = contour;
+ BoundingRectangle = boundingRectangle;
+ Type = type;
+ }
+ }
+ #endregion
+}
diff --git a/UVtools.Core/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index 86abf92..cf21310 100644
--- a/UVtools.Core/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -19,929 +19,10 @@ using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
namespace UVtools.Core
{
-
- #region LayerIssue Class
-
- public class IslandDetectionConfiguration
- {
- /// <summary>
- /// Gets if the detection is enabled
- /// </summary>
- public bool Enabled { get; set; } = true;
-
- /// <summary>
- /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
- /// Set to 0 to disable this operation
- /// </summary>
- public byte BinaryThreshold { get; set; } = 1;
-
- /// <summary>
- /// Gets the required area size (x*y) to consider process a island (0-255)
- /// </summary>
- public byte RequiredAreaToProcessCheck { get; set; } = 1;
-
- /// <summary>
- /// Gets the required brightness for check a pixel under a island (0-255)
- /// </summary>
- public byte RequiredPixelBrightnessToProcessCheck { get; set; } = 10;
-
- /// <summary>
- /// Gets the required number of pixels to support a island and discard it as a issue (0-255)
- /// </summary>
- public byte RequiredPixelsToSupport { get; set; } = 10;
-
- /// <summary>
- /// Gets the required brightness of supporting pixels to count as a valid support (0-255)
- /// </summary>
- public byte RequiredPixelBrightnessToSupport { get; set; } = 150;
- }
-
- public class ResinTrapDetectionConfiguration
- {
- /// <summary>
- /// Gets if the detection is enabled
- /// </summary>
- public bool Enabled { get; set; } = true;
-
- /// <summary>
- /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
- /// Set to 0 to disable this operation
- /// </summary>
- public byte BinaryThreshold { get; set; } = 127;
-
- /// <summary>
- /// Gets the required area size (x*y) to consider process a hollow area (0-255)
- /// </summary>
- public byte RequiredAreaToProcessCheck { get; set; } = 1;
-
- /// <summary>
- /// Gets the number of black pixels required to consider a drain
- /// </summary>
- public byte RequiredBlackPixelsToDrain { get; set; } = 10;
-
- /// <summary>
- /// Gets the maximum pixel brightness to be a drain pixel (0-150)
- /// </summary>
- public byte MaximumPixelBrightnessToDrain { get; set; } = 30;
- }
-
-
- public class LayerIssue : IEnumerable<Point>
- {
- public enum IssueType : byte
- {
- Island,
- ResinTrap,
- TouchingBound,
- //HoleSandwich,
- }
-
- /// <summary>
- /// Gets the parent layer
- /// </summary>
- public Layer Layer { get; }
-
- /// <summary>
- /// Gets the issue type associated
- /// </summary>
- public IssueType Type { get; }
-
- /// <summary>
- /// Gets the pixels containing the issue
- /// </summary>
- public Point[] Pixels { get; }
-
- /// <summary>
- /// Gets the bounding rectangle of the pixel area
- /// </summary>
- public Rectangle BoundingRectangle { get; }
-
- /// <summary>
- /// Gets the X coordinate for the first point, -1 if doesn't exists
- /// </summary>
- public int X => HaveValidPoint ? Pixels[0].X : -1;
-
- /// <summary>
- /// Gets the Y coordinate for the first point, -1 if doesn't exists
- /// </summary>
- public int Y => HaveValidPoint ? Pixels[0].Y : -1;
-
- /// <summary>
- /// Gets the XY point for first point
- /// </summary>
- public Point Point => HaveValidPoint ? Pixels[0] : new Point(-1, -1);
-
- /// <summary>
- /// Gets the number of pixels on this issue
- /// </summary>
- public uint Size {
- get
- {
- if (Type == IssueType.ResinTrap && !BoundingRectangle.IsEmpty)
- {
- return (uint) (BoundingRectangle.Width * BoundingRectangle.Height);
- }
-
- if (ReferenceEquals(Pixels, null)) return 0;
- return (uint) Pixels.Length;
- }
- }
-
- /// <summary>
- /// Check if this issue have a valid start point to show
- /// </summary>
- public bool HaveValidPoint => !ReferenceEquals(Pixels, null) && Pixels.Length > 0;
-
- public LayerIssue(Layer layer, IssueType type, Point[] pixels = null, Rectangle boundingRectangle = new Rectangle())
- {
- Layer = layer;
- Type = type;
- Pixels = pixels;
- BoundingRectangle = boundingRectangle;
- }
-
- public Point this[uint index] => Pixels[index];
-
- public Point this[int index] => Pixels[index];
-
- public IEnumerator<Point> GetEnumerator()
- {
- return ((IEnumerable<Point>)Pixels).GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public override string ToString()
- {
- return $"{nameof(Type)}: {Type}, Layer: {Layer.Index}, {nameof(X)}: {X}, {nameof(Y)}: {Y}, {nameof(Size)}: {Size}";
- }
- }
- #endregion
-
- #region LayerHollowArea
-
- public class LayerHollowArea : IEnumerable<Point>
- {
- public enum AreaType : byte
- {
- Unknown = 0,
- Trap,
- Drain
- }
- /// <summary>
- /// Gets area pixels
- /// </summary>
- public Point[] Contour { get; }
-
- public System.Drawing.Rectangle BoundingRectangle { get; }
-
- public AreaType Type { get; set; } = AreaType.Unknown;
-
- public bool Processed { get; set; }
-
- #region Indexers
- public Point this[uint index]
- {
- get => index < Contour.Length ? Contour[index] : Point.Empty;
- set => Contour[index] = value;
- }
-
- public Point this[int index]
- {
- get => index < Contour.Length ? Contour[index] : Point.Empty;
- set => Contour[index] = value;
- }
-
- public Point this[uint x, uint y]
- {
- get
- {
- for (uint i = 0; i < Contour.Length; i++)
- {
- if (Contour[i].X == x && Contour[i].Y == y) return Contour[i];
- }
- return Point.Empty;
- }
- }
-
- public Point this[int x, int y] => this[(uint) x, (uint)y];
-
- public Point this[Point point] => this[point.X, point.Y];
-
- #endregion
-
- public IEnumerator<Point> GetEnumerator()
- {
- return ((IEnumerable<Point>)Contour).GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public LayerHollowArea()
- {
- }
-
- public LayerHollowArea(Point[] contour, System.Drawing.Rectangle boundingRectangle, AreaType type = AreaType.Unknown)
- {
- Contour = contour;
- BoundingRectangle = boundingRectangle;
- Type = type;
- }
- }
- #endregion
-
- #region Layer Class
- /// <summary>
- /// Represent a Layer
- /// </summary>
- public class Layer : IEquatable<Layer>, IEquatable<uint>
- {
- #region Properties
-
- /// <summary>
- /// Gets the parent layer manager
- /// </summary>
- public LayerManager ParentLayerManager { get; set; }
-
- /// <summary>
- /// Gets the number of non zero pixels on this layer image
- /// </summary>
- public uint NonZeroPixelCount { get; private protected set; }
-
- /// <summary>
- /// Gets the bounding rectangle for the image area
- /// </summary>
- public Rectangle BoundingRectangle { get; private protected set; } = Rectangle.Empty;
-
- /// <summary>
- /// Gets the layer index
- /// </summary>
- public uint Index { get; }
-
- /// <summary>
- /// Gets or sets the exposure time in raw value
- /// </summary>
- public float ExposureTime { get; set; }
-
- /// <summary>
- /// Gets or sets the layer position on Z in raw value
- /// </summary>
- public float PositionZ { get; set; }
-
- private byte[] _compressedBytes;
- /// <summary>
- /// Gets or sets layer image compressed data
- /// </summary>
- public byte[] CompressedBytes
- {
- get => LayerManager.DecompressLayer(_compressedBytes);
- set
- {
- _compressedBytes = LayerManager.CompressLayer(value);
- IsModified = true;
- if(!ReferenceEquals(ParentLayerManager, null))
- ParentLayerManager.BoundingRectangle = Rectangle.Empty;
- }
- }
-
- /// <summary>
- /// Gets the original filename, null if no filename attached with layer
- /// </summary>
- public string Filename { get; set; }
-
- /// <summary>
- /// Gets if layer has been modified
- /// </summary>
- public bool IsModified { get; set; }
-
- /// <summary>
- /// Gets or sets a new image instance
- /// </summary>
- public Mat LayerMat
- {
- get
- {
- Mat mat = new Mat();
- CvInvoke.Imdecode(CompressedBytes, ImreadModes.Grayscale, mat);
- return mat;
- }
- set
- {
- using (var vector = new VectorOfByte())
- {
- CvInvoke.Imencode(".png", value, vector);
- CompressedBytes = vector.ToArray();
-
- GetBoundingRectangle(value, true);
- }
- }
- }
-
- /// <summary>
- /// Gets a new Brg image instance
- /// </summary>
- public Mat BrgMat
- {
- get
- {
- Mat mat = LayerMat;
- CvInvoke.CvtColor(mat, mat, ColorConversion.Gray2Bgr);
- return mat;
- }
- }
-
- #endregion
-
- #region Constructor
- public Layer(uint index, byte[] compressedBytes, string filename = null, LayerManager pararentLayerManager = null)
- {
- ParentLayerManager = pararentLayerManager;
- Index = index;
- Filename = filename ?? $"Layer{index}.png";
- CompressedBytes = compressedBytes;
- IsModified = false;
- /*if (compressedBytes.Length > 0)
- {
- GetBoundingRectangle();
- }*/
- }
-
- public Layer(uint index, Mat layerMat, string filename = null, LayerManager pararentLayerManager = null) : this(index, new byte[0], filename, pararentLayerManager)
- {
- LayerMat = layerMat;
- IsModified = false;
- }
-
-
- public Layer(uint index, Stream stream, string filename = null, LayerManager pararentLayerManager = null) : this(index, stream.ToArray(), filename, pararentLayerManager)
- { }
- #endregion
-
- #region Equatables
-
- public static bool operator ==(Layer obj1, Layer obj2)
- {
- return obj1.Equals(obj2);
- }
-
- public static bool operator !=(Layer obj1, Layer obj2)
- {
- return !obj1.Equals(obj2);
- }
-
- public static bool operator >(Layer obj1, Layer obj2)
- {
- return obj1.Index > obj2.Index;
- }
-
- public static bool operator <(Layer obj1, Layer obj2)
- {
- return obj1.Index < obj2.Index;
- }
-
- public static bool operator >=(Layer obj1, Layer obj2)
- {
- return obj1.Index >= obj2.Index;
- }
-
- public static bool operator <=(Layer obj1, Layer obj2)
- {
- return obj1.Index <= obj2.Index;
- }
-
- public bool Equals(uint other)
- {
- return Index == other;
- }
-
- public bool Equals(Layer other)
- {
- if (ReferenceEquals(null, other)) return false;
- if (ReferenceEquals(this, other)) return true;
- return Equals(_compressedBytes, other._compressedBytes);
- }
-
- public override bool Equals(object obj)
- {
- if (ReferenceEquals(null, obj)) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != this.GetType()) return false;
- return Equals((Layer)obj);
- }
-
- public override int GetHashCode()
- {
- return (_compressedBytes != null ? _compressedBytes.GetHashCode() : 0);
- }
-
- private sealed class IndexRelationalComparer : IComparer<Layer>
- {
- public int Compare(Layer x, Layer y)
- {
- if (ReferenceEquals(x, y)) return 0;
- if (ReferenceEquals(null, y)) return 1;
- if (ReferenceEquals(null, x)) return -1;
- return x.Index.CompareTo(y.Index);
- }
- }
-
- public static IComparer<Layer> IndexComparer { get; } = new IndexRelationalComparer();
- #endregion
-
- #region Formaters
- public override string ToString()
- {
- return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(IsModified)}: {IsModified}";
- }
- #endregion
-
- #region Methods
-
- public Rectangle GetBoundingRectangle(Mat mat = null, bool reCalculate = false)
- {
- if (NonZeroPixelCount > 0 && !reCalculate)
- {
- return BoundingRectangle;
- }
- bool needDispose = false;
- if (ReferenceEquals(mat, null))
- {
- mat = LayerMat;
- needDispose = true;
- }
-
- using (var nonZeroMat = new Mat())
- {
- CvInvoke.FindNonZero(mat, nonZeroMat);
- NonZeroPixelCount = (uint)nonZeroMat.Rows / 2;
- BoundingRectangle = CvInvoke.BoundingRectangle(nonZeroMat);
- }
-
-
- if(needDispose) mat.Dispose();
-
- return BoundingRectangle;
- }
-
- public Layer PreviousLayer()
- {
- if (ReferenceEquals(ParentLayerManager, null) || Index == 0)
- return null;
-
- return ParentLayerManager[Index - 1];
- }
-
- public Layer NextLayer()
- {
- if (ReferenceEquals(ParentLayerManager, null) || Index >= ParentLayerManager.Count - 1)
- return null;
-
- return ParentLayerManager[Index + 1];
- }
-
- /// <summary>
- /// Gets all islands start pixel location for this layer
- /// https://www.geeksforgeeks.org/find-number-of-islands/
- /// </summary>
- /// <returns><see cref="List{T}"/> holding all islands coordinates</returns>
- public List<LayerIssue> GetIssues(uint requiredPixelsToSupportIsland = 5)
- {
- if (requiredPixelsToSupportIsland == 0)
- requiredPixelsToSupportIsland = 1;
-
- // These arrays are used to
- // get row and column numbers
- // of 8 neighbors of a given cell
- List<LayerIssue> result = new List<LayerIssue>();
- List<Point> pixels = new List<Point>();
-
-
-
- var mat = LayerMat;
- var bytes = mat.GetPixelSpan<byte>();
-
-
-
- var previousLayerImage = PreviousLayer()?.LayerMat;
- var previousBytes = previousLayerImage?.GetBytes();
-
-
- /*var nextLayerImage = NextLayer()?.Image;
- byte[] nextBytes = null;
- if (!ReferenceEquals(nextLayerImage, null))
- {
- if (nextLayerImage.TryGetSinglePixelSpan(out var nextPixelSpan))
- {
- nextBytes = MemoryMarshal.AsBytes(nextPixelSpan).ToArray();
- }
- }*/
-
- // Make a bool array to
- // mark visited cells.
- // Initially all cells
- // are unvisited
- bool[,] visited = new bool[mat.Width, mat.Height];
-
- // Initialize count as 0 and
- // traverse through the all
- // cells of given matrix
- //uint count = 0;
-
- // Island checker
- sbyte[] rowNbr = { -1, -1, -1, 0, 0, 1, 1, 1 };
- sbyte[] colNbr = { -1, 0, 1, -1, 1, -1, 0, 1 };
- const uint minPixel = 10;
- const uint minPixelForSupportIsland = 200;
- int pixelIndex;
- uint islandSupportingPixels;
- if (Index > 0)
- {
- for (int y = 0; y < mat.Height; y++)
- {
- for (int x = 0; x < mat.Width; x++)
- {
- pixelIndex = y * mat.Width + x;
-
- /*if (bytes[pixelIndex] == 0 && previousBytes?[pixelIndex] == byte.MaxValue &&
- nextBytes?[pixelIndex] == byte.MaxValue)
- {
- result.Add(new LayerIssue(this, LayerIssue.IssueType.HoleSandwich, new []{new Point(x, y)}));
- }*/
-
- if (bytes[pixelIndex] > minPixel && !visited[x, y])
- {
- // If a cell with value 1 is not
- // visited yet, then new island
- // found, Visit all cells in this
- // island and increment island count
- pixels.Clear();
- pixels.Add(new Point(x, y));
- islandSupportingPixels = previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0;
-
- int minX = x;
- int maxX = x;
- int minY = y;
- int maxY = y;
-
- int x2;
- int y2;
-
-
- Queue<Point> queue = new Queue<Point>();
- queue.Enqueue(new Point(x, y));
- // Mark this cell as visited
- visited[x, y] = true;
-
- while (queue.Count > 0)
- {
- var point = queue.Dequeue();
- y2 = point.Y;
- x2 = point.X;
- for (byte k = 0; k < 8; k++)
- {
- //if (isSafe(y2 + rowNbr[k], x2 + colNbr[k]))
- var tempy2 = y2 + rowNbr[k];
- var tempx2 = x2 + colNbr[k];
- pixelIndex = tempy2 * mat.Width + tempx2;
- if (tempy2 >= 0 &&
- tempy2 < mat.Height &&
- tempx2 >= 0 && tempx2 < mat.Width &&
- bytes[pixelIndex] >= minPixel &&
- !visited[tempx2, tempy2])
- {
- visited[tempx2, tempy2] = true;
- point = new Point(tempx2, tempy2);
- pixels.Add(point);
- queue.Enqueue(point);
-
- minX = Math.Min(minX, tempx2);
- maxX = Math.Max(maxX, tempx2);
- minY = Math.Min(minY, tempy2);
- maxY = Math.Max(maxY, tempy2);
-
- islandSupportingPixels += previousBytes[pixelIndex] >= minPixelForSupportIsland ? 1u : 0;
- }
- }
- }
- //count++;
-
- if (islandSupportingPixels >= requiredPixelsToSupportIsland)
- continue; // Not a island, bounding is strong
- if (islandSupportingPixels > 0 && pixels.Count < requiredPixelsToSupportIsland &&
- islandSupportingPixels >= Math.Max(1, pixels.Count / 2)) continue; // Not a island
- result.Add(new LayerIssue(this, LayerIssue.IssueType.Island, pixels.ToArray(), new Rectangle(minX, minY, maxX-minX, maxY-minY)));
- }
- }
- }
- }
-
- pixels.Clear();
-
- // TouchingBounds Checker
- for (int x = 0; x < mat.Width; x++) // Check Top and Bottom bounds
- {
- if (bytes[x] >= 200) // Top
- {
- pixels.Add(new Point(x, 0));
- }
-
- if (bytes[mat.Width * mat.Height - mat.Width + x] >= 200) // Bottom
- {
- pixels.Add(new Point(x, mat.Height-1));
- }
- }
-
- for (int y = 0; y < mat.Height; y++) // Check Left and Right bounds
- {
- if (bytes[y * mat.Width] >= 200) // Left
- {
- pixels.Add(new Point(0, y));
- }
-
- if (bytes[y * mat.Width + mat.Width - 1] >= 200) // Right
- {
- pixels.Add(new Point(mat.Width-1, y));
- }
- }
-
- if (pixels.Count > 0)
- {
- result.Add(new LayerIssue(this, LayerIssue.IssueType.TouchingBound, pixels.ToArray()));
- }
-
- pixels.Clear();
-
- return result;
- }
-
- public void MutateMove(OperationMove move)
- {
- using (var layer = LayerMat)
- {
- if (move.ImageWidth == 0) move.ImageWidth = (uint) layer.Width;
- if (move.ImageHeight == 0) move.ImageHeight = (uint) layer.Height;
-
- /*layer.Transform(1.0, 1.0, move.MarginLeft - move.MarginRight, move.MarginTop-move.MarginBottom);
- LayerMat = layer;*/
- using (var layerRoi = new Mat(layer, move.SrcRoi))
- {
- using (var dstLayer = layer.CloneBlank())
- {
- using (var dstRoi = new Mat(dstLayer, move.DstRoi))
- {
- layerRoi.CopyTo(dstRoi);
- LayerMat = dstLayer;
- }
- }
- }
- }
- }
-
-
- public void MutateResize(double xScale, double yScale)
- {
- using (var mat = LayerMat)
- {
- mat.TransformFromCenter(xScale, yScale);
- LayerMat = mat;
- }
- }
-
- public void MutateFlip(FlipType flipType, bool makeCopy = true)
- {
- using (var mat = LayerMat)
- {
- if (makeCopy)
- {
- using (Mat dst = new Mat())
- {
- CvInvoke.Flip(mat, dst, flipType);
- 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;
-
- }
- }
- else
- {
- CvInvoke.Flip(mat, mat, flipType);
- }
-
- LayerMat = mat;
- }
- }
-
- public void MutateRotate(double angle = 90.0, Inter interpolation = Inter.Linear)
- {
- using (var mat = LayerMat)
- {
- var halfWidth = mat.Width / 2.0f;
- var halfHeight = mat.Height / 2.0f;
- using (var translateTransform = new Matrix<double>(2, 3))
- {
- CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), angle, 1.0, translateTransform);
- /*var rect = new RotatedRect(PointF.Empty, mat.Size, (float) angle).MinAreaRect();
- translateTransform[0, 2] += rect.Width / 2.0 - mat.Cols / 2.0;
- translateTransform[0, 2] += rect.Height / 2.0 - mat.Rows / 2.0;*/
-
- /* var abs_cos = Math.Abs(translateTransform[0, 0]);
- var abs_sin = Math.Abs(translateTransform[0, 1]);
-
- var bound_w = mat.Height * abs_sin + mat.Width * abs_cos;
- var bound_h = mat.Height * abs_cos + mat.Width * abs_sin;
-
- translateTransform[0, 2] += bound_w / 2 - halfWidth;
- translateTransform[1, 2] += bound_h / 2 - halfHeight;*/
-
-
- CvInvoke.WarpAffine(mat, mat, translateTransform, mat.Size, interpolation);
- }
-
- LayerMat = mat;
- }
- }
-
- public void MutateSolidify()
- {
- using (Mat mat = LayerMat)
- {
- using (Mat filteredMat = new Mat())
- {
- CvInvoke.Threshold(mat, filteredMat, 254, 255, ThresholdType.Binary); // Clean AA
-
- using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
- {
- using (Mat hierarchy = new Mat())
- {
- CvInvoke.FindContours(filteredMat, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
- var arr = hierarchy.GetData();
- 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);
- }
- }
- }
- }
-
- LayerMat = mat;
- }
- }
-
- public void MutateErode(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
- {
- if(anchor.IsEmpty) anchor = new Point(-1, -1);
- if (ReferenceEquals(kernel, null))
- {
- kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
- }
- using (Mat dst = LayerMat)
- {
- CvInvoke.Erode(dst, dst, kernel, anchor, iterations, borderType, borderValue);
- LayerMat = dst;
- }
- }
-
- public void MutateDilate(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
- {
- if (anchor.IsEmpty) anchor = new Point(-1, -1);
- if (ReferenceEquals(kernel, null))
- {
- kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
- }
- using (Mat dst = LayerMat)
- {
- CvInvoke.Dilate(dst, dst, kernel, anchor, iterations, borderType, borderValue);
- LayerMat = dst;
- }
- }
-
- public void MutateOpen(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
- {
- if (anchor.IsEmpty) anchor = new Point(-1, -1);
- if (ReferenceEquals(kernel, null))
- {
- kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
- }
- using (Mat dst = LayerMat)
- {
- CvInvoke.MorphologyEx(dst, dst, MorphOp.Open, kernel, anchor, iterations, borderType, borderValue);
- LayerMat = dst;
- }
- }
-
- public void MutateClose(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
- {
- if (anchor.IsEmpty) anchor = new Point(-1, -1);
- if (ReferenceEquals(kernel, null))
- {
- kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
- }
- using (Mat dst = LayerMat)
- {
- CvInvoke.MorphologyEx(dst, dst, MorphOp.Close, kernel, anchor, iterations, borderType, borderValue);
- LayerMat = dst;
- }
- }
-
- public void MutateGradient(int iterations = 1, IInputArray kernel = null, Point anchor = default, BorderType borderType = BorderType.Default, MCvScalar borderValue = default)
- {
- if (anchor.IsEmpty) anchor = new Point(-1, -1);
- if (ReferenceEquals(kernel, null))
- {
- kernel = CvInvoke.GetStructuringElement(ElementShape.Cross, new Size(3, 3), anchor);
- }
- using (Mat dst = LayerMat)
- {
- CvInvoke.MorphologyEx(dst, dst, MorphOp.Gradient, kernel, anchor, iterations, borderType, borderValue);
- LayerMat = dst;
- }
- }
-
- public void MutatePyrDownUp(BorderType borderType = BorderType.Reflect101)
- {
- using (Mat dst = LayerMat)
- {
- CvInvoke.PyrDown(dst, dst, borderType);
- CvInvoke.PyrUp(dst, dst, borderType);
- LayerMat = dst;
- }
- }
-
- public void MutateMedianBlur(int aperture = 1)
- {
- using (Mat dst = LayerMat)
- {
- CvInvoke.MedianBlur(dst, dst, aperture);
- LayerMat = dst;
- }
- }
-
- public void MutateGaussianBlur(Size size = default, int sigmaX = 0, int sigmaY = 0, BorderType borderType = BorderType.Reflect101)
- {
- if(size.IsEmpty) size = new Size(5, 5);
-
- using (Mat dst = LayerMat)
- {
- CvInvoke.GaussianBlur(dst, dst, size, sigmaX, sigmaY, borderType);
- LayerMat = dst;
- }
- }
-
- public void ToolPattern(OperationPattern settings)
- {
- using (var layer = LayerMat)
- {
- using (var layerRoi = new Mat(layer, settings.SrcRoi))
- {
- using (var dstLayer = layer.CloneBlank())
- {
- for (ushort col = 0; col < settings.Cols; col++)
- {
- for (ushort row = 0; row < settings.Rows; row++)
- {
- using (var dstRoi = new Mat(dstLayer, settings.GetRoi(col, row)))
- {
- layerRoi.CopyTo(dstRoi);
- }
- }
- }
-
- LayerMat = dstLayer;
- }
- }
- }
- }
-
-
-
- public Layer Clone()
- {
- return new Layer(Index, CompressedBytes, Filename, ParentLayerManager);
- }
-
-
-
- #endregion
- }
- #endregion
-
- #region LayerManager Class
public class LayerManager : IEnumerable<Layer>
{
#region Enums
@@ -2077,5 +1158,4 @@ namespace UVtools.Core
#endregion
}
- #endregion
}
diff --git a/UVtools.Core/MatBytes.cs b/UVtools.Core/MatBytes.cs
deleted file mode 100644
index 1dbb46a..0000000
--- a/UVtools.Core/MatBytes.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using System.Drawing;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using Emgu.CV;
-using Emgu.CV.CvEnum;
-
-namespace UVtools.Core
-{
- public sealed class MatBytes : IDisposable
- {
- private bool m_IsDisposed;
- /// <summary>
- /// Gets the byte structure of this Mat
- /// </summary>
- public byte[] Bytes;
-
- /// <summary>
- /// Gets the <see cref="Mat"/>
- /// </summary>
- public Mat Mat { get; }
-
- /// <summary>
- /// Gets the <see cref="GCHandle"/> for the allocated bytes
- /// </summary>
- public GCHandle Handle { get; }
-
- public byte this[int index]
- {
- get => Bytes[index];
- set => Bytes[index] = value;
- }
-
- public byte this[int x, int y]
- {
- get => Bytes[y * Mat.Width + x];
- set => Bytes[y * Mat.Width + x] = value;
- }
-
- public MatBytes(Mat mat) : this(mat.Size, (byte) mat.NumberOfChannels, mat.Depth)
- {
- var s = mat.DataPointer;
-
- }
-
- public MatBytes(Size size, byte channels = 1, DepthType depth = DepthType.Cv8U)
- {
- Bytes = new byte[size.Width * size.Height * channels];
- Handle = GCHandle.Alloc(Bytes, GCHandleType.Pinned);
- Mat = new Mat(size, depth, channels, Handle.AddrOfPinnedObject(), size.Width * channels);
- }
-
- public MatBytes(Size size, out byte[] bytes, byte channels = 1, DepthType depth = DepthType.Cv8U) : this(size, channels, depth)
- {
- bytes = Bytes;
- }
-
- public void Free()
- {
- Handle.Free();
- }
-
- [MethodImpl(MethodImplOptions.Synchronized)]
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool isDisposing)
- {
- if (m_IsDisposed)
- return;
-
- if (isDisposing)
- {
- Mat?.Dispose();
- Free();
- }
- m_IsDisposed = true;
- }
-
- }
-}
diff --git a/UVtools.Core/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index 8707be2..bed0879 100644
--- a/UVtools.Core/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -1,9 +1,7 @@
using System;
-using System.Collections.Generic;
using System.Drawing;
-using System.Text;
-namespace UVtools.Core
+namespace UVtools.Core.Operations
{
public enum Anchor : byte
{
diff --git a/UVtools.Core/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs
index 0f4f668..9332a7e 100644
--- a/UVtools.Core/OperationPattern.cs
+++ b/UVtools.Core/Operations/OperationPattern.cs
@@ -1,6 +1,6 @@
using System.Drawing;
-namespace UVtools.Core
+namespace UVtools.Core.Operations
{
public class OperationPattern
{
diff --git a/UVtools.Core/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs
index 8b6559d..7c6ed73 100644
--- a/UVtools.Core/OperationProgress.cs
+++ b/UVtools.Core/Operations/OperationProgress.cs
@@ -1,7 +1,7 @@
using System;
using System.Threading;
-namespace UVtools.Core
+namespace UVtools.Core.Operations
{
public sealed class OperationProgress
{
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 153a0b2..7fddd8e 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
- <Version>0.6.1.0</Version>
+ <Version>0.6.1.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
</PropertyGroup>
@@ -24,10 +24,6 @@
</PropertyGroup>
<ItemGroup>
- <Compile Remove="MatBytes.cs" />
- </ItemGroup>
-
- <ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
@@ -36,7 +32,6 @@
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
- <None Include="MatBytes.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/UVtools.GUI/Forms/FrmAbout.cs b/UVtools.GUI/Forms/FrmAbout.cs
index baeebdc..846dba8 100644
--- a/UVtools.GUI/Forms/FrmAbout.cs
+++ b/UVtools.GUI/Forms/FrmAbout.cs
@@ -11,6 +11,7 @@ using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.FileFormats;
namespace UVtools.GUI.Forms
{
diff --git a/UVtools.GUI/Forms/FrmInputBox.cs b/UVtools.GUI/Forms/FrmInputBox.cs
index 7d014dc..83328ed 100644
--- a/UVtools.GUI/Forms/FrmInputBox.cs
+++ b/UVtools.GUI/Forms/FrmInputBox.cs
@@ -10,6 +10,7 @@ using System;
using System.Globalization;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.FileFormats;
namespace UVtools.GUI.Forms
{
diff --git a/UVtools.GUI/Forms/FrmLoading.cs b/UVtools.GUI/Forms/FrmLoading.cs
index 9774a9f..10ebd38 100644
--- a/UVtools.GUI/Forms/FrmLoading.cs
+++ b/UVtools.GUI/Forms/FrmLoading.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.Operations;
namespace UVtools.GUI.Forms
{
diff --git a/UVtools.GUI/Forms/FrmMutationMove.cs b/UVtools.GUI/Forms/FrmMutationMove.cs
index 42ebbc0..4ac6a04 100644
--- a/UVtools.GUI/Forms/FrmMutationMove.cs
+++ b/UVtools.GUI/Forms/FrmMutationMove.cs
@@ -10,6 +10,7 @@ using System;
using System.Drawing;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.Operations;
namespace UVtools.GUI.Forms
{
diff --git a/UVtools.GUI/Forms/FrmSettings.cs b/UVtools.GUI/Forms/FrmSettings.cs
index e2b4d1b..b385aba 100644
--- a/UVtools.GUI/Forms/FrmSettings.cs
+++ b/UVtools.GUI/Forms/FrmSettings.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.FileFormats;
using UVtools.GUI.Properties;
namespace UVtools.GUI.Forms
diff --git a/UVtools.GUI/Forms/FrmToolPattern.cs b/UVtools.GUI/Forms/FrmToolPattern.cs
index 49e690d..34cc9c1 100644
--- a/UVtools.GUI/Forms/FrmToolPattern.cs
+++ b/UVtools.GUI/Forms/FrmToolPattern.cs
@@ -10,6 +10,7 @@ using System;
using System.Drawing;
using System.Windows.Forms;
using UVtools.Core;
+using UVtools.Core.Operations;
namespace UVtools.GUI.Forms
{
diff --git a/UVtools.GUI/FrmMain.Designer.cs b/UVtools.GUI/FrmMain.Designer.cs
index 75ad320..b28e316 100644
--- a/UVtools.GUI/FrmMain.Designer.cs
+++ b/UVtools.GUI/FrmMain.Designer.cs
@@ -138,7 +138,7 @@
this.btnNextLayer = new System.Windows.Forms.Button();
this.lbMaxLayer = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
- this.lbLayerActual = new System.Windows.Forms.Label();
+ this.lbActualLayer = new System.Windows.Forms.Label();
this.tbLayer = new System.Windows.Forms.TrackBar();
this.lbInitialLayer = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
@@ -1266,7 +1266,7 @@
//
// panel1
//
- this.panel1.Controls.Add(this.lbLayerActual);
+ this.panel1.Controls.Add(this.lbActualLayer);
this.panel1.Controls.Add(this.tbLayer);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(3, 85);
@@ -1276,13 +1276,13 @@
//
// lbLayerActual
//
- this.lbLayerActual.AutoSize = true;
- this.lbLayerActual.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
- this.lbLayerActual.Location = new System.Drawing.Point(3, 248);
- this.lbLayerActual.Name = "lbLayerActual";
- this.lbLayerActual.Size = new System.Drawing.Size(15, 15);
- this.lbLayerActual.TabIndex = 9;
- this.lbLayerActual.Text = "?";
+ this.lbActualLayer.AutoSize = true;
+ this.lbActualLayer.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.lbActualLayer.Location = new System.Drawing.Point(3, 248);
+ this.lbActualLayer.Name = "lbActualLayer";
+ this.lbActualLayer.Size = new System.Drawing.Size(15, 15);
+ this.lbActualLayer.TabIndex = 9;
+ this.lbActualLayer.Text = "?";
//
// tbLayer
//
@@ -1520,7 +1520,7 @@
private System.Windows.Forms.Button btnNextLayer;
private System.Windows.Forms.Button btnPreviousLayer;
private System.Windows.Forms.Panel panel1;
- private System.Windows.Forms.Label lbLayerActual;
+ private System.Windows.Forms.Label lbActualLayer;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Button btnFirstLayer;
private System.Windows.Forms.Button btnLastLayer;
diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs
index b40adbf..c2e9dd9 100644
--- a/UVtools.GUI/FrmMain.cs
+++ b/UVtools.GUI/FrmMain.cs
@@ -22,6 +22,8 @@ using Emgu.CV.Structure;
using Emgu.CV.Util;
using UVtools.Core;
using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
+using UVtools.Core.Operations;
using UVtools.GUI.Forms;
using UVtools.GUI.Properties;
@@ -332,10 +334,10 @@ namespace UVtools.GUI
ZoomToFit();
}
- lbLayerActual.Location = new Point(lbLayerActual.Location.X,
+ lbActualLayer.Location = new Point(lbActualLayer.Location.X,
Math.Max(1,
Math.Min(tbLayer.Height - 40,
- (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbLayerActual.Height / 2)
+ (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbActualLayer.Height / 2)
));
}
@@ -1294,11 +1296,11 @@ namespace UVtools.GUI
DisableGUI();
FrmLoading.SetDescription($"Converting {Path.GetFileName(SlicerFile.FileFullPath)} to {Path.GetExtension(dialog.FileName)}");
- Task task = Task.Factory.StartNew(() =>
+ Task<bool> task = Task<bool>.Factory.StartNew(() =>
{
try
{
- SlicerFile.Convert(fileFormat, dialog.FileName, FrmLoading.RestartProgress());
+ return SlicerFile.Convert(fileFormat, dialog.FileName, FrmLoading.RestartProgress());
}
catch (OperationCanceledException)
{
@@ -1315,9 +1317,11 @@ namespace UVtools.GUI
EnableGUI(true);
});
}
+
+ return false;
});
- if (FrmLoading.ShowDialog() == DialogResult.OK)
+ if (FrmLoading.ShowDialog() == DialogResult.OK && task.Result)
{
if (MessageBox.Show($"Convertion is completed: {Path.GetFileName(dialog.FileName)} in {FrmLoading.StopWatch.ElapsedMilliseconds / 1000}s\n" +
"Do you want open the converted file in a new window?",
@@ -1486,7 +1490,7 @@ namespace UVtools.GUI
UpdateIssuesInfo();
lbMaxLayer.Text =
- lbLayerActual.Text =
+ lbActualLayer.Text =
lbInitialLayer.Text = "???";
lvProperties.BeginUpdate();
lvProperties.Items.Clear();
@@ -1902,6 +1906,8 @@ namespace UVtools.GUI
btnLastLayer.Enabled = btnNextLayer.Enabled = layerNum < SlicerFile.LayerCount - 1;
btnFirstLayer.Enabled = btnPreviousLayer.Enabled = layerNum > 0;
+ var layer = SlicerFile[ActualLayer];
+
try
{
// OLD
@@ -2123,17 +2129,17 @@ namespace UVtools.GUI
watch.Stop();
tsLayerPreviewTime.Text = $"{watch.ElapsedMilliseconds}ms";
//lbLayers.Text = $"{SlicerFile.GetHeightFromLayer(layerNum)} / {SlicerFile.TotalHeight}mm\n{layerNum} / {SlicerFile.LayerCount-1}\n{percent}%";
- lbLayerActual.Text = $"{SlicerFile.GetHeightFromLayer(ActualLayer)}mm\n{ActualLayer}\n{percent}%";
- lbLayerActual.Location = new Point(lbLayerActual.Location.X,
+ lbActualLayer.Text = $"{layer.PositionZ}mm\n{ActualLayer}\n{percent}%";
+ lbActualLayer.Location = new Point(lbActualLayer.Location.X,
Math.Max(1,
- Math.Min(tbLayer.Height- lbLayerActual.Height,
- (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbLayerActual.Height/2)
+ Math.Min(tbLayer.Height- lbActualLayer.Height,
+ (int)(tbLayer.Height - tbLayer.Value * ((float)tbLayer.Height / tbLayer.Maximum)) - lbActualLayer.Height/2)
));
pbLayers.Value = percent;
- lbLayerActual.Invalidate();
- lbLayerActual.Update();
- lbLayerActual.Refresh();
+ lbActualLayer.Invalidate();
+ lbActualLayer.Update();
+ lbActualLayer.Refresh();
pbLayer.Invalidate();
pbLayer.Update();
pbLayer.Refresh();
diff --git a/UVtools.GUI/Program.cs b/UVtools.GUI/Program.cs
index 675c1fa..45ebbf6 100644
--- a/UVtools.GUI/Program.cs
+++ b/UVtools.GUI/Program.cs
@@ -14,6 +14,7 @@ using System.Windows.Forms;
using ApplicationManagement;
using Emgu.CV;
using UVtools.Core;
+using UVtools.Core.FileFormats;
using UVtools.GUI.Forms;
namespace UVtools.GUI
diff --git a/UVtools.GUI/Properties/AssemblyInfo.cs b/UVtools.GUI/Properties/AssemblyInfo.cs
index 2fea0eb..1998be3 100644
--- a/UVtools.GUI/Properties/AssemblyInfo.cs
+++ b/UVtools.GUI/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.6.1.0")]
-[assembly: AssemblyFileVersion("0.6.1.0")]
+[assembly: AssemblyVersion("0.6.1.1")]
+[assembly: AssemblyFileVersion("0.6.1.1")]