void PolylineAnnotation::updateRegions( GeoPainter *painter ) { if ( m_busy ) { return; } const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() ); if ( state() == SceneGraphicsItem::AddingNodes ) { // Create and update virtual nodes lists when being in the AddingPolgonNodes state, to // avoid overhead in other states. m_virtualNodesList.clear(); for ( int i = 0; i < line.size() - 1; ++i ) { const QRegion newRegion( painter->regionFromEllipse( line.at(i).interpolate( line.at(i+1), 0.5 ), hoveredDim, hoveredDim ) ); m_virtualNodesList.append( PolylineNode( newRegion ) ); } } // Update the polyline region; m_polylineRegion = painter->regionFromPolyline( line, 15 ); // Update the node lists. for ( int i = 0; i < m_nodesList.size(); ++i ) { const QRegion newRegion = m_nodesList.at(i).isSelected() ? painter->regionFromEllipse( line.at(i), selectedDim, selectedDim ) : painter->regionFromEllipse( line.at(i), regularDim, regularDim ); m_nodesList[i].setRegion( newRegion ); } }
bool PolylineAnnotation::processAddingNodesOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() ); // If a virtual node has just been clicked, add it to the polyline and start 'adjusting' // its position. const int virtualIndex = virtualNodeContains( mouseEvent->pos() ); if ( virtualIndex != -1 && m_adjustedNode == -1 ) { Q_ASSERT( m_virtualHoveredNode == virtualIndex ); line->insert( virtualIndex + 1, line->at( virtualIndex ).interpolate( line->at( virtualIndex + 1 ), 0.5 ) ); m_nodesList.insert( virtualIndex + 1, PolylineNode() ); m_adjustedNode = virtualIndex + 1; m_virtualHoveredNode = -1; return true; } // If a virtual node which has been previously clicked and selected to become a // 'real node' is clicked one more time, it stops from being 'adjusted'. const int realIndex = nodeContains( mouseEvent->pos() ); if ( realIndex != -1 && m_adjustedNode != -1 ) { m_adjustedNode = -1; return true; } return false; }
bool PolylineAnnotation::processEditingOnMove( QMouseEvent *mouseEvent ) { if ( !m_viewport ) { return false; } qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); if ( m_interactingObj == InteractingNode ) { GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() ); line->at(m_clickedNodeIndex) = newCoords; return true; } else if ( m_interactingObj == InteractingPolyline ) { GeoDataLineString *lineString = static_cast<GeoDataLineString*>( placemark()->geometry() ); const GeoDataLineString oldLineString = *lineString; lineString->clear(); const qreal deltaLat = lat - m_movedPointCoords.latitude(); const qreal deltaLon = lon - m_movedPointCoords.longitude(); Quaternion latRectAxis = Quaternion::fromEuler( 0, lon, 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; qreal lonRotated, latRotated; for ( int i = 0; i < oldLineString.size(); ++i ) { Quaternion qpos = oldLineString.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); lineString->append( movedPoint ); } m_movedPointCoords = newCoords; return true; } return dealWithHovering( mouseEvent ); }
void PlacemarkTextAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) { Q_UNUSED( source ); qreal lat = destination.latitude(); qreal lon = destination.longitude(); GeoDataCoordinates::normalizeLonLat( lon, lat ); placemark()->setCoordinate( lon, lat ); }
SatellitesMSCItem::SatellitesMSCItem( const QString &name, const QString &category, const QString &relatedBody, const QString &catalog, const QDateTime &missionStart, const QDateTime &missionEnd, int catalogIndex, PlanetarySats *planSat, const MarbleClock *clock ) : TrackerPluginItem( name ), m_showOrbit( false ), m_track( new GeoDataTrack() ), m_clock( clock ), m_planSat( planSat ), m_name( name ), m_category( category ), m_relatedBody( relatedBody ), m_catalog( catalog ), m_catalogIndex( catalogIndex ), m_missionStart( missionStart ), m_missionEnd( missionEnd ) { placemark()->setVisualCategory( GeoDataFeature::Satellite ); placemark()->setZoomLevel( 0 ); placemark()->setGeometry( m_track ); GeoDataStyle *style = new GeoDataStyle( *placemark()->style() ); placemark()->setStyle( style ); placemark()->style()->lineStyle().setColor( Oxygen::brickRed4 ); placemark()->style()->lineStyle().setPenStyle( Qt::NoPen ); placemark()->style()->labelStyle().setGlow( true ); // use special icon for moons if( m_category == "Moons" ) { placemark()->style()->iconStyle().setIcon( QImage( ":/icons/moon.png" ) ); } m_planSat->getKeplerElements( m_perc, m_apoc, m_inc, m_ecc, m_ra, m_tano, m_m0, m_a, m_n0 ); setDescription(); update(); }
void PolylineAnnotation::deleteClickedNode() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() ); if ( m_nodesList.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return; } m_nodesList.removeAt( m_clickedNodeIndex ); line->remove( m_clickedNodeIndex ); }
void SatellitesMSCItem::setDescription() { QString description = QObject::tr( "Object name: %1 <br />" "Category: %2 <br />" "Pericentre: %3 km<br />" "Apocentre: %4 km<br />" "Inclination: %5 Degree<br />" "Revolutions per day (24h): %6" ) .arg( name(), category(), QString::number( m_perc, 'f', 2 ), QString::number( m_apoc, 'f', 2 ), QString::number( m_inc, 'f', 2 ), QString::number( m_n0, 'f', 2 ) ); placemark()->setDescription( description ); }
void PolylineAnnotation::setupRegionsLists( GeoPainter *painter ) { Q_ASSERT( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ); const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() ); // Add poyline nodes. QVector<GeoDataCoordinates>::ConstIterator itBegin = line.constBegin(); QVector<GeoDataCoordinates>::ConstIterator itEnd = line.constEnd(); m_nodesList.clear(); for ( ; itBegin != itEnd; ++itBegin ) { const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) ); m_nodesList.append( newNode ); } // Add region from polyline so that events on polyline's 'lines' could be caught. m_polylineRegion = painter->regionFromPolyline( line, 15 ); }
void PolylineAnnotation::paint( GeoPainter *painter, const ViewportParams *viewport ) { m_viewport = viewport; Q_ASSERT( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ); painter->save(); if ( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ) { setupRegionsLists( painter ); m_regionsInitialized = true; } else { updateRegions( painter ); } if ( hasFocus() ) { drawNodes( painter ); } painter->restore(); }
bool PolylineAnnotation::processMergingOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataLineString line = static_cast<GeoDataLineString>( *placemark()->geometry() ); const int index = nodeContains( mouseEvent->pos() ); if ( index == -1 ) { return false; } // If this is the first node selected to be merged. if ( m_firstMergedNode == -1 ) { m_firstMergedNode = index; m_nodesList[index].setFlag( PolylineNode::NodeIsMerged ); } else { Q_ASSERT( m_firstMergedNode != -1 ); // Clicking two times the same node results in unmarking it for merging. if ( m_firstMergedNode == index ) { m_nodesList[index].setFlag( PolylineNode::NodeIsMerged, false ); m_firstMergedNode = -1; return true; } // If these two nodes are the last ones remained as part of the polyline, remove // the whole polyline. if ( line.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return true; } m_nodesList[index].setFlag( PolylineNode::NodeIsMerged ); m_secondMergedNode = index; delete m_animation; m_animation = new MergingPolylineNodesAnimation( this ); setRequest( SceneGraphicsItem::StartPolylineAnimation ); } return true; }
bool PlacemarkTextAnnotation::mouseMoveEvent( QMouseEvent *event ) { setRequest( SceneGraphicsItem::NoRequest ); qreal lon, lat; m_viewport->geoCoordinates( event->pos().x(), event->pos().y(), lon, lat, GeoDataCoordinates::Radian ); if ( m_movingPlacemark ) { placemark()->setCoordinate( lon, lat ); return true; } else { setRequest( SceneGraphicsItem::ChangeCursorPlacemarkHover ); return true; } return false; }
void PolylineAnnotation::deleteAllSelectedNodes() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() ); for ( int i = 0; i < line->size(); ++i ) { if ( m_nodesList.at(i).isSelected() ) { if ( m_nodesList.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return; } m_nodesList.removeAt( i ); line->remove( i ); --i; } } }
void PolylineAnnotation::dealWithItemChange( const SceneGraphicsItem *other ) { Q_UNUSED( other ); // So far we only deal with item changes when hovering nodes, so that // they do not remain hovered when changing the item we interact with. if ( state() == SceneGraphicsItem::Editing ) { if ( m_hoveredNodeIndex != -1 && m_hoveredNodeIndex < static_cast<GeoDataLineString*>( placemark()->geometry() )->size() ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } m_hoveredNodeIndex = -1; } else if ( state() == SceneGraphicsItem::MergingNodes ) { if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_hoveredNodeIndex = -1; } else if ( state() == SceneGraphicsItem::AddingNodes ) { m_virtualHoveredNode = -1; } }
void GroundOverlayFrame::update() { GeoDataLatLonBox overlayLatLonBox = m_overlay->latLonBox(); GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( placemark()->geometry() ); poly->outerBoundary().clear(); GeoDataCoordinates rotatedCoord; GeoDataCoordinates northWest(overlayLatLonBox.west(), overlayLatLonBox.north()); rotatedCoord = northWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates southWest(overlayLatLonBox.west(), overlayLatLonBox.south()); rotatedCoord = southWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates southEast(overlayLatLonBox.east(), overlayLatLonBox.south()); rotatedCoord = southEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates northEast(overlayLatLonBox.east(), overlayLatLonBox.north()); rotatedCoord = northEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); }
void PolylineAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) { GeoDataLineString *lineString = static_cast<GeoDataLineString*>( placemark()->geometry() ); GeoDataLineString oldLineString = *lineString; lineString->clear(); const qreal deltaLat = destination.latitude() - source.latitude(); const qreal deltaLon = destination.longitude() - source.longitude(); Quaternion latRectAxis = Quaternion::fromEuler( 0, destination.longitude(), 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; qreal lonRotated, latRotated; for ( int i = 0; i < oldLineString.size(); ++i ) { Quaternion qpos = oldLineString.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); lineString->append( movedPoint ); } }
void GroundOverlayFrame::paint(GeoPainter *painter, const ViewportParams *viewport ) { m_viewport = viewport; m_regionList.clear(); painter->save(); if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { GeoDataPolygon *polygon = static_cast<GeoDataPolygon*>( placemark()->geometry() ); GeoDataLinearRing &ring = polygon->outerBoundary(); QList<GeoDataCoordinates> coordinateList; coordinateList.append( ring.at( NorthWest ) ); coordinateList.append( ring.at( SouthWest ) ); coordinateList.append( ring.at( SouthEast ) ); coordinateList.append( ring.at( NorthEast ) ); GeoDataCoordinates northernHandle = ring.at( NorthEast ).interpolate( ring.at( NorthWest ), 0.5 ); GeoDataCoordinates southernHandle = ring.at( SouthEast ).interpolate( ring.at( SouthWest ), 0.5 ); // Special case handle position to take tessellation // along latitude circles into account if (m_overlay->latLonBox().rotation() == 0) { northernHandle.setLatitude(ring.at( NorthEast ).latitude()); southernHandle.setLatitude(ring.at( SouthEast ).latitude()); } coordinateList.append( northernHandle ); coordinateList.append( southernHandle ); coordinateList.append( ring.at( NorthEast ).interpolate( ring.at( SouthEast ), 0.5 ) ); coordinateList.append( ring.at( NorthWest ).interpolate( ring.at( SouthWest ), 0.5 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthWest ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthWest ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthEast ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthEast ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( North ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( South ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( East ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( West ), 16, 16 ) ); m_regionList.append( painter->regionFromPolygon( ring, Qt::OddEvenFill ) ); // Calculate handle icon orientation due to the projection qreal xNW, yNW, xSW, ySW; viewport->screenCoordinates(ring.at( NorthWest ), xNW, yNW); viewport->screenCoordinates(ring.at( SouthWest ), xSW, ySW); qreal westernAngle = qAtan2(ySW - yNW, xSW - xNW) - M_PI/2; qreal xNE, yNE, xSE, ySE; viewport->screenCoordinates(ring.at( NorthEast ), xNE, yNE); viewport->screenCoordinates(ring.at( SouthEast ), xSE, ySE); qreal easternAngle = qAtan2(ySE - yNE, xSE - xNE) - M_PI/2; painter->setPen( Qt::DashLine ); painter->setBrush( Qt::NoBrush ); painter->drawPolygon( ring ); qreal projectedAngle = 0; for( int i = NorthWest; i != Polygon; ++i ) { // Assign handle icon orientation due to the projection if (i == NorthWest || i == West || i == SouthWest) { projectedAngle = westernAngle; } else if (i == NorthEast || i == East || i == SouthEast) { projectedAngle = easternAngle; } else if (i == North || i == South) { projectedAngle = (westernAngle + easternAngle) / 2; } QTransform trans; trans.rotateRadians( projectedAngle ); if ( m_editStatus == Resize ){ if( m_hoveredHandle != i ) { painter->drawImage( coordinateList.at( i ), m_resizeIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) ); } else { painter->drawImage( coordinateList.at( i ), m_resizeIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) ); } } else if ( m_editStatus == Rotate ) { if( m_hoveredHandle != i ) { painter->drawImage( coordinateList.at( i ), m_rotateIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) ); } else { painter->drawImage( coordinateList.at( i ), m_rotateIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) ); } } } } painter->restore(); }
bool GroundOverlayFrame::mouseMoveEvent( QMouseEvent *event ) { if ( !m_viewport ) { return false; } // Catch hover events. if ( m_movedHandle == NoRegion ) { for ( int i = 0; i < m_regionList.size(); ++i ) { if ( m_regionList.at(i).contains( event->pos() ) ) { if ( i == Polygon ) { setRequest( ChangeCursorOverlayBodyHover ); } else { setRequest( ChangeCursorOverlayRotateHover ); } m_hoveredHandle = i; return true; } } m_hoveredHandle = NoRegion; return true; } else { m_editStatusChangeNeeded = false; } if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { qreal lon, lat; m_viewport->geoCoordinates( event->pos().x(), event->pos().y(), lon, lat, GeoDataCoordinates::Radian ); if ( m_editStatus == Resize ) { GeoDataCoordinates coord(lon, lat); GeoDataCoordinates rotatedCoord(coord); if (m_overlay->latLonBox().rotation() != 0) { rotatedCoord = coord.rotateAround(m_overlay->latLonBox().center(), -m_overlay->latLonBox().rotation()); } if ( m_movedHandle == NorthWest ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } else if ( m_movedHandle == SouthWest ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } else if ( m_movedHandle == SouthEast ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == NorthEast ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == North ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); } else if ( m_movedHandle == South ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); } else if ( m_movedHandle == East ) { m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == West ) { m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } } else if ( m_editStatus == Rotate ) { if ( m_movedHandle != Polygon ) { QPoint center = m_regionList.at( Polygon ).boundingRect().center(); qreal angle1 = qAtan2( event->pos().y() - center.y(), event->pos().x() - center.x() ); qreal angle2 = qAtan2( m_movedHandleScreenCoordinates.y() - center.y(), m_movedHandleScreenCoordinates.x() - center.x() ); m_overlay->latLonBox().setRotation( angle2 - angle1 + m_previousRotation ); } } if ( m_movedHandle == Polygon ) { const qreal centerLonDiff = lon - m_movedHandleGeoCoordinates.longitude(); const qreal centerLatDiff = lat - m_movedHandleGeoCoordinates.latitude(); m_overlay->latLonBox().setBoundaries( m_overlay->latLonBox().north() + centerLatDiff, m_overlay->latLonBox().south() + centerLatDiff, m_overlay->latLonBox().east() + centerLonDiff, m_overlay->latLonBox().west() + centerLonDiff ); m_movedHandleGeoCoordinates.set( lon, lat ); } update(); return true; } return false; }
void PolylineAnnotation::drawNodes( GeoPainter *painter ) { // These are the 'real' dimensions of the drawn nodes. The ones which have class scope are used // to generate the regions and they are a little bit larger, because, for example, it would be // a little bit too hard to select nodes. static const int d_regularDim = 10; static const int d_selectedDim = 10; static const int d_mergedDim = 20; static const int d_hoveredDim = 20; const GeoDataLineString line = static_cast<const GeoDataLineString>( *placemark()->geometry() ); QColor glowColor = QApplication::palette().highlightedText().color(); glowColor.setAlpha(120); for ( int i = 0; i < line.size(); ++i ) { // The order here is important, because a merged node can be at the same time selected. if ( m_nodesList.at(i).isBeingMerged() ) { painter->setBrush( mergedColor ); painter->drawEllipse( line.at(i), d_mergedDim, d_mergedDim ); } else if ( m_nodesList.at(i).isSelected() ) { painter->setBrush( selectedColor ); painter->drawEllipse( line.at(i), d_selectedDim, d_selectedDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( line.at(i), d_selectedDim + 2, d_selectedDim + 2 ); painter->setPen( defaultPen ); } } else { painter->setBrush( regularColor ); painter->drawEllipse( line.at(i), d_regularDim, d_regularDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setPen( newPen ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( line.at(i), d_regularDim + 2, d_regularDim + 2 ); painter->setPen( defaultPen ); } } } if ( m_virtualHoveredNode != -1 ) { painter->setBrush( hoveredColor ); GeoDataCoordinates newCoords; if ( m_virtualHoveredNode + 1 ) { newCoords = line.at( m_virtualHoveredNode + 1 ).interpolate( line.at( m_virtualHoveredNode ), 0.5 ); } else { newCoords = line.first().interpolate( line.last(), 0.5 ); } painter->drawEllipse( newCoords, d_hoveredDim, d_hoveredDim ); } }