[Marble-commits] KDE/kdeedu/marble/src/lib/routing

Dennis Nienhüser earthwings at gentoo.org
Sun May 2 14:48:02 CEST 2010


SVN commit 1121844 by nienhueser:

When creating via points in the map, insert them in the order indicated by the drag origin, not based on the minimum distance to the drop target. The latter usually results in shorter routes, but is not what a user would expect.

 M  +1 -0      RouteSkeleton.cpp  
 M  +44 -9     RoutingLayer.cpp  
 M  +63 -0     RoutingModel.cpp  
 M  +12 -0     RoutingModel.h  


--- trunk/KDE/kdeedu/marble/src/lib/routing/RouteSkeleton.cpp #1121843:1121844
@@ -193,6 +193,7 @@
 void RouteSkeleton::insert( int index, const GeoDataCoordinates &coordinates )
 {
     d->m_route.insert( index, coordinates );
+    emit positionAdded( index );
 }
 
 void RouteSkeleton::append( const GeoDataCoordinates &coordinates )
--- trunk/KDE/kdeedu/marble/src/lib/routing/RoutingLayer.cpp #1121843:1121844
@@ -69,12 +69,14 @@
 
     QPixmap m_viaPixmap;
 
-    QRect m_movingIndexDirtyRect;
+    QRect m_dirtyRect;
 
     QPoint m_dropStopOver;
 
     QPoint m_dragStopOver;
 
+    int m_dragStopOverRightIndex;
+
     bool m_pointSelection;
 
     RoutingModel *m_routingModel;
@@ -101,6 +103,8 @@
     /** Show a context menu at the specified position */
     void showContextMenu( const QPoint &position );
 
+    void storeDragPosition( const QPoint &position );
+
     // The following methods are mostly only called at one place in the code, but often
     // Inlined to avoid the function call overhead. Having functions here is just to
     // keep the code clean
@@ -138,7 +142,7 @@
 
 RoutingLayerPrivate::RoutingLayerPrivate( RoutingLayer *parent, MarbleWidget *widget ) :
         q( parent ), m_proxyModel( 0 ), m_movingIndex( -1 ), m_marbleWidget( widget ), m_targetPixmap( ":/data/bitmaps/routing_pick.png" ),
-        m_viaPixmap( ":/data/bitmaps/routing_via.png" ), m_pointSelection( false ),
+        m_viaPixmap( ":/data/bitmaps/routing_via.png" ), m_dragStopOverRightIndex( -1 ), m_pointSelection( false ),
         m_routingModel( 0 ), m_placemarkModel( 0 ), m_selectionModel( 0 ), m_routeDirty( false ), m_pixmapSize( 22, 22 ),
         m_routeSkeleton( 0 ), m_activeMenuIndex( -1 )
 {
@@ -215,7 +219,19 @@
         int dy = 1 + m_pixmapSize.height() / 2;
         QPoint center = m_dropStopOver - QPoint( dx, dy );
         painter->drawPixmap( center, m_targetPixmap );
+
+        if ( !m_dragStopOver.isNull() && m_dragStopOverRightIndex > 0 && m_dragStopOverRightIndex < m_routeSkeleton->size() ) {
+            qreal lon( 0.0 ), lat( 0.0 );
+            if ( m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(),
+                                                 lon, lat, GeoDataCoordinates::Radian ) ) {
+                GeoDataCoordinates drag( lon, lat );
+                bluePen.setStyle( Qt::DotLine );
+                painter->setPen( bluePen );
+                painter->drawLine( drag, m_routeSkeleton->at( m_dragStopOverRightIndex-1 ) );
+                painter->drawLine( drag, m_routeSkeleton->at( m_dragStopOverRightIndex ) );
     }
+        }
+    }
 
     for ( int i = 0; i < m_routingModel->rowCount(); ++i ) {
         QModelIndex index = m_routingModel->index( i, 0 );
@@ -259,6 +275,19 @@
     }
 }
 
