Path API Reference

Paths

DeviceLayout.Paths.PathType
mutable struct Path{T<:Coordinate} <: GeometryStructure{T}

Type for abstracting an arbitrary styled path in the plane. Iterating returns Paths.Node objects.

Convenience constructors for Path{T} object:

Path{T}(p0::Point=zero(Point{T}), α0::typeof(1.0°)=0.0°, metadata::Meta=UNDEF_META)
Path{T}(name::String, p0::Point=zero(Point{T}), α0::Float64=0.0, metadata::Meta=UNDEF_META)
Path(p0::Point=zero(Point{typeof(1.0UPREFERRED)}); α0=0.0, name=uniquename("path"), metadata=UNDEF_META)
Path(p0x::Coordinate, p0y::Coordinate; α0=0.0, name=uniquename("path"), metadata=UNDEF_META)
Path(u::CoordinateUnits; α0=0.0, name=uniquename("path"), metadata=UNDEF_META)
Path(v::Vector{Node{T}}; name=uniquename("path"), metadata=UNDEF_META) where {T}
source
DeviceLayout.Paths.α0Function
α0(s::Segment)

Return the first angle in a segment (calculated).

source
α0(p::Path)

First angle of a path, returns p.α0.

source
α0(r::Route)

First angle of a route, returns r.α0.

source
DeviceLayout.Paths.pathlengthFunction
pathlength(p::Path)
pathlength(array::AbstractArray{Node{T}}) where {T}
pathlength(array::AbstractArray{T}) where {T<:Segment}
pathlength(node::Node)

Physical length of a path. Note that length will return the number of segments in a path, not the physical length of the path.

source
DeviceLayout.Paths.p0Function
p0(s::Segment{T}) where {T}

Return the first point in a segment (calculated).

source
p0(p::Path)

First point of a path, returns p.p0.

source
p0(r::Route)

First point of a route, returns r.p0.

source
DeviceLayout.Paths.p1Function
p1(s::Segment{T}) where {T}

Return the last point in a segment (calculated).

source
p1(p::Path)

Last point of a path.

source
p1(r::Route)

Last point of a route, returns r.p1.

source
DeviceLayout.Paths.style1Function
style1(p::Path)

Undecorated style of the last user-provided (non-virtual) segment of a path.

Throws an error if the path is empty.

source
DeviceLayout.Paths.contstyle1Function
contstyle1(p::Path)

Return the undecorated last user-provided (non-virtual) continuous style in the path.

Throws an error if the path is empty.

source
DeviceLayout.Paths.nextstyleFunction
nextstyle(p::Path)

Return the style to be used if the path is extended without specifying a new style.

In most cases this is the last continuous, non-virtual style, but there are some special cases:

  • Attachments (from attach!) are not part of the next style
  • A TaperTrace is followed by a SimpleTrace with its final width
  • A TaperCPW is followed by a SimpleCPW with its final trace and gap
  • A CompoundStyle (from simplify!) is followed by its last style
  • An OverlayStyle (from overlay!) is followed by an OverlayStyle using the nextstyle for each overlay and base style
  • A termination is followed by NoRenderContinuous

For a path ending in a PeriodicStyle, nextstyle will return that same style, but when the path is actually extended, it will continue its periodicity from where it ended in the last segment.

source

Path Manipulation

DeviceLayout.Paths.setp0!Function
setp0!(s::Straight, p::Point)

Set the p0 of a straight segment.

source
setp0!(s::Turn, p::Point)

Set the p0 of a turn.

source
setp0!(b::BSpline, p::Point)

Translate the interpolated segment so its initial point is p.

source
DeviceLayout.Paths.setα0!Function
setα0!(s::Straight, α0′)

Set the angle of a straight segment.

source
setα0!(s::Turn, α0′)

Set the starting angle of a turn.

source
setα0!(b::BSpline, α0′)

Set the starting angle of an interpolated segment.

source
Base.append!Method
append!(p::Path, p′::Path; reconcile=true)

Given paths p and p′, path p′ is appended to path p. The p0 and initial angle of the first segment from path p′ is modified to match the last point and last angle of path p.

source
DeviceLayout.Paths.attach!Method
attach!(p::Path, c::GeometryReference, t::Coordinate;
    i::Integer=length(p), location::Integer=0)
attach!(p::Path, c::GeometryReference, t;
    i::Integer=length(p), location=zeros(Int, length(t)))

