diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2022-06-25 04:02:59 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2022-06-25 04:02:59 +0300 |
commit | 9711bb7474d90ea6b54bbcae6db059364b44655e (patch) | |
tree | ad52f4713d3273cbc2e4fc054acf9b63771aa64c | |
parent | 67fbec1fff373a6ca6ae9f512eb28fe3fc379bb7 (diff) |
v3.5.2v3.5.2
- **PCB Exposure:**
- (Add) Gerber file extensions: gko, gtl, gto, gts, gbl, gbo, gbs, gml
- (Fix) Trailing zeros suppression mode and improve the parsing of the coordinate string (#492)
- (Fix) Allow coordinates without number `XYD0*` to indicate `X=0` and `Y=0`
- (Fix) Do not try to fetch apertures lower than index 10 when a `D02` (closed shutter) is found alone
-rw-r--r-- | CHANGELOG.md | 8 | ||||
-rw-r--r-- | RELEASE_NOTES.md | 12 | ||||
-rw-r--r-- | UVtools.Core/Gerber/Enumerations.cs | 16 | ||||
-rw-r--r-- | UVtools.Core/Gerber/GerberDocument.cs | 137 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationPCBExposure.cs | 20 | ||||
-rw-r--r-- | UVtools.Core/UVtools.Core.csproj | 2 | ||||
-rw-r--r-- | UVtools.InstallerMM/UVtools.InstallerMM.wxs | 2 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs | 5 | ||||
-rw-r--r-- | UVtools.WPF/UVtools.WPF.csproj | 2 |
9 files changed, 118 insertions, 86 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 47408b9..545eeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 25/06/2022 - v3.5.2 + +- **PCB Exposure:** + - (Add) Gerber file extensions: gko, gtl, gto, gts, gbl, gbo, gbs, gml + - (Fix) Trailing zeros suppression mode and improve the parsing of the coordinate string (#492) + - (Fix) Allow coordinates without number `XYD0*` to indicate `X=0` and `Y=0` + - (Fix) Do not try to fetch apertures lower than index 10 when a `D02` (closed shutter) is found alone + ## 24/06/2022 - v3.5.1 - **PCB Exposure:** diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0dd9480..d42886c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,10 +1,6 @@ - **PCB Exposure:** - - (Fix) Able to omit X or Y coordinate and use last known value in place - - (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name - - (Fix) Implement the inch measurement (%MOIN*%) - - (Fix) Crash when redo the operation (Ctrl + Shift + Z) -- **UI - Issue list:** - - (Add) Context menu when right click issues to select an action - - (Add) Option to solidify suction cups when right click on the issue - - (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions + - (Add) Gerber file extensions: gko, gtl, gto, gts, gbl, gbo, gbs, gml + - (Fix) Trailing zeros suppression mode and improve the parsing of the coordinate string (#492) + - (Fix) Allow coordinates without number `XYD0*` to indicate `X=0` and `Y=0` + - (Fix) Do not try to fetch apertures lower than index 10 when a `D02` (closed shutter) is found alone diff --git a/UVtools.Core/Gerber/Enumerations.cs b/UVtools.Core/Gerber/Enumerations.cs index 0e38c42..d4ba962 100644 --- a/UVtools.Core/Gerber/Enumerations.cs +++ b/UVtools.Core/Gerber/Enumerations.cs @@ -7,6 +7,22 @@ */ namespace UVtools.Core.Gerber; +public enum GerberZerosSuppressionType : byte +{ + /// <summary> + /// Do not omit zeros + /// </summary> + NoSuppression, + /// <summary> + /// Omit left zeros + /// </summary> + Leading, + /// <summary> + /// Omit right zeros + /// </summary> + Trail +} + public enum GerberPositionType : byte { Absolute, diff --git a/UVtools.Core/Gerber/GerberDocument.cs b/UVtools.Core/Gerber/GerberDocument.cs index 3bd3887..5bde5bf 100644 --- a/UVtools.Core/Gerber/GerberDocument.cs +++ b/UVtools.Core/Gerber/GerberDocument.cs @@ -13,30 +13,35 @@ using System.IO; using System.Text.RegularExpressions; using Emgu.CV; using Emgu.CV.CvEnum; -using Emgu.CV.Structure; using Emgu.CV.Util; using UVtools.Core.Extensions; using UVtools.Core.Gerber.Apertures; namespace UVtools.Core.Gerber; +/// <summary> +/// https://www.ucamco.com/files/downloads/file_en/456/gerber-layer-format-specification-revision-2022-02_en.pdf?ac97011bf6bce9aaf0b1aac43d84b05f +/// </summary> public class GerberDocument { #region Properties + public GerberZerosSuppressionType ZerosSuppressionType { get; set; } = GerberZerosSuppressionType.NoSuppression; public GerberPositionType PositionType { get; set; } = GerberPositionType.Absolute; public GerberUnitType UnitType { get; set; } = GerberUnitType.Millimeter; public GerberPolarityType Polarity { get; set; } = GerberPolarityType.Dark; public GerberMoveType MoveType { get; set; } = GerberMoveType.Linear; - public bool LeadingZeroOmitted { get; set; } = true; - public byte CoordinateXIntegers { get; set; } = 3; public byte CoordinateXFractionalDigits { get; set; } = 6; + public byte CoordinateXLength => (byte)(CoordinateXIntegers + CoordinateXFractionalDigits); + public byte CoordinateYIntegers { get; set; } = 3; public byte CoordinateYFractionalDigits { get; set; } = 6; + public byte CoordinateYLength => (byte)(CoordinateYIntegers + CoordinateYFractionalDigits); + public Dictionary<int, Aperture> Apertures { get; } = new(); public Dictionary<string, Macro> Macros { get; } = new(); @@ -101,11 +106,11 @@ public class GerberDocument { // %FSLAX34Y34*% // 0123456789 - document.LeadingZeroOmitted = line[3] switch + document.ZerosSuppressionType = line[3] switch { - 'L' => true, - 'T' => false, - _ => document.LeadingZeroOmitted + 'L' => GerberZerosSuppressionType.Leading, + 'T' => GerberZerosSuppressionType.Trail, + _ => document.ZerosSuppressionType }; document.PositionType = line[4] switch { @@ -113,6 +118,7 @@ public class GerberDocument 'I' => GerberPositionType.Relative, _ => document.PositionType }; + if (document.PositionType == GerberPositionType.Relative) throw new NotImplementedException("Relative positions are not implemented yet.\nPlease use Absolute position for now."); if (line[5] != 'X') continue; if (byte.TryParse(line[6].ToString(), out var x1)) document.CoordinateXIntegers = x1; if (byte.TryParse(line[7].ToString(), out var x2)) document.CoordinateXFractionalDigits = x2; @@ -191,6 +197,7 @@ public class GerberDocument continue; } + // Aperture selector if (line[0] == 'D') { var matchD = Regex.Match(line, @"D(\d+)"); @@ -198,15 +205,17 @@ public class GerberDocument if (!int.TryParse(matchD.Groups[1].Value, out var d)) continue; + if(d < 10) continue; if (!document.Apertures.TryGetValue(d, out currentAperture)) continue; continue; } + if (line[0] == 'X' || line[0] == 'Y') { - var matchX = Regex.Match(line, @"X-?(\d+)"); - var matchY = Regex.Match(line, @"Y-?(\d+)"); + var matchX = Regex.Match(line, @"X-?(\d+)?"); + var matchY = Regex.Match(line, @"Y-?(\d+)?"); var matchD = Regex.Match(line, @"D(\d+)"); double nowX = 0; @@ -215,25 +224,20 @@ public class GerberDocument if (!matchD.Success || matchD.Groups.Count < 2) continue; if (!int.TryParse(matchD.Groups[1].Value, out var d)) continue; - if (matchX.Success && matchX.Groups.Count >= 2) + if (matchX.Success) { - if (double.TryParse(matchX.Groups[1].Value, out nowX)) + if (matchX.Groups.Count >= 2) { - if (nowX != 0) + var valueStr = document.ZerosSuppressionType switch { - if (document.CoordinateXFractionalDigits > matchX.Groups[1].Value.Length) // Leading zero omitted - { - double.TryParse($"0.{matchX.Groups[1].Value}", out nowX); - } - else - { - var integers = matchX.Groups[1].Value[..^document.CoordinateXFractionalDigits]; - var fraction = matchX.Groups[1].Value.Substring(matchX.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits); - double.TryParse($"{integers}.{fraction}", out nowX); - } - - nowX = document.GetMillimeters(nowX); - } + GerberZerosSuppressionType.Trail => matchX.Groups[1].Value.PadRight(document.CoordinateXLength, '0'), + _ => matchX.Groups[1].Value.PadLeft(document.CoordinateXLength, '0'), + }; + + var integers = valueStr[..document.CoordinateXIntegers]; + var fraction = valueStr[document.CoordinateXIntegers..]; + double.TryParse($"{integers}.{fraction}", out nowX); + nowX = document.GetMillimeters(nowX); } } else @@ -241,24 +245,21 @@ public class GerberDocument nowX = currentX; } - if (matchY.Success && matchY.Groups.Count >= 2) + if (matchY.Success) { - if (double.TryParse(matchY.Groups[1].Value, out nowY)) + if (matchY.Groups.Count >= 2) { - if (nowY != 0) + var valueStr = document.ZerosSuppressionType switch { - if (document.CoordinateYFractionalDigits > matchY.Groups[1].Value.Length) // Leading zero omitted - { - double.TryParse($"0.{matchY.Groups[1].Value}", out nowY); - } - else - { - var integers = matchY.Groups[1].Value[..^document.CoordinateYFractionalDigits]; - var fraction = matchY.Groups[1].Value.Substring(matchY.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits); - double.TryParse($"{integers}.{fraction}", out nowY); - } - nowY = document.GetMillimeters(nowY); - } + GerberZerosSuppressionType.Trail => matchY.Groups[1].Value.PadRight(document.CoordinateYLength, '0'), + _ => matchY.Groups[1].Value.PadLeft(document.CoordinateYLength, '0'), + }; + + var integers = valueStr[..document.CoordinateYIntegers]; + var fraction = valueStr[document.CoordinateYIntegers..]; + double.TryParse($"{integers}.{fraction}", out nowY); + nowY = document.GetMillimeters(nowY); + } } else @@ -289,46 +290,38 @@ public class GerberDocument { if (document.MoveType is GerberMoveType.Arc or GerberMoveType.ArcCounterClockwise) { + double xOffset = 0; + double yOffset = 0; var matchI = Regex.Match(line, @"I(-?\d+)"); var matchJ = Regex.Match(line, @"J(-?\d+)"); if(!matchI.Success || !matchJ.Success || matchI.Groups.Count < 2 || matchJ.Groups.Count < 2) continue; - if (double.TryParse(matchI.Groups[1].Value, out var xOffset)) + var valueStr = document.ZerosSuppressionType switch { - if (xOffset != 0) - { - if (document.CoordinateXFractionalDigits > matchI.Groups[1].Value.Length) // Leading zero omitted - { - double.TryParse($"0.{matchI.Groups[1].Value}", out xOffset); - } - else - { - var integers = matchI.Groups[1].Value[..^document.CoordinateXFractionalDigits]; - var fraction = matchI.Groups[1].Value.Substring(matchI.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits); - double.TryParse($"{integers}.{fraction}", out xOffset); - } - xOffset = document.GetMillimeters(xOffset); - } - } + GerberZerosSuppressionType.Trail => matchI.Groups[1].Value.PadRight(document.CoordinateXLength, '0'), + _ => matchI.Groups[1].Value.PadLeft(document.CoordinateXLength, '0'), + }; + - if (double.TryParse(matchJ.Groups[1].Value, out var yOffset)) + var integers = valueStr[..document.CoordinateXIntegers]; + var fraction = valueStr[document.CoordinateXIntegers..]; + double.TryParse($"{integers}.{fraction}", out xOffset); + xOffset = document.GetMillimeters(xOffset); + + + valueStr = document.ZerosSuppressionType switch { - if(yOffset != 0) - { - if (document.CoordinateYFractionalDigits > matchJ.Groups[1].Value.Length) // Leading zero omitted - { - double.TryParse($"0.{matchJ.Groups[1].Value}", out yOffset); - } - else - { - var integers = matchJ.Groups[1].Value[..^document.CoordinateYFractionalDigits]; - var fraction = matchJ.Groups[1].Value.Substring(matchJ.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits); - double.TryParse($"{integers}.{fraction}", out yOffset); - } - yOffset = document.GetMillimeters(yOffset); - } - } + GerberZerosSuppressionType.Trail => matchJ.Groups[1].Value.PadRight(document.CoordinateYLength, '0'), + _ => matchJ.Groups[1].Value.PadLeft(document.CoordinateYLength, '0'), + }; + + + integers = valueStr[..document.CoordinateYIntegers]; + fraction = valueStr[document.CoordinateYIntegers..]; + double.TryParse($"{integers}.{fraction}", out yOffset); + yOffset = document.GetMillimeters(yOffset); + if (currentX == nowX && currentY == nowY) // Closed circle { diff --git a/UVtools.Core/Operations/OperationPCBExposure.cs b/UVtools.Core/Operations/OperationPCBExposure.cs index 96fd82d..45aefce 100644 --- a/UVtools.Core/Operations/OperationPCBExposure.cs +++ b/UVtools.Core/Operations/OperationPCBExposure.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.IO.Compression; +using System.Linq; using System.Text; using Emgu.CV; using Emgu.CV.CvEnum; @@ -25,6 +26,22 @@ namespace UVtools.Core.Operations; [Serializable] public class OperationPCBExposure : Operation { + #region + + public static string[] ValidExtensions => new[] + { + "gbr", // Gerber + "gko", // Board outline layer + "gtl", // Top layer + "gto", // Top silkscreen layer + "gts", // Top solder mask layer + "gbl", // Bottom layer + "gbo", // Bottom silkscreen layer + "gbs", // Bottom solder mask layer + "gml", // Mechanical layer + }; + #endregion + #region Members private RangeObservableCollection<ValueDescription> _files = new(); @@ -189,7 +206,8 @@ public class OperationPCBExposure : Operation var tmpPath = PathExtensions.GetTemporaryDirectory($"{About.Software}."); foreach (var entry in zip.Entries) { - if(!entry.Name.EndsWith(".gbr")) continue; + if(!ValidExtensions.Any(extension => entry.Name.EndsWith($".{extension}", StringComparison.InvariantCultureIgnoreCase))) continue; + var filePath = entry.ImprovedExtractToFile(tmpPath, false); if (!string.IsNullOrEmpty(filePath)) { diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index eb96200..f92c898 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl> <Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description> - <Version>3.5.1</Version> + <Version>3.5.2</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs index 03b3cc7..05a325e 100644 --- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs +++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs @@ -2,7 +2,7 @@ <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <?define ComponentRules="OneToOne"?> <!-- SourceDir instructs IsWiX the location of the directory that contains files for this merge module --> - <?define SourceDir="..\publish\UVtools_win-x64_v3.5.1"?> + <?define SourceDir="..\publish\UVtools_win-x64_v3.5.2"?> <Module Id="UVtools" Language="1033" Version="1.0.0.0"> <Package Id="12aaa1cf-ff06-4a02-abd5-2ac01ac4f83b" Manufacturer="PTRTECH" InstallerVersion="200" Keywords="MSLA, DLP" Description="MSLA/DLP, file analysis, repair, conversion and manipulation" InstallScope="perMachine" Platform="x64" /> <Directory Id="TARGETDIR" Name="SourceDir"> diff --git a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs index 4bcebac..ceb8d25 100644 --- a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs @@ -92,7 +92,8 @@ namespace UVtools.WPF.Controls.Tools { return; } - if (!_selectedFile.ValueAsString.EndsWith(".gbr", StringComparison.OrdinalIgnoreCase) || !File.Exists(_selectedFile.ValueAsString)) return; + + if (!OperationPCBExposure.ValidExtensions.Any(extension => _selectedFile.ValueAsString.EndsWith($".{extension}", StringComparison.InvariantCultureIgnoreCase)) || !File.Exists(_selectedFile.ValueAsString)) return; using var mat = Operation.GetMat(_selectedFile.ValueAsString); using var matCropped = mat.CropByBounds(20); _previewImage?.Dispose(); @@ -115,7 +116,7 @@ namespace UVtools.WPF.Controls.Tools new() { Name = "Gerber files", - Extensions = new List<string>{ "gbr" } + Extensions = new List<string>(OperationPCBExposure.ValidExtensions) }, }, }; diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index e962877..7cb97cc 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ <PackageLicenseFile>LICENSE</PackageLicenseFile> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryType>Git</RepositoryType> - <Version>3.5.1</Version> + <Version>3.5.2</Version> <Platforms>AnyCPU;x64</Platforms> <PackageIcon>UVtools.png</PackageIcon> <PackageReadmeFile>README.md</PackageReadmeFile> |