Skip to content

Commit d1c88b9

Browse files
committed
v5.0.4
- PCB Exposure: - (Fix) Polygon primitive vertex count not parsing correctly when having argument (#976) - (Fix) Obround aperture to follow the correct implementation (two semicircles connected by parallel lines tangent to their endpoints) (#976) - (Fix) Implement the "hole diameter" argument in all apertures (#976) - (Fix) Implement the "rotation" argument for the polygon aperture
1 parent bf423f4 commit d1c88b9

17 files changed

+175
-89
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 08/01/2025 - v5.0.4
4+
5+
- PCB Exposure:
6+
- (Fix) Polygon primitive vertex count not parsing correctly when having argument (#976)
7+
- (Fix) Obround aperture to follow the correct implementation (two semicircles connected by parallel lines tangent to their endpoints) (#976)
8+
- (Fix) Implement the "hole diameter" argument in all apertures (#976)
9+
- (Fix) Implement the "rotation" argument for the polygon aperture
10+
311
## 28/12/2024 - v5.0.3
412

513
- Anycubic file format:

CREDITS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,5 @@
9494
- Jeremy Conoley
9595
- Brady George
9696
- Ryan Skow
97-
- Cainam
97+
- Cainam
98+
- Cory Lytle

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
3838

3939
<!-- Versions -->
40-
<UVtoolsVersion>5.0.3</UVtoolsVersion>
40+
<UVtoolsVersion>5.0.4</UVtoolsVersion>
4141
<AvaloniaVersion>11.2.3</AvaloniaVersion>
4242

4343
<!-- MvvmToolkit -->

RELEASE_NOTES.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
- Anycubic file format:
2-
- (Fix) Reset TSMC values to comply with globals when decoding file and AdvancedMode is disabled (#971)
3-
- (Fix) Setting the LiftHeight2 was setting the base value to BottomLiftHeight2
4-
- (Fix) Setting the BottomRetractSpeed was not applying the value in the base property
5-
- Multiple exposure finder:
6-
- (Fix) Counter triangles not taking all the new left space
7-
- (Fix) When doing multiple heights the text label always show the base height
8-
- (Improvement) Layer image viewer internal handling
9-
- (Fix) Settings - Send to process: Unable to pick a process file, it was selecting folder instead
10-
- (Fix) Save As can show incorrect file extension description when there are other file formats with the same extension
1+
- PCB Exposure:
2+
- (Fix) Polygon primitive vertex count not parsing correctly when having argument (#976)
3+
- (Fix) Obround aperture to follow the correct implementation (two semicircles connected by parallel lines tangent to their endpoints) (#976)
4+
- (Fix) Implement the "hole diameter" argument in all apertures (#976)
5+
- (Fix) Implement the "rotation" argument for the polygon aperture
116

UVtools.Core/Gerber/Apertures/Aperture.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,24 @@ protected Aperture(GerberFormat document, string name)
6464
case "C":
6565
{
6666
if (match.Groups.Count < 4) return null;
67-
if (!double.TryParse(match.Groups[3].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var diameter)) return null;
68-
return new CircleAperture(document, index, diameter);
67+
var split = match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
68+
if (split.Length == 0) return null;
69+
if (!double.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var diameter)) return null;
70+
var holeDiameter = 0.0;
71+
if (split.Length > 1 && !double.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out holeDiameter)) return null;
72+
return new CircleAperture(document, index, diameter, holeDiameter);
6973
}
70-
case "O":
74+
case "O": // OBround
7175
{
7276
if (match.Groups.Count < 4) return null;
7377
var split = match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
7478
if (split.Length < 2) return null;
7579
if (!float.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width)) return null;
7680
if (!float.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height)) return null;
81+
var holeDiameter = 0.0;
82+
if (split.Length > 2 && !double.TryParse(split[2], NumberStyles.Float, CultureInfo.InvariantCulture, out holeDiameter)) return null;
7783

78-
return new EllipseAperture(document, index, width, height);
84+
return new ObroundAperture(document, index, width, height, holeDiameter);
7985
}
8086
case "R":
8187
{
@@ -84,8 +90,10 @@ protected Aperture(GerberFormat document, string name)
8490
if (split.Length < 2) return null;
8591
if (!float.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width)) return null;
8692
if (!float.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height)) return null;
93+
var holeDiameter = 0.0;
94+
if (split.Length > 2 && !double.TryParse(split[2], NumberStyles.Float, CultureInfo.InvariantCulture, out holeDiameter)) return null;
8795

88-
return new RectangleAperture(document, index, width, height);
96+
return new RectangleAperture(document, index, width, height, holeDiameter);
8997
}
9098
case "P":
9199
{
@@ -94,8 +102,12 @@ protected Aperture(GerberFormat document, string name)
94102
if (split.Length < 2) return null;
95103
if (!double.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var diameter)) return null;
96104
if (!ushort.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var vertices)) return null;
105+
var rotation = 0.0;
106+
if (split.Length > 2 && !double.TryParse(split[2], NumberStyles.Float, CultureInfo.InvariantCulture, out rotation)) return null;
107+
var holeDiameter = 0.0;
108+
if (split.Length > 3 && !double.TryParse(split[3], NumberStyles.Float, CultureInfo.InvariantCulture, out holeDiameter)) return null;
97109

98-
return new PolygonAperture(document, index, diameter, vertices);
110+
return new PolygonAperture(document, index, diameter, vertices, rotation, holeDiameter);
99111
}
100112
default: // macro
101113
{
@@ -104,7 +116,7 @@ protected Aperture(GerberFormat document, string name)
104116
//var parseLine = line.TrimEnd('%', '*');
105117
//var commaIndex = parseLine.IndexOf(',')+1;
106118
//parseLine = parseLine[commaIndex..];
107-
string[] args = { "0" };
119+
string[] args = ["0"];
108120
if (match.Groups.Count >= 4)
109121
{
110122
args = args.Concat(match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)).ToArray();

UVtools.Core/Gerber/Apertures/CircleAperture.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,38 @@
1010
using Emgu.CV.CvEnum;
1111
using Emgu.CV.Structure;
1212
using System.Drawing;
13+
using UVtools.Core.Extensions;
1314

1415
namespace UVtools.Core.Gerber.Apertures;
1516

1617
public class CircleAperture : Aperture
1718
{
1819
#region Properties
1920
public double Diameter { get; set; }
21+
public double HoleDiameter { get; set; }
2022
#endregion
2123

2224
#region Constructor
2325
public CircleAperture(GerberFormat document) : base(document, "Circle") { }
2426

25-
public CircleAperture(GerberFormat document, int index, double diameter) : base(document, index, "Circle")
27+
public CircleAperture(GerberFormat document, int index, double diameter, double holeDiameter = 0) : base(document, index, "Circle")
2628
{
2729
Diameter = document.GetMillimeters(diameter);
30+
if (holeDiameter > 0) HoleDiameter = document.GetMillimeters(holeDiameter);
2831
}
2932
#endregion
3033

3134
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
3235
{
33-
CvInvoke.Ellipse(mat, Document.PositionMmToPx(at), Document.SizeMmToPx(Diameter / 2.0, Diameter / 2.0), 0, 0, 360, color, -1, lineType);
34-
//CvInvoke.Circle(mat, Document.PositionMmToPx(at), Document.SizeMmToPx(Diameter / 2), color, -1, lineType);
36+
var location = Document.PositionMmToPx(at);
37+
CvInvoke.Ellipse(mat, location, Document.SizeMmToPx(Diameter / 2.0, Diameter / 2.0), 0, 0, 360, color, -1, lineType);
38+
if (HoleDiameter > 0)
39+
{
40+
var invertColor = color.Equals(EmguExtensions.BlackColor) ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor;
41+
CvInvoke.Ellipse(mat,
42+
location,
43+
Document.SizeMmToPx(HoleDiameter / 2.0, HoleDiameter / 2.0),
44+
0, 0, 360, invertColor, -1, lineType);
45+
}
3546
}
3647
}

UVtools.Core/Gerber/Apertures/EllipseAperture.cs

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* GNU AFFERO GENERAL PUBLIC LICENSE
3+
* Version 3, 19 November 2007
4+
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5+
* Everyone is permitted to copy and distribute verbatim copies
6+
* of this license document, but changing it is not allowed.
7+
*/
8+
9+
using Emgu.CV;
10+
using Emgu.CV.CvEnum;
11+
using Emgu.CV.Structure;
12+
using System.Drawing;
13+
using UVtools.Core.Extensions;
14+
15+
namespace UVtools.Core.Gerber.Apertures;
16+
17+
public class ObroundAperture : Aperture
18+
{
19+
#region Properties
20+
public SizeF Axes { get; set; }
21+
public double HoleDiameter { get; set; }
22+
#endregion
23+
24+
#region Constructor
25+
public ObroundAperture(GerberFormat document) : base(document, "Obround") { }
26+
27+
public ObroundAperture(GerberFormat document, int index, float width, float height, double holeDiameter = 0) : this(document, index, new SizeF(width, height), holeDiameter)
28+
{
29+
30+
}
31+
32+
public ObroundAperture(GerberFormat document, int index, SizeF axes, double holeDiameter = 0) : base(document, index, "Obround")
33+
{
34+
Axes = document.GetMillimeters(axes);
35+
if (holeDiameter > 0) HoleDiameter = document.GetMillimeters(holeDiameter);
36+
}
37+
#endregion
38+
39+
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
40+
{
41+
var location = Document.PositionMmToPx(at);
42+
// Calculate radii of the semicircles
43+
var radius = Document.SizeMmToPx(Axes.Width / 2, Axes.Height / 2);
44+
var radiusFromHeight = Document.SizeMmToPx(Axes.Height / 2, Axes.Height / 2);
45+
var diameter = Document.SizeMmToPx(Axes.Width, Axes.Height);
46+
47+
// Calculate centers for the semicircles
48+
var leftCircleCenter = location with { X = location.X - radius.Width + radiusFromHeight.Width };
49+
var rightCircleCenter = location with { X = location.X + radius.Width - radiusFromHeight.Width };
50+
51+
// Draw the two semicircles
52+
CvInvoke.Ellipse(mat, leftCircleCenter, radiusFromHeight, 0, 90, 270, color, -1, lineType);
53+
CvInvoke.Ellipse(mat, rightCircleCenter, radiusFromHeight, 0, -90, 90, color, -1, lineType);
54+
55+
/*CvInvoke.Ellipse(mat,
56+
location,
57+
radius,
58+
0, 0, 360, color, -1, lineType);*/
59+
60+
// Draw the rectangle connecting the semicircles
61+
var rect = new Rectangle(leftCircleCenter with { Y = location.Y - radius.Height },
62+
diameter with { Width = diameter.Width - diameter.Height });
63+
CvInvoke.Rectangle(mat, rect, color, -1, lineType);
64+
65+
if (HoleDiameter > 0)
66+
{
67+
var invertColor = color.Equals(EmguExtensions.BlackColor) ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor;
68+
CvInvoke.Ellipse(mat,
69+
location,
70+
Document.SizeMmToPx(HoleDiameter / 2.0, HoleDiameter / 2.0),
71+
0, 0, 360, invertColor, -1, lineType);
72+
}
73+
}
74+
}

UVtools.Core/Gerber/Apertures/PoygonAperture.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,33 @@ public class PolygonAperture : Aperture
1919
#region Properties
2020
public double Diameter { get; set; }
2121
public ushort Vertices { get; set; }
22+
public double Rotation { get; set; }
23+
public double HoleDiameter { get; set; }
2224
#endregion
2325

2426
#region Constructor
2527
public PolygonAperture(GerberFormat document) : base(document, "Polygon") { }
2628

27-
public PolygonAperture(GerberFormat document, int index, double diameter, ushort vertices) : base(document, index, "Polygon")
29+
public PolygonAperture(GerberFormat document, int index, double diameter, ushort vertices, double rotation = 0.0, double holeDiameter = 0) : base(document, index, "Polygon")
2830
{
2931
Diameter = document.GetMillimeters(diameter);
3032
Vertices = vertices;
33+
Rotation = rotation;
34+
if (holeDiameter > 0) HoleDiameter = document.GetMillimeters(holeDiameter);
3135
}
3236
#endregion
3337

3438
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
3539
{
36-
mat.DrawPolygon(Vertices, Document.SizeMmToPx(Diameter), Document.PositionMmToPx(at), color, 0, -1, lineType);
40+
var location = Document.PositionMmToPx(at);
41+
mat.DrawPolygon(Vertices, Document.SizeMmToPx(Diameter), location, color, Rotation, -1, lineType);
42+
if (HoleDiameter > 0)
43+
{
44+
var invertColor = color.Equals(EmguExtensions.BlackColor) ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor;
45+
CvInvoke.Ellipse(mat,
46+
location,
47+
Document.SizeMmToPx(HoleDiameter / 2.0, HoleDiameter / 2.0),
48+
0, 0, 360, invertColor, -1, lineType);
49+
}
3750
}
3851
}

