@@ -70,6 +70,8 @@ void QgsDecorationNorthArrow::projectRead()
70
70
QgsDecorationItem::projectRead ();
71
71
mColor = QgsSymbolLayerUtils::decodeColor ( QgsProject::instance ()->readEntry ( mNameConfig , QStringLiteral ( " /Color" ), QStringLiteral ( " #000000" ) ) );
72
72
mOutlineColor = QgsSymbolLayerUtils::decodeColor ( QgsProject::instance ()->readEntry ( mNameConfig , QStringLiteral ( " /OutlineColor" ), QStringLiteral ( " #FFFFFF" ) ) );
73
+ mSize = QgsProject::instance ()->readDoubleEntry ( mNameConfig , QStringLiteral ( " /Size" ), 16.0 );
74
+ mSvgPath = QgsProject::instance ()->readEntry ( mNameConfig , QStringLiteral ( " /SvgPath" ), QString () );
73
75
mRotationInt = QgsProject::instance ()->readNumEntry ( mNameConfig , QStringLiteral ( " /Rotation" ), 0 );
74
76
mAutomatic = QgsProject::instance ()->readBoolEntry ( mNameConfig , QStringLiteral ( " /Automatic" ), true );
75
77
mMarginHorizontal = QgsProject::instance ()->readNumEntry ( mNameConfig , QStringLiteral ( " /MarginH" ), 0 );
@@ -81,7 +83,8 @@ void QgsDecorationNorthArrow::saveToProject()
81
83
QgsDecorationItem::saveToProject ();
82
84
QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /Color" ), QgsSymbolLayerUtils::encodeColor ( mColor ) );
83
85
QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /OutlineColor" ), QgsSymbolLayerUtils::encodeColor ( mOutlineColor ) );
84
- QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /Rotation" ), mRotationInt );
86
+ QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /Size" ), mSize );
87
+ QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /SvgPath" ), mSvgPath );
85
88
QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /Automatic" ), mAutomatic );
86
89
QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /MarginH" ), mMarginHorizontal );
87
90
QgsProject::instance ()->writeEntry ( mNameConfig , QStringLiteral ( " /MarginV" ), mMarginVertical );
@@ -94,128 +97,138 @@ void QgsDecorationNorthArrow::run()
94
97
dlg.exec ();
95
98
}
96
99
100
+ QString QgsDecorationNorthArrow::svgPath ()
101
+ {
102
+ if ( !mSvgPath .isEmpty () )
103
+ {
104
+ QString resolvedPath = QgsSymbolLayerUtils::svgSymbolNameToPath ( mSvgPath , QgsProject::instance ()->pathResolver () );
105
+ bool validSvg = QFileInfo::exists ( resolvedPath );
106
+ if ( validSvg )
107
+ {
108
+ return resolvedPath;
109
+ }
110
+ }
111
+
112
+ return QStringLiteral ( " :/images/north_arrows/default.svg" );
113
+ }
114
+
97
115
void QgsDecorationNorthArrow::render ( const QgsMapSettings &mapSettings, QgsRenderContext &context )
98
116
{
117
+ if ( !enabled () )
118
+ return ;
99
119
100
- // Large IF statement controlled by enable checkbox
101
- if ( enabled () )
102
- {
103
- QSize size ( 64 , 64 );
104
- QSvgRenderer svg;
120
+ double maxLength = mSize * mapSettings.outputDpi () / 25.4 ;
121
+ QSvgRenderer svg;
105
122
106
- const QByteArray &svgContent = QgsApplication::svgCache ()->svgContent ( QStringLiteral ( " :/images/north_arrows/default.svg " ), size. width () , mColor , mOutlineColor , 1.0 , 1.0 );
107
- svg.load ( svgContent );
123
+ const QByteArray &svgContent = QgsApplication::svgCache ()->svgContent ( svgPath ( ), maxLength , mColor , mOutlineColor , 1.0 , 1.0 );
124
+ svg.load ( svgContent );
108
125
109
- if ( svg.isValid () )
126
+ if ( svg.isValid () )
127
+ {
128
+ QSize size ( maxLength, maxLength );
129
+ QRectF viewBox = svg.viewBoxF ();
130
+ if ( viewBox.height () > viewBox.width () )
110
131
{
111
- double centerXDouble = size.width () / 2.0 ;
112
- double centerYDouble = size.width () / 2.0 ;
113
-
114
- // save the current canvas rotation
115
- context.painter ()->save ();
116
- //
117
- // work out how to shift the image so that it rotates
118
- // properly about its center
119
- // (x cos a + y sin a - x, -x sin a + y cos a - y)
120
- //
121
-
122
- // could move this call to somewhere else so that it is only
123
- // called when the projection or map extent changes
124
- if ( mAutomatic )
125
- {
126
- try
127
- {
128
- mRotationInt = QgsBearingUtils:: bearingTrueNorth ( mapSettings.destinationCrs (), mapSettings.transformContext (), context.extent ().center () );
129
- }
130
- catch ( QgsException & )
131
- {
132
- mRotationInt = 0.0 ;
133
- // QgsDebugMsg( "Can not get direction to true north. Probably project CRS is not defined." );
134
- }
135
- mRotationInt += mapSettings.rotation ();
136
- }
132
+ size.setWidth ( maxLength * viewBox.width () / viewBox.height () );
133
+ }
134
+ else
135
+ {
136
+ size.setHeight ( maxLength * viewBox.height () / viewBox.width () );
137
+ }
137
138
138
- double myRadiansDouble = mRotationInt * M_PI / 180.0 ;
139
- int xShift = static_cast <int >( (
140
- ( centerXDouble * std::cos ( myRadiansDouble ) ) +
141
- ( centerYDouble * std::sin ( myRadiansDouble ) )
142
- ) - centerXDouble );
143
- int yShift = static_cast <int >( (
144
- ( -centerXDouble * std::sin ( myRadiansDouble ) ) +
145
- ( centerYDouble * std::cos ( myRadiansDouble ) )
146
- ) - centerYDouble );
147
-
148
- // need width/height of paint device
149
- int myHeight = context.painter ()->device ()->height ();
150
- int myWidth = context.painter ()->device ()->width ();
151
-
152
- // QgsDebugMsg("Rendering north arrow at " + mPlacementLabels.at(mPlacementIndex));
153
-
154
- // Set margin according to selected units
155
- int myXOffset = 0 ;
156
- int myYOffset = 0 ;
157
- switch ( mMarginUnit )
139
+ double centerXDouble = size.width () / 2.0 ;
140
+ double centerYDouble = size.height () / 2.0 ;
141
+
142
+ // save the current canvas rotation
143
+ context.painter ()->save ();
144
+ //
145
+ // work out how to shift the image so that it rotates
146
+ // properly about its center
147
+ // (x cos a + y sin a - x, -x sin a + y cos a - y)
148
+ //
149
+ // could move this call to somewhere else so that it is only
150
+ // called when the projection or map extent changes
151
+ if ( mAutomatic )
152
+ {
153
+ try
158
154
{
159
- case QgsUnitTypes::RenderMillimeters:
160
- {
161
- int myPixelsInchX = context.painter ()->device ()->logicalDpiX ();
162
- int myPixelsInchY = context.painter ()->device ()->logicalDpiY ();
163
- myXOffset = myPixelsInchX * INCHES_TO_MM * mMarginHorizontal ;
164
- myYOffset = myPixelsInchY * INCHES_TO_MM * mMarginVertical ;
165
- break ;
166
- }
167
-
168
- case QgsUnitTypes::RenderPixels:
169
- myXOffset = mMarginHorizontal - 5 ; // Minus 5 to shift tight into corner
170
- myYOffset = mMarginVertical - 5 ;
171
- break ;
172
-
173
- case QgsUnitTypes::RenderPercentage:
174
- myXOffset = ( ( myWidth - size.width () ) / 100 . ) * mMarginHorizontal ;
175
- myYOffset = ( ( myHeight - size.width () ) / 100 . ) * mMarginVertical ;
176
- break ;
177
-
178
- default : // Use default of top left
179
- break ;
155
+ mRotationInt = QgsBearingUtils:: bearingTrueNorth ( mapSettings.destinationCrs (), mapSettings.transformContext (), context.extent ().center () );
180
156
}
181
- // Determine placement of label from form combo box
182
- switch ( mPlacement )
157
+ catch ( QgsException & )
183
158
{
184
- case BottomLeft:
185
- context.painter ()->translate ( myXOffset, myHeight - myYOffset - size.width () );
186
- break ;
187
- case TopLeft:
188
- context.painter ()->translate ( myXOffset, myYOffset );
189
- break ;
190
- case TopRight:
191
- context.painter ()->translate ( myWidth - myXOffset - size.width (), myYOffset );
192
- break ;
193
- case BottomRight:
194
- context.painter ()->translate ( myWidth - myXOffset - size.width (),
195
- myHeight - myYOffset - size.width () );
196
- break ;
197
- default :
198
- {
199
- // QgsDebugMsg("Unable to determine where to put north arrow so defaulting to top left");
200
- }
159
+ mRotationInt = 0.0 ;
201
160
}
161
+ mRotationInt += mapSettings.rotation ();
162
+ }
202
163
203
- // rotate the canvas by the north arrow rotation amount
204
- context.painter ()->rotate ( mRotationInt );
205
- // Now we can actually do the drawing, and draw a smooth north arrow even when rotated
206
-
207
- context.painter ()->translate ( xShift, yShift );
208
- svg.render ( context.painter (), QRectF ( 0 , 0 , size.width (), size.height () ) );
164
+ double radiansDouble = mRotationInt * M_PI / 180.0 ;
165
+ int xShift = static_cast <int >( (
166
+ ( centerXDouble * std::cos ( radiansDouble ) ) +
167
+ ( centerYDouble * std::sin ( radiansDouble ) )
168
+ ) - centerXDouble );
169
+ int yShift = static_cast <int >( (
170
+ ( -centerXDouble * std::sin ( radiansDouble ) ) +
171
+ ( centerYDouble * std::cos ( radiansDouble ) )
172
+ ) - centerYDouble );
173
+ // need width/height of paint device
174
+ int deviceHeight = context.painter ()->device ()->height ();
175
+ int deviceWidth = context.painter ()->device ()->width ();
176
+
177
+ // Set margin according to selected units
178
+ int xOffset = 0 ;
179
+ int yOffset = 0 ;
180
+ switch ( mMarginUnit )
181
+ {
182
+ case QgsUnitTypes::RenderMillimeters:
183
+ {
184
+ int pixelsInchX = context.painter ()->device ()->logicalDpiX ();
185
+ int pixelsInchY = context.painter ()->device ()->logicalDpiY ();
186
+ xOffset = pixelsInchX * INCHES_TO_MM * mMarginHorizontal ;
187
+ yOffset = pixelsInchY * INCHES_TO_MM * mMarginVertical ;
188
+ break ;
189
+ }
209
190
210
- // unrotate the canvas again
211
- context.painter ()->restore ();
191
+ case QgsUnitTypes::RenderPixels:
192
+ xOffset = mMarginHorizontal - 5 ; // Minus 5 to shift tight into corner
193
+ yOffset = mMarginVertical - 5 ;
194
+ break ;
195
+
196
+ case QgsUnitTypes::RenderPercentage:
197
+ xOffset = ( ( deviceWidth - size.width () ) / 100 . ) * mMarginHorizontal ;
198
+ yOffset = ( ( deviceHeight - size.width () ) / 100 . ) * mMarginVertical ;
199
+ break ;
200
+ case QgsUnitTypes::RenderMapUnits:
201
+ case QgsUnitTypes::RenderPoints:
202
+ case QgsUnitTypes::RenderInches:
203
+ case QgsUnitTypes::RenderUnknownUnit:
204
+ case QgsUnitTypes::RenderMetersInMapUnits:
205
+ break ;
212
206
}
213
- else
207
+ // Determine placement of label from form combo box
208
+ switch ( mPlacement )
214
209
{
215
- QFont myQFont ( QStringLiteral ( " time" ), 12 , QFont::Bold );
216
- context.painter ()->setFont ( myQFont );
217
- context.painter ()->setPen ( Qt::black );
218
- context.painter ()->drawText ( 10 , 20 , tr ( " North arrow pixmap not found" ) );
210
+ case BottomLeft:
211
+ context.painter ()->translate ( xOffset, deviceHeight - yOffset - maxLength + ( maxLength - size.height () ) / 2 );
212
+ break ;
213
+ case TopLeft:
214
+ context.painter ()->translate ( xOffset, yOffset );
215
+ break ;
216
+ case TopRight:
217
+ context.painter ()->translate ( deviceWidth - xOffset - maxLength + ( maxLength - size.width () ) / 2 , yOffset );
218
+ break ;
219
+ case BottomRight:
220
+ context.painter ()->translate ( deviceWidth - xOffset - maxLength + ( maxLength - size.width () ) / 2 ,
221
+ deviceHeight - yOffset - maxLength + ( maxLength - size.height () ) / 2 );
222
+ break ;
219
223
}
224
+
225
+ // rotate the canvas by the north arrow rotation amount
226
+ context.painter ()->rotate ( mRotationInt );
227
+ // Now we can actually do the drawing, and draw a smooth north arrow even when rotated
228
+ context.painter ()->translate ( xShift, yShift );
229
+ svg.render ( context.painter (), QRectF ( 0 , 0 , size.width (), size.height () ) );
230
+
231
+ // unrotate the canvas again
232
+ context.painter ()->restore ();
220
233
}
221
234
}
0 commit comments