+void RoutingLayerPrivate::storeDragPosition( const QPoint &pos )
+{
+    m_dragStopOver = pos;
+    m_dragStopOverRightIndex = -1;
+
+    qreal lon( 0.0 ), lat( 0.0 );
+    if ( m_routeSkeleton && !pos.isNull()
+        && m_marbleWidget->geoCoordinates( pos.x(), pos.y(), lon, lat, GeoDataCoordinates::Radian ) ) {
+        GeoDataCoordinates waypoint( lon, lat );
+        m_dragStopOverRightIndex = m_routingModel->rightNeighbor( waypoint, m_routeSkeleton );
+    }
+}
+
 bool RoutingLayerPrivate::handleMouseButtonPress( QMouseEvent *e )
 {
     if ( m_pointSelection ) {
@@ -292,7 +321,7 @@
                 }
                 m_selectionModel->select( index, command );
                 m_dropStopOver = e->pos();
-                m_dragStopOver = e->pos();
+                storeDragPosition( e->pos() );
                 return true;
             } else if ( e->button() == Qt::RightButton ) {
                 m_removeViaPointAction->setEnabled( false );
@@ -307,7 +336,7 @@
         if ( e->button() == Qt::LeftButton ) {
             /** @todo: Determine the neighbored via points and insert in order */
             m_dropStopOver = e->pos();
-            m_dragStopOver = e->pos();
+            storeDragPosition( e->pos() );
             return true;
         } else if ( e->button() == Qt::RightButton ) {
             m_removeViaPointAction->setEnabled( false );
@@ -364,9 +393,10 @@
         }
 
         qreal lon( 0.0 ), lat( 0.0 );
-        if ( m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(), lon, lat, GeoDataCoordinates::Radian ) ) {
+        if ( m_dragStopOverRightIndex > 0 && m_dragStopOverRightIndex < m_routeSkeleton->size()
+                && m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(), lon, lat, GeoDataCoordinates::Radian ) ) {
             GeoDataCoordinates position( lon, lat );
-            m_routeSkeleton->addVia( position );
+            m_routeSkeleton->insert( m_dragStopOverRightIndex, position );
             clearStopOver();
             emit q->routeDirty();
             return true;
@@ -397,7 +427,12 @@
             m_marbleWidget->setCursor( Qt::ArrowCursor );
         } else if ( !m_dragStopOver.isNull() ) {
             if ( e->buttons() & Qt::LeftButton ) {
+                // Repaint only that region of the map that is affected by the change
+                QRect dirty = m_routeRegion.boundingRect();
+                dirty |= QRect( m_dropStopOver, QSize( 22, 22 ) );
+                dirty |= QRect( e->pos(), QSize( 22, 22 ) );
                 m_dropStopOver = e->pos();
+                m_marbleWidget->repaint( dirty );
             } else {
                 m_dragStopOver = QPoint();
                 m_dropStopOver = QPoint();
@@ -453,19 +488,19 @@
 
 void RoutingLayerPrivate::paintStopOver( QRect dirty )
 {
-    m_marbleWidget->repaint( m_movingIndexDirtyRect );
+    m_marbleWidget->repaint( m_dirtyRect );
     int dx = 1 + m_pixmapSize.width() / 2;
     int dy = 1 + m_pixmapSize.height() / 2;
     dirty.adjust( -dx, -dy, -dx, -dy );
     m_marbleWidget->repaint( dirty );
-    m_movingIndexDirtyRect = dirty;
+    m_dirtyRect = dirty;
 }
 
 void RoutingLayerPrivate::clearStopOver()
 {
     m_dropStopOver = QPoint();
     m_dragStopOver = QPoint();
-    m_marbleWidget->repaint( m_movingIndexDirtyRect );
+    m_marbleWidget->repaint( m_dirtyRect );
 }
 
 RoutingLayer::RoutingLayer( MarbleWidget *widget, QWidget *parent ) :
--- trunk/KDE/kdeedu/marble/src/lib/routing/RoutingModel.cpp #1121843:1121844
@@ -12,10 +12,12 @@
 
 #include "MarbleDebug.h"
 #include "MarbleDirs.h"
+#include "MarbleMath.h"
 #include "GeoDataCoordinates.h"
 #include "GeoDataDocument.h"
 #include "GeoDataParser.h"
 #include "GeoDataPlacemark.h"
+#include "RouteSkeleton.h"
 
 #include <QtCore/QBuffer>
 #include <QtCore/QRegExp>
@@ -287,6 +289,67 @@
     reset();
 }
 
+int RoutingModel::rightNeighbor( const GeoDataCoordinates &position, RouteSkeleton const *const route ) const
+{
+    Q_ASSERT( route && "Must not pass a null route ");
+
+    // Quick result for trivial cases
+    if ( route->size() < 3 ) {
+        return route->size() - 1;
+    }
+
+    // Generate an ordered list of all waypoints
+    QVector<GeoDataCoordinates> waypoints;
+    QMap<int,int> mapping;
+    foreach( const RouteElement& element, d->m_route ) {
+        if ( element.type == WayPoint ) {
+            waypoints << element.position;
+        }
+    }
+
+    // Force first mapping point to match the route start
+    mapping[0] = 0;
+
+    // Calculate the mapping between waypoints and via points
+    // Need two for loops to avoid getting stuck in local minima
+    for ( int j=1; j<route->size()-1; ++j ) {
+        qreal minDistance = -1.0;
+        for ( int i=mapping[j-1]; i<waypoints.size(); ++i ) {
+            qreal distance = distanceSphere( waypoints[i], route->at(j) );
+            if (minDistance < 0.0 || distance < minDistance ) {
+                mapping[j] = i;
+                minDistance = distance;
+            }
+        }
+    }
+
+    // Determine waypoint with minimum distance to the provided position
+    qreal minWaypointDistance = -1.0;
+    int waypoint=0;
+    for ( int i=0; i<waypoints.size(); ++i ) {
+        qreal waypointDistance = distanceSphere( waypoints[i], position );
+        if ( minWaypointDistance < 0.0 || waypointDistance < minWaypointDistance ) {
+            minWaypointDistance = waypointDistance;
+            waypoint = i;
+        }
+    }
+
+    // Force last mapping point to match the route destination
+    mapping[route->size()-1] = waypoints.size()-1;
+
+    // Determine neighbor based on the mapping
+    QMap<int, int>::const_iterator iter = mapping.constBegin();
+    for ( ; iter != mapping.constEnd(); ++iter ) {
+        if ( iter.value() > waypoint ) {
+            int index = iter.key();
+            Q_ASSERT( index >= 0 && index <= route->size() );
+            return index;
+        }
+    }
+
+    return route->size()-1;
+}
+
 } // namespace Marble
 
 #include "RoutingModel.moc"
--- trunk/KDE/kdeedu/marble/src/lib/routing/RoutingModel.h #1121843:1121844
@@ -26,6 +26,7 @@
 {
 
 class RoutingModelPrivate;
+class RouteSkeleton;
 class GeoDataDocument;
 
 class RoutingModel : public QAbstractListModel
@@ -100,6 +101,17 @@
       */
     void clear();
 
+    /**
+      * Maps points from the provided route skeleton to waypoints in the model
+      * according to their global minimal distance. Returns the right neighbor
+      * (next route skeleton item along the waypoints) of the provided position.
+      * Provided route must not be null.
+      * @return -1 If the provided route is empty, the index of the right
+      * neighbor along the waypoints otherwise (result is a valid RouteSkeleton
+      * index in that case)
+      */
+    int rightNeighbor( const GeoDataCoordinates &position, RouteSkeleton const *const route ) const;
+
 private:
     RoutingModelPrivate *const d;
 };


More information about the Marble-commits mailing list