|
Quantum GIS API Documentation
master-ce49b66
|
00001 /*************************************************************************** 00002 qgsrasterlayer.cpp - description 00003 ------------------- 00004 begin : Sat Jun 22 2002 00005 copyright : (C) 2003 by Tim Sutton, Steve Halasz and Gary E.Sherman 00006 email : tim at linfiniti.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 #include "qgsapplication.h" 00018 #include "qgscolorrampshader.h" 00019 #include "qgscoordinatereferencesystem.h" 00020 #include "qgscoordinatetransform.h" 00021 #include "qgsdatasourceuri.h" 00022 #include "qgslogger.h" 00023 #include "qgsmaplayerregistry.h" 00024 #include "qgsmaptopixel.h" 00025 #include "qgsmessagelog.h" 00026 #include "qgsmultibandcolorrenderer.h" 00027 #include "qgspalettedrasterrenderer.h" 00028 #include "qgsprojectfiletransform.h" 00029 #include "qgsproviderregistry.h" 00030 #include "qgspseudocolorshader.h" 00031 #include "qgsrasterdrawer.h" 00032 #include "qgsrasteriterator.h" 00033 #include "qgsrasterlayer.h" 00034 #include "qgsrasterprojector.h" 00035 #include "qgsrasterrange.h" 00036 #include "qgsrasterrendererregistry.h" 00037 #include "qgsrectangle.h" 00038 #include "qgsrendercontext.h" 00039 #include "qgssinglebandcolordatarenderer.h" 00040 #include "qgssinglebandgrayrenderer.h" 00041 #include "qgssinglebandpseudocolorrenderer.h" 00042 00043 #include <cmath> 00044 #include <cstdio> 00045 #include <limits> 00046 #include <typeinfo> 00047 00048 #include <QApplication> 00049 #include <QCursor> 00050 #include <QDomElement> 00051 #include <QDomNode> 00052 #include <QFile> 00053 #include <QFileInfo> 00054 #include <QFont> 00055 #include <QFontMetrics> 00056 #include <QFrame> 00057 #include <QImage> 00058 #include <QLabel> 00059 #include <QLibrary> 00060 #include <QList> 00061 #include <QMatrix> 00062 #include <QMessageBox> 00063 #include <QPainter> 00064 #include <QPixmap> 00065 #include <QRegExp> 00066 #include <QSettings> 00067 #include <QSlider> 00068 #include <QTime> 00069 00070 // typedefs for provider plugin functions of interest 00071 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString ); 00072 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg ); 00073 00074 #define ERR(message) QGS_ERROR_MESSAGE(message,"Raster layer") 00075 00076 const double QgsRasterLayer::CUMULATIVE_CUT_LOWER = 0.02; 00077 const double QgsRasterLayer::CUMULATIVE_CUT_UPPER = 0.98; 00078 const double QgsRasterLayer::SAMPLE_SIZE = 250000; 00079 00080 QgsRasterLayer::QgsRasterLayer() 00081 : QgsMapLayer( RasterLayer ) 00082 , QSTRING_NOT_SET( "Not Set" ) 00083 , TRSTRING_NOT_SET( tr( "Not Set" ) ) 00084 , mDataProvider( 0 ) 00085 { 00086 init(); 00087 mValid = false; 00088 } 00089 00090 QgsRasterLayer::QgsRasterLayer( 00091 QString const & path, 00092 QString const & baseName, 00093 bool loadDefaultStyleFlag ) 00094 : QgsMapLayer( RasterLayer, baseName, path ) 00095 , QSTRING_NOT_SET( "Not Set" ) 00096 , TRSTRING_NOT_SET( tr( "Not Set" ) ) 00097 , mDataProvider( 0 ) 00098 { 00099 QgsDebugMsg( "Entered" ); 00100 00101 // TODO, call constructor with provider key 00102 init(); 00103 setDataProvider( "gdal" ); 00104 if ( !mValid ) return; 00105 00106 bool defaultLoadedFlag = false; 00107 if ( mValid && loadDefaultStyleFlag ) 00108 { 00109 loadDefaultStyle( defaultLoadedFlag ); 00110 } 00111 if ( !defaultLoadedFlag ) 00112 { 00113 setDefaultContrastEnhancement(); 00114 } 00115 return; 00116 } // QgsRasterLayer ctor 00117 00122 QgsRasterLayer::QgsRasterLayer( const QString & uri, 00123 const QString & baseName, 00124 const QString & providerKey, 00125 bool loadDefaultStyleFlag ) 00126 : QgsMapLayer( RasterLayer, baseName, uri ) 00127 // Constant that signals property not used. 00128 , QSTRING_NOT_SET( "Not Set" ) 00129 , TRSTRING_NOT_SET( tr( "Not Set" ) ) 00130 , mDataProvider( 0 ) 00131 , mProviderKey( providerKey ) 00132 { 00133 QgsDebugMsg( "Entered" ); 00134 init(); 00135 setDataProvider( providerKey ); 00136 if ( !mValid ) return; 00137 00138 // load default style 00139 bool defaultLoadedFlag = false; 00140 if ( mValid && loadDefaultStyleFlag ) 00141 { 00142 loadDefaultStyle( defaultLoadedFlag ); 00143 } 00144 if ( !defaultLoadedFlag ) 00145 { 00146 setDefaultContrastEnhancement(); 00147 } 00148 00149 // TODO: Connect signals from the dataprovider to the qgisapp 00150 00151 emit statusChanged( tr( "QgsRasterLayer created" ) ); 00152 } // QgsRasterLayer ctor 00153 00154 QgsRasterLayer::~QgsRasterLayer() 00155 { 00156 mValid = false; 00157 // Note: provider and other interfaces are owned and deleted by pipe 00158 } 00159 00161 // 00162 // Static Methods and members 00163 // 00165 00173 void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString ) 00174 { 00175 QgsDebugMsg( "Entered" ); 00176 buildsupportedrasterfilefilter_t *pBuild = ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( QgsProviderRegistry::instance()->function( "gdal", "buildSupportedRasterFileFilter" ) ); 00177 if ( ! pBuild ) 00178 { 00179 QgsDebugMsg( "Could get buildSupportedRasterFileFilter in gdal provider library" ); 00180 return; 00181 } 00182 00183 pBuild( theFileFiltersString ); 00184 } 00185 00189 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg ) 00190 { 00191 isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( QgsProviderRegistry::instance()->function( "gdal", "isValidRasterFileName" ) ); 00192 if ( ! pValid ) 00193 { 00194 QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" ); 00195 return false; 00196 } 00197 00198 bool myIsValid = pValid( theFileNameQString, retErrMsg ); 00199 return myIsValid; 00200 } 00201 00202 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString ) 00203 { 00204 QString retErrMsg; 00205 return isValidRasterFileName( theFileNameQString, retErrMsg ); 00206 } 00207 00208 QDateTime QgsRasterLayer::lastModified( QString const & name ) 00209 { 00210 QgsDebugMsg( "name=" + name ); 00211 QDateTime t; 00212 00213 QFileInfo fi( name ); 00214 00215 // Is it file? 00216 if ( !fi.exists() ) 00217 return t; 00218 00219 t = fi.lastModified(); 00220 00221 QgsDebugMsg( "last modified = " + t.toString() ); 00222 00223 return t; 00224 } 00225 00226 // typedef for the QgsDataProvider class factory 00227 typedef QgsDataProvider * classFactoryFunction_t( const QString * ); 00228 00230 // 00231 // Non Static Public methods 00232 // 00234 00235 int QgsRasterLayer::bandCount() const 00236 { 00237 if ( !mDataProvider ) return 0; 00238 return mDataProvider->bandCount(); 00239 } 00240 00241 const QString QgsRasterLayer::bandName( int theBandNo ) 00242 { 00243 return dataProvider()->generateBandName( theBandNo ); 00244 } 00245 00246 void QgsRasterLayer::setRendererForDrawingStyle( const DrawingStyle & theDrawingStyle ) 00247 { 00248 setRenderer( QgsRasterRendererRegistry::instance()->defaultRendererForDrawingStyle( theDrawingStyle, mDataProvider ) ); 00249 } 00250 00254 QgsRasterDataProvider* QgsRasterLayer::dataProvider() 00255 { 00256 return mDataProvider; 00257 } 00258 00262 const QgsRasterDataProvider* QgsRasterLayer::dataProvider() const 00263 { 00264 return mDataProvider; 00265 } 00266 00267 void QgsRasterLayer::reload() 00268 { 00269 if ( mDataProvider ) 00270 { 00271 mDataProvider->reloadData(); 00272 } 00273 } 00274 00275 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext ) 00276 { 00277 QgsDebugMsg( "entered. (renderContext)" ); 00278 00279 // Don't waste time drawing if transparency is at 0 (completely transparent) 00280 if ( mTransparencyLevel == 0 ) 00281 return true; 00282 00283 QgsDebugMsg( "checking timestamp." ); 00284 00285 // Check timestamp 00286 if ( !update() ) 00287 { 00288 return false; 00289 } 00290 00291 const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); 00292 00293 QgsRectangle myProjectedViewExtent; 00294 QgsRectangle myProjectedLayerExtent; 00295 00296 if ( rendererContext.coordinateTransform() ) 00297 { 00298 QgsDebugMsg( "coordinateTransform set -> project extents." ); 00299 try 00300 { 00301 myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() ); 00302 } 00303 catch ( QgsCsException &cs ) 00304 { 00305 QgsMessageLog::logMessage( tr( "Could not reproject view extent: %1" ).arg( cs.what() ), tr( "Raster" ) ); 00306 myProjectedViewExtent.setMinimal(); 00307 } 00308 00309 try 00310 { 00311 myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( extent() ); 00312 } 00313 catch ( QgsCsException &cs ) 00314 { 00315 QgsMessageLog::logMessage( tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), tr( "Raster" ) ); 00316 myProjectedViewExtent.setMinimal(); 00317 } 00318 } 00319 else 00320 { 00321 QgsDebugMsg( "coordinateTransform not set" ); 00322 myProjectedViewExtent = rendererContext.extent(); 00323 myProjectedLayerExtent = extent(); 00324 } 00325 00326 QPainter* theQPainter = rendererContext.painter(); 00327 00328 if ( !theQPainter ) 00329 { 00330 return false; 00331 } 00332 00333 // clip raster extent to view extent 00334 QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); 00335 if ( myRasterExtent.isEmpty() ) 00336 { 00337 QgsDebugMsg( "draw request outside view extent." ); 00338 // nothing to do 00339 return true; 00340 } 00341 00342 QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); 00343 QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); 00344 QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); 00345 QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); 00346 00347 // 00348 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings 00349 // relating to the size (in pixels and coordinate system units) of the raster part that is 00350 // in view in the map window. It also stores the origin. 00351 // 00352 //this is not a class level member because every time the user pans or zooms 00353 //the contents of the rasterViewPort will change 00354 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 00355 00356 myRasterViewPort->mDrawnExtent = myRasterExtent; 00357 if ( rendererContext.coordinateTransform() ) 00358 { 00359 myRasterViewPort->mSrcCRS = crs(); 00360 myRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); 00361 } 00362 else 00363 { 00364 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 00365 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 00366 } 00367 00368 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) 00369 myRasterViewPort->mTopLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); 00370 myRasterViewPort->mBottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); 00371 00372 // align to output device grid, i.e. floor/ceil to integers 00373 // TODO: this should only be done if paint device is raster - screen, image 00374 // for other devices (pdf) it can have floating point origin 00375 // we could use floating point for raster devices as well, but respecting the 00376 // output device grid should make it more effective as the resampling is done in 00377 // the provider anyway 00378 if ( true ) 00379 { 00380 myRasterViewPort->mTopLeftPoint.setX( floor( myRasterViewPort->mTopLeftPoint.x() ) ); 00381 myRasterViewPort->mTopLeftPoint.setY( floor( myRasterViewPort->mTopLeftPoint.y() ) ); 00382 myRasterViewPort->mBottomRightPoint.setX( ceil( myRasterViewPort->mBottomRightPoint.x() ) ); 00383 myRasterViewPort->mBottomRightPoint.setY( ceil( myRasterViewPort->mBottomRightPoint.y() ) ); 00384 // recalc myRasterExtent to aligned values 00385 myRasterExtent.set( 00386 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->mTopLeftPoint.x(), 00387 myRasterViewPort->mBottomRightPoint.y() ), 00388 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->mBottomRightPoint.x(), 00389 myRasterViewPort->mTopLeftPoint.y() ) 00390 ); 00391 00392 } 00393 00394 myRasterViewPort->mWidth = static_cast<int>( qAbs(( myRasterExtent.width() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00395 myRasterViewPort->mHeight = static_cast<int>( qAbs(( myRasterExtent.height() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00396 00397 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue 00398 //theQgsMapToPixel.mapUnitsPerPixel() is less then 1, 00399 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() 00400 00401 QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ), 3 ); 00402 QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( width() ), 3 ); 00403 QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( height() ), 3 ); 00404 QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); 00405 QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); 00406 QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); 00407 QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); 00408 00409 QgsDebugMsgLevel( QString( "mTopLeftPoint.x() = %1" ).arg( myRasterViewPort->mTopLeftPoint.x() ), 3 ); 00410 QgsDebugMsgLevel( QString( "mBottomRightPoint.x() = %1" ).arg( myRasterViewPort->mBottomRightPoint.x() ), 3 ); 00411 QgsDebugMsgLevel( QString( "mTopLeftPoint.y() = %1" ).arg( myRasterViewPort->mTopLeftPoint.y() ), 3 ); 00412 QgsDebugMsgLevel( QString( "mBottomRightPoint.y() = %1" ).arg( myRasterViewPort->mBottomRightPoint.y() ), 3 ); 00413 00414 QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( myRasterViewPort->mWidth ), 3 ); 00415 QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( myRasterViewPort->mHeight ), 3 ); 00416 00417 // /\/\/\ - added to handle zoomed-in rasters 00418 00419 mLastViewPort = *myRasterViewPort; 00420 00421 // TODO: is it necessary? Probably WMS only? 00422 mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); 00423 00424 draw( theQPainter, myRasterViewPort, &theQgsMapToPixel ); 00425 00426 delete myRasterViewPort; 00427 QgsDebugMsg( "exiting." ); 00428 00429 return true; 00430 00431 } 00432 00433 void QgsRasterLayer::draw( QPainter * theQPainter, 00434 QgsRasterViewPort * theRasterViewPort, 00435 const QgsMapToPixel* theQgsMapToPixel ) 00436 { 00437 QgsDebugMsg( " 3 arguments" ); 00438 QTime time; 00439 time.start(); 00440 // 00441 // 00442 // The goal here is to make as many decisions as possible early on (outside of the rendering loop) 00443 // so that we can maximise performance of the rendering process. So now we check which drawing 00444 // procedure to use : 00445 // 00446 00447 QgsRasterProjector *projector = mPipe.projector(); 00448 00449 // TODO add a method to interface to get provider and get provider 00450 // params in QgsRasterProjector 00451 if ( projector ) 00452 { 00453 projector->setCRS( theRasterViewPort->mSrcCRS, theRasterViewPort->mDestCRS ); 00454 } 00455 00456 // Drawer to pipe? 00457 QgsRasterIterator iterator( mPipe.last() ); 00458 QgsRasterDrawer drawer( &iterator ); 00459 drawer.draw( theQPainter, theRasterViewPort, theQgsMapToPixel ); 00460 00461 QgsDebugMsg( QString( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ) ); 00462 } //end of draw method 00463 00464 QString QgsRasterLayer::lastError() 00465 { 00466 return mError; 00467 } 00468 00469 QString QgsRasterLayer::lastErrorTitle() 00470 { 00471 return mErrorCaption; 00472 } 00473 00474 QList< QPair< QString, QColor > > QgsRasterLayer::legendSymbologyItems() const 00475 { 00476 QList< QPair< QString, QColor > > symbolList; 00477 QgsRasterRenderer *renderer = mPipe.renderer(); 00478 if ( renderer ) 00479 { 00480 renderer->legendSymbologyItems( symbolList ); 00481 } 00482 return symbolList; 00483 } 00484 00485 QString QgsRasterLayer::metadata() 00486 { 00487 QString myMetadata ; 00488 myMetadata += "<p class=\"glossy\">" + tr( "Driver" ) + "</p>\n"; 00489 myMetadata += "<p>"; 00490 myMetadata += mDataProvider->description(); 00491 myMetadata += "</p>\n"; 00492 00493 // Insert provider-specific (e.g. WMS-specific) metadata 00494 // crashing 00495 myMetadata += mDataProvider->metadata(); 00496 00497 myMetadata += "<p class=\"glossy\">"; 00498 myMetadata += tr( "No Data Value" ); 00499 myMetadata += "</p>\n"; 00500 myMetadata += "<p>"; 00501 // TODO: all bands 00502 if ( mDataProvider->srcHasNoDataValue( 1 ) ) 00503 { 00504 myMetadata += QString::number( mDataProvider->srcNoDataValue( 1 ) ); 00505 } 00506 else 00507 { 00508 myMetadata += "*" + tr( "NoDataValue not set" ) + "*"; 00509 } 00510 myMetadata += "</p>\n"; 00511 00512 myMetadata += "</p>\n"; 00513 myMetadata += "<p class=\"glossy\">"; 00514 myMetadata += tr( "Data Type" ); 00515 myMetadata += "</p>\n"; 00516 myMetadata += "<p>"; 00517 //just use the first band 00518 switch ( mDataProvider->srcDataType( 1 ) ) 00519 { 00520 case QGis::Byte: 00521 myMetadata += tr( "Byte - Eight bit unsigned integer" ); 00522 break; 00523 case QGis::UInt16: 00524 myMetadata += tr( "UInt16 - Sixteen bit unsigned integer " ); 00525 break; 00526 case QGis::Int16: 00527 myMetadata += tr( "Int16 - Sixteen bit signed integer " ); 00528 break; 00529 case QGis::UInt32: 00530 myMetadata += tr( "UInt32 - Thirty two bit unsigned integer " ); 00531 break; 00532 case QGis::Int32: 00533 myMetadata += tr( "Int32 - Thirty two bit signed integer " ); 00534 break; 00535 case QGis::Float32: 00536 myMetadata += tr( "Float32 - Thirty two bit floating point " ); 00537 break; 00538 case QGis::Float64: 00539 myMetadata += tr( "Float64 - Sixty four bit floating point " ); 00540 break; 00541 case QGis::CInt16: 00542 myMetadata += tr( "CInt16 - Complex Int16 " ); 00543 break; 00544 case QGis::CInt32: 00545 myMetadata += tr( "CInt32 - Complex Int32 " ); 00546 break; 00547 case QGis::CFloat32: 00548 myMetadata += tr( "CFloat32 - Complex Float32 " ); 00549 break; 00550 case QGis::CFloat64: 00551 myMetadata += tr( "CFloat64 - Complex Float64 " ); 00552 break; 00553 default: 00554 myMetadata += tr( "Could not determine raster data type." ); 00555 } 00556 myMetadata += "</p>\n"; 00557 00558 myMetadata += "<p class=\"glossy\">"; 00559 myMetadata += tr( "Pyramid overviews" ); 00560 myMetadata += "</p>\n"; 00561 myMetadata += "<p>"; 00562 00563 myMetadata += "<p class=\"glossy\">"; 00564 myMetadata += tr( "Layer Spatial Reference System" ); 00565 myMetadata += "</p>\n"; 00566 myMetadata += "<p>"; 00567 myMetadata += crs().toProj4(); 00568 myMetadata += "</p>\n"; 00569 00570 myMetadata += "<p class=\"glossy\">"; 00571 myMetadata += tr( "Layer Extent (layer original source projection)" ); 00572 myMetadata += "</p>\n"; 00573 myMetadata += "<p>"; 00574 myMetadata += mDataProvider->extent().toString(); 00575 myMetadata += "</p>\n"; 00576 00577 // output coordinate system 00578 // TODO: this is not related to layer, to be removed? [MD] 00579 #if 0 00580 myMetadata += "<tr><td class=\"glossy\">"; 00581 myMetadata += tr( "Project Spatial Reference System" ); 00582 myMetadata += "</p>\n"; 00583 myMetadata += "<p>"; 00584 myMetadata += mCoordinateTransform->destCRS().toProj4(); 00585 myMetadata += "</p>\n"; 00586 #endif 00587 00588 // 00589 // Add the stats for each band to the output table 00590 // 00591 int myBandCountInt = bandCount(); 00592 for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt ) 00593 { 00594 QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " ); 00595 //band name 00596 myMetadata += "<p class=\"glossy\">\n"; 00597 myMetadata += tr( "Band" ); 00598 myMetadata += "</p>\n"; 00599 myMetadata += "<p>"; 00600 myMetadata += bandName( myIteratorInt ); 00601 myMetadata += "</p>\n"; 00602 //band number 00603 myMetadata += "<p>"; 00604 myMetadata += tr( "Band No" ); 00605 myMetadata += "</p>\n"; 00606 myMetadata += "<p>\n"; 00607 myMetadata += QString::number( myIteratorInt ); 00608 myMetadata += "</p>\n"; 00609 00610 //check if full stats for this layer have already been collected 00611 if ( !dataProvider()->hasStatistics( myIteratorInt ) ) //not collected 00612 { 00613 QgsDebugMsg( ".....no" ); 00614 00615 myMetadata += "<p>"; 00616 myMetadata += tr( "No Stats" ); 00617 myMetadata += "</p>\n"; 00618 myMetadata += "<p>\n"; 00619 myMetadata += tr( "No stats collected yet" ); 00620 myMetadata += "</p>\n"; 00621 } 00622 else // collected - show full detail 00623 { 00624 QgsDebugMsg( ".....yes" ); 00625 00626 QgsRasterBandStats myRasterBandStats = dataProvider()->bandStatistics( myIteratorInt ); 00627 //Min Val 00628 myMetadata += "<p>"; 00629 myMetadata += tr( "Min Val" ); 00630 myMetadata += "</p>\n"; 00631 myMetadata += "<p>\n"; 00632 myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 ); 00633 myMetadata += "</p>\n"; 00634 00635 // Max Val 00636 myMetadata += "<p>"; 00637 myMetadata += tr( "Max Val" ); 00638 myMetadata += "</p>\n"; 00639 myMetadata += "<p>\n"; 00640 myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 ); 00641 myMetadata += "</p>\n"; 00642 00643 // Range 00644 myMetadata += "<p>"; 00645 myMetadata += tr( "Range" ); 00646 myMetadata += "</p>\n"; 00647 myMetadata += "<p>\n"; 00648 myMetadata += QString::number( myRasterBandStats.range, 'f', 10 ); 00649 myMetadata += "</p>\n"; 00650 00651 // Mean 00652 myMetadata += "<p>"; 00653 myMetadata += tr( "Mean" ); 00654 myMetadata += "</p>\n"; 00655 myMetadata += "<p>\n"; 00656 myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 ); 00657 myMetadata += "</p>\n"; 00658 00659 //sum of squares 00660 myMetadata += "<p>"; 00661 myMetadata += tr( "Sum of squares" ); 00662 myMetadata += "</p>\n"; 00663 myMetadata += "<p>\n"; 00664 myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 ); 00665 myMetadata += "</p>\n"; 00666 00667 //standard deviation 00668 myMetadata += "<p>"; 00669 myMetadata += tr( "Standard Deviation" ); 00670 myMetadata += "</p>\n"; 00671 myMetadata += "<p>\n"; 00672 myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 ); 00673 myMetadata += "</p>\n"; 00674 00675 //sum of all cells 00676 myMetadata += "<p>"; 00677 myMetadata += tr( "Sum of all cells" ); 00678 myMetadata += "</p>\n"; 00679 myMetadata += "<p>\n"; 00680 myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 ); 00681 myMetadata += "</p>\n"; 00682 00683 //number of cells 00684 myMetadata += "<p>"; 00685 myMetadata += tr( "Cell Count" ); 00686 myMetadata += "</p>\n"; 00687 myMetadata += "<p>\n"; 00688 myMetadata += QString::number( myRasterBandStats.elementCount ); 00689 myMetadata += "</p>\n"; 00690 } 00691 } 00692 00693 QgsDebugMsg( myMetadata ); 00694 return myMetadata; 00695 } 00696 00701 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber ) 00702 { 00703 //TODO: This function should take dimensions 00704 QgsDebugMsg( "entered." ); 00705 00706 // Only do this for the GDAL provider? 00707 // Maybe WMS can do this differently using QImage::numColors and QImage::color() 00708 if ( mDataProvider->colorInterpretation( theBandNumber ) == QgsRaster::PaletteIndex ) 00709 { 00710 QgsDebugMsg( "....found paletted image" ); 00711 QgsColorRampShader myShader; 00712 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber ); 00713 if ( myColorRampItemList.size() > 0 ) 00714 { 00715 QgsDebugMsg( "....got color ramp item list" ); 00716 myShader.setColorRampItemList( myColorRampItemList ); 00717 myShader.setColorRampType( QgsColorRampShader::DISCRETE ); 00718 // Draw image 00719 int mySize = 100; 00720 QPixmap myPalettePixmap( mySize, mySize ); 00721 QPainter myQPainter( &myPalettePixmap ); 00722 00723 QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 ); 00724 myQImage.fill( 0 ); 00725 myPalettePixmap.fill(); 00726 00727 double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize ); 00728 double myValue = 0.0; 00729 for ( int myRow = 0; myRow < mySize; myRow++ ) 00730 { 00731 QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow ); 00732 for ( int myCol = 0; myCol < mySize; myCol++ ) 00733 { 00734 myValue = myStep * ( double )( myCol + myRow * mySize ); 00735 int c1, c2, c3; 00736 myShader.shade( myValue, &c1, &c2, &c3 ); 00737 myLineBuffer[ myCol ] = qRgb( c1, c2, c3 ); 00738 } 00739 } 00740 00741 myQPainter.drawImage( 0, 0, myQImage ); 00742 return myPalettePixmap; 00743 } 00744 QPixmap myNullPixmap; 00745 return myNullPixmap; 00746 } 00747 else 00748 { 00749 //invalid layer was requested 00750 QPixmap myNullPixmap; 00751 return myNullPixmap; 00752 } 00753 } 00754 00755 QString QgsRasterLayer::providerType() const 00756 { 00757 return mProviderKey; 00758 } 00759 00763 double QgsRasterLayer::rasterUnitsPerPixelX() 00764 { 00765 // We return one raster pixel per map unit pixel 00766 // One raster pixel can have several raster units... 00767 00768 // We can only use one of the mGeoTransform[], so go with the 00769 // horisontal one. 00770 00771 if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size && mDataProvider->xSize() > 0 ) 00772 { 00773 return mDataProvider->extent().width() / mDataProvider->xSize(); 00774 } 00775 return 1; 00776 } 00777 00778 double QgsRasterLayer::rasterUnitsPerPixelY() 00779 { 00780 if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size && mDataProvider->xSize() > 0 ) 00781 { 00782 return mDataProvider->extent().height() / mDataProvider->ySize(); 00783 } 00784 return 1; 00785 } 00786 00787 void QgsRasterLayer::init() 00788 { 00789 mRasterType = QgsRasterLayer::GrayOrUndefined; 00790 00791 setRendererForDrawingStyle( QgsRasterLayer::UndefinedDrawingStyle ); 00792 00793 //Initialize the last view port structure, should really be a class 00794 mLastViewPort.mWidth = 0; 00795 mLastViewPort.mHeight = 0; 00796 } 00797 00798 void QgsRasterLayer::setDataProvider( QString const & provider ) 00799 { 00800 QgsDebugMsg( "Entered" ); 00801 mValid = false; // assume the layer is invalid until we determine otherwise 00802 00803 mPipe.remove( mDataProvider ); // deletes if exists 00804 mDataProvider = 0; 00805 00806 // XXX should I check for and possibly delete any pre-existing providers? 00807 // XXX How often will that scenario occur? 00808 00809 mProviderKey = provider; 00810 // set the layer name (uppercase first character) 00811 if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent? 00812 { 00813 setLayerName( mLayerName ); 00814 } 00815 00816 //mBandCount = 0; 00817 00818 mDataProvider = ( QgsRasterDataProvider* )QgsProviderRegistry::instance()->provider( mProviderKey, mDataSource ); 00819 if ( !mDataProvider ) 00820 { 00821 //QgsMessageLog::logMessage( tr( "Cannot instantiate the data provider" ), tr( "Raster" ) ); 00822 appendError( ERR( tr( "Cannot instantiate the '%1' data provider" ).arg( mProviderKey ) ) ); 00823 return; 00824 } 00825 QgsDebugMsg( "Data provider created" ); 00826 00827 // Set data provider into pipe even if not valid so that it is deleted with pipe (with layer) 00828 mPipe.set( mDataProvider ); 00829 if ( !mDataProvider->isValid() ) 00830 { 00831 setError( mDataProvider->error() ); 00832 appendError( ERR( tr( "Provider is not valid (provider: %1, URI: %2" ).arg( mProviderKey ).arg( mDataSource ) ) ); 00833 return; 00834 } 00835 00836 if ( provider == "gdal" ) 00837 { 00838 // make sure that the /vsigzip or /vsizip is added to uri, if applicable 00839 mDataSource = mDataProvider->dataSourceUri(); 00840 } 00841 00842 // get the extent 00843 QgsRectangle mbr = mDataProvider->extent(); 00844 00845 // show the extent 00846 QString s = mbr.toString(); 00847 QgsDebugMsg( "Extent of layer: " + s ); 00848 // store the extent 00849 setExtent( mbr ); 00850 00851 // upper case the first letter of the layer name 00852 QgsDebugMsg( "mLayerName: " + name() ); 00853 00854 // set up the raster drawing style 00855 // Do not set any 'sensible' style here, the style is set later 00856 00857 // Setup source CRS 00858 setCrs( QgsCoordinateReferenceSystem( mDataProvider->crs() ) ); 00859 00860 QString mySourceWkt = crs().toWkt(); 00861 00862 QgsDebugMsg( "using wkt:\n" + mySourceWkt ); 00863 00864 //defaults - Needs to be set after the Contrast list has been build 00865 //Try to read the default contrast enhancement from the config file 00866 00867 QSettings myQSettings; 00868 00869 //decide what type of layer this is... 00870 //TODO Change this to look at the color interp and palette interp to decide which type of layer it is 00871 QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) ); 00872 QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) ); 00873 if (( mDataProvider->bandCount() > 1 ) ) 00874 { 00875 mRasterType = Multiband; 00876 } 00877 else if ( mDataProvider->dataType( 1 ) == QGis::ARGB32 00878 || mDataProvider->dataType( 1 ) == QGis::ARGB32_Premultiplied ) 00879 { 00880 mRasterType = ColorLayer; 00881 } 00882 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex ) 00883 { 00884 mRasterType = Palette; 00885 } 00886 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette ) 00887 { 00888 mRasterType = Palette; 00889 } 00890 else 00891 { 00892 mRasterType = GrayOrUndefined; 00893 } 00894 00895 QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) ); 00896 if ( mRasterType == ColorLayer ) 00897 { 00898 QgsDebugMsg( "Setting drawing style to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 00899 setRendererForDrawingStyle( SingleBandColorDataStyle ); 00900 } 00901 else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::PaletteIndex ) 00902 { 00903 setRendererForDrawingStyle( PalettedColor ); //sensible default 00904 } 00905 else if ( mRasterType == Palette && mDataProvider->colorInterpretation( 1 ) == QgsRaster::ContinuousPalette ) 00906 { 00907 setRendererForDrawingStyle( SingleBandPseudoColor ); 00908 // Load color table 00909 QList<QgsColorRampShader::ColorRampItem> colorTable = mDataProvider->colorTable( 1 ); 00910 QgsSingleBandPseudoColorRenderer* r = dynamic_cast<QgsSingleBandPseudoColorRenderer*>( renderer() ); 00911 if ( r ) 00912 { 00913 // TODO: this should go somewhere else 00914 QgsRasterShader* shader = new QgsRasterShader(); 00915 QgsColorRampShader* colorRampShader = new QgsColorRampShader(); 00916 colorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED ); 00917 colorRampShader->setColorRampItemList( colorTable ); 00918 shader->setRasterShaderFunction( colorRampShader ); 00919 r->setShader( shader ); 00920 } 00921 } 00922 else if ( mRasterType == Multiband ) 00923 { 00924 setRendererForDrawingStyle( MultiBandColor ); //sensible default 00925 } 00926 else //GrayOrUndefined 00927 { 00928 setRendererForDrawingStyle( SingleBandGray ); //sensible default 00929 } 00930 00931 // Auto set alpha band 00932 for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ ) 00933 { 00934 if ( mDataProvider->colorInterpretation( bandNo ) == QgsRaster::AlphaBand ) 00935 { 00936 if ( mPipe.renderer() ) 00937 { 00938 mPipe.renderer()->setAlphaBand( bandNo ); 00939 } 00940 break; 00941 } 00942 } 00943 00944 // brightness filter 00945 QgsBrightnessContrastFilter * brightnessFilter = new QgsBrightnessContrastFilter(); 00946 mPipe.set( brightnessFilter ); 00947 00948 // hue/saturation filter 00949 QgsHueSaturationFilter * hueSaturationFilter = new QgsHueSaturationFilter(); 00950 mPipe.set( hueSaturationFilter ); 00951 00952 //resampler (must be after renderer) 00953 QgsRasterResampleFilter * resampleFilter = new QgsRasterResampleFilter(); 00954 mPipe.set( resampleFilter ); 00955 00956 // projector (may be anywhere in pipe) 00957 QgsRasterProjector * projector = new QgsRasterProjector; 00958 mPipe.set( projector ); 00959 00960 // Set default identify format - use the richest format available 00961 int capabilities = mDataProvider->capabilities(); 00962 QgsRaster::IdentifyFormat identifyFormat = QgsRaster::IdentifyFormatUndefined; 00963 if ( capabilities & QgsRasterInterface::IdentifyHtml ) 00964 { 00965 // HTML is usually richest 00966 identifyFormat = QgsRaster::IdentifyFormatHtml; 00967 } 00968 else if ( capabilities & QgsRasterInterface::IdentifyFeature ) 00969 { 00970 identifyFormat = QgsRaster::IdentifyFormatFeature; 00971 } 00972 else if ( capabilities & QgsRasterInterface::IdentifyText ) 00973 { 00974 identifyFormat = QgsRaster::IdentifyFormatText; 00975 } 00976 else if ( capabilities & QgsRasterInterface::IdentifyValue ) 00977 { 00978 identifyFormat = QgsRaster::IdentifyFormatValue; 00979 } 00980 setCustomProperty( "identify/format", QgsRasterDataProvider::identifyFormatName( identifyFormat ) ); 00981 00982 // Store timestamp 00983 // TODO move to provider 00984 mLastModified = lastModified( mDataSource ); 00985 00986 // Connect provider signals 00987 connect( 00988 mDataProvider, SIGNAL( progress( int, double, QString ) ), 00989 this, SLOT( onProgress( int, double, QString ) ) 00990 ); 00991 00992 // Do a passthrough for the status bar text 00993 connect( 00994 mDataProvider, SIGNAL( statusChanged( QString ) ), 00995 this, SIGNAL( statusChanged( QString ) ) 00996 ); 00997 00998 //mark the layer as valid 00999 mValid = true; 01000 01001 QgsDebugMsg( "exiting." ); 01002 } // QgsRasterLayer::setDataProvider 01003 01004 void QgsRasterLayer::closeDataProvider() 01005 { 01006 mValid = false; 01007 mPipe.remove( mDataProvider ); 01008 mDataProvider = 0; 01009 } 01010 01011 void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, QgsRaster::ContrastEnhancementLimits theLimits, QgsRectangle theExtent, int theSampleSize, bool theGenerateLookupTableFlag ) 01012 { 01013 QgsDebugMsg( QString( "theAlgorithm = %1 theLimits = %2 theExtent.isEmpty() = %3" ).arg( theAlgorithm ).arg( theLimits ).arg( theExtent.isEmpty() ) ); 01014 if ( !mPipe.renderer() || !mDataProvider ) 01015 { 01016 return; 01017 } 01018 01019 QList<int> myBands; 01020 QList<QgsContrastEnhancement*> myEnhancements; 01021 QgsSingleBandGrayRenderer* myGrayRenderer = 0; 01022 QgsMultiBandColorRenderer* myMultiBandRenderer = 0; 01023 QString rendererType = mPipe.renderer()->type(); 01024 if ( rendererType == "singlebandgray" ) 01025 { 01026 myGrayRenderer = dynamic_cast<QgsSingleBandGrayRenderer*>( mPipe.renderer() ); 01027 if ( !myGrayRenderer ) return; 01028 myBands << myGrayRenderer->grayBand(); 01029 } 01030 else if ( rendererType == "multibandcolor" ) 01031 { 01032 myMultiBandRenderer = dynamic_cast<QgsMultiBandColorRenderer*>( mPipe.renderer() ); 01033 if ( !myMultiBandRenderer ) return; 01034 myBands << myMultiBandRenderer->redBand() << myMultiBandRenderer->greenBand() << myMultiBandRenderer->blueBand(); 01035 } 01036 01037 foreach ( int myBand, myBands ) 01038 { 01039 if ( myBand != -1 ) 01040 { 01041 QGis::DataType myType = ( QGis::DataType )mDataProvider->dataType( myBand ); 01042 QgsContrastEnhancement* myEnhancement = new QgsContrastEnhancement(( QGis::DataType )myType ); 01043 myEnhancement->setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag ); 01044 01045 double myMin = std::numeric_limits<double>::quiet_NaN(); 01046 double myMax = std::numeric_limits<double>::quiet_NaN(); 01047 01048 if ( theLimits == QgsRaster::ContrastEnhancementMinMax ) 01049 { 01050 QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, theExtent, theSampleSize ); 01051 myMin = myRasterBandStats.minimumValue; 01052 myMax = myRasterBandStats.maximumValue; 01053 } 01054 else if ( theLimits == QgsRaster::ContrastEnhancementStdDev ) 01055 { 01056 double myStdDev = 1; // make optional? 01057 QgsRasterBandStats myRasterBandStats = mDataProvider->bandStatistics( myBand, QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, theExtent, theSampleSize ); 01058 myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev ); 01059 myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev ); 01060 } 01061 else if ( theLimits == QgsRaster::ContrastEnhancementCumulativeCut ) 01062 { 01063 QSettings mySettings; 01064 double myLower = mySettings.value( "/Raster/cumulativeCutLower", QString::number( CUMULATIVE_CUT_LOWER ) ).toDouble(); 01065 double myUpper = mySettings.value( "/Raster/cumulativeCutUpper", QString::number( CUMULATIVE_CUT_UPPER ) ).toDouble(); 01066 QgsDebugMsg( QString( "myLower = %1 myUpper = %2" ).arg( myLower ).arg( myUpper ) ); 01067 mDataProvider->cumulativeCut( myBand, myLower, myUpper, myMin, myMax, theExtent, theSampleSize ); 01068 } 01069 01070 QgsDebugMsg( QString( "myBand = %1 myMin = %2 myMax = %3" ).arg( myBand ).arg( myMin ).arg( myMax ) ); 01071 myEnhancement->setMinimumValue( myMin ); 01072 myEnhancement->setMaximumValue( myMax ); 01073 myEnhancements.append( myEnhancement ); 01074 } 01075 else 01076 { 01077 myEnhancements.append( 0 ); 01078 } 01079 } 01080 01081 if ( rendererType == "singlebandgray" ) 01082 { 01083 if ( myEnhancements.value( 0 ) ) myGrayRenderer->setContrastEnhancement( myEnhancements.value( 0 ) ); 01084 } 01085 else if ( rendererType == "multibandcolor" ) 01086 { 01087 if ( myEnhancements.value( 0 ) ) myMultiBandRenderer->setRedContrastEnhancement( myEnhancements.value( 0 ) ); 01088 if ( myEnhancements.value( 1 ) ) myMultiBandRenderer->setGreenContrastEnhancement( myEnhancements.value( 1 ) ); 01089 if ( myEnhancements.value( 2 ) ) myMultiBandRenderer->setBlueContrastEnhancement( myEnhancements.value( 2 ) ); 01090 } 01091 } 01092 01093 void QgsRasterLayer::setDefaultContrastEnhancement() 01094 { 01095 QgsDebugMsg( "Entered" ); 01096 01097 QSettings mySettings; 01098 01099 QString myKey; 01100 QString myDefault; 01101 01102 // TODO: we should not test renderer class here, move it somehow to renderers 01103 if ( dynamic_cast<QgsSingleBandGrayRenderer*>( renderer() ) ) 01104 { 01105 myKey = "singleBand"; 01106 myDefault = "StretchToMinimumMaximum"; 01107 } 01108 else if ( dynamic_cast<QgsMultiBandColorRenderer*>( renderer() ) ) 01109 { 01110 if ( QgsRasterBlock::typeSize( dataProvider()->srcDataType( 1 ) ) == 1 ) 01111 { 01112 myKey = "multiBandSingleByte"; 01113 myDefault = "NoEnhancement"; 01114 } 01115 else 01116 { 01117 myKey = "multiBandMultiByte"; 01118 myDefault = "StretchToMinimumMaximum"; 01119 } 01120 } 01121 01122 if ( myKey.isEmpty() ) 01123 { 01124 QgsDebugMsg( "No default contrast enhancement for this drawing style" ); 01125 } 01126 QgsDebugMsg( "myKey = " + myKey ); 01127 01128 QString myAlgorithmString = mySettings.value( "/Raster/defaultContrastEnhancementAlgorithm/" + myKey, myDefault ).toString(); 01129 QgsDebugMsg( "myAlgorithmString = " + myAlgorithmString ); 01130 01131 QgsContrastEnhancement::ContrastEnhancementAlgorithm myAlgorithm = QgsContrastEnhancement::contrastEnhancementAlgorithmFromString( myAlgorithmString ); 01132 01133 if ( myAlgorithm == QgsContrastEnhancement::NoEnhancement ) 01134 { 01135 return; 01136 } 01137 01138 QString myLimitsString = mySettings.value( "/Raster/defaultContrastEnhancementLimits", "CumulativeCut" ).toString(); 01139 QgsRaster::ContrastEnhancementLimits myLimits = QgsRaster::contrastEnhancementLimitsFromString( myLimitsString ); 01140 01141 setContrastEnhancement( myAlgorithm, myLimits ); 01142 } 01143 01149 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString ) 01150 { 01151 QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString ); 01152 DrawingStyle drawingStyle; 01153 if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui 01154 { 01155 drawingStyle = SingleBandGray; 01156 } 01157 else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui 01158 { 01159 drawingStyle = SingleBandPseudoColor; 01160 } 01161 else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui 01162 { 01163 drawingStyle = PalettedColor; 01164 } 01165 else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui 01166 { 01167 drawingStyle = PalettedSingleBandGray; 01168 } 01169 else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui 01170 { 01171 drawingStyle = PalettedSingleBandPseudoColor; 01172 } 01173 else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui 01174 { 01175 drawingStyle = PalettedMultiBandColor; 01176 } 01177 else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui 01178 { 01179 drawingStyle = MultiBandSingleBandGray; 01180 } 01181 else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui 01182 { 01183 drawingStyle = MultiBandSingleBandPseudoColor; 01184 } 01185 else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui 01186 { 01187 drawingStyle = MultiBandColor; 01188 } 01189 else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui 01190 { 01191 QgsDebugMsg( "Setting drawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 01192 drawingStyle = SingleBandColorDataStyle; 01193 QgsDebugMsg( "Setted drawingStyle to " + QString::number( drawingStyle ) ); 01194 } 01195 else 01196 { 01197 drawingStyle = UndefinedDrawingStyle; 01198 } 01199 setRendererForDrawingStyle( drawingStyle ); 01200 } 01201 01202 void QgsRasterLayer::setLayerOrder( QStringList const & layers ) 01203 { 01204 QgsDebugMsg( "entered." ); 01205 01206 if ( mDataProvider ) 01207 { 01208 QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." ); 01209 mDataProvider->setLayerOrder( layers ); 01210 } 01211 01212 } 01213 01214 void QgsRasterLayer::setSubLayerVisibility( QString name, bool vis ) 01215 { 01216 01217 if ( mDataProvider ) 01218 { 01219 QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." ); 01220 mDataProvider->setSubLayerVisibility( name, vis ); 01221 } 01222 01223 } 01224 01225 void QgsRasterLayer::setRenderer( QgsRasterRenderer* theRenderer ) 01226 { 01227 QgsDebugMsg( "Entered" ); 01228 if ( !theRenderer ) { return; } 01229 mPipe.set( theRenderer ); 01230 } 01231 01232 void QgsRasterLayer::showProgress( int theValue ) 01233 { 01234 emit progressUpdate( theValue ); 01235 } 01236 01237 01238 void QgsRasterLayer::showStatusMessage( QString const & theMessage ) 01239 { 01240 // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage)); 01241 01242 // Pass-through 01243 // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc. 01244 emit statusChanged( theMessage ); 01245 } 01246 01247 QStringList QgsRasterLayer::subLayers() const 01248 { 01249 return mDataProvider->subLayers(); 01250 } 01251 01252 QPixmap QgsRasterLayer::previewAsPixmap( QSize size, QColor bgColor ) 01253 { 01254 QPixmap myQPixmap( size ); 01255 01256 myQPixmap.fill( bgColor ); //defaults to white, set to transparent for rendering on a map 01257 01258 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 01259 01260 double myMapUnitsPerPixel; 01261 double myX = 0.0; 01262 double myY = 0.0; 01263 QgsRectangle myExtent = mDataProvider->extent(); 01264 if ( myExtent.width() / myExtent.height() >= myQPixmap.width() / myQPixmap.height() ) 01265 { 01266 myMapUnitsPerPixel = myExtent.width() / myQPixmap.width(); 01267 myY = ( myQPixmap.height() - myExtent.height() / myMapUnitsPerPixel ) / 2; 01268 } 01269 else 01270 { 01271 myMapUnitsPerPixel = myExtent.height() / myQPixmap.height(); 01272 myX = ( myQPixmap.width() - myExtent.width() / myMapUnitsPerPixel ) / 2; 01273 } 01274 01275 double myPixelWidth = myExtent.width() / myMapUnitsPerPixel; 01276 double myPixelHeight = myExtent.height() / myMapUnitsPerPixel; 01277 01278 myRasterViewPort->mTopLeftPoint = QgsPoint( myX, myY ); 01279 myRasterViewPort->mBottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight ); 01280 myRasterViewPort->mWidth = myQPixmap.width(); 01281 myRasterViewPort->mHeight = myQPixmap.height(); 01282 01283 myRasterViewPort->mDrawnExtent = myExtent; 01284 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 01285 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 01286 01287 QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel ); 01288 01289 QPainter * myQPainter = new QPainter( &myQPixmap ); 01290 draw( myQPainter, myRasterViewPort, myMapToPixel ); 01291 delete myRasterViewPort; 01292 delete myMapToPixel; 01293 myQPainter->end(); 01294 delete myQPainter; 01295 01296 return myQPixmap; 01297 } 01298 01299 void QgsRasterLayer::triggerRepaint() 01300 { 01301 emit repaintRequested(); 01302 } 01303 01304 void QgsRasterLayer::updateProgress( int theProgress, int theMax ) 01305 { 01306 //simply propogate it on! 01307 emit drawingProgress( theProgress, theMax ); 01308 } 01309 01310 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMessage ) 01311 { 01312 Q_UNUSED( theType ); 01313 Q_UNUSED( theMessage ); 01314 QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) ); 01315 emit progressUpdate(( int )theProgress ); 01316 } 01317 01319 // 01320 // Protected methods 01321 // 01323 /* 01324 * @param QDomNode node that will contain the symbology definition for this layer. 01325 * @param errorMessage reference to string that will be updated with any error messages 01326 * @return true in case of success. 01327 */ 01328 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage ) 01329 { 01330 Q_UNUSED( errorMessage ); 01331 QDomElement rasterRendererElem; 01332 01333 // pipe element was introduced in the end of 1.9 development when there were 01334 // already many project files in use so we support 1.9 backward compatibility 01335 // even it was never officialy released -> use pipe element if present, otherwise 01336 // use layer node 01337 QDomNode pipeNode = layer_node.firstChildElement( "pipe" ); 01338 if ( pipeNode.isNull() ) // old project 01339 { 01340 pipeNode = layer_node; 01341 } 01342 01343 //rasterlayerproperties element there -> old format (1.8 and early 1.9) 01344 if ( !layer_node.firstChildElement( "rasterproperties" ).isNull() ) 01345 { 01346 //copy node because layer_node is const 01347 QDomNode layerNodeCopy = layer_node.cloneNode(); 01348 QDomDocument doc = layerNodeCopy.ownerDocument(); 01349 QDomElement rasterPropertiesElem = layerNodeCopy.firstChildElement( "rasterproperties" ); 01350 QgsProjectFileTransform::convertRasterProperties( doc, layerNodeCopy, rasterPropertiesElem, 01351 this ); 01352 rasterRendererElem = layerNodeCopy.firstChildElement( "rasterrenderer" ); 01353 QgsDebugMsg( doc.toString() ); 01354 } 01355 else 01356 { 01357 rasterRendererElem = pipeNode.firstChildElement( "rasterrenderer" ); 01358 } 01359 01360 if ( !rasterRendererElem.isNull() ) 01361 { 01362 QString rendererType = rasterRendererElem.attribute( "type" ); 01363 QgsRasterRendererRegistryEntry rendererEntry; 01364 if ( QgsRasterRendererRegistry::instance()->rendererData( rendererType, rendererEntry ) ) 01365 { 01366 QgsRasterRenderer *renderer = rendererEntry.rendererCreateFunction( rasterRendererElem, dataProvider() ); 01367 mPipe.set( renderer ); 01368 } 01369 } 01370 01371 //brightness 01372 QgsBrightnessContrastFilter * brightnessFilter = new QgsBrightnessContrastFilter(); 01373 mPipe.set( brightnessFilter ); 01374 01375 //brightness coefficient 01376 QDomElement brightnessElem = pipeNode.firstChildElement( "brightnesscontrast" ); 01377 if ( !brightnessElem.isNull() ) 01378 { 01379 brightnessFilter->readXML( brightnessElem ); 01380 } 01381 01382 //hue/saturation 01383 QgsHueSaturationFilter * hueSaturationFilter = new QgsHueSaturationFilter(); 01384 mPipe.set( hueSaturationFilter ); 01385 01386 //saturation coefficient 01387 QDomElement hueSaturationElem = pipeNode.firstChildElement( "huesaturation" ); 01388 if ( !hueSaturationElem.isNull() ) 01389 { 01390 hueSaturationFilter->readXML( hueSaturationElem ); 01391 } 01392 01393 //resampler 01394 QgsRasterResampleFilter * resampleFilter = new QgsRasterResampleFilter(); 01395 mPipe.set( resampleFilter ); 01396 01397 //max oversampling 01398 QDomElement resampleElem = pipeNode.firstChildElement( "rasterresampler" ); 01399 if ( !resampleElem.isNull() ) 01400 { 01401 resampleFilter->readXML( resampleElem ); 01402 } 01403 01404 // get and set the blend mode if it exists 01405 QDomNode blendModeNode = layer_node.namedItem( "blendMode" ); 01406 if ( !blendModeNode.isNull() ) 01407 { 01408 QDomElement e = blendModeNode.toElement(); 01409 setBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) e.text().toInt() ) ); 01410 } 01411 01412 return true; 01413 } //readSymbology 01414 01421 bool QgsRasterLayer::readXml( const QDomNode& layer_node ) 01422 { 01423 QgsDebugMsg( "Entered" ); 01425 01426 //process provider key 01427 QDomNode pkeyNode = layer_node.namedItem( "provider" ); 01428 01429 if ( pkeyNode.isNull() ) 01430 { 01431 mProviderKey = "gdal"; 01432 } 01433 else 01434 { 01435 QDomElement pkeyElt = pkeyNode.toElement(); 01436 mProviderKey = pkeyElt.text(); 01437 if ( mProviderKey.isEmpty() ) 01438 { 01439 mProviderKey = "gdal"; 01440 } 01441 } 01442 01443 // Open the raster source based on provider and datasource 01444 01445 // Go down the raster-data-provider paradigm 01446 01447 // Collect provider-specific information 01448 01449 QDomNode rpNode = layer_node.namedItem( "rasterproperties" ); 01450 01451 if ( mProviderKey == "wms" ) 01452 { 01453 // >>> BACKWARD COMPATIBILITY < 1.9 01454 // The old WMS URI format does not contain all the informations, we add them here. 01455 if ( !mDataSource.contains( "crs=" ) && !mDataSource.contains( "format=" ) ) 01456 { 01457 QgsDebugMsg( "Old WMS URI format detected -> adding params" ); 01458 QgsDataSourceURI uri; 01459 uri.setEncodedUri( mDataSource ); 01460 QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" ); 01461 while ( !layerElement.isNull() ) 01462 { 01463 // TODO: sublayer visibility - post-0.8 release timeframe 01464 01465 // collect name for the sublayer 01466 uri.setParam( "layers", layerElement.namedItem( "name" ).toElement().text() ); 01467 01468 // collect style for the sublayer 01469 uri.setParam( "styles", layerElement.namedItem( "style" ).toElement().text() ); 01470 01471 layerElement = layerElement.nextSiblingElement( "wmsSublayer" ); 01472 } 01473 01474 // Collect format 01475 QDomNode formatNode = rpNode.namedItem( "wmsFormat" ); 01476 uri.setParam( "format", rpNode.namedItem( "wmsFormat" ).toElement().text() ); 01477 01478 // WMS CRS URL param should not be mixed with that assigned to the layer. 01479 // In the old WMS URI version there was no CRS and layer crs().authid() was used. 01480 uri.setParam( "crs", crs().authid() ); 01481 mDataSource = uri.encodedUri(); 01482 } 01483 // <<< BACKWARD COMPATIBILITY < 1.9 01484 } 01485 01486 setDataProvider( mProviderKey ); 01487 if ( !mValid ) return false; 01488 01489 QString theError; 01490 bool res = readSymbology( layer_node, theError ); 01491 01492 // old wms settings we need to correct 01493 if ( res && mProviderKey == "wms" ) 01494 { 01495 setRendererForDrawingStyle( SingleBandColorDataStyle ); 01496 } 01497 01498 // Check timestamp 01499 // This was probably introduced to reload completely raster if data changed and 01500 // reset completly symbology to reflect new data type etc. It creates however 01501 // problems, because user defined symbology is complete lost if data file time 01502 // changed (the content may be the same). See also 6900. 01503 #if 0 01504 QDomNode stampNode = layer_node.namedItem( "timestamp" ); 01505 if ( !stampNode.isNull() ) 01506 { 01507 QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate ); 01508 // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static? 01509 if ( stamp < mDataProvider->dataTimestamp() ) 01510 { 01511 QgsDebugMsg( "data changed, reload provider" ); 01512 closeDataProvider(); 01513 init(); 01514 setDataProvider( mProviderKey ); 01515 if ( !mValid ) return false; 01516 } 01517 } 01518 #endif 01519 01520 // Load user no data value 01521 QDomElement noDataElement = layer_node.firstChildElement( "noData" ); 01522 01523 QDomNodeList noDataBandList = noDataElement.elementsByTagName( "noDataList" ); 01524 01525 for ( int i = 0; i < noDataBandList.size(); ++i ) 01526 { 01527 QDomElement bandElement = noDataBandList.at( i ).toElement(); 01528 bool ok; 01529 int bandNo = bandElement.attribute( "bandNo" ).toInt( &ok ); 01530 QgsDebugMsg( QString( "bandNo = %1" ).arg( bandNo ) ); 01531 if ( ok && ( bandNo > 0 ) && ( bandNo <= mDataProvider->bandCount() ) ) 01532 { 01533 mDataProvider->setUseSrcNoDataValue( bandNo, bandElement.attribute( "useSrcNoData" ).toInt() ); 01534 QgsRasterRangeList myNoDataRangeList; 01535 01536 QDomNodeList rangeList = bandElement.elementsByTagName( "noDataRange" ); 01537 01538 for ( int j = 0; j < rangeList.size(); ++j ) 01539 { 01540 QDomElement rangeElement = rangeList.at( j ).toElement(); 01541 QgsRasterRange myNoDataRange( rangeElement.attribute( "min" ).toDouble(), 01542 rangeElement.attribute( "max" ).toDouble() ); 01543 QgsDebugMsg( QString( "min = %1 %2" ).arg( rangeElement.attribute( "min" ) ).arg( myNoDataRange.min() ) ); 01544 myNoDataRangeList << myNoDataRange; 01545 } 01546 mDataProvider->setUserNoDataValue( bandNo, myNoDataRangeList ); 01547 } 01548 } 01549 01550 return res; 01551 } // QgsRasterLayer::readXml( QDomNode & layer_node ) 01552 01553 /* 01554 * @param QDomNode the node that will have the style element added to it. 01555 * @param QDomDocument the document that will have the QDomNode added. 01556 * @param errorMessage reference to string that will be updated with any error messages 01557 * @return true in case of success. 01558 */ 01559 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const 01560 { 01561 Q_UNUSED( errorMessage ); 01562 QDomElement layerElem = layer_node.toElement(); 01563 01564 // Store pipe members (except provider) into pipe element, in future, it will be 01565 // possible to add custom filters into the pipe 01566 QDomElement pipeElement = document.createElement( "pipe" ); 01567 01568 for ( int i = 1; i < mPipe.size(); i++ ) 01569 { 01570 QgsRasterInterface * interface = mPipe.at( i ); 01571 if ( !interface ) continue; 01572 interface->writeXML( document, pipeElement ); 01573 } 01574 01575 layer_node.appendChild( pipeElement ); 01576 01577 // add blend mode node 01578 QDomElement blendModeElement = document.createElement( "blendMode" ); 01579 QDomText blendModeText = document.createTextNode( QString::number( QgsMapRenderer::getBlendModeEnum( blendMode() ) ) ); 01580 blendModeElement.appendChild( blendModeText ); 01581 layer_node.appendChild( blendModeElement ); 01582 01583 return true; 01584 } // bool QgsRasterLayer::writeSymbology 01585 01586 /* 01587 * virtual 01588 * @note Called by QgsMapLayer::writeXML(). 01589 */ 01590 bool QgsRasterLayer::writeXml( QDomNode & layer_node, 01591 QDomDocument & document ) 01592 { 01593 // first get the layer element so that we can append the type attribute 01594 01595 QDomElement mapLayerNode = layer_node.toElement(); 01596 01597 if ( mapLayerNode.isNull() || "maplayer" != mapLayerNode.nodeName() ) 01598 { 01599 QgsMessageLog::logMessage( tr( "<maplayer> not found." ), tr( "Raster" ) ); 01600 return false; 01601 } 01602 01603 mapLayerNode.setAttribute( "type", "raster" ); 01604 01605 // add provider node 01606 01607 QDomElement provider = document.createElement( "provider" ); 01608 QDomText providerText = document.createTextNode( mProviderKey ); 01609 provider.appendChild( providerText ); 01610 layer_node.appendChild( provider ); 01611 01612 // User no data 01613 QDomElement noData = document.createElement( "noData" ); 01614 01615 for ( int bandNo = 1; bandNo <= mDataProvider->bandCount(); bandNo++ ) 01616 { 01617 if ( mDataProvider->userNoDataValues( bandNo ).isEmpty() ) continue; 01618 01619 QDomElement noDataRangeList = document.createElement( "noDataList" ); 01620 noDataRangeList.setAttribute( "bandNo", bandNo ); 01621 noDataRangeList.setAttribute( "useSrcNoData", mDataProvider->useSrcNoDataValue( bandNo ) ); 01622 01623 foreach ( QgsRasterRange range, mDataProvider->userNoDataValues( bandNo ) ) 01624 { 01625 QDomElement noDataRange = document.createElement( "noDataRange" ); 01626 01627 noDataRange.setAttribute( "min", range.min() ); 01628 noDataRange.setAttribute( "max", range.max() ); 01629 noDataRangeList.appendChild( noDataRange ); 01630 } 01631 01632 noData.appendChild( noDataRangeList ); 01633 01634 } 01635 if ( noData.hasChildNodes() ) 01636 { 01637 layer_node.appendChild( noData ); 01638 } 01639 01640 //write out the symbology 01641 QString errorMsg; 01642 return writeSymbology( layer_node, document, errorMsg ); 01643 } 01644 01645 int QgsRasterLayer::width() const 01646 { 01647 if ( !mDataProvider ) return 0; 01648 return mDataProvider->xSize(); 01649 } 01650 01651 int QgsRasterLayer::height() const 01652 { 01653 if ( !mDataProvider ) return 0; 01654 return mDataProvider->ySize(); 01655 } 01656 01658 // 01659 // Private methods 01660 // 01662 bool QgsRasterLayer::update() 01663 { 01664 QgsDebugMsg( "entered." ); 01665 // Check if data changed 01666 if ( mDataProvider->dataTimestamp() > mDataProvider->timestamp() ) 01667 { 01668 QgsDebugMsg( "reload data" ); 01669 closeDataProvider(); 01670 init(); 01671 setDataProvider( mProviderKey ); 01672 emit dataChanged(); 01673 } 01674 return mValid; 01675 }