Skip to content

Commit 7efd24d

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(math): Support square roots
1 parent 3a3b1bc commit 7efd24d

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

packages/math/base-elements.lua

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,6 +1334,85 @@ end
13341334

13351335
function elements.table.output (_) end
13361336

1337+
elements.sqrt = pl.class(elements.mbox)
1338+
elements.sqrt._type = "Sqrt"
1339+
1340+
function elements.sqrt:__tostring ()
1341+
return self._type .. "(" .. tostring(self.radicand) .. ")"
1342+
end
1343+
1344+
function elements.sqrt:_init (radicand)
1345+
elements.mbox._init(self)
1346+
self.radicand = radicand
1347+
table.insert(self.children, radicand)
1348+
self.relX = SILE.types.length(0) -- x position relative to its parent box
1349+
self.relY = SILE.types.length(0) -- y position relative to its parent box
1350+
end
1351+
1352+
function elements.sqrt:styleChildren ()
1353+
self.radicand.mode = self.mode
1354+
end
1355+
1356+
function elements.sqrt:shape ()
1357+
local mathMetrics = self:getMathMetrics()
1358+
local scaleDown = self:getScaleDown()
1359+
local constants = mathMetrics.constants
1360+
1361+
self.radicalRuleThickness = constants.radicalRuleThickness * scaleDown
1362+
if self.mode == mathMode.display or self.mode == mathMode.displayCramped then
1363+
self.radicalVerticalGap = constants.radicalDisplayStyleVerticalGap * scaleDown
1364+
else
1365+
self.radicalVerticalGap = constants.radicalVerticalGap * scaleDown
1366+
end
1367+
self.extraAscender = constants.radicalExtraAscender * scaleDown
1368+
1369+
-- HACK: More or less ad hoc values, see output method for more details
1370+
self.symbolWidth = SILE.shaper:measureChar("").width
1371+
self.symbolHeight = SILE.types.length("1.1ex"):tonumber() * scaleDown
1372+
1373+
self.width = self.radicand.width + SILE.types.length(self.symbolWidth)
1374+
self.height = self.radicand.height + self.radicalVerticalGap + self.extraAscender
1375+
self.depth = self.radicand.depth
1376+
self.radicand:shape()
1377+
self.radicand.relX = self.symbolWidth
1378+
end
1379+
1380+
local function _r (number)
1381+
-- Lua 5.3+ formats floats as 1.0 and integers as 1
1382+
-- Also some PDF readers do not like double precision.
1383+
return math.floor(number) == number and math.floor(number) or tonumber(string.format("%.5f", number))
1384+
end
1385+
1386+
function elements.sqrt:output (x, y, line)
1387+
-- HACK FIXME:
1388+
-- OpenType might say we need to assemble the radical sign from parts.
1389+
-- Frankly, it's much easier to just draw it as a graphic :-)
1390+
-- Hence, here we use a PDF graphic operators to draw a nice radical sign.
1391+
-- Some values here are ad hoc, but they look good.
1392+
local h = self.height:tonumber()
1393+
local d = self.depth:tonumber()
1394+
local sw = self.symbolWidth
1395+
local dh = h - self.symbolHeight
1396+
local symbol = {
1397+
_r(self.radicalRuleThickness), "w", -- line width
1398+
2, "j", -- round line joins
1399+
_r(sw), _r(self.extraAscender), "m",
1400+
_r(sw * 0.4), _r(h + d), "l",
1401+
_r(sw * 0.15), _r(dh), "l",
1402+
0, _r(dh + 0.5), "l",
1403+
"S"
1404+
}
1405+
local svg = table.concat(symbol, " ")
1406+
SILE.outputter:drawSVG(svg, x, y, sw, h, 1)
1407+
-- And now we just need to draw the bar over the radicand
1408+
SILE.outputter:drawRule(
1409+
self.symbolWidth + scaleWidth(x, line),
1410+
y.length - scaleWidth(self.radicand.height, line) - self.radicalVerticalGap - self.radicalRuleThickness / 2,
1411+
scaleWidth(self.radicand.width, line),
1412+
self.radicalRuleThickness
1413+
)
1414+
end
1415+
13371416
elements.mathMode = mathMode
13381417
elements.atomType = atomType
13391418
elements.scriptType = scriptType

packages/math/texlike.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ compileToMathML(
476476
convertTexlike(nil, {
477477
[==[
478478
\def{frac}{\mfrac{#1}{#2}}
479+
\def{sqrt}{\msqrt{#1}}
479480
\def{bi}{\mi[mathvariant=bold-italic]{#1}}
480481
\def{dsi}{\mi[mathvariant=double-struck]{#1}}
481482

packages/math/typesetter.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ function ConvertMathML (_, content)
125125
SU.error("Wrong number of children in mfrac: " .. #children)
126126
end
127127
return b.fraction(children[1], children[2])
128+
elseif content.command == "msqrt" then
129+
local children = convertChildren(content)
130+
-- "The <msqrt> element generates an anonymous <mrow> box called the msqrt base
131+
return b.sqrt(b.stackbox("H", children))
128132
elseif content.command == "mtable" or content.command == "table" then
129133
local children = convertChildren(content)
130134
return b.table(children, content.options)

0 commit comments

Comments
 (0)