IMPROVEMENTS: JKQTMathText: underbrace/overbrace and angle-braket improvements

This commit is contained in:
jkriege2 2022-06-27 21:09:22 +02:00
parent ebdc183b2b
commit 56418f9504
5 changed files with 104 additions and 39 deletions

View File

@ -36,7 +36,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>IMPROVED: high-dpr-support in JKQTMathText</li>
<li>IMPROVED: typesetting of sub-/supercripts, especially for large math operators and braces</li>
<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 ...</li>
<li>IMPROVED: improved drawing of parantheses, square brackets ... , underbrace/overbrace</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>

View File

@ -78,6 +78,8 @@ JKQTMathText::JKQTMathText(QObject* parent):
frac_shift_factor=0.4;
underbrace_factor=0.75;
underbrace_separation_xfactor=0.25;
underbrace_bracesize_xfactor=0.5;
underset_factor=0.7;
decoration_height_factor=0.2;
decoration_width_reduction_Xfactor=0.2;
@ -218,6 +220,8 @@ void JKQTMathText::loadSettings(const QSettings& settings, const QString& group)
frac_factor=settings.value(group+"frac_factor", frac_factor).toDouble();
frac_shift_factor=settings.value(group+"frac_shift_factor", frac_shift_factor).toDouble();
underbrace_factor=settings.value(group+"underbrace_factor", underbrace_factor).toDouble();
underbrace_bracesize_xfactor=settings.value(group+"underbrace_bracesize_xfactor", underbrace_bracesize_xfactor).toDouble();
underbrace_separation_xfactor=settings.value(group+"underbrace_separation_xfactor", underbrace_separation_xfactor).toDouble();
underset_factor=settings.value(group+"undersetFactor", underset_factor).toDouble();
brace_y_shift_factor=settings.value(group+"brace_y_shift_factor", brace_y_shift_factor).toDouble();
decoration_height_factor=settings.value(group+"decoration_height_factor", decoration_height_factor).toDouble();
@ -249,6 +253,8 @@ void JKQTMathText::saveSettings(QSettings& settings, const QString& group) const
settings.setValue(group+ "frac_factor", frac_factor);
settings.setValue(group+ "frac_shift_factor", frac_shift_factor);
settings.setValue(group+ "underbrace_factor", underbrace_factor);
settings.setValue(group+ "underbrace_bracesize_xfactor", underbrace_bracesize_xfactor);
settings.setValue(group+ "underbrace_separation_xfactor", underbrace_separation_xfactor);
settings.setValue(group+ "undersetFactor", underset_factor);
settings.setValue(group+ "operatorsubsuper_size_factor", operatorsubsuper_size_factor);
settings.setValue(group+ "operatorsubsuper_distance_factor", operatorsubsuper_distance_factor);
@ -786,6 +792,26 @@ double JKQTMathText::getUnderbraceFactor() const
return this->underbrace_factor;
}
void JKQTMathText::setUnderbraceSeparationXFactor(double __value)
{
underbrace_separation_xfactor=__value;
}
double JKQTMathText::getUnderbraceSeparationXFactor() const
{
return underbrace_separation_xfactor;
}
void JKQTMathText::setUnderbraceBraceSizeXFactor(double __value)
{
underbrace_bracesize_xfactor=__value;
}
double JKQTMathText::getUnderbraceBraceSizeXFactor() const
{
return underbrace_bracesize_xfactor;
}
void JKQTMathText::setUndersetFactor(double __value)
{
this->underset_factor = __value;

View File

@ -486,7 +486,15 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
void setUnderbraceFactor(double __value);
/** \copydoc underbrace_factor */
double getUnderbraceFactor() const;
/** \copydoc undersetFactor */
/** \copydoc underbrace_separation_xfactor */
void setUnderbraceSeparationXFactor(double __value);
/** \copydoc underbrace_separation_xfactor */
double getUnderbraceSeparationXFactor() const;
/** \copydoc underbrace_bracesize_xfactor */
void setUnderbraceBraceSizeXFactor(double __value);
/** \copydoc underbrace_bracesize_xfactor */
double getUnderbraceBraceSizeXFactor() const;
/** \copydoc undersetFactor */
void setUndersetFactor(double __value);
/** \copydoc undersetFactor */
double getUndersetFactor() const;
@ -641,6 +649,10 @@ class JKQTMATHTEXT_LIB_EXPORT JKQTMathText : public QObject {
double underbrace_factor;
/** \brief scaling factor for font of underset/overset text */
double underset_factor;
/** \brief additional space between the main text to the curly brace and the brace to underbrace/overbrace, multiplied with height("x") */
double underbrace_separation_xfactor;
/** \brief height of the brace in underbrace/overbrace, multiplied with ascent */
double underbrace_bracesize_xfactor;
/** \brief fraction of the brace ascent that the brace is shifted downwards, when scaled */
double brace_y_shift_factor;
/** \brief size of the decorations (dot, tilde, ...), as fraction of the baselineheight

View File

@ -134,11 +134,30 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
path.cubicTo(ptc2, pbc2, pb2);
path.closeSubpath();
painter.fillPath(path, QBrush(ev.color, Qt::SolidPattern));
painter.setPen("blue");
/*painter.setPen("blue");
painter.drawLine(pb1,pbc1);
painter.drawLine(pt1,ptc1);
painter.drawLine(pb2,pbc2);
painter.drawLine(pt2,ptc2);
painter.drawLine(pt2,ptc2);*/
} else if (openbrace==MTBTAngleBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight);
const double y2=y-nodeBaselineHeight;
const double yc=(y1+y2)/2.0;
const QPointF pb1(xbrace2-paren_topwidth/2.0, y1);
const QPointF pc1(xbrace1-paren_centerwidth/2.0, yc);
const QPointF pt1(xbrace2-paren_topwidth/2.0, y2);
const QPointF pt2(xbrace2+paren_topwidth/2.0, y2);
const QPointF pc2(xbrace1+paren_centerwidth/2.0, yc);
const QPointF pb2(xbrace2+paren_topwidth/2.0, y1);
path.moveTo(pb1);
path.lineTo(pc1);
path.lineTo(pt1);
path.lineTo(pt2);
path.lineTo(pc2);
path.lineTo(pb2);
path.closeSubpath();
painter.fillPath(path, QBrush(ev.color, Qt::SolidPattern));
} else if (openbrace==MTBTSquareBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight)-lw/2.0;
@ -205,17 +224,9 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
painter.setPen(plocal);
const QLineF l(xbrace1, y1, xbrace1, y2);
if (l.length()>0) painter.drawLine(l);
const QLineF l2(xbrace1+1.5*lw, y1, xbrace1+1.5*lw, y2);
const QLineF l2(xbrace1+2.5*lw, y1, xbrace1+2.5*lw, y2);
if (l2.length()>0) painter.drawLine(l2);
painter.setPen(p);
} else if (openbrace==MTBTAngleBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight);
const double y2=y-nodeBaselineHeight;
path.moveTo(xbrace2, y1);
path.lineTo(xbrace1, (y2+y1)/2.0);
path.lineTo(xbrace2, y2);
painter.drawPath(path);
} else {
showOpeningBrace=false;
}
@ -257,7 +268,25 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
painter.drawLine(pt1,ptc1);
painter.drawLine(pb2,pbc2);
painter.drawLine(pt2,ptc2);*/
} else if (closebrace==MTBTAngleBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight);
const double y2=y-nodeBaselineHeight;
const double yc=(y1+y2)/2.0;
const QPointF pb1(xbrace1-paren_topwidth/2.0, y1);
const QPointF pc1(xbrace2-paren_centerwidth/2.0, yc);
const QPointF pt1(xbrace1-paren_topwidth/2.0, y2);
const QPointF pt2(xbrace1+paren_topwidth/2.0, y2);
const QPointF pc2(xbrace2+paren_centerwidth/2.0, yc);
const QPointF pb2(xbrace1+paren_topwidth/2.0, y1);
path.moveTo(pb1);
path.lineTo(pc1);
path.lineTo(pt1);
path.lineTo(pt2);
path.lineTo(pc2);
path.lineTo(pb2);
path.closeSubpath();
painter.fillPath(path, QBrush(ev.color, Qt::SolidPattern));
} else if (closebrace==MTBTSquareBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight)-lw/2.0;
@ -331,17 +360,9 @@ double JKQTMathTextBraceNode::draw(QPainter& painter, double x, double y, JKQTMa
plocal.setWidthF(plocal.widthF()*absnorm_linewidth_factor);
painter.setPen(plocal);
if (l.length()>0) painter.drawLine(l);
const QLineF l2(xbrace2-1.5*lw, y1, xbrace2-1.5*lw, y2);
const QLineF l2(xbrace2-2.5*lw, y1, xbrace2-2.5*lw, y2);
if (l2.length()>0) painter.drawLine(l2);
painter.setPen(p);
} else if (closebrace==MTBTAngleBracket) {
QPainterPath path;
const double y1=y+(nodeOverallHeight-nodeBaselineHeight);
const double y2=y-nodeBaselineHeight;
path.moveTo(xbrace1, y1);
path.lineTo(xbrace2, (y2+y1)/2.0);
path.lineTo(xbrace1, y2);
painter.drawPath(path);
} else {
showClosingBrace=false;
}

