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 ); } }
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 ); }
void WikipediaItem::setLongitude( qreal longitude ) { GeoDataCoordinates updatedCoordinates = coordinate(); updatedCoordinates.setLongitude( longitude ); setCoordinate( updatedCoordinates ); }
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; }
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)); } } }