Beispiel #1
0
void FoursquareModel::getAdditionalItems( const GeoDataLatLonAltBox& box, qint32 number )
{
    if( marbleModel()->planetId() != "earth" ) {
        return;
    }
    
    QString clientId = "YPRWSYFW1RVL4PJQ2XS5G14RTOGTHOKZVHC1EP5KCCCYQPZF";
    QString clientSecret = "5L2JDCAYQCEJWY5FNDU4A1RWATE4E5FIIXXRM41YBTFSERUH";
    
    QString apiUrl( "https://api.foursquare.com/v2/venues/search" );
    qreal const distanceLon = marbleModel()->planetRadius() * distanceSphere( box.west(), box.north(), box.east(), box.north() );
    qreal const distanceLat = marbleModel()->planetRadius() * distanceSphere( box.west(), box.north(), box.west(), box.south() );
    qreal const area = distanceLon * distanceLat;
    if ( area > 10 * 1000 * KM2METER * KM2METER ) {
        // Large area (> 10.000 km^2) => too large for bbox queries
        apiUrl += "?ll=" + QString::number( box.center().latitude(Marble::GeoDataCoordinates::Degree) );
        apiUrl += ',' + QString::number( box.center().longitude(Marble::GeoDataCoordinates::Degree) );
        apiUrl += "&intent=checkin";
    } else {
        apiUrl += "?ne=" + QString::number( box.north(Marble::GeoDataCoordinates::Degree) );
        apiUrl += ',' + QString::number( box.east(Marble::GeoDataCoordinates::Degree) );
        apiUrl += "&sw=" + QString::number( box.south(Marble::GeoDataCoordinates::Degree) );
        apiUrl += ',' + QString::number( box.west(Marble::GeoDataCoordinates::Degree) );
        apiUrl += "&intent=browse";
    }
    apiUrl += "&limit=" + QString::number( number );
    apiUrl += "&client_id=" + clientId;
    apiUrl += "&client_secret=" + clientSecret;
    apiUrl += "&v=20120601";
    downloadDescriptionFile( QUrl( apiUrl ) );
}
Beispiel #2
0
int RoutingModel::rightNeighbor( const GeoDataCoordinates &position, RouteRequest 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
    GeoDataLineString points = d->m_route.path();
    QMap<int,int> mapping;

    // 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<points.size(); ++i ) {
            qreal distance = distanceSphere( points[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<points.size(); ++i ) {
        qreal waypointDistance = distanceSphere( points[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] = points.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;
}
Beispiel #3
0
qreal RoutingPluginPrivate::nextInstructionDistance() const
{
    GeoDataCoordinates position = m_routingModel->route().position();
    GeoDataCoordinates interpolated = m_routingModel->route().positionOnRoute();
    GeoDataCoordinates onRoute = m_routingModel->route().currentWaypoint();
    qreal planetRadius = m_marbleWidget->model()->planet()->radius();
    qreal distance = planetRadius * ( distanceSphere( position, interpolated ) + distanceSphere( interpolated, onRoute ) );
    const RouteSegment &segment = m_routingModel->route().currentSegment();
    for (int i=0; i<segment.path().size(); ++i) {
        if (segment.path()[i] == onRoute) {
            return distance + segment.path().length( planetRadius, i );
        }
    }

    return distance;
}
void SearchRunnerManager::Private::addSearchResult( const QVector<GeoDataPlacemark *> &result )
{
    mDebug() << "Runner reports" << result.size() << " search results";
    if( result.isEmpty() )
        return;

    m_modelMutex.lock();
    int start = m_placemarkContainer.size();
    int count = 0;
    bool distanceCompare = m_marbleModel->planet() != 0;
    for( int i=0; i<result.size(); ++i ) {
        bool same = false;
        for ( int j=0; j<m_placemarkContainer.size(); ++j ) {
            if ( distanceCompare &&
                 ( distanceSphere( result[i]->coordinate(),
                                   m_placemarkContainer[j]->coordinate() )
                   * m_marbleModel->planet()->radius() < 1 ) ) {
                same = true;
            }
        }
        if ( !same ) {
            m_placemarkContainer.append( result[i] );
            ++count;
        }
    }
    m_model.addPlacemarks( start, count );
    m_modelMutex.unlock();
    emit q->searchResultChanged( &m_model );
    emit q->searchResultChanged( m_placemarkContainer );
}
Beispiel #5
0
void AutoNavigation::Private::adjustZoom( const GeoDataCoordinates &currentPosition, qreal speed )
{
    qreal currentX = 0;
    qreal currentY = 0;
    if( !m_viewport->screenCoordinates(currentPosition, currentX, currentY ) ) {
        return;
    }

    const GeoDataCoordinates destination = findIntersection( currentX, currentY );

    qreal greatCircleDistance = distanceSphere( currentPosition, destination );
    qreal radius = m_model->planetRadius();
    qreal distance = greatCircleDistance *  radius;

    if( speed != 0 ) {
        // time (in seconds) remaining to reach the border of the map
        qreal  remainingTime = distance / speed;

        // tolerance time limits (in seconds) before auto zooming
        qreal thresholdLow = 15;
        qreal thresholdHigh = 120;

        m_selfInteraction = true;
        if ( remainingTime < thresholdLow ) {
            emit m_parent->zoomOut( Instant );
        }
        else if ( remainingTime > thresholdHigh ) {
            emit m_parent->zoomIn( Instant );
        }
        m_selfInteraction = false;
    }
}
void RouteSimulationPositionProviderPlugin::update()
{
    ++m_currentIndex;

    if ( m_currentIndex >= 0 && m_currentIndex < m_lineString.size() ) {
        if ( m_status != PositionProviderStatusAvailable ) {
            m_status = PositionProviderStatusAvailable;
            emit statusChanged( PositionProviderStatusAvailable );
        }

        GeoDataCoordinates newPosition = m_lineString.at( m_currentIndex );
        const QDateTime newDateTime = QDateTime::currentDateTime();
        if ( m_currentPosition.isValid() ) {
            m_speed = distanceSphere( m_currentPosition, newPosition ) * m_marbleModel->planetRadius() / ( m_currentDateTime.msecsTo( newDateTime ) ) * 1000;
            m_direction = m_currentPosition.bearing( newPosition, GeoDataCoordinates::Degree, GeoDataCoordinates::FinalBearing );
        }
        m_currentPosition = newPosition;
        m_currentDateTime = newDateTime;
        emit positionChanged( position(), accuracy() );
    }
    else {
        // Repeat from start
        m_currentIndex = -1;
        if ( m_status != PositionProviderStatusUnavailable ) {
            m_status = PositionProviderStatusUnavailable;
            emit statusChanged( PositionProviderStatusUnavailable );
        }
    }

    QTimer::singleShot( 1000.0 / c_frequency, this, SLOT(update()) );
}
void GeoDataLineStringPrivate::optimize (GeoDataLineString& lineString) const
{

    QVector<GeoDataCoordinates>::iterator itCoords = lineString.begin();
    QVector<GeoDataCoordinates>::const_iterator itEnd = lineString.constEnd();

    if (lineString.size() < 2) return;

    // Calculate the least non-zero detail-level by checking the bounding box
    int startLevel = levelForResolution( ( lineString.latLonAltBox().width() + lineString.latLonAltBox().height() ) / 2 );

    int currentLevel = startLevel;
    int maxLevel = startLevel;
    GeoDataCoordinates currentCoords;
    lineString.first().setDetail(startLevel);

    // Iterate through the linestring to assign different detail levels to the nodes.
    // In general the first and last node should have the start level assigned as
    // a detail level.
    // Starting from the first node the algorithm picks those nodes which
    // have a distance from each other that is just above the resolution that is
    // associated with the start level (which we use as a "current level").
    // Each of those nodes get the current level assigned as the detail level.
    // After iterating through the linestring we increment the current level value
    // and starting again with the first node we assign detail values in a similar way
    // to the remaining nodes which have no final detail level assigned yet.
    // We do as many iterations through the lineString as needed and bump up the
    // current level until all nodes have a non-zero detail level assigned.

    while ( currentLevel  < 16 && currentLevel <= maxLevel + 1 ) {
        itCoords = lineString.begin();

        currentCoords = *itCoords;
        ++itCoords;

        for( ; itCoords != itEnd; ++itCoords) {
            if (itCoords->detail() != 0 && itCoords->detail() < currentLevel) continue;

            if ( currentLevel == startLevel && (itCoords->longitude() == -M_PI || itCoords->longitude() == M_PI
                || itCoords->latitude() < -89 * DEG2RAD || itCoords->latitude() > 89 * DEG2RAD)) {
                itCoords->setDetail(startLevel);
                currentCoords = *itCoords;
                maxLevel = currentLevel;
                continue;
            }
            if (distanceSphere( currentCoords, *itCoords ) < resolutionForLevel(currentLevel + 1)) {
                itCoords->setDetail(currentLevel + 1);
            }
            else {
                itCoords->setDetail(currentLevel);
                currentCoords = *itCoords;
                maxLevel = currentLevel;
            }
        }
        ++currentLevel;
    }
    lineString.last().setDetail(startLevel);
}
Beispiel #8
0
QString OsmDatabase::formatDistance( const GeoDataCoordinates &a, const GeoDataCoordinates &b )
{
    qreal distance = EARTH_RADIUS * distanceSphere( a, b);

    int precision = 0;
    QString distanceUnit = QLatin1String( "m" );

    if ( MarbleGlobal::getInstance()->locale()->measurementSystem() == MarbleLocale::ImperialSystem ) {
        precision = 1;
        distanceUnit = "mi";
        distance *= METER2KM;
        distance *= KM2MI;
    } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() ==
               MarbleLocale::MetricSystem) {
        if ( distance >= 1000 ) {
            distance /= 1000;
            distanceUnit = "km";
            precision = 1;
        } else if ( distance >= 200 ) {
            distance = 50 * qRound( distance / 50 );
        } else if ( distance >= 100 ) {
            distance = 25 * qRound( distance / 25 );
        } else {
            distance = 10 * qRound( distance / 10 );
        }
    } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() ==
               MarbleLocale::NauticalSystem) {
        precision = 2;
        distanceUnit = "nm";
        distance *= METER2KM;
        distance *= KM2NM;
    }

    QString const fuzzyDistance = QString( "%1 %2" ).arg( distance, 0, 'f', precision ).arg( distanceUnit );

    int direction = 180 + bearing( a, b ) * RAD2DEG;

    QString heading = QObject::tr( "north" );
    if ( direction > 337 ) {
        heading = QObject::tr( "north" );
    } else if ( direction > 292 ) {
        heading = QObject::tr( "north-west" );
    } else if ( direction > 247 ) {
        heading = QObject::tr( "west" );
    } else if ( direction > 202 ) {
        heading = QObject::tr( "south-west" );
    } else if ( direction > 157 ) {
        heading = QObject::tr( "south" );
    } else if ( direction > 112 ) {
        heading = QObject::tr( "south-east" );
    } else if ( direction > 67 ) {
        heading = QObject::tr( "east" );
    } else if ( direction > 22 ) {
        heading = QObject::tr( "north-east" );
    }

    return fuzzyDistance + QLatin1Char(' ') + heading;
}
Beispiel #9
0
void RoutingPluginPrivate::updateDestinationInformation()
{
    if ( m_routingModel->route().currentSegment().isValid() ) {
        qreal remaining = remainingDistance();
        qreal distanceLeft = nextInstructionDistance();
        m_audio->update( m_routingModel->route(), distanceLeft, remaining, m_routingModel->deviatedFromRoute() );

        m_nearNextInstruction = distanceLeft < thresholdDistance;

        QString pixmapHtml = "<img src=\":/flag.png\" /><br />";
        m_widget.destinationDistanceLabel->setText( pixmapHtml + richText( fuzzyDistance( remaining ) ) );

        m_widget.instructionIconLabel->setEnabled( m_nearNextInstruction );
        m_widget.progressBar->setMaximum( thresholdDistance );
        m_widget.progressBar->setValue( qRound( distanceLeft ) );

        updateButtonVisibility();

        QString pixmap = MarbleDirs::path( "bitmaps/routing_step.png" );
        pixmapHtml = QString( "<img src=\"%1\" />" ).arg( pixmap );

        qreal planetRadius = m_marbleWidget->model()->planet()->radius();
        GeoDataCoordinates const onRoute = m_routingModel->route().positionOnRoute();
        GeoDataCoordinates const ego = m_routingModel->route().position();
        qreal const distanceToRoute = planetRadius * distanceSphere( ego, onRoute );

        if ( !m_routingModel->route().currentSegment().isValid() ) {
            m_widget.instructionLabel->setText( richText( QObject::tr( "Calculate a route to get directions." ) ) );
            m_widget.instructionIconLabel->setText( pixmapHtml );
        } else if ( distanceToRoute > 300.0 ) {
            m_widget.instructionLabel->setText( richText( QObject::tr( "Route left." ) ) );
            m_widget.instructionIconLabel->setText( pixmapHtml );
        } else if ( !m_routingModel->route().currentSegment().nextRouteSegment().isValid() ) {
            m_widget.instructionLabel->setText( richText( QObject::tr( "Destination ahead." ) ) );
            m_widget.instructionIconLabel->setText( pixmapHtml );
        } else {
            pixmap = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().directionPixmap();
            QString const instructionText = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().instructionText();
            m_widget.instructionLabel->setText( richText( "%1" ).arg( instructionText ) );
            pixmapHtml = QString( "<p align=\"center\"><img src=\"%1\" /><br />%2</p>" ).arg( pixmap );
            m_widget.instructionIconLabel->setText( pixmapHtml.arg( richText( fuzzyDistance( distanceLeft ) ) ) );

            if( remaining > 50 ) {
                m_routeCompleted = false;
            } else {
                if ( !m_routeCompleted ) {
                    QString content = QObject::tr( "Arrived at destination. <a href=\"#reverse\">Calculate the way back.</a>" );
                    m_widget.instructionLabel->setText( richText( "%1" ).arg( content ) );
                }
                m_routeCompleted = true;
            }
        }

        forceRepaint();
    }
}
Beispiel #10
0
PeakAnalyzer::Peaks PeakAnalyzer::peaksNear(const GeoDataPlacemark* placemark, const Peaks &peaks, double maxDistance)
{
    // If this turns out to become a bottleneck due to quadratic runtime, use kd-tree via nanoflann from
    // https://github.com/jlblancoc/nanoflann to speed it up.
    Peaks neighbors;
    for (auto peak: peaks) {
        if (distanceSphere(peak->coordinate(), placemark->coordinate()) < maxDistance) {
            neighbors << peak;
        }
    }
    return neighbors;
}
Beispiel #11
0
void RoutingModelPrivate::updateViaPoints( const GeoDataCoordinates &position )
{
    // Mark via points visited after approaching them in a range of 500m or less
    qreal const threshold = 500 / EARTH_RADIUS;
    for( int i=0; i<m_request->size(); ++i ) {
        if ( !m_request->visited( i ) ) {
            if ( distanceSphere( position, m_request->at( i ) ) < threshold ) {
                m_request->setVisited( i, true );
            }
        }
    }
}
Beispiel #12
0
void NavigationPrivate::updateNextInstructionDistance( const Marble::Route &route )
{
    const Marble::GeoDataCoordinates position = route.position();
    const Marble::GeoDataCoordinates interpolated = route.positionOnRoute();
    const Marble::GeoDataCoordinates onRoute = route.currentWaypoint();

    qreal planetRadius = 0;
    if (model()){
        planetRadius = model()->planet()->radius();
    }
    qreal distance = planetRadius * ( distanceSphere( position, interpolated ) + distanceSphere( interpolated, onRoute ) );
    qreal remaining = 0.0;
    const Marble::RouteSegment &segment = route.currentSegment();
    for ( int i=0; i<segment.path().size(); ++i ) {
        if ( segment.path()[i] == onRoute ) {
            distance += segment.path().length( planetRadius, i );
            break;
        }
    }

    bool upcoming = false;
    for ( int i=0; i<route.size(); ++i ) {
        const Marble::RouteSegment &segment = route.at( i );

        if ( upcoming ) {
            remaining += segment.path().length( planetRadius );
        }

        if ( segment == route.currentSegment() ) {
            upcoming = true;
        }
    }

    m_nextInstructionDistance = distance;
    m_destinationDistance = distance + remaining;
}
Beispiel #13
0
qreal GeoDataLineString::length( qreal planetRadius, int offset ) const
{
    if( offset < 0 || offset >= size() ) {
        return 0;
    }

    qreal length = 0.0;
    QVector<GeoDataCoordinates> const & vector = p()->m_vector;
    int const start = qMax(offset+1, 1);
    int const end = p()->m_vector.size();
    for( int i=start; i<end; ++i )
    {
        length += distanceSphere( vector[i-1], vector[i] );
    }

    return planetRadius * length;
}
qreal AlternativeRoutesModelPrivate::distance( const GeoDataCoordinates &satellite, const GeoDataCoordinates &lineA, const GeoDataCoordinates &lineB )
{
    qreal dist = distanceSphere( lineA, satellite );
    qreal bearA = bearing( lineA, satellite );
    qreal bearB = bearing( lineA, lineB );
    qreal result = asin( sin ( dist ) * sin( bearB - bearA ) );
    Q_ASSERT( qMax<qreal>( distanceSphere(satellite, lineA), distanceSphere(satellite, lineB) ) >= qAbs<qreal>(result) );

    result = acos( cos( dist ) / cos( result ) );
    /** @todo: This is a naive approach. Look into the maths. */
    qreal final = qMin<qreal>( distanceSphere( satellite, lineA ), distanceSphere( satellite, lineB ) );
    if ( result >= 0 && result <= distanceSphere( lineA, lineB ) ) {
        GeoDataCoordinates nearest = coordinates( lineA, result, bearB );
        return qMin<qreal>( final, distanceSphere( satellite, nearest ) );
    } else {
Beispiel #15
0
void RoutingModel::updatePosition( GeoDataCoordinates location, qreal /*speed*/ )
{
    d->m_route.setPosition( location );

    d->updateViaPoints( location );
    qreal planetRadius = d->m_marbleModel->planet()->radius();
    qreal distance = planetRadius * distanceSphere( location, d->m_route.positionOnRoute() );
    emit positionChanged();

    qreal deviation = 0.0;
    if ( d->m_positionTracking && d->m_positionTracking->accuracy().vertical > 0.0 ) {
        deviation = qMax<qreal>( d->m_positionTracking->accuracy().vertical, d->m_positionTracking->accuracy().horizontal );
    }
    qreal const threshold = deviation + 100.0;

    RoutingModelPrivate::RouteDeviation const deviated = distance < threshold ? RoutingModelPrivate::OnRoute : RoutingModelPrivate::OffRoute;
    if ( d->m_deviation != deviated ) {
        d->m_deviation = deviated;
        emit deviatedFromRoute( deviated == RoutingModelPrivate::OffRoute );
    }
}
Beispiel #16
0
void PeakAnalyzer::dbScan(const Peaks &peaks, double maxDistance, int minPoints)
{
    QSet<GeoDataPlacemark*> visited;
    QMap<GeoDataPlacemark*, PeakCluster*> associations;
    Peaks noise;
    PeakClusters clusters;
    for(auto peak: peaks) {
        if (visited.contains(peak)) {
            continue;
        }
        visited << peak;
        auto neighbors = peaksNear(peak, peaks, maxDistance);
        if (neighbors.size() < minPoints) {
            noise << peak;
        } else {
            PeakCluster* fit = nullptr;
            for (auto &cluster: clusters) {
                for (auto placemark: cluster) {
                    if (distanceSphere(peak->coordinate(), placemark->coordinate()) < maxDistance) {
                        fit = &cluster;
                    }
                }
            }
            if (!fit) {
                clusters << PeakCluster();
                fit = &clusters.last();
            }

            while (!neighbors.isEmpty()) {
                auto neighbor = neighbors.front();
                neighbors.pop_front();
                if (!visited.contains(neighbor)) {
                    visited << neighbor;
                    auto const moreNeighbors = peaksNear(neighbor, peaks, maxDistance);
                    if (moreNeighbors.size() >= minPoints) {
                        neighbors += moreNeighbors;
                    }
                }
                if (associations[neighbor] == nullptr) {
                    *fit << neighbor;
                    associations[neighbor] = fit;
                }
            }
        }
    }

    for (auto &cluster: clusters) {
        Q_ASSERT(!cluster.isEmpty());
        std::sort(cluster.begin(), cluster.end(), [](GeoDataPlacemark* a, GeoDataPlacemark* b) {
            return a->coordinate().altitude() > b->coordinate().altitude();
        });
        bool first = true;
        for (auto peak: cluster) {
            peak->osmData().addTag(QLatin1String("marbleZoomLevel"), first ? QLatin1String("11") : QLatin1String("13"));
            first = false;
        }
    }
    for (auto peak: noise) {
        peak->osmData().addTag(QLatin1String("marbleZoomLevel"), QLatin1String("11"));
    }
}