示例#1
0
void GeoDataLineStringPrivate::interpolateDateLine( const GeoDataCoordinates & previousCoords,
                                                    const GeoDataCoordinates & currentCoords,
                                                    GeoDataCoordinates & previousAtDateLine,
                                                    GeoDataCoordinates & currentAtDateLine,
                                                    TessellationFlags f )
{
    GeoDataCoordinates dateLineCoords;

    int recursionCounter = 0;

//    mDebug() << Q_FUNC_INFO;

    if ( f.testFlag( RespectLatitudeCircle ) && previousCoords.latitude() == currentCoords.latitude() ) {
        dateLineCoords = currentCoords;
    }
    else {
        dateLineCoords = findDateLine( previousCoords, currentCoords, recursionCounter );
    }

    previousAtDateLine = dateLineCoords;
    currentAtDateLine = dateLineCoords;

    if ( previousCoords.longitude() < 0 ) {
        previousAtDateLine.setLongitude( -M_PI );
        currentAtDateLine.setLongitude( +M_PI );
    }
    else {
        previousAtDateLine.setLongitude( +M_PI );
        currentAtDateLine.setLongitude( -M_PI );
    }
}
示例#2
0
void PopupLayer::popup()
{
    GeoDataCoordinates coords = d->m_popupItem->coordinate();
    ViewportParams viewport( d->m_widget->viewport()->projection(),
                             coords.longitude(), coords.latitude(), d->m_widget->viewport()->radius(),
                             d->m_widget->viewport()->size() );
    qreal sx, sy, lon, lat;
    viewport.screenCoordinates( coords, sx, sy );
    sx = viewport.radius() < viewport.width() ? 0.5 * (viewport.width() + viewport.radius()) : 0.75 * viewport.width();
    viewport.geoCoordinates( sx, sy, lon, lat, GeoDataCoordinates::Radian );
    coords.setLatitude( lat );
    coords.setLongitude( lon );
    d->m_widget->centerOn( coords, true );
    setVisible( true );
}
示例#3
0
void WikipediaItem::setLongitude( qreal longitude )
{
    GeoDataCoordinates updatedCoordinates = coordinate();
    updatedCoordinates.setLongitude( longitude );
    setCoordinate( updatedCoordinates );
}
示例#4
0
GeoDataDocument* OpenRouteServiceRunner::parse( const QByteArray &content ) const
{
    QDomDocument xml;
    if ( !xml.setContent( content ) ) {
        mDebug() << "Cannot parse xml file with routing instructions.";
        return nullptr;
    }

    QDomElement root = xml.documentElement();

    GeoDataDocument* result = new GeoDataDocument();
    result->setName(QStringLiteral("OpenRouteService"));

    QDomNodeList errors = root.elementsByTagName(QStringLiteral("xls:Error"));
    if ( errors.size() > 0 ) {
        return nullptr;
        // Returning early because fallback routing providers are used now
        // The code below can be used to parse OpenGis errors reported by ORS
        // and may be useful in the future

        for (int i=0 ; i < errors.length(); ++i ) {
            QDomNode node = errors.item( i );
            QString errorMessage = node.attributes().namedItem(QStringLiteral("message")).nodeValue();
            QRegExp regexp = QRegExp( "^(.*) Please Check your Position: (-?[0-9]+.[0-9]+) (-?[0-9]+.[0-9]+) !" );
            if ( regexp.indexIn( errorMessage ) == 0 ) {
                if ( regexp.capturedTexts().size() == 4 ) {
                    GeoDataPlacemark* placemark = new GeoDataPlacemark;
                    placemark->setName( regexp.capturedTexts().at( 1 ) );
                    GeoDataCoordinates position;
                    position.setLongitude( regexp.capturedTexts().at( 2 ).toDouble(), GeoDataCoordinates::Degree );
                    position.setLatitude( regexp.capturedTexts().at( 3 ).toDouble(), GeoDataCoordinates::Degree );
                    placemark->setCoordinate( position );
                    result->append( placemark );
                }
            } else {
                mDebug() << "Error message " << errorMessage << " not parsable.";
                /** @todo: How to handle this now with plugins? */
//                QString message = tr( "Sorry, a problem occurred when calculating the route. Try adjusting start and destination points." );
//                QPointer<QMessageBox> messageBox = new QMessageBox( QMessageBox::Warning, "Route Error", message );
//                messageBox->setDetailedText( errorMessage );
//                messageBox->exec();
//                delete messageBox;
            }
        }
    }

    GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
    routePlacemark->setName(QStringLiteral("Route"));
    QTime time;
    QDomNodeList summary = root.elementsByTagName(QStringLiteral("xls:RouteSummary"));
    if ( summary.size() > 0 ) {
        QDomNodeList timeNodeList = summary.item(0).toElement().elementsByTagName(QStringLiteral("xls:TotalTime"));
        if ( timeNodeList.size() == 1 ) {
            QRegExp regexp = QRegExp( "^P(?:(\\d+)D)?T(?:(\\d+)H)?(?:(\\d+)M)?(\\d+)S" );
            if ( regexp.indexIn( timeNodeList.item( 0 ).toElement().text() ) == 0 ) {
                QStringList matches = regexp.capturedTexts();
                unsigned int hours( 0 ), minutes( 0 ), seconds( 0 );
                switch ( matches.size() ) {
                case 5:
                    // days    = regexp.cap( matches.size() - 4 ).toInt();
                    // Intentionally no break
                case 4:
                    hours   = regexp.cap( matches.size() - 3 ).toInt();
                    // Intentionally no break
                case 3:
                    minutes = regexp.cap( matches.size() - 2 ).toInt();
                    // Intentionally no break
                case 2:
                    seconds = regexp.cap( matches.size() - 1 ).toInt();
                    break;
                default:
                    mDebug() << "Unable to parse time string " << timeNodeList.item( 0 ).toElement().text();
                }

                time = QTime( hours, minutes, seconds, 0 );
            }
        }
    }

    GeoDataLineString* routeWaypoints = new GeoDataLineString;
    QDomNodeList geometry = root.elementsByTagName(QStringLiteral("xls:RouteGeometry"));
    if ( geometry.size() > 0 ) {
        QDomNodeList waypoints = geometry.item( 0 ).toElement().elementsByTagName( "gml:pos" );
        for (int i=0 ; i < waypoints.length(); ++i ) {
            QDomNode node = waypoints.item( i );
            const QStringList content = node.toElement().text().split(QLatin1Char(' '));
            if ( content.length() == 2 ) {
                GeoDataCoordinates position;
                position.setLongitude( content.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
                position.setLatitude( content.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
                routeWaypoints->append( position );
            }
        }
    }
    routePlacemark->setGeometry( routeWaypoints );

    qreal length = routeWaypoints->length( EARTH_RADIUS );
    const QString name = nameString( "ORS", length, time );
    const GeoDataExtendedData data = routeData( length, time );
    routePlacemark->setExtendedData( data );
    result->setName( name );

    result->append( routePlacemark );

    QDomNodeList instructionList = root.elementsByTagName(QStringLiteral("xls:RouteInstructionsList"));
    if ( instructionList.size() > 0 ) {
        QDomNodeList instructions = instructionList.item(0).toElement().elementsByTagName(QStringLiteral("xls:RouteInstruction"));
        for (int i=0 ; i < instructions.length(); ++i ) {
            QDomElement node = instructions.item( i ).toElement();

            QDomNodeList textNodes = node.elementsByTagName(QStringLiteral("xls:Instruction"));
            QDomNodeList positions = node.elementsByTagName(QStringLiteral("gml:pos"));

            if ( textNodes.size() > 0 && positions.size() > 0 ) {
                const QStringList content = positions.at(0).toElement().text().split(QLatin1Char(' '));
                if ( content.length() == 2 ) {
                    GeoDataLineString *lineString = new GeoDataLineString;

                    for( int i = 0; i < positions.count(); ++i ) {
                         const QStringList pointList = positions.at(i).toElement().text().split(QLatin1Char(' '));
                         GeoDataCoordinates position;
                         position.setLongitude( pointList.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
                         position.setLatitude( pointList.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
                         lineString->append( position );
                    }

                    GeoDataPlacemark* instruction = new GeoDataPlacemark;

                    QString const text = textNodes.item( 0 ).toElement().text().remove(QRegExp("<[^>]*>"));
                    GeoDataExtendedData extendedData;
                    GeoDataData turnTypeData;
                    turnTypeData.setName(QStringLiteral("turnType"));
                    QString road;
                    RoutingInstruction::TurnType turnType = parseTurnType( text, &road );
                    turnTypeData.setValue( turnType );
                    extendedData.addValue( turnTypeData );
                    if ( !road.isEmpty() ) {
                        GeoDataData roadName;
                        roadName.setName(QStringLiteral("roadName"));
                        roadName.setValue( road );
                        extendedData.addValue( roadName );
                    }

                    QString const instructionText = turnType == RoutingInstruction::Unknown ? text : RoutingInstruction::generateRoadInstruction( turnType, road );
                    instruction->setName( instructionText );
                    instruction->setExtendedData( extendedData );
                    instruction->setGeometry( lineString );
                    result->append( instruction );
                }
            }
        }
    }

    return result;
}
示例#5
0
void MeasureToolPlugin::drawSegments( GeoPainter* painter )
{
    for ( int segmentIndex = 0; segmentIndex < m_measureLineString.size() - 1; ++segmentIndex ) {
        GeoDataLineString segment( Tessellate );
        segment << m_measureLineString[segmentIndex] ;
        segment << m_measureLineString[segmentIndex + 1];

        QPen shadowPen( Oxygen::aluminumGray5 );
        shadowPen.setWidthF(4.0);
        painter->setPen( shadowPen );
        painter->drawPolyline( segment );

        QString infoString;

        if ( (m_paintMode == Polygon && m_showDistanceLabel)
             || (m_paintMode == Circular && m_showRadius) ) {
            const qreal segmentLength = segment.length( marbleModel()->planet()->radius() );
            m_radius = segmentLength;

            infoString = meterToPreferredUnit(segmentLength);
        }

        if ( m_showBearingLabel && m_paintMode != Circular ) {
            GeoDataCoordinates coordinates = segment.first();
            qreal bearing = coordinates.bearing( segment.last(), GeoDataCoordinates::Degree );

            if ( bearing < 0 ) {
                bearing += 360;
            }
            QString bearingString = QString::fromUtf8( "%1°" ).arg( bearing, 0, 'f', 2 );
            if ( !infoString.isEmpty() ) {
                infoString.append( "\n" );
            }
            infoString.append( bearingString );
        }

        if ( m_showBearingChangeLabel && segmentIndex != 0 ) {
            GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];
            qreal currentBearing = currentCoordinates.bearing(m_measureLineString[segmentIndex+1]);
            qreal previousBearing = currentCoordinates.bearing( m_measureLineString[segmentIndex-1]);

            GeoDataLinearRing ring;
            painter->setPen( Qt::NoPen );
            painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );

            if (currentBearing < previousBearing) currentBearing += 2 * M_PI;
            ring << currentCoordinates;

            qreal angleLength = qAbs(m_latLonAltBox.north() - m_latLonAltBox.south()) / 20;

            qreal iterBearing = previousBearing;
            while ( iterBearing < currentBearing ) {
                ring << currentCoordinates.moveByBearing( iterBearing, angleLength );;
                iterBearing += 0.1;
            }

            ring << currentCoordinates.moveByBearing( currentBearing, angleLength );;

            painter->drawPolygon( ring );

            qreal currentBearingChange = (currentBearing - previousBearing) * RAD2DEG;
            if (currentBearingChange < 0) currentBearingChange += 360;
            QString bearingChangedString = QString::fromUtf8( "%1°" ).arg( currentBearingChange, 0, 'f', 2 );
            painter->setPen( Qt::black );
            GeoDataCoordinates textPosition = ring.latLonAltBox().center();
            qreal deltaEast = ring.latLonAltBox().east() - currentCoordinates.longitude();
            qreal deltaWest = currentCoordinates.longitude() - ring.latLonAltBox().west();
            if (deltaEast > deltaWest) {
                textPosition.setLongitude(currentCoordinates.longitude() + deltaEast / 2);
            }
            else {
                textPosition.setLongitude(currentCoordinates.longitude() - deltaWest);
            }
            painter->drawText(textPosition, bearingChangedString );
       }

        // Drawing ellipse around 1st point towards the 2nd
        if ( m_paintMode == Circular ) {
            GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];

            GeoDataLinearRing ring;

            // planetRadius - planet radius
            // d - distance between points
            // S - area of the painted circle
            qreal planetRadius = marbleModel()->planet()->radius();
            qreal d = m_measureLineString.length(1);
            m_circularArea = 2 * M_PI * planetRadius * planetRadius * (1 - qCos(d));

            qreal iterBearing = 0;
            while ( iterBearing < 2 * M_PI ) {
                ring << currentCoordinates.moveByBearing(iterBearing, d);
                iterBearing += 0.1;
            }

            painter->setPen( Qt::NoPen );
            painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
            painter->drawPolygon(ring);

            if ( m_showCircularArea ) {
                painter->setPen(Qt::white);
                GeoDataCoordinates textPosition = ring.latLonAltBox().center();

                QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(m_circularArea, true));

                QFontMetrics fontMetrics = painter->fontMetrics();
                QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);

                painter->drawText(textPosition,
                                  areaText,
                                  -boundingRect.width()/2, -boundingRect.height()*1.5,
                                  boundingRect.width(), boundingRect.height(),
                                  QTextOption(Qt::AlignCenter));
            }

            if ( m_showCircumference ) {
                painter->setPen(Qt::white);
                GeoDataCoordinates textPosition = ring.latLonAltBox().center();

                m_circumference = 2 * M_PI * planetRadius * qSin(d);

                QString circumferenceText = tr("Circumference:\n%1").arg(meterToPreferredUnit(m_circumference));

                QFontMetrics fontMetrics = painter->fontMetrics();
                QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
                                                              circumferenceText);

                painter->drawText(textPosition,
                                  circumferenceText,
                                  -boundingRect.width()/2, boundingRect.height(),
                                  boundingRect.width(), boundingRect.height(),
                                  QTextOption(Qt::AlignCenter));
            }
        }

        if ( !infoString.isEmpty() ) {
            QPen linePen;

            // have three alternating colors for the segments
            switch ( segmentIndex % 3 ) {
            case 0:
                linePen.setColor( Oxygen::brickRed4 );
                break;
            case 1:
                linePen.setColor( Oxygen::forestGreen4 );
                break;
            case 2:
                linePen.setColor( Oxygen::skyBlue4 );
                break;
            }

            linePen.setWidthF(2.0);
            painter->setPen( linePen );
            painter->drawPolyline( segment, infoString, LineCenter );
        }
    }

    if (m_paintMode == Polygon && m_measureLineString.size() > 2) {
        GeoDataLinearRing measureRing = m_measureLineString;

        if (m_showPolygonArea || m_showPerimeter) {
            painter->setPen( Qt::NoPen );
            painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
            painter->drawPolygon(measureRing);

            QPen shadowPen( Oxygen::aluminumGray5 );
            shadowPen.setStyle(Qt::DashLine);
            shadowPen.setWidthF(3.0);
            painter->setPen( shadowPen );
            painter->drawPolyline(GeoDataLineString( Tessellate ) << m_measureLineString.first()
                                                      << m_measureLineString.last());
        }

        if (m_showPolygonArea) {
            qreal theta1 = 0.0;
            qreal n = m_measureLineString.size();

            for (int segmentIndex = 1; segmentIndex < m_measureLineString.size()-1; segmentIndex++) {
                GeoDataCoordinates current = m_measureLineString[segmentIndex];
                qreal prevBearing = current.bearing(m_measureLineString[segmentIndex-1]);
                qreal nextBearing = current.bearing(m_measureLineString[segmentIndex+1]);
                if (nextBearing < prevBearing)
                    nextBearing += 2 * M_PI;

                qreal angle = nextBearing - prevBearing;
                theta1 += angle;
            }

            // Traversing first vertex
            GeoDataCoordinates current = m_measureLineString[0];
            qreal prevBearing = current.bearing(m_measureLineString[n-1]);
            qreal nextBearing = current.bearing(m_measureLineString[1]);
            if (nextBearing < prevBearing)
                nextBearing += 2 * M_PI;
            qreal angle = nextBearing - prevBearing;
            theta1 += angle;

            // And the last one
            current = m_measureLineString[n-1];
            prevBearing = current.bearing(m_measureLineString[n-2]);
            nextBearing = current.bearing(m_measureLineString[0]);
            if (nextBearing < prevBearing)
                nextBearing += 2 * M_PI;
            angle = nextBearing - prevBearing;
            theta1 += angle;

            qreal theta2 = 2 * M_PI * n - theta1;

            // theta = smaller of theta1 and theta2
            qreal theta = (theta1 < theta2) ? theta1 : theta2;

            qreal planetRadius = marbleModel()->planet()->radius();
            qreal S = qAbs((theta - (n-2) * M_PI) * planetRadius * planetRadius);
            m_polygonArea = S;

            painter->setPen(Qt::white);
            GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();

            QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(S, true));

            QFontMetrics fontMetrics = painter->fontMetrics();
            QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);

            painter->drawText(textPosition,
                              areaText,
                              -boundingRect.width()/2, -(boundingRect.height()+fontMetrics.height()*0.25),
                              boundingRect.width(), boundingRect.height(),
                              QTextOption(Qt::AlignCenter));
        }

        if (m_showPerimeter) {
            painter->setPen(Qt::white);
            GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();

            qreal P = measureRing.length(marbleModel()->planet()->radius());
            m_perimeter = P;
            QString perimeterText = tr("Perimeter:\n%1").arg(meterToPreferredUnit(P));

            QFontMetrics fontMetrics = painter->fontMetrics();
            QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
                                                          perimeterText);

            painter->drawText(textPosition,
                              perimeterText,
                              -boundingRect.width()/2, 0,
                              boundingRect.width(), boundingRect.height(),
                              QTextOption(Qt::AlignCenter));
        }
    }
}