added base graphs für X-Y-Y2- and X-X2-Y-datasets for X- and Y-Range plots

This commit is contained in:
jkriege2 2020-09-18 19:35:53 +02:00
parent b112f9f512
commit 3105d88740
2 changed files with 534 additions and 131 deletions

View File

@ -120,7 +120,7 @@ bool JKQTPGraph::getDataMinMax(int column, double &minx, double &maxx, double &s
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(datastore->getRows(column));
@ -310,7 +310,7 @@ bool JKQTPXYGraph::getXMinMax(double& minx, double& maxx, double& smallestGreate
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
@ -336,7 +336,7 @@ bool JKQTPXYGraph::getYMinMax(double& miny, double& maxy, double& smallestGreate
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
@ -384,7 +384,9 @@ int JKQTPXYGraph::getYColumn() const
return this->yColumn;
}
void JKQTPXYGraph::setYColumn(size_t __value) { this->yColumn = static_cast<int>(__value); }
void JKQTPXYGraph::setYColumn(size_t __value) {
this->yColumn = static_cast<int>(__value);
}
void JKQTPXYGraph::setDataSortOrder(JKQTPXYGraph::DataSortOrder __value)
{
@ -445,7 +447,7 @@ double JKQTPXYGraph::hitTest(const QPointF &posSystem, QPointF *closestSpotSyste
const double baseclassResult=JKQTPPlotElement::hitTest(posSystem, closestSpotSystem, label, mode);
if (JKQTPIsOKFloat(baseclassResult)) return baseclassResult;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
if (!getIndexRange(imin, imax)) return JKQTP_NAN;
@ -548,7 +550,7 @@ void JKQTPSingleColumnGraph::intSortData()
if (parent==nullptr) return ;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
@ -573,7 +575,8 @@ bool JKQTPSingleColumnGraph::getIndexRange(int &imin, int &imax) const
{
if (parent==nullptr) return false;
JKQTPDatastore* datastore=parent->getDatastore();
const JKQTPDatastore* datastore=parent->getDatastore();
if (dataColumn>=0) {
imin=0;
imax=static_cast<int>(datastore->getRows(static_cast<size_t>(dataColumn)));
if (imax<imin) {
@ -583,8 +586,9 @@ bool JKQTPSingleColumnGraph::getIndexRange(int &imin, int &imax) const
}
if (imin<0) imin=0;
if (imax<0) imax=0;
return imin>=0 && imax>=0;
return true;
}
return false;
}
@ -642,19 +646,22 @@ void JKQTPXYGraph::intSortData()
bool JKQTPXYGraph::getIndexRange(int& imin, int& imax) const
{
if (parent==nullptr) return false;
if (xColumn>=0 && yColumn>=0) {
JKQTPDatastore* datastore=parent->getDatastore();
imin=0;
imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
// ensure correct order, i.e. imin<=imax
if (imax<imin) {
int h=imin;
imin=imax;
imax=h;
}
// ranges are always >=0
if (imin<0) imin=0;
if (imax<0) imax=0;
return imin>=0 && imax>=0;
return true;
}
return false;
}
@ -678,3 +685,286 @@ JKQTPPlotObject::DrawMode JKQTPPlotObject::getDrawMode() const
JKQTPPlotObject::~JKQTPPlotObject()
= default;
JKQTPXYYGraph::JKQTPXYYGraph(JKQTBasePlotter *parent):
JKQTPXYGraph(parent), yColumn2(-1)
{
}
bool JKQTPXYYGraph::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero)
{
bool start=true;
miny=0;
maxy=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
for (int i=imin; i<imax; i++) {
const double yv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv)) {
if (start || yv>maxy) maxy=yv;
if (start || yv<miny) miny=yv;
double xvsgz;
xvsgz=yv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double yv2=datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(yv2)) {
if (start || yv2>maxy) maxy=yv2;
if (start || yv2<miny) miny=yv2;
double xvsgz;
xvsgz=yv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
bool JKQTPXYYGraph::usesColumn(int column) const
{
return (column==yColumn2) || JKQTPXYYGraph::usesColumn(column);
}
int JKQTPXYYGraph::getYColumn2() const
{
return yColumn2;
}
double JKQTPXYYGraph::hitTest(const QPointF &posSystem, QPointF *closestSpotSystem, QString *label, JKQTPPlotElement::HitTestMode mode) const
{
if (parent==nullptr) return JKQTP_NAN;
// check base-class implementation and use it, if it returns a vaid value
const double baseclassResult=JKQTPXYGraph::hitTest(posSystem, closestSpotSystem, label, mode);
if (JKQTPIsOKFloat(baseclassResult)) return baseclassResult;
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
if (!getIndexRange(imin, imax)) return JKQTP_NAN;
int closest=-1;
double closedist=JKQTP_NAN;
double closedistsec=JKQTP_NAN;
QPointF closestPos;
QPointF posF=transform(posSystem);
for (int i=imin; i<imax; i++) {
const QPointF x(datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i)), datastore->get(static_cast<size_t>(yColumn2),static_cast<size_t>(i)));
const QPointF xpix = transform(x);
if (JKQTPIsOKFloat(xpix.x())&&JKQTPIsOKFloat(xpix.y())) {
double d=0, dsecondary=0;
switch (mode) {
case HitTestXY: d=sqrt(jkqtp_sqr(xpix.x()-posF.x())+jkqtp_sqr(xpix.y()-posF.y())); dsecondary=0; break;
case HitTestXOnly: d=fabs(xpix.x()-posF.x()); dsecondary=fabs(xpix.y()-posF.y()); break;
case HitTestYOnly: d=fabs(xpix.y()-posF.y()); dsecondary=fabs(xpix.x()-posF.x()); break;
}
if (closest<0 || d<closedist || (jkqtp_approximatelyEqual(d,closedist) && dsecondary<closedistsec)) {
closest=i;
closedist=d;
closedistsec=dsecondary;
closestPos=x;
//qDebug()<<"hitTest("<<posSystem<<"[="<<posF<<"pix]...): found closest="<<closest<<", closedist="<<closedist<<", closedistsec="<<closedistsec<<", closestPos="<<closestPos;
}
}
}
if (closest>=0) {
if (label) *label=formatHitTestDefaultLabel(closestPos.x(), closestPos.y(), closest);
if (closestSpotSystem) *closestSpotSystem=closestPos;
return closedist;
} else {
return JKQTP_NAN;
}
}
void JKQTPXYYGraph::setXYYColumns(size_t xCol, size_t yCol, size_t y2Col)
{
setXYColumns(xCol, yCol);
yColumn2=static_cast<int>(y2Col);
}
void JKQTPXYYGraph::setXYYColumns(int xCol, int yCol, int y2Col)
{
setXYColumns(xCol, yCol);
yColumn2=y2Col;
}
void JKQTPXYYGraph::setYColumn2(int __value)
{
yColumn2=__value;
}
void JKQTPXYYGraph::setYColumn2(size_t __value)
{
yColumn2=static_cast<int>(__value);
}
bool JKQTPXYYGraph::getIndexRange(int &imin, int &imax) const
{
bool ok=JKQTPXYGraph::getIndexRange(imin, imax);
if (ok) {
if (parent==nullptr) return false;
if (yColumn2<0) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
const auto rows=datastore->getRows(static_cast<size_t>(yColumn2));
imax=qMin<int>(imax, rows);
}
return ok;
}
JKQTPXXYGraph::JKQTPXXYGraph(JKQTBasePlotter *parent):
JKQTPXYGraph(parent), xColumn2(-1)
{
}
bool JKQTPXXYGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero)
{
bool start=true;
minx=0;
maxx=0;
smallestGreaterZero=0;
if (parent==nullptr) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
getIndexRange(imin, imax);
for (int i=imin; i<imax; i++) {
const double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv)) {
if (start || xv>maxx) maxx=xv;
if (start || xv<minx) minx=xv;
double xvsgz;
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
const double xv2=datastore->get(static_cast<size_t>(xColumn2),static_cast<size_t>(i));
if (JKQTPIsOKFloat(xv2)) {
if (start || xv2>maxx) maxx=xv2;
if (start || xv2<minx) minx=xv2;
double xvsgz;
xvsgz=xv2; SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
}
bool JKQTPXXYGraph::usesColumn(int column) const
{
return (column==xColumn2) || JKQTPXXYGraph::usesColumn(column);
}
int JKQTPXXYGraph::getXColumn2() const
{
return xColumn2;
}
double JKQTPXXYGraph::hitTest(const QPointF &posSystem, QPointF *closestSpotSystem, QString *label, JKQTPPlotElement::HitTestMode mode) const
{
if (parent==nullptr) return JKQTP_NAN;
// check base-class implementation and use it, if it returns a vaid value
const double baseclassResult=JKQTPXYGraph::hitTest(posSystem, closestSpotSystem, label, mode);
if (JKQTPIsOKFloat(baseclassResult)) return baseclassResult;
const JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=0;
if (!getIndexRange(imin, imax)) return JKQTP_NAN;
int closest=-1;
double closedist=JKQTP_NAN;
double closedistsec=JKQTP_NAN;
QPointF closestPos;
QPointF posF=transform(posSystem);
for (int i=imin; i<imax; i++) {
const QPointF x(datastore->get(static_cast<size_t>(xColumn2),static_cast<size_t>(i)), datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i)));
const QPointF xpix = transform(x);
if (JKQTPIsOKFloat(xpix.x())&&JKQTPIsOKFloat(xpix.y())) {
double d=0, dsecondary=0;
switch (mode) {
case HitTestXY: d=sqrt(jkqtp_sqr(xpix.x()-posF.x())+jkqtp_sqr(xpix.y()-posF.y())); dsecondary=0; break;
case HitTestXOnly: d=fabs(xpix.x()-posF.x()); dsecondary=fabs(xpix.y()-posF.y()); break;
case HitTestYOnly: d=fabs(xpix.y()-posF.y()); dsecondary=fabs(xpix.x()-posF.x()); break;
}
if (closest<0 || d<closedist || (jkqtp_approximatelyEqual(d,closedist) && dsecondary<closedistsec)) {
closest=i;
closedist=d;
closedistsec=dsecondary;
closestPos=x;
//qDebug()<<"hitTest("<<posSystem<<"[="<<posF<<"pix]...): found closest="<<closest<<", closedist="<<closedist<<", closedistsec="<<closedistsec<<", closestPos="<<closestPos;
}
}
}
if (closest>=0) {
if (label) *label=formatHitTestDefaultLabel(closestPos.x(), closestPos.y(), closest);
if (closestSpotSystem) *closestSpotSystem=closestPos;
return closedist;
} else {
return JKQTP_NAN;
}
}
void JKQTPXXYGraph::setXXYColumns(size_t xCol, size_t x2Col, size_t yCol)
{
setXYColumns(xCol, yCol);
xColumn2=static_cast<int>(x2Col);
}
void JKQTPXXYGraph::setXXYColumns(int xCol, int x2Col, int yCol)
{
setXYColumns(xCol, yCol);
xColumn2=x2Col;
}
void JKQTPXXYGraph::setXColumn2(int __value)
{
xColumn2=__value;
}
void JKQTPXXYGraph::setXColumn2(size_t __value)
{
xColumn2=static_cast<int>(__value);
}
bool JKQTPXXYGraph::getIndexRange(int &imin, int &imax) const
{
bool ok=JKQTPXYGraph::getIndexRange(imin, imax);
if (ok) {
if (parent==nullptr) return false;
if (xColumn2<0) return false;
const JKQTPDatastore* datastore=parent->getDatastore();
const auto rows=datastore->getRows(static_cast<size_t>(xColumn2));
imax=qMin<int>(imax, rows);
}
return ok;
}

