mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[fix] conflicts
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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...) */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 == ']') {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(¤tUnit);
|
||||
childI = childI.removeUnit(¤tUnit);
|
||||
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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user