Attach c along a path. The second method permits ranges or arrays of t and location to be specified (if the lengths do not match, location is cycled).

By default, the attachment(s) occur at t ∈ [zero(pathlength(s)),pathlength(s)] along the most recent path segment s, but a different path segment index can be specified using i. The reference is oriented with zero rotation if the path is pointing at 0°, otherwise it is rotated with the path.

The origin of the cell reference tells the method where to place the cell with respect to a coordinate system that rotates with the path. Suppose the path is a straight line with angle 0°. Then an origin of Point(0.,10.) will put the cell at 10 above the path, or 10 to the left of the path if it turns left by 90°.

The location option is for convenience. If location == 0, nothing special happens. If location == -1, then the point of attachment for the reference is on the leftmost edge of the waveguide (the rendered polygons; the path itself has no width). Likewise if location == 1, the point of attachment is on the rightmost edge. This option does not automatically rotate the cell reference, apart from what is already done as described in the first paragraph. You can think of this option as setting a special origin for the coordinate system that rotates with the path. For instance, an origin for the cell reference of Point(0.,10.) together with location == -1 will put the cell at 10 above the edge of a rendered (finite width) path with angle 0°.

source
DeviceLayout.Paths.bspline!Function
bspline!(p::Path{T}, nextpoints, α_end, sty::Style=nextstyle(p);
    endpoints_speed=2500μm,
    endpoints_curvature=nothing,
    auto_speed=false,
    auto_curvature=false)

Add a BSpline interpolation from the current endpoint of p through nextpoints.

The interpolation reaches nextpoints[end] making the angle α_end with the positive x-axis. The endpoints_speed is "how fast" the interpolation leaves and enters its endpoints. Higher speed means that the start and end angles are approximately α1(p) and α_end over a longer distance.

If auto_speed is true, then endpoints_speed is ignored. Instead, the endpoint speeds are optimized to make curvature changes gradual as possible (minimizing the integrated square of the curvature derivative with respect to arclength).

If endpoints_curvature (dimensions of oneunit(T)^-1) is specified, then additional waypoints are placed so that the curvature at the endpoints is equal to endpoints_curvature.

If auto_curvature is specified, then endpoints_curvature is ignored. Instead, the curvature at the end of the previous segment of the path is used, or zero curvature if the path was empty.

endpoints_speed and endpoints_curvature can also be provided as 2-element iterables to specify initial and final boundary conditions separately.

source
DeviceLayout.Paths.corner!Function
corner!(p::Path, α, sty::Style=discretestyle1(p))

Append a sharp turn or "corner" to path p with angle α.

The style chosen for this corner, if not specified, is the last DiscreteStyle used in the path.

source
DeviceLayout.Paths.launch!Function
launch!(p::Path; kwargs...)

Add a coplanar-waveguide "launcher" structure to p.

If p is empty, start the path with a launcher; otherwise, terminate with a launcher.

This method exists mainly for use in demonstrations. The launcher design is not optimized for microwave properties.

Keywords:

  • extround = 5.0μm: Rounding of the "back" of the pad and external ground plane "behind" the launcher
  • trace0 = 300.0μm: Trace width of the pad
  • trace1 = 10.0μm: Trace width of the launched CPW
  • gap0 = 150.0μm: Gap width of the pad
  • gap1 = 6.0μm: Gap width of the final CPW
  • flatlen = 250.0μm: Length of the pad
  • taperlen = 250.0μm: Length of the taper between pad and launched CPW
source
DeviceLayout.Paths.meander!Function
meander!(p::Path, len, straightlen, r, α)

Alternate between going straight with length straightlen and turning with radius r and angle α. Each turn goes the opposite direction of the previous. The total length is len. Useful for making resonators.

The straight and turn segments are combined into a CompoundSegment and appended to the path p.

source
meander!(p::Path, endpoint::Point, len, nseg::Int, r, sty::Paths.Style = style1(p); offset = 0)

Another meander method, this one extends Path p from its current end-point to meet endpoint, such that the resulting final total path length will be len.

  • nseg: the number of U-turns in the meander will be 2*nseg
source
DeviceLayout.Paths.overlay!Function
overlay!(path::Path, oversty::Style, metadata::DeviceLayout.Meta; i::Int=length(path))

Apply the style oversty in layer metadata on top of the segment at path[i].

By default, the overlay is applied to the most recent segment.

