mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
commit
2d737510d4
@ -349,6 +349,16 @@ void QgsRasterInterface::initHistogram( QgsRasterHistogram &theHistogram,
|
||||
// There is no best default value, to display something reasonable in histogram chart, binCount should be small, OTOH, to get precise data for cumulative cut, the number should be big. Because it is easier to define fixed lower value for the chart, we calc optimum binCount for higher resolution (to avoid calculating that where histogram() is used. In any any case, it does not make sense to use more than width*height;
|
||||
myBinCount = theHistogram.width * theHistogram.height;
|
||||
if ( myBinCount > 1000 ) myBinCount = 1000;
|
||||
|
||||
// for Int16/Int32 make sure bin count <= actual range, because there is no sense in having
|
||||
// bins at fractional values
|
||||
if ( !mInput && (
|
||||
mySrcDataType == QGis::Int16 || mySrcDataType == QGis::Int32 ||
|
||||
mySrcDataType == QGis::UInt16 || mySrcDataType == QGis::UInt32 ) )
|
||||
{
|
||||
if ( myBinCount > theHistogram.maximum - theHistogram.minimum + 1 )
|
||||
myBinCount = int( ceil( theHistogram.maximum - theHistogram.minimum + 1 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
theHistogram.binCount = myBinCount;
|
||||
|
@ -41,9 +41,14 @@
|
||||
#include <qwt_plot_layout.h>
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
#include <qwt_plot_renderer.h>
|
||||
#include <qwt_plot_histogram.h>
|
||||
#else
|
||||
#include "qwt5_histogram_item.h"
|
||||
#endif
|
||||
|
||||
#define RASTER_HISTOGRAM_BINS 256
|
||||
// this has been removed, now we let the provider/raster interface decide
|
||||
// how many bins are suitable depending on data type and range
|
||||
//#define RASTER_HISTOGRAM_BINS 256
|
||||
|
||||
QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget *parent )
|
||||
: QWidget( parent ),
|
||||
@ -69,9 +74,11 @@ QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget
|
||||
// mHistoLoadApplyAll = settings.value( "/Raster/histogram/loadApplyAll", false ).toBool();
|
||||
mHistoZoomToMinMax = settings.value( "/Raster/histogram/zoomToMinMax", false ).toBool();
|
||||
mHistoUpdateStyleToMinMax = settings.value( "/Raster/histogram/updateStyleToMinMax", true ).toBool();
|
||||
mHistoDrawLines = settings.value( "/Raster/histogram/drawLines", true ).toBool();
|
||||
// mHistoShowBands = (HistoShowBands) settings.value( "/Raster/histogram/showBands", (int) ShowAll ).toInt();
|
||||
mHistoShowBands = ShowAll;
|
||||
|
||||
bool isInt = true;
|
||||
if ( true )
|
||||
{
|
||||
//band selector
|
||||
@ -81,6 +88,11 @@ QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget
|
||||
++myIteratorInt )
|
||||
{
|
||||
cboHistoBand->addItem( mRasterLayer->bandName( myIteratorInt ) );
|
||||
QGis::DataType mySrcDataType = mRasterLayer->dataProvider()->srcDataType( myIteratorInt );
|
||||
if ( !( mySrcDataType == QGis::Byte ||
|
||||
mySrcDataType == QGis::Int16 || mySrcDataType == QGis::Int32 ||
|
||||
mySrcDataType == QGis::UInt16 || mySrcDataType == QGis::UInt32 ) )
|
||||
isInt = false;
|
||||
}
|
||||
|
||||
// histo min/max selectors
|
||||
@ -95,6 +107,7 @@ QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget
|
||||
connect( leHistoMax, SIGNAL( editingFinished() ), this, SLOT( applyHistoMax() ) );
|
||||
|
||||
// histo actions
|
||||
// TODO move/add options to qgis options dialog
|
||||
QMenu* menu = new QMenu( this );
|
||||
menu->setSeparatorsCollapsible( false );
|
||||
btnHistoActions->setMenu( menu );
|
||||
@ -150,6 +163,29 @@ QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget
|
||||
action->setChecked( mHistoShowBands == ShowSelected );
|
||||
menu->addAction( action );
|
||||
|
||||
// display options
|
||||
group = new QActionGroup( this );
|
||||
group->setExclusive( false );
|
||||
connect( group, SIGNAL( triggered( QAction* ) ), this, SLOT( histoActionTriggered( QAction* ) ) );
|
||||
action = new QAction( tr( "Display" ), group );
|
||||
action->setSeparator( true );
|
||||
menu->addAction( action );
|
||||
// should we plot as histogram instead of line plot? (int data only)
|
||||
action = new QAction( "", group );
|
||||
action->setData( QVariant( "Draw lines" ) );
|
||||
if ( isInt )
|
||||
{
|
||||
action->setText( tr( "Draw as lines" ) );
|
||||
action->setCheckable( true );
|
||||
action->setChecked( mHistoDrawLines );
|
||||
}
|
||||
else
|
||||
{
|
||||
action->setText( tr( "Draw as lines (only int layers)" ) );
|
||||
action->setEnabled( false );
|
||||
}
|
||||
menu->addAction( action );
|
||||
|
||||
// actions
|
||||
action = new QAction( tr( "Actions" ), group );
|
||||
action->setSeparator( true );
|
||||
@ -164,6 +200,7 @@ QgsRasterHistogramWidget::QgsRasterHistogramWidget( QgsRasterLayer* lyr, QWidget
|
||||
menu->addAction( action );
|
||||
|
||||
// these actions have been disabled for api cleanup, restore them eventually
|
||||
// TODO restore these in qgis 2.4
|
||||
#if 0
|
||||
// Load min/max needs 3 params (method, extent, accuracy), cannot put it in single item
|
||||
action = new QAction( tr( "Load min/max" ), group );
|
||||
@ -234,14 +271,15 @@ void QgsRasterHistogramWidget::on_btnHistoCompute_clicked()
|
||||
// Histogram computation can be called either by clicking the "Compute Histogram" button
|
||||
// which is only visible if there is no cached histogram or by calling the
|
||||
// "Compute Histogram" action. Due to limitations in the gdal api, it is not possible
|
||||
// to re-calculate the histogramif it has already been calculated
|
||||
// to re-calculate the histogram if it has already been calculated
|
||||
computeHistogram( true );
|
||||
refreshHistogram();
|
||||
}
|
||||
|
||||
bool QgsRasterHistogramWidget::computeHistogram( bool forceComputeFlag )
|
||||
{
|
||||
const int BINCOUNT = RASTER_HISTOGRAM_BINS;
|
||||
QgsDebugMsg( "entered." );
|
||||
|
||||
//bool myIgnoreOutOfRangeFlag = true;
|
||||
//bool myThoroughBandScanFlag = false;
|
||||
int myBandCountInt = mRasterLayer->bandCount();
|
||||
@ -253,9 +291,8 @@ bool QgsRasterHistogramWidget::computeHistogram( bool forceComputeFlag )
|
||||
myIteratorInt <= myBandCountInt;
|
||||
++myIteratorInt )
|
||||
{
|
||||
//if ( ! mRasterLayer->hasCachedHistogram( myIteratorInt, BINCOUNT ) )
|
||||
int sampleSize = 250000; // number of sample cells
|
||||
if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, BINCOUNT, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize ) )
|
||||
if ( !mRasterLayer->dataProvider()->hasHistogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "band %1 does not have cached histo" ).arg( myIteratorInt ) );
|
||||
return false;
|
||||
@ -272,9 +309,8 @@ bool QgsRasterHistogramWidget::computeHistogram( bool forceComputeFlag )
|
||||
myIteratorInt <= myBandCountInt;
|
||||
++myIteratorInt )
|
||||
{
|
||||
//mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
|
||||
int sampleSize = 250000; // number of sample cells
|
||||
mRasterLayer->dataProvider()->histogram( myIteratorInt, BINCOUNT, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize );
|
||||
mRasterLayer->dataProvider()->histogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize );
|
||||
}
|
||||
|
||||
disconnect( mRasterLayer, SIGNAL( progressUpdate( int ) ), mHistogramProgress, SLOT( setValue( int ) ) );
|
||||
@ -297,7 +333,6 @@ void QgsRasterHistogramWidget::refreshHistogram()
|
||||
// bin in all selected layers, and the min. It then draws a scaled line between min
|
||||
// and max - scaled to image height. 1 line drawn per selected band
|
||||
//
|
||||
const int BINCOUNT = RASTER_HISTOGRAM_BINS;
|
||||
int myBandCountInt = mRasterLayer->bandCount();
|
||||
|
||||
QgsDebugMsg( "entered." );
|
||||
@ -309,11 +344,9 @@ void QgsRasterHistogramWidget::refreshHistogram()
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
// clear plot
|
||||
mpPlot->detachItems();
|
||||
#else
|
||||
mpPlot->clear();
|
||||
#endif
|
||||
|
||||
//ensure all children get removed
|
||||
mpPlot->setAutoDelete( true );
|
||||
mpPlot->setTitle( QObject::tr( "Raster Histogram" ) );
|
||||
@ -441,27 +474,68 @@ void QgsRasterHistogramWidget::refreshHistogram()
|
||||
if ( ! mySelectedBands.contains( myIteratorInt ) )
|
||||
continue;
|
||||
}
|
||||
int sampleSize = 250000; // number of sample cells
|
||||
//QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( myIteratorInt );
|
||||
// mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
|
||||
QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( myIteratorInt, BINCOUNT, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize );
|
||||
|
||||
QwtPlotCurve * mypCurve = new QwtPlotCurve( tr( "Band %1" ).arg( myIteratorInt ) );
|
||||
//mypCurve->setCurveAttribute( QwtPlotCurve::Fitted );
|
||||
mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
|
||||
mypCurve->setPen( QPen( mHistoColors.at( myIteratorInt ) ) );
|
||||
int sampleSize = 250000; // number of sample cells
|
||||
QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( myIteratorInt, 0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize );
|
||||
|
||||
QgsDebugMsg( QString( "got raster histo for band %1 : min=%2 max=%3 count=%4" ).arg( myIteratorInt ).arg( myHistogram.minimum ).arg( myHistogram.maximum ).arg( myHistogram.binCount ) );
|
||||
|
||||
QGis::DataType mySrcDataType = mRasterLayer->dataProvider()->srcDataType( myIteratorInt );
|
||||
bool myDrawLines = true;
|
||||
if ( ! mHistoDrawLines &&
|
||||
( mySrcDataType == QGis::Byte ||
|
||||
mySrcDataType == QGis::Int16 || mySrcDataType == QGis::Int32 ||
|
||||
mySrcDataType == QGis::UInt16 || mySrcDataType == QGis::UInt32 ) )
|
||||
{
|
||||
myDrawLines = false;
|
||||
}
|
||||
|
||||
QwtPlotCurve * mypCurve = 0;
|
||||
if ( myDrawLines )
|
||||
{
|
||||
mypCurve = new QwtPlotCurve( tr( "Band %1" ).arg( myIteratorInt ) );
|
||||
//mypCurve->setCurveAttribute( QwtPlotCurve::Fitted );
|
||||
mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
|
||||
mypCurve->setPen( QPen( mHistoColors.at( myIteratorInt ) ) );
|
||||
}
|
||||
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
QwtPlotHistogram * mypHisto = 0;
|
||||
if ( ! myDrawLines )
|
||||
{
|
||||
mypHisto = new QwtPlotHistogram( tr( "Band %1" ).arg( myIteratorInt ) );
|
||||
mypHisto->setRenderHint( QwtPlotItem::RenderAntialiased );
|
||||
//mypHisto->setPen( QPen( mHistoColors.at( myIteratorInt ) ) );
|
||||
mypHisto->setPen( QPen( Qt::lightGray ) );
|
||||
// this is needed in order to see the colors in the legend
|
||||
mypHisto->setBrush( QBrush( mHistoColors.at( myIteratorInt ) ) );
|
||||
}
|
||||
#else
|
||||
HistogramItem *mypHistoItem = 0;
|
||||
if ( ! myDrawLines )
|
||||
{
|
||||
mypHistoItem = new HistogramItem( tr( "Band %1" ).arg( myIteratorInt ) );
|
||||
mypHistoItem->setRenderHint( QwtPlotItem::RenderAntialiased );
|
||||
mypHistoItem->setColor( mHistoColors.at( myIteratorInt ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
QVector<QPointF> data;
|
||||
QVector<QwtIntervalSample> dataHisto;
|
||||
#else
|
||||
QVector<double> myX2Data;
|
||||
QVector<double> myY2Data;
|
||||
// we safely assume that QT>=4.0 (min version is 4.7), therefore QwtArray is a QVector, so don't set size here
|
||||
QwtArray<QwtDoubleInterval> intervalsHisto;
|
||||
QwtArray<double> valuesHisto;
|
||||
|
||||
#endif
|
||||
|
||||
// calculate first bin x value and bin step size if not Byte data
|
||||
if ( mRasterLayer->dataProvider()->srcDataType( myIteratorInt ) != QGis::Byte )
|
||||
if ( mySrcDataType != QGis::Byte )
|
||||
{
|
||||
//myBinXStep = myRasterBandStats.range / BINCOUNT;
|
||||
//myBinX = myRasterBandStats.minimumValue + myBinXStep / 2.0;
|
||||
myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / BINCOUNT;
|
||||
myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / myHistogram.binCount;
|
||||
myBinX = myHistogram.minimum + myBinXStep / 2.0;
|
||||
}
|
||||
else
|
||||
@ -470,24 +544,57 @@ void QgsRasterHistogramWidget::refreshHistogram()
|
||||
myBinX = 0;
|
||||
}
|
||||
|
||||
for ( int myBin = 0; myBin < BINCOUNT; myBin++ )
|
||||
for ( int myBin = 0; myBin < myHistogram.binCount; myBin++ )
|
||||
{
|
||||
//int myBinValue = myRasterBandStats.histogramVector->at( myBin );
|
||||
int myBinValue = myHistogram.histogramVector.at( myBin );
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
data << QPointF( myBinX, myBinValue );
|
||||
if ( myDrawLines )
|
||||
{
|
||||
data << QPointF( myBinX, myBinValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
dataHisto << QwtIntervalSample( myBinValue, myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 );
|
||||
}
|
||||
#else
|
||||
myX2Data.append( double( myBinX ) );
|
||||
myY2Data.append( double( myBinValue ) );
|
||||
if ( myDrawLines )
|
||||
{
|
||||
myX2Data.append( double( myBinX ) );
|
||||
myY2Data.append( double( myBinValue ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
intervalsHisto.append( QwtDoubleInterval( myBinX - myBinXStep / 2.0, myBinX + myBinXStep / 2.0 ) );
|
||||
valuesHisto.append( double( myBinValue ) );
|
||||
}
|
||||
#endif
|
||||
myBinX += myBinXStep;
|
||||
}
|
||||
|
||||
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
|
||||
mypCurve->setSamples( data );
|
||||
if ( myDrawLines )
|
||||
{
|
||||
mypCurve->setSamples( data );
|
||||
mypCurve->attach( mpPlot );
|
||||
}
|
||||
else
|
||||
{
|
||||
mypHisto->setSamples( dataHisto );
|
||||
mypHisto->attach( mpPlot );
|
||||
}
|
||||
#else
|
||||
mypCurve->setData( myX2Data, myY2Data );
|
||||
if ( myDrawLines )
|
||||
{
|
||||
mypCurve->setData( myX2Data, myY2Data );
|
||||
mypCurve->attach( mpPlot );
|
||||
}
|
||||
else
|
||||
{
|
||||
mypHistoItem->setData( QwtIntervalData( intervalsHisto, valuesHisto ) );
|
||||
mypHistoItem->attach( mpPlot );
|
||||
}
|
||||
#endif
|
||||
mypCurve->attach( mpPlot );
|
||||
|
||||
if ( myFirstIteration || mHistoMin > myHistogram.minimum )
|
||||
{
|
||||
mHistoMin = myHistogram.minimum;
|
||||
@ -711,6 +818,14 @@ void QgsRasterHistogramWidget::histoAction( const QString actionName, bool actio
|
||||
refreshHistogram();
|
||||
return;
|
||||
}
|
||||
else if ( actionName == "Draw lines" )
|
||||
{
|
||||
mHistoDrawLines = actionFlag;
|
||||
QSettings settings;
|
||||
settings.setValue( "/Raster/histogram/drawLines", mHistoDrawLines );
|
||||
on_btnHistoCompute_clicked(); // refresh
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
else if ( actionName == "Load apply all" )
|
||||
{
|
||||
|
@ -114,6 +114,7 @@ class GUI_EXPORT QgsRasterHistogramWidget : public QWidget, private Ui::QgsRaste
|
||||
bool mHistoShowMarkers;
|
||||
bool mHistoZoomToMinMax;
|
||||
bool mHistoUpdateStyleToMinMax;
|
||||
bool mHistoDrawLines;
|
||||
/* bool mHistoLoadApplyAll; */
|
||||
HistoShowBands mHistoShowBands;
|
||||
/** \brief Returns a list of selected bands in the histogram widget- or empty if there is no selection restriction. */
|
||||
|
409
src/gui/raster/qwt5_histogram_item.h
Normal file
409
src/gui/raster/qwt5_histogram_item.h
Normal file
@ -0,0 +1,409 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef HISTOGRAM_ITEM_H
|
||||
#define HISTOGRAM_ITEM_H
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <qcolor.h>
|
||||
|
||||
#include "qwt_plot_item.h"
|
||||
|
||||
class QwtIntervalData;
|
||||
class QString;
|
||||
|
||||
class HistogramItem: public QwtPlotItem
|
||||
{
|
||||
public:
|
||||
explicit HistogramItem(const QString &title = QString::null);
|
||||
explicit HistogramItem(const QwtText &title);
|
||||
virtual ~HistogramItem();
|
||||
|
||||
void setData(const QwtIntervalData &data);
|
||||
const QwtIntervalData &data() const;
|
||||
|
||||
void setColor(const QColor &);
|
||||
QColor color() const;
|
||||
|
||||
virtual QwtDoubleRect boundingRect() const;
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
virtual void draw(QPainter *, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap, const QRect &) const;
|
||||
|
||||
virtual void updateLegend(QwtLegend *) const;
|
||||
|
||||
void setBaseline(double reference);
|
||||
double baseline() const;
|
||||
|
||||
enum HistogramAttribute
|
||||
{
|
||||
Auto = 0,
|
||||
Xfy = 1
|
||||
};
|
||||
|
||||
void setHistogramAttribute(HistogramAttribute, bool on = true);
|
||||
bool testHistogramAttribute(HistogramAttribute) const;
|
||||
|
||||
protected:
|
||||
virtual void drawBar(QPainter *,
|
||||
Qt::Orientation o, const QRect &) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#include <qstring.h>
|
||||
#include <qpainter.h>
|
||||
#include <qwt_plot.h>
|
||||
#include <qwt_interval_data.h>
|
||||
#include <qwt_painter.h>
|
||||
#include <qwt_scale_map.h>
|
||||
#include <qwt_legend_item.h>
|
||||
|
||||
class HistogramItem::PrivateData
|
||||
{
|
||||
public:
|
||||
int attributes;
|
||||
QwtIntervalData data;
|
||||
QColor color;
|
||||
double reference;
|
||||
};
|
||||
|
||||
HistogramItem::HistogramItem(const QwtText &title):
|
||||
QwtPlotItem(title)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
HistogramItem::HistogramItem(const QString &title):
|
||||
QwtPlotItem(QwtText(title))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
HistogramItem::~HistogramItem()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
void HistogramItem::init()
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
d_data->reference = 0.0;
|
||||
d_data->attributes = HistogramItem::Auto;
|
||||
|
||||
setItemAttribute(QwtPlotItem::AutoScale, true);
|
||||
setItemAttribute(QwtPlotItem::Legend, true);
|
||||
|
||||
setZ(20.0);
|
||||
}
|
||||
|
||||
void HistogramItem::setBaseline(double reference)
|
||||
{
|
||||
if ( d_data->reference != reference )
|
||||
{
|
||||
d_data->reference = reference;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
double HistogramItem::baseline() const
|
||||
{
|
||||
return d_data->reference;
|
||||
}
|
||||
|
||||
void HistogramItem::setData(const QwtIntervalData &data)
|
||||
{
|
||||
d_data->data = data;
|
||||
itemChanged();
|
||||
}
|
||||
|
||||
const QwtIntervalData &HistogramItem::data() const
|
||||
{
|
||||
return d_data->data;
|
||||
}
|
||||
|
||||
void HistogramItem::setColor(const QColor &color)
|
||||
{
|
||||
if ( d_data->color != color )
|
||||
{
|
||||
d_data->color = color;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QColor HistogramItem::color() const
|
||||
{
|
||||
return d_data->color;
|
||||
}
|
||||
|
||||
QwtDoubleRect HistogramItem::boundingRect() const
|
||||
{
|
||||
QwtDoubleRect rect = d_data->data.boundingRect();
|
||||
if ( !rect.isValid() )
|
||||
return rect;
|
||||
|
||||
if ( d_data->attributes & Xfy )
|
||||
{
|
||||
rect = QwtDoubleRect( rect.y(), rect.x(),
|
||||
rect.height(), rect.width() );
|
||||
|
||||
if ( rect.left() > d_data->reference )
|
||||
rect.setLeft( d_data->reference );
|
||||
else if ( rect.right() < d_data->reference )
|
||||
rect.setRight( d_data->reference );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rect.bottom() < d_data->reference )
|
||||
rect.setBottom( d_data->reference );
|
||||
else if ( rect.top() > d_data->reference )
|
||||
rect.setTop( d_data->reference );
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
int HistogramItem::rtti() const
|
||||
{
|
||||
return QwtPlotItem::Rtti_PlotHistogram;
|
||||
}
|
||||
|
||||
void HistogramItem::setHistogramAttribute(HistogramAttribute attribute, bool on)
|
||||
{
|
||||
if ( bool(d_data->attributes & attribute) == on )
|
||||
return;
|
||||
|
||||
if ( on )
|
||||
d_data->attributes |= attribute;
|
||||
else
|
||||
d_data->attributes &= ~attribute;
|
||||
|
||||
itemChanged();
|
||||
}
|
||||
|
||||
bool HistogramItem::testHistogramAttribute(HistogramAttribute attribute) const
|
||||
{
|
||||
return d_data->attributes & attribute;
|
||||
}
|
||||
|
||||
void HistogramItem::draw(QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap, const QRect &) const
|
||||
{
|
||||
const QwtIntervalData &iData = d_data->data;
|
||||
|
||||
painter->setPen(QPen(d_data->color));
|
||||
|
||||
const int x0 = xMap.transform(baseline());
|
||||
const int y0 = yMap.transform(baseline());
|
||||
|
||||
for ( int i = 0; i < (int)iData.size(); i++ )
|
||||
{
|
||||
if ( d_data->attributes & HistogramItem::Xfy )
|
||||
{
|
||||
const int x2 = xMap.transform(iData.value(i));
|
||||
if ( x2 == x0 )
|
||||
continue;
|
||||
|
||||
int y1 = yMap.transform( iData.interval(i).minValue());
|
||||
int y2 = yMap.transform( iData.interval(i).maxValue());
|
||||
if ( y1 > y2 )
|
||||
qSwap(y1, y2);
|
||||
|
||||
if ( i < (int)iData.size() - 2 )
|
||||
{
|
||||
const int yy1 = yMap.transform(iData.interval(i+1).minValue());
|
||||
const int yy2 = yMap.transform(iData.interval(i+1).maxValue());
|
||||
|
||||
if ( y2 == qwtMin(yy1, yy2) )
|
||||
{
|
||||
const int xx2 = xMap.transform(
|
||||
iData.interval(i+1).minValue());
|
||||
if ( xx2 != x0 && ( (xx2 < x0 && x2 < x0) ||
|
||||
(xx2 > x0 && x2 > x0) ) )
|
||||
{
|
||||
// One pixel distance between neighboured bars
|
||||
y2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBar(painter, Qt::Horizontal,
|
||||
QRect(x0, y1, x2 - x0, y2 - y1));
|
||||
}
|
||||
else
|
||||
{
|
||||
const int y2 = yMap.transform(iData.value(i));
|
||||
if ( y2 == y0 )
|
||||
continue;
|
||||
|
||||
int x1 = xMap.transform(iData.interval(i).minValue());
|
||||
int x2 = xMap.transform(iData.interval(i).maxValue());
|
||||
if ( x1 > x2 )
|
||||
qSwap(x1, x2);
|
||||
|
||||
if ( i < (int)iData.size() - 2 )
|
||||
{
|
||||
const int xx1 = xMap.transform(iData.interval(i+1).minValue());
|
||||
const int xx2 = xMap.transform(iData.interval(i+1).maxValue());
|
||||
|
||||
if ( x2 == qwtMin(xx1, xx2) )
|
||||
{
|
||||
const int yy2 = yMap.transform(iData.value(i+1));
|
||||
if ( yy2 != y0 && ( (yy2 < y0 && y2 < y0) ||
|
||||
(yy2 > y0 && y2 > y0) ) )
|
||||
{
|
||||
// One pixel distance between neighboured bars
|
||||
x2--;
|
||||
}
|
||||
}
|
||||
}
|
||||
drawBar(painter, Qt::Vertical,
|
||||
QRect(x1, y0, x2 - x1, y2 - y0) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramItem::drawBar(QPainter *painter,
|
||||
Qt::Orientation, const QRect& rect) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
const QColor color(painter->pen().color());
|
||||
#if QT_VERSION >= 0x040000
|
||||
const QRect r = rect.normalized();
|
||||
#else
|
||||
const QRect r = rect.normalize();
|
||||
#endif
|
||||
|
||||
const int factor = 125;
|
||||
const QColor light(color.light(factor));
|
||||
const QColor dark(color.dark(factor));
|
||||
|
||||
painter->setBrush(color);
|
||||
painter->setPen(Qt::NoPen);
|
||||
QwtPainter::drawRect(painter, r.x() + 1, r.y() + 1,
|
||||
r.width() - 2, r.height() - 2);
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
|
||||
painter->setPen(QPen(light, 2));
|
||||
#if QT_VERSION >= 0x040000
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left() + 1, r.top() + 2, r.right() + 1, r.top() + 2);
|
||||
#else
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left(), r.top() + 2, r.right() + 1, r.top() + 2);
|
||||
#endif
|
||||
|
||||
painter->setPen(QPen(dark, 2));
|
||||
#if QT_VERSION >= 0x040000
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left() + 1, r.bottom(), r.right() + 1, r.bottom());
|
||||
#else
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left(), r.bottom(), r.right() + 1, r.bottom());
|
||||
#endif
|
||||
|
||||
painter->setPen(QPen(light, 1));
|
||||
|
||||
#if QT_VERSION >= 0x040000
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left(), r.top() + 1, r.left(), r.bottom());
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left() + 1, r.top() + 2, r.left() + 1, r.bottom() - 1);
|
||||
#else
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left(), r.top() + 1, r.left(), r.bottom() + 1);
|
||||
QwtPainter::drawLine(painter,
|
||||
r.left() + 1, r.top() + 2, r.left() + 1, r.bottom());
|
||||
#endif
|
||||
|
||||
painter->setPen(QPen(dark, 1));
|
||||
|
||||
#if QT_VERSION >= 0x040000
|
||||
QwtPainter::drawLine(painter,
|
||||
r.right() + 1, r.top() + 1, r.right() + 1, r.bottom());
|
||||
QwtPainter::drawLine(painter,
|
||||
r.right(), r.top() + 2, r.right(), r.bottom() - 1);
|
||||
#else
|
||||
QwtPainter::drawLine(painter,
|
||||
r.right() + 1, r.top() + 1, r.right() + 1, r.bottom() + 1);
|
||||
QwtPainter::drawLine(painter,
|
||||
r.right(), r.top() + 2, r.right(), r.bottom());
|
||||
#endif
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
//! Update the widget that represents the curve on the legend
|
||||
// this was adapted from QwtPlotCurve::updateLegend()
|
||||
void HistogramItem::updateLegend(QwtLegend *legend) const
|
||||
{
|
||||
if ( !legend )
|
||||
return;
|
||||
|
||||
QwtPlotItem::updateLegend(legend);
|
||||
|
||||
QWidget *widget = legend->find(this);
|
||||
if ( !widget || !widget->inherits("QwtLegendItem") )
|
||||
return;
|
||||
|
||||
QwtLegendItem *legendItem = (QwtLegendItem *)widget;
|
||||
|
||||
#if QT_VERSION < 0x040000
|
||||
const bool doUpdate = legendItem->isUpdatesEnabled();
|
||||
#else
|
||||
const bool doUpdate = legendItem->updatesEnabled();
|
||||
#endif
|
||||
legendItem->setUpdatesEnabled(false);
|
||||
|
||||
const int policy = legend->displayPolicy();
|
||||
|
||||
if (policy == QwtLegend::FixedIdentifier)
|
||||
{
|
||||
int mode = legend->identifierMode();
|
||||
|
||||
legendItem->setCurvePen(QPen(color()));
|
||||
|
||||
if (mode & QwtLegendItem::ShowText)
|
||||
legendItem->setText(title());
|
||||
else
|
||||
legendItem->setText(QwtText());
|
||||
|
||||
legendItem->setIdentifierMode(mode);
|
||||
}
|
||||
else if (policy == QwtLegend::AutoIdentifier)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
legendItem->setCurvePen(QPen(color()));
|
||||
mode |= QwtLegendItem::ShowLine;
|
||||
if ( !title().isEmpty() )
|
||||
{
|
||||
legendItem->setText(title());
|
||||
mode |= QwtLegendItem::ShowText;
|
||||
}
|
||||
else
|
||||
{
|
||||
legendItem->setText(QwtText());
|
||||
}
|
||||
legendItem->setIdentifierMode(mode);
|
||||
}
|
||||
|
||||
legendItem->setUpdatesEnabled(doUpdate);
|
||||
legendItem->update();
|
||||
}
|
||||
|
||||
#endif
|
@ -117,7 +117,7 @@ ADD_QGIS_TEST(zoomtest testqgsmaptoolzoom.cpp)
|
||||
#QT4_WRAP_CPP(rendererv2gui_MOC_SRCS ${rendererv2gui_HDRS})
|
||||
#ADD_EXECUTABLE(qgis_rendererv2gui ${rendererv2gui_SRCS} ${rendererv2gui_MOC_SRCS})
|
||||
|
||||
ADD_QGIS_TEST(histogramtest testqgsrasterhistogram.cpp)
|
||||
#ADD_QGIS_TEST(histogramtest testqgsrasterhistogram.cpp)
|
||||
ADD_QGIS_TEST(projectionissues testprojectionissues.cpp)
|
||||
ADD_QGIS_TEST(scalecombobox testqgsscalecombobox.cpp)
|
||||
ADD_QGIS_TEST(dualviewtest testqgsdualview.cpp )
|
||||
|
BIN
tests/testdata/landsat-f32-b1.tif
vendored
Normal file
BIN
tests/testdata/landsat-f32-b1.tif
vendored
Normal file
Binary file not shown.
BIN
tests/testdata/landsat-int16-b1.tif
vendored
Normal file
BIN
tests/testdata/landsat-int16-b1.tif
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user