📄 maps.cpp
字号:
/*
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 <dirent.h>
#include <sys/stat.h>
#include "qpegps.h"
#include "mapdisp.h"
#include "track.h"
#include "convert.h"
const double PI_1_2 = M_PI / 2.0;
const double PI_1_4 = M_PI / 4.0;
const double PI_3_4 = M_PI * 0.75;
// ----- NON-MEMBER FUNCTIONS -----
inline double checkLg(double lon)
{
if ( lon > M_PI ) {
lon -= 2 * M_PI;
} else if ( lon < -M_PI ) {
lon += 2 * M_PI;
}
return lon;
}
MapSelector * MapBase::mapSelector = NULL;
// ----- METHODS ------
MapBase::MapBase(QString &, const QString &subdir)
{
// read map info
// mapIStream = new QTextIStream(&mapInfo);
// *mapIStream >> mapName >> scale >> mapSizeX >> mapSizeY;
mapDir = subdir;
}
MapBase::MapBase()
{
}
MapBase::~MapBase()
{
}
int MapBase::operator<(MapBase & map)
{
return (scale < map.scale);
}
int MapBase::operator==(MapBase & map)
{
return (scale == map.scale);
}
int MapBase::operator>(MapBase & map)
{
return (scale > map.scale);
}
bool MapBase::isInside(const Position & pos)
{
//qDebug("Latitude %f < %f < %f = %d", limitSouthEast.lat, pos.lat, limitNorthWest.lat, pos.lat>=limitSouthEast.lat && pos.lat<=limitNorthWest.lat);
//qDebug("Longitude %f < %f < %f = %d", limitSouthEast.lon, pos.lon, limitNorthWest.lon, pos.lon <= limitSouthEast.lon && pos.lon >= limitNorthWest.lon);
return (pos.lat>=limitSouthEast.lat && pos.lat<=limitNorthWest.lat &&
pos.lon <= limitSouthEast.lon && pos.lon >= limitNorthWest.lon);
}
QString MapBase::name( void )
{
QString fullname = mapDir + mapName;
return( fullname );
}
MapBase *MapBase::newMap(QString &mapType, QString &mapInfo, const QString &subdir)
{
MapBase *map;
if(mapType == "LAMBERT")
map = new MapLambert(mapInfo, subdir);
else if(mapType == "CEA")
map = new MapCEA(mapInfo, subdir);
else if(mapType == "MERCATOR")
map = new MapMercator(mapInfo, subdir);
else if(mapType == "TM")
map = new MapUTM(mapInfo,FALSE, subdir);
else if(mapType == "UTM")
map = new MapUTM(mapInfo,TRUE, subdir);
else if(mapType == "LINEAR")
map = new MapLin(mapInfo, subdir);
else if(mapType == "FRITZ")
map = new MapFritz(mapInfo, subdir);
else if(mapType == "TILED")
map = new MapTiled(mapInfo, subdir);
else
map = NULL;
return map;
}
MapSelector::MapSelector(Qpegps *app/*, QString *mapPath*/)
{
application = app;
// mapPathStr = mapPath;
maps.setAutoDelete(TRUE);
actMapList.setAutoDelete(FALSE);
actMap = NULL;
selectedScale = 0;
currentMapImg = new QImage;
MapBase::mapSelector = this;
timer = new QTimer(this);
connect( timer, SIGNAL(timeout()),
SLOT(updateMapsLoaded()) );
// check for non used image maps every 500 ms
timer->start(500, false);
}
MapSelector::~MapSelector()
{
delete currentMapImg;
}
void MapSelector::reReadMaps()
{
application->wait(true, "Please wait: reading maps...");
clearMaps();
readMaps();
emit mapsChanged();
application->wait(false);
}
void MapSelector::readMaps( const QString &subdir )
{
QString filename(mapPathStr());
/* if( newSubdir != "" ) {
newSubdir += "/";
}*/
filename.append( "/" + subdir + "maps.txt");
QFile mapFile(filename);
if ( mapFile.open(IO_ReadOnly) ) {
application->wait(true, "Please wait: reading maps from " + filename);
QTextStream t( &mapFile );
QString pro;
QString mapInfo;
MapBase *map;
const QStringList& list = QStringList::split('\n', t.read());
mapFile.close();
QStringList::ConstIterator it;
for(it=list.begin(); it!=list.end(); ++it) {
const QString& s = *it;
int sp = s.find(' ');
pro = s.left(sp);
mapInfo = s.right(s.length()-sp-1);
map = MapBase::newMap(pro, mapInfo, subdir);
// add the map
if (map)
maps.append(map);
}
maps.sort();
} else if( subdir == "" ) {
QFileInfo mfi(filename);
QMessageBox::critical( 0, "qpeGPS",
tr( "couldn't open \n%1\n"
"If file does not exist it will be created.\n"
"File info:\n"
"exists = %2\n"
"is readable = %3\n"
"is a file = %4\n"
"is a directory = %5\n"
"is a symbolic link = %6\n"
"owner = %7")
.arg(filename).arg(mfi.exists())
.arg(mfi.isReadable()).arg(mfi.isFile())
.arg(mfi.isDir()).arg(mfi.isSymLink()).arg(mfi.owner()));
if ( !mfi.exists() ) {
mapFile.open(IO_ReadWrite);
mapFile.close();
chmod((const char*)filename,0777);
}
}
/* Now open any subfolders and search for their "maps.txt"
entries and add those maps as well */
if (mapOptions.searchMapsInSubdirs) {
#ifdef __arm__
// this approach is faster than using QDir
DIR *d;
struct dirent *de;
QString newDir = "";
if( (d = ::opendir(mapPathStr() + "/" + subdir)) == NULL ) {
application->wait(false);
return;
}
while( (de = readdir( d )) != NULL ) {
if (de->d_type == DT_DIR &&
strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..")) {
newDir = subdir + de->d_name;
readMaps( newDir + "/" );
}
}
closedir( d);
#else
QDir d( mapPathStr() + "/" + subdir );
d.setFilter( QDir::Dirs );
// d.setSorting( QDir::Size | QDir::Reversed );
const QFileInfoList *list = d.entryInfoList();
QFileInfoListIterator it( *list ); // create list iterator
QFileInfo *fi; // pointer for traversing
QString newDir = "";
// printf( " BYTES FILENAME\n" ); // print header
while ( (fi=it.current()) ) { // for each file...
if( ( fi->fileName() != "." ) && ( fi->fileName() != ".." ) ) {
newDir = subdir + fi->fileName();
readMaps( newDir + "/" );
}
++it; // goto next list element
}
#endif
}
application->wait(false);
}
void MapSelector::writeMapFile()
{
QString filename = mapPathStr();
filename.append("/");
filename.append("/maps.txt");
QFile mapFile(filename);
mapFile.open(IO_WriteOnly);
QTextStream t(&mapFile);
MapBase *aMap;
for (aMap = maps.first (); aMap != 0; aMap = maps.next())
{
if( aMap->mapDir == "" ) /* Try to only save when the maps is recorded not in a sub folder */
t << aMap->getParameterStr() << "\n";
}
mapFile.close();
// re-read maps for initialiting structs
reReadMaps();
}
void MapSelector::clearMaps()
{
actMapList.clear();
clearMapsLoaded();
// clear previous map list
maps.setAutoDelete(TRUE);
maps.clear(); // FIXME => critical for mapInfo ...
}
void MapSelector::chooseLessDetailedMap()
{
MapBase *aMap;
if(actMap) {
if(actMap->scale < actMapList.last()->scale)
{
// if no scale selected
if (selectedScale == 0)
// start with the current (most detail) to search a lower detail
selectedScale = actMap->scale;
aMap=actMapList.first();
while(aMap && (aMap->scale < /*actmap->scale*/selectedScale*1.1))
{
aMap = actMapList.next();
}
if(aMap)
selectedScale = aMap->scale;
else
selectedScale = actMap->scale;
}
else
selectedScale = actMap->scale;
}
}
void MapSelector::chooseMoreDetailedMap()
{
MapBase *aMap;
if(actMap && actMap->scale > actMapList.first()->scale) {
aMap = actMapList.last();
while(aMap && (aMap->scale > /*actmap->scale*/selectedScale*0.9))
aMap = actMapList.prev();
if(aMap)
selectedScale = aMap->scale;
}
else
selectedScale = 0;
}
void MapSelector::showAvailableMaps()
{
MapBase *aMap;
qDebug(tr("Maps at current position:"));
aMap = actMapList.first();
while(aMap) {
qDebug(tr("%1 %2").arg(aMap->scale).arg(aMap->name()));
aMap = actMapList.next();
}
}
void MapSelector::clearMapsLoaded()
{
QMap<MapImage *,int>::Iterator it;
for( it = mapsLoaded.begin(); it != mapsLoaded.end(); ++it ){
it.key()->unload();
}
mapsLoaded.clear();
}
bool MapSelector::searchMap(const Position & pos/*, int maxMaps*/)
{
MapBase *aMap;
int numberOfChecks;
bool mapAdded = false;
// find map
// and get position in map coordinates
// check if the actual maps are still valid
aMap = actMapList.first();
while(aMap)
{
if(!aMap->isInside(pos))
{
actMapList.take();
aMap = actMapList.current(); //next item
}
else
aMap = actMapList.next();
}
// search all the list until it found a map
numberOfChecks = maps.count();
/* if(numberOfChecks > maxMaps)
numberOfChecks = maxMaps;
else if(numberOfChecks < 1)
// less than 10 -> check all
numberOfChecks = maps.count();*/
aMap = maps.current();
while(numberOfChecks)
{
if(aMap && aMap->isInside(pos) && !actMapList.containsRef(aMap) )
{
actMapList.append(aMap);
mapAdded = true;
}
if(aMap)
aMap = maps.next();
if(!aMap)
aMap = maps.first();
numberOfChecks--;
}
if (mapAdded)
// order the list
actMapList.sort();
if(actMapList.isEmpty())
return FALSE;
else
return TRUE;
}
void MapSelector::selectMap(const Position & pos, QRect rect)
{
MapBase *aMap, *theMap;
double xc, yc, scale, cover, tcover;
// get Map with best scale + coverage
// list is still sorted by scale
// scroll to the map, with appropriate scale
aMap = actMapList.first();
scale = aMap->scale;
while(aMap && (aMap->scale < 0.9*selectedScale))
{
aMap = actMapList.next();
};
// all maps have a lower scale => take map with highest scale
if(!aMap)
aMap = actMapList.last();
theMap = aMap;
scale = aMap->scale;
// get map with best coverage with approx. the same scale
aMap->calcxy(&xc, &yc, pos);
cover = aMap->coverage(xc, yc, rect.width(),rect.height());
aMap = actMapList.next();
while( aMap && (cover < -1) && (1.9 * scale > aMap->scale))
{
aMap->calcxy(&xc, &yc, pos);
tcover = aMap->coverage(xc, yc, rect.width(),rect.height());
if(tcover > cover)
{
theMap=aMap;
cover = tcover;
}
aMap = actMapList.next();
}
if(theMap != actMap){
// replace the current map
actMap = theMap;
}
}
bool MapSelector::loadMapImage( MapImage *map )
{
// check if it is loaded
if (mapsLoaded.contains(map)) {
// already loaded, restart counter
mapsLoaded[map] = 20; // 10 seconds
return true;
}
// load the map
if (map->load()) {
// add tracks
if (application->viewTrack)
map->addTrack(application->viewTrack,
application->viewTrack->trackOptions.trackColor,
application->viewTrack->trackOptions.track_thick);
// all ok, add the map to the loaded map list
mapsLoaded[map] = 20; // 10 seconds
return true;
}
return false;
}
void MapSelector::drawMap(QPixmap *viewer, const Position & pos)
{
if (searchMap(pos)) {
selectMap(pos, viewer->rect());
// draw the map
actMap->draw(viewer, pos);
}
else {
actMap = NULL;
}
}
double MapBase::coverage(double x, double y, int width, int height)
{
// determines the area on the display, which is not covered by the Map
// 0 = map fills the display
// <0 = -1 * pixels without map
double tmp = mapSizeX - x;
double coverX = ( x > tmp ) ? tmp : x;
tmp = mapSizeY - y;
double coverY = ( y > tmp ) ? tmp : y;
coverX -= width / 2;
coverY -= height / 2;
coverX = ( coverX > 0 ) ? 0 : coverX * height;
coverY = ( coverY > 0 ) ? 0 : coverY * width;
return coverX + coverY;
}
void MapSelector::updateMapsLoaded()
{
QMap<MapImage *,int>::Iterator it;
MapImage *deleteMap = NULL;
for( it = mapsLoaded.begin(); it != mapsLoaded.end(); ++it ){
if (deleteMap != NULL) {
mapsLoaded.remove(deleteMap);
deleteMap = NULL;
}
int counter = it.data() -1;
if (counter) {
// update value
mapsLoaded[it.key()] = counter;
}
else {
deleteMap = it.key();
deleteMap->unload();
}
}
if (deleteMap != NULL)
mapsLoaded.remove(deleteMap);
}
MapBase *MapSelector::find( QString &mapName )
{
MapBase *map;
for (map = maps.first(); map != 0; map = maps.next()) {
if (map->name() == mapName)
return map;
}
// not found
return NULL;
}
void MapSelector::delMap( MapBase *delmap )
{
if (actMapList.find(delmap))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -