#include "gps.h"
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <termios.h>
#include <time.h>
// Defining instances
GPS *Gps;
list_of<highlight> highlightlist;
void Mapwindow::mousePressEvent(QMouseEvent *mep){
// Mouse clicked somewhere. Get the coords ...
// If a map is showing, move within it
if(mymapinfo){
// Position to this location, using mostly the positioning logic
Position pos(mappos.latit - (mep->pos().y()-height()/2)/mymapinfo->pixperdegheight,
mappos.longit + (mep->pos().x()-width()/2)/mymapinfo->pixperdegwidth);
positionto(pos);
updateGPSpos(pos);
}else{
// This probably highly bogus - need to think through what it
// means if we have no visible map
picoffset.setX(picoffset.x()+mep->pos().x()-width()/2);
picoffset.setY(picoffset.y()+mep->pos().y()-height()/2);
update();
}
}
void Mapwindow::load(const char *cp){
if(currentmapname != cp){
if(mymap.load(cp)){
if(verbose) printf("Just loaded map %s\n", cp);
currentmapname = cp;
}else{
if(verbose) printf("No map loaded\n", cp);
currentmapname = String::NULLSTRING;
}
}
}
// Return a heading in degrees, given x/y lengths travelled
double Mapwindow::yxheading(double northdiff, double eastdiff){
double heading;
if(fabs(eastdiff) < 1e-9)
heading = northdiff >= 0 ? 0 : 180;
else{
heading = (atan2(eastdiff,northdiff)/deg2rad+0.5);
if(heading < 0) heading = 360+heading;
}
return heading;
}
// Given Lat/Long & time differences, maintain a smoothed velocity (speed/heading)
int Mapwindow::plotspeed(const Position &cpr, double utctime){
// approximation to speed over ground. Uses rough-and-ready
// adjustment for longitude based on cos of current latitude
// which seems to work OK in the UK
double milesperNdegree;
double milesperEdegree;
// How many metres is one degree of latitude (should be the same over
// whole globe near enough, so pick one that works in the OSGB range)
capm(49, 50, &milesperNdegree);
const double coslat = cos(cpr.latit*deg2rad);
milesperNdegree *= metres2miles;
milesperEdegree = milesperNdegree*coslat;
// printf("plotspeed, utctime %f\n", utctime);
if(!firstplot){
double tdiff = utctime-lastplottime;
if(tdiff == 0)
return 0;
if(tdiff < 0) tdiff += 24L*60*60;
double latdiffrate = (cpr.latit-lastplotpos.latit)/tdiff;
double longdiffrate = (cpr.longit-lastplotpos.longit)/tdiff;
double heading = 0;
// printf("In plotspeed, time difference is %f, latdiffrate %f, longdiffrate %f\n", tdiff, latdiffrate, longdiffrate);
for(int i = 0; i < npoles; i++){
xvfilter[i] += fconst * (latdiffrate-xvfilter[i]);
latdiffrate = xvfilter[i];
yvfilter[i] += fconst * (longdiffrate-yvfilter[i]);
longdiffrate = yvfilter[i];
if(!finite(latdiffrate) || !finite(longdiffrate)){
printf("Gone non-finite!\n");
exit(0);
}
}
heading = yxheading(latdiffrate, longdiffrate*coslat);
double ymps = latdiffrate * milesperNdegree;
double xmps = longdiffrate * milesperEdegree;
double mps = sqrt(ymps*ymps + xmps*xmps);
int mph = int(mps*60*60 + 0.5);
// printf("Smoothed: latdiffrate %f, longdiffrate %f, heading %f, speed %d\n", latdiffrate, longdiffrate, heading, mph);
String s;
s.sprintf("%d MPH", mph);
Gps->speed->setText(s.cstring());
s.sprintf("%.0f deg", heading);
Gps->hdng->setText(s.cstring());
}
lastplotpos = cpr;
lastplottime = utctime;
firstplot = false;
return 0;
}
void Mapwindow::updateGPSpos(const Position &cpr){
Gps->mymousey->setText(dmsLat(cpr.latit).cstring());
Gps->mymousex->setText(dmsLong(cpr.longit).cstring());
String oslocation;
double e, n;
if(mymapinfo->osproj && cvtongr(cpr.latit, cpr.longit, oslocation, e, n)){
Gps->altpos->setText(oslocation.cstring());
Gps->altpos->show();
}else{
Gps->altpos->setText("");
Gps->altpos->hide();
}
}
void Mapwindow::mouseMoveEvent(QMouseEvent *mev){
QPoint p = mev->pos();
char buff[512];
// If no map showing, just show x,y else show lat/long
if(mymapinfo == 0){
p.setX(p.x()+picoffset.x()-width()/2);
p.setY(p.y()+picoffset.y()-height()/2);
sprintf(buff, "x%d", p.x());
Gps->mymousex->setText(buff);
sprintf(buff, "y%d", p.y());
Gps->mymousey->setText(buff);
}else{
Position pos(
mappos.latit - (p.y()-height()/2)/mymapinfo->pixperdegheight,
mappos.longit + (p.x()-width()/2)/mymapinfo->pixperdegwidth
);
updateGPSpos(pos);
// DEBUGGING
// double e, n; // current east & north
// String dummy;
// if(cvtongr(latit, longit, dummy, e, n)){
// printf("Mousemove for lat %f long %f gives %s\n", latit, longit, dummy.cstring());
// }
}
}
void Mapwindow::drawoffsetmap(){
int xoffset = -picoffset.x() + width()/2;
int yoffset = -picoffset.y() + height()/2;
bitBlt(this, xoffset, yoffset, &mymap);
}
void Mapwindow::paintEvent(QPaintEvent *){
// If we haven't got a real map visible, don't draw it
if(mymapinfo != &mydummymapinfo){
// Put the map at the right place
drawoffsetmap();
}
QPainter qp(this);
QPen wblackpen(black, 3);
QPen nblackpen(black, 1);
//qp.begin(this);
// Draw the crosshairs
qp.setPen(wblackpen);
const midx = width()/2;
const midy = height()/2;
const crosslen = max(width(), height()) / 10;
qp.drawLine(midx-crosslen*2, midy, midx-crosslen/3, midy);
qp.drawLine(midx+crosslen*2, midy, midx+crosslen/3, midy);
qp.drawLine(midx, midy-crosslen*2, midx, midy-crosslen/3);
qp.drawLine(midx, midy+crosslen*2, midx, midy+crosslen/3);
qp.setPen(nblackpen);
qp.drawLine(midx-crosslen*2, midy, midx+crosslen*2, midy);
qp.drawLine(midx, midy-crosslen*2, midx, midy+crosslen*2);
// Any highlights to show?
QPen redpen(red, 2);
qp.setPen(redpen);
qp.setRasterOp(NotXorROP);
qp.setBackgroundMode(OpaqueMode);
if(mymapinfo && llvalid){
double minlat, maxlat, minlong, maxlong;
minlat = mappos.latit - height()/2/mymapinfo->pixperdegheight;
maxlat = mappos.latit + height()/2/mymapinfo->pixperdegheight;
minlong = mappos.longit - width()/2/mymapinfo->pixperdegwidth;
maxlong = mappos.longit + width()/2/mymapinfo->pixperdegwidth;
// printf("minlong %s maxlong %s minlat %s maxlat %s\n", dmsLong(minlong).cstring(), dmsLong(maxlong).cstring(), dmsLat(minlat).cstring(), dmsLat(maxlat).cstring());
// Scan the list of highlights for those positioned on the current map
for(int i = 0; i < highlightlist.element_count(); i++){
const highlight &chp = highlightlist[i];
if(chp.pos.latit > minlat && chp.pos.latit < maxlat && chp.pos.longit > minlong &&
chp.pos.longit < maxlong){
QPoint centre = mappixel_to_displaypixels(pos_to_mappixels(chp.pos));
const esize = 8; // should be divisble by 2
qp.drawEllipse(centre.x()-esize/2, centre.y()-esize/2, esize, esize);
qp.drawText(centre.x()+esize/2+2, centre.y()+esize/2, chp.description.cstring(), chp.description.nchars());
if(verbose)printf("Found highlight in range, name %s, x %d y %d\n", chp.description.cstring(), centre.x(), centre.y());
}
}
}
// Redraw the track, ensuring that lasttrackpoint is correctly set
QPen bluepen(blue, 2);
qp.setPen(bluepen);
for(int i = 0; i < track.element_count(); i++){
QPoint thismappoint = pos_to_mappixels(track[i]);
if(i > 0){
qp.drawLine(mappixel_to_displaypixels(lasttrackpoint), mappixel_to_displaypixels(thismappoint));
}
lasttrackpoint = thismappoint;
}
qp.setRasterOp(CopyROP);
drawFrame(&qp);
qp.end();
}
Mapwindow::Mapwindow(GPS *gpsp): QFrame(gpsp), myGpsp(gpsp), picoffset(0,0), llvalid(false), mymapinfo(0), usemapscale(1e6){
setCursor(crossCursor);
setMouseTracking(true);
cleartrack();
firstplot = true;
}
void Mapwindow::cleartrack(){
track.clear();
for(int i = 0; i < npoles; i++){
xvfilter[i] = yvfilter[i] = 0;
}
}
void Mapwindow::trackto(double latit, double longit, double utctime, int offcentrerange){
// printf("Trackto %f %f\n", latit, longit);
if(track.element_count() >= maxtrack){
// Too big. Throw away first item
track.delete_this_element(0)