43
48
#include "plugingui.h"
45
// xpm for creating the toolbar icon
49
#define QGISEXTERN extern "C" __declspec( dllexport )
51
#define QGISEXTERN extern "C"
53
#define round(x) ((x) >= 0 ? floor((x)+0.5) : floor((x)-0.5))
55
static const char * const ident_ = "$Id: plugin.cpp 6301 2006-12-22 07:43:47Z g_j_m $";
57
static const char * const ident_ = "$Id$";
57
static const QString name_ = QObject::tr("NorthArrow");
58
static const QString description_ = QObject::tr("Displays a north arrow overlayed onto the map");
59
static const QString version_ = QObject::tr("Version 0.1");
59
static const QString name_ = QObject::tr( "NorthArrow" );
60
static const QString description_ = QObject::tr( "Displays a north arrow overlayed onto the map" );
61
static const QString version_ = QObject::tr( "Version 0.1" );
60
62
static const QgisPlugin::PLUGINTYPE type_ = QgisPlugin::UI;
62
64
const double QgsNorthArrowPlugin::PI = 3.14159265358979323846;
70
72
* @param qgis Pointer to the QGIS main window
71
73
* @param _qI Pointer to the QGIS interface object
73
QgsNorthArrowPlugin::QgsNorthArrowPlugin(QgisApp * theQGisApp,
74
QgisIface * theQgisInterFace):
75
QgisPlugin(name_,description_,version_,type_),
76
qgisMainWindowPointer(theQGisApp),
77
qGisInterface(theQgisInterFace)
75
QgsNorthArrowPlugin::QgsNorthArrowPlugin( QgisInterface * theQgisInterFace ):
76
QgisPlugin( name_, description_, version_, type_ ),
77
qGisInterface( theQgisInterFace )
81
mPlacementLabels << tr("Bottom Left") << tr("Top Left")
82
<< tr("Top Right") << tr("Bottom Right");
81
mPlacementLabels << tr( "Bottom Left" ) << tr( "Top Left" )
82
<< tr( "Top Right" ) << tr( "Bottom Right" );
85
85
QgsNorthArrowPlugin::~QgsNorthArrowPlugin()
90
* Initialize the GUI interface for the plugin
90
* Initialize the GUI interface for the plugin
92
92
void QgsNorthArrowPlugin::initGui()
94
94
// Create the action for tool
95
myQActionPointer = new QAction(QIcon(icon), tr("&North Arrow"), this);
96
myQActionPointer->setWhatsThis(tr("Creates a north arrow that is displayed on the map canvas"));
95
myQActionPointer = new QAction( QIcon(), tr( "&North Arrow" ), this );
96
setCurrentTheme( "" );
97
myQActionPointer->setWhatsThis( tr( "Creates a north arrow that is displayed on the map canvas" ) );
97
98
// Connect the action to the run
98
connect(myQActionPointer, SIGNAL(activated()), this, SLOT(run()));
99
connect( myQActionPointer, SIGNAL( triggered() ), this, SLOT( run() ) );
99
100
//render the arrow each time the map is rendered
100
connect(qGisInterface->getMapCanvas(), SIGNAL(renderComplete(QPainter *)), this, SLOT(renderNorthArrow(QPainter *)));
101
connect( qGisInterface->mapCanvas(), SIGNAL( renderComplete( QPainter * ) ), this, SLOT( renderNorthArrow( QPainter * ) ) );
101
102
//this resets this plugin up if a project is loaded
102
connect(qgisMainWindowPointer, SIGNAL(projectRead()), this, SLOT(projectRead()));
103
connect( qGisInterface->mainWindow(), SIGNAL( projectRead() ), this, SLOT( projectRead() ) );
103
104
// Add the icon to the toolbar & appropriate menu
104
qGisInterface->addToolBarIcon(myQActionPointer);
105
qGisInterface->addPluginMenu(tr("&Decorations"), myQActionPointer);
105
qGisInterface->addToolBarIcon( myQActionPointer );
106
qGisInterface->addPluginToMenu( tr( "&Decorations" ), myQActionPointer );
107
// this is called when the icon theme is changed
108
connect( qGisInterface, SIGNAL( currentThemeChanged( QString ) ), this, SLOT( setCurrentTheme( QString ) ) );
112
115
void QgsNorthArrowPlugin::projectRead()
115
std::cout << "+++++++++ north arrow plugin - project read slot called...." << std::endl;
117
//default text to start with - try to fetch it from qgsproject
117
//default text to start with - try to fetch it from qgsproject
119
mRotationInt = QgsProject::instance()->readNumEntry("NorthArrow","/Rotation",0);
120
mPlacementIndex = QgsProject::instance()->readNumEntry("NorthArrow","/Placement",0);
121
mEnable = QgsProject::instance()->readBoolEntry("NorthArrow","/Enabled",true);
122
mAutomatic = QgsProject::instance()->readBoolEntry("NorthArrow","/Automatic",true);
119
mRotationInt = QgsProject::instance()->readNumEntry( "NorthArrow", "/Rotation", 0 );
120
mPlacementIndex = QgsProject::instance()->readNumEntry( "NorthArrow", "/Placement", 0 );
121
mEnable = QgsProject::instance()->readBoolEntry( "NorthArrow", "/Enabled", true );
122
mAutomatic = QgsProject::instance()->readBoolEntry( "NorthArrow", "/Automatic", true );
125
125
//method defined in interface
131
131
// Slot called when the buffer menu item is activated
132
132
void QgsNorthArrowPlugin::run()
134
QgsNorthArrowPluginGui *myPluginGui = new QgsNorthArrowPluginGui(qgisMainWindowPointer, QgisGui::ModalDialogFlags);
134
QgsNorthArrowPluginGui *myPluginGui = new QgsNorthArrowPluginGui( qGisInterface->mainWindow(), QgisGui::ModalDialogFlags );
135
myPluginGui->setAttribute( Qt::WA_DeleteOnClose );
135
136
//overides function by the same name created in .ui
136
myPluginGui->setRotation(mRotationInt);
137
myPluginGui->setPlacementLabels(mPlacementLabels);
138
myPluginGui->setPlacement(mPlacementIndex);
139
myPluginGui->setEnabled(mEnable);
140
myPluginGui->setAutomatic(mAutomatic);
137
myPluginGui->setRotation( mRotationInt );
138
myPluginGui->setPlacementLabels( mPlacementLabels );
139
myPluginGui->setPlacement( mPlacementIndex );
140
myPluginGui->setEnabled( mEnable );
141
myPluginGui->setAutomatic( mAutomatic );
142
143
//listen for when the layer has been made so we can draw it
143
connect(myPluginGui, SIGNAL(rotationChanged(int)), this, SLOT(rotationChanged(int)));
144
connect(myPluginGui, SIGNAL(changePlacement(int)), this, SLOT(setPlacement(int)));
145
connect(myPluginGui, SIGNAL(enableAutomatic(bool)), this, SLOT(setAutomatic(bool)));
146
connect(myPluginGui, SIGNAL(enableNorthArrow(bool)), this, SLOT(setEnabled(bool)));
147
connect(myPluginGui, SIGNAL(needToRefresh()), this, SLOT(refreshCanvas()));
144
connect( myPluginGui, SIGNAL( rotationChanged( int ) ), this, SLOT( rotationChanged( int ) ) );
145
connect( myPluginGui, SIGNAL( changePlacement( int ) ), this, SLOT( setPlacement( int ) ) );
146
connect( myPluginGui, SIGNAL( enableAutomatic( bool ) ), this, SLOT( setAutomatic( bool ) ) );
147
connect( myPluginGui, SIGNAL( enableNorthArrow( bool ) ), this, SLOT( setEnabled( bool ) ) );
148
connect( myPluginGui, SIGNAL( needToRefresh() ), this, SLOT( refreshCanvas() ) );
148
149
myPluginGui->show();
151
152
//! Refresh the map display using the mapcanvas exported via the plugin interface
152
153
void QgsNorthArrowPlugin::refreshCanvas()
154
qGisInterface->getMapCanvas()->refresh();
155
qGisInterface->mapCanvas()->refresh();
157
void QgsNorthArrowPlugin::renderNorthArrow(QPainter * theQPainter)
158
void QgsNorthArrowPlugin::renderNorthArrow( QPainter * theQPainter )
160
std::cout << "Rendering n-arrow" << std::endl;
162
161
//Large IF statement controlled by enable check box
164
if ( theQPainter->isActive() )
166
//QgsDebugMsg("Rendering north arrow on active painter");
170
//QgsDebugMsg("Rendering north arrow on INactive painter!!!");
165
173
QPixmap myQPixmap; //to store the north arrow image in
167
QString myFileNameQString = QgsApplication::pkgDataPath() +
168
"/images/north_arrows/default.png";
175
QString myFileNameQString = QDir::cleanPath( QgsApplication::pkgDataPath() +
176
"/images/north_arrows/default.png" );
170
//std::cout << "Trying to load " << myFileNameQString << std::cout;
171
if (myQPixmap.load(myFileNameQString))
178
//QgsDebugMsg("Trying to load " + myFileNameQString);
179
if ( myQPixmap.load( myFileNameQString ) )
174
double centerXDouble = myQPixmap.width()/2;
175
double centerYDouble = myQPixmap.height()/2;
182
double centerXDouble = myQPixmap.width() / 2;
183
double centerYDouble = myQPixmap.height() / 2;
176
184
//save the current canvas rotation
177
185
theQPainter->save();
184
192
// could move this call to somewhere else so that it is only
185
193
// called when the projection or map extent changes
187
195
calculateNorthDirection();
189
197
double myRadiansDouble = mRotationInt * PI / 180.0;
190
198
int xShift = static_cast<int>((
191
(centerXDouble * cos(myRadiansDouble)) +
192
(centerYDouble * sin(myRadiansDouble))
199
( centerXDouble * cos( myRadiansDouble ) ) +
200
( centerYDouble * sin( myRadiansDouble ) )
194
202
int yShift = static_cast<int>((
195
(-centerXDouble * sin(myRadiansDouble)) +
196
(centerYDouble * cos(myRadiansDouble))
203
( -centerXDouble * sin( myRadiansDouble ) ) +
204
( centerYDouble * cos( myRadiansDouble ) )
199
207
// need width/height of paint device
200
208
int myHeight = theQPainter->device()->height();
201
209
int myWidth = theQPainter->device()->width();
204
std::cout << "Rendering n-arrow at " << mPlacementLabels.at(mPlacementIndex).toLocal8Bit().data() << std::endl;
211
//QgsDebugMsg("Rendering north arrow at " + mPlacementLabels.at(mPlacementIndex));
206
213
//Determine placement of label from form combo box
207
switch (mPlacementIndex)
214
switch ( mPlacementIndex )
209
case 0: // Bottom Left
210
theQPainter->translate(0,myHeight-myQPixmap.height());
213
//no need to translate for TL corner because we're already at the origin
214
theQPainter->translate(0, 0);
217
theQPainter->translate(myWidth-myQPixmap.width(),0);
219
case 3: // Bottom Right
220
theQPainter->translate(myWidth-myQPixmap.width(),
221
myHeight-myQPixmap.height());
224
std::cout << "Unable to determine where to put north arrow so defaulting to top left"
216
case 0: // Bottom Left
217
theQPainter->translate( 0, myHeight - myQPixmap.height() );
220
//no need to translate for TL corner because we're already at the origin
221
theQPainter->translate( 0, 0 );
224
theQPainter->translate( myWidth - myQPixmap.width(), 0 );
226
case 3: // Bottom Right
227
theQPainter->translate( myWidth - myQPixmap.width(),
228
myHeight - myQPixmap.height() );
232
//QgsDebugMsg("Unable to determine where to put north arrow so defaulting to top left");
227
235
//rotate the canvas by the north arrow rotation amount
228
236
theQPainter->rotate( mRotationInt );
229
237
//Now we can actually do the drawing, and draw a smooth north arrow even when rotated
230
theQPainter->setRenderHint(QPainter::SmoothPixmapTransform);
231
theQPainter->drawPixmap(xShift,yShift,myQPixmap);
238
theQPainter->setRenderHint( QPainter::SmoothPixmapTransform );
239
theQPainter->drawPixmap( xShift, yShift, myQPixmap );
233
241
//unrotate the canvas again
234
242
theQPainter->restore();
238
QFont myQFont("time", 12, QFont::Bold);
239
theQPainter->setFont(myQFont);
240
theQPainter->setPen(Qt::black);
241
theQPainter->drawText(10, 20, QString(tr("North arrow pixmap not found")));
246
QFont myQFont( "time", 12, QFont::Bold );
247
theQPainter->setFont( myQFont );
248
theQPainter->setPen( Qt::black );
249
theQPainter->drawText( 10, 20, tr( "North arrow pixmap not found" ) );
247
255
void QgsNorthArrowPlugin::unload()
249
257
// remove the GUI
250
qGisInterface->removePluginMenu(tr("&Decorations"), myQActionPointer);
251
qGisInterface->removeToolBarIcon(myQActionPointer);
258
qGisInterface->removePluginMenu( tr( "&Decorations" ), myQActionPointer );
259
qGisInterface->removeToolBarIcon( myQActionPointer );
252
260
// remove the northarrow from the canvas
253
disconnect(qGisInterface->getMapCanvas(), SIGNAL(renderComplete(QPainter *)),
254
this, SLOT(renderNorthArrow(QPainter *)));
261
disconnect( qGisInterface->mapCanvas(), SIGNAL( renderComplete( QPainter * ) ),
262
this, SLOT( renderNorthArrow( QPainter * ) ) );
257
265
delete myQActionPointer;
261
void QgsNorthArrowPlugin::rotationChanged(int theInt)
269
void QgsNorthArrowPlugin::rotationChanged( int theInt )
263
271
mRotationInt = theInt;
264
QgsProject::instance()->writeEntry("NorthArrow","/Rotation", mRotationInt );
272
QgsProject::instance()->writeEntry( "NorthArrow", "/Rotation", mRotationInt );
267
275
//! set placement of north arrow
268
void QgsNorthArrowPlugin::setPlacement(int placementIndex)
276
void QgsNorthArrowPlugin::setPlacement( int placementIndex )
270
278
mPlacementIndex = placementIndex;
271
QgsProject::instance()->writeEntry("NorthArrow","/Placement", mPlacementIndex);
279
QgsProject::instance()->writeEntry( "NorthArrow", "/Placement", mPlacementIndex );
274
void QgsNorthArrowPlugin::setEnabled(bool theBool)
282
void QgsNorthArrowPlugin::setEnabled( bool theBool )
276
284
mEnable = theBool;
277
QgsProject::instance()->writeEntry("NorthArrow","/Enabled", mEnable );
285
QgsProject::instance()->writeEntry( "NorthArrow", "/Enabled", mEnable );
280
void QgsNorthArrowPlugin::setAutomatic(bool theBool)
288
void QgsNorthArrowPlugin::setAutomatic( bool theBool )
282
290
mAutomatic = theBool;
283
QgsProject::instance()->writeEntry("NorthArrow","/Automatic", mAutomatic );
291
QgsProject::instance()->writeEntry( "NorthArrow", "/Automatic", mAutomatic );
285
293
calculateNorthDirection();
288
296
bool QgsNorthArrowPlugin::calculateNorthDirection()
290
QgsMapCanvas& mapCanvas = *(qGisInterface->getMapCanvas());
298
QgsMapCanvas& mapCanvas = *( qGisInterface->mapCanvas() );
292
300
bool goodDirn = false;
294
if (mapCanvas.layerCount() > 0)
302
if ( mapCanvas.layerCount() > 0 )
296
// Grab an SRS from any layer
297
QgsMapLayer& mapLayer = *(mapCanvas.getZpos(0));
298
QgsSpatialRefSys& outputSRS = mapLayer.coordinateTransform()->destSRS();
304
QgsCoordinateReferenceSystem outputCRS = mapCanvas.mapRenderer()->destinationSrs();
300
if (outputSRS.isValid() && !outputSRS.geographicFlag())
306
if ( outputCRS.isValid() && !outputCRS.geographicFlag() )
302
// Use a geographic SRS to get lat/long to work out direction
303
QgsSpatialRefSys ourSRS;
304
ourSRS.createFromProj4("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
305
assert(ourSRS.isValid());
307
QgsCoordinateTransform transform(outputSRS, ourSRS);
309
QgsRect extent = mapCanvas.extent();
310
QgsPoint p1(extent.center());
308
// Use a geographic CRS to get lat/long to work out direction
309
QgsCoordinateReferenceSystem ourCRS;
310
ourCRS.createFromProj4( "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" );
311
assert( ourCRS.isValid() );
313
QgsCoordinateTransform transform( outputCRS, ourCRS );
315
QgsRectangle extent = mapCanvas.extent();
316
QgsPoint p1( extent.center() );
311
317
// A point a bit above p1. XXX assumes that y increases up!!
312
318
// May need to involve the maptopixel transform if this proves
313
319
// to be a problem.
314
QgsPoint p2(p1.x(), p1.y() + extent.height() * 0.25);
320
QgsPoint p2( p1.x(), p1.y() + extent.height() * 0.25 );
316
322
// project p1 and p2 to geographic coords
319
p1 = transform.transform(p1);
320
p2 = transform.transform(p2);
325
p1 = transform.transform( p1 );
326
p2 = transform.transform( p2 );
322
catch (QgsException &e)
328
catch ( QgsCsException &e )
332
QgsDebugMsg( "North Arrow: Transformation error, quitting" );
328
336
// Work out the value of the initial heading one takes to go
336
344
double angle = 0.0;
338
346
// convert to radians for the equations below
339
p1.multiply(PI/180.0);
340
p2.multiply(PI/180.0);
342
double y = sin(p2.x() - p1.x()) * cos(p2.y());
343
double x = cos(p1.y()) * sin(p2.y()) -
344
sin(p1.y()) * cos(p2.y()) * cos(p2.x()-p1.x());
347
p1.multiply( PI / 180.0 );
348
p2.multiply( PI / 180.0 );
350
double y = sin( p2.x() - p1.x() ) * cos( p2.y() );
351
double x = cos( p1.y() ) * sin( p2.y() ) -
352
sin( p1.y() ) * cos( p2.y() ) * cos( p2.x() - p1.x() );
351
angle = PI - atan(-y/x);
357
angle = atan( y / x );
359
angle = PI - atan( -y / x );
360
angle = atan(y/x) - PI;
366
angle = -atan( -y / x );
368
angle = atan( y / x ) - PI;
372
angle = 0.0; // p1 = p2
380
angle = 0.0; // p1 = p2
376
384
// And set the angle of the north arrow. Perhaps do something
377
385
// different if goodDirn = false.
378
mRotationInt = static_cast<int>(round(fmod(360.0-angle*180.0/PI, 360.0)));
386
mRotationInt = static_cast<int>( round( fmod( 360.0 - angle * 180.0 / PI, 360.0 ) ) );
382
// For geographic SRS and for when there are no layers, set the
390
// For geographic CRS and for when there are no layers, set the
383
391
// direction back to the default
384
392
mRotationInt = 0;
398
//! Set icons to the current theme
399
void QgsNorthArrowPlugin::setCurrentTheme( QString theThemeName )
401
QString myCurThemePath = QgsApplication::activeThemePath() + "/plugins/north_arrow.png";
402
QString myDefThemePath = QgsApplication::defaultThemePath() + "/plugins/north_arrow.png";
403
QString myQrcPath = ":/north_arrow.png";
404
if ( QFile::exists( myCurThemePath ) )
406
myQActionPointer->setIcon( QIcon( myCurThemePath ) );
408
else if ( QFile::exists( myDefThemePath ) )
410
myQActionPointer->setIcon( QIcon( myDefThemePath ) );
412
else if ( QFile::exists( myQrcPath ) )
414
myQActionPointer->setIcon( QIcon( myQrcPath ) );
418
myQActionPointer->setIcon( QIcon() );
395
423
* Required extern functions needed for every plugin