DSL

Shape Primitives

The built-in shapes of the laylight DSL, their parameters and variants, and their counterparts in gdsfactory, gdstk, Luceda IPKISS and Nazca.

Every piece of geometry in a laylight cell is a shape: a primitive with arguments, defined inside a layer block and placed once.

cell Demo {
    layer si {
        shape rect with width = 10um, height = 500nm as core   # named arguments
        shape rect with 10um, 500nm as copy                     # the same, positional
        place core.left_center at self.origin
        place copy.bottom_left at core.top_left offset (0, 1um)
    }
}

The primitive set is the union of the geometric primitives of gdsfactory, gdstk, Luceda IPKISS and Nazca Design. Where those tools offer several functions for closely related shapes (a rectangle, a rounded rectangle, a rectangular frame), laylight has one primitive with optional parameters. The reference at the end maps every function of the four tools to its laylight form.

The examples on this page are the bodies of a layer block. Each one is compiled in your browser; the drawing next to it is the result, and + marks the shape's local origin.

Conventions

Arguments. Arguments can be positional, in the order of the signatures below, or named (key = value). Parameters marked ? are optional. Lengths need a unit (500nm, 2um), angles too (90deg); the literal 0 works as any zero. String options such as ends and profile are checked while you type when you write them as literals.

Local coordinates and anchors. Each primitive is defined in its own coordinate system, described per primitive below. Every shape has the anchors origin, center, left_center, right_center, top_center, bottom_center, bottom_left, bottom_right, top_left and top_right (from its bounding box, all pointing along +x), and the sizes width and height. Waveguide primitives also have start and end: frames whose direction is the tangent of the waveguide there, pointing downstream, so place b.start at a.end chains two pieces.

Curves. Curved outlines are written as polygons. segments sets the number of straight segments of each curved part: the whole circle or arc, each rounded corner, each half circle of a racetrack, each rounded path corner, the whole Euler, S-bend or Bézier curve, or each edge of a curved taper. Without it, the segment count follows from a chord error of at most 1 DBU (1 nm by default), with at most 45° per segment on circles; free-form curves are sampled more densely where they bend more.

Shared variants. Closed shapes take corner_radius, which rounds the corners, and line_width, which draws the boundary as a line of that width centered on it, as one polygon. Circles and ellipses take angle and start_angle for sectors (positive angles are counter-clockwise).

Closed shapes

rect

rect(width, height, corner_radius?, line_width?, segments?)

A rectangle centered at the origin. It stays a GDS box under right-angle placements.

ParameterTypeDefaultMeaning
width, heightsizerequiredSize along x and y.
corner_radiussize0Radius of the rounded corners, at most half the shorter side; half the shorter side gives a stadium.
line_widthsize—Draw a frame of this width centered on the outline instead of a filled rectangle.
segmentsintegerautoSegments per rounded corner.
shape rect with 12um, 6um as box
place box at (0, 0)
Compiling…
shape rect with 12um, 6um, corner_radius = 2um as rounded
shape rect with 12um, 6um, corner_radius = 3um as stadium
shape rect with 12um, 6um, corner_radius = 1um, line_width = 1um as frame
place rounded at (0, 0)
place stadium at (0, -9um)
place frame at (0, -18um)
Compiling…

To give a rectangle by two corners (x1, y1) and (x2, y2), place its corner anchor: shape rect with x2 - x1, y2 - y1 as r and place r.bottom_left at (x1, y1).

polygon

polygon(points, corner_radius?, line_width?, segments?)

A polygon through points (at least 3), in local coordinates.

ParameterTypeDefaultMeaning
points[point]requiredThe vertices.
corner_radiussize0Round every corner. Where the adjacent edges are too short, that corner's radius is reduced so that the arcs never pass the middle of an edge.
line_widthsize—Draw the outline as a line of this width centered on the boundary, with mitered corners.
segmentsintegerautoSegments per rounded corner.
shape polygon with [(0, 0), (14um, 0), (4um, 10um)] as plain
shape polygon with [(0, 0), (14um, 0), (4um, 10um)], corner_radius = 2um as rounded
shape polygon with [(0, 0), (14um, 0), (4um, 10um)], line_width = 800nm as outline
place plain at (0, 0)
place rounded at (18um, 0)
place outline at (36um, 0)
Compiling…

