|
13 | 13 | /// - d (auto, str): Cardinal/diagonal direction from previous pin. |
14 | 14 | /// |
15 | 15 | /// - end (bool): Marks end of a section, allowing disconnected branches. |
| 16 | +/// - reverse (auto, bool): Whether the order of subsequent stations should be reversed. |
| 17 | +/// - reverse-before (bool): Whether to reverse the order of all previous stations. |
16 | 18 | /// |
17 | 19 | /// - cfg (str, none): Enabling conditions for subsequent segments. |
18 | 20 | /// - cfg-not (str, none): Disabling conditions for subsequent segments. |
|
32 | 34 | d: auto, |
33 | 35 | end: false, |
34 | 36 | reverse: auto, |
| 37 | + reverse-before: false, |
35 | 38 | cfg: auto, |
36 | 39 | cfg-not: auto, |
37 | 40 | layer: auto, |
|
42 | 45 | ( |
43 | 46 | raw-pos: (x: x, y: y, dx: dx, dy: dy, d: d), |
44 | 47 | end: end, |
45 | | - reverse: reverse, |
| 48 | + reversed: reverse, |
| 49 | + reverse-before: reverse-before, |
46 | 50 | cfg: cfg, |
47 | 51 | cfg-not: cfg-not, |
48 | 52 | layer: layer, |
|
56 | 60 | /// |
57 | 61 | /// - target (auto, str): The target station id where the loop ends. |
58 | 62 | /// |
| 63 | +/// - reverse (auto, bool): Whether the order of subsequent stations should be reversed. |
| 64 | +/// - reverse-before (bool): Whether to reverse the order of all previous stations. |
| 65 | +/// |
59 | 66 | /// - cfg (str, none): Enabling conditions for subsequent segments. |
60 | 67 | /// - cfg-not (str, none): Disabling conditions for subsequent segments. |
61 | 68 | /// |
|
66 | 73 | /// - ..metadata (arguments): Additional attributes of subsequent segments as named arguments. |
67 | 74 | #let loop( |
68 | 75 | target: auto, |
| 76 | + reverse: auto, |
| 77 | + reverse-before: false, |
69 | 78 | cfg: auto, |
70 | 79 | cfg-not: auto, |
71 | 80 | layer: auto, |
|
76 | 85 | ( |
77 | 86 | loop-target: target, |
78 | 87 | end: true, |
| 88 | + reversed: reverse, |
| 89 | + reverse-before: reverse-before, |
79 | 90 | cfg: cfg, |
80 | 91 | cfg-not: cfg-not, |
81 | 92 | layer: layer, |
|
100 | 111 |
|
101 | 112 | let last-pin = points.at(0) // resolved point |
102 | 113 | let cur-attrs = ( |
| 114 | + reversed: if last-pin.reversed == auto { false } else { last-pin.reversed }, |
103 | 115 | cfg: if last-pin.cfg == auto { none } else { last-pin.cfg }, |
104 | 116 | cfg-not: if last-pin.cfg-not == auto { none } else { last-pin.cfg-not }, |
105 | 117 | layer: if last-pin.layer == auto { 0 } else { last-pin.layer }, |
|
111 | 123 | let section-points = () |
112 | 124 | let segments = () |
113 | 125 | let stations = () |
| 126 | + let ordered-stations = () |
114 | 127 |
|
115 | 128 | let (sx, sy) = (last-pin.raw-pos.x, last-pin.raw-pos.y) |
116 | 129 | let start-pos = (sx, sy) |
117 | 130 | section-points.push(start-pos) |
118 | 131 | let start-station-index = 0 |
| 132 | + let reverse-first = if cur-attrs.reversed { 0 } else { -1 } |
119 | 133 |
|
120 | | - let seg-first = 1 // index of control point |
| 134 | + let seg-first = 1 // Current range of stations in `points`: [`seg-first`, `seg-last`) |
121 | 135 | while seg-first < points.len() { |
122 | 136 | let seg-last = seg-first |
123 | 137 | while "id" in points.at(seg-last) { |
|
171 | 185 | sta.line = line-id |
172 | 186 | sta.pos = if x == auto or y == auto { auto } else { (x, y) } // mark pos auto, handle it later |
173 | 187 | stations.push(sta) |
| 188 | + ordered-stations.push(sta.id) |
174 | 189 | } |
175 | 190 | if "loop-target" in cur-pin { |
176 | 191 | let i = start-station-index |
|
189 | 204 |
|
190 | 205 | // update current pin and cfg |
191 | 206 | let prev-attrs = cur-attrs |
| 207 | + if cur-pin.reversed != auto { cur-attrs.reversed = cur-pin.reversed } |
192 | 208 | if cur-pin.cfg != auto { cur-attrs.cfg = cur-pin.cfg } |
193 | 209 | if cur-pin.cfg-not != auto { cur-attrs.cfg-not = cur-pin.cfg-not } |
194 | 210 | if cur-pin.layer != auto { cur-attrs.cfg-not = cur-pin.layer } |
|
210 | 226 | if last-pin.end or cur-attrs != prev-attrs { |
211 | 227 | sections.push((points: section-points, ..prev-attrs)) |
212 | 228 | section-points = (seg.end,) |
| 229 | + // handle reversal |
| 230 | + if not cur-attrs.reversed { |
| 231 | + if prev-attrs.reversed { |
| 232 | + ordered-stations = ordered-stations.slice(0, reverse-first) + ordered-stations.slice(reverse-first).rev() |
| 233 | + } |
| 234 | + reverse-first = ordered-stations.len() |
| 235 | + } |
| 236 | + // reverse all stations before |
| 237 | + if last-pin.reverse-before { |
| 238 | + ordered-stations = ordered-stations.rev() |
| 239 | + } |
213 | 240 | } |
214 | 241 |
|
215 | 242 | last-pin = cur-pin |
216 | 243 | sx = tx |
217 | 244 | sy = ty |
218 | 245 | seg-first = seg-last + 1 |
219 | 246 | } |
| 247 | + if cur-attrs.reversed { |
| 248 | + ordered-stations = ordered-stations.slice(0, reverse-first) + ordered-stations.slice(reverse-first).rev() |
| 249 | + } |
| 250 | + if last-pin.reverse-before { |
| 251 | + ordered-stations = ordered-stations.rev() |
| 252 | + } |
220 | 253 | if section-points.len() > 0 { |
221 | 254 | sections.push((points: section-points, ..cur-attrs)) |
222 | 255 | } |
|
231 | 264 | } |
232 | 265 | } |
233 | 266 |
|
234 | | - return (stations: stations, sections: sections, segments: segments) |
| 267 | + return (stations: stations, sections: sections, segments: segments, ordered-stations: ordered-stations) |
235 | 268 | } |
236 | 269 |
|
237 | 270 | /// Constructor of metro line. |
|
257 | 290 | stroke: auto, |
258 | 291 | ..points, |
259 | 292 | ) = { |
260 | | - let (stations, sections, segments) = _extract-stations(points.pos(), id) |
| 293 | + let (stations, sections, segments, ordered-stations) = _extract-stations(points.pos(), id) |
261 | 294 | let station-indexer = stations.enumerate().map(((i, sta)) => (sta.id, i)).to-dict() |
262 | 295 | let data = ( |
263 | 296 | id: id, |
|
266 | 299 | sections: sections, |
267 | 300 | segments: segments, |
268 | 301 | stations: stations, |
| 302 | + ordered-stations: ordered-stations, |
269 | 303 | station-indexer: station-indexer, |
270 | 304 | optional: optional, |
271 | 305 | features: features, |
|
0 commit comments