Support \oiint and \oiiint (#1430)

* Support \oiint and \oiiint

* Fix sub. Add tests

* Add phony screenshots

* Add real screenshots
This commit is contained in:
Ron Kok
2018-06-19 06:41:00 -07:00
committed by Erik Demaine
parent 3f1b13e352
commit 3e932b1ecb
9 changed files with 104 additions and 12 deletions

View File

@@ -746,7 +746,11 @@ const svgData: {
[string]: ([string, number, number])
} = {
// path, width, height
vec: ["vec", 0.471, 0.714], // values from the font glyph
vec: ["vec", 0.471, 0.714], // values from the font glyph
oiintSize1: ["oiintSize1", 0.957, 0.499], // oval to overlay the integrand
oiintSize2: ["oiintSize2", 1.472, 0.659],
oiiintSize1: ["oiiintSize1", 1.304, 0.499],
oiiintSize2: ["oiiintSize2", 1.98, 0.659],
};
const staticSvg = function(value: string, options: Options): SvgSpan {

View File

@@ -54,9 +54,39 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
if (group.value.symbol) {
// If this is a symbol, create the symbol.
const fontName = large ? "Size2-Regular" : "Size1-Regular";
let stash = "";
if (group.value.body === "\\oiint" || group.value.body === "\\oiiint") {
// No font glyphs yet, so use a glyph w/o the oval.
// TODO: When font glyphs are available, delete this code.
stash = group.value.body.substr(1);
// $FlowFixMe
group.value.body = stash === "oiint" ? "\\iint" : "\\iiint";
}
base = buildCommon.makeSymbol(
group.value.body, fontName, "math", options,
["mop", "op-symbol", large ? "large-op" : "small-op"]);
if (stash.length > 0) {
// We're in \oiint or \oiiint. Overlay the oval.
// TODO: When font glyphs are available, delete this code.
const italic = base.italic;
const oval = buildCommon.staticSvg(stash + "Size"
+ (large ? "2" : "1"), options);
base = buildCommon.makeVList({
positionType: "individualShift",
children: [
{type: "elem", elem: base, shift: 0},
{type: "elem", elem: oval, shift: large ? 0.08 : 0},
],
}, options);
// $FlowFixMe
group.value.body = "\\" + stash;
base.classes.unshift("mop");
// $FlowFixMe
base.italic = italic;
}
} else if (group.value.value) {
// If this is a list, compose that list.
const inner = html.buildExpression(group.value.value, options, true);
@@ -81,7 +111,9 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
// If content of op is a single symbol, shift it vertically.
let baseShift = 0;
let slant = 0;
if (base instanceof domTree.symbolNode && !group.value.suppressBaseShift) {
if ((base instanceof domTree.symbolNode
|| group.value.body === "\\oiint" || group.value.body === "\\oiiint")
&& !group.value.suppressBaseShift) {
// We suppress the shift of the base of \overset and \underset. Otherwise,
// shift the symbol so its center lies on the axis (rule 13). It
// appears that our fonts have the centers of the symbols already
@@ -92,6 +124,7 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
options.fontMetrics().axisHeight;
// The slant of the symbol is just its italic correction.
// $FlowFixMe
slant = base.italic;
}
@@ -308,6 +341,8 @@ const singleCharIntegrals: {[string]: string} = {
"\u222c": "\\iint",
"\u222d": "\\iiint",
"\u222e": "\\oint",
"\u222f": "\\oiint",
"\u2230": "\\oiiint",
};
defineFunction({
@@ -379,8 +414,8 @@ defineFunction({
defineFunction({
type: "op",
names: [
"\\int", "\\iint", "\\iiint", "\\oint", "\u222b", "\u222c",
"\u222d", "\u222e",
"\\int", "\\iint", "\\iiint", "\\oint", "\\oiint", "\\oiiint",
"\u222b", "\u222c", "\u222d", "\u222e", "\u222f", "\u2230",
],
props: {
numArgs: 0,

View File

@@ -109,6 +109,22 @@ defineFunctionBuilders({
const multiplier = options.sizeMultiplier;
const marginRight = (0.5 / metrics.ptPerEm) / multiplier + "em";
let marginLeft = null;
if (subm) {
// Subscripts shouldn't be shifted by the base's italic correction.
// Account for that by shifting the subscript back the appropriate
// amount. Note we only do this when the base is a single symbol.
let isOiint = false;
if (group.value.base) {
isOiint = group.value.base.value.body === "\\oiint" ||
group.value.base.value.body === "\\oiiint";
}
if (base instanceof domTree.symbolNode || isOiint) {
// $FlowFixMe
marginLeft = -base.italic + "em";
}
}
let supsub;
if (supm && subm) {
supShift = Math.max(
@@ -128,11 +144,6 @@ defineFunctionBuilders({
}
}
// Subscripts shouldn't be shifted by the base's italic correction.
// Account for that by shifting the subscript back the appropriate
// amount. Note we only do this when the base is a single symbol.
const marginLeft =
base instanceof domTree.symbolNode ? -base.italic + "em" : null;
const vlistElem = [
{type: "elem", elem: subm, shift: subShift, marginRight,
marginLeft},
@@ -149,9 +160,6 @@ defineFunctionBuilders({
subShift, metrics.sub1,
subm.height - 0.8 * metrics.xHeight);
// See comment above about subscripts not being shifted.
const marginLeft =
base instanceof domTree.symbolNode ? -base.italic + "em" : null;
const vlistElem =
[{type: "elem", elem: subm, marginLeft, marginRight}];

View File

@@ -160,6 +160,26 @@ c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14
11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0
-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`,
oiintSize1: `M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6
-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z
m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8
60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`,
oiintSize2: `M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8
-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z
m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2
c0 110 84 276 504 276s502.4-166 502.4-276z`,
oiiintSize1: `M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6
-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z
m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0
85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`,
oiiintSize2: `M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8
-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z
m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1
c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`,
rightarrow: `M0 241v40h399891c-47.3 35.3-84 78-110 128
-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20
11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7

View File

@@ -656,6 +656,8 @@ defineSymbol(math, main, op, "\u2a02", "\\bigotimes");
defineSymbol(math, main, op, "\u2a01", "\\bigoplus");
defineSymbol(math, main, op, "\u2a00", "\\bigodot");
defineSymbol(math, main, op, "\u222e", "\\oint");
defineSymbol(math, main, op, "\u222f", "\\oiint");
defineSymbol(math, main, op, "\u2230", "\\oiiint");
defineSymbol(math, main, op, "\u2a06", "\\bigsqcup");
defineSymbol(math, main, op, "\u222b", "\\smallint");
defineSymbol(text, main, inner, "\u2026", "\\textellipsis");

View File

@@ -1350,6 +1350,23 @@ describe("A TeX-compliant parser", function() {
});
});
describe("An op symbol builder", function() {
it("should not fail", function() {
expect("\\int_i^n").toBuild();
expect("\\iint_i^n").toBuild();
expect("\\iiint_i^n").toBuild();
expect("\\int\nolimits_i^n").toBuild();
expect("\\iint\nolimits_i^n").toBuild();
expect("\\iiint\nolimits_i^n").toBuild();
expect("\\oint_i^n").toBuild();
expect("\\oiint_i^n").toBuild();
expect("\\oiiint_i^n").toBuild();
expect("\\oint\nolimits_i^n").toBuild();
expect("\\oiint\nolimits_i^n").toBuild();
expect("\\oiiint\nolimits_i^n").toBuild();
});
});
describe("A style change parser", function() {
it("should not fail", function() {
expect("\\displaystyle x").toParse();

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -132,6 +132,12 @@ GroupMacros:
\endExp: \egroup
tex: \startExp a+b\endExp
HorizontalBraces: \overbrace{\displaystyle{\oint_S{\vec E\cdot\hat n\,\mathrm d a}}}^\text{emf} = \underbrace{\frac{q_{\text{enc}}}{\varepsilon_0}}_{\text{charge}}
Integrands: |
\begin{array}{l}
\displaystyle \int + \oint + \iint + \oiint_i^n \\[0.6em]
\displaystyle \iiint + \oiiint + \textstyle \int + \oint_i^n \\[0.6em]
\iint + \oiint + \iiint + \oiiint
\end{array}
KaTeX:
tex: \KaTeX
nolatex: \KaTeX not supported by LaTeX