void QgsDecorationScaleBar::render( QPainter * theQPainter ) { QgsMapCanvas* canvas = QgisApp::instance()->mapCanvas(); int myBufferSize = 1; //softcode this later //Get canvas dimensions int myCanvasHeight = theQPainter->device()->height(); int myCanvasWidth = theQPainter->device()->width(); //Get map units per pixel. This can be negative at times (to do with //projections) and that just confuses the rest of the code in this //function, so force to a positive number. double myMapUnitsPerPixelDouble = qAbs( canvas->mapUnitsPerPixel() ); double myActualSize = mPreferredSize; // Exit if the canvas width is 0 or layercount is 0 or QGIS will freeze int myLayerCount = canvas->layerCount(); if ( !myLayerCount || !myCanvasWidth || !myMapUnitsPerPixelDouble ) return; //Large if statement which determines whether to render the scale bar if ( enabled() ) { // Hard coded sizes int myMajorTickSize = 8; int myTextOffsetX = 3; int myMargin = 20; QSettings settings; QGis::UnitType myPreferredUnits = QGis::fromLiteral( settings.value( "/qgis/measure/displayunits", QGis::toLiteral( QGis::Meters ) ).toString() ); QGis::UnitType myMapUnits = canvas->mapUnits(); // Adjust units meter/feet/... or vice versa myMapUnitsPerPixelDouble *= QGis::fromUnitToUnitFactor( myMapUnits, myPreferredUnits ); myMapUnits = myPreferredUnits; //Calculate size of scale bar for preferred number of map units double myScaleBarWidth = mPreferredSize / myMapUnitsPerPixelDouble; //If scale bar is very small reset to 1/4 of the canvas wide if ( myScaleBarWidth < 30 ) { myScaleBarWidth = myCanvasWidth / 4; // pixels myActualSize = myScaleBarWidth * myMapUnitsPerPixelDouble; // map units }; //if scale bar is more than half the canvas wide keep halving until not while ( myScaleBarWidth > myCanvasWidth / 3 ) { myScaleBarWidth = myScaleBarWidth / 3; }; myActualSize = myScaleBarWidth * myMapUnitsPerPixelDouble; // Work out the exponent for the number - e.g, 1234 will give 3, // and .001234 will give -3 double myPowerOf10 = floor( log10( myActualSize ) ); // snap to integer < 10 times power of 10 if ( mSnapping ) { double scaler = pow( 10.0, myPowerOf10 ); myActualSize = qRound( myActualSize / scaler ) * scaler; myScaleBarWidth = myActualSize / myMapUnitsPerPixelDouble; } //Get type of map units and set scale bar unit label text QString myScaleBarUnitLabel; switch ( myMapUnits ) { case QGis::Meters: if ( myActualSize > 1000.0 ) { myScaleBarUnitLabel = tr( " km" ); myActualSize = myActualSize / 1000; } else if ( myActualSize < 0.01 ) { myScaleBarUnitLabel = tr( " mm" ); myActualSize = myActualSize * 1000; } else if ( myActualSize < 0.1 ) { myScaleBarUnitLabel = tr( " cm" ); myActualSize = myActualSize * 100; } else myScaleBarUnitLabel = tr( " m" ); break; case QGis::Feet: if ( myActualSize > 5280.0 ) //5280 feet to the mile { myScaleBarUnitLabel = tr( " miles" ); // Adjust scale bar width to get even numbers myActualSize = myActualSize / 5000; myScaleBarWidth = ( myScaleBarWidth * 5280 ) / 5000; } else if ( myActualSize == 5280.0 ) //5280 feet to the mile { myScaleBarUnitLabel = tr( " mile" ); // Adjust scale bar width to get even numbers myActualSize = myActualSize / 5000; myScaleBarWidth = ( myScaleBarWidth * 5280 ) / 5000; } else if ( myActualSize < 1 ) { myScaleBarUnitLabel = tr( " inches" ); myActualSize = myActualSize * 10; myScaleBarWidth = ( myScaleBarWidth * 10 ) / 12; } else if ( myActualSize == 1.0 ) { myScaleBarUnitLabel = tr( " foot" ); } else { myScaleBarUnitLabel = tr( " feet" ); } break; case QGis::Degrees: if ( myActualSize == 1.0 ) myScaleBarUnitLabel = tr( " degree" ); else myScaleBarUnitLabel = tr( " degrees" ); break; case QGis::UnknownUnit: myScaleBarUnitLabel = tr( " unknown" ); default: QgsDebugMsg( QString( "Error: not picked up map units - actual value = %1" ).arg( myMapUnits ) ); }; //Set font and calculate width of unit label int myFontSize = 10; //we use this later for buffering QFont myFont( "helvetica", myFontSize ); theQPainter->setFont( myFont ); QFontMetrics myFontMetrics( myFont ); double myFontWidth = myFontMetrics.width( myScaleBarUnitLabel ); double myFontHeight = myFontMetrics.height(); //Set the maximum label QString myScaleBarMaxLabel = QLocale::system().toString( myActualSize ); //Calculate total width of scale bar and label double myTotalScaleBarWidth = myScaleBarWidth + myFontWidth; //determine the origin of scale bar depending on placement selected int myOriginX = myMargin; int myOriginY = myMargin; switch ( mPlacementIndex ) { case 0: // Bottom Left myOriginX = myMargin; myOriginY = myCanvasHeight - myMargin; break; case 1: // Top Left myOriginX = myMargin; myOriginY = myMargin; break; case 2: // Top Right myOriginX = myCanvasWidth - (( int ) myTotalScaleBarWidth ) - myMargin; myOriginY = myMargin; break; case 3: // Bottom Right myOriginX = myCanvasWidth - (( int ) myTotalScaleBarWidth ) - myMargin; myOriginY = myCanvasHeight - myMargin; break; default: QgsDebugMsg( "Unable to determine where to put scale bar so defaulting to top left" ); } //Set pen to draw with QPen myForegroundPen( mColor, 2 ); QPen myBackgroundPen( Qt::white, 4 ); //Cast myScaleBarWidth to int for drawing int myScaleBarWidthInt = ( int ) myScaleBarWidth; //Create array of vertices for scale bar depending on style switch ( mStyleIndex ) { case 0: // Tick Down { QPolygon myTickDownArray( 4 ); //draw a buffer first so bar shows up on dark images theQPainter->setPen( myBackgroundPen ); myTickDownArray.putPoints( 0, 4, myOriginX , ( myOriginY + myMajorTickSize ) , myOriginX , myOriginY , ( myScaleBarWidthInt + myOriginX ), myOriginY , ( myScaleBarWidthInt + myOriginX ), ( myOriginY + myMajorTickSize ) ); theQPainter->drawPolyline( myTickDownArray ); //now draw the bar itself in user selected color theQPainter->setPen( myForegroundPen ); myTickDownArray.putPoints( 0, 4, myOriginX , ( myOriginY + myMajorTickSize ) , myOriginX , myOriginY , ( myScaleBarWidthInt + myOriginX ), myOriginY , ( myScaleBarWidthInt + myOriginX ), ( myOriginY + myMajorTickSize ) ); theQPainter->drawPolyline( myTickDownArray ); break; } case 1: // tick up { QPolygon myTickUpArray( 4 ); //draw a buffer first so bar shows up on dark images theQPainter->setPen( myBackgroundPen ); myTickUpArray.putPoints( 0, 4, myOriginX , myOriginY , myOriginX , myOriginY + myMajorTickSize , ( myScaleBarWidthInt + myOriginX ), myOriginY + myMajorTickSize , ( myScaleBarWidthInt + myOriginX ), myOriginY ); theQPainter->drawPolyline( myTickUpArray ); //now draw the bar itself in user selected color theQPainter->setPen( myForegroundPen ); myTickUpArray.putPoints( 0, 4, myOriginX , myOriginY , myOriginX , myOriginY + myMajorTickSize , ( myScaleBarWidthInt + myOriginX ), myOriginY + myMajorTickSize , ( myScaleBarWidthInt + myOriginX ), myOriginY ); theQPainter->drawPolyline( myTickUpArray ); break; } case 2: // Bar { QPolygon myBarArray( 2 ); //draw a buffer first so bar shows up on dark images theQPainter->setPen( myBackgroundPen ); myBarArray.putPoints( 0, 2, myOriginX , ( myOriginY + ( myMajorTickSize / 2 ) ), ( myScaleBarWidthInt + myOriginX ), ( myOriginY + ( myMajorTickSize / 2 ) ) ); theQPainter->drawPolyline( myBarArray ); //now draw the bar itself in user selected color theQPainter->setPen( myForegroundPen ); myBarArray.putPoints( 0, 2, myOriginX , ( myOriginY + ( myMajorTickSize / 2 ) ), ( myScaleBarWidthInt + myOriginX ), ( myOriginY + ( myMajorTickSize / 2 ) ) ); theQPainter->drawPolyline( myBarArray ); break; } case 3: // box { // Want square corners for a box myBackgroundPen.setJoinStyle( Qt::MiterJoin ); myForegroundPen.setJoinStyle( Qt::MiterJoin ); QPolygon myBoxArray( 5 ); //draw a buffer first so bar shows up on dark images theQPainter->setPen( myBackgroundPen ); myBoxArray.putPoints( 0, 5, myOriginX , myOriginY, ( myScaleBarWidthInt + myOriginX ), myOriginY, ( myScaleBarWidthInt + myOriginX ), ( myOriginY + myMajorTickSize ), myOriginX , ( myOriginY + myMajorTickSize ), myOriginX , myOriginY ); theQPainter->drawPolyline( myBoxArray ); //now draw the bar itself in user selected color theQPainter->setPen( myForegroundPen ); theQPainter->setBrush( QBrush( mColor, Qt::SolidPattern ) ); int midPointX = myScaleBarWidthInt / 2 + myOriginX; myBoxArray.putPoints( 0, 5, myOriginX , myOriginY, midPointX, myOriginY, midPointX, ( myOriginY + myMajorTickSize ), myOriginX , ( myOriginY + myMajorTickSize ), myOriginX , myOriginY ); theQPainter->drawPolygon( myBoxArray ); theQPainter->setBrush( Qt::NoBrush ); myBoxArray.putPoints( 0, 5, midPointX , myOriginY, ( myScaleBarWidthInt + myOriginX ), myOriginY, ( myScaleBarWidthInt + myOriginX ), ( myOriginY + myMajorTickSize ), midPointX , ( myOriginY + myMajorTickSize ), midPointX , myOriginY ); theQPainter->drawPolygon( myBoxArray ); break; } default: QgsDebugMsg( "Unknown style" ); } //Do actual drawing of scale bar // //Do drawing of scale bar text // QColor myBackColor = Qt::white; QColor myForeColor = Qt::black; //Draw the minimum label buffer theQPainter->setPen( myBackColor ); myFontWidth = myFontMetrics.width( "0" ); myFontHeight = myFontMetrics.height(); for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { theQPainter->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ), int( j + ( myOriginY - ( myFontHeight / 4 ) ) ), "0" ); } } //Draw minimum label theQPainter->setPen( myForeColor ); theQPainter->drawText( int( myOriginX - ( myFontWidth / 2 ) ), int( myOriginY - ( myFontHeight / 4 ) ), "0" ); // //Draw maximum label // theQPainter->setPen( myBackColor ); myFontWidth = myFontMetrics.width( myScaleBarMaxLabel ); myFontHeight = myFontMetrics.height(); //first the buffer for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { theQPainter->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ), int( j + ( myOriginY - ( myFontHeight / 4 ) ) ), myScaleBarMaxLabel ); } } //then the text itself theQPainter->setPen( myForeColor ); theQPainter->drawText( int( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ), int( myOriginY - ( myFontHeight / 4 ) ), myScaleBarMaxLabel ); // //Draw unit label // theQPainter->setPen( myBackColor ); //first the buffer for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { theQPainter->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ), j + ( myOriginY + myMajorTickSize ), myScaleBarUnitLabel ); } } //then the text itself theQPainter->setPen( myForeColor ); theQPainter->drawText( ( myOriginX + myScaleBarWidthInt + myTextOffsetX ), ( myOriginY + myMajorTickSize ), myScaleBarUnitLabel ); } }
void QgsQuickPrint::renderPrintScaleBar( QPainter * thepPainter, QgsMapRenderer * thepMapRenderer, int theMaximumWidth ) { //hard coding some options for now bool mySnappingFlag = true; QColor mColor = Qt::black; // Hard coded sizes int myTextOffsetX = 0; int myTextOffsetY = 5; int myXMargin = 20; int myYMargin = 20; int myPreferredSize = theMaximumWidth - ( myXMargin * 2 ); double myActualSize = 0; int myBufferSize = 1; //softcode this later QColor myBackColor = Qt::white; //used for text QColor myForeColor = Qt::black; //used for text //Get canvas dimensions //int myCanvasHeight = thepMapCanvas->height(); //Get map units per pixel. This can be negative at times (to do with //projections) and that just confuses the rest of the code in this //function, so force to a positive number. double myMapUnitsPerPixelDouble = qAbs( thepMapRenderer->mapUnitsPerPixel() ); // // Exit if the canvas width is 0 or layercount is 0 or QGIS will freeze int myLayerCount = thepMapRenderer->layerSet().count(); if ( !myLayerCount || !myMapUnitsPerPixelDouble ) return; //Calculate size of scale bar for preferred number of map units double myScaleBarWidth = myPreferredSize; myActualSize = myScaleBarWidth * myMapUnitsPerPixelDouble; // Work out the exponent for the number - e.g, 1234 will give 3, // and .001234 will give -3 double myPowerOf10 = floor( log10( myActualSize ) ); // snap to integer < 10 times power of 10 if ( mySnappingFlag ) { double scaler = pow( 10.0, myPowerOf10 ); myActualSize = round( myActualSize / scaler ) * scaler; myScaleBarWidth = myActualSize / myMapUnitsPerPixelDouble; } //Get type of map units and set scale bar unit label text QGis::UnitType myMapUnits = thepMapRenderer->mapUnits(); QString myScaleBarUnitLabel; switch ( myMapUnits ) { case QGis::Meters: if ( myActualSize > 1000.0 ) { myScaleBarUnitLabel = tr( " km" ); myActualSize = myActualSize / 1000; } else if ( myActualSize < 0.01 ) { myScaleBarUnitLabel = tr( " mm" ); myActualSize = myActualSize * 1000; } else if ( myActualSize < 0.1 ) { myScaleBarUnitLabel = tr( " cm" ); myActualSize = myActualSize * 100; } else myScaleBarUnitLabel = tr( " m" ); break; case QGis::Feet: if ( myActualSize > 5280.0 ) //5280 feet to the mile { myScaleBarUnitLabel = tr( " miles" ); myActualSize = myActualSize / 5280; } else if ( myActualSize == 5280.0 ) //5280 feet to the mile { myScaleBarUnitLabel = tr( " mile" ); myActualSize = myActualSize / 5280; } else if ( myActualSize < 1 ) { myScaleBarUnitLabel = tr( " inches" ); myActualSize = myActualSize * 12; } else if ( myActualSize == 1.0 ) { myScaleBarUnitLabel = tr( " foot" ); } else { myScaleBarUnitLabel = tr( " feet" ); } break; case QGis::Degrees: if ( myActualSize == 1.0 ) myScaleBarUnitLabel = tr( " degree" ); else myScaleBarUnitLabel = tr( " degrees" ); break; case QGis::UnknownUnit: myScaleBarUnitLabel = tr( " unknown" ); default: QgsDebugMsg( "Error: not picked up map units - actual value = " + QString::number( myMapUnits ) ); }; //Set font and calculate width of unit label int myFontSize = 10; //we use this later for buffering QFont myFont( "helvetica", myFontSize ); thepPainter->setFont( myFont ); QFontMetrics myFontMetrics( myFont ); double myFontWidth = myFontMetrics.width( myScaleBarUnitLabel ); double myFontHeight = myFontMetrics.height(); //Set the maximum label QString myScaleBarMaxLabel = QString::number( myActualSize ); //Calculate total width of scale bar and label //we divide by 2 because the max scale label //will be centered over the endpoint of the scale bar double myTotalScaleBarWidth = myScaleBarWidth + ( myFontWidth / 2 ); //determine the origin of scale bar (bottom right) //for x origin set things up so the scalebar is centered int myOriginX = ( theMaximumWidth - myTotalScaleBarWidth ) / 2; int myOriginY = myYMargin; //Set pen to draw with QPen myForegroundPen( mColor, 2 ); QPen myBackgroundPen( Qt::white, 3 ); //Cast myScaleBarWidth to int for drawing int myScaleBarWidthInt = ( int ) myScaleBarWidth; //now draw the bar itself in user selected color thepPainter->setPen( myForegroundPen ); //make a glossygradient for the background QGradientStops myStops; myStops << QGradientStop( 0.0, QColor( "#616161" ) ); myStops << QGradientStop( 0.5, QColor( "#505050" ) ); myStops << QGradientStop( 0.6, QColor( "#434343" ) ); myStops << QGradientStop( 1.0, QColor( "#656565" ) ); //draw again with the brush in the revers direction to complete teh glossiness QLinearGradient myReverseGlossyBrush( QPointF( myOriginX, myOriginY + myFontHeight*3 ), QPointF( myOriginX, myOriginY ) ); thepPainter->setBrush( myReverseGlossyBrush ); thepPainter->drawRect( myOriginX, myOriginY, myOriginX + myScaleBarWidthInt, myOriginY + myFontHeight ); // //Do drawing of scale bar text // //Draw the minimum label buffer thepPainter->setPen( myBackColor ); myFontWidth = myFontMetrics.width( "0" ); for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { thepPainter->drawText( int( i + ( myOriginX - ( myFontWidth / 2 ) ) ), int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY, "0" ); } } //Draw minimum label thepPainter->setPen( myForeColor ); thepPainter->drawText( int( myOriginX - ( myFontWidth / 2 ) ), int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY, "0" ); // //Draw maximum label // thepPainter->setPen( myBackColor ); myFontWidth = myFontMetrics.width( myScaleBarMaxLabel ); myFontHeight = myFontMetrics.height(); //first the buffer for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { thepPainter->drawText( int( i + ( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ) ), int( j + ( myOriginY - ( myFontHeight / 4 ) ) ) - myTextOffsetY, myScaleBarMaxLabel ); } } //then the text itself thepPainter->setPen( myForeColor ); thepPainter->drawText( int( myOriginX + myScaleBarWidthInt - ( myFontWidth / 2 ) ), int( myOriginY - ( myFontHeight / 4 ) ) - myTextOffsetY, myScaleBarMaxLabel ); // //Draw unit label // thepPainter->setPen( myBackColor ); myFontWidth = myFontMetrics.width( myScaleBarUnitLabel ); //first the buffer for ( int i = 0 - myBufferSize; i <= myBufferSize; i++ ) { for ( int j = 0 - myBufferSize; j <= myBufferSize; j++ ) { thepPainter->drawText( i + ( myOriginX + myScaleBarWidthInt + myTextOffsetX ), j + myOriginY + myFontHeight + ( myFontHeight*2.5 ) + myTextOffsetY, myScaleBarUnitLabel ); } } //then the text itself thepPainter->setPen( myForeColor ); thepPainter->drawText( myOriginX + myScaleBarWidthInt + myTextOffsetX, myOriginY + myFontHeight + ( myFontHeight*2.5 ) + myTextOffsetY, myScaleBarUnitLabel ); }