Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
- run: |
git config --global user.name github-actions
git config --global user.email github-actions@github.com
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.13'
cache: 'pip' # caching pip dependencies
Expand Down
4 changes: 3 additions & 1 deletion src/DeviceLayout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -462,12 +462,13 @@ export CoordinateSystems,
traverse!

include("hooks.jl")
export HandedPointHook, Hook, PointHook, compass, in_direction, out_direction
export HandedPointHook, Hook, PointHook, compass, hook_style, in_direction, out_direction

include("paths/paths.jl")
import .Paths:
Path,
Route,
StyledHook,
α0,
α1,
reconcile!,
Expand Down Expand Up @@ -513,6 +514,7 @@ import .Paths:
export Paths,
Path,
Route,
StyledHook,
α0,
α1,
reconcile!,
Expand Down
9 changes: 9 additions & 0 deletions src/hooks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ end
DeviceLayout.transform(x::HandedPointHook, f::Transformation) =
HandedPointHook(f(x.h), xrefl(f) ⊻ x.right_handed)

"""
hook_style(h::Hook)

Return the path style associated with a hook, or `nothing` if the hook has no
style. Only `StyledHook` carries a style; bare `PointHook` and `HandedPointHook`
return `nothing`.
"""
hook_style(::Hook) = nothing

