IMPROVED: JKQTMathText: rendering of sqrt

This commit is contained in:
jkriege2 2022-06-28 12:00:20 +02:00
parent b83e0a3292
commit 6c26e250da
10 changed files with 159 additions and 40 deletions

View File

@ -38,6 +38,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>MODIFIED: brace node now calculates the extension of the child height above or below the strikeoutPos, in order to center braces around the strikeoutPos</li>
<li>IMPROVED: improved drawing of parantheses, square brackets ... , underbrace/overbrace</li>
<li>IMPROVED: added x-correction for sub/superscript above/below/besides integrals</li>
<li>IMPROVED: rendering of sqrt</li>
<li>remove/breaking: \v[a-zA-Z] and shorthand for \vec{a-zA-Z} was removed, implementation of \bbR,\bbC,... changed</li>
<li>NEW: now supports new decoration instructions: \cancel, \xcancel, \bcancel, \sout, \ocirc, \widetilde, \widehat, \breve</li>
<li>NEW: reworked drawing of decorations: improved appearance and positioning!</li>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -89,7 +89,12 @@
\item\textbf{math 1:} \[f(x)=\int_{-\infty}^xe^{-t^2}\;\mathrm{d}t \]
\item\textbf{math 2:} \[\sum_{i=1}^\infty\frac{-e^{i\pi}}{2^n} \]
\item\textbf{math 3:} \[\mbox{det} \begin{pmatrix} 1 & x_1 & \ldots & x_1^{n-1} \\ 1 & x_2 & \ldots & x_2^{n-1} \\ \vdots & \vdots & \ddots & \vdots \\ 1 & x_n & \ldots & x_n^{n-1} \end{pmatrix} = \prod_{1 \leq i < j \leq n} (x_j - x_i) \]
\item\textbf{math 4:} \[\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+x}}}}}} \]
\item\textbf{math 4:} \[M\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+x}}}}}} \]
\item\textbf{math 4:} \[M\sqrt[3]{1+\sqrt[3]{1+\sqrt[3]{1+\sqrt[3]{1+\sqrt[3]{1+\sqrt[3]{1+x}}}}}} \]
\item\textbf{math 4:} \[M\sqrt{1+X}\sqrt[3]{1+X}\sqrt[3.14156]{1+X} \]
\item\textbf{math 4:} \[M\sqrt{1+X}\sqrt[\frac{1}{2}]{1+X}\sqrt[3.14156\cdot\frac{1}{2}]{1+X} \]
\item\textbf{math 4:} \[M\sqrt{\frac{1}{2}+\sqrt{\frac{1}{2}+\sqrt{\frac{1}{2}+\sqrt{\frac{1}{2}+\sqrt{\frac{1}{2}+\sqrt{1+x}}}}}} \]
\item\textbf{math 4:} \[M\sqrt{a}\frac{\sqrt{a}}{\sqrt{a}}\sqrt{\frac{1}{a}} \]
\item\textbf{math 5:} \[\left(\stackrel{p}{2}\right)=x^2y^{p-2}-\frac{1}{1-x}\frac{1}{1-x^2} \]
\item\textbf{math 6:} \[a_0+\frac{1}{a_1+\frac{1}{a_2+\frac{1}{a_3+\frac{1}{a_4}}}} \]
\item\textbf{math 7:} \[\left(\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\right)\left|\varphi(x+\mathrm{i}y)\right|^2=0 \]

View File

