1
0
mirror of git://projects.qi-hardware.com/nanomap.git synced 2025-01-23 17:41:05 +02:00
nanomap/monav/gpsgrid/gpsgridclient.cpp
Niels f1a2430393 Revert "first try to fix building with OpenWRT toolchain that does not include QtCore and QtGui in the include path"
This reverts commit da88ec21cdbda458d04368292008126c3ebe5715.

This was not the right solution
2010-11-17 22:05:12 +01:00

291 lines
9.1 KiB
C++

/*
Copyright 2010 Christian Vetter veaac.fdirct@gmail.com
This file is part of MoNav.
MoNav 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.
MoNav 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 MoNav. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gpsgridclient.h"
#include <QtDebug>
#include <QHash>
#include <algorithm>
#include "utils/qthelpers.h"
#ifndef NOGUI
#include <QInputDialog>
#endif
#include <QSettings>
GPSGridClient::GPSGridClient()
{
index = NULL;
gridFile = NULL;
QSettings settings( "MoNavClient" );
settings.beginGroup( "GPS Grid" );
cacheSize = settings.value( "cacheSize", 1 ).toInt();
cache.setMaxCost( 1024 * 1024 * 3 * cacheSize / 4 );
}
GPSGridClient::~GPSGridClient()
{
QSettings settings( "MoNavClient" );
settings.beginGroup( "GPS Grid" );
settings.setValue( "cacheSize", cacheSize );
unload();
}
void GPSGridClient::unload()
{
if ( index != NULL )
delete index;
index = NULL;
if ( gridFile != NULL )
delete gridFile;
gridFile = NULL;
cache.clear();
}
QString GPSGridClient::GetName()
{
return "GPS Grid";
}
void GPSGridClient::SetInputDirectory( const QString& dir )
{
directory = dir;
}
void GPSGridClient::ShowSettings()
{
#ifndef NOGUI
bool ok = false;
int result = QInputDialog::getInt( NULL, "Settings", "Enter Cache Size [MB]", cacheSize, 1, 1024, 1, &ok );
if ( !ok )
return;
cacheSize = result;
if ( index != NULL )
index->SetCacheSize( 1024 * 1024 * cacheSize / 4 );
cache.setMaxCost( 1024 * 1024 * 3 * cacheSize / 4 );
#endif
}
bool GPSGridClient::LoadData()
{
unload();
QString filename = fileInDirectory( directory, "GPSGrid" );
QFile configFile( filename + "_config" );
if ( !openQFile( &configFile, QIODevice::ReadOnly ) )
return false;
index = new gg::Index( filename + "_index" );
index->SetCacheSize( 1024 * 1024 * cacheSize / 4 );
gridFile = new QFile( filename + "_grid" );
if ( !gridFile->open( QIODevice::ReadOnly ) ) {
qCritical() << "failed to open file: " << gridFile->fileName();
return false;
}
return true;
}
bool GPSGridClient::GetNearestEdge( Result* result, const UnsignedCoordinate& coordinate, double radius, bool headingPenalty, double heading )
{
const GPSCoordinate gps = coordinate.ToProjectedCoordinate().ToGPSCoordinate();
const GPSCoordinate gpsMoved( gps.latitude, gps.longitude + 1 );
const double meter = gps.ApproximateDistance( gpsMoved );
double gridRadius = (( double ) UnsignedCoordinate( ProjectedCoordinate( gpsMoved ) ).x - coordinate.x ) / meter * radius;
gridRadius *= gridRadius;
heading = fmod( ( heading + 270 ) * 2.0 * M_PI / 360.0, 2 * M_PI );
static const int width = 32 * 32 * 32;
ProjectedCoordinate position = coordinate.ToProjectedCoordinate();
NodeID yGrid = floor( position.y * width );
NodeID xGrid = floor( position.x * width );
result->distance = gridRadius;
QVector< UnsignedCoordinate > path;
checkCell( result, &path, xGrid - 1, yGrid - 1, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid - 1, yGrid, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid - 1, yGrid + 1, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid, yGrid - 1, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid, yGrid, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid, yGrid + 1, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid + 1, yGrid - 1, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid + 1, yGrid, coordinate, heading, headingPenalty );
checkCell( result, &path, xGrid + 1, yGrid + 1, coordinate, heading, headingPenalty );
if ( path.empty() )
return false;
double length = 0;
double lengthToNearest = 0;
for ( int pathID = 1; pathID < path.size(); pathID++ ) {
UnsignedCoordinate sourceCoord = path[pathID - 1];
UnsignedCoordinate targetCoord = path[pathID];
double xDiff = ( double ) sourceCoord.x - targetCoord.x;
double yDiff = ( double ) sourceCoord.y - targetCoord.y;
double distance = sqrt( xDiff * xDiff + yDiff * yDiff );
length += distance;
if ( pathID < ( int ) result->previousWayCoordinates )
lengthToNearest += distance;
else if ( pathID == ( int ) result->previousWayCoordinates )
lengthToNearest += result->percentage * distance;
}
if ( length == 0 )
result->percentage = 0;
else
result->percentage = lengthToNearest / length;
return true;
}
bool GPSGridClient::checkCell( Result* result, QVector< UnsignedCoordinate >* path, NodeID gridX, NodeID gridY, const UnsignedCoordinate& coordinate, double heading, double headingPenalty ) {
static const int width = 32 * 32 * 32;
ProjectedCoordinate minPos( ( double ) gridX / width, ( double ) gridY / width );
ProjectedCoordinate maxPos( ( double ) ( gridX + 1 ) / width, ( double ) ( gridY + 1 ) / width );
UnsignedCoordinate min( minPos );
UnsignedCoordinate max( maxPos );
if ( distance( min, max, coordinate ) >= result->distance )
return false;
qint64 cellNumber = ( qint64( gridX ) << 32 ) + gridY;
if ( !cache.contains( cellNumber ) ) {
qint64 position = index->GetIndex( gridX, gridY );
if ( position == -1 )
return true;
gridFile->seek( position );
int size;
gridFile->read( (char* ) &size, sizeof( size ) );
unsigned char* buffer = new unsigned char[size + 8]; // reading buffer + 4 bytes
gridFile->read( ( char* ) buffer, size );
gg::Cell* cell = new gg::Cell();
cell->read( buffer, min, max );
cache.insert( cellNumber, cell, cell->edges.size() * sizeof( gg::Cell::Edge ) );
delete[] buffer;
}
gg::Cell* cell = cache.object( cellNumber );
if ( cell == NULL )
return true;
UnsignedCoordinate nearestPoint;
for ( std::vector< gg::Cell::Edge >::const_iterator i = cell->edges.begin(), e = cell->edges.end(); i != e; ++i ) {
bool found = false;
for ( int pathID = 1; pathID < i->pathLength; pathID++ ) {
UnsignedCoordinate sourceCoord = cell->coordinates[pathID + i->pathID - 1];
UnsignedCoordinate targetCoord = cell->coordinates[pathID + i->pathID];
double percentage = 0;
double d = distance( &nearestPoint, &percentage, sourceCoord, targetCoord, coordinate );
if ( d + headingPenalty > result->distance )
continue;
double xDiff = ( double ) targetCoord.x - sourceCoord.x;
double yDiff = ( double ) targetCoord.y - sourceCoord.y;
double direction = 0;
if ( xDiff != 0 || yDiff != 0 )
direction = fmod( atan2( yDiff, xDiff ), 2 * M_PI );
else
headingPenalty = 0;
double penalty = fabs( direction - heading );
if ( penalty > M_PI )
penalty = 2 * M_PI - penalty;
if ( i->bidirectional && penalty > M_PI / 2 )
penalty = M_PI - penalty;
penalty = penalty / M_PI * headingPenalty;
d += penalty;
if ( d < result->distance ) {
result->nearestPoint = nearestPoint;
result->distance = d;
result->previousWayCoordinates = pathID;
result->percentage = percentage;
found = true;
}
}
if ( found ) {
result->source = i->source;
result->target = i->target;
result->edgeID = i->edgeID;
path->clear();
for ( int pathID = 0; pathID < i->pathLength; pathID++ )
path->push_back( cell->coordinates[pathID + i->pathID] );
}
}
return true;
}
double GPSGridClient::distance( UnsignedCoordinate* nearestPoint, double* percentage, const UnsignedCoordinate source, const UnsignedCoordinate target, const UnsignedCoordinate& coordinate ) {
const double vY = ( double ) target.y - source.y;
const double vX = ( double ) target.x - source.x;
const double wY = ( double ) coordinate.y - source.y;
const double wX = ( double ) coordinate.x - source.x;
const double vLengthSquared = vY * vY + vX * vX;
double r = 0;
if ( vLengthSquared != 0 )
r = ( vX * wX + vY * wY ) / vLengthSquared;
*percentage = r;
if ( r <= 0 ) {
*nearestPoint = source;
*percentage = 0;
return wY * wY + wX * wX;
} else if ( r >= 1 ) {
*nearestPoint = target;
*percentage = 1;
const double dY = ( double ) coordinate.y - target.y;
const double dX = ( double ) coordinate.x - target.x;
return dY * dY + dX * dX;
}
nearestPoint->x = source.x + r * vX;
nearestPoint->y = source.y + r * vY;
const double dX = ( double ) nearestPoint->x - coordinate.x;
const double dY = ( double ) nearestPoint->y - coordinate.y;
return dY * dY + dX * dX;
}
double GPSGridClient::distance( const UnsignedCoordinate& min, const UnsignedCoordinate& max, const UnsignedCoordinate& coordinate ) {
UnsignedCoordinate nearest = coordinate;
if ( coordinate.x <= min.x )
nearest.x = min.x;
else if ( coordinate.x >= max.x )
nearest.x = max.x;
if ( coordinate.y <= min.y )
nearest.y = min.y;
else if ( coordinate.y >= max.y )
nearest.y = max.y;
double xDiff = ( double ) coordinate.x - nearest.x;
double yDiff = ( double ) coordinate.y - nearest.y;
return xDiff * xDiff + yDiff * yDiff;
}
Q_EXPORT_PLUGIN2(gpsgridclient, GPSGridClient)