Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsticksscalebarrenderer.cpp 3 : : ---------------------------- 4 : : begin : June 2008 5 : : copyright : (C) 2008 by Marco Hugentobler 6 : : email : marco.hugentobler@karto.baug.ethz.ch 7 : : ***************************************************************************/ 8 : : /*************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #include "qgsticksscalebarrenderer.h" 18 : : #include "qgsscalebarsettings.h" 19 : : #include "qgslayoututils.h" 20 : : #include "qgssymbol.h" 21 : : #include "qgstextrenderer.h" 22 : : #include <QPainter> 23 : : 24 : 15 : QgsTicksScaleBarRenderer::QgsTicksScaleBarRenderer( QgsTicksScaleBarRenderer::TickPosition position ) 25 : 15 : : mTickPosition( position ) 26 : 30 : { 27 : : 28 : 15 : } 29 : : 30 : 15 : QString QgsTicksScaleBarRenderer::id() const 31 : : { 32 : 15 : switch ( mTickPosition ) 33 : : { 34 : : case TicksUp: 35 : 10 : return QStringLiteral( "Line Ticks Up" ); 36 : : case TicksDown: 37 : 10 : return QStringLiteral( "Line Ticks Down" ); 38 : : case TicksMiddle: 39 : 10 : return QStringLiteral( "Line Ticks Middle" ); 40 : : } 41 : 0 : return QString(); // to make gcc happy 42 : 15 : } 43 : : 44 : 0 : QString QgsTicksScaleBarRenderer::visibleName() const 45 : : { 46 : 0 : switch ( mTickPosition ) 47 : : { 48 : : case TicksUp: 49 : 0 : return QObject::tr( "Line Ticks Up" ); 50 : : case TicksDown: 51 : 0 : return QObject::tr( "Line Ticks Down" ); 52 : : case TicksMiddle: 53 : 0 : return QObject::tr( "Line Ticks Middle" ); 54 : : } 55 : 0 : return QString(); // to make gcc happy 56 : : 57 : 0 : } 58 : : 59 : 0 : int QgsTicksScaleBarRenderer::sortKey() const 60 : : { 61 : 0 : switch ( mTickPosition ) 62 : : { 63 : : case TicksUp: 64 : 0 : return 5; 65 : : case TicksDown: 66 : 0 : return 4; 67 : : case TicksMiddle: 68 : 0 : return 3; 69 : : } 70 : 0 : return 6; 71 : 0 : } 72 : : 73 : 0 : QgsScaleBarRenderer::Flags QgsTicksScaleBarRenderer::flags() const 74 : : { 75 : 0 : return Flag::FlagUsesLineSymbol | 76 : 0 : Flag::FlagUsesDivisionSymbol | 77 : 0 : Flag::FlagUsesSubdivisionSymbol | 78 : 0 : Flag::FlagRespectsUnits | 79 : 0 : Flag::FlagRespectsMapUnitsPerScaleBarUnit | 80 : 0 : Flag::FlagUsesUnitLabel | 81 : 0 : Flag::FlagUsesSegments | 82 : 0 : Flag::FlagUsesLabelBarSpace | 83 : 0 : Flag::FlagUsesLabelVerticalPlacement | 84 : 0 : Flag::FlagUsesLabelHorizontalPlacement | 85 : 0 : Flag::FlagUsesSubdivisions | 86 : : Flag::FlagUsesSubdivisionsHeight; 87 : : } 88 : : 89 : 0 : QgsTicksScaleBarRenderer *QgsTicksScaleBarRenderer::clone() const 90 : : { 91 : 0 : return new QgsTicksScaleBarRenderer( * this ); 92 : : } 93 : : 94 : 0 : void QgsTicksScaleBarRenderer::draw( QgsRenderContext &context, const QgsScaleBarSettings &settings, const ScaleBarContext &scaleContext ) const 95 : : { 96 : 0 : if ( !context.painter() ) 97 : 0 : return; 98 : : 99 : 0 : QPainter *painter = context.painter(); 100 : : 101 : 0 : const double scaledLabelBarSpace = context.convertToPainterUnits( settings.labelBarSpace(), QgsUnitTypes::RenderMillimeters ); 102 : 0 : const double scaledBoxContentSpace = context.convertToPainterUnits( settings.boxContentSpace(), QgsUnitTypes::RenderMillimeters ); 103 : 0 : const QFontMetricsF fontMetrics = QgsTextRenderer::fontMetrics( context, settings.textFormat() ); 104 : 0 : const double barTopPosition = scaledBoxContentSpace + ( settings.labelVerticalPlacement() == QgsScaleBarSettings::LabelAboveSegment ? fontMetrics.ascent() + scaledLabelBarSpace : 0 ); 105 : 0 : const double scaledHeight = context.convertToPainterUnits( settings.height(), QgsUnitTypes::RenderMillimeters ); 106 : 0 : const double scaledSubdivisionsHeight = context.convertToPainterUnits( settings.subdivisionsHeight(), QgsUnitTypes::RenderMillimeters ); 107 : 0 : const double scaledMaxHeight = ( ( settings.numberOfSubdivisions() > 1 ) && ( scaledSubdivisionsHeight > scaledHeight ) ) ? scaledSubdivisionsHeight : scaledHeight; 108 : 0 : const double middlePosition = barTopPosition + scaledMaxHeight / 2.0; 109 : 0 : const double bottomPosition = barTopPosition + scaledMaxHeight; 110 : : 111 : 0 : const double xOffset = firstLabelXOffset( settings, context, scaleContext ); 112 : : 113 : 0 : painter->save(); 114 : 0 : context.setPainterFlagsUsingContext( painter ); 115 : : 116 : 0 : std::unique_ptr< QgsLineSymbol > symbol( settings.lineSymbol()->clone() ); 117 : 0 : symbol->startRender( context ); 118 : : 119 : 0 : std::unique_ptr< QgsLineSymbol > divisionSymbol( settings.divisionLineSymbol()->clone() ); 120 : 0 : divisionSymbol->startRender( context ); 121 : : 122 : 0 : std::unique_ptr< QgsLineSymbol > subdivisionSymbol( settings.subdivisionLineSymbol()->clone() ); 123 : 0 : subdivisionSymbol->startRender( context ); 124 : : 125 : 0 : const QList<double> positions = segmentPositions( context, scaleContext, settings ); 126 : : 127 : : // vertical positions 128 : 0 : double verticalPos = 0.0; 129 : 0 : QList<double> subTickPositionsY; 130 : 0 : QList<double> tickPositionsY; 131 : 0 : switch ( mTickPosition ) 132 : : { 133 : : case TicksDown: 134 : 0 : verticalPos = barTopPosition; 135 : 0 : subTickPositionsY << verticalPos; 136 : 0 : subTickPositionsY << verticalPos + scaledSubdivisionsHeight; 137 : 0 : tickPositionsY << verticalPos; 138 : 0 : tickPositionsY << verticalPos + scaledHeight; 139 : 0 : break; 140 : : case TicksMiddle: 141 : 0 : verticalPos = middlePosition; 142 : 0 : subTickPositionsY << verticalPos + scaledSubdivisionsHeight / 2.0; 143 : 0 : subTickPositionsY << verticalPos - scaledSubdivisionsHeight / 2.0; 144 : 0 : tickPositionsY << verticalPos + scaledHeight / 2.0; 145 : 0 : tickPositionsY << verticalPos - scaledHeight / 2.0; 146 : 0 : break; 147 : : case TicksUp: 148 : 0 : verticalPos = bottomPosition; 149 : 0 : subTickPositionsY << verticalPos; 150 : 0 : subTickPositionsY << verticalPos - scaledSubdivisionsHeight; 151 : 0 : tickPositionsY << verticalPos; 152 : 0 : tickPositionsY << verticalPos - scaledHeight; 153 : 0 : break; 154 : : } 155 : : 156 : 0 : int symbolLayerCount = symbol->symbolLayerCount(); 157 : 0 : symbolLayerCount = std::max( symbolLayerCount, divisionSymbol->symbolLayerCount() ); 158 : 0 : symbolLayerCount = std::max( symbolLayerCount, subdivisionSymbol->symbolLayerCount() ); 159 : : 160 : : // we render the bar symbol-layer-by-symbol-layer, to avoid ugliness where the lines overlap in multi-layer symbols 161 : 0 : for ( int layer = 0; layer < symbolLayerCount; ++ layer ) 162 : : { 163 : 0 : const bool drawDivisionsForThisSymbolLayer = layer < divisionSymbol->symbolLayerCount(); 164 : 0 : const bool drawSubdivisionsForThisSymbolLayer = layer < subdivisionSymbol->symbolLayerCount(); 165 : 0 : const bool drawLineForThisSymbolLayer = layer < symbol->symbolLayerCount(); 166 : : 167 : 0 : if ( drawDivisionsForThisSymbolLayer ) 168 : : { 169 : : // first draw the vertical lines for segments 170 : 0 : for ( int i = 0; i < positions.size(); ++i ) 171 : : { 172 : 0 : const double thisX = context.convertToPainterUnits( positions.at( i ), QgsUnitTypes::RenderMillimeters ) + xOffset; 173 : 0 : divisionSymbol->renderPolyline( QPolygonF() << QPointF( thisX, tickPositionsY.at( 0 ) ) 174 : 0 : << QPointF( thisX, tickPositionsY.at( 1 ) ), nullptr, context, layer ); 175 : 0 : } 176 : 0 : } 177 : : 178 : : // draw the vertical lines for right subdivisions 179 : 0 : if ( drawSubdivisionsForThisSymbolLayer ) 180 : : { 181 : 0 : for ( int i = settings.numberOfSegmentsLeft(); i < positions.size(); ++i ) 182 : : { 183 : 0 : for ( int j = 1; j < settings.numberOfSubdivisions(); ++j ) 184 : : { 185 : 0 : const double thisSubX = context.convertToPainterUnits( positions.at( i ) + j * scaleContext.segmentWidth / settings.numberOfSubdivisions(), QgsUnitTypes::RenderMillimeters ) + xOffset; 186 : 0 : subdivisionSymbol->renderPolyline( QPolygonF() << QPointF( thisSubX, subTickPositionsY.at( 0 ) ) 187 : 0 : << QPointF( thisSubX, subTickPositionsY.at( 1 ) ), nullptr, context, layer ); 188 : 0 : } 189 : 0 : } 190 : 0 : } 191 : : 192 : : //draw last tick and horizontal line 193 : 0 : if ( !positions.isEmpty() ) 194 : : { 195 : 0 : double lastTickPositionX = context.convertToPainterUnits( positions.at( positions.size() - 1 ) + scaleContext.segmentWidth, QgsUnitTypes::RenderMillimeters ) + xOffset; 196 : : 197 : : //last vertical line 198 : 0 : if ( drawDivisionsForThisSymbolLayer ) 199 : : { 200 : 0 : divisionSymbol->renderPolyline( QPolygonF() << QPointF( lastTickPositionX, tickPositionsY.at( 0 ) ) 201 : 0 : << QPointF( lastTickPositionX, tickPositionsY.at( 1 ) ), 202 : 0 : nullptr, context, layer ); 203 : 0 : } 204 : : 205 : : //horizontal line 206 : 0 : if ( drawLineForThisSymbolLayer ) 207 : : { 208 : 0 : symbol->renderPolyline( QPolygonF() << QPointF( xOffset + context.convertToPainterUnits( positions.at( 0 ), QgsUnitTypes::RenderMillimeters ), verticalPos ) 209 : 0 : << QPointF( lastTickPositionX, verticalPos ), nullptr, context, layer ); 210 : 0 : } 211 : 0 : } 212 : 0 : } 213 : : 214 : 0 : symbol->stopRender( context ); 215 : 0 : divisionSymbol->stopRender( context ); 216 : 0 : subdivisionSymbol->stopRender( context ); 217 : : 218 : 0 : painter->restore(); 219 : : 220 : : //draw labels using the default method 221 : 0 : drawDefaultLabels( context, settings, scaleContext ); 222 : 0 : } 223 : : 224 : :