21 #include <QVBoxLayout>    22 #include <QMouseEvent>    26 #include <qwt_global.h>    27 #include <qwt_plot_canvas.h>    29 #include <qwt_plot_curve.h>    30 #include <qwt_plot_grid.h>    31 #include <qwt_plot_marker.h>    32 #include <qwt_plot_picker.h>    33 #include <qwt_picker_machine.h>    34 #include <qwt_plot_layout.h>    35 #include <qwt_symbol.h>    36 #include <qwt_legend.h>    38 #include <qwt_plot_renderer.h>    39 #include <qwt_plot_histogram.h>    45   mPlot = 
new QwtPlot();
    46   mPlot->setMinimumSize( QSize( 0, 100 ) );
    47   mPlot->setAxisScale( QwtPlot::yLeft, 0, 1 );
    48   mPlot->setAxisScale( QwtPlot::yRight, 0, 1 );
    49   mPlot->setAxisScale( QwtPlot::xBottom, 0, 1 );
    50   mPlot->setAxisScale( QwtPlot::xTop, 0, 1 );
    52   QVBoxLayout *vlayout = 
new QVBoxLayout();
    53   vlayout->addWidget( mPlot );
    57   mPlot->setFrameStyle( QFrame::NoFrame );
    58   QFrame *plotCanvasFrame = 
dynamic_cast<QFrame *
>( mPlot->canvas() );
    59   if ( plotCanvasFrame )
    60     plotCanvasFrame->setFrameStyle( QFrame::NoFrame );
    62   mPlot->enableAxis( QwtPlot::yLeft, 
false );
    63   mPlot->enableAxis( QwtPlot::xBottom, 
false );
    66   QwtPlotGrid *grid = 
new QwtPlotGrid();
    67   QwtScaleDiv gridDiv( 0.0, 1.0, QList<double>(), QList<double>(), QList<double>() << 0.2 << 0.4 << 0.6 << 0.8 );
    68   grid->setXDiv( gridDiv );
    69   grid->setYDiv( gridDiv );
    70   grid->setPen( QPen( QColor( 0, 0, 0, 50 ) ) );
    71   grid->attach( mPlot );
    73   mPlotCurve = 
new QwtPlotCurve();
    74   mPlotCurve->setTitle( QStringLiteral( 
"Curve" ) );
    75   mPlotCurve->setPen( QPen( QColor( 30, 30, 30 ), 0.0 ) ),
    76              mPlotCurve->setRenderHint( QwtPlotItem::RenderAntialiased, 
true );
    77   mPlotCurve->attach( mPlot );
    79   mPlotFilter = 
