📄 mapdisp.cpp
字号:
/*
** $Id: mapdisp.h 236 2006-11-12 10:20:24Z ztep $
qpegps is a program for displaying a map centered at the current longitude/
latitude as read from a gps receiver.
Copyright (C) 2002 Ralf Haselmeier <Ralf.Haselmeier@gmx.de>
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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mapdisp.h"
#include <math.h>
#include <qdatetime.h>
#include <qpopupmenu.h>
#include "convert.h"
// ----- NON-MEMBER FUNCTIONS -----
double calcAngle(Position & dest, Position & src) // angle in degrees
{
double angle;
double cos_dlat = cos(deg2rad(dest.lat));
double sin_dlat = sin(deg2rad(dest.lat));
double cos_dlon = cos(deg2rad(dest.lon));
double sin_dlon = sin(deg2rad(dest.lon));
double cos_slat = cos(deg2rad(src.lat));
double sin_slat = sin(deg2rad(src.lat));
double cos_slon = cos(deg2rad(src.lon));
double sin_slon = sin(deg2rad(src.lon));
double a = acos(
cos_slat * (cos_dlat * square(cos_slon) + cos_dlat * square(sin_slon))
+ sin_dlat * sin_slat
) * 6378;
double b = acos(
square(cos_slat) * (cos_dlon * cos_slon + sin_dlon * sin_slon)
+ square(sin_slat)
) * 6378;
if ( (a != 0) || (b != 0) ) {
angle = rad2deg(acos(a / sqrt(square(a) + square(b))));
if ( dest.lon < src.lon ) {
angle += 180;
if ( dest.lat > src.lat ) {
angle = (360 + 180) - angle;
}
} else if ( dest.lat < src.lat ) {
angle = 180 - angle;
}
} else {
angle = 0;
}
return angle;
}
// ----- METHODS -----
MapDisp::MapDisp(Qpegps * app, MapSelector * maps, GpsData *gps,
QWidget * parent, const char *name, WFlags f)
: QWidget (parent, name, f | WRepaintNoErase),
app(app), gpsData(gps), places(app->places),
mapSelector(maps), centerX(0), centerY(0),
mapOrientation(0), accDist(0),
placesIt(*places), ManualWp(false),
ttwph(0), ttwpm(0), ttwps(0),
WriteTimeout(1200), FirstKey(true)
{
mapdisp = new QPixmap;
placesIt.toFirst();
// skip "none"
++placesIt;
mapDispOptions.textSize = 10;
placesOptions.placesTextSize = 10;
setBackgroundMode(NoBackground);
createMap();
timer = new QTimer(this);
connect( timer, SIGNAL(timeout()), this, SLOT(timerDone()) );
aniTimer = new QTimer( this );
connect( aniTimer, SIGNAL(timeout()),
this, SLOT(animateTrack()));
connect( this, SIGNAL(lessDetail()),
mapSelector, SLOT(chooseLessDetailedMap()) );
connect( this, SIGNAL(moreDetail()),
mapSelector, SLOT(chooseMoreDetailedMap()) );
connect( this, SIGNAL(debugMaps()),
mapSelector, SLOT(showAvailableMaps()) );
connect( this, SIGNAL(waypointsChanged()),
mapSelector, SLOT(clearMapsLoaded()) );
setFocusPolicy(QWidget::StrongFocus);
setFocus();
//WTconunter = 0;
WTTimer = time(NULL);
#ifndef DESKTOP
// enables Right click on hold.
QPEApplication::setStylusOperation (this, QPEApplication::RightOnHold);
#endif
inAnimation = false;
}
void MapDisp::createMap()
{
static QSize geoSize(0,0);
QPainter painter;
double xc, yc;
if ( FirstKey ){
emit mouseClick(this);
emit mouseClick(this);
FirstKey = false;
}
/* Debug only */
// gpsData->fix.position.lon = -4.744162;
// gpsData->fix.position.lat = 42.799525;
/* Debug only */
QSize newSize = geometry().size();
if (newSize != geoSize) {
mapdisp->resize(newSize);
geoSize = newSize;
}
if ( app->viewTrack && (time(NULL)-WTTimer) >= WriteTimeout ){
app->viewTrack->Write(app->viewTrack->wLog->currentText());
WTTimer=time(NULL);
}
if (!mapDispOptions.mode) {
currentPos.lat = gpsData->fix.position.lat;
currentPos.lon = gpsData->fix.position.lon;
currentAltitude.val = gpsData->fix.altitude.val;
}
if (mapDispOptions.rotateMap && !mapDispOptions.mode) {
if (gpsData->fix.speed.val > 0.7) {
mapOrientation = -gpsData->fix.heading.val;
}
int ns;
if (mapDispOptions.zoom2x)
ns = (int) (sqrt((newSize.width()*newSize.width()+newSize.height()*newSize.height()))/2);
else
ns = (int) sqrt(newSize.width()*newSize.width()+newSize.height()*newSize.height());
QPixmap pm(ns, ns);
// get the map
pm.fill();
mapSelector->drawMap(&pm, currentPos);
// zoom the map
QWMatrix m;
if (mapDispOptions.zoom2x)
m.scale(2, 2);
m.rotate(mapOrientation);
pm = pm.xForm(m);
int ix = (pm.width()-newSize.width())/2;
int iy = (pm.height()-newSize.height())/2;
bitBlt(mapdisp, 0, 0, &pm, ix, iy, newSize.width(), newSize.height());
}
else if (mapDispOptions.zoom2x) {
QPixmap pm((newSize.width()+1)/2, (newSize.height()+1)/2);
// get the map
pm.fill();
mapSelector->drawMap(&pm, currentPos);
// zoom the map
QWMatrix m;
m.scale(2, 2);
//m.rotate(0.01);
pm = pm.xForm(m);
bitBlt(mapdisp, 0, 0, &pm, 0, 0, newSize.width(), newSize.height());
}
else {
mapdisp->fill();
// get the map
mapSelector->drawMap(mapdisp, currentPos);
}
if ( mapSelector->isMap() ) {
mapSelector->currentMap()->calcxy(&xc, &yc, currentPos);
centerX=(int)rint(xc); /* Added by A. Karhov */
centerY=(int)rint(yc);
}
painter.begin(mapdisp);
QPen p=painter.pen();
p.setWidth(1);
statColor = ( gpsData->status ) ?
mapDispOptions.statusOkColor : mapDispOptions.statusNoFixColor;
p.setColor(statColor);
painter.setPen(p);
int xcenter = mapdisp->width()/2;
int ycenter = mapdisp->height()/2;
if( xcenter < ycenter )
lgth = xcenter/6;
else
lgth = ycenter/6;
if (placesOptions.showPlaces)
DrawPlaces(&painter);
if ( mapSelector->isMap() )
DrawScaleLine(&painter);
DrawStatus(&painter);
if ( !mapDispOptions.mode ){ // GPS mode
DrawCross(&painter);
if(mapDispOptions.showBearing)
DrawBearingLine(&painter);
if(mapDispOptions.showHeading)
DrawHeading(&painter);
}
painter.end();
}
void MapDisp::DrawStatus(QPainter *painter)
{
QRect rect = mapdisp->rect();
QFont f=painter->font();
f.setPointSize(mapDispOptions.textSize);
painter->setFont(f);
QPen p=painter->pen();
// p.setWidth(1);
p.setColor(statColor);
painter->setPen(p);
painter->drawText(rect, AlignVCenter | AlignLeft,
Position::string(currentPos.lat, Position::Lat));
painter->drawText(rect, AlignVCenter | AlignRight,
Position::string(currentPos.lon, Position::Lon));
if( gpsData->statusStr.length() > 0)
painter->drawText(rect, AlignVCenter | AlignHCenter, gpsData->statusStr);
else if ( mapDispOptions.mode )
{
painter->drawText(rect, AlignVCenter | AlignHCenter, "X");
if ( inAnimation ) {
int tx=aniTime/(60*60*1000);
int ty=(aniTime-tx*(60*60*1000))/60000;
int th=(aniTime-tx*(60*60*1000)-ty*60000)/1000;
painter->drawText(rect, AlignBottom | AlignHCenter,
tr("%1:%2:%3")
.arg(tx, 2)
.arg(ty, 2)
.arg(th, 2));
}
}
else
{
if ( mapSelector->scale() > 1 ) { // != 0
QString mapSelectString;
if ( mapSelector->canLessDetail() ) {
mapSelectString.append(tr("-/"));
} else {
mapSelectString.append(tr(" /"));
}
if ( mapSelector->canMoreDetail() ) {
mapSelectString.append(tr("+"));
} else {
mapSelectString.append(tr("D"));
}
//if(mapSelector->istMap()) // only for debugging, don't forget to remove this !!!!
//QTextOStream(&mapSelectString) << mapSelectString << mapSelector->currentMap()->scale << " " << selectedScale;
painter->drawText(rect, AlignTop | AlignLeft, mapSelectString);
}
Angle Bearing(gpsData->fix.bearing);
if ( ManualWp ) {
// if (gpsData->wpDistance.distUnit != Distance::None) dist.distUnit=gpsData->wpDistance.distUnit;
// else dist.distUnit=Distance::Km;
double latr = deg2rad(currentPos.lat);
double lonr = deg2rad(currentPos.lon);
double destlatr = deg2rad(dest.lat);
double destlonr = deg2rad(dest.lon);
wpDistance.val = acos(
cos(destlatr) * cos(destlonr) * cos(latr) * cos(lonr)
+ cos(destlatr) * sin(destlonr) * cos(latr) * sin(lonr)
+ sin(destlatr) * sin(latr)) * 6378;
wpDistance.val /= 1.852; // Conversion from km to GPS distance units (Nautical mile)
// FIXME: wrap Bearing with deg2rad (like others instances)?
Bearing.val = calcAngle(dest, currentPos);
}
painter->drawText( rect, AlignTop | AlignHCenter,
currentAltitude.toString(false) );
painter->drawText( rect, AlignBottom | AlignHCenter,
tr("%1 %2\n%3 %4 %5").arg(gpsData->fix.heading.toString())
.arg(gpsData->fix.speed.toString())
.arg(Bearing.toString())
.arg(wpDistance.toString())
.arg(timeToString()) );
}
}
void MapDisp::DrawCross(QPainter *painter)
{
int xcenter = mapdisp->width()/2;
int ycenter = mapdisp->height()/2;
//cross
QPen p= painter->pen();
p.setWidth(1);
painter->setPen(p);
painter->drawLine(xcenter, ycenter, xcenter, ycenter + lgth );
painter->drawLine(xcenter - lgth, ycenter , xcenter + lgth, ycenter );
p.setWidth(2);
painter->setPen(p);
painter->drawLine(xcenter, ycenter - lgth , xcenter, ycenter);
}
void MapDisp::DrawHeading(QPainter *painter)
{
// heading line
int xcenter = mapdisp->width()/2; /* Added by A. Karhov */
int ycenter = mapdisp->height()/2;
int tx, ty, tw,th;
double headingAngle = gpsData->fix.heading.val;
if (mapDispOptions.rotateMap)
headingAngle += mapOrientation;
tx = xcenter;
ty = ycenter;
tw = xcenter + (int)((double)(sin(deg2rad(headingAngle))
*(double)lgth*2.0));
th = ycenter - (int)((double)(cos(deg2rad(headingAngle))
*(double)lgth*2.0));
QPen p=painter->pen();
p.setColor(mapDispOptions.headColor);
p.setWidth(3);
painter->setPen(p);
painter->drawLine(tx,ty,tw,th);
#if 1
int tw1, th1, tw2, th2;
// draw arrow,
tw1 = xcenter + (int)((double)(sin(deg2rad(headingAngle+120))
*(double)lgth*1.0));
th1 = ycenter - (int)((double)(cos(deg2rad(headingAngle+120))
*(double)lgth*1.0));
tw2 = xcenter + (int)((double)(sin(deg2rad(headingAngle-120))
*(double)lgth*1.0));
th2 = ycenter - (int)((double)(cos(deg2rad(headingAngle-120))
*(double)lgth*1.0));
p.setWidth(2);
painter->setPen(p);
painter->drawLine(tx,ty,tw1,th1);
painter->drawLine(tx,ty,tw2,th2);
painter->drawLine(tw,th,tw1,th1);
painter->drawLine(tw,th,tw2,th2);
#endif
}
void MapDisp::DrawBearingLine(QPainter *painter)
{
double xwp=0,ywp=0;
int tx = 0, ty = 0;
int xcenter = mapdisp->width()/2;
int ycenter = mapdisp->height()/2;
int halflgth = lgth / 2;
if ( mapSelector->isMap() ) {
// current waypoint
Position wp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -