786 changes: 786 additions & 0 deletions images/themes/default/histogram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/pie-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
755 changes: 755 additions & 0 deletions images/themes/default/pie-chart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
766 changes: 766 additions & 0 deletions images/themes/default/text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/core/core.sip
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
%Include qgsrectangle.sip
%Include qgsrendercontext.sip
%Include qgsrenderer.sip
%Include qgsrenderchecker.sip
%Include qgsrunprocess.sip
%Include qgsscalecalculator.sip
%Include qgssinglesymbolrenderer.sip
Expand Down
5 changes: 5 additions & 0 deletions python/core/qgscomposition.sip
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ class QgsComposition: QGraphicsScene
/**Reads settings from xml file*/
bool readXML( const QDomElement& compositionElem, const QDomDocument& doc );

/**Load a template document
@param doc template document
@param substitutionMap map with text to replace. Text needs to be enclosed by brackets (e.g. '[text]' )*/
bool loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap = 0, bool addUndoCommands = false );

/**Add items from XML representation to the graphics scene (for project file reading, pasting items from clipboard)
@param elem items parent element, e.g. <Composer> or <ComposerItemClipboard>
@param doc xml document
Expand Down
9 changes: 9 additions & 0 deletions python/core/qgsrasterlayer.sip
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ public:
Multiband
} ;

/** \brief Contrast enhancement limits */
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};

/** \brief A list containing on ContrastEnhancement object per raster band in this raster layer */
typedef QList<QgsContrastEnhancement> ContrastEnhancementList;

Expand Down
43 changes: 43 additions & 0 deletions python/core/qgsrenderchecker.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

/** Render checker for tests in python */

class QgsRenderChecker
{
%TypeHeaderCode
#include <qgsrenderchecker.h>
%End
public:

QgsRenderChecker();

~QgsRenderChecker();

QString controlImagePath() const;

QString report();

float matchPercent();

unsigned int mismatchCount();

unsigned int matchTarget();

int elapsedTime();

void setControlName( const QString theName );

void setControlPathPrefix( const QString theName );

QString imageToHash( QString theImageFile );

void setRenderedImage( QString theImageFileName );

void setMapRenderer( QgsMapRenderer * thepMapRenderer );

bool runTest( QString theTestName, unsigned int theMismatchCount = 0 );

bool compareImages( QString theTestName, unsigned int theMismatchCount = 0, QString theRenderedImageFile = "" );

bool isKnownAnomaly( QString theDiffImageFile );
};

2 changes: 1 addition & 1 deletion src/analysis/network/qgslinevectorlayerdirector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c

if ( pointLengthMap[ i ].mLength > info.mLength )
{
info.mTiedPoint = info.mTiedPoint ;
Q_UNUSED( info.mTiedPoint );
info.mFirstPoint = pt1;
info.mLastPoint = pt2;

Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ SET(QGIS_APP_SRCS
qgsformannotationdialog.cpp
qgshtmlannotationdialog.cpp
qgsdelattrdialog.cpp
qgsdiagramproperties.cpp
qgsdisplayangle.cpp
qgsfieldcalculator.cpp
qgsgraduatedsymboldialog.cpp
Expand Down Expand Up @@ -185,6 +186,7 @@ SET (QGIS_APP_MOC_HDRS
qgsdecorationgrid.h
qgsdecorationgriddialog.h
qgsdelattrdialog.h
qgsdiagramproperties.h
qgsdisplayangle.h
qgsembedlayerdialog.h
qgsfeatureaction.h
Expand Down
16 changes: 6 additions & 10 deletions src/app/composer/qgscomposer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,18 +915,14 @@ void QgsComposer::on_mActionLoadFromTemplate_triggered()
return;
}

emit composerWillBeRemoved( mView );

QDomDocument templateDocument;
if ( !templateDocument.setContent( &templateFile, false ) )
if ( mComposition )
{
QMessageBox::warning( 0, tr( "Read error" ), tr( "Content of template file is not valid" ) );
return;
QDomDocument templateDoc;
if ( templateDoc.setContent( &templateFile ) )
{
mComposition->loadFromTemplate( templateDoc, 0, false );
}
}

deleteItemWidgets();
readXML( templateDocument );
emit composerAdded( mView );
}

void QgsComposer::on_mActionMoveItemContent_triggered()
Expand Down
2 changes: 1 addition & 1 deletion src/app/composer/qgscomposerhtmlwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <QFileDialog>
#include <QSettings>

QgsComposerHtmlWidget::QgsComposerHtmlWidget( QgsComposerHtml* html, QgsComposerFrame* frame ): mHtml( html ), mFrame( frame )
QgsComposerHtmlWidget::QgsComposerHtmlWidget( QgsComposerHtml* html, QgsComposerFrame* frame ): QWidget(), mHtml( html ), mFrame( frame )
{
setupUi( this );

Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,7 @@ void QgisApp::initLegend()

mMapLayerOrder->setWhatsThis( tr( "Map layer list that displays all layers in drawing order." ) );
mLayerOrderDock = new QDockWidget( tr( "Layer order" ), this );
mLayerOrderDock->setObjectName( "Legend" );
mLayerOrderDock->setObjectName( "LayerOrder" );
mLayerOrderDock->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );

w = new QWidget( this );
Expand Down
590 changes: 590 additions & 0 deletions src/app/qgsdiagramproperties.cpp

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions src/app/qgsdiagramproperties.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/***************************************************************************
qgsdiagramproperties.h
Properties for diagram layers
-------------------
begin : August 2012
copyright : (C) Matthias Kuhn
email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#ifndef QGSDIAGRAMPROPERTIES_H
#define QGSDIAGRAMPROPERTIES_H

#include <QDialog>
#include <ui_qgsdiagrampropertiesbase.h>

class QgsVectorLayer;

class QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPropertiesBase
{
Q_OBJECT

public:
QgsDiagramProperties( QgsVectorLayer* layer, QWidget* parent );
/**Adds an attribute from the list of available attributes to the assigned attributes with a random color.*/
void addAttribute( QTreeWidgetItem * item );

public slots:
void apply();
void on_mDiagramTypeComboBox_currentIndexChanged( int index );
void on_mTransparencySlider_valueChanged( int value );
void on_mAddCategoryPushButton_clicked();
void on_mAttributesTreeWidget_itemDoubleClicked( QTreeWidgetItem * item, int column );
void on_mBackgroundColorButton_clicked();
void on_mFindMaximumValueButton_clicked();
void on_mDiagramPenColorButton_clicked();
void on_mDisplayDiagramsGroupBox_toggled( bool checked );
void on_mRemoveCategoryPushButton_clicked();
void on_mDiagramFontButton_clicked();
void on_mDiagramAttributesTreeWidget_itemDoubleClicked( QTreeWidgetItem * item, int column );
void on_mEngineSettingsButton_clicked();

protected:
QFont mDiagramFont;

QgsVectorLayer* mLayer;

private:
};

#endif // QGSDIAGRAMPROPERTIES_H
2 changes: 2 additions & 0 deletions src/app/qgslabelinggui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
sliderPriority->setValue( lyr.priority );
chkNoObstacle->setChecked( !lyr.obstacle );
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
mPalShowAllLabelsForLayerChkBx->setChecked( lyr.displayAll );
chkMergeLines->setChecked( lyr.mergeLines );
mMinSizeSpinBox->setValue( lyr.minFeatureSize );
chkAddDirectionSymbol->setChecked( lyr.addDirectionSymbol );
Expand Down Expand Up @@ -348,6 +349,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
lyr.priority = sliderPriority->value();
lyr.obstacle = !chkNoObstacle->isChecked();
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
lyr.mergeLines = chkMergeLines->isChecked();
if ( chkScaleBasedVisibility->isChecked() )
{
Expand Down
221 changes: 139 additions & 82 deletions src/app/qgsoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* *
***************************************************************************/
#include "qgsapplication.h"
#include "qgsdistancearea.h"
#include "qgsoptions.h"
#include "qgis.h"
#include "qgisapp.h"
Expand Down Expand Up @@ -77,6 +78,8 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :

connect( spinFontSize, SIGNAL( valueChanged( const QString& ) ), this, SLOT( fontSizeChanged( const QString& ) ) );

connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) );

#ifdef Q_WS_X11
connect( chkEnableBackbuffer, SIGNAL( stateChanged( int ) ), this, SLOT( toggleEnableBackbuffer( int ) ) );
#endif
Expand Down Expand Up @@ -279,24 +282,34 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
leProjectGlobalCrs->setText( mDefaultCrs.authid() + " - " + mDefaultCrs.description() );

// populate combo box with ellipsoids

QgsDebugMsg( "Setting upp ellipsoid" );

getEllipsoidList();
// Pre-select current ellipsoid
QString myEllipsoidId = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString();
cmbEllipsoid->setCurrentIndex( cmbEllipsoid->findText( getEllipsoidName( myEllipsoidId ), Qt::MatchExactly ) );
// Check if CRS transformation is on, or else turn combobox off
if ( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() )
mEllipsoidIndex = 0;
populateEllipsoidList();

// Reading ellipsoid from setttings
QStringList mySplitEllipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString().split( ':' );

int myIndex = 0;
int i;
for ( i = 0; i < mEllipsoidList.length(); i++ )
{
cmbEllipsoid->setEnabled( true );
cmbEllipsoid->setToolTip( "" );
if ( mEllipsoidList[ i ].acronym.startsWith( mySplitEllipsoid[ 0 ] ) )
{
myIndex = i;
break;
}
}
else
// Update paramaters if present.
if ( mySplitEllipsoid.length() >= 3 )
{
cmbEllipsoid->setEnabled( false );
cmbEllipsoid->setToolTip( "Can only use ellipsoidal calculations when CRS transformation is enabled" );
mEllipsoidList[ myIndex ].semiMajor = mySplitEllipsoid[ 1 ].toDouble();
mEllipsoidList[ myIndex ].semiMinor = mySplitEllipsoid[ 2 ].toDouble();
}

updateEllipsoidUI( myIndex );

// Set the units for measuring
QGis::UnitType myDisplayUnits = QGis::fromLiteral( settings.value( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Meters ) ).toString() );
if ( myDisplayUnits == QGis::Feet )
Expand Down Expand Up @@ -940,7 +953,25 @@ void QgsOptions::saveOptions()
settings.setValue( "/Projections/otfTransformEnabled", chkOtfTransform->isChecked() );
settings.setValue( "/Projections/projectDefaultCrs", mDefaultCrs.authid() );

