• 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
  • plugins
  • render
  • elevationprofilefloatitem
ElevationProfileFloatItem.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 2011-2012 Florian Eßer <f.esser@rwth-aachen.de>
9 // Copyright 2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
10 //
11 
12 #include "ElevationProfileFloatItem.h"
13 
14 #include <QRect>
15 #include <QPainter>
16 #include <QPushButton>
17 #include <QMenu>
18 
19 #include "ui_ElevationProfileConfigWidget.h"
20 #include "MarbleLocale.h"
21 #include "MarbleModel.h"
22 #include "MarbleWidget.h"
23 #include "GeoDataPlacemark.h"
24 #include "GeoDataTreeModel.h"
25 #include "ViewportParams.h"
26 #include "routing/RoutingModel.h"
27 #include "routing/RoutingManager.h"
28 #include "MarbleDirs.h"
29 #include "ElevationModel.h"
30 #include "MarbleGraphicsGridLayout.h"
31 #include "MarbleMath.h"
32 
33 namespace Marble
34 {
35 
36 ElevationProfileFloatItem::ElevationProfileFloatItem()
37  : AbstractFloatItem( 0 ),
38  m_configDialog( 0 ),
39  ui_configWidget( 0 ),
40  m_markerPlacemark( 0 )
41 {
42 }
43 
44 ElevationProfileFloatItem::ElevationProfileFloatItem( const MarbleModel *marbleModel )
45  : AbstractFloatItem( marbleModel, QPointF( 220, 10.5 ), QSizeF( 0.0, 50.0 ) ),
46  m_configDialog( 0 ),
47  ui_configWidget( 0 ),
48  m_leftGraphMargin( 0 ),
49  m_eleGraphWidth( 0 ),
50  m_viewportWidth( 0 ),
51  m_shrinkFactorY( 1.2 ),
52  m_fontHeight( 10 ),
53  m_markerPlacemark( new GeoDataPlacemark ),
54  m_documentIndex( -1 ),
55  m_cursorPositionX( 0 ),
56  m_isInitialized( false ),
57  m_contextMenu( 0 ),
58  m_marbleWidget( 0 ),
59  m_routingModel( 0 ),
60  m_routeAvailable( false ),
61  m_firstVisiblePoint( 0 ),
62  m_lastVisiblePoint( 0 ),
63  m_zoomToViewport( false )
64 {
65  setVisible( false );
66  bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
67  if ( smallScreen ) {
68  setPosition( QPointF( 10.5, 10.5 ) );
69  }
70  bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution;
71  m_eleGraphHeight = highRes ? 100 : 50;
72 
73  setPadding( 1 );
74 
75  m_markerDocument.setDocumentRole( UnknownDocument );
76  m_markerDocument.setName( "Elevation Profile" );
77 
78  m_markerPlacemark->setName( "Elevation Marker" );
79  m_markerPlacemark->setVisible( false );
80  m_markerDocument.append( m_markerPlacemark );
81 }
82 
83 ElevationProfileFloatItem::~ElevationProfileFloatItem()
84 {
85 }
86 
87 QStringList ElevationProfileFloatItem::backendTypes() const
88 {
89  return QStringList( "elevationprofile" );
90 }
91 
92 qreal ElevationProfileFloatItem::zValue() const
93 {
94  return 3.0;
95 }
96 
97 QString ElevationProfileFloatItem::name() const
98 {
99  return tr("Elevation Profile");
100 }
101 
102 QString ElevationProfileFloatItem::guiString() const
103 {
104  return tr("&Elevation Profile");
105 }
106 
107 QString ElevationProfileFloatItem::nameId() const
108 {
109  return QString( "elevationprofile" );
110 }
111 
112 QString ElevationProfileFloatItem::version() const
113 {
114  return "1.2";
115 }
116 
117 QString ElevationProfileFloatItem::description() const
118 {
119  return tr( "A float item that shows the elevation profile of the current route." );
120 }
121 
122 QString ElevationProfileFloatItem::copyrightYears() const
123 {
124  return "2011, 2012";
125 }
126 
127 QList<PluginAuthor> ElevationProfileFloatItem::pluginAuthors() const
128 {
129  return QList<PluginAuthor>()
130  << PluginAuthor( QString::fromUtf8 ( "Florian Eßer" ), "f.esser@rwth-aachen.de" )
131  << PluginAuthor( "Bernhard Beschow", "bbeschow@cs.tu-berlin.de" );
132 }
133 
134 QIcon ElevationProfileFloatItem::icon () const
135 {
136  return QIcon(":/icons/elevationprofile.png");
137 }
138 
139 void ElevationProfileFloatItem::initialize ()
140 {
141  connect( marbleModel()->elevationModel(), SIGNAL(updateAvailable()), SLOT(updateData()) );
142 
143  m_routingModel = marbleModel()->routingManager()->routingModel();
144  connect( m_routingModel, SIGNAL(currentRouteChanged()), this, SLOT(updateData()) );
145 
146  m_fontHeight = QFontMetricsF( font() ).ascent() + 1;
147  m_leftGraphMargin = QFontMetricsF( font() ).width( "0000 m" ); // TODO make this dynamic according to actual need
148  connect( this, SIGNAL(dataUpdated()), SLOT(forceRepaint()) );
149 
150  updateData();
151 
152  m_isInitialized = true;
153 }
154 
155 bool ElevationProfileFloatItem::isInitialized () const
156 {
157  return m_isInitialized;
158 }
159 
160 void ElevationProfileFloatItem::changeViewport( ViewportParams *viewport )
161 {
162  if ( !( viewport->width() == m_viewportWidth && m_isInitialized ) ) {
163  bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution;
164  int const widthRatio = highRes ? 2 : 3;
165  setContentSize( QSizeF( viewport->width() / widthRatio,
166  m_eleGraphHeight + m_fontHeight * 2.5 ) );
167  m_eleGraphWidth = contentSize().width() - m_leftGraphMargin;
168  m_axisX.setLength( m_eleGraphWidth );
169  m_axisY.setLength( m_eleGraphHeight );
170  m_axisX.setTickCount( 3, m_eleGraphWidth / ( m_leftGraphMargin * 1.5 ) );
171  m_axisY.setTickCount( 2, m_eleGraphHeight / m_fontHeight );
172  m_viewportWidth = viewport->width();
173  bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
174  if ( !m_isInitialized && !smallScreen ) {
175  setPosition( QPointF( (viewport->width() - contentSize().width()) / 2 , 10.5 ) );
176  }
177  }
178 
179  update();
180 }
181 
182 void ElevationProfileFloatItem::paintContent( QPainter *painter )
183 {
184  painter->save();
185  painter->setRenderHint( QPainter::Antialiasing, true );
186  painter->setFont( font() );
187 
188  if ( ! ( m_routeAvailable && m_isInitialized && m_eleData.size() > 0 ) ) {
189  painter->setPen( QColor( Qt::black ) );
190  QString text = tr( "Create a route to view its elevation profile." );
191  painter->drawText( contentRect().toRect(), Qt::TextWordWrap | Qt::AlignCenter, text );
192  painter->restore();
193  return;
194  }
195  if ( m_zoomToViewport && ( m_lastVisiblePoint - m_firstVisiblePoint < 5 ) ) {
196  painter->setPen( QColor( Qt::black ) );
197  QString text = tr( "Not enough points in the current viewport.\nTry to disable 'Zoom to viewport'." );
198  painter->drawText( contentRect().toRect(), Qt::TextWordWrap | Qt::AlignCenter, text );
199  painter->restore();
200  return;
201  }
202 
203  QString intervalStr;
204  int lastStringEnds;
205 
206  // draw viewport bounds
207  if ( ! m_zoomToViewport && ( m_firstVisiblePoint > 0 || m_lastVisiblePoint < m_eleData.size() - 1 ) ) {
208  QColor color( Qt::black );
209  color.setAlpha( 64 );
210  QRect rect;
211  rect.setLeft( m_leftGraphMargin + m_eleData.value( m_firstVisiblePoint ).x() * m_eleGraphWidth / m_axisX.range() );
212  rect.setTop( 0 );
213  rect.setWidth( ( m_eleData.value( m_lastVisiblePoint ).x() - m_eleData.value( m_firstVisiblePoint ).x() ) * m_eleGraphWidth / m_axisX.range() );
214  rect.setHeight( m_eleGraphHeight );
215  painter->fillRect( rect, color );
216  }
217 
218  // draw X and Y axis
219  painter->setPen( Oxygen::aluminumGray4 );
220  painter->drawLine( m_leftGraphMargin, m_eleGraphHeight, contentSize().width(), m_eleGraphHeight );
221  painter->drawLine( m_leftGraphMargin, m_eleGraphHeight, m_leftGraphMargin, 0 );
222 
223  // draw Y grid and labels
224  painter->setPen( QColor( Qt::black ) );
225  QPen dashedPen( Qt::DashLine );
226  dashedPen.setColor( Oxygen::aluminumGray4 );
227  QRect labelRect( 0, 0, m_leftGraphMargin - 1, m_fontHeight + 2 );
228  lastStringEnds = m_eleGraphHeight + m_fontHeight;
229 // painter->drawText( m_leftGraphMargin + 1, m_fontHeight, "[" + m_axisY.unit() + "]" );
230  foreach ( const AxisTick &tick, m_axisY.ticks() ) {
231  const int posY = m_eleGraphHeight - tick.position;
232  painter->setPen( dashedPen );
233  painter->drawLine( m_leftGraphMargin, posY, contentSize().width(), posY );
234 
235  labelRect.moveCenter( QPoint( labelRect.center().x(), posY ) );
236  if ( labelRect.top() < 0 ) {
237  // don't cut off uppermost label
238  labelRect.moveTop( 0 );
239  }
240  if ( labelRect.bottom() >= lastStringEnds ) {
241  // Don't print overlapping labels
242  continue;
243  }
244  lastStringEnds = labelRect.top();
245  painter->setPen( QColor( Qt::black ) );
246  intervalStr.setNum( tick.value * m_axisY.scale() );
247  painter->drawText( labelRect, Qt::AlignRight, intervalStr );
248  }
249 
250  // draw X grid and labels
251  painter->setPen( QColor( Qt::black ) );
252  labelRect.moveTop( m_eleGraphHeight + 1 );
253  lastStringEnds = 0;
254  foreach ( const AxisTick &tick, m_axisX.ticks() ) {
255  const int posX = m_leftGraphMargin + tick.position;
256  painter->setPen( dashedPen );
257  painter->drawLine( posX, 0, posX, m_eleGraphHeight );
258 
259  intervalStr.setNum( tick.value * m_axisX.scale() );
260  if ( tick.position == m_axisX.ticks().last().position ) {
261  intervalStr += ' ' + m_axisX.unit();
262  }
263  labelRect.setWidth( QFontMetricsF( font() ).width( intervalStr ) * 1.5 );
264  labelRect.moveCenter( QPoint( posX, labelRect.center().y() ) );
265  if ( labelRect.right() > m_leftGraphMargin + m_eleGraphWidth ) {
266  // don't cut off rightmost label
267  labelRect.moveRight( m_leftGraphMargin + m_eleGraphWidth );
268  }
269  if ( labelRect.left() <= lastStringEnds ) {
270  // Don't print overlapping labels
271  continue;
272  }
273  lastStringEnds = labelRect.right();
274  painter->setPen( QColor( Qt::black ) );
275  painter->drawText( labelRect, Qt::AlignCenter, intervalStr );
276  }
277 
278  // display elevation gain/loss data
279  painter->setPen( QColor( Qt::black ) );
280  intervalStr = tr( "Difference: %1 %2" )
281  .arg( QString::number( m_gain - m_loss, 'f', 0 ) )
282  .arg( m_axisY.unit() );
283  intervalStr += QString::fromUtf8( " (↗ %1 %3 ↘ %2 %3)" )
284  .arg( QString::number( m_gain, 'f', 0 ) )
285  .arg( QString::number( m_loss, 'f', 0 ) )
286  .arg( m_axisY.unit() );
287  painter->drawText( contentRect().toRect(), Qt::AlignBottom | Qt::AlignCenter, intervalStr );
288 
289  // draw elevation profile
290  painter->setPen( QColor( Qt::black ) );
291  bool const highRes = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::HighResolution;
292  QPen pen = painter->pen();
293  pen.setWidth( highRes ? 2 : 1 );
294  painter->setPen( pen );
295 
296  QLinearGradient fillGradient( 0, 0, 0, m_eleGraphHeight );
297  QColor startColor = Oxygen::forestGreen4;
298  QColor endColor = Oxygen::hotOrange4;
299  startColor.setAlpha( 200 );
300  endColor.setAlpha( 32 );
301  fillGradient.setColorAt( 0.0, startColor );
302  fillGradient.setColorAt( 1.0, endColor );
303  QBrush brush = QBrush( fillGradient );
304  painter->setBrush( brush );
305 
306  QPoint oldPos;
307  oldPos.setX( m_leftGraphMargin );
308  oldPos.setY( ( m_axisY.minValue() - m_axisY.minValue() )
309  * m_eleGraphHeight / ( m_axisY.range() / m_shrinkFactorY ) );
310  oldPos.setY( m_eleGraphHeight - oldPos.y() );
311  QPainterPath path;
312  path.moveTo( oldPos.x(), m_eleGraphHeight );
313  path.lineTo( oldPos.x(), oldPos.y() );
314 
315  const int start = m_zoomToViewport ? m_firstVisiblePoint : 0;
316  const int end = m_zoomToViewport ? m_lastVisiblePoint : m_eleData.size() - 1;
317  for ( int i = start; i <= end; ++i ) {
318  QPoint newPos;
319  if ( i == start ) {
320  // make sure the plot always starts at the y-axis
321  newPos.setX( 0 );
322  } else {
323  newPos.setX( ( m_eleData.value(i).x() - m_axisX.minValue() ) * m_eleGraphWidth / m_axisX.range() );
324  }
325  newPos.rx() += m_leftGraphMargin;
326  if ( newPos.x() != oldPos.x() || newPos.y() != oldPos.y() ) {
327  newPos.setY( ( m_eleData.value(i).y() - m_axisY.minValue() )
328  * m_eleGraphHeight / ( m_axisY.range() * m_shrinkFactorY ) );
329  newPos.setY( m_eleGraphHeight - newPos.y() );
330  path.lineTo( newPos.x(), newPos.y() );
331  oldPos = newPos;
332  }
333  }
334  path.lineTo( oldPos.x(), m_eleGraphHeight );
335  // fill
336  painter->setPen( QPen( Qt::NoPen ) );
337  painter->drawPath( path );
338  // contour
339  // "remove" the first and last path element first, they are only used to fill down to the bottom
340  painter->setBrush( QBrush( Qt::NoBrush ) );
341  path.setElementPositionAt( 0, path.elementAt( 1 ).x, path.elementAt( 1 ).y );
342  path.setElementPositionAt( path.elementCount()-1,
343  path.elementAt( path.elementCount()-2 ).x,
344  path.elementAt( path.elementCount()-2 ).y );
345  painter->setPen( pen );
346  painter->drawPath( path );
347 
348  pen.setWidth( 1 );
349  painter->setPen( pen );
350 
351  // draw interactive cursor
352  const GeoDataCoordinates currentPoint = m_markerPlacemark->coordinate();
353  if ( currentPoint.isValid() ) {
354  painter->setPen( QColor( Qt::white ) );
355  painter->drawLine( m_leftGraphMargin + m_cursorPositionX, 0,
356  m_leftGraphMargin + m_cursorPositionX, m_eleGraphHeight );
357  qreal xpos = m_axisX.minValue() + ( m_cursorPositionX / m_eleGraphWidth ) * m_axisX.range();
358  qreal ypos = m_eleGraphHeight - ( ( currentPoint.altitude() - m_axisY.minValue() ) / ( qMax<qreal>( 1.0, m_axisY.range() ) * m_shrinkFactorY ) ) * m_eleGraphHeight;
359 
360  painter->drawLine( m_leftGraphMargin + m_cursorPositionX - 5, ypos,
361  m_leftGraphMargin + m_cursorPositionX + 5, ypos );
362  intervalStr.setNum( xpos * m_axisX.scale(), 'f', 2 );
363  intervalStr += ' ' + m_axisX.unit();
364  int currentStringBegin = m_leftGraphMargin + m_cursorPositionX
365  - QFontMetricsF( font() ).width( intervalStr ) / 2;
366  painter->drawText( currentStringBegin, contentSize().height() - 1.5 * m_fontHeight, intervalStr );
367 
368  intervalStr.setNum( currentPoint.altitude(), 'f', 1 );
369  intervalStr += ' ' + m_axisY.unit();
370  if ( m_cursorPositionX + QFontMetricsF( font() ).width( intervalStr ) + m_leftGraphMargin
371  < m_eleGraphWidth ) {
372  currentStringBegin = ( m_leftGraphMargin + m_cursorPositionX + 5 + 2 );
373  } else {
374  currentStringBegin = m_leftGraphMargin + m_cursorPositionX - 5
375  - QFontMetricsF( font() ).width( intervalStr ) * 1.5;
376  }
377  // Make sure the text still fits into the window
378  while ( ypos < m_fontHeight ) {
379  ypos++;
380  }
381  painter->drawText( currentStringBegin, ypos + m_fontHeight / 2, intervalStr );
382  }
383 
384  painter->restore();
385 }
386 
387 QDialog *ElevationProfileFloatItem::configDialog() //FIXME TODO Make a config dialog?
388 {
389  if ( !m_configDialog ) {
390  // Initializing configuration dialog
391  m_configDialog = new QDialog();
392  ui_configWidget = new Ui::ElevationProfileConfigWidget;
393  ui_configWidget->setupUi( m_configDialog );
394 
395  readSettings();
396 
397  connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), SLOT(writeSettings()) );
398  connect( ui_configWidget->m_buttonBox, SIGNAL(rejected()), SLOT(readSettings()) );
399  QPushButton *applyButton = ui_configWidget->m_buttonBox->button( QDialogButtonBox::Apply );
400  connect( applyButton, SIGNAL(clicked()), this, SLOT(writeSettings()) );
401  }
402  return m_configDialog;
403 }
404 
405 void ElevationProfileFloatItem::contextMenuEvent( QWidget *w, QContextMenuEvent *e )
406 {
407  if ( !m_contextMenu ) {
408  m_contextMenu = contextMenu();
409 
410  foreach( QAction *action, m_contextMenu->actions() ) {
411  if ( action->text() == tr( "&Configure..." ) ) {
412  m_contextMenu->removeAction( action );
413  break;
414  }
415  }
416 
417  QAction *toggleAction = m_contextMenu->addAction( tr("&Zoom to viewport"), this,
418  SLOT(toggleZoomToViewport()) );
419  toggleAction->setCheckable( true );
420  toggleAction->setChecked( m_zoomToViewport );
421  }
422 
423  Q_ASSERT( m_contextMenu );
424  m_contextMenu->exec( w->mapToGlobal( e->pos() ) );
425 }
426 
427 bool ElevationProfileFloatItem::eventFilter( QObject *object, QEvent *e )
428 {
429  if ( !enabled() || !visible() ) {
430  return false;
431  }
432 
433  MarbleWidget *widget = dynamic_cast<MarbleWidget*>( object );
434  if ( !widget ) {
435  return AbstractFloatItem::eventFilter(object,e);
436  }
437 
438  if ( widget && !m_marbleWidget ) {
439  m_marbleWidget = widget;
440  connect( this, SIGNAL(dataUpdated()), this, SLOT(updateVisiblePoints()) );
441  connect( m_marbleWidget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
442  this, SLOT(updateVisiblePoints()) );
443  connect( this, SIGNAL(settingsChanged(QString)), this, SLOT(updateVisiblePoints()) );
444  }
445 
446  if ( e->type() == QEvent::MouseButtonDblClick || e->type() == QEvent::MouseMove ) {
447  GeoDataTreeModel *const treeModel = const_cast<MarbleModel *>( marbleModel() )->treeModel();
448 
449  QMouseEvent *event = static_cast<QMouseEvent*>( e );
450  QRectF plotRect = QRectF ( m_leftGraphMargin, 0, m_eleGraphWidth, contentSize().height() );
451  plotRect.translate( positivePosition() );
452  plotRect.translate( padding(), padding() );
453 
454  // for antialiasing: increase size by 1 px to each side
455  plotRect.translate(-1, -1);
456  plotRect.setSize(plotRect.size() + QSize(2, 2) );
457 
458  const bool cursorAboveFloatItem = plotRect.contains(event->pos());
459 
460  if ( cursorAboveFloatItem ) {
461  const int start = m_zoomToViewport ? m_firstVisiblePoint : 0;
462  const int end = m_zoomToViewport ? m_lastVisiblePoint : m_eleData.size();
463 
464  // Double click triggers recentering the map at the specified position
465  if ( e->type() == QEvent::MouseButtonDblClick ) {
466  const QPointF mousePosition = event->pos() - plotRect.topLeft();
467  const int xPos = mousePosition.x();
468  for ( int i = start; i < end; ++i) {
469  const int plotPos = ( m_eleData.value(i).x() - m_axisX.minValue() ) * m_eleGraphWidth / m_axisX.range();
470  if ( plotPos >= xPos ) {
471  widget->centerOn( m_points[i], true );
472  break;
473  }
474  }
475  return true;
476  }
477 
478  if ( e->type() == QEvent::MouseMove && !event->buttons() & Qt::LeftButton ) {
479  // Cross hair cursor when moving above the float item
480  // and mark the position on the graph
481  widget->setCursor(QCursor(Qt::CrossCursor));
482  if ( m_cursorPositionX != event->pos().x() - plotRect.left() ) {
483  m_cursorPositionX = event->pos().x() - plotRect.left();
484  const qreal xpos = m_axisX.minValue() + ( m_cursorPositionX / m_eleGraphWidth ) * m_axisX.range();
485  GeoDataCoordinates currentPoint; // invalid coordinates
486  for ( int i = start; i < end; ++i) {
487  if ( m_eleData.value(i).x() >= xpos ) {
488  currentPoint = m_points[i];
489  currentPoint.setAltitude( m_eleData.value(i).y() );
490  break;
491  }
492  }
493  m_markerPlacemark->setCoordinate( currentPoint );
494  if ( m_documentIndex < 0 ) {
495  m_documentIndex = treeModel->addDocument( &m_markerDocument );
496  }
497  emit repaintNeeded();
498  }
499 
500  return true;
501  }
502  }
503  else {
504  if ( m_documentIndex >= 0 ) {
505  m_markerPlacemark->setCoordinate( GeoDataCoordinates() ); // set to invalid
506  treeModel->removeDocument( &m_markerDocument );
507  m_documentIndex = -1;
508  emit repaintNeeded();
509  }
510  }
511  }
512 
513  return AbstractFloatItem::eventFilter(object,e);
514 }
515 
516 void ElevationProfileFloatItem::updateData()
517 {
518  m_routeAvailable = m_routingModel && m_routingModel->rowCount() > 0;
519  m_points = m_routeAvailable ? m_routingModel->route().path() : GeoDataLineString();
520  m_eleData = calculateElevationData( m_points );
521 
522  calculateStatistics( m_eleData );
523  if ( m_eleData.length() >= 2 ) {
524  m_axisX.setRange( m_eleData.first().x(), m_eleData.last().x() );
525  m_axisY.setRange( qMin( m_minElevation, qreal( 0.0 ) ), m_maxElevation );
526  }
527  emit dataUpdated();
528 
529  forceRepaint();
530 }
531 
532 void ElevationProfileFloatItem::updateVisiblePoints()
533 {
534  if ( ! ( m_routeAvailable && m_routingModel ) ) {
535  return;
536  }
537  GeoDataLineString points = m_routingModel->route().path();
538  if ( points.size() < 2 ) {
539  return;
540  }
541 
542  // find the longest visible route section on screen
543  QList<QList<int> > routeSegments;
544  QList<int> currentRouteSegment;
545  for ( int i = 0; i < m_eleData.count(); i++ ) {
546  qreal lon = points[i].longitude(GeoDataCoordinates::Degree);
547  qreal lat = points[i].latitude (GeoDataCoordinates::Degree);
548  qreal x = 0;
549  qreal y = 0;
550 
551  if ( m_marbleWidget->screenCoordinates(lon, lat, x, y) ) {
552  // on screen --> add point to list
553  currentRouteSegment.append(i);
554  } else {
555  // off screen --> start new list
556  if ( !currentRouteSegment.isEmpty() ) {
557  routeSegments.append( currentRouteSegment );
558  currentRouteSegment.clear();
559  }
560  }
561  }
562  routeSegments.append( currentRouteSegment ); // in case the route ends on screen
563 
564  int maxLenght = 0;
565  foreach ( currentRouteSegment, routeSegments ) {
566  if ( currentRouteSegment.size() > maxLenght ) {
567  maxLenght = currentRouteSegment.size() ;
568  m_firstVisiblePoint = currentRouteSegment.first();
569  m_lastVisiblePoint = currentRouteSegment.last();
570  }
571  }
572  if ( m_firstVisiblePoint < 0 ) {
573  m_firstVisiblePoint = 0;
574  }
575  if ( m_lastVisiblePoint < 0 || m_lastVisiblePoint >= m_eleData.count() ) {
576  m_lastVisiblePoint = m_eleData.count() - 1;
577  }
578 
579  if ( m_zoomToViewport ) {
580  calculateStatistics( m_eleData );
581  m_axisX.setRange( m_eleData.value( m_firstVisiblePoint ).x(),
582  m_eleData.value( m_lastVisiblePoint ).x() );
583  m_axisY.setRange( m_minElevation, m_maxElevation );
584  }
585 
586  return;
587 }
588 
589 QList<QPointF> ElevationProfileFloatItem::calculateElevationData( const GeoDataLineString &lineString ) const
590 {
591  // TODO: Don't re-calculate the whole route if only a small part of it was changed
592  QList<QPointF> result;
593 
594  GeoDataLineString path;
595  for ( int i = 0; i < lineString.size(); i++ ) {
596  path.append( lineString[i] );
597 
598  const qreal lat = lineString[i].latitude ( GeoDataCoordinates::Degree );
599  const qreal lon = lineString[i].longitude( GeoDataCoordinates::Degree );
600  qreal ele = marbleModel()->elevationModel()->height( lon, lat );
601  if ( ele == invalidElevationData ) { // no data
602  ele = 0;
603  }
604 
605  // result.append( QPointF( path.length( EARTH_RADIUS ), ele ) );
606  // The code below does the same as the line above, but is much faster - O(1) instead of O(n)
607  if ( i ) {
608  Q_ASSERT( !result.isEmpty() ); // The else part below appended something in the first run
609  qreal const distance = EARTH_RADIUS * distanceSphere( lineString[i-1], lineString[i] );
610  result.append( QPointF( result.last().x() + distance, ele ) );
611  } else {
612  result.append( QPointF( 0, ele ) );
613  }
614  }
615 
616  return result;
617 }
618 
619 void ElevationProfileFloatItem::calculateStatistics( const QList<QPointF> &eleData )
620 {
621  const int averageOrder = 5;
622 
623  qreal lastAverage = 0;
624  m_maxElevation = 0.0;
625  m_minElevation = invalidElevationData;
626  m_gain = 0;
627  m_loss = 0;
628  const int start = m_zoomToViewport ? m_firstVisiblePoint : 0;
629  const int end = m_zoomToViewport ? m_lastVisiblePoint : eleData.size();
630  for ( int i = start; i < end; ++i ) {
631  m_maxElevation = qMax( m_maxElevation, eleData.value( i ).y() );
632  m_minElevation = qMin( m_minElevation, eleData.value( i ).y() );
633 
634  // Low-pass filtering (moving average) of the elevation profile to calculate gain and loss values
635  // not always the best method, see for example
636  // http://www.ikg.uni-hannover.de/fileadmin/ikg/staff/thesis/finished/documents/StudArb_Schulze.pdf
637  // (German), chapter 4.2
638 
639  if ( i >= averageOrder ) {
640  qreal average = 0;
641  for( int j = 0; j < averageOrder; j++ ) {
642  average += eleData.value( i-j ).y();
643  }
644  average /= averageOrder;
645  if ( i == averageOrder ) {
646  lastAverage = average; // else the initial elevation would be counted as gain
647  }
648  if ( average > lastAverage ) {
649  m_gain += average - lastAverage;
650  } else {
651  m_loss += lastAverage - average;
652  }
653  lastAverage = average;
654  }
655  }
656 }
657 
658 void ElevationProfileFloatItem::forceRepaint()
659 {
660  // We add one pixel as antialiasing could result into painting on these pixels to.
661  QRectF floatItemRect = QRectF( positivePosition() - QPoint( 1, 1 ),
662  size() + QSize( 2, 2 ) );
663  update();
664  emit repaintNeeded( floatItemRect.toRect() );
665 }
666 
667 void ElevationProfileFloatItem::readSettings()
668 {
669  if ( !m_configDialog )
670  return;
671 
672  if ( m_zoomToViewport ) {
673  ui_configWidget->m_zoomToViewportCheckBox->setCheckState( Qt::Checked );
674  }
675  else {
676  ui_configWidget->m_zoomToViewportCheckBox->setCheckState( Qt::Unchecked );
677  }
678 }
679 
680 void ElevationProfileFloatItem::writeSettings()
681 {
682  if ( ui_configWidget->m_zoomToViewportCheckBox->checkState() == Qt::Checked ) {
683  m_zoomToViewport = true;
684  } else {
685  m_zoomToViewport = false;
686  }
687 
688  emit settingsChanged( nameId() );
689 }
690 
691 void ElevationProfileFloatItem::toggleZoomToViewport()
692 {
693  m_zoomToViewport = ! m_zoomToViewport;
694  calculateStatistics( m_eleData );
695  if ( ! m_zoomToViewport ) {
696  m_axisX.setRange( m_eleData.first().x(), m_eleData.last().x() );
697  m_axisY.setRange( qMin( m_minElevation, qreal( 0.0 ) ), m_maxElevation );
698  }
699  readSettings();
700  emit settingsChanged( nameId() );
701 }
702 
703 
704 }
705 
706 Q_EXPORT_PLUGIN2(ElevationProfileFloatItem, Marble::ElevationProfileFloatItem)
707 
708 #include "ElevationProfileFloatItem.moc"
QPainter
Marble::AxisTick::position
int position
Definition: ElevationProfilePlotAxis.h:22
Marble::ElevationProfilePlotAxis::setTickCount
void setTickCount(const int min, const int max)
Definition: ElevationProfilePlotAxis.cpp:46
Marble::ElevationProfileFloatItem::backendTypes
virtual QStringList backendTypes() const
Returns the name(s) of the backend that the plugin can render This method should return the name of t...
Definition: ElevationProfileFloatItem.cpp:87
Marble::GeoDataCoordinates
A 3d point representation.
Definition: GeoDataCoordinates.h:52
RoutingModel.h
Marble::ElevationProfilePlotAxis::minValue
qreal minValue() const
Definition: ElevationProfilePlotAxis.cpp:58
Marble::AbstractFloatItem::visible
bool visible() const
Check visibility of the float item.
Definition: AbstractFloatItem.cpp:135
Marble::ElevationProfileFloatItem::nameId
virtual QString nameId() const
Returns the unique name of the plugin.
Definition: ElevationProfileFloatItem.cpp:107
Marble::GeoDataTreeModel
The representation of GeoData in a model This class represents all available data given by kml-data f...
Definition: GeoDataTreeModel.h:32
Marble::GeoDataDocument::setDocumentRole
void setDocumentRole(DocumentRole role)
Definition: GeoDataDocument.cpp:62
Marble::MarbleGlobal::HighResolution
Definition: MarbleGlobal.h:269
Marble::GeoDataCoordinates::setAltitude
void setAltitude(const qreal altitude)
set the altitude of the Point in meters
Definition: GeoDataCoordinates.cpp:1191
Marble::ElevationProfileFloatItem::pluginAuthors
virtual QList< PluginAuthor > pluginAuthors() const
Definition: ElevationProfileFloatItem.cpp:127
MarbleMath.h
Marble::RenderPlugin::repaintNeeded
void repaintNeeded(QRegion dirtyRegion=QRegion())
This signal is emitted if an update of the view is needed.
QDialog
Marble::MarbleWidget::screenCoordinates
bool screenCoordinates(qreal lon, qreal lat, qreal &x, qreal &y) const
Get the screen coordinates corresponding to geographical coordinates in the widget.
Definition: MarbleWidget.cpp:758
Marble::ElevationProfilePlotAxis::unit
QString unit() const
Definition: ElevationProfilePlotAxis.cpp:78
Marble::ElevationProfileFloatItem::zValue
virtual qreal zValue() const
Returns the z value of the layer (default: 0.0).
Definition: ElevationProfileFloatItem.cpp:92
MarbleModel.h
This file contains the headers for MarbleModel.
Marble::ElevationProfilePlotAxis::setRange
void setRange(const qreal &minValue, const qreal &maxValue)
Definition: ElevationProfilePlotAxis.cpp:33
QWidget
Marble::PluginAuthor
Definition: PluginInterface.h:28
Marble::AbstractFloatItem::pen
QPen pen() const
current pen for rendering
Definition: AbstractFloatItem.cpp:96
Marble::AbstractFloatItem::eventFilter
virtual bool eventFilter(QObject *object, QEvent *e)
Definition: AbstractFloatItem.cpp:161
Marble::FrameGraphicsItem::contentSize
QSizeF contentSize() const
Returns the size of the content of the MarbleGraphicsItem.
Definition: FrameGraphicsItem.cpp:184
Marble::GeoDataPlacemark::coordinate
GeoDataCoordinates coordinate(const QDateTime &dateTime=QDateTime(), bool *iconAtCoordinates=0) const
Return the coordinates of the placemark at time dateTime as a GeoDataCoordinates. ...
Definition: GeoDataPlacemark.cpp:78
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
Marble::MarbleGraphicsItem::size
QSizeF size() const
Returns the size of the item.
Definition: MarbleGraphicsItem.cpp:136
Marble::RoutingModel::route
const Route & route() const
Definition: RoutingModel.cpp:416
Marble::RenderPlugin::action
QAction * action() const
Plugin's menu action.
Definition: RenderPlugin.cpp:86
Marble::RoutingModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const
Overload of QAbstractListModel.
Definition: RoutingModel.cpp:158
Marble::GeoDataPlacemark::setCoordinate
void setCoordinate(qreal longitude, qreal latitude, qreal altitude=0, GeoDataCoordinates::Unit _unit=GeoDataCoordinates::Radian)
Set the coordinate of the placemark in longitude and latitude.
Definition: GeoDataPlacemark.cpp:121
QObject
Marble::GeoDataTreeModel::addDocument
int addDocument(GeoDataDocument *document)
Definition: GeoDataTreeModel.cpp:595
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
Marble::ElevationProfileFloatItem::ElevationProfileFloatItem
ElevationProfileFloatItem()
Definition: ElevationProfileFloatItem.cpp:36
Marble::Oxygen::hotOrange4
QColor const hotOrange4
Definition: MarbleColors.h:86
Marble::UnknownDocument
Definition: GeoDataDocument.h:40
Marble::ElevationProfilePlotAxis::range
qreal range() const
Definition: ElevationProfilePlotAxis.cpp:68
Marble::MarbleWidget
A widget class that displays a view of the earth.
Definition: MarbleWidget.h:102
Marble::RoutingManager::routingModel
RoutingModel * routingModel()
Provides access to the routing model which contains a list of routing instructions describing steps t...
Definition: RoutingManager.cpp:260
Marble::GeoDataCoordinates::altitude
qreal altitude() const
return the altitude of the Point in meters
Definition: GeoDataCoordinates.cpp:1197
Marble::AxisTick::value
qreal value
Definition: ElevationProfilePlotAxis.h:23
RoutingManager.h
Marble::ElevationProfileFloatItem::paintContent
virtual void paintContent(QPainter *painter)
Here the items paint their content.
Definition: ElevationProfileFloatItem.cpp:182
Marble::ViewportParams::width
int width() const
Definition: ViewportParams.cpp:250
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:238
Marble::ElevationProfileFloatItem::contextMenuEvent
virtual void contextMenuEvent(QWidget *w, QContextMenuEvent *e)
Definition: ElevationProfileFloatItem.cpp:405
Marble::GeoDataFeature::setName
void setName(const QString &value)
Set a new name for this feature.
Definition: GeoDataFeature.cpp:485
Marble::Oxygen::aluminumGray4
QColor const aluminumGray4
Definition: MarbleColors.h:92
Marble::MarbleModel::routingManager
RoutingManager * routingManager()
Definition: MarbleModel.cpp:605
Marble::ElevationProfileFloatItem::copyrightYears
virtual QString copyrightYears() const
Definition: ElevationProfileFloatItem.cpp:122
Marble::ElevationProfileFloatItem::description
virtual QString description() const
Returns a user description of the plugin.
Definition: ElevationProfileFloatItem.cpp:117
Marble::GeoDataTreeModel::removeDocument
void removeDocument(int index)
Definition: GeoDataTreeModel.cpp:646
Marble::RenderPlugin::settingsChanged
void settingsChanged(QString nameId)
This signal is emitted if the settings of the RenderPlugin changed.
Marble::AbstractFloatItem
The abstract class for float item plugins.
Definition: AbstractFloatItem.h:48
Marble::FrameGraphicsItem::contentRect
QRectF contentRect() const
Returns the rect of the content in item coordinates.
Definition: FrameGraphicsItem.cpp:171
MarbleDirs.h
MarbleLocale.h
Marble::ElevationModel::height
qreal height(qreal lon, qreal lat) const
Definition: ElevationModel.cpp:83
GeoDataPlacemark.h
Marble::MarbleModel::elevationModel
ElevationModel * elevationModel()
Definition: MarbleModel.cpp:699
GeoDataTreeModel.h
Marble::GeoDataLineString::append
void append(const GeoDataCoordinates &position)
Appends a given geodesic position as a new node to the LineString.
Definition: GeoDataLineString.cpp:221
Marble::GeoDataLineString
A LineString that allows to store a contiguous set of line segments.
Definition: GeoDataLineString.h:75
Marble::FrameGraphicsItem::padding
qreal padding() const
Returns the padding of the item.
Definition: FrameGraphicsItem.cpp:125
Marble::ViewportParams
A public class that controls what is visible in the viewport of a Marble map.
Definition: ViewportParams.h:44
Marble::GeoDataContainer::append
void append(GeoDataFeature *other)
add an element
Definition: GeoDataContainer.cpp:165
Marble::ScreenGraphicsItem::positivePosition
QPointF positivePosition() const
Return the positive position of the ScreenGraphicsItem.
Definition: ScreenGraphicsItem.cpp:49
Q_EXPORT_PLUGIN2
#define Q_EXPORT_PLUGIN2(a, b)
Definition: marble_export.h:34
Marble::MarbleWidget::centerOn
void centerOn(const qreal lon, const qreal lat, bool animated=false)
Center the view on a geographical point.
Definition: MarbleWidget.cpp:626
MarbleGraphicsGridLayout.h
ViewportParams.h
This file contains the headers for ViewportParams.
Marble::AxisTick
Definition: ElevationProfilePlotAxis.h:21
Marble::MarbleGlobal::SmallScreen
Definition: MarbleGlobal.h:268
Marble::ElevationProfilePlotAxis::scale
qreal scale() const
Definition: ElevationProfilePlotAxis.cpp:73
Marble::MarbleGlobal::getInstance
static MarbleGlobal * getInstance()
Definition: MarbleGlobal.cpp:37
Marble::ElevationProfileFloatItem::eventFilter
bool eventFilter(QObject *object, QEvent *e)
Definition: ElevationProfileFloatItem.cpp:427
Marble::GeoDataFeature::setVisible
void setVisible(bool value)
Set a new value for visibility.
Definition: GeoDataFeature.cpp:586
ElevationProfileFloatItem.h
Marble::MarbleModel
The data model (not based on QAbstractModel) for a MarbleWidget.
Definition: MarbleModel.h:96
ElevationModel.h
Marble::ElevationProfileFloatItem::changeViewport
virtual void changeViewport(ViewportParams *viewport)
Definition: ElevationProfileFloatItem.cpp:160
Marble::ElevationProfileFloatItem::initialize
virtual void initialize()
Definition: ElevationProfileFloatItem.cpp:139
Marble::ScreenGraphicsItem::setPosition
void setPosition(const QPointF &position)
Set the position of the ScreenGraphicsItem.
Definition: ScreenGraphicsItem.cpp:44
Marble::MarbleGlobal::profiles
Profiles profiles() const
Definition: MarbleGlobal.cpp:48
Marble::Oxygen::forestGreen4
QColor const forestGreen4
Definition: MarbleColors.h:74
Marble::MarbleGraphicsItem::update
void update()
Marks the item and all parent items as invalid.
Definition: MarbleGraphicsItem.cpp:167
MarbleWidget.h
This file contains the headers for MarbleWidget.
Marble::ElevationProfileFloatItem::version
virtual QString version() const
Definition: ElevationProfileFloatItem.cpp:112
Marble::AbstractFloatItem::font
QFont font() const
current font for rendering
Definition: AbstractFloatItem.cpp:107
Marble::RenderPlugin::enabled
bool enabled() const
is enabled
Marble::ElevationProfileFloatItem::isInitialized
virtual bool isInitialized() const
Definition: ElevationProfileFloatItem.cpp:155
Marble::ElevationProfileFloatItem::dataUpdated
void dataUpdated()
Marble::ElevationProfilePlotAxis::setLength
void setLength(const int &length)
Definition: ElevationProfilePlotAxis.cpp:40
Marble::Route::path
const GeoDataLineString & path() const
Definition: Route.cpp:66
Marble::GeoDataCoordinates::isValid
bool isValid() const
Returns.
Definition: GeoDataCoordinates.cpp:624
Marble::ElevationProfileFloatItem::name
virtual QString name() const
Returns the user-visible name of the plugin.
Definition: ElevationProfileFloatItem.cpp:97
Marble::ElevationProfilePlotAxis::ticks
AxisTickList ticks() const
Definition: ElevationProfilePlotAxis.cpp:83
Marble::RenderPlugin::marbleModel
const MarbleModel * marbleModel() const
Access to the MarbleModel.
Definition: RenderPlugin.cpp:81
Marble::FrameGraphicsItem::setPadding
void setPadding(qreal width)
Set the padding of the item.
Definition: FrameGraphicsItem.cpp:130
Marble::FrameGraphicsItem::setContentSize
void setContentSize(const QSizeF &size)
Sets the size of the content of the item.
Definition: FrameGraphicsItem.cpp:204
Marble::ElevationProfileFloatItem::~ElevationProfileFloatItem
~ElevationProfileFloatItem()
Definition: ElevationProfileFloatItem.cpp:83
Marble::AbstractFloatItem::contextMenu
QMenu * contextMenu()
Definition: AbstractFloatItem.cpp:230
Marble::ElevationProfileFloatItem::configDialog
QDialog * configDialog()
Returns a pointer to the configuration dialog of the plugin.
Definition: ElevationProfileFloatItem.cpp:387
Marble::ElevationProfileFloatItem::icon
virtual QIcon icon() const
Returns an icon for the plugin.
Definition: ElevationProfileFloatItem.cpp:134
Marble::GeoDataPlacemark
a class representing a point of interest on the map
Definition: GeoDataPlacemark.h:54
Marble::GeoDataLatLonAltBox
A class that defines a 3D bounding box for geographic data.
Definition: GeoDataLatLonAltBox.h:49
Marble::ElevationProfileFloatItem::guiString
virtual QString guiString() const
String that should be displayed in GUI.
Definition: ElevationProfileFloatItem.cpp:102
Marble::ElevationProfileFloatItem
The class that creates an interactive elvation profile.
Definition: ElevationProfileFloatItem.h:43
Marble::AbstractFloatItem::setVisible
void setVisible(bool visible)
Set visibility of the float item.
Definition: AbstractFloatItem.cpp:128
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:49 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