示例#1
0
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
    );
  }
}
示例#2
0
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
  );
}