Skip to content

Commit 96cd0de

Browse files
committed
Manual channel routing prototype
1 parent 74634d6 commit 96cd0de

File tree

17 files changed

+267
-6
lines changed

17 files changed

+267
-6
lines changed

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ version = "1.4.2"
44

55
[deps]
66
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
7+
BipartiteMatching = "79040ab4-24c8-4c92-950c-d48b5991a0f6"
78
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
89
Clipper = "c8f6d549-b3ab-5508-a0d1-48fe138e8cc1"
910
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
1011
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298"
1112
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
13+
Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9"
1214
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
1315
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
1416
Gmsh = "705231aa-382f-11e9-3f0c-b7cb4346fdeb"
@@ -43,6 +45,7 @@ SchematicGraphMakieExt = "GraphMakie"
4345
[compat]
4446
Accessors = "0.1"
4547
Aqua = "0.8"
48+
BipartiteMatching = "0.1.1"
4649
Cairo = "1.0"
4750
Clipper = "0.6"
4851
ColorSchemes = "3"

src/DeviceLayout.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ Return the coordinate type of the geometry.
191191
coordinatetype(::Type{S}) where {T, S <: AbstractGeometry{T}} = T
192192
coordinatetype(::S) where {T, S <: AbstractGeometry{T}} = T
193193
coordinatetype(::AbstractArray{S}) where {T, S <: AbstractGeometry{T}} = T
194-
coordinatetype(iterable) = promote_type(coordinatetype.(iterable))
194+
coordinatetype(iterable) = promote_type(coordinatetype.(iterable)...)
195195

196196
# Entity interface
197197
include("entities.jl")

src/hooks.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Contains information describing how one component can attach to others.
55
"""
66
abstract type Hook{T} <: AbstractGeometry{T} end
7+
getp(h::Hook) = h.p
78

89
"""
910
PointHook(p::Point, in_direction)