@ -149,12 +149,14 @@ TestForm::TestForm(QWidget *parent) :
ui->cmbTestset->addItem("math 1", "$f(x)=\\int_{-\\infty}^xe^{-t^2}\\;\\mathrm{d}t$");
ui->cmbTestset->addItem("math 2", "$\\sum_{i=1}^\\infty\\frac{-e^{i\\pi}}{2^n}$");
ui->cmbTestset->addItem("math 3", "$\\mbox{det} \\begin{pmatrix} 1 & x_1 & \\ldots & x_1^{n-1} \\\\ 1 & x_2 & \\ldots & x_2^{n-1} \\\\ \\vdots & \\vdots & \\ddots & \\vdots \\\\ 1 & x_n & \\ldots & x_n^{n-1} \\end{pmatrix} = \\prod_{1 \\leq i < j \\leq n} (x_j - x_i) $");
ui->cmbTestset->addItem("math 4", "$\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+x}}}}}}$");
ui->cmbTestset->addItem("math 5", "$\\left(\\stackrel{p}{2}\\right)=x^2y^{p-2}-\\frac{1}{1-x}\\frac{1}{1-x^2}$");
ui->cmbTestset->addItem("math 6", "$a_0+\\frac{1}{a_1+\\frac{1}{a_2+\\frac{1}{a_3+\\frac{1}{a_4}}}}$");
ui->cmbTestset->addItem("math 7", "$\\left(\\frac{\\partial^2}{\\partial x^2}+\\frac{\\partial^2}{\\partial y^2}\\right)\\left|\\varphi(x+\\mathrm{i}y)\\right|^2=0$");
ui->cmbTestset->addItem("math 8", "$2^{2^{2^{x}}}$");
ui->cmbTestset->addItem("math 9", "$\\iint_Df(x,y)\\;\\mathrm{d}x\\;\\mathrm{d}y$");
ui->cmbTestset->addItem("math: nestes sqrt", "$\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+\\sqrt{1+x}}}}}}$");
ui->cmbTestset->addItem("math: nestes cbrt", "$\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+\\sqrt[3]{1+x}}}}}}$");
ui->cmbTestset->addItem("math: nestes sqrt, high contents", "$\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+\\sqrt{\\frac{1}{2}+x}}}}}}$");
ui->cmbTestset->addItem("math 5 (frac+stackrel)", "$\\left(\\stackrel{p}{2}\\right)=x^2y^{p-2}-\\frac{1}{1-x}\\frac{1}{1-x^2}$");
ui->cmbTestset->addItem("math 6 (nested frac)", "$a_0+\\frac{1}{a_1+\\frac{1}{a_2+\\frac{1}{a_3+\\frac{1}{a_4}}}}$");
ui->cmbTestset->addItem("math 7 (partial derivatives)", "$\\left(\\frac{\\partial^2}{\\partial x^2}+\\frac{\\partial^2}{\\partial y^2}\\right)\\left|\\varphi(x+\\mathrm{i}y)\\right|^2=0$");
ui->cmbTestset->addItem("math 8 (powers of powers)", "$2^{2^{2^{x}}}$");
ui->cmbTestset->addItem("math 9 (integral)", "$\\iint_Df(x,y)\\;\\mathrm{d}x\\;\\mathrm{d}y$");
ui->cmbTestset->addItem("math 10 (overbrace+overbracket)", "$\\overbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}$");
ui->cmbTestset->addItem("math 11 (underbrace+underbracket)", "$\\underbrace{x+x+...+x}{k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{x+x+...+x}{k\\ \\mathrm{times}}$");
ui->cmbTestset->addItem("math 12 (under/overbrace+under/overbracket)", "$\\underbrace{\\overbrace{x+x+...+x}{k\\ \\mathrm{times}} \\overbrace{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}\\ \\ \\ \\underbracket{\\overbracket{x+x+...+x}{k\\ \\mathrm{times}} \\overbracket{x+x+...+x}{k\\ \\mathrm{times}}}{2k\\ \\mathrm{times}}$");

View File

