Route
Waypoint-based waveguide route.
Route connects an ordered sequence of waypoints with straight segments, inserting circular bends at corners and tapers for width transitions. It is not an auto-router — you must supply intermediate waypoints to create the path shape you want.
Waypoints create the shape
When connecting two ports, always add intermediate (x, y) waypoints
so the route departs and arrives along each port's axis. Two ports alone
produce a straight diagonal line between them, ignoring port directions.
# Connecting two ports with an S-bend:
route = Route(Layer(1, 0), width=0.5, bend_radius=5.0)
route.start_at_port(port_a) # departs along port_a's axis
route.to(mid_x, port_a.position.y) # horizontal segment out
route.to(mid_x, port_b.position.y) # vertical transition
route.end_at_port(port_b) # arrives along port_b's axis
cell = route.to_cell("my_route")
# Manual waypoints:
route = Route(Layer(1, 0), width=0.5, bend_radius=5.0)
route.start_at(0, 0, angle=0)
route.to(50, 0)
route.to(50, 30)
route.end_at(100, 30, angle=0)
cell = route.to_cell("my_route") # Returns Cell with .at()Attributes
attributepath_lengthfloatTotal optical path length.
attributewarningslist[str]Warnings from route generation (e.g., auto-reduced bend radii).
Methods
func__init__(layer, width=0.5, bend_radius=5.0, auto_taper=True, taper_length=10.0) -> NoneCreate a new Route.
paramlayerLayer | int | tuple[int, int]The layer for the route geometry.
paramwidthfloat= 0.5Default waveguide width.
parambend_radiusfloat= 5.0Default bend radius.
paramauto_taperbool= TrueWhether to automatically add tapers for width changes.
paramtaper_lengthfloat= 10.0Length of auto-generated tapers.
Returns
Nonefuncstart_at(x, y, angle=0.0) -> NoneStart the route at a specific position and angle (degrees).
paramxfloatX coordinate.
paramyfloatY coordinate.
paramanglefloat= 0.0Departure angle in degrees (0 = +X direction).
Returns
Nonefuncstart_at_port(port) -> NoneStart the route at a port's position, heading into the port.
The port's outward-facing direction is flipped 180 degrees so the route departs in the correct direction (away from the component). The port's width is used as the starting width.
The first waypoint after this should continue along the port's axis (e.g., same y for a horizontal port) before turning.
paramportPortThe port to start at.
Returns
Nonefuncto(x, y, width=None, bend_radius=None) -> NoneAdd a waypoint to the route.
The route draws a straight segment from the previous waypoint to
(x, y), inserting a circular bend at the corner if the direction
changes. Provide intermediate waypoints to create L-bends and
S-bends — the router does not infer turns on its own.
paramxfloatX coordinate of the waypoint.
paramyfloatY coordinate of the waypoint.
paramwidthfloat | None= NoneOverride width at this waypoint. If set and auto_taper is enabled,
a taper is inserted.
parambend_radiusfloat | None= NoneOverride bend radius at this corner.
Returns
Nonefuncend_at(x, y, angle=0.0) -> NoneEnd the route at a specific position and angle (degrees).
paramxfloatX coordinate.
paramyfloatY coordinate.
paramanglefloat= 0.0Arrival angle in degrees.
Returns
Nonefuncend_at_port(port) -> NoneEnd the route arriving into a port.
The port's outward-facing direction is flipped 180 degrees so the route arrives heading into the component. The port's width is used as the ending width.
The last waypoint before this should approach along the port's axis (e.g., same y for a horizontal port) to ensure a flush connection.
paramportPortThe port to end at.
Returns
Nonefuncto_cell(name) -> CellConvert the route to a Cell.
Warnings are printed to stderr if the route had to auto-reduce bend radii or encountered other issues. This provides immediate feedback to both users and AI agents about potential design problems.
paramnamestrName for the generated cell.
Returns
CellA Cell containing the route geometry, with path_length set.
functhrough(*waypoints, layer, width=0.5, bend_radius=5.0) -> RouteCreate a route through a series of waypoints (static method).
A convenience method that creates a Route, adds all waypoints, and returns the result. You must include intermediate waypoints to create turns — two ports alone produce a straight diagonal line regardless of port directions.
Port directions are used only for the first and last waypoint
(to set departure/arrival angle). Intermediate ports are treated
as plain (x, y) positions — their direction is ignored.
Example
# S-bend between two component ports:
route = Route.through(
port_a, # start at port_a, depart along its axis
(25, port_a.position.y), # extend horizontally
(25, port_b.position.y), # shift vertically
port_b, # arrive at port_b along its axis
layer=Layer(1, 0),
bend_radius=10.0,
)
cell = route.to_cell("my_route")param*waypointsPort | Point | tuple[float, float] | tuple[float, float, float]Sequence of waypoints. Each can be a Port (position + width; direction
used only if first/last), a Point (position only), an (x, y) tuple,
or an (x, y, angle) tuple (for first/last waypoint).
paramlayerLayer | int | tuple[int, int]The layer for the route.
paramwidthfloat= 0.5Default waveguide width.
parambend_radiusfloat= 5.0Default bend radius.
Returns
RouteA Route that can be converted to a Cell with to_cell().