mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
[poincare] Sum and Product can specify their variable name
This commit is contained in:
@@ -50,7 +50,7 @@ PermuteCommandWithArg = "permute(n,r)"
|
||||
P = "p"
|
||||
Prediction95CommandWithArg = "prediction95(p,n)"
|
||||
PredictionCommandWithArg = "prediction(p,n)"
|
||||
ProductCommandWithArg = "product(f(n),nmin,nmax)"
|
||||
ProductCommandWithArg = "product(f(n),n,nmin,nmax)"
|
||||
QuoCommandWithArg = "quo(p,q)"
|
||||
RandintCommandWithArg = "randint(a,b)"
|
||||
RandomCommandWithArg = "random()"
|
||||
@@ -65,7 +65,7 @@ Shift = "shift"
|
||||
Sigma = "σ"
|
||||
SinhCommandWithArg = "sinh(x)"
|
||||
SortCommandWithArg = "sort<(L)"
|
||||
SumCommandWithArg = "sum(f(n),nmin,nmax)"
|
||||
SumCommandWithArg = "sum(f(n),n,nmin,nmax)"
|
||||
Sxy = "Σxy"
|
||||
TanhCommandWithArg = "tanh(x)"
|
||||
TraceCommandWithArg = "trace(M)"
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
private:
|
||||
const char * name() const override { return "product"; }
|
||||
float emptySequenceValue() const override { return 1.0f; }
|
||||
Layout createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
|
||||
Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
|
||||
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
|
||||
return templatedApproximateWithNextTerm<double>(a, b);
|
||||
}
|
||||
@@ -34,10 +34,11 @@ friend class ProductNode;
|
||||
public:
|
||||
Product();
|
||||
Product(const ProductNode * n) : Expression(n) {}
|
||||
Product(Expression operand0, Expression operand1, Expression operand2) : Product() {
|
||||
Product(Expression operand0, Expression operand1, Expression operand2, Expression op) : Product() {
|
||||
replaceChildAtIndexInPlace(0, operand0);
|
||||
replaceChildAtIndexInPlace(1, operand1);
|
||||
replaceChildAtIndexInPlace(2, operand2);
|
||||
replaceChildAtIndexInPlace(3, operand2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,12 +25,13 @@ private:
|
||||
|
||||
class ProductLayout final : public Layout {
|
||||
public:
|
||||
ProductLayout(Layout argument, Layout lowerB, Layout upperB) :
|
||||
ProductLayout(Layout argument, Layout variable, Layout lowerB, Layout upperB) :
|
||||
Layout(TreePool::sharedPool()->createTreeNode<ProductLayoutNode>())
|
||||
{
|
||||
replaceChildAtIndexInPlace(0, argument);
|
||||
replaceChildAtIndexInPlace(1, lowerB);
|
||||
replaceChildAtIndexInPlace(2, upperB);
|
||||
replaceChildAtIndexInPlace(1, variable);
|
||||
replaceChildAtIndexInPlace(2, lowerB);
|
||||
replaceChildAtIndexInPlace(3, upperB);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ namespace Poincare {
|
||||
|
||||
class SequenceNode : public ExpressionNode {
|
||||
public:
|
||||
int numberOfChildren() const override { return 3; }
|
||||
int numberOfChildren() const override { return 4; }
|
||||
private:
|
||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override {
|
||||
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name());
|
||||
}
|
||||
virtual Layout createSequenceLayout(Layout subscriptLayout, Layout superscriptLayout, Layout argumentLayout) const = 0;
|
||||
virtual Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const = 0;
|
||||
virtual const char * name() const = 0;
|
||||
/* Approximation */
|
||||
Evaluation<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
|
||||
|
||||
@@ -23,15 +23,15 @@ public:
|
||||
char XNTChar() const override { return 'n'; }
|
||||
|
||||
// TreeNode
|
||||
int numberOfChildren() const override { return 3; }
|
||||
int numberOfChildren() const override { return 4; }
|
||||
|
||||
protected:
|
||||
constexpr static KDCoordinate k_boundHeightMargin = 2;
|
||||
constexpr static KDCoordinate k_argumentWidthMargin = 2;
|
||||
constexpr static const KDFont * k_font = KDFont::LargeFont;
|
||||
constexpr static char k_nEquals[] = {'n', '=', 0};
|
||||
constexpr static char k_equal[] = {'=', 0};
|
||||
|
||||
KDSize lowerBoundSizeWithNEquals();
|
||||
KDSize lowerBoundSizeWithVariableEquals();
|
||||
|
||||
// LayoutNode
|
||||
KDSize computeSize() override;
|
||||
@@ -40,9 +40,13 @@ protected:
|
||||
|
||||
int writeDerivedClassInBuffer(const char * operatorName, char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const;
|
||||
LayoutNode * argumentLayout() { return childAtIndex(0); }
|
||||
LayoutNode * lowerBoundLayout() { return childAtIndex(1); }
|
||||
LayoutNode * upperBoundLayout() { return childAtIndex(2); }
|
||||
LayoutNode * variableLayout() { return childAtIndex(1); }
|
||||
LayoutNode * lowerBoundLayout() { return childAtIndex(2); }
|
||||
LayoutNode * upperBoundLayout() { return childAtIndex(3); }
|
||||
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
|
||||
private:
|
||||
KDCoordinate completeLowerBoundX();
|
||||
KDCoordinate subscriptBaseline();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
private:
|
||||
const char * name() const override { return "sum"; }
|
||||
float emptySequenceValue() const override { return 0.0f; }
|
||||
Layout createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
|
||||
Layout createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const override;
|
||||
Evaluation<double> evaluateWithNextTerm(DoublePrecision p, Evaluation<double> a, Evaluation<double> b) const override {
|
||||
return templatedApproximateWithNextTerm<double>(a, b);
|
||||
}
|
||||
@@ -34,10 +34,11 @@ friend class SumNode;
|
||||
public:
|
||||
Sum();
|
||||
Sum(const SumNode * n) : Expression(n) {}
|
||||
Sum(Expression operand0, Expression operand1, Expression operand2) : Sum() {
|
||||
Sum(Expression operand0, Expression operand1, Expression operand2, Expression operand3) : Sum() {
|
||||
replaceChildAtIndexInPlace(0, operand0);
|
||||
replaceChildAtIndexInPlace(1, operand1);
|
||||
replaceChildAtIndexInPlace(2, operand2);
|
||||
replaceChildAtIndexInPlace(3, operand3);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -23,12 +23,13 @@ private:
|
||||
|
||||
class SumLayout final : public Layout {
|
||||
public:
|
||||
SumLayout(Layout argument, Layout lowerB, Layout upperB) :
|
||||
SumLayout(Layout argument, Layout variable, Layout lowerB, Layout upperB) :
|
||||
Layout(TreePool::sharedPool()->createTreeNode<SumLayoutNode>())
|
||||
{
|
||||
replaceChildAtIndexInPlace(0, argument);
|
||||
replaceChildAtIndexInPlace(1, lowerB);
|
||||
replaceChildAtIndexInPlace(2, upperB);
|
||||
replaceChildAtIndexInPlace(1, variable);
|
||||
replaceChildAtIndexInPlace(2, lowerB);
|
||||
replaceChildAtIndexInPlace(3, upperB);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ atanh { *yylval = HyperbolicArcTangent(); return FUNCTION; }
|
||||
binomial { *yylval = BinomialCoefficient(); return FUNCTION; }
|
||||
ceil { *yylval = Ceiling(); return FUNCTION; }
|
||||
confidence { *yylval = ConfidenceInterval(); return FUNCTION; }
|
||||
diff { *yylval = Derivative(); return DIFF_FUNCTION; }
|
||||
diff { *yylval = Derivative(); return VARIABLE_DEPENDENT_FUNCTION; }
|
||||
dim { *yylval = MatrixDimension(); return FUNCTION; }
|
||||
conj { *yylval = Conjugate(); return FUNCTION; }
|
||||
det { *yylval = Determinant(); return FUNCTION; }
|
||||
@@ -126,7 +126,7 @@ floor { *yylval = Floor(); return FUNCTION; }
|
||||
frac { *yylval = FracPart(); return FUNCTION; }
|
||||
gcd { *yylval = GreatCommonDivisor(); return FUNCTION; }
|
||||
im { *yylval = ImaginaryPart(); return FUNCTION; }
|
||||
int { *yylval = Integral(); return INT_FUNCTION; }
|
||||
int { *yylval = Integral(); return VARIABLE_DEPENDENT_FUNCTION; }
|
||||
inverse { *yylval = MatrixInverse(); return FUNCTION; }
|
||||
lcm { *yylval = LeastCommonMultiple(); return FUNCTION; }
|
||||
ln { *yylval = NaperianLogarithm(); return FUNCTION; }
|
||||
@@ -135,7 +135,7 @@ log\_\{ { return LOG_FUNCTION_TWO_ARGUMENTS; }
|
||||
permute { *yylval = PermuteCoefficient(); return FUNCTION; }
|
||||
prediction95 { *yylval = PredictionInterval(); return FUNCTION; }
|
||||
prediction { *yylval = SimplePredictionInterval(); return FUNCTION; }
|
||||
product { *yylval = Product(); return FUNCTION; }
|
||||
product { *yylval = Product(); return VARIABLE_DEPENDENT_FUNCTION; }
|
||||
quo { *yylval = DivisionQuotient(); return FUNCTION; }
|
||||
random { *yylval = Random(); return FUNCTION; }
|
||||
randint { *yylval = Randint(); return FUNCTION; }
|
||||
@@ -145,7 +145,7 @@ root { *yylval = NthRoot(); return FUNCTION; }
|
||||
round { *yylval = Round(); return FUNCTION; }
|
||||
sin { *yylval = Sine(); return FUNCTION; }
|
||||
sinh { *yylval = HyperbolicSine(); return FUNCTION; }
|
||||
sum { *yylval = Sum(); return FUNCTION; }
|
||||
sum { *yylval = Sum(); return VARIABLE_DEPENDENT_FUNCTION; }
|
||||
tan { *yylval = Tangent(); return FUNCTION; }
|
||||
tanh { *yylval = HyperbolicTangent(); return FUNCTION; }
|
||||
trace { *yylval = MatrixTrace(); return FUNCTION; }
|
||||
|
||||
@@ -73,7 +73,7 @@ using namespace Poincare;
|
||||
%nonassoc RIGHT_BRACKET
|
||||
%nonassoc LEFT_BRACE
|
||||
%nonassoc RIGHT_BRACE
|
||||
%nonassoc FUNCTION LOG_FUNCTION LOG_FUNCTION_TWO_ARGUMENTS DIFF_FUNCTION INT_FUNCTION
|
||||
%nonassoc FUNCTION LOG_FUNCTION LOG_FUNCTION_TWO_ARGUMENTS VARIABLE_DEPENDENT_FUNCTION
|
||||
%left COMMA
|
||||
%nonassoc UNDERSCORE
|
||||
%nonassoc DIGITS
|
||||
@@ -134,8 +134,7 @@ term : TERM { $$ = $1; }
|
||||
/* Special case for logarithm, as we do not at first if it needs 1 or 2 children */
|
||||
| LOG_FUNCTION lstData RIGHT_PARENTHESIS { if ($2.numberOfChildren() == 1) { $$ = Logarithm($2.childAtIndex(0)); } else if ($2.numberOfChildren() == 2) { $$ = Logarithm($2.childAtIndex(0), $2.childAtIndex(1));} else { YYERROR; } ; }
|
||||
| LOG_FUNCTION_TWO_ARGUMENTS exp RIGHT_BRACE LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = Logarithm($5, $2); }
|
||||
| DIFF_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); }
|
||||
| INT_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol && $3.childAtIndex(1).type() != ExpressionNode::Type::EmptyExpression ) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); }
|
||||
| VARIABLE_DEPENDENT_FUNCTION LEFT_PARENTHESIS lstData RIGHT_PARENTHESIS { if ($$.numberOfChildren() != ($3.numberOfChildren())) { YYERROR; } ; if ($3.childAtIndex(1).type() != ExpressionNode::Type::Symbol && $3.childAtIndex(1).type() != ExpressionNode::Type::EmptyExpression ) { YYERROR; } ; $$ = $1; $$.setChildrenInPlace($3); }
|
||||
| LEFT_PARENTHESIS exp RIGHT_PARENTHESIS { $$ = Parenthesis($2); }
|
||||
/* MATRICES_ARE_DEFINED */
|
||||
| LEFT_BRACKET mtxData RIGHT_BRACKET { $$ = $2; }
|
||||
|
||||
@@ -9,8 +9,8 @@ extern "C" {
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const {
|
||||
return ProductLayout(argumentLayout, subscriptLayout, superscriptLayout);
|
||||
Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
|
||||
return ProductLayout(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -13,7 +13,7 @@ int ProductLayoutNode::serialize(char * buffer, int bufferSize, Preferences::Pri
|
||||
void ProductLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
|
||||
// Compute sizes.
|
||||
KDSize upperBoundSize = upperBoundLayout()->layoutSize();
|
||||
KDSize lowerBoundNEqualsSize = lowerBoundSizeWithNEquals();
|
||||
KDSize lowerBoundNEqualsSize = lowerBoundSizeWithVariableEquals();
|
||||
|
||||
// Render the Product symbol.
|
||||
ctx->fillRect(KDRect(p.x() + max(max(0, (upperBoundSize.width()-k_symbolWidth)/2), (lowerBoundNEqualsSize.width()-k_symbolWidth)/2),
|
||||
|
||||
@@ -12,19 +12,19 @@ extern "C" {
|
||||
namespace Poincare {
|
||||
|
||||
Layout SequenceNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
return createSequenceLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits));
|
||||
return createSequenceLayout(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(1)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(2)->createLayout(floatDisplayMode, numberOfSignificantDigits), childAtIndex(3)->createLayout(floatDisplayMode, numberOfSignificantDigits));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Evaluation<T> SequenceNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
|
||||
Evaluation<T> aInput = childAtIndex(1)->approximate(T(), context, angleUnit);
|
||||
Evaluation<T> bInput = childAtIndex(2)->approximate(T(), context, angleUnit);
|
||||
Evaluation<T> aInput = childAtIndex(2)->approximate(T(), context, angleUnit);
|
||||
Evaluation<T> bInput = childAtIndex(3)->approximate(T(), context, angleUnit);
|
||||
T start = aInput.toScalar();
|
||||
T end = bInput.toScalar();
|
||||
if (std::isnan(start) || std::isnan(end) || start != (int)start || end != (int)end || end - start > k_maxNumberOfSteps) {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
VariableContext nContext = VariableContext("n", &context);
|
||||
VariableContext nContext = VariableContext(static_cast<SymbolNode *>(childAtIndex(1))->name(), &context);
|
||||
Evaluation<T> result = Complex<T>((T)emptySequenceValue());
|
||||
for (int i = (int)start; i <= (int)end; i++) {
|
||||
if (Expression::shouldStopProcessing()) {
|
||||
|
||||
@@ -9,20 +9,34 @@ namespace Poincare {
|
||||
|
||||
static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
|
||||
|
||||
constexpr char SequenceLayoutNode::k_nEquals[];
|
||||
constexpr char SequenceLayoutNode::k_equal[];
|
||||
|
||||
void SequenceLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
|
||||
if (cursor->position() == LayoutCursor::Position::Left
|
||||
&& (cursor->layoutNode() == lowerBoundLayout()
|
||||
|| cursor->layoutNode() == upperBoundLayout()))
|
||||
if (cursor->layoutNode() == upperBoundLayout())
|
||||
{
|
||||
// Case: Left of the bounds. Go Left of the sequence.
|
||||
assert(cursor->position() == LayoutCursor::Position::Left);
|
||||
// Case: Left of the upper bound. Go Left of the sequence.
|
||||
cursor->setLayoutNode(this);
|
||||
return;
|
||||
}
|
||||
if (cursor->position() == LayoutCursor::Position::Left
|
||||
&& cursor->layoutNode() == argumentLayout())
|
||||
if (cursor->layoutNode() == lowerBoundLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Left);
|
||||
// Case: Left of the lower bound. Go Right of the variable name.
|
||||
cursor->setLayoutNode(variableLayout());
|
||||
cursor->setPosition(LayoutCursor::Position::Right);
|
||||
return;
|
||||
}
|
||||
if (cursor->layoutNode() == variableLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Left);
|
||||
// Case: Left of the variable name. Go Left of the sequence.
|
||||
cursor->setLayoutNode(this);
|
||||
return;
|
||||
}
|
||||
if (cursor->layoutNode() == argumentLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Left);
|
||||
// Case: Left of the argument. Go Right of the lower bound.
|
||||
cursor->setLayoutNode(lowerBoundLayout());
|
||||
cursor->setPosition(LayoutCursor::Position::Right);
|
||||
@@ -44,18 +58,26 @@ void SequenceLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldReco
|
||||
}
|
||||
|
||||
void SequenceLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
|
||||
if (cursor->position() == LayoutCursor::Position::Right
|
||||
&& (cursor->layoutNode() == lowerBoundLayout()
|
||||
|| cursor->layoutNode() == upperBoundLayout()))
|
||||
if (cursor->layoutNode() == lowerBoundLayout()
|
||||
|| cursor->layoutNode() == upperBoundLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Right);
|
||||
// Case: Right of the bounds. Go Left of the argument.
|
||||
cursor->setLayoutNode(argumentLayout());
|
||||
cursor->setPosition(LayoutCursor::Position::Left);
|
||||
return;
|
||||
}
|
||||
if (cursor->position() == LayoutCursor::Position::Right
|
||||
&& cursor->layoutNode() == argumentLayout())
|
||||
if (cursor->layoutNode() == variableLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Right);
|
||||
// Case: Right of the variable name. Go Left of the lower bound.
|
||||
cursor->setLayoutNode(lowerBoundLayout());
|
||||
cursor->setPosition(LayoutCursor::Position::Left);
|
||||
return;
|
||||
}
|
||||
if (cursor->layoutNode() == argumentLayout())
|
||||
{
|
||||
assert(cursor->position() == LayoutCursor::Position::Right);
|
||||
// Case: Right of the argument. Go Right.
|
||||
cursor->setLayoutNode(this);
|
||||
return;
|
||||
@@ -75,8 +97,8 @@ void SequenceLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRec
|
||||
}
|
||||
|
||||
void SequenceLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) {
|
||||
if (cursor->layoutNode()->hasAncestor(lowerBoundLayout(), true)) {
|
||||
// If the cursor is inside the lower bound, move it to the upper bound
|
||||
if (cursor->layoutNode()->hasAncestor(lowerBoundLayout(), true) || cursor->layoutNode()->hasAncestor(variableLayout(), true)) {
|
||||
// If the cursor is inside the lower bound or inside the variable name, move it to the upper bound
|
||||
upperBoundLayout()->moveCursorUpInDescendants(cursor, shouldRecomputeLayout);
|
||||
return;
|
||||
}
|
||||
@@ -119,16 +141,25 @@ void SequenceLayoutNode::deleteBeforeCursor(LayoutCursor * cursor) {
|
||||
|
||||
// Protected
|
||||
|
||||
KDSize SequenceLayoutNode::lowerBoundSizeWithVariableEquals() {
|
||||
KDSize variableSize = variableLayout()->layoutSize();
|
||||
KDSize lowerBoundSize = lowerBoundLayout()->layoutSize();
|
||||
KDSize equalSize = k_font->stringSize(k_equal);
|
||||
return KDSize(
|
||||
variableSize.width() + equalSize.width() + lowerBoundSize.width(),
|
||||
subscriptBaseline() + max(max(variableSize.height() - variableLayout()->baseline(), lowerBoundSize.height() - lowerBoundLayout()->baseline()), equalSize.height()/2));
|
||||
}
|
||||
|
||||
KDSize SequenceLayoutNode::computeSize() {
|
||||
KDSize nEqualslowerBoundSize = lowerBoundSizeWithNEquals();
|
||||
KDSize totalLowerBoundSize = lowerBoundSizeWithVariableEquals();
|
||||
KDSize upperBoundSize = upperBoundLayout()->layoutSize();
|
||||
KDSize argumentSize = argumentLayout()->layoutSize();
|
||||
KDSize argumentSizeWithParentheses = KDSize(
|
||||
argumentSize.width() + 2*ParenthesisLayoutNode::ParenthesisWidth(),
|
||||
ParenthesisLayoutNode::HeightGivenChildHeight(argumentSize.height()));
|
||||
KDSize result = KDSize(
|
||||
max(max(k_symbolWidth, nEqualslowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSizeWithParentheses.width(),
|
||||
baseline() + max(k_symbolHeight/2+k_boundHeightMargin+nEqualslowerBoundSize.height(), argumentSizeWithParentheses.height() - argumentLayout()->baseline()));
|
||||
max(max(k_symbolWidth, totalLowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+argumentSizeWithParentheses.width(),
|
||||
baseline() + max(k_symbolHeight/2+k_boundHeightMargin+totalLowerBoundSize.height(), argumentSizeWithParentheses.height() - argumentLayout()->baseline()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -137,21 +168,22 @@ KDCoordinate SequenceLayoutNode::computeBaseline() {
|
||||
}
|
||||
|
||||
KDPoint SequenceLayoutNode::positionOfChild(LayoutNode * l) {
|
||||
KDSize nEqualslowerBoundSize = lowerBoundSizeWithNEquals();
|
||||
KDSize nEqualsSize = k_font->stringSize(k_nEquals);
|
||||
KDSize variableSize = variableLayout()->layoutSize();
|
||||
KDSize equalSize = k_font->stringSize(k_equal);
|
||||
KDSize upperBoundSize = upperBoundLayout()->layoutSize();
|
||||
KDCoordinate x = 0;
|
||||
KDCoordinate y = 0;
|
||||
if (l == lowerBoundLayout()) {
|
||||
x = nEqualsSize.width() +
|
||||
max(max(0, (k_symbolWidth-nEqualslowerBoundSize.width())/2),
|
||||
(upperBoundSize.width()-nEqualslowerBoundSize.width())/2);
|
||||
y = baseline() + k_symbolHeight/2 + k_boundHeightMargin;
|
||||
if (l == variableLayout()) {
|
||||
x = completeLowerBoundX();
|
||||
y = baseline() + k_symbolHeight/2 + k_boundHeightMargin + subscriptBaseline() - variableLayout()->baseline();
|
||||
} else if (l == lowerBoundLayout()) {
|
||||
x = completeLowerBoundX() + equalSize.width() + variableSize.width();
|
||||
y = baseline() + k_symbolHeight/2 + k_boundHeightMargin + subscriptBaseline() - lowerBoundLayout()->baseline();
|
||||
} else if (l == upperBoundLayout()) {
|
||||
x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (nEqualslowerBoundSize.width()-upperBoundSize.width())/2);
|
||||
x = max(max(0, (k_symbolWidth-upperBoundSize.width())/2), (lowerBoundSizeWithVariableEquals().width()-upperBoundSize.width())/2);
|
||||
y = baseline() - (k_symbolHeight+1)/2- k_boundHeightMargin-upperBoundSize.height();
|
||||
} else if (l == argumentLayout()) {
|
||||
x = max(max(k_symbolWidth, nEqualslowerBoundSize.width()), upperBoundSize.width())+k_argumentWidthMargin+ParenthesisLayoutNode::ParenthesisWidth();
|
||||
x = max(max(k_symbolWidth, lowerBoundSizeWithVariableEquals().width()), upperBoundSize.width())+k_argumentWidthMargin+ParenthesisLayoutNode::ParenthesisWidth();
|
||||
y = baseline() - argumentLayout()->baseline();
|
||||
} else {
|
||||
assert(false);
|
||||
@@ -174,25 +206,16 @@ int SequenceLayoutNode::writeDerivedClassInBuffer(const char * operatorName, cha
|
||||
buffer[numberOfChar++] = '(';
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
|
||||
// Write the argument
|
||||
numberOfChar += const_cast<SequenceLayoutNode *>(this)->argumentLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
|
||||
// Write the comma
|
||||
buffer[numberOfChar++] = ',';
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
|
||||
// Write the lower bound
|
||||
numberOfChar += const_cast<SequenceLayoutNode *>(this)->lowerBoundLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
|
||||
// Write the comma
|
||||
buffer[numberOfChar++] = ',';
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
|
||||
// Write the upper bound
|
||||
numberOfChar += const_cast<SequenceLayoutNode *>(this)->upperBoundLayout()->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
LayoutNode * argLayouts[] = {const_cast<SequenceLayoutNode *>(this)->argumentLayout(), const_cast<SequenceLayoutNode *>(this)->variableLayout(), const_cast<SequenceLayoutNode *>(this)->lowerBoundLayout(), const_cast<SequenceLayoutNode *>(this)->upperBoundLayout()};
|
||||
for (uint8_t i = 0; i < sizeof(argLayouts)/sizeof(argLayouts[0]); i++) {
|
||||
if (i != 0) {
|
||||
// Write the comma
|
||||
buffer[numberOfChar++] = ',';
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
}
|
||||
numberOfChar += argLayouts[i]->serialize(buffer+numberOfChar, bufferSize-numberOfChar, floatDisplayMode, numberOfSignificantDigits);
|
||||
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
|
||||
}
|
||||
|
||||
// Write the closing parenthesis
|
||||
buffer[numberOfChar++] = ')';
|
||||
@@ -201,9 +224,10 @@ int SequenceLayoutNode::writeDerivedClassInBuffer(const char * operatorName, cha
|
||||
}
|
||||
|
||||
void SequenceLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
|
||||
// Render the "n="
|
||||
KDPoint nEqualsPosition = positionOfChild(lowerBoundLayout()).translatedBy(KDPoint(-k_font->stringSize(k_nEquals).width(), 0));
|
||||
ctx->drawString(k_nEquals, p.translatedBy(nEqualsPosition), k_font, expressionColor, backgroundColor);
|
||||
// Render the "="
|
||||
KDSize variableSize = variableLayout()->layoutSize();
|
||||
KDPoint equalPosition = positionOfChild(variableLayout()).translatedBy(KDPoint(variableSize.width(), variableLayout()->baseline()-k_font->stringSize(k_equal).height()/2));
|
||||
ctx->drawString(k_equal, p.translatedBy(equalPosition), k_font, expressionColor, backgroundColor);
|
||||
|
||||
// Render the parentheses
|
||||
KDCoordinate argumentWithParenthesesHeight = ParenthesisLayoutNode::HeightGivenChildHeight(argumentLayout()->layoutSize().height());
|
||||
@@ -220,12 +244,14 @@ void SequenceLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionCo
|
||||
RightParenthesisLayoutNode::RenderWithChildHeight(argumentWithParenthesesHeight, ctx, rightParenthesisPoint, expressionColor, backgroundColor);
|
||||
}
|
||||
|
||||
KDSize SequenceLayoutNode::lowerBoundSizeWithNEquals() {
|
||||
KDSize lowerBoundSize = lowerBoundLayout()->layoutSize();
|
||||
KDSize nEqualsSize = k_font->stringSize(k_nEquals);
|
||||
return KDSize(
|
||||
nEqualsSize.width() + lowerBoundSize.width(),
|
||||
max(nEqualsSize.height(), lowerBoundSize.height()));
|
||||
KDCoordinate SequenceLayoutNode::completeLowerBoundX() {
|
||||
KDSize upperBoundSize = upperBoundLayout()->layoutSize();
|
||||
return max(max(0, (k_symbolWidth-lowerBoundSizeWithVariableEquals().width())/2),
|
||||
(upperBoundSize.width()-lowerBoundSizeWithVariableEquals().width())/2);
|
||||
}
|
||||
|
||||
KDCoordinate SequenceLayoutNode::subscriptBaseline() {
|
||||
return max(max(variableLayout()->baseline(), lowerBoundLayout()->baseline()), k_font->stringSize(k_equal).height()/2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ extern "C" {
|
||||
namespace Poincare {
|
||||
|
||||
|
||||
Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout subscriptLayout, Layout superscriptLayout) const {
|
||||
return SumLayout(argumentLayout, subscriptLayout, superscriptLayout);
|
||||
Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {
|
||||
return SumLayout(argumentLayout, symbolLayout, subscriptLayout, superscriptLayout);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -32,7 +32,7 @@ int SumLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintFl
|
||||
void SumLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
|
||||
// Computes sizes.
|
||||
KDSize upperBoundSize = upperBoundLayout()->layoutSize();
|
||||
KDSize lowerBoundNEqualsSize = lowerBoundSizeWithNEquals();
|
||||
KDSize lowerBoundNEqualsSize = lowerBoundSizeWithVariableEquals();
|
||||
|
||||
// Render the Sum symbol.
|
||||
KDColor workingBuffer[k_symbolWidth*k_symbolHeight];
|
||||
|
||||
Reference in New Issue
Block a user