2018-11-25 21:53:26 +08:00
|
|
|
/*
|
2019-01-20 23:15:10 +08:00
|
|
|
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>)
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This software is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
2019-02-08 00:24:46 +08:00
|
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
2018-11-25 21:53:26 +08:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License (LGPL) for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-12-19 00:13:18 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsbase.h"
|
2018-11-26 03:25:44 +08:00
|
|
|
#include "jkqtplotter/jkqtpbaseplotter.h"
|
2018-11-25 21:53:26 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <iostream>
|
2019-05-30 04:40:02 +08:00
|
|
|
#include "jkqtplotter/jkqtptools.h"
|
2018-12-19 00:13:18 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsimage.h"
|
2018-11-26 03:25:44 +08:00
|
|
|
#include "jkqtplotter/jkqtpbaseelements.h"
|
|
|
|
#include "jkqtplotter/jkqtplotter.h"
|
2018-12-28 05:52:00 +08:00
|
|
|
#include "jkqtpgraphsbase.h"
|
2019-02-08 00:24:46 +08:00
|
|
|
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPPlotElement::JKQTPPlotElement(JKQTBasePlotter* parent):
|
2018-11-25 21:53:26 +08:00
|
|
|
QObject(parent)
|
|
|
|
{
|
|
|
|
title="";
|
|
|
|
visible=true;
|
2019-04-22 19:27:50 +08:00
|
|
|
highlighted=false;
|
|
|
|
parentPlotStyle=-1;
|
2018-11-25 21:53:26 +08:00
|
|
|
setParent(parent);
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPPlotElement::JKQTPPlotElement(JKQTPlotter *parent):
|
2019-04-22 19:27:50 +08:00
|
|
|
JKQTPPlotElement(parent->getPlotter())
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2018-12-28 05:52:00 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPGraph::JKQTPGraph(JKQTBasePlotter* parent):
|
|
|
|
JKQTPPlotElement(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPGraph::JKQTPGraph(JKQTPlotter *parent):
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPPlotElement(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-02-03 21:04:48 +08:00
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
QImage JKQTPPlotElement::generateKeyMarker(QSize size)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
QImage img(size.width(),size.height(),QImage::Format_ARGB32);
|
2019-04-25 01:33:51 +08:00
|
|
|
if (parent) img.fill(Qt::transparent);//->getKeyBackgroundColor());
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
JKQTPEnhancedPainter painter(&img);
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
|
|
|
painter.setRenderHint(QPainter::TextAntialiasing, true);
|
|
|
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
|
|
|
painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
|
|
|
|
QRectF rect(0,0,size.width(),size.height());
|
|
|
|
drawKeyMarker(painter, rect);
|
|
|
|
}
|
|
|
|
return img;
|
|
|
|
}
|
|
|
|
|
2019-02-03 21:04:48 +08:00
|
|
|
void JKQTPPlotElement::setTitle(const QString &__value)
|
|
|
|
{
|
|
|
|
this->title = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString JKQTPPlotElement::getTitle() const
|
|
|
|
{
|
|
|
|
return this->title;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPPlotElement::setVisible(bool __value)
|
|
|
|
{
|
|
|
|
this->visible = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTPPlotElement::isVisible() const
|
|
|
|
{
|
|
|
|
return this->visible;
|
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
void JKQTPPlotElement::setHighlighted(bool __value)
|
|
|
|
{
|
|
|
|
highlighted=__value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JKQTPPlotElement::isHighlighted() const
|
|
|
|
{
|
|
|
|
return highlighted;
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
2018-12-28 05:52:00 +08:00
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPPlotElement::setParent(JKQTBasePlotter* parent) {
|
2018-11-25 21:53:26 +08:00
|
|
|
this->parent=parent;
|
|
|
|
QObject::setParent(parent);
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
void JKQTPPlotElement::setParent(JKQTPlotter *parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-01-26 03:16:04 +08:00
|
|
|
setParent(parent->getPlotter());
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPGraph::getDataMinMax(int column, double &minx, double &maxx, double &smallestGreaterZero)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
bool start=true;
|
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
2019-05-13 04:22:48 +08:00
|
|
|
int imax=static_cast<int>(datastore->getRows(column));
|
2019-02-03 21:04:48 +08:00
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
for (int i=imin; i<imax; i++) {
|
2019-05-06 01:31:20 +08:00
|
|
|
double xv=datastore->get(column,static_cast<size_t>(i));
|
2018-11-25 21:53:26 +08:00
|
|
|
if (start || xv>maxx) maxx=xv;
|
|
|
|
if (start || xv<minx) minx=xv;
|
|
|
|
double xvsgz;
|
|
|
|
xvsgz=xv; SmallestGreaterZeroCompare_xvsgz();
|
|
|
|
start=false;
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPPlotElement::getOutsideSize(JKQTPEnhancedPainter& /*painter*/, int& leftSpace, int& rightSpace, int& topSpace, int& bottomspace) {
|
2018-11-25 21:53:26 +08:00
|
|
|
leftSpace=0;
|
|
|
|
rightSpace=0;
|
|
|
|
topSpace=0;
|
|
|
|
bottomspace=0;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPPlotElement::drawOutside(JKQTPEnhancedPainter& /*painter*/, QRect /*leftSpace*/, QRect /*rightSpace*/, QRect /*topSpace*/, QRect /*bottomSpace*/) {
|
2018-12-28 05:52:00 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
QString JKQTPPlotElement::formatHitTestDefaultLabel(double x, double y, int index, JKQTPDatastore* datastore) const {
|
|
|
|
const JKQTPXGraphErrorData* errgx=dynamic_cast<const JKQTPXGraphErrorData*>(this);
|
|
|
|
QString xerrstr;
|
|
|
|
// retrieve x-error data
|
|
|
|
if (errgx && datastore) {
|
|
|
|
if (errgx->getXErrorColumn()>=0) {
|
|
|
|
if (errgx->getXErrorColumnLower()>=0) {
|
|
|
|
xerrstr=QString("\\:+%1\\:-%2")
|
2019-05-30 04:40:02 +08:00
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3))
|
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumnLower(),static_cast<size_t>(index)), 3));
|
2019-05-06 01:31:20 +08:00
|
|
|
} else {
|
|
|
|
xerrstr=QString("{\\:}{\\pm}%1")
|
2019-05-30 04:40:02 +08:00
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgx->getXErrorColumn(),static_cast<size_t>(index)), 3));
|
2019-05-06 01:31:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// retrieve y-error data
|
|
|
|
const JKQTPYGraphErrorData* errgy=dynamic_cast<const JKQTPYGraphErrorData*>(this);
|
|
|
|
QString yerrstr;
|
|
|
|
if (errgy && datastore) {
|
|
|
|
if (errgy->getYErrorColumn()>=0) {
|
|
|
|
if (errgy->getYErrorColumnLower()>=0) {
|
|
|
|
yerrstr=QString("\\:+%1\\:-%2")
|
2019-05-30 04:40:02 +08:00
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3))
|
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumnLower(),static_cast<size_t>(index)), 3));
|
2019-05-06 01:31:20 +08:00
|
|
|
} else {
|
|
|
|
yerrstr=QString("{\\:}{\\pm}%1")
|
2019-05-30 04:40:02 +08:00
|
|
|
.arg(jkqtp_floattolatexqstr(datastore->get(errgy->getYErrorColumn(),static_cast<size_t>(index)), 3));
|
2019-05-06 01:31:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-30 04:40:02 +08:00
|
|
|
return QString("\\ensuremath{\\left[{\\:}%1%3{\\;},{\\;}%2%4{\\:}\\right]}").arg(jkqtp_floattolatexqstr(x, 3)).arg(jkqtp_floattolatexqstr(y, 3)).arg(xerrstr).arg(yerrstr);
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
double JKQTPPlotElement::hitTest(const QPointF & posSystem, QPointF* closestSpotSystem, QString* label, HitTestMode mode) const
|
|
|
|
{
|
2019-05-11 21:56:11 +08:00
|
|
|
if (parent==nullptr) return JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
int closest=-1;
|
2019-05-11 21:56:11 +08:00
|
|
|
double closedist=JKQTP_NAN;
|
|
|
|
double closedistsec=JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
QPointF closestPos;
|
|
|
|
QPointF posF=transform(posSystem);
|
|
|
|
for (int i=0; i<m_hitTestData.count(); i++) {
|
|
|
|
const QPointF x=m_hitTestData[i].pos;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (closest>=0) {
|
|
|
|
if (closestSpotSystem) *closestSpotSystem=closestPos;
|
|
|
|
if (label) *label=m_hitTestData[closest].label;
|
|
|
|
return closedist;
|
|
|
|
} else {
|
2019-05-11 21:56:11 +08:00
|
|
|
return JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
double JKQTPPlotElement::transformX(double x) const {
|
2019-01-26 03:16:04 +08:00
|
|
|
return parent->getXAxis()->x2p(x);
|
2018-12-28 05:52:00 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
double JKQTPPlotElement::transformY(double y) const {
|
2019-01-26 03:16:04 +08:00
|
|
|
return parent->getYAxis()->x2p(y);
|
2018-12-28 05:52:00 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
double JKQTPPlotElement::backtransformX(double x) const {
|
2019-01-26 03:16:04 +08:00
|
|
|
return parent->getXAxis()->p2x(x);
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
double JKQTPPlotElement::backtransformY(double y) const {
|
2019-01-26 03:16:04 +08:00
|
|
|
return parent->getYAxis()->p2x(y);
|
2018-12-28 05:52:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPGraph::usesColumn(int /*column*/) const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPGraph::drawErrorsBefore(JKQTPEnhancedPainter &)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPGraph::drawErrorsAfter(JKQTPEnhancedPainter &)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
QVector<QPointF> JKQTPPlotElement::transform(const QVector<QPointF> &x) const {
|
2018-12-28 05:52:00 +08:00
|
|
|
QVector<QPointF> res;
|
|
|
|
for (int i=0; i<x.size(); i++) {
|
|
|
|
res.append(transform(x[i]));
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
QPainterPath JKQTPPlotElement::transformToLinePath(const QVector<QPointF> &x) const {
|
2018-12-28 05:52:00 +08:00
|
|
|
QPainterPath res;
|
|
|
|
if (x.size()>0) {
|
|
|
|
res.moveTo(transform(x[0]));
|
|
|
|
for (int i=1; i<x.size(); i++) {
|
|
|
|
res.lineTo(transform(x[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPXYGraph::JKQTPXYGraph(JKQTBasePlotter* parent):
|
|
|
|
JKQTPGraph(parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortData=Unsorted;
|
|
|
|
xColumn=-1;
|
|
|
|
yColumn=-1;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPXYGraph::JKQTPXYGraph(JKQTPlotter *parent):
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPGraph(parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortData=Unsorted;
|
|
|
|
xColumn=-1;
|
|
|
|
yColumn=-1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPXYGraph::getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
minx=0;
|
|
|
|
maxx=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
2019-05-06 01:31:20 +08:00
|
|
|
int imax=0;
|
|
|
|
getIndexRange(imin, imax);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=imin; i<imax; i++) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPXYGraph::getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) {
|
2018-11-25 21:53:26 +08:00
|
|
|
bool start=true;
|
|
|
|
miny=0;
|
|
|
|
maxy=0;
|
|
|
|
smallestGreaterZero=0;
|
|
|
|
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
2019-05-06 01:31:20 +08:00
|
|
|
int imax=0;
|
|
|
|
getIndexRange(imin, imax);
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=imin; i<imax; i++) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return !start;
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
bool JKQTPXYGraph::usesColumn(int column) const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
return (column==xColumn)||(column==yColumn);
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
void JKQTPXYGraph::setXColumn(int __value)
|
|
|
|
{
|
|
|
|
this->xColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPXYGraph::getXColumn() const
|
|
|
|
{
|
|
|
|
return this->xColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXColumn(size_t __value) {
|
|
|
|
this->xColumn = static_cast<int>(__value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setYColumn(int __value)
|
|
|
|
{
|
|
|
|
this->yColumn = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
int JKQTPXYGraph::getYColumn() const
|
|
|
|
{
|
|
|
|
return this->yColumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setYColumn(size_t __value) { this->yColumn = static_cast<int>(__value); }
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setDataSortOrder(JKQTPXYGraph::DataSortOrder __value)
|
|
|
|
{
|
|
|
|
this->sortData = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTPXYGraph::DataSortOrder JKQTPXYGraph::getDataSortOrder() const
|
|
|
|
{
|
|
|
|
return this->sortData;
|
|
|
|
}
|
|
|
|
|
2019-02-03 21:04:48 +08:00
|
|
|
void JKQTPXYGraph::setDataSortOrder(int __value) {
|
2019-05-06 01:31:20 +08:00
|
|
|
sortData=static_cast<DataSortOrder>(__value);
|
|
|
|
}
|
|
|
|
|
2019-05-13 04:22:48 +08:00
|
|
|
void JKQTPXYGraph::setXYColumns(size_t xCol, size_t yCol)
|
|
|
|
{
|
|
|
|
setXColumn(xCol);
|
|
|
|
setYColumn(yCol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXYColumns(int xCol, int yCol)
|
|
|
|
{
|
|
|
|
setXColumn(xCol);
|
|
|
|
setYColumn(yCol);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXYColumns(std::pair<int, int> xyColPair)
|
|
|
|
{
|
|
|
|
setXColumn(xyColPair.first);
|
|
|
|
setYColumn(xyColPair.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXYColumns(std::pair<size_t, size_t> xyColPair)
|
|
|
|
{
|
|
|
|
setXColumn(xyColPair.first);
|
|
|
|
setYColumn(xyColPair.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXYColumns(QPair<int, int> xyColPair)
|
|
|
|
{
|
|
|
|
setXColumn(xyColPair.first);
|
|
|
|
setYColumn(xyColPair.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JKQTPXYGraph::setXYColumns(QPair<size_t, size_t> xyColPair)
|
|
|
|
{
|
|
|
|
setXColumn(xyColPair.first);
|
|
|
|
setYColumn(xyColPair.second);
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
double JKQTPXYGraph::hitTest(const QPointF &posSystem, QPointF *closestSpotSystem, QString *label, HitTestMode mode) const
|
|
|
|
{
|
2019-05-11 21:56:11 +08:00
|
|
|
if (parent==nullptr) return JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
// check base-class implementation and use it, if it returns a vaid value
|
|
|
|
const double baseclassResult=JKQTPPlotElement::hitTest(posSystem, closestSpotSystem, label, mode);
|
|
|
|
if (JKQTPIsOKFloat(baseclassResult)) return baseclassResult;
|
|
|
|
|
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
|
|
|
int imin=0;
|
|
|
|
int imax=0;
|
2019-05-11 21:56:11 +08:00
|
|
|
if (!getIndexRange(imin, imax)) return JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
int closest=-1;
|
2019-05-11 21:56:11 +08:00
|
|
|
double closedist=JKQTP_NAN;
|
|
|
|
double closedistsec=JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
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>(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 {
|
2019-05-11 21:56:11 +08:00
|
|
|
return JKQTP_NAN;
|
2019-05-06 01:31:20 +08:00
|
|
|
}
|
2018-12-28 05:52:00 +08:00
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPSingleColumnGraph::JKQTPSingleColumnGraph(JKQTBasePlotter *parent):
|
|
|
|
JKQTPGraph(parent)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortData=Unsorted;
|
|
|
|
dataColumn=-1;
|
|
|
|
}
|
|
|
|
|
2019-02-08 00:24:46 +08:00
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
JKQTPSingleColumnGraph::JKQTPSingleColumnGraph(JKQTPlotter *parent):
|
|
|
|
JKQTPSingleColumnGraph(parent->getPlotter())
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
void JKQTPSingleColumnGraph::setDataColumn(int __value)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
this->dataColumn = __value;
|
2019-05-30 04:40:02 +08:00
|
|
|
if (this->title.size()==0 && parent && __value>=0) this->title=parent->getDatastore()->getColumnName(static_cast<size_t>(__value));
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
int JKQTPSingleColumnGraph::getDataColumn() const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
return this->dataColumn;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPSingleColumnGraph::setDataColumn(size_t __value) {
|
|
|
|
this->dataColumn = static_cast<int>(__value);
|
2019-05-30 04:40:02 +08:00
|
|
|
if (this->title.size()==0 && parent) this->title=parent->getDatastore()->getColumnName(__value);
|
2019-04-22 23:19:52 +08:00
|
|
|
}
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2019-04-22 23:19:52 +08:00
|
|
|
void JKQTPSingleColumnGraph::setDataSortOrder(JKQTPSingleColumnGraph::DataSortOrder __value)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
this->sortData = __value;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
JKQTPSingleColumnGraph::DataSortOrder JKQTPSingleColumnGraph::getDataSortOrder() const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
return this->sortData;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-02-03 21:04:48 +08:00
|
|
|
void JKQTPSingleColumnGraph::setDataSortOrder(int __value) {
|
2019-05-06 01:31:20 +08:00
|
|
|
sortData=static_cast<DataSortOrder>(__value);
|
2018-12-28 05:52:00 +08:00
|
|
|
if (__value>0) sortData=Sorted;
|
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
void JKQTPSingleColumnGraph::setDataDirection(JKQTPSingleColumnGraph::DataDirection __value)
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
this->dataDirection = __value;
|
|
|
|
}
|
|
|
|
|
|
|
|
JKQTPSingleColumnGraph::DataDirection JKQTPSingleColumnGraph::getDataDirection() const
|
|
|
|
{
|
|
|
|
return this->dataDirection;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
bool JKQTPSingleColumnGraph::usesColumn(int c) const
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
2019-04-22 19:27:50 +08:00
|
|
|
return c==dataColumn;
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
|
2019-04-22 19:27:50 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPSingleColumnGraph::intSortData()
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortedIndices.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parent==nullptr) return ;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
2019-05-06 01:31:20 +08:00
|
|
|
int imax=0;
|
|
|
|
getIndexRange(imin, imax);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
QVector<double> datas;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
if (sortData==JKQTPSingleColumnGraph::Sorted) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=0; i<imax; i++) {
|
2019-05-06 01:31:20 +08:00
|
|
|
double xv=datastore->get(dataColumn,static_cast<size_t>(i));
|
2018-11-25 21:53:26 +08:00
|
|
|
sortedIndices<<i;
|
|
|
|
datas<<xv;
|
|
|
|
}
|
|
|
|
|
2019-05-23 04:20:00 +08:00
|
|
|
jkqtpQuicksortDual(datas.data(), sortedIndices.data(), datas.size());
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
bool JKQTPSingleColumnGraph::getIndexRange(int &imin, int &imax) const
|
|
|
|
{
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
|
|
|
imin=0;
|
2019-05-13 04:22:48 +08:00
|
|
|
imax=static_cast<int>(datastore->getRows(static_cast<size_t>(dataColumn)));
|
2019-05-06 01:31:20 +08:00
|
|
|
if (imax<imin) {
|
|
|
|
int h=imin;
|
|
|
|
imin=imax;
|
|
|
|
imax=h;
|
|
|
|
}
|
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
return imin>=0 && imax>=0;
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
void JKQTPXYGraph::intSortData()
|
2018-11-25 21:53:26 +08:00
|
|
|
{
|
|
|
|
sortedIndices.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parent==nullptr) return ;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
2018-11-25 21:53:26 +08:00
|
|
|
int imin=0;
|
2019-05-06 01:31:20 +08:00
|
|
|
int imax=0;
|
|
|
|
getIndexRange(imin, imax);
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
QVector<double> datas;
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
if (sortData==JKQTPXYLineGraph::SortedX) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=0; i<imax; i++) {
|
|
|
|
double xv=datastore->get(static_cast<size_t>(xColumn),static_cast<size_t>(i));
|
|
|
|
sortedIndices<<i;
|
|
|
|
datas<<xv;
|
|
|
|
}
|
|
|
|
|
2019-05-23 04:20:00 +08:00
|
|
|
jkqtpQuicksortDual(datas.data(), sortedIndices.data(), datas.size());
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
} else if (sortData==JKQTPXYLineGraph::SortedY) {
|
2018-11-25 21:53:26 +08:00
|
|
|
|
|
|
|
for (int i=0; i<imax; i++) {
|
|
|
|
double xv=datastore->get(static_cast<size_t>(yColumn),static_cast<size_t>(i));
|
|
|
|
sortedIndices<<i;
|
|
|
|
datas<<xv;
|
|
|
|
}
|
|
|
|
|
2019-05-23 04:20:00 +08:00
|
|
|
jkqtpQuicksortDual(datas.data(), sortedIndices.data(), datas.size());
|
2018-11-25 21:53:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-06 01:31:20 +08:00
|
|
|
bool JKQTPXYGraph::getIndexRange(int& imin, int& imax) const
|
|
|
|
{
|
|
|
|
if (parent==nullptr) return false;
|
|
|
|
|
|
|
|
JKQTPDatastore* datastore=parent->getDatastore();
|
|
|
|
imin=0;
|
2019-05-13 04:22:48 +08:00
|
|
|
imax=static_cast<int>(qMin(datastore->getRows(static_cast<size_t>(xColumn)), datastore->getRows(static_cast<size_t>(yColumn))));
|
2019-05-06 01:31:20 +08:00
|
|
|
if (imax<imin) {
|
|
|
|
int h=imin;
|
|
|
|
imin=imax;
|
|
|
|
imax=h;
|
|
|
|
}
|
|
|
|
if (imin<0) imin=0;
|
|
|
|
if (imax<0) imax=0;
|
|
|
|
|
|
|
|
return imin>=0 && imax>=0;
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:53:26 +08:00
|
|
|
|
2018-12-28 05:52:00 +08:00
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPPlotObject::JKQTPPlotObject(JKQTBasePlotter *parent):
|
|
|
|
JKQTPPlotElement(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPPlotObject::JKQTPPlotObject(JKQTPlotter *parent):
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPPlotElement(parent)
|
2018-12-28 05:52:00 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:49:29 +08:00
|
|
|
JKQTPPlotObject::~JKQTPPlotObject()
|
2019-01-26 19:28:44 +08:00
|
|
|
= default;
|