[apps/shared] New automatic zoom on curves

Initial zoom for displaying curves is computed according to the
following rules :
  - For polar and parametric curves, the algorithm has not changed.
    Vertical and horizontal ranges are chosen in order to display the
    full curve with orthonormal graduations.
  - For cartesian curves, the horizontal range is chosen in order to
    display all points of interest (roots, extrema, asymptotes...).
    The vertical range is fitted to be able to display those points, but
    also cuts out points outside of the function's order of magnitude.

Change-Id: Idf8233fc2e6586b85d34c4da152c83e75513d85c
This commit is contained in:
Gabriel Ozouf
2020-08-03 17:10:17 +02:00
committed by Émilie Feral
parent 1917999f6d
commit 8104caea50
10 changed files with 400 additions and 214 deletions

View File

@@ -73,53 +73,6 @@ void FunctionGraphController::reloadBannerView() {
reloadBannerViewForCursorOnFunction(m_cursor, record, functionStore(), AppsContainer::sharedAppsContainer()->globalContext());
}
InteractiveCurveViewRangeDelegate::Range FunctionGraphController::computeYRange(InteractiveCurveViewRange * interactiveCurveViewRange) {
Poincare::Context * context = textFieldDelegateApp()->localContext();
float min = FLT_MAX;
float max = -FLT_MAX;
float xMin = interactiveCurveViewRange->xMin();
float xMax = interactiveCurveViewRange->xMax();
assert(functionStore()->numberOfActiveFunctions() > 0);
for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) {
ExpiringPointer<Function> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
/* Scan x-range from the middle to the extrema in order to get balanced
* y-range for even functions (y = 1/x). */
double tMin = f->tMin();
if (std::isnan(tMin)) {
tMin = xMin;
} else if (f->shouldClipTRangeToXRange()) {
tMin = std::max<double>(tMin, xMin);
}
double tMax = f->tMax();
if (std::isnan(tMax)) {
tMax = xMax;
} else if (f->shouldClipTRangeToXRange()) {
tMax = std::min<double>(tMax, xMax);
}
/* In practice, a step smaller than a pixel's width is needed for sampling
* the values of a function. Otherwise some relevant extremal values may be
* missed. */
float rangeStep = f->rangeStep();
const float step = std::isnan(rangeStep) ? curveView()->pixelWidth() / 2.0f : rangeStep;
const int balancedBound = std::floor((tMax-tMin)/2/step);
for (int j = -balancedBound; j <= balancedBound ; j++) {
float t = (tMin+tMax)/2 + step * j;
Coordinate2D<float> xy = f->evaluateXYAtParameter(t, context);
float x = xy.x1();
if (!std::isnan(x) && !std::isinf(x) && x >= xMin && x <= xMax) {
float y = xy.x2();
if (!std::isnan(y) && !std::isinf(y)) {
min = std::min(min, y);
max = std::max(max, y);
}
}
}
}
InteractiveCurveViewRangeDelegate::Range range;
range.min = min;
range.max = max;
return range;
}
double FunctionGraphController::defaultCursorT(Ion::Storage::Record record) {
return (interactiveCurveViewRange()->xMin()+interactiveCurveViewRange()->xMax())/2.0f;