Overlays generally count as "decorations". For example, they appear in refs(path) and not elements(path). They are removed by undecorated(sty), and they are ignored when choosing the default style for continuing a Path with methods like straight!.

Overlay styles should not be generic Paths.Tapers, since they can't see neighboring styles to resolve the taper style.

You can use overlay! after attach!, in which case the overlay is applied to the style underlying the DecoratedStyle that holds the attachments.

source
DeviceLayout.Paths.reconcile!Function
reconcile!(path::Path, endpoint::Point, end_direction, rule::RouteRule, waypoints, waydirs;
    initialize_waydirs = false)

Ensure that path can be routed to endpoint at end_direction using rule, waypoints, waydirs, or log an error.

Does nothing for a generic RouteRule. Subtypes of RouteRule may implement specialized methods to do their own validation when route! is called.

May insert inferred constraints to waypoints and waydirs to allow the path to be drawn leg-by-leg. For example, reconcile! with rule::StraightAnd90, no waypoints, and α1(path) == end_direction will insert a waypoint halfway between p1(path) and endpoint, allowing two successive StraightAnd90 legs with opposite bends.

source
reconcile!(p::Path, n::Integer=1)

Reconcile all inconsistencies in a path starting from index n. Used internally whenever segments are inserted into the path, but can be safely used by the user as well.

source
DeviceLayout.Paths.round_trace_transitions!Function
round_trace_transitions!(pa::Path; α_max=60°, radius=nothing, side=:before)

Replace linear TaperTraces and discontinuous transitions between SimpleTrace segments with smooth (quintic Hermite, C²) tapers.

For discontinuous transitions between adjacent SimpleTrace styles:

  • α_max controls the maximum angle between the taper edge and the path direction. 0° < α_max < 90° is required.
  • radius sets a lower bound on the edge radius of curvature (e.g. for fab constraints). When both α_max and radius are provided, the more conservative constraint wins.
  • side controls which segment donates space for the taper: :before (default) takes from the preceding segment, :after takes from the following segment.

TaperTrace rounding uses the existing taper length and is unaffected by α_max, radius, and side. If a segment is too short for the computed taper length, the transition is skipped with a warning.

source
DeviceLayout.Paths.simplifyFunction
simplify(p::Path, inds::UnitRange=firstindex(p):lastindex(p))

At inds, segments of a path are turned into a CompoundSegment and styles of a path are turned into a CompoundStyle. The method returns a Paths.Node, (segment, style).

  • Indexing the path becomes more sane when you can combine several path segments into one logical element. A launcher would have several indices in a path unless you could simplify it.
  • You don't need to think hard about boundaries between straights and turns when you want a continuous styling of a very long path.
source
DeviceLayout.Paths.straight!Function
straight!(p::Path, l::Coordinate, sty::Style=nextstyle(p))

Extend a path p straight by length l in the current direction. By default, we take the last continuous style in the path.

source
DeviceLayout.Paths.terminate!Function
terminate!(pa::Path{T}; gap=Paths.terminationlength(pa), rounding=zero(T), initial=false, overlay_index=0, margin=zero(T)) where {T}

End a Paths.Path with a termination.

Keywords

  • rounding: Radius to round corners of termination. Rounding keeps the pathlength constant by removing some length from the preceding segment and adding a rounded section of equivalent maximum length.
  • gap: If the preceding style is a CPW, this is a "short termination" if iszero(gap) and is an "open termination" with a gap of gap otherwise, defaulting to the gap of the preceding CPW. Has no effect for Trace terminations.
  • initial: If true, the termination is added at the beginning of the Path.
  • margin: If positive, the termination will begin an additional length margin away from the end of the path (adding to the backtracking to accommodate rounding). The underlying pathlength and path endpoints are unchanged.
  • overlay_index: If nonzero, the termination is applied to the overlay style at that index.

Trace terminations and CPW short terminations do not change the underlying curve, while CPW open terminations add a straight length of gap. However, rounding is always drawn with exact circular arcs, as though the rounded section were actually straight, even for terminations on curves.

source
DeviceLayout.Paths.turn!Function
turn!(p::Path, α, r::Coordinate, sty::Style=nextstyle(p))

Turn a path p by angle α with a turning radius r in the current direction. Positive angle turns left. By default, we take the last continuous style in the path.

source
turn!(p::Path, str::String, r::Coordinate, sty::Style=nextstyle(p))

Turn a path p with direction coded by string str:

  • "l": turn by 90° (left)
  • "r": turn by -90° (right)
  • "lrlrllrrll": do those turns in that order

