dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
uavitem.cpp
Go to the documentation of this file.
1 
13 /*
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, see <http://www.gnu.org/licenses/>
26 */
27 
28 #include "tlmapwidget.h"
29 #include <math.h>
30 
31 #include "uavitem.h"
32 #include "waypointitem.h"
33 
34 namespace mapcontrol
35 {
36 
37  double UAVItem::groundspeed_mps_filt = 0;
38 
39  UAVItem::UAVItem(MapGraphicItem *map, TLMapWidget *parent, QString uavPic) :
40  mapwidget(parent),
41  showtrail(true),
42  showtrailline(true),
43  trailtime(5),
44  traildistance(50),
45  autosetreached(true),
46  autosetdistance(100),
47  showUAVInfo(false)
48  {
49  this->map = map;
50  altitude = 0;
51  pic.load(uavPic);
52  this->setFlag(QGraphicsItem::ItemIsMovable,false);
53  this->setFlag(QGraphicsItem::ItemIsSelectable,false);
54  localposition=map->FromLatLngToLocal(mapwidget->CurrentPosition());
55  this->setPos(localposition.X(),localposition.Y());
56  this->setZValue(4);
57  trail=new QGraphicsItemGroup(this);
58  trail->setParentItem(map);
59  trailLine=new QGraphicsItemGroup(this);
60  trailLine->setParentItem(map);
61  this->setFlag(QGraphicsItem::ItemIgnoresTransformations,true);
62  setCacheMode(QGraphicsItem::ItemCoordinateCache);
63  mapfollowtype=UAVMapFollowType::None;
64  trailtype=UAVTrailType::ByDistance;
65  timer.start();
66  generateArrowhead();
67  double pixels2meters = map->Projection()->GetGroundResolution(map->ZoomTotal(),coord.Lat());
68  meters2pixels=1.0 / pixels2meters;
69  setCacheMode(QGraphicsItem::DeviceCoordinateCache);
70  connect(map,SIGNAL(childRefreshPosition()),this,SLOT(RefreshPos()));
71  connect(map,SIGNAL(childSetOpacity(qreal)),this,SLOT(setOpacitySlot(qreal)));
72  connect(map,SIGNAL(zoomChanged(double,double,double)),this,SLOT(zoomChangedSlot()));
73  }
74  UAVItem::~UAVItem()
75  {
76 
77  }
78 
79  void UAVItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
80  {
81  Q_UNUSED(option);
82  Q_UNUSED(widget);
83 
84  //Draw plane
85  painter->drawPixmap(-pic.width()/2,-pic.height()/2,pic);
86 
87  //Return if UAV Info context menu is turned off
88  if(!showUAVInfo){
89  return;
90  }
91 
92  QPen myPen;
93 
94  //Turn on anti-aliasing so the fonts don't look terrible
95  painter->setRenderHint(QPainter::Antialiasing, true);
96 
97  //Set pen attributes
98  QColor myColor(Qt::red);
99  myPen.setWidth(3);
100  myPen.setColor(myColor);
101  painter->setPen(myPen);
102  painter->drawPolygon(arrowHead);
103  painter->setPen(myPen);
104  painter->drawLine(arrowShaft);
105 
106  //Set trend arc's color
107  myPen.setColor(Qt::magenta);
108  painter->setPen(myPen);
109 
110  if (trendSpanAngle > 0){
111  QRectF rect(0, -trendRadius, trendRadius*2, trendRadius*2);
112  painter->drawArc(rect, 180*16, -trendSpanAngle*16);
113  }
114  else{
115  QRectF rect(-2*trendRadius, -trendRadius, trendRadius*2, trendRadius*2);
116  painter->drawArc(rect, 0*16, -trendSpanAngle*16);
117  }
118 
119  //*********** Create time rings
120  if(groundspeed_mps_filt > 0){ //Don't clutter the display with rings that are only one pixel wide
121  myPen.setWidth(2);
122 
123  myPen.setColor(QColor(0, 0, 0, 100));
124  painter->setPen(myPen);
125  painter->drawEllipse(QPointF(0,0),precalcRings,precalcRings);
126 
127  myPen.setColor(QColor(0, 0, 0, 110));
128  painter->setPen(myPen);
129  painter->drawEllipse(QPointF(0,0),precalcRings*2,precalcRings*2);
130 
131  myPen.setColor(QColor(0, 0, 0, 120));
132  painter->setPen(myPen);
133  painter->drawEllipse(QPointF(0,0),precalcRings*4,precalcRings*4);
134  }
135  //Rotate the text back to vertical
136  qreal rot=this->rotation();
137  painter->rotate(-1*rot);
138 
139  myPen.setWidth(1);
140  myPen.setColor(Qt::white);
141  painter->setBrush(Qt::white);
142  painter->setPen(myPen);
143  painter->drawPath(textPath);
144  }
145 
146  void UAVItem::updateTextOverlay()
147  {
148  QPainterPath temp;
149  if(!showUAVInfo)
150  {
151  temp.swap(textPath);
152  return;
153  }
154 
155  QFont borderfont( "Arial", 14, QFont::Normal, false );
156 
157  //Top left corner of text
158  int textAnchorX = 20;
159  int textAnchorY = 20;
160 
161  QString uavoInfoStrLine1, uavoInfoStrLine2;
162  QString uavoInfoStrLine3, uavoInfoStrLine4;
163  QString uavoInfoStrLine5;
164 
165  uavoInfoStrLine2.append(QString("Groundspeed: %1 kph").arg(groundspeed_kph, 0, 'f',1));
166  uavoInfoStrLine3.append(QString("Lat-Lon: %1, %2").arg(coord.Lat(), 0, 'f',7).arg(coord.Lng(), 0, 'f',7));
167  uavoInfoStrLine4.append(QString("North-East: %1 m, %2 m").arg(NED[0], 0, 'f',1).arg(NED[1], 0, 'f',1));
168  uavoInfoStrLine5.append(QString("Altitude: %1 m").arg(-NED[2], 0, 'f',1));
169  temp.addText(textAnchorX, textAnchorY+16*0, borderfont, uavoInfoStrLine1);
170  temp.addText(textAnchorX, textAnchorY+16*1, borderfont, uavoInfoStrLine2);
171  temp.addText(textAnchorX, textAnchorY+16*2, borderfont, uavoInfoStrLine3);
172  temp.addText(textAnchorX, textAnchorY+16*3, borderfont, uavoInfoStrLine4);
173  temp.addText(textAnchorX, textAnchorY+16*4, borderfont, uavoInfoStrLine5);
174 
175  //Add text for time rings.
176  if(groundspeed_mps > 0){
177  //Always add the left side...
178  temp.addText(-(groundspeed_mps_filt*ringTime*1*meters2pixels+10), 0, borderfont, QString("%1 s").arg(ringTime,0,'f',0));
179  temp.addText(-(groundspeed_mps_filt*ringTime*2*meters2pixels+10), 0, borderfont, QString("%1 s").arg(ringTime*2,0,'f',0));
180  temp.addText(-(groundspeed_mps_filt*ringTime*4*meters2pixels+10), 0, borderfont, QString("%1 s").arg(ringTime*4,0,'f',0));
181  //... and add the right side, only if it doesn't interfere with the uav info text
182  if(groundspeed_mps_filt*ringTime*4*meters2pixels > 200){
183  if(groundspeed_mps_filt*ringTime*2*meters2pixels > 200){
184  if(groundspeed_mps_filt*ringTime*1*meters2pixels > 200){
185  temp.addText(groundspeed_mps_filt*ringTime*1*meters2pixels-8, 0, borderfont, QString("%1 s").arg(ringTime,0,'f',0));
186  }
187  temp.addText(groundspeed_mps_filt*ringTime*2*meters2pixels-8, 0, borderfont, QString("%1 s").arg(ringTime*2,0,'f',0));
188  }
189  temp.addText(groundspeed_mps_filt*ringTime*4*meters2pixels-8, 0, borderfont, QString("%1 s").arg(ringTime*4,0,'f',0));
190  }
191  }
192  temp.swap(textPath);
193  }
194 
195  QRectF UAVItem::boundingRect()const
196  {
197  if(showUAVInfo){
198  if (boundingRectSize < 220){
199  //In case the bounding rectangle isn't big enough to get the whole of the UAV Info graphic
200  return QRectF(-boundingRectSize,-80,boundingRectSize+220,180);
201  }
202  else{
203  return QRectF(-boundingRectSize,-boundingRectSize,2*boundingRectSize,2*boundingRectSize);
204  }
205  }
206  else{
207  return QRectF(-pic.width()/2,-pic.height()/2,pic.width(),pic.height());
208  }
209  }
210 
211  void UAVItem::SetNED(double NED[3]){
212  this->NED[0] = NED[0];
213  this->NED[1] = NED[1];
214  this->NED[2] = NED[2];
215  }
216 
217  void UAVItem::SetYawRate(double yawRate_dps){
218  this->yawRate_dps=yawRate_dps;
219 
220  if (fabs(this->yawRate_dps) < 5e-1){ //This number is really the smallest we can go. Any smaller, and it might have problems if we forecast a shorter distance into the future
221  this->yawRate_dps=5e-1;
222  }
223 
224  //*********** Create trend arc
225  trendSpanAngle = this->yawRate_dps * 5; //Forecast 5 seconds into the future
226 
227  //Calculate radius in [m], and then convert to pixels in local frame (not the same frame as is displayed on the map widget)
228  trendRadius=fabs(groundspeed_mps/(this->yawRate_dps*M_PI/180))*meters2pixels;
229  }
230 
231  void UAVItem::SetCAS(double CAS_mps){
232  this->CAS_mps=CAS_mps;
233  }
234 
235  void UAVItem::SetGroundspeed(double vNED[3], int m_maxUpdateRate_ms){
236  this->vNED[0] = vNED[0];
237  this->vNED[1] = vNED[1];
238  this->vNED[2] = vNED[2];
239  groundspeed_kph=sqrt(vNED[0]*vNED[0] + vNED[1]*vNED[1] + vNED[2]*vNED[2])*3.6;
240  groundspeed_mps=groundspeed_kph/3.6;
241  //On the first pass, set the filtered speed to the reported speed.
242  static bool firstGroundspeed=true;
243  if (firstGroundspeed){
244  groundspeed_mps_filt=groundspeed_kph/3.6;
245  firstGroundspeed=false;
246  }
247  else{
248  int riseTime_ms=1000;
249  double alpha= m_maxUpdateRate_ms/(double)(m_maxUpdateRate_ms+riseTime_ms);
250  groundspeed_mps_filt= alpha*groundspeed_mps_filt + (1-alpha)*(groundspeed_kph/3.6);
251  }
252  ringTime=10*pow(2,17-map->ZoomTotal()); //Basic ring is 10 seconds wide at zoom level 17
253  precalcRings=groundspeed_mps_filt*ringTime*meters2pixels;
254  boundingRectSize=groundspeed_mps_filt*ringTime*4*meters2pixels+20;
255  prepareGeometryChange();
256  }
257 
258 
259  void UAVItem::SetUAVPos(const internals::PointLatLng &position, const int &altitude)
260  {
261  if(coord.IsEmpty())
262  lastcoord=coord;
263  if(coord!=position)
264  {
265 
266  if(trailtype==UAVTrailType::ByTimeElapsed)
267  {
268  if(timer.elapsed()>trailtime*1000)
269  {
270  TrailItem * ob=new TrailItem(position,altitude,Qt::green,map);
271  trail->addToGroup(ob);
272  connect(this,SIGNAL(setChildPosition()),ob,SLOT(setPosSLOT()));
273  if(!lasttrailline.IsEmpty())
274  {
275  TrailLineItem * obj=new TrailLineItem(lasttrailline,position,Qt::red,map);
276  trailLine->addToGroup(obj);
277  connect(this,SIGNAL(setChildLine()),obj,SLOT(setLineSlot()));
278  }
279  lasttrailline=position;
280  timer.restart();
281  }
282 
283  }
284  else if(trailtype==UAVTrailType::ByDistance)
285  {
286  if(qAbs(internals::PureProjection::DistanceBetweenLatLng(lastcoord, position)) > traildistance)
287  {
288  TrailItem * ob=new TrailItem(position,altitude,Qt::green,map);
289  trail->addToGroup(ob);
290  connect(this,SIGNAL(setChildPosition()),ob,SLOT(setPosSLOT()));
291  if(!lasttrailline.IsEmpty())
292  {
293  TrailLineItem * obj=new TrailLineItem(lasttrailline,position,Qt::red,map);
294  trailLine->addToGroup(obj);
295  connect(this,SIGNAL(setChildLine()),obj,SLOT(setLineSlot()));
296  }
297  lasttrailline=position;
298  lastcoord=position;
299  }
300  }
301  coord=position;
302  this->altitude=altitude;
303  RefreshPos();
304  if(mapfollowtype==UAVMapFollowType::CenterAndRotateMap||mapfollowtype==UAVMapFollowType::CenterMap)
305  {
306  mapwidget->SetCurrentPosition(coord);
307  }
308  if(autosetreached)
309  {
310  foreach(QGraphicsItem* i,map->childItems())
311  {
312  WayPointItem* wp=qgraphicsitem_cast<WayPointItem*>(i);
313  if(wp)
314  {
315  if (DistanceToPoint_3D(wp->Coord(), wp->Altitude()) < autosetdistance)
316  {
317  wp->SetReached(true);
318  emit UAVReachedWayPoint(wp->Number(),wp);
319  }
320  }
321  }
322  }
323  if(mapwidget->Home!=nullptr)
324  {
325  //verify if the UAV is inside the safety cylinder
326  if(DistanceToPoint_2D(mapwidget->Home->Coord()) > mapwidget->Home->SafeArea())
327  {
328  if(mapwidget->Home->safe!=false)
329  {
330  mapwidget->Home->safe=false;
331  mapwidget->Home->update();
332  emit UAVLeftSafetyBouble(this->coord);
333  }
334  }
335  else
336  {
337  if(mapwidget->Home->safe!=true)
338  {
339  mapwidget->Home->safe=true;
340  mapwidget->Home->update();
341  }
342  }
343 
344  }
345  }
346  }
347 
352  void UAVItem::SetUAVHeading(const qreal &value)
353  {
354  if(mapfollowtype==UAVMapFollowType::CenterAndRotateMap)
355  {
356  mapwidget->SetRotate(-value);
357  }
358  else {
359  if (this->rotation() != value)
360  this->setRotation(value);
361  }
362  }
363 
364 
365  int UAVItem::type()const
366  {
367  return Type;
368  }
369 
370 
372  {
373  localposition=map->FromLatLngToLocal(coord);
374  this->setPos(localposition.X(),localposition.Y());
375  emit setChildPosition();
376  emit setChildLine();
377  updateTextOverlay();
378  }
379 
380  void UAVItem::setOpacitySlot(qreal opacity)
381  {
382  this->setOpacity(opacity);
383  }
384 
386  {
387  double pixels2meters = map->Projection()->GetGroundResolution(map->ZoomTotal(),coord.Lat());
388  meters2pixels=1.0 / pixels2meters;
389  boundingRectSize=groundspeed_mps_filt*ringTime*4*meters2pixels+20;
390  prepareGeometryChange();
391  updateTextOverlay();
392  update();
393  }
394  void UAVItem::SetTrailType(const UAVTrailType::Types &value)
395  {
396  trailtype=value;
397  if(trailtype==UAVTrailType::ByTimeElapsed)
398  timer.restart();
399  }
400  void UAVItem::SetShowTrail(const bool &value)
401  {
402  showtrail=value;
403  trail->setVisible(value);
404  }
405  void UAVItem::SetShowTrailLine(const bool &value)
406  {
407  showtrailline=value;
408  trailLine->setVisible(value);
409  }
410 
411  void UAVItem::DeleteTrail()const
412  {
413  foreach(QGraphicsItem* i,trail->childItems())
414  delete i;
415  foreach(QGraphicsItem* i,trailLine->childItems())
416  delete i;
417  }
418 
419  void UAVItem::SetUavPic(QString UAVPic)
420  {
421  pic.load(":/uavs/images/"+UAVPic);
422  }
423 
424  void UAVItem::SetShowUAVInfo(bool const& value)
425  {
426  showUAVInfo=value;
427  showJustChanged=true;
428  update();
429  }
430 
431  void UAVItem::generateArrowhead(){
432  qreal arrowSize = 10;
433 
434  //Create line from (0,0), to (1,1). Later, we'll scale and rotate it
435  arrowShaft=QLineF(0,0,1.0,1.0);
436 
437  //Set the starting point to (0,0)
438  arrowShaft.setP1(QPointF(0,0));
439 
440  //Set angle and length
441  arrowShaft.setLength(60.0);
442  arrowShaft.setAngle(90.0);
443 
444  //Form arrowhead
445  double angle = ::acos(arrowShaft.dx() / arrowShaft.length());
446  if (arrowShaft.dy() <= 0)
447  angle = (M_PI * 2) - angle;
448 
449  QPointF arrowP1 = arrowShaft.pointAt(1) + QPointF(sin(angle + M_PI / 3) * arrowSize,
450  cos(angle + M_PI / 3) * arrowSize);
451  QPointF arrowP2 = arrowShaft.pointAt(1) + QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize,
452  cos(angle + M_PI - M_PI / 3) * arrowSize);
453 
454  //Assemble arrowhead
455  arrowHead.clear();
456  arrowHead << arrowShaft.pointAt(1) << arrowP1 << arrowP2;
457 
458  }
459 }
qint64 X() const
Definition: point.h:51
A graphicsItem representing a WayPoint.
void zoomChangedSlot()
Definition: uavitem.cpp:385
The Map Widget, this is the part exposed to the user.
internals::PointLatLng coord
Definition: mappointitem.h:109
double DistanceToPoint_3D(const internals::PointLatLng &coord, const int &altitude)
MapPointItem::DistanceToPoint_3D Calculates distance from this point to second point.
axis equal end function NED
Definition: OPPlots.m:63
for i
Definition: OPPlots.m:140
double Lng() const
Definition: pointlatlng.h:76
double Lat() const
Definition: pointlatlng.h:64
void UAVReachedWayPoint(int const &waypointnumber, WayPointItem *waypoint)
double DistanceToPoint_2D(const internals::PointLatLng &coord)
MapPointItem::DistanceToPoint_2D Calculates distance from this point to second point.
void UAVLeftSafetyBouble(internals::PointLatLng const &position)
void SetRotate(qreal const &value)
A graphicsItem representing a WayPoint.
static double DistanceBetweenLatLng(PointLatLng const &p1, PointLatLng const &p2)
PureProjection::DistanceBetweenLatLng Returns 2D distance between two geodetic points.
void SetCurrentPosition(internals::PointLatLng const &value)
Definition: tlmapwidget.h:225
qint64 Y() const
Definition: point.h:52
e
Definition: OPPlots.m:99
void setOpacitySlot(qreal opacity)
Definition: uavitem.cpp:380