/**************************** REGION ********************************/ void QgsGrassNewMapset::setRegionPage() { // Set defaults if ( !mRegionModified ) { setGrassRegionDefaults(); } // Create new projection QgsCoordinateReferenceSystem newCrs; if ( mProjRadioButton->isChecked() ) { QgsDebugMsg( QString( "selectedCrsId() = %1" ).arg( mProjectionSelector->crs().srsid() ) ); if ( mProjectionSelector->crs().srsid() > 0 ) { newCrs = mProjectionSelector->crs(); if ( ! newCrs.isValid() ) { QgsGrass::warning( tr( "Cannot create projection." ) ); } } } // Reproject previous region if it was modified // and if previous and current projection is valid if ( mRegionModified && newCrs.isValid() && mCrs.isValid() && newCrs.srsid() != mCrs.srsid() ) { QgsCoordinateTransform trans( mCrs, newCrs, QgsProject::instance() ); double n = mNorthLineEdit->text().toDouble(); double s = mSouthLineEdit->text().toDouble(); double e = mEastLineEdit->text().toDouble(); double w = mWestLineEdit->text().toDouble(); std::vector<QgsPointXY> points; // TODO: this is not perfect points.push_back( QgsPointXY( w, s ) ); points.push_back( QgsPointXY( e, n ) ); bool ok = true; for ( int i = 0; i < 2; i++ ) { try { points[i] = trans.transform( points[i] ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); QgsDebugMsg( "Cannot transform point" ); ok = false; break; } } if ( ok ) { int precision = newCrs.mapUnits() == QgsUnitTypes::DistanceDegrees ? 6 : 1; mNorthLineEdit->setText( qgsDoubleToString( points[1].y(), precision ) ); mSouthLineEdit->setText( qgsDoubleToString( points[0].y(), precision ) ); mEastLineEdit->setText( qgsDoubleToString( points[1].x(), precision ) ); mWestLineEdit->setText( qgsDoubleToString( points[0].x(), precision ) ); } else { QgsGrass::warning( tr( "Cannot reproject previously set region, default region set." ) ); setGrassRegionDefaults(); } } // Set current region projection mCrs = newCrs; // Enable / disable region selection widgets if ( mNoProjRadioButton->isChecked() ) { mRegionMap->hide(); mCurrentRegionButton->hide(); mRegionsComboBox->hide(); mRegionButton->hide(); mSetRegionFrame->hide(); } else { mRegionMap->show(); mCurrentRegionButton->show(); mRegionsComboBox->show(); mRegionButton->show(); mSetRegionFrame->show(); QgsRectangle ext = mIface->mapCanvas()->extent(); mCurrentRegionButton->setEnabled( !ext.isEmpty() ); } checkRegion(); if ( !mNoProjRadioButton->isChecked() ) { drawRegion(); } }
bool QgsVectorLayerRenderer::render() { if ( mGeometryType == QgsWkbTypes::NullGeometry || mGeometryType == QgsWkbTypes::UnknownGeometry ) return true; if ( !mRenderer ) { mErrors.append( QObject::tr( "No renderer for drawing." ) ); return false; } bool usingEffect = false; if ( mRenderer->paintEffect() && mRenderer->paintEffect()->enabled() ) { usingEffect = true; mRenderer->paintEffect()->begin( mContext ); } // Per feature blending mode if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) { // set the painter to the feature blend mode, so that features drawn // on this layer will interact and blend with each other mContext.painter()->setCompositionMode( mFeatureBlendMode ); } mRenderer->startRender( mContext, mFields ); QString rendererFilter = mRenderer->filter( mFields ); QgsRectangle requestExtent = mContext.extent(); mRenderer->modifyRequestExtent( requestExtent, mContext ); QgsFeatureRequest featureRequest = QgsFeatureRequest() .setFilterRect( requestExtent ) .setSubsetOfAttributes( mAttrNames, mFields ) .setExpressionContext( mContext.expressionContext() ); if ( mRenderer->orderByEnabled() ) { featureRequest.setOrderBy( mRenderer->orderBy() ); } const QgsFeatureFilterProvider *featureFilterProvider = mContext.featureFilterProvider(); if ( featureFilterProvider ) { featureFilterProvider->filterFeatures( mLayer, featureRequest ); } if ( !rendererFilter.isEmpty() && rendererFilter != QLatin1String( "TRUE" ) ) { featureRequest.combineFilterExpression( rendererFilter ); } // enable the simplification of the geometries (Using the current map2pixel context) before send it to renderer engine. if ( mSimplifyGeometry ) { double map2pixelTol = mSimplifyMethod.threshold(); bool validTransform = true; const QgsMapToPixel &mtp = mContext.mapToPixel(); map2pixelTol *= mtp.mapUnitsPerPixel(); QgsCoordinateTransform ct = mContext.coordinateTransform(); // resize the tolerance using the change of size of an 1-BBOX from the source CoordinateSystem to the target CoordinateSystem if ( ct.isValid() && !ct.isShortCircuited() ) { try { QgsPointXY center = mContext.extent().center(); double rectSize = ct.sourceCrs().isGeographic() ? 0.0008983 /* ~100/(40075014/360=111319.4833) */ : 100; QgsRectangle sourceRect = QgsRectangle( center.x(), center.y(), center.x() + rectSize, center.y() + rectSize ); QgsRectangle targetRect = ct.transform( sourceRect ); QgsDebugMsgLevel( QString( "Simplify - SourceTransformRect=%1" ).arg( sourceRect.toString( 16 ) ), 4 ); QgsDebugMsgLevel( QString( "Simplify - TargetTransformRect=%1" ).arg( targetRect.toString( 16 ) ), 4 ); if ( !sourceRect.isEmpty() && sourceRect.isFinite() && !targetRect.isEmpty() && targetRect.isFinite() ) { QgsPointXY minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() ); QgsPointXY maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() ); QgsPointXY minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() ); QgsPointXY maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() ); double sourceHypothenuse = std::sqrt( minimumSrcPoint.sqrDist( maximumSrcPoint ) ); double targetHypothenuse = std::sqrt( minimumDstPoint.sqrDist( maximumDstPoint ) ); QgsDebugMsgLevel( QString( "Simplify - SourceHypothenuse=%1" ).arg( sourceHypothenuse ), 4 ); QgsDebugMsgLevel( QString( "Simplify - TargetHypothenuse=%1" ).arg( targetHypothenuse ), 4 ); if ( !qgsDoubleNear( targetHypothenuse, 0.0 ) ) map2pixelTol *= ( sourceHypothenuse / targetHypothenuse ); } } catch ( QgsCsException &cse ) { QgsMessageLog::logMessage( QObject::tr( "Simplify transform error caught: %1" ).arg( cse.what() ), QObject::tr( "CRS" ) ); validTransform = false; } } if ( validTransform ) { QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); simplifyMethod.setThreshold( mSimplifyMethod.threshold() ); simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); QgsVectorSimplifyMethod vectorMethod = mSimplifyMethod; vectorMethod.setTolerance( map2pixelTol ); mContext.setVectorSimplifyMethod( vectorMethod ); } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } } else { QgsVectorSimplifyMethod vectorMethod; vectorMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification ); mContext.setVectorSimplifyMethod( vectorMethod ); } QgsFeatureIterator fit = mSource->getFeatures( featureRequest ); // Attach an interruption checker so that iterators that have potentially // slow fetchFeature() implementations, such as in the WFS provider, can // check it, instead of relying on just the mContext.renderingStopped() check // in drawRenderer() fit.setInterruptionChecker( &mInterruptionChecker ); if ( ( mRenderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && mRenderer->usingSymbolLevels() ) drawRendererLevels( fit ); else drawRenderer( fit ); if ( usingEffect ) { mRenderer->paintEffect()->end( mContext ); } return true; }
QgsRasterBlock * QgsRasterDataProvider::block( int theBandNo, QgsRectangle const & theExtent, int theWidth, int theHeight ) { QgsDebugMsg( QString( "theBandNo = %1 theWidth = %2 theHeight = %3" ).arg( theBandNo ).arg( theWidth ).arg( theHeight ) ); QgsDebugMsg( QString( "theExtent = %1" ).arg( theExtent.toString() ) ); QgsRasterBlock *block = new QgsRasterBlock( dataType( theBandNo ), theWidth, theHeight, noDataValue( theBandNo ) ); if ( block->isEmpty() ) { QgsDebugMsg( "Couldn't create raster block" ); return block; } // Read necessary extent only QgsRectangle tmpExtent = extent().intersect( &theExtent ); if ( tmpExtent.isEmpty() ) { QgsDebugMsg( "Extent outside provider extent" ); block->setIsNoData(); return block; } double xRes = theExtent.width() / theWidth; double yRes = theExtent.height() / theHeight; double tmpXRes, tmpYRes; double providerXRes = 0; double providerYRes = 0; if ( capabilities() & ExactResolution ) { providerXRes = extent().width() / xSize(); providerYRes = extent().height() / ySize(); tmpXRes = qMax( providerXRes, xRes ); tmpYRes = qMax( providerYRes, yRes ); if ( doubleNear( tmpXRes, xRes ) ) tmpXRes = xRes; if ( doubleNear( tmpYRes, yRes ) ) tmpYRes = yRes; } else { tmpXRes = xRes; tmpYRes = yRes; } if ( tmpExtent != theExtent || tmpXRes > xRes || tmpYRes > yRes ) { // Read smaller extent or lower resolution // Calculate row/col limits (before tmpExtent is aligned) int fromRow = qRound(( theExtent.yMaximum() - tmpExtent.yMaximum() ) / yRes ); int toRow = qRound(( theExtent.yMaximum() - tmpExtent.yMinimum() ) / yRes ) - 1; int fromCol = qRound(( tmpExtent.xMinimum() - theExtent.xMinimum() ) / xRes ) ; int toCol = qRound(( tmpExtent.xMaximum() - theExtent.xMinimum() ) / xRes ) - 1; QgsDebugMsg( QString( "fromRow = %1 toRow = %2 fromCol = %3 toCol = %4" ).arg( fromRow ).arg( toRow ).arg( fromCol ).arg( toCol ) ); if ( fromRow < 0 || fromRow >= theHeight || toRow < 0 || toRow >= theHeight || fromCol < 0 || fromCol >= theWidth || toCol < 0 || toCol >= theWidth ) { // Should not happen QgsDebugMsg( "Row or column limits out of range" ); return block; } // If lower source resolution is used, the extent must beS aligned to original // resolution to avoid possible shift due to resampling if ( tmpXRes > xRes ) { int col = floor(( tmpExtent.xMinimum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMinimum( extent().xMinimum() + col * providerXRes ); col = ceil(( tmpExtent.xMaximum() - extent().xMinimum() ) / providerXRes ); tmpExtent.setXMaximum( extent().xMinimum() + col * providerXRes ); } if ( tmpYRes > yRes ) { int row = floor(( extent().yMaximum() - tmpExtent.yMaximum() ) / providerYRes ); tmpExtent.setYMaximum( extent().yMaximum() - row * providerYRes ); row = ceil(( extent().yMaximum() - tmpExtent.yMinimum() ) / providerYRes ); tmpExtent.setYMinimum( extent().yMaximum() - row * providerYRes ); } int tmpWidth = qRound( tmpExtent.width() / tmpXRes ); int tmpHeight = qRound( tmpExtent.height() / tmpYRes ); tmpXRes = tmpExtent.width() / tmpWidth; tmpYRes = tmpExtent.height() / tmpHeight; QgsDebugMsg( QString( "Reading smaller block tmpWidth = %1 theHeight = %2" ).arg( tmpWidth ).arg( tmpHeight ) ); QgsDebugMsg( QString( "tmpExtent = %1" ).arg( tmpExtent.toString() ) ); block->setIsNoData(); QgsRasterBlock *tmpBlock = new QgsRasterBlock( dataType( theBandNo ), tmpWidth, tmpHeight, noDataValue( theBandNo ) ); readBlock( theBandNo, tmpExtent, tmpWidth, tmpHeight, tmpBlock->data() ); int pixelSize = dataTypeSize( theBandNo ); double xMin = theExtent.xMinimum(); double yMax = theExtent.yMaximum(); double tmpXMin = tmpExtent.xMinimum(); double tmpYMax = tmpExtent.yMaximum(); for ( int row = fromRow; row <= toRow; row++ ) { double y = yMax - ( row + 0.5 ) * yRes; int tmpRow = floor(( tmpYMax - y ) / tmpYRes ); for ( int col = fromCol; col <= toCol; col++ ) { double x = xMin + ( col + 0.5 ) * xRes; int tmpCol = floor(( x - tmpXMin ) / tmpXRes ); if ( tmpRow < 0 || tmpRow >= tmpHeight || tmpCol < 0 || tmpCol >= tmpWidth ) { QgsDebugMsg( "Source row or column limits out of range" ); block->setIsNoData(); // so that the problem becomes obvious and fixed delete tmpBlock; return block; } size_t tmpIndex = tmpRow * tmpWidth + tmpCol; size_t index = row * theWidth + col; char *tmpBits = tmpBlock->bits( tmpIndex ); char *bits = block->bits( index ); if ( !tmpBits ) { QgsDebugMsg( QString( "Cannot get input block data tmpRow = %1 tmpCol = %2 tmpIndex = %3." ).arg( tmpRow ).arg( tmpCol ).arg( tmpIndex ) ); continue; } if ( !bits ) { QgsDebugMsg( "Cannot set output block data." ); continue; } memcpy( bits, tmpBits, pixelSize ); } } delete tmpBlock; } else { readBlock( theBandNo, theExtent, theWidth, theHeight, block->data() ); } // apply user no data values // TODO: there are other readBlock methods where no data are not applied block->applyNodataValues( userNoDataValue( theBandNo ) ); return block; }
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle rect, TransformDirection direction ) const { // Calculate the bounding box of a QgsRectangle in the source CRS // when projected to the destination CRS (or the inverse). // This is done by looking at a number of points spread evenly // across the rectangle if ( mShortCircuit || !mInitialisedFlag ) return rect; if ( rect.isEmpty() ) { QgsPoint p = transform( rect.xMinimum(), rect.yMinimum(), direction ); return QgsRectangle( p, p ); } static const int numP = 8; QgsRectangle bb_rect; bb_rect.setMinimal(); // We're interfacing with C-style vectors in the // end, so let's do C-style vectors here too. double x[numP * numP]; double y[numP * numP]; double z[numP * numP]; QgsDebugMsg( "Entering transformBoundingBox..." ); // Populate the vectors double dx = rect.width() / ( double )( numP - 1 ); double dy = rect.height() / ( double )( numP - 1 ); double pointY = rect.yMinimum(); for ( int i = 0; i < numP ; i++ ) { // Start at right edge double pointX = rect.xMinimum(); for ( int j = 0; j < numP; j++ ) { x[( i*numP ) + j] = pointX; y[( i*numP ) + j] = pointY; // and the height... z[( i*numP ) + j] = 0.0; // QgsDebugMsg(QString("BBox coord: (%1, %2)").arg(x[(i*numP) + j]).arg(y[(i*numP) + j])); pointX += dx; } pointY += dy; } // Do transformation. Any exception generated must // be handled in above layers. try { transformCoords( numP * numP, x, y, z, direction ); } catch ( const QgsCsException & ) { // rethrow the exception QgsDebugMsg( "rethrowing exception" ); throw; } // Calculate the bounding box and use that for the extent for ( int i = 0; i < numP * numP; i++ ) { if ( qIsFinite( x[i] ) && qIsFinite( y[i] ) ) bb_rect.combineExtentWith( x[i], y[i] ); } QgsDebugMsg( "Projected extent: " + bb_rect.toString() ); if ( bb_rect.isEmpty() ) { QgsDebugMsg( "Original extent: " + rect.toString() ); } return bb_rect; }
bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &attributeMaps ) { if ( !mVectorLayer ) { return false; } QScopedPointer< QgsExpressionContext > context( createExpressionContext() ); context->setFields( mVectorLayer->fields() ); attributeMaps.clear(); //prepare filter expression QScopedPointer<QgsExpression> filterExpression; bool activeFilter = false; if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) { filterExpression.reset( new QgsExpression( mFeatureFilter ) ); if ( !filterExpression->hasParserError() ) { activeFilter = true; } } QgsRectangle selectionRect; if ( mComposerMap && mShowOnlyVisibleFeatures ) { selectionRect = *mComposerMap->currentMapExtent(); if ( mVectorLayer && mComposition->mapSettings().hasCrsTransformEnabled() ) { //transform back to layer CRS QgsCoordinateTransform coordTransform( mVectorLayer->crs(), mComposition->mapSettings().destinationCrs() ); try { selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); return false; } } } QgsFeatureRequest req; if ( !selectionRect.isEmpty() ) req.setFilterRect( selectionRect ); req.setFlags( mShowOnlyVisibleFeatures ? QgsFeatureRequest::ExactIntersect : QgsFeatureRequest::NoFlags ); QgsFeature f; int counter = 0; QgsFeatureIterator fit = mVectorLayer->getFeatures( req ); while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures ) { context->setFeature( f ); //check feature against filter if ( activeFilter && !filterExpression.isNull() ) { QVariant result = filterExpression->evaluate( context.data() ); // skip this feature if the filter evaluation is false if ( !result.toBool() ) { continue; } } attributeMaps.push_back( QgsAttributeMap() ); QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin(); int i = 0; for ( ; columnIt != mColumns.constEnd(); ++columnIt ) { int idx = mVectorLayer->fieldNameIndex(( *columnIt )->attribute() ); if ( idx != -1 ) { attributeMaps.last().insert( i, f.attributes()[idx] ); } else { // Lets assume it's an expression QgsExpression* expression = new QgsExpression(( *columnIt )->attribute() ); context->lastScope()->setVariable( QString( "_rownum_" ), counter + 1 ); expression->prepare( context.data() ); QVariant value = expression->evaluate( context.data() ); attributeMaps.last().insert( i, value.toString() ); } i++; } ++counter; } //sort the list, starting with the last attribute QgsComposerAttributeTableCompare c; QList< QPair<int, bool> > sortColumns = sortAttributes(); for ( int i = sortColumns.size() - 1; i >= 0; --i ) { c.setSortColumn( sortColumns.at( i ).first ); c.setAscending( sortColumns.at( i ).second ); qStableSort( attributeMaps.begin(), attributeMaps.end(), c ); } adjustFrameToSize(); return true; }
void QgsGeometryCheckerResultTab::highlightErrors( bool current ) { qDeleteAll( mCurrentRubberBands ); mCurrentRubberBands.clear(); QList<QTableWidgetItem *> items; QVector<QgsPointXY> errorPositions; QgsRectangle totextent; if ( current ) { items.append( ui.tableWidgetErrors->currentItem() ); } else { items.append( ui.tableWidgetErrors->selectedItems() ); } for ( QTableWidgetItem *item : items ) { QgsGeometryCheckError *error = ui.tableWidgetErrors->item( item->row(), 0 )->data( Qt::UserRole ).value<QgsGeometryCheckError *>(); const QgsAbstractGeometry *geometry = error->geometry(); if ( ui.checkBoxHighlight->isChecked() && geometry ) { QgsRubberBand *featureRubberBand = new QgsRubberBand( mIface->mapCanvas() ); QgsGeometry geom( geometry->clone() ); featureRubberBand->addGeometry( geom, nullptr ); featureRubberBand->setWidth( 5 ); featureRubberBand->setColor( Qt::yellow ); mCurrentRubberBands.append( featureRubberBand ); } if ( ui.radioButtonError->isChecked() || current || error->status() == QgsGeometryCheckError::StatusFixed ) { QgsRubberBand *pointRubberBand = new QgsRubberBand( mIface->mapCanvas(), QgsWkbTypes::PointGeometry ); pointRubberBand->addPoint( error->location() ); pointRubberBand->setWidth( 20 ); pointRubberBand->setColor( Qt::red ); mCurrentRubberBands.append( pointRubberBand ); errorPositions.append( error->location() ); } else if ( ui.radioButtonFeature->isChecked() ) { QgsRectangle geomextent = error->affectedAreaBBox(); if ( totextent.isEmpty() ) { totextent = geomextent; } else { totextent.combineExtentWith( geomextent ); } } } // If error positions positions are marked, pan to the center of all positions, // and zoom out if necessary to make all points fit. if ( !errorPositions.isEmpty() ) { double cx = 0., cy = 0.; QgsRectangle pointExtent( errorPositions.first(), errorPositions.first() ); Q_FOREACH ( const QgsPointXY &p, errorPositions ) { cx += p.x(); cy += p.y(); pointExtent.include( p ); }
void QgsRasterCalculator::readRasterPart( double* targetGeotransform, int xOffset, int yOffset, int nCols, int nRows, double* sourceTransform, GDALRasterBandH sourceBand, float* rasterBuffer ) { //If dataset transform is the same as the requested transform, do a normal GDAL raster io if ( transformationsEqual( targetGeotransform, sourceTransform ) ) { GDALRasterIO( sourceBand, GF_Read, xOffset, yOffset, nCols, nRows, rasterBuffer, nCols, nRows, GDT_Float32, 0, 0 ); return; } //pixel calculation needed because of different raster position / resolution int nodataSuccess; double nodataValue = GDALGetRasterNoDataValue( sourceBand, &nodataSuccess ); QgsRectangle targetRect( targetGeotransform[0] + targetGeotransform[1] * xOffset, targetGeotransform[3] + yOffset * targetGeotransform[5] + nRows * targetGeotransform[5] , targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] * nCols, targetGeotransform[3] + yOffset * targetGeotransform[5] ); QgsRectangle sourceRect( sourceTransform[0], sourceTransform[3] + GDALGetRasterBandYSize( sourceBand ) * sourceTransform[5], sourceTransform[0] + GDALGetRasterBandXSize( sourceBand )* sourceTransform[1], sourceTransform[3] ); QgsRectangle intersection = targetRect.intersect( &sourceRect ); //no intersection, fill all the pixels with nodata values if ( intersection.isEmpty() ) { int nPixels = nCols * nRows; for ( int i = 0; i < nPixels; ++i ) { rasterBuffer[i] = nodataValue; } return; } //do raster io in source resolution int sourcePixelOffsetXMin = floor(( intersection.xMinimum() - sourceTransform[0] ) / sourceTransform[1] ); int sourcePixelOffsetXMax = ceil(( intersection.xMaximum() - sourceTransform[0] ) / sourceTransform[1] ); int nSourcePixelsX = sourcePixelOffsetXMax - sourcePixelOffsetXMin; int sourcePixelOffsetYMax = floor(( intersection.yMaximum() - sourceTransform[3] ) / sourceTransform[5] ); int sourcePixelOffsetYMin = ceil(( intersection.yMinimum() - sourceTransform[3] ) / sourceTransform[5] ); int nSourcePixelsY = sourcePixelOffsetYMin - sourcePixelOffsetYMax; float* sourceRaster = ( float * ) CPLMalloc( sizeof( float ) * nSourcePixelsX * nSourcePixelsY ); double sourceRasterXMin = sourceRect.xMinimum() + sourcePixelOffsetXMin * sourceTransform[1]; double sourceRasterYMax = sourceRect.yMaximum() + sourcePixelOffsetYMax * sourceTransform[5]; GDALRasterIO( sourceBand, GF_Read, sourcePixelOffsetXMin, sourcePixelOffsetYMax, nSourcePixelsX, nSourcePixelsY, sourceRaster, nSourcePixelsX, nSourcePixelsY, GDT_Float32, 0, 0 ); double targetPixelX; double targetPixelXMin = targetGeotransform[0] + targetGeotransform[1] * xOffset + targetGeotransform[1] / 2.0; double targetPixelY = targetGeotransform[3] + targetGeotransform[5] * yOffset + targetGeotransform[5] / 2.0; //coordinates of current target pixel int sourceIndexX, sourceIndexY; //current raster index in source pixels double sx, sy; for ( int i = 0; i < nRows; ++i ) { targetPixelX = targetPixelXMin; for ( int j = 0; j < nCols; ++j ) { sx = ( targetPixelX - sourceRasterXMin ) / sourceTransform[1]; sourceIndexX = sx > 0 ? sx : floor( sx ); sy = ( targetPixelY - sourceRasterYMax ) / sourceTransform[5]; sourceIndexY = sy > 0 ? sy : floor( sy ); if ( sourceIndexX >= 0 && sourceIndexX < nSourcePixelsX && sourceIndexY >= 0 && sourceIndexY < nSourcePixelsY ) { rasterBuffer[j + i*nRows] = sourceRaster[ sourceIndexX + nSourcePixelsX * sourceIndexY ]; } else { rasterBuffer[j + i*j] = nodataValue; } targetPixelX += targetGeotransform[1]; } targetPixelY += targetGeotransform[5]; } CPLFree( sourceRaster ); return; }
void QgsRasterInterface::initHistogram( QgsRasterHistogram &theHistogram, int theBandNo, int theBinCount, double theMinimum, double theMaximum, const QgsRectangle & theExtent, int theSampleSize, bool theIncludeOutOfRange ) { theHistogram.bandNumber = theBandNo; theHistogram.minimum = theMinimum; theHistogram.maximum = theMaximum; theHistogram.includeOutOfRange = theIncludeOutOfRange; int mySrcDataType = sourceDataType( theBandNo ); if ( qIsNaN( theHistogram.minimum ) ) { // TODO: this was OK when stats/histogram were calced in provider, // but what TODO in other interfaces? Check for mInput for now. if ( !mInput && mySrcDataType == Qgis::Byte ) { theHistogram.minimum = 0; // see histogram() for shift for rounding } else { // We need statistics -> avoid histogramDefaults in hasHistogram if possible // TODO: use approximated statistics if aproximated histogram is requested // (theSampleSize > 0) QgsRasterBandStats stats = bandStatistics( theBandNo, QgsRasterBandStats::Min, theExtent, theSampleSize ); theHistogram.minimum = stats.minimumValue; } } if ( qIsNaN( theHistogram.maximum ) ) { if ( !mInput && mySrcDataType == Qgis::Byte ) { theHistogram.maximum = 255; } else { QgsRasterBandStats stats = bandStatistics( theBandNo, QgsRasterBandStats::Max, theExtent, theSampleSize ); theHistogram.maximum = stats.maximumValue; } } QgsRectangle myExtent; if ( theExtent.isEmpty() ) { myExtent = extent(); } else { myExtent = extent().intersect( &theExtent ); } theHistogram.extent = myExtent; if ( theSampleSize > 0 ) { // Calc resolution from theSampleSize double xRes, yRes; xRes = yRes = sqrt(( myExtent.width() * myExtent.height() ) / theSampleSize ); // But limit by physical resolution if ( capabilities() & Size ) { double srcXRes = extent().width() / xSize(); double srcYRes = extent().height() / ySize(); if ( xRes < srcXRes ) xRes = srcXRes; if ( yRes < srcYRes ) yRes = srcYRes; } QgsDebugMsgLevel( QString( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ), 4 ); theHistogram.width = static_cast <int>( myExtent.width() / xRes ); theHistogram.height = static_cast <int>( myExtent.height() / yRes ); } else { if ( capabilities() & Size ) { theHistogram.width = xSize(); theHistogram.height = ySize(); } else { theHistogram.width = 1000; theHistogram.height = 1000; } } QgsDebugMsgLevel( QString( "theHistogram.width = %1 theHistogram.height = %2" ).arg( theHistogram.width ).arg( theHistogram.height ), 4 ); int myBinCount = theBinCount; if ( myBinCount == 0 ) { // TODO: this was OK when stats/histogram were calced in provider, // but what TODO in other interfaces? Check for mInput for now. if ( !mInput && mySrcDataType == Qgis::Byte ) { myBinCount = 256; // Cannot store more values in byte } else { // There is no best default value, to display something reasonable in histogram chart, binCount should be small, OTOH, to get precise data for cumulative cut, the number should be big. Because it is easier to define fixed lower value for the chart, we calc optimum binCount for higher resolution (to avoid calculating that where histogram() is used. In any any case, it does not make sense to use more than width*height; myBinCount = theHistogram.width * theHistogram.height; if ( myBinCount > 1000 ) myBinCount = 1000; // for Int16/Int32 make sure bin count <= actual range, because there is no sense in having // bins at fractional values if ( !mInput && ( mySrcDataType == Qgis::Int16 || mySrcDataType == Qgis::Int32 || mySrcDataType == Qgis::UInt16 || mySrcDataType == Qgis::UInt32 ) ) { if ( myBinCount > theHistogram.maximum - theHistogram.minimum + 1 ) myBinCount = int( ceil( theHistogram.maximum - theHistogram.minimum + 1 ) ); } } } theHistogram.binCount = myBinCount; QgsDebugMsgLevel( QString( "theHistogram.binCount = %1" ).arg( theHistogram.binCount ), 4 ); }
QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext ) : QgsMapLayerRenderer( layer->id() ) , mRasterViewPort( nullptr ) , mPipe( nullptr ) , mContext( rendererContext ) , mFeedback( new Feedback( this ) ) { 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().isValid() ) { QgsDebugMsgLevel( "coordinateTransform set -> project extents.", 4 ); 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 { QgsDebugMsgLevel( "coordinateTransform not set", 4 ); 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; } QgsDebugMsgLevel( "theViewExtent is " + rendererContext.extent().toString(), 4 ); QgsDebugMsgLevel( "myProjectedViewExtent is " + myProjectedViewExtent.toString(), 4 ); QgsDebugMsgLevel( "myProjectedLayerExtent is " + myProjectedLayerExtent.toString(), 4 ); QgsDebugMsgLevel( "myRasterExtent is " + myRasterExtent.toString(), 4 ); // // 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().isValid() ) { mRasterViewPort->mSrcCRS = layer->crs(); mRasterViewPort->mDestCRS = rendererContext.coordinateTransform().destinationCrs(); 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 because //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( 25.4 * rendererContext.scaleFactor() ); // copy the whole raster pipe! mPipe = new QgsRasterPipe( *layer->pipe() ); QgsRasterRenderer* rasterRenderer = mPipe->renderer(); if ( rasterRenderer ) layer->refreshRendererIfNeeded( rasterRenderer, rendererContext.extent() ); }
QgsRectangle QgsCoordinateTransform::transformBoundingBox( const QgsRectangle &rect, TransformDirection direction, const bool handle180Crossover ) const { // Calculate the bounding box of a QgsRectangle in the source CRS // when projected to the destination CRS (or the inverse). // This is done by looking at a number of points spread evenly // across the rectangle if ( !d->mIsValid || d->mShortCircuit ) return rect; if ( rect.isEmpty() ) { QgsPointXY p = transform( rect.xMinimum(), rect.yMinimum(), direction ); return QgsRectangle( p, p ); } // 64 points (<=2.12) is not enough, see #13665, for EPSG:4326 -> EPSG:3574 (say that it is a hard one), // are decent result from about 500 points and more. This method is called quite often, but // even with 1000 points it takes < 1ms // TODO: how to effectively and precisely reproject bounding box? const int nPoints = 1000; double d = std::sqrt( ( rect.width() * rect.height() ) / std::pow( std::sqrt( static_cast< double >( nPoints ) ) - 1, 2.0 ) ); int nXPoints = static_cast< int >( std::ceil( rect.width() / d ) ) + 1; int nYPoints = static_cast< int >( std::ceil( rect.height() / d ) ) + 1; QgsRectangle bb_rect; bb_rect.setMinimal(); // We're interfacing with C-style vectors in the // end, so let's do C-style vectors here too. QVector<double> x( nXPoints * nYPoints ); QVector<double> y( nXPoints * nYPoints ); QVector<double> z( nXPoints * nYPoints ); QgsDebugMsgLevel( QStringLiteral( "Entering transformBoundingBox..." ), 4 ); // Populate the vectors double dx = rect.width() / static_cast< double >( nXPoints - 1 ); double dy = rect.height() / static_cast< double >( nYPoints - 1 ); double pointY = rect.yMinimum(); for ( int i = 0; i < nYPoints ; i++ ) { // Start at right edge double pointX = rect.xMinimum(); for ( int j = 0; j < nXPoints; j++ ) { x[( i * nXPoints ) + j] = pointX; y[( i * nXPoints ) + j] = pointY; // and the height... z[( i * nXPoints ) + j] = 0.0; // QgsDebugMsg(QString("BBox coord: (%1, %2)").arg(x[(i*numP) + j]).arg(y[(i*numP) + j])); pointX += dx; } pointY += dy; } // Do transformation. Any exception generated must // be handled in above layers. try { transformCoords( nXPoints * nYPoints, x.data(), y.data(), z.data(), direction ); } catch ( const QgsCsException & ) { // rethrow the exception QgsDebugMsg( QStringLiteral( "rethrowing exception" ) ); throw; } // Calculate the bounding box and use that for the extent for ( int i = 0; i < nXPoints * nYPoints; i++ ) { if ( !std::isfinite( x[i] ) || !std::isfinite( y[i] ) ) { continue; } if ( handle180Crossover ) { //if crossing the date line, temporarily add 360 degrees to -ve longitudes bb_rect.combineExtentWith( x[i] >= 0.0 ? x[i] : x[i] + 360.0, y[i] ); } else { bb_rect.combineExtentWith( x[i], y[i] ); } } if ( bb_rect.isNull() ) { // something bad happened when reprojecting the filter rect... no finite points were left! throw QgsCsException( QObject::tr( "Could not transform bounding box to target CRS" ) ); } if ( handle180Crossover ) { //subtract temporary addition of 360 degrees from longitudes if ( bb_rect.xMinimum() > 180.0 ) bb_rect.setXMinimum( bb_rect.xMinimum() - 360.0 ); if ( bb_rect.xMaximum() > 180.0 ) bb_rect.setXMaximum( bb_rect.xMaximum() - 360.0 ); } QgsDebugMsgLevel( "Projected extent: " + bb_rect.toString(), 4 ); if ( bb_rect.isEmpty() ) { QgsDebugMsgLevel( "Original extent: " + rect.toString(), 4 ); } return bb_rect; }
QVariantMap QgsZonalHistogramAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { std::unique_ptr< QgsFeatureSource > zones( parameterAsSource( parameters, QStringLiteral( "INPUT_VECTOR" ), context ) ); if ( !zones ) throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT_VECTOR" ) ) ); long count = zones->featureCount(); double step = count > 0 ? 100.0 / count : 1; long current = 0; QList< double > uniqueValues; QMap< QgsFeatureId, QHash< double, qgssize > > featuresUniqueValues; // First loop through the zones to build up a list of unique values across all zones to determine sink fields list QgsFeatureRequest request; request.setNoAttributes(); if ( zones->sourceCrs() != mCrs ) { request.setDestinationCrs( mCrs, context.transformContext() ); } QgsFeatureIterator it = zones->getFeatures( request ); QgsFeature f; while ( it.nextFeature( f ) ) { if ( feedback && feedback->isCanceled() ) { break; } feedback->setProgress( current * step ); if ( !f.hasGeometry() ) { current++; continue; } QgsGeometry featureGeometry = f.geometry(); QgsRectangle featureRect = featureGeometry.boundingBox().intersect( mRasterExtent ); if ( featureRect.isEmpty() ) { current++; continue; } int nCellsX, nCellsY; QgsRectangle rasterBlockExtent; QgsRasterAnalysisUtils::cellInfoForBBox( mRasterExtent, featureRect, mCellSizeX, mCellSizeY, nCellsX, nCellsY, mNbCellsXProvider, mNbCellsYProvider, rasterBlockExtent ); QHash< double, qgssize > fUniqueValues; QgsRasterAnalysisUtils::statisticsFromMiddlePointTest( mRasterInterface.get(), mRasterBand, featureGeometry, nCellsX, nCellsY, mCellSizeX, mCellSizeY, rasterBlockExtent, [ &fUniqueValues]( double value ) { fUniqueValues[value]++; }, false ); if ( fUniqueValues.count() < 1 ) { // The cell resolution is probably larger than the polygon area. We switch to slower precise pixel - polygon intersection in this case // TODO: eventually deal with weight if needed QgsRasterAnalysisUtils::statisticsFromPreciseIntersection( mRasterInterface.get(), mRasterBand, featureGeometry, nCellsX, nCellsY, mCellSizeX, mCellSizeY, rasterBlockExtent, [ &fUniqueValues]( double value, double ) { fUniqueValues[value]++; }, false ); } for ( auto it = fUniqueValues.constBegin(); it != fUniqueValues.constEnd(); ++it ) { if ( uniqueValues.indexOf( it.key() ) == -1 ) { uniqueValues << it.key(); } featuresUniqueValues[f.id()][it.key()] += it.value(); } current++; } std::sort( uniqueValues.begin(), uniqueValues.end() ); QString fieldPrefix = parameterAsString( parameters, QStringLiteral( "COLUMN_PREFIX" ), context ); QgsFields newFields; for ( auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it ) { newFields.append( QgsField( QStringLiteral( "%1%2" ).arg( fieldPrefix, mHasNoDataValue && *it == mNodataValue ? QStringLiteral( "NODATA" ) : QString::number( *it ) ), QVariant::LongLong, QString(), -1, 0 ) ); } QgsFields fields = QgsProcessingUtils::combineFields( zones->fields(), newFields ); QString dest; std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, zones->wkbType(), zones->sourceCrs() ) ); if ( !sink ) throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); it = zones->getFeatures( QgsFeatureRequest() ); while ( it.nextFeature( f ) ) { QgsAttributes attributes = f.attributes(); QHash< double, qgssize > fUniqueValues = featuresUniqueValues.value( f.id() ); for ( auto it = uniqueValues.constBegin(); it != uniqueValues.constEnd(); ++it ) { attributes += fUniqueValues.value( *it, 0 ); } QgsFeature outputFeature; outputFeature.setGeometry( f.geometry() ); outputFeature.setAttributes( attributes ); sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ); } QVariantMap outputs; outputs.insert( QStringLiteral( "OUTPUT" ), dest ); return outputs; }
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->mapSettings().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; } } mRotationInt += mapCanvas->mapSettings().rotation(); return goodDirn; }
void QgsInterpolationDialog::on_buttonBox_accepted() { if ( !mInterpolatorDialog ) { return; } QgsRectangle outputBBox = currentBoundingBox(); if ( outputBBox.isEmpty() ) { return; } //warn the user if there isn't any input layer if ( mLayersTreeWidget->topLevelItemCount() < 1 ) { QMessageBox::information( nullptr, tr( "No input data for interpolation" ), tr( "Please add one or more input layers" ) ); return; } //read file name QString fileName = mOutputFileLineEdit->text(); QFileInfo theFileInfo( fileName ); if ( fileName.isEmpty() || !theFileInfo.dir().exists() ) { QMessageBox::information( nullptr, tr( "Output file name invalid" ), tr( "Please enter a valid output file name" ) ); return; } //add .asc suffix if the user did not provider it already QString suffix = theFileInfo.suffix(); if ( suffix.isEmpty() ) { fileName.append( ".asc" ); } int nLayers = mLayersTreeWidget->topLevelItemCount(); QList< QgsInterpolator::LayerData > inputLayerList; for ( int i = 0; i < nLayers; ++i ) { QString layerName = mLayersTreeWidget->topLevelItem( i )->text( 0 ); QgsVectorLayer* theVectorLayer = vectorLayerFromName( layerName ); if ( !theVectorLayer ) { continue; } QgsVectorDataProvider* theProvider = theVectorLayer->dataProvider(); if ( !theProvider ) { continue; } QgsInterpolator::LayerData currentLayerData; currentLayerData.vectorLayer = theVectorLayer; QString interpolationAttString = mLayersTreeWidget->topLevelItem( i )->text( 1 ); if ( interpolationAttString == "Z_COORD" ) { currentLayerData.zCoordInterpolation = true; currentLayerData.interpolationAttribute = -1; } else { currentLayerData.zCoordInterpolation = false; int attributeIndex = theProvider->fieldNameIndex( interpolationAttString ); currentLayerData.interpolationAttribute = attributeIndex; } //type (point/structure line/ breakline) QComboBox* itemCombo = qobject_cast<QComboBox *>( mLayersTreeWidget->itemWidget( mLayersTreeWidget->topLevelItem( i ), 2 ) ); if ( itemCombo ) { QString typeString = itemCombo->currentText(); if ( typeString == tr( "Break lines" ) ) { currentLayerData.mInputType = QgsInterpolator::BREAK_LINES; } else if ( typeString == tr( "Structure lines" ) ) { currentLayerData.mInputType = QgsInterpolator::STRUCTURE_LINES; } else //Points { currentLayerData.mInputType = QgsInterpolator::POINTS; } } else { currentLayerData.mInputType = QgsInterpolator::POINTS; } inputLayerList.push_back( currentLayerData ); } mInterpolatorDialog->setInputData( inputLayerList ); QgsInterpolator* theInterpolator = mInterpolatorDialog->createInterpolator(); if ( !theInterpolator ) { return; } //create grid file writer QgsGridFileWriter theWriter( theInterpolator, fileName, outputBBox, mNumberOfColumnsSpinBox->value(), mNumberOfRowsSpinBox->value(), mCellsizeXSpinBox->value(), mCellSizeYSpinBox->value() ); if ( theWriter.writeFile( true ) == 0 ) { if ( mAddResultToProjectCheckBox->isChecked() ) { mIface->addRasterLayer( fileName, QFileInfo( fileName ).baseName() ); } accept(); } delete theInterpolator; }