By default, we take the last continuous style in the path.

source

Path Intersection

DeviceLayout.Intersect.AirBridgeType
AirBridge(; crossing_gap, foot_gap, foot_length, extent_gap, scaffold_gap,
    scaffold_meta=SemanticMeta(:scaffold), air_bridge_meta=SemanticMeta(:air_bridge), 
    name="airbridge", unit=[nm or NoUnits])

Style for automatically leaping one path over another with scaffolded air bridges.

Parameters ("lengths" are along path direction, "extents" are transverse from the center)

  • name: Prefix for unique CoordinateSystem name
  • scaffold_meta: Scaffold layer metadata
  • air_bridge_meta: Air bridge layer metadata
  • crossing_gap: Extra length beyond extent of path being crossed (on one side)
  • foot_gap: Extra length beyond original path termination before bridge foot starts
  • foot_length: Length of bridge foot
  • extent_gap: Gap between edge of bridge trace and edge of original path trace
  • scaffold_gap: Gap between edge of original trace and edge of scaffold
  • rounding: Rounding radius for scaffold and air bridge rectangles
  • unit: Coordinate system unit
source
Base.intersect!Function
intersect!(sty::IntersectStyle, paths::Path...;
    intersections=prepared_intersections(paths...))

Automatically modify paths to handle cases where they intersect.

Paths later in the argument list cross over paths earlier in the argument list. For self-intersection (path with itself), segments later in a path will cross over segments earlier in the same path (perhaps later this will be configurable by an option).

source

Path Nodes

Base.splitMethod
split(n::Node, x::Coordinate)
split(n::Node, x::AbstractVector{<:Coordinate}; issorted=false)

Splits a path node at position(s) x along the segment, returning a path. If issorted, don't sort x first (otherwise required for this to work).

A useful idiom, splitting and splicing back into a path: splice!(path, i, split(path[i], x))

source
DeviceLayout.styleFunction
style(x::Node)

Return the style associated with node x.

source
style(styled_ent::StyledEntity)

Return the GeometryEntityStyle of styled_ent.

source
DeviceLayout.Paths.setsegment!Function
setsegment!(n::Node, s::Segment)

Set the segment associated with node n to s. If reconcile, then modify fields as appropriate for internal consistency (possibly including other linked nodes).

source
DeviceLayout.Paths.setstyle!Function
setstyle!(n::Node, s::Style; reconcile=true)

Set the style associated with node n to s. If reconcile, then modify fields as appropriate for internal consistency.

source

Path Segments

DeviceLayout.Paths.SegmentType
abstract type Segment{T<:Coordinate} end

Path segment in the plane. All Segment objects should have the implement the following methods:

  • pathlength
  • p0
  • α0
  • setp0!
  • setα0!
  • α1
source
DeviceLayout.Paths.StraightType
mutable struct Straight{T} <: ContinuousSegment{T}

A straight line segment is parameterized by its length. It begins at a point p0 with initial angle α0.

source
DeviceLayout.Paths.TurnType
mutable struct Turn{T} <: ContinuousSegment{T}

A circular turn is parameterized by the turn angle α and turning radius r. It begins at a point p0 with initial angle α0.

source
DeviceLayout.Paths.CornerType
mutable struct Corner{T} <: DiscreteSegment{T}

A corner, or sudden kink in a path. The only parameter is the angle α of the corner. The corner begins at a point p0 with initial angle α0. It will also end at p0, since the corner has zero path length. However, during rendering, neighboring segments will be tweaked slightly so that the rendered path is properly centered about the path function (the rendered corner has a finite width).

source
DeviceLayout.Paths.CompoundSegmentType
struct CompoundSegment{T} <: ContinuousSegment{T}

Consider an array of segments as one contiguous segment. Useful e.g. for applying styles, uninterrupted over segment changes. The array of segments given to the constructor is copied and retained by the compound segment.

Note that Corners introduce a discontinuity in the derivative of the path function, and are not allowed in a CompoundSegment.

source
DeviceLayout.Paths.BSplineType
mutable struct BSpline{T} <: ContinuousSegment{T}

Interpolate between points p with start and end tangents t0, t1.

Computes the interpolated coordinate r(t) as a function of a dimensionless parameter t, using b-spline interpolation knots spaced uniformly in t. That is, r(0) == p[1] and r(1) == p[end], and generally r((i-1)*tinc) == p[i] where tinc is the knot value spacing 1/(length(p)-1).

