|
3 | 3 |
|
4 | 4 | #import "/src/ticks.typ"
|
5 | 5 | #import "/src/projection.typ"
|
| 6 | +#import "/src/axis.typ" |
6 | 7 |
|
7 | 8 | /// Default axis style
|
8 | 9 | ///
|
|
85 | 86 | ),
|
86 | 87 | y: (
|
87 | 88 | tick: (
|
88 |
| - flip: true, |
89 | 89 | label: (
|
90 | 90 | anchor: "east",
|
91 | 91 | ),
|
92 | 92 | ),
|
93 | 93 | ),
|
94 |
| - x2: ( |
| 94 | + u: ( |
95 | 95 | tick: (
|
96 |
| - flip: true, |
97 | 96 | label: (
|
98 | 97 | anchor: "south",
|
99 | 98 | ),
|
100 | 99 | ),
|
101 | 100 | ),
|
102 |
| - y2: ( |
| 101 | + v: ( |
103 | 102 | tick: (
|
104 | 103 | label: (
|
105 | 104 | anchor: "west",
|
|
108 | 107 | ),
|
109 | 108 | distal: (
|
110 | 109 | tick: (
|
111 |
| - flip: true, |
112 | 110 | label: (
|
113 | 111 | anchor: "east",
|
114 | 112 | )
|
|
160 | 158 |
|
161 | 159 | #let _get-axis-style(ptx, style, name) = {
|
162 | 160 | return _prepare-style(ptx, if name in style {
|
163 |
| - cetz.util.merge-dictionary(style, style.at(name)) |
| 161 | + cetz.util.merge-dictionary(style, style.at(name, default: (:))) |
164 | 162 | } else {
|
165 | 163 | style
|
166 | 164 | })
|
167 | 165 | }
|
168 | 166 |
|
| 167 | +/// |
| 168 | +#let cartesian-axis-projection(ax, start, stop) = { |
| 169 | + let dir = vector.norm(vector.sub(stop, start)) |
| 170 | + let dist = vector.dist(start, stop) |
| 171 | + return (value) => { |
| 172 | + vector.add(start, vector.scale(dir, axis.transform(ax, value, 0, dist))) |
| 173 | + } |
| 174 | +} |
| 175 | + |
169 | 176 |
|
170 | 177 | ///
|
171 | 178 | #let cartesian-scientific(projections: none, name: none, style: (:)) = {
|
172 | 179 | return (
|
173 | 180 | name: name,
|
174 | 181 | draw: (ptx) => {
|
175 |
| - let proj = projections.at(0) |
176 |
| - let axes = proj.axes |
177 |
| - let x = axes.at(0) |
178 |
| - let y = axes.at(1) |
| 182 | + let xy-proj = projections.at(0) |
| 183 | + let uv-proj = projections.at(1, default: xy-proj) |
| 184 | + let has-uv = projections.len() > 1 |
| 185 | + let (x, y) = xy-proj.axes |
| 186 | + let (u, v) = uv-proj.axes |
179 | 187 |
|
180 | 188 | let style = _prepare-style(ptx, cetz.styles.resolve(ptx.cetz-ctx.style,
|
181 | 189 | root: "axes", merge: style, base: default-style))
|
182 | 190 | let x-style = _get-axis-style(ptx, style, "x")
|
183 | 191 | let y-style = _get-axis-style(ptx, style, "y")
|
184 |
| - let x2-style = _get-axis-style(ptx, style, "x2") |
185 |
| - let y2-style = _get-axis-style(ptx, style, "y2") |
| 192 | + let u-style = _get-axis-style(ptx, style, "u") |
| 193 | + let v-style = _get-axis-style(ptx, style, "v") |
186 | 194 |
|
187 |
| - let (south-west, south-east, north-west, north-east) = (proj.transform)( |
| 195 | + let (x-low, x-high, y-low, y-high) = (xy-proj.transform)( |
188 | 196 | (x.min, y.min), (x.max, y.min),
|
189 |
| - (x.min, y.max), (x.max, y.max), |
| 197 | + (x.min, y.min), (x.min, y.max), |
| 198 | + ) |
| 199 | + let (u-low, u-high, v-low, v-high) = (uv-proj.transform)( |
| 200 | + (u.min, v.max), (u.max, v.max), |
| 201 | + (u.max, v.min), (u.max, v.max), |
190 | 202 | )
|
191 | 203 |
|
192 |
| - let x-padding = x-style.padding |
193 |
| - let y-padding = y-style.padding |
194 |
| - |
195 |
| - let x-low = vector.add(south-west, (-x-padding.at(0), -y-padding.at(0))) |
196 |
| - let x-high = vector.add(south-east, (+x-padding.at(1), -y-padding.at(0))) |
197 |
| - let y-low = vector.add(south-west, (-x-padding.at(0), -y-padding.at(0))) |
198 |
| - let y-high = vector.add(north-west, (-x-padding.at(0), y-padding.at(1))) |
| 204 | + let move-vec(v, direction, length) = { |
| 205 | + vector.add(v, direction.enumerate().map(((i, v)) => v * length.at(i))) |
| 206 | + } |
199 | 207 |
|
200 |
| - let x2-low = vector.add(north-west, (-x-padding.at(0), y-padding.at(1))) |
201 |
| - let x2-high = vector.add(north-east, (+x-padding.at(1), y-padding.at(1))) |
202 |
| - let y2-low = vector.add(south-east, (x-padding.at(1), -y-padding.at(0))) |
203 |
| - let y2-high = vector.add(north-east, (x-padding.at(1), y-padding.at(1))) |
| 208 | + // Outset axes |
| 209 | + x-low = move-vec(x-low, (0, -1), x-style.padding) |
| 210 | + x-high = move-vec(x-high, (0, -1), x-style.padding) |
| 211 | + y-low = move-vec(y-low, (-1, 0), y-style.padding) |
| 212 | + y-high = move-vec(y-high, (-1, 0), y-style.padding) |
| 213 | + u-low = move-vec(u-low, (0, 1), u-style.padding) |
| 214 | + u-high = move-vec(u-high, (0, 1), u-style.padding) |
| 215 | + v-low = move-vec(v-low, (1, 0), v-style.padding) |
| 216 | + v-high = move-vec(v-high, (1, 0), v-style.padding) |
| 217 | + |
| 218 | + // Frame corners (FIX for uv axes) |
| 219 | + let south-west = move-vec(x-low, (-1, 0), x-style.padding) |
| 220 | + let south-east = move-vec(x-high, (+1, 0), x-style.padding) |
| 221 | + let north-west = move-vec(u-low, (-1, 0), u-style.padding) |
| 222 | + let north-east = move-vec(u-high, (+1, 0), u-style.padding) |
| 223 | + |
| 224 | + // Grid lengths |
| 225 | + let x-grid-length = u-low.at(1) - x-low.at(1) |
| 226 | + let y-grid-length = v-low.at(0) - y-low.at(0) |
| 227 | + let u-grid-length = x-low.at(1) - u-low.at(1) |
| 228 | + let v-grid-length = y-low.at(0) - v-low.at(0) |
204 | 229 |
|
205 | 230 | let axes = (
|
206 |
| - (x, 0, south-west, south-east, x-low, x-high, x-style, false), |
207 |
| - (y, 1, south-west, north-west, y-low, y-high, y-style, false), |
208 |
| - (x, 0, north-west, north-east, x2-low, x2-high, x2-style, true), |
209 |
| - (y, 1, south-east, north-east, y2-low, y2-high, y2-style, true), |
| 231 | + (x, (0,+1), (0,x-grid-length), cartesian-axis-projection(x, x-low, x-high), x-style, false), |
| 232 | + (y, (+1,0), (y-grid-length,0), cartesian-axis-projection(y, y-low, y-high), y-style, false), |
| 233 | + (u, (0,-1), (0,u-grid-length), cartesian-axis-projection(u, u-low, u-high), u-style, not has-uv), |
| 234 | + (v, (-1,0), (v-grid-length,0), cartesian-axis-projection(v, v-low, v-high), v-style, not has-uv), |
210 | 235 | )
|
211 | 236 |
|
212 |
| - for (ax, component, low, high, frame-low, frame-high, style, mirror) in axes { |
213 |
| - draw.on-layer(style.axis-layer, { |
214 |
| - draw.line(frame-low, frame-high, stroke: style.stroke, mark: style.mark) |
215 |
| - }) |
216 |
| - if "computed-ticks" in ax { |
217 |
| - let low = low.enumerate().map(((i, v)) => { |
218 |
| - if i == component { v } else { frame-low.at(i) } |
| 237 | + draw.group(name: "spine", { |
| 238 | + for (ax, dir, grid-dir, proj, style, mirror) in axes { |
| 239 | + draw.on-layer(style.axis-layer, { |
| 240 | + draw.line(proj(ax.min), proj(ax.max), stroke: style.stroke, mark: style.mark) |
219 | 241 | })
|
220 |
| - let high = high.enumerate().map(((i, v)) => { |
221 |
| - if i == component { v } else { frame-low.at(i) } |
222 |
| - }) |
223 |
| - |
224 |
| - if not mirror { |
225 |
| - ticks.draw-cartesian-grid(low, high, component, ax, ax.computed-ticks, (0,0), (1,0), style) |
| 242 | + if "computed-ticks" in ax { |
| 243 | + if not mirror { |
| 244 | + ticks.draw-cartesian-grid(proj, grid-dir, ax, ax.computed-ticks, style) |
| 245 | + } |
| 246 | + ticks.draw-cartesian(proj, dir, ax.computed-ticks, style, is-mirror: mirror) |
226 | 247 | }
|
227 |
| - ticks.draw-cartesian(low, high, ax.computed-ticks, style, is-mirror: mirror) |
228 | 248 | }
|
229 |
| - } |
| 249 | + }) |
| 250 | + |
| 251 | + // TODO: Draw labels |
230 | 252 | },
|
231 | 253 | )
|
232 | 254 | }
|
|
247 | 269 | let x-style = _get-axis-style(ptx, style, "x")
|
248 | 270 | let y-style = _get-axis-style(ptx, style, "y")
|
249 | 271 |
|
| 272 | + let zero-x = calc.max(x.min, calc.min(0, x.max)) |
| 273 | + let zero-y = calc.max(y.min, calc.min(0, y.max)) |
| 274 | + let zero-pt = ( |
| 275 | + calc.max(x.min, calc.min(zero.at(0), x.max)), |
| 276 | + calc.max(y.min, calc.min(zero.at(1), y.max)), |
| 277 | + ) |
| 278 | + |
250 | 279 | let (zero, min-x, max-x, min-y, max-y) = (proj.transform)(
|
251 |
| - zero, |
252 |
| - vector.add(zero, (x.min, 0)), vector.add(zero, (x.max, 0)), |
253 |
| - vector.add(zero, (0, y.min)), vector.add(zero, (0, y.max)), |
| 280 | + zero-pt, |
| 281 | + vector.add(zero-pt, (x.min, zero-y)), vector.add(zero-pt, (x.max, zero-y)), |
| 282 | + vector.add(zero-pt, (zero-x, y.min)), vector.add(zero-pt, (zero-x, y.max)), |
254 | 283 | )
|
255 | 284 |
|
256 | 285 | let x-padding = x-style.padding
|
|
272 | 301 | let outset-min-y = vector.scale(outset-lo-y, -1)
|
273 | 302 | let outset-max-y = vector.scale(outset-hi-y, +1)
|
274 | 303 |
|
| 304 | + |
275 | 305 | draw.on-layer(x-style.axis-layer, {
|
276 | 306 | draw.line((rel: outset-min-x, to: min-x),
|
277 | 307 | (rel: outset-max-x, to: max-x),
|
278 | 308 | mark: x-style.mark,
|
279 | 309 | stroke: x-style.stroke)
|
280 | 310 | })
|
281 | 311 | if "computed-ticks" in x {
|
282 |
| - ticks.draw-cartesian-grid(min-x, max-x, 0, x, x.computed-ticks, min-y, max-y, x-style) |
283 |
| - ticks.draw-cartesian(min-x, max-x, x.computed-ticks, x-style) |
| 312 | + //ticks.draw-cartesian-grid(grid-proj, grid-dir, ax, ax.computed-ticks, style) |
| 313 | + let tick-proj = cartesian-axis-projection(x, min-x, max-x) |
| 314 | + ticks.draw-cartesian(tick-proj, (0,+1), x.computed-ticks, x-style) |
284 | 315 | }
|
285 | 316 |
|
286 | 317 | draw.on-layer(y-style.axis-layer, {
|
|
290 | 321 | stroke: y-style.stroke)
|
291 | 322 | })
|
292 | 323 | if "computed-ticks" in y {
|
293 |
| - ticks.draw-cartesian-grid(min-y, max-y, 1, y, y.computed-ticks, min-x, max-x, y-style) |
294 |
| - ticks.draw-cartesian(min-y, max-y, y.computed-ticks, y-style) |
| 324 | + //ticks.draw-cartesian-grid(min-y, max-y, 1, y, y.computed-ticks, min-x, max-x, y-style) |
| 325 | + let tick-proj = cartesian-axis-projection(y, min-y, max-y) |
| 326 | + ticks.draw-cartesian(tick-proj, (+1,0), y.computed-ticks, y-style) |
295 | 327 | }
|
296 | 328 | }
|
297 | 329 | )
|
|
332 | 364 | if "computed-ticks" in distal {
|
333 | 365 | // TODO
|
334 | 366 | ticks.draw-distal-grid(proj, distal.computed-ticks, distal-style)
|
335 |
| - ticks.draw-cartesian(r-start, r-end, distal.computed-ticks, distal-style) |
| 367 | + //ticks.draw-cartesian(r-start, r-end, distal.computed-ticks, distal-style) |
336 | 368 | }
|
337 | 369 |
|
338 | 370 | if start == stop {
|
|
0 commit comments