|
|
/*------------------------------------------------------------------------------
|
|
|
-- This file is a part of the ColorMapChart API
|
|
|
-- Copyright (C) 2016, Plasma Physics Laboratory - CNRS
|
|
|
--
|
|
|
-- This program is free software; you can redistribute it and/or modify
|
|
|
-- it under the terms of the GNU General Public License as published by
|
|
|
-- the Free Software Foundation; either version 2 of the License, or
|
|
|
-- (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 General Public License for more details.
|
|
|
--
|
|
|
-- You should have received a copy of the GNU General Public License
|
|
|
-- along with this program; if not, write to the Free Software
|
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
-------------------------------------------------------------------------------*/
|
|
|
/*-- Author : Hugo Winter
|
|
|
-- Mail : hugo.winter@lpp.polytechnique.fr
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
|
|
#include "qcolormapseries.h"
|
|
|
#include <private/qcolormapseries_p.h>
|
|
|
#include <private/abstractdomain_p.h>
|
|
|
#include <QtCharts/QValueAxis>
|
|
|
#include <private/colormapchart_p.h>
|
|
|
#include <QtCharts/QColorMapLegendMarker>
|
|
|
#include <private/charthelpers_p.h>
|
|
|
#include <private/qchart_p.h>
|
|
|
#include <QtGui/QPainter>
|
|
|
#include <cmath>
|
|
|
|
|
|
#include <cmath>
|
|
|
#include <QtConcurrent>
|
|
|
|
|
|
#include "qcolorbaraxis.h"
|
|
|
|
|
|
QT_CHARTS_BEGIN_NAMESPACE
|
|
|
|
|
|
/*!
|
|
|
\internal
|
|
|
|
|
|
Constructs empty series object which is a child of \a parent.
|
|
|
When series object is added to QChart instance ownerships is transferred.
|
|
|
*/
|
|
|
QColorMapSeries::QColorMapSeries(QObject *parent)
|
|
|
: QAbstractSeries(*new QColorMapSeriesPrivate(this), parent)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
\internal
|
|
|
|
|
|
Constructs empty series object which is a child of \a parent.
|
|
|
When series object is added to QChart instance ownerships is transferred.
|
|
|
*/
|
|
|
QColorMapSeries::QColorMapSeries(QColorMapSeriesPrivate &d, QObject *parent)
|
|
|
: QAbstractSeries(d, parent)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
|
|
|
/*!
|
|
|
Destroys the object. Series added to QChart instances are owned by those,
|
|
|
and are destroyed when QChart instances are destroyed.
|
|
|
*/
|
|
|
QColorMapSeries::~QColorMapSeries()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
\fn virtual SeriesType QBoxPlotSeries::type() const
|
|
|
\brief Returns type of series.
|
|
|
\sa QAbstractSeries, SeriesType
|
|
|
*/
|
|
|
QAbstractSeries::SeriesType QColorMapSeries::type() const
|
|
|
{
|
|
|
return QAbstractSeries::SeriesTypeColorMap;
|
|
|
}
|
|
|
|
|
|
|
|
|
/*!
|
|
|
Adds data part \a dataPart to the series.\n
|
|
|
If \a copy is true, adds a copy of the data part instead.
|
|
|
*/
|
|
|
void QColorMapSeries::append(ColorMapDataPart* dataPart, bool copy)
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
if(copy)
|
|
|
d->m_dataParts << new ColorMapDataPart(dataPart);
|
|
|
else
|
|
|
d->m_dataParts << dataPart;
|
|
|
d->recomputeDataRange();
|
|
|
emit dataPartAdded(d->m_dataParts.count() - 1);
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
This is an overloaded function.\n
|
|
|
Adds data parts \a dataParts to the series.\n
|
|
|
If \a copy is true, adds a copy of the data part instead.
|
|
|
*/
|
|
|
void QColorMapSeries::append(const QList<ColorMapDataPart*> &dataParts, bool copy)
|
|
|
{
|
|
|
foreach (ColorMapDataPart* dataPart , dataParts)
|
|
|
append(dataPart,copy);
|
|
|
}
|
|
|
|
|
|
|
|
|
/*!
|
|
|
Returns number of data parts within series.
|
|
|
*/
|
|
|
int QColorMapSeries::count() const
|
|
|
{
|
|
|
Q_D(const QColorMapSeries);
|
|
|
return d->m_dataParts.count();
|
|
|
}
|
|
|
|
|
|
|
|
|
/*!
|
|
|
Stream operator for adding a data part \a point to the series.
|
|
|
\sa append()
|
|
|
*/
|
|
|
QColorMapSeries &QColorMapSeries::operator <<(const ColorMapDataPart &dataPart)
|
|
|
{
|
|
|
append(new ColorMapDataPart(dataPart));
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Stream operator for adding a vector of data parts \a dataParts to the series.
|
|
|
\sa append()
|
|
|
*/
|
|
|
QColorMapSeries &QColorMapSeries::operator <<(const QList<ColorMapDataPart*> &dataParts)
|
|
|
{
|
|
|
append(dataParts);
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns a ColorMapData part containing a uniform grid of data points to be mapped in a ColorMapChart.\n
|
|
|
The rectangle of data returned is determined by \a width and \height,\n
|
|
|
from the position \a xpos , \a ypos (starting at the top left corner of the plot area).\n
|
|
|
When there are more points than pixels, \a strategy is applied to determine which to choose.
|
|
|
*/
|
|
|
void QColorMapSeries::getUniformGrid(double minX, double maxX, double minY, double maxY, int width, int height, QVector<double> &grid, QColorMapSeries::Strategy strategy)
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
d->getUniformGrid(minX, maxX,minY,maxY,width,height, grid, strategy);
|
|
|
}
|
|
|
|
|
|
//void QColorMapSeries::attachAxis(QAbstractAxis *axis)
|
|
|
//{
|
|
|
// axis = static_cast<QColorBarAxis*>();
|
|
|
// if(axis)
|
|
|
// {
|
|
|
|
|
|
// }
|
|
|
// else
|
|
|
// {
|
|
|
// QAbstractSeries::attachAxis(axis);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
/*!
|
|
|
Sets \a pen used for drawing points on the chart. If the pen is not defined, the
|
|
|
pen from chart theme is used.
|
|
|
\sa QChart::setTheme()
|
|
|
*/
|
|
|
void QColorMapSeries::setPen(const QPen &pen)
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
if (d->m_pen != pen)
|
|
|
{
|
|
|
//bool emitColorChanged = d->m_pen.color() != pen.color();
|
|
|
d->m_pen = pen;
|
|
|
emit d->updated();
|
|
|
// if (emitColorChanged)
|
|
|
// emit colorChanged(pen.color());
|
|
|
emit penChanged(pen);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QPen QColorMapSeries::pen() const
|
|
|
{
|
|
|
Q_D(const QColorMapSeries);
|
|
|
if (d->m_pen == QChartPrivate::defaultPen())
|
|
|
return QPen();
|
|
|
else
|
|
|
return d->m_pen;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Sets \a brush used for drawing points on the chart. If the brush is not defined, brush
|
|
|
from chart theme setting is used.
|
|
|
\sa QChart::setTheme()
|
|
|
*/
|
|
|
void QColorMapSeries::setBrush(const QBrush &brush)
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
if (d->m_brush != brush)
|
|
|
{
|
|
|
d->m_brush = brush;
|
|
|
emit d->updated();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QBrush QColorMapSeries::brush() const
|
|
|
{
|
|
|
Q_D(const QColorMapSeries);
|
|
|
if (d->m_brush == QChartPrivate::defaultBrush())
|
|
|
return QBrush();
|
|
|
else
|
|
|
return d->m_brush;
|
|
|
}
|
|
|
|
|
|
//void QColorMapSeries::setColor(const QColor &color)
|
|
|
//{
|
|
|
// QPen p = pen();
|
|
|
// if (p.color() != color)
|
|
|
// {
|
|
|
// p.setColor(color);
|
|
|
// setPen(p);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//QColor QColorMapSeries::color() const
|
|
|
//{
|
|
|
// return pen().color();
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointsVisible(bool visible)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointsVisible != visible)
|
|
|
// {
|
|
|
// d->m_pointsVisible = visible;
|
|
|
// emit d->updated();
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//bool QColorMapSeries::pointsVisible() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// return d->m_pointsVisible;
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointLabelsFormat(const QString &format)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointLabelsFormat != format)
|
|
|
// {
|
|
|
// d->m_pointLabelsFormat = format;
|
|
|
// emit pointLabelsFormatChanged(format);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//QString QColorMapSeries::pointLabelsFormat() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// return d->m_pointLabelsFormat;
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointLabelsVisible(bool visible)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointLabelsVisible != visible)
|
|
|
// {
|
|
|
// d->m_pointLabelsVisible = visible;
|
|
|
// emit pointLabelsVisibilityChanged(visible);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//bool QColorMapSeries::pointLabelsVisible() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// return d->m_pointLabelsVisible;
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointLabelsFont(const QFont &font)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointLabelsFont != font) {
|
|
|
// d->m_pointLabelsFont = font;
|
|
|
// emit pointLabelsFontChanged(font);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//QFont QColorMapSeries::pointLabelsFont() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// return d->m_pointLabelsFont;
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointLabelsColor(const QColor &color)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointLabelsColor != color) {
|
|
|
// d->m_pointLabelsColor = color;
|
|
|
// emit pointLabelsColorChanged(color);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//QColor QColorMapSeries::pointLabelsColor() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color())
|
|
|
// return QPen().color();
|
|
|
// else
|
|
|
// return d->m_pointLabelsColor;
|
|
|
//}
|
|
|
|
|
|
//void QColorMapSeries::setPointLabelsClipping(bool enabled)
|
|
|
//{
|
|
|
// Q_D(QColorMapSeries);
|
|
|
// if (d->m_pointLabelsClipping != enabled) {
|
|
|
// d->m_pointLabelsClipping = enabled;
|
|
|
// emit pointLabelsClippingChanged(enabled);
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
//bool QColorMapSeries::pointLabelsClipping() const
|
|
|
//{
|
|
|
// Q_D(const QColorMapSeries);
|
|
|
// return d->m_pointLabelsClipping;
|
|
|
//}
|
|
|
/*!
|
|
|
Returns the minimum value of the series on the X axis.
|
|
|
*/
|
|
|
double QColorMapSeries::minX()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_minX;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the minimum value of the series on the Y axis.
|
|
|
*/
|
|
|
double QColorMapSeries::minY()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_minY;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the minimum value of the series on the Z axis.
|
|
|
*/
|
|
|
double QColorMapSeries::minZ()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_minZ;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the maximum value of the series on the X axis.
|
|
|
*/
|
|
|
double QColorMapSeries::maxX()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_maxX;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the maximum value of the series on the Y axis.
|
|
|
*/
|
|
|
double QColorMapSeries::maxY()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_maxY;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the maximum value of the series on the Z axis.
|
|
|
*/
|
|
|
double QColorMapSeries::maxZ()
|
|
|
{
|
|
|
Q_D(QColorMapSeries);
|
|
|
return d->m_maxZ;
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
QColorMapSeriesPrivate::QColorMapSeriesPrivate(QColorMapSeries *q)
|
|
|
: QAbstractSeriesPrivate(q),
|
|
|
m_pen(QChartPrivate::defaultPen()),
|
|
|
m_brush(QChartPrivate::defaultBrush()),
|
|
|
m_pointsVisible(false),
|
|
|
m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")), //TODO : change
|
|
|
m_pointLabelsVisible(false),
|
|
|
m_pointLabelsFont(QChartPrivate::defaultFont()),
|
|
|
m_pointLabelsColor(QChartPrivate::defaultPen().color()),
|
|
|
m_pointLabelsClipping(true)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
void QColorMapSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
|
|
|
{
|
|
|
Q_Q(QColorMapSeries);
|
|
|
ColorMapChart *colormap = new ColorMapChart(q,parent);
|
|
|
m_item.reset(colormap);
|
|
|
QAbstractSeriesPrivate::initializeGraphics(parent);
|
|
|
}
|
|
|
|
|
|
void QColorMapSeriesPrivate::initializeDomain()
|
|
|
{
|
|
|
domain()->setRange(m_minX, m_maxX, m_minY, m_maxY);
|
|
|
}
|
|
|
|
|
|
void QColorMapSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
|
|
|
{
|
|
|
// Q_Q(QColorMapSeries);
|
|
|
|
|
|
// const QList<QGradient> gradients = theme->seriesGradients();
|
|
|
// const QList<QColor> colors = theme->seriesColors();
|
|
|
|
|
|
// if (forced || QChartPrivate::defaultPen() == m_pen) {
|
|
|
// QPen pen;
|
|
|
// pen.setColor(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0));
|
|
|
// pen.setWidthF(2);
|
|
|
// q->setPen(pen);
|
|
|
// }
|
|
|
|
|
|
// if (forced || QChartPrivate::defaultBrush() == m_brush) {
|
|
|
// QBrush brush(colors.at(index % colors.size()));
|
|
|
// q->setBrush(brush);
|
|
|
// }
|
|
|
|
|
|
// if (forced || QChartPrivate::defaultPen().color() == m_pointLabelsColor) {
|
|
|
// QColor color = theme->labelBrush().color();
|
|
|
// q->setPointLabelsColor(color);
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
QList<QLegendMarker*> QColorMapSeriesPrivate::createLegendMarkers(QLegend* legend)
|
|
|
{
|
|
|
Q_Q(QColorMapSeries);
|
|
|
QList<QLegendMarker*> list;
|
|
|
return list << new QColorMapLegendMarker(q,legend);
|
|
|
}
|
|
|
|
|
|
void QColorMapSeriesPrivate::initializeAxes()
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
QAbstractAxis::AxisType QColorMapSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
|
|
|
{
|
|
|
Q_UNUSED(orientation);
|
|
|
return QAbstractAxis::AxisTypeValue;
|
|
|
}
|
|
|
|
|
|
QAbstractAxis* QColorMapSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
|
|
|
{
|
|
|
Q_UNUSED(orientation);
|
|
|
return new QValueAxis;
|
|
|
}
|
|
|
|
|
|
|
|
|
void QColorMapSeriesPrivate::getUniformGrid(double minX, double maxX, double minY, double maxY, int width, int height, QVector<double> &grid, QColorMapSeries::Strategy strategy)
|
|
|
{
|
|
|
m_imageHeight = height;
|
|
|
m_imageWidth = width;
|
|
|
m_strategy = strategy;
|
|
|
|
|
|
m_requestedMinX = minX;
|
|
|
m_requestedMaxX = maxX;
|
|
|
m_requestedMinY = minY;
|
|
|
m_requestedMaxY = maxY;
|
|
|
|
|
|
int index=0;
|
|
|
std::generate(grid.begin(),grid.end(),[&index]{return index++;});
|
|
|
|
|
|
QFuture<void> futureWatcher = QtConcurrent::map(grid,[this] (double &index) { return computePixelValue(index); });
|
|
|
|
|
|
futureWatcher.waitForFinished();
|
|
|
}
|
|
|
|
|
|
double QColorMapSeriesPrivate::computePixelValue(double &index)
|
|
|
{
|
|
|
QVector<Point3D> cluster;
|
|
|
cluster.reserve(m_imageHeight*m_imageWidth/1000);
|
|
|
cluster.resize(0);
|
|
|
|
|
|
double dx = (m_requestedMaxX - m_requestedMinX)/m_imageWidth;
|
|
|
double dy = (m_requestedMaxY - m_requestedMinY)/m_imageHeight;
|
|
|
|
|
|
int x = (int)index%m_imageWidth;
|
|
|
int y = (int)index/m_imageWidth;
|
|
|
this->buildCluster(x,y,dx,dy,cluster);
|
|
|
if(m_strategy == QColorMapSeries::LastPixel)
|
|
|
index = this->clusterStrategyLast(cluster);
|
|
|
else if(m_strategy == QColorMapSeries::MeanPixel)
|
|
|
index = this->clusterStrategyMean(cluster);
|
|
|
else if(m_strategy == QColorMapSeries::MedianPixel)
|
|
|
index = this->clusterStrategyMedian(cluster);
|
|
|
|
|
|
return index;//not used
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Recompute the data range on X, Y and Z axes each time a ColorMapDataPart is added to the series.\n
|
|
|
The minimum distance between 2 adjacent values on X and Y axis is added to the maximum on X and Y respectively\n
|
|
|
in order to take account of the width of the last element.
|
|
|
*/
|
|
|
void QColorMapSeriesPrivate::recomputeDataRange()
|
|
|
{
|
|
|
//TODO : if non empty
|
|
|
m_minX = m_dataParts.first()->timesSeries().first();
|
|
|
m_maxX = m_dataParts.last()->timesSeries().last();
|
|
|
|
|
|
m_minY = m_dataParts.last()->ySeries().last();
|
|
|
m_maxY = m_dataParts.last()->ySeries().first();
|
|
|
m_minZ = m_dataParts.first()->dataSeries().first();
|
|
|
m_maxZ = m_dataParts.last()->dataSeries().last();
|
|
|
double minDeltaX=m_maxX-m_minX;
|
|
|
double minDeltaY=m_minY-m_maxY;
|
|
|
foreach(ColorMapDataPart* datapart, m_dataParts)
|
|
|
{
|
|
|
m_minY = qMin(datapart->ySeries().first(),m_minY);
|
|
|
m_maxY = qMax(datapart->ySeries().last(),m_maxY);
|
|
|
for(int i=1;i<datapart->timesSeries().size();i++)
|
|
|
{
|
|
|
double newDeltaX=datapart->timesSeries()[i]-datapart->timesSeries()[i-1];
|
|
|
minDeltaX=qMin(minDeltaX,newDeltaX);
|
|
|
}
|
|
|
for(int i=1;i<datapart->ySeries().size();i++)
|
|
|
{
|
|
|
double newDeltaY=datapart->ySeries()[i]-datapart->ySeries()[i-1];
|
|
|
minDeltaY=qMin(minDeltaY,newDeltaY);
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < datapart->dataSeries().count(); i++)
|
|
|
{
|
|
|
double z = datapart->dataSeries().at(i);
|
|
|
m_minZ = qMin(m_minZ, z);
|
|
|
m_maxZ = qMax(m_maxZ, z);
|
|
|
}
|
|
|
}
|
|
|
m_maxX+=minDeltaX;
|
|
|
m_maxY+=minDeltaY;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the last value (bottom right Z value) of a \a cluster of points passed as argument.
|
|
|
*/
|
|
|
double QColorMapSeriesPrivate::clusterStrategyLast(QVector<Point3D>& cluster)
|
|
|
{
|
|
|
if(!cluster.isEmpty())
|
|
|
return cluster.last().value();
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the mean value (mean Z value) of a \a cluster of points passed as argument.
|
|
|
*/
|
|
|
double QColorMapSeriesPrivate::clusterStrategyMean(QVector<Point3D>& cluster)
|
|
|
{
|
|
|
if(!cluster.isEmpty())
|
|
|
{
|
|
|
double sum=0;
|
|
|
int count =0;
|
|
|
for(int i =0;i<cluster.size();i++)
|
|
|
{
|
|
|
if(!std::isnan(Point3D(cluster.at(i)).value()))
|
|
|
{
|
|
|
sum+= Point3D(cluster.at(i)).value();
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
return (sum/count);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Returns the median value (median Z value) of a \a cluster of points passed as argument.
|
|
|
*/
|
|
|
double QColorMapSeriesPrivate::clusterStrategyMedian(QVector<Point3D>& cluster)
|
|
|
{
|
|
|
if(!cluster.isEmpty())
|
|
|
{
|
|
|
QVector<double> *copy = new QVector<double>();
|
|
|
|
|
|
for(int i =0;i<cluster.size();i++)
|
|
|
{
|
|
|
if(!std::isnan(Point3D(cluster.at(i)).value()))
|
|
|
copy->append(Point3D(cluster.at(i)).value());
|
|
|
}
|
|
|
|
|
|
if(!copy->isEmpty())
|
|
|
{
|
|
|
std::sort(copy->begin(), copy->end());
|
|
|
|
|
|
if(copy->count() & 1) // odd
|
|
|
{
|
|
|
int middle = (copy->count()+1)/2;
|
|
|
return copy->at(middle-1);
|
|
|
}
|
|
|
else //even
|
|
|
{
|
|
|
int middle = copy->count()/2;
|
|
|
return (copy->at(middle-1)+copy->at(middle))/2;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
Computes which data points correspond to the given position and returns the in a \a cluster.
|
|
|
*/
|
|
|
void QColorMapSeriesPrivate::buildCluster(int xpos, int ypos, double dx, double dy, QVector<Point3D>& cluster)
|
|
|
{
|
|
|
foreach(ColorMapDataPart *dataPart, m_dataParts)
|
|
|
{
|
|
|
QPair<int,int> xRange = dataPart->getRange(dataPart->timesSeries(),m_requestedMinX+xpos*dx,m_requestedMinX+(xpos+1)*dx);
|
|
|
QPair<int,int> yRange = dataPart->getRange(dataPart->ySeries(),m_requestedMaxY-(ypos+1)*dy,m_requestedMaxY-ypos*dy);
|
|
|
|
|
|
int timeSeriesSize = dataPart->timesSeries().size();
|
|
|
|
|
|
if(xRange.first != xRange.second && yRange.first != yRange.second)
|
|
|
{
|
|
|
for(int i =xRange.first+1;i<xRange.second;i++)
|
|
|
{
|
|
|
qreal xval=dataPart->timesSeries()[i];
|
|
|
for(int j=yRange.first+1;j<yRange.second;j++)
|
|
|
{
|
|
|
qreal yval=dataPart->ySeries()[j];
|
|
|
qreal val=dataPart->dataSeries()[ i + (timeSeriesSize * j)];
|
|
|
cluster.append(Point3D(xval,yval,val));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void QColorMapSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options,
|
|
|
int duration, QEasingCurve &curve)
|
|
|
{
|
|
|
// ColorMapChart *item = static_cast<ColorMapChart *>(m_item.data());
|
|
|
// Q_ASSERT(item);
|
|
|
// if (item->animation())
|
|
|
// item->animation()->stopAndDestroyLater();
|
|
|
|
|
|
// if (options.testFlag(QChart::SeriesAnimations))
|
|
|
// item->setAnimation(new XYAnimation(item, duration, curve));
|
|
|
// else
|
|
|
// item->setAnimation(0);
|
|
|
QAbstractSeriesPrivate::initializeAnimations(options, duration, curve);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "moc_qcolormapseries.cpp"
|
|
|
#include "moc_qcolormapseries_p.cpp"
|
|
|
|
|
|
QT_CHARTS_END_NAMESPACE
|
|
|
|