View File

@ -515,13 +515,13 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPPlotObject: public JKQTPPlotElement {
* ... and overrides/implements the functions:
* - getXMinMax()
* - getYMinMax()
+ - usesColumn()
* - usesColumn()
* .
*
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraph: public JKQTPGraph {
Q_OBJECT
public:
public:
/** \brief specifies how to sort the data in a JKQTPXYGraph before drawing
*
* \image html jkqtplotter_unsorted.png "Unsorted Data"
@ -575,7 +575,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraph: public JKQTPGraph {
* \see See JKQTPPlotElement::hitTest() for details on the function definition!
*/
virtual double hitTest(const QPointF &posSystem, QPointF* closestSpotSystem=nullptr, QString* label=nullptr, HitTestMode mode=HitTestXY) const override;
public slots:
public slots:
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns(size_t xCol, size_t yCol);
/** \brief sets xColumn and yColumn at the same time */
@ -600,7 +600,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraph: public JKQTPGraph {
void setYColumn(int __value);
/*! \copydoc yColumn */
void setYColumn (size_t __value);
protected:
protected:
/** \brief the column that contains the x-component of the datapoints */
int xColumn;
@ -636,6 +636,119 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraph: public JKQTPGraph {
/** \brief This virtual JKQTPGraph descendent extends JKQTPXYGraph to two columns for y-values (e.g. for filled range plots in JKQTPFilledVerticalRangeGraph).
* \ingroup jkqtplotter_basegraphs
*
* \see JKQTPXXYGraph and e.g. JKQTPFilledVerticalRangeGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYYGraph: public JKQTPXYGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPXYYGraph(JKQTBasePlotter* parent=nullptr);
/** \brief get the maximum and minimum y-value of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int column) const override;
/*! \copydoc yColumn2 */
int getYColumn2() const;
/** \copydoc JKQTPXYGraph::hitTest() */
virtual double hitTest(const QPointF &posSystem, QPointF* closestSpotSystem=nullptr, QString* label=nullptr, HitTestMode mode=HitTestXY) const override;
Q_PROPERTY(int yColumn2 READ getYColumn2 WRITE setYColumn2)
public slots:
/** \brief sets xColumn, yColumn and yColumn2 at the same time */
void setXYYColumns(size_t xCol, size_t yCol, size_t y2Col);
/** \brief sets xColumn, yColumn and yColumn2 at the same time */
void setXYYColumns(int xCol, int yCol, int y2Col);
/*! \copydoc yColumn2 */
void setYColumn2(int __value);
/*! \copydoc yColumn2 */
void setYColumn2(size_t __value);
protected:
/** \brief the column that contains the second y-component of the datapoints */
int yColumn2;
/** \brief determines the range of row indexes available in the data columns of this graph
*
* \param[out] imin first usable row-index
* \param[out] imax last usable row-index
* \return \c true on success and \c false if the information is not available
*/
virtual bool getIndexRange(int &imin, int &imax) const;
};
/** \brief This virtual JKQTPGraph descendent extends JKQTPXYGraph to two columns for x-values (e.g. for filled range plots).
* \ingroup jkqtplotter_basegraphs
*
* \see JKQTPXYYGraph and e.g. JKQTPFilledVerticalRangeGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXXYGraph: public JKQTPXYGraph {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPXXYGraph(JKQTBasePlotter* parent=nullptr);
/** \brief get the maximum and minimum x-value of the graph
*
* The result is given in the two parameters which are call-by-reference parameters!
*/
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int column) const override;
/*! \copydoc xColumn2 */
int getXColumn2() const;
/** \copydoc JKQTPXYGraph::hitTest() */
virtual double hitTest(const QPointF &posSystem, QPointF* closestSpotSystem=nullptr, QString* label=nullptr, HitTestMode mode=HitTestXY) const override;
Q_PROPERTY(int xColumn2 READ getXColumn2 WRITE setXColumn2)
public slots:
/** \brief sets xColumn, yColumn and xColumn2 at the same time */
void setXXYColumns(size_t xCol, size_t x2Col, size_t yCol);
/** \brief sets xColumn, yColumn and xColumn2 at the same time */
void setXXYColumns(int xCol, int x2Col, int yCol);
/*! \copydoc yColumn2 */
void setXColumn2(int __value);
/*! \copydoc yColumn2 */
void setXColumn2(size_t __value);
protected:
/** \brief the column that contains the second y-component of the datapoints */
int xColumn2;
/** \brief determines the range of row indexes available in the data columns of this graph
*
* \param[out] imin first usable row-index
* \param[out] imax last usable row-index
* \return \c true on success and \c false if the information is not available
*/
virtual bool getIndexRange(int &imin, int &imax) const;
};