mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-25 10:01:38 +08:00
simplification/unification: JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph now use JKQTPAdaptiveFunctionGraphEvaluator to generate sample points
This commit is contained in:
parent
c57c672f78
commit
8c0c8bf62e
@ -24,21 +24,20 @@ private:
|
||||
double a;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
template <class TFUNCGRAPH>
|
||||
void drawExample(QApplication& app, const QString& name) {
|
||||
// 1. create a window that contains a line-edit to edit a function
|
||||
// and a JKQTPlotter to display the function, combine everything in a layout
|
||||
QWidget mainWin;
|
||||
JKQTPlotter* plot=new JKQTPlotter(&mainWin);
|
||||
QWidget* mainWin=new QWidget();
|
||||
mainWin->setWindowTitle(name);
|
||||
JKQTPlotter* plot=new JKQTPlotter(mainWin);
|
||||
QVBoxLayout* layout=new QVBoxLayout;
|
||||
mainWin.setLayout(layout);
|
||||
mainWin->setLayout(layout);
|
||||
layout->addWidget(plot);
|
||||
|
||||
// 2. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
// the function is defined as C++ inline function
|
||||
JKQTPXFunctionLineGraph* func1=new JKQTPXFunctionLineGraph(plot);
|
||||
TFUNCGRAPH* func1=new TFUNCGRAPH(plot);
|
||||
func1->setPlotFunctionFunctor([](double x) { return 0.2*x*x-0.015*x*x*x; });
|
||||
func1->setTitle("C++-inline function $0.2x^2-0.015x^3$");
|
||||
plot->addGraph(func1);
|
||||
@ -46,7 +45,7 @@ int main(int argc, char* argv[])
|
||||
// 3. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
// the function is again defined as C++ inline function, but now uses internal
|
||||
// parameters (handed over to the function as a pointer to QVector<double>
|
||||
JKQTPXFunctionLineGraph* func2=new JKQTPXFunctionLineGraph(plot);
|
||||
TFUNCGRAPH* func2=new TFUNCGRAPH(plot);
|
||||
func2->setPlotFunctionFunctor([](double x, void* params) {
|
||||
QVector<double>* p=static_cast<QVector<double>*>(params);
|
||||
return p->at(0)*sin(2.0*JKQTPSTATISTICS_PI*x*p->at(1));
|
||||
@ -59,7 +58,7 @@ int main(int argc, char* argv[])
|
||||
// 4. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
// the function is again defined as C++ inline function, but now uses external
|
||||
// parameters, which may have any type (here QMap<QString,double)
|
||||
JKQTPXFunctionLineGraph* func3=new JKQTPXFunctionLineGraph(plot);
|
||||
/*TFUNCGRAPH* func3=new TFUNCGRAPH(plot);
|
||||
func3->setPlotFunctionFunctor([](double x, void* params) {
|
||||
QMap<QString,double>* p=static_cast<QMap<QString,double>*>(params);
|
||||
return p->value("amplitude")*sin(2.0*JKQTPSTATISTICS_PI*x*p->value("frequency"));
|
||||
@ -70,32 +69,32 @@ int main(int argc, char* argv[])
|
||||
params3["frequency"]=0.3;
|
||||
func3->setParams(¶ms3);
|
||||
func3->setTitle("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
|
||||
plot->addGraph(func3);
|
||||
plot->addGraph(func3);*/
|
||||
|
||||
// 5. of course the function may also be any C+ funtor object:
|
||||
JKQTPXFunctionLineGraph* func4=new JKQTPXFunctionLineGraph(plot);
|
||||
TFUNCGRAPH* func4=new TFUNCGRAPH(plot);
|
||||
func4->setPlotFunctionFunctor(SincSqr(-8));
|
||||
func4->setTitle("C++ functor $-8*\\sin^2(x)/x^2$");
|
||||
plot->addGraph(func4);
|
||||
|
||||
|
||||
// 6. now we use a JKQTPXFunctionLineGraph to draw a static C function
|
||||
JKQTPXFunctionLineGraph* func5=new JKQTPXFunctionLineGraph(plot);
|
||||
TFUNCGRAPH* func5=new TFUNCGRAPH(plot);
|
||||
func5->setPlotFunctionFunctor(&sinc);
|
||||
func5->setTitle("static C function $10*\\sin(x)/x$");
|
||||
plot->addGraph(func5);
|
||||
|
||||
// 7. finally JKQTPXFunctionLineGraph defines a small set of common functions
|
||||
JKQTPXFunctionLineGraph* func6=new JKQTPXFunctionLineGraph(plot);
|
||||
func6->setSpecialFunction(JKQTPXFunctionLineGraph::Line);
|
||||
TFUNCGRAPH* func6=new TFUNCGRAPH(plot);
|
||||
func6->setSpecialFunction(TFUNCGRAPH::Line);
|
||||
// here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x
|
||||
func6->setParamsV(-1,1.5);
|
||||
func6->setTitle("special function: linear p_0=-1, p_1=1.5");
|
||||
plot->addGraph(func6);
|
||||
|
||||
// 7. finally JKQTPXFunctionLineGraph defines a small set of common functions
|
||||
JKQTPXFunctionLineGraph* func7=new JKQTPXFunctionLineGraph(plot);
|
||||
func7->setSpecialFunction(JKQTPXFunctionLineGraph::Line);
|
||||
TFUNCGRAPH* func7=new TFUNCGRAPH(plot);
|
||||
func7->setSpecialFunction(TFUNCGRAPH::Line);
|
||||
// here we set offset p0=1 and slope p1=-1.5 of the line p0+p1*x by adding these into a column
|
||||
// in the internal datastore and then set that column as parameterColumn for the function graph
|
||||
QVector<double> params;
|
||||
@ -114,10 +113,20 @@ int main(int argc, char* argv[])
|
||||
|
||||
// 4. scale the plot so the graph is contained
|
||||
plot->setXY(-10,10,-10,10);
|
||||
plot->redrawPlot();
|
||||
|
||||
// show window and make it a decent size
|
||||
mainWin.show();
|
||||
mainWin.resize(800,800);
|
||||
mainWin->show();
|
||||
mainWin->resize(800,800);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
drawExample<JKQTPXFunctionLineGraph>(app, "functionplot: JKQTPXFunctionLineGraph");
|
||||
drawExample<JKQTPYFunctionLineGraph>(app, "functionplot: JKQTPYFunctionLineGraph");
|
||||
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ void JKQTPAdaptiveFunctionGraphEvaluator::refine(JKQTPAdaptiveFunctionGraphEvalu
|
||||
if (degree>=maxRefinementDegree) return;
|
||||
const double ta=a->first;
|
||||
const double tb=b->first;
|
||||
const double tmid=ta+(tb-ta)/2.0;
|
||||
const double tmid=ta+(tb-ta)*(0.5 +(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)/5.0);
|
||||
const QPointF pa=a->second;
|
||||
const QPointF pb=b->second;
|
||||
const QPointF pmid(fxy(tmid));
|
||||
|
@ -193,7 +193,7 @@ JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitPolylineIntoPoints(const QVecto
|
||||
\note this implements an incomplete algorithm
|
||||
|
||||
*/
|
||||
JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSimplyfyLineSegemnts(const QVector<QPointF>& points, double maxConsecutiveAngleDegree=1.0);
|
||||
JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSimplyfyLineSegemnts(const QVector<QPointF>& points, double maxConsecutiveAngleDegree=0.2);
|
||||
|
||||
|
||||
/** \brief cleans a polygon by uniting all consecutive points that were closer than distanceThreshold are united
|
||||
|
@ -40,13 +40,13 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent):
|
||||
drawLine=true;
|
||||
fillCurve=false;
|
||||
params=nullptr;
|
||||
minSamples=10;
|
||||
maxRefinementDegree=7;
|
||||
minSamples=50;
|
||||
maxRefinementDegree=5;
|
||||
slopeTolerance=0.005;
|
||||
minPixelPerSample=32;
|
||||
plotRefinement=true;
|
||||
displaySamplePoints=false;
|
||||
data=nullptr;
|
||||
data.clear();
|
||||
|
||||
initLineStyle(parent, parentPlotStyle);
|
||||
initFillStyle(parent, parentPlotStyle);
|
||||
@ -88,7 +88,7 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionTy
|
||||
plotFunction=jkqtpPlotFunctionType();
|
||||
simplePlotFunction=f;
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
|
||||
@ -103,7 +103,7 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f
|
||||
plotFunction=jkqtpPlotFunctionType();
|
||||
simplePlotFunction=std::move(f);
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTPlotter *parent):
|
||||
@ -118,7 +118,7 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::Specia
|
||||
title=title_;
|
||||
functionType=type;
|
||||
setParams(params);
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> ¶ms, const QString &title, JKQTPlotter *parent):
|
||||
@ -129,17 +129,9 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::Specia
|
||||
|
||||
|
||||
JKQTPXFunctionLineGraph::~JKQTPXFunctionLineGraph() {
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::clearData() {
|
||||
while (data!=nullptr) {
|
||||
doublePair* d=data;
|
||||
data=data->next;
|
||||
delete d;
|
||||
}
|
||||
data=nullptr;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setDrawLine(bool __value)
|
||||
{
|
||||
@ -157,7 +149,7 @@ void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(const jkqtpPlotFunctionType
|
||||
plotFunction = __value;
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(const jkqtpSimplePlotFunctionType &__value)
|
||||
@ -166,7 +158,7 @@ void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(const jkqtpSimplePlotFuncti
|
||||
simplePlotFunction=__value;
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpPlotFunctionType &&__value)
|
||||
@ -174,7 +166,7 @@ void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpPlotFunctionType &&__v
|
||||
simplePlotFunction=jkqtpSimplePlotFunctionType();
|
||||
plotFunction = std::move(__value);
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpSimplePlotFunctionType &&__value)
|
||||
@ -183,7 +175,7 @@ void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpSimplePlotFunctionType
|
||||
simplePlotFunction=std::move(__value);
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
jkqtpPlotFunctionType JKQTPXFunctionLineGraph::getPlotFunctionFunctor() const
|
||||
@ -200,7 +192,7 @@ void JKQTPXFunctionLineGraph::setParams(void *__value)
|
||||
{
|
||||
if (this->params != __value) {
|
||||
this->params = __value;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +236,7 @@ void JKQTPXFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
#ifdef JKQTBP_AUTOTIMER
|
||||
JKQTPAutoOutputTimer jkaat(QString("JKQTPXFunctionLineGraph[%1]::createPlotData()").arg(title));
|
||||
#endif
|
||||
clearData();
|
||||
data.clear();
|
||||
if (collectParams) collectParameters();
|
||||
|
||||
if (parent==nullptr) return;
|
||||
@ -254,52 +246,14 @@ void JKQTPXFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, params);
|
||||
else if (simplePlotFunction) func=simplePlotFunction;
|
||||
|
||||
double xmin=parent->getXMin();
|
||||
double xmax=parent->getXMax();
|
||||
double pxmin=transformX(xmin);
|
||||
double pxmax=transformX(xmax);
|
||||
double delta0=(pxmax-pxmin)/static_cast<double>(minSamples);
|
||||
//double logdelta0=(log(xmax)-log(xmin))/static_cast<double>(minSamples);
|
||||
const double xmin=parent->getXMin();
|
||||
const double xmax=parent->getXMax();
|
||||
|
||||
// initially sample function
|
||||
doublePair* d=new doublePair;
|
||||
d->x=xmin;
|
||||
d->f=func(xmin);
|
||||
d->next=nullptr;
|
||||
data=d;
|
||||
/*if (parent && parent->getXAxis()->isLogAxis()) {
|
||||
for (double x=log(xmin)+logdelta0; x<log(xmax); x=x+logdelta0) {
|
||||
d->next = new doublePair;
|
||||
d->next->x=exp(x+(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)*delta0/2.0);
|
||||
d->next->f=func(d->next->x,);
|
||||
d->next->next=nullptr;
|
||||
doublePair* dd=d;
|
||||
d=d->next;
|
||||
refine(dd, d);
|
||||
}
|
||||
} else {*/
|
||||
QVector<double>* dv=static_cast<QVector<double>*>(params);
|
||||
if (functionType==Polynomial && dv && dv->size()<=2) {
|
||||
// we only need the first and last datapoint
|
||||
} else {
|
||||
for (double x=pxmin+delta0; x<pxmax; x=x+delta0) {
|
||||
d->next = new doublePair;
|
||||
d->next->x=parent->p2x(x+(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)*delta0/2.0);
|
||||
d->next->f=func(d->next->x);
|
||||
d->next->next=nullptr;
|
||||
doublePair* dd=d;
|
||||
d=d->next;
|
||||
refine(dd, d);
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
d->next = new doublePair;
|
||||
d->next->x=xmax;
|
||||
d->next->f=func(xmax);
|
||||
d->next->next=nullptr;
|
||||
refine(d, d->next);
|
||||
std::function<QPointF(double)> fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double x) -> QPointF { return plot->transform(x, func(x)); }, this, std::placeholders::_1);
|
||||
|
||||
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
|
||||
data=evaluator.evaluate(xmin, xmax);
|
||||
data=JKQTPSimplyfyLineSegemnts(data);
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::collectParameters()
|
||||
@ -347,40 +301,14 @@ void JKQTPXFunctionLineGraph::collectParameters()
|
||||
}
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::refine(doublePair* a, doublePair* b, unsigned int degree) {
|
||||
if (degree>=maxRefinementDegree) return;
|
||||
double ax=transformX(a->x);
|
||||
double af=transformX(a->f);
|
||||
double bx=transformX(b->x);
|
||||
double bf=transformX(b->f);
|
||||
|
||||
double delta=bx - ax;
|
||||
//double logdelta=log(bx) - log(ax);
|
||||
double xmid=ax+(delta)/2.0;
|
||||
/*if (parent && parent->getXAxis()->isLogAxis()) {
|
||||
xmid=log(a->x)+(logdelta)/2.0;
|
||||
xmid=xmid+(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)*delta/5.0;
|
||||
xmid=exp(xmid);
|
||||
} else {*/
|
||||
xmid=xmid+(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)*delta/5.0; // shake by 10%
|
||||
//}
|
||||
const double realxmid=parent->p2x(xmid);
|
||||
double realfmid = 0.0;
|
||||
if (plotFunction) realfmid=plotFunction(realxmid, params);
|
||||
else if (simplePlotFunction) realfmid=simplePlotFunction(realxmid);
|
||||
const double fmid=transformY(realfmid);
|
||||
const double a1=(fmid - af)/(xmid - ax);
|
||||
const double a2=(bf - fmid)/(bx - xmid);
|
||||
//std::cout<<std::string(degree*2, ' ')<<"refine( ["<<a->x<<", "<<a->f<<"], ["<<xmid<<", "<<fmid<<"], ["<<b->x<<", "<<b->f<<"] ): a1="<<a1<<", a2="<<a2<<" acrit="<<abs(a2/a1)-1.0<<"\n";
|
||||
//std::cout<<std::string(degree*2, ' ')<<"refine(): a1="<<a1<<", a2="<<a2<<" acrit="<<fabs(a2-a1)<<"\n";
|
||||
if (fabs(a2-a1)>slopeTolerance || delta>minPixelPerSample) {
|
||||
doublePair* dmid = new doublePair;
|
||||
dmid->x=realxmid;
|
||||
dmid->f=realfmid;
|
||||
a->next=dmid;
|
||||
dmid->next=b;
|
||||
refine(a, dmid, degree+1);
|
||||
refine(dmid, b, degree+1);
|
||||
void JKQTPXFunctionLineGraph::drawSamplePoints(JKQTPEnhancedPainter& painter) {
|
||||
QColor c=getLineColor();
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
painter.save(); auto __finalpaintsamplepoints=JKQTPFinally([&painter]() {painter.restore();});
|
||||
for (const auto& d: data) {
|
||||
if (JKQTPIsOKFloat(d.x()) && JKQTPIsOKFloat(d.y())) {
|
||||
JKQTPPlotSymbol(painter, d.x(), d.y(), JKQTPCross, 6,1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,34 +345,25 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
eb.setStyle(errorFillStyle);
|
||||
|
||||
|
||||
// double xold=-1;
|
||||
// double yold=-1;
|
||||
// double ypeold=-1;
|
||||
// double ymeold=-1;
|
||||
|
||||
// double x0=transformX(0);
|
||||
// if (parent->getXAxis()->isLogAxis()) x0=transformX(parent->getXAxis()->getMin());
|
||||
double y0=transformY(0);
|
||||
if (parent->getYAxis()->isLogAxis()) y0=transformY(parent->getYAxis()->getMin());
|
||||
bool first=false;
|
||||
doublePair* d=data;
|
||||
//QPainterPath pa, pfill;
|
||||
//QPainterPath pel, pef;
|
||||
QPolygonF filledPolygon, linePolygon, errorLineTop, errorLineBottom;
|
||||
QList<QPointF> epTop, epBottom;
|
||||
double yami=qMin(transformY(parent->getYAxis()->getMin()),transformY(parent->getYAxis()->getMax()));
|
||||
double yama=qMax(transformY(parent->getYAxis()->getMin()),transformY(parent->getYAxis()->getMax()));
|
||||
double dypix=fabs(yama-yami);
|
||||
yami=yami-2*dypix;
|
||||
yama=yama+2*dypix;
|
||||
while (d!=nullptr) {
|
||||
yami=yami-2.0*dypix;
|
||||
yama=yama+2.0*dypix;
|
||||
for (auto it=data.begin(); it!=data.end(); ++it) {
|
||||
const QPointF& d=*it;
|
||||
double x=d.x();
|
||||
double y=d.y();
|
||||
|
||||
double xv=d->x;
|
||||
double yv=d->f;
|
||||
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
||||
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv)) {
|
||||
double x=transformX(xv);
|
||||
double y=transformY(yv);
|
||||
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
|
||||
double xv=backtransformX(x);
|
||||
double yv=backtransformY(y);
|
||||
double ype=0, yme=0;
|
||||
if ((drawErrorLines || drawErrorPolygons) && (static_cast<bool>(errorPlotFunction))) {
|
||||
double e=errorPlotFunction(xv, errorParams);
|
||||
@ -459,7 +378,7 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
if (fillCurve) {
|
||||
if (!first) filledPolygon<<QPointF(x, y0);
|
||||
filledPolygon<<QPointF(x, y);
|
||||
if (!d->next) filledPolygon<<QPointF(x, y0);
|
||||
if (it+1==data.end()) filledPolygon<<QPointF(x, y0);
|
||||
}
|
||||
|
||||
if (drawErrorPolygons && (static_cast<bool>(errorPlotFunction))) {
|
||||
@ -476,20 +395,14 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
errorLineBottom<<QPointF(x, yme);
|
||||
}
|
||||
|
||||
// xold=x;
|
||||
// yold=y;
|
||||
// ypeold=ype;
|
||||
// ymeold=yme;
|
||||
first=true;
|
||||
}
|
||||
d=d->next;
|
||||
}
|
||||
if (drawErrorPolygons) {
|
||||
painter.save(); auto __finalpainterrpoly=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setBrush(eb);
|
||||
painter.setPen(np);
|
||||
QPolygonF poly;
|
||||
//poly << QPointF(xold, ypeold) << QPointF(x, ype)<< QPointF(x, yme) << QPointF(xold, ymeold) ;
|
||||
for (int i=0; i<epTop.size(); i++) {
|
||||
poly<<epTop[i];
|
||||
}
|
||||
@ -504,13 +417,11 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setBrush(b);
|
||||
painter.setPen(np);
|
||||
painter.drawPolygon(filledPolygon, Qt::OddEvenFill);
|
||||
|
||||
}
|
||||
if (drawLine) {
|
||||
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(linePolygon);
|
||||
|
||||
}
|
||||
|
||||
if (drawErrorLines && (static_cast<bool>(errorPlotFunction))) {
|
||||
@ -518,29 +429,10 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setPen(ep);
|
||||
painter.drawPolyline(errorLineTop);
|
||||
painter.drawPolyline(errorLineBottom);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
QColor c=getLineColor();
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
d=data;
|
||||
if (displaySamplePoints) {
|
||||
painter.save(); auto __finalpaintsamplepoints=JKQTPFinally([&painter]() {painter.restore();});
|
||||
while (d!=nullptr) {
|
||||
double xv=d->x;
|
||||
double yv=d->f;
|
||||
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
||||
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv)) {
|
||||
double x=transformX(xv);
|
||||
double y=transformY(yv);
|
||||
JKQTPPlotSymbol(painter, x, y, JKQTPCross, 6,1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
}
|
||||
d=d->next;
|
||||
}
|
||||
|
||||
}
|
||||
if (displaySamplePoints) drawSamplePoints(painter);
|
||||
}
|
||||
drawErrorsAfter(painter);
|
||||
//std::cout<<"plot done\n";
|
||||
@ -642,121 +534,93 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
eb.setStyle(errorFillStyle);
|
||||
|
||||
|
||||
double xold=-1;
|
||||
double yold=-1;
|
||||
double xpeold=-1;
|
||||
double xmeold=-1;
|
||||
|
||||
double x0=transformX(0);
|
||||
if (parent->getXAxis()->isLogAxis()) x0=transformX(parent->getXAxis()->getMin());
|
||||
// double y0=transformY(0);
|
||||
// if (parent->getYAxis()->isLogAxis()) y0=transformY(parent->getYAxis()->getMin());
|
||||
bool first=false;
|
||||
doublePair* d=data;
|
||||
QPolygonF filledPolygon, linePolygon, errorLineTop, errorLineBottom;
|
||||
QList<QPointF> epTop, epBottom;
|
||||
double xami=qMin(transformY(parent->getXAxis()->getMin()),transformY(parent->getXAxis()->getMax()));
|
||||
double xama=qMax(transformY(parent->getXAxis()->getMin()),transformY(parent->getXAxis()->getMax()));
|
||||
double dxpix=fabs(xama-xami);
|
||||
xami=xami-2.0*dxpix;
|
||||
xama=xama+2.0*dxpix;
|
||||
for (auto it=data.begin(); it!=data.end(); ++it) {
|
||||
const QPointF& d=*it;
|
||||
double x=d.x();
|
||||
double y=d.y();
|
||||
|
||||
while (d!=nullptr) {
|
||||
double yv=d->x;
|
||||
double xv=d->f;
|
||||
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
||||
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv)) {
|
||||
double x=transformX(xv);
|
||||
double y=transformY(yv);
|
||||
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
|
||||
double xv=backtransformX(x);
|
||||
double yv=backtransformY(y);
|
||||
double xpe=0, xme=0;
|
||||
if ((drawErrorLines || drawErrorPolygons) && (static_cast<bool>(errorPlotFunction))) {
|
||||
double e=errorPlotFunction(xv, errorParams);
|
||||
double e=errorPlotFunction(yv, errorParams);
|
||||
xpe=transformX(xv+e);
|
||||
xme=transformX(xv-e);
|
||||
xpe=qBound(xami, xpe, xama);
|
||||
xme=qBound(xami, xme, xama);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
double xl1=xold;
|
||||
double yl1=yold;
|
||||
double xl2=x;
|
||||
double yl2=y;
|
||||
x=qBound(xami, x, xama);
|
||||
|
||||
if (fillCurve) {
|
||||
painter.save(); auto __finalpaintfillcurve=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setBrush(b);
|
||||
painter.setPen(np);
|
||||
QPolygonF poly;
|
||||
poly << QPointF(xl1, yl1) << QPointF(xl2, yl2) << QPointF(x0, yl2) << QPointF(x0, yl1);
|
||||
painter.drawConvexPolygon(poly);
|
||||
|
||||
/*pfill.lineTo(x, y);
|
||||
if (d->next==nullptr) { // last datapoint
|
||||
pfill.lineTo(x, y0);
|
||||
}*/
|
||||
if (!first) filledPolygon<<QPointF(x0, y);
|
||||
filledPolygon<<QPointF(x, y);
|
||||
if (it+1==data.end()) filledPolygon<<QPointF(x0, y);
|
||||
}
|
||||
|
||||
if (drawErrorPolygons && (static_cast<bool>(errorPlotFunction))) {
|
||||
painter.save(); auto __finalpainterrorpoly=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setBrush(eb);
|
||||
painter.setPen(np);
|
||||
QPolygonF poly;
|
||||
poly << QPointF(xpeold, yold) << QPointF(xpe, y)<< QPointF(xme, y) << QPointF(xmeold, yold) ;
|
||||
painter.drawConvexPolygon(poly);
|
||||
|
||||
epTop<<QPointF(xpe, y);
|
||||
epBottom<<QPointF(xme, y);
|
||||
}
|
||||
|
||||
if (drawLine) {
|
||||
painter.setPen(p);
|
||||
//pa.lineTo(x, y);
|
||||
painter.drawLine(QLineF(xl1, yl1, xl2, yl2));
|
||||
linePolygon<<QPointF(x, y);
|
||||
}
|
||||
|
||||
if (drawErrorLines && (static_cast<bool>(errorPlotFunction))) {
|
||||
painter.setPen(ep);
|
||||
painter.drawLine(QLineF(xpeold, yold, xpe, y));
|
||||
painter.drawLine(QLineF(xmeold, yold, xme, y));
|
||||
errorLineTop<<QPointF(xpe, y);
|
||||
errorLineBottom<<QPointF(xme, y);
|
||||
}
|
||||
|
||||
//std::cout<<"line ("<<xl1<<", "<<yl1<<") -- ("<<xl2<<", "<<yl2<<")"<<std::endl;
|
||||
} /*else {
|
||||
if (drawLine) {
|
||||
pa.moveTo(x, y);
|
||||
}
|
||||
if (fillCurve) {
|
||||
pfill.moveTo(x, y0);
|
||||
pfill.lineTo(x, y);
|
||||
}
|
||||
}*/
|
||||
xold=x;
|
||||
yold=y;
|
||||
xpeold=xpe;
|
||||
xmeold=xme;
|
||||
first=true;
|
||||
}
|
||||
d=d->next;
|
||||
}
|
||||
/*if (fillCurve) {
|
||||
pfill.closeSubpath();
|
||||
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
||||
if (drawErrorPolygons) {
|
||||
painter.save(); auto __finalpainterrpoly=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setBrush(eb);
|
||||
painter.setPen(np);
|
||||
QPolygonF poly;
|
||||
for (int i=0; i<epTop.size(); i++) {
|
||||
poly<<epTop[i];
|
||||
}
|
||||
for (int i=epBottom.size()-1; i>=0; i--) {
|
||||
poly<<epBottom[i];
|
||||
}
|
||||
painter.drawPolygon(poly, Qt::OddEvenFill);
|
||||
}
|
||||
if (fillCurve) {
|
||||
painter.save(); auto __finalpaintfillc=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setBrush(b);
|
||||
painter.setPen(np);
|
||||
painter.drawPath(pfill);
|
||||
|
||||
painter.drawPolygon(filledPolygon, Qt::OddEvenFill);
|
||||
}
|
||||
|
||||
if (drawLine) {
|
||||
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(p);
|
||||
painter.drawPath(pa);
|
||||
|
||||
}*/
|
||||
|
||||
QColor c=getLineColor();
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
d=data;
|
||||
if (displaySamplePoints) while (d!=nullptr) {
|
||||
double yv=d->x;
|
||||
double xv=d->f;
|
||||
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
|
||||
if (JKQTPIsOKFloat(xv) && JKQTPIsOKFloat(yv)) {
|
||||
double x=transformX(xv);
|
||||
double y=transformY(yv);
|
||||
JKQTPPlotSymbol(painter, x, y, JKQTPCross, 6, 1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
painter.drawPolyline(linePolygon);
|
||||
}
|
||||
d=d->next;
|
||||
|
||||
if (drawErrorLines && (static_cast<bool>(errorPlotFunction))) {
|
||||
painter.save(); auto __finalpainterrline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(ep);
|
||||
painter.drawPolyline(errorLineTop);
|
||||
painter.drawPolyline(errorLineBottom);
|
||||
}
|
||||
|
||||
|
||||
if (displaySamplePoints) drawSamplePoints(painter);
|
||||
}
|
||||
drawErrorsAfter(painter);
|
||||
//std::cout<<"plot done\n";
|
||||
@ -764,7 +628,7 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
|
||||
|
||||
void JKQTPYFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
clearData();
|
||||
data.clear();
|
||||
if (collectParams) collectParameters();
|
||||
|
||||
if (parent==nullptr) return;
|
||||
@ -774,30 +638,14 @@ void JKQTPYFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, params);
|
||||
else if (simplePlotFunction) func=simplePlotFunction;
|
||||
|
||||
double ymin=parent->getYMin();
|
||||
double ymax=parent->getYMax();
|
||||
double delta0=(ymax-ymin)/static_cast<double>(minSamples);
|
||||
const double ymin=parent->getYMin();
|
||||
const double ymax=parent->getYMax();
|
||||
|
||||
// initially sample function
|
||||
doublePair* d=new doublePair;
|
||||
d->x=ymin;
|
||||
d->f=func(ymin);
|
||||
d->next=nullptr;
|
||||
data=d;
|
||||
for (double y=ymin+delta0; y<ymax; y=y+delta0) {
|
||||
d->next = new doublePair;
|
||||
d->next->x=y+(static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5)*delta0/2.0;
|
||||
d->next->f=func(d->next->x);
|
||||
d->next->next=nullptr;
|
||||
doublePair* dd=d;
|
||||
d=d->next;
|
||||
refine(dd, d);
|
||||
}
|
||||
d->next = new doublePair;
|
||||
d->next->x=ymax;
|
||||
d->next->f=func(ymax);
|
||||
d->next->next=nullptr;
|
||||
refine(d, d->next);
|
||||
std::function<QPointF(double)> fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double y) -> QPointF { return plot->transform(func(y), y); }, this, std::placeholders::_1);
|
||||
|
||||
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
|
||||
data=evaluator.evaluate(ymin, ymax);
|
||||
data=JKQTPSimplyfyLineSegemnts(data);
|
||||
|
||||
}
|
||||
|
||||
@ -1094,14 +942,14 @@ void JKQTPXFunctionLineGraph::setErrorPlotFunction(const jkqtpPlotFunctionType &
|
||||
{
|
||||
errorSimplePlotFunction=jkqtpSimplePlotFunctionType();
|
||||
errorPlotFunction=__value;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setErrorPlotFunction(jkqtpPlotFunctionType &&__value)
|
||||
{
|
||||
errorSimplePlotFunction=jkqtpSimplePlotFunctionType();
|
||||
errorPlotFunction = std::move(__value);
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
jkqtpPlotFunctionType JKQTPXFunctionLineGraph::getErrorPlotFunction() const
|
||||
{
|
||||
@ -1112,14 +960,14 @@ void JKQTPXFunctionLineGraph::setErrorPlotFunction(const jkqtpSimplePlotFunction
|
||||
{
|
||||
errorPlotFunction=jkqtpPlotFunctionType();
|
||||
errorSimplePlotFunction=__value;
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setErrorPlotFunction(jkqtpSimplePlotFunctionType &&__value)
|
||||
{
|
||||
errorPlotFunction=jkqtpPlotFunctionType();
|
||||
errorSimplePlotFunction = std::move(__value);
|
||||
clearData();
|
||||
data.clear();
|
||||
}
|
||||
jkqtpSimplePlotFunctionType JKQTPXFunctionLineGraph::getErrorSimplePlotFunction() const
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "jkqtplotter/graphs/jkqtpscatter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
|
||||
#include "jkqtplotter/jkqtplotter_imexport.h"
|
||||
#include "jkqtcommon/jkqtpgeometrytools.h"
|
||||
#include <functional>
|
||||
|
||||
#ifndef jkqtpgraphsevaluatedfunction_H
|
||||
@ -67,7 +68,7 @@ typedef std::function<double(double)> jkqtpSimplePlotFunctionType;
|
||||
|
||||
\image html plot_functionplots.png
|
||||
|
||||
\see \ref JKQTPlotterFunctionPlots, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
|
||||
\see \ref JKQTPlotterFunctionPlots, JKQTPAdaptiveFunctionGraphEvaluator, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
|
||||
Q_OBJECT
|
||||
@ -120,9 +121,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
*/
|
||||
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
|
||||
|
||||
/** \brief clear the data sampled from the function. */
|
||||
void clearData();
|
||||
|
||||
/*! \brief set color, fill color and error color at the same time */
|
||||
void setColor(QColor c);
|
||||
|
||||
@ -287,20 +285,14 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
protected:
|
||||
|
||||
|
||||
struct doublePair {
|
||||
double x;
|
||||
double f;
|
||||
doublePair* next;
|
||||
};
|
||||
/** \brief a linked list holding the datapoints \f$ \left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
|
||||
doublePair* data;
|
||||
/** \brief plot data calculated by createPlotData(), i.e. the datapoints \f$ \mbox{transform}\left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
|
||||
QVector<QPointF> data;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
/** \brief ensure that current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams and ierrorparams */
|
||||
virtual void collectParameters();
|
||||
/** \brief refine datapoints on the function graph between two evaluations \a a and \a b */
|
||||
void refine(doublePair* a, doublePair* b, unsigned int degree=0);
|
||||
|
||||
|
||||
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the plot function */
|
||||
int parameterColumn;
|
||||
@ -366,6 +358,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
QVector<double> iparams;
|
||||
/** \brief internal storage for the current error function parameters for errorPlotFunction (which may stem from different sources, as direct data, a datastore column ...) */
|
||||
QVector<double> ierrorparams;
|
||||
/** \brief draw all the sample points in data as small symbols */
|
||||
void drawSamplePoints(JKQTPEnhancedPainter &painter);
|
||||
};
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
|
||||
|
@ -264,7 +264,7 @@ void JKQTPXYFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, params);
|
||||
else if (simplePlotFunction) func=simplePlotFunction;
|
||||
|
||||
jkqtpSimpleParametricCurveFunctionType fTransformedFunc= std::bind([&](const JKQTPXYFunctionLineGraph* plot, double t) -> QPointF { return plot->transform(func(t)); }, this, std::placeholders::_1);
|
||||
jkqtpSimpleParametricCurveFunctionType fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double t) -> QPointF { return plot->transform(func(t)); }, this, std::placeholders::_1);
|
||||
|
||||
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
|
||||
data=evaluator.evaluate(tmin, tmax);
|
||||
|
Loading…
Reference in New Issue
Block a user