QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsrasterlayerrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayerrenderer.cpp
3  --------------------------------------
4  Date : December 2013
5  Copyright : (C) 2013 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsrasterlayerrenderer.h"
17 
18 #include "qgsmessagelog.h"
19 #include "qgsrasterdrawer.h"
20 #include "qgsrasteriterator.h"
21 #include "qgsrasterlayer.h"
22 
23 
25  : QgsMapLayerRenderer( layer->id() )
26  , mRasterViewPort( 0 )
27  , mPipe( 0 )
28 {
29 
30  mPainter = rendererContext.painter();
31  const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel();
32  mMapToPixel = &theQgsMapToPixel;
33 
34  QgsRectangle myProjectedViewExtent;
35  QgsRectangle myProjectedLayerExtent;
36 
37  if ( rendererContext.coordinateTransform() )
38  {
39  QgsDebugMsg( "coordinateTransform set -> project extents." );
40  try
41  {
42  myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() );
43  }
44  catch ( QgsCsException &cs )
45  {
46  QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
47  myProjectedViewExtent.setMinimal();
48  }
49 
50  try
51  {
52  myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( layer->extent() );
53  }
54  catch ( QgsCsException &cs )
55  {
56  QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
57  myProjectedViewExtent.setMinimal();
58  }
59  }
60  else
61  {
62  QgsDebugMsg( "coordinateTransform not set" );
63  myProjectedViewExtent = rendererContext.extent();
64  myProjectedLayerExtent = layer->extent();
65  }
66 
67  // clip raster extent to view extent
68  QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent );
69  if ( myRasterExtent.isEmpty() )
70  {
71  QgsDebugMsg( "draw request outside view extent." );
72  // nothing to do
73  return;
74  }
75 
76  QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() );
77  QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() );
78  QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() );
79  QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() );
80 
81  //
82  // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings
83  // relating to the size (in pixels and coordinate system units) of the raster part that is
84  // in view in the map window. It also stores the origin.
85  //
86  //this is not a class level member because every time the user pans or zooms
87  //the contents of the rasterViewPort will change
89 
90  mRasterViewPort->mDrawnExtent = myRasterExtent;
91  if ( rendererContext.coordinateTransform() )
92  {
93  mRasterViewPort->mSrcCRS = layer->crs();
94  mRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS();
95  mRasterViewPort->mSrcDatumTransform = rendererContext.coordinateTransform()->sourceDatumTransform();
96  mRasterViewPort->mDestDatumTransform = rendererContext.coordinateTransform()->destinationDatumTransform();
97  }
98  else
99  {
100  mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid
101  mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid
102  mRasterViewPort->mSrcDatumTransform = -1;
103  mRasterViewPort->mDestDatumTransform = -1;
104  }
105 
106  // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport)
107  mRasterViewPort->mTopLeftPoint = theQgsMapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() );
108  mRasterViewPort->mBottomRightPoint = theQgsMapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() );
109 
110  // align to output device grid, i.e. floor/ceil to integers
111  // TODO: this should only be done if paint device is raster - screen, image
112  // for other devices (pdf) it can have floating point origin
113  // we could use floating point for raster devices as well, but respecting the
114  // output device grid should make it more effective as the resampling is done in
115  // the provider anyway
116  mRasterViewPort->mTopLeftPoint.setX( floor( mRasterViewPort->mTopLeftPoint.x() ) );
117  mRasterViewPort->mTopLeftPoint.setY( floor( mRasterViewPort->mTopLeftPoint.y() ) );
118  mRasterViewPort->mBottomRightPoint.setX( ceil( mRasterViewPort->mBottomRightPoint.x() ) );
119  mRasterViewPort->mBottomRightPoint.setY( ceil( mRasterViewPort->mBottomRightPoint.y() ) );
120  // recalc myRasterExtent to aligned values
121  myRasterExtent.set(
122  theQgsMapToPixel.toMapCoordinatesF( mRasterViewPort->mTopLeftPoint.x(),
123  mRasterViewPort->mBottomRightPoint.y() ),
124  theQgsMapToPixel.toMapCoordinatesF( mRasterViewPort->mBottomRightPoint.x(),
125  mRasterViewPort->mTopLeftPoint.y() )
126  );
127 
128  //raster viewport top left / bottom right are already rounded to int
129  mRasterViewPort->mWidth = static_cast<int>( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() );
130  mRasterViewPort->mHeight = static_cast<int>( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() );
131 
132 
133  //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue
134  //theQgsMapToPixel.mapUnitsPerPixel() is less then 1,
135  //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas()
136 
137  QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( theQgsMapToPixel.mapUnitsPerPixel() ), 3 );
138  QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( layer->width() ), 3 );
139  QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( layer->height() ), 3 );
140  QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 );
141  QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 );
142  QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 );
143  QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 );
144 
145  QgsDebugMsgLevel( QString( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 );
146  QgsDebugMsgLevel( QString( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 );
147  QgsDebugMsgLevel( QString( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 );
148  QgsDebugMsgLevel( QString( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 );
149 
150  QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 );
151  QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 );
152 
153  // /\/\/\ - added to handle zoomed-in rasters
154 
155  // TODO R->mLastViewPort = *mRasterViewPort;
156 
157  // TODO: is it necessary? Probably WMS only?
158  layer->dataProvider()->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() );
159 
160 
161  // copy the whole raster pipe!
162  mPipe = new QgsRasterPipe( *layer->pipe() );
163 }
164 
166 {
167  delete mRasterViewPort;
168  delete mPipe;
169 }
170 
172 {
173  if ( !mRasterViewPort )
174  return true; // outside of layer extent - nothing to do
175 
176  //R->draw( mPainter, mRasterViewPort, &mMapToPixel );
177 
178  QTime time;
179  time.start();
180  //
181  //
182  // The goal here is to make as many decisions as possible early on (outside of the rendering loop)
183  // so that we can maximise performance of the rendering process. So now we check which drawing
184  // procedure to use :
185  //
186 
187  QgsRasterProjector *projector = mPipe->projector();
188 
189  // TODO add a method to interface to get provider and get provider
190  // params in QgsRasterProjector
191  if ( projector )
192  {
194  }
195 
196  // Drawer to pipe?
197  QgsRasterIterator iterator( mPipe->last() );
198  QgsRasterDrawer drawer( &iterator );
199  drawer.draw( mPainter, mRasterViewPort, mMapToPixel );
200 
201  QgsDebugMsg( QString( "total raster draw time (ms): %1" ).arg( time.elapsed(), 5 ) );
202 
203  return true;
204 }
A rectangle specified with double values.
Definition: qgsrectangle.h:35
bool isEmpty() const
test if rectangle is empty.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
Base class for processing modules.
Definition: qgsrasterpipe.h:41
void setCRS(const QgsCoordinateReferenceSystem &theSrcCRS, const QgsCoordinateReferenceSystem &theDestCRS, int srcDatumTransform=-1, int destDatumTransform=-1)
set source and destination CRS
Iterator for sequentially processing raster cells.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:194
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QgsRasterPipe * pipe()
Get raster pipe.
const QgsMapToPixel * mMapToPixel
QgsPoint transform(const QgsPoint &p) const
QgsRasterInterface * last() const
Definition: qgsrasterpipe.h:86
const QgsRectangle & extent() const
double scaleFactor() const
const QgsCoordinateTransform * coordinateTransform() const
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QgsCoordinateReferenceSystem mDestCRS
Target coordinate system.
void set(const QgsPoint &p1, const QgsPoint &p2)
Set the rectangle from two QgsPoints.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
The drawing pipe for raster layers.
int height() const
Accessor that returns the height of the (unclipped) raster.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:199
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:184
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
QgsRasterLayerRenderer(QgsRasterLayer *layer, QgsRenderContext &rendererContext)
double rasterScaleFactor() const
double mapUnitsPerPixel() const
Return current map units per pixel.
QgsRasterProjector * projector() const
void setX(double x)
Definition: qgspoint.h:87
QgsCoordinateReferenceSystem mSrcCRS
Source coordinate system.
QgsPoint toMapCoordinatesF(double x, double y) const
QString what() const
Definition: qgsexception.h:35
QgsRasterViewPort * mRasterViewPort
Contains information about the context of a rendering operation.
QgsRectangle transformBoundingBox(const QgsRectangle theRect, TransformDirection direction=ForwardTransform) const
QPainter * painter()
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
Class for storing a coordinate reference system (CRS)
const QgsMapToPixel & mapToPixel() const
Base class for utility classes that encapsulate information necessary for rendering of map layers...
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
QgsRasterDataProvider * dataProvider()
Returns the data provider.
Custom exception class for Coordinate Reference System related exceptions.
virtual bool render()
Do the rendering (based on data stored in the class)
This class provides details of the viewable area that a raster will be rendered into.
const QgsCoordinateReferenceSystem & destCRS() const
virtual QgsRectangle extent()
Return the extent of the layer.
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189
void setDpi(int dpi)
Sets the output device resolution.
int width() const
Accessor that returns the width of the (unclipped) raster.
#define tr(sourceText)