new QgsCurveEditorPlotEventFilter( mPlot );
    80   connect( mPlotFilter, &QgsCurveEditorPlotEventFilter::mousePress, 
this, &QgsCurveEditorWidget::plotMousePress );
    81   connect( mPlotFilter, &QgsCurveEditorPlotEventFilter::mouseRelease, 
this, &QgsCurveEditorWidget::plotMouseRelease );
    82   connect( mPlotFilter, &QgsCurveEditorPlotEventFilter::mouseMove, 
this, &QgsCurveEditorWidget::plotMouseMove );
    84   mPlotCurve->setVisible( 
true );
    90   if ( mGatherer && mGatherer->isRunning() )
    92     connect( mGatherer.get(), &QgsHistogramValuesGatherer::finished, mGatherer.get(), &QgsHistogramValuesGatherer::deleteLater );
    94     ( void )mGatherer.release();
   109     mGatherer.reset( 
new QgsHistogramValuesGatherer() );
   110     connect( mGatherer.get(), &QgsHistogramValuesGatherer::calculatedHistogram, 
this, [ = ]
   112       mHistogram.reset( 
new QgsHistogram( mGatherer->histogram() ) );
   117   bool changed = mGatherer->layer() != layer || mGatherer->expression() != expression;
   120     mGatherer->setExpression( expression );
   121     mGatherer->setLayer( layer );
   123     if ( mGatherer->isRunning() )
   127       while ( mGatherer->isRunning() )
   129         QCoreApplication::processEvents();
   142   mMinValueRange = minValueRange;
   148   mMaxValueRange = maxValueRange;
   154   if ( event->key() == Qt::Key_Delete || 
event->key() == Qt::Key_Backspace )
   157     if ( mCurrentPlotMarkerIndex > 0 && mCurrentPlotMarkerIndex < cp.count() - 1 )
   159       cp.removeAt( mCurrentPlotMarkerIndex );
   167 void QgsCurveEditorWidget::plotMousePress( QPointF point )
   169   mCurrentPlotMarkerIndex = findNearestControlPoint( point );
   170   if ( mCurrentPlotMarkerIndex < 0 )
   174     mCurrentPlotMarkerIndex = findNearestControlPoint( point );
   181 int QgsCurveEditorWidget::findNearestControlPoint( QPointF point )
 const   183   double minDist = 3.0 / mPlot->width();
   184   int currentPlotMarkerIndex = -1;
   188   for ( 
int i = 0; i < controlPoints.count(); ++i )
   190     QgsPointXY currentPoint = controlPoints.at( i );
   192     currentDist = std::pow( point.x() - currentPoint.
x(), 2.0 ) + std::pow( point.y() - currentPoint.
y(), 2.0 );
   193     if ( currentDist < minDist )
   195       minDist = currentDist;
   196       currentPlotMarkerIndex = i;
   199   return currentPlotMarkerIndex;
   203 void QgsCurveEditorWidget::plotMouseRelease( QPointF )
   207 void QgsCurveEditorWidget::plotMouseMove( QPointF point )
   209   if ( mCurrentPlotMarkerIndex < 0 )
   213   bool removePoint = 
false;
   214   if ( mCurrentPlotMarkerIndex == 0 )
   216     point.setX( std::min( point.x(), cp.at( 1 ).x() - 0.01 ) );
   220     removePoint = point.x() <= cp.at( mCurrentPlotMarkerIndex - 1 ).x();
   222   if ( mCurrentPlotMarkerIndex == cp.count() - 1 )
   224     point.setX( std::max( point.x(), cp.at( mCurrentPlotMarkerIndex - 1 ).x() + 0.01 ) );
   229     removePoint = removePoint || point.x() >= cp.at( mCurrentPlotMarkerIndex + 1 ).x();
   234     cp.removeAt( mCurrentPlotMarkerIndex );
   235     mCurrentPlotMarkerIndex = -1;
   239     cp[ mCurrentPlotMarkerIndex ] = 
QgsPointXY( point.x(), point.y() );
   246 void QgsCurveEditorWidget::addPlotMarker( 
double x, 
double y, 
bool isSelected )
   248   QColor borderColor( 0, 0, 0 );
   250   QColor brushColor = isSelected ? borderColor : QColor( 255, 255, 255, 0 );
   252   QwtPlotMarker *marker = 
new QwtPlotMarker();
   253   marker->setSymbol( 
new QwtSymbol( QwtSymbol::Ellipse,  QBrush( brushColor ), QPen( borderColor, isSelected ? 2 : 1 ), QSize( 8, 8 ) ) );
   254   marker->setValue( x, y );
   255   marker->attach( mPlot );
   256   marker->setRenderHint( QwtPlotItem::RenderAntialiased, 
true );
   260 void QgsCurveEditorWidget::updateHistogram()
   266   QBrush histoBrush( QColor( 0, 0, 0, 70 ) );
   268   delete mPlotHistogram;
   269   mPlotHistogram = createPlotHistogram( histoBrush );
   270   QVector<QwtIntervalSample> dataHisto;
   273   QList<double> edges = mHistogram->binEdges( bins );
   274   QList<int> counts = mHistogram->counts( bins );
   277   double max = *std::max_element( counts.constBegin(), counts.constEnd() );
   282     std::transform( edges.begin(), edges.end(), edges.begin(),
   283                     [
this]( 
double d ) -> 
double { 
return ( d - mMinValueRange ) / ( mMaxValueRange - mMinValueRange ); } );
   286   for ( 
int bin = 0; bin < bins; ++bin )
   288     double binValue = counts.at( bin ) / max;
   290     double upperEdge = edges.at( bin + 1 );
   292     dataHisto << QwtIntervalSample( binValue, edges.at( bin ), upperEdge );
   295   mPlotHistogram->setSamples( dataHisto );
   296   mPlotHistogram->attach( mPlot );
   300 void QgsCurveEditorWidget::updatePlot()
   303   Q_FOREACH ( QwtPlotMarker *marker, mMarkers )
   310   QPolygonF curvePoints;
   317     addPlotMarker( point.
x(), point.
y(), mCurrentPlotMarkerIndex == i );
   323   for ( 
double p = 0; p <= 1.0; p += 0.01 )
   327   std::sort( x.begin(), x.end() );
   328   QVector< double > y = mCurve.
y( x );
   330   for ( 
int j = 0; j < x.count(); ++j )
   332     curvePoints << QPointF( x.at( j ), y.at( j ) );
   335   mPlotCurve->setSamples( curvePoints );
   339 QwtPlotHistogram *QgsCurveEditorWidget::createPlotHistogram( 
const QBrush &brush, 
const QPen &pen )
 const   341   QwtPlotHistogram *histogram = 
new QwtPlotHistogram( QString() );
   342   histogram->setBrush( brush );
   343   if ( pen != Qt::NoPen )
   345     histogram->setPen( pen );
   347   else if ( brush.color().lightness() > 200 )
   350     p.setColor( brush.color().darker( 150 ) );
   352     p.setCosmetic( 
true );
   353     histogram->setPen( p );
   357     histogram->setPen( QPen( Qt::NoPen ) );
   364 QgsCurveEditorPlotEventFilter::QgsCurveEditorPlotEventFilter( QwtPlot *plot )
   368   mPlot->canvas()->installEventFilter( 
this );
   371 bool QgsCurveEditorPlotEventFilter::eventFilter( QObject *
object, QEvent *event )
   373   if ( !mPlot->isEnabled() )
   374     return QObject::eventFilter( 
object, event );
   376   switch ( event->type() )
   378     case QEvent::MouseButtonPress:
   380       const QMouseEvent *mouseEvent = 
static_cast<QMouseEvent * 
>( event );
   381       if ( mouseEvent->button() == Qt::LeftButton )
   383         emit mousePress( mapPoint( mouseEvent->pos() ) );
   387     case QEvent::MouseMove:
   389       const QMouseEvent *mouseEvent = 
static_cast<QMouseEvent * 
>( event );
   390       if ( mouseEvent->buttons() & Qt::LeftButton )
   393         emit mouseMove( mapPoint( mouseEvent->pos() ) );
   397     case QEvent::MouseButtonRelease:
   399       const QMouseEvent *mouseEvent = 
static_cast<QMouseEvent * 
>( event );
   400       if ( mouseEvent->button() == Qt::LeftButton )
   402         emit mouseRelease( mapPoint( mouseEvent->pos() ) );
   410   return QObject::eventFilter( 
object, event );
   413 QPointF QgsCurveEditorPlotEventFilter::mapPoint( QPointF point )
 const   418   return QPointF( mPlot->canvasMap( QwtPlot::xBottom ).invTransform( point.x() ),
   419                   mPlot->canvasMap( QwtPlot::yLeft ).invTransform( point.y() ) );
 
A class to represent a 2D point. 
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference) 
 
Calculator for a numeric histogram from a list of values. 
 
Represents a vector layer which manages a vector based data sets.