diff --git a/python/core/qgsexpression.sip b/python/core/qgsexpression.sip index e529b4b33e3..aa52cce1839 100644 --- a/python/core/qgsexpression.sip +++ b/python/core/qgsexpression.sip @@ -61,6 +61,10 @@ class QgsExpression //! (used by internal functions) QgsDistanceArea* geomCalculator(); + //! Sets the geometry calculator used in evaluation of expressions, + // instead of the default. + void setGeomCalculator( QgsDistanceArea& calc ); + /** This function currently replaces each expression between [% and %] in the string with the result of its evaluation on the feature passed as argument. diff --git a/python/gui/qgsexpressionbuilderdialog.sip b/python/gui/qgsexpressionbuilderdialog.sip index 4761a65e5d6..1dcbbbcd7db 100644 --- a/python/gui/qgsexpressionbuilderdialog.sip +++ b/python/gui/qgsexpressionbuilderdialog.sip @@ -17,6 +17,11 @@ class QgsExpressionBuilderDialog : QDialog QString expressionText(); + /** Sets geometry calculator used in distance/area calculations. + * @note added in version 2.0 + */ + void setGeomCalculator( const QgsDistanceArea & da ); + protected: /** * Handle closing of the window diff --git a/python/gui/qgsexpressionbuilderwidget.sip b/python/gui/qgsexpressionbuilderwidget.sip index 31271d27920..c8b7f1f6bf7 100644 --- a/python/gui/qgsexpressionbuilderwidget.sip +++ b/python/gui/qgsexpressionbuilderwidget.sip @@ -84,6 +84,11 @@ class QgsExpressionBuilderWidget : QWidget void loadFieldNames( QMap fields ); + /** Sets geometry calculator used in distance/area calculations. + * @note added in version 2.0 + */ + void setGeomCalculator( const QgsDistanceArea & da ); + /** Gets the expression string that has been set in the expression area. * @returns The expression as a string. */ QString expressionText(); diff --git a/src/app/qgsattributeactiondialog.cpp b/src/app/qgsattributeactiondialog.cpp index 181df64075d..4ac2d96f6d6 100644 --- a/src/app/qgsattributeactiondialog.cpp +++ b/src/app/qgsattributeactiondialog.cpp @@ -23,6 +23,9 @@ back to QgsVectorLayer. #include "qgsattributeactiondialog.h" #include "qgsattributeaction.h" #include "qgsexpressionbuilderdialog.h" +#include "qgisapp.h" +#include "qgsproject.h" +#include "qgsmapcanvas.h" #include #include @@ -173,6 +176,13 @@ void QgsAttributeActionDialog::insertExpression() // display the expression builder QgsExpressionBuilderDialog dlg( mActions->layer(), selText, this ); dlg.setWindowTitle( tr( "Insert expression" ) ); + + QgsDistanceArea myDa; + myDa.setSourceCrs( mActions->layer()->crs().srsid() ); + myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + dlg.setGeomCalculator( myDa ); + if ( dlg.exec() == QDialog::Accepted ) { QString expression = dlg.expressionBuilder()->expressionText(); diff --git a/src/app/qgsattributedialog.cpp b/src/app/qgsattributedialog.cpp index e1fdf5ba868..64116dda212 100644 --- a/src/app/qgsattributedialog.cpp +++ b/src/app/qgsattributedialog.cpp @@ -17,7 +17,8 @@ #include "qgsattributedialog.h" #include "qgsfield.h" #include "qgslogger.h" - +#include "qgsmapcanvas.h" +#include "qgsproject.h" #include "qgsvectorlayer.h" #include "qgsvectordataprovider.h" #include "qgsuniquevaluerenderer.h" @@ -218,6 +219,13 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat } else { + + QgsDistanceArea myDa; + + myDa.setSourceCrs( vl->crs().srsid() ); + myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + for ( QgsFieldMap::const_iterator it = theFieldMap.begin(); it != theFieldMap.end(); ++it ) { QList myWidgets = mDialog->findChildren( it->name() ); @@ -258,6 +266,8 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat } } + exp.setGeomCalculator( myDa ); + QVariant value = exp.evaluate( mFeature, vl->pendingFields() ); if ( !exp.hasEvalError() ) diff --git a/src/app/qgsattributetabledialog.cpp b/src/app/qgsattributetabledialog.cpp index 0b64d733be8..6153a5fa9fe 100644 --- a/src/app/qgsattributetabledialog.cpp +++ b/src/app/qgsattributetabledialog.cpp @@ -32,6 +32,7 @@ #include "qgssearchquerybuilder.h" #include "qgslogger.h" #include "qgsmapcanvas.h" +#include "qgsproject.h" #include "qgsfieldcalculator.h" #include "qgsfeatureaction.h" #include "qgsattributeaction.h" @@ -536,6 +537,13 @@ void QgsAttributeTableDialog::updateSelectionFromLayer() void QgsAttributeTableDialog::doSearch( QString searchString ) { + + QgsDistanceArea myDa; + + myDa.setSourceCrs( mLayer->crs().srsid() ); + myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + // parse search string and build parsed tree QgsExpression search( searchString ); if ( search.hasParserError() ) @@ -556,6 +564,7 @@ void QgsAttributeTableDialog::doSearch( QString searchString ) QApplication::setOverrideCursor( Qt::WaitCursor ); mSelectedFeatures.clear(); + search.setGeomCalculator( myDa ); if ( cbxSearchSelectedOnly->isChecked() ) { QgsFeatureList selectedFeatures = mLayer->selectedFeatures(); diff --git a/src/app/qgsfieldcalculator.cpp b/src/app/qgsfieldcalculator.cpp index 2178504ce88..40687ba7064 100644 --- a/src/app/qgsfieldcalculator.cpp +++ b/src/app/qgsfieldcalculator.cpp @@ -13,12 +13,17 @@ * * ***************************************************************************/ +#include "qgisapp.h" #include "qgsfieldcalculator.h" +#include "qgsdistancearea.h" #include "qgsexpression.h" +#include "qgsmapcanvas.h" +#include "qgsproject.h" #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" #include +#include QgsFieldCalculator::QgsFieldCalculator( QgsVectorLayer* vl ) : QDialog() @@ -78,6 +83,15 @@ QgsFieldCalculator::~QgsFieldCalculator() void QgsFieldCalculator::accept() { + + // Set up QgsDistanceArea each time we (re-)calculate + QgsDistanceArea myDa; + + myDa.setSourceCrs( mVectorLayer->crs().srsid() ); + myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + + QString calcString = builder->expressionText(); QgsExpression exp( calcString ); @@ -163,6 +177,7 @@ void QgsFieldCalculator::accept() } exp.setCurrentRowNumber( rownum ); + exp.setGeomCalculator( myDa ); QVariant value = exp.evaluate( &feature ); if ( exp.hasEvalError() ) diff --git a/src/app/qgslabelinggui.cpp b/src/app/qgslabelinggui.cpp index f537a3c4352..d92297aa267 100644 --- a/src/app/qgslabelinggui.cpp +++ b/src/app/qgslabelinggui.cpp @@ -25,7 +25,8 @@ #include "qgslabelengineconfigdialog.h" #include "qgsexpressionbuilderdialog.h" #include "qgsexpression.h" -#include "qgsmapcanvas.h" +#include "qgisapp.h" +#include "qgsproject.h" #include "qgscharacterselectdialog.h" #include @@ -901,6 +902,13 @@ void QgsLabelingGui::showExpressionDialog() { QgsExpressionBuilderDialog dlg( mLayer, cboFieldName->currentText() , this ); dlg.setWindowTitle( tr( "Expression based label" ) ); + + QgsDistanceArea myDa; + myDa.setSourceCrs( mLayer->crs().srsid() ); + myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + dlg.setGeomCalculator( myDa ); + if ( dlg.exec() == QDialog::Accepted ) { QString expression = dlg.expressionText(); diff --git a/src/app/qgsmaptoolidentify.cpp b/src/app/qgsmaptoolidentify.cpp index 47e25cc6acb..4b26f9ad407 100644 --- a/src/app/qgsmaptoolidentify.cpp +++ b/src/app/qgsmaptoolidentify.cpp @@ -214,7 +214,8 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int // load identify radius from settings QSettings settings; double identifyValue = settings.value( "/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS ).toDouble(); - QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString(); + + QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ); if ( identifyValue <= 0.0 ) identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS; diff --git a/src/app/qgsmaptoolmeasureangle.cpp b/src/app/qgsmaptoolmeasureangle.cpp index 33a7532d97b..d9cf3aa2bf4 100644 --- a/src/app/qgsmaptoolmeasureangle.cpp +++ b/src/app/qgsmaptoolmeasureangle.cpp @@ -19,6 +19,7 @@ #include "qgslogger.h" #include "qgsmapcanvas.h" #include "qgsmaptopixel.h" +#include "qgsproject.h" #include "qgsrubberband.h" #include #include @@ -182,7 +183,7 @@ void QgsMapToolMeasureAngle::updateSettings() void QgsMapToolMeasureAngle::configureDistanceArea() { QSettings settings; - QString ellipsoidId = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString(); + QString ellipsoidId = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ); mDa.setSourceCrs( mCanvas->mapRenderer()->destinationCrs().srsid() ); mDa.setEllipsoid( ellipsoidId ); // Only use ellipsoidal calculation when project wide transformation is enabled. diff --git a/src/app/qgsmeasuredialog.cpp b/src/app/qgsmeasuredialog.cpp index f7dcaddfdd0..538b3cfc3bf 100644 --- a/src/app/qgsmeasuredialog.cpp +++ b/src/app/qgsmeasuredialog.cpp @@ -22,6 +22,7 @@ #include "qgsdistancearea.h" #include "qgsmapcanvas.h" #include "qgsmaprenderer.h" +#include "qgsproject.h" #include "qgscoordinatereferencesystem.h" #include @@ -60,7 +61,7 @@ void QgsMeasureDialog::updateSettings() mDisplayUnits = QGis::fromLiteral( settings.value( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Meters ) ).toString() ); // Configure QgsDistanceArea mDa.setSourceCrs( mTool->canvas()->mapRenderer()->destinationCrs().srsid() ); - mDa.setEllipsoid( settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString() ); + mDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); // Only use ellipsoidal calculation when project wide transformation is enabled. if ( mTool->canvas()->mapRenderer()->hasCrsTransformEnabled() ) { diff --git a/src/app/qgsoptions.cpp b/src/app/qgsoptions.cpp index 4567dd6e350..e3574508137 100644 --- a/src/app/qgsoptions.cpp +++ b/src/app/qgsoptions.cpp @@ -58,7 +58,6 @@ #include // for setting gdal options #include "qgsconfig.h" -const char * QgsOptions::GEO_NONE_DESC = QT_TRANSLATE_NOOP( "QgsOptions", "None / Planimetric" ); /** * \class QgsOptions - Set user options and preferences @@ -82,8 +81,6 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) : connect( mFontFamilyRadioCustom, SIGNAL( released() ), this, SLOT( updateAppStyleSheet() ) ); connect( mFontFamilyComboBox, SIGNAL( currentFontChanged( const QFont& ) ), this, SLOT( updateAppStyleSheet() ) ); - connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) ); - #ifdef Q_WS_X11 connect( chkEnableBackbuffer, SIGNAL( stateChanged( int ) ), this, SLOT( toggleEnableBackbuffer( int ) ) ); #endif @@ -286,34 +283,6 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) : //display the crs as friendly text rather than in wkt leProjectGlobalCrs->setText( mDefaultCrs.authid() + " - " + mDefaultCrs.description() ); - // populate combo box with ellipsoids - - QgsDebugMsg( "Setting upp ellipsoid" ); - - 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++ ) - { - if ( mEllipsoidList[ i ].acronym.startsWith( mySplitEllipsoid[ 0 ] ) ) - { - myIndex = i; - break; - } - } - // Update paramaters if present. - if ( mySplitEllipsoid.length() >= 3 ) - { - 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() ); @@ -1000,26 +969,6 @@ void QgsOptions::saveOptions() settings.setValue( "/Projections/otfTransformEnabled", chkOtfTransform->isChecked() ); settings.setValue( "/Projections/projectDefaultCrs", mDefaultCrs.authid() ); - 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() ) { settings.setValue( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Feet ) ); @@ -1245,88 +1194,6 @@ bool QgsOptions::newVisible() { return chkAddedVisibility->isChecked(); } -void QgsOptions::populateEllipsoidList() -{ - // - // 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 ); - - //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, 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 ) - { - 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 ); - - // Add all items to selector - - foreach ( i, mEllipsoidList ) - { - cmbEllipsoid->addItem( i.description ); - } -} QStringList QgsOptions::i18nList() { @@ -1736,53 +1603,3 @@ void QgsOptions::saveContrastEnhancement( QComboBox *cbox, QString name ) 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" ) ); - } -} diff --git a/src/app/qgsoptions.h b/src/app/qgsoptions.h index 15626b6cfb0..d337f991ec9 100644 --- a/src/app/qgsoptions.h +++ b/src/app/qgsoptions.h @@ -189,12 +189,6 @@ class QgsOptions : public QDialog, private Ui::QgsOptionsBase */ void saveGdalDriverList(); - /* 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(); void initContrastEnhancement( QComboBox *cbox, QString name, QString defaultVal ); @@ -203,21 +197,6 @@ 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 mEllipsoidList; - int mEllipsoidIndex; - - //! Populates list with ellipsoids from Sqlite3 db - void populateEllipsoidList(); - - static const char * GEO_NONE_DESC; }; #endif // #ifndef QGSOPTIONS_H diff --git a/src/app/qgsprojectproperties.cpp b/src/app/qgsprojectproperties.cpp index 7b28fbf5f5c..198398a505e 100644 --- a/src/app/qgsprojectproperties.cpp +++ b/src/app/qgsprojectproperties.cpp @@ -19,6 +19,8 @@ #include "qgsprojectproperties.h" //qgis includes +#include "qgsapplication.h" +#include "qgsdistancearea.h" #include "qgisapp.h" #include "qgscomposer.h" #include "qgscontexthelp.h" @@ -50,11 +52,16 @@ #include // Qt 4.4 #include +const char * QgsProjectProperties::GEO_NONE_DESC = QT_TRANSLATE_NOOP( "QgsOptions", "None / Planimetric" ); + //stdc++ includes QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *parent, Qt::WFlags fl ) : QDialog( parent, fl ) , mMapCanvas( mapCanvas ) + , mEllipsoidList() + , mEllipsoidIndex( 0 ) + { setupUi( this ); connect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); @@ -63,6 +70,8 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa connect( this, SIGNAL( accepted() ), this, SLOT( apply() ) ); connect( projectionSelector, SIGNAL( sridSelected( QString ) ), this, SLOT( setMapUnitsToCurrentProjection() ) ); + connect( cmbEllipsoid, SIGNAL( currentIndexChanged( int ) ), this, SLOT( updateEllipsoidUI( int ) ) ); + /////////////////////////////////////////////////////////// // Properties stored in map canvas's QgsMapRenderer // these ones are propagated to QgsProject by a signal @@ -104,6 +113,34 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas* mapCanvas, QWidget *pa cbxAbsolutePath->setCurrentIndex( QgsProject::instance()->readBoolEntry( "Paths", "/Absolute", true ) ? 0 : 1 ); + // populate combo box with ellipsoids + + QgsDebugMsg( "Setting upp ellipsoid" ); + + populateEllipsoidList(); + + // Reading ellipsoid from setttings + QStringList mySplitEllipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ).split( ':' ); + + int myIndex = 0; + for ( int i = 0; i < mEllipsoidList.length(); i++ ) + { + if ( mEllipsoidList[ i ].acronym.startsWith( mySplitEllipsoid[ 0 ] ) ) + { + myIndex = i; + break; + } + } + // Update paramaters if present. + if ( mySplitEllipsoid.length() >= 3 ) + { + mEllipsoidList[ myIndex ].semiMajor = mySplitEllipsoid[ 1 ].toDouble(); + mEllipsoidList[ myIndex ].semiMinor = mySplitEllipsoid[ 2 ].toDouble(); + } + + updateEllipsoidUI( myIndex ); + + int dp = QgsProject::instance()->readNumEntry( "PositionPrecision", "/DecimalPlaces" ); spinBoxDP->setValue( dp ); @@ -507,6 +544,26 @@ void QgsProjectProperties::apply() QgsProject::instance()->writeEntry( "Paths", "/Absolute", cbxAbsolutePath->currentIndex() == 0 ); + 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() ); + } + QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", QString( "PARAMETER:%1:%2" ) + .arg( major, 0, 'g', 17 ) + .arg( minor, 0, 'g', 17 ) ); + } + else + { + QgsProject::instance()->writeEntry( "Measure", "/Ellipsoid", mEllipsoidList[ mEllipsoidIndex ].acronym ); + } + //set the color for selections QColor myColor = pbnSelectionColor->color(); QgsProject::instance()->writeEntry( "Gui", "/SelectionColorRedPart", myColor.red() ); @@ -773,6 +830,9 @@ void QgsProjectProperties::on_cbxProjectionEnabled_stateChanged( int state ) mLayerSrsId = projectionSelector->selectedCrsId(); projectionSelector->setSelectedCrsId( mProjectSrsId ); } + + // Enable/Disabel selector and update tool-tip + updateEllipsoidUI( mEllipsoidIndex ); } void QgsProjectProperties::on_cbxWFSPublied_stateChanged( int aIdx ) @@ -1252,3 +1312,142 @@ void QgsProjectProperties::resetPythonMacros() "def saveProject():\n pass\n\n" \ "def closeProject():\n pass\n" ); } + +void QgsProjectProperties::populateEllipsoidList() +{ + // + // 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 ); + + //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, 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 ) + { + 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 ); + + // Add all items to selector + + foreach ( i, mEllipsoidList ) + { + cmbEllipsoid->addItem( i.description ); + } +} + +void QgsProjectProperties::updateEllipsoidUI( int newIndex ) +{ + // Just return if the list isn't populated yet + if ( mEllipsoidList.isEmpty() ) + { + return; + } + // 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 ( cbxProjectionEnabled->isChecked() ) + { + 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" ) ); + } +} diff --git a/src/app/qgsprojectproperties.h b/src/app/qgsprojectproperties.h index 820795e7332..31b85b4e9ec 100644 --- a/src/app/qgsprojectproperties.h +++ b/src/app/qgsprojectproperties.h @@ -153,6 +153,12 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas */ void setMapUnitsToCurrentProjection(); + /* Update ComboBox accorindg to the selected new index + * Also sets the new selected Ellipsoid. + * @note added in 2.0 + */ + void updateEllipsoidUI( int newIndex ); + signals: //! Signal used to inform listeners that the mouse display precision may have changed void displayPrecisionChanged(); @@ -188,4 +194,21 @@ class QgsProjectProperties : public QDialog, private Ui::QgsProjectPropertiesBas long mProjectSrsId; long mLayerSrsId; + + // List for all ellispods, also None and Custom + struct EllipsoidDefs + { + QString acronym; + QString description; + double semiMajor; + double semiMinor; + }; + QList mEllipsoidList; + int mEllipsoidIndex; + + //! Populates list with ellipsoids from Sqlite3 db + void populateEllipsoidList(); + + static const char * GEO_NONE_DESC; + }; diff --git a/src/core/composer/qgscomposerscalebar.cpp b/src/core/composer/qgscomposerscalebar.cpp index 8ce1ef8eced..37eb7275f68 100644 --- a/src/core/composer/qgscomposerscalebar.cpp +++ b/src/core/composer/qgscomposerscalebar.cpp @@ -24,6 +24,7 @@ #include "qgssingleboxscalebarstyle.h" #include "qgsticksscalebarstyle.h" #include "qgsrectangle.h" +#include "qgsproject.h" #include #include #include @@ -189,8 +190,8 @@ double QgsComposerScaleBar::mapWidth() const QgsDistanceArea da; da.setEllipsoidalMode( mComposerMap->mapRenderer()->hasCrsTransformEnabled() ); da.setSourceCrs( mComposerMap->mapRenderer()->destinationCrs().srsid() ); - QSettings s; - da.setEllipsoid( s.value( "/qgis/measure/ellipsoid", "WGS84" ).toString() ); + da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", "WGS84" ) ); + double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) ); if ( mUnits == Feet ) { diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp index ca92663ffd4..315a7d2976d 100644 --- a/src/core/qgsexpression.cpp +++ b/src/core/qgsexpression.cpp @@ -1213,8 +1213,10 @@ QgsExpression::QgsExpression( const QString& expr ) : mExpression( expr ) , mRowNumber( 0 ) , mScale( 0 ) - , mCalc( NULL ) + { + initGeomCalculator(); + mRootNode = ::parseExpression( mExpression, mParserErrorString ); if ( mParserErrorString.isNull() ) @@ -1226,7 +1228,6 @@ QgsExpression::QgsExpression( const QString& expr ) QgsExpression::~QgsExpression() { delete mRootNode; - delete mCalc; } QStringList QgsExpression::referencedColumns() @@ -1261,11 +1262,16 @@ bool QgsExpression::needsGeometry() void QgsExpression::initGeomCalculator() { - mCalc = new QgsDistanceArea; - QSettings settings; - QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", GEO_NONE ).toString(); - mCalc->setEllipsoid( ellipsoid ); - mCalc->setEllipsoidalMode( false ); + // Use planimetric as default + mCalc.setEllipsoidalMode( false ); +} + +void QgsExpression::setGeomCalculator( QgsDistanceArea& calc ) +{ + // Copy from supplied calculator + mCalc.setEllipsoid( calc.ellipsoid() ); + mCalc.setEllipsoidalMode( calc.ellipsoidalEnabled() ); + mCalc.setSourceCrs( calc.sourceCrs() ); } bool QgsExpression::prepare( const QgsFieldMap& fields ) @@ -1311,7 +1317,6 @@ QString QgsExpression::dump() const return mRootNode->dump(); } - void QgsExpression::toOgcFilter( QDomDocument &doc, QDomElement &element ) const { if ( !mRootNode ) @@ -1393,7 +1398,6 @@ QString QgsExpression::replaceExpressionText( QString action, QgsFeature* feat, int start = index; index = pos + rx.matchedLength(); - QString to_replace = rx.cap( 1 ).trimmed(); QgsDebugMsg( "Found expression: " + to_replace ); diff --git a/src/core/qgsexpression.h b/src/core/qgsexpression.h index 24b18a60998..42d0f681677 100644 --- a/src/core/qgsexpression.h +++ b/src/core/qgsexpression.h @@ -24,9 +24,9 @@ #include "qgsfield.h" #include "qgsvectorlayer.h" +#include "qgsdistancearea.h" #include "qgsgeometry.h" -class QgsDistanceArea; class QgsFeature; class QgsGeometry; class QDomElement; @@ -140,7 +140,11 @@ class CORE_EXPORT QgsExpression //! Return calculator used for distance and area calculations //! (used by internal functions) - QgsDistanceArea* geomCalculator() { if ( !mCalc ) initGeomCalculator(); return mCalc; } + QgsDistanceArea* geomCalculator() { return & mCalc; } + + //! Sets the geometry calculator used in evaluation of expressions, + // instead of the default. + void setGeomCalculator( QgsDistanceArea& calc ); /** This function currently replaces each expression between [% and %] in the string with the result of its evaluation on the feature @@ -157,8 +161,6 @@ class CORE_EXPORT QgsExpression static QString replaceExpressionText( QString action, QgsFeature& feat, QgsVectorLayer* layer, const QMap *substitutionMap = 0 ); - // - enum UnaryOperator { uoNot, @@ -589,7 +591,7 @@ class CORE_EXPORT QgsExpression protected: // internally used to create an empty expression - QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ), mCalc( NULL ) {} + QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ) {} void initGeomCalculator(); @@ -603,8 +605,8 @@ class CORE_EXPORT QgsExpression double mScale; static QMap gmSpecialColumns; + QgsDistanceArea mCalc; - QgsDistanceArea* mCalc; }; Q_DECLARE_METATYPE( QgsExpression::Interval ); diff --git a/src/gui/qgsexpressionbuilderdialog.cpp b/src/gui/qgsexpressionbuilderdialog.cpp index 479d31acf69..aac1fbefbaf 100644 --- a/src/gui/qgsexpressionbuilderdialog.cpp +++ b/src/gui/qgsexpressionbuilderdialog.cpp @@ -55,3 +55,9 @@ void QgsExpressionBuilderDialog::closeEvent( QCloseEvent *event ) QSettings settings; settings.setValue( "/Windows/ExpressionBuilderDialog/geometry", saveGeometry() ); } + +void QgsExpressionBuilderDialog::setGeomCalculator( const QgsDistanceArea & da ) +{ + // Store in child widget only. + builder->setGeomCalculator( da ); +} diff --git a/src/gui/qgsexpressionbuilderdialog.h b/src/gui/qgsexpressionbuilderdialog.h index 04088eb35ec..dae9d9ff8d5 100644 --- a/src/gui/qgsexpressionbuilderdialog.h +++ b/src/gui/qgsexpressionbuilderdialog.h @@ -17,6 +17,7 @@ #define QGSEXPRESSIONBUILDERDIALOG_H #include +#include "qgsdistancearea.h" #include "ui_qgsexpressionbuilderdialogbase.h" /** A generic dialog for building expression strings @@ -34,6 +35,11 @@ class GUI_EXPORT QgsExpressionBuilderDialog : public QDialog, private Ui::QgsExp QString expressionText(); + /** Sets geometry calculator used in distance/area calculations. + * @note added in version 2.0 + */ + void setGeomCalculator( const QgsDistanceArea & da ); + protected: /** * Handle closing of the window diff --git a/src/gui/qgsexpressionbuilderwidget.cpp b/src/gui/qgsexpressionbuilderwidget.cpp index ece37fc89ee..45b1c1477c0 100644 --- a/src/gui/qgsexpressionbuilderwidget.cpp +++ b/src/gui/qgsexpressionbuilderwidget.cpp @@ -240,6 +240,11 @@ bool QgsExpressionBuilderWidget::isExpressionValid() return mExpressionValid; } +void QgsExpressionBuilderWidget::setGeomCalculator( const QgsDistanceArea & da ) +{ + mDa = da; +} + QString QgsExpressionBuilderWidget::expressionText() { return txtExpressionString->toPlainText(); @@ -266,10 +271,15 @@ void QgsExpressionBuilderWidget::on_txtExpressionString_textChanged() return; } + + QgsExpression exp( text ); if ( mLayer ) { + // Only set calculator if we have layer, else use default. + exp.setGeomCalculator( mDa ); + if ( !mFeature.isValid() ) { mLayer->select( mLayer->pendingAllAttributesList(), QgsRectangle(), mLayer->geometryType() != QGis::NoGeometry && exp.needsGeometry() ); @@ -406,12 +416,12 @@ QString QgsExpressionBuilderWidget::loadFunctionHelp( QgsExpressionItem* express return ""; QString helpContents; - // Return the function help that is set for the function if there is one. + // Return the function help that is set for the function if there is one. if ( !expressionItem->getHelpText().isEmpty() ) { - QString myStyle = QgsApplication::reportStyleSheet(); - helpContents = "" + expressionItem->getHelpText() + ""; - return helpContents; + QString myStyle = QgsApplication::reportStyleSheet(); + helpContents = "" + expressionItem->getHelpText() + ""; + return helpContents; } // set up the path to the help file QString helpFilesPath = QgsApplication::pkgDataPath() + "/resources/function_help/"; diff --git a/src/gui/qgsexpressionbuilderwidget.h b/src/gui/qgsexpressionbuilderwidget.h index 7cab7681c76..a7c2e1e649c 100644 --- a/src/gui/qgsexpressionbuilderwidget.h +++ b/src/gui/qgsexpressionbuilderwidget.h @@ -20,6 +20,7 @@ #include "ui_qgsexpressionbuilder.h" #include "qgsvectorlayer.h" #include "qgsexpressionhighlighter.h" +#include "qgsdistancearea.h" #include "QStandardItemModel" #include "QStandardItem" @@ -122,6 +123,11 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp void loadFieldNames( QgsFieldMap fields ); + /** Sets geometry calculator used in distance/area calculations. + * @note added in version 2.0 + */ + void setGeomCalculator( const QgsDistanceArea & da ); + /** Gets the expression string that has been set in the expression area. * @returns The expression as a string. */ QString expressionText(); @@ -176,6 +182,7 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp QgsFeature mFeature; QgsExpressionHighlighter* highlighter; bool mExpressionValid; + QgsDistanceArea mDa; }; #endif // QGSEXPRESSIONBUILDER_H diff --git a/src/ui/qgsoptionsbase.ui b/src/ui/qgsoptionsbase.ui index 70568e8888b..9601ae87773 100644 --- a/src/ui/qgsoptionsbase.ui +++ b/src/ui/qgsoptionsbase.ui @@ -33,7 +33,7 @@ - 0 + 4 @@ -1561,7 +1561,7 @@ 0 0 770 - 757 + 691 @@ -1780,21 +1780,14 @@ Measure tool - - - - Semi-minor - - - - + Rubberband color - + @@ -1807,103 +1800,80 @@ - + Preferred measurements units - + Meters - + Feet - + Preferred angle units - + Degrees - + Radians - + Decimal places - + - + Keep base unit - + - - - - - - - Semi-major - - - - + Gon - - - - - - - - - - Ellipsoid for distance calculations - - - - + Qt::Horizontal @@ -1950,8 +1920,8 @@ 0 0 - 786 - 585 + 274 + 87 @@ -2031,7 +2001,7 @@ 0 0 - 770 + 581 606 @@ -2407,8 +2377,8 @@ 0 0 - 786 - 585 + 653 + 415 @@ -2594,8 +2564,8 @@ 0 0 - 786 - 585 + 519 + 565 @@ -2691,8 +2661,8 @@ 0 0 - 786 - 585 + 505 + 573 @@ -2974,7 +2944,6 @@ cmbIdentifyMode cbxAutoFeatureForm spinBoxIdentifyValue - cmbEllipsoid pbnMeasureColor mDecimalPlacesSpinBox mKeepBaseUnitCheckBox diff --git a/src/ui/qgsprojectpropertiesbase.ui b/src/ui/qgsprojectpropertiesbase.ui index dfd70ccb894..f963ddc279e 100644 --- a/src/ui/qgsprojectpropertiesbase.ui +++ b/src/ui/qgsprojectpropertiesbase.ui @@ -197,6 +197,45 @@ + + + Measure tool + + + + + + Ellipsoid for distance calculations + + + + + + + + + + + + + Semi-minor + + + + + + + + + + Semi-major + + + + + + + Used when CRS transformation is turned off @@ -232,7 +271,7 @@ - + Degree display @@ -262,7 +301,7 @@ - + Precision @@ -326,7 +365,7 @@ - + Project scales