mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[apps/graph] Reworked function caching
Instead of being memoized all at once before display, functions values are now stored at evaluation time. Fixed some quirks with caching preparation. Change-Id: I5d212c271c8c41a6dc9074a15c720f0bccf8ac40
This commit is contained in:
committed by
Émilie Feral
parent
42fcf557b8
commit
1bee23cf4f
@@ -16,7 +16,7 @@ public:
|
||||
return recordSatisfyingTestAtIndex(i, &isFunctionActiveOfType, &plotType);
|
||||
}
|
||||
Shared::ExpiringPointer<Shared::ContinuousFunction> modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer<Shared::ContinuousFunction>(static_cast<Shared::ContinuousFunction *>(privateModelForRecord(record))); }
|
||||
Shared::ExpiringPointer<Shared::ContinuousFunctionCache> cacheAtIndex(int i) const { return (i < Shared::ContinuousFunctionCache::k_numberOfAvailableCaches) ? Shared::ExpiringPointer<Shared::ContinuousFunctionCache>(k_functionCaches + i) : nullptr; }
|
||||
Shared::ContinuousFunctionCache * cacheAtIndex(int i) const { return (i < Shared::ContinuousFunctionCache::k_numberOfAvailableCaches) ? m_functionCaches + i : nullptr; }
|
||||
Ion::Storage::Record::ErrorStatus addEmptyModel() override;
|
||||
private:
|
||||
const char * modelExtension() const override { return Ion::Storage::funcExtension; }
|
||||
@@ -27,7 +27,7 @@ private:
|
||||
return isFunctionActive(model, context) && plotType == static_cast<Shared::ContinuousFunction *>(model)->plotType();
|
||||
}
|
||||
mutable Shared::ContinuousFunction m_functions[k_maxNumberOfMemoizedModels];
|
||||
mutable Shared::ContinuousFunctionCache k_functionCaches[Shared::ContinuousFunctionCache::k_numberOfAvailableCaches];
|
||||
mutable Shared::ContinuousFunctionCache m_functionCaches[Shared::ContinuousFunctionCache::k_numberOfAvailableCaches];
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "graph_view.h"
|
||||
#include "../app.h"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
@@ -28,7 +29,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
for (int i = 0; i < activeFunctionsCount ; i++) {
|
||||
Ion::Storage::Record record = functionStore->activeRecordAtIndex(i);
|
||||
ExpiringPointer<ContinuousFunction> f = functionStore->modelForRecord(record);
|
||||
ExpiringPointer<ContinuousFunctionCache> cch = functionStore->cacheAtIndex(i);
|
||||
ContinuousFunctionCache * cch = functionStore->cacheAtIndex(i);
|
||||
Shared::ContinuousFunction::PlotType type = f->plotType();
|
||||
Poincare::Expression e = f->expressionReduced(context());
|
||||
if (e.isUndefined() || (
|
||||
@@ -52,6 +53,17 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
* how fast the function moves... */
|
||||
float tstep = (tmax-tmin)/10.0938275501223f;
|
||||
|
||||
float tCacheMin, tCacheStep;
|
||||
if (type == ContinuousFunction::PlotType::Cartesian) {
|
||||
float rectLeft = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin);
|
||||
tCacheMin = std::isnan(rectLeft) ? tmin : std::max(tmin, rectLeft);
|
||||
tCacheStep = pixelWidth();
|
||||
} else {
|
||||
tCacheMin = tmin;
|
||||
tCacheStep = tstep;
|
||||
}
|
||||
ContinuousFunctionCache::PrepareForCaching(f.operator->(), cch, tCacheMin, tCacheStep);
|
||||
|
||||
// Cartesian
|
||||
if (type == Shared::ContinuousFunction::PlotType::Cartesian) {
|
||||
drawCartesianCurve(ctx, rect, tmin, tmax, [](float t, void * model, void * context) {
|
||||
@@ -63,8 +75,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ContinuousFunction * f = (ContinuousFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
return f->evaluateXYAtParameter(t, c);
|
||||
},
|
||||
&ContinuousFunctionCache::PrepareCache, cch.operator->());
|
||||
});
|
||||
/* Draw tangent */
|
||||
if (m_tangent && record == m_selectedRecord) {
|
||||
float tangentParameterA = f->approximateDerivative(m_curveViewCursor->x(), context());
|
||||
@@ -85,9 +96,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ContinuousFunction * f = (ContinuousFunction *)model;
|
||||
Poincare::Context * c = (Poincare::Context *)context;
|
||||
return f->evaluateXYAtParameter(t, c);
|
||||
}, f.operator->(), context(), false, f->color(),
|
||||
true, false, 0.0f, 0.0f, /* drawCurve's default arguments */
|
||||
&ContinuousFunctionCache::PrepareCache, cch.operator->());
|
||||
}, f.operator->(), context(), false, f->color());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -351,18 +351,6 @@ Poincare::Expression ContinuousFunction::sumBetweenBounds(double start, double e
|
||||
* the derivative table. */
|
||||
}
|
||||
|
||||
Poincare::Coordinate2D<float> ContinuousFunction::checkForCacheHitAndEvaluate(float t, Poincare::Context * context) const {
|
||||
Poincare::Coordinate2D<float> res(NAN, NAN);
|
||||
if (cacheIsFilled()) {
|
||||
res = cache()->valueForParameter(this, t);
|
||||
}
|
||||
if (std::isnan(res.x1()) || std::isnan(res.x2())) {
|
||||
res = privateEvaluateXYAtParameter(t, context);
|
||||
//res = Poincare::Coordinate2D<float>(privateEvaluateXYAtParameter(t, context).x1(), 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Ion::Storage::Record::ErrorStatus ContinuousFunction::setContent(const char * c, Poincare::Context * context) {
|
||||
clearCache();
|
||||
return ExpressionModelHandle::setContent(c, context);
|
||||
|
||||
@@ -26,7 +26,8 @@ public:
|
||||
static void DefaultName(char buffer[], size_t bufferSize);
|
||||
static ContinuousFunction NewModel(Ion::Storage::Record::ErrorStatus * error, const char * baseName = nullptr);
|
||||
ContinuousFunction(Ion::Storage::Record record = Record()) :
|
||||
Function(record)
|
||||
Function(record),
|
||||
m_cache(nullptr)
|
||||
{}
|
||||
I18n::Message parameterMessageName() const override;
|
||||
CodePoint symbol() const override;
|
||||
@@ -47,8 +48,7 @@ public:
|
||||
return templatedApproximateAtParameter(t, context);
|
||||
}
|
||||
Poincare::Coordinate2D<float> evaluateXYAtParameter(float t, Poincare::Context * context) const override {
|
||||
//return privateEvaluateXYAtParameter<float>(t, context);
|
||||
return checkForCacheHitAndEvaluate(t, context);
|
||||
return (m_cache) ? m_cache->valueForParameter(this, context, t) : privateEvaluateXYAtParameter<float>(t, context);
|
||||
}
|
||||
Poincare::Coordinate2D<double> evaluateXYAtParameter(double t, Poincare::Context * context) const override {
|
||||
return privateEvaluateXYAtParameter<double>(t, context);
|
||||
@@ -83,14 +83,12 @@ public:
|
||||
ContinuousFunctionCache * cache() const { return m_cache; }
|
||||
void setCache(ContinuousFunctionCache * v) { m_cache = v; }
|
||||
void clearCache() { m_cache = nullptr; }
|
||||
bool cacheIsFilled() const { return cache() && cache()->filled(); }
|
||||
Ion::Storage::Record::ErrorStatus setContent(const char * c, Poincare::Context * context) override;
|
||||
private:
|
||||
constexpr static float k_polarParamRangeSearchNumberOfPoints = 100.0f; // This is ad hoc, no special justification
|
||||
typedef Poincare::Coordinate2D<double> (*ComputePointOfInterest)(Poincare::Expression e, char * symbol, double start, double step, double max, Poincare::Context * context);
|
||||
Poincare::Coordinate2D<double> nextPointOfInterestFrom(double start, double step, double max, Poincare::Context * context, ComputePointOfInterest compute) const;
|
||||
template <typename T> Poincare::Coordinate2D<T> privateEvaluateXYAtParameter(T t, Poincare::Context * context) const;
|
||||
Poincare::Coordinate2D<float> checkForCacheHitAndEvaluate(float t, Poincare::Context * context) const;
|
||||
/* RecordDataBuffer is the layout of the data buffer of Record
|
||||
* representing a ContinuousFunction. See comment on
|
||||
* Shared::Function::RecordDataBuffer about packing. */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "continuous_function_cache.h"
|
||||
#include "continuous_function.h"
|
||||
#include <limits.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
@@ -8,43 +9,38 @@ constexpr float ContinuousFunctionCache::k_cacheHitTolerance;
|
||||
constexpr int ContinuousFunctionCache::k_numberOfAvailableCaches;
|
||||
|
||||
// public
|
||||
void ContinuousFunctionCache::PrepareCache(void * f, void * ctx, void * cch, float tMin, float tStep) {
|
||||
if (!cch) {
|
||||
void ContinuousFunctionCache::PrepareForCaching(void * fun, ContinuousFunctionCache * cache, float tMin, float tStep) {
|
||||
if (!cache) {
|
||||
/* ContinuousFunctionStore::cacheAtIndex has returned a nullptr : the index
|
||||
* of the function we are trying to draw is greater than the number of
|
||||
* available caches, so we do nothing.*/
|
||||
return;
|
||||
}
|
||||
ContinuousFunction * function = (ContinuousFunction *)f;
|
||||
Poincare::Context * context = (Poincare::Context *)ctx;
|
||||
if (!function->cache()) {
|
||||
ContinuousFunctionCache * cache = (ContinuousFunctionCache *)cch;
|
||||
|
||||
ContinuousFunction * function = static_cast<ContinuousFunction *>(fun);
|
||||
if (function->cache() != cache) {
|
||||
cache->clear();
|
||||
function->setCache(cache);
|
||||
}
|
||||
if (function->cache()->filled() && tStep / StepFactor(function) == function->cache()->step()) {
|
||||
if (function->plotType() == ContinuousFunction::PlotType::Cartesian) {
|
||||
function->cache()->pan(function, context, tMin);
|
||||
}
|
||||
return;
|
||||
|
||||
if (function->plotType() == ContinuousFunction::PlotType::Cartesian && tStep != 0) {
|
||||
function->cache()->pan(function, tMin);
|
||||
}
|
||||
function->cache()->setRange(function, tMin, tStep);
|
||||
function->cache()->memoize(function, context);
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::clear() {
|
||||
m_filled = false;
|
||||
m_startOfCache = 0;
|
||||
m_tStep = 0;
|
||||
invalidateBetween(0, k_sizeOfCache);
|
||||
}
|
||||
|
||||
Poincare::Coordinate2D<float> ContinuousFunctionCache::valueForParameter(const ContinuousFunction * function, float t) const {
|
||||
int iRes = indexForParameter(function, t);
|
||||
/* If t does not map to an index, iRes is -1 */
|
||||
if (iRes < 0) {
|
||||
return Poincare::Coordinate2D<float>(NAN, NAN);
|
||||
Poincare::Coordinate2D<float> ContinuousFunctionCache::valueForParameter(const ContinuousFunction * function, Poincare::Context * context, float t) {
|
||||
int resIndex = indexForParameter(function, t);
|
||||
if (resIndex < 0) {
|
||||
return function->privateEvaluateXYAtParameter(t, context);
|
||||
}
|
||||
if (function->plotType() == ContinuousFunction::PlotType::Cartesian) {
|
||||
return Poincare::Coordinate2D<float>(t, m_cache[iRes]);
|
||||
}
|
||||
assert(m_startOfCache == 0);
|
||||
return Poincare::Coordinate2D<float>(m_cache[2*iRes], m_cache[2*iRes+1]);
|
||||
return valuesAtIndex(function, context, t, resIndex);
|
||||
}
|
||||
|
||||
// private
|
||||
@@ -55,48 +51,17 @@ float ContinuousFunctionCache::StepFactor(ContinuousFunction * function) {
|
||||
return (function->plotType() == ContinuousFunction::PlotType::Cartesian) ? 1.f : 16.f;
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::invalidateBetween(int iInf, int iSup) {
|
||||
for (int i = iInf; i < iSup; i++) {
|
||||
m_cache[i] = NAN;
|
||||
}
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::setRange(ContinuousFunction * function, float tMin, float tStep) {
|
||||
m_tMin = tMin;
|
||||
m_tStep = tStep / StepFactor(function);
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::memoize(ContinuousFunction * function, Poincare::Context * context) {
|
||||
m_filled = true;
|
||||
m_startOfCache = 0;
|
||||
if (function->plotType() == ContinuousFunction::PlotType::Cartesian) {
|
||||
memoizeYForX(function, context);
|
||||
return;
|
||||
}
|
||||
memoizeXYForT(function, context);
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::memoizeYForX(ContinuousFunction * function, Poincare::Context * context) {
|
||||
memoizeYForXBetweenIndices(function, context, 0, k_sizeOfCache);
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::memoizeYForXBetweenIndices(ContinuousFunction * function, Poincare::Context * context, int iInf, int iSup) {
|
||||
assert(function->plotType() == ContinuousFunction::PlotType::Cartesian);
|
||||
for (int i = iInf; i < iSup; i++) {
|
||||
m_cache[i] = function->privateEvaluateXYAtParameter(parameterForIndex(i), context).x2();
|
||||
}
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::memoizeXYForT(ContinuousFunction * function, Poincare::Context * context) {
|
||||
assert(function->plotType() != ContinuousFunction::PlotType::Cartesian);
|
||||
for (int i = 1; i < k_sizeOfCache; i += 2) {
|
||||
Poincare::Coordinate2D<float> res = function->privateEvaluateXYAtParameter(parameterForIndex(i/2), context);
|
||||
m_cache[i - 1] = res.x1();
|
||||
m_cache[i] = res.x2();
|
||||
}
|
||||
}
|
||||
|
||||
float ContinuousFunctionCache::parameterForIndex(int i) const {
|
||||
if (i < m_startOfCache) {
|
||||
i += k_sizeOfCache;
|
||||
}
|
||||
return m_tMin + m_tStep * (i - m_startOfCache);
|
||||
}
|
||||
|
||||
int ContinuousFunctionCache::indexForParameter(const ContinuousFunction * function, float t) const {
|
||||
float delta = (t - m_tMin) / m_tStep;
|
||||
if (delta < 0 || delta > INT_MAX) {
|
||||
@@ -104,14 +69,31 @@ int ContinuousFunctionCache::indexForParameter(const ContinuousFunction * functi
|
||||
}
|
||||
int res = std::round(delta);
|
||||
assert(res >= 0);
|
||||
if (res >= k_sizeOfCache || std::abs(res - delta) > k_cacheHitTolerance) {
|
||||
if ((res >= k_sizeOfCache && function->plotType() == ContinuousFunction::PlotType::Cartesian)
|
||||
|| (res >= k_sizeOfCache / 2 && function->plotType() != ContinuousFunction::PlotType::Cartesian)
|
||||
|| std::abs(res - delta) > k_cacheHitTolerance) {
|
||||
return -1;
|
||||
}
|
||||
assert(function->plotType() == ContinuousFunction::PlotType::Cartesian || m_startOfCache == 0);
|
||||
return (res + m_startOfCache) % k_sizeOfCache;
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::pan(ContinuousFunction * function, Poincare::Context * context, float newTMin) {
|
||||
Poincare::Coordinate2D<float> ContinuousFunctionCache::valuesAtIndex(const ContinuousFunction * function, Poincare::Context * context, float t, int i) {
|
||||
if (function->plotType() == ContinuousFunction::PlotType::Cartesian) {
|
||||
if (std::isnan(m_cache[i])) {
|
||||
m_cache[i] = function->privateEvaluateXYAtParameter(t, context).x2();
|
||||
}
|
||||
return Poincare::Coordinate2D<float>(t, m_cache[i]);
|
||||
}
|
||||
if (std::isnan(m_cache[2 * i]) || std::isnan(m_cache[2 * i + 1])) {
|
||||
Poincare::Coordinate2D<float> res = function->privateEvaluateXYAtParameter(t, context);
|
||||
m_cache[2 * i] = res.x1();
|
||||
m_cache[2 * i + 1] = res.x2();
|
||||
}
|
||||
return Poincare::Coordinate2D<float>(m_cache[2 * i], m_cache[2 * i + 1]);
|
||||
}
|
||||
|
||||
void ContinuousFunctionCache::pan(ContinuousFunction * function, float newTMin) {
|
||||
assert(function->plotType() == ContinuousFunction::PlotType::Cartesian);
|
||||
if (newTMin == m_tMin) {
|
||||
return;
|
||||
@@ -120,12 +102,12 @@ void ContinuousFunctionCache::pan(ContinuousFunction * function, Poincare::Conte
|
||||
float dT = (newTMin - m_tMin) / m_tStep;
|
||||
m_tMin = newTMin;
|
||||
if (std::abs(dT) > INT_MAX) {
|
||||
memoize(function, context);
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
int dI = std::round(dT);
|
||||
if (dI >= k_sizeOfCache || dI <= -k_sizeOfCache || std::abs(dT - dI) > k_cacheHitTolerance) {
|
||||
memoize(function, context);
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,17 +118,17 @@ void ContinuousFunctionCache::pan(ContinuousFunction * function, Poincare::Conte
|
||||
}
|
||||
if (dI > 0) {
|
||||
if (m_startOfCache > oldStart) {
|
||||
memoizeYForXBetweenIndices(function, context, oldStart, m_startOfCache);
|
||||
invalidateBetween(oldStart, m_startOfCache);
|
||||
} else {
|
||||
memoizeYForXBetweenIndices(function, context, oldStart, k_sizeOfCache);
|
||||
memoizeYForXBetweenIndices(function, context, 0, m_startOfCache);
|
||||
invalidateBetween(oldStart, k_sizeOfCache);
|
||||
invalidateBetween(0, m_startOfCache);
|
||||
}
|
||||
} else {
|
||||
if (m_startOfCache > oldStart) {
|
||||
memoizeYForXBetweenIndices(function, context, m_startOfCache, k_sizeOfCache);
|
||||
memoizeYForXBetweenIndices(function, context, 0, oldStart);
|
||||
invalidateBetween(m_startOfCache, k_sizeOfCache);
|
||||
invalidateBetween(0, oldStart);
|
||||
} else {
|
||||
memoizeYForXBetweenIndices(function, context, m_startOfCache, oldStart);
|
||||
invalidateBetween(m_startOfCache, oldStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@ public:
|
||||
* function */
|
||||
static constexpr int k_numberOfAvailableCaches = 2;
|
||||
|
||||
static void PrepareCache(void * f, void * ctx, void * cch, float tMin, float tStep);
|
||||
static void PrepareForCaching(void * fun, ContinuousFunctionCache * cache, float tMin, float tStep);
|
||||
|
||||
ContinuousFunctionCache() { clear(); }
|
||||
|
||||
float step() const { return m_tStep; }
|
||||
bool filled() const { return m_filled; }
|
||||
void clear();
|
||||
Poincare::Coordinate2D<float> valueForParameter(const ContinuousFunction * function, float t) const;
|
||||
Poincare::Coordinate2D<float> valueForParameter(const ContinuousFunction * function, Poincare::Context * context, float t);
|
||||
private:
|
||||
/* The size of the cache is chosen to optimize the display of cartesian
|
||||
* function */
|
||||
@@ -29,14 +30,11 @@ private:
|
||||
|
||||
static float StepFactor(ContinuousFunction * function);
|
||||
|
||||
void invalidateBetween(int iInf, int iSup);
|
||||
void setRange(ContinuousFunction * function, float tMin, float tStep);
|
||||
void memoize(ContinuousFunction * function, Poincare::Context * context);
|
||||
void memoizeYForX(ContinuousFunction * function, Poincare::Context * context);
|
||||
void memoizeYForXBetweenIndices(ContinuousFunction * function, Poincare::Context * context, int iInf, int iSup);
|
||||
void memoizeXYForT(ContinuousFunction * function, Poincare::Context * context);
|
||||
float parameterForIndex(int i) const;
|
||||
int indexForParameter(const ContinuousFunction * function, float t) const;
|
||||
void pan(ContinuousFunction * function, Poincare::Context * context, float newTMin);
|
||||
Poincare::Coordinate2D<float> valuesAtIndex(const ContinuousFunction * function, Poincare::Context * context, float t, int i);
|
||||
void pan(ContinuousFunction * function, float newTMin);
|
||||
|
||||
float m_tMin, m_tStep;
|
||||
float m_cache[k_sizeOfCache];
|
||||
@@ -44,7 +42,6 @@ private:
|
||||
* with cartesian functions. When dealing with parametric or polar functions,
|
||||
* m_startOfCache should be zero.*/
|
||||
int m_startOfCache;
|
||||
bool m_filled;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -602,8 +602,7 @@ const uint8_t thickStampMask[(thickStampSize+1)*(thickStampSize+1)] = {
|
||||
|
||||
constexpr static int k_maxNumberOfIterations = 10;
|
||||
|
||||
void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool thick, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, EvaluateXYForDoubleParameter xyDoubleEvaluation, PrepareContinuousFunction functionPreparator, void * cache) const {
|
||||
functionPreparator(model, context, cache, tStart, tStep);
|
||||
void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool thick, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, EvaluateXYForDoubleParameter xyDoubleEvaluation) const {
|
||||
float previousT = NAN;
|
||||
float t = NAN;
|
||||
float previousX = NAN;
|
||||
@@ -635,7 +634,7 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void CurveView::drawCartesianCurve(KDContext * ctx, KDRect rect, float xMin, float xMax, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, KDColor color, bool thick, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, EvaluateXYForDoubleParameter xyDoubleEvaluation, PrepareContinuousFunction functionPreparator, void * cache) const {
|
||||
void CurveView::drawCartesianCurve(KDContext * ctx, KDRect rect, float xMin, float xMax, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, KDColor color, bool thick, bool colorUnderCurve, float colorLowerBound, float colorUpperBound, EvaluateXYForDoubleParameter xyDoubleEvaluation) const {
|
||||
float rectLeft = pixelToFloat(Axis::Horizontal, rect.left() - k_externRectMargin);
|
||||
float rectRight = pixelToFloat(Axis::Horizontal, rect.right() + k_externRectMargin);
|
||||
float tStart = std::isnan(rectLeft) ? xMin : std::max(xMin, rectLeft);
|
||||
@@ -645,7 +644,7 @@ void CurveView::drawCartesianCurve(KDContext * ctx, KDRect rect, float xMin, flo
|
||||
return;
|
||||
}
|
||||
float tStep = pixelWidth();
|
||||
drawCurve(ctx, rect, tStart, tEnd, tStep, xyFloatEvaluation, model, context, true, color, thick, colorUnderCurve, colorLowerBound, colorUpperBound, xyDoubleEvaluation, functionPreparator, cache);
|
||||
drawCurve(ctx, rect, tStart, tEnd, tStep, xyFloatEvaluation, model, context, true, color, thick, colorUnderCurve, colorLowerBound, colorUpperBound, xyDoubleEvaluation);
|
||||
}
|
||||
|
||||
void CurveView::drawHistogram(KDContext * ctx, KDRect rect, EvaluateYForX yEvaluation, void * model, void * context, float firstBarAbscissa, float barWidth,
|
||||
|
||||
@@ -19,7 +19,6 @@ public:
|
||||
typedef Poincare::Coordinate2D<float> (*EvaluateXYForFloatParameter)(float t, void * model, void * context);
|
||||
typedef Poincare::Coordinate2D<double> (*EvaluateXYForDoubleParameter)(double t, void * model, void * context);
|
||||
typedef float (*EvaluateYForX)(float x, void * model, void * context);
|
||||
typedef void (* PrepareContinuousFunction)(void * model, void * context, void * cache, float xMin, float xStep);
|
||||
enum class Axis {
|
||||
Horizontal = 0,
|
||||
Vertical = 1
|
||||
@@ -108,8 +107,8 @@ protected:
|
||||
void drawGrid(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxes(KDContext * ctx, KDRect rect) const;
|
||||
void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const;
|
||||
void drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool thick = true, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, EvaluateXYForDoubleParameter xyDoubleEvaluation = nullptr,PrepareContinuousFunction functionPreparator = [](void * model, void * context, void * cache, float xMin, float xStep) {}, void * cache = nullptr) const;
|
||||
void drawCartesianCurve(KDContext * ctx, KDRect rect, float xMin, float xMax, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, KDColor color, bool thick = true, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, EvaluateXYForDoubleParameter xyDoubleEvaluation = nullptr, PrepareContinuousFunction functionPreparator = [](void * model, void * context, void * cache, float xMin, float xStep) {}, void * cache = nullptr) const;
|
||||
void drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd, float tStep, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, bool drawStraightLinesEarly, KDColor color, bool thick = true, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, EvaluateXYForDoubleParameter xyDoubleEvaluation = nullptr) const;
|
||||
void drawCartesianCurve(KDContext * ctx, KDRect rect, float xMin, float xMax, EvaluateXYForFloatParameter xyFloatEvaluation, void * model, void * context, KDColor color, bool thick = true, bool colorUnderCurve = false, float colorLowerBound = 0.0f, float colorUpperBound = 0.0f, EvaluateXYForDoubleParameter xyDoubleEvaluation = nullptr) const;
|
||||
void drawHistogram(KDContext * ctx, KDRect rect, EvaluateYForX yEvaluation, void * model, void * context, float firstBarAbscissa, float barWidth,
|
||||
bool fillBar, KDColor defaultColor, KDColor highlightColor, float highlightLowerBound = INFINITY, float highlightUpperBound = -INFINITY) const;
|
||||
void computeLabels(Axis axis);
|
||||
|
||||
Reference in New Issue
Block a user