Points can be computed in a loop, which covers parametric shapes that have no primitive of their own:

define star: [point] = []
for i in 0..10 {
    define r = 6um - 3um * (i % 2)
    star.append((r * cos(i * 36deg + 90deg), r * sin(i * 36deg + 90deg)))
}
shape polygon with star as s
place s at (0, 0)
Compiling…

regular_polygon

regular_polygon(sides, radius?, side_length?, rotation?, corner_radius?, line_width?, segments?)

A regular polygon centered at the origin. Give either the circumradius radius or the side_length, not both. Unrotated, the bottom edge is horizontal: vertex k sits at −90° + 180°/n + k·360°/n. So an unrotated square is axis-aligned and a triangle points up.

ParameterTypeDefaultMeaning
sidesintegerrequiredNumber of sides, 3 to 4096.
radiussize—Circumradius.
side_lengthsize—Edge length; the circumradius is side_length / (2 sin(180°/n)).
rotationangle0Counter-clockwise rotation about the center.
corner_radius, line_width, segmentsAs for polygon.
shape regular_polygon with 3, radius = 5um as triangle
shape regular_polygon with 6, side_length = 5um as hexagon
shape regular_polygon with 8, radius = 5um, rotation = 22.5deg, line_width = 1um as octagon
shape regular_polygon with 5, radius = 5um, corner_radius = 1um as pentagon
place triangle at (0, 0)
place hexagon at (12um, 0)
place octagon at (24um, 0)
place pentagon at (36um, 0)
Compiling…

circle

circle(radius, segments?, angle?, start_angle?)

A disk centered at the origin, or with angle a sector (a pie slice, including the center) that starts at start_angle and sweeps angle counter-clockwise; negative angles sweep clockwise.

ParameterTypeDefaultMeaning
radiussizerequiredRadius.
segmentsintegerautoSegments of the circle or of the sector's arc.
angleangle360degSweep of a sector, non-zero and at most 360°.
start_angleangle0Where the sector (or the vertex list of a full circle) starts.
shape circle with 5um as disk
shape circle with 5um, angle = 270deg, start_angle = 45deg as pie
shape circle with 5um, angle = 60deg as slice
place disk at (0, 0)
place pie at (13um, 0)
place slice at (22um, -3um)
Compiling…

ellipse

ellipse(rx, ry, segments?, angle?, start_angle?, line_width?)

An ellipse centered at the origin with semi-axes rx along x and ry along y. Sector angles are polar angles, as in gdstk: angle = 90deg covers exactly the first quadrant.

ParameterTypeDefaultMeaning
rx, rysizerequiredSemi-axes.
segmentsintegerautoSegments of the ellipse or of the sector's arc.
angle, start_angleanglefull, 0Sector, as for circle.
line_widthsize—Draw the curve as a line of this width, offset along the normal. A full ellipse gives a closed outline; with angle, an elliptical arc band. Half the width must be less than the smallest radius of curvature, min(rx, ry)² / max(rx, ry).
shape ellipse with 8um, 4um as oval
shape ellipse with 8um, 4um, angle = 90deg as quadrant
shape ellipse with 8um, 4um, line_width = 800nm as outline
shape ellipse with 8um, 4um, angle = 180deg, line_width = 800nm as arch
place oval at (0, 0)
place quadrant at (12um, -2um)
place outline at (0, -11um)
place arch at (20um, -11um)
Compiling…

ring

ring(radius, width, segments?, angle?, start_angle?)

An annulus centered at the origin. radius is the centerline radius, as in gdsfactory: the ring spans radius ± width/2. A full ring is one polygon with a zero-width cut at start_angle; with angle it is an annular sector.

ParameterTypeDefaultMeaning
radiussizerequiredCenterline radius.
widthsizerequiredRing width, less than 2 · radius.
segmentsintegerautoSegments of the (outer) circle or arc.
angle, start_angleanglefull, 0Annular sector, as for circle.
shape ring with 5um, 1um as full
shape ring with 5um, 2um, angle = 120deg, start_angle = 30deg as segment
place full at (0, 0)
place segment at (13um, -3um)
Compiling…

racetrack

racetrack(radius, length, width, segments?)

A closed waveguide loop centered at the origin: two half circles of centerline radius joined by straight sections of length along x, drawn with width. The zero-width cut is at the middle of the bottom straight. length = 0 gives a ring.

