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; }
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::processAddingNodesOnMove( QMouseEvent *mouseEvent ) { Q_ASSERT( mouseEvent->button() == Qt::NoButton ); const int index = virtualNodeContains( mouseEvent->pos() ); // If we are adjusting a virtual node which has just been clicked and became real, just // change its coordinates when moving it, as we do with nodes in Editing state on move. if ( m_adjustedNode != -1 ) { // The virtual node which has just been added is always the last within // GeoDataLinearRing's container.qreal lon, lat; qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); GeoDataLineString *line = static_cast<GeoDataLineString*>( placemark()->geometry() ); line->at(m_adjustedNode) = newCoords; return true; // If we are hovering a virtual node, store its index in order to be painted in drawNodes // method. } else if ( index != -1 ) { m_virtualHoveredNode = index; 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 EditPolylineDialog::handleItemMoving( GeoDataPlacemark *item ) { if( item == d->m_placemark ) { d->m_nodeModel->clear(); if( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { GeoDataLineString *lineString = static_cast<GeoDataLineString*>( d->m_placemark->geometry() ); for( int i = 0; i < lineString->size(); ++i ) { d->m_nodeModel->addNode( lineString->at( i ) ); } } } }
void RoutingModelPrivate::importPlacemark( RouteSegment &outline, QVector<RouteSegment> &segments, const GeoDataPlacemark *placemark ) { GeoDataGeometry* geometry = placemark->geometry(); GeoDataLineString* lineString = dynamic_cast<GeoDataLineString*>( geometry ); QStringList blacklist = QStringList() << "" << "Route" << "Tessellated"; RouteSegment segment; bool isOutline = true; if ( !blacklist.contains( placemark->name() ) ) { if( lineString ) { Maneuver maneuver; maneuver.setInstructionText( placemark->name() ); maneuver.setPosition( lineString->at( 0 ) ); if ( placemark->extendedData().contains( "turnType" ) ) { QVariant turnType = placemark->extendedData().value( "turnType" ).value(); // The enum value is converted to/from an int in the QVariant // because only a limited set of data types can be serialized with QVariant's // toString() method (which is used to serialize <ExtendedData>/<Data> values) maneuver.setDirection( Maneuver::Direction( turnType.toInt() ) ); } if ( placemark->extendedData().contains( "roadName" ) ) { QVariant roadName = placemark->extendedData().value( "roadName" ).value(); maneuver.setRoadName( roadName.toString() ); } segment.setManeuver( maneuver ); isOutline = false; } } if ( lineString ) { segment.setPath( *lineString ); if ( isOutline ) { outline = segment; } else { segments.push_back( segment ); } } }
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 ); } }
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; }
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 ); } }