Skip to content

Commit

Permalink
Merge pull request #2119 from Omikhleia/feat-math-sqrt
Browse files Browse the repository at this point in the history
  • Loading branch information
alerque authored Oct 1, 2024
2 parents a80093d + 7efd24d commit aebe021
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 0 deletions.
79 changes: 79 additions & 0 deletions packages/math/base-elements.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,85 @@ end

function elements.table.output (_) end

elements.sqrt = pl.class(elements.mbox)
elements.sqrt._type = "Sqrt"

function elements.sqrt:__tostring ()
return self._type .. "(" .. tostring(self.radicand) .. ")"
end

function elements.sqrt:_init (radicand)
elements.mbox._init(self)
self.radicand = radicand
table.insert(self.children, radicand)
self.relX = SILE.types.length(0) -- x position relative to its parent box
self.relY = SILE.types.length(0) -- y position relative to its parent box
end

function elements.sqrt:styleChildren ()
self.radicand.mode = self.mode
end

function elements.sqrt:shape ()
local mathMetrics = self:getMathMetrics()
local scaleDown = self:getScaleDown()
local constants = mathMetrics.constants

self.radicalRuleThickness = constants.radicalRuleThickness * scaleDown
if self.mode == mathMode.display or self.mode == mathMode.displayCramped then
self.radicalVerticalGap = constants.radicalDisplayStyleVerticalGap * scaleDown
else
self.radicalVerticalGap = constants.radicalVerticalGap * scaleDown
end
self.extraAscender = constants.radicalExtraAscender * scaleDown

-- HACK: More or less ad hoc values, see output method for more details
self.symbolWidth = SILE.shaper:measureChar("").width
self.symbolHeight = SILE.types.length("1.1ex"):tonumber() * scaleDown

self.width = self.radicand.width + SILE.types.length(self.symbolWidth)
self.height = self.radicand.height + self.radicalVerticalGap + self.extraAscender
self.depth = self.radicand.depth
self.radicand:shape()
self.radicand.relX = self.symbolWidth
end

local function _r (number)
-- Lua 5.3+ formats floats as 1.0 and integers as 1
-- Also some PDF readers do not like double precision.
return math.floor(number) == number and math.floor(number) or tonumber(string.format("%.5f", number))
end

function elements.sqrt:output (x, y, line)
-- HACK FIXME:
-- OpenType might say we need to assemble the radical sign from parts.
-- Frankly, it's much easier to just draw it as a graphic :-)
-- Hence, here we use a PDF graphic operators to draw a nice radical sign.
-- Some values here are ad hoc, but they look good.
local h = self.height:tonumber()
local d = self.depth:tonumber()
local sw = self.symbolWidth
local dh = h - self.symbolHeight
local symbol = {
_r(self.radicalRuleThickness), "w", -- line width
2, "j", -- round line joins
_r(sw), _r(self.extraAscender), "m",
_r(sw * 0.4), _r(h + d), "l",
_r(sw * 0.15), _r(dh), "l",
0, _r(dh + 0.5), "l",
"S"
}
local svg = table.concat(symbol, " ")
SILE.outputter:drawSVG(svg, x, y, sw, h, 1)
-- And now we just need to draw the bar over the radicand
SILE.outputter:drawRule(
self.symbolWidth + scaleWidth(x, line),
y.length - scaleWidth(self.radicand.height, line) - self.radicalVerticalGap - self.radicalRuleThickness / 2,
scaleWidth(self.radicand.width, line),
self.radicalRuleThickness
)
end

elements.mathMode = mathMode
elements.atomType = atomType
elements.scriptType = scriptType
Expand Down
1 change: 1 addition & 0 deletions packages/math/texlike.lua
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ compileToMathML(
convertTexlike(nil, {
[==[
\def{frac}{\mfrac{#1}{#2}}
\def{sqrt}{\msqrt{#1}}
\def{bi}{\mi[mathvariant=bold-italic]{#1}}
\def{dsi}{\mi[mathvariant=double-struck]{#1}}
Expand Down
4 changes: 4 additions & 0 deletions packages/math/typesetter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ function ConvertMathML (_, content)
SU.error("Wrong number of children in mfrac: " .. #children)
end
return b.fraction(children[1], children[2])
elseif content.command == "msqrt" then
local children = convertChildren(content)
-- "The <msqrt> element generates an anonymous <mrow> box called the msqrt base
return b.sqrt(b.stackbox("H", children))
elseif content.command == "mtable" or content.command == "table" then
local children = convertChildren(content)
return b.table(children, content.options)
Expand Down

0 comments on commit aebe021

Please sign in to comment.