~ubuntu-branches/ubuntu/hardy/qgis/hardy

« back to all changes in this revision

Viewing changes to src/plugins/north_arrow/plugin.cpp

  • Committer: Bazaar Package Importer
  • Author(s): William Grant
  • Date: 2007-05-06 13:42:32 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134232-pyli6t388w5asd8x
Tags: 0.8.0-3ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules, debian/qgis.install, debian/qgis.dirs debian/qgis.desktop:
    Add and install .desktop.
* debian/qgis.desktop: Remove Applications category; it's not real.
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
  plugin.cpp
 
3
  Import tool for various worldmap analysis output files
 
4
Functions:
 
5
 
 
6
-------------------
 
7
begin                : Jan 21, 2004
 
8
copyright            : (C) 2004 by Tim Sutton
 
9
email                : tim@linfiniti.com
 
10
 
 
11
 ***************************************************************************/
 
12
 
 
13
/***************************************************************************
 
14
 *                                                                         *
 
15
 *   This program is free software; you can redistribute it and/or modify  *
 
16
 *   it under the terms of the GNU General Public License as published by  *
 
17
 *   the Free Software Foundation; either version 2 of the License, or     *
 
18
 *   (at your option) any later version.                                   *
 
19
 *                                                                         *
 
20
 ***************************************************************************/
 
21
/*  $Id: plugin.cpp 6301 2006-12-22 07:43:47Z g_j_m $ */
 
22
 
 
23
// includes
 
24
 
 
25
#include <qgisapp.h>
 
26
#include "qgisgui.h"
 
27
#include <qgsmaplayer.h>
 
28
#include "plugin.h"
 
29
#include "qgsproject.h"
 
30
#include "qgsmapcanvas.h"
 
31
#include "qgsapplication.h"
 
32
 
 
33
// qt includes
 
34
#include <QPainter>
 
35
#include <QMenu>
 
36
 
 
37
//non qt includes
 
38
#include <iostream>
 
39
#include <cmath>
 
40
#include <cassert>
 
41
 
 
42
//the gui subclass
 
43
#include "plugingui.h"
 
44
 
 
45
// xpm for creating the toolbar icon
 
46
#include "icon.xpm"
 
47
 
 
48
#ifdef WIN32
 
49
#define QGISEXTERN extern "C" __declspec( dllexport )
 
50
#else
 
51
#define QGISEXTERN extern "C"
 
52
#endif
 
53
 
 
54
//
 
55
static const char * const ident_ = "$Id: plugin.cpp 6301 2006-12-22 07:43:47Z g_j_m $";
 
56
 
 
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");
 
60
static const QgisPlugin::PLUGINTYPE type_ = QgisPlugin::UI;
 
61
 
 
62
const double QgsNorthArrowPlugin::PI = 3.14159265358979323846;
 
63
//  const double QgsNorthArrowPlugin::DEG2RAD = 0.0174532925199433;
 
64
const double QgsNorthArrowPlugin::TOL = 1e-8;
 
65
 
 
66
 
 
67
/**
 
68
 * Constructor for the plugin. The plugin is passed a pointer to the main app
 
69
 * and an interface object that provides access to exposed functions in QGIS.
 
70
 * @param qgis Pointer to the QGIS main window
 
71
 * @param _qI Pointer to the QGIS interface object
 
72
 */
 
73
QgsNorthArrowPlugin::QgsNorthArrowPlugin(QgisApp * theQGisApp,
 
74
                                         QgisIface * theQgisInterFace):
 
75
    QgisPlugin(name_,description_,version_,type_),
 
76
    qgisMainWindowPointer(theQGisApp),
 
77
    qGisInterface(theQgisInterFace)
 
78
{
 
79
  mRotationInt=0;
 
80
  mAutomatic=true;
 
81
  mPlacementLabels << tr("Bottom Left") << tr("Top Left") 
 
82
                   << tr("Top Right") << tr("Bottom Right");
 
83
}
 
84
 
 
85
QgsNorthArrowPlugin::~QgsNorthArrowPlugin()
 
86
{
 
87
}
 
88
 
 
89
  /*
 
90
 * Initialize the GUI interface for the plugin
 
91
 */
 
92
void QgsNorthArrowPlugin::initGui()
 
