| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- //##########################################################################
- //# #
- //# CLOUDCOMPARE #
- //# #
- //# 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; version 2 or later of the License. #
- //# #
- //# 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. #
- //# #
- //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
- //# #
- //##########################################################################
- #ifndef CC_QCUSTOMPLOT_HEADER
- #define CC_QCUSTOMPLOT_HEADER
- //QCustomPlot
- #ifdef _MSC_VER
- //To get rid of the really annoying warnings about unsafe methods
- #pragma warning( push )
- #pragma warning( disable : 4996 )
- #endif
- #include <qcustomplot.h>
- #ifdef _MSC_VER
- #pragma warning( pop )
- #endif
- //System
- #include <assert.h>
- /*********************************/
- /*** Custom QCustomPlot wigets ***/
- /*********************************/
- //! QCustomPlot: vertical bar with text along side
- class QCPBarsWithText : public QCPBars
- {
- Q_OBJECT
- public:
- QCPBarsWithText(QCPAxis* keyAxis, QCPAxis* valueAxis) : QCPBars(keyAxis,valueAxis), m_textOnTheLeft(false) {}
- void setText(QString text) { m_text = QStringList(text); }
- void appendText(QString text) { m_text.append(text); }
- void setTextAlignment(bool left) { m_textOnTheLeft = left; }
- protected:
-
- QStringList m_text;
- bool m_textOnTheLeft;
-
- // reimplemented virtual draw method
- virtual void draw(QCPPainter *painter)
- {
- if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
- //switch to standard display
- QCPBars::draw(painter);
- int fontHeight = painter->fontMetrics().height();
- if (!data()->isEmpty())
- {
- double& key = data()->begin()->key;
- double& value = data()->begin()->value;
- QPointF P = coordsToPixels(key, value);
- //apply a small shift
- int margin = 5; //in pixels
- if (m_textOnTheLeft)
- margin = -margin;
- P.setX(P.x() + margin);
- //we draw at the 'base' line
- P.setY(P.y() + fontHeight);
- for (int i=0; i<m_text.size(); ++i)
- {
- QPointF Pstart = P;
- if (m_textOnTheLeft)
- Pstart.setX(P.x() - painter->fontMetrics().width(m_text[i]));
- painter->drawText(Pstart,m_text[i]);
- P.setY(P.y() + fontHeight);
- }
- }
- }
- };
- //! QCustomPlot: colored histogram
- class QCPColoredBars : public QCPBars
- {
- Q_OBJECT
- public:
- class QCPColoredBarData : public QCPBarsData
- {
- public:
- QCPColoredBarData()
- : color(Qt::blue)
- {}
- QColor color;
- };
- typedef QMap<double, QCPColoredBarData> QCPColoredBarDataMap;
- QCPColoredBars(QCPAxis *keyAxis, QCPAxis *valueAxis) : QCPBars(keyAxis,valueAxis) {}
-
- void setData(const QVector<double> &key, const QVector<double> &value)
- {
- //no colors? we switch to the standard QCPBars object
- m_coloredData.clear();
- QCPBars::setData(key,value);
- }
- void setData(const QVector<double> &key, const QVector<double> &value, const QVector<QColor>& colors)
- {
- Q_ASSERT(colors.size() == key.size());
- data()->clear(); //we duplicate the structures so that other stuff in QCPBarData works!
- int n = qMin(key.size(), value.size());
- for (int i=0; i<n; ++i)
- {
- QCPColoredBarData newData;
- newData.key = key[i];
- newData.value = value[i];
- if (colors.size() > i)
- newData.color = colors[i];
- m_coloredData.insertMulti(newData.key, newData);
- QCPBars::addData(newData.key,newData.value);
- }
- }
- inline QRect rect() const { return clipRect(); }
- // reimplemented virtual methods:
- virtual void clearData() { QCPBars::data().clear(); m_coloredData.clear(); }
- protected:
- // reimplemented virtual draw method
- virtual void draw(QCPPainter *painter)
- {
- //no colors?
- if (m_coloredData.empty())
- {
- //switch to standard display
- QCPBars::draw(painter);
- }
- if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
- QCPColoredBarDataMap::const_iterator it;
- for (it = m_coloredData.constBegin(); it != m_coloredData.constEnd(); ++it)
- {
- // skip bar if not visible in key axis range:
- if (it.key()+mWidth*0.5 < mKeyAxis.data()->range().lower || it.key()-mWidth*0.5 > mKeyAxis.data()->range().upper)
- continue;
- QRectF barRect = getBarRect(it.key(), it.value().value);
- // draw bar fill:
- if (brush().style() != Qt::NoBrush && brush().color().alpha() != 0)
- {
- QBrush theBrush = brush();
- theBrush.setColor(it.value().color);
-
- applyFillAntialiasingHint(painter);
- painter->setPen(Qt::NoPen);
- painter->setBrush(theBrush);
- painter->drawRect(barRect);
- }
- // draw bar line:
- if (pen().style() != Qt::NoPen && pen().color().alpha() != 0)
- {
- QPen thePen = pen();
- thePen.setColor(it.value().color);
- applyDefaultAntialiasingHint(painter);
- painter->setPen(thePen);
- painter->setBrush(Qt::NoBrush);
- painter->drawPolyline(barRect);
- }
- }
- }
- QCPColoredBarDataMap m_coloredData;
- };
- //! QCustomPlot: selectable cursor interface
- class QCPSelectableCursor : public QCPAbstractPlottable
- {
- Q_OBJECT
- public:
-
- //! Default constructor
- explicit QCPSelectableCursor(QCPAxis *keyAxis, QCPAxis *valueAxis)
- : QCPAbstractPlottable(keyAxis, valueAxis)
- , mCurrentVal(0)
- , mMinVal(0)
- , mMaxVal(0)
- , mLastPos(-1,-1)
- , mLastRadius(0)
- {}
- //! Returns whether the item is "selectable" when the mouse is clicked at a given position
- inline virtual bool isSelectable(QPoint click) const
- {
- if (mLastPos.x() < 0 || mLastPos.y() < 0)
- return false;
- QPoint d = mLastPos - click;
- return (d.x()*d.x() + d.y()*d.y() <= mLastRadius*mLastRadius);
- }
- // getters
- inline double currentVal() const { return mCurrentVal; }
- inline double minVal() const { return mMinVal; }
- inline double maxVal() const { return mMaxVal; }
- inline void range(double& minVal, double& maxVal) const { minVal = mMinVal; maxVal = mMaxVal; }
- // setters
- inline void setCurrentVal(double val) { mCurrentVal = std::max(std::min(val,mMaxVal),mMinVal); }
- inline void setRange(double minVal, double maxVal) { mMinVal = minVal; mMaxVal = maxVal; }
- //! Converts a pixel value (X) to the equivalent key
- inline double pixelToKey(int pixX) const { return keyAxis() ? keyAxis()->pixelToCoord(pixX) : 0; }
- //! Converts a pixel value (Y) to the equivalent value
- inline double pixelToValue(int pixY) const { return valueAxis() ? valueAxis()->pixelToCoord(pixY) : 0; }
- // reimplemented virtual methods:
- virtual void clearData() {}
- double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const override { return -1; } //we don't use the QCP internal selection mechanism!
- protected:
- // reimplemented virtual methods:
- void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const override {}
- QCPRange getKeyRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth) const override { foundRange = false; return QCPRange(); }
- QCPRange getValueRange(bool &foundRange, QCP::SignDomain inSignDomain=QCP::sdBoth, const QCPRange &inKeyRange=QCPRange()) const override { foundRange = false; return QCPRange(); }
- // property members:
- double mCurrentVal;
- double mMinVal,mMaxVal;
- QPoint mLastPos;
- int mLastRadius;
- };
- //! QCustomPlot: greyed areas
- class QCPHiddenArea : public QCPSelectableCursor
- {
- Q_OBJECT
- public:
- explicit QCPHiddenArea(bool leftSide, QCPAxis *keyAxis, QCPAxis *valueAxis)
- : QCPSelectableCursor(keyAxis, valueAxis)
- , mLeftSide(leftSide)
- {
- mPen = QPen(QColor(80, 80, 80),Qt::SolidLine); // dark grey
- mPen.setWidth(2);
- setPen( mPen );
-
- mBrush = QBrush(Qt::white,Qt::SolidPattern); // white
- setBrush( mBrush );
- }
- protected:
- // reimplemented virtual methods:
- virtual void draw(QCPPainter *painter)
- {
- if (!keyAxis())
- return;
- QRect rect = clipRect();
- double currentPosd = keyAxis()->coordToPixel(mCurrentVal);
- if (mLeftSide)
- {
- int x2 = static_cast<int>(ceil(currentPosd));
- //assert(x2 >= rect.x());
- if (x2 < rect.x())
- return;
- rect.setWidth(x2 - rect.x());
- }
- else
- {
- int x1 = static_cast<int>(floor(currentPosd));
- //assert(x1 >= rect.x());
- if (x1 < rect.x())
- return;
- int newWidth = rect.width() - (x1 - rect.x());
- rect.setX(x1);
- rect.setWidth(newWidth);
- }
- // draw greyed rect
- if ( (mLeftSide && mCurrentVal > mMinVal)
- || (!mLeftSide && mCurrentVal < mMaxVal) )
- {
- applyFillAntialiasingHint(painter);
- painter->setPen(Qt::NoPen);
- painter->setBrush(QBrush(QColor(128, 128, 128, 128),Qt::SolidPattern)); // semi-transparent grey
- painter->drawPolygon(rect);
- }
- //draw circle (handle)
- if (pen().style() != Qt::NoPen && pen().color().alpha() != 0)
- {
- //circle
- QPoint C(mLeftSide ? rect.x()+rect.width() : rect.x(), rect.y()+rect.height()/2);
- int r = rect.height() / 10;
- painter->setPen(pen());
- painter->setBrush(brush());
- painter->drawEllipse(C,r,r);
- painter->setPen(QPen(QColor(128, 128, 128, 128),Qt::SolidLine)); // semi-transparent grey
- painter->drawLine(C+QPoint(0,r),C-QPoint(0,r));
- //save last circle position
- mLastPos = C;
- mLastRadius = r;
- }
- else
- {
- //no circle
- mLastPos = QPoint(-1,-1);
- mLastRadius = 0;
- }
- }
- //! Whether the cursor is displayed on the left side or not
- bool mLeftSide;
- };
- //! QCustomPlot: small arrows at the bottom
- class QCPArrow : public QCPSelectableCursor
- {
- Q_OBJECT
- public:
- explicit QCPArrow(QCPAxis *keyAxis, QCPAxis *valueAxis)
- : QCPSelectableCursor(keyAxis, valueAxis)
- {
- mPen.setColor(QColor(128, 128, 0)); // dark yellow
- mPen.setStyle(Qt::SolidLine);
- mPen.setWidth(2);
- setPen( mPen );
-
- mBrush.setColor(QColor(255, 255, 0, 196)); // semi-transparent yellow
- mBrush.setStyle(Qt::SolidPattern);
- setBrush( mBrush );
- }
- //! Sets triangle 'inside' color
- void setColor(int r, int g, int b)
- {
- mBrush.setColor(QColor(r, g, b, 196)); // semi-transparent color
- setBrush( mBrush );
- }
-
- protected:
- // reimplemented virtual methods:
- virtual void draw(QCPPainter *painter)
- {
- if (!keyAxis())
- return;
- QRect rect = clipRect();
- int currentPos = static_cast<int>(keyAxis()->coordToPixel(mCurrentVal));
- int r = rect.height() / 10;
- // draw dashed line
- {
- QPen pen(QColor(128, 128, 128, 128),Qt::DashLine);
- pen.setWidth(1);
- painter->setPen(pen); // semi-transparent grey
- painter->drawLine(QPoint(currentPos,rect.y()+2*r), QPoint(currentPos,rect.y()+rect.height()));
- }
- //draw triangle(handle)
- if (pen().style() != Qt::NoPen && pen().color().alpha() != 0)
- {
- //QPoint O(currentPos,rect.y() + rect.height() - r);
- //QPoint T[3] = { O - QPoint(0,r), O + QPoint(r,r), O + QPoint(-r,r) };
- QPoint O(currentPos,rect.y() + r);
- QPoint T[3] = { O + QPoint(0,r), O - QPoint(r,r), O - QPoint(-r,r) };
- painter->setPen(pen());
- painter->setBrush(brush());
- painter->drawPolygon(T,3);
- //save last circle position
- mLastPos = O;
- mLastRadius = r;
- }
- else
- {
- //no circle
- mLastPos = QPoint(-1,-1);
- mLastRadius = 0;
- }
- }
- };
- #endif //CC_QCUSTOMPLOT_HEADER
|