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
0 commit comments