@ -92,6 +92,10 @@ JKQTMathText::JKQTMathText(QObject* parent):
mathoperator_width_factor=1.5;
bigmathoperator_font_factor=1.8;
sqrt_width_Xfactor=0.8;
sqrt_height_factor=1.2;
sqrt_smallfont_factor=0.57;
blackboardSimulated=true;
@ -234,6 +238,9 @@ void JKQTMathText::loadSettings(const QSettings& settings, const QString& group)
mathoperator_width_factor=settings.value(group+"mathoperator_width_factor", mathoperator_width_factor).toDouble();
intsubsuper_xcorrection_factor=settings.value(group+"intsubsuper_xcorrection_factor", intsubsuper_xcorrection_factor).toDouble();
intsubbesides_xcorrection_xfactor=settings.value(group+"intsubbesides_xcorrection_xfactor", intsubbesides_xcorrection_xfactor).toDouble();
sqrt_width_Xfactor=settings.value(group+"sqrt_width_Xfactor", sqrt_width_Xfactor).toDouble();
sqrt_height_factor=settings.value(group+"sqrt_height_factor", sqrt_height_factor).toDouble();
sqrt_smallfont_factor=settings.value(group+"sqrt_smallfont_factor", sqrt_smallfont_factor).toDouble();
if (settings.value(group+"use_stix_fonts", false).toBool()) useSTIX();
@ -269,6 +276,9 @@ void JKQTMathText::saveSettings(QSettings& settings, const QString& group) const
settings.setValue(group+ "brace_y_shift_factor", brace_y_shift_factor);
settings.setValue(group+ "decoration_height_factor", decoration_height_factor);
settings.setValue(group+ "decoration_width_reduction_xfactor", decoration_width_reduction_Xfactor);
settings.setValue(group+ "sqrt_width_Xfactor", sqrt_width_Xfactor);
settings.setValue(group+ "sqrt_height_factor", sqrt_height_factor);
settings.setValue(group+ "sqrt_smallfont_factor", sqrt_smallfont_factor);
}
bool JKQTMathText::useSTIX(bool mathModeOnly) {
@ -908,6 +918,36 @@ double JKQTMathText::getDecorationWidthReductionXFactor() const
return decoration_width_reduction_Xfactor;
}
void JKQTMathText::setSqrtWidthXFactor(double __value)
{
sqrt_width_Xfactor=__value;
}
double JKQTMathText::getSqrtWidthXFactor() const
{
return sqrt_width_Xfactor;
}
void JKQTMathText::setSqrtHeightFactor(double __value)
{
sqrt_height_factor=__value;
}
double JKQTMathText::getSqrtHeightFactor() const
{
return sqrt_height_factor;
}
void JKQTMathText::setSqrtSmallFontFactor(double __value)
{
sqrt_smallfont_factor=__value;
}
double JKQTMathText::getSqrtSmallFontFactor() const
{
return sqrt_smallfont_factor;
}
void JKQTMathText::setUseUnparsed(bool __value)
{
this->useUnparsed = __value;

View File

@ -152,6 +152,12 @@ class JKQTMathTextNode; // forward
- You can use \c \\left. or \c \\right. to have only right or only left brace
.
\subsection JKQTMathTextSuppoertedLaTeXRoots Roots
There are also instructions that allow to write roots:
- <code>$\\sqrt{1+\\sqrt{1+x}}$</code> \image html jkqtmathtext/jkqtmathtext_sqrt.png
- <code>$\\sqrt[3]{1+\\sqrt[3]{1+x}}$</code> \image html jkqtmathtext/jkqtmathtext_cbrt.png
.
\subsection JKQTMathTextSuppoertedLaTeXUnderOver Undersetting, Oversetting, Underbraces, Overbraces ...
There are also instructions that allow to under/overset braces, arrows, ...:
- <code>$\\underbrace{x+x+...+x}{k\\ \\mathrm{times}}$</code> \image html jkqtmathtext/jkqtmathtext_brace_underbrace.png
@ -535,6 +541,23 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
void setDecorationWidthReductionXFactor(double __value);
/** \copydoc decoration_width_reduction_Xfactor */
double getDecorationWidthReductionXFactor() const;
/** \copydoc sqrt_width_Xfactor */
void setSqrtWidthXFactor(double __value);
/** \copydoc sqrt_width_Xfactor */
double getSqrtWidthXFactor() const;
/** \copydoc sqrt_height_factor */
void setSqrtHeightFactor(double __value);
/** \copydoc sqrt_height_factor */
double getSqrtHeightFactor() const;
/** \copydoc sqrt_smallfont_factor */
void setSqrtSmallFontFactor(double __value);
/** \copydoc sqrt_smallfont_factor */
double getSqrtSmallFontFactor() const;
/** \copydoc useUnparsed */
void setUseUnparsed(bool __value);
/** \copydoc useUnparsed */
@ -692,6 +715,12 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
* \image html jkqtmathtext/decoration_sizing.png
*/
double decoration_width_reduction_Xfactor;
/** \brief scaling factor for the small font used to indicate the degree of the sqrt */
double sqrt_smallfont_factor;
/** \brief width of the sqrt-symbol, as factor to width("X") */
double sqrt_width_Xfactor;
/** \brief height-increase of the sqrt-symbol, as factor of the child's height */
double sqrt_height_factor;
/** \brief a list that will be filled with error messages while parsing, if any error occur */
QStringList error_list;

View File

@ -45,54 +45,92 @@ JKQTMathTextSqrtNode::~JKQTMathTextSqrtNode() {
}
void JKQTMathTextSqrtNode::getSizeInternal(QPainter& painter, JKQTMathTextEnvironment currentEv, double& width, double& baselineHeight, double& overallHeight, double& strikeoutPos, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
const QFontMetricsF fm(currentEv.getFont(parentMathText), painter.device());
QFont fsmall=currentEv.getFont(parentMathText);
fsmall.setPointSizeF(fsmall.pointSizeF()*parentMathText->getSqrtSmallFontFactor());
fsmall.setItalic(false);
const QFontMetricsF fmsmall(fsmall, painter.device());
getChild()->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
const double descent=overallHeight-baselineHeight;
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent());
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent());
overallHeight=overallHeight*1.2;//+fm.ascent()*0.1;
baselineHeight=baselineHeight*1.2;//+fm.ascent()*0.1;
width=width+fm.boundingRect("A").width()*2; // 1.53
overallHeight=newAscent+newDescent;;
baselineHeight=newAscent;
width=width+sqrtwidth;
if (degree!=2) {
const QString degreetext=QLocale::c().toString(degree);
const double degwidth=fmsmall.width(degreetext);
const double smalltextIndent=0.6*sqrtwidth;
if (degwidth>smalltextIndent) width=width+(degwidth-smalltextIndent);
}
}
double JKQTMathTextSqrtNode::draw(QPainter& painter, double x, double y, JKQTMathTextEnvironment currentEv, const JKQTMathTextNodeSize* /*prevNodeSize*/) {
doDrawBoxes(painter, x, y, currentEv);
double width=0, baselineHeight=0, overallHeight=0, sp=0;
getChild()->getSize(painter, currentEv, width, baselineHeight, overallHeight, sp);
QFont f=currentEv.getFont(parentMathText);
const QFont f=currentEv.getFont(parentMathText);
QFont fsmall=f;
QFontMetricsF fm(f, painter.device());
double w=fm.boundingRect("A").width();
double a=baselineHeight*1.15;
double d=overallHeight-baselineHeight;
const QFontMetricsF fm(f, painter.device());
fsmall.setPointSizeF(fsmall.pointSizeF()*parentMathText->getSqrtSmallFontFactor());
fsmall.setItalic(false);
const QFontMetricsF fmsmall(fsmall, painter.device());
double width=0, baselineHeight=0, overallHeight=0, strikeoutPos=0;
getChild()->getSize(painter, currentEv, width, baselineHeight, overallHeight, strikeoutPos);
const double descent=overallHeight-baselineHeight;
const double sqrtwidth=fm.boundingRect("X").width()*parentMathText->getSqrtWidthXFactor();
const double newAscent=qMax(baselineHeight*parentMathText->getSqrtHeightFactor(), fm.ascent());
const double newDescent=qMax(descent*parentMathText->getSqrtHeightFactor(), fm.descent());
const double linewidth=fm.lineWidth();
const double tinyhookSize=sqrtwidth*0.1;
const double smalltextIndent=0.6*sqrtwidth;
const QString degreetext=(degree!=2)?QLocale::c().toString(degree):"";
const double degwidth=fmsmall.width(degreetext);
const double degheight=fmsmall.boundingRect(degreetext).height();
const double degree_overwidth=(degwidth>smalltextIndent)?(degwidth-smalltextIndent):0.0;
//painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=painter.pen();
p.setColor(currentEv.color);
p.setWidthF(fm.lineWidth());
p.setWidthF(linewidth);
p.setCapStyle(Qt::RoundCap);
p.setJoinStyle(Qt::RoundJoin);
//painter.setPen(p);
double xnew=getChild()->draw(painter, x+sqrtwidth+degree_overwidth, y, currentEv);
const bool useAltForm=overallHeight>4.0*sqrtwidth;
const double y_tinyhooktop=y-strikeoutPos;
const double y_bottom=y+newDescent-linewidth/2.0;
const double y_top=y-newAscent+linewidth/2.0;
const double x_start=x+degree_overwidth+linewidth/2.0;
const double x_tinyhooktop=x_start+tinyhookSize;
const double x_hookbottom=(!useAltForm)?(x_start+0.33*sqrtwidth):(x_start+0.66*sqrtwidth);
const double x_hooktop=(!useAltForm)?(x_start+sqrtwidth):x_hookbottom;
const double x_smalltextend=x_start+smalltextIndent;
const double y_smalltext=y_top+fmsmall.ascent()+(fabs(y_top-(y_tinyhooktop-linewidth))-degheight)/2.0;
if (sqrtwidth>0) {
QPainterPath path;
if (w>0) {
path.moveTo(x+0.1*w, y-0.4*a);
path.lineTo(x+0.33*w, y-0.4*a);
path.lineTo( x+0.66*w, y+0.5*d);
path.lineTo(x+w, y-a);
}
if (degree!=2) {
fsmall.setPointSizeF(fsmall.pointSizeF()/2.0);
fsmall.setItalic(false);
painter.setFont(fsmall);
painter.drawText(QPointF(x+0.33*w, y-0.55*a), QLocale::c().toString(degree));
}
//painter.restore();
double xnew=getChild()->draw(painter, x+1.2*w, y, currentEv);
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
path.moveTo(x_start, y_tinyhooktop+tinyhookSize);
path.lineTo(x_tinyhooktop, y_tinyhooktop);
path.lineTo(x_hookbottom, y_bottom);
path.lineTo(x_hooktop, y_top);
path.lineTo(xnew-linewidth/2.0, y_top);
path.moveTo(x_tinyhooktop,y_tinyhooktop);
path.lineTo(x_tinyhooktop+linewidth*0.8, y_tinyhooktop-linewidth*0.8);
path.lineTo(x_hookbottom, y_bottom-2.0*linewidth);
painter.setPen(p);
if (w>0) {
path.lineTo( xnew+0.2*w, y-a);
path.lineTo(xnew+0.2*w, y-0.8*a);
painter.drawPath(path);
}
if (degree!=2) {
painter.setFont(fsmall);
painter.drawText(QPointF(x_smalltextend-degwidth, y_smalltext), degreetext);
}
return xnew+0.33*w;
return xnew;
}
bool JKQTMathTextSqrtNode::toHtml(QString &html, JKQTMathTextEnvironment currentEv, JKQTMathTextEnvironment defaultEv) {

View File

@ -35,6 +35,10 @@ class JKQTMathText; // forward
/** \brief subclass representing a sqrt node
* \ingroup jkqtmathtext_items
*
* This node renders square roots without and with an explicitly shown degree:
* \image html jkqtmathtext/jkqtmathtext_sqrt.png
* \image html jkqtmathtext/jkqtmathtext_cbrt.png
*/
class JKQTMATHTEXT_LIB_EXPORT JKQTMathTextSqrtNode: public JKQTMathTextSingleChildNode {
public: