mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[apps/solver] Display user variables in the solutions
This commit is contained in:
@@ -23,3 +23,7 @@ OnlyFirstSolutionsDisplayed0 = "Es werden nur die ersten"
|
||||
OnlyFirstSolutionsDisplayed1 = "zehn Lösungen angezeigt."
|
||||
PolynomeHasNoRealSolution0 = "Das Polynom hat"
|
||||
PolynomeHasNoRealSolution1 = "keine reelle Nullstelle"
|
||||
PredefinedVariablesUsedLeft = "Verwen"
|
||||
PredefinedVariablesUsedRight = "dete vordefinierte Variablen"
|
||||
PredefinedVariablesIgnoredLeft = "Ignorie"
|
||||
PredefinedVariablesIgnoredRight = "rt vordefinierte Variablen"
|
||||
|
||||
@@ -23,3 +23,7 @@ OnlyFirstSolutionsDisplayed0 = "Only the first 10 solutions"
|
||||
OnlyFirstSolutionsDisplayed1 = "are displayed"
|
||||
PolynomeHasNoRealSolution0 = "The polynomial has no"
|
||||
PolynomeHasNoRealSolution1 = "real root"
|
||||
PredefinedVariablesUsedLeft = "Used "
|
||||
PredefinedVariablesUsedRight = "predefined variables"
|
||||
PredefinedVariablesIgnoredLeft = "Ignor"
|
||||
PredefinedVariablesIgnoredRight = "ed predefined variables"
|
||||
|
||||
@@ -23,3 +23,7 @@ OnlyFirstSolutionsDisplayed0 = "Sólo se muestran las"
|
||||
OnlyFirstSolutionsDisplayed1 = "10 primeras soluciones"
|
||||
PolynomeHasNoRealSolution0 = "El polinomio no tiene"
|
||||
PolynomeHasNoRealSolution1 = "ninguna raíz real"
|
||||
PredefinedVariablesUsedLeft = "Variable"
|
||||
PredefinedVariablesUsedRight = "s predefinidas utilizadas"
|
||||
PredefinedVariablesIgnoredLeft = "Variable"
|
||||
PredefinedVariablesIgnoredRight = "s predefinidas ignoradas"
|
||||
|
||||
@@ -23,3 +23,7 @@ OnlyFirstSolutionsDisplayed0 = "Seulement les 10 premières"
|
||||
OnlyFirstSolutionsDisplayed1 = "solutions sont affichées"
|
||||
PolynomeHasNoRealSolution0 = "Le polynôme n'admet pas"
|
||||
PolynomeHasNoRealSolution1 = "de racine réelle"
|
||||
PredefinedVariablesUsedLeft = "Variable"
|
||||
PredefinedVariablesUsedRight = "s prédéfinies utilisées"
|
||||
PredefinedVariablesIgnoredLeft = "Variable"
|
||||
PredefinedVariablesIgnoredRight = "s prédéfinies ignorées"
|
||||
|
||||
@@ -23,3 +23,7 @@ OnlyFirstSolutionsDisplayed0 = "Somente as 10 primeiras"
|
||||
OnlyFirstSolutionsDisplayed1 = "soluções são exibidas"
|
||||
PolynomeHasNoRealSolution0 = "O polinômio não tem"
|
||||
PolynomeHasNoRealSolution1 = "nenhuma raiz real"
|
||||
PredefinedVariablesUsedLeft = "Variáveis "
|
||||
PredefinedVariablesUsedRight = "pré-definidas utilizadas"
|
||||
PredefinedVariablesIgnoredLeft = "Variáveis"
|
||||
PredefinedVariablesIgnoredRight = " pré-definidas ignoradas"
|
||||
|
||||
@@ -27,7 +27,8 @@ EquationStore::EquationStore() :
|
||||
m_type(Type::LinearSystem),
|
||||
m_numberOfSolutions(0),
|
||||
m_exactSolutionExactLayouts{},
|
||||
m_exactSolutionApproximateLayouts{}
|
||||
m_exactSolutionApproximateLayouts{},
|
||||
m_numberOfUserVariables(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -100,14 +101,15 @@ bool EquationStore::haveMoreApproximationSolutions(Context * context, bool solve
|
||||
return !std::isnan(PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context, solveWithoutContext), m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], context));
|
||||
}
|
||||
|
||||
void EquationStore::approximateSolve(Poincare::Context * context, bool shouldReplaceFuncionsButNotSymbols) {
|
||||
void EquationStore::approximateSolve(Poincare::Context * context, bool shouldReplaceFunctionsButNotSymbols) {
|
||||
m_userVariablesUsed = !shouldReplaceFunctionsButNotSymbols;
|
||||
assert(m_variables[0][0] != 0 && m_variables[1][0] == 0);
|
||||
assert(m_type == Type::Monovariable);
|
||||
m_numberOfSolutions = 0;
|
||||
double start = m_intervalApproximateSolutions[0];
|
||||
double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision;
|
||||
for (int i = 0; i < k_maxNumberOfApproximateSolutions; i++) {
|
||||
m_approximateSolutions[i] = PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context, shouldReplaceFuncionsButNotSymbols), m_variables[0], start, step, m_intervalApproximateSolutions[1], context);
|
||||
m_approximateSolutions[i] = PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context, shouldReplaceFunctionsButNotSymbols), m_variables[0], start, step, m_intervalApproximateSolutions[1], context);
|
||||
if (std::isnan(m_approximateSolutions[i])) {
|
||||
break;
|
||||
} else {
|
||||
@@ -120,6 +122,8 @@ void EquationStore::approximateSolve(Poincare::Context * context, bool shouldRep
|
||||
EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool replaceFunctionsButNotSymbols) {
|
||||
tidySolution();
|
||||
|
||||
m_userVariablesUsed = !replaceFunctionsButNotSymbols;
|
||||
|
||||
// Step 0. Get unknown variables
|
||||
m_variables[0][0] = 0;
|
||||
int numberOfVariables = 0;
|
||||
@@ -131,7 +135,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool
|
||||
if (e.type() == ExpressionNode::Type::Unreal) {
|
||||
return Error::EquationUnreal;
|
||||
}
|
||||
numberOfVariables = e.getVariables(context, [](const char * symbol) { return true; }, (char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize);
|
||||
numberOfVariables = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return true; }, (char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize);
|
||||
if (numberOfVariables == -1) {
|
||||
return Error::TooManyVariables;
|
||||
}
|
||||
@@ -140,7 +144,22 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool
|
||||
assert(numberOfVariables >= 0);
|
||||
}
|
||||
|
||||
// Step 1. Linear System?
|
||||
// Step 1. Get user defined variables
|
||||
// TODO used previously fetched variables?
|
||||
m_userVariables[0][0] = 0;
|
||||
m_numberOfUserVariables = 0;
|
||||
for (int i = 0; i < numberOfDefinedModels(); i++) {
|
||||
const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context, true);
|
||||
assert(!e.isUninitialized() && e.type() != ExpressionNode::Type::Undefined && e.type() != ExpressionNode::Type::Unreal);
|
||||
int varCount = e.getVariables(context, [](const char * symbol, Poincare::Context * context) { return context->expressionTypeForIdentifier(symbol, strlen(symbol)) == Poincare::Context::SymbolAbstractType::Symbol; }, (char *)m_userVariables, Poincare::SymbolAbstract::k_maxNameSize);
|
||||
if (varCount < 0) {
|
||||
m_numberOfUserVariables = Expression::k_maxNumberOfVariables;
|
||||
break;
|
||||
}
|
||||
m_numberOfUserVariables = varCount;
|
||||
}
|
||||
|
||||
// Step 2. Linear System?
|
||||
|
||||
/* Create matrix coefficients and vector constants as:
|
||||
* coefficients * (x y z ...) = constants */
|
||||
@@ -177,7 +196,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool
|
||||
m_type = Type::LinearSystem;
|
||||
error = resolveLinearSystem(exactSolutions, exactSolutionsApproximations, coefficients, constants, context);
|
||||
} else {
|
||||
// Step 2. Polynomial & Monovariable?
|
||||
// Step 3. Polynomial & Monovariable?
|
||||
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
|
||||
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
|
||||
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit());
|
||||
@@ -186,7 +205,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool
|
||||
m_type = Type::PolynomialMonovariable;
|
||||
error = oneDimensialPolynomialSolve(exactSolutions, exactSolutionsApproximations, polynomialCoefficients, degree, context);
|
||||
} else {
|
||||
// Step 3. Monovariable non-polynomial or polynomial with degree > 2
|
||||
// Step 4. Monovariable non-polynomial or polynomial with degree > 2
|
||||
m_type = Type::Monovariable;
|
||||
m_intervalApproximateSolutions[0] = -10;
|
||||
m_intervalApproximateSolutions[1] = 10;
|
||||
|
||||
@@ -38,6 +38,16 @@ public:
|
||||
assert(i < Poincare::Expression::k_maxNumberOfVariables && m_variables[i][0] != 0);
|
||||
return m_variables[i];
|
||||
}
|
||||
const char * userVariableAtIndex(size_t i) {
|
||||
assert(i < Poincare::Expression::k_maxNumberOfVariables && m_userVariables[i][0] != 0);
|
||||
return m_userVariables[i];
|
||||
}
|
||||
int numberOfUserVariables() const {
|
||||
return m_numberOfUserVariables;
|
||||
}
|
||||
bool userVariablesUsed() const {
|
||||
return m_userVariablesUsed;
|
||||
}
|
||||
int numberOfSolutions() const {
|
||||
return m_numberOfSolutions;
|
||||
}
|
||||
@@ -93,6 +103,7 @@ private:
|
||||
mutable Equation m_equations[k_maxNumberOfEquations];
|
||||
Type m_type;
|
||||
char m_variables[Poincare::Expression::k_maxNumberOfVariables][Poincare::SymbolAbstract::k_maxNameSize];
|
||||
char m_userVariables[Poincare::Expression::k_maxNumberOfVariables][Poincare::SymbolAbstract::k_maxNameSize];
|
||||
int m_numberOfSolutions;
|
||||
Poincare::Layout m_exactSolutionExactLayouts[k_maxNumberOfApproximateSolutions];
|
||||
Poincare::Layout m_exactSolutionApproximateLayouts[k_maxNumberOfExactSolutions];
|
||||
@@ -100,6 +111,8 @@ private:
|
||||
bool m_exactSolutionEquality[k_maxNumberOfExactSolutions];
|
||||
double m_intervalApproximateSolutions[2];
|
||||
double m_approximateSolutions[k_maxNumberOfApproximateSolutions];
|
||||
int m_numberOfUserVariables;
|
||||
bool m_userVariablesUsed;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <poincare/horizontal_layout.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <poincare/symbol_abstract.h>
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/vertical_offset_layout.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -17,19 +18,21 @@ namespace Solver {
|
||||
|
||||
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
|
||||
|
||||
constexpr KDColor SolutionsController::ContentView::k_backgroundColor;
|
||||
|
||||
SolutionsController::ContentView::ContentView(SolutionsController * controller) :
|
||||
m_warningMessageView0(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark),
|
||||
m_warningMessageView1(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, Palette::WallScreenDark),
|
||||
m_warningMessageView0(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, k_backgroundColor),
|
||||
m_warningMessageView1(KDFont::SmallFont, I18n::Message::Default, 0.5f, 0.5f, KDColorBlack, k_backgroundColor),
|
||||
m_selectableTableView(controller),
|
||||
m_displayWarningMoreSolutions(false)
|
||||
{
|
||||
m_selectableTableView.setBackgroundColor(Palette::WallScreenDark);
|
||||
m_selectableTableView.setBackgroundColor(k_backgroundColor);
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
}
|
||||
|
||||
void SolutionsController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
if (m_displayWarningMoreSolutions) {
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), Palette::WallScreenDark);
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_topMargin), k_backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +83,7 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
|
||||
m_deltaCell(0.5f, 0.5f),
|
||||
m_delta2Layout(),
|
||||
m_contentView(this),
|
||||
m_shouldReplaceFuncionsButNotSymbols(false)
|
||||
m_shouldReplaceFunctionsButNotSymbols(false)
|
||||
{
|
||||
m_delta2Layout = HorizontalLayout::Builder(VerticalOffsetLayout::Builder(CodePointLayout::Builder('2', KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Superscript), LayoutHelper::String("-4ac", 4, KDFont::SmallFont));
|
||||
const char * deltaB = "Δ=b";
|
||||
@@ -93,6 +96,7 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
|
||||
}
|
||||
for (int i = 0; i < k_numberOfSymbolCells; i++) {
|
||||
m_symbolCells[i].setAlignment(0.5f, 0.5f);
|
||||
m_symbolCells[i].setFont(KDFont::LargeFont);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +113,7 @@ void SolutionsController::viewWillAppear() {
|
||||
bool requireWarning = false;
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
m_contentView.setWarningMessages(I18n::Message::OnlyFirstSolutionsDisplayed0, I18n::Message::OnlyFirstSolutionsDisplayed1);
|
||||
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext(), m_shouldReplaceFuncionsButNotSymbols);
|
||||
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext(), m_shouldReplaceFunctionsButNotSymbols);
|
||||
} else if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && m_equationStore->numberOfSolutions() == 1) {
|
||||
assert(Preferences::sharedPreferences()->complexFormat() == Preferences::ComplexFormat::Real);
|
||||
m_contentView.setWarningMessages(I18n::Message::PolynomeHasNoRealSolution0, I18n::Message::PolynomeHasNoRealSolution1);
|
||||
@@ -158,52 +162,76 @@ Responder * SolutionsController::defaultController() {
|
||||
/* TableViewDataSource */
|
||||
|
||||
int SolutionsController::numberOfRows() const {
|
||||
return m_equationStore->numberOfSolutions();
|
||||
return m_equationStore->numberOfSolutions() + (m_equationStore->numberOfUserVariables() > 0 ? 1 + m_equationStore->numberOfUserVariables() : 0);
|
||||
}
|
||||
|
||||
void SolutionsController::willDisplayCellAtLocation(HighlightCell * cell, int i, int j) {
|
||||
const int rowOfUserVariablesMessage = userVariablesMessageRow();
|
||||
if (j == rowOfUserVariablesMessage) {
|
||||
// Predefined varaible used/ignored message
|
||||
assert(i >= 0);
|
||||
MessageCell * messageCell = static_cast<MessageCell *>(cell);
|
||||
messageCell->setHorizontalAlignment(i == 0 ? 1.0f : 0.0f);
|
||||
if (usedUserVariables()) {
|
||||
messageCell->setMessage(i == 0 ? I18n::Message::PredefinedVariablesUsedLeft : I18n::Message::PredefinedVariablesUsedRight);
|
||||
} else {
|
||||
messageCell->setMessage(i == 0 ? I18n::Message::PredefinedVariablesIgnoredLeft : I18n::Message::PredefinedVariablesIgnoredRight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
// Name of the variable or discriminant
|
||||
if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && j == m_equationStore->numberOfSolutions()-1) {
|
||||
// Discriminant
|
||||
// Formula of the discriminant
|
||||
EvenOddExpressionCell * deltaCell = static_cast<EvenOddExpressionCell *>(cell);
|
||||
deltaCell->setLayout(m_delta2Layout);
|
||||
} else {
|
||||
EvenOddBufferTextCell * symbolCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
symbolCell->setFont(KDFont::LargeFont);
|
||||
char bufferSymbol[Poincare::SymbolAbstract::k_maxNameSize+1]; // Hold at maximum Delta = b^2-4ac or the variable name + a digit
|
||||
switch (m_equationStore->type()) {
|
||||
case EquationStore::Type::LinearSystem:
|
||||
char bufferSymbol[Poincare::SymbolAbstract::k_maxNameSize+1]; // Holds at maximum the variable name + a digit
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
// Solution symbol name
|
||||
if (m_equationStore->type() == EquationStore::Type::LinearSystem) {
|
||||
/* The system has more than one variable: the cell text is the
|
||||
* variable name */
|
||||
strlcpy(bufferSymbol, m_equationStore->variableAtIndex(j), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
/* The system has one variable but might have many solutions: the cell
|
||||
* text is variableX, with X the row index + 1 (e.g. x1, x2,...) */
|
||||
int length = strlcpy(bufferSymbol, m_equationStore->variableAtIndex(0), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
bufferSymbol[length++] = j+'1';
|
||||
bufferSymbol[length++] = j+'1'; // TODO LEA change for 10
|
||||
bufferSymbol[length] = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// User variable name
|
||||
assert(rowOfUserVariablesMessage > 0);
|
||||
strlcpy(bufferSymbol, m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1), Poincare::SymbolAbstract::k_maxNameSize);
|
||||
}
|
||||
symbolCell->setText(bufferSymbol);
|
||||
}
|
||||
} else {
|
||||
// Value of the variable or discriminant
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
EvenOddBufferTextCell * valueCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char bufferValue[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(m_equationStore->approximateSolutionAtIndex(j), bufferValue, bufferSize, precision);
|
||||
valueCell->setText(bufferValue);
|
||||
} else {
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutsAtIndexAreIdentical(j) ? Poincare::Layout() : m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
valueCell->setLayouts(exactLayout, m_equationStore->exactSolutionLayoutAtIndex(j, false));
|
||||
if (!exactLayout.isUninitialized()) {
|
||||
valueCell->setEqualMessage(m_equationStore->exactSolutionLayoutsAtIndexAreEqual(j) ? I18n::Message::Equal : I18n::Message::AlmostEqual);
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
// Values of the solutions
|
||||
EvenOddBufferTextCell * valueCell = static_cast<EvenOddBufferTextCell *>(cell);
|
||||
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
|
||||
char bufferValue[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(m_equationStore->approximateSolutionAtIndex(j), bufferValue, bufferSize, precision);
|
||||
valueCell->setText(bufferValue);
|
||||
} else {
|
||||
// Values of the solutions or discriminant
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutsAtIndexAreIdentical(j) ? Poincare::Layout() : m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
valueCell->setLayouts(exactLayout, m_equationStore->exactSolutionLayoutAtIndex(j, false));
|
||||
if (!exactLayout.isUninitialized()) {
|
||||
valueCell->setEqualMessage(m_equationStore->exactSolutionLayoutsAtIndexAreEqual(j) ? I18n::Message::Equal : I18n::Message::AlmostEqual);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Values of the solutions or discriminant
|
||||
ScrollableTwoExpressionsCell * valueCell = static_cast<ScrollableTwoExpressionsCell *>(cell);
|
||||
const char * symbol = m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1);
|
||||
Poincare::Layout layout = PoincareHelpers::CreateLayout(App::app()->localContext()->expressionForSymbolAbstract(Poincare::Symbol::Builder(symbol, strlen(symbol)), false));
|
||||
valueCell->setLayouts(Poincare::Layout(), layout);
|
||||
}
|
||||
}
|
||||
EvenOddCell * evenOddCell = static_cast<EvenOddCell *>(cell);
|
||||
@@ -218,12 +246,22 @@ KDCoordinate SolutionsController::rowHeight(int j) {
|
||||
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
return k_defaultCellHeight;
|
||||
}
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
Poincare::Layout approximateLayout = m_equationStore->exactSolutionLayoutAtIndex(j, false);
|
||||
KDCoordinate exactLayoutHeight = exactLayout.layoutSize().height();
|
||||
KDCoordinate approximateLayoutHeight = approximateLayout.layoutSize().height();
|
||||
KDCoordinate layoutHeight = maxCoordinate(exactLayout.baseline(), approximateLayout.baseline()) + maxCoordinate(exactLayoutHeight-exactLayout.baseline(), approximateLayoutHeight-approximateLayout.baseline());
|
||||
return layoutHeight + 2 * Metric::CommonSmallMargin;
|
||||
const int rowOfUserVariablesMessage = userVariablesMessageRow();
|
||||
if (rowOfUserVariablesMessage < 0 || j < rowOfUserVariablesMessage) {
|
||||
Poincare::Layout exactLayout = m_equationStore->exactSolutionLayoutAtIndex(j, true);
|
||||
Poincare::Layout approximateLayout = m_equationStore->exactSolutionLayoutAtIndex(j, false);
|
||||
KDCoordinate exactLayoutHeight = exactLayout.layoutSize().height();
|
||||
KDCoordinate approximateLayoutHeight = approximateLayout.layoutSize().height();
|
||||
KDCoordinate layoutHeight = maxCoordinate(exactLayout.baseline(), approximateLayout.baseline()) + maxCoordinate(exactLayoutHeight-exactLayout.baseline(), approximateLayoutHeight-approximateLayout.baseline());
|
||||
return layoutHeight + 2 * Metric::CommonSmallMargin;
|
||||
}
|
||||
if (j == rowOfUserVariablesMessage) {
|
||||
return Metric::CommonTopMargin + k_defaultCellHeight + Metric::CommonBottomMargin;
|
||||
}
|
||||
// TODO: memoize user symbols if too slow
|
||||
const char * symbol = m_equationStore->userVariableAtIndex(j - rowOfUserVariablesMessage - 1);
|
||||
Poincare::Layout layout = PoincareHelpers::CreateLayout(App::app()->localContext()->expressionForSymbolAbstract(Poincare::Symbol::Builder(symbol, strlen(symbol)), false));
|
||||
return layout.layoutSize().height() + 2 * Metric::CommonSmallMargin;
|
||||
}
|
||||
|
||||
KDCoordinate SolutionsController::cumulatedWidthFromIndex(int i) {
|
||||
@@ -232,11 +270,9 @@ KDCoordinate SolutionsController::cumulatedWidthFromIndex(int i) {
|
||||
return 0;
|
||||
case 1:
|
||||
return k_symbolCellWidth;
|
||||
case 2:
|
||||
return k_symbolCellWidth+k_valueCellWidth;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
assert(i == 2);
|
||||
return k_symbolCellWidth+k_valueCellWidth;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +296,8 @@ HighlightCell * SolutionsController::reusableCell(int index, int type) {
|
||||
return &m_deltaCell;
|
||||
case k_exactValueCellType:
|
||||
return &m_exactValueCells[index];
|
||||
case k_messageCellType:
|
||||
return &m_messageCells[index];
|
||||
default:
|
||||
assert(type == k_approximateValueCellType);
|
||||
return &m_approximateValueCells[index];
|
||||
@@ -269,29 +307,43 @@ HighlightCell * SolutionsController::reusableCell(int index, int type) {
|
||||
int SolutionsController::reusableCellCount(int type) {
|
||||
switch (type) {
|
||||
case k_symbolCellType:
|
||||
return EquationStore::k_maxNumberOfSolutions;
|
||||
return k_numberOfSymbolCells;
|
||||
case k_deltaCellType:
|
||||
return 1;
|
||||
case k_exactValueCellType:
|
||||
return EquationStore::k_maxNumberOfExactSolutions;
|
||||
return k_numberOfExactValueCells;
|
||||
case k_messageCellType:
|
||||
return k_numberOfMessageCells;
|
||||
default:
|
||||
assert(type == k_approximateValueCellType);
|
||||
return EquationStore::k_maxNumberOfApproximateSolutions;
|
||||
return k_numberOfApproximateValueCells;
|
||||
}
|
||||
}
|
||||
|
||||
int SolutionsController::typeAtLocation(int i, int j) {
|
||||
const int rowOfUserVariableMessage = userVariablesMessageRow();
|
||||
if (j == rowOfUserVariableMessage) {
|
||||
return k_messageCellType;
|
||||
}
|
||||
if (i == 0) {
|
||||
if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && j == m_equationStore->numberOfSolutions()-1) {
|
||||
return k_deltaCellType;
|
||||
}
|
||||
return k_symbolCellType;
|
||||
}
|
||||
return m_equationStore->type() == EquationStore::Type::Monovariable ? k_approximateValueCellType : k_exactValueCellType;
|
||||
if ((rowOfUserVariableMessage < 0 || j < rowOfUserVariableMessage) && m_equationStore->type() == EquationStore::Type::Monovariable) {
|
||||
return k_approximateValueCellType;
|
||||
}
|
||||
return k_exactValueCellType;
|
||||
}
|
||||
|
||||
void SolutionsController::didBecomeFirstResponder() {
|
||||
Container::activeApp()->setFirstResponder(m_contentView.selectableTableView());
|
||||
}
|
||||
|
||||
int SolutionsController::userVariablesMessageRow() const {
|
||||
assert(m_equationStore->numberOfUserVariables() >= 0);
|
||||
return m_equationStore->numberOfUserVariables() == 0 ? -1 : m_equationStore->numberOfSolutions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Solver {
|
||||
class SolutionsController : public ViewController, public AlternateEmptyViewDefaultDelegate, public SelectableTableViewDataSource, public TableViewDataSource {
|
||||
public:
|
||||
SolutionsController(Responder * parentResponder, EquationStore * equationStore);
|
||||
void setShouldReplaceFuncionsButNotSymbols(bool shouldReplaceFuncionsButNotSymbols) { m_shouldReplaceFuncionsButNotSymbols = shouldReplaceFuncionsButNotSymbols; }
|
||||
bool shouldReplaceFuncionsButNotSymbols() const { return m_shouldReplaceFuncionsButNotSymbols; }
|
||||
void setShouldReplaceFuncionsButNotSymbols(bool shouldReplaceFuncionsButNotSymbols) { m_shouldReplaceFunctionsButNotSymbols = shouldReplaceFuncionsButNotSymbols; }
|
||||
bool shouldReplaceFuncionsButNotSymbols() const { return m_shouldReplaceFunctionsButNotSymbols; }
|
||||
/* ViewController */
|
||||
const char * title() override;
|
||||
View * view() override { return &m_contentView; }
|
||||
@@ -40,13 +40,12 @@ private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
constexpr static KDCoordinate k_topMargin = 50;
|
||||
constexpr static KDColor k_backgroundColor = Palette::WallScreenDark;
|
||||
ContentView(SolutionsController * controller);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setWarning(bool warning);
|
||||
void setWarningMessages(I18n::Message message0, I18n::Message message1);
|
||||
SelectableTableView * selectableTableView() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
SelectableTableView * selectableTableView() { return &m_selectableTableView; }
|
||||
private:
|
||||
constexpr static KDCoordinate k_middleMargin = 50;
|
||||
int numberOfSubviews() const override;
|
||||
@@ -58,11 +57,26 @@ private:
|
||||
bool m_displayWarningMoreSolutions;
|
||||
};
|
||||
|
||||
class MessageCell : public HighlightCell {
|
||||
public:
|
||||
MessageCell() : m_messageView(KDFont::SmallFont, (I18n::Message)0, 0.0f, k_verticalAlignment, KDColorBlack, SolutionsController::ContentView::k_backgroundColor) {}
|
||||
void setBackgroundColor(KDColor color) { m_messageView.setBackgroundColor(color); }
|
||||
void setHorizontalAlignment(float alignment) { m_messageView.setAlignment(alignment, k_verticalAlignment); }
|
||||
void setMessage(I18n::Message message) { m_messageView.setMessage(message); }
|
||||
private:
|
||||
constexpr static float k_verticalAlignment = 0.8f;
|
||||
int numberOfSubviews() const override { return 1; }
|
||||
View * subviewAtIndex(int index) override { assert(index == 0); return &m_messageView; }
|
||||
void layoutSubviews(bool force = false) override { m_messageView.setFrame(bounds(), force); }
|
||||
MessageTextView m_messageView;
|
||||
};
|
||||
|
||||
// Cell types
|
||||
constexpr static int k_symbolCellType = 0;
|
||||
constexpr static int k_deltaCellType = 1;
|
||||
constexpr static int k_exactValueCellType = 2;
|
||||
constexpr static int k_approximateValueCellType = 3;
|
||||
constexpr static int k_messageCellType = 4;
|
||||
|
||||
// Heights and widths
|
||||
constexpr static KDCoordinate k_defaultCellHeight = 20;
|
||||
@@ -70,11 +84,19 @@ private:
|
||||
constexpr static int k_valueCellWidth = 190;
|
||||
|
||||
// Number of cells
|
||||
constexpr static int k_maxNumberOfVisibleCells = (Ion::Display::Height - 3 * Meric::TitleBarHeight - ContentView::k_topMargin) / k_defaultCellHeight + 1;
|
||||
constexpr static int k_maxNumberOfVisibleCells = (Ion::Display::Height - 3 * Metric::TitleBarHeight - ContentView::k_topMargin) / k_defaultCellHeight + 1;
|
||||
static_assert(k_maxNumberOfVisibleCells <= EquationStore::k_maxNumberOfSolutions + Poincare::Expression::k_maxNumberOfVariables, "We can reduce the number of cells in Solver:SolutionsController.");
|
||||
constexpr static int k_numberOfSymbolCells = k_maxNumberOfVisibleCells < EquationStore::k_maxNumberOfSolutions ? k_maxNumberOfVisibleCells : EquationStore::k_maxNumberOfSolutions;
|
||||
constexpr static int k_numberOfExactValueCells = k_maxNumberOfVisibleCells < EquationStore::k_maxNumberOfExactSolutions ? k_maxNumberOfVisibleCells : EquationStore::k_maxNumberOfExactSolutions;
|
||||
constexpr static int k_maxNumberOfSymbols = EquationStore::k_maxNumberOfSolutions + Poincare::Expression::k_maxNumberOfVariables;
|
||||
constexpr static int k_numberOfSymbolCells = k_maxNumberOfVisibleCells < k_maxNumberOfSymbols ? k_maxNumberOfVisibleCells : k_maxNumberOfSymbols;
|
||||
constexpr static int k_maxNumberOfExactValues = EquationStore::k_maxNumberOfExactSolutions + Poincare::Expression::k_maxNumberOfVariables;
|
||||
constexpr static int k_numberOfExactValueCells = k_maxNumberOfVisibleCells < k_maxNumberOfExactValues ? k_maxNumberOfVisibleCells : k_maxNumberOfExactValues;
|
||||
constexpr static int k_numberOfApproximateValueCells = k_maxNumberOfVisibleCells < EquationStore::k_maxNumberOfApproximateSolutions ? k_maxNumberOfVisibleCells : EquationStore::k_maxNumberOfApproximateSolutions;
|
||||
constexpr static int k_numberOfMessageCells = 2;
|
||||
|
||||
bool usedUserVariables() const {
|
||||
return m_equationStore->userVariablesUsed();
|
||||
}
|
||||
int userVariablesMessageRow() const;
|
||||
|
||||
EquationStore * m_equationStore;
|
||||
EvenOddBufferTextCell m_symbolCells[k_numberOfSymbolCells];
|
||||
@@ -82,8 +104,9 @@ private:
|
||||
Poincare::Layout m_delta2Layout;
|
||||
Shared::ScrollableTwoExpressionsCell m_exactValueCells[k_numberOfExactValueCells];
|
||||
EvenOddBufferTextCell m_approximateValueCells[k_numberOfApproximateValueCells];
|
||||
MessageCell m_messageCells[k_numberOfMessageCells];
|
||||
ContentView m_contentView;
|
||||
bool m_shouldReplaceFuncionsButNotSymbols;
|
||||
bool m_shouldReplaceFunctionsButNotSymbols;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user