[fix] conflicts

This commit is contained in:
Quentin Guidée
2020-08-09 13:28:22 +02:00
45 changed files with 325 additions and 311 deletions

View File

@@ -26,10 +26,10 @@ void ComplexListController::setExpression(Poincare::Expression e) {
}
Poincare::Context * context = App::app()->localContext();
// Fill Calculation Store
m_calculationStore.push("im(z)", context);
m_calculationStore.push("re(z)", context);
m_calculationStore.push("arg(z)", context);
m_calculationStore.push("abs(z)", context);
m_calculationStore.push("im(z)", context, CalculationHeight);
m_calculationStore.push("re(z)", context, CalculationHeight);
m_calculationStore.push("arg(z)", context, CalculationHeight);
m_calculationStore.push("abs(z)", context, CalculationHeight);
// Set Complex illustration
// Compute a and b as in Expression::hasDefinedComplexApproximation to ensure the same defined result

View File

@@ -80,16 +80,7 @@ KDCoordinate IllustratedListController::rowHeight(int j) {
}
Shared::ExpiringPointer<Calculation> calculation = m_calculationStore.calculationAtIndex(calculationIndex);
constexpr bool expanded = true;
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = ScrollableThreeExpressionsCell::Height(calculation.pointer());
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
return result + Metric::CellSeparatorThickness;
return calculation->height(expanded) + Metric::CellSeparatorThickness;
}
int IllustratedListController::typeAtLocation(int i, int j) {
@@ -98,7 +89,6 @@ int IllustratedListController::typeAtLocation(int i, int j) {
void IllustratedListController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (index == 0) {
// TODO ?
return;
}
Poincare::Context * context = App::app()->localContext();
@@ -106,7 +96,6 @@ void IllustratedListController::willDisplayCellForIndex(HighlightCell * cell, in
Calculation * c = m_calculationStore.calculationAtIndex(index-1).pointer();
myCell->setCalculation(c);
myCell->setDisplayCenter(c->displayOutput(context) != Calculation::DisplayOutput::ApproximateOnly);
//myCell->setHighlighted(myCell->isHighlighted()); //TODO??
}
void IllustratedListController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {

View File

@@ -10,8 +10,6 @@
namespace Calculation {
class IllustratedListController : public ListController, public SelectableTableViewDelegate {
/* TODO There is factorizable code between this and
* Calculation::HistoryController (at least rowHeight). */
public:
IllustratedListController(EditExpressionController * editExpressionController);
@@ -35,6 +33,7 @@ public:
constexpr static KDCoordinate k_illustrationHeight = 120;
protected:
static KDCoordinate CalculationHeight(Calculation * c, bool expanded) { return ScrollableThreeExpressionsCell::Height(c); }
Poincare::Expression m_savedExpression;
CalculationStore m_calculationStore;
private:

View File

@@ -8,8 +8,8 @@ void ScrollableThreeExpressionsView::resetMemoization() {
setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout());
}
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
// TODO: factorize with HistoryViewCell!
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool canChangeDisplayOutput) {
Poincare::Context * context = App::app()->localContext();
// Clean the layouts to make room in the pool
@@ -24,13 +24,10 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b
bool couldNotCreateExactLayout = false;
exactOutputLayout = calculation->createExactOutputLayout(&couldNotCreateExactLayout);
if (couldNotCreateExactLayout) {
if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ExactOnly) {
Poincare::ExceptionCheckpoint::Raise();
} else {
if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} else {
Poincare::ExceptionCheckpoint::Raise();
}
}
}
@@ -44,21 +41,18 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b
bool couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ApproximateOnly) {
Poincare::ExceptionCheckpoint::Raise();
} else {
if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ApproximateOnly) {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
Poincare::ExceptionCheckpoint::Raise();
}
} else {
Poincare::ExceptionCheckpoint::Raise();
}
}
@@ -74,16 +68,7 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, b
KDCoordinate ScrollableThreeExpressionsCell::Height(Calculation * calculation) {
ScrollableThreeExpressionsCell cell;
bool didForceOutput = false;
cell.setCalculation(calculation, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
cell.setCalculation(calculation, true);
KDRect leftFrame = KDRectZero;
KDRect centerFrame = KDRectZero;
KDRect approximateSignFrame = KDRectZero;
@@ -103,8 +88,8 @@ void ScrollableThreeExpressionsCell::reinitSelection() {
m_view.reloadScroll();
}
void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool * didForceOutput) {
m_view.setCalculation(calculation, didForceOutput);
void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool canChangeDisplayOutput) {
m_view.setCalculation(calculation, canChangeDisplayOutput);
layoutSubviews();
}

View File

@@ -20,7 +20,7 @@ public:
setBackgroundColor(Palette::BackgroundApps);
}
void resetMemoization();
void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void setCalculation(Calculation * calculation, bool canChangeDisplayOutput);
void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) {
return m_contentCell.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame);
}
@@ -61,7 +61,7 @@ public:
void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); }
void resetMemoization() { m_view.resetMemoization(); }
void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void setCalculation(Calculation * calculation, bool canChangeDisplayOutput = false);
void setDisplayCenter(bool display);
ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); }
void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); }

View File