ParameterTypeDefaultMeaning
radiussizerequiredCenterline radius of the bends.
lengthsizerequiredLength of each straight section (may be 0).
widthsizerequiredWaveguide width, less than 2 · radius.
segmentsintegerautoSegments per half circle.
shape racetrack with 5um, 10um, 1um as track
place track at (0, 0)
Compiling…

A filled racetrack (a stadium) is a rect whose corner_radius is half its height.

cross

cross(length, arm_width)

A plus sign centered at the origin: two arms of arm_width, each length long from tip to tip, as one 12-vertex polygon.

shape cross with 10um, 3um as plus
place plus at (0, 0)
Compiling…

trapezoid

trapezoid(width, height, top_width, offset?)

A trapezoid height tall, centered on y = 0. The bottom edge is width long and centered on x = 0; the top edge is top_width long and centered on x = offset. A top_width of 0 gives a triangle; a top_width equal to width with an offset gives a parallelogram.

ParameterTypeDefaultMeaning
widthsizerequiredBottom edge.
heightsizerequiredHeight.
top_widthsizerequiredTop edge (0 for a triangle).
offsetsize0Shift of the top edge's center along x.
shape trapezoid with 10um, 6um, 4um as trapezoid
shape trapezoid with 10um, 6um, 0 as triangle
shape trapezoid with 10um, 6um, 10um, offset = 3um as parallelogram
shape trapezoid with 10um, 6um, 0, offset = -5um as right_triangle
place trapezoid at (0, 0)
place triangle at (13um, 0)
place parallelogram at (27um, 0)
place right_triangle at (42um, 0)
Compiling…

Shapes described by base angles convert directly. Nazca's trapezoid(length, height, angle1, angle2) is trapezoid with length, height, length - height / tan(angle1) - height / tan(angle2), offset = (height / tan(angle1) - height / tan(angle2)) / 2, and a parallelogram with base angle a has offset = height / tan(a).

Waveguides and paths

All of these have the start and end anchors.

path

path(points, width, ends?, bend_radius?, segments?)

A polyline of width through points. The start and end anchors are at the first and last points, facing along the first and last segments.

ParameterTypeDefaultMeaning
points[point]requiredThe vertices (at least 2).
widthsizerequiredLine width.
endsstring"flush""flush" ends at the points (GDS path type 0); "square" extends each end by half the width (path type 2); "round" closes the ends with half circles and is written as a polygon.
bend_radiussize—Replace every corner by a circular arc of this radius. The arcs must fit: at each segment, the tangent lengths of its two corners must not add up to more than its length.
segmentsintegerautoSegments per rounded corner or round end.
shape path with [(0, 0), (8um, 0), (8um, 6um)], 1um as flush
shape path with [(0, 0), (8um, 0), (8um, 6um)], 1um, ends = "square" as square
shape path with [(0, 0), (8um, 0), (8um, 6um)], 1um, ends = "round" as round
place flush at (0, 0)
place square at (12um, 0)
place round at (24um, 0)
Compiling…
shape path with [(0, 0), (10um, 0), (10um, 10um), (20um, 10um)], 1um, bend_radius = 4um as route
place route at (0, 0)
Compiling…