settings.setValue( "/qgis/measure/ellipsoid", getEllipsoidAcronym( cmbEllipsoid->currentText() ) );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER" ) )
{
double major = mEllipsoidList[ mEllipsoidIndex ].semiMajor;
double minor = mEllipsoidList[ mEllipsoidIndex ].semiMinor;
// If the user fields have changed, use them instead.
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Using paramteric major/minor" );
major = QLocale::system().toDouble( leSemiMajor->text() );
minor = QLocale::system().toDouble( leSemiMinor->text() );
}
settings.setValue( "/qgis/measure/ellipsoid", QString( "PARAMETER:%1:%2" )
.arg( major, 0, 'g', 17 )
.arg( minor, 0, 'g', 17 ) );
}
else
{
settings.setValue( "/qgis/measure/ellipsoid", mEllipsoidList[ mEllipsoidIndex ].acronym );
}

if ( radFeet->isChecked() )
{
Expand Down Expand Up @@ -1163,21 +1194,29 @@ bool QgsOptions::newVisible()
{
return chkAddedVisibility->isChecked();
}

void QgsOptions::getEllipsoidList()
void QgsOptions::populateEllipsoidList()
{
// (copied from qgscustomprojectiondialog.cpp)

//
// Populate the ellipsoid combo
// Populate the ellipsoid list
//
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
EllipsoidDefs myItem, i;

myItem.acronym = GEO_NONE;
myItem.description = tr( GEO_NONE_DESC );
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
mEllipsoidList.append( myItem );

myItem.acronym = QString( "PARAMETER:6370997:6370997" );
myItem.description = tr( "Parameters :" );
myItem.semiMajor = 6370997.0;
myItem.semiMinor = 6370997.0;
mEllipsoidList.append( myItem );

cmbEllipsoid->addItem( tr( GEO_NONE_DESC ) );
//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
Expand All @@ -1189,86 +1228,53 @@ void QgsOptions::getEllipsoidList()
}

// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select * from tbl_ellipsoid order by name";
QString mySql = "select acronym, name, radius, parameter2 from tbl_ellipsoid order by name";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
{
while ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
{
cmbEllipsoid->addItem(( const char * )sqlite3_column_text( myPreparedStatement, 1 ) );
QString para1, para2;
myItem.acronym = ( const char * )sqlite3_column_text( myPreparedStatement, 0 );
myItem.description = ( const char * )sqlite3_column_text( myPreparedStatement, 1 );

// Copied from QgsDistanecArea. Should perhaps be moved there somehow?
// No error checking, this values are for show only, never used in calculations.

// Fall-back values
myItem.semiMajor = 0.0;
myItem.semiMinor = 0.0;
// Crash if no column?
para1 = ( const char * )sqlite3_column_text( myPreparedStatement, 2 );
para2 = ( const char * )sqlite3_column_text( myPreparedStatement, 3 );
myItem.semiMajor = para1.mid( 2 ).toDouble();
if ( para2.left( 2 ) == "b=" )
{
myItem.semiMinor = para2.mid( 2 ).toDouble();
}
else if ( para2.left( 3 ) == "rf=" )
{
double invFlattening = para2.mid( 3 ).toDouble();
if ( invFlattening != 0.0 )
{
myItem.semiMinor = myItem.semiMajor - ( myItem.semiMajor / invFlattening );
}
}
mEllipsoidList.append( myItem );
}
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
}

QString QgsOptions::getEllipsoidAcronym( QString theEllipsoidName )
{
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
QString myName = GEO_NONE;

//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
{
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
Q_ASSERT( myResult == 0 );
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select acronym from tbl_ellipsoid where name='" + theEllipsoidName + "'";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
{
if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
myName = QString(( const char * )sqlite3_column_text( myPreparedStatement, 0 ) );
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
return myName;

}
// Add all items to selector

QString QgsOptions::getEllipsoidName( QString theEllipsoidAcronym )
{
sqlite3 *myDatabase;
const char *myTail;
sqlite3_stmt *myPreparedStatement;
int myResult;
QString myName;

myName = tr( GEO_NONE_DESC );
//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
{
QgsDebugMsg( QString( "Can't open database: %1" ).arg( sqlite3_errmsg( myDatabase ) ) );
// XXX This will likely never happen since on open, sqlite creates the
// database if it does not exist.
Q_ASSERT( myResult == 0 );
}
// Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
QString mySql = "select name from tbl_ellipsoid where acronym='" + theEllipsoidAcronym + "'";
myResult = sqlite3_prepare( myDatabase, mySql.toUtf8(), mySql.toUtf8().length(), &myPreparedStatement, &myTail );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK )
foreach ( i, mEllipsoidList )
{
if ( sqlite3_step( myPreparedStatement ) == SQLITE_ROW )
myName = QString(( const char * )sqlite3_column_text( myPreparedStatement, 0 ) );
cmbEllipsoid->addItem( i.description );
}
// close the sqlite3 statement
sqlite3_finalize( myPreparedStatement );
sqlite3_close( myDatabase );
return myName;

}

QStringList QgsOptions::i18nList()
Expand Down Expand Up @@ -1678,3 +1684,54 @@ void QgsOptions::saveContrastEnhancement( QComboBox *cbox, QString name )
QString value = cbox->itemData( cbox->currentIndex() ).toString();
settings.setValue( "/Raster/defaultContrastEnhancementAlgorithm/" + name, value );
}

void QgsOptions::updateEllipsoidUI( int newIndex )
{
// Called whenever settings change, adjusts the UI accordingly
// Pre-select current ellipsoid

// Check if CRS transformation is on, or else turn everything off
double myMajor = mEllipsoidList[ newIndex ].semiMajor;
double myMinor = mEllipsoidList[ newIndex ].semiMinor;

// If user has modified the radii (only possible if parametric!), before
// changing ellipsoid, save the modified coordinates
if ( leSemiMajor->isModified() || leSemiMinor->isModified() )
{
QgsDebugMsg( "Saving major/minor" );
mEllipsoidList[ mEllipsoidIndex ].semiMajor = QLocale::system().toDouble( leSemiMajor->text() );
mEllipsoidList[ mEllipsoidIndex ].semiMinor = QLocale::system().toDouble( leSemiMinor->text() );
}

mEllipsoidIndex = newIndex;
leSemiMajor->setEnabled( false );
leSemiMinor->setEnabled( false );
leSemiMajor->setText( "" );
leSemiMinor->setText( "" );
if ( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() )
{
cmbEllipsoid->setEnabled( true );
cmbEllipsoid->setToolTip( "" );
if ( mEllipsoidList[ mEllipsoidIndex ].acronym.startsWith( "PARAMETER:" ) )
{
leSemiMajor->setEnabled( true );
leSemiMinor->setEnabled( true );
}
else
{
leSemiMajor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
leSemiMinor->setToolTip( QString( "Select %1 from pull-down menu to adjust radii" ).arg( tr( "Parameters:" ) ) );
}
cmbEllipsoid->setCurrentIndex( mEllipsoidIndex ); // Not always necessary
if ( mEllipsoidList[ mEllipsoidIndex ].acronym != GEO_NONE )
{
leSemiMajor->setText( QLocale::system().toString( myMajor, 'f', 3 ) );
leSemiMinor->setText( QLocale::system().toString( myMinor, 'f', 3 ) );
}
}
else
{
cmbEllipsoid->setEnabled( false );
cmbEllipsoid->setToolTip( tr( "Can only use ellipsoidal calculations when CRS transformation is enabled" ) );
}
}
26 changes: 20 additions & 6 deletions src/app/qgsoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include <qgscoordinatereferencesystem.h>

#include <QList>

/**
* \class QgsOptions
Expand Down Expand Up @@ -180,12 +181,11 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
*/
void saveGdalDriverList();

protected:
//! Populates combo box with ellipsoids
void getEllipsoidList();

QString getEllipsoidAcronym( QString theEllipsoidName );
QString getEllipsoidName( QString theEllipsoidAcronym );
/* Update ComboBox accorindg to the selected new index
* Also sets the new selected Ellipsoid.
* @note added in 2.0
*/
void updateEllipsoidUI( int newIndex );

private:
QStringList i18nList();
Expand All @@ -195,6 +195,20 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase
QgsCoordinateReferenceSystem mLayerDefaultCrs;
bool mLoadedGdalDriverList;

// List for all ellispods, also None and Custom
struct EllipsoidDefs
{
QString acronym;
QString description;
double semiMajor;
double semiMinor;
};
QList<EllipsoidDefs> mEllipsoidList;
int mEllipsoidIndex;

//! Populates list with ellipsoids from Sqlite3 db
void populateEllipsoidList();

static const char * GEO_NONE_DESC;
};

Expand Down
400 changes: 15 additions & 385 deletions src/app/qgsvectorlayerproperties.cpp

Large diffs are not rendered by default.

18 changes: 4 additions & 14 deletions src/app/qgsvectorlayerproperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class QgsLabelDialog;
class QgsVectorLayer;
class QgsVectorOverlayPlugin;
class QgsLabelingGui;
class QgsDiagramProperties;

class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase
{
Expand Down Expand Up @@ -119,14 +120,6 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_pbnSelectEditForm_clicked();
void on_tabWidget_currentChanged( int idx );
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
void on_mAddCategoryPushButton_clicked();
void on_mRemoveCategoryPushButton_clicked();
void on_mDiagramFontButton_clicked();
void on_mFixedSizeCheckBox_stateChanged( int state );
void on_mScaleDependentDiagramVisibilityCheckBox_stateChanged( int state );
void on_mFindMaximumValueButton_clicked();
void on_mBackgroundColorButton_clicked();
void on_mDiagramPenColorButton_clicked();
void on_pbnUpdateExtents_clicked();

void enableLabelOptions( bool theFlag );
Expand All @@ -142,9 +135,6 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_mButtonAddJoin_clicked();
void on_mButtonRemoveJoin_clicked();

/**Set color for diagram category*/
void handleDiagramItemDoubleClick( QTreeWidgetItem * item, int column );

signals:

/** emitted when changes to layer were saved to update legend */
Expand Down Expand Up @@ -187,11 +177,13 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
/**Buffer renderer, which is assigned to the vector layer when apply is pressed*/
//QgsRenderer* bufferRenderer;
/**Labeling dialog. If apply is pressed, options are applied to vector's QgsLabel */
QgsLabelingGui *labelingDialog;
QgsLabelingGui* labelingDialog;
/**Label dialog. If apply is pressed, options are applied to vector's QgsLabel */
QgsLabelDialog* labelDialog;
/**Actions dialog. If apply is pressed, the actions are stored for later use */
QgsAttributeActionDialog* actionDialog;
/**Diagram dialog. If apply is pressed, options are applied to vector's diagrams*/
QgsDiagramProperties* diagramPropertiesDialog;

QList<QgsApplyDialog*> mOverlayDialogs;
QMap<int, QPushButton*> mButtonMap;
Expand All @@ -201,8 +193,6 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
QMap<int, QgsVectorLayer::ValueRelationData> mValueRelationData;
QMap<int, QPair<QString, QString> > mCheckedStates;

QFont mDiagramFont;

void updateButtons();
void loadRows();
void setRow( int row, int idx, const QgsField &field );
Expand Down
22 changes: 20 additions & 2 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ SET(QGIS_CORE_SRCS
symbology-ng/qgsellipsesymbollayerv2.cpp
symbology-ng/qgspointdisplacementrenderer.cpp
symbology-ng/qgsvectorfieldsymbollayer.cpp


diagram/qgsdiagram.cpp
diagram/qgspiediagram.cpp
diagram/qgstextdiagram.cpp
diagram/qgshistogramdiagram.cpp

qgis.cpp
qgsapplication.cpp
qgsattributeaction.cpp
Expand All @@ -55,7 +60,6 @@ SET(QGIS_CORE_SRCS
qgsdatasourceuri.cpp
qgsdataitem.cpp
qgsdbfilterproxymodel.cpp
qgsdiagram.cpp
qgsdiagramrendererv2.cpp
qgsdistancearea.cpp
qgsexpression.cpp
Expand Down Expand Up @@ -96,6 +100,7 @@ SET(QGIS_CORE_SRCS
qgsrasterprojector.cpp
qgsrasterdataprovider.cpp
qgsrendercontext.cpp
qgsrenderchecker.cpp
qgsrectangle.cpp
qgsrunprocess.cpp
qgsscalecalculator.cpp
Expand Down Expand Up @@ -164,6 +169,7 @@ SET(QGIS_CORE_SRCS
raster/qgslinearminmaxenhancement.cpp
raster/qgslinearminmaxenhancementwithclip.cpp
raster/qgspseudocolorshader.cpp
raster/qgsrasterchecker.cpp
raster/qgsrasterinterface.cpp
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
Expand Down Expand Up @@ -376,6 +382,7 @@ SET(QGIS_CORE_HDRS
qgsrasterdataprovider.h
qgsrectangle.h
qgsrendercontext.h
qgsrenderchecker.h
qgsrunprocess.h
qgsscalecalculator.h
qgssnapper.h
Expand All @@ -387,6 +394,12 @@ SET(QGIS_CORE_HDRS
qgsvectoroverlay.h
qgstolerance.h

diagram/qgsdiagram.h
diagram/qgspiediagram.h
diagram/qgstextdiagram.h
diagram/qgshistogramdiagram.h


composer/qgslegendmodel.h
composer/qgscomposerlegenditem.h

Expand All @@ -399,6 +412,7 @@ SET(QGIS_CORE_HDRS
raster/qgslinearminmaxenhancement.h
raster/qgslinearminmaxenhancementwithclip.h
raster/qgspseudocolorshader.h
raster/qgsrasterchecker.h
raster/qgsrasterpyramid.h
raster/qgsrasterbandstats.h
raster/qgsrasterhistogram.h
Expand Down Expand Up @@ -492,6 +506,9 @@ ELSE (WIN32)
ADD_DEFINITIONS("-D_HAVE_PTHREAD_")
ENDIF (WIN32)

# Test data dir for QgsRenderChecker
ADD_DEFINITIONS(-DTEST_DATA_DIR="\\"${TEST_DATA_DIR}\\"")

#############################################################
# qgis_core library

Expand Down Expand Up @@ -581,3 +598,4 @@ IF (APPLE AND QGIS_MACAPP_INSTALL_DEV)
INSTALL(TARGETS qgis_core FRAMEWORK DESTINATION ${QGIS_MACAPP_DEV_PREFIX})
INSTALL(CODE "EXECUTE_PROCESS(COMMAND install_name_tool -id \"${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/Versions/${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}/qgis_core\" \"$ENV{DESTDIR}${QGIS_MACAPP_DEV_PREFIX}/qgis_core.framework/qgis_core\")")
ENDIF (APPLE AND QGIS_MACAPP_INSTALL_DEV)

4 changes: 2 additions & 2 deletions src/core/composer/qgscomposermultiframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@ void QgsComposerMultiFrame::deleteFrames()
{
ResizeMode bkResizeMode = mResizeMode;
mResizeMode = UseExistingFrames;
mComposition->blockSignals( true );
QObject::disconnect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
for ( ; frameIt != mFrameItems.end(); ++frameIt )
{
mComposition->removeComposerItem( *frameIt, false );
delete *frameIt;
}
mComposition->blockSignals( false );
QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
mFrameItems.clear();
mResizeMode = bkResizeMode;
}
Expand Down
74 changes: 67 additions & 7 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ QgsComposition::QgsComposition():
QgsComposition::~QgsComposition()
{
removePaperItems();

QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin();
for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt )
{
delete *multiFrameIt;
}
mMultiFrames.clear();
deleteAndRemoveMultiFrames();

// make sure that all composer items are removed before
// this class is deconstructed - to avoid segfaults
Expand Down Expand Up @@ -320,6 +314,62 @@ bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocu
return true;
}

bool QgsComposition::loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap, bool addUndoCommands )
{
deleteAndRemoveMultiFrames();

//delete all items and emit itemRemoved signal
QList<QGraphicsItem *> itemList = items();
QList<QGraphicsItem *>::iterator itemIter = itemList.begin();
for ( ; itemIter != itemList.end(); ++itemIter )
{
QgsComposerItem* cItem = dynamic_cast<QgsComposerItem*>( *itemIter );
if ( cItem )
{
removeItem( cItem );
emit itemRemoved( cItem );
delete cItem;
}
}
mItemZList.clear();

mPages.clear();
mUndoStack.clear();

QDomDocument importDoc;
if ( substitutionMap )
{
QString xmlString = doc.toString();
QMap<QString, QString>::const_iterator sIt = substitutionMap->constBegin();
for ( ; sIt != substitutionMap->constEnd(); ++sIt )
{
xmlString = xmlString.replace( "[" + sIt.key() + "]", sIt.value() );
}
importDoc.setContent( xmlString );
}
else
{
importDoc = doc;
}

//read general settings
QDomElement compositionElem = importDoc.documentElement().firstChildElement( "Composition" );
if ( compositionElem.isNull() )
{
return false;
}

bool ok = readXML( compositionElem, importDoc );
if ( !ok )
{
return false;
}

//addItemsFromXML
addItemsFromXML( importDoc.documentElement(), importDoc, 0, addUndoCommands, 0 );
return true;
}

void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocument& doc, QMap< QgsComposerMap*, int >* mapsToRestore,
bool addUndoCommands, QPointF* pos )
{
Expand Down Expand Up @@ -1374,6 +1424,16 @@ void QgsComposition::removePaperItems()
mPages.clear();
}

void QgsComposition::deleteAndRemoveMultiFrames()
{
QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin();
for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt )
{
delete *multiFrameIt;
}
mMultiFrames.clear();
}

void QgsComposition::exportAsPDF( const QString& file )
{
QPrinter printer;
Expand Down
24 changes: 24 additions & 0 deletions src/core/composer/qgscomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Returns pointers to all composer maps in the scene*/
QList<const QgsComposerMap*> composerMapItems() const;

/**Return composer items of a specific type*/
template<class T> void composerItems( QList<T*>& itemList );

/**Returns the composer map with specified id
@return id or 0 pointer if the composer map item does not exist*/
const QgsComposerMap* getComposerMapById( int id ) const;
Expand Down Expand Up @@ -153,6 +156,11 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Reads settings from xml file*/
bool readXML( const QDomElement& compositionElem, const QDomDocument& doc );

/**Load a template document
@param doc template document
@param substitutionMap map with text to replace. Text needs to be enclosed by brackets (e.g. '[text]' )*/
bool loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap = 0, bool addUndoCommands = false );

/**Add items from XML representation to the graphics scene (for project file reading, pasting items from clipboard)
@param elem items parent element, e.g. \verbatim <Composer> \endverbatim or \verbatim <ComposerItemClipboard> \endverbatim
@param doc xml document
Expand Down Expand Up @@ -308,6 +316,7 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
void updatePaperItems();
void addPaperItem();
void removePaperItems();
void deleteAndRemoveMultiFrames();

signals:
void paperSizeChanged();
Expand Down Expand Up @@ -337,6 +346,21 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
void itemRemoved( QgsComposerItem* );
};

template<class T> void QgsComposition::composerItems( QList<T*>& itemList )
{
itemList.clear();
QList<QGraphicsItem *> graphicsItemList = items();
QList<QGraphicsItem *>::iterator itemIt = graphicsItemList.begin();
for ( ; itemIt != graphicsItemList.end(); ++itemIt )
{
T* item = dynamic_cast<T*>( *itemIt );
if ( item )
{
itemList.push_back( item );
}
}
}

#endif


Expand Down
71 changes: 71 additions & 0 deletions src/core/diagram/qgsdiagram.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/***************************************************************************
qgsdiagram.cpp
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"

#include <QPainter>

void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
pen.setWidthF( s.penWidth * c.scaleFactor() );
}
else
{
pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
}
}


QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
return QSizeF( size.width() * c.scaleFactor(), size.height() * c.scaleFactor() );
}
else
{
return QSizeF( size.width() / c.mapToPixel().mapUnitsPerPixel(), size.height() / c.mapToPixel().mapUnitsPerPixel() );
}
}

float QgsDiagram::sizePainterUnits( float l, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
return l * c.scaleFactor();
}
else
{
return l / c.mapToPixel().mapUnitsPerPixel();
}
}

QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
{
QFont f = s.font;
if ( s.sizeType == QgsDiagramSettings::MM )
{
f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
}
else
{
f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
}

return f;
}
79 changes: 79 additions & 0 deletions src/core/diagram/qgsdiagram.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/***************************************************************************
qgsdiagram.h
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef QGSDIAGRAM_H
#define QGSDIAGRAM_H

#include "qgsfeature.h"
#include <QPen>
#include <QBrush>

class QPainter;
class QPointF;
struct QgsDiagramSettings;
struct QgsDiagramInterpolationSettings;

class QgsRenderContext;



/**Base class for all diagram types*/
class CORE_EXPORT QgsDiagram
{
public:
virtual ~QgsDiagram() {}
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual QString diagramName() const = 0;
/**Returns the size in map units the diagram will use to render.*/
virtual QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s ) = 0;
/**Returns the size in map units the diagram will use to render. Interpolate size*/
virtual QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) = 0;

protected:
/** Changes the pen width to match the current settings and rendering context
* @param pen The pen to modify
* @param s The settings that specify the pen width
* @param c The rendering specifying the proper scale units for pixel conversion
*/
void setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c );

/** Calculates a size to match the current settings and rendering context
* @param size The size to convert
* @param s The settings that specify the size type
* @param c The rendering specifying the proper scale units for pixel conversion
*
* @return The converted size for rendering
*/
QSizeF sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c );

/** Calculates a length to match the current settings and rendering context
* @param l The length to convert
* @param s Unused
* @param c The rendering specifying the proper scale units for pixel conversion
*
* @return The converted length for rendering
*/
float sizePainterUnits( float l, const QgsDiagramSettings& s, const QgsRenderContext& c );

/** Calculates a size to match the current settings and rendering context
* @param s The settings that contain the font size and size type
* @param c The rendering specifying the proper scale units for pixel conversion
*
* @return The properly scaled font for rendering
*/
QFont scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c );
};

