From 5965b8b7e36ed9a08b8bb47e8cf2c99dfe4a3318 Mon Sep 17 00:00:00 2001 From: timlinux Date: Wed, 21 Jan 2004 08:33:53 +0000 Subject: [PATCH] Fixed a stupid bug causing a segfault in hasBand() method. Added a short circuit to calculate stats loop to prevent repeating stats gathering when it has already been done before. git-svn-id: http://svn.osgeo.org/qgis/trunk@546 c8812cc2-4d05-0410-92ff-de0c093fc19c --- src/qgsrasterlayer.cpp | 276 ++++++++++++++++++++--------------------- src/qgsrasterlayer.h | 7 ++ 2 files changed, 143 insertions(+), 140 deletions(-) diff --git a/src/qgsrasterlayer.cpp b/src/qgsrasterlayer.cpp index 9fbee13a19a..2836375684a 100644 --- a/src/qgsrasterlayer.cpp +++ b/src/qgsrasterlayer.cpp @@ -154,7 +154,7 @@ QgsRasterLayer::~QgsRasterLayer() void QgsRasterLayer::showLayerProperties() { QgsRasterLayerProperties *myRasterLayerProperties = new QgsRasterLayerProperties(this); - + } // emit a signal asking for a repaint void QgsRasterLayer::triggerRepaint() @@ -187,12 +187,14 @@ bool QgsRasterLayer::hasBand(QString theBandName) { GDALRasterBand *myGdalBand = gdalDataset->GetRasterBand( i ); QString myColorQString = GDALGetColorInterpretationName(myGdalBand->GetColorInterpretation()); + std::cout << "band : " << i << std::endl; if (myColorQString==theBandName) { + std::cout << "band : " << i << std::endl; std::cout << "Found band : " << theBandName << std::endl; return true; } - std::cout << "Found unmatched band : " << myIterator.key().latin1() << std::endl; + std::cout << "Found unmatched band : " << i << " " << myColorQString << std::endl; } return false; } @@ -993,28 +995,33 @@ void QgsRasterLayer::calculateStats(QString theBandNameQString) RasterBandStats myRasterBandStats; GDALRasterBand *myGdalBand = gdalDataset->GetRasterBand( i ); QString myColorInterpretation = GDALGetColorInterpretationName(myGdalBand->GetColorInterpretation()); - //see if we are calculating all bands or just a particular band - if (theBandNameQString=="" || - myColorInterpretation==theBandNameQString || - (myColorInterpretation=="Palette" && - ( theBandNameQString=="Red" || + //Decide if we want to process this band... + if (theBandNameQString=="" || //process if no band name was passed to this fn + myColorInterpretation==theBandNameQString || //process if theband name passed to fn matches this band + (myColorInterpretation=="Palette" && //process if the current band is palette and the band name + ( theBandNameQString=="Red" || //passed to this fn is red, green or blue theBandNameQString=="Green" || theBandNameQString=="Blue" ) ) ) { - + //check if we have previously gathered stats for this band... + rasterStatsMap[myColorInterpretation]; + //declare a colorTable to hold a palette - will only be used of the layer color interp is palette GDALColorTable *colorTable; if ( myColorInterpretation=="Palette" ) { + //check if we have previously gathered stats for this band... + RasterBandStats myTempRasterBandrStats = rasterStatsMap[theBandNameQString]; + if (myTempRasterBandrStats.statsGatheredFlag) continue; //should revert to outer loop if true colorTable = myGdalBand->GetColorTable(); - myRasterBandStats.bandName=theBandNameQString; + myRasterBandStats.bandName=theBandNameQString; } - else - { + else + { myRasterBandStats.bandName=myColorInterpretation; - } + } myRasterBandStats.bandNo=i; std::cout << "Getting stats for band " << i << " (" << myColorInterpretation << ")" << std::endl; // get the dimensions of the raster @@ -1023,143 +1030,132 @@ void QgsRasterLayer::calculateStats(QString theBandNameQString) myRasterBandStats.elementCountInt=myColsInt*myRowsInt; myRasterBandStats.noDataDouble=myGdalBand->GetNoDataValue(); - //avoid collecting stats for rgb images for now - if (myColorInterpretation=="Gray" || - myColorInterpretation=="Undefined" || - (myColorInterpretation=="Palette" && - ( theBandNameQString=="Red" || - theBandNameQString=="Green" || - theBandNameQString=="Blue" - ) - ) - ) + + //allocate a buffer to hold one row of ints + int myAllocationSizeInt = sizeof(uint)*myColsInt; + uint * myScanlineAllocInt = (uint*) CPLMalloc(myAllocationSizeInt); + bool myFirstIterationFlag = true; + //unfortunately we need to make two passes through the data to calculate stddev + for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++) { - //allocate a buffer to hold one row of ints - int myAllocationSizeInt = sizeof(uint)*myColsInt; - uint * myScanlineAllocInt = (uint*) CPLMalloc(myAllocationSizeInt); - bool myFirstIterationFlag = true; - //unfortunately we need to make two passes through the data to calculate stddev - for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++) + CPLErr myResult = myGdalBand->RasterIO( + GF_Read, 0, myCurrentRowInt, myColsInt, 1, myScanlineAllocInt, myColsInt, 1, GDT_UInt32, 0, 0 ); + for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++) { - CPLErr myResult = myGdalBand->RasterIO( - GF_Read, 0, myCurrentRowInt, myColsInt, 1, myScanlineAllocInt, myColsInt, 1, GDT_UInt32, 0, 0 ); - for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++) + double myDouble=0; + //get the nth element from the current row + if (myColorInterpretation!="Palette") { - double myDouble=0; - //get the nth element from the current row - if (myColorInterpretation!="Palette") + myDouble=myScanlineAllocInt[myCurrentColInt]; + } + else + { + //this is a palette layer so red / green / blue 'layers are 'virtual' + //in that we need to obtain the palette entry and then get the r,g or g + //component from that palette entry + const GDALColorEntry *myColorEntry = GDALGetColorEntry(colorTable,myScanlineAllocInt[myCurrentColInt]); + //check colorEntry is valid + if (myColorEntry!=NULL) { - myDouble=myScanlineAllocInt[myCurrentColInt]; + //check for alternate color mappings + if (theBandNameQString=="Red") + { + myDouble=static_cast (myColorEntry->c1); + } + if (theBandNameQString=="Green") + { + myDouble=static_cast (myColorEntry->c2); + } + if (theBandNameQString=="Blue") + { + myDouble=static_cast (myColorEntry->c3); + } } + + + } + //only use this element if we have a non null element + if (myDouble != myRasterBandStats.noDataDouble ) + { + if (myFirstIterationFlag) + { + //this is the first iteration so initialise vars + myFirstIterationFlag=false; + myRasterBandStats.minValDouble=myDouble; + myRasterBandStats.maxValDouble=myDouble; + } //end of true part for first iteration check else { - //this is a palette layer so red / green / blue 'layers are 'virtual' - //in that we need to obtain the palette entry and then get the r,g or g - //component from that palette entry - const GDALColorEntry *myColorEntry = GDALGetColorEntry(colorTable,myScanlineAllocInt[myCurrentColInt]); - //check colorEntry is valid - if (myColorEntry!=NULL) + //this is done for all subsequent iterations + if (myDouble < myRasterBandStats.minValDouble) { - //check for alternate color mappings - if (theBandNameQString=="Red") - { - myDouble=static_cast (myColorEntry->c1); - } - if (theBandNameQString=="Green") - { - myDouble=static_cast (myColorEntry->c2); - } - if (theBandNameQString=="Blue") - { - myDouble=static_cast (myColorEntry->c3); - } - } - - - } - //only use this element if we have a non null element - if (myDouble != myRasterBandStats.noDataDouble ) - { - if (myFirstIterationFlag) - { - //this is the first iteration so initialise vars - myFirstIterationFlag=false; myRasterBandStats.minValDouble=myDouble; - myRasterBandStats.maxValDouble=myDouble; - } //end of true part for first iteration check - else - { - //this is done for all subsequent iterations - if (myDouble < myRasterBandStats.minValDouble) - { - myRasterBandStats.minValDouble=myDouble; - } - if (myDouble > myRasterBandStats.maxValDouble) - { - myRasterBandStats.maxValDouble=myDouble; - } - //only increment the running total if it is not a nodata value - if (myDouble != myRasterBandStats.noDataDouble) - { - myRasterBandStats.sumDouble += myDouble; - ++myRasterBandStats.elementCountInt; - } - } //end of false part for first iteration check - } //end of nodata chec - } //end of column wise loop - } //end of row wise loop - // - //end of first pass through data now calculate the range - myRasterBandStats.rangeDouble = myRasterBandStats.maxValDouble-myRasterBandStats.minValDouble; - //calculate the mean - myRasterBandStats.meanDouble = myRasterBandStats.sumDouble / myRasterBandStats.elementCountInt; - //for the second pass we will get the sum of the squares / mean - for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++) - { - CPLErr myResult = myGdalBand->RasterIO( - GF_Read, 0, myCurrentRowInt, myColsInt, 1, myScanlineAllocInt, myColsInt, 1, GDT_UInt32, 0, 0 ); - for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++) - { - double myDouble=0; - //get the nth element from the current row - if (myColorInterpretation!="Palette") - { - myDouble=myScanlineAllocInt[myCurrentColInt]; - } - else - { - //this is a palette layer so red / green / blue 'layers are 'virtual' - //in that we need to obtain the palette entry and then get the r,g or g - //component from that palette entry - const GDALColorEntry *myColorEntry = GDALGetColorEntry(colorTable,myScanlineAllocInt[myCurrentColInt]); - //check colorEntry is valid - if (myColorEntry!=NULL) - { - //check for alternate color mappings - if (theBandNameQString=="Red") - { - myDouble=myColorEntry->c1; - } - if (theBandNameQString=="Green") - { - myDouble=myColorEntry->c2; - } - if (theBandNameQString=="Blue") - { - myDouble=myColorEntry->c3; - } } - - + if (myDouble > myRasterBandStats.maxValDouble) + { + myRasterBandStats.maxValDouble=myDouble; + } + //only increment the running total if it is not a nodata value + if (myDouble != myRasterBandStats.noDataDouble) + { + myRasterBandStats.sumDouble += myDouble; + ++myRasterBandStats.elementCountInt; + } + } //end of false part for first iteration check + } //end of nodata chec + } //end of column wise loop + } //end of row wise loop + // + //end of first pass through data now calculate the range + myRasterBandStats.rangeDouble = myRasterBandStats.maxValDouble-myRasterBandStats.minValDouble; + //calculate the mean + myRasterBandStats.meanDouble = myRasterBandStats.sumDouble / myRasterBandStats.elementCountInt; + //for the second pass we will get the sum of the squares / mean + for (int myCurrentRowInt=0; myCurrentRowInt < myRowsInt;myCurrentRowInt++) + { + CPLErr myResult = myGdalBand->RasterIO( + GF_Read, 0, myCurrentRowInt, myColsInt, 1, myScanlineAllocInt, myColsInt, 1, GDT_UInt32, 0, 0 ); + for (int myCurrentColInt=0; myCurrentColInt < myColsInt; myCurrentColInt++) + { + double myDouble=0; + //get the nth element from the current row + if (myColorInterpretation!="Palette") + { + myDouble=myScanlineAllocInt[myCurrentColInt]; + } + else + { + //this is a palette layer so red / green / blue 'layers are 'virtual' + //in that we need to obtain the palette entry and then get the r,g or g + //component from that palette entry + const GDALColorEntry *myColorEntry = GDALGetColorEntry(colorTable,myScanlineAllocInt[myCurrentColInt]); + //check colorEntry is valid + if (myColorEntry!=NULL) + { + //check for alternate color mappings + if (theBandNameQString=="Red") + { + myDouble=myColorEntry->c1; + } + if (theBandNameQString=="Green") + { + myDouble=myColorEntry->c2; + } + if (theBandNameQString=="Blue") + { + myDouble=myColorEntry->c3; + } } - myRasterBandStats.sumSqrDevDouble += static_cast(pow(myDouble - myRasterBandStats.meanDouble,2)); - } //end of column wise loop - } //end of row wise loop - //divide result by sample size - 1 and get square root to get stdev - myRasterBandStats.stdDevDouble = static_cast(sqrt(myRasterBandStats.sumSqrDevDouble / - (myRasterBandStats.elementCountInt - 1))); - CPLFree(myScanlineAllocInt); - }//end of gray / undefined raster color interp check + + + } + myRasterBandStats.sumSqrDevDouble += static_cast(pow(myDouble - myRasterBandStats.meanDouble,2)); + } //end of column wise loop + } //end of row wise loop + //divide result by sample size - 1 and get square root to get stdev + myRasterBandStats.stdDevDouble = static_cast(sqrt(myRasterBandStats.sumSqrDevDouble / + (myRasterBandStats.elementCountInt - 1))); + CPLFree(myScanlineAllocInt); //add this band to the class stats map rasterStatsMap[myColorInterpretation]=myRasterBandStats; }//end of "" / bandNameQString check @@ -1342,8 +1338,8 @@ QPixmap QgsRasterLayer::getLegendQPixmap() myDouble+=myAdjustedRasterBandStats.rangeDouble/100) { if (drawingStyle!=MULTI_BAND_SINGLE_BAND_PSEUDO_COLOR && - drawingStyle!=PALETTED_SINGLE_BAND_PSEUDO_COLOR && - drawingStyle!=SINGLE_BAND_PSEUDO_COLOR) + drawingStyle!=PALETTED_SINGLE_BAND_PSEUDO_COLOR && + drawingStyle!=SINGLE_BAND_PSEUDO_COLOR) { //draw legend as grayscale int myGrayInt = static_cast((255/myAdjustedRasterBandStats.rangeDouble) * myDouble); diff --git a/src/qgsrasterlayer.h b/src/qgsrasterlayer.h index e7f45badd6a..cd8ff0428d2 100644 --- a/src/qgsrasterlayer.h +++ b/src/qgsrasterlayer.h @@ -66,6 +66,7 @@ class GDALRasterBand; struct RasterBandStats { QString bandName; + bool statsGatheredFlag; //use so we can only gather stats once for a layer int bandNo; double minValDouble; double maxValDouble; @@ -299,6 +300,12 @@ public: void setRasterLayerType( RASTER_LAYER_TYPE theRasterLayerType ) { rasterLayerType=theRasterLayerType; }; //get a legend image for this layer QPixmap getLegendQPixmap(); + //similar to above but returns a pointer. Implemented for qgsmaplayer interface + QPixmap * legendPixmap() + { + QPixmap myQPixmap = getLegendQPixmap(); + return new QPixmap(myQPixmap); + }; // emit a signal asking for a repaint void triggerRepaint();