A BSpline instance itself can be called as a parametric function of a length that ranges from zero to the total path length.

source

Path Styles

DeviceLayout.Paths.ContinuousStyleType
abstract type ContinuousStyle{CanStretch} <: Style end

Any style that applies to segments which have non-zero path length. For most styles, CanStretch == false. An example of an exception is a linear taper, e.g. Paths.TaperTrace, where you fix the starting and ending trace widths and let the segment length dictate the abruptness of the transition (hence, stretching the style). Concrete types inheriting from ContinuousStyle{true} should have a length field as the last field of their structure.

source
DeviceLayout.Paths.TraceType
Trace(width)
Trace(width::Coordinate)
Trace(width_start::Coordinate, width_end::Coordinate)

Constructor for Trace styles. Automatically chooses SimpleTrace, GeneralTrace, and TaperTrace as appropriate.

source
DeviceLayout.Paths.CPWType
CPW(trace::Coordinate, gap::Coordinate)
CPW(trace, gap::Coordinate)
CPW(trace::Coordinate, gap)
CPW(trace, gap)
CPW(trace_start::Coordinate, gap_start::Coordinate, trace_end::Coordinate, gap_end::Coordinate)

Constructors for CPW styles. Automatically chooses between SimpleCPW, GeneralCPW, or TaperCPW styles as appropriate.

source
DeviceLayout.Paths.TaperType
Taper()

Constructor for generic Taper style. Will automatically create a linearly tapered region between an initial CPW or Trace and an end CPW or Trace of different dimensions.

source
DeviceLayout.Paths.StrandsType
Strands(offset::Coordinate, width::Coordinate, spacing::Coordinate, num::Int)
Strands(offset, width::Coordinate, spacing::Coordinate, num::Int)
Strands(offset::Coordinate, width, spacing::Coordinate, num::Int)
Strands(offset::Coordinate, width::Coordinate, spacing, num::Int)
Strands(offset::Coordinate, width, spacing, num::Int)
Strands(offset, width::Coordinate, spacing, num::Int)
Strands(offset, width, spacing::Coordinate, num::Int)
Strands(offset, width, spacing, num::Int)

              example for num = 2
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
<-><---><-><-----------|-----------><-><---><->
 w   s   w    offset                 w   s   w

Constructors for Strands styles. Automatically chooses between SimpleStrandsor GeneralStrands styles as appropriate.

source
DeviceLayout.Paths.NoRenderType
struct NoRender <: Style

Style for suppressing rendering. When asked, it will claim to have zero width. Converts to a continuous or discrete style as needed by straight!, turn!, corner!, etc.

source
DeviceLayout.Paths.SimpleNoRenderType
struct SimpleNoRender{T} <: ContinuousStyle{false}
SimpleNoRender(width::T; virtual=false)

A style that inhibits path rendering, but pretends to have a finite width for Paths.attach!.

May be "virtual", in which case it is ignored when looking up the last style of a Path with laststyle or contstyle1, or when extending a Path with (for example) straight!.

source
DeviceLayout.Paths.SimpleCPWType
struct SimpleCPW{T <: Coordinate} <: CPW{false}
    trace::T
    gap::T
end

A CPW with fixed trace and gap as a function of path length.

source
DeviceLayout.Paths.GeneralCPWType
struct GeneralCPW{S, T} <: CPW{false}
    trace::S
    gap::T
end

A CPW with variable trace and gap as a function of path length. trace and gap are callable.

source
DeviceLayout.Paths.TaperTraceType
struct TaperTrace{T<:Coordinate} <: Trace{true}
    width_start::T
    width_end::T
    length::T
end

A single trace with a linearly tapered width as a function of path length.

source
DeviceLayout.Paths.TaperCPWType
struct TaperCPW{T<:Coordinate} <: CPW{true}
    trace_start::T
    gap_start::T
    trace_end::T
    gap_end::T
    length::T
end

A CPW with a linearly tapered trace and gap as a function of path length.

source
DeviceLayout.Paths.SimpleStrandsType
struct SimpleStrands{T<:Coordinate} <: Strands{false}
    offset::T
    width::T
    spacing::T
    num::Int
end

              example for num = 2
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
<-><---><-><-----------|-----------><-><---><->
 w   s   w    offset                 w   s   w

Strands with fixed center offset, width, and spacing as a function of path length.

