cetz icon indicating copy to clipboard operation
cetz copied to clipboard

Incorrect base anchors for equations

Open hooyuser opened this issue 1 year ago • 0 comments

In Issue #683 Content-Relative Anchors and #684 PR, CeTZ added support for base anchors, which works well for text. However, I observed incorrect results when using base anchors with equations. Below are examples demonstrating the issue, along with a proposed solution.

Examples of Incorrect Base Anchors

  1. Inline Equation The equation is $limits(sum)_(i in I)F(U_i)$
  1. Block Equation The equation is $ limits(sum)_(i in I)F(U_i) $

Proposed Solution

The #684 PR introduced a measure function to calculate the base anchor. While it works for text, it fails to measure equation baselines correctly.

@Enter-tainer suggested a way to accurately calculate the baseline of equations. I adapted this approach from the rehype-typst project and created a demo measure_equation.typ. The code for measure_equation.typ is hosted on (Typst App) and here are some tests for this baseline measure function:

measure_equation_test

This method uses the following strategy:

  • Define height as the part of the equation above the baseline.
  • Define depth as the part below the baseline.
  • Insert a function call pin(label) at the start of the equation.
    // a dict that stores the height of equations
    #let s = state("eq_height_dict", (:))
    
    // when called, retrieves the height of the equation, which is then stored in a state variable
    #let pin(label) = context {
      let height = measure(line(length: here().position().y)).width
      s.update(it => it.insert(label, height) + it)
    }
    
    // get the bounding box of an equation
    #let bounded(eq) = text(top-edge: "bounds", bottom-edge: "bounds", eq)
    
    // insert a function call `pin(label)`` at the start of the equation.
    #let add_pin(eq) = {
      let label = repr(eq)
      let formula = if eq.block == true {
        $ pin(label)#eq $
      } else {
        $pin(label)#eq$
      }
      bounded(formula)
    }
    
    The function is triggered when the equation is displayed at the top-left corner of the page. Within the function, here().position().y retrieves the height of the equation, which is then stored in a state variable.
  • Calculate height + depth using measure(text(top-edge: "bounds", bottom-edge: "bounds", eq)), and subtract the height to derive depth.
  • The equation must be displayed before any call to state.get(). The hide function is used to display the equation "virtually", preventing the equation from appearing in the final output.

Accurate base anchor for equation is crucial in math diagramming, as we expect math formulas within a line to align perfectly by their baselines. This alignment is essential for achieving a professional and polished look in mathematical diagrams. Currently, the incorrect calculation of base anchors blocks me from using Typst for diagram drawing, as demonstrated as follows:

unaligned

I hope we could introduce a specialized method for measuring equation to ensure correct base anchors, achieving functionality on par with LaTeX TikZ, and making it a more viable option for math diagrams. Let me know if there’s more I can do to help!

hooyuser avatar Jan 15 '25 20:01 hooyuser