• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.12
  • kdeedu
  • marble
  • src
  • lib
  • marble
  • routing
AlternativeRoutesModel.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2010 Dennis Nienhüser <earthwings@gentoo.org>
9 //
10 
11 #include "AlternativeRoutesModel.h"
12 
13 #include "GeoDataDocument.h"
14 #include "GeoDataFolder.h"
15 #include "GeoDataExtendedData.h"
16 #include "GeoDataPlacemark.h"
17 #include "MarbleMath.h"
18 #include "RoutingModel.h"
19 
20 #include <QTimer>
21 #include <QPainter>
22 
23 namespace Marble {
24 
25 class AlternativeRoutesModelPrivate
26 {
27 public:
29  QVector<GeoDataDocument*> m_routes;
30 
32  QVector<GeoDataDocument*> m_restrainedRoutes;
33 
35  QTime m_responseTime;
36 
37  int m_currentIndex;
38 
39  AlternativeRoutesModelPrivate();
40 
44  bool filter( const GeoDataDocument* document ) const;
45 
53  static qreal similarity( const GeoDataDocument* routeA, const GeoDataDocument* routeB );
54 
58  static qreal distance( GeoDataLineString* wayPoints, const GeoDataCoordinates &position );
59 
64  static qreal bearing( const GeoDataCoordinates &one, const GeoDataCoordinates &two );
65 
70  static qreal distance( const GeoDataCoordinates &satellite, const GeoDataCoordinates &lineA, const GeoDataCoordinates &lineB );
71 
75  static GeoDataCoordinates coordinates( const GeoDataCoordinates &start, qreal distance, qreal bearing );
76 
81  static qreal unidirectionalSimilarity( const GeoDataDocument* routeA, const GeoDataDocument* routeB );
82 
86  static bool higherScore( const GeoDataDocument* one, const GeoDataDocument* two );
87 
91  static qreal instructionScore( const GeoDataDocument* document );
92 
93  static GeoDataLineString* waypoints( const GeoDataDocument* document );
94 
95  static int nonZero( const QImage &image );
96 
97  static QPolygonF polygon( const GeoDataLineString* lineString, qreal x, qreal y, qreal sx, qreal sy );
98 };
99 
100 
101 AlternativeRoutesModelPrivate::AlternativeRoutesModelPrivate() :
102  m_currentIndex( -1 )
103 {
104  // nothing to do
105 }
106 
107 int AlternativeRoutesModelPrivate::nonZero( const QImage &image )
108 {
109  QRgb* destLine = 0;
110  QRgb const black = qRgb( 0, 0, 0 );
111  int count = 0;
112  for ( int y = 0; y < image.height(); ++y ) {
113  destLine = (QRgb*) image.scanLine( y );
114  for ( int x = 0; x < image.width(); ++x ) {
115  count += destLine[x] == black ? 0 : 1;
116  }
117  }
118  return count;
119 }
120 
121 QPolygonF AlternativeRoutesModelPrivate::polygon( const GeoDataLineString* lineString, qreal x, qreal y, qreal sx, qreal sy )
122 {
123  QPolygonF poly;
124  for ( int i=0; i<lineString->size(); ++i ) {
125  poly << QPointF( qAbs( ( *lineString)[i].longitude() - x ) * sx,
126  qAbs( ( *lineString)[i].latitude() - y ) * sy );
127  }
128  return poly;
129 }
130 
131 bool AlternativeRoutesModelPrivate::filter( const GeoDataDocument* document ) const
132 {
133  for ( int i=0; i<m_routes.size(); ++i ) {
134  qreal similarity = AlternativeRoutesModelPrivate::similarity( document, m_routes.at( i ) );
135  if ( similarity > 0.8 ) {
136  return true;
137  }
138  }
139 
140  return false;
141 }
142 
143 qreal AlternativeRoutesModelPrivate::similarity( const GeoDataDocument* routeA, const GeoDataDocument* routeB )
144 {
145  return qMax<qreal>( unidirectionalSimilarity( routeA, routeB ),
146  unidirectionalSimilarity( routeB, routeA ) );
147 }
148 
149 qreal AlternativeRoutesModelPrivate::distance( GeoDataLineString* wayPoints, const GeoDataCoordinates &position )
150 {
151  Q_ASSERT( wayPoints && !wayPoints->isEmpty() );
152  qreal minDistance = 0;
153  for ( int i=1; i<wayPoints->size(); ++i ) {
154  qreal dist = distance( position, wayPoints->at( i-1 ), wayPoints->at( i ) );
155  if ( minDistance <= 0 || dist < minDistance ) {
156  minDistance = dist;
157  }
158  }
159 
160  return minDistance;
161 }
162 
163 qreal AlternativeRoutesModelPrivate::bearing( const GeoDataCoordinates &one, const GeoDataCoordinates &two )
164 {
165  qreal delta = two.longitude() - one.longitude();
166  qreal lat1 = one.latitude();
167  qreal lat2 = two.latitude();
168  return fmod( atan2( sin ( delta ) * cos ( lat2 ),
169  cos( lat1 ) * sin( lat2 ) - sin( lat1 ) * cos( lat2 ) * cos ( delta ) ), 2 * M_PI );
170 }
171 
172 GeoDataCoordinates AlternativeRoutesModelPrivate::coordinates( const GeoDataCoordinates &start, qreal distance, qreal bearing )
173 {
174  qreal lat1 = start.latitude();
175  qreal lon1 = start.longitude();
176  qreal lat2 = asin( sin( lat1 ) * cos( distance ) + cos( lat1 ) * sin( distance ) * cos( bearing ) );
177  qreal lon2 = lon1 + atan2( sin( bearing ) * sin( distance ) * cos( lat1 ), cos( distance ) - sin( lat1 ) * sin( lat2 ) );
178  return GeoDataCoordinates( lon2, lat2 );
179 }
180 
181 qreal AlternativeRoutesModelPrivate::distance( const GeoDataCoordinates &satellite, const GeoDataCoordinates &lineA, const GeoDataCoordinates &lineB )
182 {
183  qreal dist = distanceSphere( lineA, satellite );
184  qreal bearA = bearing( lineA, satellite );
185  qreal bearB = bearing( lineA, lineB );
186  qreal result = asin( sin ( dist ) * sin( bearB - bearA ) );
187  Q_ASSERT( qMax<qreal>( distanceSphere(satellite, lineA), distanceSphere(satellite, lineB) ) >= qAbs<qreal>(result) );
188 
189  result = acos( cos( dist ) / cos( result ) );
191  qreal final = qMin<qreal>( distanceSphere( satellite, lineA ), distanceSphere( satellite, lineB ) );
192  if ( result >= 0 && result <= distanceSphere( lineA, lineB ) ) {
193  GeoDataCoordinates nearest = coordinates( lineA, result, bearB );
194  return qMin<qreal>( final, distanceSphere( satellite, nearest ) );
195  } else {
196  return final;
197  }
198 }
199 
200 qreal AlternativeRoutesModelPrivate::unidirectionalSimilarity( const GeoDataDocument* routeA, const GeoDataDocument* routeB )
201 {
202  GeoDataLineString* waypointsA = waypoints( routeA );
203  GeoDataLineString* waypointsB = waypoints( routeB );
204  if ( !waypointsA || !waypointsB )
205  {
206  return 0.0;
207  }
208 
209  QImage image( 64, 64, QImage::Format_ARGB32_Premultiplied );
210  image.fill( qRgb( 0, 0, 0 ) );
211  GeoDataLatLonBox box = GeoDataLatLonBox::fromLineString( *waypointsA );
212  box = box.united( GeoDataLatLonBox::fromLineString( *waypointsB ) );
213  if ( !box.width() || !box.height() ) {
214  return 0.0;
215  }
216 
217  qreal const sw = image.width() / box.width();
218  qreal const sh = image.height() / box.height();
219 
220  QPainter painter( &image );
221  painter.setPen( QColor( Qt::white ) );
222 
223  painter.drawPoints( AlternativeRoutesModelPrivate::polygon( waypointsA, box.west(), box.north(), sw, sh ) );
224  int const countA = AlternativeRoutesModelPrivate::nonZero( image );
225 
226  painter.drawPoints( AlternativeRoutesModelPrivate::polygon( waypointsB, box.west(), box.north(), sw, sh ) );
227  int const countB = AlternativeRoutesModelPrivate::nonZero( image );
228  Q_ASSERT( countA <= countB );
229  return countB ? 1.0 - qreal( countB - countA ) / countB : 0;
230 }
231 
232 bool AlternativeRoutesModelPrivate::higherScore( const GeoDataDocument* one, const GeoDataDocument* two )
233 {
234  qreal instructionScoreA = instructionScore( one );
235  qreal instructionScoreB = instructionScore( two );
236  if ( instructionScoreA != instructionScoreB ) {
237  return instructionScoreA > instructionScoreB;
238  }
239 
240  qreal lengthA = waypoints( one )->length( EARTH_RADIUS );
241  qreal lengthB = waypoints( two )->length( EARTH_RADIUS );
242 
243  return lengthA < lengthB;
244 }
245 
246 qreal AlternativeRoutesModelPrivate::instructionScore( const GeoDataDocument* document )
247 {
248  bool hasInstructions = false;
249 
250  QStringList blacklist = QStringList() << "" << "Route" << "Tessellated";
251  QVector<GeoDataFolder*> folders = document->folderList();
252  foreach( const GeoDataFolder *folder, folders ) {
253  foreach( const GeoDataPlacemark *placemark, folder->placemarkList() ) {
254  if ( !blacklist.contains( placemark->name() ) ) {
255  hasInstructions = true;
256  break;
257  }
258  }
259  }
260 
261  foreach( const GeoDataPlacemark *placemark, document->placemarkList() ) {
262  if ( !blacklist.contains( placemark->name() ) ) {
263  hasInstructions = true;
264 
265  if ( placemark->extendedData().contains( "turnType" ) ) {
266  return 1.0;
267  }
268  }
269  }
270 
271  return hasInstructions ? 0.5 : 0.0;
272 }
273 
274 GeoDataLineString* AlternativeRoutesModelPrivate::waypoints( const GeoDataDocument* document )
275 {
276  QVector<GeoDataFolder*> folders = document->folderList();
277  foreach( const GeoDataFolder *folder, folders ) {
278  foreach( const GeoDataPlacemark *placemark, folder->placemarkList() ) {
279  GeoDataGeometry* geometry = placemark->geometry();
280  GeoDataLineString* lineString = dynamic_cast<GeoDataLineString*>( geometry );
281  if ( lineString ) {
282  return lineString;
283  }
284  }
285  }
286 
287  foreach( const GeoDataPlacemark *placemark, document->placemarkList() ) {
288  GeoDataGeometry* geometry = placemark->geometry();
289  GeoDataLineString* lineString = dynamic_cast<GeoDataLineString*>( geometry );
290  if ( lineString ) {
291  return lineString;
292  }
293  }
294 
295  return 0;
296 }
297 
298 AlternativeRoutesModel::AlternativeRoutesModel( QObject *parent ) :
299  QAbstractListModel( parent ),
300  d( new AlternativeRoutesModelPrivate() )
301 {
302  // nothing to do
303 }
304 
305 AlternativeRoutesModel::~AlternativeRoutesModel()
306 {
307  delete d;
308 }
309 
310 int AlternativeRoutesModel::rowCount ( const QModelIndex & ) const
311 {
312  return d->m_routes.size();
313 }
314 
315 QVariant AlternativeRoutesModel::headerData ( int, Qt::Orientation, int ) const
316 {
317  return QVariant();
318 }
319 
320 QVariant AlternativeRoutesModel::data ( const QModelIndex &index, int role ) const
321 {
322  QVariant result;
323 
324  if ( role == Qt::DisplayRole && index.column() == 0 && index.row() >= 0 && index.row() < d->m_routes.size() ) {
325  result = d->m_routes.at( index.row() )->name();
326  }
327 
328  return result;
329 }
330 
331 GeoDataDocument* AlternativeRoutesModel::route( int index )
332 {
333  if ( index >= 0 && index < d->m_routes.size() ) {
334  return d->m_routes.at(index);
335  }
336 
337  return 0;
338 }
339 
340 void AlternativeRoutesModel::newRequest( RouteRequest * )
341 {
342  d->m_responseTime.start();
343  d->m_currentIndex = -1;
344  clear();
345 }
346 
347 void AlternativeRoutesModel::addRestrainedRoutes()
348 {
349  Q_ASSERT( d->m_routes.isEmpty() );
350  qSort( d->m_restrainedRoutes.begin(), d->m_restrainedRoutes.end(), AlternativeRoutesModelPrivate::higherScore );
351 
352  foreach( GeoDataDocument* route, d->m_restrainedRoutes ) {
353  if ( !d->filter( route ) ) {
354  int affected = d->m_routes.size();
355  beginInsertRows( QModelIndex(), affected, affected );
356 // GeoDataDocument* base = d->m_routes.isEmpty() ? 0 : d->m_routes.first();
357  d->m_routes.push_back( route );
358  endInsertRows();
359  }
360  }
361 
362  d->m_restrainedRoutes.clear();
363  Q_ASSERT( !d->m_routes.isEmpty() );
364  setCurrentRoute( 0 );
365 }
366 
367 void AlternativeRoutesModel::addRoute( GeoDataDocument* document, WritePolicy policy )
368 {
369  if ( policy == Instant ) {
370  int affected = d->m_routes.size();
371  beginInsertRows( QModelIndex(), affected, affected );
372  d->m_routes.push_back( document );
373  endInsertRows();
374  return;
375  }
376 
377  if ( d->m_routes.isEmpty() && d->m_restrainedRoutes.isEmpty() ) {
378  // First
379  int responseTime = d->m_responseTime.elapsed();
380  d->m_restrainedRoutes.push_back( document );
381  int timeout = qMin<int>( 500, qMax<int>( 50, responseTime * 2 ) );
382  QTimer::singleShot( timeout, this, SLOT(addRestrainedRoutes()) );
383  return;
384  } else if ( d->m_routes.isEmpty() && !d->m_restrainedRoutes.isEmpty() ) {
385  d->m_restrainedRoutes.push_back( document );
386  } else {
387  for ( int i=0; i<d->m_routes.size(); ++i ) {
388  qreal similarity = AlternativeRoutesModelPrivate::similarity( document, d->m_routes.at( i ) );
389  if ( similarity > 0.8 ) {
390  if ( AlternativeRoutesModelPrivate::higherScore( document, d->m_routes.at( i ) ) ) {
391  d->m_routes[i] = document;
392  QModelIndex changed = index( i );
393  emit dataChanged( changed, changed );
394  }
395 
396  return;
397  }
398  }
399 
400  Q_ASSERT( !d->m_routes.isEmpty() );
401  int affected = d->m_routes.size();
402  beginInsertRows( QModelIndex(), affected, affected );
403  d->m_routes.push_back( document );
404  endInsertRows();
405  }
406 }
407 
408 qreal AlternativeRoutesModel::distance( const GeoDataCoordinates &satellite, const GeoDataCoordinates &lineA, const GeoDataCoordinates &lineB )
409 {
410  return AlternativeRoutesModelPrivate::distance( satellite, lineA, lineB );
411 }
412 
413 QVector<qreal> AlternativeRoutesModel::deviation( const GeoDataDocument* routeA, const GeoDataDocument* routeB )
414 {
415  GeoDataLineString* waypointsA = waypoints( routeA );
416  GeoDataLineString* waypointsB = waypoints( routeB );
417  QVector<qreal> result;
418  for ( int a=0; a<waypointsA->size(); ++a ) {
419  result.push_back( AlternativeRoutesModelPrivate::distance( waypointsB, waypointsA->at( a ) ) );
420  }
421  return result;
422 }
423 
424 void AlternativeRoutesModel::update( GeoDataDocument* route )
425 {
426  for ( int i=0; i<d->m_routes.size(); ++i ) {
427  if ( d->m_routes[i] == route ) {
428  emit dataChanged( index( i), index( i ) );
429  }
430  }
431 }
432 
433 GeoDataLineString* AlternativeRoutesModel::waypoints( const GeoDataDocument* document )
434 {
435  return AlternativeRoutesModelPrivate::waypoints( document );
436 }
437 
438 void AlternativeRoutesModel::setCurrentRoute( int index )
439 {
440  if ( index >= 0 && index < rowCount() && d->m_currentIndex != index ) {
441  d->m_currentIndex = index;
442  emit currentRouteChanged( currentRoute() );
443  emit currentRouteChanged( d->m_currentIndex );
444  }
445 }
446 
447 GeoDataDocument * AlternativeRoutesModel::currentRoute()
448 {
449  GeoDataDocument* result = 0;
450  if ( d->m_currentIndex >= 0 && d->m_currentIndex < rowCount() ) {
451  result = d->m_routes[d->m_currentIndex];
452  }
453 
454  return result;
455 }
456 
457 void AlternativeRoutesModel::clear()
458 {
459  QVector<GeoDataDocument*> routes = d->m_routes;
460  d->m_currentIndex = -1;
461  d->m_routes.clear();
462  beginResetModel();
463  endResetModel();
464  qDeleteAll(routes);
465 }
466 
467 } // namespace Marble
468 
469 #include "AlternativeRoutesModel.moc"
QPainter
GeoDataDocument.h
Marble::GeoDataCoordinates
A 3d point representation.
Definition: GeoDataCoordinates.h:52
RoutingModel.h
Marble::GeoDataDocument
A container for Features, Styles and in the future Schemas.
Definition: GeoDataDocument.h:64
Marble::AlternativeRoutesModel::clear
void clear()
Remove all alternative routes from the model.
Definition: AlternativeRoutesModel.cpp:457
Marble::AlternativeRoutesModel::WritePolicy
WritePolicy
Definition: AlternativeRoutesModel.h:36
Marble::AlternativeRoutesModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const
Overload of QAbstractListModel.
Definition: AlternativeRoutesModel.cpp:310
Marble::AlternativeRoutesModel::currentRouteChanged
void currentRouteChanged(GeoDataDocument *newRoute)
MarbleMath.h
Marble::AlternativeRoutesModel::addRoute
void addRoute(GeoDataDocument *document, WritePolicy policy=Lazy)
Old data in the model is discarded, the parsed content of the provided document is used as the new mo...
Definition: AlternativeRoutesModel.cpp:367
Marble::AlternativeRoutesModel::newRequest
void newRequest(RouteRequest *request)
Invalidate the current alternative routes and prepare for new ones to arrive.
Definition: AlternativeRoutesModel.cpp:340
Marble::GeoDataLineString::size
int size() const
Returns the number of nodes in a LineString.
Definition: GeoDataLineString.cpp:134
Marble::distanceSphere
qreal distanceSphere(qreal lon1, qreal lat1, qreal lon2, qreal lat2)
This method calculates the shortest distance between two points on a sphere.
Definition: MarbleMath.h:52
GeoDataExtendedData.h
Marble::AlternativeRoutesModel::currentRoute
GeoDataDocument * currentRoute()
Definition: AlternativeRoutesModel.cpp:447
QObject
Marble::AlternativeRoutesModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Overload of QAbstractListModel.
Definition: AlternativeRoutesModel.cpp:320
Marble::RouteRequest
Points to be included in a route.
Definition: RouteRequest.h:31
Marble::AlternativeRoutesModel::Instant
Definition: AlternativeRoutesModel.h:37
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:238
Marble::AlternativeRoutesModel::waypoints
static GeoDataLineString * waypoints(const GeoDataDocument *document)
Returns the waypoints contained in the route as a linestring.
Definition: AlternativeRoutesModel.cpp:433
Marble::AlternativeRoutesModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Overload of QAbstractListModel.
Definition: AlternativeRoutesModel.cpp:315
Marble::AlternativeRoutesModel::setCurrentRoute
void setCurrentRoute(int index)
Definition: AlternativeRoutesModel.cpp:438
GeoDataPlacemark.h
Marble::GeoDataLineString
A LineString that allows to store a contiguous set of line segments.
Definition: GeoDataLineString.h:75
Marble::GeoDataLineString::at
GeoDataCoordinates & at(int pos)
Returns a reference to the coordinates of a node at a given position. This method detaches the return...
Definition: GeoDataLineString.cpp:139
Marble::AlternativeRoutesModel::distance
static qreal distance(const GeoDataCoordinates &satellite, const GeoDataCoordinates &lineA, const GeoDataCoordinates &lineB)
Returns the distance between the given point and the given great circle path.
Definition: AlternativeRoutesModel.cpp:408
GeoDataFolder.h
Marble::AlternativeRoutesModel::deviation
static QVector< qreal > deviation(const GeoDataDocument *routeA, const GeoDataDocument *routeB)
Returns the minimal distance of each waypoint of routeA to routeB.
Definition: AlternativeRoutesModel.cpp:413
Marble::AlternativeRoutesModel::~AlternativeRoutesModel
~AlternativeRoutesModel()
Destructor.
Definition: AlternativeRoutesModel.cpp:305
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
AlternativeRoutesModel.h
Marble::AlternativeRoutesModel::route
GeoDataDocument * route(int index)
Definition: AlternativeRoutesModel.cpp:331
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:48 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal