23 #include <QDataStream>
24 #include <QStringList>
29 #include <QSqlDatabase>
37 class PlacemarkSmallerDistance
40 PlacemarkSmallerDistance(
const GeoDataCoordinates ¤tPosition ) :
44 bool operator()(
const OsmPlacemark &a,
const OsmPlacemark &b )
const
56 class PlacemarkHigherScore
59 PlacemarkHigherScore(
const DatabaseQuery *currentQuery ) :
63 bool operator()(
const OsmPlacemark &a,
const OsmPlacemark &b )
const
75 m_databaseFiles( databaseFiles )
81 if ( m_databaseFiles.isEmpty() ) {
82 return QVector<OsmPlacemark>();
85 QSqlDatabase database = QSqlDatabase::addDatabase(
"QSQLITE", QString(
"marble/local-osm-search-%1" ).arg( reinterpret_cast<size_t>(
this ) ) );
87 QVector<OsmPlacemark> result;
90 foreach(
const QString &databaseFile, m_databaseFiles ) {
91 database.setDatabaseName( databaseFile );
92 if ( !database.open() ) {
93 qWarning() <<
"Failed to connect to database" << databaseFile;
96 QString regionRestriction;
97 if ( !userQuery.
region().isEmpty() ) {
101 const QString regionsQueryString =
"SELECT lft, rgt FROM regions WHERE name LIKE '%" + userQuery.
region() +
"%';";
102 QSqlQuery regionsQuery( regionsQueryString, database );
103 if ( regionsQuery.lastError().isValid() ) {
104 qWarning() << regionsQuery.lastError() <<
"in" << databaseFile <<
"with query" << regionsQuery.lastQuery();
106 regionRestriction =
" AND (";
108 while ( regionsQuery.next() ) {
109 if ( regionCount > 0 ) {
110 regionRestriction +=
" OR ";
112 regionRestriction +=
" (regions.lft >= " + regionsQuery.value( 0 ).toString();
113 regionRestriction +=
" AND regions.lft <= " + regionsQuery.value( 1 ).toString() +
')';
116 regionRestriction +=
')';
118 mDebug() << Q_FUNC_INFO <<
"region query in" << databaseFile <<
"with query" << regionsQueryString
119 <<
"took" << regionTimer.elapsed() <<
"ms for" << regionCount <<
"results";
121 if ( regionCount == 0 ) {
128 queryString =
" SELECT regions.name,"
129 " places.name, places.number,"
130 " places.category, places.lon, places.lat"
131 " FROM regions, places";
134 queryString +=
" WHERE regions.id = places.region";
137 queryString +=
" AND places.category <> 0 AND places.category <> 6";
140 queryString +=
" AND places.category = %1";
141 queryString = queryString.arg( (qint32) userQuery.
category() );
145 queryString +=
" ORDER BY ((places.lat-%1)*(places.lat-%1)+(places.lon-%2)*(places.lon-%2))";
150 queryString += regionRestriction;
153 queryString +=
" WHERE regions.id = places.region"
154 " AND places.name " + wildcardQuery( userQuery.
searchTerm() );
156 queryString +=
" WHERE regions.id = places.region"
157 " AND places.name " + wildcardQuery( userQuery.
street() );
159 queryString +=
" AND places.number " + wildcardQuery( userQuery.
houseNumber() );
161 queryString +=
" AND places.number IS NULL";
163 queryString += regionRestriction;
166 queryString +=
" LIMIT 50;";
170 QSqlQuery query( database );
171 query.setForwardOnly(
true );
174 if ( !query.exec( queryString ) ) {
175 qWarning() << query.lastError() <<
"in" << databaseFile <<
"with query" << query.lastQuery();
180 while ( query.next() ) {
188 placemark.
setName( query.value(1).toString() );
194 result.push_back( placemark );
198 mDebug() << Q_FUNC_INFO <<
"query in" << databaseFile <<
"with query" << queryString
199 <<
"took" << queryTimer.elapsed() <<
"ms for" << resultCount <<
"results";
202 mDebug() <<
"Offline OSM search query took" << timer.elapsed() <<
"ms for" << result.count() <<
"results.";
204 qSort( result.begin(), result.end() );
208 const PlacemarkSmallerDistance placemarkSmallerDistance( userQuery.
position() );
209 qSort( result.begin(), result.end(), placemarkSmallerDistance );
211 const PlacemarkHigherScore placemarkHigherScore( &userQuery );
212 qSort( result.begin(), result.end(), placemarkHigherScore );
215 if ( result.size() > 50 ) {
216 result.remove( 50, result.size()-50 );
222 void OsmDatabase::unique( QVector<OsmPlacemark> &placemarks )
const
224 for (
int i=1; i<placemarks.size(); ++i ) {
225 if ( placemarks[i-1] == placemarks[i] ) {
226 placemarks.remove( i );
232 QString OsmDatabase::formatDistance(
const GeoDataCoordinates &a,
const GeoDataCoordinates &b )
const
237 QString distanceUnit = QLatin1String(
"m" );
245 if ( distance >= 1000 ) {
249 }
else if ( distance >= 200 ) {
250 distance = 50 * qRound( distance / 50 );
251 }
else if ( distance >= 100 ) {
252 distance = 25 * qRound( distance / 25 );
254 distance = 10 * qRound( distance / 10 );
258 QString
const fuzzyDistance = QString(
"%1 %2" ).arg( distance, 0,
'f', precision ).arg( distanceUnit );
262 QString heading = QObject::tr(
"north" );
263 if ( direction > 337 ) {
264 heading = QObject::tr(
"north" );
265 }
else if ( direction > 292 ) {
266 heading = QObject::tr(
"north-west" );
267 }
else if ( direction > 247 ) {
268 heading = QObject::tr(
"west" );
269 }
else if ( direction > 202 ) {
270 heading = QObject::tr(
"south-west" );
271 }
else if ( direction > 157 ) {
272 heading = QObject::tr(
"south" );
273 }
else if ( direction > 112 ) {
274 heading = QObject::tr(
"south-east" );
275 }
else if ( direction > 67 ) {
276 heading = QObject::tr(
"east" );
277 }
else if ( direction > 22 ) {
278 heading = QObject::tr(
"north-east" );
281 return fuzzyDistance +
' ' + heading;
284 qreal OsmDatabase::bearing(
const GeoDataCoordinates &a,
const GeoDataCoordinates &b )
const
286 qreal delta = b.longitude() - a.longitude();
287 qreal lat1 = a.latitude();
288 qreal lat2 = b.latitude();
289 return fmod( atan2( sin ( delta ) * cos ( lat2 ),
290 cos( lat1 ) * sin( lat2 ) - sin( lat1 ) * cos( lat2 ) * cos ( delta ) ), 2 *
M_PI );
293 QString OsmDatabase::wildcardQuery(
const QString &term )
const
295 QString result = term;
296 if ( term.contains(
'*' ) ) {
297 return " LIKE '" + result.replace(
'*',
'%' ) +
'\'';
299 return " = '" + result +
'\'';
A 3d point representation.
GeoDataCoordinates m_currentPosition
QVector< OsmPlacemark > find(const DatabaseQuery &userQuery)
Search the database for matching regions and placemarks.
This file contains the headers for MarbleModel.
void setAdditionalInformation(const QString &name)
A lightweight data structure to represent points of interest like addresses with support for serializ...
void setCategory(OsmCategory category)
ResultFormat resultFormat() const
qreal distanceSphere(qreal lon1, qreal lat1, qreal lon2, qreal lat2)
This method calculates the shortest distance between two points on a sphere.
qreal latitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
QueryType queryType() const
void setName(const QString &name)
QString searchTerm() const
OsmPlacemark::OsmCategory category() const
QString houseNumber() const
GeoDataCoordinates position() const
void setLatitude(qreal latitude)
const DatabaseQuery *const m_currentQuery
search which contains a poi category
precise search for an address
qreal longitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
static MarbleGlobal * getInstance()
void setLongitude(qreal longitude)
void setHouseNumber(const QString &houseNumber)
OsmDatabase(const QStringList &databaseFiles)
Parse result of a user's search term.
bool isValid() const
Returns.
display results with location information
QDebug mDebug()
a function to replace qDebug() in Marble library code