source
DeviceLayout.Paths.GeneralStrandsType
struct GeneralStrands{S,T,U} <: Strands{false}
    offset::S
    width::T
    spacing::U
    num::Int
end

              example for num = 2
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
|||     |||                         |||     |||
<-><---><-><-----------|-----------><-><---><->
 w   s   w    offset                 w   s   w

Strands with variable center offset, width, and spacing as a function of path length. offset, width, and spacing are callable.

source
DeviceLayout.Paths.CompoundStyleType
struct CompoundStyle{T<:FloatCoordinate} <: AbstractCompoundStyle
    styles::Vector{Style}
    grid::Vector{T}
end

Combines styles together, typically for use with a CompoundSegment.

  • styles: Array of styles making up the object. This is deep-copied by the outer constructor.
  • grid: An array of t values needed for rendering the parametric path.
source
DeviceLayout.Paths.DecoratedStyleType
mutable struct DecoratedStyle{T<:FloatCoordinate} <: ContinuousStyle{false}
    s::Style
    ts::Vector{Float64}
    dirs::Vector{Int}
    refs::Vector{GeometryReference}
end

Style with decorations, like structures periodically repeated along the path, etc.

source
DeviceLayout.Paths.PeriodicStyleType
struct PeriodicStyle{T <: Coordinate} <: AbstractCompoundStyle

Continuous style cycling through a series of underlying styles, each for a fixed length.

If a path has two consecutive segments with the same periodic style, then the second will continue the cycle from where the first ended.

PeriodicStyle(styles::Vector{<:Style}, lengths::Vector{T}, l0=zero(T))

Style cycling through each style in style for the corresponding length in lengths, repeating after every sum(lengths). Periodicity starts at l0.

PeriodicStyle(styles::Vector{<:Style}; period::T, weights=ones(length(styles)), l0=zero(T))

Convenience constructor using a period keyword with weights rather than explicit lengths, such that the length for each style in a period is given by lengths = period * weights/sum(weights).

PeriodicStyle(pa::Path{T}; l0=zero(T))

Convenience constructor for a periodic style cycling between the styles in pa, each for the length of the corresponding segment in pa.

source
DeviceLayout.Paths.pinFunction
pin(s::ContinuousStyle; start=nothing, stop=nothing)

Imagine having a styled segment of length L split into two, the first segment having length l and the second having length L-l. In all but the simplest styles, the styles need to be modified in order to maintain the rendered appearances. A style appropriate for the segment of length l (L-l) is given by pin(s; stop=l) (pin(s; start=l)).

source
DeviceLayout.Paths.translateFunction
translate(s::ContinuousStyle, x)

Creates a style s′ such that all properties f(s′, t) == f(s, t+x). Basically, advance the style forward by path length x.

source
DeviceLayout.Paths.undecoratedFunction
undecorated(s::DecoratedStyle)
undecorated(s::Style)

Return the underlying, undecorated style if decorated; otherwise just return the style.

source

Routes

DeviceLayout.Paths.RouteType
struct Route{T<:RouteRule, S<:Coordinate}
Route(rule, startpoint::Point{S}, endpoint::Point, start_direction, end_direction; waypoints=Point{S}[], waydirs=[])
Route(rule, path0::Path, endpoint::Point, end_direction)

A Route implicitly defines a Path between two points with given start and end directions.

Use Path(r::Route, sty::Paths.Style) to create the explicit path.

Contains a RouteRule to determine how the Path should be drawn.

May contain waypoints and waydirs that additionally constrain the route. The RouteRule determines how these are handled, by default routing waypoint-to-waypoint such that the path starts at p0, passes through each point in waypoints in order, and then ends at p1.

If waydirs is not nothing, it should have the same length as waypoints. If waydirs is provided and is not ignored by the RouteRule (check the specific rule documentation), then waypoints[i] will be reached with the path pointing along waydirs[i].

source

Route rules

DeviceLayout.Paths.RouteRuleType
abstract type RouteRule end

Controls how a Route is turned into a Path.

A RouteRule may contain parameters or be used only for dispatch. It should implement one of the following two methods:

_route!(p::Path, p1::Point, α1, rule::MyRouteRule, sty, waypoints, waydirs)
_route_leg!(p::Path, next::Point, rule::MyRouteRule,
    sty::Paths.Style=Paths.nextstyle(p))

It may also implement

