QgsRasterBlock * QgsRasterNuller::block( int bandNo, QgsRectangle const & extent, int width, int height ) { QgsDebugMsg( "Entered" ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } //void * rasterData = mInput->block( bandNo, extent, width, height ); QgsRasterBlock *inputBlock = mInput->block( bandNo, extent, width, height ); // Input may be without no data value //double noDataValue = mInput->noDataValue( bandNo ); double noDataValue = mOutputNoData; for ( int i = 0; i < height; i++ ) { for ( int j = 0; j < width; j++ ) { //int index = i * width + j; //double value = readValue( rasterData, dataType, index ); double value = inputBlock->value( i, j ); foreach ( NoData noData, mNoData ) { if (( value >= noData.min && value <= noData.max ) || doubleNear( value, noData.min ) || doubleNear( value, noData.max ) ) { inputBlock->setValue( i, j, noDataValue ); } } } } return inputBlock; }
void * QgsRasterNuller::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { QgsDebugMsg( "Entered" ); if ( !mInput ) return 0; //QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() ); void * rasterData = mInput->block( bandNo, extent, width, height ); QgsRasterInterface::DataType dataType = mInput->dataType( bandNo ); int pixelSize = mInput->typeSize( dataType ) / 8; double noDataValue = mInput->noDataValue ( bandNo ); for ( int i = 0; i < height; ++i ) { for ( int j = 0; j < width; ++j ) { int index = pixelSize * ( i * width + j ); double value = readValue( rasterData, dataType, index ); foreach ( NoData noData, mNoData ) { if ( ( value >= noData.min && value <= noData.max ) || doubleNear( value, noData.min ) || doubleNear( value, noData.max ) ) { writeValue( rasterData, dataType, index, noDataValue ); } } } } return rasterData; }
QgsSvgCacheEntry* QgsSvgCache::cacheEntry( const QString& file, double size, const QColor& fill, const QColor& outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor ) { //search entries in mEntryLookup QgsSvgCacheEntry* currentEntry = 0; QList<QgsSvgCacheEntry*> entries = mEntryLookup.values( file ); QList<QgsSvgCacheEntry*>::iterator entryIt = entries.begin(); for ( ; entryIt != entries.end(); ++entryIt ) { QgsSvgCacheEntry* cacheEntry = *entryIt; if ( cacheEntry->file == file && doubleNear( cacheEntry->size, size ) && cacheEntry->fill == fill && cacheEntry->outline == outline && cacheEntry->outlineWidth == outlineWidth && cacheEntry->widthScaleFactor == widthScaleFactor && cacheEntry->rasterScaleFactor == rasterScaleFactor ) { currentEntry = cacheEntry; break; } } //if not found: create new entry //cache and replace params in svg content if ( !currentEntry ) { currentEntry = insertSVG( file, size, fill, outline, outlineWidth, widthScaleFactor, rasterScaleFactor ); } else { takeEntryFromList( currentEntry ); if ( !mMostRecentEntry ) //list is empty { mMostRecentEntry = currentEntry; mLeastRecentEntry = currentEntry; } else { mMostRecentEntry->nextEntry = currentEntry; currentEntry->previousEntry = mMostRecentEntry; currentEntry->nextEntry = 0; mMostRecentEntry = currentEntry; } } //debugging //printEntryList(); return currentEntry; }
void QgsImageFillSymbolLayer::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsSymbolV2RenderContext& context ) { QPainter* p = context.renderContext().painter(); if ( !p ) { return; } p->setPen( QPen( Qt::NoPen ) ); if ( context.selected() ) { QColor selColor = context.selectionColor(); // Alister - this doesn't seem to work here //if ( ! selectionIsOpaque ) // selColor.setAlphaF( context.alpha() ); p->setBrush( QBrush( selColor ) ); _renderPolygon( p, points, rings ); } if ( doubleNear( mAngle, 0.0 ) ) { p->setBrush( mBrush ); } else { QTransform t = mBrush.transform(); t.rotate( mAngle ); QBrush rotatedBrush = mBrush; rotatedBrush.setTransform( t ); p->setBrush( rotatedBrush ); } _renderPolygon( p, points, rings ); if ( mOutline ) { mOutline->renderPolyline( points, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() ); if ( rings ) { QList<QPolygonF>::const_iterator ringIt = rings->constBegin(); for ( ; ringIt != rings->constEnd(); ++ringIt ) { mOutline->renderPolyline( *ringIt, context.feature(), context.renderContext(), -1, selectFillBorder && context.selected() ); } } } }
void QgsSvgCache::cachePicture( QgsSvgCacheEntry *entry ) { if ( !entry ) { return; } delete entry->picture; entry->picture = 0; //correct QPictures dpi correction QPicture* picture = new QPicture(); QRectF rect; QSvgRenderer r( entry->svgContent ); double hwRatio = 1.0; if ( r.viewBoxF().width() > 0 ) { hwRatio = r.viewBoxF().height() / r.viewBoxF().width(); } bool drawOnScreen = doubleNear( entry->rasterScaleFactor, 1.0, 0.1 ); if ( drawOnScreen ) { // fix to ensure rotated symbols scale with composer page (i.e. not map item) zoom double wSize = entry->size; double hSize = wSize * hwRatio; QSizeF s( r.viewBoxF().size() ); s.scale( wSize, hSize, Qt::KeepAspectRatio ); rect = QRectF( -s.width() / 2.0, -s.height() / 2.0, s.width(), s.height() ); } else { // output for print or image saving @ specific dpi double scaledSize = entry->size / 25.4 / ( entry->rasterScaleFactor * entry->widthScaleFactor ); double wSize = scaledSize * picture->logicalDpiX(); double hSize = scaledSize * picture->logicalDpiY() * r.viewBoxF().height() / r.viewBoxF().width(); rect = QRectF( QPointF( -wSize / 2.0, -hSize / 2.0 ), QSizeF( wSize, hSize ) ); } QPainter p( picture ); r.render( &p, rect ); entry->picture = picture; mTotalSize += entry->picture->size(); }
double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint ) const { double nx, ny; //normal vector nx = y2 - y1; ny = -( x2 - x1 ); double t; t = ( m_x * ny - m_y * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx ); if ( t < 0.0 ) { minDistPoint.setX( x1 ); minDistPoint.setY( y1 ); } else if ( t > 1.0 ) { minDistPoint.setX( x2 ); minDistPoint.setY( y2 ); } else { minDistPoint.setX( x1 + t *( x2 - x1 ) ); minDistPoint.setY( y1 + t *( y2 - y1 ) ); } double dist = sqrDist( minDistPoint ); //prevent rounding errors if the point is directly on the segment if ( doubleNear( dist, 0.0, 0.00000001 ) ) { minDistPoint.setX( m_x ); minDistPoint.setY( m_y ); return 0.0; } return dist; }
QgsRasterBlock * QgsRasterResampleFilter::block( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); QgsDebugMsg( "Entered" ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) return outputBlock; double oversampling = 1.0; // approximate global oversampling factor if ( mZoomedInResampler || mZoomedOutResampler ) { QgsRasterDataProvider *provider = dynamic_cast<QgsRasterDataProvider*>( mInput->srcInput() ); // Do not oversample if data source does not have fixed resolution (WMS) if ( provider && ( provider->capabilities() & QgsRasterDataProvider::ExactResolution ) ) { double xRes = extent.width() / width; double providerXRes = provider->extent().width() / provider->xSize(); double pixelRatio = xRes / providerXRes; oversampling = ( pixelRatio > mMaxOversampling ) ? mMaxOversampling : pixelRatio; QgsDebugMsg( QString( "xRes = %1 providerXRes = %2 pixelRatio = %3 oversampling = %4" ).arg( xRes ).arg( providerXRes ).arg( pixelRatio ).arg( oversampling ) ); } } //set oversampling back to 1.0 if no resampler for zoomed in / zoomed out (nearest neighbour) if (( oversampling < 1.0 && !mZoomedInResampler ) || ( oversampling > 1.0 && !mZoomedOutResampler ) ) { oversampling = 1.0; } QgsDebugMsg( QString( "oversampling %1" ).arg( oversampling ) ); //effective oversampling factors are different to global one because of rounding double oversamplingX = (( double )width * oversampling ) / width; double oversamplingY = (( double )height * oversampling ) / height; // TODO: we must also increase the extent to get correct result on borders of parts int resWidth = width * oversamplingX; int resHeight = height * oversamplingY; // At moment we know that we read rendered image int bandNumber = 1; //void *rasterData = mInput->block( bandNumber, extent, resWidth, resHeight ); QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, resWidth, resHeight ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } if ( doubleNear( oversamplingX, 1.0 ) || doubleNear( oversamplingY, 1.0 ) ) { QgsDebugMsg( "No oversampling." ); delete outputBlock; return inputBlock; } if ( !outputBlock->reset( QgsRasterBlock::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; return outputBlock; } //resample image QImage img = inputBlock->image(); QImage dstImg = QImage( width, height, QImage::Format_ARGB32_Premultiplied ); if ( mZoomedInResampler && oversamplingX < 1.0 ) { QgsDebugMsg( "zoomed in resampling" ); mZoomedInResampler->resample( img, dstImg ); } else if ( mZoomedOutResampler && oversamplingX > 1.0 ) { QgsDebugMsg( "zoomed out resampling" ); mZoomedOutResampler->resample( img, dstImg ); } else { // Should not happen QgsDebugMsg( "Unexpected resampling" ); dstImg = img.scaled( width, height ); } outputBlock->setImage( &dstImg ); delete inputBlock; return outputBlock; // No resampling }
QImage* QgsPieDiagramFactory::createDiagram( int size, const QgsFeature& f, const QgsRenderContext& renderContext ) const { QgsAttributeMap dataValues = f.attributeMap(); double sizeScaleFactor = diagramSizeScaleFactor( renderContext ); //create transparent QImage int imageSideLength = size * sizeScaleFactor * renderContext.rasterScaleFactor() + 2 * mMaximumPenWidth + 2 * mMaximumGap; QImage* diagramImage = new QImage( QSize( imageSideLength, imageSideLength ), QImage::Format_ARGB32_Premultiplied ); diagramImage->fill( qRgba( 0, 0, 0, 0 ) ); //transparent background QPainter p; p.begin( diagramImage ); p.setRenderHint( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); //calculate sum of data values double sum = 0; QList<double> valueList; //cash the values to use them in drawing later QgsAttributeMap::const_iterator value_it; QList<QgsDiagramCategory>::const_iterator it = mCategories.constBegin(); for ( ; it != mCategories.constEnd(); ++it ) { value_it = dataValues.find( it->propertyIndex() ); valueList.push_back( value_it->toDouble() ); if ( value_it != dataValues.constEnd() ) { sum += value_it->toDouble(); } } if ( doubleNear( sum, 0.0 ) ) { p.end(); delete diagramImage; return 0; } //draw pies int totalAngle = 0; int currentAngle, currentGap; int xGapOffset = 0; int yGapOffset = 0; QList<QgsDiagramCategory>::const_iterator category_it = mCategories.constBegin(); QList<double>::const_iterator valueList_it = valueList.constBegin(); for ( ; category_it != mCategories.constEnd() && valueList_it != valueList.constEnd(); ++category_it, ++valueList_it ) { p.setPen( category_it->pen() ); currentAngle = ( int )(( *valueList_it ) / sum * 360 * 16 ); p.setBrush( category_it->brush() ); xGapOffset = 0; yGapOffset = 0; currentGap = category_it->gap(); if ( currentGap != 0 ) { //qt angles are degrees*16 gapOffsetsForPieSlice( currentGap, totalAngle + currentAngle / 2, xGapOffset, yGapOffset ); } p.drawPie( mMaximumPenWidth * renderContext.rasterScaleFactor() + mMaximumGap + xGapOffset, mMaximumPenWidth * renderContext.rasterScaleFactor() + mMaximumGap - yGapOffset, sizeScaleFactor * renderContext.rasterScaleFactor() * size, sizeScaleFactor * renderContext.rasterScaleFactor() * size, totalAngle, currentAngle ); totalAngle += currentAngle; } p.end(); return diagramImage; }
void * QgsMultiBandColorRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); if ( !mInput ) { return 0; } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency() && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement && !mInvertColor ); QgsRasterInterface::DataType redType = QgsRasterInterface::UnknownDataType; if ( mRedBand > 0 ) { redType = ( QgsRasterInterface::DataType )mInput->dataType( mRedBand ); } QgsRasterInterface::DataType greenType = QgsRasterInterface::UnknownDataType; if ( mGreenBand > 0 ) { greenType = ( QgsRasterInterface::DataType )mInput->dataType( mGreenBand ); } QgsRasterInterface::DataType blueType = QgsRasterInterface::UnknownDataType; if ( mBlueBand > 0 ) { blueType = ( QgsRasterInterface::DataType )mInput->dataType( mBlueBand ); } QgsRasterInterface::DataType transparencyType = QgsRasterInterface::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand ); } QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.size() < 1 ) { return 0; //no need to draw anything if no band is set } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, void*> bandData; void* defaultPointer = 0; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); } void* redData = 0; void* greenData = 0; void* blueData = 0; void* alphaData = 0; bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData[*bandIt] = mInput->block( *bandIt, extent, width, height ); if ( !bandData[*bandIt] ) { // We should free the alloced mem from block(). QgsDebugMsg( "No input band" ); bandIt--; for ( ; bandIt != bands.constBegin(); bandIt-- ) { VSIFree( bandData[*bandIt] ); } return 0; } } if ( mRedBand > 0 ) { redData = bandData[mRedBand]; } if ( mGreenBand > 0 ) { greenData = bandData[mGreenBand]; } if ( mBlueBand > 0 ) { blueData = bandData[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaData = bandData[mAlphaBand]; } QImage img( width, height, QImage::Format_ARGB32_Premultiplied ); if ( img.isNull() ) { QgsDebugMsg( "Could not create QImage" ); bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { VSIFree( bandData[*bandIt] ); } return 0; } QRgb* imageScanLine = 0; int currentRasterPos = 0; int redVal = 0; int greenVal = 0; int blueVal = 0; QRgb defaultColor = qRgba( 255, 255, 255, 0 ); double currentOpacity = mOpacity; //opacity (between 0 and 1) for ( int i = 0; i < height; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < width; ++j ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { redVal = readValue( redData, redType, currentRasterPos ); greenVal = readValue( greenData, greenType, currentRasterPos ); blueVal = readValue( blueData, blueType, currentRasterPos ); if ( mInput->isNoDataValue( mRedBand, redVal ) || mInput->isNoDataValue( mGreenBand, greenVal ) || mInput->isNoDataValue( mBlueBand, blueVal ) ) { imageScanLine[j] = defaultColor; } else { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } ++currentRasterPos; continue; } bool isNoData = false; if ( mRedBand > 0 ) { redVal = readValue( redData, redType, currentRasterPos ); if ( mInput->isNoDataValue( mRedBand, redVal ) ) isNoData = true; } if ( mGreenBand > 0 ) { greenVal = readValue( greenData, greenType, currentRasterPos ); if ( mInput->isNoDataValue( mGreenBand, greenVal ) ) isNoData = true; } if ( mBlueBand > 0 ) { blueVal = readValue( blueData, blueType, currentRasterPos ); if ( mInput->isNoDataValue( mBlueBand, blueVal ) ) isNoData = true; } if ( isNoData ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //apply default color if red, green or blue not in displayable range if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } if ( mInvertColor ) { redVal = 255 - redVal; greenVal = 255 - greenVal; blueVal = 255 - blueVal; } //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redVal, greenVal, blueVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 ); } if ( doubleNear( currentOpacity, 1.0 ) ) { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } else { imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ); } ++currentRasterPos; } } bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { VSIFree( bandData[*bandIt] ); } void * data = VSIMalloc( img.byteCount() ); if ( ! data ) { QgsDebugMsg( QString( "Couldn't allocate output data memory of % bytes" ).arg( img.byteCount() ) ); return 0; } return memcpy( data, img.bits(), img.byteCount() ); }
void QgsLinePatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context ) { double outlinePixelWidth = context.outputPixelSize( mLineWidth ); double outputPixelDist = context.outputPixelSize( mDistance ); double outputPixelOffset = context.outputPixelSize( mOffset ); //create image int height, width; if ( doubleNear( mLineAngle, 0 ) || doubleNear( mLineAngle, 360 ) || doubleNear( mLineAngle, 90 ) || doubleNear( mLineAngle, 180 ) || doubleNear( mLineAngle, 270 ) ) { height = outputPixelDist; width = height; //width can be set to arbitrary value } else { height = qAbs( outputPixelDist / cos( mLineAngle * M_PI / 180 ) ); //keep perpendicular distance between lines constant width = qAbs( height / tan( mLineAngle * M_PI / 180 ) ); } //depending on the angle, we might need to render into a larger image and use a subset of it int dx = 0; int dy = 0; QImage patternImage( width, height, QImage::Format_ARGB32 ); patternImage.fill( 0 ); QPainter p( &patternImage ); p.setRenderHint( QPainter::Antialiasing, true ); QPen pen( mColor ); pen.setWidthF( outlinePixelWidth ); pen.setCapStyle( Qt::FlatCap ); p.setPen( pen ); QPoint p1, p2, p3, p4, p5, p6; if ( doubleNear( mLineAngle, 0.0 ) || doubleNear( mLineAngle, 360.0 ) || doubleNear( mLineAngle, 180.0 ) ) { p1 = QPoint( 0, height ); p2 = QPoint( width, height ); p3 = QPoint( 0, 0 ); p4 = QPoint( width, 0 ); p5 = QPoint( 0, 2 * height ); p6 = QPoint( width, 2 * height ); } else if ( doubleNear( mLineAngle, 90.0 ) || doubleNear( mLineAngle, 270.0 ) ) { p1 = QPoint( 0, height ); p2 = QPoint( 0, 0 ); p3 = QPoint( width, height ); p4 = QPoint( width, 0 ); p5 = QPoint( -width, height ); p6 = QPoint( -width, 0 ); } else if (( mLineAngle > 0 && mLineAngle < 90 ) || ( mLineAngle > 180 && mLineAngle < 270 ) ) { dx = outputPixelDist * cos(( 90 - mLineAngle ) * M_PI / 180.0 ); dy = outputPixelDist * sin(( 90 - mLineAngle ) * M_PI / 180.0 ); p1 = QPoint( 0, height ); p2 = QPoint( width, 0 ); p3 = QPoint( -dx, height - dy ); p4 = QPoint( width - dx, -dy ); //p4 = QPoint( p3.x() + width, p3.y() - height ); p5 = QPoint( dx, height + dy ); p6 = QPoint( width + dx, dy ); //p6 = QPoint( p5.x() + width, p5.y() - height ); } else if (( mLineAngle < 180 ) || ( mLineAngle > 270 && mLineAngle < 360 ) ) { dy = outputPixelDist * cos(( 180 - mLineAngle ) * M_PI / 180 ); dx = outputPixelDist * sin(( 180 - mLineAngle ) * M_PI / 180 ); p1 = QPoint( width, height ); p2 = QPoint( 0, 0 ); p5 = QPoint( width + dx, height - dy ); p6 = QPoint( p5.x() - width, p5.y() - height ); //p6 = QPoint( dx, -dy ); p3 = QPoint( width - dx, height + dy ); p4 = QPoint( p3.x() - width, p3.y() - height ); //p4 = QPoint( -dx, dy ); } if ( !doubleNear( mOffset, 0.0 ) ) //shift everything { QPointF tempPt; tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelDist + outputPixelOffset ); p3 = QPoint( tempPt.x(), tempPt.y() ); tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelDist + outputPixelOffset ); p4 = QPoint( tempPt.x(), tempPt.y() ); tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p5, outputPixelDist - outputPixelOffset ); p5 = QPoint( tempPt.x(), tempPt.y() ); tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p6, outputPixelDist - outputPixelOffset ); p6 = QPoint( tempPt.x(), tempPt.y() ); //update p1, p2 last tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p1, p3, outputPixelOffset ).toPoint(); p1 = QPoint( tempPt.x(), tempPt.y() ); tempPt = QgsSymbolLayerV2Utils::pointOnLineWithDistance( p2, p4, outputPixelOffset ).toPoint(); p2 = QPoint( tempPt.x(), tempPt.y() );; } p.drawLine( p1, p2 ); p.drawLine( p3, p4 ); p.drawLine( p5, p6 ); p.end(); //set image to mBrush if ( !doubleNear( context.alpha(), 1.0 ) ) { QImage transparentImage = patternImage.copy(); QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() ); mBrush.setTextureImage( transparentImage ); } else { mBrush.setTextureImage( patternImage ); } QTransform brushTransform; brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() ); mBrush.setTransform( brushTransform ); if ( mOutline ) { mOutline->startRender( context.renderContext() ); } }
void QgsPointPatternFillSymbolLayer::startRender( QgsSymbolV2RenderContext& context ) { //render 3 rows and columns in one go to easily incorporate displacement double width = context.outputPixelSize( mDistanceX ) * 2.0; double height = context.outputPixelSize( mDistanceY ) * 2.0; QImage patternImage( width, height, QImage::Format_ARGB32 ); patternImage.fill( 0 ); if ( mMarkerSymbol ) { QPainter p( &patternImage ); //marker rendering needs context for drawing on patternImage QgsRenderContext pointRenderContext; pointRenderContext.setPainter( &p ); pointRenderContext.setRasterScaleFactor( 1.0 ); pointRenderContext.setScaleFactor( context.renderContext().scaleFactor() * context.renderContext().rasterScaleFactor() ); QgsMapToPixel mtp( context.renderContext().mapToPixel().mapUnitsPerPixel() / context.renderContext().rasterScaleFactor() ); pointRenderContext.setMapToPixel( mtp ); pointRenderContext.setForceVectorOutput( false ); mMarkerSymbol->setOutputUnit( context.outputUnit() ); mMarkerSymbol->startRender( pointRenderContext ); //render corner points mMarkerSymbol->renderPoint( QPointF( 0, 0 ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( width, 0 ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( 0, height ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( width, height ), context.feature(), pointRenderContext ); //render displaced points double displacementPixelX = context.outputPixelSize( mDisplacementX ); double displacementPixelY = context.outputPixelSize( mDisplacementY ); mMarkerSymbol->renderPoint( QPointF( width / 2.0, -displacementPixelY ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( width / 2.0 + displacementPixelX, height / 2.0 - displacementPixelY ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( width + displacementPixelX, height / 2.0 ), context.feature(), pointRenderContext ); mMarkerSymbol->renderPoint( QPointF( width / 2.0, height - displacementPixelY ), context.feature(), pointRenderContext ); mMarkerSymbol->stopRender( pointRenderContext ); } if ( !doubleNear( context.alpha(), 1.0 ) ) { QImage transparentImage = patternImage.copy(); QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() ); mBrush.setTextureImage( transparentImage ); } else { mBrush.setTextureImage( patternImage ); } QTransform brushTransform; brushTransform.scale( 1.0 / context.renderContext().rasterScaleFactor(), 1.0 / context.renderContext().rasterScaleFactor() ); mBrush.setTransform( brushTransform ); if ( mOutline ) { mOutline->startRender( context.renderContext() ); } }
bool QgsMapToolSimplify::calculateSliderBoudaries() { double minTolerance = -1, maxTolerance = -1; double tol = 0.000001; bool found = false; bool isLine = mSelectedFeature.geometry()->type() == QGis::Line; QVector<QgsPoint> pts = getPointList( mSelectedFeature ); int size = pts.size(); if ( size == 0 || ( isLine && size <= 2 ) || ( !isLine && size <= 4 ) ) { return false; } // calculate minimum tolerance where no vertex is excluded bool maximized = false; int count = 0; while ( !found ) { count++; if ( count == 30 && !maximized ) { //special case when tolerance is too low to be correct so it's near 0 // else in some special cases this algorithm would create infinite loop found = true; minTolerance = 0; } if ( QgsSimplifyFeature::simplifyPoints( pts, tol ).size() < size ) { //some vertexes were already excluded if ( maximized ) //if we were already in second direction end { found = true; minTolerance = tol / 2; } else //only lowering tolerance till it's low enough to have all vertexes { tol = tol / 2; } } else { // simplified feature has all vertexes therefore no need we need higher tolerance also ending flag set // when some tolerance will exclude some of vertexes maximized = true; tol = tol * 2; } } found = false; int requiredCnt = ( isLine ? 2 : 4 ); //4 for polygon is correct because first and last points are the same bool bottomFound = false; double highTol = DBL_MAX, lowTol = DBL_MIN;// two boundaries to be used when no directly correct solution is found // calculate minimum tolerance where minimum (requiredCnt) of vertexes are left in geometry while ( !found ) { int foundVertexes = QgsSimplifyFeature::simplifyPoints( pts, tol ).size(); if ( foundVertexes < requiredCnt + 1 ) { //required or lower number of verticies found if ( foundVertexes == requiredCnt ) { found = true; maxTolerance = tol; } else { //solving problem that polygon would have less than minimum alowed vertexes bottomFound = true; highTol = tol; tol = ( highTol + lowTol ) / 2; if ( doubleNear( highTol, lowTol ) ) { //solving problem that two points are in same distance from line, so they will be both excluded at same time //so some time more than required count of vertices can stay found = true; maxTolerance = lowTol; } } } else { if ( bottomFound ) { lowTol = tol; tol = ( highTol + lowTol ) / 2; if ( doubleNear( highTol, lowTol ) ) { //solving problem that two points are in same distance from line, so they will be both excluded at same time //so some time more than required count of vertices can stay found = true; maxTolerance = lowTol; } } else { //still too much verticies left so we need to increase tolerance lowTol = tol; tol = tol * 2; } } } toleranceDivider = calculateDivider( minTolerance, maxTolerance ); // set min and max mSimplifyDialog->setRange( int( minTolerance * toleranceDivider ), int( maxTolerance * toleranceDivider ) ); return true; }
bool QgsRasterRenderer::usesTransparency( ) const { if ( !mInput ) { return true; } // TODO: nodata per band return ( mAlphaBand > 0 || ( mRasterTransparency && !mRasterTransparency->isEmpty( mInput->noDataValue( 1 ) ) ) || !doubleNear( mOpacity, 1.0 ) ); }
void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 ) { bool reversed = false; pt1Ok = false; pt2Ok = false; double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints if ( m1 > m2 ) { double tmp = m1; m1 = m2; m2 = tmp; reversed = true; } //segment does not match if (( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance ) { pt1Ok = false; pt2Ok = false; return; } //match with vertex1 if ( doubleNear( m1, measure, tolerance ) ) { if ( reversed ) { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } else { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } } //match with vertex2 if ( doubleNear( m2, measure, tolerance ) ) { if ( reversed ) { pt1Ok = true; pt1.setX( x1 ); pt1.setY( y1 ); } else { pt2Ok = true; pt2.setX( x2 ); pt2.setY( y2 ); } } if ( pt1Ok || pt2Ok ) { return; } //match between the vertices if ( doubleNear( m1, m2 ) ) { pt1.setX( x1 ); pt1.setY( y1 ); pt1Ok = true; return; } double dist = ( measure - m1 ) / ( m2 - m1 ); if ( reversed ) { dist = 1 - dist; } pt1.setX( x1 + dist * ( x2 - x1 ) ); pt1.setY( y1 + dist * ( y2 - y1 ) ); pt1Ok = true; }
void * QgsSingleBandGrayRenderer::readBlock( int bandNo, QgsRectangle const & extent, int width, int height ) { Q_UNUSED( bandNo ); if ( !mInput ) { return 0; } QgsRasterInterface::DataType rasterType = ( QgsRasterInterface::DataType )mInput->dataType( mGrayBand ); QgsRasterInterface::DataType alphaType = QgsRasterInterface::UnknownDataType; if ( mAlphaBand > 0 ) { alphaType = ( QgsRasterInterface::DataType )mInput->dataType( mAlphaBand ); } void* rasterData = mInput->block( mGrayBand, extent, width, height ); if ( !rasterData ) return 0; void* alphaData = 0; double currentAlpha = mOpacity; int grayVal; QRgb myDefaultColor = qRgba( 0, 0, 0, 0 ); if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) { alphaData = mInput->block( mAlphaBand, extent, width, height ); if ( !alphaData ) { free( rasterData ); return 0; } } else if ( mAlphaBand > 0 ) { alphaData = rasterData; } QImage *img = createImage( width, height, QImage::Format_ARGB32_Premultiplied ); QRgb* imageScanLine = 0; int currentRasterPos = 0; for ( int i = 0; i < height; ++i ) { imageScanLine = ( QRgb* )( img->scanLine( i ) ); for ( int j = 0; j < width; ++j ) { grayVal = readValue( rasterData, rasterType, currentRasterPos ); //alpha currentAlpha = mOpacity; if ( mRasterTransparency ) { currentAlpha = mRasterTransparency->alphaValue( grayVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentAlpha *= ( readValue( alphaData, alphaType, currentRasterPos ) / 255.0 ); } if ( mContrastEnhancement ) { if ( !mContrastEnhancement->isValueInDisplayableRange( grayVal ) ) { imageScanLine[ j ] = myDefaultColor; ++currentRasterPos; continue; } grayVal = mContrastEnhancement->enhanceContrast( grayVal ); } if ( mInvertColor ) { grayVal = 255 - grayVal; } if ( doubleNear( currentAlpha, 1.0 ) ) { imageScanLine[j] = qRgba( grayVal, grayVal, grayVal, 255 ); } else { imageScanLine[j] = qRgba( currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * grayVal, currentAlpha * 255 ); } ++currentRasterPos; } } free( rasterData ); if ( mAlphaBand > 0 && mGrayBand != mAlphaBand ) { free( alphaData ); } void * data = ( void * )img->bits(); delete img; return data; // OK, the image was created with extraneous data }
void QgsMultiBandColorRenderer::draw( QPainter* p, QgsRasterViewPort* viewPort, const QgsMapToPixel* theQgsMapToPixel ) { if ( !p || !mProvider || !viewPort || !theQgsMapToPixel ) { return; } //In some (common) cases, we can simplify the drawing loop considerably and save render time bool fastDraw = ( !usesTransparency( viewPort->mSrcCRS, viewPort->mDestCRS ) && mRedBand > 0 && mGreenBand > 0 && mBlueBand > 0 && mAlphaBand < 1 && !mRedContrastEnhancement && !mGreenContrastEnhancement && !mBlueContrastEnhancement && !mInvertColor ); QgsRasterDataProvider::DataType redType = QgsRasterDataProvider::UnknownDataType; if ( mRedBand > 0 ) { redType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mRedBand ); } QgsRasterDataProvider::DataType greenType = QgsRasterDataProvider::UnknownDataType; if ( mGreenBand > 0 ) { greenType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mGreenBand ); } QgsRasterDataProvider::DataType blueType = QgsRasterDataProvider::UnknownDataType; if ( mBlueBand > 0 ) { blueType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mBlueBand ); } QgsRasterDataProvider::DataType transparencyType = QgsRasterDataProvider::UnknownDataType; if ( mAlphaBand > 0 ) { transparencyType = ( QgsRasterDataProvider::DataType )mProvider->dataType( mAlphaBand ); } double oversamplingX = 1.0, oversamplingY = 1.0; QSet<int> bands; if ( mRedBand > 0 ) { bands << mRedBand; } if ( mGreenBand > 0 ) { bands << mGreenBand; } if ( mBlueBand > 0 ) { bands << mBlueBand; } if ( bands.size() < 1 ) { return; //no need to draw anything if no band is set } if ( mAlphaBand > 0 ) { bands << mAlphaBand; } QMap<int, void*> bandData; void* defaultPointer = 0; QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { bandData.insert( *bandIt, defaultPointer ); startRasterRead( *bandIt, viewPort, theQgsMapToPixel, oversamplingX, oversamplingY ); } void* redData = 0; void* greenData = 0; void* blueData = 0; void* alphaData = 0; //number of cols/rows in output pixels int nCols = 0; int nRows = 0; //number of raster cols/rows with oversampling int nRasterCols = 0; int nRasterRows = 0; //shift to top left point for the raster part int topLeftCol = 0; int topLeftRow = 0; bool readSuccess = true; while ( true ) { QSet<int>::const_iterator bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { readSuccess = readSuccess && readNextRasterPart( *bandIt, oversamplingX, oversamplingY, viewPort, nCols, nRows, nRasterCols, nRasterRows, &bandData[*bandIt], topLeftCol, topLeftRow ); } if ( !readSuccess ) { break; } if ( mRedBand > 0 ) { redData = bandData[mRedBand]; } if ( mGreenBand > 0 ) { greenData = bandData[mGreenBand]; } if ( mBlueBand > 0 ) { blueData = bandData[mBlueBand]; } if ( mAlphaBand > 0 ) { alphaData = bandData[mAlphaBand]; } QImage img( nRasterCols, nRasterRows, QImage::Format_ARGB32_Premultiplied ); QRgb* imageScanLine = 0; int currentRasterPos = 0; int redVal = 0; int greenVal = 0; int blueVal = 0; int redDataVal = 0; int greenDataVal = 0; int blueDataVal = 0; QRgb defaultColor = qRgba( 255, 255, 255, 0 ); double currentOpacity = mOpacity; //opacity (between 0 and 1) for ( int i = 0; i < nRasterRows; ++i ) { imageScanLine = ( QRgb* )( img.scanLine( i ) ); for ( int j = 0; j < nRasterCols; ++j ) { if ( fastDraw ) //fast rendering if no transparency, stretching, color inversion, etc. { redVal = readValue( redData, redType, currentRasterPos ); greenVal = readValue( greenData, greenType, currentRasterPos ); blueVal = readValue( blueData, blueType, currentRasterPos ); imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); ++currentRasterPos; continue; } if ( mRedBand > 0 ) { redVal = readValue( redData, redType, currentRasterPos ); redDataVal = redVal; } if ( mGreenBand > 0 ) { greenVal = readValue( greenData, greenType, currentRasterPos ); greenDataVal = greenVal; } if ( mBlueBand > 0 ) { blueVal = readValue( blueData, blueType, currentRasterPos ); blueDataVal = blueVal; } //apply default color if red, green or blue not in displayable range if (( mRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( redVal ) ) || ( mBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( redVal ) ) ) { imageScanLine[j] = defaultColor; ++currentRasterPos; continue; } //stretch color values if ( mRedContrastEnhancement ) { redVal = mRedContrastEnhancement->enhanceContrast( redVal ); } if ( mGreenContrastEnhancement ) { greenVal = mGreenContrastEnhancement->enhanceContrast( greenVal ); } if ( mBlueContrastEnhancement ) { blueVal = mBlueContrastEnhancement->enhanceContrast( blueVal ); } if ( mInvertColor ) { redVal = 255 - redVal; greenVal = 255 - greenVal; blueVal = 255 - blueVal; } //opacity currentOpacity = mOpacity; if ( mRasterTransparency ) { currentOpacity = mRasterTransparency->alphaValue( redDataVal, greenDataVal, blueDataVal, mOpacity * 255 ) / 255.0; } if ( mAlphaBand > 0 ) { currentOpacity *= ( readValue( alphaData, transparencyType, currentRasterPos ) / 255.0 ); } if ( doubleNear( currentOpacity, 1.0 ) ) { imageScanLine[j] = qRgba( redVal, greenVal, blueVal, 255 ); } else { imageScanLine[j] = qRgba( currentOpacity * redVal, currentOpacity * greenVal, currentOpacity * blueVal, currentOpacity * 255 ); } ++currentRasterPos; } } drawImage( p, viewPort, img, topLeftCol, topLeftRow, nCols, nRows, oversamplingX, oversamplingY ); } bandIt = bands.constBegin(); for ( ; bandIt != bands.constEnd(); ++bandIt ) { stopRasterRead( *bandIt ); } }
void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const { for ( int i = 0; i < mMarker->symbolLayerCount(); i++ ) { QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" ); if ( !props.value( "uom", "" ).isEmpty() ) symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) ); element.appendChild( symbolizerElem ); // <Geometry> QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) ); QString gap; switch ( mPlacement ) { case FirstVertex: symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) ); break; case LastVertex: symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) ); break; case CentralPoint: symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) ); break; case Vertex: // no way to get line/polygon's vertices, use a VendorOption symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) ); break; default: gap = QString::number( mInterval ); break; } if ( !mRotateMarker ) { // markers in LineSymbolizer must be drawn following the line orientation, // use a VendorOption when no marker rotation symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) ); } // <Stroke> QDomElement strokeElem = doc.createElement( "se:Stroke" ); symbolizerElem.appendChild( strokeElem ); // <GraphicStroke> QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" ); strokeElem.appendChild( graphicStrokeElem ); QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i ); QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer ); if ( !markerLayer ) { graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) ); } else { markerLayer->writeSldMarker( doc, graphicStrokeElem, props ); } if ( !gap.isEmpty() ) { QDomElement gapElem = doc.createElement( "se:Gap" ); QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap ); graphicStrokeElem.appendChild( gapElem ); } if ( !doubleNear( mOffset, 0.0 ) ) { QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" ); perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) ); symbolizerElem.appendChild( perpOffsetElem ); } } }
bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height ) const { if ( qAbs( mRotation ) <= 0.0 ) //width and height stays the same if there is no rotation { return true; } if ( doubleNear( qAbs( mRotation ), 90 ) || doubleNear( qAbs( mRotation ), 270 ) ) { double tmp = width; width = height; height = tmp; return true; } double x1 = 0; double y1 = 0; double x2 = width; double y2 = 0; double x3 = width; double y3 = height; double x4 = 0; double y4 = height; double midX = width / 2.0; double midY = height / 2.0; if ( !cornerPointOnRotatedAndScaledRect( x1, y1, width, height ) ) { return false; } if ( !cornerPointOnRotatedAndScaledRect( x2, y2, width, height ) ) { return false; } if ( !cornerPointOnRotatedAndScaledRect( x3, y3, width, height ) ) { return false; } if ( !cornerPointOnRotatedAndScaledRect( x4, y4, width, height ) ) { return false; } //assume points 1 and 3 are on the rectangle boundaries. Calculate 2 and 4. double distM1 = sqrt(( x1 - midX ) * ( x1 - midX ) + ( y1 - midY ) * ( y1 - midY ) ); QPointF p2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x2, y2 ), distM1 ); if ( p2.x() < width && p2.x() > 0 && p2.y() < height && p2.y() > 0 ) { width = sqrt(( p2.x() - x1 ) * ( p2.x() - x1 ) + ( p2.y() - y1 ) * ( p2.y() - y1 ) ); height = sqrt(( x3 - p2.x() ) * ( x3 - p2.x() ) + ( y3 - p2.y() ) * ( y3 - p2.y() ) ); return true; } //else assume that points 2 and 4 are on the rectangle boundaries. Calculate 1 and 3 double distM2 = sqrt(( x2 - midX ) * ( x2 - midX ) + ( y2 - midY ) * ( y2 - midY ) ); QPointF p1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x1, y1 ), distM2 ); QPointF p3 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x3, y3 ), distM2 ); width = sqrt(( x2 - p1.x() ) * ( x2 - p1.x() ) + ( y2 - p1.y() ) * ( y2 - p1.y() ) ); height = sqrt(( p3.x() - x2 ) * ( p3.x() - x2 ) + ( p3.y() - y2 ) * ( p3.y() - y2 ) ); return true; }
void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) { QPainter* p = context.renderContext().painter(); if ( !p ) { return; } double size = context.outputLineWidth( mSize ); //don't render symbols with size below one or above 10,000 pixels if (( int )size < 1 || 10000.0 < size ) { return; } p->save(); QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) ); if ( mAngle ) outputOffset = _rotatedOffset( outputOffset, mAngle ); p->translate( point + outputOffset ); bool rotated = !doubleNear( mAngle, 0 ); bool drawOnScreen = doubleNear( context.renderContext().rasterScaleFactor(), 1.0, 0.1 ); if ( rotated ) p->rotate( mAngle ); bool fitsInCache = true; bool usePict = true; double hwRatio = 1.0; if ( drawOnScreen && !rotated ) { usePict = false; const QImage& img = QgsSvgCache::instance()->svgAsImage( mPath, size, mFillColor, mOutlineColor, mOutlineWidth, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache ); if ( fitsInCache && img.width() > 1 ) { //consider transparency if ( !doubleNear( context.alpha(), 1.0 ) ) { QImage transparentImage = img.copy(); QgsSymbolLayerV2Utils::multiplyImageOpacity( &transparentImage, context.alpha() ); p->drawImage( -transparentImage.width() / 2.0, -transparentImage.height() / 2.0, transparentImage ); hwRatio = ( double )transparentImage.height() / ( double )transparentImage.width(); } else { p->drawImage( -img.width() / 2.0, -img.height() / 2.0, img ); hwRatio = ( double )img.height() / ( double )img.width(); } } } if ( usePict || !fitsInCache ) { p->setOpacity( context.alpha() ); const QPicture& pct = QgsSvgCache::instance()->svgAsPicture( mPath, size, mFillColor, mOutlineColor, mOutlineWidth, context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor() ); if ( pct.width() > 1 ) { p->drawPicture( 0, 0, pct ); hwRatio = ( double )pct.height() / ( double )pct.width(); } } if ( context.selected() ) { QPen pen( context.selectionColor() ); double penWidth = context.outputLineWidth( 1.0 ); if ( penWidth > size / 20 ) { // keep the pen width from covering symbol penWidth = size / 20; } double penOffset = penWidth / 2; pen.setWidth( penWidth ); p->setPen( pen ); p->setBrush( Qt::NoBrush ); double wSize = size + penOffset; double hSize = size * hwRatio + penOffset; p->drawRect( QRectF( -wSize / 2.0, -hSize / 2.0, wSize, hSize ) ); } p->restore(); }
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; }