/** ****************************************************************************** * * @file opmapwidget.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief The Map Widget, this is the part exposed to the user * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget * @{ * *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "opmapwidget.h" #include #include #include "waypointitem.h" namespace mapcontrol { OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView(parent), configuration(config), UAV(0), GPS(0), Home(0), followmouse(true), compass(0), showuav(false), showhome(false), diagTimer(0), showDiag(false), diagGraphItem(0) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); core=new internals::Core; map=new MapGraphicItem(core,config); mscene.addItem(map); this->setScene(&mscene); this->adjustSize(); connect(map,SIGNAL(zoomChanged(double,double,double)),this,SIGNAL(zoomChanged(double,double,double))); connect(map->core,SIGNAL(OnCurrentPositionChanged(internals::PointLatLng)),this,SIGNAL(OnCurrentPositionChanged(internals::PointLatLng))); connect(map->core,SIGNAL(OnEmptyTileError(int,core::Point)),this,SIGNAL(OnEmptyTileError(int,core::Point))); connect(map->core,SIGNAL(OnMapDrag()),this,SIGNAL(OnMapDrag())); connect(map->core,SIGNAL(OnMapTypeChanged(MapType::Types)),this,SIGNAL(OnMapTypeChanged(MapType::Types))); connect(map->core,SIGNAL(OnMapZoomChanged()),this,SIGNAL(OnMapZoomChanged())); connect(map->core,SIGNAL(OnMapZoomChanged()),this,SLOT(emitMapZoomChanged())); connect(map->core,SIGNAL(OnTileLoadComplete()),this,SIGNAL(OnTileLoadComplete())); connect(map->core,SIGNAL(OnTileLoadStart()),this,SIGNAL(OnTileLoadStart())); connect(map->core,SIGNAL(OnTilesStillToLoad(int)),this,SIGNAL(OnTilesStillToLoad(int))); SetShowDiagnostics(showDiag); this->setMouseTracking(followmouse); SetShowCompass(true); } void OPMapWidget::SetShowDiagnostics(bool const& value) { showDiag=value; if(!showDiag) { if(diagGraphItem!=0) { delete diagGraphItem; diagGraphItem=0; } if(diagTimer!=0) { delete diagTimer; diagTimer=0; } } else { diagTimer=new QTimer(); connect(diagTimer,SIGNAL(timeout()),this,SLOT(diagRefresh())); diagTimer->start(500); } } void OPMapWidget::SetUavPic(QString UAVPic) { if(UAV!=0) UAV->SetUavPic(UAVPic); if(GPS!=0) GPS->SetUavPic(UAVPic); } UAVItem* OPMapWidget::AddUAV(int id) { UAVItem* newUAV = new UAVItem(map,this); newUAV->setParentItem(map); UAVS.insert(id, newUAV); QGraphicsItemGroup* waypointLine = new QGraphicsItemGroup(map); waypointLines.insert(id, waypointLine); return newUAV; } void OPMapWidget::AddUAV(int id, UAVItem* uav) { uav->setParentItem(map); QGraphicsItemGroup* waypointLine = new QGraphicsItemGroup(map); waypointLines.insert(id, waypointLine); UAVS.insert(id, uav); } void OPMapWidget::DeleteUAV(int id) { UAVItem* uav = UAVS.value(id, NULL); UAVS.remove(id); if (uav) { delete uav; uav = NULL; } QGraphicsItemGroup* wpLine = waypointLines.value(id, NULL); waypointLines.remove(id); if (wpLine) { delete wpLine; wpLine = NULL; } } /** * @return The reference to the UAVItem or NULL if no item exists yet * @see AddUAV() for adding a not yet existing UAV to the map */ UAVItem* OPMapWidget::GetUAV(int id) { return UAVS.value(id, 0); } const QList OPMapWidget::GetUAVS() { return UAVS.values(); } QGraphicsItemGroup* OPMapWidget::waypointLine(int id) { return waypointLines.value(id, NULL); } void OPMapWidget::SetShowUAV(const bool &value) { if(value && UAV==0) { UAV=new UAVItem(map,this); UAV->setParentItem(map); // FIXME XXX The map widget is here actually handling // safety and mission logic - might be worth some refactoring connect(this,SIGNAL(UAVLeftSafetyBouble(internals::PointLatLng)),UAV,SIGNAL(UAVLeftSafetyBouble(internals::PointLatLng))); connect(this,SIGNAL(UAVReachedWayPoint(int,WayPointItem*)),UAV,SIGNAL(UAVReachedWayPoint(int,WayPointItem*))); } else if(!value) { if(UAV!=0) { delete UAV; UAV=0; } } if(value && GPS==0) { GPS=new GPSItem(map,this); GPS->setParentItem(map); } else if(!value) { if(GPS!=0) { delete GPS; GPS=0; } } } void OPMapWidget::SetShowHome(const bool &value) { if(value && Home==0) { Home=new HomeItem(map,this); Home->setParentItem(map); } else if(!value) { if(Home!=0) { delete Home; Home=0; } } } void OPMapWidget::resizeEvent(QResizeEvent *event) { if (scene()) scene()->setSceneRect( QRect(QPoint(0, 0), event->size())); QGraphicsView::resizeEvent(event); if(compass) compass->setScale(0.1+0.05*(qreal)(event->size().width())/1000*(qreal)(event->size().height())/600); } QSize OPMapWidget::sizeHint() const { return map->sizeHint(); } void OPMapWidget::showEvent(QShowEvent *event) { connect(&mscene,SIGNAL(sceneRectChanged(QRectF)),map,SLOT(resize(QRectF)), Qt::UniqueConnection); map->start(); QGraphicsView::showEvent(event); } OPMapWidget::~OPMapWidget() { delete UAV; foreach(UAVItem* uav, this->UAVS) { delete uav; } delete Home; delete map; delete core; delete configuration; foreach(QGraphicsItem* i,this->items()) { delete i; } } void OPMapWidget::closeEvent(QCloseEvent *event) { core->OnMapClose(); event->accept(); } void OPMapWidget::SetUseOpenGL(const bool &value) { useOpenGL=value; if (useOpenGL) setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); else setupViewport(new QWidget()); update(); } internals::PointLatLng OPMapWidget::currentMousePosition() { return currentmouseposition; } void OPMapWidget::mouseMoveEvent(QMouseEvent *event) { QGraphicsView::mouseMoveEvent(event); QPointF p=event->localPos(); p=map->mapFromParent(p); currentmouseposition=map->FromLocalToLatLng(p.x(),p.y()); } ////////////////WAYPOINT//////////////////////// WayPointItem* OPMapWidget::WPCreate() { WayPointItem* item=new WayPointItem(this->CurrentPosition(),0,map); ConnectWP(item); item->setParentItem(map); return item; } void OPMapWidget::WPCreate(WayPointItem* item) { ConnectWP(item); item->setParentItem(map); } void OPMapWidget::WPCreate(int id, WayPointItem* item) { Q_UNUSED(id); static internals::PointLatLng lastPos; ConnectWP(item); item->setParentItem(map); // QGraphicsItemGroup* wpLine = waypointLines.value(id, NULL); // if (!wpLine) // { // wpLine = new QGraphicsItemGroup(map); // waypointLines.insert(id, wpLine); // } // if (!lastPos.IsEmpty()) // { // wpLine->addToGroup(new TrailLineItem(lastPos, item->Coord(), Qt::red, map)); // lastPos = item->Coord(); // } // Add waypoint line // trail->addToGroup(new TrailItem(position,altitude,color,this)); // if(!lasttrailline.IsEmpty()) // trailLine->addToGroup((new TrailLineItem(lasttrailline,position,color,map))); // lasttrailline=position; } WayPointItem* OPMapWidget::WPCreate(internals::PointLatLng const& coord,int const& altitude) { WayPointItem* item=new WayPointItem(coord,altitude,map); ConnectWP(item); item->setParentItem(map); return item; } WayPointItem* OPMapWidget::WPCreate(internals::PointLatLng const& coord,int const& altitude, QString const& description) { WayPointItem* item=new WayPointItem(coord,altitude,description,map); ConnectWP(item); item->setParentItem(map); return item; } WayPointItem* OPMapWidget::WPInsert(const int &position) { WayPointItem* item=new WayPointItem(this->CurrentPosition(),0,map); item->SetNumber(position); ConnectWP(item); item->setParentItem(map); emit WPInserted(position,item); return item; } void OPMapWidget::WPInsert(WayPointItem* item,const int &position) { item->SetNumber(position); ConnectWP(item); item->setParentItem(map); emit WPInserted(position,item); } WayPointItem* OPMapWidget::WPInsert(internals::PointLatLng const& coord,int const& altitude,const int &position) { WayPointItem* item=new WayPointItem(coord,altitude,map); item->SetNumber(position); ConnectWP(item); item->setParentItem(map); emit WPInserted(position,item); return item; } WayPointItem* OPMapWidget::WPInsert(internals::PointLatLng const& coord,int const& altitude, QString const& description,const int &position) { WayPointItem* item=new WayPointItem(coord,altitude,description,map); item->SetNumber(position); ConnectWP(item); item->setParentItem(map); emit WPInserted(position,item); return item; } void OPMapWidget::WPDelete(WayPointItem *item) { emit WPDeleted(item->Number()); delete item; } void OPMapWidget::WPDeleteAll() { foreach(QGraphicsItem* i,map->childItems()) { WayPointItem* w=qgraphicsitem_cast(i); if(w) delete w; } } QList OPMapWidget::WPSelected() { QList list; foreach(QGraphicsItem* i,mscene.selectedItems()) { WayPointItem* w=qgraphicsitem_cast(i); if(w) list.append(w); } return list; } void OPMapWidget::WPRenumber(WayPointItem *item, const int &newnumber) { item->SetNumber(newnumber); } void OPMapWidget::ConnectWP(WayPointItem *item) { connect(item,SIGNAL(WPNumberChanged(int,int,WayPointItem*)),this,SIGNAL(WPNumberChanged(int,int,WayPointItem*))); connect(item,SIGNAL(WPValuesChanged(WayPointItem*)),this,SIGNAL(WPValuesChanged(WayPointItem*))); connect(this,SIGNAL(WPInserted(int,WayPointItem*)),item,SLOT(WPInserted(int,WayPointItem*))); connect(this,SIGNAL(WPNumberChanged(int,int,WayPointItem*)),item,SLOT(WPRenumbered(int,int,WayPointItem*))); connect(this,SIGNAL(WPDeleted(int)),item,SLOT(WPDeleted(int))); } void OPMapWidget::diagRefresh() { if(showDiag) { if(diagGraphItem==0) { diagGraphItem=new QGraphicsTextItem(); mscene.addItem(diagGraphItem); diagGraphItem->setPos(10,100); diagGraphItem->setZValue(3); diagGraphItem->setFlag(QGraphicsItem::ItemIsMovable,true); diagGraphItem->setDefaultTextColor(Qt::yellow); } diagGraphItem->setPlainText(core->GetDiagnostics().toString()); } else if(diagGraphItem!=0) { delete diagGraphItem; diagGraphItem=0; } } ////////////////////////////////////////////// void OPMapWidget::SetShowCompass(const bool &value) { if(value && !compass) { compass=new QGraphicsSvgItem(QString::fromUtf8(":/markers/images/compas.svg")); compass->setScale(0.1+0.05*(qreal)(this->size().width())/1000*(qreal)(this->size().height())/600); // compass->setTransformOriginPoint(compass->boundingRect().width(),compass->boundingRect().height()); compass->setFlag(QGraphicsItem::ItemIsMovable,true); mscene.addItem(compass); compass->setTransformOriginPoint(compass->boundingRect().width()/2,compass->boundingRect().height()/2); compass->setPos(55-compass->boundingRect().width()/2,55-compass->boundingRect().height()/2); compass->setZValue(3); compass->setOpacity(0.7); } if(!value && compass) { delete compass; compass=0; } } void OPMapWidget::SetRotate(qreal const& value) { map->mapRotate(value); if(compass && (compass->rotation() != value)) { compass->setRotation(value); } } void OPMapWidget::RipMap() { new MapRipper(core,map->SelectedArea()); } #define deg_to_rad ((double)M_PI / 180.0) #define rad_to_deg (180.0 / (double)M_PI) #define earth_mean_radius 6371 // kilometers // ************************************************************************************* // return the bearing from one point to another .. in degrees double OPMapWidget::bearing(internals::PointLatLng from, internals::PointLatLng to) { double lat1 = from.Lat() * deg_to_rad; double lon1 = from.Lng() * deg_to_rad; double lat2 = to.Lat() * deg_to_rad; double lon2 = to.Lng() * deg_to_rad; // double delta_lat = lat2 - lat1; double delta_lon = lon2 - lon1; double y = sin(delta_lon) * cos(lat2); double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_lon); double bear = atan2(y, x) * rad_to_deg; bear += 360; while (bear < 0) bear += 360; while (bear >= 360) bear -= 360; return bear; } // ************************************************************************************* // return a destination lat/lon point given a source lat/lon point and the bearing and distance from the source point internals::PointLatLng OPMapWidget::destPoint(internals::PointLatLng source, double bear, double dist) { double lat1 = source.Lat() * deg_to_rad; double lon1 = source.Lng() * deg_to_rad; bear *= deg_to_rad; double ad = dist / earth_mean_radius; double lat2 = asin(sin(lat1) * cos(ad) + cos(lat1) * sin(ad) * cos(bear)); double lon2 = lon1 + atan2(sin(bear) * sin(ad) * cos(lat1), cos(ad) - sin(lat1) * sin(lat2)); return internals::PointLatLng(lat2 * rad_to_deg, lon2 * rad_to_deg); } }