地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

510 lines
16 KiB

/**
******************************************************************************
*
* @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 <QtGui>
#include <QMetaObject>
#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<UAVItem*> 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)));
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<WayPointItem*>(i);
if(w)
delete w;
}
}
QList<WayPointItem*> OPMapWidget::WPSelected()
{
QList<WayPointItem*> list;
foreach(QGraphicsItem* i,mscene.selectedItems())
{
WayPointItem* w=qgraphicsitem_cast<WayPointItem*>(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);
}
}