Base.keys(h::Hook) = error(
"No method matching keys(::Hook). You might be missing a leading semicolon in a `hooks` method returning a single hook: `return (hookname=h)` should be `return (; hookname=h)`."
)
20 changes: 2 additions & 18 deletions src/paths/channels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function track_section_offset(n_tracks, section_width::Function, track_idx; reve
end

reverse(n::Node) = Paths.Node(reverse(n.seg), reverse(n.sty, pathlength(n.seg)))
######## Methods required to use segments and styles as RouteChannels
######## Methods required to use segments as RouteChannels
function reverse(b::BSpline{T}) where {T}
p = reverse(b.p)
t0 = RotationPi()(b.t1)
Expand All @@ -117,15 +117,6 @@ function reverse(b::BSpline{T}) where {T}
end
reverse(s::Turn) = Turn(-s.α, s.r, p1(s), α1(s) + 180°)
reverse(s::Straight) = Straight(s.l, p1(s), s.α0 + 180°)
# Reversing a GeneralTrace requires knowing its length, so we'll require that as an argument even if unused
reverse(s::TaperTrace{T}, l) where {T} = TaperTrace{T}(s.width_end, s.width_start, s.length)
reverse(s::SimpleTrace, l) = s
reverse(s::GeneralTrace, l) = GeneralTrace(t -> width(s, l - t))
# Define methods for CPW even though they're not allowed for channels
reverse(s::TaperCPW{T}, l) where {T} =
TaperCPW{T}(s.trace_end, s.gap_end, s.trace_start, s.gap_start, s.length)
reverse(s::SimpleCPW, l) = s
reverse(s::GeneralCPW, l) = GeneralCPW(t -> trace(s, l - t), t -> gap(s, l - t))
# For compound segments, reverse the individual sections and reverse their order
# Keep the same tag so if a compound segment/style pair matched before they will still match
reverse(s::CompoundSegment) = CompoundSegment(reverse(reverse.(s.segments)), s.tag)
Expand All @@ -139,14 +130,7 @@ function reverse(s::GeneralOffset{T, S}) where {T, S}
l = pathlength(s.seg)
return GeneralOffset{T, S}(reverse(s.seg), t -> -s.offset(l - t))
end
function reverse(s::CompoundStyle{T}, l) where {T}
lengths = diff(s.grid)
return CompoundStyle{T}(
reverse(reverse.(s.styles, lengths)),
[zero(T); cumsum(reverse(lengths))],
s.tag
)
end
# `reverse(s::Style, l)` methods are implemented in corresponding style files

abstract type AbstractMultiRouting <: RouteRule end

Expand Down
9 changes: 9 additions & 0 deletions src/paths/contstyles/compound.jl
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,12 @@ function pin(s::CompoundStyle; start=nothing, stop=nothing, tag=gensym())
end
return copy(s, tag)
end

function reverse(s::CompoundStyle{T}, l) where {T}
lengths = diff(s.grid)
return CompoundStyle{T}(
reverse(reverse.(s.styles, lengths)),
[zero(T); cumsum(reverse(lengths))],
s.tag
)
end
2 changes: 2 additions & 0 deletions src/paths/contstyles/cpw.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ trace(s::GeneralCPW) = s.trace
gap(s::GeneralCPW, t) = s.gap(t)
gap(s::GeneralCPW) = s.gap
translate(s::GeneralCPW, t) = GeneralCPW(x -> s.trace(x + t), x -> s.gap(x + t))
reverse(s::GeneralCPW, l) = GeneralCPW(t -> trace(s, l - t), t -> gap(s, l - t))

"""
struct SimpleCPW{T <: Coordinate} <: CPW{false}
Expand All @@ -44,6 +45,7 @@ extent(s::SimpleCPW, t...) = s.trace / 2 + s.gap
trace(s::SimpleCPW, t...) = s.trace
gap(s::SimpleCPW, t...) = s.gap
translate(s::SimpleCPW, t) = copy(s)
reverse(s::SimpleCPW, l) = s

"""
CPW(trace::Coordinate, gap::Coordinate)
Expand Down
12 changes: 12 additions & 0 deletions src/paths/contstyles/decorated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ A copy of `sty`, with shallow copies of attached references.
Base.copy(sty::DecoratedStyle{T}) where {T} =
DecoratedStyle{T}(deepcopy(sty.s), copy(sty.ts), copy(sty.dirs), copy(sty.refs))

function reverse(s::DecoratedStyle{T}, l) where {T}
return DecoratedStyle{T}(
reverse(s.s, l),
l .- s.ts,
-1 .* s.dirs,
RotationPi().(s.refs)
)
end

"""
attach!(p::Path, c::GeometryReference, t::Coordinate;
i::Integer=length(p), location::Integer=0)
Expand Down Expand Up @@ -255,6 +264,9 @@ summary(s::OverlayStyle) = string(summary(s.s), " with ", length(s.overlay), " o
Base.copy(sty::OverlayStyle) =
OverlayStyle(deepcopy(sty.s), copy(sty.overlay), copy(sty.overlay_metadata))

reverse(s::OverlayStyle, l) =
OverlayStyle(reverse(s.s, l), reverse.(s.overlay, l), s.overlay_metadata)

function _refs(segment::Paths.Segment{T}, s::OverlayStyle) where {T}
cs = DeviceLayout.CoordinateSystem{T}(uniquename("overlay"))
for (oversty, meta) in zip(s.overlay, s.overlay_metadata)
Expand Down
11 changes: 10 additions & 1 deletion src/paths/contstyles/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function width end
"""
translate(s::ContinuousStyle, x)

Creates a style `s′` such that all properties `f(s′, t) == f(s, t+x)`. Basically, advance
Create a style `s′` such that all properties `f(s′, t) == f(s, t+x)`. Basically, advance
the style forward by path length `x`.
"""
function translate end
Expand All @@ -37,3 +37,12 @@ function pin(s::ContinuousStyle{false}; start=nothing, stop=nothing)
end
return s
end

"""
reverse(s::Style, l)

Create a style `s′` such that all properties `f(s′, x) == f(s, l - x)`. Basically, reverse
the style assuming it is applied to a segment of pathlength `l`.
"""
function reverse end
# Reversing a GeneralTrace/CPW requires knowing its length, so we require that as an argument even if unused
8 changes: 8 additions & 0 deletions src/paths/contstyles/periodic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,11 @@ undecorated(sty::PeriodicStyle) =
function translate(sty::PeriodicStyle, x)
return PeriodicStyle(sty.styles, sty.lengths, sty.l0 + x)
end

function reverse(s::PeriodicStyle{T}, l) where {T}
return PeriodicStyle{T}(
reverse(reverse.(s.styles, s.lengths)),
reverse(s.lengths),
sum(s.lengths) - ((s.l0 + l) % sum(s.lengths))
)
end
3 changes: 3 additions & 0 deletions src/paths/contstyles/strands.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ spacing(s::GeneralStrands, t) = s.spacing(t)
num(s::GeneralStrands, t...) = s.num
translate(s::GeneralStrands, t) =
GeneralStrands(x -> s.offset(x + t), x -> s.width(x + t), x -> s.spacing(x + t), s.num)
reverse(s::GeneralStrands, l) =
GeneralStrands(x -> s.offset(l - x), x -> s.width(l - x), x -> s.spacing(l - x), s.num)

"""
struct SimpleStrands{T<:Coordinate} <: Strands{false}
Expand Down Expand Up @@ -67,6 +69,7 @@ width(s::SimpleStrands, t...) = s.width
spacing(s::SimpleStrands, t...) = s.spacing
num(s::SimpleStrands, t...) = s.num
translate(s::SimpleStrands, t) = copy(s)
reverse(s::SimpleStrands, l) = s

"""
Strands(offset::Coordinate, width::Coordinate, spacing::Coordinate, num::Int)
Expand Down
5 changes: 5 additions & 0 deletions src/paths/contstyles/tapers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ width(s::TaperTrace, t) =
width(s::TaperTrace) = t -> width(s, t)
trace(s::TaperTrace, t) = width(s, t)
trace(s::TaperTrace) = width(s)
reverse(s::TaperTrace{T}, l) where {T} = TaperTrace{T}(s.width_end, s.width_start, s.length)

function pin(s::TaperTrace{T}; start=nothing, stop=nothing) where {T}
iszero(s.length) && error("cannot `pin`; length of $s not yet determined.")
Expand Down Expand Up @@ -126,6 +127,9 @@ function pin(sty::TaperCPW{T}; start=nothing, stop=nothing) where {T}
)
end

reverse(s::TaperCPW{T}, l) where {T} =
TaperCPW{T}(s.trace_end, s.gap_end, s.trace_start, s.gap_start, s.length)

nextstyle(sty::TaperCPW) = CPW(sty.trace_end, sty.gap_end)

summary(s::TaperTrace) = string(
Expand Down Expand Up @@ -153,6 +157,7 @@ between an initial `CPW` or `Trace` and an end `CPW` or `Trace` of different dim
"""
struct Taper <: ContinuousStyle{false} end
copy(::Taper) = Taper()
reverse(s::Taper, l) = s

summary(::Taper) = string("Generic linear taper between neighboring segments in a path")

Expand Down
24 changes: 24 additions & 0 deletions src/paths/contstyles/termination.jl
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,27 @@ end
function nextstyle(::Union{TraceTermination, CPWOpenTermination, CPWShortTermination})
return NoRenderContinuous()
end

function reverse(sty::CPWOpenTermination{T}, l) where {T}
return CPWOpenTermination{T}(
sty.trace,
sty.gap,
sty.open_gap,
sty.rounding,
!sty.initial
)
end

function reverse(sty::CPWShortTermination{T}, l) where {T}
return CPWShortTermination{T}(
sty.trace,
sty.gap,
sty.open_gap,
sty.rounding,
!sty.initial
)
end

function reverse(sty::TraceTermination{T}, l) where {T}
return TraceTermination{T}(sty.width, sty.rounding, !sty.initial)
end
2 changes: 2 additions & 0 deletions src/paths/contstyles/trace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ width(s::GeneralTrace) = s.width
trace(s::GeneralTrace, t) = s.width(t)
trace(s::GeneralTrace) = s.width
translate(s::GeneralTrace, t) = GeneralTrace(x -> s.width(x + t))
reverse(s::GeneralTrace, l) = GeneralTrace(t -> width(s, l - t))

"""
struct SimpleTrace{T <: Coordinate} <: Trace{false}
Expand All @@ -34,6 +35,7 @@ extent(s::SimpleTrace, t...) = 0.5 * s.width
width(s::SimpleTrace, t...) = s.width
trace(s::SimpleTrace, t...) = s.width
translate(s::SimpleTrace, t) = copy(s)
reverse(s::SimpleTrace, l) = s

"""
Trace(width)
Expand Down
1 change: 1 addition & 0 deletions src/paths/discretestyles/simple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
"""
struct SimpleTraceCorner <: DiscreteStyle end
Base.copy(c::SimpleTraceCorner) = c
reverse(c::SimpleTraceCorner, l) = c
2 changes: 2 additions & 0 deletions src/paths/norender.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ translate(s::SimpleNoRender, t) = copy(s)
translate(s::NoRenderContinuous, t) = copy(s)

pin(s::NoRender; start=nothing, stop=nothing) = s

reverse(s::Union{NoRender, NoRenderDiscrete, NoRenderContinuous, SimpleNoRender}, l) = s
66 changes: 56 additions & 10 deletions src/paths/paths.jl
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,45 @@ function pathlength_nearest(seg::Paths.Segment{T}, pt::Point) where {T}
return Optim.minimizer(optimize(errfunc, 0.0, 1.0))[1] * pathlength(seg)
end

### StyledHook definition for Paths
"""
StyledHook{T, H<:Hook{T}, S<:Paths.Style} <: Hook{T}
h::H
style::S

A `Hook` augmented with a path-style object. Used by graph-level `terminate!`
(and other style-aware operations) to read the cross-section that terminates at
the hook without consulting the owning component's internals. Wraps any
underlying `Hook` so `style` composes orthogonally with handedness.
"""
struct StyledHook{T, H <: Hook{T}, S <: Paths.Style} <: Hook{T}
h::H
style::S
end
StyledHook(h::Hook, ::Nothing) = StyledHook(h, Paths.NoRenderContinuous())

function DeviceLayout.transformation(h1::StyledHook, h2::StyledHook)
return transformation(getfield(h1, :h), getfield(h2, :h))
end
DeviceLayout.transformation(h1::StyledHook, h2::Hook) = transformation(getfield(h1, :h), h2)
DeviceLayout.transformation(h1::Hook, h2::StyledHook) = transformation(h1, getfield(h2, :h))

function Base.getproperty(h::StyledHook, s::Symbol)
(s === :h || s === :style) && return getfield(h, s)
return getproperty(getfield(h, :h), s)
end

function Base.propertynames(h::StyledHook)
return (:h, :style, propertynames(getfield(h, :h))...)
end

DeviceLayout.in_direction(h::StyledHook) = in_direction(getfield(h, :h))

DeviceLayout.transform(x::StyledHook, f::Transformation) =
StyledHook(transform(getfield(x, :h), f), getfield(x, :style))

DeviceLayout.hook_style(h::StyledHook) = getfield(h, :style)

"""
mutable struct Path{T<:Coordinate} <: AbstractComponent{T}

Expand Down Expand Up @@ -457,26 +496,33 @@ A `Path` starting at h, pointing along its outward direction.
path_out(h::Hook) = Path(h.p, α0=out_direction(h))

"""
p0_hook(pa::Path, right_handed=true) = HandedPointHook(p0(pa), α0(pa), right_handed)
p0_hook(pa::Path, right_handed=true) = StyledHook(HandedPointHook(p0(pa), α0(pa), right_handed), style)

A `HandedPointHook` looking into the start of path `pa`.
A `StyledHook` wrapping a `HandedPointHook` looking into the start of path `pa` with a `style`.

The style is `nothing` for an empty path and otherwise `nextstyle` of the reversed initial node.
"""
p0_hook(pa::Path, right_handed=true) = HandedPointHook(p0(pa), α0(pa), right_handed)
p0_hook(pa::Path, right_handed=true) = StyledHook(
HandedPointHook(p0(pa), α0(pa), right_handed),
isempty(pa.nodes) ? nothing :
nextstyle(without_attachments(reverse(pa[1].sty, pathlength(pa[1].seg))))
)

"""
p1_hook(pa::Path, right_handed=true) = HandedPointHook(p1(pa), α1(pa) + π, right_handed)
p1_hook(pa::Path, right_handed=true) = StyledHook(HandedPointHook(p1(pa), α1(pa) + π, right_handed), nextstyle(pa))

A `HandedPointHook` looking into the end of path `pa`.
A `StyledHook` wrapping a `HandedPointHook` looking into the end of path `pa` with `nextstyle(pa)`.
"""
p1_hook(pa::Path, right_handed=true) = HandedPointHook(p1(pa), α1(pa) + π, right_handed)
p1_hook(pa::Path, right_handed=true) =
StyledHook(HandedPointHook(p1(pa), α1(pa) + π, right_handed), nextstyle(pa))

"""
hooks(pa::Path)

- `:p0`: A `HandedPointHook` looking into the start of path `pa`.
- `:p1`: A `HandedPointHook` looking into the end of path `pa`.
- `:p0_lh`: A left-handed `HandedPointHook` looking into the start of path `pa`.
- `:p1_lh`: A left-handed `HandedPointHook` looking into the end of path `pa`.
- `:p0`: A right-handed `StyledHook` looking into the start of path `pa` with `nextstyle` of the reversed path.
- `:p1`: A right-handed `StyledHook` looking into the end of path `pa` with `nextstyle(pa)`.
- `:p0_lh`: A left-handed `StyledHook` looking into the start of path `pa` with `nextstyle` of the reversed path.
- `:p1_lh`: A left-handed `StyledHook` looking into the end of path `pa` with `nextstyle(pa)`.
"""
DeviceLayout.hooks(pa::Path) =
(p0=p0_hook(pa), p1=p1_hook(pa), p0_lh=p0_hook(pa, false), p1_lh=p1_hook(pa, false))
Expand Down
5 changes: 5 additions & 0 deletions src/schematics/SchematicDrivenLayout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import DeviceLayout:
Hook,
Meta,
PointHook,
StyledHook,
Transformation,
UPREFERRED
import DeviceLayout: hook_style
import DeviceLayout:
attach!,
autofill!,
Expand All @@ -51,10 +53,13 @@ import DeviceLayout:
map_metadata!,
name,
origin,
out_direction,
parameters,
refs,
render!,
sref,
straight!,
terminate!,
transform,
transformation,
_geometry!
Expand Down
Loading
Loading