UVtools.Core/Gerber/Apertures/RectangleAperture.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,48 @@
99
using Emgu.CV;
1010
using Emgu.CV.CvEnum;
1111
using Emgu.CV.Structure;
12+
using Microsoft.CodeAnalysis;
1213
using System;
1314
using System.Drawing;
15+
using UVtools.Core.Extensions;
1416

1517
namespace UVtools.Core.Gerber.Apertures;
1618

1719
public class RectangleAperture : Aperture
1820
{
1921
#region Properties
2022
public SizeF Size { get; set; }
23+
public double HoleDiameter { get; set; }
2124
#endregion
2225

2326
#region Constructor
2427
public RectangleAperture(GerberFormat document) : base(document, "Rectangle") { }
2528

26-
public RectangleAperture(GerberFormat document, int index, float width, float height) : this(document, index, new SizeF(width, height))
27-
{ }
29+
public RectangleAperture(GerberFormat document, int index, float width, float height, double holeDiameter = 0) : this(document, index, new SizeF(width, height), holeDiameter)
30+
{
31+
}
2832

29-
public RectangleAperture(GerberFormat document, int index, SizeF size) : base(document, index, "Rectangle")
33+
public RectangleAperture(GerberFormat document, int index, SizeF size, double holeDiameter = 0) : base(document, index, "Rectangle")
3034
{
3135
Size = document.GetMillimeters(size);
36+
if (holeDiameter > 0) HoleDiameter = document.GetMillimeters(holeDiameter);
3237
}
3338
#endregion
3439

3540
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
3641
{
42+
var location = Document.PositionMmToPx(at);
43+
3744
at = new PointF(Math.Max(0, at.X - Size.Width / 2), Math.Max(0, at.Y - Size.Height / 2));
3845
CvInvoke.Rectangle(mat, new Rectangle(Document.PositionMmToPx(at), Document.SizeMmToPx(Size)), color, -1, lineType);
46+
47+
if (HoleDiameter > 0)
48+
{
49+
var invertColor = color.Equals(EmguExtensions.BlackColor) ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor;
50+
CvInvoke.Ellipse(mat,
51+
location,
52+
Document.SizeMmToPx(HoleDiameter / 2.0, HoleDiameter / 2.0),
53+
0, 0, 360, invertColor, -1, lineType);
54+
}
3955
}
4056
}

UVtools.Core/Gerber/Macro.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public void ParsePrimitive(string line)
7171
Primitives.Add(primitive);
7272
break;
7373
}
74-
// 21 Center Line: Exposure, Width, Hight, Center X, Center Y, Rotation
74+
// 21 Center Line: Exposure, Width, Height, Center X, Center Y, Rotation
7575
case CenterLinePrimitive.Code:
7676
{
7777
var primitive = new CenterLinePrimitive(Document, commaSplit[1], commaSplit[2], commaSplit[3], commaSplit[4], commaSplit[5]);
@@ -85,7 +85,7 @@ public void ParsePrimitive(string line)
8585
Primitives.Add(new OutlinePrimitive(Document, commaSplit[1], commaSplit[3..^1], commaSplit[^1]));
8686
break;
8787
}
88-
// 5 Outline: Exposure, # vertices, Start X, Start Y, Subsequent points..., Rotation
88+
// 5 Outline: Exposure, # vertices, Center X, Center Y, Diameter, Rotation
8989
case PolygonPrimitive.Code:
9090
{
9191
var primitive = new PolygonPrimitive(Document, commaSplit[1], commaSplit[2], commaSplit[3], commaSplit[4], commaSplit[5]);

0 commit comments

Comments
 (0)