Routes
A Paths.Route
implicitly defines a Path
between two points, following a Paths.RouteRule
, with a specified start and end direction. It's a building block for "interactive autorouting". For simple cases, it lets you define a path between two points without having to do any geometric calculations yourself. In more complicated cases, you can provide additional waypoint constraints to guide it.
To draw a Path
from a Route
, you can use Path(r::Route, sty)
.
More often, you won't work directly with the Route
type but will instead use route!
to extend an existing path to an endpoint according to the rules you specify.
Route API
DeviceLayout.Paths.Route
— Typestruct 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
— Typeabstract 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.contstyle1(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
— TypeBase.@kwdef struct BSplineRouting <: RouteRule
endpoints_speed = 2500μm
end
Specifies rules for routing from one point to another using BSplines.
Ignores waydirs
.
DeviceLayout.Paths.StraightAnd90
— TypeBase.@kwdef struct StraightAnd90 <: RouteRule
min_bend_radius = 200μm
max_bend_radius = Inf*μm
end
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
— TypeBase.@kwdef struct StraightAnd45 <: RouteRule
min_bend_radius = 200μm
max_bend_radius = Inf*μm
end
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
— TypeCompoundRouteRule <: 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.
Route drawing
Calling Path(r::Route, sty::Style)
creates a new Path
at p0(r)
, then extends it to p1(r)
using route!
. The default implementation of route!
, for a generic RouteRule
, first calls reconcile!
to validate and modify waypoints as necessary. It then calls _route!
to draw the path, which by default calls _route_leg!
to each waypoint in order. (A "leg" is an informal abstraction describing the "unit" that the RouteRule
works with, which may be more than one Paths.Segment
. For example, each leg in StraightAnd90
routing has a single 90-degree bend with up to one straight segment on either side, or a single straight segment if no bend is necessary.)
DeviceLayout.Paths.Path
— MethodPath(r::Route, sty)
The explicit Path
defined by r
, with style sty
.
DeviceLayout.Paths.route!
— Functionfunction route!(path::Path{S}, p_end::Point, α_end, rule::RouteRule, sty=Paths.contstyle1(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!
— Methodreconcile!(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 throw 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
A Route
supports endpoint inspection much like a Path
does:
DeviceLayout.Paths.p0
— Methodp0(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
— Methodp1(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
.