93
{
 
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"));
 
97
  // Connect the action to the run
 
98
  connect(myQActionPointer, SIGNAL(activated()), this, SLOT(run()));
 
99
  //render the arrow each time the map is rendered
 
100
  connect(qGisInterface->getMapCanvas(), SIGNAL(renderComplete(QPainter *)), this, SLOT(renderNorthArrow(QPainter *)));
 
101
  //this resets this plugin up if a project is loaded
 
102
  connect(qgisMainWindowPointer, SIGNAL(projectRead()), this, SLOT(projectRead()));
 
103
  // Add the icon to the toolbar & appropriate menu
 
104
  qGisInterface->addToolBarIcon(myQActionPointer);
 
105
  qGisInterface->addPluginMenu(tr("&Decorations"), myQActionPointer);
 
106
 
 
107
  projectRead();
 
108
  refreshCanvas();
 
109
 
 
110
}
 
111
 
 
112
void QgsNorthArrowPlugin::projectRead()
 
113
{
 
114
#ifdef QGISDEBUG
 
115
    std::cout << "+++++++++ north arrow plugin - project read slot called...." << std::endl;
 
116
#endif
 
117
    //default text to start with - try to fetch it from qgsproject
 
118
 
 
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);
 
123
}
 
124
 
 
125
//method defined in interface
 
126
void QgsNorthArrowPlugin::help()
 
127
{
 
128
  //implement me!
 
129
}
 
130
 
 
131
// Slot called when the buffer menu item is activated
 
132
void QgsNorthArrowPlugin::run()
 
133
{
 
134
  QgsNorthArrowPluginGui *myPluginGui = new QgsNorthArrowPluginGui(qgisMainWindowPointer, QgisGui::ModalDialogFlags);
 
135
  //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);
 
141
 
 
142
  //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()));
 
148
  myPluginGui->show();
 
149
}
 
150
 
 
151
//! Refresh the map display using the mapcanvas exported via the plugin interface
 
152
void QgsNorthArrowPlugin::refreshCanvas()
 
153
{
 
154
  qGisInterface->getMapCanvas()->refresh();
 
155
}
 
156
 
 
157
void QgsNorthArrowPlugin::renderNorthArrow(QPainter * theQPainter)
 
158
{
 
159
#ifdef QGISDEBUG
 
160
      std::cout << "Rendering n-arrow"  << std::endl;
 
161
#endif
 
162
  //Large IF statement controlled by enable check box
 
163
  if (mEnable)
 
164
  {
 
165
    QPixmap myQPixmap; //to store the north arrow image in
 
166
 
 
167
    QString myFileNameQString = QgsApplication::pkgDataPath() +
 
168
                                "/images/north_arrows/default.png";
 
169
 
 
170
    //std::cout << "Trying to load " << myFileNameQString << std::cout;
 
171
    if (myQPixmap.load(myFileNameQString))
 
172
    {
 
173
 
 
174
      double centerXDouble = myQPixmap.width()/2;
 
175
      double centerYDouble = myQPixmap.height()/2;
 
176
      //save the current canvas rotation
 
177
      theQPainter->save();
 
178
      //
 
179
      //work out how to shift the image so that it rotates
 
180
      //           properly about its center
 
181
      //(x cos a + y sin a - x, -x sin a + y cos a - y)
 
182
      //
 
183
 
 
184
      // could move this call to somewhere else so that it is only
 
185
      // called when the projection or map extent changes
 
186
      if (mAutomatic)
 
187
        calculateNorthDirection();
 
188
 
 
189
      double myRadiansDouble = mRotationInt * PI / 180.0;
 
190
      int xShift = static_cast<int>((
 
191
                                      (centerXDouble * cos(myRadiansDouble)) +
 
192
                                      (centerYDouble * sin(myRadiansDouble))
 
193
                                    ) - centerXDouble);
 
194
      int yShift = static_cast<int>((
 
195
                                      (-centerXDouble * sin(myRadiansDouble)) +
 
196
                                      (centerYDouble * cos(myRadiansDouble))
 
197
                                    ) - centerYDouble);
 
198
 
 
199
      // need width/height of paint device
 
200
      int myHeight = theQPainter->device()->height();
 
201
      int myWidth = theQPainter->device()->width();
 
202
 
 
203
#ifdef QGISDEBUG
 
204
      std::cout << "Rendering n-arrow at " << mPlacementLabels.at(mPlacementIndex).toLocal8Bit().data() << std::endl;
 
205
#endif
 
206
      //Determine placement of label from form combo box
 
207
      switch (mPlacementIndex)
 
208
      {
 
209
      case 0: // Bottom Left
 
210
        theQPainter->translate(0,myHeight-myQPixmap.height());
 
211
        break;
 
212
      case 1: // Top Left
 
213
        //no need to translate for TL corner because we're already at the origin
 
214
        theQPainter->translate(0, 0);
 
215
        break;
 
216
      case 2: // Top Right
 
217
        theQPainter->translate(myWidth-myQPixmap.width(),0);
 
218
        break;
 
219
      case 3: // Bottom Right
 
220
        theQPainter->translate(myWidth-myQPixmap.width(),
 
221
                             myHeight-myQPixmap.height());
 
222
        break;
 
223
      default:
 
224
        std::cout << "Unable to determine where to put north arrow so defaulting to top left" 
 
225
                  << std::endl;
 
226
      }
 
227
      //rotate the canvas by the north arrow rotation amount
 
228
      theQPainter->rotate( mRotationInt );
 
229
      //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);
 
232
 
 
233
      //unrotate the canvas again
 
234
      theQPainter->restore();
 
235
    }
 
236
    else
 
237
    {
 
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")));
 
242
    }
 
243
  }
 
244
 
 
245
}
 