@@ -11,9 +11,9 @@ void TrigonometryListController::setExpression(Poincare::Expression e) {
// Fill calculation store
Poincare::Context * context = App::app()->localContext();
m_calculationStore.push("sin(θ)", context);
m_calculationStore.push("cos(θ)", context);
m_calculationStore.push("θ", context);
m_calculationStore.push("sin(θ)", context, CalculationHeight);
m_calculationStore.push("cos(θ)", context, CalculationHeight);
m_calculationStore.push("θ", context, CalculationHeight);
// Set trigonometry illustration
float angle = Shared::PoincareHelpers::ApproximateToScalar<float>(m_calculationStore.calculationAtIndex(0)->approximateOutput(context, Calculation::NumberOfSignificantDigits::Maximal), context);

View File

@@ -38,12 +38,6 @@ Calculation * Calculation::next() const {
return reinterpret_cast<Calculation *>(const_cast<char *>(result));
}
void Calculation::tidy() {
/* Reset height memoization (the complex format could have changed when
* re-entering Calculation app which would impact the heights). */
resetHeightMemoization();
}
const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const {
const char * exactOutput = exactOutputText();
const char * approximateOutputTextWithMaxNumberOfDigits = exactOutput + strlen(exactOutput) + 1;
@@ -126,12 +120,15 @@ Layout Calculation::createApproximateOutputLayout(Context * context, bool * coul
}
}
void Calculation::setMemoizedHeight(bool expanded, KDCoordinate height) {
if (expanded) {
m_expandedHeight = height;
} else {
m_height = height;
}
KDCoordinate Calculation::height(bool expanded) {
KDCoordinate h = expanded ? m_expandedHeight : m_height;
assert(h >= 0);
return h;
}
void Calculation::setHeights(KDCoordinate height, KDCoordinate expandedHeight) {
m_height = height;
m_expandedHeight = expandedHeight;
}
Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
@@ -190,9 +187,9 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
}
void Calculation::forceDisplayOutput(DisplayOutput d) {
// Heights haven't been computed yet
assert(m_height == -1 && m_expandedHeight == -1);
m_displayOutput = d;
// Reset heights memoization as it might have changed when we modify the display output
resetHeightMemoization();
}
bool Calculation::shouldOnlyDisplayExactOutput() {
@@ -219,6 +216,7 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(
Poincare::ExceptionCheckpoint ecp;
if (ExceptionRun(ecp)) {
Preferences * preferences = Preferences::sharedPreferences();
// TODO: complex format should not be needed here (as it is not used to create layouts)
Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText);
m_equalSign = Expression::ParsedExpressionsAreEqual(exactOutputText(), approximateOutputText(NumberOfSignificantDigits::UserDefined), context, complexFormat, preferences->angleUnit()) ? EqualSign::Equal : EqualSign::Approximation;
return m_equalSign;
@@ -256,25 +254,32 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
}
if (o.hasUnit()) {
Expression unit;
PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User,ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None);
PoincareHelpers::Reduce(&o,
App::app()->localContext(),
ExpressionNode::ReductionTarget::User,
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined,
ExpressionNode::UnitConversion::None);
o = o.removeUnit(&unit);
if (Unit::IsSI(unit)) {
if (Unit::IsSISpeed(unit) || Unit::IsSIVolume(unit) || Unit::IsSIEnergy(unit)) {
/* All these units will provide misc. classic representatives in
* addition to the SI unit in additional information. */
return AdditionalInformationType::Unit;
}
if (Unit::IsSITime(unit)) {
/* If the number of seconds is above 60s, we can write it in the form
* of an addition: 23_min + 12_s for instance. */
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(o, App::app()->localContext());
if (value > Unit::SecondsPerMinute) {
// There might be no unit in the end, if the reduction was interrupted.
if (!unit.isUninitialized()) {
if (Unit::IsSI(unit)) {
if (Unit::IsSISpeed(unit) || Unit::IsSIVolume(unit) || Unit::IsSIEnergy(unit)) {
/* All these units will provide misc. classic representatives in
* addition to the SI unit in additional information. */
return AdditionalInformationType::Unit;
}
if (Unit::IsSITime(unit)) {
/* If the number of seconds is above 60s, we can write it in the form
* of an addition: 23_min + 12_s for instance. */
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(o, App::app()->localContext());
if (value > Unit::SecondsPerMinute) {
return AdditionalInformationType::Unit;
}
}
return AdditionalInformationType::None;
}
return AdditionalInformationType::None;
return AdditionalInformationType::Unit;
}
return AdditionalInformationType::Unit;
}
if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) {
return AdditionalInformationType::Integer;
@@ -289,9 +294,4 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
return AdditionalInformationType::None;
}
void Calculation::resetHeightMemoization() {
m_height = -1;
m_expandedHeight = -1;
}
}

View File

@@ -61,8 +61,6 @@ public:
bool operator==(const Calculation& c);
Calculation * next() const;
void tidy();
// Texts
enum class NumberOfSignificantDigits {
Maximal,
@@ -83,9 +81,8 @@ public:
Poincare::Layout createExactOutputLayout(bool * couldNotCreateExactLayout);
Poincare::Layout createApproximateOutputLayout(Poincare::Context * context, bool * couldNotCreateApproximateLayout);
// Memoization of height
KDCoordinate memoizedHeight(bool expanded) { return expanded ? m_expandedHeight : m_height; }
void setMemoizedHeight(bool expanded, KDCoordinate height);
// Heights
KDCoordinate height(bool expanded);
// Displayed output
DisplayOutput displayOutput(Poincare::Context * context);
@@ -100,7 +97,9 @@ private:
static constexpr int k_numberOfExpressions = 4;
static constexpr KDCoordinate k_heightComputationFailureHeight = 50;
static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000";
void resetHeightMemoization();
void setHeights(KDCoordinate height, KDCoordinate expandedHeight);
/* Buffers holding text expressions have to be longer than the text written
* by user (of maximum length TextField::maxBufferSize()) because when we
* print an expression we add omitted signs (multiplications, parenthesis...) */

View File

@@ -51,7 +51,7 @@ ExpiringPointer<Calculation> CalculationStore::calculationAtIndex(int i) {
return calculationAtIndex(i);
}
ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context * context) {
ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) {
/* Compute ans now, before the buffer is slided and before the calculation
* might be deleted */
Expression ans = ansExpression(context);
@@ -85,7 +85,7 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
/* If the input does not fit in the store (event if the current
* calculation is the only calculation), just replace the calculation with
* undef. */
return emptyStoreAndPushUndef(context);
return emptyStoreAndPushUndef(context, heightComputer);
}
nextSerializationLocation += strlen(nextSerializationLocation) + 1;
}
@@ -116,7 +116,7 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
* undef if it fits, else replace the whole calcualtion with undef. */
Expression undef = Undefined::Builder();
if (!pushSerializeExpression(undef, nextSerializationLocation, &newCalculationsLocation)) {
return emptyStoreAndPushUndef(context);
return emptyStoreAndPushUndef(context, heightComputer);
}
}
nextSerializationLocation += strlen(nextSerializationLocation) + 1;
@@ -133,7 +133,15 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
// Clean the memoization
resetMemoizedModelsAfterCalculationIndex(-1);
return ExpiringPointer<Calculation>(reinterpret_cast<Calculation *>(m_buffer));
ExpiringPointer<Calculation> calculation = ExpiringPointer<Calculation>(reinterpret_cast<Calculation *>(m_buffer));
/* Heights are computed now to make sure that the display output is decided
* accordingly to the remaining size in the Poincare pool. Once it is, it
* can't change anymore: the calculation heights are fixed which ensures that
* scrolling computation is right. */
calculation->setHeights(
heightComputer(calculation.pointer(), false),
heightComputer(calculation.pointer(), true));
return calculation;
}
void CalculationStore::deleteCalculationAtIndex(int i) {
@@ -164,9 +172,6 @@ void CalculationStore::tidy() {
return;
}
resetMemoizedModelsAfterCalculationIndex(-1);
for (Calculation * c : *this) {
c->tidy();
}
}
Expression CalculationStore::ansExpression(Context * context) {
@@ -255,12 +260,12 @@ const char * CalculationStore::lastCalculationPosition(const char * calculations
return reinterpret_cast<const char *>(c);
}
Shared::ExpiringPointer<Calculation> CalculationStore::emptyStoreAndPushUndef(Context * context) {
Shared::ExpiringPointer<Calculation> CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) {
/* We end up here as a result of a failed calculation push. The store
* attributes are not necessarily clean, so we need to reset them. */
m_slidedBuffer = false;
deleteAll();
return push(Undefined::Name(), context);
return push(Undefined::Name(), context, heightComputer);
}
void CalculationStore::resetMemoizedModelsAfterCalculationIndex(int index) {

View File

@@ -28,7 +28,8 @@ class CalculationStore {
public:
CalculationStore();
Shared::ExpiringPointer<Calculation> calculationAtIndex(int i);
Shared::ExpiringPointer<Calculation> push(const char * text, Poincare::Context * context);
typedef KDCoordinate (*HeightComputer)(Calculation * c, bool expanded);
Shared::ExpiringPointer<Calculation> push(const char * text, Poincare::Context * context, HeightComputer heightComputer);
void deleteCalculationAtIndex(int i);
void deleteAll();
int numberOfCalculations() const { return m_numberOfCalculations; }
@@ -60,7 +61,7 @@ private:
char * slideCalculationsToEndOfBuffer(); // returns the new position of the calculations
size_t deleteLastCalculation(const char * calculationsStart = nullptr);
const char * lastCalculationPosition(const char * calculationsStart) const;
Shared::ExpiringPointer<Calculation> emptyStoreAndPushUndef(Poincare::Context * context);
Shared::ExpiringPointer<Calculation> emptyStoreAndPushUndef(Poincare::Context * context, HeightComputer heightComputer);
char m_buffer[k_bufferSize];
const char * m_bufferEnd;

View File

@@ -122,7 +122,7 @@ bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event
if (!myApp->isAcceptableText(m_cacheBuffer)) {
return true;
}
m_calculationStore->push(m_cacheBuffer, myApp->localContext());
m_calculationStore->push(m_cacheBuffer, myApp->localContext(), HistoryViewCell::Height);
m_historyController->reload();
return true;
}
@@ -145,7 +145,7 @@ bool EditExpressionController::inputViewDidFinishEditing(const char * text, Layo
} else {
layoutR.serializeParsedExpression(m_cacheBuffer, k_cacheBufferSize, context);
}
m_calculationStore->push(m_cacheBuffer, context);
m_calculationStore->push(m_cacheBuffer, context, HistoryViewCell::Height);
m_historyController->reload();
m_contentView.expressionField()->setEditing(true, true);
telemetryReportEvent("Input", m_cacheBuffer);

View File

@@ -129,7 +129,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
return true;
}
m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0);
setSelectedSubviewType(subviewType, true, 0, selectedRow());
/* The parameters 'sameCell' and 'previousSelectedY' are chosen to enforce
* toggling of the output when necessary. */
setSelectedSubviewType(subviewType, false, 0, (subviewType == SubviewType::Input) ? selectedRow() : -1);
return true;
}
if (event == Ion::Events::Clear) {
@@ -204,20 +206,7 @@ KDCoordinate HistoryController::rowHeight(int j) {
}
Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(j);
bool expanded = j == selectedRow() && selectedSubviewType() == SubviewType::Output;
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = HistoryViewCell::Height(calculation.pointer(), expanded);
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
/* We might want to put an assertion here to check the memoization:
* assert(result == HistoryViewCell::Height(calculation.pointer(), expanded));
* However, Height might fail due to pool memory exhaustion, in which case the
* assertion fails even if "result" had the right value. */
return result;
return calculation->height(expanded);
}
int HistoryController::typeAtLocation(int i, int j) {

View File

@@ -36,16 +36,7 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType,
KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) {
HistoryViewCell cell(nullptr);
bool didForceOutput = false;
cell.setCalculation(calculation, expanded, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
cell.setCalculation(calculation, expanded, true);
KDRect ellipsisFrame = KDRectZero;
KDRect inputFrame = KDRectZero;
KDRect outputFrame = KDRectZero;
@@ -246,8 +237,7 @@ void HistoryViewCell::resetMemoization() {
m_calculationCRC32 = 0;
}
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool canChangeDisplayOutput) {
uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation));
if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) {
return;
@@ -273,11 +263,8 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, b
bool couldNotCreateExactLayout = false;
exactOutputLayout = calculation->createExactOutputLayout(&couldNotCreateExactLayout);
if (couldNotCreateExactLayout) {
if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} else {
/* We should only display the exact result, but we cannot create it
* -> raise an exception. */
@@ -294,21 +281,18 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, b
bool couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
if (calculation->displayOutput(context) == ::Calculation::Calculation::DisplayOutput::ApproximateOnly) {
Poincare::ExceptionCheckpoint::Raise();
} else {
if (canChangeDisplayOutput && calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ApproximateOnly) {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
Poincare::ExceptionCheckpoint::Raise();
}
} else {
Poincare::ExceptionCheckpoint::Raise();
}
}
}