#endif // QGSDIAGRAM_H
167 changes: 167 additions & 0 deletions src/core/diagram/qgshistogramdiagram.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/***************************************************************************
qgshistogramdiagram.cpp
---------------------
begin : August 2012
copyright : (C) 2012 by Matthias Kuhn
email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgshistogramdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"

#include <QPainter>

QgsHistogramDiagram::QgsHistogramDiagram()
{
mCategoryBrush.setStyle( Qt::SolidPattern );
mPen.setStyle( Qt::SolidLine );
mScaleFactor = 0;
}

QgsHistogramDiagram::~QgsHistogramDiagram()
{
}

QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
Q_UNUSED( c );
QSize size;
QgsAttributeMap::const_iterator attIt = attributes.constBegin();
if ( attIt == attributes.constEnd() )
{
return QSizeF(); //zero size if no attributes
}

double maxValue = attIt.value().toDouble();

for ( ++attIt; attIt != attributes.constEnd(); ++attIt )
{
maxValue = qMax( attIt.value().toDouble(), maxValue );
}

// Scale, if extension is smaller than the specified minimum
if ( maxValue < s.minimumSize )
{
maxValue = s.minimumSize;
}

switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
case QgsDiagramSettings::Down:
mScaleFactor = (( is.upperSize.width() - is.lowerSize.height() ) / ( is.upperValue - is.lowerValue ) );
size.scale( s.barWidth * attributes.size(), maxValue * mScaleFactor, Qt::IgnoreAspectRatio );
break;

case QgsDiagramSettings::Right:
case QgsDiagramSettings::Left:
mScaleFactor = (( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) );
size.scale( maxValue * mScaleFactor, s.barWidth * attributes.size(), Qt::IgnoreAspectRatio );
break;
}

return size;
}

QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s )
{
Q_UNUSED( c );
QSizeF size;

QgsAttributeMap::const_iterator attIt = attributes.constBegin();
if ( attIt == attributes.constEnd() )
{
return QSizeF(); //zero size if no attributes
}

double maxValue = attIt.value().toDouble();

for ( ; attIt != attributes.constEnd(); ++attIt )
{
maxValue = qMax( attIt.value().toDouble(), maxValue );
}

switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
case QgsDiagramSettings::Down:
mScaleFactor = maxValue / s.size.height();
size.scale( s.barWidth * s.categoryColors.size(), s.size.height(), Qt::IgnoreAspectRatio );
break;

case QgsDiagramSettings::Right:
case QgsDiagramSettings::Left:
default: // just in case...
mScaleFactor = maxValue / s.size.width();
size.scale( s.size.width(), s.barWidth * s.categoryColors.size(), Qt::IgnoreAspectRatio );
break;
}

return size;
}

void QgsHistogramDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
{
return;
}

QList<double> values;

QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
{
double currentVal = att[*catIt].toDouble();
values.push_back( currentVal );
}

double currentOffset = 0;
double scaledWidth = sizePainterUnits( s.barWidth, s, c );

double baseX = position.x();
double baseY = position.y();

mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );

QList<double>::const_iterator valIt = values.constBegin();
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
{
double length = sizePainterUnits( *valIt * mScaleFactor, s, c );

mCategoryBrush.setColor( *colIt );
p->setBrush( mCategoryBrush );

switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
p->drawRect( baseX + currentOffset, baseY, scaledWidth, 0 - length );
break;

case QgsDiagramSettings::Down:
p->drawRect( baseX + currentOffset, baseY, scaledWidth, length );
break;

case QgsDiagramSettings::Right:
p->drawRect( baseX, baseY + currentOffset, length, scaledWidth );
break;

case QgsDiagramSettings::Left:
p->drawRect( baseX, baseY + currentOffset, 0 - length, scaledWidth );
break;
}

currentOffset += scaledWidth;
}
}
52 changes: 52 additions & 0 deletions src/core/diagram/qgshistogramdiagram.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***************************************************************************
qgshistogramdiagram.h
---------------------
begin : August 2012
copyright : (C) 2012 by Matthias Kuhn
email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#ifndef QGSHISTOGRAMDIAGRAM_H
#define QGSHISTOGRAMDIAGRAM_H

#define DIAGRAM_NAME_HISTOGRAM "Histogram"

#include "qgsdiagram.h"
#include "qgsfeature.h"
#include <QPen>
#include <QBrush>

class QPainter;
class QPointF;
struct QgsDiagramSettings;
struct QgsDiagramInterpolationSettings;

class QgsRenderContext;


class CORE_EXPORT QgsHistogramDiagram: public QgsDiagram
{
public:
QgsHistogramDiagram();
~QgsHistogramDiagram();

void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const { return DIAGRAM_NAME_HISTOGRAM; }

private:
QBrush mCategoryBrush;
QPen mPen;
double mScaleFactor;
};


#endif // QGSHISTOGRAMDIAGRAM_H
153 changes: 153 additions & 0 deletions src/core/diagram/qgspiediagram.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/***************************************************************************
qgspiediagram.cpp
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgspiediagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"

#include <QPainter>


QgsPieDiagram::QgsPieDiagram()
{
mCategoryBrush.setStyle( Qt::SolidPattern );
mPen.setStyle( Qt::SolidLine );
}

QgsPieDiagram::~QgsPieDiagram()
{
}

QSizeF QgsPieDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
Q_UNUSED( c );
QgsAttributeMap::const_iterator attIt = attributes.find( is.classificationAttribute );
if ( attIt == attributes.constEnd() )
{
return QSizeF(); //zero size if attribute is missing
}

double scaledValue = attIt.value().toDouble();
double scaledLowerValue = is.lowerValue;
double scaledUpperValue = is.upperValue;
double scaledLowerSizeWidth = is.lowerSize.width();
double scaledLowerSizeHeight = is.lowerSize.height();
double scaledUpperSizeWidth = is.upperSize.width();
double scaledUpperSizeHeight = is.upperSize.height();

// interpolate the squared value if scale by area
if ( s.scaleByArea )
{
scaledValue = sqrt( scaledValue );
scaledLowerValue = sqrt( scaledLowerValue );
scaledUpperValue = sqrt( scaledUpperValue );
scaledLowerSizeWidth = sqrt( scaledLowerSizeWidth );
scaledLowerSizeHeight = sqrt( scaledLowerSizeHeight );
scaledUpperSizeWidth = sqrt( scaledUpperSizeWidth );
scaledUpperSizeHeight = sqrt( scaledUpperSizeHeight );
}

//interpolate size
double scaledRatio = ( scaledValue - scaledLowerValue ) / ( scaledUpperValue - scaledLowerValue );

QSizeF size = QSizeF( is.upperSize.width() * scaledRatio + is.lowerSize.width() * ( 1 - scaledRatio ),
is.upperSize.height() * scaledRatio + is.lowerSize.height() * ( 1 - scaledRatio ) );

// Scale, if extension is smaller than the specified minimum
if ( size.width() <= s.minimumSize && size.height() <= s.minimumSize )
{
size.scale( s.minimumSize, s.minimumSize, Qt::KeepAspectRatio );
}

return size;
}

QSizeF QgsPieDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s )
{
Q_UNUSED( c );
Q_UNUSED( attributes );
return s.size;
}

int QgsPieDiagram::sCount = 0;

void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
{
return;
}

//get sum of values
QList<double> values;
double currentVal = 0;
double valSum = 0;
int valCount = 0;

QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
{
currentVal = att[*catIt].toDouble();
values.push_back( currentVal );
valSum += currentVal;
if ( currentVal ) valCount++;
}

//draw the slices
double totalAngle = 0;
double currentAngle;

//convert from mm / map units to painter units
QSizeF spu = sizePainterUnits( s.size, s, c );
double w = spu.width();
double h = spu.height();

double baseX = position.x();
double baseY = position.y() - h;

mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );

// there are some values > 0 available
if ( valSum > 0 )
{
QList<double>::const_iterator valIt = values.constBegin();
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
{
currentAngle = *valIt / valSum * 360 * 16;
mCategoryBrush.setColor( *colIt );
p->setBrush( mCategoryBrush );
// if only 1 value is > 0, draw a circle
if ( valCount == 1 )
{
p->drawEllipse( baseX, baseY, w, h );
}
else
{
p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
}
totalAngle += currentAngle;
}
}
else // valSum > 0
{
// draw empty circle if no values are defined at all
mCategoryBrush.setColor( Qt::transparent );
p->setBrush( mCategoryBrush );
p->drawEllipse( baseX, baseY, w, h );
}
}
50 changes: 50 additions & 0 deletions src/core/diagram/qgspiediagram.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/***************************************************************************
qgspiediagram.h
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef QGSPIEDIAGRAM_H
#define QGSPIEDIAGRAM_H

#define DIAGRAM_NAME_PIE "Pie"

#include "qgsdiagram.h"
#include "qgsfeature.h"
#include <QPen>
#include <QBrush>

class QPainter;
class QPointF;
struct QgsDiagramSettings;
struct QgsDiagramInterpolationSettings;

class QgsRenderContext;

class CORE_EXPORT QgsPieDiagram: public QgsDiagram
{
public:
QgsPieDiagram();
~QgsPieDiagram();

void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const { return DIAGRAM_NAME_PIE; }

private:
QBrush mCategoryBrush;
QPen mPen;

static int sCount;
};

#endif // QGSPIEDIAGRAM_H
168 changes: 69 additions & 99 deletions src/core/qgsdiagram.cpp → src/core/diagram/qgstextdiagram.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
qgsdiagram.cpp
qgstextdiagram.cpp
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
Expand All @@ -12,62 +12,76 @@
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsdiagram.h"
#include "qgstextdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"

#include <QPainter>

void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
pen.setWidthF( s.penWidth * c.scaleFactor() );
}
else
{
pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
}
mPen.setWidthF( 2.0 );
mPen.setColor( QColor( 0, 0, 0 ) );
mPen.setCapStyle( Qt::FlatCap );
mBrush.setStyle( Qt::SolidPattern );
}

QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
QgsTextDiagram::~QgsTextDiagram()
{
Q_UNUSED( size );
if ( s.sizeType == QgsDiagramSettings::MM )
{
return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
}
else
{
return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
}
}

QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
QSizeF QgsTextDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is )
{
QFont f = s.font;
if ( s.sizeType == QgsDiagramSettings::MM )
Q_UNUSED( c );

QgsAttributeMap::const_iterator attIt = attributes.find( is.classificationAttribute );

if ( attIt == attributes.constEnd() )
{
f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
return QSizeF(); //zero size if attribute is missing
}
else

double scaledValue = attIt.value().toDouble();
double scaledLowerValue = is.lowerValue;
double scaledUpperValue = is.upperValue;
double scaledLowerSizeWidth = is.lowerSize.width();
double scaledLowerSizeHeight = is.lowerSize.height();
double scaledUpperSizeWidth = is.upperSize.width();
double scaledUpperSizeHeight = is.upperSize.height();

// interpolate the squared value if scale by area
if ( s.scaleByArea )
{
f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
scaledValue = sqrt( scaledValue );
scaledLowerValue = sqrt( scaledLowerValue );
scaledUpperValue = sqrt( scaledUpperValue );
scaledLowerSizeWidth = sqrt( scaledLowerSizeWidth );
scaledLowerSizeHeight = sqrt( scaledLowerSizeHeight );
scaledUpperSizeWidth = sqrt( scaledUpperSizeWidth );
scaledUpperSizeHeight = sqrt( scaledUpperSizeHeight );
}

return f;
}
//interpolate size
double scaledRatio = ( scaledValue - scaledLowerValue ) / ( scaledUpperValue - scaledLowerValue );

QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
{
mPen.setWidthF( 2.0 );
mPen.setColor( QColor( 0, 0, 0 ) );
mPen.setCapStyle( Qt::FlatCap );
mBrush.setStyle( Qt::SolidPattern );
QSizeF size = QSizeF( is.upperSize.width() * scaledRatio + is.lowerSize.width() * ( 1 - scaledRatio ),
is.upperSize.height() * scaledRatio + is.lowerSize.height() * ( 1 - scaledRatio ) );

// Scale, if extension is smaller than the specified minimum
if ( size.width() <= s.minimumSize && size.height() <= s.minimumSize )
{
size.scale( s.minimumSize, s.minimumSize, Qt::KeepAspectRatio );
}

return size;
}

QgsTextDiagram::~QgsTextDiagram()
{
QSizeF QgsTextDiagram::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s )
{
Q_UNUSED( c );
Q_UNUSED( attributes );

return s.size;
}

void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
Expand Down Expand Up @@ -197,13 +211,28 @@ void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext
for ( int i = 0; i < textPositions.size(); ++i )
{
QString val = att[ s.categoryIndices.at( i )].toString();
//find out dimensions
double textHeight = fontMetrics.height();
//find out dimesions
double textWidth = fontMetrics.width( val );
double textHeight = fontMetrics.height();

mPen.setColor( s.categoryColors.at( i ) );
p->setPen( mPen );
QPointF position = textPositions.at( i );
p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + textHeight / 2.0 ), val );

// Calculate vertical placement
double xOffset = 0;

switch( s.labelPlacementMethod )
{
case QgsDiagramSettings::Height:
xOffset = textHeight / 2.0;
break;

case QgsDiagramSettings::XHeight:
xOffset = fontMetrics.xHeight();
break;
}
p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + xOffset ), val );
}
}

Expand Down Expand Up @@ -237,62 +266,3 @@ void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QP
}
}
}

QgsPieDiagram::QgsPieDiagram()
{
mCategoryBrush.setStyle( Qt::SolidPattern );
mPen.setStyle( Qt::SolidLine );
}

QgsPieDiagram::~QgsPieDiagram()
{
}

void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
{
return;
}

//get sum of values
QList<double> values;
double currentVal = 0;
double valSum = 0;

QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
{
currentVal = att[*catIt].toDouble();
values.push_back( currentVal );
valSum += currentVal;
}

//draw the slices
double totalAngle = 0;
double currentAngle;

//convert from mm / map units to painter units
QSizeF spu = sizePainterUnits( s.size, s, c );
double w = spu.width();
double h = spu.height();

double baseX = position.x();
double baseY = position.y() - h;

mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );

QList<double>::const_iterator valIt = values.constBegin();
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
{
currentAngle = *valIt / valSum * 360 * 16;
mCategoryBrush.setColor( *colIt );
p->setBrush( mCategoryBrush );
p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
totalAngle += currentAngle;
}
}
44 changes: 11 additions & 33 deletions src/core/qgsdiagram.h → src/core/diagram/qgstextdiagram.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
qgsdiagram.h
qgstextdiagram.h
---------------------
begin : March 2011
copyright : (C) 2011 by Marco Hugentobler
Expand All @@ -12,33 +12,23 @@
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSDIAGRAM_H
#define QGSDIAGRAM_H
#ifndef QGSTEXTDIAGRAM_H
#define QGSTEXTDIAGRAM_H

#define DIAGRAM_NAME_TEXT "Text"

#include "qgsdiagram.h"
#include "qgsfeature.h"
#include <QPen>
#include <QBrush>

class QPainter;
class QPointF;
struct QgsDiagramSettings;
struct QgsDiagramInterpolationSettings;

class QgsRenderContext;

/**Base class for all diagram types*/
class CORE_EXPORT QgsDiagram
{
public:
virtual ~QgsDiagram() {}
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual QString diagramName() const = 0;

protected:
void setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c );
QSizeF sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c );
QFont scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c );
};

