Path API Reference
Paths
DeviceLayout.Paths.Path — Type
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}DeviceLayout.Paths.α0 — Function
α0(s::Segment)Return the first angle in a segment (calculated).
α0(p::Path)First angle of a path, returns p.α0.
α0(r::Route)First angle of a route, returns r.α0.
DeviceLayout.Paths.α1 — Function
α1(s::Segment)Return the last angle in a segment (calculated).
α1(p::Path)Last angle of a path.
α1(r::Route)Last angle of a route, returns r.α1.
DeviceLayout.Paths.direction — Function
direction(s, t)Return the angle at which some function t->Point(x(t),y(t)) is pointing.
DeviceLayout.Paths.pathlength — Function
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.
DeviceLayout.Paths.p0 — Function
p0(s::Segment{T}) where {T}Return the first point in a segment (calculated).
p0(p::Path)First point of a path, returns p.p0.
p0(r::Route)First point of a route, returns r.p0.
DeviceLayout.Paths.p1 — Function
p1(s::Segment{T}) where {T}Return the last point in a segment (calculated).
p1(p::Path)Last point of a path.
p1(r::Route)Last point of a route, returns r.p1.
DeviceLayout.Paths.style0 — Function
style0(p::Path)Style of the first segment of a path.
DeviceLayout.Paths.style1 — Function
style1(p::Path)Undecorated style of the last user-provided (non-virtual) segment of a path.
Throws an error if the path is empty.
DeviceLayout.Paths.discretestyle1 — Function
discretestyle1(p::Path)Return the last-used discrete style in the path.
DeviceLayout.Paths.contstyle1 — Function
contstyle1(p::Path)Return the undecorated last user-provided (non-virtual) continuous style in the path.
Throws an error if the path is empty.
DeviceLayout.Paths.nextstyle — Function
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
TaperTraceis followed by aSimpleTracewith its final width - A
TaperCPWis followed by aSimpleCPWwith its final trace and gap - A
CompoundStyle(fromsimplify!) is followed by its last style - An
OverlayStyle(fromoverlay!) is followed by anOverlayStyleusing thenextstylefor 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.
Path Manipulation
DeviceLayout.Paths.setp0! — Function
setp0!(s::Straight, p::Point)Set the p0 of a straight segment.
setp0!(s::Turn, p::Point)Set the p0 of a turn.
setp0!(b::BSpline, p::Point)Translate the interpolated segment so its initial point is p.
DeviceLayout.Paths.setα0! — Function
setα0!(s::Straight, α0′)Set the angle of a straight segment.
setα0!(s::Turn, α0′)Set the starting angle of a turn.
setα0!(b::BSpline, α0′)Set the starting angle of an interpolated segment.
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.
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°.
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.
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.
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 launchertrace0 = 300.0μm: Trace width of the padtrace1 = 10.0μm: Trace width of the launched CPWgap0 = 150.0μm: Gap width of the padgap1 = 6.0μm: Gap width of the final CPWflatlen = 250.0μm: Length of the padtaperlen = 250.0μm: Length of the taper between pad and launched CPW
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.
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
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.
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.
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.
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:
α_maxcontrols the maximum angle between the taper edge and the path direction.0° < α_max < 90°is required.radiussets a lower bound on the edge radius of curvature (e.g. for fab constraints). When bothα_maxandradiusare provided, the more conservative constraint wins.sidecontrols which segment donates space for the taper::before(default) takes from the preceding segment,:aftertakes 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.
DeviceLayout.Paths.simplify — Function
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.
DeviceLayout.Paths.simplify! — Function
simplify!(p::Path, inds::UnitRange=firstindex(p):lastindex(p))In-place version of simplify.
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.
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" ifiszero(gap)and is an "open termination" with a gap ofgapotherwise, defaulting to the gap of the preceding CPW. Has no effect forTraceterminations.initial: Iftrue, the termination is added at the beginning of thePath.margin: If positive, the termination will begin an additional lengthmarginaway from the end of the path (adding to the backtracking to accommodaterounding). 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.
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.
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.
Path Intersection
DeviceLayout.Intersect.IntersectStyle — Type
IntersectStyle{N}Abstract type specifying "2-body interactions" for path intersection.
DeviceLayout.Intersect.AirBridge — Type
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 uniqueCoordinateSystemnamescaffold_meta: Scaffold layer metadataair_bridge_meta: Air bridge layer metadatacrossing_gap: Extra length beyond extent of path being crossed (on one side)foot_gap: Extra length beyond original path termination before bridge foot startsfoot_length: Length of bridge footextent_gap: Gap between edge of bridge trace and edge of original path tracescaffold_gap: Gap between edge of original trace and edge of scaffoldrounding: Rounding radius for scaffold and air bridge rectanglesunit: Coordinate system unit
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).
Path Nodes
DeviceLayout.Paths.Node — Type
Node(a::Segment{T}, b::Style) where {T}Create a node with segment a and style b.
DeviceLayout.Paths.previous — Function
previous(x::Node)Return the node before x in a doubly linked list.
DeviceLayout.Paths.next — Function
next(x::Node)Return the node after x in a doubly linked list.
DeviceLayout.Paths.segment — Function
segment(x::Node)Return the segment associated with node x.
Base.split — Method
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))
DeviceLayout.style — Function
style(x::Node)Return the style associated with node x.
style(styled_ent::StyledEntity)Return the GeometryEntityStyle of styled_ent.
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).
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.
Path Segments
DeviceLayout.Paths.Segment — Type
abstract type Segment{T<:Coordinate} endPath segment in the plane. All Segment objects should have the implement the following methods:
pathlengthp0α0setp0!setα0!α1
DeviceLayout.Paths.Straight — Type
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.
DeviceLayout.Paths.Turn — Type
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.
DeviceLayout.Paths.Corner — Type
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).
DeviceLayout.Paths.CompoundSegment — Type
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.
DeviceLayout.Paths.BSpline — Type
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.
Path Styles
DeviceLayout.Paths.Style — Type
abstract type Style endHow to render a given path segment.
DeviceLayout.Paths.ContinuousStyle — Type
abstract type ContinuousStyle{CanStretch} <: Style endAny 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.
DeviceLayout.Paths.DiscreteStyle — Type
abstract type DiscreteStyle <: Style endAny style that applies to segments which have zero path length.
DeviceLayout.Paths.Trace — Type
Trace(width)
Trace(width::Coordinate)
Trace(width_start::Coordinate, width_end::Coordinate)Constructor for Trace styles. Automatically chooses SimpleTrace, GeneralTrace, and TaperTrace as appropriate.
DeviceLayout.Paths.CPW — Type
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.
DeviceLayout.Paths.Taper — Type
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.
DeviceLayout.Paths.Strands — Type
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 wConstructors for Strands styles. Automatically chooses between SimpleStrandsor GeneralStrands styles as appropriate.
DeviceLayout.Paths.NoRender — Type
struct NoRender <: StyleStyle 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.
DeviceLayout.Paths.SimpleNoRender — Type
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!.
DeviceLayout.Paths.SimpleTrace — Type
struct SimpleTrace{T <: Coordinate} <: Trace{false}
width::T
endA single trace with fixed width as a function of path length.
DeviceLayout.Paths.GeneralTrace — Type
struct GeneralTrace{T} <: Trace{false}
width::T
endA single trace with variable width as a function of path length. width is callable.
DeviceLayout.Paths.SimpleCPW — Type
struct SimpleCPW{T <: Coordinate} <: CPW{false}
trace::T
gap::T
endA CPW with fixed trace and gap as a function of path length.
DeviceLayout.Paths.GeneralCPW — Type
struct GeneralCPW{S, T} <: CPW{false}
trace::S
gap::T
endA CPW with variable trace and gap as a function of path length. trace and gap are callable.
DeviceLayout.Paths.TaperTrace — Type
struct TaperTrace{T<:Coordinate} <: Trace{true}
width_start::T
width_end::T
length::T
endA single trace with a linearly tapered width as a function of path length.
DeviceLayout.Paths.TaperCPW — Type
struct TaperCPW{T<:Coordinate} <: CPW{true}
trace_start::T
gap_start::T
trace_end::T
gap_end::T
length::T
endA CPW with a linearly tapered trace and gap as a function of path length.
DeviceLayout.Paths.SimpleStrands — Type
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 wStrands with fixed center offset, width, and spacing as a function of path length.
DeviceLayout.Paths.GeneralStrands — Type
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 wStrands with variable center offset, width, and spacing as a function of path length. offset, width, and spacing are callable.
DeviceLayout.Paths.CompoundStyle — Type
struct CompoundStyle{T<:FloatCoordinate} <: AbstractCompoundStyle
styles::Vector{Style}
grid::Vector{T}
endCombines 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 oftvalues needed for rendering the parametric path.
DeviceLayout.Paths.DecoratedStyle — Type
mutable struct DecoratedStyle{T<:FloatCoordinate} <: ContinuousStyle{false}
s::Style
ts::Vector{Float64}
dirs::Vector{Int}
refs::Vector{GeometryReference}
endStyle with decorations, like structures periodically repeated along the path, etc.
DeviceLayout.Paths.PeriodicStyle — Type
struct PeriodicStyle{T <: Coordinate} <: AbstractCompoundStyleContinuous 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.
DeviceLayout.Paths.pin — Function
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)).
DeviceLayout.Paths.translate — Function
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.
DeviceLayout.Paths.undecorated — Function
undecorated(s::DecoratedStyle)
undecorated(s::Style)Return the underlying, undecorated style if decorated; otherwise just return the style.
Routes
DeviceLayout.Paths.Route — Type
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].
Route rules
DeviceLayout.Paths.RouteRule — Type
abstract type RouteRule endControls 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.
DeviceLayout.Paths.BSplineRouting — Type
Base.@kwdef struct BSplineRouting <: RouteRule
endpoints_speed = 2500μm
auto_speed = false
endpoints_curvature = nothing
auto_curvature = false
endSpecifies 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.
DeviceLayout.Paths.StraightAnd90 — Type
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.
DeviceLayout.Paths.StraightAnd45 — Type
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.
DeviceLayout.Paths.CompoundRouteRule — Type
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.
DeviceLayout.Paths.SingleChannelRouting — Type
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.
DeviceLayout.Paths.RouteChannel — Type
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.
Route drawing
DeviceLayout.Paths.Path — Method
Path(r::Route, sty)The explicit Path defined by r, with style sty.
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.
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.
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.
Route inspection
DeviceLayout.Paths.p0 — Method
p0(s::Segment{T}) where {T}Return the first point in a segment (calculated).
p0(r::Route)First point of a route, returns r.p0.
DeviceLayout.Paths.α0 — Method
α0(s::Segment)Return the first angle in a segment (calculated).
α0(r::Route)First angle of a route, returns r.α0.
DeviceLayout.Paths.p1 — Method
p1(s::Segment{T}) where {T}Return the last point in a segment (calculated).
p1(r::Route)Last point of a route, returns r.p1.
DeviceLayout.Paths.α1 — Method
α1(r::Route)Last angle of a route, returns r.α1.