コード例 #1
0
void PolylineAnnotation::updateRegions( GeoPainter *painter )
{
    if ( m_busy ) {
        return;
    }

    const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() );

    if ( state() == SceneGraphicsItem::AddingNodes ) {
        // Create and update virtual nodes lists when being in the AddingPolgonNodes state, to
        // avoid overhead in other states.
        m_virtualNodesList.clear();
        for ( int i = 0; i < line.size() - 1; ++i ) {
            const QRegion newRegion( painter->regionFromEllipse( line.at(i).interpolate( line.at(i+1), 0.5 ),
                                                                 hoveredDim, hoveredDim ) );
            m_virtualNodesList.append( PolylineNode( newRegion ) );
        }
    }


    // Update the polyline region;
    m_polylineRegion = painter->regionFromPolyline( line, 15 );

    // Update the node lists.
    for ( int i = 0; i < m_nodesList.size(); ++i ) {
        const QRegion newRegion = m_nodesList.at(i).isSelected() ?
                                  painter->regionFromEllipse( line.at(i), selectedDim, selectedDim ) :
                                  painter->regionFromEllipse( line.at(i), regularDim, regularDim );
        m_nodesList[i].setRegion( newRegion );
    }
}
コード例 #2
0
bool PolylineAnnotation::processAddingNodesOnPress( QMouseEvent *mouseEvent )
{
    if ( mouseEvent->button() != Qt::LeftButton ) {
        return false;
    }

    GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() );

    // If a virtual node has just been clicked, add it to the polyline and start 'adjusting'
    // its position.
    const int virtualIndex = virtualNodeContains( mouseEvent->pos() );
    if ( virtualIndex != -1 && m_adjustedNode == -1 ) {
        Q_ASSERT( m_virtualHoveredNode == virtualIndex );

        line->insert( virtualIndex + 1, line->at( virtualIndex ).interpolate( line->at( virtualIndex + 1 ), 0.5 ) );
        m_nodesList.insert( virtualIndex + 1, PolylineNode() );

        m_adjustedNode = virtualIndex + 1;
        m_virtualHoveredNode = -1;
        return true;
    }

    // If a virtual node which has been previously clicked and selected to become a
    // 'real node' is clicked one more time, it stops from being 'adjusted'.
    const int realIndex = nodeContains( mouseEvent->pos() );
    if ( realIndex != -1 && m_adjustedNode != -1 ) {
        m_adjustedNode = -1;
        return true;
    }

    return false;
}
コード例 #3
0
bool PolylineAnnotation::processEditingOnMove( QMouseEvent *mouseEvent )
{
    if ( !m_viewport ) {
        return false;
    }

    qreal lon, lat;
    m_viewport->geoCoordinates( mouseEvent->pos().x(),
                                mouseEvent->pos().y(),
                                lon, lat,
                                GeoDataCoordinates::Radian );
    const GeoDataCoordinates newCoords( lon, lat );

    if ( m_interactingObj == InteractingNode ) {
        GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() );
        line->at(m_clickedNodeIndex) = newCoords;

        return true;
    } else if ( m_interactingObj == InteractingPolyline ) {
        GeoDataLineString *lineString = static_cast<GeoDataLineString*>( placemark()->geometry() );
        const GeoDataLineString oldLineString = *lineString;
        lineString->clear();

        const qreal deltaLat = lat - m_movedPointCoords.latitude();
        const qreal deltaLon = lon - m_movedPointCoords.longitude();

        Quaternion latRectAxis = Quaternion::fromEuler( 0, lon, 0);
        Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0);
        Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0);
        Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis;

        qreal lonRotated, latRotated;
        for ( int i = 0; i < oldLineString.size(); ++i ) {
            Quaternion qpos = oldLineString.at(i).quaternion();
            qpos.rotateAroundAxis(rotAxis);
            qpos.getSpherical( lonRotated, latRotated );
            GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 );

            lineString->append( movedPoint );
        }

        m_movedPointCoords = newCoords;
        return true;
    }

    return dealWithHovering( mouseEvent );
}
コード例 #4
0
void PlacemarkTextAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination )
{
    Q_UNUSED( source );
    qreal lat = destination.latitude();
    qreal lon = destination.longitude();
    GeoDataCoordinates::normalizeLonLat( lon, lat );
    placemark()->setCoordinate( lon, lat );
}
コード例 #5
0
SatellitesMSCItem::SatellitesMSCItem( const QString &name, 
                                      const QString &category,
                                      const QString &relatedBody,
                                      const QString &catalog,
                                      const QDateTime &missionStart,
                                      const QDateTime &missionEnd,
                                      int catalogIndex,
                                      PlanetarySats *planSat,
                                      const MarbleClock *clock )
    : TrackerPluginItem( name ),
      m_showOrbit( false ),
      m_track( new GeoDataTrack() ),
      m_clock( clock ),
      m_planSat( planSat ),
      m_name( name ),
      m_category( category ),
      m_relatedBody( relatedBody ),
      m_catalog( catalog ),
      m_catalogIndex( catalogIndex ),
      m_missionStart( missionStart ),
      m_missionEnd( missionEnd )
{
    placemark()->setVisualCategory( GeoDataFeature::Satellite );
    placemark()->setZoomLevel( 0 );
    placemark()->setGeometry( m_track );

    GeoDataStyle *style = new GeoDataStyle( *placemark()->style() );
    placemark()->setStyle( style );
    placemark()->style()->lineStyle().setColor( Oxygen::brickRed4 );
    placemark()->style()->lineStyle().setPenStyle( Qt::NoPen );
    placemark()->style()->labelStyle().setGlow( true );

    // use special icon for moons
    if( m_category == "Moons" ) {
        placemark()->style()->iconStyle().setIcon(
            QImage( ":/icons/moon.png" ) );
    }


    m_planSat->getKeplerElements(
        m_perc, m_apoc, m_inc, m_ecc, m_ra, m_tano, m_m0, m_a, m_n0 );

    setDescription();
    update();
}
コード例 #6
0
void PolylineAnnotation::deleteClickedNode()
{
    if ( state() != SceneGraphicsItem::Editing ) {
        return;
    }

    GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() );
    if ( m_nodesList.size() <= 2 ) {
        setRequest( SceneGraphicsItem::RemovePolylineRequest );
        return;
    }

    m_nodesList.removeAt( m_clickedNodeIndex );
    line->remove( m_clickedNodeIndex );
 }
