Ejemplo n.º 1
0
GeoDataDocument* MapQuestRunner::parse( const QByteArray &content ) const
{
    QDomDocument xml;
    if ( !xml.setContent( content ) ) {
        mDebug() << "Cannot parse xml file with routing instructions.";
        return 0;
    }

    // mDebug() << xml.toString(2);
    QDomElement root = xml.documentElement();

    GeoDataDocument* result = new GeoDataDocument();
    result->setName( "MapQuest" );
    GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
    routePlacemark->setName( "Route" );

    GeoDataLineString* routeWaypoints = new GeoDataLineString;
    QDomNodeList shapePoints = root.elementsByTagName( "shapePoints" );
    if ( shapePoints.size() == 1 ) {
        QDomNodeList geometry = shapePoints.at( 0 ).toElement().elementsByTagName( "latLng" );
        for ( int i=0; i<geometry.size(); ++i ) {
            double const lat = geometry.item( i ).namedItem( "lat" ).toElement().text().toDouble();
            double const lon = geometry.item( i ).namedItem( "lng" ).toElement().text().toDouble();
            GeoDataCoordinates const position( lon, lat, 0.0, GeoDataCoordinates::Degree );
            routeWaypoints->append( position );
        }
    }
    routePlacemark->setGeometry( routeWaypoints );

    QTime time;
    time = time.addSecs( root.elementsByTagName( "time" ).at( 0 ).toElement().text().toInt() );
    qreal length = routeWaypoints->length( EARTH_RADIUS );
    const QString name = nameString( "MQ", length, time );
    const GeoDataExtendedData data = routeData( length, time );
    routePlacemark->setExtendedData( data );
    result->setName( name );
    result->append( routePlacemark );

    QMap<int,int> mapping;
    QDomNodeList maneuvers = root.elementsByTagName( "maneuverIndexes" );
    if ( maneuvers.size() == 1 ) {
        maneuvers = maneuvers.at( 0 ).childNodes();
        for ( int i=0; i<maneuvers.size(); ++i ) {
            mapping[i] = maneuvers.at( i ).toElement().text().toInt();
            if ( mapping[i] == routeWaypoints->size() ) {
                --mapping[i];
            }
        }
    }

    QDomNodeList instructions = root.elementsByTagName( "maneuver" );
    unsigned int const lastInstruction = qMax<int>( 0, instructions.length()-1 ); // ignore the last 'Welcome to xy' instruction
    for ( unsigned int i = 0; i < lastInstruction; ++i ) {
        QDomElement node = instructions.item( i ).toElement();

        QDomNodeList maneuver = node.elementsByTagName( "turnType" );
        QDomNodeList textNodes = node.elementsByTagName( "narrative" );
        QDomNodeList points = node.elementsByTagName( "startPoint" );
        QDomNodeList streets = node.elementsByTagName( "streets" );

        Q_ASSERT( mapping.contains( i ) );
        if ( textNodes.size() == 1 && maneuver.size() == 1 && points.size() == 1 && mapping.contains( i ) ) {
            GeoDataPlacemark* instruction = new GeoDataPlacemark;
            instruction->setName( textNodes.at( 0 ).toElement().text() );

            GeoDataExtendedData extendedData;
            GeoDataData turnType;
            turnType.setName( "turnType" );
            turnType.setValue( maneuverType( maneuver.at( 0 ).toElement().text().toInt() ) );
            extendedData.addValue( turnType );
            if ( streets.size() == 1 ) {
                GeoDataData roadName;
                roadName.setName( "roadName" );
                roadName.setValue( streets.at( 0 ).toElement().text() );
                extendedData.addValue( roadName );
            }
            instruction->setExtendedData( extendedData );

            int const start = mapping[i];
            int const end = mapping.contains(i+1) ? mapping[i+1] : routeWaypoints->size()-1;
            if ( start >= 0 && start < routeWaypoints->size() && end < routeWaypoints->size() ) {
                instruction->setName( textNodes.item( 0 ).toElement().text() );
                GeoDataLineString *lineString = new GeoDataLineString;
                for ( int j=start; j<=end; ++j ) {
                    *lineString << GeoDataCoordinates( routeWaypoints->at( j ).longitude(), routeWaypoints->at( j ).latitude() );
                }

                if ( !lineString->isEmpty() ) {
                    instruction->setGeometry( lineString );
                    result->append( instruction );
                }
            }
        }
    }

    if ( routeWaypoints->size() < 1 ) {
        delete result;
        result = 0;
    }

    return result;
}
Ejemplo n.º 2
0
void GeoDataLineStringPrivate::toDateLineCorrected(
                           const GeoDataLineString & q,
                           QVector<GeoDataLineString*> & lineStrings
                           )
{
    const bool isClosed = q.isClosed();

    const QVector<GeoDataCoordinates>::const_iterator itStartPoint = q.constBegin();
    const QVector<GeoDataCoordinates>::const_iterator itEndPoint = q.constEnd();
    QVector<GeoDataCoordinates>::const_iterator itPoint = itStartPoint;
    QVector<GeoDataCoordinates>::const_iterator itPreviousPoint = itPoint;

    TessellationFlags f = q.tessellationFlags();

    GeoDataLineString * unfinishedLineString = 0;

    GeoDataLineString * dateLineCorrected = isClosed ? new GeoDataLinearRing( f )
                                                     : new GeoDataLineString( f );

    qreal currentLon = 0.0;
    qreal previousLon = 0.0;
    int previousSign = 1;

    bool unfinished = false;

    for (; itPoint != itEndPoint; ++itPoint ) {
        currentLon = itPoint->longitude();

        int currentSign = ( currentLon < 0.0 ) ? -1 : +1 ;

        if( itPoint == q.constBegin() ) {
            previousSign = currentSign;
            previousLon  = currentLon;
        }

        // If we are crossing the date line ...
        if ( previousSign != currentSign && fabs(previousLon) + fabs(currentLon) > M_PI ) {

            unfinished = !unfinished;

            GeoDataCoordinates previousTemp;
            GeoDataCoordinates currentTemp;

            interpolateDateLine( *itPreviousPoint, *itPoint,
                                 previousTemp, currentTemp, q.tessellationFlags() );

            *dateLineCorrected << previousTemp;

            if ( isClosed && unfinished ) {
                // If it's a linear ring and if it crossed the IDL only once then
                // store the current string inside the unfinishedLineString for later use ...
                unfinishedLineString = dateLineCorrected;
                // ... and start a new linear ring for now.
                dateLineCorrected = new GeoDataLinearRing( f );
            }
            else {
                // Now it can only be a (finished) line string or a finished linear ring.
                // Store it in the vector  if the size is not zero.
                if ( dateLineCorrected->size() > 0 ) {
                    lineStrings << dateLineCorrected;
                }
                else {
                    // Or delete it.
                    delete dateLineCorrected;
                }

                // If it's a finished linear ring restore the "remembered" unfinished String
                if ( isClosed && !unfinished && unfinishedLineString ) {
                    dateLineCorrected = unfinishedLineString;
                }
                else {
                    // if it's a line string just create a new line string.
                    dateLineCorrected = new GeoDataLineString( f );
                }
            }

            *dateLineCorrected << currentTemp;
            *dateLineCorrected << *itPoint;

        }
        else {
            *dateLineCorrected << *itPoint;
        }

        previousSign = currentSign;
        previousLon  = currentLon;
        itPreviousPoint = itPoint;
    }

    // If the line string doesn't cross the dateline an even number of times
    // then need to take care of the data stored in the unfinishedLineString
    if ( unfinished && unfinishedLineString && !unfinishedLineString->isEmpty() ) {
        *dateLineCorrected << *unfinishedLineString;
        delete unfinishedLineString;
    }

    lineStrings << dateLineCorrected;
}