View File

@ -90,6 +90,8 @@ void JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JKQTMathTextEnviro
const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
const double xwidth=JKQTMathTextGetTightBoundingRect(f, "x", painter.device()).width();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent();
const double braceheight=fm.xHeight()*parentMathText->getUnderbraceBraceSizeXFactor();
const double braceseparation=fm.xHeight()*parentMathText->getUnderbraceSeparationXFactor();
if (mode==JKQTMathTextFracNode::MTFMunderbrace || mode==JKQTMathTextFracNode::MTFMoverbrace) {
ev2.fontSize=ev2.fontSize*parentMathText->getUnderbraceFactor();
@ -108,6 +110,7 @@ void JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JKQTMathTextEnviro
double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos2=0;
child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos1);
child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos2);
const double descent1=overallHeight1-baselineHeight1;
overallHeight=0;
@ -135,13 +138,14 @@ void JKQTMathTextFracNode::getSizeInternal(QPainter& painter, JKQTMathTextEnviro
overallHeight=newascent+newdescent;
baselineHeight=newascent;
} else if (mode==JKQTMathTextFracNode::MTFMunderbrace) {
overallHeight=overallHeight1+overallHeight2+Mheight/2.0;
const double newdescent=descent1+overallHeight2+braceheight+2.0*braceseparation;
overallHeight=newdescent+baselineHeight1;
baselineHeight=baselineHeight1;
width=qMax(width1, width2)+xwidth;
strikeoutPos=line_ascent;
} else if (mode==JKQTMathTextFracNode::MTFMoverbrace) {
overallHeight=overallHeight1+overallHeight2+Mheight/2.0;
baselineHeight=baselineHeight1+overallHeight2+Mheight/2.0;
overallHeight=overallHeight1+overallHeight2+braceheight+2.0*braceseparation;
baselineHeight=baselineHeight1+overallHeight2+braceheight+2.0*braceseparation;
width=qMax(width1, width2)+xwidth;
strikeoutPos=line_ascent;
} else if (mode==JKQTMathTextFracNode::MTFMunderset) {
@ -189,7 +193,8 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
const double linewideth=qMax(0.0,ceil(currentEv.fontSize/16.0));//fm.lineWidth();
const double Mheight=JKQTMathTextGetTightBoundingRect(f, "M", painter.device()).height();//fm.ascent();
const double qheight=JKQTMathTextGetTightBoundingRect(f, "q", painter.device()).height();//fm.ascent();
const double bw=Mheight/2.0;
const double braceheight=fm.xHeight()*parentMathText->getUnderbraceBraceSizeXFactor();
const double braceseparation=fm.xHeight()*parentMathText->getUnderbraceSeparationXFactor();
if (mode==JKQTMathTextFracNode::MTFMunderbrace || mode==JKQTMathTextFracNode::MTFMoverbrace) {
ev2.fontSize=ev2.fontSize*parentMathText->getUnderbraceFactor();
@ -208,12 +213,12 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
double width2=0, baselineHeight2=0, overallHeight2=0, strikeoutPos=0;
child1->getSize(painter, ev1, width1, baselineHeight1, overallHeight1, strikeoutPos);
child2->getSize(painter, ev2, width2, baselineHeight2, overallHeight2, strikeoutPos);
double ascent1=baselineHeight1;
double descent1=overallHeight1-baselineHeight1;
double ascent2=baselineHeight2;
double descent2=overallHeight2-baselineHeight2;
const double ascent1=baselineHeight1;
const double descent1=overallHeight1-baselineHeight1;
const double ascent2=baselineHeight2;
const double descent2=overallHeight2-baselineHeight2;
double yline=y-xheight*0.5;
const double yline=y-xheight*0.5;
//double overallHeight=overallHeight1+overallHeight2+xh;
@ -247,35 +252,36 @@ double JKQTMathTextFracNode::draw(QPainter& painter, double x, double y, JKQTMat
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, y+descent1+xheight/6.0+ascent2, ev2);
deltaWidth=xwidth;
} else if (mode==JKQTMathTextFracNode::MTFMunderbrace) {
double ybrace=y+descent1+bw/2.0;
const double ybrace=y+descent1+braceseparation+braceheight/2.0;
const double ybot=y+descent1+2.0*braceseparation+braceheight+ascent2;
{
const QPainterPath path=JKQTMathTextMakeHBracePath(x+xwidth/2.0+(width1)/2.0, ybrace, maxWidth, bw, p.width());
const QPainterPath path=JKQTMathTextMakeHBracePath(x+xwidth/2.0+(width1)/2.0, ybrace, maxWidth, braceheight, p.width());
QPen plocal=p;
plocal.setWidthF(0.0001);
painter.fillPath(path, QBrush(ev1.color));
}
child1->draw(painter, x+xwidth/2.0+(maxWidth-width1)/2.0, y, ev1);
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, y+descent1+bw+ascent2, ev2);
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, ybot, ev2);
deltaWidth=xwidth;
} else if (mode==JKQTMathTextFracNode::MTFMoverset) {
child1->draw(painter, x+xwidth/2.0+(maxWidth-width1)/2.0, y, ev1);
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, y-ascent1-xheight/6.0-descent2, ev2);
deltaWidth=xwidth;
} else if (mode==JKQTMathTextFracNode::MTFMoverbrace) {
const double ybrace=y-ascent1-bw/2.0;
const double ybrace=y-ascent1-braceheight/2.0-braceseparation;
const double ytop=y-ascent1-2.0*braceseparation-braceheight-descent2;
{
painter.save(); auto __finalpaintinner=JKQTPFinally([&painter]() {painter.restore();});
painter.translate(x+xwidth/2.0+(width1)/2.0, ybrace);
painter.rotate(180);
const QPainterPath path=JKQTMathTextMakeHBracePath(0,0, maxWidth, bw, p.widthF());
const QPainterPath path=JKQTMathTextMakeHBracePath(0,0, maxWidth, braceheight, p.widthF());
QPen plocal=p;
plocal.setWidthF(0.0001);
painter.fillPath(path, QBrush(ev1.color));
}
child1->draw(painter, x+xwidth/2.0+(maxWidth-width1)/2.0, y, ev1);
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, y-ascent1-bw-descent2, ev2);
child2->draw(painter, x+xwidth/2.0+(maxWidth-width2)/2.0, ytop, ev2);
deltaWidth=xwidth;
}