src/paths/channels.jl

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
"""
2+
RouteChannel{T} <: AbstractComponent{T}
3+
RouteChannel(pa::Path)
4+
"""
5+
struct RouteChannel{T} <: AbstractComponent{T}
6+
path::Path{T}
7+
node::Node{T} # path as single node
8+
capacity::Int # Currently unused
9+
end
10+
11+
function RouteChannel(pa::Path{T}, capacity=0) where {T}
12+
length(nodes(pa)) != 1 && return RouteChannel{T}(pa, simplify(pa), capacity)
13+
return RouteChannel{T}(pa, only(nodes(pa)), capacity)
14+
end
15+
16+
# Return a node corresponding to the section of the channel that the segment actually runs through
17+
function segment_channel_section(ch::RouteChannel{T}, wireseg_start, wireseg_stop, prev_width, next_width; margin=zero(T)) where {T}
18+
d = wireseg_stop - wireseg_start
19+
# Adjust for margins and track vs channel direction to get the channel node section used by actual segment
20+
if abs(d) <= 2*margin + prev_width + next_width
21+
# handle case where margin consumes entire segment
22+
# Just have a zero length Straight at the midpoint
23+
track_mid = (wireseg_start + wireseg_stop)/2
24+
midpoint = ch.node.seg(track_mid)
25+
middir = direction(ch.node.seg, track_mid)
26+
channel_section = Node(Straight(zero(T), midpoint, middir), SimpleTrace(width(ch.node.sty, track_mid)))
27+
elseif d > zero(d) # segment is along channel direction
28+
channel_section = split(ch.node,
29+
[wireseg_start + margin + prev_width/2,
30+
wireseg_stop - margin - next_width/2])[2]
31+
elseif d < zero(d) # segment is counter to channel direction
32+
channel_section = reverse(split(ch.node,
33+
[wireseg_stop + margin + next_width/2,
34+
wireseg_start - margin - prev_width/2])[2])
35+
end
36+
return channel_section
37+
end
38+
39+
function track_path_segment(n_tracks, channel_section, track_idx; reversed=false)
40+
return offset(channel_section.seg,
41+
track_section_offset(n_tracks, width(channel_section.sty), track_idx; reversed))
42+
end
43+
44+
function track_section_offset(n_tracks, section_width::Coordinate, track_idx; reversed=false)
45+
# (spacing) * number of tracks away from middle track
46+
sgn = reversed ? -1 : 1
47+
spacing = section_width / (n_tracks + 1)
48+
return sgn * spacing * (track_idx - (1 + n_tracks) / 2)
49+
end
50+
51+
function track_section_offset(n_tracks, section_width::Function, track_idx; reversed=false)
52+
# (spacing) * number of tracks away from middle track
53+
return t -> (reversed ? -1 : 1) * (section_width(t) / (n_tracks + 1)) * (track_idx - (1 + n_tracks) / 2)
54+
end
55+
56+
reverse(n::Node) = Paths.Node(reverse(n.seg), reverse(n.sty, pathlength(n.seg)))
57+
######## Methods required to use segments and styles as RouteChannels
58+
function reverse(b::BSpline{T}) where {T}
59+
p = reverse(b.p)
60+
t0 = RotationPi()(b.t1)
61+
t1 = RotationPi()(b.t0)
62+
# Use true t range for interpolations defined by points that have been scaled out of [0,1]
63+
tmin = b.r.ranges[1][1]
64+
tmax = b.r.ranges[1][end]
65+
(tmin == 0 && tmax == 1) && return BSpline(p, t0, t1)
66+
p0 = b.p1
67+
p1 = b.p0
68+
r = Interpolations.scale(
69+
interpolate(p, Interpolations.BSpline(Cubic(NeumannBC(t0, t1)))),
70+
range(1-tmax, stop=1-tmin, length=length(p))
71+
)
72+
α0 = rotated_direction(b.α1, RotationPi())
73+
α1 = rotated_direction(b.α0, RotationPi())
74+
return BSpline(p, t0, t1, r, p0, p1, α0, α1)
75+
end
76+
reverse(s::Turn) = Turn(-s.α, s.r, p1(s), α1(s) + 180°)
77+
reverse(s::Straight) = Straight(s.l, p1(s), s.α0 + 180°)
78+
# Reversing a GeneralTrace requires knowing its length, so we'll require that as an argument even if unused
79+
reverse(s::TaperTrace{T}, l) where {T} = TaperTrace{T}(s.width_end, s.width_start, s.length)
80+
reverse(s::SimpleTrace, l) = s
81+
reverse(s::GeneralTrace, l) = GeneralTrace(t -> width(s, l - t))
82+
# Define methods for CPW even though they're not allowed for channels
83+
reverse(s::TaperCPW{T}, l) where {T} = TaperCPW{T}(s.trace_end, s.gap_end, s.trace_start, s.gap_start, s.length)
84+
reverse(s::SimpleCPW, l) = s
85+
reverse(s::GeneralCPW, l) = GeneralCPW(t -> trace(s, l - t), t -> gap(s, l - t))
86+
# For compound segments, reverse the individual sections and reverse their order
87+
# Keep the same tag so if a compound segment/style pair matched before they will still match
88+
reverse(s::CompoundSegment) = CompoundSegment(reverse(reverse.(s.segments)), s.tag)
89+
function reverse(s::CompoundStyle{T}, l) where {T}
90+
lengths = reverse(diff(s.tgrid))
91+
CompoundStyle{T}(reverse(reverse.(s.styles, lengths)), cumsum(reverse(lengths)), s.tag)
92+
end
93+
94+
abstract type AbstractMultiRouting <: RouteRule end
95+
96+
abstract type AbstractChannelRouting <: AbstractMultiRouting end
97+
98+
function _route!(p::Path{T}, p1::Point, α1, rule::AbstractChannelRouting,
99+
sty, waypoints, waydirs) where {T}
100+
# Track segments for each channel
101+
track_path_segs = track_path_segments(rule, p, p1)
102+
waypoints = Point{T}[] # Segments too short for margins will just become waypoints for transitions
103+
# Add segments and transitions
104+
for (track_path_seg, next_entry_rule) in zip(track_path_segs, entry_rules(rule))
105+
if iszero(pathlength(track_path_seg)) # Was too short for margins
106+
push!(waypoints, p0(track_path_seg))
107+
else
108+
route!(p, p0(track_path_seg), α0(track_path_seg), next_entry_rule, sty; waypoints)
109+
push!(p, Node(track_path_seg, sty), reconcile=false) # already reconciled by construction
110+
empty!(waypoints)
111+
end
112+
end
113+
# Exit
114+
route!(p, p1, α1, exit_rule(rule), sty; waypoints)
115+
return
116+
end
117+
118+
struct SingleChannelRouting{T} <: AbstractChannelRouting
119+
channel::RouteChannel{T}
120+
transition_rules::Tuple{<:RouteRule,<:RouteRule}
121+
transition_margins::Tuple{T,T}
122+
segment_tracks::Dict{Path{T}, Int}
123+
end
124+
function SingleChannelRouting(ch::RouteChannel{T}, rule::RouteRule, margin::T) where {T}
125+
return SingleChannelRouting{T}(ch, (rule, rule), (margin, margin), Dict{Path{T}, Int}())
126+
end
127+
entry_rules(scr::SingleChannelRouting) = [first(scr.transition_rules)]
128+
exit_rule(scr::SingleChannelRouting) = last(scr.transition_rules)
129+
entry_margin(scr::SingleChannelRouting) = first(scr.transition_margins)
130+
exit_margin(scr::SingleChannelRouting) = last(scr.transition_margins)
131+
num_tracks(scr::SingleChannelRouting) = maximum(values(scr.segment_tracks))
132+
track_idx(scr, pa) = scr.segment_tracks[pa]
133+
function set_track!(scr, pa, track_idx)
134+
scr.segment_tracks[pa] = track_idx
135+
end
136+
137+
function track_path_segments(rule::SingleChannelRouting, pa::Path, endpt)
138+
wireseg_start = pathlength_nearest(rule.channel.node.seg, p1(pa))
139+
wireseg_stop = pathlength_nearest(rule.channel.node.seg, endpt)
140+
return [track_path_segment(num_tracks(rule),
141+
segment_channel_section(rule.channel, wireseg_start, wireseg_stop, 2*entry_margin(rule), 2*exit_margin(rule)),
142+
track_idx(rule, pa),
143+
reversed=wireseg_start > wireseg_stop)]
144+
end
145+
146+
function _update_with_graph!(rule::SingleChannelRouting, route_node, graph; track=num_tracks(rule)+1, kwargs...)
147+
set_track!(rule, route_node.component._path, track)
148+
end