class CORE_EXPORT QgsTextDiagram: public QgsDiagram
{
Expand All @@ -59,8 +49,10 @@ class CORE_EXPORT QgsTextDiagram: public QgsDiagram
QgsTextDiagram();
~QgsTextDiagram();
void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );

QString diagramName() const { return "Text"; }
QString diagramName() const { return DIAGRAM_NAME_TEXT; }

private:
Orientation mOrientation;
Expand All @@ -73,18 +65,4 @@ class CORE_EXPORT QgsTextDiagram: public QgsDiagram
void lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const;
};

class CORE_EXPORT QgsPieDiagram: public QgsDiagram
{
public:
QgsPieDiagram();
~QgsPieDiagram();

void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QString diagramName() const { return "Pie"; }

private:
QBrush mCategoryBrush;
QPen mPen;
};

#endif // QGSDIAGRAM_H
#endif // QGSTEXTDIAGRAM_H
4 changes: 2 additions & 2 deletions src/core/pal/layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
namespace pal
{

Layer::Layer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, Pal *pal )
Layer::Layer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, Pal *pal, bool displayAll )
: pal( pal ), obstacle( obstacle ), active( active ),
toLabel( toLabel ), label_unit( label_unit ),
toLabel( toLabel ), displayAll( displayAll ), label_unit( label_unit ),
min_scale( min_scale ), max_scale( max_scale ),
arrangement( arrangement ), arrangementFlags( 0 ), mode( LabelPerFeature ), mergeLines( false )
{
Expand Down
5 changes: 4 additions & 1 deletion src/core/pal/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace pal

public:
enum LabelMode { LabelPerFeature, LabelPerFeaturePart };
bool getDisplayAll() const { return displayAll; }

protected:
char *name; /* unique */
Expand All @@ -92,6 +93,7 @@ namespace pal
bool obstacle;
bool active;
bool toLabel;
bool displayAll;

Units label_unit;

Expand Down Expand Up @@ -126,9 +128,10 @@ namespace pal
* @param active is the layer is active (currently displayed)
* @param toLabel the layer will be labeled whether toLablel is true
* @param pal pointer to the pal object
* @param displayAll if true, all features will be labelled even though overlaps occur
*
*/
Layer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, Pal *pal );
Layer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, Pal *pal, bool displayAll = false );

/**
* \brief Delete the layer
Expand Down
4 changes: 2 additions & 2 deletions src/core/pal/pal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ namespace pal
}


Layer * Pal::addLayer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel )
Layer * Pal::addLayer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, bool displayAll )
{
Layer *lyr;
lyrsMutex->lock();
Expand All @@ -187,7 +187,7 @@ namespace pal
}
}

lyr = new Layer( lyrName, min_scale, max_scale, arrangement, label_unit, defaultPriority, obstacle, active, toLabel, this );
lyr = new Layer( lyrName, min_scale, max_scale, arrangement, label_unit, defaultPriority, obstacle, active, toLabel, this, displayAll );
layers->push_back( lyr );

lyrsMutex->unlock();
Expand Down
3 changes: 2 additions & 1 deletion src/core/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,13 @@ namespace pal
* @param obstacle 'true' will discourage other label to be placed above features of this layer
* @param active is the layer is active (currently displayed)
* @param toLabel the layer will be labeled only if toLablel is true
* @param displayAll if true, all features will be labelled even though overlaps occur
*
* @throws PalException::LayerExists
*
* @todo add symbolUnit
*/
Layer * addLayer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel );
Layer * addLayer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, bool displayAll = false );