reconcile!(path::Path, endpoint::Point,
    end_direction, rule::RouteRule, waypoints, waydirs; initialize_waydirs)

If only _route_leg! is implemented, then a Path drawn from r::Route with MyRouteRule will first call reconcile! to validate constraints and insert waypoints if necessary. (The default implementation of reconcile! does nothing.) The Path will then be routed waypoint-to-waypoint such that the path starts at r.p0, passes through each point in r.waypoints in order, and then ends at r.p1, ignoring waydirs. Alternatively, _route! can be implemented to use r.waypoints and/or r.waydirs all at once as desired.

source
DeviceLayout.Paths.BSplineRoutingType
Base.@kwdef struct BSplineRouting <: RouteRule
    endpoints_speed = 2500μm
    auto_speed = false
    endpoints_curvature = nothing
    auto_curvature = false
end

Specifies rules for routing from one point to another using BSplines. Ignores waydirs.

Routes using this rule create a BSpline interpolation, similar to calling Paths.bspline! with the supplied keyword arguments.

The endpoints_speed is "how fast" the interpolation leaves and enters its endpoints. Higher speed means that the start and end directions are maintained over a longer distance.

If auto_speed is true, then endpoints_speed is ignored. Instead, the endpoint speeds are optimized to make curvature changes gradual as possible (minimizing the integrated square of the curvature derivative with respect to arclength).

If endpoints_curvature (dimensions of inverse length) is specified, then additional waypoints are placed so that the curvature at the endpoints is equal to endpoints_curvature.

If auto_curvature is specified, then endpoints_curvature is ignored. Instead, zero curvature is used. Note that bspline! in this case uses the ending curvature of the previous segment if it exists, but a Route does not have any previous segments.

endpoints_speed and endpoints_curvature can also be provided as 2-element iterables to specify initial and final boundary conditions separately.

source
DeviceLayout.Paths.StraightAnd90Type
Base.@kwdef struct StraightAnd90 <: RouteRule
    min_bend_radius = 200μm
    max_bend_radius = Inf*μm
end
StraightAnd90(r) = StraightAnd90(min_bend_radius=r, max_bend_radius=r)

Specifies rules for routing from one point to another using straight segments and 90° bends.

Can be used with no waydirs if each waypoint is reachable from the previous with a single turn and the endpoint is reachable with a single turn or two turns in opposite directions.

If waydirs are used, then any waypoint may be reachable with two turns in opposite directions if that satisfies the corresponding waydirection.

source
DeviceLayout.Paths.StraightAnd45Type
Base.@kwdef struct StraightAnd45 <: RouteRule
    min_bend_radius = 200μm
    max_bend_radius = Inf*μm
end
StraightAnd45(r) = StraightAnd45(min_bend_radius=r, max_bend_radius=r)

Specifies rules for routing from one point to another using using straight segments and 45° bends.

Can be used with no waydirs if each waypoint is reachable from the previous with a single turn and the endpoint is reachable with one or two turns.

If waydirs are used, then any waypoint may be reachable with two turns if that satisfies the corresponding waydirection.

source
DeviceLayout.Paths.CompoundRouteRuleType
CompoundRouteRule <: RouteRule
CompoundRouteRule(rules::Vector{RouteRule}, leg_length::Vector{Int}=ones(length(rules)))

Specifies a sequence of rules for routing from one point to another, where rules[i] is used to route through the next leg_length[i] waypoints and/or endpoint.

source
DeviceLayout.Paths.SingleChannelRoutingType
struct SingleChannelRouting{T <: Coordinate} <: AbstractChannelRouting
SingleChannelRouting(ch::RouteChannel, transition_rule::RouteRule, margin::T)
SingleChannelRouting(ch::RouteChannel, transition_rules, margins)

A RouteRule for guiding routed paths along tracks in a Paths.RouteChannel.

Tracks

"Tracks" are offsets of the channel's path, with equal spacing between each other and the extents of the channel's trace width. Tracks are ordered from left to right when facing along the channel. For example, for a channel directed along the positive x axis, track 1 is the top track (most positive offset), while the highest track index is its bottom track.

The user manually assigns tracks to paths that will be routed with rule::SingleChannelRouting using Paths.set_track!(rule, path, track_idx) for each path, prior to calling route!(path, ...). Because the track offset depends on the total number of tracks, and the number of tracks is determined by the maximum track index of any path added to rule, all paths should be assigned tracks before any route! call.