コード例 #7
0
void SatellitesMSCItem::setDescription()
{
    QString description =
      QObject::tr( "Object name: %1 <br />"
                   "Category: %2 <br />"
                   "Pericentre: %3 km<br />"
                   "Apocentre: %4 km<br />"
                   "Inclination: %5 Degree<br />"
                   "Revolutions per day (24h): %6" )
        .arg( name(), category(), QString::number( m_perc, 'f', 2 ),
                                  QString::number( m_apoc, 'f', 2 ),
                                  QString::number( m_inc, 'f', 2 ),
                                  QString::number( m_n0, 'f', 2 ) );
     placemark()->setDescription( description );
}
コード例 #8
0
void PolylineAnnotation::setupRegionsLists( GeoPainter *painter )
{
    Q_ASSERT( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized );
    const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() );

    // Add poyline nodes.
    QVector<GeoDataCoordinates>::ConstIterator itBegin = line.constBegin();
    QVector<GeoDataCoordinates>::ConstIterator itEnd = line.constEnd();

    m_nodesList.clear();
    for ( ; itBegin != itEnd; ++itBegin ) {
        const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) );
        m_nodesList.append( newNode );
    }

    // Add region from polyline so that events on polyline's 'lines' could be caught.
    m_polylineRegion = painter->regionFromPolyline( line, 15 );
}
コード例 #9
0
void PolylineAnnotation::paint( GeoPainter *painter, const ViewportParams *viewport )
{
    m_viewport = viewport;
    Q_ASSERT( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType );

    painter->save();
    if ( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ) {
        setupRegionsLists( painter );
        m_regionsInitialized = true;
    } else {
        updateRegions( painter );
    }

    if ( hasFocus() ) {
        drawNodes( painter );
    }
    painter->restore();
}
コード例 #10
0
bool PolylineAnnotation::processMergingOnPress( QMouseEvent *mouseEvent )
{
    if ( mouseEvent->button() != Qt::LeftButton ) {
        return false;
    }

    GeoDataLineString line = static_cast<GeoDataLineString>( *placemark()->geometry() );

    const int index = nodeContains( mouseEvent->pos() );
    if ( index == -1 ) {
        return false;
    }

    // If this is the first node selected to be merged.
    if ( m_firstMergedNode == -1 ) {
        m_firstMergedNode = index;
        m_nodesList[index].setFlag( PolylineNode::NodeIsMerged );
   } else {
        Q_ASSERT( m_firstMergedNode != -1 );

        // Clicking two times the same node results in unmarking it for merging.
        if ( m_firstMergedNode == index ) {
            m_nodesList[index].setFlag( PolylineNode::NodeIsMerged, false );
            m_firstMergedNode = -1;
            return true;
        }

        // If these two nodes are the last ones remained as part of the polyline, remove
        // the whole polyline.
        if ( line.size() <= 2 ) {
            setRequest( SceneGraphicsItem::RemovePolylineRequest );
            return true;
        }
        m_nodesList[index].setFlag( PolylineNode::NodeIsMerged );
        m_secondMergedNode = index;

        delete m_animation;
        m_animation = new MergingPolylineNodesAnimation( this );
        setRequest( SceneGraphicsItem::StartPolylineAnimation );
    }

    return true;
}
コード例 #11
0
bool PlacemarkTextAnnotation::mouseMoveEvent( QMouseEvent *event )
{
    setRequest( SceneGraphicsItem::NoRequest );

    qreal lon, lat;
    m_viewport->geoCoordinates( event->pos().x(),
                                event->pos().y(),
                                lon, lat,
                                GeoDataCoordinates::Radian );

    if ( m_movingPlacemark ) {
        placemark()->setCoordinate( lon, lat );
        return true;
    } else {
        setRequest( SceneGraphicsItem::ChangeCursorPlacemarkHover );
        return true;
    }

    return false;
}
コード例 #12
0
void PolylineAnnotation::deleteAllSelectedNodes()
{
    if ( state() != SceneGraphicsItem::Editing ) {
        return;
    }

    GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() );

    for ( int i = 0; i < line->size(); ++i ) {
        if ( m_nodesList.at(i).isSelected() ) {
            if ( m_nodesList.size() <= 2 ) {
                setRequest( SceneGraphicsItem::RemovePolylineRequest );
                return;
            }

            m_nodesList.removeAt( i );
            line->remove( i );
            --i;
        }
    }
}
コード例 #13
0
void PolylineAnnotation::dealWithItemChange( const SceneGraphicsItem *other )
{
    Q_UNUSED( other );

    // So far we only deal with item changes when hovering nodes, so that
    // they do not remain hovered when changing the item we interact with.
    if ( state() == SceneGraphicsItem::Editing ) {
        if ( m_hoveredNodeIndex != -1 &&
             m_hoveredNodeIndex < static_cast<GeoDataLineString*>( placemark()->geometry() )->size() ) {
            m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsEditingHighlighted, false );
        }

        m_hoveredNodeIndex = -1;
    } else if ( state() == SceneGraphicsItem::MergingNodes ) {
        if ( m_hoveredNodeIndex != -1 ) {
            m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsMergingHighlighted, false );
        }

        m_hoveredNodeIndex = -1;
    } else if ( state() == SceneGraphicsItem::AddingNodes ) {
        m_virtualHoveredNode = -1;
    }
}
コード例 #14
0
void GroundOverlayFrame::update()
{
    GeoDataLatLonBox overlayLatLonBox = m_overlay->latLonBox();
    GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( placemark()->geometry() );
    poly->outerBoundary().clear();

    GeoDataCoordinates rotatedCoord;

    GeoDataCoordinates northWest(overlayLatLonBox.west(), overlayLatLonBox.north());
    rotatedCoord = northWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation());
    poly->outerBoundary().append( rotatedCoord );

    GeoDataCoordinates southWest(overlayLatLonBox.west(), overlayLatLonBox.south());
    rotatedCoord = southWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation());
    poly->outerBoundary().append( rotatedCoord );

    GeoDataCoordinates southEast(overlayLatLonBox.east(), overlayLatLonBox.south());
    rotatedCoord = southEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation());
    poly->outerBoundary().append( rotatedCoord );

    GeoDataCoordinates northEast(overlayLatLonBox.east(), overlayLatLonBox.north());
    rotatedCoord = northEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation());
    poly->outerBoundary().append( rotatedCoord );
}
コード例 #15
0
void PolylineAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination )
{
    GeoDataLineString *lineString = static_cast<GeoDataLineString*>( placemark()->geometry() );
    GeoDataLineString oldLineString = *lineString;
    lineString->clear();

    const qreal deltaLat = destination.latitude() - source.latitude();
    const qreal deltaLon = destination.longitude() - source.longitude();

    Quaternion latRectAxis = Quaternion::fromEuler( 0, destination.longitude(), 0);
    Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0);
    Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0);
    Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis;

    qreal lonRotated, latRotated;
    for ( int i = 0; i < oldLineString.size(); ++i ) {
        Quaternion qpos = oldLineString.at(i).quaternion();
        qpos.rotateAroundAxis(rotAxis);
        qpos.getSpherical( lonRotated, latRotated );
        GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 );

        lineString->append( movedPoint );
    }
}
コード例 #16
0
void GroundOverlayFrame::paint(GeoPainter *painter, const ViewportParams *viewport )
{
    m_viewport = viewport;
    m_regionList.clear();

    painter->save();
    if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
        GeoDataPolygon *polygon = static_cast<GeoDataPolygon*>( placemark()->geometry() );
        GeoDataLinearRing &ring = polygon->outerBoundary();
        QList<GeoDataCoordinates> coordinateList;

        coordinateList.append( ring.at( NorthWest ) );
        coordinateList.append( ring.at( SouthWest ) );
        coordinateList.append( ring.at( SouthEast ) );
        coordinateList.append( ring.at( NorthEast ) );

        GeoDataCoordinates northernHandle = ring.at( NorthEast ).interpolate( ring.at( NorthWest ), 0.5 );
        GeoDataCoordinates southernHandle = ring.at( SouthEast ).interpolate( ring.at( SouthWest ), 0.5 );
        // Special case handle position to take tessellation
        // along latitude circles into account
        if (m_overlay->latLonBox().rotation() == 0) {
            northernHandle.setLatitude(ring.at( NorthEast ).latitude());
            southernHandle.setLatitude(ring.at( SouthEast ).latitude());
        }
        coordinateList.append( northernHandle );
        coordinateList.append( southernHandle );

        coordinateList.append( ring.at( NorthEast ).interpolate( ring.at( SouthEast ), 0.5 ) );
        coordinateList.append( ring.at( NorthWest ).interpolate( ring.at( SouthWest ), 0.5 ) );

        m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthWest ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthWest ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthEast ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthEast ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( North ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( South ), 16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( East ),  16, 16 ) );
        m_regionList.append( painter->regionFromEllipse( coordinateList.at( West ),  16, 16 ) );
        m_regionList.append( painter->regionFromPolygon( ring, Qt::OddEvenFill ) );

        // Calculate handle icon orientation due to the projection
        qreal xNW, yNW, xSW, ySW;
        viewport->screenCoordinates(ring.at( NorthWest ), xNW, yNW);
        viewport->screenCoordinates(ring.at( SouthWest ), xSW, ySW);
        qreal westernAngle = qAtan2(ySW - yNW, xSW - xNW) - M_PI/2;
        qreal xNE, yNE, xSE, ySE;
        viewport->screenCoordinates(ring.at( NorthEast ), xNE, yNE);
        viewport->screenCoordinates(ring.at( SouthEast ), xSE, ySE);
        qreal easternAngle = qAtan2(ySE - yNE, xSE - xNE) - M_PI/2;

        painter->setPen( Qt::DashLine );
        painter->setBrush( Qt::NoBrush );
        painter->drawPolygon( ring );

        qreal projectedAngle = 0;

        for( int i = NorthWest; i != Polygon; ++i ) {

            // Assign handle icon orientation due to the projection
            if (i == NorthWest || i == West || i == SouthWest) {
                projectedAngle = westernAngle;
            }
            else if (i == NorthEast || i == East || i == SouthEast) {
                projectedAngle = easternAngle;
            }
            else if (i == North || i == South) {
                projectedAngle = (westernAngle + easternAngle) / 2;
            }
            QTransform trans;
            trans.rotateRadians( projectedAngle );
            if ( m_editStatus == Resize ){
                if( m_hoveredHandle != i ) {
                    painter->drawImage( coordinateList.at( i ),
                                        m_resizeIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) );
                } else {
                    painter->drawImage( coordinateList.at( i ),
                                        m_resizeIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) );
                }
            } else if ( m_editStatus == Rotate ) {
                if( m_hoveredHandle != i ) {
                    painter->drawImage( coordinateList.at( i ),
                                        m_rotateIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) );
                } else {
                    painter->drawImage( coordinateList.at( i ),
                                        m_rotateIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) );
                }
            }
        }
    }
    painter->restore();
}
コード例 #17
0
bool GroundOverlayFrame::mouseMoveEvent( QMouseEvent *event )
{
    if ( !m_viewport ) {
        return false;
    }

    // Catch hover events.
    if ( m_movedHandle == NoRegion ) {
        for ( int i = 0; i < m_regionList.size(); ++i ) {
            if ( m_regionList.at(i).contains( event->pos() ) ) {
                if ( i == Polygon ) {
                    setRequest( ChangeCursorOverlayBodyHover );
                } else {
                    setRequest( ChangeCursorOverlayRotateHover );
                }
                m_hoveredHandle = i;
                return true;
            }
        }
        m_hoveredHandle = NoRegion;
        return true;
    } else {
        m_editStatusChangeNeeded = false;
    }

    if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
        qreal lon, lat;
        m_viewport->geoCoordinates( event->pos().x(),
                                    event->pos().y(),
                                    lon, lat,
                                    GeoDataCoordinates::Radian );

        if ( m_editStatus == Resize ) {

            GeoDataCoordinates coord(lon, lat);
            GeoDataCoordinates rotatedCoord(coord);

            if (m_overlay->latLonBox().rotation() != 0) {
                rotatedCoord = coord.rotateAround(m_overlay->latLonBox().center(),
                                                 -m_overlay->latLonBox().rotation());
            }

            if ( m_movedHandle == NorthWest ) {
                m_overlay->latLonBox().setNorth( rotatedCoord.latitude() );
                m_overlay->latLonBox().setWest( rotatedCoord.longitude() );
            } else if ( m_movedHandle == SouthWest ) {
                m_overlay->latLonBox().setSouth( rotatedCoord.latitude() );
                m_overlay->latLonBox().setWest( rotatedCoord.longitude() );
            } else if ( m_movedHandle == SouthEast ) {
                m_overlay->latLonBox().setSouth( rotatedCoord.latitude() );
                m_overlay->latLonBox().setEast( rotatedCoord.longitude() );
            } else if ( m_movedHandle == NorthEast ) {
                m_overlay->latLonBox().setNorth( rotatedCoord.latitude() );
                m_overlay->latLonBox().setEast( rotatedCoord.longitude() );
            } else if ( m_movedHandle == North ) {
                m_overlay->latLonBox().setNorth( rotatedCoord.latitude() );
            } else if ( m_movedHandle == South ) {
                m_overlay->latLonBox().setSouth( rotatedCoord.latitude() );
            } else if ( m_movedHandle == East ) {
                m_overlay->latLonBox().setEast( rotatedCoord.longitude() );
            } else if ( m_movedHandle == West ) {
                m_overlay->latLonBox().setWest( rotatedCoord.longitude() );
            }

        } else if ( m_editStatus == Rotate ) {
            if ( m_movedHandle != Polygon ) {
                QPoint center = m_regionList.at( Polygon ).boundingRect().center();
                qreal angle1 = qAtan2( event->pos().y() - center.y(),
                                       event->pos().x() - center.x() );
                qreal angle2 = qAtan2( m_movedHandleScreenCoordinates.y() - center.y(),
                                       m_movedHandleScreenCoordinates.x() - center.x() );
                m_overlay->latLonBox().setRotation( angle2 - angle1 + m_previousRotation );
            }
        }

        if ( m_movedHandle == Polygon ) {
            const qreal centerLonDiff = lon - m_movedHandleGeoCoordinates.longitude();
            const qreal centerLatDiff = lat - m_movedHandleGeoCoordinates.latitude();

            m_overlay->latLonBox().setBoundaries( m_overlay->latLonBox().north() + centerLatDiff,
                                                  m_overlay->latLonBox().south() + centerLatDiff,
                                                  m_overlay->latLonBox().east()  + centerLonDiff,
                                                  m_overlay->latLonBox().west()  + centerLonDiff );

            m_movedHandleGeoCoordinates.set( lon, lat );
        }

        update();
        return true;
    }
    return false;
}
コード例 #18
0
void PolylineAnnotation::drawNodes( GeoPainter *painter )
{
    // These are the 'real' dimensions of the drawn nodes. The ones which have class scope are used
    // to generate the regions and they are a little bit larger, because, for example, it would be
    // a little bit too hard to select nodes.
    static const int d_regularDim = 10;
    static const int d_selectedDim = 10;
    static const int d_mergedDim = 20;
    static const int d_hoveredDim = 20;

    const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() );

    QColor glowColor = QApplication::palette().highlightedText().color();
    glowColor.setAlpha(120);

    for ( int i = 0; i < line.size(); ++i ) {
        // The order here is important, because a merged node can be at the same time selected.
        if ( m_nodesList.at(i).isBeingMerged() ) {
            painter->setBrush( mergedColor );
            painter->drawEllipse( line.at(i), d_mergedDim, d_mergedDim );
        } else if ( m_nodesList.at(i).isSelected() ) {
            painter->setBrush( selectedColor );
            painter->drawEllipse( line.at(i), d_selectedDim, d_selectedDim );

            if ( m_nodesList.at(i).isEditingHighlighted() ||
                 m_nodesList.at(i).isMergingHighlighted() ) {
                QPen defaultPen = painter->pen();
                QPen newPen;
                newPen.setWidth( defaultPen.width() + 3 );
                newPen.setColor( glowColor );

                painter->setBrush( Qt::NoBrush );
                painter->setPen( newPen );
                painter->drawEllipse( line.at(i), d_selectedDim + 2, d_selectedDim + 2 );
                painter->setPen( defaultPen );
            }
        } else {
            painter->setBrush( regularColor );
            painter->drawEllipse( line.at(i), d_regularDim, d_regularDim );

            if ( m_nodesList.at(i).isEditingHighlighted() ||
                 m_nodesList.at(i).isMergingHighlighted() ) {
                QPen defaultPen = painter->pen();
                QPen newPen;
                newPen.setWidth( defaultPen.width() + 3 );
                newPen.setColor( glowColor );

                painter->setPen( newPen );
                painter->setBrush( Qt::NoBrush );
                painter->drawEllipse( line.at(i), d_regularDim + 2, d_regularDim + 2 );
                painter->setPen( defaultPen );
            }
        }
    }

    if ( m_virtualHoveredNode != -1 ) {
        painter->setBrush( hoveredColor );

        GeoDataCoordinates newCoords;
        if ( m_virtualHoveredNode + 1 ) {
            newCoords = line.at( m_virtualHoveredNode + 1 ).interpolate( line.at( m_virtualHoveredNode ), 0.5 );
        } else {
            newCoords = line.first().interpolate( line.last(), 0.5 );
        }
        painter->drawEllipse( newCoords, d_hoveredDim, d_hoveredDim );
    }
}