|
20 | 20 | #include <QPainter> |
21 | 21 | #include <QVBoxLayout> |
22 | 22 | #include <QMouseEvent> |
| 23 | +#include <algorithm> |
23 | 24 |
|
24 | 25 | // QWT Charting widget |
25 | 26 | #include <qwt_global.h> |
|
34 | 35 | #include <qwt_symbol.h> |
35 | 36 | #include <qwt_legend.h> |
36 | 37 |
|
| 38 | +#if defined(QWT_VERSION) && QWT_VERSION>=0x060000 |
| 39 | +#include <qwt_plot_renderer.h> |
| 40 | +#include <qwt_plot_histogram.h> |
| 41 | +#else |
| 42 | +#include "../raster/qwt5_histogram_item.h" |
| 43 | +#endif |
| 44 | + |
37 | 45 | QgsCurveEditorWidget::QgsCurveEditorWidget( QWidget* parent, const QgsCurveTransform& transform ) |
38 | 46 | : QWidget( parent ) |
39 | 47 | , mCurve( transform ) |
@@ -86,13 +94,70 @@ QgsCurveEditorWidget::QgsCurveEditorWidget( QWidget* parent, const QgsCurveTrans |
86 | 94 | updatePlot(); |
87 | 95 | } |
88 | 96 |
|
| 97 | +QgsCurveEditorWidget::~QgsCurveEditorWidget() |
| 98 | +{ |
| 99 | + if ( mGatherer && mGatherer->isRunning() ) |
| 100 | + { |
| 101 | + connect( mGatherer.get(), &QgsHistogramValuesGatherer::finished, mGatherer.get(), &QgsHistogramValuesGatherer::deleteLater ); |
| 102 | + mGatherer->stop(); |
| 103 | + ( void )mGatherer.release(); |
| 104 | + } |
| 105 | +} |
| 106 | + |
89 | 107 | void QgsCurveEditorWidget::setCurve( const QgsCurveTransform& curve ) |
90 | 108 | { |
91 | 109 | mCurve = curve; |
92 | 110 | updatePlot(); |
93 | 111 | emit changed(); |
94 | 112 | } |
95 | 113 |
|
| 114 | +void QgsCurveEditorWidget::setHistogramSource( const QgsVectorLayer* layer, const QString& expression ) |
| 115 | +{ |
| 116 | + if ( !mGatherer ) |
| 117 | + { |
| 118 | + mGatherer.reset( new QgsHistogramValuesGatherer() ); |
| 119 | + connect( mGatherer.get(), &QgsHistogramValuesGatherer::calculatedHistogram, this, [=] |
| 120 | + { |
| 121 | + mHistogram.reset( new QgsHistogram( mGatherer->histogram() ) ); |
| 122 | + updateHistogram(); |
| 123 | + } ); |
| 124 | + } |
| 125 | + |
| 126 | + bool changed = mGatherer->layer() != layer || mGatherer->expression() != expression; |
| 127 | + if ( changed ) |
| 128 | + { |
| 129 | + mGatherer->setExpression( expression ); |
| 130 | + mGatherer->setLayer( layer ); |
| 131 | + mGatherer->start(); |
| 132 | + if ( mGatherer->isRunning() ) |
| 133 | + { |
| 134 | + //stop any currently running task |
| 135 | + mGatherer->stop(); |
| 136 | + while ( mGatherer->isRunning() ) |
| 137 | + { |
| 138 | + QCoreApplication::processEvents(); |
| 139 | + } |
| 140 | + } |
| 141 | + mGatherer->start(); |
| 142 | + } |
| 143 | + else |
| 144 | + { |
| 145 | + updateHistogram(); |
| 146 | + } |
| 147 | +} |
| 148 | + |
| 149 | +void QgsCurveEditorWidget::setMinHistogramValueRange( double minValueRange ) |
| 150 | +{ |
| 151 | + mMinValueRange = minValueRange; |
| 152 | + updateHistogram(); |
| 153 | +} |
| 154 | + |
| 155 | +void QgsCurveEditorWidget::setMaxHistogramValueRange( double maxValueRange ) |
| 156 | +{ |
| 157 | + mMaxValueRange = maxValueRange; |
| 158 | + updateHistogram(); |
| 159 | +} |
| 160 | + |
96 | 161 | void QgsCurveEditorWidget::keyPressEvent( QKeyEvent* event ) |
97 | 162 | { |
98 | 163 | if ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace ) |
@@ -205,6 +270,63 @@ void QgsCurveEditorWidget::addPlotMarker( double x, double y, bool isSelected ) |
205 | 270 | mMarkers << marker; |
206 | 271 | } |
207 | 272 |
|
| 273 | +void QgsCurveEditorWidget::updateHistogram() |
| 274 | +{ |
| 275 | + if ( !mHistogram ) |
| 276 | + return; |
| 277 | + |
| 278 | + //draw histogram |
| 279 | + QBrush histoBrush( QColor( 0, 0, 0, 70 ) ); |
| 280 | + |
| 281 | +#if defined(QWT_VERSION) && QWT_VERSION>=0x060000 |
| 282 | + delete mPlotHistogram; |
| 283 | + mPlotHistogram = createPlotHistogram( histoBrush ); |
| 284 | + QVector<QwtIntervalSample> dataHisto; |
| 285 | +#else |
| 286 | + delete mPlotHistogramItem; |
| 287 | + mPlotHistogramItem = createHistoItem( histoBrush ); |
| 288 | + QwtArray<QwtDoubleInterval> intervalsHisto; |
| 289 | + QwtArray<double> valuesHisto; |
| 290 | +#endif |
| 291 | + |
| 292 | + int bins = 40; |
| 293 | + QList<double> edges = mHistogram->binEdges( bins ); |
| 294 | + QList<int> counts = mHistogram->counts( bins ); |
| 295 | + |
| 296 | + // scale counts to 0->1 |
| 297 | + double max = *std::max_element( counts.constBegin(), counts.constEnd() ); |
| 298 | + |
| 299 | + // scale bin edges to fit in 0->1 range |
| 300 | + if ( !qgsDoubleNear( mMinValueRange, mMaxValueRange ) ) |
| 301 | + { |
| 302 | + std::transform( edges.begin(), edges.end(), edges.begin(), |
| 303 | + [this]( double d ) -> double { return ( d - mMinValueRange ) / ( mMaxValueRange - mMinValueRange ); } ); |
| 304 | + } |
| 305 | + |
| 306 | + for ( int bin = 0; bin < bins; ++bin ) |
| 307 | + { |
| 308 | + double binValue = counts.at( bin ) / max; |
| 309 | + |
| 310 | + double upperEdge = edges.at( bin + 1 ); |
| 311 | + |
| 312 | +#if defined(QWT_VERSION) && QWT_VERSION>=0x060000 |
| 313 | + dataHisto << QwtIntervalSample( binValue, edges.at( bin ), upperEdge ); |
| 314 | +#else |
| 315 | + intervalsHisto.append( QwtDoubleInterval( edges.at( bin ), upperEdge ) ); |
| 316 | + valuesHisto.append( double( binValue ) ); |
| 317 | +#endif |
| 318 | + } |
| 319 | + |
| 320 | +#if defined(QWT_VERSION) && QWT_VERSION>=0x060000 |
| 321 | + mPlotHistogram->setSamples( dataHisto ); |
| 322 | + mPlotHistogram->attach( mPlot ); |
| 323 | +#else |
| 324 | + mPlotHistogramItem->setData( QwtIntervalData( intervalsHisto, valuesHisto ) ); |
| 325 | + mPlotHistogramItem->attach( mPlot ); |
| 326 | +#endif |
| 327 | + mPlot->replot(); |
| 328 | +} |
| 329 | + |
208 | 330 | void QgsCurveEditorWidget::updatePlot() |
209 | 331 | { |
210 | 332 | // remove existing markers |
@@ -249,6 +371,52 @@ void QgsCurveEditorWidget::updatePlot() |
249 | 371 | } |
250 | 372 |
|
251 | 373 |
|
| 374 | +#if defined(QWT_VERSION) && QWT_VERSION>=0x060000 |
| 375 | +QwtPlotHistogram* QgsCurveEditorWidget::createPlotHistogram( const QBrush& brush, const QPen& pen ) const |
| 376 | +{ |
| 377 | + QwtPlotHistogram* histogram = new QwtPlotHistogram( QString() ); |
| 378 | + histogram->setBrush( brush ); |
| 379 | + if ( pen != Qt::NoPen ) |
| 380 | + { |
| 381 | + histogram->setPen( pen ); |
| 382 | + } |
| 383 | + else if ( brush.color().lightness() > 200 ) |
| 384 | + { |
| 385 | + QPen p; |
| 386 | + p.setColor( brush.color().darker( 150 ) ); |
| 387 | + p.setWidth( 0 ); |
| 388 | + p.setCosmetic( true ); |
| 389 | + histogram->setPen( p ); |
| 390 | + } |
| 391 | + else |
| 392 | + { |
| 393 | + histogram->setPen( QPen( Qt::NoPen ) ); |
| 394 | + } |
| 395 | + return histogram; |
| 396 | +} |
| 397 | +#else |
| 398 | +HistogramItem * QgsCurveEditorWidget::createHistoItem( const QBrush& brush, const QPen& pen ) const |
| 399 | +{ |
| 400 | + HistogramItem* item = new HistogramItem( QString() ); |
| 401 | + item->setColor( brush.color() ); |
| 402 | + item->setFlat( true ); |
| 403 | + item->setSpacing( 0 ); |
| 404 | + if ( pen != Qt::NoPen ) |
| 405 | + { |
| 406 | + item->setPen( pen ); |
| 407 | + } |
| 408 | + else if ( brush.color().lightness() > 200 ) |
| 409 | + { |
| 410 | + QPen p; |
| 411 | + p.setColor( brush.color().darker( 150 ) ); |
| 412 | + p.setWidth( 0 ); |
| 413 | + p.setCosmetic( true ); |
| 414 | + item->setPen( p ); |
| 415 | + } |
| 416 | + return item; |
| 417 | +} |
| 418 | +#endif |
| 419 | + |
252 | 420 | /// @cond PRIVATE |
253 | 421 |
|
254 | 422 | QgsCurveEditorPlotEventFilter::QgsCurveEditorPlotEventFilter( QwtPlot *plot ) |
@@ -309,4 +477,5 @@ QPointF QgsCurveEditorPlotEventFilter::mapPoint( QPointF point ) const |
309 | 477 | mPlot->canvasMap( QwtPlot::yLeft ).invTransform( point.y() ) ); |
310 | 478 | } |
311 | 479 |
|
| 480 | + |
312 | 481 | ///@endcond |
0 commit comments