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

marble

  • sources
  • kde-4.14
  • 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  makeUnique( 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::makeUnique( QVector<OsmPlacemark> &placemarks )
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 )
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() == MarbleLocale::MetricSystem ) {
240  precision = 1;
241  distanceUnit = "mi";
242  distance *= METER2KM;
243  distance *= KM2MI;
244  } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() ==
245  MarbleLocale::MetricSystem) {
246  if ( distance >= 1000 ) {
247  distance /= 1000;
248  distanceUnit = "km";
249  precision = 1;
250  } else if ( distance >= 200 ) {
251  distance = 50 * qRound( distance / 50 );
252  } else if ( distance >= 100 ) {
253  distance = 25 * qRound( distance / 25 );
254  } else {
255  distance = 10 * qRound( distance / 10 );
256  }
257  } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() ==
258  MarbleLocale::NauticalSystem) {
259  precision = 2;
260  distanceUnit = "nm";
261  distance *= METER2KM;
262  distance *= KM2NM;
263  }
264 
265  QString const fuzzyDistance = QString( "%1 %2" ).arg( distance, 0, 'f', precision ).arg( distanceUnit );
266 
267  int direction = 180 + bearing( a, b ) * RAD2DEG;
268 
269  QString heading = QObject::tr( "north" );
270  if ( direction > 337 ) {
271  heading = QObject::tr( "north" );
272  } else if ( direction > 292 ) {
273  heading = QObject::tr( "north-west" );
274  } else if ( direction > 247 ) {
275  heading = QObject::tr( "west" );
276  } else if ( direction > 202 ) {
277  heading = QObject::tr( "south-west" );
278  } else if ( direction > 157 ) {
279  heading = QObject::tr( "south" );
280  } else if ( direction > 112 ) {
281  heading = QObject::tr( "south-east" );
282  } else if ( direction > 67 ) {
283  heading = QObject::tr( "east" );
284  } else if ( direction > 22 ) {
285  heading = QObject::tr( "north-east" );
286  }
287 
288  return fuzzyDistance + ' ' + heading;
289 }
290 
291 qreal OsmDatabase::bearing( const GeoDataCoordinates &a, const GeoDataCoordinates &b )
292 {
293  qreal delta = b.longitude() - a.longitude();
294  qreal lat1 = a.latitude();
295  qreal lat2 = b.latitude();
296  return fmod( atan2( sin ( delta ) * cos ( lat2 ),
297  cos( lat1 ) * sin( lat2 ) - sin( lat1 ) * cos( lat2 ) * cos ( delta ) ), 2 * M_PI );
298 }
299 
300 QString OsmDatabase::wildcardQuery( const QString &term )
301 {
302  QString result = term;
303  if ( term.contains( '*' ) ) {
304  return " LIKE '" + result.replace( '*', '%' ) + '\'';
305  } else {
306  return " = '" + result + '\'';
307  }
308 }
309 
310 }
Marble::RAD2DEG
const qreal RAD2DEG
Definition: MarbleGlobal.h:220
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
Marble::MarbleLocale::NauticalSystem
Definition: MarbleLocale.h:40
MarbleMath.h
Marble::DatabaseQuery::region
QString region() const
Definition: DatabaseQuery.cpp:197
QVector::begin
iterator begin()
MarbleModel.h
This file contains the headers for MarbleModel.
QSqlQuery::exec
bool exec(const QString &query)
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
QSqlDatabase::addDatabase
QSqlDatabase addDatabase(const QString &type, const QString &connectionName)
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
QTime
MarbleDebug.h
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
Marble::DatabaseQuery::queryType
QueryType queryType() const
Definition: DatabaseQuery.cpp:177
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
QSqlDatabase
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
QTime::elapsed
int elapsed() const
Marble::OsmPlacemark::setLatitude
void setLatitude(qreal latitude)
Definition: OsmPlacemark.cpp:88
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:257
QVariant::toInt
int toInt(bool *ok) const
QSqlQuery::value
QVariant value(int index) const
QSqlQuery::lastQuery
QString lastQuery() const
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
QVector::remove
void remove(int i)
QSqlQuery
m_currentQuery
const DatabaseQuery *const m_currentQuery
Definition: OsmDatabase.cpp:69
Marble::OsmPlacemark::UnknownCategory
Definition: OsmPlacemark.h:28
QSqlQuery::next
bool next()
Marble::DatabaseQuery::BroadSearch
search which contains a poi category
Definition: DatabaseQuery.h:35
QSqlDatabase::open
bool open()
QString
MarbleLocale.h
Marble::DEG2RAD
const qreal DEG2RAD
Definition: MarbleGlobal.h:219
QSqlQuery::setForwardOnly
void setForwardOnly(bool forward)
Marble::METER2KM
const qreal METER2KM
Definition: MarbleGlobal.h:224
QStringList
QVariant::toFloat
float toFloat(bool *ok) const
Marble::DatabaseQuery::CategorySearch
precise search for an address
Definition: DatabaseQuery.h:34
Marble::KM2MI
const qreal KM2MI
Definition: MarbleGlobal.h:203
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
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
Marble::MarbleGlobal::getInstance
static MarbleGlobal * getInstance()
Definition: MarbleGlobal.cpp:37
Marble::OsmPlacemark::setLongitude
void setLongitude(qreal longitude)
Definition: OsmPlacemark.cpp:78
Marble::MarbleLocale::MetricSystem
Definition: MarbleLocale.h:38
QString::replace
QString & replace(int position, int n, QChar after)
direction
qreal direction
Definition: tools/osm-addresses/OsmParser.cpp:40
Marble::DatabaseQuery::street
QString street() const
Definition: DatabaseQuery.cpp:187
QVector
QLatin1String
GeoDataLatLonAltBox.h
OsmDatabase.h
QVector::count
int count(const T &value) const
Marble::OsmPlacemark::OsmCategory
OsmCategory
Definition: OsmPlacemark.h:27
QSqlQuery::lastError
QSqlError lastError() const
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
QVector::push_back
void push_back(const T &value)
QTime::start
void start()
Marble::KM2NM
const qreal KM2NM
Definition: MarbleGlobal.h:207
QSqlError::isValid
bool isValid() const
QSqlDatabase::setDatabaseName
void setDatabaseName(const QString &name)
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
QVector::size
int size() const
DatabaseQuery.h
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QVariant::toString
QString toString() const
QVector::end
iterator end()
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:41 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
  • 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