MeasureToolPlugin::MeasureToolPlugin( const MarbleModel *marbleModel ) : RenderPlugin( marbleModel ), m_measureLineString( GeoDataLineString( Tessellate ) ), #ifdef Q_OS_MACX m_font_regular( QFont( "Sans Serif", 10, 50, false ) ), #else m_font_regular( QFont( "Sans Serif", 8, 50, false ) ), #endif m_fontascent( QFontMetrics( m_font_regular ).ascent() ), m_pen( Qt::red ), m_marbleWidget( 0 ), m_configDialog( 0 ), m_uiConfigWidget( 0 ), m_showSegmentLabels( false ) { m_pen.setWidthF( 2.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)); } } }