src/paths/contstyles/strands.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ extent(s::GeneralStrands, t) =
3232
offset(s::GeneralStrands, t) = s.offset(t)
3333
width(s::GeneralStrands, t) = s.width(t)
3434
spacing(s::GeneralStrands, t) = s.spacing(t)
35-
num(s::GeneralStrands, t) = s.num
35+
num(s::GeneralStrands, t...) = s.num
3636
translate(s::GeneralStrands, t) =
3737
GeneralStrands(x -> s.offset(x + t), x -> s.width(x + t), x -> s.spacing(x + t), s.num)
3838

src/paths/contstyles/tapers.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ copy(x::TaperTrace{T}) where {T} = TaperTrace{T}(x.width_start, x.width_end, x.l
1717
extent(s::TaperTrace, t) = 0.5 * width(s, t)
1818
width(s::TaperTrace, t) =
1919
(1 - uconvert(NoUnits, t / s.length)) * s.width_start + t / s.length * s.width_end
20+
width(s::TaperTrace) = t -> width(s, t)
21+
trace(s::TaperTrace, t) = width(s, t)
2022

2123
function pin(s::TaperTrace{T}; start=nothing, stop=nothing) where {T}
2224
iszero(s.length) && error("cannot `pin`; length of $s not yet determined.")

src/paths/contstyles/trace.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ struct GeneralTrace{T} <: Trace{false}
1212
end
1313
copy(x::GeneralTrace) = GeneralTrace(x.width)
1414
extent(s::GeneralTrace, t) = 0.5 * s.width(t)
15+
extent(s::GeneralTrace) = t -> 0.5 * s.width(t)
1516
width(s::GeneralTrace, t) = s.width(t)
17+
width(s::GeneralTrace) = s.width
1618
trace(s::GeneralTrace, t) = s.width(t)
1719
translate(s::GeneralTrace, t) = GeneralTrace(x -> s.width(x + t))
1820

src/paths/paths.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import Base:
2626
intersect!,
2727
show,
2828
summary,
29-
dims2string
29+
dims2string,
30+
reverse
3031

3132
import Base.Iterators
3233

@@ -48,6 +49,7 @@ import DeviceLayout:
4849
Hook,
4950
Meta,
5051
PointHook,
52+
Polygon,
5153
Polygons,
5254
Reflection,
5355
Rotation,
@@ -350,7 +352,7 @@ Return `s` on `seg` that minimizes `norm(seg(s) - pt)`.
350352
"""
351353
function pathlength_nearest(seg::Paths.Segment{T}, pt::Point) where {T}
352354
errfunc(s) = ustrip(unit(T), norm(seg(s * pathlength(seg)) - pt))
353-
return Optim.minimizer(optimize(errfunc, 0.0, 1.0))[1] * oneunit(T)
355+
return Optim.minimizer(optimize(errfunc, 0.0, 1.0))[1] * pathlength(seg)
354356
end
355357

356358
"""
@@ -694,6 +696,9 @@ include("segments/bspline_optimization.jl")
694696

695697
include("routes.jl")
696698

699+
include("channels.jl")
700+
include("channel_routers.jl")
701+
697702
function change_handedness!(seg::Union{Turn, Corner})
698703
return seg.α = -seg.α
699704
end

src/paths/routes.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,6 @@ function _route_leg!(
610610
turn!(p, 45° * sign(perp), bend_r, seg_sty[2])
611611
return d_diag > zero(dx) && straight!(p, d_diag, seg_sty[3])
612612
end
613+
614+
function _update_with_plan!(rule::RouteRule, route_node, schematic) end
615+
function _update_with_graph!(rule::RouteRule, route_node, graph; kwargs...) end

src/paths/segments/compound.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ end
2828
copy(s::CompoundSegment) = (typeof(s))(s.segments, s.tag)
2929
CompoundSegment(nodes::AbstractVector{Node{T}}, tag=gensym()) where {T} =
3030
CompoundSegment{T}(map(segment, nodes), tag)
31-
CompoundSegment(segments::AbstractVector{Segment{T}}, tag=gensym()) where {T} =
31+
CompoundSegment(segments::AbstractVector{<:Segment{T}}, tag=gensym()) where {T} =
3232
CompoundSegment{T}(segments, tag)
3333

3434
convert(::Type{CompoundSegment{T}}, x::CompoundSegment) where {T} =

0 commit comments

Comments
 (0)