Joins are mitered, as in GDS. L- and C-shaped outlines (gdsfactory's L and C) are flush paths through the arm centerlines.

arc

arc(radius, width, angle, segments?)

A circular bend that starts at the origin heading +x, with its center of curvature at (0, radius) for positive angles: positive angles turn left, negative angles turn right. end lies at (radius · sin angle, radius · (1 − cos angle)).

ParameterTypeDefaultMeaning
radiussizerequiredCenterline radius, more than width / 2.
widthsizerequiredWaveguide width.
angleanglerequiredTurn, non-zero and at most 360°.
segmentsintegerautoSegments of the bend.
shape arc with 8um, 1um, 90deg as left
shape arc with 8um, 1um, -45deg as right
place left.start at (0, 0)
place right.start at (12um, 0)
Compiling…

euler

euler(radius?, width, angle, p?, segments?, min_radius?)

An Euler bend: from the origin heading +x, the curvature grows linearly with arc length (a clothoid), stays constant through a circular section, and falls back to zero. The ends therefore join straight waveguides without a curvature jump. p is the fraction of the turn spent in the two clothoids; p = 1 is a pure Euler bend, p = 0 the circular arc.

Give the size in one of two ways:

  • radius: the effective radius. The bend ends exactly where an arc of that radius would, so the two are drop-in replacements. This is gdsfactory's bend_euler default (with_arc_floorplan=True).
  • min_radius: the smallest radius of curvature, reached in the circular section. This is IPKISS's default and gdsfactory's with_arc_floorplan=False. For a 90° bend with p = 1, the effective radius is 1.8701 times the minimum radius.
ParameterTypeDefaultMeaning
radiussize—Effective radius.
widthsizerequiredWaveguide width; half of it must be less than the minimum radius.
angleanglerequiredTurn, non-zero and less than 360°; positive turns left.
pnumber0.5Euler fraction, from 0 to 1.
segmentsintegerautoSegments of the bend (auto: denser where it bends more).
min_radiussize—Minimum radius of curvature.
shape arc with 10um, 800nm, 90deg as circular
shape euler with 10um, 800nm, 90deg as half
shape euler with 10um, 800nm, 90deg, p = 1 as full
place circular.start at (0, 0)
place half.start at (0, 0)
place full.start at (0, 0)
Compiling…

The three bends above share their end points; the Euler bends swing further into the corner.

sbend

sbend(length, offset, width, profile?, segments?)

An S-bend from the origin heading +x to (length, offset), level at both ends. Positive offsets go to the left. With t = x / length and H = offset, the profiles are:

profileCenterlineNotes
"bezier" (default)Cubic Bézier with control points (0, 0), (L/2, 0), (L/2, H), (L, H)gdsfactory's bend_s.
"sine"y = H · (t − sin(2πt) / 2π)Zero curvature at both ends; Nazca's sinebend.
"cosine"y = H · (1 − cos(πt)) / 2Raised cosine.
"circular"Two opposite circular arcs of equal radiusEach arc turns A = 2·atan(H/L) with radius L / (2 sin A); no straight section.

The radius of curvature must stay above half the width; a bend that is too short for its offset is an error.

shape sbend with 20um, 6um, 800nm as bezier
shape sbend with 20um, 6um, 800nm, profile = "sine" as sine
shape sbend with 20um, 6um, 800nm, profile = "cosine" as cosine
shape sbend with 20um, 6um, 800nm, profile = "circular" as circular
place bezier.start at (0, 0)
place sine.start at (0, -4um)
place cosine.start at (0, -8um)
place circular.start at (0, -12um)
Compiling…

bezier

bezier(points, width, segments?)

A waveguide of width along the Bézier curve with control points points, of any degree (2 points is a straight line, 3 a quadratic, 4 a cubic curve). The curve passes through the first and last points; start and end face along the first and last distinct control-point directions.

shape bezier with [(0, 0), (12um, 0), (0, 12um), (12um, 12um)], 1um as cubic
shape bezier with [(0, 0), (10um, 10um), (20um, 0)], 1um as quadratic
place cubic.start at (0, 0)
place quadratic.start at (18um, 0)
Compiling…

taper

taper(length, width1, width2, profile?, segments?)

A width transition from width1 at x = 0 to width2 at x = length, symmetric about the x axis. start is at the origin and end at (length, 0), both facing +x.

profileWidth at t = x / lengthNotes
"linear" (default)w1 + (w2 − w1) · tA trapezoid.
"parabolic"√(w1² + (w2² − w1²) · t)The square of the width changes linearly (the classic adiabatic taper). The same law as IPKISS's ParabolicWedge and Nazca's ptaper.
"exponential"w1 · (w2 / w1)^tConstant relative change of width per length.
shape taper with 16um, 1um, 6um as linear
shape taper with 16um, 1um, 6um, profile = "parabolic" as parabolic
shape taper with 16um, 1um, 6um, profile = "exponential" as exponential
place linear.start at (0, 0)
place parabolic.start at (0, -8um)
place exponential.start at (0, -16um)
Compiling…

gdsfactory's taper_parabolic uses another law, w1 + (w2 − w1) · t^0.5 (its exp parameter); write that as a polygon from a loop if you need it exactly.

Text

text

text(text, size)

Polygon text in a built-in 5×7 pixel font: printable ASCII and \n for new lines. size is the height of a capital letter (7 pixels). Characters advance by 6 pixels, lines by 11, and descenders reach 2 pixels below the baseline. The origin is at the start of the first line's baseline. Each run of pixels is written as a GDS box.

shape text with "laylight\nDSL 0.1", 3500nm as label
place label at (0, 0)
Compiling…

Align text with its anchors, for example place label.top_center at device.bottom_center offset (0, -2um). Text that should not be fabricated belongs in a marker, which is written as a GDS TEXT on the marker layer.

Recipes

Some shapes of the other tools are compositions rather than primitives:

  • Spiral. Compute the centerline in a loop and draw it with path. An Archimedean spiral (gdsfactory's spiral_archimedean):
define turns: [point] = []
for i in 0..200 {
    define a = i * 9deg
    define r = 2um + 1500nm * i * 9 / 360
    turns.append((r * cos(a), r * sin(a)))
}
shape path with turns, 500nm as spiral
place spiral.start at (0, 0)
Compiling…
  • Parametric curves (gdstk's parametric, Curve): the same pattern, feeding the points to polygon, path or bezier.
  • L, C and die frames: flush paths, or rect with line_width.
  • Rectangle from two corners: size the rect from the corners and place its bottom_left.
  • Boolean operations and offsets (gdstk's boolean and offset, KLayout regions) are derived shapes; see Boolean and Morphological Operations.

Reference: equivalents in other tools

One table per tool maps its shape functions to the laylight primitive and the arguments that give the same geometry. Versions: gdsfactory 9, gdstk 0.9, Luceda IPKISS 3 (import ipkiss3.all as i3) and Nazca Design 0.6 (nazca.geometries as geom, interconnects as ic). width in the laylight column is the waveguide width, which the other tools often take from a cross-section. A dash means laylight has no counterpart yet.

gdsfactory

gdsfactorylaylight
rectangle(size=(w, h), centered=True), compass(size)rect with w, h. The default centered=False puts the lower-left corner at the origin: place bottom_left.
rounded_rectangle(width, height, corner_radius_x)rect with width, height, corner_radius = corner_radius_x (circular corners only)
circle(radius)circle with radius
ellipse(radii=(rx, ry))ellipse with rx, ry
ring(radius, width, angle)ring with radius, width, angle = angle
regular_polygon(sides, side_length), hexagon, octagonregular_polygon with sides, side_length = side_length; add rotation = 180deg for odd sides (gdsfactory's flat edge is on top)
triangle(x, xtop, y)trapezoid with x, y, xtop, offset = (xtop - x) / 2
ramp(length, width1, width2)polygon with [(0, width1), (length, width2), (length, 0), (0, 0)]
cross(length, width)cross with length, width
L(width, size), C(width, size)a flush path through the arm centerlines
straight(length)rect with length, width
taper(length, width1, width2)taper with length, width1, width2
taper_parabolic(length, width1, width2, exp)a polygon from a loop; it is not profile = "parabolic" (see below)
bend_circular(radius, angle), gf.path.arcarc with radius, width, angle
bend_euler(radius, angle, p)euler with radius, width, angle, p = p
bend_euler(..., with_arc_floorplan=False), gf.path.euler(radius, angle, p)euler with min_radius = radius, width = width, angle = angle, p = p
bend_s(size=(dx, dy))sbend with dx, dy, width
bezier(control_points)bezier with control_points, width
gf.path.smooth(points, radius, bend=gf.path.arc)path with points, width, bend_radius = radius
gf.path.spiral_archimedean(...)the spiral recipe
text(text, size)text with text, size
text_rectangular(text, size)text with text, 7 * size (same pixel size, different glyphs)
Component.add_polygon(points, layer)polygon with points in the layer's block
Component.add_label(text)a marker

gdstk

gdstk angles are radians; laylight angles carry a unit, so write a * 1rad or convert to degrees.

gdstklaylight
rectangle(corner1, corner2)rect sized from the corners, placed by bottom_left
Polygon(points)polygon with points
Polygon.fillet(radius)polygon with points, corner_radius = radius (the same reduction on short edges)
regular_polygon(center, side_length, sides, rotation)regular_polygon with sides, side_length = side_length, rotation = rotation
ellipse(center, r)circle with r
ellipse(center, (rx, ry))ellipse with rx, ry
ellipse(center, r, initial_angle=a0, final_angle=a1)circle with r, angle = a1 - a0, start_angle = a0 (also for (rx, ry) with ellipse)
ellipse(center, ro, inner_radius=ri)ring with (ro + ri) / 2, ro - ri
ellipse(center, ro, inner_radius=ri, initial_angle=a0, final_angle=a1)ring with (ro + ri) / 2, ro - ri, angle = a1 - a0, start_angle = a0
racetrack(center, straight_length, radius, inner_radius)racetrack with (radius + inner_radius) / 2, straight_length, radius - inner_radius
racetrack(center, straight_length, radius)rect with straight_length + 2 * radius, 2 * radius, corner_radius = radius
cross(center, full_size, arm_width)cross with full_size, arm_width
text(text, size, position)text with text, 0.75 * size (about the same capital height, different glyphs)
FlexPath(points, width)path with points, width
FlexPath(..., ends="extended"), ends="round"path with ..., ends = "square", ends = "round"
FlexPath(..., bend_radius=r)path with ..., bend_radius = r
FlexPath.turn(radius, angle), .arc(...)arc with radius, width, angle
.bezier(xy), .quadratic, .cubic, Curve.bezierbezier
RobustPath with a width functiontaper profiles
.parametric(f), Curve.parametricpoints from a loop, see recipes
Label(text, origin)a marker
offset, booleandilate / erode, union / intersection / difference / xor (Boolean Operations)

Luceda IPKISS

IPKISSlaylight
i3.Rectangle(layer, center, box_size=(w, h)), i3.Boxrect with w, h placed at center
i3.RoundedRectangle(..., radius)rect with w, h, corner_radius = radius
i3.RectanglePath(..., line_width)rect with w, h, line_width = line_width
i3.RoundedRectanglePath(..., radius, line_width)rect with w, h, corner_radius = radius, line_width = line_width; a stadium-shaped one is a racetrack
i3.Boundary(layer, shape)polygon with points
i3.Path(layer, closed_shape, line_width)polygon with points, line_width = line_width
i3.ShapeRound(shape, radius)corner_radius (closed shapes) or bend_radius (paths)
i3.RegularPolygon(center, radius, n_o_sides), i3.Hexagonregular_polygon with n, radius = radius; add rotation = 180deg for odd n
i3.RegularPolygonPath, i3.HexagonPathregular_polygon with ..., line_width = line_width
i3.Circle(center, radius)circle with radius
i3.CirclePath(center, radius, line_width)ring with radius, line_width
i3.Ellipse(center, box_size=(a, b))ellipse with a / 2, b / 2
i3.EllipsePath(..., line_width)ellipse with a / 2, b / 2, line_width = line_width
i3.EllipseArcPath(..., start_angle, end_angle, line_width)ellipse with ..., angle, start_angle, line_width; IPKISS angles are parametric, laylight's polar
i3.ArcPath(center, radius, start_angle, end_angle, line_width)ring with radius, line_width, angle = end_angle - start_angle, start_angle = start_angle
i3.RingSegment(center, angle_start, angle_end, inner_radius, outer_radius)ring with (inner_radius + outer_radius) / 2, outer_radius - inner_radius, angle = angle_end - angle_start, start_angle = angle_start
i3.Cross(center, box_size, thickness), i3.CrossPathcross with box_size, thickness
i3.Wedge(begin_coord, end_coord, begin_width, end_width)taper with length, begin_width, end_width, placed along the wedge's axis
i3.ParabolicWedge(...)taper with length, begin_width, end_width, profile = "parabolic"
i3.Path(layer, shape, line_width, path_type=NORMAL), EXTENDED, ROUNDEDpath with points, line_width, with ends = "square", ends = "round"
i3.ShapeBend, i3.ShapeBendRelativearc with radius, width, angle
i3.EulerRoundingAlgorithm(p), i3.ShapeRoundEuler(..., radius, p)euler with min_radius = radius, width = width, angle = angle, p = p
i3.EulerRoundingAlgorithm(p, use_effective_radius=True)euler with radius, width, angle, p = p
i3.ShapeSineSBend, i3.ShapeCosineSBend, i3.ShapeRadialSBendsbend with profile = "sine", "cosine", "circular" (similar curves; compare the definitions before relying on them)
i3.ShapeBezierbezier
i3.PolygonText(text, coordinate, height)text with text, size (IPKISS upper-cases the text)
i3.Labela marker

Nazca Design

Nazcalaylight
geom.box(length, width)rect with length, width, placed by left_center
geom.rectangle(length, height, position), geom.squarerect with length, height; position=5 is the center, 1 the bottom_left corner at the origin
geom.rounded_rect(length, height, shrink)rect with length, height, corner_radius = shrink * min(length, height)
geom.frame(sizew, sizel, sizeh)rect with sizel, sizeh, line_width = sizew, centered at ((sizel - sizew) / 2, (sizeh - sizew) / 2)
geom.circle(radius, N)circle with radius, N
geom.pie(radius, angle)circle with radius, angle = -angle, start_angle = 90deg (Nazca runs clockwise from +y)
geom.ring(radius, width)ring with radius - width / 2, width (Nazca's radius is the outer one)
geom.arc(radius, width, angle)ring with radius - width / 2, width, angle = angle, start_angle = -90deg
geom.trapezoid(length, height, angle1, angle2)trapezoid with length, height, length - height / tan(angle1) - height / tan(angle2), offset = (height / tan(angle1) - height / tan(angle2)) / 2
geom.parallelogram(length, height, angle)trapezoid with length, height, length, offset = height / tan(angle)
geom.rhombus(length, angle)trapezoid with length, length * sin(angle), length, offset = length * cos(angle)
geom.taper(length, width1, width2), ic.tapertaper with length, width1, width2
ic.ptaper(length, width1, width2)taper with length, width1, width2, profile = "parabolic"
ic.strt(length)rect with length, width
ic.bend(radius, angle)arc with radius, width, angle
ic.euler_arc_euler(...)euler (ic.euler is only the half from straight to curved)
ic.sinebend(distance, offset)sbend with distance, offset, width, profile = "sine"
ic.sbend(radius, offset)two arcs with a straight section; sbend with profile = "circular" when no straight section is wanted
nd.Polygon(points)polygon with points
nd.Polyline(points, width, pathtype)path with points, width; pathtype=1 is ends = "round"
nd.text(text, height)text with text, size (Nazca's height includes the line spacing)
nd.Annotationa marker

Conventions that differ

Watch these when you port a layout. They are the places where the same name means different geometry.

  • Angles. gdstk takes radians everywhere; laylight, gdsfactory, IPKISS and Nazca use degrees.
  • Ring radius. laylight ring and gdsfactory ring use the centerline radius. Nazca's ring(radius, width) takes the outer radius and grows inward, so it equals laylight ring with radius - width / 2, width. IPKISS CirclePath is centered on its radius, like laylight.
  • Racetrack radius. gdstk's racetrack(radius, inner_radius) takes the outer radius: racetrack with (radius + inner_radius) / 2, straight_length, radius - inner_radius.
  • Regular polygon orientation. laylight and gdstk put a flat edge at the bottom. gdsfactory and IPKISS put a flat edge at the top, which differs for odd numbers of sides: add rotation = 180deg.
  • Parabolic taper. laylight, IPKISS and Nazca change the square of the width linearly. gdsfactory's taper_parabolic changes the width with the square root of the length instead.
  • Euler bend size. gdsfactory's bend_euler defaults to the effective radius (laylight radius). IPKISS's EulerRoundingAlgorithm defaults to the minimum radius (laylight min_radius). Nazca's euler is a half bend from straight to curved; euler_arc_euler is the symmetric one.
  • S-bend. gdsfactory's bend_s is laylight's default "bezier" profile. Nazca's sinebend is the "sine" profile. Nazca's sbend(radius, offset) uses two arcs of a given radius with a straight section between them. The "circular" profile instead picks the radius that fills length without a straight section.
  • Ellipse angles. laylight and gdstk take polar angles; IPKISS's EllipseArcPath takes parametric ones.
  • Text size. laylight's size and gdsfactory's text size are the height of a capital letter. gdstk's size is the full font height, with capitals about 0.75 of it. Nazca's height is scaled by the font's line height. gdsfactory's text_rectangular size is one pixel.
  • Rectangle origin. laylight shapes are centered (rect) or start at the origin (waveguides). gdsfactory's rectangle defaults to its lower-left corner at the origin, and Nazca's rectangles take a keypad position (1 = lower left, 5 = center).
  • Point density. segments corresponds to gdsfactory's npoints / angle_resolution, gdstk's tolerance, IPKISS's angle_step (1° by default) and Nazca's N (20 by default).

On this page