How to use custom symbols as marks on fletcher arrows?

The goal is to draw simple diagrams to visualize different kinds of intervals on the number line, is it possible to define simple custom marks for fletcher arrows like shown below?:

#diagram($ a edge("[-]") & b $) // or ]-[ , [-[ , (-) and so on

I tried marks: ("[","]") with no success!
Is this achievable through fletcher or even another method?

1 Like

It’s all documented in the manual.

#import "@preview/fletcher:0.5.7" as fletcher: *
#fletcher.MARKS.update(m => {
  let new-marks = (
    "]": (
      size: 5,
      dir: ltr,
      draw: mark => draw.line(
        (-mark.size, mark.size),
        (0, mark.size),
        (0, -mark.size),
        (-mark.size, -mark.size),
        fill: none,
      ),
    ),
    "[": (inherit: "]"),
    ")": (
      size: 5,
      dir: ltr,
      draw: mark => draw.arc(
        (0, 0),
        start: -90deg,
        stop: 90deg,
        radius: mark.size,
        fill: none,
        anchor: "origin",
      ),
    ),
    "(": (inherit: ")"),
  )
  m + new-marks
})

#diagram({
  node((0, 0))[$a$]
  edge("[-]")
  node((1, 0))[$b$]

  node((0, 1))[$a$]
  edge("(-)")
  node((1, 1))[$b$]
})

image

2 Likes

This is great. Here’s a slight tweak ensuring the correct use of the rev mark property, and using the tip/tail-origin/end properties to make the alignments look right:

#import "@preview/fletcher:0.5.7" as fletcher: diagram, node, edge
#fletcher.MARKS.update(m => {
  import fletcher.cetz.draw
  m + (
    "]": (
      rev: false,
      size: 6,
      depth: 3,
      draw: mark => draw.line(
        (-mark.depth, mark.size),
        (0, mark.size),
        (0, -mark.size),
        (-mark.depth, -mark.size),
        fill: none,
      ),
      tail-origin: mark => -mark.depth,
    ),
    "[": (inherit: "]", rev: true),
    ")": (
      rev: false,
      size: 8,
      angle: 50deg,
      draw: mark => draw.arc(
        (0, 0),
        start: -mark.angle,
        stop: mark.angle,
        radius: mark.size,
        fill: none,
        anchor: "origin",
      ),
      tail-end: mark => mark.size,
      tip-end: mark => mark.size,
      tip-origin: mark => mark.size,
      tail-origin: mark => mark.size*calc.cos(mark.angle),
    ),
    "(": (inherit: ")", rev: true),
  )
})

#diagram(spacing: (20mm, 5mm), $
  a edge("[-]") & b edge("(-)") & c \
  a edge("]-[") & b edge(")-(") & c \
$)

#table(
  columns: 2,
  fletcher.mark-debug("("),
  fletcher.mark-demo("("),
  fletcher.mark-debug("["),
  fletcher.mark-demo("["),
)

2 Likes

Yeah, I wanted to ask why it auto-reverses anyway? I wanted to pass something similar, but since it does it automatically anyway, I just straight up inherited those so that it doesn’t panic.

Is rev built-in property that is somehow being auto-enabled for one shorthand and not enabled for the other? Like auto-mirror or something.

Thank you both for the detailed answers. I tried to mark them both as answers XD.

I was generally aware of the method both of you used to use custom mark, but found it a bit more nuanced that I could chew at first glance, so I came checking if there was a simpler way to do it before having to tackle the proper way. your example helped me understand the process.

and maybe even these marks could make it in the standard fletcher marks collection sometime in the future as they seem common enough!

1 Like

Agreed! Feel free to add a feature request or PR at GitHub · Where software is built — it would get added pretty quickly.

1 Like
1 Like