/**
* \brief Look for a layer
Expand Down
21 changes: 20 additions & 1 deletion src/core/pal/problem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2939,20 +2939,39 @@ namespace pal
//#undef _DEBUG_FULL_
#endif

bool Problem::compareLabelArea( pal::LabelPosition* l1, pal::LabelPosition* l2 )
{
return l1->getWidth() * l1->getHeight() > l2->getWidth() * l2->getHeight();
}

std::list<LabelPosition*> * Problem::getSolution( bool returnInactive )
{

int i;
std::list<LabelPosition*> *solList = new std::list<LabelPosition*>();

if ( nbft == 0 )
{
return solList;
}

for ( i = 0; i < nbft; i++ )
{
if ( sol->s[i] != -1 )
{
solList->push_back( labelpositions[sol->s[i]] ); // active labels
else if ( returnInactive )
}
else if ( returnInactive || labelpositions[featStartId[i]]->getFeaturePart()->getLayer()->getDisplayAll() )
{
solList->push_back( labelpositions[featStartId[i]] ); // unplaced label
}
}

// if features collide, order by size, so smaller ones appear on top
if ( returnInactive )
{
solList->sort( compareLabelArea );
}

return solList;
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/pal/problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ namespace pal
void init_sol_empty();
void init_sol_falp();

static bool compareLabelArea( pal::LabelPosition* l1, pal::LabelPosition* l2 );

#ifdef _EXPORT_MAP_
void drawLabels( std::ofstream &svgmap );
#endif
Expand Down
158 changes: 128 additions & 30 deletions src/core/qgsdiagramrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
* *
***************************************************************************/
#include "qgsdiagramrendererv2.h"
#include "qgsdiagram.h"
#include "diagram/qgstextdiagram.h"
#include "diagram/qgspiediagram.h"
#include "diagram/qgshistogramdiagram.h"
#include "qgsrendercontext.h"
#include <QDomElement>
#include <QPainter>
Expand Down Expand Up @@ -50,8 +52,12 @@ void QgsDiagramSettings::readXML( const QDomElement& elem )
backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
size.setWidth( elem.attribute( "width" ).toDouble() );
size.setHeight( elem.attribute( "height" ).toDouble() );
transparency = elem.attribute( "transparency", "0" ).toInt();
penColor.setNamedColor( elem.attribute( "penColor" ) );
int penAlpha = elem.attribute( "penAlpha", "255" ).toInt();
penColor.setAlpha( penAlpha );
penWidth = elem.attribute( "penWidth" ).toDouble();

minScaleDenominator = elem.attribute( "minScaleDenominator", "-1" ).toDouble();
maxScaleDenominator = elem.attribute( "maxScaleDenominator", "-1" ).toDouble();

Expand All @@ -65,13 +71,57 @@ void QgsDiagramSettings::readXML( const QDomElement& elem )
sizeType = MapUnits;
}

//label placement method
if ( elem.attribute( "labelPlacementMethod" ) == "Height" )
{
labelPlacementMethod = Height;
}
else
{
labelPlacementMethod = XHeight;
}

// orientation
if ( elem.attribute( "diagramOrientation" ) == "Left" )
{
diagramOrientation = Left;
}
else if ( elem.attribute( "diagramOrientation" ) == "Right" )
{
diagramOrientation = Right;
}
else if ( elem.attribute( "diagramOrientation" ) == "Down" )
{
diagramOrientation = Down;
}
else
{
diagramOrientation = Up;
}

// scale dependency
if ( elem.attribute( "scaleDependency" ) == "Diameter" )
{
scaleByArea = false;
}
else
{
scaleByArea = true;
}

barWidth = elem.attribute( "barWidth" ).toDouble();

minimumSize = elem.attribute( "minimumSize" ).toDouble();

//colors
categoryColors.clear();
QStringList colorList = elem.attribute( "colors" ).split( "/" );
QStringList::const_iterator colorIt = colorList.constBegin();
for ( ; colorIt != colorList.constEnd(); ++colorIt )
{
categoryColors.append( QColor( *colorIt ) );
QColor newColor( *colorIt );
newColor.setAlpha( 255 - transparency );
categoryColors.append( QColor( newColor ) );
}

//attribute indices
Expand All @@ -93,9 +143,13 @@ void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc
categoryElem.setAttribute( "width", QString::number( size.width() ) );
categoryElem.setAttribute( "height", QString::number( size.height() ) );
categoryElem.setAttribute( "penColor", penColor.name() );
categoryElem.setAttribute( "penAlpha", penColor.alpha() );
categoryElem.setAttribute( "penWidth", QString::number( penWidth ) );
categoryElem.setAttribute( "minScaleDenominator", QString::number( minScaleDenominator ) );
categoryElem.setAttribute( "maxScaleDenominator", QString::number( maxScaleDenominator ) );
categoryElem.setAttribute( "transparency", QString::number( transparency ) );

// site type (mm vs. map units)
if ( sizeType == MM )
{
categoryElem.setAttribute( "sizeType", "MM" );
Expand All @@ -105,6 +159,52 @@ void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc
categoryElem.setAttribute( "sizeType", "MapUnits" );
}

// label placement method (text diagram)
if ( labelPlacementMethod == Height )
{
categoryElem.setAttribute( "labelPlacementMethod", "Height" );
}
else
{
categoryElem.setAttribute( "labelPlacementMethod", "XHeight" );
}

if ( scaleByArea )
{
categoryElem.setAttribute( "scaleDependency", "Area" );
}
else
{
categoryElem.setAttribute( "scaleDependency", "Diameter" );
}

// orientation (histogram)
switch ( diagramOrientation )
{
case Left:
categoryElem.setAttribute( "diagramOrientation", "Left" );
break;

case Right:
categoryElem.setAttribute( "diagramOrientation", "Right" );
break;

case Down:
categoryElem.setAttribute( "diagramOrientation", "Down" );
break;

case Up:
categoryElem.setAttribute( "diagramOrientation", "Up" );
break;

default:
categoryElem.setAttribute( "diagramOrientation", "Up" );
break;
}

categoryElem.setAttribute( "barWidth", QString::number( barWidth ) );
categoryElem.setAttribute( "minimumSize", QString::number( minimumSize ) );

QString colors;
for ( int i = 0; i < categoryColors.size(); ++i )
{
Expand Down Expand Up @@ -214,6 +314,10 @@ void QgsDiagramRendererV2::_readXML( const QDomElement& elem )
{
mDiagram = new QgsTextDiagram();
}
else if ( diagramType == "Histogram" )
{
mDiagram = new QgsHistogramDiagram();
}
else
{
mDiagram = 0;
Expand Down Expand Up @@ -244,6 +348,11 @@ bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsAttributeMap&,
return true;
}

QSizeF QgsSingleCategoryDiagramRenderer::diagramSize( const QgsAttributeMap &attributes, const QgsRenderContext &c )
{
return mDiagram->diagramSize( attributes, c, mSettings );
}

QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
{
QList<QgsDiagramSettings> settingsList;
Expand Down Expand Up @@ -297,38 +406,27 @@ bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsAttribute
QList<int> QgsLinearlyInterpolatedDiagramRenderer::diagramAttributes() const
{
QList<int> attributes = mSettings.categoryIndices;
if ( !attributes.contains( mClassificationAttribute ) )
if ( !attributes.contains( mInterpolationSettings.classificationAttribute ) )
{
attributes.push_back( mClassificationAttribute );
attributes.push_back( mInterpolationSettings.classificationAttribute );
}
return attributes;
}

QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c )
{
Q_UNUSED( c );
QgsAttributeMap::const_iterator attIt = attributes.find( mClassificationAttribute );
if ( attIt == attributes.constEnd() )
{
return QSizeF(); //zero size if attribute is missing
}
double value = attIt.value().toDouble();

//interpolate size
double ratio = ( value - mLowerValue ) / ( mUpperValue - mLowerValue );
return QSizeF( mUpperSize.width() * ratio + mLowerSize.width() * ( 1 - ratio ),
mUpperSize.height() * ratio + mLowerSize.height() * ( 1 - ratio ) );
return mDiagram->diagramSize( attributes, c, mSettings, mInterpolationSettings );
}

void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem )
{
mLowerValue = elem.attribute( "lowerValue" ).toDouble();
mUpperValue = elem.attribute( "upperValue" ).toDouble();
mLowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
mLowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
mUpperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
mUpperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
mClassificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
mInterpolationSettings.lowerValue = elem.attribute( "lowerValue" ).toDouble();
mInterpolationSettings.upperValue = elem.attribute( "upperValue" ).toDouble();
mInterpolationSettings.lowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
mInterpolationSettings.lowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
mInterpolationSettings.upperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
mInterpolationSettings.upperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
mInterpolationSettings.classificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
if ( !settingsElem.isNull() )
{
Expand All @@ -340,13 +438,13 @@ void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem )
void QgsLinearlyInterpolatedDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc ) const
{
QDomElement rendererElem = doc.createElement( "LinearlyInterpolatedDiagramRenderer" );
rendererElem.setAttribute( "lowerValue", QString::number( mLowerValue ) );
rendererElem.setAttribute( "upperValue", QString::number( mUpperValue ) );
rendererElem.setAttribute( "lowerWidth", QString::number( mLowerSize.width() ) );
rendererElem.setAttribute( "lowerHeight", QString::number( mLowerSize.height() ) );
rendererElem.setAttribute( "upperWidth", QString::number( mUpperSize.width() ) );
rendererElem.setAttribute( "upperHeight", QString::number( mUpperSize.height() ) );
rendererElem.setAttribute( "classificationAttribute", mClassificationAttribute );
rendererElem.setAttribute( "lowerValue", QString::number( mInterpolationSettings.lowerValue ) );
rendererElem.setAttribute( "upperValue", QString::number( mInterpolationSettings.upperValue ) );
rendererElem.setAttribute( "lowerWidth", QString::number( mInterpolationSettings.lowerSize.width() ) );
rendererElem.setAttribute( "lowerHeight", QString::number( mInterpolationSettings.lowerSize.height() ) );
rendererElem.setAttribute( "upperWidth", QString::number( mInterpolationSettings.upperSize.width() ) );
rendererElem.setAttribute( "upperHeight", QString::number( mInterpolationSettings.upperSize.height() ) );
rendererElem.setAttribute( "classificationAttribute", mInterpolationSettings.classificationAttribute );
mSettings.writeXML( rendererElem, doc );
_writeXML( rendererElem, doc );
layerElem.appendChild( rendererElem );
Expand Down
522 changes: 275 additions & 247 deletions src/core/qgsdiagramrendererv2.h

Large diffs are not rendered by default.

24 changes: 23 additions & 1 deletion src/core/qgsdistancearea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,28 @@ bool QgsDistanceArea::setEllipsoid( const QString& ellipsoid )
return true;
}

