• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.12
  • kdeedu
  • marble
  • src
  • plugins
  • runner
  • local-osm-search
OsmDatabase.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2011 Dennis Nienhüser <earthwings@gentoo.org>
9 // Copyright 2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
10 //
11 
12 #include "OsmDatabase.h"
13 
14 #include "DatabaseQuery.h"
15 #include "GeoDataLatLonAltBox.h"
16 #include "MarbleDebug.h"
17 #include "MarbleMath.h"
18 #include "MarbleLocale.h"
19 #include "MarbleModel.h"
20 #include "PositionTracking.h"
21 
22 #include <QFile>
23 #include <QDataStream>
24 #include <QStringList>
25 #include <QRegExp>
26 #include <QVariant>
27 #include <QTime>
28 
29 #include <QSqlDatabase>
30 #include <QSqlQuery>
31 #include <QSqlError>
32 
33 namespace Marble {
34 
35 namespace {
36 
37 class PlacemarkSmallerDistance
38 {
39 public:
40  PlacemarkSmallerDistance( const GeoDataCoordinates &currentPosition ) :
41  m_currentPosition( currentPosition )
42  {}
43 
44  bool operator()( const OsmPlacemark &a, const OsmPlacemark &b ) const
45  {
46  return distanceSphere( a.longitude() * DEG2RAD, a.latitude() * DEG2RAD,
47  m_currentPosition.longitude(), m_currentPosition.latitude() )
48  < distanceSphere( b.longitude() * DEG2RAD, b.latitude() * DEG2RAD,
49  m_currentPosition.longitude(), m_currentPosition.latitude() );
50  }
51 
52 private:
53  GeoDataCoordinates m_currentPosition;
54 };
55 
56 class PlacemarkHigherScore
57 {
58 public:
59  PlacemarkHigherScore( const DatabaseQuery *currentQuery ) :
60  m_currentQuery( currentQuery )
61  {}
62 
63  bool operator()( const OsmPlacemark &a, const OsmPlacemark &b ) const
64  {
65  return a.matchScore( m_currentQuery ) > b.matchScore( m_currentQuery );
66  }
67 
68 private:
69  const DatabaseQuery *const m_currentQuery;
70 };
71 
72 }
73 
74 OsmDatabase::OsmDatabase( const QStringList &databaseFiles ) :
75  m_databaseFiles( databaseFiles )
76 {
77 }
78 
79 QVector<OsmPlacemark> OsmDatabase::find( const DatabaseQuery &userQuery )
80 {
81  if ( m_databaseFiles.isEmpty() ) {
82  return QVector<OsmPlacemark>();
83  }
84 
85  QSqlDatabase database = QSqlDatabase::addDatabase( "QSQLITE", QString( "marble/local-osm-search-%1" ).arg( reinterpret_cast<size_t>( this ) ) );
86 
87  QVector<OsmPlacemark> result;
88  QTime timer;
89  timer.start();
90  foreach( const QString &databaseFile, m_databaseFiles ) {
91  database.setDatabaseName( databaseFile );
92  if ( !database.open() ) {
93  qWarning() << "Failed to connect to database" << databaseFile;
94  }
95 
96  QString regionRestriction;
97  if ( !userQuery.region().isEmpty() ) {
98  QTime regionTimer;
99  regionTimer.start();
100  // Nested set model to support region hierarchies, see http://en.wikipedia.org/wiki/Nested_set_model
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();
105  }
106  regionRestriction = " AND (";
107  int regionCount = 0;
108  while ( regionsQuery.next() ) {
109  if ( regionCount > 0 ) {
110  regionRestriction += " OR ";
111  }
112  regionRestriction += " (regions.lft >= " + regionsQuery.value( 0 ).toString();
113  regionRestriction += " AND regions.lft <= " + regionsQuery.value( 1 ).toString() + ')';
114  regionCount++;
115  }
116  regionRestriction += ')';
117 
118  mDebug() << Q_FUNC_INFO << "region query in" << databaseFile << "with query" << regionsQueryString
119  << "took" << regionTimer.elapsed() << "ms for" << regionCount << "results";
120 
121  if ( regionCount == 0 ) {
122  continue;
123  }
124  }
125 
126  QString queryString;
127 
128  queryString = " SELECT regions.name,"
129  " places.name, places.number,"
130  " places.category, places.lon, places.lat"
131  " FROM regions, places";
132 
133  if ( userQuery.queryType() == DatabaseQuery::CategorySearch ) {
134  queryString += " WHERE regions.id = places.region";
135  if( userQuery.category() == OsmPlacemark::UnknownCategory ) {
136  // search for all pois which are not street nor address
137  queryString += " AND places.category <> 0 AND places.category <> 6";
138  } else {
139  // search for specific category
140  queryString += " AND places.category = %1";
141  queryString = queryString.arg( (qint32) userQuery.category() );
142  }
143  if ( userQuery.position().isValid() && userQuery.region().isEmpty() ) {
144  // sort by distance
145  queryString += " ORDER BY ((places.lat-%1)*(places.lat-%1)+(places.lon-%2)*(places.lon-%2))";
146  GeoDataCoordinates position = userQuery.position();
147  queryString = queryString.arg( position.latitude( GeoDataCoordinates::Degree ), 0, 'f', 8 )
148  .arg( position.longitude( GeoDataCoordinates::Degree ), 0, 'f', 8 );
149  } else {
150  queryString += regionRestriction;
151  }
152  } else if ( userQuery.queryType() == DatabaseQuery::BroadSearch ) {
153  queryString += " WHERE regions.id = places.region"
154  " AND places.name " + wildcardQuery( userQuery.searchTerm() );
155  } else {
156  queryString += " WHERE regions.id = places.region"
157  " AND places.name " + wildcardQuery( userQuery.street() );
158  if ( !userQuery.houseNumber().isEmpty() ) {
159  queryString += " AND places.number " + wildcardQuery( userQuery.houseNumber() );
160  } else {
161  queryString += " AND places.number IS NULL";
162  }
163  queryString += regionRestriction;
164  }
165 
166  queryString += " LIMIT 50;";
167 
170  QSqlQuery query( database );
171  query.setForwardOnly( true );
172  QTime queryTimer;
173  queryTimer.start();
174  if ( !query.exec( queryString ) ) {
175  qWarning() << query.lastError() << "in" << databaseFile << "with query" << query.lastQuery();
176  continue;
177  }
178 
179  int resultCount = 0;
180  while ( query.next() ) {
181  OsmPlacemark placemark;
182  if ( userQuery.resultFormat() == DatabaseQuery::DistanceFormat ) {
183  GeoDataCoordinates coordinates( query.value(4).toFloat(), query.value(5).toFloat(), 0.0, GeoDataCoordinates::Degree );
184  placemark.setAdditionalInformation( formatDistance( coordinates, userQuery.position() ) );
185  } else {
186  placemark.setAdditionalInformation( query.value( 0 ).toString() );
187  }
188  placemark.setName( query.value(1).toString() );
189  placemark.setHouseNumber( query.value(2).toString() );
190  placemark.setCategory( (OsmPlacemark::OsmCategory) query.value(3).toInt() );
191  placemark.setLongitude( query.value(4).toFloat() );
192  placemark.setLatitude( query.value(5).toFloat() );
193 
194  result.push_back( placemark );
195  resultCount++;
196  }
197 
198  mDebug() << Q_FUNC_INFO << "query in" << databaseFile << "with query" << queryString
199  << "took" << queryTimer.elapsed() << "ms for" << resultCount << "results";
200  }
201 
202  mDebug() << "Offline OSM search query took" << timer.elapsed() << "ms for" << result.count() << "results.";
203 
204  qSort( result.begin(), result.end() );
205  unique( result );
206 
207  if ( userQuery.position().isValid() ) {
208  const PlacemarkSmallerDistance placemarkSmallerDistance( userQuery.position() );
209  qSort( result.begin(), result.end(), placemarkSmallerDistance );
210  } else {
211  const PlacemarkHigherScore placemarkHigherScore( &userQuery );
212  qSort( result.begin(), result.end(), placemarkHigherScore );
213  }
214 
215  if ( result.size() > 50 ) {
216  result.remove( 50, result.size()-50 );
217  }
218 
219  return result;
220 }
221 
222 void OsmDatabase::unique( QVector<OsmPlacemark> &placemarks ) const
223 {
224  for ( int i=1; i<placemarks.size(); ++i ) {
225  if ( placemarks[i-1] == placemarks[i] ) {
226  placemarks.remove( i );
227  --i;
228  }
229  }
230 }
231 
232 QString OsmDatabase::formatDistance( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
233 {
234  qreal distance = EARTH_RADIUS * distanceSphere( a, b);
235 
236  int precision = 0;
237  QString distanceUnit = QLatin1String( "m" );
238 
239  if ( MarbleGlobal::getInstance()->locale()->measurementSystem() == QLocale::ImperialSystem ) {
240  precision = 1;
241  distanceUnit = "mi";
242  distance *= METER2KM;
243  distance *= KM2MI;
244  } else {
245  if ( distance >= 1000 ) {
246  distance /= 1000;
247  distanceUnit = "km";
248  precision = 1;
249  } else if ( distance >= 200 ) {
250  distance = 50 * qRound( distance / 50 );
251  } else if ( distance >= 100 ) {
252  distance = 25 * qRound( distance / 25 );
253  } else {
254  distance = 10 * qRound( distance / 10 );
255  }
256  }
257 
258  QString const fuzzyDistance = QString( "%1 %2" ).arg( distance, 0, 'f', precision ).arg( distanceUnit );
259 
260  int direction = 180 + bearing( a, b ) * RAD2DEG;
261 
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" );
279  }
280 
281  return fuzzyDistance + ' ' + heading;
282 }
283 
284 qreal OsmDatabase::bearing( const GeoDataCoordinates &a, const GeoDataCoordinates &b ) const
285 {
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 );
291 }
292 
293 QString OsmDatabase::wildcardQuery( const QString &term ) const
294 {
295  QString result = term;
296  if ( term.contains( '*' ) ) {
297  return " LIKE '" + result.replace( '*', '%' ) + '\'';
298  } else {
299  return " = '" + result + '\'';
300  }
301 }
302 
303 }
Marble::RAD2DEG
const qreal RAD2DEG
Definition: MarbleGlobal.h:201
Marble::GeoDataCoordinates
A 3d point representation.
Definition: GeoDataCoordinates.h:52
m_currentPosition
GeoDataCoordinates m_currentPosition
Definition: OsmDatabase.cpp:53
Marble::OsmDatabase::find
QVector< OsmPlacemark > find(const DatabaseQuery &userQuery)
Search the database for matching regions and placemarks.
Definition: OsmDatabase.cpp:79
MarbleMath.h
Marble::DatabaseQuery::region
QString region() const
Definition: DatabaseQuery.cpp:197
MarbleModel.h
This file contains the headers for MarbleModel.
Marble::OsmPlacemark::setAdditionalInformation
void setAdditionalInformation(const QString &name)
Definition: OsmPlacemark.cpp:68
Marble::OsmPlacemark
A lightweight data structure to represent points of interest like addresses with support for serializ...
Definition: OsmPlacemark.h:24
Marble::OsmPlacemark::setCategory
void setCategory(OsmCategory category)
Definition: OsmPlacemark.cpp:28
Marble::DatabaseQuery::resultFormat
ResultFormat resultFormat() const
Definition: DatabaseQuery.cpp:182
Marble::distanceSphere
qreal distanceSphere(qreal lon1, qreal lat1, qreal lon2, qreal lat2)
This method calculates the shortest distance between two points on a sphere.
Definition: MarbleMath.h:52
Marble::GeoDataCoordinates::latitude
qreal latitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
Definition: GeoDataCoordinates.cpp:751
MarbleDebug.h
Marble::DatabaseQuery::queryType
QueryType queryType() const
Definition: DatabaseQuery.cpp:177
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
Marble::OsmPlacemark::setName
void setName(const QString &name)
Definition: OsmPlacemark.cpp:38
Marble::DatabaseQuery::searchTerm
QString searchTerm() const
Definition: DatabaseQuery.cpp:202
Marble::DatabaseQuery::category
OsmPlacemark::OsmCategory category() const
Definition: DatabaseQuery.cpp:172
Marble::DatabaseQuery::houseNumber
QString houseNumber() const
Definition: DatabaseQuery.cpp:192
Marble::DatabaseQuery::position
GeoDataCoordinates position() const
Definition: DatabaseQuery.cpp:207
Marble::OsmPlacemark::setLatitude
void setLatitude(qreal latitude)
Definition: OsmPlacemark.cpp:88
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:238
m_currentQuery
const DatabaseQuery *const m_currentQuery
Definition: OsmDatabase.cpp:69
Marble::OsmPlacemark::UnknownCategory
Definition: OsmPlacemark.h:28
Marble::DatabaseQuery::BroadSearch
search which contains a poi category
Definition: DatabaseQuery.h:35
MarbleLocale.h
Marble::DEG2RAD
const qreal DEG2RAD
Definition: MarbleGlobal.h:200
Marble::METER2KM
const qreal METER2KM
Definition: MarbleGlobal.h:205
Marble::DatabaseQuery::CategorySearch
precise search for an address
Definition: DatabaseQuery.h:34
Marble::KM2MI
const qreal KM2MI
Definition: MarbleGlobal.h:189
Marble::GeoDataCoordinates::longitude
qreal longitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
Definition: GeoDataCoordinates.cpp:739
Marble::MarbleGlobal::getInstance
static MarbleGlobal * getInstance()
Definition: MarbleGlobal.cpp:37
Marble::OsmPlacemark::setLongitude
void setLongitude(qreal longitude)
Definition: OsmPlacemark.cpp:78
direction
qreal direction
Definition: tools/osm-addresses/OsmParser.cpp:39
Marble::DatabaseQuery::street
QString street() const
Definition: DatabaseQuery.cpp:187
GeoDataLatLonAltBox.h
OsmDatabase.h
Marble::OsmPlacemark::OsmCategory
OsmCategory
Definition: OsmPlacemark.h:27
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
Marble::OsmPlacemark::setHouseNumber
void setHouseNumber(const QString &houseNumber)
Definition: OsmPlacemark.cpp:48
Marble::OsmDatabase::OsmDatabase
OsmDatabase(const QStringList &databaseFiles)
Definition: OsmDatabase.cpp:74
Marble::DatabaseQuery
Parse result of a user's search term.
Definition: DatabaseQuery.h:29
Marble::GeoDataCoordinates::isValid
bool isValid() const
Returns.
Definition: GeoDataCoordinates.cpp:624
PositionTracking.h
Marble::DatabaseQuery::DistanceFormat
display results with location information
Definition: DatabaseQuery.h:40
DatabaseQuery.h
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:52 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal