Quantum GIS API Documentation
1.7.4
|
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 /* $Id$ */ 00018 00019 #include "qgsapplication.h" 00020 #include "qgslogger.h" 00021 #include "qgsmaplayerregistry.h" 00022 #include "qgsmaptopixel.h" 00023 #include "qgsproviderregistry.h" 00024 #include "qgsrasterbandstats.h" 00025 #include "qgsrasterlayer.h" 00026 #include "qgsrasterpyramid.h" 00027 #include "qgsrectangle.h" 00028 #include "qgsrendercontext.h" 00029 #include "qgscoordinatereferencesystem.h" 00030 #include "qgscoordinatetransform.h" 00031 00032 #include "gdalwarper.h" 00033 #include "cpl_conv.h" 00034 00035 #include "qgspseudocolorshader.h" 00036 #include "qgsfreakoutshader.h" 00037 #include "qgscolorrampshader.h" 00038 00039 #include <cstdio> 00040 #include <cmath> 00041 #include <limits> 00042 00043 #include <QApplication> 00044 #include <QCursor> 00045 #include <QDomElement> 00046 #include <QDomNode> 00047 #include <QFile> 00048 #include <QFileInfo> 00049 #include <QFont> 00050 #include <QFontMetrics> 00051 #include <QFrame> 00052 #include <QImage> 00053 #include <QLabel> 00054 #include <QList> 00055 #include <QMatrix> 00056 #include <QMessageBox> 00057 #include <QLibrary> 00058 #include <QPainter> 00059 #include <QPixmap> 00060 #include <QRegExp> 00061 #include <QSlider> 00062 #include <QSettings> 00063 #include <QTime> 00064 00065 // typedefs for provider plugin functions of interest 00066 typedef void buildsupportedrasterfilefilter_t( QString & theFileFiltersString ); 00067 typedef bool isvalidrasterfilename_t( QString const & theFileNameQString, QString & retErrMsg ); 00068 00069 // workaround for MSVC compiler which already has defined macro max 00070 // that interferes with calling std::numeric_limits<int>::max 00071 #ifdef _MSC_VER 00072 # ifdef max 00073 # undef max 00074 # endif 00075 #endif 00076 00077 // Comparison value for equality; i.e., we shouldn't directly compare two 00078 // floats so it's better to take their difference and see if they're within 00079 // a certain range -- in this case twenty times the smallest value that 00080 // doubles can take for the current system. (Yes, 20 was arbitrary.) 00081 #define TINY_VALUE std::numeric_limits<double>::epsilon() * 20 00082 00083 00084 QgsRasterLayer::QgsRasterLayer( 00085 QString const & path, 00086 QString const & baseName, 00087 bool loadDefaultStyleFlag ) 00088 : QgsMapLayer( RasterLayer, baseName, path ) 00089 // Constant that signals property not used. 00090 , QSTRING_NOT_SET( "Not Set" ) 00091 , TRSTRING_NOT_SET( tr( "Not Set" ) ) 00092 , mStandardDeviations( 0 ) 00093 , mDataProvider( 0 ) 00094 , mWidth( std::numeric_limits<int>::max() ) 00095 , mHeight( std::numeric_limits<int>::max() ) 00096 , mInvertColor( false ) 00097 { 00098 QgsDebugMsg( "Entered" ); 00099 00100 // TODO, call constructor with provider key for now 00101 init(); 00102 setDataProvider( "gdal", QStringList(), QStringList(), QString(), QString(), loadDefaultStyleFlag ); 00103 00104 if ( mValid && loadDefaultStyleFlag ) 00105 { 00106 bool defaultLoadedFlag = false; 00107 loadDefaultStyle( defaultLoadedFlag ); 00108 // I'm no sure if this should be used somehow, in pre raster-providers there was 00109 // only mLastViewPort init after this block, nothing to do with style 00110 //if ( defaultLoadedFlag ) 00111 //{ 00112 //return; 00113 //} 00114 } 00115 return; 00116 00117 00118 } // QgsRasterLayer ctor 00119 00124 QgsRasterLayer::QgsRasterLayer( int dummy, 00125 QString const & rasterLayerPath, 00126 QString const & baseName, 00127 QString const & providerKey, 00128 QStringList const & layers, 00129 QStringList const & styles, 00130 QString const & format, 00131 QString const & crs ) 00132 : QgsMapLayer( RasterLayer, baseName, rasterLayerPath ) 00133 , mStandardDeviations( 0 ) 00134 , mDataProvider( 0 ) 00135 , mEditable( false ) 00136 , mWidth( std::numeric_limits<int>::max() ) 00137 , mHeight( std::numeric_limits<int>::max() ) 00138 , mInvertColor( false ) 00139 , mModified( false ) 00140 , mProviderKey( providerKey ) 00141 , mLayers( layers ) 00142 , mStyles( styles ) 00143 , mFormat( format ) 00144 , mCrs( crs ) 00145 { 00146 QgsDebugMsg( "(8 arguments) starting. with layer list of " + 00147 layers.join( ", " ) + " and style list of " + styles.join( ", " ) + " and format of " + 00148 format + " and CRS of " + crs ); 00149 00150 00151 init(); 00152 // if we're given a provider type, try to create and bind one to this layer 00153 bool loadDefaultStyleFlag = false ; // ??? 00154 setDataProvider( providerKey, layers, styles, format, crs, loadDefaultStyleFlag ); 00155 00156 // Default for the popup menu 00157 // TODO: popMenu = 0; 00158 00159 // Get the update threshold from user settings. We 00160 // do this only on construction to avoid the penality of 00161 // fetching this each time the layer is drawn. If the user 00162 // changes the threshold from the preferences dialog, it will 00163 // have no effect on existing layers 00164 // TODO: QSettings settings; 00165 // updateThreshold = settings.readNumEntry("Map/updateThreshold", 1000); 00166 00167 00168 // TODO: Connect signals from the dataprovider to the qgisapp 00169 00170 QgsDebugMsg( "(8 arguments) exiting." ); 00171 00172 emit statusChanged( tr( "QgsRasterLayer created" ) ); 00173 } // QgsRasterLayer ctor 00174 00175 QgsRasterLayer::~QgsRasterLayer() 00176 { 00177 mValid = false; 00178 delete mRasterShader; 00179 delete mDataProvider; 00180 } 00181 00183 // 00184 // Static Methods and members 00185 // 00187 00195 void QgsRasterLayer::buildSupportedRasterFileFilter( QString & theFileFiltersString ) 00196 { 00197 QgsDebugMsg( "Entered" ); 00198 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" ); 00199 if ( !myLib ) 00200 { 00201 QgsDebugMsg( "Could not load gdal provider library" ); 00202 return; 00203 } 00204 buildsupportedrasterfilefilter_t *pBuild = ( buildsupportedrasterfilefilter_t * ) cast_to_fptr( myLib->resolve( "buildSupportedRasterFileFilter" ) ); 00205 if ( ! pBuild ) 00206 { 00207 QgsDebugMsg( "Could not resolve buildSupportedRasterFileFilter in gdal provider library" ); 00208 return; 00209 } 00210 00211 pBuild( theFileFiltersString ); 00212 delete myLib; 00213 } 00214 00218 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString, QString & retErrMsg ) 00219 { 00220 00221 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( "gdal" ); 00222 if ( !myLib ) 00223 { 00224 QgsDebugMsg( "Could not load gdal provider library" ); 00225 return false; 00226 } 00227 isvalidrasterfilename_t *pValid = ( isvalidrasterfilename_t * ) cast_to_fptr( myLib->resolve( "isValidRasterFileName" ) ); 00228 if ( ! pValid ) 00229 { 00230 QgsDebugMsg( "Could not resolve isValidRasterFileName in gdal provider library" ); 00231 return false; 00232 } 00233 00234 bool myIsValid = pValid( theFileNameQString, retErrMsg ); 00235 delete myLib; 00236 return myIsValid; 00237 } 00238 00239 bool QgsRasterLayer::isValidRasterFileName( QString const & theFileNameQString ) 00240 { 00241 QString retErrMsg; 00242 return isValidRasterFileName( theFileNameQString, retErrMsg ); 00243 } 00244 00245 QDateTime QgsRasterLayer::lastModified( QString const & name ) 00246 { 00247 QgsDebugMsg( "name=" + name ); 00248 QDateTime t; 00249 00250 QFileInfo fi( name ); 00251 00252 // Is it file? 00253 if ( !fi.exists() ) return t; 00254 00255 t = fi.lastModified(); 00256 00257 QgsDebugMsg( "last modified = " + t.toString() ); 00258 00259 return t; 00260 } 00261 00262 // typedef for the QgsDataProvider class factory 00263 typedef QgsDataProvider * classFactoryFunction_t( const QString * ); 00264 00266 // 00267 // Non Static Public methods 00268 // 00270 00271 unsigned int QgsRasterLayer::bandCount() 00272 { 00273 return mBandCount; 00274 } 00275 00276 const QString QgsRasterLayer::bandName( int theBandNo ) 00277 { 00278 if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 ) 00279 { 00280 //vector starts at base 0, band counts at base1! 00281 return mRasterStatsList[theBandNo - 1].bandName; 00282 } 00283 else 00284 { 00285 return QString( "" ); 00286 } 00287 } 00288 00289 int QgsRasterLayer::bandNumber( QString const & theBandName ) 00290 { 00291 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 00292 { 00293 //find out the name of this band 00294 QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator]; 00295 QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + " :: theBandName: " 00296 + theBandName ); 00297 00298 if ( myRasterBandStats.bandName == theBandName ) 00299 { 00300 QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) + 00301 " was found in bandNumber " + theBandName ); 00302 00303 return myRasterBandStats.bandNumber; 00304 } 00305 } 00306 QgsDebugMsg( "********** no band was found in bandNumber " + theBandName ); 00307 00308 return 0; //no band was found 00309 } 00310 00330 const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo ) 00331 { 00332 QgsDebugMsg( "theBandNo = " + QString::number( theBandNo ) ); 00333 QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) ); 00334 if ( mRasterType == ColorLayer ) 00335 { 00336 // Statistics have no sense for ColorLayer 00337 QgsRasterBandStats myNullReturnStats; 00338 return myNullReturnStats; 00339 } 00340 // check if we have received a valid band number 00341 if (( mDataProvider->bandCount() < theBandNo ) && mRasterType != Palette ) 00342 { 00343 // invalid band id, return nothing 00344 QgsRasterBandStats myNullReturnStats; 00345 return myNullReturnStats; 00346 } 00347 if ( mRasterType == Palette && ( theBandNo > 3 ) ) 00348 { 00349 // invalid band id, return nothing 00350 QgsRasterBandStats myNullReturnStats; 00351 return myNullReturnStats; 00352 } 00353 // check if we have previously gathered stats for this band... 00354 if ( theBandNo < 1 || theBandNo > mRasterStatsList.size() ) 00355 { 00356 // invalid band id, return nothing 00357 QgsRasterBandStats myNullReturnStats; 00358 return myNullReturnStats; 00359 } 00360 00361 QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1]; 00362 myRasterBandStats.bandNumber = theBandNo; 00363 00364 // don't bother with this if we already have stats 00365 if ( myRasterBandStats.statsGathered ) 00366 { 00367 return myRasterBandStats; 00368 } 00369 00370 myRasterBandStats = mDataProvider->bandStatistics( theBandNo ); 00371 QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) ); 00372 //add this band to the class stats map 00373 mRasterStatsList[theBandNo - 1] = myRasterBandStats; 00374 emit drawingProgress( mHeight, mHeight ); //reset progress 00375 QgsDebugMsg( "Stats collection completed returning" ); 00376 return myRasterBandStats; 00377 } // QgsRasterLayer::bandStatistics 00378 00379 const QgsRasterBandStats QgsRasterLayer::bandStatistics( QString const & theBandName ) 00380 { 00381 // only print message if we are actually gathering the stats 00382 emit statusChanged( tr( "Retrieving stats for %1" ).arg( name() ) ); 00383 qApp->processEvents(); 00384 //reset the main app progress bar 00385 emit drawingProgress( 0, 0 ); 00386 //we cant use a vector iterator because the iterator is astruct not a class 00387 //and the qvector model does not like this. 00388 for ( int i = 1; i <= mDataProvider->bandCount(); i++ ) 00389 { 00390 QgsRasterBandStats myRasterBandStats = bandStatistics( i ); 00391 if ( myRasterBandStats.bandName == theBandName ) 00392 { 00393 return myRasterBandStats; 00394 } 00395 } 00396 00397 return QgsRasterBandStats(); // return a null one 00398 } 00399 00400 00401 QString QgsRasterLayer::buildPyramids( RasterPyramidList const & theRasterPyramidList, 00402 QString const & theResamplingMethod, bool theTryInternalFlag ) 00403 { 00404 return mDataProvider->buildPyramids( theRasterPyramidList, theResamplingMethod, theTryInternalFlag ); 00405 } 00406 00407 00408 QgsRasterLayer::RasterPyramidList QgsRasterLayer::buildPyramidList() 00409 { 00410 return mDataProvider->buildPyramidList(); 00411 } 00412 00413 QString QgsRasterLayer::colorShadingAlgorithmAsString() const 00414 { 00415 switch ( mColorShadingAlgorithm ) 00416 { 00417 case PseudoColorShader: 00418 return QString( "PseudoColorShader" ); 00419 break; 00420 case FreakOutShader: 00421 return QString( "FreakOutShader" ); 00422 break; 00423 case ColorRampShader: 00424 return QString( "ColorRampShader" ); 00425 break; 00426 case UserDefinedShader: 00427 return QString( "UserDefinedShader" ); 00428 break; 00429 default: 00430 break; 00431 } 00432 00433 return QString( "UndefinedShader" ); 00434 } 00435 00440 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double* theMinMax ) 00441 { 00442 if ( 0 == theMinMax ) { return; } 00443 00444 if ( 0 < theBand && theBand <= ( int ) bandCount() ) 00445 { 00446 theMinMax[0] = mDataProvider->minimumValue( theBand ); 00447 theMinMax[1] = mDataProvider->maximumValue( theBand ); 00448 } 00449 } 00450 00455 void QgsRasterLayer::computeMinimumMaximumEstimates( QString theBand, double* theMinMax ) 00456 { 00457 computeMinimumMaximumEstimates( bandNumber( theBand ), theMinMax ); 00458 } 00459 00460 void QgsRasterLayer::computeMinimumMaximumEstimates( int theBand, double& theMin, double& theMax ) 00461 { 00462 double theMinMax[2]; 00463 computeMinimumMaximumEstimates( theBand, theMinMax ); 00464 theMin = theMinMax[0]; 00465 theMax = theMinMax[1]; 00466 } 00467 00472 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double* theMinMax ) 00473 { 00474 if ( 0 == theMinMax ) { return; } 00475 00476 int myDataType = mDataProvider->dataType( theBand ); 00477 void* myScanData = readData( theBand, &mLastViewPort ); 00478 00479 /* Check for out of memory error */ 00480 if ( myScanData == NULL ) 00481 { 00482 return; 00483 } 00484 00485 if ( 0 < theBand && theBand <= ( int ) bandCount() ) 00486 { 00487 // Was there any reason to use float for myMin, myMax, myValue? 00488 // It was breaking Float64 data obviously, especially if an extreme value 00489 // was used for NoDataValue. 00490 double myMin = std::numeric_limits<double>::max(); 00491 double myMax = -1 * std::numeric_limits<double>::max(); 00492 double myValue = 0.0; 00493 for ( int myRow = 0; myRow < mLastViewPort.drawableAreaYDim; ++myRow ) 00494 { 00495 for ( int myColumn = 0; myColumn < mLastViewPort.drawableAreaXDim; ++myColumn ) 00496 { 00497 myValue = readValue( myScanData, myDataType, myRow * mLastViewPort.drawableAreaXDim + myColumn ); 00498 if ( mValidNoDataValue && ( qAbs( myValue - mNoDataValue ) <= TINY_VALUE || myValue != myValue ) ) 00499 { 00500 continue; 00501 } 00502 myMin = qMin( myMin, myValue ); 00503 myMax = qMax( myMax, myValue ); 00504 } 00505 } 00506 theMinMax[0] = myMin; 00507 theMinMax[1] = myMax; 00508 } 00509 } 00510 00515 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( QString theBand, double* theMinMax ) 00516 { 00517 computeMinimumMaximumFromLastExtent( bandNumber( theBand ), theMinMax ); 00518 } 00519 00520 void QgsRasterLayer::computeMinimumMaximumFromLastExtent( int theBand, double& theMin, double& theMax ) 00521 { 00522 double theMinMax[2]; 00523 computeMinimumMaximumFromLastExtent( theBand, theMinMax ); 00524 theMin = theMinMax[0]; 00525 theMax = theMinMax[1]; 00526 } 00527 00532 QgsContrastEnhancement* QgsRasterLayer::contrastEnhancement( unsigned int theBand ) 00533 { 00534 if ( 0 < theBand && theBand <= bandCount() ) 00535 { 00536 return &mContrastEnhancementList[theBand - 1]; 00537 } 00538 00539 return 0; 00540 } 00541 00542 QString QgsRasterLayer::contrastEnhancementAlgorithmAsString() const 00543 { 00544 switch ( mContrastEnhancementAlgorithm ) 00545 { 00546 case QgsContrastEnhancement::NoEnhancement: 00547 return QString( "NoEnhancement" ); 00548 break; 00549 case QgsContrastEnhancement::StretchToMinimumMaximum: 00550 return QString( "StretchToMinimumMaximum" ); 00551 break; 00552 case QgsContrastEnhancement::StretchAndClipToMinimumMaximum: 00553 return QString( "StretchAndClipToMinimumMaximum" ); 00554 break; 00555 case QgsContrastEnhancement::ClipToMinimumMaximum: 00556 return QString( "ClipToMinimumMaximum" ); 00557 break; 00558 case QgsContrastEnhancement::UserDefinedEnhancement: 00559 return QString( "UserDefined" ); 00560 break; 00561 } 00562 00563 return QString( "NoEnhancement" ); 00564 } 00565 00570 bool QgsRasterLayer::copySymbologySettings( const QgsMapLayer& theOther ) 00571 { 00572 //preventwarnings 00573 if ( theOther.type() < 0 ) 00574 { 00575 return false; 00576 } 00577 return false; 00578 } //todo 00579 00584 QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo ) 00585 { 00586 return &( mRasterStatsList[theBandNo-1].colorTable ); 00587 } 00588 00592 QgsRasterDataProvider* QgsRasterLayer::dataProvider() 00593 { 00594 return mDataProvider; 00595 } 00596 00600 const QgsRasterDataProvider* QgsRasterLayer::dataProvider() const 00601 { 00602 return mDataProvider; 00603 } 00604 00605 void QgsRasterLayer::reload() 00606 { 00607 if ( mDataProvider ) 00608 { 00609 mDataProvider->reloadData(); 00610 } 00611 } 00612 00613 bool QgsRasterLayer::draw( QgsRenderContext& rendererContext ) 00614 { 00615 QgsDebugMsg( "entered. (renderContext)" ); 00616 00617 // Don't waste time drawing if transparency is at 0 (completely transparent) 00618 if ( mTransparencyLevel == 0 ) 00619 return true; 00620 00621 QgsDebugMsg( "checking timestamp." ); 00622 00623 // Check timestamp 00624 if ( !update() ) 00625 { 00626 return false; 00627 } 00628 00629 const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); 00630 00631 QgsRectangle myProjectedViewExtent; 00632 QgsRectangle myProjectedLayerExtent; 00633 00634 if ( rendererContext.coordinateTransform() ) 00635 { 00636 QgsDebugMsg( "coordinateTransform set -> project extents." ); 00637 myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( 00638 rendererContext.extent() ); 00639 myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( 00640 mLayerExtent ); 00641 } 00642 else 00643 { 00644 QgsDebugMsg( "coordinateTransform not set" ); 00645 myProjectedViewExtent = rendererContext.extent(); 00646 myProjectedLayerExtent = mLayerExtent; 00647 } 00648 00649 QPainter* theQPainter = rendererContext.painter(); 00650 00651 if ( !theQPainter ) 00652 { 00653 return false; 00654 } 00655 00656 // clip raster extent to view extent 00657 //QgsRectangle myRasterExtent = theViewExtent.intersect( &mLayerExtent ); 00658 QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); 00659 if ( myRasterExtent.isEmpty() ) 00660 { 00661 QgsDebugMsg( "draw request outside view extent." ); 00662 // nothing to do 00663 return true; 00664 } 00665 00666 QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); 00667 QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); 00668 QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); 00669 QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); 00670 00671 // 00672 // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings 00673 // relating to the size (in pixels and coordinate system units) of the raster part that is 00674 // in view in the map window. It also stores the origin. 00675 // 00676 //this is not a class level member because every time the user pans or zooms 00677 //the contents of the rasterViewPort will change 00678 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 00679 00680 myRasterViewPort->mDrawnExtent = myRasterExtent; 00681 if ( rendererContext.coordinateTransform() ) 00682 { 00683 myRasterViewPort->mSrcCRS = crs(); 00684 myRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); 00685 } 00686 else 00687 { 00688 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 00689 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 00690 } 00691 00692 // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) 00693 myRasterViewPort->topLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); 00694 myRasterViewPort->bottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); 00695 00696 // align to output device grid, i.e. floor/ceil to integers 00697 // TODO: this should only be done if paint device is raster - screen, image 00698 // for other devices (pdf) it can have floating point origin 00699 // we could use floating point for raster devices as well, but respecting the 00700 // output device grid should make it more effective as the resampling is done in 00701 // the provider anyway 00702 if ( true ) 00703 { 00704 myRasterViewPort->topLeftPoint.setX( floor( myRasterViewPort->topLeftPoint.x() ) ); 00705 myRasterViewPort->topLeftPoint.setY( floor( myRasterViewPort->topLeftPoint.y() ) ); 00706 myRasterViewPort->bottomRightPoint.setX( ceil( myRasterViewPort->bottomRightPoint.x() ) ); 00707 myRasterViewPort->bottomRightPoint.setY( ceil( myRasterViewPort->bottomRightPoint.y() ) ); 00708 // recalc myRasterExtent to aligned values 00709 myRasterExtent.set( 00710 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->topLeftPoint.x(), 00711 myRasterViewPort->bottomRightPoint.y() ), 00712 theQgsMapToPixel.toMapCoordinatesF( myRasterViewPort->bottomRightPoint.x(), 00713 myRasterViewPort->topLeftPoint.y() ) 00714 ); 00715 00716 } 00717 00718 myRasterViewPort->drawableAreaXDim = static_cast<int>( qAbs(( myRasterExtent.width() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00719 myRasterViewPort->drawableAreaYDim = static_cast<int>( qAbs(( myRasterExtent.height() / theQgsMapToPixel.mapUnitsPerPixel() ) ) ); 00720 00721 //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue 00722 //theQgsMapToPixel.mapUnitsPerPixel() is less then 1, 00723 //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() 00724 #if 0 00725 if ( 2 >= myRasterViewPort->clippedWidth && 2 >= myRasterViewPort->clippedHeight ) 00726 { 00727 myRasterViewPort->drawableAreaXDim = myRasterViewPort->clippedWidth; 00728 myRasterViewPort->drawableAreaYDim = myRasterViewPort->clippedHeight; 00729 } 00730 #endif 00731 00732 QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ), 3 ); 00733 QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mWidth ), 3 ); 00734 QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mHeight ), 3 ); 00735 QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); 00736 QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); 00737 QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); 00738 QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); 00739 00740 QgsDebugMsgLevel( QString( "topLeftPoint.x() = %1" ).arg( myRasterViewPort->topLeftPoint.x() ), 3 ); 00741 QgsDebugMsgLevel( QString( "bottomRightPoint.x() = %1" ).arg( myRasterViewPort->bottomRightPoint.x() ), 3 ); 00742 QgsDebugMsgLevel( QString( "topLeftPoint.y() = %1" ).arg( myRasterViewPort->topLeftPoint.y() ), 3 ); 00743 QgsDebugMsgLevel( QString( "bottomRightPoint.y() = %1" ).arg( myRasterViewPort->bottomRightPoint.y() ), 3 ); 00744 00745 QgsDebugMsgLevel( QString( "drawableAreaXDim = %1" ).arg( myRasterViewPort->drawableAreaXDim ), 3 ); 00746 QgsDebugMsgLevel( QString( "drawableAreaYDim = %1" ).arg( myRasterViewPort->drawableAreaYDim ), 3 ); 00747 00748 QgsDebugMsgLevel( "ReadXml: gray band name : " + mGrayBandName, 3 ); 00749 QgsDebugMsgLevel( "ReadXml: red band name : " + mRedBandName, 3 ); 00750 QgsDebugMsgLevel( "ReadXml: green band name : " + mGreenBandName, 3 ); 00751 QgsDebugMsgLevel( "ReadXml: blue band name : " + mBlueBandName, 3 ); 00752 00753 // /\/\/\ - added to handle zoomed-in rasters 00754 00755 mLastViewPort = *myRasterViewPort; 00756 00757 // Provider mode: See if a provider key is specified, and if so use the provider instead 00758 00759 mDataProvider->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); 00760 00761 draw( theQPainter, myRasterViewPort, &theQgsMapToPixel ); 00762 00763 delete myRasterViewPort; 00764 QgsDebugMsg( "exiting." ); 00765 00766 return true; 00767 00768 } 00769 00770 void QgsRasterLayer::draw( QPainter * theQPainter, 00771 QgsRasterViewPort * theRasterViewPort, 00772 const QgsMapToPixel* theQgsMapToPixel ) 00773 { 00774 QgsDebugMsg( " 3 arguments" ); 00775 QTime time; 00776 time.start(); 00777 // 00778 // 00779 // The goal here is to make as many decisions as possible early on (outside of the rendering loop) 00780 // so that we can maximise performance of the rendering process. So now we check which drawing 00781 // procedure to use : 00782 // 00783 00784 QgsDebugMsg( "mDrawingStyle = " + QString::number( mDrawingStyle ) ); 00785 switch ( mDrawingStyle ) 00786 { 00787 // a "Gray" or "Undefined" layer drawn as a range of gray colors 00788 case SingleBandGray: 00789 //check the band is set! 00790 if ( mGrayBandName == TRSTRING_NOT_SET ) 00791 { 00792 break; 00793 } 00794 else 00795 { 00796 drawSingleBandGray( theQPainter, theRasterViewPort, 00797 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00798 break; 00799 } 00800 // a "Gray" or "Undefined" layer drawn using a pseudocolor algorithm 00801 case SingleBandPseudoColor: 00802 //check the band is set! 00803 if ( mGrayBandName == TRSTRING_NOT_SET ) 00804 { 00805 break; 00806 } 00807 else 00808 { 00809 drawSingleBandPseudoColor( theQPainter, theRasterViewPort, 00810 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00811 break; 00812 } 00813 // a single band with a color map 00814 case PalettedColor: 00815 //check the band is set! 00816 if ( mGrayBandName == TRSTRING_NOT_SET ) 00817 { 00818 break; 00819 } 00820 else 00821 { 00822 QgsDebugMsg( "PalettedColor drawing type detected..." ); 00823 00824 drawPalettedSingleBandColor( theQPainter, theRasterViewPort, 00825 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00826 break; 00827 } 00828 // a "Palette" layer drawn in gray scale (using only one of the color components) 00829 case PalettedSingleBandGray: 00830 //check the band is set! 00831 if ( mGrayBandName == TRSTRING_NOT_SET ) 00832 { 00833 break; 00834 } 00835 else 00836 { 00837 QgsDebugMsg( "PalettedSingleBandGray drawing type detected..." ); 00838 00839 int myBandNo = 1; 00840 drawPalettedSingleBandGray( theQPainter, theRasterViewPort, 00841 theQgsMapToPixel, myBandNo ); 00842 00843 break; 00844 } 00845 // a "Palette" layer having only one of its color components rendered as psuedo color 00846 case PalettedSingleBandPseudoColor: 00847 //check the band is set! 00848 if ( mGrayBandName == TRSTRING_NOT_SET ) 00849 { 00850 break; 00851 } 00852 else 00853 { 00854 00855 int myBandNo = 1; 00856 drawPalettedSingleBandPseudoColor( theQPainter, theRasterViewPort, 00857 theQgsMapToPixel, myBandNo ); 00858 break; 00859 } 00860 //a "Palette" image where the bands contains 24bit color info and 8 bits is pulled out per color 00861 case PalettedMultiBandColor: 00862 drawPalettedMultiBandColor( theQPainter, theRasterViewPort, 00863 theQgsMapToPixel, 1 ); 00864 break; 00865 // a layer containing 2 or more bands, but using only one band to produce a grayscale image 00866 case MultiBandSingleBandGray: 00867 QgsDebugMsg( "MultiBandSingleBandGray drawing type detected..." ); 00868 //check the band is set! 00869 if ( mGrayBandName == TRSTRING_NOT_SET ) 00870 { 00871 QgsDebugMsg( "MultiBandSingleBandGray Not Set detected..." + mGrayBandName ); 00872 break; 00873 } 00874 else 00875 { 00876 00877 //get the band number for the mapped gray band 00878 drawMultiBandSingleBandGray( theQPainter, theRasterViewPort, 00879 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00880 break; 00881 } 00882 //a layer containing 2 or more bands, but using only one band to produce a pseudocolor image 00883 case MultiBandSingleBandPseudoColor: 00884 //check the band is set! 00885 if ( mGrayBandName == TRSTRING_NOT_SET ) 00886 { 00887 break; 00888 } 00889 else 00890 { 00891 00892 drawMultiBandSingleBandPseudoColor( theQPainter, theRasterViewPort, 00893 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00894 break; 00895 } 00896 //a layer containing 2 or more bands, mapped to the three RGBcolors. 00897 //In the case of a multiband with only two bands, 00898 //one band will have to be mapped to more than one color 00899 case MultiBandColor: 00900 if ( mRedBandName == TRSTRING_NOT_SET || 00901 mGreenBandName == TRSTRING_NOT_SET || 00902 mBlueBandName == TRSTRING_NOT_SET ) 00903 { 00904 break; 00905 } 00906 else 00907 { 00908 drawMultiBandColor( theQPainter, theRasterViewPort, 00909 theQgsMapToPixel ); 00910 } 00911 break; 00912 case SingleBandColorDataStyle: 00913 //check the band is set! 00914 if ( mGrayBandName == TRSTRING_NOT_SET ) 00915 { 00916 break; 00917 } 00918 else 00919 { 00920 drawSingleBandColorData( theQPainter, theRasterViewPort, 00921 theQgsMapToPixel, bandNumber( mGrayBandName ) ); 00922 break; 00923 } 00924 00925 default: 00926 break; 00927 00928 } 00929 QgsDebugMsg( QString( "raster draw time (ms): %1" ).arg( time.elapsed() ) ); 00930 } //end of draw method 00931 00932 QString QgsRasterLayer::drawingStyleAsString() const 00933 { 00934 switch ( mDrawingStyle ) 00935 { 00936 case SingleBandGray: 00937 return QString( "SingleBandGray" ); //no need to tr() this its not shown in ui 00938 break; 00939 case SingleBandPseudoColor: 00940 return QString( "SingleBandPseudoColor" );//no need to tr() this its not shown in ui 00941 break; 00942 case PalettedColor: 00943 return QString( "PalettedColor" );//no need to tr() this its not shown in ui 00944 break; 00945 case PalettedSingleBandGray: 00946 return QString( "PalettedSingleBandGray" );//no need to tr() this its not shown in ui 00947 break; 00948 case PalettedSingleBandPseudoColor: 00949 return QString( "PalettedSingleBandPseudoColor" );//no need to tr() this its not shown in ui 00950 break; 00951 case PalettedMultiBandColor: 00952 return QString( "PalettedMultiBandColor" );//no need to tr() this its not shown in ui 00953 break; 00954 case MultiBandSingleBandGray: 00955 return QString( "MultiBandSingleBandGray" );//no need to tr() this its not shown in ui 00956 break; 00957 case MultiBandSingleBandPseudoColor: 00958 return QString( "MultiBandSingleBandPseudoColor" );//no need to tr() this its not shown in ui 00959 break; 00960 case MultiBandColor: 00961 return QString( "MultiBandColor" );//no need to tr() this its not shown in ui 00962 break; 00963 case SingleBandColorDataStyle: 00964 return QString( "SingleBandColorDataStyle" );//no need to tr() this its not shown in ui 00965 break; 00966 default: 00967 break; 00968 } 00969 00970 return QString( "UndefinedDrawingStyle" ); 00971 00972 } 00973 00978 bool QgsRasterLayer::hasCompatibleSymbology( const QgsMapLayer& theOther ) const 00979 { 00980 //preventwarnings 00981 if ( theOther.type() < 0 ) 00982 { 00983 return false; 00984 } 00985 return false; 00986 } //todo 00987 00992 bool QgsRasterLayer::hasStatistics( int theBandNo ) 00993 { 00994 if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 ) 00995 { 00996 //vector starts at base 0, band counts at base1! 00997 return mRasterStatsList[theBandNo - 1].statsGathered; 00998 } 00999 else 01000 { 01001 return false; 01002 } 01003 } 01004 01010 bool QgsRasterLayer::identify( const QgsPoint& thePoint, QMap<QString, QString>& theResults ) 01011 { 01012 theResults.clear(); 01013 01014 QgsDebugMsg( "identify provider : " + mProviderKey ) ; 01015 return ( mDataProvider->identify( thePoint, theResults ) ); 01016 } 01017 01024 QString QgsRasterLayer::identifyAsText( const QgsPoint& thePoint ) 01025 { 01026 if ( mProviderKey != "wms" ) 01027 { 01028 // Currently no meaning for anything other than OGC WMS layers 01029 return QString(); 01030 } 01031 01032 return mDataProvider->identifyAsText( thePoint ); 01033 } 01034 01041 QString QgsRasterLayer::identifyAsHtml( const QgsPoint& thePoint ) 01042 { 01043 if ( mProviderKey != "wms" ) 01044 { 01045 // Currently no meaning for anything other than OGC WMS layers 01046 return QString(); 01047 } 01048 01049 return mDataProvider->identifyAsHtml( thePoint ); 01050 } 01051 01056 bool QgsRasterLayer::isEditable() const 01057 { 01058 return false; 01059 } 01060 01061 QString QgsRasterLayer::lastError() 01062 { 01063 return mError; 01064 } 01065 01066 QString QgsRasterLayer::lastErrorTitle() 01067 { 01068 return mErrorCaption; 01069 } 01070 01075 QPixmap QgsRasterLayer::legendAsPixmap() 01076 { 01077 return legendAsPixmap( false ); 01078 } 01079 01084 QPixmap QgsRasterLayer::legendAsPixmap( bool theWithNameFlag ) 01085 { 01086 QgsDebugMsg( "called (" + drawingStyleAsString() + ")" ); 01087 01088 QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active 01089 QPainter myQPainter; 01090 01091 01092 if ( !mProviderKey.isEmpty() ) 01093 { 01094 QgsDebugMsg( "provider Key (" + mProviderKey + ")" ); 01095 myLegendQPixmap = QPixmap( 3, 1 ); 01096 myQPainter.begin( &myLegendQPixmap ); 01097 //draw legend red part 01098 myQPainter.setPen( QPen( QColor( 255, 0, 0 ), 0 ) ); 01099 myQPainter.drawPoint( 0, 0 ); 01100 //draw legend green part 01101 myQPainter.setPen( QPen( QColor( 0, 255, 0 ), 0 ) ); 01102 myQPainter.drawPoint( 1, 0 ); 01103 //draw legend blue part 01104 myQPainter.setPen( QPen( QColor( 0, 0, 255 ), 0 ) ); 01105 myQPainter.drawPoint( 2, 0 ); 01106 01107 } 01108 else 01109 { 01110 // Legacy GDAL (non-provider) 01111 01112 // 01113 // Get the adjusted matrix stats 01114 // 01115 QString myColorerpretation = mDataProvider->colorInterpretationName( 1 ); 01116 01117 // 01118 // Create the legend pixmap - note it is generated on the preadjusted stats 01119 // 01120 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01121 { 01122 01123 myLegendQPixmap = QPixmap( 100, 1 ); 01124 myQPainter.begin( &myLegendQPixmap ); 01125 int myPos = 0; 01126 for ( double my = 0; my < 255; my += 2.55 ) 01127 { 01128 if ( !mInvertColor ) //histogram is not inverted 01129 { 01130 //draw legend as grayscale 01131 int myGray = static_cast < int >( my ); 01132 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01133 } 01134 else //histogram is inverted 01135 { 01136 //draw legend as inverted grayscale 01137 int myGray = 255 - static_cast < int >( my ); 01138 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01139 } //end of invert histogram check 01140 myQPainter.drawPoint( myPos++, 0 ); 01141 } 01142 } //end of gray check 01143 else if ( mDrawingStyle == MultiBandSingleBandPseudoColor || 01144 mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor ) 01145 { 01146 01147 //set up the three class breaks for pseudocolor mapping 01148 double myRangeSize = 90; //hard coded for now 01149 double myBreakSize = myRangeSize / 3; 01150 double myClassBreakMin1 = 0; 01151 double myClassBreakMax1 = myClassBreakMin1 + myBreakSize; 01152 double myClassBreakMin2 = myClassBreakMax1; 01153 double myClassBreakMax2 = myClassBreakMin2 + myBreakSize; 01154 double myClassBreakMin3 = myClassBreakMax2; 01155 01156 // 01157 // Create the legend pixmap - note it is generated on the preadjusted stats 01158 // 01159 myLegendQPixmap = QPixmap( 100, 1 ); 01160 myQPainter.begin( &myLegendQPixmap ); 01161 int myPos = 0; 01162 for ( double my = 0; my < myRangeSize; my += myRangeSize / 100.0 ) 01163 { 01164 //draw pseudocolor legend 01165 if ( !mInvertColor ) 01166 { 01167 //check if we are in the first class break 01168 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01169 { 01170 int myRed = 0; 01171 int myBlue = 255; 01172 int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 ); 01173 // testing this stuff still ... 01174 if ( mColorShadingAlgorithm == FreakOutShader ) 01175 { 01176 myRed = 255 - myGreen; 01177 } 01178 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01179 } 01180 //check if we are in the second class break 01181 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01182 { 01183 int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01184 int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01185 int myGreen = 255; 01186 // testing this stuff still ... 01187 if ( mColorShadingAlgorithm == FreakOutShader ) 01188 { 01189 myGreen = myBlue; 01190 } 01191 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01192 } 01193 //otherwise we must be in the third classbreak 01194 else 01195 { 01196 int myRed = 255; 01197 int myBlue = 0; 01198 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) ); 01199 // testing this stuff still ... 01200 if ( mColorShadingAlgorithm == FreakOutShader ) 01201 { 01202 myRed = myGreen; 01203 myGreen = 255 - myGreen; 01204 } 01205 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01206 } 01207 } //end of invert !histogram false check 01208 else //invert histogram toggle is off 01209 { 01210 //check if we are in the first class break 01211 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01212 { 01213 int myRed = 255; 01214 int myBlue = 0; 01215 int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) ); 01216 // testing this stuff still ... 01217 if ( mColorShadingAlgorithm == FreakOutShader ) 01218 { 01219 myRed = 255 - myGreen; 01220 } 01221 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01222 } 01223 //check if we are in the second class break 01224 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01225 { 01226 int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01227 int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01228 int myGreen = 255; 01229 // testing this stuff still ... 01230 if ( mColorShadingAlgorithm == FreakOutShader ) 01231 { 01232 myGreen = myBlue; 01233 } 01234 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01235 } 01236 //otherwise we must be in the third classbreak 01237 else 01238 { 01239 int myRed = 0; 01240 int myBlue = 255; 01241 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) ); 01242 // testing this stuff still ... 01243 if ( mColorShadingAlgorithm == FreakOutShader ) 01244 { 01245 myRed = 255 - myGreen; 01246 } 01247 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01248 } 01249 01250 } //end of invert histogram check 01251 myQPainter.drawPoint( myPos++, 0 ); 01252 } 01253 01254 } //end of pseudocolor check 01255 else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor || mDrawingStyle == PalettedColor ) 01256 { 01257 // 01258 // Create the legend pixmap showing red green and blue band mappings 01259 // 01260 // TODO update this so it actually shows the mappings for paletted images 01261 myLegendQPixmap = QPixmap( 3, 1 ); 01262 myQPainter.begin( &myLegendQPixmap ); 01263 //draw legend red part 01264 myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) ); 01265 myQPainter.drawPoint( 0, 0 ); 01266 //draw legend green part 01267 myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) ); 01268 myQPainter.drawPoint( 1, 0 ); 01269 //draw legend blue part 01270 myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) ); 01271 myQPainter.drawPoint( 2, 0 ); 01272 } 01273 } 01274 01275 myQPainter.end(); 01276 01277 01278 // see if the caller wants the name of the layer in the pixmap (used for legend bar) 01279 if ( theWithNameFlag ) 01280 { 01281 QFont myQFont( "arial", 10, QFont::Normal ); 01282 QFontMetrics myQFontMetrics( myQFont ); 01283 01284 int myHeight = ( myQFontMetrics.height() + 10 > 35 ) ? myQFontMetrics.height() + 10 : 35; 01285 01286 //create a matrix to 01287 QMatrix myQWMatrix; 01288 //scale the raster legend up a bit bigger to the legend item size 01289 //note that scaling parameters are factors, not absolute values, 01290 // so scale (0.25,1) scales the painter to a quarter of its size in the x direction 01291 //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix 01292 //hard coding thes values for now. 01293 if ( myLegendQPixmap.width() == 3 ) 01294 { 01295 //scale width by factor of 50 (=150px wide) 01296 myQWMatrix.scale( 60, myHeight ); 01297 } 01298 else 01299 { 01300 //assume 100px so scale by factor of 1.5 (=150px wide) 01301 myQWMatrix.scale( 1.8, myHeight ); 01302 } 01303 //apply the matrix 01304 QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix ); 01305 QPainter myQPainter( &myQPixmap2 ); 01306 01307 //load up the pyramid icons 01308 QString myThemePath = QgsApplication::activeThemePath(); 01309 QPixmap myPyramidPixmap( myThemePath + "/mIconPyramid.png" ); 01310 QPixmap myNoPyramidPixmap( myThemePath + "/mIconNoPyramid.png" ); 01311 01312 // 01313 // Overlay a pyramid icon 01314 // 01315 if ( mHasPyramids ) 01316 { 01317 myQPainter.drawPixmap( 0, myHeight - myPyramidPixmap.height(), myPyramidPixmap ); 01318 } 01319 else 01320 { 01321 myQPainter.drawPixmap( 0, myHeight - myNoPyramidPixmap.height(), myNoPyramidPixmap ); 01322 } 01323 // 01324 // Overlay the layer name 01325 // 01326 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01327 { 01328 myQPainter.setPen( Qt::white ); 01329 } 01330 else 01331 { 01332 myQPainter.setPen( Qt::black ); 01333 } 01334 myQPainter.setFont( myQFont ); 01335 myQPainter.drawText( 25, myHeight - 10, name() ); 01336 // 01337 // finish up 01338 // 01339 myLegendQPixmap = myQPixmap2; 01340 myQPainter.end(); 01341 } 01342 //finish up 01343 01344 return myLegendQPixmap; 01345 01346 } //end of legendAsPixmap function 01347 01352 QPixmap QgsRasterLayer::legendAsPixmap( int theLabelCount ) 01353 { 01354 QgsDebugMsg( "entered." ); 01355 QFont myQFont( "arial", 10, QFont::Normal ); 01356 QFontMetrics myQFontMetrics( myQFont ); 01357 01358 int myFontHeight = ( myQFontMetrics.height() ); 01359 const int myerLabelSpacing = 5; 01360 int myImageHeight = (( myFontHeight + ( myerLabelSpacing * 2 ) ) * theLabelCount ); 01361 //these next two vars are not used anywhere so commented out for now 01362 //int myLongestLabelWidth = myQFontMetrics.width(name()); 01363 //const int myHorizontalLabelSpacing = 5; 01364 const int myColorBarWidth = 10; 01365 // 01366 // Get the adjusted matrix stats 01367 // 01368 QString myColorerpretation = mDataProvider->colorInterpretationName( 1 ); 01369 QPixmap myLegendQPixmap; //will be initialised once we know what drawing style is active 01370 QPainter myQPainter; 01371 // 01372 // Create the legend pixmap - note it is generated on the preadjusted stats 01373 // 01374 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01375 { 01376 01377 myLegendQPixmap = QPixmap( 1, myImageHeight ); 01378 const double myIncrement = static_cast<double>( myImageHeight ) / 255.0; 01379 myQPainter.begin( &myLegendQPixmap ); 01380 int myPos = 0; 01381 for ( double my = 0; my < 255; my += myIncrement ) 01382 { 01383 if ( !mInvertColor ) //histogram is not inverted 01384 { 01385 //draw legend as grayscale 01386 int myGray = static_cast < int >( my ); 01387 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01388 } 01389 else //histogram is inverted 01390 { 01391 //draw legend as inverted grayscale 01392 int myGray = 255 - static_cast < int >( my ); 01393 myQPainter.setPen( QPen( QColor( myGray, myGray, myGray ), 0 ) ); 01394 } //end of invert histogram check 01395 myQPainter.drawPoint( 0, myPos++ ); 01396 } 01397 } //end of gray check 01398 else if ( mDrawingStyle == MultiBandSingleBandPseudoColor || 01399 mDrawingStyle == PalettedSingleBandPseudoColor || mDrawingStyle == SingleBandPseudoColor ) 01400 { 01401 01402 //set up the three class breaks for pseudocolor mapping 01403 double myRangeSize = 90; //hard coded for now 01404 double myBreakSize = myRangeSize / 3; 01405 double myClassBreakMin1 = 0; 01406 double myClassBreakMax1 = myClassBreakMin1 + myBreakSize; 01407 double myClassBreakMin2 = myClassBreakMax1; 01408 double myClassBreakMax2 = myClassBreakMin2 + myBreakSize; 01409 double myClassBreakMin3 = myClassBreakMax2; 01410 01411 // 01412 // Create the legend pixmap - note it is generated on the preadjusted stats 01413 // 01414 myLegendQPixmap = QPixmap( 1, myImageHeight ); 01415 const double myIncrement = myImageHeight / myRangeSize; 01416 myQPainter.begin( &myLegendQPixmap ); 01417 int myPos = 0; 01418 for ( double my = 0; my < 255; my += myIncrement ) 01419 for ( double my = 0; my < myRangeSize; my += myIncrement ) 01420 { 01421 //draw pseudocolor legend 01422 if ( !mInvertColor ) 01423 { 01424 //check if we are in the first class break 01425 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01426 { 01427 int myRed = 0; 01428 int myBlue = 255; 01429 int myGreen = static_cast < int >((( 255 / myRangeSize ) * ( my - myClassBreakMin1 ) ) * 3 ); 01430 // testing this stuff still ... 01431 if ( mColorShadingAlgorithm == FreakOutShader ) 01432 { 01433 myRed = 255 - myGreen; 01434 } 01435 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01436 } 01437 //check if we are in the second class break 01438 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01439 { 01440 int myRed = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01441 int myBlue = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01442 int myGreen = 255; 01443 // testing this stuff still ... 01444 if ( mColorShadingAlgorithm == FreakOutShader ) 01445 { 01446 myGreen = myBlue; 01447 } 01448 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01449 } 01450 //otherwise we must be in the third classbreak 01451 else 01452 { 01453 int myRed = 255; 01454 int myBlue = 0; 01455 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin3 ) / 1 ) * 3 ) ) ); 01456 // testing this stuff still ... 01457 if ( mColorShadingAlgorithm == FreakOutShader ) 01458 { 01459 myRed = myGreen; 01460 myGreen = 255 - myGreen; 01461 } 01462 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01463 } 01464 } //end of invert !histogram check 01465 else //invert histogram toggle is off 01466 { 01467 //check if we are in the first class break 01468 if (( my >= myClassBreakMin1 ) && ( my < myClassBreakMax1 ) ) 01469 { 01470 int myRed = 255; 01471 int myBlue = 0; 01472 int myGreen = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin1 ) / 1 ) * 3 ) ); 01473 // testing this stuff still ... 01474 if ( mColorShadingAlgorithm == FreakOutShader ) 01475 { 01476 myRed = 255 - myGreen; 01477 } 01478 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01479 } 01480 //check if we are in the second class break 01481 else if (( my >= myClassBreakMin2 ) && ( my < myClassBreakMax2 ) ) 01482 { 01483 int myRed = static_cast < int >( 255 - ((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ) ); 01484 int myBlue = static_cast < int >((( 255 / myRangeSize ) * (( my - myClassBreakMin2 ) / 1 ) ) * 3 ); 01485 int myGreen = 255; 01486 // testing this stuff still ... 01487 if ( mColorShadingAlgorithm == FreakOutShader ) 01488 { 01489 myGreen = myBlue; 01490 } 01491 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01492 } 01493 //otherwise we must be in the third classbreak 01494 else 01495 { 01496 int myRed = 0; 01497 int myBlue = 255; 01498 int myGreen = static_cast < int >( 255 - ((( 255 / myRangeSize ) * ( my - myClassBreakMin3 ) ) * 3 ) ); 01499 // testing this stuff still ... 01500 if ( mColorShadingAlgorithm == FreakOutShader ) 01501 { 01502 myRed = 255 - myGreen; 01503 } 01504 myQPainter.setPen( QPen( QColor( myRed, myGreen, myBlue ), 0 ) ); 01505 } 01506 01507 } //end of invert histogram check 01508 myQPainter.drawPoint( 0, myPos++ ); 01509 } 01510 01511 } //end of pseudocolor check 01512 else if ( mDrawingStyle == PalettedMultiBandColor || mDrawingStyle == MultiBandColor ) 01513 { 01514 // 01515 // Create the legend pixmap showing red green and blue band mappings 01516 // 01517 // TODO update this so it actually shows the mappings for paletted images 01518 myLegendQPixmap = QPixmap( 1, 3 ); 01519 myQPainter.begin( &myLegendQPixmap ); 01520 //draw legend red part 01521 myQPainter.setPen( QPen( QColor( 224, 103, 103 ), 0 ) ); 01522 myQPainter.drawPoint( 0, 0 ); 01523 //draw legend green part 01524 myQPainter.setPen( QPen( QColor( 132, 224, 127 ), 0 ) ); 01525 myQPainter.drawPoint( 0, 1 ); 01526 //draw legend blue part 01527 myQPainter.setPen( QPen( QColor( 127, 160, 224 ), 0 ) ); 01528 myQPainter.drawPoint( 0, 2 ); 01529 } 01530 01531 01532 myQPainter.end(); 01533 01534 01535 01536 //create a matrix to 01537 QMatrix myQWMatrix; 01538 //scale the raster legend up a bit bigger to the legend item size 01539 //note that scaling parameters are factors, not absolute values, 01540 // so scale (0.25,1) scales the painter to a quarter of its size in the x direction 01541 //TODO We need to decide how much to scale by later especially for rgb images which are only 3x1 pix 01542 //hard coding thes values for now. 01543 if ( myLegendQPixmap.height() == 3 ) 01544 { 01545 myQWMatrix.scale( myColorBarWidth, 2 ); 01546 } 01547 else 01548 { 01549 myQWMatrix.scale( myColorBarWidth, 2 ); 01550 } 01551 //apply the matrix 01552 QPixmap myQPixmap2 = myLegendQPixmap.transformed( myQWMatrix ); 01553 QPainter myQPainter2( &myQPixmap2 ); 01554 // 01555 // Overlay the layer name 01556 // 01557 if ( mDrawingStyle == MultiBandSingleBandGray || mDrawingStyle == PalettedSingleBandGray || mDrawingStyle == SingleBandGray ) 01558 { 01559 myQPainter2.setPen( Qt::white ); 01560 } 01561 else 01562 { 01563 myQPainter2.setPen( Qt::black ); 01564 } 01565 myQPainter2.setFont( myQFont ); 01566 myQPainter2.drawText( 25, myImageHeight - 10, name() ); 01567 // 01568 // finish up 01569 // 01570 myLegendQPixmap = myQPixmap2; 01571 myQPainter2.end(); 01572 //finish up 01573 01574 return myLegendQPixmap; 01575 01576 }//end of getDetailedLegend 01577 01582 double QgsRasterLayer::maximumValue( unsigned int theBand ) 01583 { 01584 if ( 0 < theBand && theBand <= bandCount() ) 01585 { 01586 return mContrastEnhancementList[theBand - 1].maximumValue(); 01587 } 01588 01589 return 0.0; 01590 } 01591 01596 double QgsRasterLayer::maximumValue( QString theBand ) 01597 { 01598 if ( theBand != tr( "Not Set" ) ) 01599 { 01600 return maximumValue( bandNumber( theBand ) ); 01601 } 01602 01603 return 0.0; 01604 } 01605 01606 01607 QString QgsRasterLayer::metadata() 01608 { 01609 QString myMetadata ; 01610 myMetadata += "<p class=\"glossy\">" + tr( "Driver:" ) + "</p>\n"; 01611 myMetadata += "<p>"; 01612 myMetadata += mDataProvider->description(); 01613 myMetadata += "</p>\n"; 01614 01615 // Insert provider-specific (e.g. WMS-specific) metadata 01616 // crashing 01617 //QString s = mDataProvider->metadata(); 01618 //QgsDebugMsg( s ); 01619 myMetadata += mDataProvider->metadata(); 01620 01621 myMetadata += "<p class=\"glossy\">"; 01622 myMetadata += tr( "No Data Value" ); 01623 myMetadata += "</p>\n"; 01624 myMetadata += "<p>"; 01625 if ( mValidNoDataValue ) 01626 { 01627 myMetadata += QString::number( mNoDataValue ); 01628 } 01629 else 01630 { 01631 myMetadata += "*" + tr( "NoDataValue not set" ) + "*"; 01632 } 01633 myMetadata += "</p>\n"; 01634 01635 myMetadata += "</p>\n"; 01636 myMetadata += "<p class=\"glossy\">"; 01637 myMetadata += tr( "Data Type:" ); 01638 myMetadata += "</p>\n"; 01639 myMetadata += "<p>"; 01640 //just use the first band 01641 switch ( mDataProvider->dataType( 1 ) ) 01642 { 01643 case GDT_Byte: 01644 myMetadata += tr( "GDT_Byte - Eight bit unsigned integer" ); 01645 break; 01646 case GDT_UInt16: 01647 myMetadata += tr( "GDT_UInt16 - Sixteen bit unsigned integer " ); 01648 break; 01649 case GDT_Int16: 01650 myMetadata += tr( "GDT_Int16 - Sixteen bit signed integer " ); 01651 break; 01652 case GDT_UInt32: 01653 myMetadata += tr( "GDT_UInt32 - Thirty two bit unsigned integer " ); 01654 break; 01655 case GDT_Int32: 01656 myMetadata += tr( "GDT_Int32 - Thirty two bit signed integer " ); 01657 break; 01658 case GDT_Float32: 01659 myMetadata += tr( "GDT_Float32 - Thirty two bit floating point " ); 01660 break; 01661 case GDT_Float64: 01662 myMetadata += tr( "GDT_Float64 - Sixty four bit floating point " ); 01663 break; 01664 case GDT_CInt16: 01665 myMetadata += tr( "GDT_CInt16 - Complex Int16 " ); 01666 break; 01667 case GDT_CInt32: 01668 myMetadata += tr( "GDT_CInt32 - Complex Int32 " ); 01669 break; 01670 case GDT_CFloat32: 01671 myMetadata += tr( "GDT_CFloat32 - Complex Float32 " ); 01672 break; 01673 case GDT_CFloat64: 01674 myMetadata += tr( "GDT_CFloat64 - Complex Float64 " ); 01675 break; 01676 default: 01677 myMetadata += tr( "Could not determine raster data type." ); 01678 } 01679 myMetadata += "</p>\n"; 01680 01681 myMetadata += "<p class=\"glossy\">"; 01682 myMetadata += tr( "Pyramid overviews:" ); 01683 myMetadata += "</p>\n"; 01684 myMetadata += "<p>"; 01685 01686 myMetadata += "<p class=\"glossy\">"; 01687 myMetadata += tr( "Layer Spatial Reference System: " ); 01688 myMetadata += "</p>\n"; 01689 myMetadata += "<p>"; 01690 myMetadata += mCRS->toProj4(); 01691 myMetadata += "</p>\n"; 01692 01693 myMetadata += "<p class=\"glossy\">"; 01694 myMetadata += tr( "Layer Extent (layer original source projection): " ); 01695 myMetadata += "</p>\n"; 01696 myMetadata += "<p>"; 01697 myMetadata += mDataProvider->extent().toString(); 01698 myMetadata += "</p>\n"; 01699 01700 // output coordinate system 01701 // TODO: this is not related to layer, to be removed? [MD] 01702 #if 0 01703 myMetadata += "<tr><td class=\"glossy\">"; 01704 myMetadata += tr( "Project Spatial Reference System: " ); 01705 myMetadata += "</p>\n"; 01706 myMetadata += "<p>"; 01707 myMetadata += mCoordinateTransform->destCRS().toProj4(); 01708 myMetadata += "</p>\n"; 01709 #endif 01710 01711 // 01712 // Add the stats for each band to the output table 01713 // 01714 int myBandCountInt = bandCount(); 01715 for ( int myIteratorInt = 1; myIteratorInt <= myBandCountInt; ++myIteratorInt ) 01716 { 01717 QgsDebugMsg( "Raster properties : checking if band " + QString::number( myIteratorInt ) + " has stats? " ); 01718 //band name 01719 myMetadata += "<p class=\"glossy\">\n"; 01720 myMetadata += tr( "Band" ); 01721 myMetadata += "</p>\n"; 01722 myMetadata += "<p>"; 01723 myMetadata += bandName( myIteratorInt ); 01724 myMetadata += "</p>\n"; 01725 //band number 01726 myMetadata += "<p>"; 01727 myMetadata += tr( "Band No" ); 01728 myMetadata += "</p>\n"; 01729 myMetadata += "<p>\n"; 01730 myMetadata += QString::number( myIteratorInt ); 01731 myMetadata += "</p>\n"; 01732 01733 //check if full stats for this layer have already been collected 01734 if ( !hasStatistics( myIteratorInt ) ) //not collected 01735 { 01736 QgsDebugMsg( ".....no" ); 01737 01738 myMetadata += "<p>"; 01739 myMetadata += tr( "No Stats" ); 01740 myMetadata += "</p>\n"; 01741 myMetadata += "<p>\n"; 01742 myMetadata += tr( "No stats collected yet" ); 01743 myMetadata += "</p>\n"; 01744 } 01745 else // collected - show full detail 01746 { 01747 QgsDebugMsg( ".....yes" ); 01748 01749 QgsRasterBandStats myRasterBandStats = bandStatistics( myIteratorInt ); 01750 //Min Val 01751 myMetadata += "<p>"; 01752 myMetadata += tr( "Min Val" ); 01753 myMetadata += "</p>\n"; 01754 myMetadata += "<p>\n"; 01755 myMetadata += QString::number( myRasterBandStats.minimumValue, 'f', 10 ); 01756 myMetadata += "</p>\n"; 01757 01758 // Max Val 01759 myMetadata += "<p>"; 01760 myMetadata += tr( "Max Val" ); 01761 myMetadata += "</p>\n"; 01762 myMetadata += "<p>\n"; 01763 myMetadata += QString::number( myRasterBandStats.maximumValue, 'f', 10 ); 01764 myMetadata += "</p>\n"; 01765 01766 // Range 01767 myMetadata += "<p>"; 01768 myMetadata += tr( "Range" ); 01769 myMetadata += "</p>\n"; 01770 myMetadata += "<p>\n"; 01771 myMetadata += QString::number( myRasterBandStats.range, 'f', 10 ); 01772 myMetadata += "</p>\n"; 01773 01774 // Mean 01775 myMetadata += "<p>"; 01776 myMetadata += tr( "Mean" ); 01777 myMetadata += "</p>\n"; 01778 myMetadata += "<p>\n"; 01779 myMetadata += QString::number( myRasterBandStats.mean, 'f', 10 ); 01780 myMetadata += "</p>\n"; 01781 01782 //sum of squares 01783 myMetadata += "<p>"; 01784 myMetadata += tr( "Sum of squares" ); 01785 myMetadata += "</p>\n"; 01786 myMetadata += "<p>\n"; 01787 myMetadata += QString::number( myRasterBandStats.sumOfSquares, 'f', 10 ); 01788 myMetadata += "</p>\n"; 01789 01790 //standard deviation 01791 myMetadata += "<p>"; 01792 myMetadata += tr( "Standard Deviation" ); 01793 myMetadata += "</p>\n"; 01794 myMetadata += "<p>\n"; 01795 myMetadata += QString::number( myRasterBandStats.stdDev, 'f', 10 ); 01796 myMetadata += "</p>\n"; 01797 01798 //sum of all cells 01799 myMetadata += "<p>"; 01800 myMetadata += tr( "Sum of all cells" ); 01801 myMetadata += "</p>\n"; 01802 myMetadata += "<p>\n"; 01803 myMetadata += QString::number( myRasterBandStats.sum, 'f', 10 ); 01804 myMetadata += "</p>\n"; 01805 01806 //number of cells 01807 myMetadata += "<p>"; 01808 myMetadata += tr( "Cell Count" ); 01809 myMetadata += "</p>\n"; 01810 myMetadata += "<p>\n"; 01811 myMetadata += QString::number( myRasterBandStats.elementCount ); 01812 myMetadata += "</p>\n"; 01813 } 01814 } 01815 01816 QgsDebugMsg( myMetadata ); 01817 return myMetadata; 01818 } 01819 01824 double QgsRasterLayer::minimumValue( unsigned int theBand ) 01825 { 01826 if ( 0 < theBand && theBand <= bandCount() ) 01827 { 01828 return mContrastEnhancementList[theBand - 1].minimumValue(); 01829 } 01830 01831 return 0.0; 01832 } 01833 01838 double QgsRasterLayer::minimumValue( QString theBand ) 01839 { 01840 return minimumValue( bandNumber( theBand ) ); 01841 } 01842 01847 QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber ) 01848 { 01849 //TODO: This function should take dimensions 01850 QgsDebugMsg( "entered." ); 01851 01852 // Only do this for the non-provider (hard-coded GDAL) scenario... 01853 // Maybe WMS can do this differently using QImage::numColors and QImage::color() 01854 if ( mProviderKey.isEmpty() && hasBand( "Palette" ) && theBandNumber > 0 ) //don't tr() this its a gdal word! 01855 { 01856 QgsDebugMsg( "....found paletted image" ); 01857 QgsColorRampShader myShader; 01858 //QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = myShader.colorRampItemList(); 01859 01860 //if ( readColorTable( 1, &myColorRampItemList ) ) 01861 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( 1 ); 01862 // TODO: add CT capability? It can depends on band (?) 01863 if ( myColorRampItemList.size() > 0 ) 01864 { 01865 QgsDebugMsg( "....got color ramp item list" ); 01866 myShader.setColorRampItemList( myColorRampItemList ); 01867 myShader.setColorRampType( QgsColorRampShader::DISCRETE ); 01868 // Draw image 01869 int mySize = 100; 01870 QPixmap myPalettePixmap( mySize, mySize ); 01871 QPainter myQPainter( &myPalettePixmap ); 01872 01873 QImage myQImage = QImage( mySize, mySize, QImage::Format_RGB32 ); 01874 myQImage.fill( 0 ); 01875 myPalettePixmap.fill(); 01876 01877 double myStep = (( double )myColorRampItemList.size() - 1 ) / ( double )( mySize * mySize ); 01878 double myValue = 0.0; 01879 for ( int myRow = 0; myRow < mySize; myRow++ ) 01880 { 01881 QRgb* myLineBuffer = ( QRgb* )myQImage.scanLine( myRow ); 01882 for ( int myCol = 0; myCol < mySize; myCol++ ) 01883 { 01884 myValue = myStep * ( double )( myCol + myRow * mySize ); 01885 int c1, c2, c3; 01886 myShader.shade( myValue, &c1, &c2, &c3 ); 01887 myLineBuffer[ myCol ] = qRgb( c1, c2, c3 ); 01888 } 01889 } 01890 01891 myQPainter.drawImage( 0, 0, myQImage ); 01892 return myPalettePixmap; 01893 } 01894 QPixmap myNullPixmap; 01895 return myNullPixmap; 01896 } 01897 else 01898 { 01899 //invalid layer was requested 01900 QPixmap myNullPixmap; 01901 return myNullPixmap; 01902 } 01903 } 01904 01905 /* 01906 * @param theBandNoInt - which band to compute the histogram for 01907 * @param theBinCountInt - how many 'bins' to categorise the data into 01908 * @param theIgnoreOutOfRangeFlag - whether to ignore values that are out of range (default=true) 01909 * @param theThoroughBandScanFlag - whether to visit each cell when computing the histogram (default=false) 01910 */ 01911 void QgsRasterLayer::populateHistogram( int theBandNo, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag ) 01912 { 01913 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 01914 mDataProvider->populateHistogram( theBandNo, myRasterBandStats, theBinCount, theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag ); 01915 } 01916 01917 QString QgsRasterLayer::providerKey() const 01918 { 01919 if ( mProviderKey.isEmpty() ) 01920 { 01921 return QString(); 01922 } 01923 else 01924 { 01925 return mProviderKey; 01926 } 01927 } 01928 01932 double QgsRasterLayer::rasterUnitsPerPixel() 01933 { 01934 // We return one raster pixel per map unit pixel 01935 // One raster pixel can have several raster units... 01936 01937 // We can only use one of the mGeoTransform[], so go with the 01938 // horisontal one. 01939 01940 //return qAbs( mGeoTransform[1] ); 01941 if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactResolution && mDataProvider->xSize() > 0 ) 01942 { 01943 return mDataProvider->extent().width() / mDataProvider->xSize(); 01944 } 01945 return 1; 01946 } 01947 01948 01949 void QgsRasterLayer::resetNoDataValue() 01950 { 01951 mNoDataValue = std::numeric_limits<int>::max(); 01952 mValidNoDataValue = false; 01953 if ( mDataProvider != NULL && mDataProvider->bandCount() > 0 ) 01954 { 01955 // TODO: add 'has null value' to capabilities 01956 #if 0 01957 int myRequestValid; 01958 myRequestValid = 1; 01959 double myValue = mDataProvider->noDataValue(); 01960 01961 if ( 0 != myRequestValid ) 01962 { 01963 setNoDataValue( myValue ); 01964 } 01965 else 01966 { 01967 setNoDataValue( -9999.0 ); 01968 mValidNoDataValue = false; 01969 01970 } 01971 #endif 01972 setNoDataValue( mDataProvider->noDataValue() ); 01973 mValidNoDataValue = mDataProvider->isNoDataValueValid(); 01974 } 01975 } 01976 01977 01978 void QgsRasterLayer::setBlueBandName( QString const & theBandName ) 01979 { 01980 mBlueBandName = validateBandName( theBandName ); 01981 } 01982 01983 void QgsRasterLayer::init() 01984 { 01985 // keep this until mGeoTransform occurences are removed! 01986 mGeoTransform[0] = 0; 01987 mGeoTransform[1] = 1; 01988 mGeoTransform[2] = 0; 01989 mGeoTransform[3] = 0; 01990 mGeoTransform[4] = 0; 01991 mGeoTransform[5] = -1; 01992 01993 01994 mRasterType = QgsRasterLayer::GrayOrUndefined; 01995 01996 mRedBandName = TRSTRING_NOT_SET; 01997 mGreenBandName = TRSTRING_NOT_SET; 01998 mBlueBandName = TRSTRING_NOT_SET; 01999 mGrayBandName = TRSTRING_NOT_SET; 02000 mTransparencyBandName = TRSTRING_NOT_SET; 02001 02002 02003 mUserDefinedRGBMinimumMaximum = false; //defaults needed to bypass enhanceContrast 02004 mUserDefinedGrayMinimumMaximum = false; 02005 mRGBMinimumMaximumEstimated = true; 02006 mGrayMinimumMaximumEstimated = true; 02007 02008 mDrawingStyle = QgsRasterLayer::UndefinedDrawingStyle; 02009 mContrastEnhancementAlgorithm = QgsContrastEnhancement::NoEnhancement; 02010 mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader; 02011 mRasterShader = new QgsRasterShader(); 02012 02013 mBandCount = 0; 02014 mHasPyramids = false; 02015 mNoDataValue = -9999.0; 02016 mValidNoDataValue = false; 02017 02018 //Initialize the last view port structure, should really be a class 02019 mLastViewPort.drawableAreaXDim = 0; 02020 mLastViewPort.drawableAreaYDim = 0; 02021 } 02022 02023 QLibrary* QgsRasterLayer::loadProviderLibrary( QString theProviderKey ) 02024 { 02025 QgsDebugMsg( "theProviderKey = " + theProviderKey ); 02026 // load the plugin 02027 QgsProviderRegistry * pReg = QgsProviderRegistry::instance(); 02028 QString myLibPath = pReg->library( theProviderKey ); 02029 QgsDebugMsg( "myLibPath = " + myLibPath ); 02030 02031 #ifdef TESTPROVIDERLIB 02032 const char *cOgrLib = ( const char * ) myLibPath; 02033 // test code to help debug provider loading problems 02034 // void *handle = dlopen(cOgrLib, RTLD_LAZY); 02035 void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL ); 02036 if ( !handle ) 02037 { 02038 QgsLogger::warning( "Error in dlopen: " ); 02039 } 02040 else 02041 { 02042 QgsDebugMsg( "dlopen suceeded" ); 02043 dlclose( handle ); 02044 } 02045 02046 #endif 02047 02048 // load the data provider 02049 QLibrary* myLib = new QLibrary( myLibPath ); 02050 02051 QgsDebugMsg( "Library name is " + myLib->fileName() ); 02052 bool loaded = myLib->load(); 02053 02054 if ( !loaded ) 02055 { 02056 QgsLogger::warning( "QgsRasterLayer::loadProviderLibrary: Failed to load " ); 02057 return NULL; 02058 } 02059 QgsDebugMsg( "Loaded data provider library" ); 02060 return myLib; 02061 } 02062 02063 // This code should be shared also by vector layer -> move it to QgsMapLayer 02064 QgsRasterDataProvider* QgsRasterLayer::loadProvider( QString theProviderKey, QString theDataSource ) 02065 { 02066 QgsDebugMsg( "Entered" ); 02067 QLibrary* myLib = QgsRasterLayer::loadProviderLibrary( theProviderKey ); 02068 QgsDebugMsg( "Library loaded" ); 02069 if ( !myLib ) 02070 { 02071 QgsDebugMsg( "myLib is NULL" ); 02072 return NULL; 02073 } 02074 02075 QgsDebugMsg( "Attempting to resolve the classFactory function" ); 02076 classFactoryFunction_t * classFactory = ( classFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "classFactory" ) ); 02077 02078 if ( !classFactory ) 02079 { 02080 QgsLogger::warning( "QgsRasterLayer::loadProvider: Cannot resolve the classFactory function" ); 02081 return NULL; 02082 } 02083 QgsDebugMsg( "Getting pointer to a mDataProvider object from the library" ); 02084 //XXX - This was a dynamic cast but that kills the Windows 02085 // version big-time with an abnormal termination error 02086 // mDataProvider = (QgsRasterDataProvider*)(classFactory((const 02087 // char*)(dataSource.utf8()))); 02088 02089 // Copied from qgsproviderregistry in preference to the above. 02090 QgsRasterDataProvider* myDataProvider = ( QgsRasterDataProvider* )( *classFactory )( &theDataSource ); 02091 02092 if ( !myDataProvider ) 02093 { 02094 QgsLogger::warning( "QgsRasterLayer::loadProvider: Unable to instantiate the data provider plugin" ); 02095 return NULL; 02096 } 02097 QgsDebugMsg( "Data driver created" ); 02098 return myDataProvider; 02099 } 02100 02101 void QgsRasterLayer::setDataProvider( QString const & provider, 02102 QStringList const & layers, 02103 QStringList const & styles, 02104 QString const & format, 02105 QString const & crs ) 02106 { 02107 setDataProvider( provider, layers, styles, format, crs, false ); 02108 } 02109 02113 void QgsRasterLayer::setDataProvider( QString const & provider, 02114 QStringList const & layers, 02115 QStringList const & styles, 02116 QString const & format, 02117 QString const & crs, 02118 bool loadDefaultStyleFlag ) 02119 { 02120 // XXX should I check for and possibly delete any pre-existing providers? 02121 // XXX How often will that scenario occur? 02122 02123 mProviderKey = provider; 02124 mValid = false; // assume the layer is invalid until we determine otherwise 02125 02126 // set the layer name (uppercase first character) 02127 02128 if ( ! mLayerName.isEmpty() ) // XXX shouldn't this happen in parent? 02129 { 02130 setLayerName( mLayerName ); 02131 } 02132 02133 mBandCount = 0; 02134 mRasterShader = new QgsRasterShader(); 02135 02136 mDataProvider = QgsRasterLayer::loadProvider( mProviderKey, mDataSource ); 02137 if ( !mDataProvider ) 02138 { 02139 return; 02140 } 02141 02142 02143 QgsDebugMsg( "Instantiated the data provider plugin" 02144 + QString( " with layer list of " ) + layers.join( ", " ) 02145 + " and style list of " + styles.join( ", " ) 02146 + " and format of " + format + " and CRS of " + crs ); 02147 if ( ! mDataProvider->isValid() ) 02148 { 02149 QgsLogger::warning( "QgsRasterLayer::setDataProvider: Data provider is invalid." ); 02150 return; 02151 } 02152 02153 mDataProvider->addLayers( layers, styles ); 02154 mDataProvider->setImageEncoding( format ); 02155 mDataProvider->setImageCrs( crs ); 02156 02157 setNoDataValue( mDataProvider->noDataValue() ); 02158 02159 // get the extent 02160 QgsRectangle mbr = mDataProvider->extent(); 02161 02162 // show the extent 02163 QString s = mbr.toString(); 02164 QgsDebugMsg( "Extent of layer: " + s ); 02165 // store the extent 02166 mLayerExtent.setXMaximum( mbr.xMaximum() ); 02167 mLayerExtent.setXMinimum( mbr.xMinimum() ); 02168 mLayerExtent.setYMaximum( mbr.yMaximum() ); 02169 mLayerExtent.setYMinimum( mbr.yMinimum() ); 02170 02171 mWidth = mDataProvider->xSize(); 02172 mHeight = mDataProvider->ySize(); 02173 02174 02175 // upper case the first letter of the layer name 02176 QgsDebugMsg( "mLayerName: " + name() ); 02177 02178 // set up the raster drawing style 02179 mDrawingStyle = MultiBandColor; //sensible default 02180 02181 // Setup source CRS 02182 if ( mProviderKey == "wms" ) 02183 { 02184 *mCRS = QgsCoordinateReferenceSystem(); 02185 mCRS->createFromOgcWmsCrs( crs ); 02186 } 02187 else 02188 { 02189 *mCRS = QgsCoordinateReferenceSystem( mDataProvider->crs() ); 02190 } 02191 //get the project projection, defaulting to this layer's projection 02192 //if none exists.... 02193 if ( !mCRS->isValid() ) 02194 { 02195 mCRS->setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) ); 02196 mCRS->validate(); 02197 } 02198 QString mySourceWkt = mCRS->toWkt(); 02199 02200 QgsDebugMsg( "using wkt:\n" + mySourceWkt ); 02201 02202 mBandCount = mDataProvider->bandCount( ); 02203 for ( int i = 1; i <= mBandCount; i++ ) 02204 { 02205 QgsRasterBandStats myRasterBandStats; 02206 myRasterBandStats.bandName = mDataProvider->generateBandName( i ); 02207 myRasterBandStats.bandNumber = i; 02208 myRasterBandStats.statsGathered = false; 02209 myRasterBandStats.histogramVector->clear(); 02210 //Store the default color table 02211 //readColorTable( i, &myRasterBandStats.colorTable ); 02212 QList<QgsColorRampShader::ColorRampItem> ct; 02213 ct = mDataProvider->colorTable( i ); 02214 myRasterBandStats.colorTable = ct; 02215 02216 mRasterStatsList.push_back( myRasterBandStats ); 02217 02218 //Build a new contrast enhancement for the band and store in list 02219 //QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->dataType( i ) ); 02220 QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->srcDataType( i ) ); 02221 mContrastEnhancementList.append( myContrastEnhancement ); 02222 } 02223 02224 //defaults - Needs to be set after the Contrast list has been build 02225 //Try to read the default contrast enhancement from the config file 02226 02227 QSettings myQSettings; 02228 setContrastEnhancementAlgorithm( myQSettings.value( "/Raster/defaultContrastEnhancementAlgorithm", "NoEnhancement" ).toString() ); 02229 02230 //decide what type of layer this is... 02231 //TODO Change this to look at the color interp and palette interp to decide which type of layer it is 02232 QgsDebugMsg( "bandCount = " + QString::number( mDataProvider->bandCount() ) ); 02233 QgsDebugMsg( "dataType = " + QString::number( mDataProvider->dataType( 1 ) ) ); 02234 if (( mDataProvider->bandCount() > 1 ) ) 02235 { 02236 mRasterType = Multiband; 02237 } 02238 else if ( mDataProvider->dataType( 1 ) == QgsRasterDataProvider::ARGBDataType ) 02239 { 02240 mRasterType = ColorLayer; 02241 } 02242 //TODO hasBand is really obsolete and only used in the Palette instance, change to new function hasPalette(int) 02243 //else if ( hasBand( "Palette" ) ) //don't tr() this its a gdal word! 02244 // not sure if is worth to add colorTable capability - CT can be empty in any case 02245 // Calc bandStatistics is very slow!!! 02246 //else if ( bandStatistics(1).colorTable.count() > 0 ) 02247 else if ( mDataProvider->colorInterpretation( 1 ) == QgsRasterDataProvider::PaletteIndex ) 02248 { 02249 mRasterType = Palette; 02250 } 02251 else 02252 { 02253 mRasterType = GrayOrUndefined; 02254 } 02255 02256 // Set min/max values for single band if we have them ready (no need to calculate which is slow) 02257 // don't set min/max on multiband even if available because it would cause stretch of bands and thus colors distortion 02258 if ( mDataProvider->bandCount() == 1 && ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactMinimumMaximum ) ) 02259 { 02260 setMinimumValue( 1, mDataProvider->minimumValue( 1 ) ); 02261 setMaximumValue( 1, mDataProvider->maximumValue( 1 ) ); 02262 } 02263 02264 QgsDebugMsg( "mRasterType = " + QString::number( mRasterType ) ); 02265 if ( mRasterType == ColorLayer ) 02266 { 02267 QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 02268 mDrawingStyle = SingleBandColorDataStyle; 02269 mGrayBandName = bandName( 1 ); //sensible default 02270 } 02271 else if ( mRasterType == Palette ) 02272 { 02273 mRedBandName = TRSTRING_NOT_SET; // sensible default 02274 mGreenBandName = TRSTRING_NOT_SET; // sensible default 02275 mBlueBandName = TRSTRING_NOT_SET;// sensible default 02276 mTransparencyBandName = TRSTRING_NOT_SET; // sensible default 02277 mGrayBandName = bandName( 1 ); //sensible default 02278 QgsDebugMsg( mGrayBandName ); 02279 02280 mDrawingStyle = PalettedColor; //sensible default 02281 02282 //Set up a new color ramp shader 02283 setColorShadingAlgorithm( ColorRampShader ); 02284 QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction(); 02285 //TODO: Make sure the set algorithm and cast was successful, 02286 //e.g., if ( 0 != myColorRampShader && myColorRampShader->shaderTypeAsString == "ColorRampShader" ) 02287 myColorRampShader->setColorRampType( QgsColorRampShader::INTERPOLATED ); 02288 myColorRampShader->setColorRampItemList( *colorTable( 1 ) ); 02289 } 02290 else if ( mRasterType == Multiband ) 02291 { 02292 //we know we have at least 2 layers... 02293 mRedBandName = bandName( myQSettings.value( "/Raster/defaultRedBand", 1 ).toInt() ); // sensible default 02294 mGreenBandName = bandName( myQSettings.value( "/Raster/defaultGreenBand", 2 ).toInt() ); // sensible default 02295 02296 //Check to make sure preferred bands combinations are valid 02297 if ( mRedBandName.isEmpty() ) 02298 { 02299 mRedBandName = bandName( 1 ); 02300 } 02301 02302 if ( mGreenBandName.isEmpty() ) 02303 { 02304 mGreenBandName = bandName( 2 ); 02305 } 02306 02307 //for the third band we cant be sure so.. 02308 if (( mDataProvider->bandCount() > 2 ) ) 02309 { 02310 mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 3 ).toInt() ); // sensible default 02311 if ( mBlueBandName.isEmpty() ) 02312 { 02313 mBlueBandName = bandName( 3 ); 02314 } 02315 } 02316 else 02317 { 02318 mBlueBandName = bandName( myQSettings.value( "/Raster/defaultBlueBand", 2 ).toInt() ); // sensible default 02319 if ( mBlueBandName.isEmpty() ) 02320 { 02321 mBlueBandName = bandName( 2 ); 02322 } 02323 } 02324 02325 02326 mTransparencyBandName = TRSTRING_NOT_SET; 02327 mGrayBandName = TRSTRING_NOT_SET; //sensible default 02328 mDrawingStyle = MultiBandColor; //sensible default 02329 02330 // read standard deviations 02331 if ( mContrastEnhancementAlgorithm == QgsContrastEnhancement::StretchToMinimumMaximum ) 02332 { 02333 setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toInt() ); 02334 } 02335 } 02336 else //GrayOrUndefined 02337 { 02338 mRedBandName = TRSTRING_NOT_SET; //sensible default 02339 mGreenBandName = TRSTRING_NOT_SET; //sensible default 02340 mBlueBandName = TRSTRING_NOT_SET; //sensible default 02341 mTransparencyBandName = TRSTRING_NOT_SET; //sensible default 02342 mDrawingStyle = SingleBandGray; //sensible default 02343 mGrayBandName = bandName( 1 ); 02344 02345 // If we have min/max available (without calculation), it is better to use StretchToMinimumMaximum 02346 // TODO: in GUI there is 'Contrast enhancement - Default' which is overwritten here 02347 // and that is confusing 02348 if ( mDataProvider->capabilities() & QgsRasterDataProvider::ExactMinimumMaximum ) 02349 { 02350 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum ); 02351 } 02352 02353 // read standard deviations 02354 if ( mContrastEnhancementAlgorithm == QgsContrastEnhancement::StretchToMinimumMaximum ) 02355 { 02356 setStandardDeviations( myQSettings.value( "/Raster/defaultStandardDeviation", 2.0 ).toInt() ); 02357 } 02358 } 02359 // Debug 02360 //mDrawingStyle = SingleBandPseudoColor; 02361 02362 // Store timestamp 02363 // TODO move to provider 02364 mLastModified = lastModified( mDataSource ); 02365 02366 mValidNoDataValue = mDataProvider->isNoDataValueValid(); 02367 if ( mValidNoDataValue ) 02368 { 02369 mRasterTransparency.initializeTransparentPixelList( mNoDataValue, mNoDataValue, mNoDataValue ); 02370 mRasterTransparency.initializeTransparentPixelList( mNoDataValue ); 02371 } 02372 02373 // Connect provider signals 02374 connect( 02375 mDataProvider, SIGNAL( progress( int, double, QString ) ), 02376 this, SLOT( onProgress( int, double, QString ) ) 02377 ); 02378 02379 // Do a passthrough for the status bar text 02380 connect( 02381 mDataProvider, SIGNAL( statusChanged( QString ) ), 02382 this, SIGNAL( statusChanged( QString ) ) 02383 ); 02384 02385 //mark the layer as valid 02386 mValid = true; 02387 02388 QgsDebugMsg( "exiting." ); 02389 } // QgsRasterLayer::setDataProvider 02390 02391 void QgsRasterLayer::closeDataProvider() 02392 { 02393 mValid = false; 02394 delete mRasterShader; 02395 mRasterShader = 0; 02396 delete mDataProvider; 02397 mDataProvider = 0; 02398 02399 mRasterStatsList.clear(); 02400 mContrastEnhancementList.clear(); 02401 02402 mHasPyramids = false; 02403 mPyramidList.clear(); 02404 } 02405 02406 void QgsRasterLayer::setColorShadingAlgorithm( ColorShadingAlgorithm theShadingAlgorithm ) 02407 { 02408 QgsDebugMsg( "called with [" + QString::number( theShadingAlgorithm ) + "]" ); 02409 if ( mColorShadingAlgorithm != theShadingAlgorithm ) 02410 { 02411 if ( 0 == mRasterShader ) 02412 { 02413 mRasterShader = new QgsRasterShader(); 02414 } 02415 02416 switch ( theShadingAlgorithm ) 02417 { 02418 case PseudoColorShader: 02419 mRasterShader->setRasterShaderFunction( new QgsPseudoColorShader() ); 02420 break; 02421 case FreakOutShader: 02422 mRasterShader->setRasterShaderFunction( new QgsFreakOutShader() ); 02423 break; 02424 case ColorRampShader: 02425 mRasterShader->setRasterShaderFunction( new QgsColorRampShader() ); 02426 break; 02427 case UserDefinedShader: 02428 //do nothing 02429 break; 02430 default: 02431 mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() ); 02432 break; 02433 } 02434 02435 //Set the class variable after the call to setRasterShader(), so memory recovery can happen 02436 mColorShadingAlgorithm = theShadingAlgorithm; 02437 } 02438 QgsDebugMsg( "mColorShadingAlgorithm = " + QString::number( theShadingAlgorithm ) ); 02439 } 02440 02441 void QgsRasterLayer::setColorShadingAlgorithm( QString theShaderAlgorithm ) 02442 { 02443 QgsDebugMsg( "called with [" + theShaderAlgorithm + "]" ); 02444 02445 if ( theShaderAlgorithm == "PseudoColorShader" ) 02446 setColorShadingAlgorithm( PseudoColorShader ); 02447 else if ( theShaderAlgorithm == "FreakOutShader" ) 02448 setColorShadingAlgorithm( FreakOutShader ); 02449 else if ( theShaderAlgorithm == "ColorRampShader" ) 02450 setColorShadingAlgorithm( ColorRampShader ); 02451 else if ( theShaderAlgorithm == "UserDefinedShader" ) 02452 setColorShadingAlgorithm( UserDefinedShader ); 02453 else 02454 setColorShadingAlgorithm( UndefinedShader ); 02455 } 02456 02457 void QgsRasterLayer::setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm, bool theGenerateLookupTableFlag ) 02458 { 02459 QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin(); 02460 while ( myIterator != mContrastEnhancementList.end() ) 02461 { 02462 ( *myIterator ).setContrastEnhancementAlgorithm( theAlgorithm, theGenerateLookupTableFlag ); 02463 ++myIterator; 02464 } 02465 mContrastEnhancementAlgorithm = theAlgorithm; 02466 } 02467 02468 void QgsRasterLayer::setContrastEnhancementAlgorithm( QString theAlgorithm, bool theGenerateLookupTableFlag ) 02469 { 02470 QgsDebugMsg( "called with [" + theAlgorithm + "] and flag=" + QString::number(( int )theGenerateLookupTableFlag ) ); 02471 02472 if ( theAlgorithm == "NoEnhancement" ) 02473 { 02474 setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag ); 02475 } 02476 else if ( theAlgorithm == "StretchToMinimumMaximum" ) 02477 { 02478 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchToMinimumMaximum, theGenerateLookupTableFlag ); 02479 } 02480 else if ( theAlgorithm == "StretchAndClipToMinimumMaximum" ) 02481 { 02482 setContrastEnhancementAlgorithm( QgsContrastEnhancement::StretchAndClipToMinimumMaximum, theGenerateLookupTableFlag ); 02483 } 02484 else if ( theAlgorithm == "ClipToMinimumMaximum" ) 02485 { 02486 setContrastEnhancementAlgorithm( QgsContrastEnhancement::ClipToMinimumMaximum, theGenerateLookupTableFlag ); 02487 } 02488 else if ( theAlgorithm == "UserDefined" ) 02489 { 02490 setContrastEnhancementAlgorithm( QgsContrastEnhancement::UserDefinedEnhancement, theGenerateLookupTableFlag ); 02491 } 02492 else 02493 { 02494 setContrastEnhancementAlgorithm( QgsContrastEnhancement::NoEnhancement, theGenerateLookupTableFlag ); 02495 } 02496 } 02497 02498 void QgsRasterLayer::setContrastEnhancementFunction( QgsContrastEnhancementFunction* theFunction ) 02499 { 02500 if ( theFunction ) 02501 { 02502 QList<QgsContrastEnhancement>::iterator myIterator = mContrastEnhancementList.begin(); 02503 while ( myIterator != mContrastEnhancementList.end() ) 02504 { 02505 ( *myIterator ).setContrastEnhancementFunction( theFunction ); 02506 ++myIterator; 02507 } 02508 } 02509 } 02510 02516 void QgsRasterLayer::setDrawingStyle( QString const & theDrawingStyleQString ) 02517 { 02518 QgsDebugMsg( "DrawingStyle = " + theDrawingStyleQString ); 02519 if ( theDrawingStyleQString == "SingleBandGray" )//no need to tr() this its not shown in ui 02520 { 02521 mDrawingStyle = SingleBandGray; 02522 } 02523 else if ( theDrawingStyleQString == "SingleBandPseudoColor" )//no need to tr() this its not shown in ui 02524 { 02525 mDrawingStyle = SingleBandPseudoColor; 02526 } 02527 else if ( theDrawingStyleQString == "PalettedColor" )//no need to tr() this its not shown in ui 02528 { 02529 mDrawingStyle = PalettedColor; 02530 } 02531 else if ( theDrawingStyleQString == "PalettedSingleBandGray" )//no need to tr() this its not shown in ui 02532 { 02533 mDrawingStyle = PalettedSingleBandGray; 02534 } 02535 else if ( theDrawingStyleQString == "PalettedSingleBandPseudoColor" )//no need to tr() this its not shown in ui 02536 { 02537 mDrawingStyle = PalettedSingleBandPseudoColor; 02538 } 02539 else if ( theDrawingStyleQString == "PalettedMultiBandColor" )//no need to tr() this its not shown in ui 02540 { 02541 mDrawingStyle = PalettedMultiBandColor; 02542 } 02543 else if ( theDrawingStyleQString == "MultiBandSingleBandGray" )//no need to tr() this its not shown in ui 02544 { 02545 mDrawingStyle = MultiBandSingleBandGray; 02546 } 02547 else if ( theDrawingStyleQString == "MultiBandSingleBandPseudoColor" )//no need to tr() this its not shown in ui 02548 { 02549 mDrawingStyle = MultiBandSingleBandPseudoColor; 02550 } 02551 else if ( theDrawingStyleQString == "MultiBandColor" )//no need to tr() this its not shown in ui 02552 { 02553 mDrawingStyle = MultiBandColor; 02554 } 02555 else if ( theDrawingStyleQString == "SingleBandColorDataStyle" )//no need to tr() this its not shown in ui 02556 { 02557 QgsDebugMsg( "Setting mDrawingStyle to SingleBandColorDataStyle " + QString::number( SingleBandColorDataStyle ) ); 02558 mDrawingStyle = SingleBandColorDataStyle; 02559 QgsDebugMsg( "Setted mDrawingStyle to " + QString::number( mDrawingStyle ) ); 02560 } 02561 else 02562 { 02563 mDrawingStyle = UndefinedDrawingStyle; 02564 } 02565 } 02566 02567 void QgsRasterLayer::setGrayBandName( QString const & theBandName ) 02568 { 02569 mGrayBandName = validateBandName( theBandName ); 02570 } 02571 02572 void QgsRasterLayer::setGreenBandName( QString const & theBandName ) 02573 { 02574 mGreenBandName = validateBandName( theBandName ); 02575 } 02576 02577 void QgsRasterLayer::setLayerOrder( QStringList const & layers ) 02578 { 02579 QgsDebugMsg( "entered." ); 02580 02581 if ( mDataProvider ) 02582 { 02583 QgsDebugMsg( "About to mDataProvider->setLayerOrder(layers)." ); 02584 mDataProvider->setLayerOrder( layers ); 02585 } 02586 02587 } 02588 02589 void QgsRasterLayer::setMaximumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag ) 02590 { 02591 QgsDebugMsg( "setMaximumValue theValue = " + QString::number( theValue ) ); 02592 if ( 0 < theBand && theBand <= bandCount() ) 02593 { 02594 mContrastEnhancementList[theBand - 1].setMaximumValue( theValue, theGenerateLookupTableFlag ); 02595 } 02596 } 02597 02598 void QgsRasterLayer::setMaximumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag ) 02599 { 02600 if ( theBand != tr( "Not Set" ) ) 02601 { 02602 setMaximumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag ); 02603 } 02604 } 02605 02606 void QgsRasterLayer::setMinimumMaximumUsingLastExtent() 02607 { 02608 double myMinMax[2]; 02609 if ( rasterType() == QgsRasterLayer::GrayOrUndefined || drawingStyle() == QgsRasterLayer::SingleBandGray || drawingStyle() == QgsRasterLayer::MultiBandSingleBandGray ) 02610 { 02611 computeMinimumMaximumFromLastExtent( grayBandName(), myMinMax ); 02612 setMinimumValue( grayBandName(), myMinMax[0] ); 02613 setMaximumValue( grayBandName(), myMinMax[1] ); 02614 02615 setUserDefinedGrayMinimumMaximum( true ); 02616 } 02617 else if ( rasterType() == QgsRasterLayer::Multiband ) 02618 { 02619 computeMinimumMaximumFromLastExtent( redBandName(), myMinMax ); 02620 setMinimumValue( redBandName(), myMinMax[0], false ); 02621 setMaximumValue( redBandName(), myMinMax[1], false ); 02622 02623 computeMinimumMaximumFromLastExtent( greenBandName(), myMinMax ); 02624 setMinimumValue( greenBandName(), myMinMax[0], false ); 02625 setMaximumValue( greenBandName(), myMinMax[1], false ); 02626 02627 computeMinimumMaximumFromLastExtent( blueBandName(), myMinMax ); 02628 setMinimumValue( blueBandName(), myMinMax[0], false ); 02629 setMaximumValue( blueBandName(), myMinMax[1], false ); 02630 02631 setUserDefinedRGBMinimumMaximum( true ); 02632 } 02633 } 02634 02635 void QgsRasterLayer::setMinimumMaximumUsingDataset() 02636 { 02637 if ( rasterType() == QgsRasterLayer::GrayOrUndefined || drawingStyle() == QgsRasterLayer::SingleBandGray || drawingStyle() == QgsRasterLayer::MultiBandSingleBandGray ) 02638 { 02639 QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mGrayBandName ) ); 02640 double myMin = myRasterBandStats.minimumValue; 02641 double myMax = myRasterBandStats.maximumValue; 02642 setMinimumValue( grayBandName(), myMin ); 02643 setMaximumValue( grayBandName(), myMax ); 02644 setUserDefinedGrayMinimumMaximum( false ); 02645 } 02646 else if ( rasterType() == QgsRasterLayer::Multiband ) 02647 { 02648 QgsRasterBandStats myRasterBandStats = bandStatistics( bandNumber( mRedBandName ) ); 02649 double myMin = myRasterBandStats.minimumValue; 02650 double myMax = myRasterBandStats.maximumValue; 02651 setMinimumValue( redBandName(), myMin ); 02652 setMaximumValue( redBandName(), myMax ); 02653 02654 myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) ); 02655 myMin = myRasterBandStats.minimumValue; 02656 myMax = myRasterBandStats.maximumValue; 02657 setMinimumValue( greenBandName(), myMin ); 02658 setMaximumValue( greenBandName(), myMax ); 02659 02660 myRasterBandStats = bandStatistics( bandNumber( mGreenBandName ) ); 02661 myMin = myRasterBandStats.minimumValue; 02662 myMax = myRasterBandStats.maximumValue; 02663 setMinimumValue( greenBandName(), myMin ); 02664 setMaximumValue( greenBandName(), myMax ); 02665 02666 setUserDefinedRGBMinimumMaximum( false ); 02667 } 02668 } 02669 02670 void QgsRasterLayer::setMinimumValue( unsigned int theBand, double theValue, bool theGenerateLookupTableFlag ) 02671 { 02672 QgsDebugMsg( "setMinimumValue theValue = " + QString::number( theValue ) ); 02673 if ( 0 < theBand && theBand <= bandCount() ) 02674 { 02675 mContrastEnhancementList[theBand - 1].setMinimumValue( theValue, theGenerateLookupTableFlag ); 02676 } 02677 } 02678 02679 void QgsRasterLayer::setMinimumValue( QString theBand, double theValue, bool theGenerateLookupTableFlag ) 02680 { 02681 if ( theBand != tr( "Not Set" ) ) 02682 { 02683 setMinimumValue( bandNumber( theBand ), theValue, theGenerateLookupTableFlag ); 02684 } 02685 02686 } 02687 02688 void QgsRasterLayer::setNoDataValue( double theNoDataValue ) 02689 { 02690 if ( theNoDataValue != mNoDataValue ) 02691 { 02692 mNoDataValue = theNoDataValue; 02693 mValidNoDataValue = true; 02694 //Basically set the raster stats as invalid 02695 QList<QgsRasterBandStats>::iterator myIterator = mRasterStatsList.begin(); 02696 while ( myIterator != mRasterStatsList.end() ) 02697 { 02698 ( *myIterator ).statsGathered = false; 02699 ++myIterator; 02700 } 02701 } 02702 } 02703 02704 void QgsRasterLayer::setRasterShaderFunction( QgsRasterShaderFunction* theFunction ) 02705 { 02706 if ( theFunction ) 02707 { 02708 mRasterShader->setRasterShaderFunction( theFunction ); 02709 mColorShadingAlgorithm = QgsRasterLayer::UserDefinedShader; 02710 } 02711 else 02712 { 02713 //If NULL as passed in, set a default shader function to prevent segfaults 02714 mRasterShader->setRasterShaderFunction( new QgsRasterShaderFunction() ); 02715 mColorShadingAlgorithm = QgsRasterLayer::UndefinedShader; 02716 } 02717 } 02718 02719 void QgsRasterLayer::setRedBandName( QString const & theBandName ) 02720 { 02721 QgsDebugMsg( "setRedBandName : " + theBandName ); 02722 mRedBandName = validateBandName( theBandName ); 02723 } 02724 02725 void QgsRasterLayer::setSubLayerVisibility( QString const & name, bool vis ) 02726 { 02727 02728 if ( mDataProvider ) 02729 { 02730 QgsDebugMsg( "About to mDataProvider->setSubLayerVisibility(name, vis)." ); 02731 mDataProvider->setSubLayerVisibility( name, vis ); 02732 } 02733 02734 } 02735 02736 void QgsRasterLayer::setTransparentBandName( QString const & theBandName ) 02737 { 02738 mTransparencyBandName = validateBandName( theBandName ); 02739 } 02740 02741 void QgsRasterLayer::showProgress( int theValue ) 02742 { 02743 emit progressUpdate( theValue ); 02744 } 02745 02746 02747 void QgsRasterLayer::showStatusMessage( QString const & theMessage ) 02748 { 02749 // QgsDebugMsg(QString("entered with '%1'.").arg(theMessage)); 02750 02751 // Pass-through 02752 // TODO: See if we can connect signal-to-signal. This is a kludge according to the Qt doc. 02753 emit statusChanged( theMessage ); 02754 } 02755 02756 02757 QStringList QgsRasterLayer::subLayers() const 02758 { 02759 return mDataProvider->subLayers(); 02760 } 02761 02762 02763 void QgsRasterLayer::thumbnailAsPixmap( QPixmap * theQPixmap ) 02764 { 02765 //TODO: This should be depreciated and a new function written that just returns a new QPixmap, it will be safer 02766 if ( 0 == theQPixmap ) { return; } 02767 02768 theQPixmap->fill( ); //defaults to white 02769 02770 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 02771 02772 double myMapUnitsPerPixel; 02773 double myX = 0.0; 02774 double myY = 0.0; 02775 QgsRectangle myExtent = mDataProvider->extent(); 02776 if ( myExtent.width() / myExtent.height() >= theQPixmap->width() / theQPixmap->height() ) 02777 { 02778 myMapUnitsPerPixel = myExtent.width() / theQPixmap->width(); 02779 myY = ( theQPixmap->height() - myExtent.height() / myMapUnitsPerPixel ) / 2; 02780 } 02781 else 02782 { 02783 myMapUnitsPerPixel = myExtent.height() / theQPixmap->height(); 02784 myX = ( theQPixmap->width() - myExtent.width() / myMapUnitsPerPixel ) / 2; 02785 } 02786 02787 double myPixelWidth = myExtent.width() / myMapUnitsPerPixel; 02788 double myPixelHeight = myExtent.height() / myMapUnitsPerPixel; 02789 02790 //myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 ); 02791 myRasterViewPort->topLeftPoint = QgsPoint( myX, myY ); 02792 02793 //myRasterViewPort->bottomRightPoint = QgsPoint( theQPixmap->width(), theQPixmap->height() ); 02794 02795 myRasterViewPort->bottomRightPoint = QgsPoint( myPixelWidth, myPixelHeight ); 02796 myRasterViewPort->drawableAreaXDim = theQPixmap->width(); 02797 myRasterViewPort->drawableAreaYDim = theQPixmap->height(); 02798 //myRasterViewPort->drawableAreaXDim = myPixelWidth; 02799 //myRasterViewPort->drawableAreaYDim = myPixelHeight; 02800 02801 myRasterViewPort->mDrawnExtent = myExtent; 02802 myRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid 02803 myRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid 02804 02805 QgsMapToPixel *myMapToPixel = new QgsMapToPixel( myMapUnitsPerPixel ); 02806 02807 QPainter * myQPainter = new QPainter( theQPixmap ); 02808 draw( myQPainter, myRasterViewPort, myMapToPixel ); 02809 delete myRasterViewPort; 02810 delete myMapToPixel; 02811 myQPainter->end(); 02812 delete myQPainter; 02813 } 02814 02815 void QgsRasterLayer::thumbnailAsImage( QImage * thepImage ) 02816 { 02817 //TODO: This should be depreciated and a new function written that just returns a new QImage, it will be safer 02818 if ( 0 == thepImage ) { return; } 02819 02820 thepImage->fill( Qt::white ); //defaults to white 02821 02822 // Raster providers are disabled (for the moment) 02823 if ( mProviderKey.isEmpty() ) 02824 { 02825 QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort(); 02826 myRasterViewPort->topLeftPoint = QgsPoint( 0, 0 ); 02827 myRasterViewPort->bottomRightPoint = QgsPoint( thepImage->width(), thepImage->height() ); 02828 myRasterViewPort->drawableAreaXDim = thepImage->width(); 02829 myRasterViewPort->drawableAreaYDim = thepImage->height(); 02830 02831 QPainter * myQPainter = new QPainter( thepImage ); 02832 draw( myQPainter, myRasterViewPort ); 02833 delete myRasterViewPort; 02834 myQPainter->end(); 02835 delete myQPainter; 02836 } 02837 02838 } 02839 02840 void QgsRasterLayer::triggerRepaint() 02841 { 02842 emit repaintRequested(); 02843 } 02844 02845 void QgsRasterLayer::updateProgress( int theProgress, int theMax ) 02846 { 02847 //simply propogate it on! 02848 emit drawingProgress( theProgress, theMax ); 02849 } 02850 02851 void QgsRasterLayer::onProgress( int theType, double theProgress, QString theMesssage ) 02852 { 02853 QgsDebugMsg( QString( "theProgress = %1" ).arg( theProgress ) ); 02854 emit progressUpdate(( int )theProgress ); 02855 } 02856 02858 // 02859 // Protected methods 02860 // 02862 /* 02863 * @param QDomNode node that will contain the symbology definition for this layer. 02864 * @param errorMessage reference to string that will be updated with any error messages 02865 * @return true in case of success. 02866 */ 02867 bool QgsRasterLayer::readSymbology( const QDomNode& layer_node, QString& errorMessage ) 02868 { 02869 QDomNode mnl = layer_node.namedItem( "rasterproperties" ); 02870 QDomNode snode = mnl.namedItem( "mDrawingStyle" ); 02871 QDomElement myElement = snode.toElement(); 02872 setDrawingStyle( myElement.text() ); 02873 02874 snode = mnl.namedItem( "mColorShadingAlgorithm" ); 02875 myElement = snode.toElement(); 02876 setColorShadingAlgorithm( myElement.text() ); 02877 02878 snode = mnl.namedItem( "mInvertColor" ); 02879 myElement = snode.toElement(); 02880 QVariant myVariant = ( QVariant ) myElement.attribute( "boolean" ); 02881 setInvertHistogram( myVariant.toBool() ); 02882 02883 snode = mnl.namedItem( "mRedBandName" ); 02884 myElement = snode.toElement(); 02885 setRedBandName( myElement.text() ); 02886 02887 snode = mnl.namedItem( "mGreenBandName" ); 02888 myElement = snode.toElement(); 02889 setGreenBandName( myElement.text() ); 02890 02891 snode = mnl.namedItem( "mBlueBandName" ); 02892 myElement = snode.toElement(); 02893 setBlueBandName( myElement.text() ); 02894 02895 snode = mnl.namedItem( "mGrayBandName" ); 02896 myElement = snode.toElement(); 02897 QgsDebugMsg( QString( " Setting gray band to : " ) + myElement.text() ); 02898 setGrayBandName( myElement.text() ); 02899 02900 snode = mnl.namedItem( "mStandardDeviations" ); 02901 myElement = snode.toElement(); 02902 setStandardDeviations( myElement.text().toDouble() ); 02903 02904 snode = mnl.namedItem( "mUserDefinedRGBMinimumMaximum" ); 02905 myElement = snode.toElement(); 02906 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 02907 setUserDefinedRGBMinimumMaximum( myVariant.toBool() ); 02908 02909 snode = mnl.namedItem( "mRGBMinimumMaximumEstimated" ); 02910 myElement = snode.toElement(); 02911 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 02912 setRGBMinimumMaximumEstimated( myVariant.toBool() ); 02913 02914 snode = mnl.namedItem( "mUserDefinedGrayMinimumMaximum" ); 02915 myElement = snode.toElement(); 02916 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 02917 setUserDefinedGrayMinimumMaximum( myVariant.toBool() ); 02918 02919 snode = mnl.namedItem( "mGrayMinimumMaximumEstimated" ); 02920 myElement = snode.toElement(); 02921 myVariant = ( QVariant ) myElement.attribute( "boolean" ); 02922 setGrayMinimumMaximumEstimated( myVariant.toBool() ); 02923 02924 snode = mnl.namedItem( "mContrastEnhancementAlgorithm" ); 02925 myElement = snode.toElement(); 02926 setContrastEnhancementAlgorithm( myElement.text(), false ); 02927 02928 QDomNode contrastEnhancementMinMaxValues = mnl.namedItem( "contrastEnhancementMinMaxValues" ); 02929 QDomNodeList minMaxValueList = contrastEnhancementMinMaxValues.toElement().elementsByTagName( "minMaxEntry" ); 02930 for ( int i = 0; i < minMaxValueList.size(); ++i ) 02931 { 02932 QDomNode minMaxEntry = minMaxValueList.at( i ).toElement(); 02933 if ( minMaxEntry.isNull() ) 02934 { 02935 continue; 02936 } 02937 QDomNode minEntry = minMaxEntry.namedItem( "min" ); 02938 QDomNode maxEntry = minMaxEntry.namedItem( "max" ); 02939 02940 setMinimumValue( i + 1, minEntry.toElement().text().toDouble(), false ); 02941 setMaximumValue( i + 1, maxEntry.toElement().text().toDouble(), false ); 02942 } 02943 02944 QgsDebugMsg( "ReadXml: gray band name " + mGrayBandName ); 02945 QgsDebugMsg( "ReadXml: red band name " + mRedBandName ); 02946 QgsDebugMsg( "ReadXml: green band name " + mGreenBandName ); 02947 QgsDebugMsg( "Drawing style " + drawingStyleAsString() ); 02948 02949 /* 02950 * Transparency tab 02951 */ 02952 snode = mnl.namedItem( "mNoDataValue" ); 02953 myElement = snode.toElement(); 02954 QgsDebugMsg( "ReadXml: mNoDataValue = " + myElement.text() ); 02955 setNoDataValue( myElement.text().toDouble() ); 02956 QgsDebugMsg( "ReadXml: mNoDataValue = " + QString::number( mNoDataValue ) ); 02957 if ( myElement.attribute( "mValidNoDataValue", "false" ).compare( "true" ) ) 02958 { 02959 // If flag element is not true, set to false. 02960 mValidNoDataValue = false; 02961 } 02962 02963 QDomNode singleValuePixelListNode = mnl.namedItem( "singleValuePixelList" ); 02964 if ( !singleValuePixelListNode.isNull() ) 02965 { 02966 QList<QgsRasterTransparency::TransparentSingleValuePixel> newSingleValuePixelList; 02967 02968 //entries 02969 QDomNodeList singleValuePixelList = singleValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" ); 02970 for ( int i = 0; i < singleValuePixelList.size(); ++i ) 02971 { 02972 QgsRasterTransparency::TransparentSingleValuePixel myNewItem; 02973 QDomElement singleValuePixelListElement = singleValuePixelList.at( i ).toElement(); 02974 if ( singleValuePixelListElement.isNull() ) 02975 { 02976 continue; 02977 } 02978 02979 myNewItem.pixelValue = singleValuePixelListElement.attribute( "pixelValue" ).toDouble(); 02980 myNewItem.percentTransparent = singleValuePixelListElement.attribute( "percentTransparent" ).toDouble(); 02981 02982 newSingleValuePixelList.push_back( myNewItem ); 02983 } 02984 mRasterTransparency.setTransparentSingleValuePixelList( newSingleValuePixelList ); 02985 } 02986 02987 QDomNode threeValuePixelListNode = mnl.namedItem( "threeValuePixelList" ); 02988 if ( !threeValuePixelListNode.isNull() ) 02989 { 02990 QList<QgsRasterTransparency::TransparentThreeValuePixel> newThreeValuePixelList; 02991 02992 //entries 02993 QDomNodeList threeValuePixelList = threeValuePixelListNode.toElement().elementsByTagName( "pixelListEntry" ); 02994 for ( int i = 0; i < threeValuePixelList.size(); ++i ) 02995 { 02996 QgsRasterTransparency::TransparentThreeValuePixel myNewItem; 02997 QDomElement threeValuePixelListElement = threeValuePixelList.at( i ).toElement(); 02998 if ( threeValuePixelListElement.isNull() ) 02999 { 03000 continue; 03001 } 03002 03003 myNewItem.red = threeValuePixelListElement.attribute( "red" ).toDouble(); 03004 myNewItem.green = threeValuePixelListElement.attribute( "green" ).toDouble(); 03005 myNewItem.blue = threeValuePixelListElement.attribute( "blue" ).toDouble(); 03006 myNewItem.percentTransparent = threeValuePixelListElement.attribute( "percentTransparent" ).toDouble(); 03007 03008 newThreeValuePixelList.push_back( myNewItem ); 03009 } 03010 mRasterTransparency.setTransparentThreeValuePixelList( newThreeValuePixelList ); 03011 } 03012 03013 /* 03014 * Color Ramp tab 03015 */ 03016 //restore custom color ramp settings 03017 QDomNode customColorRampNode = mnl.namedItem( "customColorRamp" ); 03018 if ( !customColorRampNode.isNull() ) 03019 { 03020 QgsColorRampShader* myColorRampShader = ( QgsColorRampShader* ) mRasterShader->rasterShaderFunction(); 03021 03022 //TODO: Remove the customColorRampType check and following if() in v2.0, added for compatibility with older ( bugged ) project files 03023 QDomNode customColorRampTypeNode = customColorRampNode.namedItem( "customColorRampType" ); 03024 QDomNode colorRampTypeNode = customColorRampNode.namedItem( "colorRampType" ); 03025 QString myRampType = ""; 03026 if ( "" == customColorRampTypeNode.toElement().text() ) 03027 { 03028 myRampType = colorRampTypeNode.toElement().text(); 03029 } 03030 else 03031 { 03032 myRampType = customColorRampTypeNode.toElement().text(); 03033 } 03034 myColorRampShader->setColorRampType( myRampType ); 03035 03036 03037 //entries 03038 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList; 03039 QDomNodeList colorRampEntryList = customColorRampNode.toElement().elementsByTagName( "colorRampEntry" ); 03040 for ( int i = 0; i < colorRampEntryList.size(); ++i ) 03041 { 03042 QgsColorRampShader::ColorRampItem myNewItem; 03043 QDomElement colorRampEntryElement = colorRampEntryList.at( i ).toElement(); 03044 if ( colorRampEntryElement.isNull() ) 03045 { 03046 continue; 03047 } 03048 03049 myNewItem.color = QColor( colorRampEntryElement.attribute( "red" ).toInt(), colorRampEntryElement.attribute( "green" ).toInt(), colorRampEntryElement.attribute( "blue" ).toInt() ); 03050 myNewItem.label = colorRampEntryElement.attribute( "label" ); 03051 myNewItem.value = colorRampEntryElement.attribute( "value" ).toDouble(); 03052 03053 myColorRampItemList.push_back( myNewItem ); 03054 } 03055 myColorRampShader->setColorRampItemList( myColorRampItemList ); 03056 } 03057 return true; 03058 } //readSymbology 03059 03084 bool QgsRasterLayer::readXml( QDomNode & layer_node ) 03085 { 03087 03088 //process provider key 03089 QDomNode pkeyNode = layer_node.namedItem( "provider" ); 03090 03091 if ( pkeyNode.isNull() ) 03092 { 03093 mProviderKey = "gdal"; 03094 } 03095 else 03096 { 03097 QDomElement pkeyElt = pkeyNode.toElement(); 03098 mProviderKey = pkeyElt.text(); 03099 if ( mProviderKey.isEmpty() ) 03100 { 03101 mProviderKey = "gdal"; 03102 } 03103 } 03104 03105 // Open the raster source based on provider and datasource 03106 03107 // Go down the raster-data-provider paradigm 03108 03109 // Collect provider-specific information 03110 03111 QDomNode rpNode = layer_node.namedItem( "rasterproperties" ); 03112 03113 // Collect sublayer names and styles 03114 mLayers.clear(); 03115 mStyles.clear(); 03116 03117 if ( mProviderKey == "wms" ) 03118 { 03119 QDomElement layerElement = rpNode.firstChildElement( "wmsSublayer" ); 03120 while ( !layerElement.isNull() ) 03121 { 03122 // TODO: sublayer visibility - post-0.8 release timeframe 03123 03124 // collect name for the sublayer 03125 mLayers += layerElement.namedItem( "name" ).toElement().text(); 03126 03127 // collect style for the sublayer 03128 mStyles += layerElement.namedItem( "style" ).toElement().text(); 03129 03130 layerElement = layerElement.nextSiblingElement( "wmsSublayer" ); 03131 } 03132 03133 // Collect format 03134 mFormat = rpNode.namedItem( "wmsFormat" ).toElement().text(); 03135 } 03136 03137 mCrs = crs().authid(); 03138 // Collect CRS 03139 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 03140 03141 QString theError; 03142 bool res = readSymbology( layer_node, theError ); 03143 03144 // old wms settings we need to correct 03145 if ( res && 03146 mProviderKey == "wms" && 03147 mDrawingStyle == MultiBandColor && 03148 mRedBandName == TRSTRING_NOT_SET && 03149 mGreenBandName == TRSTRING_NOT_SET && 03150 mBlueBandName == TRSTRING_NOT_SET ) 03151 { 03152 mDrawingStyle = SingleBandColorDataStyle; 03153 mGrayBandName = bandName( 1 ); 03154 } 03155 03156 // Check timestamp 03157 QDomNode stampNode = layer_node.namedItem( "timestamp" ); 03158 if ( !stampNode.isNull() ) 03159 { 03160 QDateTime stamp = QDateTime::fromString( stampNode.toElement().text(), Qt::ISODate ); 03161 // TODO: very bad, we have to load twice!!! Make QgsDataProvider::timestamp() static? 03162 if ( stamp < mDataProvider->dataTimestamp() ) 03163 { 03164 QgsDebugMsg( "data changed, reload provider" ); 03165 closeDataProvider(); 03166 init(); 03167 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 03168 } 03169 } 03170 03171 return res; 03172 } // QgsRasterLayer::readXml( QDomNode & layer_node ) 03173 03174 /* 03175 * @param QDomNode the node that will have the style element added to it. 03176 * @param QDomDocument the document that will have the QDomNode added. 03177 * @param errorMessage reference to string that will be updated with any error messages 03178 * @return true in case of success. 03179 */ 03180 bool QgsRasterLayer::writeSymbology( QDomNode & layer_node, QDomDocument & document, QString& errorMessage ) const 03181 { 03182 // <rasterproperties> 03183 QDomElement rasterPropertiesElement = document.createElement( "rasterproperties" ); 03184 layer_node.appendChild( rasterPropertiesElement ); 03185 03186 QStringList sl = subLayers(); 03187 QStringList sls = mDataProvider->subLayerStyles(); 03188 03189 QStringList::const_iterator layerStyle = sls.begin(); 03190 03191 if ( mProviderKey == "wms" ) 03192 { 03193 // <rasterproperties><wmsSublayer> 03194 for ( QStringList::const_iterator layerName = sl.begin(); 03195 layerName != sl.end(); 03196 ++layerName ) 03197 { 03198 03199 QgsDebugMsg( QString( "<rasterproperties><wmsSublayer> %1" ).arg( layerName->toLocal8Bit().data() ) ); 03200 03201 QDomElement sublayerElement = document.createElement( "wmsSublayer" ); 03202 03203 // TODO: sublayer visibility - post-0.8 release timeframe 03204 03205 // <rasterproperties><wmsSublayer><name> 03206 QDomElement sublayerNameElement = document.createElement( "name" ); 03207 QDomText sublayerNameText = document.createTextNode( *layerName ); 03208 sublayerNameElement.appendChild( sublayerNameText ); 03209 sublayerElement.appendChild( sublayerNameElement ); 03210 03211 // <rasterproperties><wmsSublayer><style> 03212 QDomElement sublayerStyleElement = document.createElement( "style" ); 03213 QDomText sublayerStyleText = document.createTextNode( *layerStyle ); 03214 sublayerStyleElement.appendChild( sublayerStyleText ); 03215 sublayerElement.appendChild( sublayerStyleElement ); 03216 03217 rasterPropertiesElement.appendChild( sublayerElement ); 03218 03219 // This assumes there are exactly the same number of "layerName"s as there are "layerStyle"s 03220 ++layerStyle; 03221 } 03222 03223 // <rasterproperties><wmsFormat> 03224 QDomElement formatElement = document.createElement( "wmsFormat" ); 03225 QDomText formatText = 03226 document.createTextNode( mDataProvider->imageEncoding() ); 03227 formatElement.appendChild( formatText ); 03228 rasterPropertiesElement.appendChild( formatElement ); 03229 } 03230 03231 // <mDrawingStyle> 03232 QDomElement drawStyleElement = document.createElement( "mDrawingStyle" ); 03233 QDomText drawStyleText = document.createTextNode( drawingStyleAsString() ); 03234 03235 drawStyleElement.appendChild( drawStyleText ); 03236 03237 rasterPropertiesElement.appendChild( drawStyleElement ); 03238 03239 // <colorShadingAlgorithm> 03240 QDomElement colorShadingAlgorithmElement = document.createElement( "mColorShadingAlgorithm" ); 03241 QDomText colorShadingAlgorithmText = document.createTextNode( colorShadingAlgorithmAsString() ); 03242 03243 colorShadingAlgorithmElement.appendChild( colorShadingAlgorithmText ); 03244 03245 rasterPropertiesElement.appendChild( colorShadingAlgorithmElement ); 03246 03247 // <mInvertColor> 03248 QDomElement mInvertColorElement = document.createElement( "mInvertColor" ); 03249 03250 if ( invertHistogram() ) 03251 { 03252 mInvertColorElement.setAttribute( "boolean", "true" ); 03253 } 03254 else 03255 { 03256 mInvertColorElement.setAttribute( "boolean", "false" ); 03257 } 03258 03259 rasterPropertiesElement.appendChild( mInvertColorElement ); 03260 03261 // <mRedBandName> 03262 QDomElement mRedBandNameElement = document.createElement( "mRedBandName" ); 03263 QString writtenRedBandName = redBandName(); 03264 if ( writtenRedBandName == TRSTRING_NOT_SET ) 03265 { 03266 // Write english "not set" only. 03267 writtenRedBandName = QSTRING_NOT_SET; 03268 } 03269 QDomText mRedBandNameText = document.createTextNode( writtenRedBandName ); 03270 03271 mRedBandNameElement.appendChild( mRedBandNameText ); 03272 03273 rasterPropertiesElement.appendChild( mRedBandNameElement ); 03274 03275 03276 // <mGreenBandName> 03277 QDomElement mGreenBandNameElement = document.createElement( "mGreenBandName" ); 03278 QString writtenGreenBandName = greenBandName(); 03279 if ( writtenGreenBandName == TRSTRING_NOT_SET ) 03280 { 03281 // Write english "not set" only. 03282 writtenGreenBandName = QSTRING_NOT_SET; 03283 } 03284 QDomText mGreenBandNameText = document.createTextNode( writtenGreenBandName ); 03285 03286 mGreenBandNameElement.appendChild( mGreenBandNameText ); 03287 03288 rasterPropertiesElement.appendChild( mGreenBandNameElement ); 03289 03290 // <mBlueBandName> 03291 QDomElement mBlueBandNameElement = document.createElement( "mBlueBandName" ); 03292 QString writtenBlueBandName = blueBandName(); 03293 if ( writtenBlueBandName == TRSTRING_NOT_SET ) 03294 { 03295 // Write english "not set" only. 03296 writtenBlueBandName = QSTRING_NOT_SET; 03297 } 03298 QDomText mBlueBandNameText = document.createTextNode( writtenBlueBandName ); 03299 03300 mBlueBandNameElement.appendChild( mBlueBandNameText ); 03301 03302 rasterPropertiesElement.appendChild( mBlueBandNameElement ); 03303 03304 // <mGrayBandName> 03305 QDomElement mGrayBandNameElement = document.createElement( "mGrayBandName" ); 03306 QString writtenGrayBandName = grayBandName(); 03307 if ( writtenGrayBandName == TRSTRING_NOT_SET ) 03308 { 03309 // Write english "not set" only. 03310 writtenGrayBandName = QSTRING_NOT_SET; 03311 } 03312 QDomText mGrayBandNameText = document.createTextNode( writtenGrayBandName ); 03313 03314 mGrayBandNameElement.appendChild( mGrayBandNameText ); 03315 rasterPropertiesElement.appendChild( mGrayBandNameElement ); 03316 03317 // <mStandardDeviations> 03318 QDomElement mStandardDeviationsElement = document.createElement( "mStandardDeviations" ); 03319 QDomText mStandardDeviationsText = document.createTextNode( QString::number( standardDeviations() ) ); 03320 03321 mStandardDeviationsElement.appendChild( mStandardDeviationsText ); 03322 03323 rasterPropertiesElement.appendChild( mStandardDeviationsElement ); 03324 03325 // <mUserDefinedRGBMinimumMaximum> 03326 QDomElement userDefinedRGBMinMaxFlag = document.createElement( "mUserDefinedRGBMinimumMaximum" ); 03327 03328 if ( hasUserDefinedRGBMinimumMaximum() ) 03329 { 03330 userDefinedRGBMinMaxFlag.setAttribute( "boolean", "true" ); 03331 } 03332 else 03333 { 03334 userDefinedRGBMinMaxFlag.setAttribute( "boolean", "false" ); 03335 } 03336 03337 rasterPropertiesElement.appendChild( userDefinedRGBMinMaxFlag ); 03338 03339 // <mRGBMinimumMaximumEstimated> 03340 QDomElement RGBMinimumMaximumEstimated = document.createElement( "mRGBMinimumMaximumEstimated" ); 03341 03342 if ( isRGBMinimumMaximumEstimated() ) 03343 { 03344 RGBMinimumMaximumEstimated.setAttribute( "boolean", "true" ); 03345 } 03346 else 03347 { 03348 RGBMinimumMaximumEstimated.setAttribute( "boolean", "false" ); 03349 } 03350 03351 rasterPropertiesElement.appendChild( RGBMinimumMaximumEstimated ); 03352 03353 // <mUserDefinedGrayMinimumMaximum> 03354 QDomElement userDefinedGrayMinMaxFlag = document.createElement( "mUserDefinedGrayMinimumMaximum" ); 03355 03356 if ( hasUserDefinedGrayMinimumMaximum() ) 03357 { 03358 userDefinedGrayMinMaxFlag.setAttribute( "boolean", "true" ); 03359 } 03360 else 03361 { 03362 userDefinedGrayMinMaxFlag.setAttribute( "boolean", "false" ); 03363 } 03364 03365 rasterPropertiesElement.appendChild( userDefinedGrayMinMaxFlag ); 03366 03367 // <mGrayMinimumMaximumEstimated> 03368 QDomElement GrayMinimumMaximumEstimated = document.createElement( "mGrayMinimumMaximumEstimated" ); 03369 03370 if ( isGrayMinimumMaximumEstimated() ) 03371 { 03372 GrayMinimumMaximumEstimated.setAttribute( "boolean", "true" ); 03373 } 03374 else 03375 { 03376 GrayMinimumMaximumEstimated.setAttribute( "boolean", "false" ); 03377 } 03378 03379 rasterPropertiesElement.appendChild( GrayMinimumMaximumEstimated ); 03380 03381 // <contrastEnhancementAlgorithm> 03382 QDomElement contrastEnhancementAlgorithmElement = document.createElement( "mContrastEnhancementAlgorithm" ); 03383 QDomText contrastEnhancementAlgorithmText = document.createTextNode( contrastEnhancementAlgorithmAsString() ); 03384 03385 contrastEnhancementAlgorithmElement.appendChild( contrastEnhancementAlgorithmText ); 03386 03387 rasterPropertiesElement.appendChild( contrastEnhancementAlgorithmElement ); 03388 03389 // <minMaxValues> 03390 QList<QgsContrastEnhancement>::const_iterator it; 03391 QDomElement contrastEnhancementMinMaxValuesElement = document.createElement( "contrastEnhancementMinMaxValues" ); 03392 for ( it = mContrastEnhancementList.constBegin(); it != mContrastEnhancementList.constEnd(); ++it ) 03393 { 03394 QDomElement minMaxEntry = document.createElement( "minMaxEntry" ); 03395 QDomElement minEntry = document.createElement( "min" ); 03396 QDomElement maxEntry = document.createElement( "max" ); 03397 03398 QDomText minEntryText = document.createTextNode( QString::number( it->minimumValue() ) ); 03399 minEntry.appendChild( minEntryText ); 03400 03401 QDomText maxEntryText = document.createTextNode( QString::number( it->maximumValue() ) ); 03402 maxEntry.appendChild( maxEntryText ); 03403 03404 minMaxEntry.appendChild( minEntry ); 03405 minMaxEntry.appendChild( maxEntry ); 03406 03407 contrastEnhancementMinMaxValuesElement.appendChild( minMaxEntry ); 03408 } 03409 03410 rasterPropertiesElement.appendChild( contrastEnhancementMinMaxValuesElement ); 03411 03412 /* 03413 * Transparency tab 03414 */ 03415 // <mNodataValue> 03416 QDomElement mNoDataValueElement = document.createElement( "mNoDataValue" ); 03417 QDomText mNoDataValueText = document.createTextNode( QString::number( mNoDataValue, 'f' ) ); 03418 if ( mValidNoDataValue ) 03419 { 03420 mNoDataValueElement.setAttribute( "mValidNoDataValue", "true" ); 03421 } 03422 else 03423 { 03424 mNoDataValueElement.setAttribute( "mValidNoDataValue", "false" ); 03425 } 03426 03427 mNoDataValueElement.appendChild( mNoDataValueText ); 03428 03429 rasterPropertiesElement.appendChild( mNoDataValueElement ); 03430 03431 03432 if ( mRasterTransparency.transparentSingleValuePixelList().count() > 0 ) 03433 { 03434 QDomElement singleValuePixelListElement = document.createElement( "singleValuePixelList" ); 03435 03436 QList<QgsRasterTransparency::TransparentSingleValuePixel> myPixelList = mRasterTransparency.transparentSingleValuePixelList(); 03437 QList<QgsRasterTransparency::TransparentSingleValuePixel>::iterator it; 03438 for ( it = myPixelList.begin(); it != myPixelList.end(); ++it ) 03439 { 03440 QDomElement pixelListElement = document.createElement( "pixelListEntry" ); 03441 pixelListElement.setAttribute( "pixelValue", QString::number( it->pixelValue, 'f' ) ); 03442 pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) ); 03443 03444 singleValuePixelListElement.appendChild( pixelListElement ); 03445 } 03446 03447 rasterPropertiesElement.appendChild( singleValuePixelListElement ); 03448 } 03449 03450 if ( mRasterTransparency.transparentThreeValuePixelList().count() > 0 ) 03451 { 03452 QDomElement threeValuePixelListElement = document.createElement( "threeValuePixelList" ); 03453 03454 QList<QgsRasterTransparency::TransparentThreeValuePixel> myPixelList = mRasterTransparency.transparentThreeValuePixelList(); 03455 QList<QgsRasterTransparency::TransparentThreeValuePixel>::iterator it; 03456 for ( it = myPixelList.begin(); it != myPixelList.end(); ++it ) 03457 { 03458 QDomElement pixelListElement = document.createElement( "pixelListEntry" ); 03459 pixelListElement.setAttribute( "red", QString::number( it->red, 'f' ) ); 03460 pixelListElement.setAttribute( "green", QString::number( it->green, 'f' ) ); 03461 pixelListElement.setAttribute( "blue", QString::number( it->blue, 'f' ) ); 03462 pixelListElement.setAttribute( "percentTransparent", QString::number( it->percentTransparent ) ); 03463 03464 threeValuePixelListElement.appendChild( pixelListElement ); 03465 } 03466 03467 rasterPropertiesElement.appendChild( threeValuePixelListElement ); 03468 } 03469 03470 /* 03471 * Color Ramp tab 03472 */ 03473 if ( QgsRasterLayer::ColorRampShader == colorShadingAlgorithm() ) 03474 { 03475 QDomElement customColorRampElement = document.createElement( "customColorRamp" ); 03476 03477 QDomElement customColorRampType = document.createElement( "colorRampType" ); 03478 QDomText customColorRampTypeText = document.createTextNode((( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampTypeAsQString() ); 03479 customColorRampType.appendChild( customColorRampTypeText ); 03480 customColorRampElement.appendChild( customColorRampType ); 03481 03482 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = (( QgsColorRampShader* )mRasterShader->rasterShaderFunction() )->colorRampItemList(); 03483 QList<QgsColorRampShader::ColorRampItem>::iterator it; 03484 for ( it = myColorRampItemList.begin(); it != myColorRampItemList.end(); ++it ) 03485 { 03486 QDomElement colorRampEntryElement = document.createElement( "colorRampEntry" ); 03487 colorRampEntryElement.setAttribute( "red", QString::number( it->color.red() ) ); 03488 colorRampEntryElement.setAttribute( "green", QString::number( it->color.green() ) ); 03489 colorRampEntryElement.setAttribute( "blue", QString::number( it->color.blue() ) ); 03490 colorRampEntryElement.setAttribute( "value", QString::number( it->value, 'f' ) ); 03491 colorRampEntryElement.setAttribute( "label", it->label ); 03492 03493 customColorRampElement.appendChild( colorRampEntryElement ); 03494 } 03495 03496 rasterPropertiesElement.appendChild( customColorRampElement ); 03497 } 03498 03499 return true; 03500 } // bool QgsRasterLayer::writeSymbology 03501 03502 /* 03503 * virtual 03504 * @note Called by QgsMapLayer::writeXML(). 03505 */ 03506 bool QgsRasterLayer::writeXml( QDomNode & layer_node, 03507 QDomDocument & document ) 03508 { 03509 // first get the layer element so that we can append the type attribute 03510 03511 QDomElement mapLayerNode = layer_node.toElement(); 03512 03513 if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) ) 03514 { 03515 QgsLogger::warning( "QgsRasterLayer::writeXML() can't find <maplayer>" ); 03516 return false; 03517 } 03518 03519 mapLayerNode.setAttribute( "type", "raster" ); 03520 03521 // add provider node 03522 03523 QDomElement provider = document.createElement( "provider" ); 03524 QDomText providerText = document.createTextNode( mProviderKey ); 03525 provider.appendChild( providerText ); 03526 layer_node.appendChild( provider ); 03527 03528 //write out the symbology 03529 QString errorMsg; 03530 return writeSymbology( layer_node, document, errorMsg ); 03531 } 03532 03534 // 03535 // Private methods 03536 // 03538 void QgsRasterLayer::drawSingleBandColorData( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03539 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03540 { 03541 QgsDebugMsg( "entered." ); 03542 03543 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03544 imageBuffer.reset(); 03545 03546 QRgb* imageScanLine = 0; 03547 void* rasterScanLine = 0; 03548 03549 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) ) 03550 { 03551 if ( mTransparencyLevel == 255 ) 03552 { 03553 int size = theRasterViewPort->drawableAreaXDim * 4; 03554 memcpy( imageScanLine, rasterScanLine, size ); 03555 } 03556 else 03557 { 03558 uint *p = ( uint* ) rasterScanLine; 03559 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03560 { 03561 QRgb c( *p++ ); 03562 03563 imageScanLine[ i ] = qRgba( qRed( c ), qGreen( c ), qBlue( c ), qAlpha( c ) * mTransparencyLevel / 255 ); 03564 } 03565 } 03566 } 03567 } 03568 03569 void QgsRasterLayer::drawMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03570 const QgsMapToPixel* theQgsMapToPixel ) 03571 { 03572 QgsDebugMsg( "entered." ); 03573 int myRedBandNo = bandNumber( mRedBandName ); 03574 //Invalid band number, segfault prevention 03575 if ( 0 >= myRedBandNo ) 03576 { 03577 return; 03578 } 03579 03580 int myGreenBandNo = bandNumber( mGreenBandName ); 03581 //Invalid band number, segfault prevention 03582 if ( 0 >= myGreenBandNo ) 03583 { 03584 return; 03585 } 03586 03587 int myBlueBandNo = bandNumber( mBlueBandName ); 03588 //Invalid band number, segfault prevention 03589 if ( 0 >= myBlueBandNo ) 03590 { 03591 return; 03592 } 03593 03594 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 03595 bool hasTransparencyBand = 0 < myTransparencyBandNo; 03596 03597 int myRedType = mDataProvider->dataType( myRedBandNo ); 03598 int myGreenType = mDataProvider->dataType( myGreenBandNo ); 03599 int myBlueType = mDataProvider->dataType( myBlueBandNo ); 03600 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 03601 03602 QRgb* redImageScanLine = 0; 03603 void* redRasterScanLine = 0; 03604 QRgb* greenImageScanLine = 0; 03605 void* greenRasterScanLine = 0; 03606 QRgb* blueImageScanLine = 0; 03607 void* blueRasterScanLine = 0; 03608 QRgb* transparencyImageScanLine = 0; 03609 void* transparencyRasterScanLine = 0; 03610 03611 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 03612 03613 QgsRasterBandStats myRedBandStats; 03614 QgsRasterBandStats myGreenBandStats; 03615 QgsRasterBandStats myBlueBandStats; 03616 03617 /* 03618 * If a stetch is requested and there are no user defined Min Max values 03619 * we need to get these values from the bands themselves. 03620 * 03621 */ 03622 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum && mStandardDeviations > 0 ) 03623 { 03624 myRedBandStats = bandStatistics( myRedBandNo ); 03625 myGreenBandStats = bandStatistics( myGreenBandNo ); 03626 myBlueBandStats = bandStatistics( myBlueBandNo ); 03627 mRGBMinimumMaximumEstimated = false; 03628 setMaximumValue( myRedBandNo, myRedBandStats.mean + ( mStandardDeviations * myRedBandStats.stdDev ) ); 03629 setMinimumValue( myRedBandNo, myRedBandStats.mean - ( mStandardDeviations * myRedBandStats.stdDev ) ); 03630 setMaximumValue( myGreenBandNo, myGreenBandStats.mean + ( mStandardDeviations * myGreenBandStats.stdDev ) ); 03631 setMinimumValue( myGreenBandNo, myGreenBandStats.mean - ( mStandardDeviations * myGreenBandStats.stdDev ) ); 03632 setMaximumValue( myBlueBandNo, myBlueBandStats.mean + ( mStandardDeviations * myBlueBandStats.stdDev ) ); 03633 setMinimumValue( myBlueBandNo, myBlueBandStats.mean - ( mStandardDeviations * myBlueBandStats.stdDev ) ); 03634 } 03635 else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedRGBMinimumMaximum ) 03636 { 03637 //This case will be true the first time the image is loaded, so just approimate the min max to keep 03638 //from calling generate raster band stats 03639 mRGBMinimumMaximumEstimated = true; 03640 03641 setMinimumValue( myRedBandNo, mDataProvider->minimumValue( myRedBandNo ) ); 03642 setMaximumValue( myRedBandNo, mDataProvider->maximumValue( myRedBandNo ) ); 03643 03644 setMinimumValue( myGreenBandNo, mDataProvider->minimumValue( myGreenBandNo ) ); 03645 setMaximumValue( myGreenBandNo, mDataProvider->maximumValue( myGreenBandNo ) ); 03646 03647 setMinimumValue( myBlueBandNo, mDataProvider->minimumValue( myBlueBandNo ) ); 03648 setMaximumValue( myBlueBandNo, mDataProvider->maximumValue( myBlueBandNo ) ); 03649 } 03650 03651 //Read and display pixels 03652 double myRedValue = 0.0; 03653 double myGreenValue = 0.0; 03654 double myBlueValue = 0.0; 03655 int myTransparencyValue = 0; 03656 03657 int myStretchedRedValue = 0; 03658 int myStretchedGreenValue = 0; 03659 int myStretchedBlueValue = 0; 03660 int myAlphaValue = 0; 03661 QgsContrastEnhancement* myRedContrastEnhancement = contrastEnhancement( myRedBandNo ); 03662 QgsContrastEnhancement* myGreenContrastEnhancement = contrastEnhancement( myGreenBandNo ); 03663 QgsContrastEnhancement* myBlueContrastEnhancement = contrastEnhancement( myBlueBandNo ); 03664 03665 QgsRasterImageBuffer redImageBuffer( mDataProvider, myRedBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03666 redImageBuffer.reset(); 03667 QgsRasterImageBuffer greenImageBuffer( mDataProvider, myGreenBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03668 greenImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer 03669 greenImageBuffer.reset(); 03670 QgsRasterImageBuffer blueImageBuffer( mDataProvider, myBlueBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03671 blueImageBuffer.setWritingEnabled( false ); //only draw to redImageBuffer 03672 blueImageBuffer.reset(); 03673 03674 QgsRasterImageBuffer *transparencyImageBuffer = 0; 03675 if ( hasTransparencyBand ) 03676 { 03677 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03678 transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer 03679 transparencyImageBuffer->reset(); 03680 } 03681 03682 while ( redImageBuffer.nextScanLine( &redImageScanLine, &redRasterScanLine ) 03683 && greenImageBuffer.nextScanLine( &greenImageScanLine, &greenRasterScanLine ) 03684 && blueImageBuffer.nextScanLine( &blueImageScanLine, &blueRasterScanLine ) 03685 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 03686 { 03687 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03688 { 03689 if ( transparencyImageBuffer ) 03690 { 03691 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 03692 if ( 0 == myTransparencyValue ) 03693 { 03694 redImageScanLine[ i ] = myDefaultColor; 03695 continue; 03696 } 03697 } 03698 03699 myRedValue = readValue( redRasterScanLine, myRedType, i ); 03700 myGreenValue = readValue( greenRasterScanLine, myGreenType, i ); 03701 myBlueValue = readValue( blueRasterScanLine, myBlueType, i ); 03702 03703 if ( mValidNoDataValue && 03704 ( 03705 ( qAbs( myRedValue - mNoDataValue ) <= TINY_VALUE || myRedValue != myRedValue ) || 03706 ( qAbs( myGreenValue - mNoDataValue ) <= TINY_VALUE || myGreenValue != myGreenValue ) || 03707 ( qAbs( myBlueValue - mNoDataValue ) <= TINY_VALUE || myBlueValue != myBlueValue ) 03708 ) 03709 ) 03710 { 03711 redImageScanLine[ i ] = myDefaultColor; 03712 continue; 03713 } 03714 03715 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && 03716 ( !myRedContrastEnhancement->isValueInDisplayableRange( myRedValue ) || 03717 !myGreenContrastEnhancement->isValueInDisplayableRange( myGreenValue ) || 03718 !myBlueContrastEnhancement->isValueInDisplayableRange( myBlueValue ) ) ) 03719 { 03720 redImageScanLine[ i ] = myDefaultColor; 03721 continue; 03722 } 03723 03724 myAlphaValue = mRasterTransparency.alphaValue( myRedValue, myGreenValue, myBlueValue, mTransparencyLevel ); 03725 if ( 0 == myAlphaValue ) 03726 { 03727 redImageScanLine[ i ] = myDefaultColor; 03728 continue; 03729 } 03730 03731 if ( QgsContrastEnhancement::NoEnhancement == contrastEnhancementAlgorithm() ) 03732 { 03733 myStretchedRedValue = myRedValue; 03734 myStretchedGreenValue = myGreenValue; 03735 myStretchedBlueValue = myBlueValue; 03736 } 03737 else 03738 { 03739 myStretchedRedValue = myRedContrastEnhancement->enhanceContrast( myRedValue ); 03740 myStretchedGreenValue = myGreenContrastEnhancement->enhanceContrast( myGreenValue ); 03741 myStretchedBlueValue = myBlueContrastEnhancement->enhanceContrast( myBlueValue ); 03742 } 03743 03744 if ( mInvertColor ) 03745 { 03746 myStretchedRedValue = 255 - myStretchedRedValue; 03747 myStretchedGreenValue = 255 - myStretchedGreenValue; 03748 myStretchedBlueValue = 255 - myStretchedBlueValue; 03749 } 03750 03751 if ( myTransparencyValue ) 03752 myAlphaValue *= myTransparencyValue / 255.0; 03753 03754 redImageScanLine[ i ] = qRgba( myStretchedRedValue, myStretchedGreenValue, myStretchedBlueValue, myAlphaValue ); 03755 } 03756 } 03757 03758 if ( transparencyImageBuffer ) 03759 delete transparencyImageBuffer; 03760 } 03761 03762 void QgsRasterLayer::drawMultiBandSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03763 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03764 { 03765 //delegate to drawSingleBandGray! 03766 drawSingleBandGray( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo ); 03767 } 03768 03769 void QgsRasterLayer::drawMultiBandSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03770 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03771 { 03772 //delegate to drawSinglePseudocolor! 03773 drawSingleBandPseudoColor( theQPainter, theRasterViewPort, theQgsMapToPixel, theBandNo ); 03774 } 03775 03783 void QgsRasterLayer::drawPalettedSingleBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03784 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03785 { 03786 QgsDebugMsg( "entered." ); 03787 //Invalid band number, segfault prevention 03788 if ( 0 >= theBandNo ) 03789 { 03790 return; 03791 } 03792 03793 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 03794 bool hasTransparencyBand = 0 < myTransparencyBandNo; 03795 03796 if ( NULL == mRasterShader ) 03797 { 03798 return; 03799 } 03800 03801 int myDataType = mDataProvider->dataType( theBandNo ); 03802 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 03803 03804 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03805 imageBuffer.reset(); 03806 03807 QgsRasterImageBuffer *transparencyImageBuffer = 0; 03808 if ( hasTransparencyBand ) 03809 { 03810 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03811 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 03812 transparencyImageBuffer->reset(); 03813 } 03814 03815 QRgb* imageScanLine = 0; 03816 void* rasterScanLine = 0; 03817 QRgb* transparencyImageScanLine = 0; 03818 void* transparencyRasterScanLine = 0; 03819 03820 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 03821 double myPixelValue = 0.0; 03822 int myRedValue = 0; 03823 int myGreenValue = 0; 03824 int myBlueValue = 0; 03825 int myTransparencyValue = 0; 03826 int myAlphaValue = 0; 03827 03828 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 03829 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 03830 { 03831 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03832 { 03833 if ( transparencyImageBuffer ) 03834 { 03835 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 03836 if ( 0 == myTransparencyValue ) 03837 { 03838 imageScanLine[ i ] = myDefaultColor; 03839 continue; 03840 } 03841 } 03842 03843 myRedValue = 0; 03844 myGreenValue = 0; 03845 myBlueValue = 0; 03846 //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i ); 03847 myPixelValue = readValue( rasterScanLine, myDataType, i ); 03848 03849 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 03850 { 03851 imageScanLine[ i ] = myDefaultColor; 03852 continue; 03853 } 03854 03855 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 03856 if ( 0 == myAlphaValue ) 03857 { 03858 imageScanLine[ i ] = myDefaultColor; 03859 continue; 03860 } 03861 03862 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 03863 { 03864 imageScanLine[ i ] = myDefaultColor; 03865 continue; 03866 } 03867 03868 if ( myTransparencyValue ) 03869 myAlphaValue *= myTransparencyValue / 255.0; 03870 03871 if ( mInvertColor ) 03872 { 03873 //Invert flag, flip blue and red 03874 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 03875 } 03876 else 03877 { 03878 //Normal 03879 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 03880 } 03881 } 03882 } 03883 03884 if ( transparencyImageBuffer ) 03885 delete transparencyImageBuffer; 03886 } 03887 03895 void QgsRasterLayer::drawPalettedSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 03896 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 03897 { 03898 QgsDebugMsg( "entered." ); 03899 //Invalid band number, segfault prevention 03900 if ( 0 >= theBandNo ) 03901 { 03902 return; 03903 } 03904 03905 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 03906 bool hasTransparencyBand = 0 < myTransparencyBandNo; 03907 03908 if ( NULL == mRasterShader ) 03909 { 03910 return; 03911 } 03912 03913 int myDataType = mDataProvider->dataType( theBandNo ); 03914 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 03915 03916 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03917 imageBuffer.reset(); 03918 03919 QgsRasterImageBuffer *transparencyImageBuffer = 0; 03920 if ( hasTransparencyBand ) 03921 { 03922 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 03923 transparencyImageBuffer->setWritingEnabled( false ); //only draw to redImageBuffer 03924 transparencyImageBuffer->reset(); 03925 } 03926 03927 QRgb* imageScanLine = 0; 03928 void* rasterScanLine = 0; 03929 QRgb* transparencyImageScanLine = 0; 03930 void* transparencyRasterScanLine = 0; 03931 03932 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 03933 double myPixelValue = 0.0; 03934 int myRedValue = 0; 03935 int myGreenValue = 0; 03936 int myBlueValue = 0; 03937 int myTransparencyValue = 0; 03938 int myAlphaValue = 0; 03939 03940 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 03941 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 03942 { 03943 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 03944 { 03945 if ( transparencyImageBuffer ) 03946 { 03947 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 03948 if ( 0 == myTransparencyValue ) 03949 { 03950 imageScanLine[ i ] = myDefaultColor; 03951 continue; 03952 } 03953 } 03954 03955 myRedValue = 0; 03956 myGreenValue = 0; 03957 myBlueValue = 0; 03958 //myPixelValue = readValue( rasterScanLine, ( GDALDataType )myDataType, i ); 03959 myPixelValue = readValue( rasterScanLine, myDataType, i ); 03960 03961 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 03962 { 03963 imageScanLine[ i ] = myDefaultColor; 03964 continue; 03965 } 03966 03967 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 03968 if ( 0 == myAlphaValue ) 03969 { 03970 imageScanLine[ i ] = myDefaultColor; 03971 continue; 03972 } 03973 03974 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 03975 { 03976 imageScanLine[ i ] = myDefaultColor; 03977 continue; 03978 } 03979 03980 if ( myTransparencyValue ) 03981 myAlphaValue *= myTransparencyValue / 255.0; 03982 03983 if ( mInvertColor ) 03984 { 03985 //Invert flag, flip blue and red 03986 double myGrayValue = ( 0.3 * ( double )myRedValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myBlueValue ); 03987 imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue ); 03988 } 03989 else 03990 { 03991 //Normal 03992 double myGrayValue = ( 0.3 * ( double )myBlueValue ) + ( 0.59 * ( double )myGreenValue ) + ( 0.11 * ( double )myRedValue ); 03993 imageScanLine[ i ] = qRgba(( int )myGrayValue, ( int )myGrayValue, ( int )myGrayValue, myAlphaValue ); 03994 } 03995 } 03996 } 03997 03998 if ( transparencyImageBuffer ) 03999 delete transparencyImageBuffer; 04000 } 04001 04010 void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04011 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04012 { 04013 QgsDebugMsg( "entered." ); 04014 //Invalid band number, segfault prevention 04015 if ( 0 >= theBandNo ) 04016 { 04017 return; 04018 } 04019 04020 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04021 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04022 04023 if ( NULL == mRasterShader ) 04024 { 04025 return; 04026 } 04027 04028 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 04029 int myDataType = mDataProvider->dataType( theBandNo ); 04030 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04031 04032 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04033 imageBuffer.reset(); 04034 04035 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04036 if ( hasTransparencyBand ) 04037 { 04038 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04039 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04040 transparencyImageBuffer->reset(); 04041 } 04042 04043 QRgb* imageScanLine = 0; 04044 void* rasterScanLine = 0; 04045 QRgb* transparencyImageScanLine = 0; 04046 void* transparencyRasterScanLine = 0; 04047 04048 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04049 double myMinimumValue = 0.0; 04050 double myMaximumValue = 0.0; 04051 //Use standard deviations if set, otherwise, use min max of band 04052 if ( mStandardDeviations > 0 ) 04053 { 04054 myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04055 myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04056 } 04057 else 04058 { 04059 myMinimumValue = myRasterBandStats.minimumValue; 04060 myMaximumValue = myRasterBandStats.maximumValue; 04061 } 04062 04063 mRasterShader->setMinimumValue( myMinimumValue ); 04064 mRasterShader->setMaximumValue( myMaximumValue ); 04065 04066 double myPixelValue = 0.0; 04067 int myRedValue = 0; 04068 int myGreenValue = 0; 04069 int myBlueValue = 0; 04070 int myTransparencyValue = 0; 04071 int myAlphaValue = 0; 04072 04073 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04074 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04075 { 04076 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04077 { 04078 if ( transparencyImageBuffer ) 04079 { 04080 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04081 if ( 0 == myTransparencyValue ) 04082 { 04083 imageScanLine[ i ] = myDefaultColor; 04084 continue; 04085 } 04086 } 04087 04088 myPixelValue = readValue( rasterScanLine, myDataType, i ); 04089 04090 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 04091 { 04092 imageScanLine[ i ] = myDefaultColor; 04093 continue; 04094 } 04095 04096 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 04097 if ( 0 == myAlphaValue ) 04098 { 04099 imageScanLine[ i ] = myDefaultColor; 04100 continue; 04101 } 04102 04103 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04104 { 04105 imageScanLine[ i ] = myDefaultColor; 04106 continue; 04107 } 04108 04109 if ( myTransparencyValue ) 04110 myAlphaValue *= myTransparencyValue / 255.0; 04111 04112 if ( mInvertColor ) 04113 { 04114 //Invert flag, flip blue and red 04115 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 04116 } 04117 else 04118 { 04119 //Normal 04120 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 04121 } 04122 } 04123 } 04124 04125 if ( transparencyImageBuffer ) 04126 delete transparencyImageBuffer; 04127 } 04128 04137 void QgsRasterLayer::drawPalettedMultiBandColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04138 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04139 { 04140 QgsDebugMsg( "Not supported at this time" ); 04141 } 04142 04143 void QgsRasterLayer::drawSingleBandGray( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04144 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04145 { 04146 QgsDebugMsg( "layer=" + QString::number( theBandNo ) ); 04147 //Invalid band number, segfault prevention 04148 if ( 0 >= theBandNo ) 04149 { 04150 return; 04151 } 04152 04153 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04154 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04155 04156 int myDataType = mDataProvider->dataType( theBandNo ); 04157 QgsDebugMsg( "myDataType = " + QString::number( myDataType ) ); 04158 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04159 04160 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04161 imageBuffer.reset(); 04162 04163 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04164 if ( hasTransparencyBand ) 04165 { 04166 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04167 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04168 transparencyImageBuffer->reset(); 04169 } 04170 04171 QRgb* imageScanLine = 0; 04172 void* rasterScanLine = 0; 04173 QRgb* transparencyImageScanLine = 0; 04174 void* transparencyRasterScanLine = 0; 04175 04176 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04177 double myGrayValue = 0.0; 04178 int myGrayVal = 0; 04179 int myTransparencyValue = 0; 04180 int myAlphaValue = 0; 04181 QgsContrastEnhancement* myContrastEnhancement = contrastEnhancement( theBandNo ); 04182 04183 QgsRasterBandStats myGrayBandStats; 04184 //myGrayBandStats = bandStatistics( theBandNo ); // debug 04185 if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum && mStandardDeviations > 0 ) 04186 { 04187 mGrayMinimumMaximumEstimated = false; 04188 myGrayBandStats = bandStatistics( theBandNo ); 04189 setMaximumValue( theBandNo, myGrayBandStats.mean + ( mStandardDeviations * myGrayBandStats.stdDev ) ); 04190 setMinimumValue( theBandNo, myGrayBandStats.mean - ( mStandardDeviations * myGrayBandStats.stdDev ) ); 04191 } 04192 else if ( QgsContrastEnhancement::NoEnhancement != contrastEnhancementAlgorithm() && !mUserDefinedGrayMinimumMaximum ) 04193 { 04194 //This case will be true the first time the image is loaded, so just approimate the min max to keep 04195 //from calling generate raster band stats 04196 mGrayMinimumMaximumEstimated = true; 04197 setMaximumValue( theBandNo, mDataProvider->maximumValue( theBandNo ) ); 04198 setMinimumValue( theBandNo, mDataProvider->minimumValue( theBandNo ) ); 04199 } 04200 04201 QgsDebugMsg( " -> imageBuffer.nextScanLine" ); 04202 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04203 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04204 { 04205 //QgsDebugMsg( " rendering line"); 04206 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04207 { 04208 if ( transparencyImageBuffer ) 04209 { 04210 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04211 if ( 0 == myTransparencyValue ) 04212 { 04213 imageScanLine[ i ] = myDefaultColor; 04214 continue; 04215 } 04216 } 04217 04218 myGrayValue = readValue( rasterScanLine, myDataType, i ); 04219 //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 ").arg(i).arg( myGrayValue ) ); 04220 //if ( myGrayValue != -2147483647 ) { 04221 //QgsDebugMsg( "myGrayValue = " + QString::number( myGrayValue ) ); 04222 //} 04223 04224 if ( mValidNoDataValue && ( qAbs( myGrayValue - mNoDataValue ) <= TINY_VALUE || myGrayValue != myGrayValue ) ) 04225 { 04226 imageScanLine[ i ] = myDefaultColor; 04227 continue; 04228 } 04229 04230 if ( !myContrastEnhancement->isValueInDisplayableRange( myGrayValue ) ) 04231 { 04232 imageScanLine[ i ] = myDefaultColor; 04233 continue; 04234 } 04235 04236 myAlphaValue = mRasterTransparency.alphaValue( myGrayValue, mTransparencyLevel ); 04237 if ( 0 == myAlphaValue ) 04238 { 04239 imageScanLine[ i ] = myDefaultColor; 04240 continue; 04241 } 04242 04243 04244 myGrayVal = myContrastEnhancement->enhanceContrast( myGrayValue ); 04245 04246 if ( mInvertColor ) 04247 { 04248 myGrayVal = 255 - myGrayVal; 04249 } 04250 04251 if ( myTransparencyValue ) 04252 myAlphaValue *= myTransparencyValue / 255.0; 04253 04254 //QgsDebugMsg( QString( "i = %1 myGrayValue = %2 myGrayVal = %3 myAlphaValue = %4").arg(i).arg( myGrayValue ).arg(myGrayVal).arg(myAlphaValue) ); 04255 imageScanLine[ i ] = qRgba( myGrayVal, myGrayVal, myGrayVal, myAlphaValue ); 04256 } 04257 } 04258 04259 if ( transparencyImageBuffer ) 04260 delete transparencyImageBuffer; 04261 } // QgsRasterLayer::drawSingleBandGray 04262 04263 void QgsRasterLayer::drawSingleBandPseudoColor( QPainter * theQPainter, QgsRasterViewPort * theRasterViewPort, 04264 const QgsMapToPixel* theQgsMapToPixel, int theBandNo ) 04265 { 04266 QgsDebugMsg( "entered." ); 04267 //Invalid band number, segfault prevention 04268 if ( 0 >= theBandNo ) 04269 { 04270 return; 04271 } 04272 04273 int myTransparencyBandNo = bandNumber( mTransparencyBandName ); 04274 bool hasTransparencyBand = 0 < myTransparencyBandNo; 04275 04276 if ( NULL == mRasterShader ) 04277 { 04278 return; 04279 } 04280 04281 QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo ); 04282 int myDataType = mDataProvider->dataType( theBandNo ); 04283 int myTransparencyType = hasTransparencyBand ? mDataProvider->dataType( myTransparencyBandNo ) : 0; 04284 04285 QgsRasterImageBuffer imageBuffer( mDataProvider, theBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04286 imageBuffer.reset(); 04287 04288 QgsRasterImageBuffer *transparencyImageBuffer = 0; 04289 if ( hasTransparencyBand ) 04290 { 04291 transparencyImageBuffer = new QgsRasterImageBuffer( mDataProvider, myTransparencyBandNo, theQPainter, theRasterViewPort, theQgsMapToPixel, &mGeoTransform[0] ); 04292 transparencyImageBuffer->setWritingEnabled( false ); //only draw to imageBuffer 04293 transparencyImageBuffer->reset(); 04294 } 04295 04296 QRgb* imageScanLine = 0; 04297 void* rasterScanLine = 0; 04298 QRgb* transparencyImageScanLine = 0; 04299 void* transparencyRasterScanLine = 0; 04300 04301 QRgb myDefaultColor = qRgba( 255, 255, 255, 0 ); 04302 04303 double myMinimumValue = 0.0; 04304 double myMaximumValue = 0.0; 04305 //Use standard deviations if set, otherwise, use min max of band 04306 if ( mStandardDeviations > 0 ) 04307 { 04308 myMinimumValue = ( myRasterBandStats.mean - ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04309 myMaximumValue = ( myRasterBandStats.mean + ( mStandardDeviations * myRasterBandStats.stdDev ) ); 04310 } 04311 else 04312 { 04313 myMinimumValue = myRasterBandStats.minimumValue; 04314 myMaximumValue = myRasterBandStats.maximumValue; 04315 } 04316 04317 mRasterShader->setMinimumValue( myMinimumValue ); 04318 mRasterShader->setMaximumValue( myMaximumValue ); 04319 04320 int myRedValue = 255; 04321 int myGreenValue = 255; 04322 int myBlueValue = 255; 04323 int myTransparencyValue = 0; 04324 04325 double myPixelValue = 0.0; 04326 int myAlphaValue = 0; 04327 04328 while ( imageBuffer.nextScanLine( &imageScanLine, &rasterScanLine ) 04329 && ( !transparencyImageBuffer || transparencyImageBuffer->nextScanLine( &transparencyImageScanLine, &transparencyRasterScanLine ) ) ) 04330 { 04331 for ( int i = 0; i < theRasterViewPort->drawableAreaXDim; ++i ) 04332 { 04333 if ( transparencyImageBuffer ) 04334 { 04335 myTransparencyValue = readValue( transparencyRasterScanLine, myTransparencyType, i ); 04336 if ( 0 == myTransparencyValue ) 04337 { 04338 imageScanLine[ i ] = myDefaultColor; 04339 continue; 04340 } 04341 } 04342 04343 myPixelValue = readValue( rasterScanLine, myDataType, i ); 04344 04345 if ( mValidNoDataValue && ( qAbs( myPixelValue - mNoDataValue ) <= TINY_VALUE || myPixelValue != myPixelValue ) ) 04346 { 04347 imageScanLine[ i ] = myDefaultColor; 04348 continue; 04349 } 04350 04351 myAlphaValue = mRasterTransparency.alphaValue( myPixelValue, mTransparencyLevel ); 04352 if ( 0 == myAlphaValue ) 04353 { 04354 imageScanLine[ i ] = myDefaultColor; 04355 continue; 04356 } 04357 04358 if ( !mRasterShader->shade( myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) 04359 { 04360 imageScanLine[ i ] = myDefaultColor; 04361 continue; 04362 } 04363 04364 if ( myTransparencyValue ) 04365 myAlphaValue *= myTransparencyValue / 255.0; 04366 04367 if ( mInvertColor ) 04368 { 04369 //Invert flag, flip blue and red 04370 imageScanLine[ i ] = qRgba( myBlueValue, myGreenValue, myRedValue, myAlphaValue ); 04371 } 04372 else 04373 { 04374 //Normal 04375 imageScanLine[ i ] = qRgba( myRedValue, myGreenValue, myBlueValue, myAlphaValue ); 04376 //QgsDebugMsg ( QString ( "%1 value : %2 rgba : %3 %4 %5 %6" ).arg (i).arg( myPixelValue ).arg(myRedValue).arg(myGreenValue).arg(myBlueValue).arg(myAlphaValue) ); 04377 } 04378 } 04379 } 04380 04381 if ( transparencyImageBuffer ) 04382 delete transparencyImageBuffer; 04383 } 04384 04385 #if 0 04386 QString QgsRasterLayer::generateBandName( int theBandNumber ) 04387 { 04388 return tr( "Band" ) + QString( " %1" ) .arg( theBandNumber, 1 + ( int ) log10(( float ) bandCount() ), 10, QChar( '0' ) ); 04389 } 04390 #endif 04391 04396 bool QgsRasterLayer::hasBand( QString const & theBandName ) 04397 { 04398 //TODO: This function is no longer really needed and about be removed -- it is only used to see if "Palette" exists which is not the correct way to see if a band is paletted or not 04399 QgsDebugMsg( "Looking for band : " + theBandName ); 04400 04401 for ( int i = 1; i <= mDataProvider->bandCount(); i++ ) 04402 { 04403 QString myColorQString = mDataProvider->colorInterpretationName( i ); 04404 #ifdef QGISDEBUG 04405 QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 ); 04406 #endif 04407 04408 if ( myColorQString == theBandName ) 04409 { 04410 #ifdef QGISDEBUG 04411 QgsLogger::debug( "band", i, __FILE__, __FUNCTION__, __LINE__, 2 ); 04412 QgsDebugMsgLevel( "Found band : " + theBandName, 2 ); 04413 #endif 04414 04415 return true; 04416 } 04417 QgsDebugMsgLevel( "Found unmatched band : " + QString::number( i ) + " " + myColorQString, 2 ); 04418 } 04419 return false; 04420 } 04421 04422 QString QgsRasterLayer::projectionWkt() 04423 { 04424 // TODO: where is it used? It would be better to use crs. 04425 return mDataProvider->crs().toWkt(); 04426 } 04427 04428 /* 04429 *data type is the same as raster band. The memory must be released later! 04430 * \return pointer to the memory 04431 */ 04432 void *QgsRasterLayer::readData( int bandNo, QgsRasterViewPort *viewPort ) 04433 { 04434 int size = mDataProvider->dataTypeSize( bandNo ) / 8; 04435 04436 #if 0 04437 QgsDebugMsg( "calling RasterIO with " + 04438 QString( ", source NW corner: " ) + QString::number( viewPort->rectXOffset ) + 04439 ", " + QString::number( viewPort->rectYOffset ) + 04440 ", source size: " + QString::number( viewPort->clippedWidth ) + 04441 ", " + QString::number( viewPort->clippedHeight ) + 04442 ", dest size: " + QString::number( viewPort->drawableAreaXDim ) + 04443 ", " + QString::number( viewPort->drawableAreaYDim ) ); 04444 #endif 04445 void *data = VSIMalloc( size * viewPort->drawableAreaXDim * viewPort->drawableAreaYDim ); 04446 04447 /* Abort if out of memory */ 04448 if ( data == NULL ) 04449 { 04450 QgsDebugMsg( "Layer " + name() + " couldn't allocate enough memory. Ignoring" ); 04451 } 04452 else 04453 { 04454 // TODO: check extent 04455 QgsRectangle partExtent( 04456 viewPort->mDrawnExtent.xMinimum(), 04457 viewPort->mDrawnExtent.yMinimum(), 04458 viewPort->mDrawnExtent.xMaximum(), 04459 viewPort->mDrawnExtent.yMaximum() 04460 ); 04461 mDataProvider->readBlock( bandNo, partExtent, viewPort->drawableAreaXDim, viewPort->drawableAreaYDim, viewPort->mSrcCRS, viewPort->mDestCRS, data ); 04462 } 04463 return data; 04464 } 04465 04466 /* 04467 * @note Called from ctor if a raster image given there 04468 * 04469 * @param theFilename absolute path and filename of the raster to be loaded 04470 * @returns true if successfully read file 04471 */ 04472 bool QgsRasterLayer::readFile( QString const &theFilename ) 04473 { 04474 mValid = false; 04475 return true; 04476 } // QgsRasterLayer::readFile 04477 04478 /* 04479 * @param index index in memory block 04480 */ 04481 double QgsRasterLayer::readValue( void *data, int type, int index ) 04482 { 04483 if ( !data ) 04484 return mValidNoDataValue ? mNoDataValue : 0.0; 04485 04486 switch ( type ) 04487 { 04488 case QgsRasterDataProvider::Byte: 04489 return ( double )(( GByte * )data )[index]; 04490 break; 04491 case QgsRasterDataProvider::UInt16: 04492 return ( double )(( GUInt16 * )data )[index]; 04493 break; 04494 case QgsRasterDataProvider::Int16: 04495 return ( double )(( GInt16 * )data )[index]; 04496 break; 04497 case QgsRasterDataProvider::UInt32: 04498 return ( double )(( GUInt32 * )data )[index]; 04499 break; 04500 case QgsRasterDataProvider::Int32: 04501 return ( double )(( GInt32 * )data )[index]; 04502 break; 04503 case QgsRasterDataProvider::Float32: 04504 return ( double )(( float * )data )[index]; 04505 break; 04506 case QgsRasterDataProvider::Float64: 04507 return ( double )(( double * )data )[index]; 04508 break; 04509 default: 04510 QgsLogger::warning( "GDAL data type is not supported" ); 04511 } 04512 04513 return mValidNoDataValue ? mNoDataValue : 0.0; 04514 } 04515 04516 bool QgsRasterLayer::update() 04517 { 04518 QgsDebugMsg( "entered." ); 04519 // Check if data changed 04520 if ( mDataProvider->dataTimestamp() > mDataProvider->timestamp() ) 04521 { 04522 QgsDebugMsg( "reload data" ); 04523 closeDataProvider(); 04524 init(); 04525 setDataProvider( mProviderKey, mLayers, mStyles, mFormat, mCrs ); 04526 emit dataChanged(); 04527 } 04528 return mValid; 04529 } 04530 04531 bool QgsRasterLayer::usesProvider() 04532 { 04533 return !mProviderKey.isEmpty(); 04534 } 04535 04536 QString QgsRasterLayer::validateBandName( QString const & theBandName ) 04537 { 04538 QgsDebugMsg( "Checking..." ); 04539 //check if the band is unset 04540 if ( theBandName == TRSTRING_NOT_SET || theBandName == QSTRING_NOT_SET ) 04541 { 04542 QgsDebugMsg( "Band name is '" + QSTRING_NOT_SET + "'. Nothing to do." ); 04543 // Use translated name internally 04544 return TRSTRING_NOT_SET; 04545 } 04546 04547 //check that a valid band name was passed 04548 QgsDebugMsg( "Looking through raster band stats for matching band name" ); 04549 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 04550 { 04551 //find out the name of this band 04552 if ( mRasterStatsList[myIterator].bandName == theBandName ) 04553 { 04554 QgsDebugMsg( "Matching band name found" ); 04555 return theBandName; 04556 } 04557 } 04558 QgsDebugMsg( "No matching band name found in raster band stats" ); 04559 04560 QgsDebugMsg( "Testing for non zero-buffered names" ); 04561 //TODO Remove test in v2.0 or earlier 04562 QStringList myBandNameComponents = theBandName.split( " " ); 04563 if ( myBandNameComponents.size() == 2 ) 04564 { 04565 int myBandNumber = myBandNameComponents.at( 1 ).toInt(); 04566 if ( myBandNumber > 0 ) 04567 { 04568 QString myBandName = mDataProvider->generateBandName( myBandNumber ); 04569 for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator ) 04570 { 04571 //find out the name of this band 04572 if ( mRasterStatsList[myIterator].bandName == myBandName ) 04573 { 04574 QgsDebugMsg( "Matching band name found" ); 04575 return myBandName; 04576 } 04577 } 04578 } 04579 } 04580 04581 QgsDebugMsg( "Testing older naming format" ); 04582 //See of the band in an older format #:something. 04583 //TODO Remove test in v2.0 or earlier 04584 myBandNameComponents.clear(); 04585 if ( theBandName.contains( ':' ) ) 04586 { 04587 myBandNameComponents = theBandName.split( ":" ); 04588 if ( myBandNameComponents.size() == 2 ) 04589 { 04590 int myBandNumber = myBandNameComponents.at( 0 ).toInt(); 04591 if ( myBandNumber > 0 ) 04592 { 04593 QgsDebugMsg( "Transformed older name format to current format" ); 04594 return "Band " + QString::number( myBandNumber ); 04595 } 04596 } 04597 } 04598 04599 //if no matches were found default to not set 04600 QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" ); 04601 return TRSTRING_NOT_SET; 04602 } 04603 04604 QgsRasterImageBuffer::QgsRasterImageBuffer( QgsRasterDataProvider *dataProvider, int bandNo, QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* mapToPixel, double* geoTransform ): 04605 mDataProvider( dataProvider ), mBandNo( bandNo ), mPainter( p ), mViewPort( viewPort ), mMapToPixel( mapToPixel ), mGeoTransform( geoTransform ), mValid( false ), mWritingEnabled( true ), mDrawPixelRect( false ), mCurrentImage( 0 ), mCurrentGDALData( 0 ) 04606 { 04607 04608 } 04609 04610 QgsRasterImageBuffer::~QgsRasterImageBuffer() 04611 { 04612 delete mCurrentImage; 04613 CPLFree( mCurrentGDALData ); 04614 } 04615 04616 void QgsRasterImageBuffer::reset( int maxPixelsInVirtualMemory ) 04617 { 04618 QgsDebugMsg( "Start" ); 04619 //if ( !mRasterBand || !mPainter || !mViewPort ) 04620 if ( !mDataProvider || mBandNo <= 0 || !mPainter || !mViewPort ) 04621 { 04622 mValid = false; 04623 return; 04624 } 04625 04626 mValid = true; 04627 04628 //decide on the partition of the image 04629 04630 int pixels = mViewPort->drawableAreaXDim * mViewPort->drawableAreaYDim; 04631 int mNumPartImages = pixels / maxPixelsInVirtualMemory + 1.0; 04632 mNumRasterRowsPerPart = ( double )mViewPort->drawableAreaYDim / ( double )mNumPartImages + 0.5; 04633 04634 mCurrentPartRasterMin = -1; 04635 mCurrentPartRasterMax = -1; 04636 mCurrentPartImageRow = 0; 04637 mNumCurrentImageRows = 0; 04638 04639 mCurrentPart = 0; 04640 04641 createNextPartImage(); 04642 04643 // TODO 04644 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04645 if ( false ) 04646 { 04647 //use Peter's fix for zoomed in rasters 04648 mDrawPixelRect = true; 04649 } 04650 } 04651 04652 bool QgsRasterImageBuffer::nextScanLine( QRgb** imageScanLine, void** rasterScanLine ) 04653 { 04654 //QgsDebugMsg( "mCurrentRow = " + QString::number( mCurrentRow ) ); 04655 if ( !mValid ) 04656 return false; 04657 04658 if ( !mCurrentImage && !mCurrentGDALData ) 04659 { 04660 return false; 04661 } 04662 04663 if ( mCurrentPartImageRow >= mNumCurrentImageRows ) 04664 { 04665 if ( !createNextPartImage() ) 04666 { 04667 return false; 04668 } 04669 } 04670 04671 if ( mWritingEnabled ) 04672 { 04673 *imageScanLine = ( QRgb* ) mCurrentImage->scanLine( mCurrentPartImageRow ); 04674 } 04675 else 04676 { 04677 *imageScanLine = 0; 04678 } 04679 int size = mDataProvider->dataTypeSize( mBandNo ) / 8; 04680 *rasterScanLine = ( unsigned char * )mCurrentGDALData + mCurrentPartImageRow * mViewPort->drawableAreaXDim * size; 04681 04682 ++mCurrentPartImageRow; 04683 ++mCurrentRow; 04684 return !mWritingEnabled || *imageScanLine; 04685 } 04686 04687 bool QgsRasterImageBuffer::createNextPartImage() 04688 { 04689 QgsDebugMsg( "Entered" ); 04690 //draw the last image if mCurrentImage exists 04691 if ( mCurrentImage ) 04692 { 04693 if ( mWritingEnabled ) 04694 { 04695 // TODO: consider similar system with raster providers, see the comment 04696 // in QgsRasterImageBuffer::drawPixelRectangle() 04697 // e.g request the block with raster resolution and draw pixels as rectangles 04698 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04699 if ( false ) 04700 { 04701 drawPixelRectangle(); 04702 } 04703 else 04704 { 04705 //int paintXoffset = 0; 04706 //int paintYoffset = 0; 04707 double imageX = 0; 04708 double imageY = 0; 04709 04710 if ( mMapToPixel ) 04711 { 04712 imageX = mViewPort->topLeftPoint.x(); 04713 imageY = mViewPort->topLeftPoint.y() + mCurrentPartRasterMin; 04714 } 04715 04716 QgsDebugMsg( QString( "mCurrentPartRasterMin = %1" ).arg( mCurrentPartRasterMin ) ); 04717 QgsDebugMsg( QString( "imageX = %1 imageY = %2" ).arg( imageX ).arg( imageY ) ); 04718 mPainter->drawImage( QPointF( imageX, imageY ), //the top-left point in the paint device 04719 *mCurrentImage ); 04720 } 04721 } 04722 } 04723 04724 delete mCurrentImage; mCurrentImage = 0; 04725 CPLFree( mCurrentGDALData ); mCurrentGDALData = 0; 04726 04727 mCurrentPart++; // NEW 04728 QgsDebugMsg( QString( "mCurrentPartRasterMax = %1 mViewPort->drawableAreaYDim = %2" ).arg( mCurrentPartRasterMax ).arg( mViewPort->drawableAreaYDim ) ); 04729 if ( mCurrentPartRasterMax >= mViewPort->drawableAreaYDim ) 04730 { 04731 return false; //already at the end... 04732 } 04733 04734 mCurrentPartRasterMin = mCurrentPartRasterMax + 1; 04735 mCurrentPartRasterMax = mCurrentPartRasterMin + mNumRasterRowsPerPart; 04736 if ( mCurrentPartRasterMax > mViewPort->drawableAreaYDim ) 04737 { 04738 mCurrentPartRasterMax = mViewPort->drawableAreaYDim; 04739 } 04740 mCurrentRow = mCurrentPartRasterMin; 04741 mCurrentPartImageRow = 0; 04742 04743 //read GDAL image data 04744 int size = mDataProvider->dataTypeSize( mBandNo ) / 8 ; 04745 int xSize = mViewPort->drawableAreaXDim; 04746 int ySize = mViewPort->drawableAreaYDim; 04747 04748 //make the raster tiles overlap at least 2 pixels to avoid white stripes 04749 int overlapRows = 0; 04750 if ( mMapToPixel ) 04751 { 04752 // TODO: do we still need overlaps? 04753 overlapRows = mMapToPixel->mapUnitsPerPixel() / qAbs( mGeoTransform[5] ) + 2; 04754 } 04755 //if ( mCurrentPartRasterMax + overlapRows >= mViewPort->clippedHeight ) 04756 if ( mCurrentPartRasterMax + overlapRows >= mViewPort->drawableAreaYDim ) 04757 { 04758 overlapRows = 0; 04759 } 04760 int rasterYSize = mCurrentPartRasterMax - mCurrentPartRasterMin + overlapRows; 04761 QgsDebugMsg( "rasterYSize = " + QString::number( rasterYSize ) ); 04762 04763 // TODO: consider something like this 04764 //if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) //for zoomed in rasters 04765 if ( false ) 04766 { 04767 //rasterYSize = mViewPort->clippedHeight; 04768 //ySize = mViewPort->drawableAreaYDim; 04769 } 04770 else //normal mode 04771 { 04772 if ( mMapToPixel ) 04773 { 04774 // makes no more sense 04775 //ySize = qAbs((( rasterYSize ) / mMapToPixel->mapUnitsPerPixel() * mGeoTransform[5] ) ) + 0.5; 04776 } 04777 } 04778 QgsDebugMsg( QString( "xSize = %1 ySize = %2" ).arg( xSize ).arg( ySize ) ); 04779 if ( ySize < 1 || xSize < 1 ) 04780 { 04781 return false; 04782 } 04783 mNumCurrentImageRows = rasterYSize; 04784 QgsDebugMsg( "alloc " + QString::number( size * xSize * rasterYSize ) ); 04785 mCurrentGDALData = VSIMalloc( size * xSize * rasterYSize ); 04786 04787 double yMax = mViewPort->mDrawnExtent.yMaximum() - mCurrentRow * mMapToPixel->mapUnitsPerPixel(); 04788 double yMin = yMax - rasterYSize * mMapToPixel->mapUnitsPerPixel(); 04789 04790 QgsDebugMsg( QString( "mCurrentRow = %1 yMaximum = %2 ySize = %3 mapUnitsPerPixel = %4" ).arg( mCurrentRow ).arg( mViewPort->mDrawnExtent.yMaximum() ).arg( ySize ).arg( mMapToPixel->mapUnitsPerPixel() ) ); 04791 QgsRectangle myPartExtent( mViewPort->mDrawnExtent.xMinimum(), yMin, 04792 mViewPort->mDrawnExtent.xMaximum(), yMax ); 04793 QgsDebugMsg( "myPartExtent is " + myPartExtent.toString() ); 04794 mDataProvider->readBlock( mBandNo, myPartExtent, xSize, rasterYSize , mViewPort->mSrcCRS, mViewPort->mDestCRS, mCurrentGDALData ); 04795 04796 //create the QImage 04797 if ( mWritingEnabled ) 04798 { 04799 mCurrentImage = new QImage( xSize, ySize, QImage::Format_ARGB32 ); 04800 mCurrentImage->fill( qRgba( 255, 255, 255, 0 ) ); 04801 } 04802 else 04803 { 04804 mCurrentImage = 0; 04805 } 04806 return true; 04807 } 04808 04809 void QgsRasterImageBuffer::drawPixelRectangle() 04810 { 04811 // TODO: consider using similar with raster providers, originaly it was used only with 04812 // 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight 04813 // but why? but I believe that it should be used always if the ration of original 04814 // raster resolution and device resolution is under certain limit 04815 #if 0 04816 // Set up the initial offset into the myQImage we want to copy to the map canvas 04817 // This is useful when the source image pixels are larger than the screen image. 04818 int paintXoffset = 0; 04819 int paintYoffset = 0; 04820 04821 if ( mMapToPixel ) 04822 { 04823 paintXoffset = static_cast<int>( 04824 ( mViewPort->rectXOffsetFloat - 04825 mViewPort->rectXOffset ) 04826 / mMapToPixel->mapUnitsPerPixel() 04827 * qAbs( mGeoTransform[1] ) 04828 ); 04829 04830 paintYoffset = static_cast<int>( 04831 ( mViewPort->rectYOffsetFloat - 04832 mViewPort->rectYOffset ) 04833 / mMapToPixel->mapUnitsPerPixel() 04834 * qAbs( mGeoTransform[5] ) 04835 ); 04836 04837 04838 } 04839 04840 //fix for zoomed in rasters 04841 //Catch special rendering cases 04842 //INSTANCE: 1x1 04843 if ( 1 == mViewPort->clippedWidth && 1 == mViewPort->clippedHeight ) 04844 { 04845 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 04846 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 04847 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04848 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04849 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04850 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04851 QBrush( myColor ) ); 04852 } 04853 //1x2, 2x1 or 2x2 04854 else if ( 2 >= mViewPort->clippedWidth && 2 >= mViewPort->clippedHeight ) 04855 { 04856 int myPixelBoundaryX = 0; 04857 int myPixelBoundaryY = 0; 04858 if ( mMapToPixel ) 04859 { 04860 myPixelBoundaryX = static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[1] / mMapToPixel->mapUnitsPerPixel() ) ) - paintXoffset; 04861 myPixelBoundaryY = static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ) + static_cast<int>( qAbs( mGeoTransform[5] / mMapToPixel->mapUnitsPerPixel() ) ) - paintYoffset; 04862 } 04863 04864 //INSTANCE: 1x2 04865 if ( 1 == mViewPort->clippedWidth ) 04866 { 04867 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 04868 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 04869 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04870 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04871 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04872 static_cast<int>( myPixelBoundaryY ), 04873 QBrush( myColor ) ); 04874 myColor = QColor( mCurrentImage->pixel( 0, 1 ) ); 04875 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) ); 04876 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04877 static_cast<int>( myPixelBoundaryY ), 04878 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04879 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04880 QBrush( myColor ) ); 04881 } 04882 else 04883 { 04884 //INSTANCE: 2x1 04885 if ( 1 == mViewPort->clippedHeight ) 04886 { 04887 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 04888 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 04889 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04890 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04891 static_cast<int>( myPixelBoundaryX ), 04892 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04893 QBrush( myColor ) ); 04894 myColor = QColor( mCurrentImage->pixel( 1, 0 ) ); 04895 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) ); 04896 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 04897 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04898 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04899 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04900 QBrush( myColor ) ); 04901 } 04902 //INSTANCE: 2x2 04903 else 04904 { 04905 QColor myColor( mCurrentImage->pixel( 0, 0 ) ); 04906 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 0 ) ) ); 04907 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04908 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04909 static_cast<int>( myPixelBoundaryX ), 04910 static_cast<int>( myPixelBoundaryY ), 04911 QBrush( myColor ) ); 04912 myColor = QColor( mCurrentImage->pixel( 1, 0 ) ); 04913 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 0 ) ) ); 04914 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 04915 static_cast<int>( mViewPort->topLeftPoint.y() + 0.5 ), 04916 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04917 static_cast<int>( myPixelBoundaryY ), 04918 QBrush( myColor ) ); 04919 myColor = QColor( mCurrentImage->pixel( 0, 1 ) ); 04920 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 0, 1 ) ) ); 04921 mPainter->fillRect( static_cast<int>( mViewPort->topLeftPoint.x() + 0.5 ), 04922 static_cast<int>( myPixelBoundaryY ), 04923 static_cast<int>( myPixelBoundaryX ), 04924 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04925 QBrush( myColor ) ); 04926 myColor = QColor( mCurrentImage->pixel( 1, 1 ) ); 04927 myColor.setAlpha( qAlpha( mCurrentImage->pixel( 1, 1 ) ) ); 04928 mPainter->fillRect( static_cast<int>( myPixelBoundaryX ), 04929 static_cast<int>( myPixelBoundaryY ), 04930 static_cast<int>( mViewPort->bottomRightPoint.x() ), 04931 static_cast<int>( mViewPort->bottomRightPoint.y() ), 04932 QBrush( myColor ) ); 04933 } 04934 } 04935 } 04936 #endif 04937 } 04938 04939 // Keep this for now, it is used by Python interface!!! 04940 void QgsRasterLayer::registerGdalDrivers() 04941 { 04942 if ( GDALGetDriverCount() == 0 ) 04943 GDALAllRegister(); 04944 } 04945 04946 // Keep this for QgsRasterLayerProperties 04947 bool QgsRasterLayer::readColorTable( int theBandNumber, QList<QgsColorRampShader::ColorRampItem>* theList ) 04948 { 04949 // TODO : check if exists - returned vale? 04950 QList<QgsColorRampShader::ColorRampItem> myColorRampItemList = mDataProvider->colorTable( theBandNumber ); 04951 if ( myColorRampItemList.size() == 0 ) 04952 { 04953 return false; 04954 } 04955 *theList = myColorRampItemList; 04956 return true; 04957 } 04958