// Check if we have a custom projection, and set from text string.
// Format is "PARAMETER:<semi-major axis>:<semi minor axis>
// Numbers must be with (optional) decimal point and no other separators (C locale)
// Distances in meters. Flattening is calculated.
if ( ellipsoid.startsWith( "PARAMETER" ) )
{
QStringList paramList = ellipsoid.split( ":" );
bool semiMajorOk, semiMinorOk;
double semiMajor = paramList[1].toDouble( & semiMajorOk );
double semiMinor = paramList[2].toDouble( & semiMinorOk );
if ( semiMajorOk && semiMinorOk )
{
return setEllipsoid( semiMajor, semiMinor );
}
else
{
return false;
}
}

// Continue with PROJ.4 list of ellipsoids.

//check the db is available
myResult = sqlite3_open_v2( QgsApplication::srsDbFilePath().toUtf8().data(), &myDatabase, SQLITE_OPEN_READONLY, NULL );
if ( myResult )
Expand Down Expand Up @@ -213,7 +235,7 @@ bool QgsDistanceArea::setEllipsoid( const QString& ellipsoid )
// Also, b = a-(a/invf)
bool QgsDistanceArea::setEllipsoid( double semiMajor, double semiMinor )
{
mEllipsoid = "PARAMETER";
mEllipsoid = QString( "PARAMETER:%1:%2" ).arg( semiMajor ).arg( semiMinor );
mSemiMajor = semiMajor;
mSemiMinor = semiMinor;
mInvFlattening = mSemiMajor / ( mSemiMajor - mSemiMinor );
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -775,13 +775,13 @@ static QVariant fcnRound( const QVariantList& values , QgsFeature *f, QgsExpress
{
double number = getDoubleValue( values.at( 0 ), parent );
double scaler = pow( 10.0, getIntValue( values.at( 1 ), parent ) );
return QVariant( round( number * scaler ) / scaler );
return QVariant( qRound( number * scaler ) / scaler );
}

if ( values.length() == 1 )
{
double number = getIntValue( values.at( 0 ), parent );
return QVariant( round( number ) ).toInt();
return QVariant( qRound( number ) ).toInt();
}

return QVariant();
Expand Down
9 changes: 7 additions & 2 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#include <QTime>
#include <QPainter>

#include "qgsdiagram.h"
#include "diagram/qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgslabelsearchtree.h"
#include "qgsexpression.h"
Expand Down Expand Up @@ -167,6 +167,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
decimals = 3;
plusSign = false;
labelPerPart = false;
displayAll = false;
mergeLines = false;
minFeatureSize = 0.0;
vectorScaleFactor = 1.0;
Expand Down Expand Up @@ -212,6 +213,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
decimals = s.decimals;
plusSign = s.plusSign;
labelPerPart = s.labelPerPart;
displayAll = s.displayAll;
mergeLines = s.mergeLines;
minFeatureSize = s.minFeatureSize;
vectorScaleFactor = s.vectorScaleFactor;
Expand Down Expand Up @@ -392,6 +394,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
decimals = layer->customProperty( "labeling/decimals" ).toInt();
plusSign = layer->customProperty( "labeling/plussign" ).toInt();
labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool();
displayAll = layer->customProperty( "labeling/displayAll", QVariant( false ) ).toBool();
mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool();
addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool();
minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
Expand Down Expand Up @@ -448,6 +451,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/decimals", decimals );
layer->setCustomProperty( "labeling/plussign", plusSign );
layer->setCustomProperty( "labeling/labelPerPart", labelPerPart );
layer->setCustomProperty( "labeling/displayAll", displayAll );
layer->setCustomProperty( "labeling/mergeLines", mergeLines );
layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol );
layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
Expand Down Expand Up @@ -1114,7 +1118,8 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices,

Layer* l = mPal->addLayer( layer->id().toUtf8().data(),
min_scale, max_scale, arrangement,
METER, priority, lyr.obstacle, true, true );
METER, priority, lyr.obstacle, true, true,
lyr.displayAll );

if ( lyr.placementFlags )
l->setArrangementFlags( lyr.placementFlags );
Expand Down
1 change: 1 addition & 0 deletions src/core/qgspallabeling.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class CORE_EXPORT QgsPalLayerSettings
int decimals;
bool plusSign;
bool labelPerPart; // whether to label every feature's part or only the biggest one
bool displayAll; // if true, all features will be labelled even though overlaps occur
bool mergeLines;
double minFeatureSize; // minimum feature size to be labelled (in mm)
// Adds '<' or '>' to the label string pointing to the direction of the line / polygon ring
Expand Down
5 changes: 3 additions & 2 deletions src/core/qgsrasterdataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
{
UndefinedColorInterpretation = 0,
/*! Greyscale */ GrayIndex = 1,
/*! Paletted (see associated color table) */ PaletteIndex = 2,
/*! Paletted (see associated color table) */ PaletteIndex = 2, // indexed color table
/*! Red band of RGBA image */ RedBand = 3,
/*! Green band of RGBA image */ GreenBand = 4,
/*! Blue band of RGBA image */ BlueBand = 5,
Expand All @@ -91,7 +91,8 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
/*! Y Luminance */ YCbCr_YBand = 14,
/*! Cb Chroma */ YCbCr_CbBand = 15,
/*! Cr Chroma */ YCbCr_CrBand = 16,
/*! Max current value */ ColorInterpretationMax = 16
/*! Continuous palette, QGIS addition, GRASS */ ContinuousPalette = 17,
/*! Max current value */ ColorInterpretationMax = 17
};

// Progress types
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class QImage;
* write an image and compare it to an expected result
* or render time.
*/
class QgsRenderChecker
class CORE_EXPORT QgsRenderChecker
{
public:

Expand Down
9 changes: 8 additions & 1 deletion src/core/qgsvectordataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,11 @@ QVariant QgsVectorDataProvider::convertValue( QVariant::Type type, QString value
return v;
}

static bool _compareEncodings( const QString& s1, const QString& s2 )
{
return s1.toLower() < s2.toLower();
}

const QStringList &QgsVectorDataProvider::availableEncodings()
{
if ( smEncodings.isEmpty() )
Expand All @@ -468,7 +473,6 @@ const QStringList &QgsVectorDataProvider::availableEncodings()
{
smEncodings << codec;
}
qSort( smEncodings );
#if 0
smEncodings << "BIG5";
smEncodings << "BIG5-HKSCS";
Expand Down Expand Up @@ -518,6 +522,9 @@ const QStringList &QgsVectorDataProvider::availableEncodings()
#endif
}

// Do case-insensitive sorting of encodings
qSort( smEncodings.begin(), smEncodings.end(), _compareEncodings );

return smEncodings;
}

