int QgsZonalStatistics::cellInfoForBBox( const QgsRectangle &rasterBBox, const QgsRectangle &featureBBox, double cellSizeX, double cellSizeY, int &offsetX, int &offsetY, int &nCellsX, int &nCellsY ) const { //get intersecting bbox QgsRectangle intersectBox = rasterBBox.intersect( &featureBBox ); if ( intersectBox.isEmpty() ) { nCellsX = 0; nCellsY = 0; offsetX = 0; offsetY = 0; return 0; } //get offset in pixels in x- and y- direction offsetX = ( int )( ( intersectBox.xMinimum() - rasterBBox.xMinimum() ) / cellSizeX ); offsetY = ( int )( ( rasterBBox.yMaximum() - intersectBox.yMaximum() ) / cellSizeY ); int maxColumn = ( int )( ( intersectBox.xMaximum() - rasterBBox.xMinimum() ) / cellSizeX ) + 1; int maxRow = ( int )( ( rasterBBox.yMaximum() - intersectBox.yMinimum() ) / cellSizeY ) + 1; nCellsX = maxColumn - offsetX; nCellsY = maxRow - offsetY; return 0; }
int QgsDemHeightMapGenerator::render( int x, int y, int z ) { Q_ASSERT( mJobs.isEmpty() ); // should be always just one active job... // extend the rect by half-pixel on each side? to get the values in "corners" QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z ); float mapUnitsPerPixel = extent.width() / mResolution; extent.grow( mapUnitsPerPixel / 2 ); // but make sure not to go beyond the full extent (returns invalid values) QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 ); extent = extent.intersect( &fullExtent ); JobData jd; jd.jobId = ++mLastJobId; jd.extent = extent; jd.timer.start(); // make a clone of the data provider so it is safe to use in worker thread jd.future = QtConcurrent::run( _readDtmData, mClonedProvider, extent, mResolution ); QFutureWatcher<QByteArray> *fw = new QFutureWatcher<QByteArray>; fw->setFuture( jd.future ); connect( fw, &QFutureWatcher<QByteArray>::finished, this, &QgsDemHeightMapGenerator::onFutureFinished ); mJobs.insert( fw, jd ); return jd.jobId; }
void QgsZonalStatistics::statisticsFromMiddlePointTest( const QgsGeometry &poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle &rasterBBox, FeatureStats &stats ) { double cellCenterX, cellCenterY; cellCenterY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2; stats.reset(); GEOSGeometry *polyGeos = poly.exportToGeos(); if ( !polyGeos ) { return; } GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler(); const GEOSPreparedGeometry *polyGeosPrepared = GEOSPrepare_r( geosctxt, polyGeos ); if ( !polyGeosPrepared ) { GEOSGeom_destroy_r( geosctxt, polyGeos ); return; } GEOSCoordSequence *cellCenterCoords = nullptr; GEOSGeometry *currentCellCenter = nullptr; QgsRectangle featureBBox = poly.boundingBox().intersect( &rasterBBox ); QgsRectangle intersectBBox = rasterBBox.intersect( &featureBBox ); QgsRasterBlock *block = mRasterProvider->block( mRasterBand, intersectBBox, nCellsX, nCellsY ); for ( int i = 0; i < nCellsY; ++i ) { cellCenterX = rasterBBox.xMinimum() + pixelOffsetX * cellSizeX + cellSizeX / 2; for ( int j = 0; j < nCellsX; ++j ) { if ( validPixel( block->value( i, j ) ) ) { GEOSGeom_destroy_r( geosctxt, currentCellCenter ); cellCenterCoords = GEOSCoordSeq_create_r( geosctxt, 1, 2 ); GEOSCoordSeq_setX_r( geosctxt, cellCenterCoords, 0, cellCenterX ); GEOSCoordSeq_setY_r( geosctxt, cellCenterCoords, 0, cellCenterY ); currentCellCenter = GEOSGeom_createPoint_r( geosctxt, cellCenterCoords ); if ( GEOSPreparedContains_r( geosctxt, polyGeosPrepared, currentCellCenter ) ) { stats.addValue( block->value( i, j ) ); } } cellCenterX += cellSizeX; } cellCenterY -= cellSizeY; } GEOSGeom_destroy_r( geosctxt, currentCellCenter ); GEOSPreparedGeom_destroy_r( geosctxt, polyGeosPrepared ); GEOSGeom_destroy_r( geosctxt, polyGeos ); delete block; }
void QgsZonalStatistics::statisticsFromPreciseIntersection( const QgsGeometry &poly, int pixelOffsetX, int pixelOffsetY, int nCellsX, int nCellsY, double cellSizeX, double cellSizeY, const QgsRectangle &rasterBBox, FeatureStats &stats ) { stats.reset(); double currentY = rasterBBox.yMaximum() - pixelOffsetY * cellSizeY - cellSizeY / 2; QgsGeometry pixelRectGeometry; double hCellSizeX = cellSizeX / 2.0; double hCellSizeY = cellSizeY / 2.0; double pixelArea = cellSizeX * cellSizeY; double weight = 0; QgsRectangle featureBBox = poly.boundingBox().intersect( &rasterBBox ); QgsRectangle intersectBBox = rasterBBox.intersect( &featureBBox ); QgsRasterBlock *block = mRasterProvider->block( mRasterBand, intersectBBox, nCellsX, nCellsY ); for ( int i = 0; i < nCellsY; ++i ) { double currentX = rasterBBox.xMinimum() + cellSizeX / 2.0 + pixelOffsetX * cellSizeX; for ( int j = 0; j < nCellsX; ++j ) { if ( !validPixel( block->value( i, j ) ) ) { continue; } pixelRectGeometry = QgsGeometry::fromRect( QgsRectangle( currentX - hCellSizeX, currentY - hCellSizeY, currentX + hCellSizeX, currentY + hCellSizeY ) ); if ( !pixelRectGeometry.isNull() ) { //intersection QgsGeometry intersectGeometry = pixelRectGeometry.intersection( poly ); if ( !intersectGeometry.isNull() ) { double intersectionArea = intersectGeometry.area(); if ( intersectionArea >= 0.0 ) { weight = intersectionArea / pixelArea; stats.addValue( block->value( i, j ), weight ); } } pixelRectGeometry = QgsGeometry(); } currentX += cellSizeX; } currentY -= cellSizeY; } delete block; }
QByteArray QgsDemHeightMapGenerator::renderSynchronously( int x, int y, int z ) { // extend the rect by half-pixel on each side? to get the values in "corners" QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z ); float mapUnitsPerPixel = extent.width() / mResolution; extent.grow( mapUnitsPerPixel / 2 ); // but make sure not to go beyond the full extent (returns invalid values) QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 ); extent = extent.intersect( &fullExtent ); QgsRasterBlock *block = mDtm->dataProvider()->block( 1, extent, mResolution, mResolution ); QByteArray data; if ( block ) { block->convert( Qgis::Float32 ); // currently we expect just floats data = block->data(); data.detach(); // this should make a deep copy delete block; } return data; }
QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext ) : QgsMapLayerRenderer( layer->id() ) , mRasterViewPort( nullptr ) , mPipe( nullptr ) { mPainter = rendererContext.painter(); const QgsMapToPixel& theQgsMapToPixel = rendererContext.mapToPixel(); mMapToPixel = &theQgsMapToPixel; QgsMapToPixel mapToPixel = theQgsMapToPixel; if ( mapToPixel.mapRotation() ) { // unset rotation for the sake of local computations. // Rotation will be handled by QPainter later // TODO: provide a method of QgsMapToPixel to fetch map center // in geographical units QgsPoint center = mapToPixel.toMapCoordinates( mapToPixel.mapWidth() / 2.0, mapToPixel.mapHeight() / 2.0 ); mapToPixel.setMapRotation( 0, center.x(), center.y() ); } QgsRectangle myProjectedViewExtent; QgsRectangle myProjectedLayerExtent; if ( rendererContext.coordinateTransform() ) { QgsDebugMsg( "coordinateTransform set -> project extents." ); try { myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedViewExtent.setMinimal(); } try { myProjectedLayerExtent = rendererContext.coordinateTransform()->transformBoundingBox( layer->extent() ); } catch ( QgsCsException &cs ) { QgsMessageLog::logMessage( QObject::tr( "Could not reproject layer extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) ); myProjectedLayerExtent.setMinimal(); } } else { QgsDebugMsg( "coordinateTransform not set" ); myProjectedViewExtent = rendererContext.extent(); myProjectedLayerExtent = layer->extent(); } // clip raster extent to view extent QgsRectangle myRasterExtent = myProjectedViewExtent.intersect( &myProjectedLayerExtent ); if ( myRasterExtent.isEmpty() ) { QgsDebugMsg( "draw request outside view extent." ); // nothing to do return; } QgsDebugMsg( "theViewExtent is " + rendererContext.extent().toString() ); QgsDebugMsg( "myProjectedViewExtent is " + myProjectedViewExtent.toString() ); QgsDebugMsg( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString() ); QgsDebugMsg( "myRasterExtent is " + myRasterExtent.toString() ); // // The first thing we do is set up the QgsRasterViewPort. This struct stores all the settings // relating to the size (in pixels and coordinate system units) of the raster part that is // in view in the map window. It also stores the origin. // //this is not a class level member because every time the user pans or zooms //the contents of the rasterViewPort will change mRasterViewPort = new QgsRasterViewPort(); mRasterViewPort->mDrawnExtent = myRasterExtent; if ( rendererContext.coordinateTransform() ) { mRasterViewPort->mSrcCRS = layer->crs(); mRasterViewPort->mDestCRS = rendererContext.coordinateTransform()->destCRS(); mRasterViewPort->mSrcDatumTransform = rendererContext.coordinateTransform()->sourceDatumTransform(); mRasterViewPort->mDestDatumTransform = rendererContext.coordinateTransform()->destinationDatumTransform(); } else { mRasterViewPort->mSrcCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mDestCRS = QgsCoordinateReferenceSystem(); // will be invalid mRasterViewPort->mSrcDatumTransform = -1; mRasterViewPort->mDestDatumTransform = -1; } // get dimensions of clipped raster image in device coordinate space (this is the size of the viewport) mRasterViewPort->mTopLeftPoint = mapToPixel.transform( myRasterExtent.xMinimum(), myRasterExtent.yMaximum() ); mRasterViewPort->mBottomRightPoint = mapToPixel.transform( myRasterExtent.xMaximum(), myRasterExtent.yMinimum() ); // align to output device grid, i.e. floor/ceil to integers // TODO: this should only be done if paint device is raster - screen, image // for other devices (pdf) it can have floating point origin // we could use floating point for raster devices as well, but respecting the // output device grid should make it more effective as the resampling is done in // the provider anyway mRasterViewPort->mTopLeftPoint.setX( floor( mRasterViewPort->mTopLeftPoint.x() ) ); mRasterViewPort->mTopLeftPoint.setY( floor( mRasterViewPort->mTopLeftPoint.y() ) ); mRasterViewPort->mBottomRightPoint.setX( ceil( mRasterViewPort->mBottomRightPoint.x() ) ); mRasterViewPort->mBottomRightPoint.setY( ceil( mRasterViewPort->mBottomRightPoint.y() ) ); // recalc myRasterExtent to aligned values myRasterExtent.set( mapToPixel.toMapCoordinatesF( mRasterViewPort->mTopLeftPoint.x(), mRasterViewPort->mBottomRightPoint.y() ), mapToPixel.toMapCoordinatesF( mRasterViewPort->mBottomRightPoint.x(), mRasterViewPort->mTopLeftPoint.y() ) ); //raster viewport top left / bottom right are already rounded to int mRasterViewPort->mWidth = static_cast<int>( mRasterViewPort->mBottomRightPoint.x() - mRasterViewPort->mTopLeftPoint.x() ); mRasterViewPort->mHeight = static_cast<int>( mRasterViewPort->mBottomRightPoint.y() - mRasterViewPort->mTopLeftPoint.y() ); //the drawable area can start to get very very large when you get down displaying 2x2 or smaller, this is becasue //mapToPixel.mapUnitsPerPixel() is less then 1, //so we will just get the pixel data and then render these special cases differently in paintImageToCanvas() QgsDebugMsgLevel( QString( "mapUnitsPerPixel = %1" ).arg( mapToPixel.mapUnitsPerPixel() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( layer->width() ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( layer->height() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMinimum() = %1" ).arg( myRasterExtent.xMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.xMaximum() = %1" ).arg( myRasterExtent.xMaximum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMinimum() = %1" ).arg( myRasterExtent.yMinimum() ), 3 ); QgsDebugMsgLevel( QString( "myRasterExtent.yMaximum() = %1" ).arg( myRasterExtent.yMaximum() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.x() = %1" ).arg( mRasterViewPort->mTopLeftPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.x() = %1" ).arg( mRasterViewPort->mBottomRightPoint.x() ), 3 ); QgsDebugMsgLevel( QString( "mTopLeftPoint.y() = %1" ).arg( mRasterViewPort->mTopLeftPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mBottomRightPoint.y() = %1" ).arg( mRasterViewPort->mBottomRightPoint.y() ), 3 ); QgsDebugMsgLevel( QString( "mWidth = %1" ).arg( mRasterViewPort->mWidth ), 3 ); QgsDebugMsgLevel( QString( "mHeight = %1" ).arg( mRasterViewPort->mHeight ), 3 ); // /\/\/\ - added to handle zoomed-in rasters // TODO R->mLastViewPort = *mRasterViewPort; // TODO: is it necessary? Probably WMS only? layer->dataProvider()->setDpi( rendererContext.rasterScaleFactor() * 25.4 * rendererContext.scaleFactor() ); // copy the whole raster pipe! mPipe = new QgsRasterPipe( *layer->pipe() ); }
bool QgsDecorationNorthArrow::calculateNorthDirection() { QgsMapCanvas* mapCanvas = QgisApp::instance()->mapCanvas(); bool goodDirn = false; // Get the shown extent... QgsRectangle canvasExtent = mapCanvas->extent(); // ... and all layers extent, ... QgsRectangle fullExtent = mapCanvas->fullExtent(); // ... and combine QgsRectangle extent = canvasExtent.intersect( & fullExtent ); // If no layers are added or shown, we can't get any direction if ( mapCanvas->layerCount() > 0 && ! extent.isEmpty() ) { QgsCoordinateReferenceSystem outputCRS = mapCanvas->mapRenderer()->destinationCrs(); if ( outputCRS.isValid() && !outputCRS.geographicFlag() ) { // Use a geographic CRS to get lat/long to work out direction QgsCoordinateReferenceSystem ourCRS; ourCRS.createFromOgcWmsCrs( GEO_EPSG_CRS_AUTHID ); assert( ourCRS.isValid() ); QgsCoordinateTransform transform( outputCRS, ourCRS ); QgsPoint p1( extent.center() ); // A point a bit above p1. XXX assumes that y increases up!! // May need to involve the maptopixel transform if this proves // to be a problem. QgsPoint p2( p1.x(), p1.y() + extent.height() * 0.25 ); // project p1 and p2 to geographic coords try { p1 = transform.transform( p1 ); p2 = transform.transform( p2 ); } catch ( QgsCsException &e ) { Q_UNUSED( e ); // just give up QgsDebugMsg( "North Arrow: Transformation error, quitting" ); return false; } // Work out the value of the initial heading one takes to go // from point p1 to point p2. The north direction is then that // many degrees anti-clockwise or vertical. // Take some care to not divide by zero, etc, and ensure that we // get sensible results for all possible values for p1 and p2. goodDirn = true; double angle = 0.0; // convert to radians for the equations below p1.multiply( PI / 180.0 ); p2.multiply( PI / 180.0 ); double y = sin( p2.x() - p1.x() ) * cos( p2.y() ); double x = cos( p1.y() ) * sin( p2.y() ) - sin( p1.y() ) * cos( p2.y() ) * cos( p2.x() - p1.x() ); // Use TOL to decide if the quotient is big enough. // Both x and y can be very small, if heavily zoomed // For small y/x, we set directly angle 0. Not sure // if this is needed. if ( y > 0.0 ) { if ( x > 0.0 && ( y / x ) > TOL ) angle = atan( y / x ); else if ( x < 0.0 && ( y / x ) < -TOL ) angle = PI - atan( -y / x ); else angle = 0.5 * PI; } else if ( y < 0.0 ) { if ( x > 0.0 && ( y / x ) < -TOL ) angle = -atan( -y / x ); else if ( x < 0.0 && ( y / x ) > TOL ) angle = atan( y / x ) - PI; else angle = 1.5 * PI; } else { if ( x > TOL ) angle = 0.0; else if ( x < -TOL ) angle = PI; else { angle = 0.0; // p1 = p2 goodDirn = false; } } // And set the angle of the north arrow. Perhaps do something // different if goodDirn = false. mRotationInt = qRound( fmod( 360.0 - angle * 180.0 / PI, 360.0 ) ); } else { // For geographic CRS and for when there are no layers, set the // direction back to the default mRotationInt = 0; } } return goodDirn; }