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.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.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.

source
DeviceLayout.Paths.BSplineRoutingType
Base.@kwdef struct BSplineRouting <: RouteRule
    endpoints_speed = 2500μm
end

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

Ignores waydirs.

source
DeviceLayout.Paths.StraightAnd90Type
Base.@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.

source
DeviceLayout.Paths.StraightAnd45Type
Base.@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.

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

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.route!Function
function 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.

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 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.

source

Route inspection

A Route supports endpoint inspection much like a Path does:

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