@@ -510,6 +510,9 @@ QImage* QgsGdalProvider::draw( QgsRectangle const & viewExtent, int pixelWidth,
510
510
511
511
void QgsGdalProvider::readBlock ( int theBandNo, int xBlock, int yBlock, void *block )
512
512
{
513
+ // TODO!!!: Check data alignment!!! May it happen that nearest value which
514
+ // is not nearest is assigned to an output cell???
515
+
513
516
QgsDebugMsg ( " Entered" );
514
517
515
518
QgsDebugMsg ( " yBlock = " + QString::number ( yBlock ) );
@@ -528,7 +531,165 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
528
531
QgsDebugMsg ( " thePixelWidth = " + QString::number ( thePixelWidth ) );
529
532
QgsDebugMsg ( " thePixelHeight = " + QString::number ( thePixelHeight ) );
530
533
QgsDebugMsg ( " theExtent: " + theExtent.toString () );
531
- QgsDebugMsg ( " crs(): " + crs ().toWkt () );
534
+
535
+ // TODO: fill block with no data values
536
+
537
+ QgsRectangle myRasterExtent = theExtent.intersect ( &mExtent );
538
+ if ( myRasterExtent.isEmpty () )
539
+ {
540
+ QgsDebugMsg ( " draw request outside view extent." );
541
+ return ;
542
+ }
543
+ QgsDebugMsg ( " myRasterExtent: " + myRasterExtent.toString () );
544
+
545
+ double xRes = theExtent.width ()/thePixelWidth;
546
+ double yRes = theExtent.height ()/thePixelHeight;
547
+
548
+ // Find top, bottom rows and left, right column the raster extent covers
549
+ // These are limits in target grid space
550
+ int top = 0 ;
551
+ int bottom = thePixelHeight-1 ;
552
+ int left = 0 ;
553
+ int right = thePixelWidth-1 ;
554
+
555
+ if ( myRasterExtent.yMaximum () < theExtent.yMaximum () )
556
+ {
557
+ top = static_cast <int > ( round ( ( theExtent.yMaximum () - myRasterExtent.yMaximum () ) / yRes ) );
558
+ }
559
+ if ( myRasterExtent.yMinimum () > theExtent.yMinimum () )
560
+ {
561
+ bottom = static_cast <int > ( round ( ( theExtent.yMaximum () - myRasterExtent.yMinimum () ) / yRes ) - 1 );
562
+ }
563
+
564
+ if ( myRasterExtent.xMinimum () > theExtent.xMinimum () )
565
+ {
566
+ left = static_cast <int > ( round ( ( myRasterExtent.xMinimum () - theExtent.xMinimum () ) / xRes ) );
567
+ }
568
+ if ( myRasterExtent.xMaximum () < theExtent.xMaximum () )
569
+ {
570
+ right = static_cast <int > ( round ( ( myRasterExtent.xMaximum () - theExtent.xMinimum () ) / xRes ) - 1 );
571
+ }
572
+ QgsDebugMsg ( QString (" top = %1 bottom = %2 left = %3 right = %4" ).arg (top).arg (bottom).arg (left).arg (right) );
573
+
574
+ // We want to avoid another resampling, so we read data approximately with
575
+ // the same resolution as requested and exactly the width/height we need.
576
+
577
+ // Calculate rows/cols limits in raster grid space
578
+
579
+ // IMHO, we cannot align target grid to raster grid using target grid edges
580
+ // and finding the nearest raster grid because it could lead to cell center
581
+ // getting outside the right cell when doing resampling, example
582
+ // Raster width is 30m and it has 3 columns and we want to read xrange 5.1-30
583
+ // to 3 columns, the nearest edge for beginning in raster grid is 10.0
584
+ // reading cols 1-2, we get raster[1] value in target[0], but the center of
585
+ // target[0] is 5.1 + ((30-5.1)/3)/2 = 9.25 so it falls to raster[0]. Is it right?
586
+ // => We are looking for such alignment with which the center of first/last cell
587
+ // alls to the right raster cell
588
+
589
+ double center, centerRaster;
590
+ int rasterTop, rasterBottom, rasterLeft, rasterRight;
591
+
592
+ // top
593
+ center = myRasterExtent.yMaximum () - yRes/2 ;
594
+ // center in raster space
595
+ // GDAL states that mGeoTransform[3] is top, but probably it can be also bottom
596
+ // if mGeoTransform[5] is negative
597
+ if ( mGeoTransform [5 ] > 0 )
598
+ {
599
+ centerRaster = ( mGeoTransform [3 ] - center ) / mGeoTransform [5 ];
600
+ }
601
+ else
602
+ {
603
+ centerRaster = ( center - mGeoTransform [3 ] ) / mGeoTransform [5 ];
604
+ }
605
+ rasterTop = static_cast <int > ( floor ( centerRaster ) );
606
+
607
+ // bottom
608
+ center = myRasterExtent.yMinimum () + yRes/2 ;
609
+ if ( mGeoTransform [5 ] > 0 )
610
+ {
611
+ centerRaster = ( mGeoTransform [3 ] - center ) / mGeoTransform [5 ];
612
+ }
613
+ else
614
+ {
615
+ centerRaster = ( center - mGeoTransform [3 ] ) / mGeoTransform [5 ];
616
+ }
617
+ rasterBottom = static_cast <int > ( floor ( centerRaster ) );
618
+
619
+ // left
620
+ center = myRasterExtent.xMinimum () + xRes/2 ;
621
+ centerRaster = ( center - mGeoTransform [0 ] ) / mGeoTransform [1 ];
622
+ rasterLeft = static_cast <int > ( floor ( centerRaster ) );
623
+
624
+ // right
625
+ center = myRasterExtent.xMaximum () - xRes/2 ;
626
+ centerRaster = ( center - mGeoTransform [0 ] ) / mGeoTransform [1 ];
627
+ rasterRight = static_cast <int > ( floor ( centerRaster ) );
628
+
629
+ QgsDebugMsg ( QString (" rasterTop = %1 rasterBottom = %2 rasterLeft = %3 rasterRight = %4" ).arg (rasterTop).arg (rasterBottom).arg (rasterLeft).arg (rasterRight) );
630
+
631
+ // Allocate temporary block
632
+ int width = right - left + 1 ;
633
+ int height = bottom - top + 1 ;
634
+
635
+ int rasterWidth = rasterRight - rasterLeft + 1 ;
636
+ int rasterHeight = rasterBottom - rasterTop + 1 ;
637
+
638
+ QgsDebugMsg ( QString (" width = %1 height = %2 rasterWidth = %3 rasterHeight = %4" ).arg (width).arg (height).arg (rasterWidth).arg (rasterHeight) );
639
+
640
+ int size = dataTypeSize (theBandNo) / 8 ;
641
+
642
+ // fill with null values
643
+ QByteArray ba = noValueBytes (theBandNo);
644
+ char *nodata = ba.data ();
645
+ char *block = (char *) theBlock;
646
+ for ( int i = 0 ; i < thePixelWidth * thePixelHeight; i++ )
647
+ {
648
+ memcpy ( block, nodata, size );
649
+ block += size;
650
+ }
651
+
652
+ GDALRasterBandH gdalBand = GDALGetRasterBand ( mGdalDataset , theBandNo );
653
+
654
+ // Calc beginnig of data if raster does not start at top
655
+ block = (char *) theBlock;
656
+ if ( top != 0 )
657
+ {
658
+ block += size * thePixelWidth * top;
659
+ }
660
+
661
+ // Cal nLineSpace if raster does not cover whole extent
662
+ int nLineSpace = size * thePixelWidth;
663
+ if ( left != 0 ) {
664
+ block += size * left;
665
+ }
666
+
667
+ GDALDataType type = ( GDALDataType )mGdalDataType [theBandNo-1 ];
668
+
669
+ CPLErrorReset ();
670
+ CPLErr err = GDALRasterIO ( gdalBand, GF_Read,
671
+ rasterLeft, rasterTop, rasterWidth, rasterHeight,
672
+ (void *)block,
673
+ width, height, type,
674
+ 0 , nLineSpace );
675
+
676
+ if ( err != CPLE_None )
677
+ {
678
+ QgsLogger::warning ( " RasterIO error: " + QString::fromUtf8 ( CPLGetLastErrorMsg () ) );
679
+ QgsDebugMsg ( " RasterIO error: " + QString::fromUtf8 ( CPLGetLastErrorMsg () ) );
680
+ }
681
+
682
+
683
+ }
684
+
685
+ // this is old version which was using GDALWarpOperation, unfortunately
686
+ // it may be very slow on large datasets
687
+ #if 0
688
+ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent, int thePixelWidth, int thePixelHeight, void *theBlock )
689
+ {
690
+ QgsDebugMsg( "thePixelWidth = " + QString::number( thePixelWidth ) );
691
+ QgsDebugMsg( "thePixelHeight = " + QString::number( thePixelHeight ) );
692
+ QgsDebugMsg( "theExtent: " + theExtent.toString() );
532
693
533
694
QString myMemDsn;
534
695
myMemDsn.sprintf( "DATAPOINTER = %p", theBlock );
@@ -672,6 +833,7 @@ void QgsGdalProvider::readBlock( int theBandNo, QgsRectangle const & theExtent,
672
833
GDALClose( myGdalMemDataset );
673
834
674
835
}
836
+ #endif
675
837
676
838
double QgsGdalProvider::noDataValue () const
677
839
{
0 commit comments