If used for schematic routing, the track is supplied as a keyword argument, defaulting to a new track added at the bottom of the channel: route!(g::SchematicGraph, rule, ...; track=num_tracks(rule)+1).

Routing

A path routed from p0 to p1 using this rule will enter the channel at the channel's closest point to p0 and exit at the closest point to p1 if margin is zero. For nonzero margin, the entry and exit points are each shifted towards the other along the channel by margin, allowing more space for the transitions into and out of the channel.

The middle "tracked" section is offset from the channel's center line according to the path's track, the maximum track assigned to any path by the rule, and the channel width.

The path is routed from p0 to the tracked section and from the tracked section to p1 using transition_rule.

Transition rules and margins can also be supplied as tuples to the constructor to allow different parameters for entry and exit transitions.

source
DeviceLayout.Paths.RouteChannelType
RouteChannel{T} <: AbstractComponent{T}
RouteChannel(pa::Path)

A channel that routes can be guided through along parallel tracks.

Used in route! with Paths.SingleChannelRouting.

The Path used to construct a RouteChannel should use Trace styles only.

A RouteChannel is an AbstractComponent with the same hooks as its Path and an empty geometry.

source

Route drawing

DeviceLayout.Paths.route!Function
function route!(path::Path{S}, p_end::Point, α_end, rule::RouteRule, sty=Paths.nextstyle(path);
                waypoints=Point{S}[], waydirs=Vector{typeof(1.0°)}(undef, length(waypoints)))) where {S}

Extend path to p_end with arrival angle α_end according to RouteRule. The default implementation is

reconcile!(path, p_end, α_end, rule, waypoints, waydirs)
_route!(path, p_end, α_end, rule, sty, waypoints, waydirs)

followed by checking that the endpoint was successfully reached.

source
route!(g::SchematicGraph, rule::RouteRule,
    nodehook1::Pair{ComponentNode,Symbol}, nodehook2::Pair{ComponentNode,Symbol},
    sty, meta;
    waypoints=[], waydirs=[], global_waypoints=false,
    name=uniquename("r_$(component(nodehook1.first).name)_$(component(nodehook2.first).name)"),
    kwargs...)
route!(g::SchematicGraph, rule::RouteRule, node1::ComponentNode, nodehook2::Pair{ComponentNode,Symbol}, sty, meta; kwargs...)
route!(g::SchematicGraph, rule::RouteRule, nodehook1::Pair{ComponentNode,Symbol}, node2::ComponentNode, sty, meta; kwargs...)
route!(g::SchematicGraph, rule::RouteRule, node1::ComponentNode, node2::ComponentNode, sty, meta; kwargs...)

Creates a RouteComponent with given style sty and metadata meta, and fuses it between the specified nodes and hooks in g.

Returns the resulting ComponentNode in g.

Example usage: route!(g, BSplineRouting(), zline_node=>:feedline, z_launcher_node=>:line, Paths.CPW(10μm, 6μm), GDSMeta(1, 2))

If one or both hook symbols are not specified, then matching_hook or matching_hooks will be used to attempt to automatically find the correct hook or hooks.

The route will have start and endpoints at the origin until a method like plan! is called. waypoints and waydirs are in component-local coordinates (unless global_waypoints is true), and rule determines how they will be used.

Additional keyword arguments will become vertex properties for the RouteComponent's node.

name should be unique.

source
DeviceLayout.Paths.reconcile!Method
reconcile!(path::Path, endpoint::Point, end_direction, rule::RouteRule, waypoints, waydirs;
    initialize_waydirs = false)

Ensure that path can be routed to endpoint at end_direction using rule, waypoints, waydirs, or log an error.

Does nothing for a generic RouteRule. Subtypes of RouteRule may implement specialized methods to do their own validation when route! is called.

May insert inferred constraints to waypoints and waydirs to allow the path to be drawn leg-by-leg. For example, reconcile! with rule::StraightAnd90, no waypoints, and α1(path) == end_direction will insert a waypoint halfway between p1(path) and endpoint, allowing two successive StraightAnd90 legs with opposite bends.

source

Route inspection

DeviceLayout.Paths.p0Method
p0(s::Segment{T}) where {T}

Return the first point in a segment (calculated).

source
p0(r::Route)

First point of a route, returns r.p0.

source
DeviceLayout.Paths.p1Method
p1(s::Segment{T}) where {T}

Return the last point in a segment (calculated).

source
p1(r::Route)

Last point of a route, returns r.p1.

source