View File

@@ -51,7 +51,7 @@ public:
Poincare::Layout layout() const override;
KDColor backgroundColor() const override { return m_even ? Palette::CalculationBackgroundEven : Palette::CalculationBackgroundOdd; }
void resetMemoization();
void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr);
void setCalculation(Calculation * calculation, bool expanded, bool canChangeDisplayOutput = false);
int numberOfSubviews() const override { return 2 + displayedEllipsis(); }
View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override;

View File

@@ -14,6 +14,7 @@ void assert_store_is(CalculationStore * store, const char * * result) {
}
}
KDCoordinate dummyHeight(::Calculation::Calculation * c, bool expanded) { return 0; }
QUIZ_CASE(calculation_store) {
Shared::GlobalContext globalContext;
@@ -22,7 +23,7 @@ QUIZ_CASE(calculation_store) {
const char * result[] = {"9", "8", "7", "6", "5", "4", "3", "2", "1", "0"};
for (int i = 0; i < 10; i++) {
char text[2] = {(char)(i+'0'), 0};
store.push(text, &globalContext);
store.push(text, &globalContext, dummyHeight);
quiz_assert(store.numberOfCalculations() == i+1);
}
assert_store_is(&store, result);
@@ -41,13 +42,13 @@ QUIZ_CASE(calculation_ans) {
Shared::GlobalContext globalContext;
CalculationStore store;
store.push("1+3/4", &globalContext);
store.push("ans+2/3", &globalContext);
store.push("1+3/4", &globalContext, dummyHeight);
store.push("ans+2/3", &globalContext, dummyHeight);
Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store.calculationAtIndex(0);
quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximate);
quiz_assert(strcmp(lastCalculation->exactOutputText(),"29/12") == 0);
store.push("ans+0.22", &globalContext);
store.push("ans+0.22", &globalContext, dummyHeight);
lastCalculation = store.calculationAtIndex(0);
quiz_assert(lastCalculation->displayOutput(&globalContext) == ::Calculation::Calculation::DisplayOutput::ExactAndApproximateToggle);
quiz_assert(strcmp(lastCalculation->approximateOutputText(::Calculation::Calculation::NumberOfSignificantDigits::Maximal),"2.6366666666667") == 0);
@@ -56,7 +57,7 @@ QUIZ_CASE(calculation_ans) {
}
void assertCalculationIs(const char * input, ::Calculation::Calculation::DisplayOutput display, ::Calculation::Calculation::EqualSign sign, const char * exactOutput, const char * displayedApproximateOutput, const char * storedApproximateOutput, Context * context, CalculationStore * store) {
store->push(input, context);
store->push(input, context, dummyHeight);
Shared::ExpiringPointer<::Calculation::Calculation> lastCalculation = store->calculationAtIndex(0);
quiz_assert(lastCalculation->displayOutput(context) == display);
if (sign != ::Calculation::Calculation::EqualSign::Unknown) {

View File

@@ -1,7 +1,7 @@
AddScript = "Aggiungere script"
AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _"
Autocomplete = "Autocompletamento"
AutoImportScript = "Importazione automatica dello script"
AutoImportScript = "Auto importazione nella console"
BuiltinsAndKeywords = "Funzioni native e parole chiave"
Console = "Console d'esecuzione"
DeleteScript = "Eliminare lo script"

View File

@@ -21,10 +21,6 @@ PreimageParameterController::PreimageParameterController(
{
}
const char * PreimageParameterController::title() {
return I18n::translate(I18n::Message::Preimage);
}
void PreimageParameterController::viewWillAppear() {
setParameterName(I18n::Message::Y);
m_preimageGraphController->setImage(m_cursor->y());
@@ -32,19 +28,17 @@ void PreimageParameterController::viewWillAppear() {
}
void PreimageParameterController::buttonAction() {
m_preimageGraphController->setRecord(m_record);
StackViewController * stack = static_cast<StackViewController *>(parentResponder());
stack->pop();
stack->pop();
stack->pop();
stack->push(m_preimageGraphController);
if (confirmParameterAtIndex(0, m_tempParameter)) {
m_preimageGraphController->setRecord(m_record);
StackViewController * stack = static_cast<StackViewController *>(parentResponder());
stack->pop();
stack->pop();
stack->pop();
stack->push(m_preimageGraphController);
}
}
double PreimageParameterController::parameterAtIndex(int index) {
assert(index == 0);
return m_preimageGraphController->image();
}
bool PreimageParameterController::setParameterAtIndex(int parameterIndex, double f) {
bool PreimageParameterController::confirmParameterAtIndex(int parameterIndex, double f) {
assert(parameterIndex == 0);
m_preimageGraphController->setImage(f);
return true;

View File

@@ -15,13 +15,16 @@ public:
Shared::CurveViewCursor * cursor,
PreimageGraphController * preimageGraphController
);
const char * title() override;
const char * title() override { return I18n::translate(I18n::Message::Preimage); }
void setRecord(Ion::Storage::Record record) { m_record = record; }
void viewWillAppear() override;
private:
void buttonAction() override;
double parameterAtIndex(int index) override;
bool setParameterAtIndex(int parameterIndex, double f) override;
double extractParameterAtIndex(int index) override {
assert(index == 0);
return m_preimageGraphController->image();
}
bool confirmParameterAtIndex(int parameterIndex, double f) override;
Ion::Storage::Record m_record;
PreimageGraphController * m_preimageGraphController;
};

View File

@@ -30,7 +30,7 @@ const char * GoToParameterController::title() {
return I18n::translate(I18n::Message::YPrediction);
}
double GoToParameterController::parameterAtIndex(int index) {
double GoToParameterController::extractParameterAtIndex(int index) {
assert(index == 0);
if (m_xPrediction) {
return m_cursor->x();
@@ -38,7 +38,7 @@ double GoToParameterController::parameterAtIndex(int index) {
return m_cursor->y();
}
bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) {
bool GoToParameterController::confirmParameterAtIndex(int parameterIndex, double f) {
assert(parameterIndex == 0);
int series = m_graphController->selectedSeriesIndex();
Poincare::Context * globContext = AppsContainer::sharedAppsContainer()->globalContext();

View File

@@ -15,8 +15,8 @@ public:
void setXPrediction(bool xPrediction);
const char * title() override;
private:
double parameterAtIndex(int index) override;
bool setParameterAtIndex(int parameterIndex, double f) override;
double extractParameterAtIndex(int index) override;
bool confirmParameterAtIndex(int parameterIndex, double f) override;
Store * m_store;
bool m_xPrediction;
GraphController * m_graphController;

View File

@@ -11,16 +11,7 @@ FunctionGoToParameterController::FunctionGoToParameterController(Responder * par
{
}
const char * FunctionGoToParameterController::title() {
return I18n::translate(I18n::Message::Goto);
}
double FunctionGoToParameterController::parameterAtIndex(int index) {
assert(index == 0);
return m_cursor->t();
}
bool FunctionGoToParameterController::setParameterAtIndex(int parameterIndex, double f) {
bool FunctionGoToParameterController::confirmParameterAtIndex(int parameterIndex, double f) {
assert(parameterIndex == 0);
FunctionApp * myApp = FunctionApp::app();
ExpiringPointer<Function> function = myApp->functionStore()->modelForRecord(m_record);

View File

@@ -9,13 +9,16 @@ namespace Shared {
class FunctionGoToParameterController : public GoToParameterController {
public:
FunctionGoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor);
const char * title() override;
const char * title() override { return I18n::translate(I18n::Message::Goto); }
void setRecord(Ion::Storage::Record record);
protected:
bool setParameterAtIndex(int parameterIndex, double f) override;
bool confirmParameterAtIndex(int parameterIndex, double f) override;
Ion::Storage::Record m_record;
private:
double parameterAtIndex(int index) override;
double extractParameterAtIndex(int index) override {
assert(index == 0);
return m_cursor->t();
}
};
}

View File

@@ -11,19 +11,11 @@ GoToParameterController::GoToParameterController(Responder * parentResponder, In
{
}
int GoToParameterController::numberOfRows() const {
return 2;
}
HighlightCell * GoToParameterController::reusableParameterCell(int index, int type) {
assert(index == 0);
return &m_parameterCell;
}
int GoToParameterController::reusableParameterCellCount(int type) {
return 1;
}
bool GoToParameterController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Left) {
stackController()->pop();
@@ -32,10 +24,25 @@ bool GoToParameterController::handleEvent(Ion::Events::Event event) {
return false;
}
void GoToParameterController::viewWillAppear() {
// Initialize m_tempParameter to the extracted value.
setParameterAtIndex(0, extractParameterAtIndex(0));
FloatParameterController::viewWillAppear();
}
bool GoToParameterController::setParameterAtIndex(int parameterIndex, double f) {
assert(parameterIndex == 0);
m_tempParameter = f;
return true;
}
void GoToParameterController::buttonAction() {
StackViewController * stack = (StackViewController *)parentResponder();
stack->pop();
stack->pop();
// Update parameter value to m_tempParameter, and proceed if value is valid
if (confirmParameterAtIndex(0, m_tempParameter)) {
StackViewController * stack = (StackViewController *)parentResponder();
stack->pop();
stack->pop();
}
}
}

View File

@@ -11,16 +11,28 @@ namespace Shared {
class GoToParameterController : public FloatParameterController<double> {
public:
GoToParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor);
int numberOfRows() const override;
int numberOfRows() const override { return 2; }
bool handleEvent(Ion::Events::Event event) override;
protected:
void setParameterName(I18n::Message message) { m_parameterCell.setMessage(message); }
void viewWillAppear() override;
// extractParameterAtIndex extracts the current value of the parameter
virtual double extractParameterAtIndex(int index) = 0;
// confirmParameterAtIndex updates the current value of the parameter
virtual bool confirmParameterAtIndex(int parameterIndex, double f) = 0;
// parameterAtIndex and setParameterAtIndex manipulate m_tempParameter only
double parameterAtIndex(int index) override {
assert(index == 0);
return m_tempParameter;
}
bool setParameterAtIndex(int parameterIndex, double f) override;
CurveViewCursor * m_cursor;
InteractiveCurveViewRange * m_graphRange;
double m_tempParameter;
private:
void buttonAction() override;
HighlightCell * reusableParameterCell(int index, int type) override;
int reusableParameterCellCount(int type) override;
int reusableParameterCellCount(int type) override { return 1; }
MessageTableCellWithEditableText m_parameterCell;
};

View File

@@ -15,8 +15,10 @@ InteractiveCurveViewController::InteractiveCurveViewController(Responder * paren
m_rangeVersion(rangeVersion),
m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange),
m_zoomParameterController(this, interactiveRange, curveView),
m_interactiveRange(interactiveRange),
m_rangeButton(this, I18n::Message::Axis, Invocation([](void * context, void * sender) {
InteractiveCurveViewController * graphController = (InteractiveCurveViewController *) context;
graphController->rangeParameterController()->setRange(graphController->interactiveRange());
StackViewController * stack = graphController->stackController();
stack->push(graphController->rangeParameterController());
return true;
@@ -113,7 +115,7 @@ void InteractiveCurveViewController::didBecomeFirstResponder() {
}
}
ViewController * InteractiveCurveViewController::rangeParameterController() {
RangeParameterController * InteractiveCurveViewController::rangeParameterController() {
return &m_rangeParameterController;
}

View File

@@ -19,7 +19,7 @@ public:
void didBecomeFirstResponder() override;
TELEMETRY_ID("Graph");
ViewController * rangeParameterController();
RangeParameterController * rangeParameterController();
ViewController * zoomParameterController();
virtual ViewController * initialisationParameterController() = 0;
@@ -35,6 +35,7 @@ public:
void willExitResponderChain(Responder * nextFirstResponder) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
protected:
Responder * tabController() const;
virtual StackViewController * stackController() const;
@@ -56,6 +57,8 @@ protected:
// SimpleInteractiveCurveViewController
float cursorBottomMarginRatio() override;
InteractiveCurveViewRange * interactiveRange() { return m_interactiveRange; }
OkView m_okView;
private:
/* The value 21 is the actual height of the ButtonRow, that is
@@ -75,6 +78,7 @@ private:
uint32_t * m_rangeVersion;
RangeParameterController m_rangeParameterController;
ZoomParameterController m_zoomParameterController;
InteractiveCurveViewRange * m_interactiveRange;
Button m_rangeButton;
Button m_zoomButton;
Button m_defaultInitialisationButton;

View File

@@ -29,21 +29,6 @@ double Interval::element(int i) {
return m_intervalBuffer[i];
}
void Interval::setStart(double f) {
m_start = f;
m_needCompute = true;
}
void Interval::setEnd(double f) {
m_end = f;
m_needCompute = true;
}
void Interval::setStep(double f) {
m_step = f;
m_needCompute = true;
}
void Interval::setElement(int i, double f) {
assert(i <= numberOfElements() && i < k_maxNumberOfElements);
computeElements();
@@ -54,16 +39,16 @@ void Interval::setElement(int i, double f) {
}
void Interval::reset() {
m_start = 0.0;
m_end = 10.0;
m_step = 1.0;
m_parameters.setStart(0.0);
m_parameters.setEnd(10.0);
m_parameters.setStep(1.0);
m_needCompute = true;
}
void Interval::clear() {
m_start = 1.0;
m_end = 0.0;
m_step = 1.0;
m_parameters.setStart(1.0);
m_parameters.setEnd(0.0);
m_parameters.setStep(1.0);
m_needCompute = true;
}
@@ -71,14 +56,14 @@ void Interval::computeElements() {
if (!m_needCompute) {
return;
}
if (m_start > m_end) {
if (m_parameters.start() > m_parameters.end()) {
m_numberOfElements = 0;
} else {
m_numberOfElements = m_step > 0 ? 1 + (m_end - m_start)/m_step : k_maxNumberOfElements;
m_numberOfElements = m_parameters.step() > 0 ? 1 + (m_parameters.end() - m_parameters.start())/m_parameters.step() : k_maxNumberOfElements;
m_numberOfElements = m_numberOfElements > k_maxNumberOfElements || m_numberOfElements < 0 ? k_maxNumberOfElements : m_numberOfElements;
}
for (int i = 0; i < m_numberOfElements; i += 1) {
m_intervalBuffer[i] = m_start + i * m_step;
m_intervalBuffer[i] = m_parameters.start() + i * m_parameters.step();
}
m_needCompute = false;
}

View File

@@ -10,13 +10,22 @@ public:
Interval(const Interval&) = delete;
int numberOfElements();
void deleteElementAtIndex(int index);
class IntervalParameters {
public:
void setStart(double f) { m_start = f; }
void setEnd(double f) { m_end = f; }
void setStep(double f) { m_step = f; }
double start() const { return m_start; }
double end() const { return m_end; }
double step() const { return m_step; }
private:
double m_start;
double m_end;
double m_step;
};
double element(int i);
double start() const { return m_start; }
double end() const { return m_end; }
double step() const { return m_step; }
void setStart(double f);
void setEnd(double f);
void setStep(double f);
IntervalParameters * parameters() { return &m_parameters; }
void setParameters(IntervalParameters parameters) { m_parameters = parameters; }
void setElement(int i, double f);
void forceRecompute(){ m_needCompute = true;}
void reset();
@@ -27,14 +36,12 @@ private:
void computeElements();
int m_numberOfElements;
double m_intervalBuffer[k_maxNumberOfElements];
double m_start;
double m_end;
double m_step;
bool m_needCompute;
IntervalParameters m_parameters;
};
typedef void (Interval::*SetterPointer)(double);
typedef double (Interval::*GetterPointer)() const;
typedef void (Interval::IntervalParameters::*SetterPointer)(double);
typedef double (Interval::IntervalParameters::*GetterPointer)() const;
}

View File

@@ -2,6 +2,11 @@
namespace Shared {
Interval::IntervalParameters * IntervalParameterController::SharedTempIntervalParameters() {
static Interval::IntervalParameters sTempIntervalParameters;
return &sTempIntervalParameters;
}
IntervalParameterController::IntervalParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate) :
FloatParameterController<double>(parentResponder),
m_interval(nullptr),
@@ -16,6 +21,11 @@ IntervalParameterController::IntervalParameterController(Responder * parentRespo
}
}
void IntervalParameterController::setInterval(Interval * interval) {
m_interval = interval;
*SharedTempIntervalParameters() = *(interval->parameters());
}
const char * IntervalParameterController::title() {
return I18n::translate(m_title);
}
@@ -42,8 +52,8 @@ void IntervalParameterController::willDisplayCellForIndex(HighlightCell * cell,
}
double IntervalParameterController::parameterAtIndex(int index) {
GetterPointer getters[k_totalNumberOfCell] = {&Interval::start, &Interval::end, &Interval::step};
return (m_interval->*getters[index])();
GetterPointer getters[k_totalNumberOfCell] = {&Shared::Interval::IntervalParameters::start, &Shared::Interval::IntervalParameters::end, &Shared::Interval::IntervalParameters::step};
return (SharedTempIntervalParameters()->*getters[index])();
}
bool IntervalParameterController::setParameterAtIndex(int parameterIndex, double f) {
@@ -51,18 +61,18 @@ bool IntervalParameterController::setParameterAtIndex(int parameterIndex, double
Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue);
return false;
}
double start = parameterIndex == 0 ? f : m_interval->start();
double end = parameterIndex == 1 ? f : m_interval->end();
double start = parameterIndex == 0 ? f : SharedTempIntervalParameters()->start();
double end = parameterIndex == 1 ? f : SharedTempIntervalParameters()->end();
if (start > end) {
if (parameterIndex == 1) {
Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue);
return false;
}
double g = f+1.0;
m_interval->setEnd(g);
SharedTempIntervalParameters()->setEnd(g);
}
SetterPointer setters[k_totalNumberOfCell] = {&Interval::setStart, &Interval::setEnd, &Interval::setStep};
(m_interval->*setters[parameterIndex])(f);
SetterPointer setters[k_totalNumberOfCell] = {&Shared::Interval::IntervalParameters::setStart, &Shared::Interval::IntervalParameters::setEnd, &Shared::Interval::IntervalParameters::setStep};
(SharedTempIntervalParameters()->*setters[parameterIndex])(f);
return true;
}
@@ -85,6 +95,7 @@ int IntervalParameterController::reusableParameterCellCount(int type) {
}
void IntervalParameterController::buttonAction() {
m_interval->setParameters(*SharedTempIntervalParameters());
m_interval->forceRecompute();
StackViewController * stack = stackController();
stack->pop();

View File

@@ -12,7 +12,7 @@ class IntervalParameterController : public Shared::FloatParameterController<doub
public:
IntervalParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate);
Interval * interval() { assert(m_interval); return m_interval; }
void setInterval(Interval * interval) { m_interval = interval; }
void setInterval(Interval * interval);
const char * title() override;
void setTitle(I18n::Message title) { m_title = title; }
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
@@ -24,6 +24,7 @@ protected:
Interval * m_interval;
bool handleEvent(Ion::Events::Event event) override;
private:
static Interval::IntervalParameters * SharedTempIntervalParameters();
HighlightCell * reusableParameterCell(int index, int type) override;
int reusableParameterCellCount(int type) override;
double parameterAtIndex(int index) override;

View File

@@ -8,6 +8,7 @@ namespace Shared {
RangeParameterController::RangeParameterController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, InteractiveCurveViewRange * interactiveRange) :
FloatParameterController<float>(parentResponder),
m_interactiveRange(interactiveRange),
m_tempInteractiveRange(*interactiveRange),
m_xRangeCells{},
m_yRangeCells{},
m_yAutoCell(I18n::Message::YAuto)
@@ -18,7 +19,7 @@ RangeParameterController::RangeParameterController(Responder * parentResponder,
}
for (int i = 0; i < k_numberOfConvertibleTextCell; i++) {
m_yRangeCells[i].setParentResponder(&m_selectableTableView);
m_yRangeCells[i].setInteractiveCurveViewRange(m_interactiveRange);
m_yRangeCells[i].setInteractiveCurveViewRange(&m_tempInteractiveRange);
m_yRangeCells[i].textField()->setDelegates(inputEventHandlerDelegate, this);
}
}
@@ -50,13 +51,13 @@ void RangeParameterController::willDisplayCellForIndex(HighlightCell * cell, int
}
if (index == 2) {
SwitchView * switchView = (SwitchView *)m_yAutoCell.accessoryView();
switchView->setState(m_interactiveRange->yAuto());
switchView->setState(m_tempInteractiveRange.yAuto());
return;
}
MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *)cell;
I18n::Message labels[k_numberOfTextCell+1] = {I18n::Message::XMin, I18n::Message::XMax, I18n::Message::Default, I18n::Message::YMin, I18n::Message::YMax};
myCell->setMessage(labels[index]);
KDColor yColor = m_interactiveRange->yAuto() ? Palette::SecondaryText : Palette::PrimaryText;
KDColor yColor = m_tempInteractiveRange.yAuto() ? Palette::SecondaryText : Palette::PrimaryText;
KDColor colors[k_numberOfTextCell+1] = {Palette::PrimaryText, Palette::PrimaryText, Palette::PrimaryText, yColor, yColor};
myCell->setTextColor(colors[index]);
FloatParameterController::willDisplayCellForIndex(cell, index);
@@ -70,9 +71,14 @@ bool RangeParameterController::textFieldDidFinishEditing(TextField * textField,
return false;
}
void RangeParameterController::setRange(InteractiveCurveViewRange * range){
m_interactiveRange = range;
m_tempInteractiveRange = *range;
}
bool RangeParameterController::handleEvent(Ion::Events::Event event) {
if (activeCell() == 2 && (event == Ion::Events::OK || event == Ion::Events::EXE)) {
m_interactiveRange->setYAuto(!m_interactiveRange->yAuto());
m_tempInteractiveRange.setYAuto(!m_tempInteractiveRange.yAuto());
m_selectableTableView.reloadData();
return true;
}
@@ -83,14 +89,14 @@ float RangeParameterController::parameterAtIndex(int parameterIndex) {
ParameterGetterPointer getters[k_numberOfTextCell] = {&InteractiveCurveViewRange::xMin,
&InteractiveCurveViewRange::xMax, &InteractiveCurveViewRange::yMin, &InteractiveCurveViewRange::yMax};
int index = parameterIndex > 2 ? parameterIndex - 1 : parameterIndex;
return (m_interactiveRange->*getters[index])();
return (m_tempInteractiveRange.*getters[index])();
}
bool RangeParameterController::setParameterAtIndex(int parameterIndex, float f) {
ParameterSetterPointer setters[k_numberOfTextCell] = {&InteractiveCurveViewRange::setXMin,
&InteractiveCurveViewRange::setXMax, &InteractiveCurveViewRange::setYMin, &InteractiveCurveViewRange::setYMax};
int index = parameterIndex > 2 ? parameterIndex - 1 : parameterIndex;
(m_interactiveRange->*setters[index])(f);
(m_tempInteractiveRange.*setters[index])(f);
return true;
}
@@ -119,4 +125,10 @@ int RangeParameterController::reusableParameterCellCount(int type) {
return k_numberOfConvertibleTextCell;
}
void RangeParameterController::buttonAction() {
*m_interactiveRange = m_tempInteractiveRange;
StackViewController * stack = stackController();
stack->pop();
}
}

View File

@@ -16,6 +16,7 @@ public:
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
bool handleEvent(Ion::Events::Event event) override;
void setRange(InteractiveCurveViewRange * range);
TELEMETRY_ID("Range");
private:
class MessageTableCellWithConvertibleEditableText : public MessageTableCellWithEditableText {
@@ -35,10 +36,12 @@ private:
int reusableParameterCellCount(int type) override;
float parameterAtIndex(int index) override;
bool setParameterAtIndex(int parameterIndex, float f) override;
void buttonAction() override;
constexpr static int k_numberOfEditableTextCell = 2;
constexpr static int k_numberOfConvertibleTextCell = 2;
constexpr static int k_numberOfTextCell = k_numberOfEditableTextCell+k_numberOfConvertibleTextCell;
InteractiveCurveViewRange * m_interactiveRange;
InteractiveCurveViewRange m_tempInteractiveRange;
MessageTableCellWithEditableText m_xRangeCells[k_numberOfEditableTextCell];
MessageTableCellWithConvertibleEditableText m_yRangeCells[k_numberOfConvertibleTextCell];
MessageTableCellWithSwitch m_yAutoCell;

View File

@@ -41,7 +41,7 @@ void TextToInsertForCommandText(const char * command, int commandLength, char *
UTF8Decoder decoder(command);
CodePoint codePoint = decoder.nextCodePoint();
while (codePoint != UCodePointNull && (commandLength < 0 || (decoder.stringPosition() - command <= commandLength))) {
while (codePoint != UCodePointNull && index < bufferSize - 1 && (commandLength < 0 || (decoder.stringPosition() - command <= commandLength))) {
if (codePoint == ')') {
numberOfOpenParentheses--;
} else if (codePoint == ']') {

View File

@@ -116,7 +116,7 @@ BasedLogarithm = "Logaritme met grondtal a"
Calculation = "Calculatie"
ComplexNumber = "Complexe getallen"
Combinatorics = "Combinatoriek"
Arithmetic = "rekenkunde"
Arithmetic = "Rekenkunde"
Matrices = "Matrix"
NewMatrix = "Nieuwe matrix"
Identity = "Eenheidsmatrix van formaat n"

View File

@@ -434,8 +434,9 @@ void initPanel() {
// Calibration
const uint8_t * gammaCalibration = nullptr;
uint32_t panelId = panelIdentifier();
if (panelId == 0x4E4101) {
// Don't forget the "static" qualifier, otherwise this array can be deleted before reaching send_long_command
if (panelId == 0x4E4101 || panelId == 0x4E4801) {
/* Don't forget the "static" qualifier, otherwise this array can be deleted
* before reaching send_long_command. */
static const uint8_t calibration[] = {0xA2, 0xA, 0x11, 0xA, 0xC, 0x1A, 0x34, 0x22, 0x4D, 0x28, 0x15, 0x13, 0x29, 0x2D};
gammaCalibration = calibration;
}

View File

@@ -156,13 +156,16 @@ Expression Addition::shallowReduce(ExpressionNode::ReductionContext reductionCon
* the result is not homogeneous. */
{
Expression unit;
childAtIndex(0).removeUnit(&unit);
if (childAtIndex(0).removeUnit(&unit).isUndefined()) {
return replaceWithUndefinedInPlace();
}
const bool hasUnit = !unit.isUninitialized();
for (int i = 1; i < childrenCount; i++) {
Expression otherUnit;
childAtIndex(i).removeUnit(&otherUnit);
if (hasUnit == otherUnit.isUninitialized() ||
(hasUnit && !unit.isIdenticalTo(otherUnit)))
Expression childI = childAtIndex(i).removeUnit(&otherUnit);
if (childI.isUndefined()
|| hasUnit == otherUnit.isUninitialized()
|| (hasUnit && !unit.isIdenticalTo(otherUnit)))
{
return replaceWithUndefinedInPlace();
}

View File

@@ -366,8 +366,8 @@ Expression Expression::defaultHandleUnitsInChildren() {
const int childrenCount = numberOfChildren();
for (int i = 0; i < childrenCount; i++) {
Expression unit;
childAtIndex(i).removeUnit(&unit);
if (!unit.isUninitialized()) {
Expression childI = childAtIndex(i).removeUnit(&unit);
if (childI.isUndefined() || !unit.isUninitialized()) {
return replaceWithUndefinedInPlace();
}
}
@@ -817,7 +817,11 @@ Expression Expression::angleUnitToRadian(Preferences::AngleUnit angleUnit) {
Expression Expression::reduce(ExpressionNode::ReductionContext reductionContext) {
sSimplificationHasBeenInterrupted = false;
return deepReduce(reductionContext);
Expression result = deepReduce(reductionContext);
if (sSimplificationHasBeenInterrupted) {
return replaceWithUndefinedInPlace();
}
return result;
}
Expression Expression::deepReduce(ExpressionNode::ReductionContext reductionContext) {

View File

@@ -279,8 +279,16 @@ Expression Multiplication::removeUnit(Expression * unit) {
Multiplication unitMult = Multiplication::Builder();
int resultChildrenCount = 0;
for (int i = 0; i < numberOfChildren(); i++) {
Expression childI = childAtIndex(i);
assert(!childI.isUndefined());
Expression currentUnit;
childAtIndex(i).removeUnit(&currentUnit);
childI = childI.removeUnit(&currentUnit);
if (childI.isUndefined()) {
/* If the child was a unit convert, it replaced itself with an undefined
* during the removeUnit. */
*unit = Expression();
return replaceWithUndefinedInPlace();
}
if (!currentUnit.isUninitialized()) {
unitMult.addChildAtIndexInPlace(currentUnit, resultChildrenCount, resultChildrenCount);
resultChildrenCount++;
@@ -384,7 +392,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu
self = deepReduce(reductionContext); // removeUnit has to be called on reduced expression
self = removeUnit(&units);
if (units.isUninitialized()) {
if (self.isUndefined() || units.isUninitialized()) {
// TODO: handle error "Invalid unit"
result = Undefined::Builder();
goto replace_by_result;

View File

@@ -407,8 +407,8 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex
{
Expression indexUnit;
index = index.removeUnit(&indexUnit);
if (!indexUnit.isUninitialized()) {
// There must be no unit in the exponent
if (!indexUnit.isUninitialized() || index.isUndefined()) {
// There must be no unit nor undefined in the exponent
return replaceWithUndefinedInPlace();
}
assert(index == childAtIndex(1));

View File

@@ -59,8 +59,8 @@ Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext reducti
reductionContext.target(),
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined);
Expression unit;
childAtIndex(1).clone().deepReduce(reductionContextWithUnits).removeUnit(&unit);
if (unit.isUninitialized()) {
Expression childWithoutUnit = childAtIndex(1).clone().deepReduce(reductionContextWithUnits).removeUnit(&unit);
if (childWithoutUnit.isUndefined() || unit.isUninitialized()) {
// There is no unit on the right
return replaceWithUndefinedInPlace();
}

View File

@@ -70,8 +70,8 @@ QUIZ_CASE(poincare_context_user_variable_simple) {
}
QUIZ_CASE(poincare_context_user_variable_2_circular_variables) {
assert_simplify("a→b");
assert_simplify("b→a");
assert_reduce("a→b");
assert_reduce("b→a");
assert_expression_approximates_to<double>("a", Undefined::Name());
assert_expression_approximates_to<double>("b", Undefined::Name());
@@ -81,9 +81,9 @@ QUIZ_CASE(poincare_context_user_variable_2_circular_variables) {
}
QUIZ_CASE(poincare_context_user_variable_3_circular_variables) {
assert_simplify("a→b");
assert_simplify("b→c");
assert_simplify("c→a");
assert_reduce("a→b");
assert_reduce("b→c");
assert_reduce("c→a");
assert_expression_approximates_to<double>("a", Undefined::Name());
assert_expression_approximates_to<double>("b", Undefined::Name());
assert_expression_approximates_to<double>("c", Undefined::Name());
@@ -96,7 +96,7 @@ QUIZ_CASE(poincare_context_user_variable_3_circular_variables) {
QUIZ_CASE(poincare_context_user_variable_1_circular_function) {
// h: x → h(x)
assert_simplify("h(x)→h(x)");
assert_reduce("h(x)→h(x)");
assert_expression_approximates_to<double>("h(1)", Undefined::Name());
// Clean the storage for other tests
@@ -104,9 +104,9 @@ QUIZ_CASE(poincare_context_user_variable_1_circular_function) {
}
QUIZ_CASE(poincare_context_user_variable_2_circular_functions) {
assert_simplify("1→f(x)");
assert_simplify("f(x)→g(x)");
assert_simplify("g(x)→f(x)");
assert_reduce("1→f(x)");
assert_reduce("f(x)→g(x)");
assert_reduce("g(x)→f(x)");
assert_expression_approximates_to<double>("f(1)", Undefined::Name());
assert_expression_approximates_to<double>("g(1)", Undefined::Name());
@@ -116,10 +116,10 @@ QUIZ_CASE(poincare_context_user_variable_2_circular_functions) {
}
QUIZ_CASE(poincare_context_user_variable_3_circular_functions) {
assert_simplify("1→f(x)");
assert_simplify("f(x)→g(x)");
assert_simplify("g(x)→h(x)");
assert_simplify("h(x)→f(x)");
assert_reduce("1→f(x)");
assert_reduce("f(x)→g(x)");
assert_reduce("g(x)→h(x)");
assert_reduce("h(x)→f(x)");
assert_expression_approximates_to<double>("f(1)", Undefined::Name());
assert_expression_approximates_to<double>("g(1)", Undefined::Name());
assert_expression_approximates_to<double>("h(1)", Undefined::Name());
@@ -131,9 +131,9 @@ QUIZ_CASE(poincare_context_user_variable_3_circular_functions) {
}
QUIZ_CASE(poincare_context_user_variable_circular_variables_and_functions) {
assert_simplify("a→b");
assert_simplify("b→a");
assert_simplify("a→f(x)");
assert_reduce("a→b");
assert_reduce("b→a");
assert_reduce("a→f(x)");
assert_expression_approximates_to<double>("f(1)", Undefined::Name());
assert_expression_approximates_to<double>("a", Undefined::Name());
assert_expression_approximates_to<double>("b", Undefined::Name());
@@ -146,21 +146,21 @@ QUIZ_CASE(poincare_context_user_variable_circular_variables_and_functions) {
QUIZ_CASE(poincare_context_user_variable_composed_functions) {
// f: x→x^2
assert_simplify("x^2→f(x)");
assert_reduce("x^2→f(x)");
// g: x→f(x-2)
assert_simplify("f(x-2)→g(x)");
assert_reduce("f(x-2)→g(x)");
assert_expression_approximates_to<double>("f(2)", "4");
assert_expression_approximates_to<double>("g(3)", "1");
assert_expression_approximates_to<double>("g(5)", "9");
// g: x→f(x-2)+f(x+1)
assert_simplify("f(x-2)+f(x+1)→g(x)");
assert_reduce("f(x-2)+f(x+1)→g(x)");
// Add a sum to bypass simplification
assert_expression_approximates_to<double>("g(3)+sum(1, n, 2, 4)", "20");
assert_expression_approximates_to<double>("g(5)", "45");
// g: x→x+1
assert_simplify("x+1→g(x)");
assert_reduce("x+1→g(x)");
assert_expression_approximates_to<double>("f(g(4))", "25");
// Add a sum to bypass simplification
assert_expression_approximates_to<double>("f(g(4))+sum(1, n, 2, 4)", "28");
@@ -172,7 +172,7 @@ QUIZ_CASE(poincare_context_user_variable_composed_functions) {
QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_symbol) {
// f : x→ x^2
assert_simplify("x^2→f(x)");
assert_reduce("x^2→f(x)");
// Approximate f(?-2) with ? = 5
constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1;
@@ -187,7 +187,7 @@ QUIZ_CASE(poincare_context_user_variable_functions_approximation_with_value_for_
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
// f : x → √(-1)
assert_simplify("√(-1)×√(-1)→f(x)");
assert_reduce("√(-1)×√(-1)→f(x)");
// Approximate f(?) with ? = 5
// Cartesian
assert_parsed_expression_approximates_with_value_for_symbol(Function::Builder("f", 1, Symbol::Builder(UCodePointUnknown)), x, 1.0, -1.0);

View File

@@ -48,7 +48,7 @@ QUIZ_CASE(poincare_properties_is_approximate) {
assert_expression_has_property("3.4", &context, Expression::IsApproximate);
assert_expression_has_property("2.3+1", &context, Expression::IsApproximate);
assert_expression_has_not_property("a", &context, Expression::IsApproximate);
assert_simplify("42.3→a");
assert_reduce("42.3→a");
assert_expression_has_property("a", &context, Expression::IsApproximate);
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
}
@@ -93,7 +93,7 @@ QUIZ_CASE(poincare_properties_is_infinity) {
assert_expression_has_property("3.4+inf", &context, Expression::IsInfinity);
assert_expression_has_not_property("2.3+1", &context, Expression::IsInfinity);
assert_expression_has_not_property("a", &context, Expression::IsInfinity);
assert_simplify("42.3+inf→a");
assert_reduce("42.3+inf→a");
assert_expression_has_property("a", &context, Expression::IsInfinity);
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
}
@@ -155,7 +155,7 @@ QUIZ_CASE(poincare_properties_sign) {
assert_reduced_expression_sign("sign(π)", Positive);
assert_reduced_expression_sign("sign(-π)", Negative);
assert_reduced_expression_sign("a", Unknown);
assert_simplify("42→a");
assert_reduce("42→a");
assert_reduced_expression_sign("a", Positive);
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
}
@@ -232,7 +232,7 @@ QUIZ_CASE(poincare_properties_polynomial_degree) {
assert_reduced_expression_polynomial_degree("π×x", 1);
assert_reduced_expression_polynomial_degree("√(-1)×x", -1, "x", Real);
// f: x→x^2+πx+1
assert_simplify("1+π×x+x^2→f(x)");
assert_reduce("1+π×x+x^2→f(x)");
assert_reduced_expression_polynomial_degree("f(x)", 2);
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
}
@@ -271,7 +271,7 @@ QUIZ_CASE(poincare_properties_characteristic_range) {
// cos(cos(x)), degree
assert_reduced_expression_has_characteristic_range(Cosine::Builder((Expression)Cosine::Builder(Symbol::Builder(UCodePointUnknown))), 360.0f);
// f(x) with f : x --> cos(x), degree
assert_simplify("cos(x)→f(x)");
assert_reduce("cos(x)→f(x)");
assert_reduced_expression_has_characteristic_range(Function::Builder("f",1,Symbol::Builder(UCodePointUnknown)), 360.0f);
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
}
@@ -309,7 +309,7 @@ QUIZ_CASE(poincare_properties_get_variables) {
assert_expression_has_variables("a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+aa+bb+cc+dd+ee+ff+gg+hh+ii+jj+kk+ll+mm+nn+oo", variableBuffer6, -1);
assert_expression_has_variables("a+b+c+d+e+f+g", variableBuffer6, -1);
// f: x→1+πx+x^2+toto
assert_simplify("1+π×x+x^2+toto→f(x)");
assert_reduce("1+π×x+x^2+toto→f(x)");
const char * variableBuffer7[] = {"tata","toto", ""};
assert_expression_has_variables("f(tata)", variableBuffer7, 2);
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
@@ -347,7 +347,7 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) {
assert_reduced_expression_has_polynomial_coefficient("x^2-π×x+1", "x", coefficient3);
// f: x→x^2+Px+1
assert_simplify("1+π×x+x^2→f(x)");
assert_reduce("1+π×x+x^2→f(x)");
const char * coefficient4[] = {"1", "π", "1", 0}; //x^2+π×x+1
assert_reduced_expression_has_polynomial_coefficient("f(x)", "x", coefficient4);
const char * coefficient5[] = {"0", "𝐢", 0}; //√(-1)x
@@ -356,7 +356,7 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) {
assert_reduced_expression_has_polynomial_coefficient("√(-1)x", "x", coefficient6, Real);
// 3 -> x
assert_simplify("3→x");
assert_reduce("3→x");
const char * coefficient7[] = {"4", 0};
assert_reduced_expression_has_polynomial_coefficient("x+1", "x", coefficient7 );
const char * coefficient8[] = {"2", "1", 0};

View File

@@ -76,13 +76,13 @@ Poincare::Expression parse_expression(const char * expression, Context * context
return result;
}
void assert_simplify(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) {
void assert_reduce(const char * expression, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target) {
Shared::GlobalContext globalContext;
Expression e = parse_expression(expression, &globalContext, false);
assert_expression_simplify(e, angleUnit, complexFormat, target, expression);
assert_expression_reduce(e, angleUnit, complexFormat, target, expression);
}
void assert_expression_simplify(Expression e, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target, const char * printIfFailure) {
void assert_expression_reduce(Expression e, Preferences::AngleUnit angleUnit, Preferences::ComplexFormat complexFormat, ExpressionNode::ReductionTarget target, const char * printIfFailure) {
Shared::GlobalContext globalContext;
e = e.reduce(ExpressionNode::ReductionContext(&globalContext, complexFormat, angleUnit, target));
quiz_assert_print_if_failure(!(e.isUninitialized()), printIfFailure);

View File

@@ -39,9 +39,9 @@ Poincare::Expression parse_expression(const char * expression, Poincare::Context
// Simplification
void assert_simplify(const char * expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User);
void assert_reduce(const char * expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User);
void assert_expression_simplify(Poincare::Expression expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User, const char * printIfFailure = "Error");
void assert_expression_reduce(Poincare::Expression expression, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::ReductionTarget target = User, const char * printIfFailure = "Error");
void assert_parsed_expression_simplify_to(const char * expression, const char * simplifiedExpression, Poincare::ExpressionNode::ReductionTarget target = User, Poincare::Preferences::AngleUnit angleUnit = Radian, Poincare::Preferences::ComplexFormat complexFormat = Cartesian, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = DefaultUnitConversion);

View File

@@ -898,7 +898,7 @@ QUIZ_CASE(poincare_simplification_matrix) {
assert_parsed_expression_simplify_to("transpose(√(4))", "2");
// Expressions with unreduced matrix
assert_simplify("confidence(cos(2)/25,3)→a");
assert_reduce("confidence(cos(2)/25,3)→a");
// Check that matrices are not permuted in multiplication
assert_parsed_expression_simplify_to("cos(3a)*abs(transpose(a))", "cos(3×confidence(cos(2)/25,3))×abs(transpose(confidence(cos(2)/25,3)))");
assert_parsed_expression_simplify_to("abs(transpose(a))*cos(3a)", "abs(transpose(confidence(cos(2)/25,3)))×cos(3×confidence(cos(2)/25,3))");
@@ -1054,13 +1054,13 @@ QUIZ_CASE(poincare_simplification_unit_convert) {
assert_parsed_expression_simplify_to("4→_km/_m", Undefined::Name());
assert_parsed_expression_simplify_to("3×_min→_s+1-1", Undefined::Name());
assert_simplify("_m→a", Radian, Real);
assert_simplify("_m→b", Radian, Real);
assert_reduce("_m→a", Radian, Real);
assert_reduce("_m→b", Radian, Real);
assert_parsed_expression_simplify_to("1_km→a×b", Undefined::Name());
assert_simplify("2→a");
assert_reduce("2→a");
assert_parsed_expression_simplify_to("3_m→a×_km", Undefined::Name());
assert_simplify("2→f(x)");
assert_reduce("2→f(x)");
assert_parsed_expression_simplify_to("3_m→f(2)×_km", Undefined::Name());
// Clean the storage for other tests
@@ -1087,13 +1087,13 @@ QUIZ_CASE(poincare_simplification_complex_format) {
// User defined variable
assert_parsed_expression_simplify_to("a", "a", User, Radian, Real);
// a = 2+i
assert_simplify("2+𝐢→a", Radian, Real);
assert_reduce("2+𝐢→a", Radian, Real);
assert_parsed_expression_simplify_to("a", "unreal", User, Radian, Real);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
// User defined function
// f : x → x+1
assert_simplify("x+1+𝐢→f(x)", Radian, Real);
assert_reduce("x+1+𝐢→f(x)", Radian, Real);
assert_parsed_expression_simplify_to("f(3)", "unreal", User, Radian, Real);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
@@ -1173,13 +1173,13 @@ QUIZ_CASE(poincare_simplification_complex_format) {
// User defined variable
assert_parsed_expression_simplify_to("a", "a", User, Radian, Cartesian);
// a = 2+i
assert_simplify("2+𝐢→a", Radian, Cartesian);
assert_reduce("2+𝐢→a", Radian, Cartesian);
assert_parsed_expression_simplify_to("a", "2+𝐢", User, Radian, Cartesian);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
// User defined function
// f : x → x+1
assert_simplify("x+1+𝐢→f(x)", Radian, Cartesian);
assert_reduce("x+1+𝐢→f(x)", Radian, Cartesian);
assert_parsed_expression_simplify_to("f(3)", "4+𝐢", User, Radian, Cartesian);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
@@ -1223,13 +1223,13 @@ QUIZ_CASE(poincare_simplification_complex_format) {
// User defined variable
assert_parsed_expression_simplify_to("a", "a", User, Radian, Polar);
// a = 2 + 𝐢
assert_simplify("2+𝐢→a", Radian, Polar);
assert_reduce("2+𝐢→a", Radian, Polar);
assert_parsed_expression_simplify_to("a", "√(5)×^\u0012\u0012-2×atan(2)+π\u0013/2×𝐢\u0013", User, Radian, Polar);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
// User defined function
// f: x → x+1
assert_simplify("x+1+𝐢→f(x)", Radian, Polar);
assert_reduce("x+1+𝐢→f(x)", Radian, Polar);
assert_parsed_expression_simplify_to("f(3)", "√(17)×^\u0012\u0012-2×atan(4)+π\u0013/2×𝐢\u0013", User, Radian, Polar);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
@@ -1295,10 +1295,10 @@ QUIZ_CASE(poincare_simplification_unit_conversion) {
QUIZ_CASE(poincare_simplification_user_function) {
// User defined function
// f: x → x*1
assert_simplify("x*3→f(x)", Radian, Polar);
assert_reduce("x*3→f(x)", Radian, Polar);
assert_parsed_expression_simplify_to("f(1+1)", "6", User, Radian, Polar);
// f: x → 3
assert_simplify("3→f(x)", Radian, Polar);
assert_reduce("3→f(x)", Radian, Polar);
assert_parsed_expression_simplify_to("f(1/0)", Undefined::Name(), User, Radian, Polar);
// Clean the storage for other tests
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
@@ -1315,8 +1315,19 @@ QUIZ_CASE(poincare_simplification_user_function_with_convert) {
Function::Builder(
"f", 1,
Symbol::Builder('x')));
assert_expression_simplify(e);
assert_simplify("e^(f(0))", Radian, Polar);
assert_expression_reduce(e);
assert_parsed_expression_simplify_to("e^(f(0))", "undef");
e = Store::Builder(
UnitConvert::Builder(
Rational::Builder(0),
Unit::Second()),
Function::Builder(
"f", 1,
Symbol::Builder('x')));
assert_expression_reduce(e);
assert_parsed_expression_simplify_to("0f(0)", "undef");
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
}