246
// Unload the plugin by cleaning up the GUI
 
247
void QgsNorthArrowPlugin::unload()
 
248
{
 
249
  // remove the GUI
 
250
  qGisInterface->removePluginMenu(tr("&Decorations"), myQActionPointer);
 
251
  qGisInterface->removeToolBarIcon(myQActionPointer);
 
252
  // remove the northarrow from the canvas
 
253
  disconnect(qGisInterface->getMapCanvas(), SIGNAL(renderComplete(QPainter *)),
 
254
             this, SLOT(renderNorthArrow(QPainter *)));
 
255
  refreshCanvas();
 
256
 
 
257
  delete myQActionPointer;
 
258
}
 
259
 
 
260
 
 
261
void QgsNorthArrowPlugin::rotationChanged(int theInt)
 
262
{
 
263
  mRotationInt = theInt;
 
264
  QgsProject::instance()->writeEntry("NorthArrow","/Rotation", mRotationInt  );
 
265
}
 
266
 
 
267
//! set placement of north arrow
 
268
void QgsNorthArrowPlugin::setPlacement(int placementIndex)
 
269
{
 
270
  mPlacementIndex = placementIndex;
 
271
  QgsProject::instance()->writeEntry("NorthArrow","/Placement", mPlacementIndex);
 
272
}
 
273
 
 
274
void QgsNorthArrowPlugin::setEnabled(bool theBool)
 
275
{
 
276
  mEnable = theBool;
 
277
  QgsProject::instance()->writeEntry("NorthArrow","/Enabled", mEnable );
 
278
}
 
279
 
 
280
void QgsNorthArrowPlugin::setAutomatic(bool theBool)
 
281
{
 
282
  mAutomatic = theBool;
 
283
  QgsProject::instance()->writeEntry("NorthArrow","/Automatic", mAutomatic );
 
284
  if (mAutomatic)
 
285
    calculateNorthDirection();
 
286
}
 
287
 
 
288
bool QgsNorthArrowPlugin::calculateNorthDirection()
 