Expand Down
236 changes: 236 additions & 0 deletions src/core/raster/qgsrasterchecker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/***************************************************************************
qgsrasterchecker.cpp
--------------------------------------
Date : 5 Sep 2012
Copyright : (C) 2012 by Radim Blazek
Email : radim dot blazek at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#include "qgsrasterchecker.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterlayer.h"

#include <qmath.h>
#include <QColor>
#include <QPainter>
#include <QImage>
#include <QTime>
#include <QCryptographicHash>
#include <QByteArray>
#include <QDebug>
#include <QBuffer>

QgsRasterChecker::QgsRasterChecker( ) :
mReport( "" )
{
mTabStyle = "border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid;";
mCellStyle = "border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center;";
mOkStyle = "background: #00ff00;";
mErrStyle = "background: #ff0000;";
mErrMsgStyle = "color: #ff0000;";
}

bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
QString theExpectedKey, QString theExpectedUri )
{
bool ok = true;
mReport += "\n\n";

QgsRasterDataProvider* verifiedProvider = QgsRasterLayer::loadProvider( theVerifiedKey, theVerifiedUri );
if ( !verifiedProvider || !verifiedProvider->isValid() )
{
error( QString( "Cannot load provider %1 with URI: %2" ).arg( theVerifiedKey).arg( theVerifiedUri), mReport );
ok = false;
}

QgsRasterDataProvider* expectedProvider = QgsRasterLayer::loadProvider( theExpectedKey, theExpectedUri );
if ( !expectedProvider || !expectedProvider->isValid() )
{
error( QString( "Cannot load provider %1 with URI: %2" ).arg( theExpectedKey).arg( theExpectedUri ), mReport );
ok = false;
}

if ( !ok ) return false;

mReport += QString( "Verified URI: %1<br>" ).arg( theVerifiedUri.replace( "&", "&amp;" ) );
mReport += QString( "Expected URI: %1<br>" ).arg( theExpectedUri.replace( "&", "&amp;" ) );

mReport += "<br>";
mReport += QString("<table style='%1'>\n").arg( mTabStyle );
mReport += compareHead();

compare( "Band count", verifiedProvider->bandCount(), expectedProvider->bandCount(), mReport, ok );

compare( "Width", verifiedProvider->xSize(), expectedProvider->xSize(), mReport, ok );
compare( "Height", verifiedProvider->ySize(), expectedProvider->ySize(), mReport, ok );

compareRow( "Extent", verifiedProvider->extent().toString(), expectedProvider->extent().toString(), mReport, verifiedProvider->extent() == expectedProvider->extent() );

if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false;

compare( "No data (NULL) value", verifiedProvider->noDataValue(), expectedProvider->noDataValue(), mReport, ok );

mReport += "</table>\n";

if ( !ok ) return false;

bool allOk = true;
for ( int band = 1; band <= expectedProvider->bandCount(); band++ )
{
bool bandOk = true;
mReport += QString( "<h3>Band %1</h3>\n" ).arg( band );
mReport += QString("<table style='%1'>\n").arg( mTabStyle );
mReport += compareHead();

// Data types may differ (?)
bool typesOk = true;
compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk );
compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ;

bool statsOk = true;
QgsRasterBandStats verifiedStats = verifiedProvider->bandStatistics( band );
QgsRasterBandStats expectedStats = expectedProvider->bandStatistics( band );

// Min/max may 'slightly' differ, for big numbers however, the difference may
// be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24
double tol = tolerance( expectedStats.minimumValue );
compare( "Minimum value", verifiedStats.minimumValue, expectedStats.minimumValue, mReport, statsOk, tol );
tol = tolerance( expectedStats.maximumValue );
compare( "Maximum value", verifiedStats.maximumValue, expectedStats.maximumValue, mReport, statsOk, tol );

// TODO: enable once fixed (WCS excludes nulls but GDAL does not)
//compare( "Cells count", verifiedStats.elementCount, expectedStats.elementCount, mReport, statsOk );

tol = tolerance( expectedStats.mean );
compare( "Mean", verifiedStats.mean, expectedStats.mean, mReport, statsOk, tol );

// stdDev usually differ significantly
tol = tolerance( expectedStats.stdDev, 1 );
compare( "Standard deviation", verifiedStats.stdDev, expectedStats.stdDev, mReport, statsOk, tol );

mReport += "</table>";
mReport += "<br>";

if ( !bandOk )
{
allOk = false;
continue;
}

if ( !statsOk || !typesOk )
{
allOk = false;
// create values table anyway so that values are available
}

mReport += "<table><tr>";
mReport += "<td>Data comparison</td>";
mReport += QString( "<td style='%1 %2 border: 1px solid'>correct&nbsp;value</td>" ).arg( mCellStyle).arg( mOkStyle );
mReport += "<td></td>";
mReport += QString( "<td style='%1 %2 border: 1px solid'>wrong&nbsp;value<br>expected value</td></tr>").arg( mCellStyle).arg( mErrStyle );
mReport += "</tr></table>";
mReport += "<br>";

int width = expectedProvider->xSize();
int height = expectedProvider->ySize();
int blockSize = width * height * expectedProvider->typeSize( expectedProvider->dataType( band ) ) ;
void * expectedData = malloc( blockSize );
void * verifiedData = malloc( blockSize );

expectedProvider->readBlock( band, expectedProvider->extent(), width, height, expectedData );
verifiedProvider->readBlock( band, expectedProvider->extent(), width, height, verifiedData );

// compare data values
QString htmlTable = QString("<table style='%1'>").arg( mTabStyle );
for ( int row = 0; row < height; row ++ )
{
htmlTable += "<tr>";
for ( int col = 0; col < width; col ++ )
{
bool cellOk = true;
double verifiedVal = verifiedProvider->readValue( verifiedData, verifiedProvider->dataType( band ), row * width + col );
double expectedVal = expectedProvider->readValue( expectedData, expectedProvider->dataType( band ), row * width + col );

QString valStr;
if ( compare( verifiedVal, expectedVal, 0 ) )
{
valStr = QString( "%1" ).arg( verifiedVal );
}
else
{
cellOk = false;
allOk = false;
valStr = QString( "%1<br>%2" ).arg( verifiedVal ).arg( expectedVal );
}
htmlTable += QString( "<td style='%1 %2'>%3</td>" ).arg( mCellStyle).arg( cellOk ? mOkStyle : mErrStyle ).arg( valStr );
}
htmlTable += "</tr>";
}
htmlTable += "</table>";

mReport += htmlTable;

free( expectedData );
free( verifiedData );
}
delete verifiedProvider;
delete expectedProvider;
return allOk;
}

void QgsRasterChecker::error( QString theMessage, QString &theReport )
{
theReport += QString( "<font style='%1'>Error: ").arg(mErrMsgStyle);
theReport += theMessage;
theReport += "</font>";
}

double QgsRasterChecker::tolerance( double val, int places )
{
// float precision is about 7 decimal digits, double about 16
// default places = 6
return 1. * qPow( 10, qRound( log10( qAbs( val ) ) - places ) );
}

QString QgsRasterChecker::compareHead()
{
QString html;
html += QString( "<tr><th style='%1'>Param name</th><th style='%1'>Verified value</th><th style='%1'>Eexpected value</th><th style='%1'>Difference</th><th style='%1'>Tolerance</th></tr>").arg( mCellStyle );
return html;
}

void QgsRasterChecker::compare( QString theParamName, int verifiedVal, int expectedVal, QString &theReport, bool &theOk )
{
bool ok = verifiedVal == expectedVal;
compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ) );
if ( !ok ) theOk = false;
}

bool QgsRasterChecker::compare( double verifiedVal, double expectedVal, double theTolerance )
{
// values may be nan
return ( qIsNaN( verifiedVal ) && qIsNaN( expectedVal ) ) || ( qAbs( verifiedVal - expectedVal ) <= theTolerance );
}

void QgsRasterChecker::compare( QString theParamName, double verifiedVal, double expectedVal, QString &theReport, bool &theOk, double theTolerance )
{
bool ok = compare( verifiedVal, expectedVal, theTolerance );
compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ), QString::number( theTolerance ) );
if ( !ok ) theOk = false;
}

void QgsRasterChecker::compareRow( QString theParamName, QString verifiedVal, QString expectedVal, QString &theReport, bool theOk, QString theDifference, QString theTolerance )
{
theReport += "<tr>\n";
theReport += QString( "<td style='%1'>%2</td><td style='%1 %3'>%4</td><td style='%1'>%5</td>\n" ).arg(mCellStyle).arg( theParamName ).arg( theOk ? mOkStyle : mErrStyle ).arg( verifiedVal ).arg( expectedVal );
theReport += QString( "<td style='%1'>%2</td>\n" ).arg(mCellStyle).arg( theDifference );
theReport += QString( "<td style='%1'>%2</td>\n" ).arg(mCellStyle).arg( theTolerance );
theReport += "</tr>";
}
71 changes: 71 additions & 0 deletions src/core/raster/qgsrasterchecker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/***************************************************************************
qgsrasterchecker.h - compare two rasters
--------------------------------------
Date : 5 Sep 2012
Copyright : (C) 2012 by Radim Blazek
email : radim dot blazek at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#ifndef QGSRASTERCHECKER_H
#define QGSRASTERCHECKER_H

#include <QDir>
#include <QString>
#include <qgsmaprenderer.h>
class QImage;

/** \ingroup UnitTests
* This is a helper class for unit tests that need to
* write an image and compare it to an expected result
* or render time.
*/
class CORE_EXPORT QgsRasterChecker
{
public:

QgsRasterChecker();

//! Destructor
~QgsRasterChecker() {};

QString controlImagePath() const;

QString report() { return mReport; };
/**
* Test using renderer to generate the image to be compared.
* @param theVerifiedKey verified provider key
* @param theVerifiedUri URI of the raster to be verified
* @param theExpectedKey expected provider key
* @param theExpectedUri URI of the expected (control) raster
*/
bool runTest( QString theVerifiedKey, QString theVerifiedUri,
QString theExpectedKey, QString theExpectedUri );
private:
QString mReport;
QString mExpectedUri;
QString mCheckedUri;
QString mTabStyle;
QString mCellStyle;
QString mOkStyle;
QString mErrStyle;
QString mErrMsgStyle;

// Log error in html
void error( QString theMessage, QString &theReport );
// compare values and add table row in html report, set ok to false if not equal
QString compareHead();
bool compare( double verifiedVal, double expectedVal, double theTolerance );
void compare( QString theParamName, int verifiedVal, int expectedVal, QString &theReport, bool &theOk );
void compare( QString theParamName, double verifiedVal, double expectedVal, QString &theReport, bool &theOk, double theTolerance = 0 );
void compareRow( QString theParamName, QString verifiedVal, QString expectedVal, QString &theReport, bool theOk, QString theDifference = "", QString theTolerance = "" );
double tolerance( double val, int places = 6 );
}; // class QgsRasterChecker

#endif
24 changes: 22 additions & 2 deletions src/core/raster/qgsrasterlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,10 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
{
mRasterType = Palette;
}
else if ( mDataProvider->colorInterpretation( 1 ) == QgsRasterDataProvider::ContinuousPalette )
{
mRasterType = Palette;
}
else
{
mRasterType = GrayOrUndefined;
Expand All @@ -1811,11 +1815,27 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) );
setDrawingStyle( SingleBandColorDataStyle );
}
else if ( mRasterType == Palette )
else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRasterDataProvider::PaletteIndex )
{

setDrawingStyle( PalettedColor ); //sensible default
}
else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRasterDataProvider::ContinuousPalette )
{
setDrawingStyle( SingleBandPseudoColor );
// Load color table
QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 );
QgsSingleBandPseudoColorRenderer* r = dynamic_cast<QgsSingleBandPseudoColorRenderer*>( renderer() );
if ( r )
{
// TODO: this should go somewhere else
QgsRasterShader* shader = new QgsRasterShader();
QgsColorRampShader* colorRampShader = new QgsColorRampShader();
colorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED );
colorRampShader->setColorRampItemList( colorTable );
shader->setRasterShaderFunction( colorRampShader );
r->setShader( shader );
}
}
else if ( mRasterType == Multiband )
{
setDrawingStyle( MultiBandColor ); //sensible default
Expand Down
7 changes: 7 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName
mCategories( categories ),
mSourceSymbol( NULL ),
mSourceColorRamp( NULL ),
mScaleMethod( QgsSymbolV2::ScaleArea ),
mRotationFieldIdx( -1 ),
mSizeScaleFieldIdx( -1 )
{
Expand Down Expand Up @@ -216,6 +217,7 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
markerSymbol->setScaleMethod( mScaleMethod );
}
else if ( tempSymbol->type() == QgsSymbolV2::Line )
{
Expand Down Expand Up @@ -374,6 +376,7 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
r->setUsingSymbolLevels( usingSymbolLevels() );
r->setRotationField( rotationField() );
r->setSizeScaleField( sizeScaleField() );
r->setScaleMethod( scaleMethod() );
return r;
}

Expand Down Expand Up @@ -464,7 +467,10 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::create( QDomElement& eleme

QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
{
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
}

// TODO: symbol levels
return r;
Expand Down Expand Up @@ -524,6 +530,7 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )

QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
rendererElem.appendChild( sizeScaleElem );

return rendererElem;
Expand Down
6 changes: 6 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,19 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
//! @note added in 1.6
QString sizeScaleField() const { return mSizeScaleField; }

//! @note added in 2.0
void setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod ) { mScaleMethod = scaleMethod; }
//! @note added in 2.0
QgsSymbolV2::ScaleMethod scaleMethod() const { return mScaleMethod; }

protected:
QString mAttrName;
QgsCategoryList mCategories;
QgsSymbolV2* mSourceSymbol;
QgsVectorColorRampV2* mSourceColorRamp;
QString mRotationField;
QString mSizeScaleField;
QgsSymbolV2::ScaleMethod mScaleMethod;

//! attribute index (derived from attribute name in startRender)
int mAttrNum;
Expand Down
Loading