diff --git a/GdsGenerator/Program.cs b/GdsGenerator/Program.cs
index e0b2a46..7ac6c65 100644
--- a/GdsGenerator/Program.cs
+++ b/GdsGenerator/Program.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Builders;
+using System.Numerics;
+using GdsSharp.Lib.Builders;
using GdsSharp.Lib.NonTerminals;
using GdsSharp.Lib.NonTerminals.Elements;
@@ -53,7 +54,43 @@
new GdsPoint(-1250, 0)
]
}
- }
+ },
+
+ // Use the path builder to create a path
+ new PathBuilder(
+ 100f,
+ new Vector2(-3100, -3300),
+ Vector2.UnitX)
+ // Straight ahead for 2000 units
+ .Straight(2000)
+
+ // Bend 45 degrees to the left with a radius of 500 units
+ .BendDeg(-45, 500)
+
+ // Generate shape like <=>
+ .Straight(100, widthEnd: 250)
+ .Straight(100)
+ .Straight(100, widthEnd: 100)
+
+ // Some more bends
+ .BendDeg(-45, 500)
+ .Straight(100)
+ .Straight(200, 250)
+ .BendDeg(180, 300)
+ .BendDeg(-180, 300)
+
+ // Example of using a function to change the width
+ .BendDeg(-180, 900, f => MathF.Cos(f * 50) * 100 + 150)
+
+ // PathBuilder also supports Bézier curves
+ .Bezier(b => b
+ .AddPoint(0, 0)
+ .AddPoint(0, 1000)
+ .AddPoint(2000, 1000)
+ .AddPoint(1000, 0),
+ t => 250 - (250 - 50) * t)
+ .Straight(800)
+ .Build()
]
});
diff --git a/GdsSharp.Lib.Test/VectorExtensionsTests.cs b/GdsSharp.Lib.Test/VectorExtensionsTests.cs
new file mode 100644
index 0000000..baf97ba
--- /dev/null
+++ b/GdsSharp.Lib.Test/VectorExtensionsTests.cs
@@ -0,0 +1,84 @@
+using System.Numerics;
+
+namespace GdsSharp.Lib.Test;
+
+[TestFixture]
+public class VectorExtensionsTests
+{
+ private const float TwoPi = 2 * MathF.PI;
+
+ [Test]
+ public void Rotate_Rotate90Degrees_CorrectResult()
+ {
+ var vec = new Vector2(1, 0);
+ const float radians = MathF.PI / 2;
+
+ var result = vec.Rotate(radians);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(result.X, Is.EqualTo(0).Within(1e-6)); // allowing a small tolerance for floating point errors
+ Assert.That(result.Y, Is.EqualTo(1).Within(1e-6));
+ });
+ }
+
+ [Test]
+ public void Rotate_Rotate180Degrees_CorrectResult()
+ {
+ var vec = new Vector2(1, 0);
+ const float radians = MathF.PI;
+
+ var result = vec.Rotate(radians);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(result.X, Is.EqualTo(-1).Within(1e-6));
+ Assert.That(result.Y, Is.EqualTo(0).Within(1e-6));
+ });
+ }
+
+ [Test]
+ public void Rotate_Rotate360Degrees_CorrectResult()
+ {
+ var vec = new Vector2(1, 0);
+ const float radians = 2 * MathF.PI;
+
+ var result = vec.Rotate(radians);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(result.X, Is.EqualTo(1).Within(1e-6));
+ Assert.That(result.Y, Is.EqualTo(0).Within(1e-6));
+ });
+ }
+
+ [Test]
+ public void Angle_VectorAt45Degrees_CorrectResult()
+ {
+ var vec = new Vector2(1, 1);
+
+ var result = vec.Angle();
+
+ Assert.That(result, Is.EqualTo(MathF.PI / 4).Within(1e-6));
+ }
+
+ [Test]
+ public void Angle_VectorAt90Degrees_CorrectResult()
+ {
+ var vec = new Vector2(0, 1);
+
+ var result = vec.Angle();
+
+ Assert.That(result, Is.EqualTo(MathF.PI / 2).Within(1e-6));
+ }
+
+ [Test]
+ public void Angle_VectorAtNegative45Degrees_CorrectResult()
+ {
+ var vec = new Vector2(1, -1);
+
+ var result = vec.Angle();
+
+ Assert.That(result, Is.EqualTo(-MathF.PI / 4).Within(1e-6));
+ }
+}
\ No newline at end of file
diff --git a/GdsSharp.Lib/Abstractions/GdsStreamOperator.cs b/GdsSharp.Lib/Abstractions/GdsStreamOperator.cs
index 6e92671..f1a15b5 100644
--- a/GdsSharp.Lib/Abstractions/GdsStreamOperator.cs
+++ b/GdsSharp.Lib/Abstractions/GdsStreamOperator.cs
@@ -3,7 +3,7 @@
using GdsSharp.Lib.Terminals.Abstractions;
using GdsSharp.Lib.Terminals.Records;
-namespace GdsSharp.Lib;
+namespace GdsSharp.Lib.Abstractions;
public class GdsStreamOperator
{
diff --git a/GdsSharp.Lib/Binary/GdsBinaryReader.cs b/GdsSharp.Lib/Binary/GdsBinaryReader.cs
index 2b203f1..7ece0b5 100644
--- a/GdsSharp.Lib/Binary/GdsBinaryReader.cs
+++ b/GdsSharp.Lib/Binary/GdsBinaryReader.cs
@@ -2,7 +2,7 @@
using System.Text;
using GdsSharp.Lib.Terminals;
-namespace GdsSharp.Lib;
+namespace GdsSharp.Lib.Binary;
public class GdsBinaryReader : BinaryReader
{
diff --git a/GdsSharp.Lib/Binary/GdsBinaryWriter.cs b/GdsSharp.Lib/Binary/GdsBinaryWriter.cs
index e585f9c..5475368 100644
--- a/GdsSharp.Lib/Binary/GdsBinaryWriter.cs
+++ b/GdsSharp.Lib/Binary/GdsBinaryWriter.cs
@@ -2,7 +2,7 @@
using System.Text;
using GdsSharp.Lib.Terminals;
-namespace GdsSharp.Lib;
+namespace GdsSharp.Lib.Binary;
public class GdsBinaryWriter : BinaryWriter
{
diff --git a/GdsSharp.Lib/Builders/BezierBuilder.cs b/GdsSharp.Lib/Builders/BezierBuilder.cs
index 7ee95aa..ff17132 100644
--- a/GdsSharp.Lib/Builders/BezierBuilder.cs
+++ b/GdsSharp.Lib/Builders/BezierBuilder.cs
@@ -147,7 +147,12 @@ public GdsElement BuildPolygon(int width, int numVertices = 64)
}
}
- private Vector2 Evaluate(float t)
+ ///
+ /// Evaluates the Bézier curve at a given t.
+ ///
+ /// [0,1]
+ /// Position on the curve at .
+ public Vector2 Evaluate(float t)
{
var n = _controlPoints.Count - 1;
var x = 0.0f;
@@ -162,7 +167,12 @@ private Vector2 Evaluate(float t)
return new Vector2(x, y);
}
- private Vector2 EvaluateTangent(float t)
+ ///
+ /// Evaluates the tangent of the Bézier curve at a given t.
+ ///
+ /// [0,1]
+ /// Tangent vector of the curve at .
+ public Vector2 EvaluateTangent(float t)
{
var n = _controlPoints.Count - 1;
var nMinusOne = n - 1;
diff --git a/GdsSharp.Lib/Builders/PathBuilder.cs b/GdsSharp.Lib/Builders/PathBuilder.cs
new file mode 100644
index 0000000..82f43b8
--- /dev/null
+++ b/GdsSharp.Lib/Builders/PathBuilder.cs
@@ -0,0 +1,220 @@
+using System.Numerics;
+using GdsSharp.Lib.NonTerminals;
+using GdsSharp.Lib.NonTerminals.Elements;
+using SoftCircuits.Collections;
+
+namespace GdsSharp.Lib.Builders;
+
+public class PathBuilder
+{
+ private readonly Vector2 _initialHeading;
+ private readonly Vector2 _initialPosition;
+ private readonly float _initialWidth;
+ private readonly List _pathSegments = new();
+
+ public PathBuilder(float initialWidth, Vector2? initialPosition = null, Vector2? initialHeading = null)
+ {
+ _initialWidth = initialWidth;
+ _initialPosition = initialPosition ?? Vector2.Zero;
+ _initialHeading = initialHeading ?? Vector2.UnitY;
+ }
+
+ ///
+ /// Adds a path segment to the path.
+ ///
+ /// Function that returns the coordinates of the path.
+ /// Function that returns derivative vectors of the path.
+ ///
+ /// Function that returns the width of the path. Can be null or return null, in this case the last
+ /// available width will be used.
+ ///
+ /// Number of vertices used for the path. The final mesh will have two times this amount.
+ public PathBuilder AddPathSegment(Func path, Func derivative, Func? width = null, int vertices = 10)
+ {
+ _pathSegments.Add(new PathSegment(path, derivative, width, vertices));
+ return this;
+ }
+
+ ///
+ /// Adds a straight segment to the path.
+ /// If is provided it takes precedence over and .
+ /// If only is provided the width will be interpolated between the previous width and
+ /// .
+ ///
+ /// Length of the segment.
+ /// (optional) Width at the start of the segment.
+ /// (optional) Width at the end of the segment.
+ /// (optional) Function that provides a width for t on the interval [0,1].
+ /// (optional) Number of vertices used for the path. Increase this if using .
+ public PathBuilder Straight(int length, float? widthStart = null, float? widthEnd = null, Func? width = null, int vertices = 2)
+ {
+ width ??= t => t < 0.5f ? widthStart : widthEnd;
+
+ return AddPathSegment(
+ t => new Vector2(0, t * length),
+ _ => new Vector2(0, 1),
+ width,
+ vertices);
+ }
+
+ ///
+ /// Adds a bend to the path.
+ ///
+ /// Angle of the bend in radians.
+ /// Radius of the bend.
+ /// (optional) Function that provides a width for t on the interval [0,1].
+ /// (optional) Number of vertices used for the path.
+ public PathBuilder BendRad(float angle, int radius, Func? width = null, int vertices = 128)
+ {
+ var sign = Math.Sign(angle);
+ angle = MathF.Abs(angle);
+ var phase = sign == -1 ? MathF.PI : 0;
+
+ return AddPathSegment(
+ t => new Vector2(
+ radius * (1 - MathF.Cos(t * angle)) * sign,
+ radius * MathF.Sin(t * angle)
+ ),
+ t => new Vector2(
+ angle * radius * MathF.Sin(t * angle + phase),
+ angle * radius * MathF.Cos(t * angle)
+ ),
+ t => width?.Invoke(t),
+ vertices);
+ }
+
+ ///
+ /// Adds a bend to the path.
+ ///
+ /// Angle of the bend in degrees.
+ /// Radius of the bend.
+ /// (optional) Function that provides a width for t on the interval [0,1].
+ /// (optional) Number of vertices used for the path.
+ public PathBuilder BendDeg(float angle, int radius, Func? width = null, int vertices = 128)
+ {
+ angle = MathF.PI * angle / 180;
+ return BendRad(angle, radius, width, vertices);
+ }
+
+ ///
+ /// Adds a Bézier curve to the path.
+ ///
+ /// Bézier builder where you can add control points.
+ /// (optional) Function that provides a width for t on the interval [0,1].
+ /// (optional) Number of vertices used for the path.
+ public PathBuilder Bezier(Action build, Func? width = null, int vertices = 128)
+ {
+ var builder = new BezierBuilder();
+ build(builder);
+
+ return AddPathSegment(
+ t => builder.Evaluate(t),
+ t => builder.EvaluateTangent(t), // It works like this without rotation for some reason
+ t => width?.Invoke(t),
+ vertices);
+ }
+
+ ///
+ /// Builds the path into a GdsElement.
+ ///
+ /// GdsBoundaryElement.
+ public GdsElement Build()
+ {
+ return new GdsElement
+ {
+ Element = new GdsBoundaryElement
+ {
+ Points = GetPolygonPoints().ToList()
+ }
+ };
+ }
+
+ ///
+ /// Builds a polygon from the path.
+ ///
+ ///
+ private IEnumerable GetPolygonPoints()
+ {
+ var segments = GetPathPoints();
+
+ List meshUp = new();
+ List meshDown = new();
+
+ foreach (var (_, points) in segments)
+ foreach (var (point, normal, width) in points)
+ {
+ meshUp.Add(new GdsPoint(point + normal * width / 2));
+ meshDown.Insert(0, new GdsPoint(point - normal * width / 2));
+ }
+
+ return meshUp.Concat(meshDown);
+ }
+
+ ///
+ /// Generates a list of points for each segment in the path.
+ ///
+ /// List of points per segment.
+ private OrderedDictionary> GetPathPoints()
+ {
+ var points = new OrderedDictionary>();
+ var position = _initialPosition;
+ var heading = _initialHeading;
+ var currentWidth = _initialWidth;
+
+ foreach (var segment in _pathSegments)
+ {
+ var segmentPoints = new List();
+
+ Vector2? lastPosition = null;
+ Vector2? lastHeading = null;
+
+ for (var i = 0; i <= segment.Vertices; i++)
+ {
+ var t = i / (float)segment.Vertices;
+
+ // Get data from this point
+ var point = segment.Path(t);
+ var derivative = Vector2.Normalize(segment.Derivative(t));
+ var width = segment.Width?.Invoke(t);
+
+ // Correct the point and derivative for the heading
+ var rotationAngle = Vector2.UnitY.Angle() - heading.Angle();
+ point = point.Rotate(-rotationAngle);
+ derivative = derivative.Rotate(-rotationAngle);
+
+ lastHeading = derivative;
+ lastPosition = point;
+ currentWidth = width ?? currentWidth;
+
+ var normal = new Vector2(-derivative.Y, derivative.X);
+ segmentPoints.Add(new PathPoint(point + position, normal, currentWidth));
+ }
+
+ if (lastPosition.HasValue)
+ position += lastPosition.Value;
+ if (lastHeading.HasValue)
+ heading = lastHeading.Value;
+
+ points.Add(segment, segmentPoints);
+ }
+
+ return points;
+ }
+
+ ///
+ /// Represents a path segment.
+ ///
+ /// Function that defines the path of the segment.
+ /// Function that defines the derivative of the segment.
+ /// Function that defines the width of the segment.
+ /// Number of vertices of the segment.
+ private record struct PathSegment(Func Path, Func Derivative, Func? Width, int Vertices);
+
+ ///
+ /// Represents a single point in the path.
+ ///
+ /// The coordinates of the point.
+ /// The normal of the point.
+ /// The width at the point.
+ private record struct PathPoint(Vector2 Point, Vector2 Normal, float Width);
+}
\ No newline at end of file
diff --git a/GdsSharp.Lib/Extensions.cs b/GdsSharp.Lib/Extensions.cs
index aa3b722..96e7bed 100644
--- a/GdsSharp.Lib/Extensions.cs
+++ b/GdsSharp.Lib/Extensions.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.NonTerminals;
+using System.Numerics;
+using GdsSharp.Lib.NonTerminals;
namespace GdsSharp.Lib;
@@ -13,4 +14,27 @@ public static List AsGdsPoints(this List<(int x, int y)> coordinates)
{
return coordinates.ConvertAll(c => (c.X, c.Y));
}
+
+ ///
+ /// Rotates a vector by the given angle in radians.
+ ///
+ /// Vector to rotate.
+ /// Angle to rotate by.
+ /// Rotated vector.
+ public static Vector2 Rotate(this Vector2 vec, float radians)
+ {
+ var ca = MathF.Cos(radians);
+ var sa = MathF.Sin(radians);
+ return new Vector2(ca * vec.X - sa * vec.Y, sa * vec.X + ca * vec.Y);
+ }
+
+ ///
+ /// Gets the angle of a vector in radians.
+ ///
+ /// Vector.
+ /// Angle of the vector in radians.
+ public static float Angle(this Vector2 vec)
+ {
+ return MathF.Atan2(vec.Y, vec.X);
+ }
}
\ No newline at end of file
diff --git a/GdsSharp.Lib/GdsParser.cs b/GdsSharp.Lib/GdsParser.cs
index db1820c..bd280f4 100644
--- a/GdsSharp.Lib/GdsParser.cs
+++ b/GdsSharp.Lib/GdsParser.cs
@@ -1,5 +1,5 @@
-using GdsSharp.Lib.Abstractions;
-using GdsSharp.Lib.NonTerminals;
+using GdsSharp.Lib.NonTerminals;
+using GdsSharp.Lib.NonTerminals.Abstractions;
using GdsSharp.Lib.NonTerminals.Elements;
using GdsSharp.Lib.NonTerminals.Enum;
using GdsSharp.Lib.Terminals.Abstractions;
diff --git a/GdsSharp.Lib/GdsSharp.Lib.csproj b/GdsSharp.Lib/GdsSharp.Lib.csproj
index 4ec294c..b0ca84d 100644
--- a/GdsSharp.Lib/GdsSharp.Lib.csproj
+++ b/GdsSharp.Lib/GdsSharp.Lib.csproj
@@ -29,4 +29,8 @@
+
+
+
+
diff --git a/GdsSharp.Lib/GdsTokenWriter.cs b/GdsSharp.Lib/GdsTokenWriter.cs
index ae03fcd..9d83c54 100644
--- a/GdsSharp.Lib/GdsTokenWriter.cs
+++ b/GdsSharp.Lib/GdsTokenWriter.cs
@@ -1,5 +1,5 @@
-using GdsSharp.Lib.Abstractions;
-using GdsSharp.Lib.NonTerminals;
+using GdsSharp.Lib.NonTerminals;
+using GdsSharp.Lib.NonTerminals.Abstractions;
using GdsSharp.Lib.NonTerminals.Elements;
using GdsSharp.Lib.NonTerminals.Enum;
using GdsSharp.Lib.Terminals.Abstractions;
diff --git a/GdsSharp.Lib/GdsTokenizer.cs b/GdsSharp.Lib/GdsTokenizer.cs
index 976c8b3..568f968 100644
--- a/GdsSharp.Lib/GdsTokenizer.cs
+++ b/GdsSharp.Lib/GdsTokenizer.cs
@@ -1,4 +1,6 @@
-using GdsSharp.Lib.Terminals;
+using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals;
using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib;
diff --git a/GdsSharp.Lib/GdsWriter.cs b/GdsSharp.Lib/GdsWriter.cs
index 378acfc..830e68f 100644
--- a/GdsSharp.Lib/GdsWriter.cs
+++ b/GdsSharp.Lib/GdsWriter.cs
@@ -1,3 +1,5 @@
+using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.Binary;
using GdsSharp.Lib.Terminals;
using GdsSharp.Lib.Terminals.Abstractions;
diff --git a/GdsSharp.Lib/NonTerminals/Abstractions/IGdsElement.cs b/GdsSharp.Lib/NonTerminals/Abstractions/IGdsElement.cs
index 0888081..10e5f28 100644
--- a/GdsSharp.Lib/NonTerminals/Abstractions/IGdsElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Abstractions/IGdsElement.cs
@@ -1,4 +1,4 @@
-namespace GdsSharp.Lib.Abstractions;
+namespace GdsSharp.Lib.NonTerminals.Abstractions;
public interface IGdsElement
{
diff --git a/GdsSharp.Lib/NonTerminals/Abstractions/IGdsLayeredElement.cs b/GdsSharp.Lib/NonTerminals/Abstractions/IGdsLayeredElement.cs
index a2508f8..4acabc7 100644
--- a/GdsSharp.Lib/NonTerminals/Abstractions/IGdsLayeredElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Abstractions/IGdsLayeredElement.cs
@@ -1,4 +1,4 @@
-namespace GdsSharp.Lib.Abstractions;
+namespace GdsSharp.Lib.NonTerminals.Abstractions;
public interface IGdsLayeredElement : IGdsElement
{
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsArrayReferenceElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsArrayReferenceElement.cs
index 2c4f376..fb0baf2 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsArrayReferenceElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsArrayReferenceElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsBoundaryElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsBoundaryElement.cs
index 352f82e..fc38f88 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsBoundaryElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsBoundaryElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsBoxElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsBoxElement.cs
index f92fcaf..ce8e6d6 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsBoxElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsBoxElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsElement.cs
index 95817ab..65af966 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsNodeElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsNodeElement.cs
index 76c5484..ae645d2 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsNodeElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsNodeElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsPathElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsPathElement.cs
index bee0196..158a479 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsPathElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsPathElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
using GdsSharp.Lib.NonTerminals.Enum;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsStructureReferenceElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsStructureReferenceElement.cs
index 3102e81..8bd2bf0 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsStructureReferenceElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsStructureReferenceElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/NonTerminals/Elements/GdsTextElement.cs b/GdsSharp.Lib/NonTerminals/Elements/GdsTextElement.cs
index 82512fc..23325cf 100644
--- a/GdsSharp.Lib/NonTerminals/Elements/GdsTextElement.cs
+++ b/GdsSharp.Lib/NonTerminals/Elements/GdsTextElement.cs
@@ -1,4 +1,4 @@
-using GdsSharp.Lib.Abstractions;
+using GdsSharp.Lib.NonTerminals.Abstractions;
using GdsSharp.Lib.NonTerminals.Enum;
namespace GdsSharp.Lib.NonTerminals.Elements;
diff --git a/GdsSharp.Lib/Terminals/Abstractions/IGdsReadableRecord.cs b/GdsSharp.Lib/Terminals/Abstractions/IGdsReadableRecord.cs
index e820ee6..aa836c2 100644
--- a/GdsSharp.Lib/Terminals/Abstractions/IGdsReadableRecord.cs
+++ b/GdsSharp.Lib/Terminals/Abstractions/IGdsReadableRecord.cs
@@ -1,3 +1,5 @@
+using GdsSharp.Lib.Binary;
+
namespace GdsSharp.Lib.Terminals.Abstractions;
public interface IGdsReadableRecord : IGdsRecord
diff --git a/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleRead.cs b/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleRead.cs
index c665783..6dc935e 100644
--- a/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleRead.cs
+++ b/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleRead.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using GdsSharp.Lib.Binary;
namespace GdsSharp.Lib.Terminals.Abstractions;
diff --git a/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleWrite.cs b/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleWrite.cs
index eb7daf9..3d63141 100644
--- a/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleWrite.cs
+++ b/GdsSharp.Lib/Terminals/Abstractions/IGdsSimpleWrite.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using GdsSharp.Lib.Binary;
namespace GdsSharp.Lib.Terminals.Abstractions;
diff --git a/GdsSharp.Lib/Terminals/Abstractions/IGdsWriteableRecord.cs b/GdsSharp.Lib/Terminals/Abstractions/IGdsWriteableRecord.cs
index 7b54ada..04187f4 100644
--- a/GdsSharp.Lib/Terminals/Abstractions/IGdsWriteableRecord.cs
+++ b/GdsSharp.Lib/Terminals/Abstractions/IGdsWriteableRecord.cs
@@ -1,3 +1,5 @@
+using GdsSharp.Lib.Binary;
+
namespace GdsSharp.Lib.Terminals.Abstractions;
public interface IGdsWriteableRecord : IGdsRecord
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordElFlags.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordElFlags.cs
index 88d40f6..11fa714 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordElFlags.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordElFlags.cs
@@ -1,3 +1,4 @@
+using GdsSharp.Lib.Binary;
using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordFonts.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordFonts.cs
index d0b4e75..af47399 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordFonts.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordFonts.cs
@@ -1,3 +1,4 @@
+using GdsSharp.Lib.Binary;
using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordNoData.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordNoData.cs
index 986bf87..e4030ed 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordNoData.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordNoData.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Terminals.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordPresentation.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordPresentation.cs
index 23c393f..545df40 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordPresentation.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordPresentation.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Terminals.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordRefLibs.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordRefLibs.cs
index 43f6865..d89a9b9 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordRefLibs.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordRefLibs.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Terminals.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordSTrans.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordSTrans.cs
index 1062f36..6a4dafa 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordSTrans.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordSTrans.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Terminals.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/GdsSharp.Lib/Terminals/Records/GdsRecordXy.cs b/GdsSharp.Lib/Terminals/Records/GdsRecordXy.cs
index 18958b8..304b73e 100644
--- a/GdsSharp.Lib/Terminals/Records/GdsRecordXy.cs
+++ b/GdsSharp.Lib/Terminals/Records/GdsRecordXy.cs
@@ -1,4 +1,5 @@
-using GdsSharp.Lib.Terminals.Abstractions;
+using GdsSharp.Lib.Binary;
+using GdsSharp.Lib.Terminals.Abstractions;
namespace GdsSharp.Lib.Terminals.Records;
diff --git a/README.md b/README.md
index 742e459..bee9432 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,8 @@
[![NuGet](https://img.shields.io/nuget/v/GdsSharp.svg)](https://www.nuget.org/packages/GdsSharp/)\
A library for reading, editing, and writing [Calma GDSII](https://en.wikipedia.org/wiki/GDSII) files.
-Some helpers are also provided for drawing curves like circles and Bézier curves.
+Some helpers are also provided for drawing shapes like circles and Bézier curves.
+Additionally, a path builder is included to create parameterized paths with multiple segments.
## Usage
@@ -26,7 +27,7 @@ file.WriteTo(fileStream);
An example of how to create a GDS file from scratch and creating some shapes using the helpers can be found in
the [example project](https://github.com/BorisGerretzen/GdsSharp/blob/master/GdsGenerator/Program.cs).
This is the created GDS file:
-![image](https://github.com/user-attachments/assets/0e0e524f-129d-433f-b560-626846b6e991)
+![image](https://github.com/user-attachments/assets/6629195b-64e3-4778-87e7-d8cae87826d7)
## Helpers
@@ -70,6 +71,49 @@ var elemLine = new BezierBuilder()
.BuildLine(width: 200, numVertices: 128);
```
+### Path builder
+
+GdsSharp also includes a path builder that can be used to create paths with multiple segments.
+The output of this code can be seen on the bottom part of the picture above.
+
+```csharp
+// Use the path builder to create a path
+new PathBuilder(
+ initialWidth: 100f,
+ initialPosition: new Vector2(-3100, -3300),
+ initialHeading: Vector2.UnitX)
+ // Straight ahead for 2000 units
+ .Straight(2000)
+
+ // Bend 45 degrees to the left with a radius of 500 units
+ .BendDeg(-45, 500)
+
+ // Generate shape like <=>
+ .Straight(100, widthEnd: 250)
+ .Straight(100)
+ .Straight(100, widthEnd: 100)
+
+ // Some more bends
+ .BendDeg(-45, 500)
+ .Straight(100)
+ .Straight(200, widthStart: 250)
+ .BendDeg(180, 300)
+ .BendDeg(-180, 300)
+
+ // Example of using a function to change the width
+ .BendDeg(-180, 900, f => MathF.Cos(f * 50) * 100 + 150)
+
+ // PathBuilder also supports Bézier curves
+ .Bezier(b => b
+ .AddPoint(0, 0)
+ .AddPoint(0,1000)
+ .AddPoint(2000, 1000)
+ .AddPoint(1000, 0),
+ width: t => 250 - (250-50) * t)
+ .Straight(800)
+ .Build();
+```
+
## Missing features
I have not implemented all features of the GDSii spec, some terminals
diff --git a/build/Build.cs b/build/Build.cs
index 12eb3e5..dd49c08 100644
--- a/build/Build.cs
+++ b/build/Build.cs
@@ -134,7 +134,13 @@ from framework in project.GetTargetFrameworks()
.SetTargetPath(v)
)
);
- Git($"push --set-upstream origin {PackageVersion ?? GitVersion.NuGetVersionV2}");
+
+ var version = PackageVersion ?? GitVersion.NuGetVersionV2;
+
+ Git("config --global user.email \"<>\"");
+ Git("config --global user.name \"GitHub Actions\"");
+ Git($"tag -a {version} -m \"Created release '{version}'\"");
+ Git($"push --tags");
});
public static int Main() => Execute(x => x.Test);