289
{
 
290
  QgsMapCanvas& mapCanvas = *(qGisInterface->getMapCanvas());
 
291
 
 
292
  bool goodDirn = false;
 
293
 
 
294
  if (mapCanvas.layerCount() > 0)
 
295
  {
 
296
    // Grab an SRS from any layer
 
297
    QgsMapLayer& mapLayer = *(mapCanvas.getZpos(0));
 
298
    QgsSpatialRefSys& outputSRS = mapLayer.coordinateTransform()->destSRS();
 
299
 
 
300
    if (outputSRS.isValid() && !outputSRS.geographicFlag())
 
301
    {
 
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());
 
306
 
 
307
      QgsCoordinateTransform transform(outputSRS, ourSRS);
 
308
 
 
309
      QgsRect extent = mapCanvas.extent();
 
310
      QgsPoint p1(extent.center());
 
311
      // A point a bit above p1. XXX assumes that y increases up!!
 
312
      // May need to involve the maptopixel transform if this proves
 
313
      // to be a problem.
 
314
      QgsPoint p2(p1.x(), p1.y() + extent.height() * 0.25); 
 
315
 
 
316
      // project p1 and p2 to geographic coords
 
317
      try
 
318
      {        
 
319
        p1 = transform.transform(p1);
 
320
        p2 = transform.transform(p2);
 
321
      }
 
322
      catch (QgsException &e)
 
323
      {
 
324
        // just give up
 
325
        return false;
 
326
      }
 
327
 
 
328
      // Work out the value of the initial heading one takes to go
 
329
      // from point p1 to point p2. The north direction is then that
 
330
      // many degrees anti-clockwise or vertical.
 
331
 
 
332
      // Take some care to not divide by zero, etc, and ensure that we
 
333
      // get sensible results for all possible values for p1 and p2.
 
334
 
 
335
      goodDirn = true;
 
336
      double angle = 0.0;
 
337
 
 
338
      // convert to radians for the equations below
 
339
      p1.multiply(PI/180.0);
 
340
      p2.multiply(PI/180.0);
 
341
 
 
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());
 
345
 
 
346
      if (y > 0.0)
 
347
      {
 
348
        if (x > TOL) 
 
349
          angle = atan(y/x);
 
350
        else if (x < -TOL) 
 
351
          angle = PI - atan(-y/x);
 
352
        else
 
353
          angle = 0.5 * PI;
 
354
      }
 
355
      else if (y < 0.0)
 
356
      {
 
357
        if (x > TOL)
 
358
          angle = -atan(-y/x);
 
359
        else if (x < -TOL)
 
360
          angle = atan(y/x) - PI;
 
361
        else
 
362
          angle = 1.5 * PI;
 
363
      }
 
364
      else
 
365
      {
 
366
        if (x > TOL)
 
367
          angle = 0.0;
 
368
        else if (x < -TOL)
 
369
          angle = PI;
 
370
        else
 
371
        {
 
372
          angle = 0.0; // p1 = p2
 
373
          goodDirn = false;
 
374
        }
 
375
      }
 
376
      // And set the angle of the north arrow. Perhaps do something
 
377
      // different if goodDirn = false.
 
378
      mRotationInt = static_cast<int>(round(fmod(360.0-angle*180.0/PI, 360.0)));
 
379
    }
 
380
    else
 
381
    {
 
382
      // For geographic SRS and for when there are no layers, set the
 
383
      // direction back to the default
 
384
      mRotationInt = 0;
 
385
    }
 
386
  }
 
387
  return goodDirn;
 
388
}
 
389
 
 
390
 
 
391
 
 
392
 
 
393
 
 
394
/**
 
395
 * Required extern functions needed  for every plugin
 
396
 * These functions can be called prior to creating an instance
 
397
 * of the plugin class
 
398
 */
 
399
// Class factory to return a new instance of the plugin class
 
400
QGISEXTERN QgisPlugin * classFactory(QgisApp * theQGisAppPointer, QgisIface * theQgisInterfacePointer)
 
401
{
 
402
  return new QgsNorthArrowPlugin(theQGisAppPointer, theQgisInterfacePointer);
 
403
}
 
404
 
 
405
// Return the name of the plugin - note that we do not user class members as
 
406
// the class may not yet be insantiated when this method is called.
 
407
QGISEXTERN QString name()
 
408
{
 
409
  return name_;
 
410
}
 
411
 
 
412
// Return the description
 
413
QGISEXTERN QString description()
 
414
{
 
415
  return description_;
 
416
}
 
417
 
 
418
// Return the type (either UI or MapLayer plugin)
 
419
QGISEXTERN int type()
 
420
{
 
421
  return type_;
 
422
}
 
423
 
 
424
// Return the version number for the plugin
 
425
QGISEXTERN QString version()
 
426
{
 
427
  return version_;
 
428
}
 
429
 
 
430
// Delete ourself
 
431
QGISEXTERN void unload(QgisPlugin * thePluginPointer)
 
432
{
 
433
  delete thePluginPointer;
 
434
}