From cbba14ed0484ff64d93b4ae2483abc1959cd459c Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Tue, 30 Jul 2024 18:20:50 +0200 Subject: [PATCH] fixed and completed arrow tips --- TODO.md | 2 +- gallery/example3.pdf | Bin 418225 -> 418975 bytes gallery/example3.typ | 40 ++++++++++++++++--- src/consts.typ | 2 + src/sequence.typ | 92 +++++++++++++++++++++++++++++++++++++++---- 5 files changed, 122 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index 53c8180..781ff9c 100644 --- a/TODO.md +++ b/TODO.md @@ -12,7 +12,7 @@ - [x] Notes - [x] Synchronized arrows - [x] Slanted arrows -- [ ] Different types of arrow tips (WIP) +- [x] Different types of arrow tips - [ ] Fix column spacing with notes over multiple columns - [ ] Fix notes with arrows from start / to end / small arrows - [ ] Fix group size with self arrows + notes diff --git a/gallery/example3.pdf b/gallery/example3.pdf index 1bb20e672c7d321e0a2fcb200924f45d9ee0fd77..b20dd931f50c75b6e3d77a3fc86ddd9cfc53cd01 100644 GIT binary patch delta 3537 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 Pt%bp8Kou0uTI2r@nO9@x delta 2747 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 diff --git a/gallery/example3.typ b/gallery/example3.typ index 65014ff..3cdce3a 100644 --- a/gallery/example3.typ +++ b/gallery/example3.typ @@ -65,11 +65,11 @@ chronos.diagram({ _seq("a", "b", end-tip: "x", comment: `->x`) _seq("a", "b", start-tip: "x", comment: `x->`) _seq("a", "b", start-tip: "o", comment: `o->`) - _seq("a", "b", end-tip: "o", comment: `->o`) - _seq("a", "b", start-tip: "o", end-tip: "o", comment: `o->o`) + _seq("a", "b", end-tip: ("o", ">"), comment: `->o`) + _seq("a", "b", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`) _seq("a", "b", start-tip: ">", end-tip: ">", comment: `<->`) _seq("a", "b", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`) - _seq("a", "b", start-tip: ("x", ">"), end-tip: ("x", ">"), comment: `x<->x`) + _seq("a", "b", start-tip: "x", end-tip: "x", comment: `x<->x`) _seq("a", "b", end-tip: ("o", ">>"), comment: `->>o`) _seq("a", "b", end-tip: ("o", "\\"), comment: `-\o`) _seq("a", "b", end-tip: ("o", "\\\\"), comment: `-\\o`) @@ -78,6 +78,34 @@ chronos.diagram({ _seq("a", "b", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`) }), +chronos.diagram({ + import chronos: * + + _par("a", display-name: "Alice") + _par("b", display-name: "Bob") + + _seq("b", "a", end-tip: ">", comment: `->`) + _seq("b", "a", end-tip: ">>", comment: `->>`) + _seq("b", "a", end-tip: "\\", comment: `-\`) + _seq("b", "a", end-tip: "\\\\", comment: `-\\`) + _seq("b", "a", end-tip: "/", comment: `-/`) + _seq("b", "a", end-tip: "//", comment: `-//`) + _seq("b", "a", end-tip: "x", comment: `->x`) + _seq("b", "a", start-tip: "x", comment: `x->`) + _seq("b", "a", start-tip: "o", comment: `o->`) + _seq("b", "a", end-tip: ("o", ">"), comment: `->o`) + _seq("b", "a", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`) + _seq("b", "a", start-tip: ">", end-tip: ">", comment: `<->`) + _seq("b", "a", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`) + _seq("b", "a", start-tip: "x", end-tip: "x", comment: `x<->x`) + _seq("b", "a", end-tip: ("o", ">>"), comment: `->>o`) + _seq("b", "a", end-tip: ("o", "\\"), comment: `-\o`) + _seq("b", "a", end-tip: ("o", "\\\\"), comment: `-\\o`) + _seq("b", "a", end-tip: ("o", "/"), comment: `-/o`) + _seq("b", "a", end-tip: ("o", "//"), comment: `-//o`) + _seq("b", "a", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`) +}), + chronos.diagram({ import chronos: * @@ -93,11 +121,11 @@ chronos.diagram({ _seq("a", "a", end-tip: "x", comment: `->x`) _seq("a", "a", start-tip: "x", comment: `x->`) _seq("a", "a", start-tip: "o", comment: `o->`) - _seq("a", "a", end-tip: "o", comment: `->o`) - _seq("a", "a", start-tip: "o", end-tip: "o", comment: `o->o`) + _seq("a", "a", end-tip: ("o", ">"), comment: `->o`) + _seq("a", "a", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`) _seq("a", "a", start-tip: ">", end-tip: ">", comment: `<->`) _seq("a", "a", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`) - _seq("a", "a", start-tip: ("x", ">"), end-tip: ("x", ">"), comment: `x<->x`) + _seq("a", "a", start-tip: "x", end-tip: "x", comment: `x<->x`) _seq("a", "a", end-tip: ("o", ">>"), comment: `->>o`) _seq("a", "a", end-tip: ("o", "\\"), comment: `-\o`) _seq("a", "a", end-tip: ("o", "\\\\"), comment: `-\\o`) diff --git a/src/consts.typ b/src/consts.typ index 4857aa7..ba99801 100644 --- a/src/consts.typ +++ b/src/consts.typ @@ -4,6 +4,8 @@ #let LIFELINE-W = 10 #let CREATE-OFFSET = 15 #let DEFAULT-SLANT = 10 +#let CROSS-TIP-SIZE = 4 +#let CIRCLE-TIP-RADIUS = 3 #let SYM-GAP = 5 #let PAR-PAD = (5pt, 3pt) diff --git a/src/sequence.typ b/src/sequence.typ index 4866e41..0485d49 100644 --- a/src/sequence.typ +++ b/src/sequence.typ @@ -16,10 +16,34 @@ "/": (symbol: ">", fill: color, harpoon: true), "//": (symbol: "straight", harpoon: true), "x": none, - "o": (symbol: "o"), + "o": none, ).at(sym) } +#let reverse-arrow-mark(mark) = { + if type(mark) == array { + return mark.map(m => reverse-arrow-mark(m)) + } + let mark2 = mark + if type(mark) == dictionary and mark.at("harpoon", default: false) { + let flipped = mark.at("flip", default: false) + mark2.insert("flip", not flipped) + } + return mark2 +} + +#let is-tip-of-type(type_, tip) = { + if type(tip) == str and tip == type_ { + return true + } + if type(tip) == array and tip.contains(type_) { + return true + } + return false +} +#let is-circle-tip = is-tip-of-type.with("o") +#let is-cross-tip = is-tip-of-type.with("x") + #let _seq( p1, p2, @@ -175,6 +199,15 @@ shapes += shps } + let flip-mark = end-info.i <= start-info.i + if elmt.flip { + flip-mark = not flip-mark + } + if flip-mark { + style.mark.end = reverse-arrow-mark(style.mark.end) + } + + let pts if elmt.p1 == elmt.p2 { if elmt.flip { x1 = start-info.lx @@ -197,12 +230,11 @@ ) } - shapes += draw.line( + pts = ( (x1, start-info.y), (x-mid, start-info.y), (x-mid, end-info.y), - (x2, end-info.y), - ..style + (x2, end-info.y) ) } else { @@ -219,12 +251,58 @@ ) } - shapes += draw.line( + pts = ( (x1, start-info.y), - (x2, end-info.y), - ..style + (x2, end-info.y) ) } + + // Start circle tip + if is-circle-tip(elmt.start-tip) { + shapes += draw.circle(pts.first(), radius: CIRCLE-TIP-RADIUS, stroke: elmt.color, fill: none, name: "_circle-start-tip") + pts.at(0) = "_circle-start-tip" + + // Start cross tip + } else if is-cross-tip(elmt.start-tip) { + let size = CROSS-TIP-SIZE + let cross-pt = (pts.first(), size * 2, pts.at(1)) + shapes += draw.line( + (rel: (-size, -size), to: cross-pt), + (rel: (size, size), to: cross-pt), + stroke: elmt.color + 1.5pt + ) + shapes += draw.line( + (rel: (-size, size), to: cross-pt), + (rel: (size, -size), to: cross-pt), + stroke: elmt.color + 1.5pt + ) + pts.at(0) = cross-pt + } + + // End circle tip + if is-circle-tip(elmt.end-tip) { + shapes += draw.circle(pts.last(), radius: 3, stroke: elmt.color, fill: none, name: "_circle-end-tip") + pts.at(pts.len() - 1) = "_circle-end-tip" + + // End cross tip + } else if is-cross-tip(elmt.end-tip) { + let size = CROSS-TIP-SIZE + let cross-pt = (pts.last(), size * 2, pts.at(pts.len() - 2)) + shapes += draw.line( + (rel: (-size, -size), to: cross-pt), + (rel: (size, size), to: cross-pt), + stroke: elmt.color + 1.5pt + ) + shapes += draw.line( + (rel: (-size, size), to: cross-pt), + (rel: (size, -size), to: cross-pt), + stroke: elmt.color + 1.5pt + ) + pts.at(pts.len() - 1) = cross-pt + } + + shapes += draw.line(..pts, ..style) + if elmt.enable-dst { let dst-line = lifelines.at(i2) dst-line.lines.push(("enable", end-info.y, elmt.lifeline-style))