tormapwidget.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /** 
00023  * \file tormapwidget.cpp
00024  * \version $Id: tormapwidget.cpp 1262 2006-10-03 07:16:16Z edmanm $
00025  * \brief Displays Tor servers and circuits on a map of the world
00026  */
00027 
00028 #include <QStringList>
00029 #include <cmath>
00030 #include "tormapwidget.h"
00031 
00032 #define IMG_WORLD_MAP   ":/images/map/world-map.png"
00033 
00034 /** QPens to use for drawing different map elements */
00035 #define PEN_ROUTER        QPen(QColor("#ff030d"), 1.0)
00036 #define PEN_CIRCUIT       QPen(Qt::yellow, 0.5)
00037 #define PEN_SELECTED      QPen(Qt::green, 2.0)
00038 
00039 /** Size of the map image */
00040 #define IMG_WIDTH       1000
00041 #define IMG_HEIGHT      507
00042 
00043 /** Border between the edge of the image and the actual map */
00044 #define MAP_TOP         2
00045 #define MAP_BOTTOM      2
00046 #define MAP_RIGHT       5
00047 #define MAP_LEFT        5
00048 #define MAP_WIDTH       (IMG_WIDTH-MAP_LEFT-MAP_RIGHT)
00049 #define MAP_HEIGHT      (IMG_HEIGHT-MAP_TOP-MAP_BOTTOM)
00050 
00051 /** Map offset from zero longitude */
00052 #define MAP_ORIGIN       -10
00053 
00054 /** Minimum allowable size for this widget */
00055 #define MIN_SIZE        QSize(512,256)
00056 
00057 /** Robinson projection table */
00058 /** Length of the parallel of latitude */
00059 float  plen[] = {
00060     1.0000, 0.9986, 0.9954, 0.9900,
00061     0.9822, 0.9730, 0.9600, 0.9427,
00062     0.9216, 0.8962, 0.8679, 0.8350,
00063     0.7986, 0.7597, 0.7186, 0.6732,
00064     0.6213, 0.5722, 0.5322
00065   };
00066 
00067 /** Distance of corresponding parallel from equator */ 
00068 float  pdfe[] = {
00069     0.0000, 0.0620, 0.1240, 0.1860,
00070     0.2480, 0.3100, 0.3720, 0.4340,
00071     0.4958, 0.5571, 0.6176, 0.6769,
00072     0.7346, 0.7903, 0.8435, 0.8936,
00073     0.9394, 0.9761, 1.0000
00074   };
00075 
00076 /** Default constructor */
00077 TorMapWidget::TorMapWidget(QWidget *parent)
00078 : ZImageView(parent)
00079 {
00080   QImage map(IMG_WORLD_MAP);
00081   setImage(map);
00082 }
00083 
00084 /** Destructor */
00085 TorMapWidget::~TorMapWidget()
00086 {
00087   clear();
00088 }
00089 
00090 /** Adds a router to the map. */
00091 void
00092 TorMapWidget::addRouter(QString id, float latitude, float longitude)
00093 {
00094   QPointF routerCoord = toMapSpace(latitude, longitude);
00095   
00096   /* Add data the hash of known routers, and plot the point on the map */
00097   _routers.insert(id, new QPair<QPointF,bool>(routerCoord, false));
00098 }
00099 
00100 /** Adds a circuit to the map using the given ordered list of router IDs. */
00101 void
00102 TorMapWidget::addCircuit(quint64 circid, QStringList path)
00103 {
00104   QPainterPath *circPainterPath = new QPainterPath;
00105   
00106   /* Build the new circuit */
00107   for (int i = 0; i < path.size()-1; i++) {
00108     QString fromNode = path.at(i);
00109     QString toNode = path.at(i+1);
00110    
00111     /* Add the coordinates of the hops to the circuit */
00112     if (_routers.contains(fromNode) && _routers.contains(toNode)) {
00113       /* Find the two endpoints for this path segment */
00114       QPointF fromPos = _routers.value(fromNode)->first;
00115       QPointF endPos = _routers.value(toNode)->first;
00116       
00117       /* Draw the path segment */ 
00118       circPainterPath->moveTo(fromPos);
00119       circPainterPath->lineTo(endPos);
00120       circPainterPath->moveTo(endPos);
00121     }
00122   }
00123   
00124   /** Add the data to the hash of known circuits and plot the circuit on the map */
00125   if (_circuits.contains(circid)) {
00126     /* This circuit is being updated, so just update the path, making sure we
00127      * free the memory allocated to the old one. */
00128     QPair<QPainterPath*,bool> *circuitPair = _circuits.value(circid);
00129     delete circuitPair->first;
00130     circuitPair->first = circPainterPath;
00131   } else {
00132     /* This is a new path, so just add it to our list */
00133     _circuits.insert(circid, new QPair<QPainterPath*,bool>(circPainterPath,false));
00134   }
00135 }
00136 
00137 /** Removes a circuit from the map. */
00138 void
00139 TorMapWidget::removeCircuit(quint64 circid)
00140 {
00141   QPair<QPainterPath*,bool> *circ = _circuits.take(circid);
00142   QPainterPath *circpath = circ->first;
00143   if (circpath) {
00144     delete circpath;
00145   }
00146 }
00147 
00148 /** Selects and highlights the router on the map. */
00149 void
00150 TorMapWidget::selectRouter(QString id)
00151 {
00152   if (_routers.contains(id)) {
00153     QPair<QPointF, bool> *routerPair = _routers.value(id);
00154     routerPair->second = true;
00155   }
00156   repaint();
00157 }
00158 
00159 /** Selects and highlights the circuit with the id <b>circid</b> 
00160  * on the map. */
00161 void
00162 TorMapWidget::selectCircuit(quint64 circid)
00163 {
00164   if (_circuits.contains(circid)) {
00165     QPair<QPainterPath*, bool> *circuitPair = _circuits.value(circid);
00166     circuitPair->second = true;
00167   }
00168   repaint();
00169 }
00170 
00171 /** Deselects any highlighted routers or circuits */
00172 void
00173 TorMapWidget::deselectAll()
00174 {
00175   /* Deselect all router points */
00176   foreach (QString router, _routers.keys()) {
00177     QPair<QPointF,bool> *routerPair = _routers.value(router);
00178     routerPair->second = false;
00179   }
00180   /* Deselect all circuit paths */
00181   foreach (quint64 circid, _circuits.keys()) {
00182     QPair<QPainterPath*,bool> *circuitPair = _circuits.value(circid);
00183     circuitPair->second = false;
00184   }
00185 }
00186 
00187 /** Clears the list of routers and removes all the data on the map */
00188 void
00189 TorMapWidget::clear()
00190 {
00191   /* Clear out all the router points and free their memory */
00192   foreach (QString router, _routers.keys()) {
00193     delete _routers.take(router);
00194   }
00195   /* Clear out all the circuit paths and free their memory */
00196   foreach (quint64 circid, _circuits.keys()) {
00197     QPair<QPainterPath*,bool> *circuitPair = _circuits.take(circid);
00198     delete circuitPair->first;
00199     delete circuitPair;
00200   }
00201 }
00202   
00203 /** Draws the routers and paths onto the map image. */
00204 void
00205 TorMapWidget::paintImage(QPainter *painter)
00206 {
00207   painter->setRenderHint(QPainter::Antialiasing);
00208   
00209   /* Draw the router points */
00210   foreach(QString router, _routers.keys()) {
00211     QPair<QPointF,bool> *routerPair = _routers.value(router);
00212     painter->setPen((routerPair->second ? PEN_SELECTED : PEN_ROUTER)); 
00213     painter->drawPoint(routerPair->first);
00214   }
00215   /* Draw the circuit paths */
00216   foreach(quint64 circid, _circuits.keys()) {
00217     QPair<QPainterPath*,bool> *circuitPair = _circuits.value(circid);
00218     painter->setPen((circuitPair->second ? PEN_SELECTED : PEN_CIRCUIT));
00219     painter->drawPath(*(circuitPair->first));
00220   }
00221 }
00222 
00223 /** Converts world space coordinates into map space coordinates */
00224 QPointF
00225 TorMapWidget::toMapSpace(float latitude, float longitude)
00226 {
00227   float width  = MAP_WIDTH;
00228   float height = MAP_HEIGHT;
00229   float deg = width / 360.0;
00230   longitude += MAP_ORIGIN;
00231 
00232   float lat;
00233   float lon;
00234   
00235   lat = floor(longitude * (deg * lerp(abs(int(latitude)), plen))
00236               + width/2 + MAP_LEFT);
00237   
00238   if (latitude < 0) {
00239     lon = floor((height/2) + (lerp(abs(int(latitude)), pdfe) * (height/2))
00240                 + MAP_TOP);
00241   } else {
00242     lon = floor((height/2) - (lerp(abs(int(latitude)), pdfe) * (height/2))
00243                 + MAP_TOP);
00244   }
00245 
00246   return QPointF(lat, lon);
00247 }
00248   
00249 /** Linearly interpolates using the values in the Robinson projection table */
00250 float
00251 TorMapWidget::lerp(float input, float *table)
00252 {
00253   int x = int(floor(input / 5));
00254 
00255   return ((table[x+1] - table[x]) / 
00256           (((x+1)*5) - (x*5))) * (input - x*5) + table[x];
00257 }
00258 
00259 /** Returns the minimum size of the widget */
00260 QSize
00261 TorMapWidget::minimumSizeHint() const
00262 {
00263   return MIN_SIZE;
00264 }
00265 
00266 /** Zooms to fit all currently displayed circuits on the map. If there are no
00267  * circuits on the map, the viewport will be returned to its default position
00268  * (zoomed all the way out and centered). */
00269 void
00270 TorMapWidget::zoomToFit()
00271 {
00272   QRectF rect = circuitBoundingBox();
00273   
00274   if (rect.isNull()) {
00275     /* If there are no circuits, zoom all the way out */
00276     resetZoomPoint();
00277     zoom(0.0);
00278   } else {
00279     /* Zoom in on the displayed circuits */
00280     float zoomLevel = 1.0 - qMax(rect.height()/float(MAP_HEIGHT),
00281                                  rect.width()/float(MAP_WIDTH));
00282     
00283     zoom(rect.center().toPoint(), zoomLevel+0.2);
00284   }
00285 }
00286 
00287 /** Computes a bounding box around all currently displayed circuit paths on
00288  * the map. */
00289 QRectF
00290 TorMapWidget::circuitBoundingBox()
00291 {
00292   QRectF rect;
00293 
00294   /* Compute the union of bounding rectangles for all circuit paths */
00295   foreach (quint64 circid, _circuits.keys()) {
00296     QPair<QPainterPath*,bool> *pair = _circuits.value(circid);
00297     QPainterPath *circuit = pair->first;
00298     rect = rect.unite(circuit->boundingRect());
00299   }
00300   return rect;
00301 }
00302 

Generated on Mon Oct 23 20:08:16 2006 for Vidalia by  doxygen 1.5.0