SVN checkout 11/12/2010
[monav:monav.git] / plugins / osmimporter / osmimporter.cpp
1 /*
2 Copyright 2010  Christian Vetter veaac.fdirct@gmail.com
3
4 This file is part of MoNav.
5
6 MoNav is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 MoNav is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with MoNav.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "osmimporter.h"
21 #include "xmlreader.h"
22 #include "pbfreader.h"
23 #include "utils/qthelpers.h"
24 #include <algorithm>
25 #include <QtDebug>
26 #include <limits>
27
28 OSMImporter::OSMImporter()
29 {
30         Q_INIT_RESOURCE(speedprofiles);
31         m_settingsDialog = NULL;
32
33         m_kmhStrings.push_back( "kmh" );
34         m_kmhStrings.push_back( " kmh" );
35         m_kmhStrings.push_back( "km/h" );
36         m_kmhStrings.push_back( " km/h" );
37         m_kmhStrings.push_back( "kph" );
38         m_kmhStrings.push_back( " kph" );
39
40         m_mphStrings.push_back( "mph" );
41         m_mphStrings.push_back( " mph" );
42 }
43
44 void OSMImporter::setRequiredTags( IEntityReader *reader )
45 {
46         QStringList list;
47         // Place = 0, Population = 1, Highway = 2
48         list.push_back( "place" );
49         list.push_back( "population" );
50         list.push_back( "barrier" );
51         for ( int i = 0; i < m_settings.languageSettings.size(); i++ )
52                 list.push_back( m_settings.languageSettings[i] );
53         for ( int i = 0; i < m_settings.accessList.size(); i++ )
54                 list.push_back( m_settings.accessList[i] );
55         for ( int i = 0; i < m_settings.nodeModificators.size(); i++ ) {
56                 int index = list.indexOf( m_settings.nodeModificators[i].key );
57                 if ( index == -1 ) {
58                         index = list.size();
59                         list.push_back( m_settings.nodeModificators[i].key );
60                 }
61                 m_nodeModificatorIDs.push_back( index );
62         }
63         reader->setNodeTags( list );
64
65         list.clear();
66         //Oneway = 0, Junction = 1, Highway = 2, Ref = 3, PlaceName = 4, Place = 5, MaxSpeed = 6,
67         list.push_back( "oneway" );
68         list.push_back( "junction" );
69         list.push_back( "highway" );
70         list.push_back( "ref" );
71         list.push_back( "place_name" );
72         list.push_back( "place" );
73         list.push_back( "maxspeed" );
74         for ( int i = 0; i < m_settings.languageSettings.size(); i++ )
75                 list.push_back( m_settings.languageSettings[i] );
76         for ( int i = 0; i < m_settings.accessList.size(); i++ )
77                 list.push_back( m_settings.accessList[i] );
78         for ( int i = 0; i < m_settings.wayModificators.size(); i++ ) {
79                 int index = list.indexOf( m_settings.wayModificators[i].key );
80                 if ( index == -1 ) {
81                         index = list.size();
82                         list.push_back( m_settings.wayModificators[i].key );
83                 }
84                 m_wayModificatorIDs.push_back( index );
85         }
86         reader->setWayTags( list );
87
88         list.clear();
89         list.push_back( "type" );
90         list.push_back( "restriction" );
91         list.push_back( "except" );
92         reader->setRelationTags( list );
93 }
94
95 OSMImporter::~OSMImporter()
96 {
97         Q_CLEANUP_RESOURCE(speedprofiles);
98         if ( m_settingsDialog != NULL )
99                 delete m_settingsDialog;
100 }
101
102 QString OSMImporter::GetName()
103 {
104         return "OpenStreetMap Importer";
105 }
106
107 void OSMImporter::SetOutputDirectory( const QString& dir )
108 {
109         m_outputDirectory = dir;
110 }
111
112 QWidget* OSMImporter::GetSettings()
113 {
114         if ( m_settingsDialog == NULL )
115                 m_settingsDialog = new OISettingsDialog;
116         return m_settingsDialog;
117 }
118
119 bool OSMImporter::LoadSettings( QSettings* settings )
120 {
121         if ( m_settingsDialog == NULL )
122                 m_settingsDialog = new OISettingsDialog;
123         return m_settingsDialog->loadSettings( settings );
124 }
125
126 bool OSMImporter::SaveSettings( QSettings* settings )
127 {
128         if ( m_settingsDialog == NULL )
129                 m_settingsDialog = new OISettingsDialog;
130         return m_settingsDialog->saveSettings( settings );
131 }
132
133 void OSMImporter::clear()
134 {
135         std::vector< unsigned >().swap( m_usedNodes );
136         std::vector< unsigned >().swap( m_outlineNodes );
137         std::vector< unsigned >().swap( m_routingNodes );
138         std::vector< NodePenalty >().swap( m_penaltyNodes );
139         std::vector< unsigned >().swap( m_noAccessNodes );
140         m_wayNames.clear();
141         m_wayRefs.clear();
142         std::vector< int >().swap( m_nodeModificatorIDs );
143         std::vector< int >().swap( m_wayModificatorIDs );
144         std::vector< char >().swap( m_inDegree );
145         std::vector< char >().swap( m_outDegree );
146         std::vector< EdgeInfo >().swap( m_edgeInfo );
147 }
148
149 bool OSMImporter::Preprocess( QString inputFilename )
150 {
151         if ( m_settingsDialog == NULL )
152                 m_settingsDialog = new OISettingsDialog();
153
154         if ( !m_settingsDialog->getSettings( &m_settings ) )
155                 return false;
156
157         if ( m_settings.highways.size() == 0 ) {
158                 qCritical( "no highway types specified" );
159                 return false;
160         }
161
162         clear();
163
164         QString filename = fileInDirectory( m_outputDirectory, "OSM Importer" );
165         FileStream typeData( filename + "_way_types" );
166         if ( !typeData.open( QIODevice::WriteOnly ) )
167                 return false;
168
169         for ( int type = 0; type < m_settings.highways.size(); type++ )
170                 typeData << m_settings.highways[type].value;
171         typeData << QString( "roundabout" );
172
173         m_statistics = Statistics();
174
175         Timer time;
176
177         if ( !read( inputFilename, filename ) )
178                 return false;
179         qDebug() << "OSM Importer: finished import pass 1:" << time.restart() << "ms";
180
181         if ( m_usedNodes.size() == 0 ) {
182                 qCritical( "OSM Importer: no routing nodes found in the data set" );
183                 return false;
184         }
185
186         std::sort( m_usedNodes.begin(), m_usedNodes.end() );
187         for ( unsigned i = 0; i < m_usedNodes.size(); ) {
188                 unsigned currentNode = m_usedNodes[i];
189                 int count = 1;
190                 for ( i++; i < m_usedNodes.size() && currentNode == m_usedNodes[i]; i++ )
191                         count++;
192
193                 if ( count > 1 )
194                         m_routingNodes.push_back( currentNode );
195         }
196         m_usedNodes.resize( std::unique( m_usedNodes.begin(), m_usedNodes.end() ) - m_usedNodes.begin() );
197         std::sort( m_outlineNodes.begin(), m_outlineNodes.end() );
198         m_outlineNodes.resize( std::unique( m_outlineNodes.begin(), m_outlineNodes.end() ) - m_outlineNodes.begin() );
199         std::sort( m_penaltyNodes.begin(), m_penaltyNodes.end() );
200         std::sort( m_noAccessNodes.begin(), m_noAccessNodes.end() );
201         std::sort( m_routingNodes.begin(), m_routingNodes.end() );
202         m_routingNodes.resize( std::unique( m_routingNodes.begin(), m_routingNodes.end() ) - m_routingNodes.begin() );
203
204         if ( !preprocessData( filename ) )
205                 return false;
206         qDebug() << "OSM Importer: finished import pass 2:" << time.restart() << "ms";
207         printStats();
208         clear();
209         return true;
210 }
211
212 void OSMImporter::printStats()
213 {
214         qDebug() << "OSM Importer: === Statistics ===";
215         qDebug() << "OSM Importer: nodes:" << m_statistics.numberOfNodes;
216         qDebug() << "OSM Importer: ways:" << m_statistics.numberOfWays;
217         qDebug() << "OSM Importer: relations" << m_statistics.numberOfRelations;
218         qDebug() << "OSM Importer: used nodes:" << m_statistics.numberOfUsedNodes;
219         qDebug() << "OSM Importer: segments" << m_statistics.numberOfSegments;
220         qDebug() << "OSM Importer: routing edges:" << m_statistics.numberOfEdges;
221         qDebug() << "OSM Importer: routing nodes:" << m_routingNodes.size();
222         qDebug() << "OSM Importer: nodes with penalty:" << m_penaltyNodes.size();
223         qDebug() << "OSM Importer: nodes with no access:" << m_noAccessNodes.size();
224         qDebug() << "OSM Importer: maxspeed:" << m_statistics.numberOfMaxspeed;
225         qDebug() << "OSM Importer: zero speed ways:" << m_statistics.numberOfZeroSpeed;
226         qDebug() << "OSM Importer: default city speed:" << m_statistics.numberOfDefaultCitySpeed;
227         qDebug() << "OSM Importer: distinct way names:" << m_wayNames.size();
228         qDebug() << "OSM Importer: distinct way refs:" << m_wayRefs.size();
229         qDebug() << "OSM Importer: restrictions:" << m_statistics.numberOfRestrictions;
230         qDebug() << "OSM Importer: restrictions applied:" << m_statistics.numberOfRestrictionsApplied;
231         qDebug() << "OSM Importer: turning penalties:" << m_statistics.numberOfTurningPenalties;
232         qDebug() << "OSM Importer: max turning penalty:" << m_statistics.maxTurningPenalty;
233         qDebug() << "OSM Importer: average turning left penalty:" << m_statistics.averageLeftPenalty;
234         qDebug() << "OSM Importer: average turning right penalty:" << m_statistics.averageRightPenalty;
235         qDebug() << "OSM Importer: average turning straight penalty:" << m_statistics.averageStraightPenalty;
236         qDebug() << "OSM Importer: places:" << m_statistics.numberOfPlaces;
237         qDebug() << "OSM Importer: places outlines:" << m_statistics.numberOfOutlines;
238         qDebug() << "OSM Importer: places outline nodes:" << m_outlineNodes.size();
239 }
240
241 bool OSMImporter::read( const QString& inputFilename, const QString& filename ) {
242         FileStream edgeData( filename + "_edges" );
243         FileStream onewayEdgeData( filename + "_oneway_edges" );
244         FileStream placeData( filename + "_places" );
245         FileStream boundingBoxData( filename + "_bounding_box" );
246         FileStream nodeData( filename + "_all_nodes" );
247         FileStream cityOutlineData( filename + "_city_outlines" );
248         FileStream wayNameData( filename + "_way_names" );
249         FileStream wayRefData( filename + "_way_refs" );
250         FileStream restrictionData( filename + "_restrictions" );
251
252         if ( !edgeData.open( QIODevice::WriteOnly ) )
253                 return false;
254         if ( !onewayEdgeData.open( QIODevice::WriteOnly ) )
255                 return false;
256         if ( !placeData.open( QIODevice::WriteOnly ) )
257                 return false;
258         if ( !boundingBoxData.open( QIODevice::WriteOnly ) )
259                 return false;
260         if ( !nodeData.open( QIODevice::WriteOnly ) )
261                 return false;
262         if ( !cityOutlineData.open( QIODevice::WriteOnly ) )
263                 return false;
264         if ( !wayNameData.open( QIODevice::WriteOnly ) )
265                 return false;
266         if ( !wayRefData.open( QIODevice::WriteOnly ) )
267                 return false;
268         if ( !restrictionData.open( QIODevice::WriteOnly ) )
269                 return false;
270
271         m_wayNames[QString()] = 0;
272         wayNameData << QString();
273         m_wayRefs[QString()] = 0;
274         wayRefData << QString();
275
276         IEntityReader* reader = NULL;
277         if ( inputFilename.endsWith( "osm.bz2" ) || inputFilename.endsWith( ".osm" ) )
278                 reader = new XMLReader();
279         else if ( inputFilename.endsWith( ".pbf" ) )
280                 reader = new PBFReader();
281
282         if ( reader == NULL ) {
283                 qCritical() << "file format not supporter";
284                 return false;
285         }
286
287         if ( !reader->open( inputFilename ) ) {
288                 qCritical() << "error opening file";
289                 return false;
290         }
291
292         try {
293                 GPSCoordinate min( std::numeric_limits< double >::max(), std::numeric_limits< double >::max() );
294                 GPSCoordinate max( std::numeric_limits< double >::min(), std::numeric_limits< double >::min() );
295
296                 setRequiredTags( reader );
297
298                 IEntityReader::Way inputWay;
299                 IEntityReader::Node inputNode;
300                 IEntityReader::Relation inputRelation;
301                 Node node;
302                 Way way;
303                 Relation relation;
304                 while ( true ) {
305                         IEntityReader::EntityType type = reader->getEntitiy( &inputNode, &inputWay, &inputRelation );
306
307                         if ( type == IEntityReader::EntityNone )
308                                 break;
309
310                         if ( type == IEntityReader::EntityNode ) {
311                                 m_statistics.numberOfNodes++;
312                                 readNode( &node, inputNode );
313
314                                 min.latitude = std::min( min.latitude, inputNode.coordinate.latitude );
315                                 min.longitude = std::min( min.longitude, inputNode.coordinate.longitude );
316                                 max.latitude = std::max( max.latitude, inputNode.coordinate.latitude );
317                                 max.longitude = std::max( max.longitude, inputNode.coordinate.longitude );
318
319                                 if ( node.penalty != 0 )
320                                         m_penaltyNodes.push_back( NodePenalty( inputNode.id, node.penalty ) );
321
322                                 if ( !node.access )
323                                         m_noAccessNodes.push_back( inputNode.id );
324
325                                 UnsignedCoordinate coordinate( inputNode.coordinate );
326                                 nodeData << unsigned( inputNode.id ) << coordinate.x << coordinate.y;
327
328                                 if ( node.type != Place::None && !node.name.isEmpty() ) {
329                                         placeData << inputNode.coordinate.latitude << inputNode.coordinate.longitude << unsigned( node.type ) << node.population << node.name;
330                                         m_statistics.numberOfPlaces++;
331                                 }
332
333                                 continue;
334                         }
335
336                         if ( type == IEntityReader::EntityWay ) {
337                                 m_statistics.numberOfWays++;
338                                 readWay( &way, inputWay );
339
340                                 if ( way.usefull && way.access && inputWay.nodes.size() > 1 ) {
341                                         for ( unsigned node = 0; node < inputWay.nodes.size(); ++node )
342                                                 m_usedNodes.push_back( inputWay.nodes[node] );
343
344                                         m_routingNodes.push_back( inputWay.nodes.front() ); // first and last node are always considered routing nodes
345                                         m_routingNodes.push_back( inputWay.nodes.back() );  // as ways are never merged
346
347                                         QString name = way.name.simplified();
348
349                                         if ( !m_wayNames.contains( name ) ) {
350                                                 wayNameData << name;
351                                                 int id = m_wayNames.size();
352                                                 m_wayNames[name] = id;
353                                         }
354
355                                         QString ref = name; // fallback to name
356                                         if ( !way.ref.isEmpty() )
357                                                 ref = way.ref.simplified();
358
359                                         if ( !m_wayRefs.contains( ref ) ) {
360                                                 wayRefData << ref;
361                                                 int id = m_wayRefs.size();
362                                                 m_wayRefs[ref] = id;
363                                         }
364
365                                         if ( m_settings.ignoreOneway )
366                                                 way.direction = Way::Bidirectional;
367                                         if ( m_settings.ignoreMaxspeed )
368                                                 way.maximumSpeed = -1;
369
370                                         if ( way.direction == Way::Opposite )
371                                                 std::reverse( inputWay.nodes.begin(), inputWay.nodes.end() );
372
373                                         // seperate oneway edges from bidirectional ones. neccessary to determine consistent edgeIDAtSource / edgeIDAtTarget
374                                         if ( ( way.direction == Way::Oneway || way.direction == Way::Opposite ) ) {
375                                                 onewayEdgeData << inputWay.id;
376                                                 onewayEdgeData << m_wayNames[name];
377                                                 onewayEdgeData << m_wayRefs[ref];
378                                                 onewayEdgeData << way.type;
379                                                 onewayEdgeData << way.roundabout;
380                                                 onewayEdgeData << way.maximumSpeed;
381                                                 onewayEdgeData << way.addFixed << way.addPercentage;
382                                                 onewayEdgeData << bool( false ); // bidirectional?
383                                                 onewayEdgeData << unsigned( inputWay.nodes.size() );
384                                                 for ( unsigned node = 0; node < inputWay.nodes.size(); ++node )
385                                                         onewayEdgeData << inputWay.nodes[node];
386                                         } else {
387                                                 edgeData << inputWay.id;
388                                                 edgeData << m_wayNames[name];
389                                                 edgeData << m_wayRefs[ref];
390                                                 edgeData << way.type;
391                                                 edgeData << way.roundabout;
392                                                 edgeData << way.maximumSpeed;
393                                                 edgeData << way.addFixed << way.addPercentage;
394                                                 edgeData << bool( true ); // bidirectional?
395                                                 edgeData << unsigned( inputWay.nodes.size() );
396                                                 for ( unsigned node = 0; node < inputWay.nodes.size(); ++node )
397                                                         edgeData << inputWay.nodes[node];
398                                         }
399
400                                 }
401
402                                 bool closedWay = inputWay.nodes.size() != 0 && inputWay.nodes.front() == inputWay.nodes.back();
403
404                                 if ( closedWay && way.placeType != Place::None && !way.placeName.isEmpty() ) {
405                                         QString name = way.placeName.simplified();
406
407                                         cityOutlineData << unsigned( way.placeType ) << unsigned( inputWay.nodes.size() - 1 );
408                                         cityOutlineData << name;
409                                         for ( unsigned i = 1; i < inputWay.nodes.size(); ++i ) {
410                                                 m_outlineNodes.push_back( inputWay.nodes[i] );
411                                                 cityOutlineData << inputWay.nodes[i];
412                                         }
413                                         m_statistics.numberOfOutlines++;
414                                 }
415
416                                 continue;
417                         }
418
419                         if ( type == IEntityReader::EntityRelation ) {
420                                 m_statistics.numberOfRelations++;
421                                 readRelation( &relation, inputRelation );
422
423                                 if ( relation.type != Relation::TypeRestriction )
424                                         continue;
425
426                                 if ( !relation.restriction.access )
427                                         continue;
428                                 if ( relation.restriction.type == Restriction::None )
429                                         continue;
430                                 if ( relation.restriction.from == std::numeric_limits< unsigned >::max() )
431                                         continue;
432                                 if ( relation.restriction.to == std::numeric_limits< unsigned >::max() )
433                                         continue;
434                                 if ( relation.restriction.via == std::numeric_limits< unsigned >::max() )
435                                         continue;
436
437                                 m_statistics.numberOfRestrictions++;
438
439                                 restrictionData << ( relation.restriction.type == Restriction::No );
440                                 restrictionData << relation.restriction.from;
441                                 restrictionData << relation.restriction.to;
442                                 restrictionData << relation.restriction.via;
443
444                                 continue;
445                         }
446                 }
447
448                 boundingBoxData << min.latitude << min.longitude << max.latitude << max.longitude;
449
450         } catch ( const std::exception& e ) {
451                 qCritical( "OSM Importer: caught execption: %s", e.what() );
452                 return false;
453         }
454
455         delete reader;
456         return true;
457 }
458
459 bool OSMImporter::preprocessData( const QString& filename ) {
460         std::vector< UnsignedCoordinate > nodeCoordinates( m_usedNodes.size() );
461         std::vector< UnsignedCoordinate > outlineCoordinates( m_outlineNodes.size() );
462
463         FileStream allNodesData( filename + "_all_nodes" );
464
465         if ( !allNodesData.open( QIODevice::ReadOnly ) )
466                 return false;
467
468         FileStream routingCoordinatesData( filename + "_routing_coordinates" );
469
470         if ( !routingCoordinatesData.open( QIODevice::WriteOnly ) )
471                 return false;
472
473         Timer time;
474
475         while ( true ) {
476                 unsigned node;
477                 UnsignedCoordinate coordinate;
478                 allNodesData >> node >> coordinate.x >> coordinate.y;
479                 if ( allNodesData.status() == QDataStream::ReadPastEnd )
480                         break;
481                 std::vector< NodeID >::const_iterator element = std::lower_bound( m_usedNodes.begin(), m_usedNodes.end(), node );
482                 if ( element != m_usedNodes.end() && *element == node )
483                         nodeCoordinates[element - m_usedNodes.begin()] = coordinate;
484                 element = std::lower_bound( m_outlineNodes.begin(), m_outlineNodes.end(), node );
485                 if ( element != m_outlineNodes.end() && *element == node )
486                         outlineCoordinates[element - m_outlineNodes.begin()] = coordinate;
487         }
488
489         qDebug() << "OSM Importer: filtered node coordinates:" << time.restart() << "ms";
490
491         m_statistics.numberOfUsedNodes = m_usedNodes.size();
492         std::vector< NodeLocation > nodeLocation( m_usedNodes.size() );
493
494         if ( !computeInCityFlags( filename, &nodeLocation, nodeCoordinates, outlineCoordinates ) )
495                 return false;
496         std::vector< UnsignedCoordinate >().swap( outlineCoordinates );
497
498         m_inDegree.resize( m_routingNodes.size(), 0 );
499         m_outDegree.resize( m_routingNodes.size(), 0 );
500         if ( !remapEdges( filename, nodeCoordinates, nodeLocation ) )
501                 return false;
502
503         for ( unsigned i = 0; i < m_routingNodes.size(); i++ ) {
504                 unsigned mapped = std::lower_bound( m_usedNodes.begin(), m_usedNodes.end(), m_routingNodes[i] ) - m_usedNodes.begin();
505                 routingCoordinatesData << nodeCoordinates[mapped].x << nodeCoordinates[mapped].y;
506         }
507
508         qDebug() << "OSM Importer: wrote routing node coordinates:" << time.restart() << "ms";
509
510         std::vector< unsigned >().swap( m_usedNodes );
511         std::vector< UnsignedCoordinate >().swap( nodeCoordinates );
512
513         if ( !computeTurningPenalties( filename ) )
514                 return false;
515
516         return true;
517 }
518
519 bool OSMImporter::computeInCityFlags( QString filename, std::vector< NodeLocation >* nodeLocation, const std::vector< UnsignedCoordinate >& nodeCoordinates, const std::vector< UnsignedCoordinate >& outlineCoordinates )
520 {
521         FileStream cityOutlinesData( filename + "_city_outlines" );
522         FileStream placesData( filename + "_places" );
523
524         if ( !cityOutlinesData.open( QIODevice::ReadOnly ) )
525                 return false;
526         if ( !placesData.open( QIODevice::ReadOnly ) )
527                 return false;
528
529         Timer time;
530
531         std::vector< Outline > cityOutlines;
532         while ( true ) {
533                 Outline outline;
534                 unsigned type, numberOfPathNodes;
535                 cityOutlinesData >> type >> numberOfPathNodes >> outline.name;
536                 if ( cityOutlinesData.status() == QDataStream::ReadPastEnd )
537                         break;
538
539                 bool valid = true;
540                 for ( int i = 0; i < ( int ) numberOfPathNodes; ++i ) {
541                         unsigned node;
542                         cityOutlinesData >> node;
543                         NodeID mappedNode = std::lower_bound( m_outlineNodes.begin(), m_outlineNodes.end(), node ) - m_outlineNodes.begin();
544                         if ( !outlineCoordinates[mappedNode].IsValid() ) {
545                                 qDebug( "OSM Importer: inconsistent OSM data: missing outline node coordinate %d", ( int ) mappedNode );
546                                 valid = false;
547                         }
548                         DoublePoint point( outlineCoordinates[mappedNode].x, outlineCoordinates[mappedNode].y );
549                         outline.way.push_back( point );
550                 }
551                 if ( valid )
552                         cityOutlines.push_back( outline );
553         }
554         std::sort( cityOutlines.begin(), cityOutlines.end() );
555
556         qDebug() << "OSM Importer: read city outlines:" << time.restart() << "ms";
557
558         std::vector< Location > places;
559         while ( true ) {
560                 Location place;
561                 unsigned type;
562                 int population;
563                 placesData >> place.coordinate.latitude >> place.coordinate.longitude >> type >> population >> place.name;
564
565                 if ( placesData.status() == QDataStream::ReadPastEnd )
566                         break;
567
568                 place.type = ( Place::Type ) type;
569                 places.push_back( place );
570         }
571
572         qDebug() << "OSM Importer: read places:" << time.restart() << "ms";
573
574         typedef GPSTree::InputPoint InputPoint;
575         std::vector< InputPoint > kdPoints;
576         kdPoints.reserve( m_usedNodes.size() );
577         for ( std::vector< UnsignedCoordinate >::const_iterator node = nodeCoordinates.begin(), endNode = nodeCoordinates.end(); node != endNode; ++node ) {
578                 InputPoint point;
579                 point.data = node - nodeCoordinates.begin();
580                 point.coordinates[0] = node->x;
581                 point.coordinates[1] = node->y;
582                 kdPoints.push_back( point );
583                 nodeLocation->at( point.data ).isInPlace = false;
584                 nodeLocation->at( point.data ).distance = std::numeric_limits< double >::max();
585         }
586         GPSTree kdTree( kdPoints );
587
588         qDebug() << "OSM Importer: build kd-tree:" << time.restart() << "ms";
589
590         for ( std::vector< Location >::const_iterator place = places.begin(), endPlace = places.end(); place != endPlace; ++place ) {
591                 InputPoint point;
592                 UnsignedCoordinate placeCoordinate( place->coordinate );
593                 point.coordinates[0] = placeCoordinate.x;
594                 point.coordinates[1] = placeCoordinate.y;
595                 std::vector< InputPoint > result;
596
597                 const Outline* placeOutline = NULL;
598                 double radius = 0;
599                 Outline searchOutline;
600                 searchOutline.name = place->name;
601                 for ( std::vector< Outline >::const_iterator outline = std::lower_bound( cityOutlines.begin(), cityOutlines.end(), searchOutline ), outlineEnd = std::upper_bound( cityOutlines.begin(), cityOutlines.end(), searchOutline ); outline != outlineEnd; ++outline ) {
602                         UnsignedCoordinate cityCoordinate = UnsignedCoordinate( place->coordinate );
603                         DoublePoint cityPoint( cityCoordinate.x, cityCoordinate.y );
604                         if ( pointInPolygon( outline->way.size(), &outline->way[0], cityPoint ) ) {
605                                 placeOutline = &( *outline );
606                                 for ( std::vector< DoublePoint >::const_iterator way = outline->way.begin(), wayEnd = outline->way.end(); way != wayEnd; ++way ) {
607                                         UnsignedCoordinate coordinate( way->x, way->y );
608                                         double distance = coordinate.ToGPSCoordinate().ApproximateDistance( place->coordinate );
609                                         radius = std::max( radius, distance );
610                                 }
611                                 break;
612                         }
613                 }
614
615                 if ( placeOutline != NULL ) {
616                         kdTree.NearNeighbors( &result, point, radius );
617                         for ( std::vector< InputPoint >::const_iterator i = result.begin(), e = result.end(); i != e; ++i ) {
618                                 UnsignedCoordinate coordinate( i->coordinates[0], i->coordinates[1] );
619                                 DoublePoint nodePoint;
620                                 nodePoint.x = coordinate.x;
621                                 nodePoint.y = coordinate.y;
622                                 if ( !pointInPolygon( placeOutline->way.size(), &placeOutline->way[0], nodePoint ) )
623                                         continue;
624                                 nodeLocation->at( i->data ).isInPlace = true;
625                                 nodeLocation->at( i->data ).place = place - places.begin();
626                                 nodeLocation->at( i->data ).distance = 0;
627                         }
628                 } else {
629                         switch ( place->type ) {
630                         case Place::None:
631                                 continue;
632                         case Place::Suburb:
633                                 continue;
634                         case Place::Hamlet:
635                                 kdTree.NearNeighbors( &result, point, 300 );
636                                 break;
637                         case Place::Village:
638                                 kdTree.NearNeighbors( &result, point, 1000 );
639                                 break;
640                         case Place::Town:
641                                 kdTree.NearNeighbors( &result, point, 5000 );
642                                 break;
643                         case Place::City:
644                                 kdTree.NearNeighbors( &result, point, 10000 );
645                                 break;
646                         }
647
648                         for ( std::vector< InputPoint >::const_iterator i = result.begin(), e = result.end(); i != e; ++i ) {
649                                 UnsignedCoordinate coordinate( i->coordinates[0], i->coordinates[1] );
650                                 double distance =  coordinate.ToGPSCoordinate().ApproximateDistance( place->coordinate );
651                                 if ( distance >= nodeLocation->at( i->data ).distance )
652                                         continue;
653                                 nodeLocation->at( i->data ).isInPlace = true;
654                                 nodeLocation->at( i->data ).place = place - places.begin();
655                                 nodeLocation->at( i->data ).distance = distance;
656                         }
657                 }
658         }
659
660         qDebug() << "OSM Importer: assigned 'in-city' flags:" << time.restart() << "ms";
661
662         return true;
663 }
664
665 bool OSMImporter::remapEdges( QString filename, const std::vector< UnsignedCoordinate >& nodeCoordinates, const std::vector< NodeLocation >& nodeLocation )
666 {
667         FileStream edgeData( filename + "_edges" );
668         FileStream onewayEdgeData( filename + "_oneway_edges" );
669
670         if ( !edgeData.open( QIODevice::ReadOnly ) )
671                 return false;
672         if ( !onewayEdgeData.open( QIODevice::ReadOnly ) )
673                         return false;
674
675         FileStream mappedEdgesData( filename + "_mapped_edges" );
676         FileStream edgeAddressData( filename + "_address" );
677         FileStream edgePathsData( filename + "_paths" );
678
679         if ( !mappedEdgesData.open( QIODevice::WriteOnly ) )
680                 return false;
681         if ( !edgeAddressData.open( QIODevice::WriteOnly ) )
682                 return false;
683         if ( !edgePathsData.open( QIODevice::WriteOnly ) )
684                 return false;
685
686         unsigned oldRoutingNodes = m_routingNodes.size();
687
688         Timer time;
689
690         unsigned pathID = 0;
691         unsigned addressID = 0;
692
693         // bidirectional && oneway
694         for ( int onewayType = 0; onewayType < 2; onewayType++ ) {
695                 while ( true ) {
696                         double speed;
697                         unsigned id, numberOfPathNodes, type, nameID, refID;
698                         int addFixed, addPercentage;
699                         bool bidirectional, roundabout;
700                         std::vector< unsigned > way;
701
702                         if ( onewayType == 0 ) {
703                                 edgeData >> id >> nameID >> refID >> type >> roundabout >> speed >> addFixed >> addPercentage >> bidirectional >> numberOfPathNodes;
704                                 if ( edgeData.status() == QDataStream::ReadPastEnd )
705                                         break;
706                                 assert( bidirectional );
707                         } else {
708                                 onewayEdgeData >> id >> nameID >> refID >> type >> roundabout >> speed >> addFixed >> addPercentage >> bidirectional >> numberOfPathNodes;
709                                 if ( onewayEdgeData.status() == QDataStream::ReadPastEnd )
710                                         break;
711                                 assert( !bidirectional );
712                         }
713
714                         assert( ( int ) type < m_settings.highways.size() );
715                         if ( speed <= 0 )
716                                 speed = std::numeric_limits< double >::max();
717
718                         bool valid = true;
719
720                         for ( int i = 0; i < ( int ) numberOfPathNodes; ++i ) {
721                                 unsigned node;
722                                 if ( onewayType == 0 )
723                                         edgeData >> node;
724                                 else
725                                         onewayEdgeData >> node;
726                                 if ( !valid )
727                                         continue;
728
729                                 NodeID mappedNode = std::lower_bound( m_usedNodes.begin(), m_usedNodes.end(), node ) - m_usedNodes.begin();
730                                 if ( !nodeCoordinates[mappedNode].IsValid() ) {
731                                         qDebug() << "OSM Importer: inconsistent OSM data: skipping way with missing node coordinate";
732                                         valid = false;
733                                 }
734                                 way.push_back( mappedNode );
735                         }
736                         if ( !valid )
737                                 continue;
738
739                         for ( unsigned pathNode = 0; pathNode + 1 < way.size(); ) {
740                                 unsigned source = std::lower_bound( m_routingNodes.begin(), m_routingNodes.begin() + oldRoutingNodes, m_usedNodes[way[pathNode]] ) - m_routingNodes.begin();
741                                 if ( std::binary_search( m_noAccessNodes.begin(), m_noAccessNodes.end(), m_usedNodes[way[pathNode]] ) ) {
742                                         source = m_routingNodes.size();
743                                         m_routingNodes.push_back( m_usedNodes[way[pathNode]] );
744                                         m_inDegree.push_back( 0 );
745                                         m_outDegree.push_back( 0 );
746                                 }
747                                 assert( source < m_routingNodes.size() );
748                                 NodeID target = 0;
749                                 double seconds = 0;
750
751                                 EdgeInfo sourceInfo;
752                                 EdgeInfo targetInfo;
753                                 targetInfo.backward = sourceInfo.forward = true;
754                                 targetInfo.forward = sourceInfo.backward = bidirectional;
755                                 targetInfo.crossing = sourceInfo.crossing = false;
756                                 targetInfo.oldID = sourceInfo.oldID = id;
757                                 targetInfo.type = sourceInfo.type = type;
758
759                                 unsigned nextRoutingNode = pathNode + 1;
760                                 double lastAngle = 0;
761                                 while ( true ) {
762                                         m_statistics.numberOfSegments++;
763
764                                         NodeID from = way[nextRoutingNode - 1];
765                                         NodeID to = way[nextRoutingNode];
766                                         GPSCoordinate fromCoordinate = nodeCoordinates[from].ToGPSCoordinate();
767                                         GPSCoordinate toCoordinate = nodeCoordinates[to].ToGPSCoordinate();
768
769                                         double distance = fromCoordinate.Distance( toCoordinate );
770
771                                         double segmentSpeed = speed;
772                                         if ( m_settings.defaultCitySpeed && ( nodeLocation[from].isInPlace || nodeLocation[to].isInPlace ) ) {
773                                                 if ( segmentSpeed == std::numeric_limits< double >::max() ) {
774                                                         segmentSpeed = m_settings.highways[type].defaultCitySpeed;
775                                                         m_statistics.numberOfDefaultCitySpeed++;
776                                                 }
777                                         }
778
779                                         segmentSpeed = std::min( ( double ) m_settings.highways[type].maxSpeed, segmentSpeed );
780
781                                         segmentSpeed *= m_settings.highways[type].averageSpeed / 100.0;
782                                         segmentSpeed /= 1.0 + addPercentage / 100.0;
783
784                                         double toAngle;
785                                         if ( nextRoutingNode == pathNode + 1 ) {
786                                                 sourceInfo.angle = atan2( ( double ) nodeCoordinates[to].y - nodeCoordinates[from].y, ( double ) nodeCoordinates[to].x - nodeCoordinates[from].x );;
787                                                 sourceInfo.speed = segmentSpeed;
788                                                 sourceInfo.length = distance;
789                                                 lastAngle = sourceInfo.angle;
790                                                 toAngle = sourceInfo.angle + M_PI;
791                                         } else {
792                                                 toAngle = atan2( ( double ) nodeCoordinates[from].y - nodeCoordinates[to].y, ( double ) nodeCoordinates[from].x - nodeCoordinates[to].x );
793                                                 double halfAngle = ( lastAngle - toAngle ) / 2.0;
794                                                 double radius = sin( fabs( halfAngle ) ) / cos( fabs( halfAngle ) ) * distance / 2.0;
795                                                 double maxSpeed = sqrt( m_settings.tangentialAcceleration * radius ) * 3.6;
796                                                 if ( radius < 1000 && radius > 2.5 && maxSpeed < segmentSpeed ) // NAN and inf not possible
797                                                         segmentSpeed = maxSpeed; // turn radius and maximum tangential acceleration limit turning speed
798                                                 lastAngle = toAngle + M_PI;
799                                         }
800
801                                         seconds += distance * 3.6 / segmentSpeed;
802                                         seconds += addFixed;
803
804                                         unsigned nodePenalty = std::lower_bound( m_penaltyNodes.begin(), m_penaltyNodes.end(), m_usedNodes[from] ) - m_penaltyNodes.begin();
805                                         if ( nodePenalty < m_penaltyNodes.size() && m_penaltyNodes[nodePenalty].id == m_usedNodes[from] )
806                                                 seconds += m_penaltyNodes[nodePenalty].seconds;
807                                         nodePenalty = std::lower_bound( m_penaltyNodes.begin(), m_penaltyNodes.end(), m_usedNodes[to] ) - m_penaltyNodes.begin();
808                                         if ( nodePenalty < m_penaltyNodes.size() && m_penaltyNodes[nodePenalty].id == m_usedNodes[to] )
809                                                 seconds += m_penaltyNodes[nodePenalty].seconds;
810
811                                         bool splitPath = false;
812
813                                         if ( std::binary_search( m_noAccessNodes.begin(), m_noAccessNodes.end(), m_usedNodes[to] ) ) {
814                                                 target = m_routingNodes.size();
815                                                 m_routingNodes.push_back( m_usedNodes[to] );
816                                                 m_inDegree.push_back( 0 );
817                                                 m_outDegree.push_back( 0 );
818                                                 splitPath = true;
819                                         } else {
820                                                 target = std::lower_bound( m_routingNodes.begin(), m_routingNodes.begin() + oldRoutingNodes, m_usedNodes[to] ) - m_routingNodes.begin();
821                                                 if ( target < m_routingNodes.size() && m_routingNodes[target] == m_usedNodes[to] )
822                                                         splitPath = true;
823                                         }
824
825                                         if ( splitPath ) {
826                                                 targetInfo.angle = toAngle;
827                                                 if ( targetInfo.angle > M_PI )
828                                                         targetInfo.angle -= 2 * M_PI;
829                                                 targetInfo.speed = segmentSpeed;
830                                                 targetInfo.length = distance;
831                                                 break;
832                                         }
833
834                                         edgePathsData << nodeCoordinates[to].x << nodeCoordinates[to].y;
835
836                                         nextRoutingNode++;
837                                 }
838
839                                 char edgeIDAtSource = m_outDegree[source]; // == inDegree[source] for bidirectional edges
840                                 char edgeIDAtTarget = m_inDegree[target]; // == outDegree[target] for bidirectional edges
841
842                                 m_outDegree[source]++;
843                                 m_inDegree[target]++;
844                                 if ( m_outDegree[source] == std::numeric_limits< char >::max() ) {
845                                         qCritical() << "OSM Importer: node degree too large, node:" << m_usedNodes[source];
846                                         return false;
847                                 }
848                                 if ( m_inDegree[target] == std::numeric_limits< char >::max() ) {
849                                         qCritical() << "OSM Importer: node degree too large, node:" << m_usedNodes[target];
850                                         return false;
851                                 }
852                                 if ( onewayType == 0 ) {
853                                         m_outDegree[target]++;
854                                         m_inDegree[source]++;
855                                         if ( m_inDegree[source] == std::numeric_limits< char >::max() ) {
856                                                 qCritical() << "OSM Importer: node degree too large, node:" << m_usedNodes[source];
857                                                 return false;
858                                         }
859                                         if ( m_outDegree[target] == std::numeric_limits< char >::max() ) {
860                                                 qCritical() << "OSM Importer: node degree too large, node:" << m_usedNodes[target];
861                                                 return false;
862                                         }
863                                 }
864
865                                 sourceInfo.id = edgeIDAtSource;
866                                 targetInfo.id = edgeIDAtTarget;
867                                 sourceInfo.node = source;
868                                 targetInfo.node = target;
869                                 m_edgeInfo.push_back( sourceInfo );
870                                 m_edgeInfo.push_back( targetInfo );
871
872                                 std::vector< unsigned > wayPlaces;
873                                 for ( unsigned i = pathNode; i < nextRoutingNode; i++ ) {
874                                         if ( nodeLocation[way[i]].isInPlace )
875                                                 wayPlaces.push_back( nodeLocation[way[i]].place );
876                                 }
877                                 std::sort( wayPlaces.begin(), wayPlaces.end() );
878                                 wayPlaces.resize( std::unique( wayPlaces.begin(), wayPlaces.end() ) - wayPlaces.begin() );
879                                 for ( unsigned i = 0; i < wayPlaces.size(); i++ )
880                                         edgeAddressData << wayPlaces[i];
881
882                                 mappedEdgesData << source << target << bidirectional << seconds;
883                                 mappedEdgesData << nameID << refID;
884                                 if ( roundabout )
885                                         mappedEdgesData << unsigned( m_settings.highways.size() );
886                                 else
887                                         mappedEdgesData << type;
888                                 mappedEdgesData << pathID << nextRoutingNode - pathNode - 1;
889                                 mappedEdgesData << addressID << unsigned( wayPlaces.size() );
890                                 mappedEdgesData << qint8( edgeIDAtSource ) << qint8( edgeIDAtTarget );
891
892                                 pathID += nextRoutingNode - pathNode - 1;
893                                 addressID += wayPlaces.size();
894                                 pathNode = nextRoutingNode;
895
896                                 m_statistics.numberOfEdges++;
897                         }
898                 }
899
900                 if ( onewayType == 0 )
901                         qDebug() << "OSM Importer: remapped edges" << time.restart() << "ms";
902                 else
903                         qDebug() << "OSM Importer: remapped oneway edges" << time.restart() << "ms";
904         }
905
906         return true;
907 }
908
909 bool OSMImporter::computeTurningPenalties( QString filename )
910 {
911         FileStream restrictionData( filename + "_restrictions" );
912
913         if ( !restrictionData.open( QIODevice::ReadOnly ) )
914                 return false;
915
916         FileStream penaltyData( filename + "_penalties" );
917
918         if ( !penaltyData.open( QIODevice::WriteOnly ) )
919                 return false;
920
921         Timer time;
922
923         std::vector< RestrictionInfo > restrictions;
924         while ( true ) {
925                 RestrictionInfo restriction;
926                 restrictionData >> restriction.exclude;
927                 restrictionData >> restriction.from;
928                 restrictionData >> restriction.to;
929                 restrictionData >> restriction.via;
930
931                 if ( restrictionData.status() == QDataStream::ReadPastEnd )
932                         break;
933
934                 restrictions.push_back( restriction );
935         }
936
937         qDebug() << "OSM Importer: read restrictions:" << time.restart() << "ms";
938
939         std::sort( restrictions.begin(), restrictions.end() );
940         std::sort( m_edgeInfo.begin(), m_edgeInfo.end() );
941         double leftSum = 0;
942         double rightSum = 0;
943         double straightSum = 0;
944         unsigned left = 0;
945         unsigned right = 0;
946         unsigned straight = 0;
947         unsigned edge = 0;
948         unsigned restriction = 0;
949         std::vector< double > table;
950         std::vector< int > histogram( m_settings.highways.size(), 0 );
951         for ( unsigned node = 0; node < m_routingNodes.size(); node++ ) {
952                 penaltyData << ( int ) m_inDegree[node] << ( int ) m_outDegree[node];
953
954                 while ( edge < m_edgeInfo.size() && m_edgeInfo[edge].node < node )
955                         edge++;
956                 while ( restriction < restrictions.size() && restrictions[restriction].via < m_routingNodes[node] )
957                         restriction++;
958
959                 table.clear();
960                 table.resize( ( int ) m_inDegree[node] * m_outDegree[node], 0 );
961
962                 for ( unsigned i = restriction; i < restrictions.size() && restrictions[i].via == m_routingNodes[node]; i++ ) {
963                         unsigned from = std::numeric_limits< unsigned >::max();
964                         unsigned to = std::numeric_limits< unsigned >::max();
965                         //qDebug() << restrictions[i].from << restrictions[i].to;
966                         for ( unsigned j = edge; j < m_edgeInfo.size() && m_edgeInfo[j].node == node; j++ ) {
967                                 //qDebug() << m_edgeInfo[j].oldID;
968                                 if ( m_edgeInfo[j].oldID == restrictions[i].from )
969                                         from = m_edgeInfo[j].id;
970                                 if ( m_edgeInfo[j].oldID == restrictions[i].to )
971                                         to = m_edgeInfo[j].id;
972                                 if ( from != std::numeric_limits< unsigned >::max() && to != std::numeric_limits< unsigned >::max() ) {
973                                         table[from * m_outDegree[node] + to] = -1; // infinity == not allowed
974                                         m_statistics.numberOfRestrictionsApplied++;
975                                         break;
976                                 }
977                         }
978                 }
979
980                 histogram.assign( histogram.size(), 0 );
981                 for ( unsigned i = edge; i < m_edgeInfo.size() && m_edgeInfo[i].node == node; i++ ) {
982                         if ( m_edgeInfo[i].backward )
983                                 histogram[m_edgeInfo[i].type]++;
984                 }
985
986                 //penalties
987                 for ( unsigned i = edge; i < m_edgeInfo.size() && m_edgeInfo[i].node == node; i++ ) {
988                         const EdgeInfo& from = m_edgeInfo[i];
989                         if ( !from.backward )
990                                 continue;
991                         for ( unsigned j = edge; j < m_edgeInfo.size() && m_edgeInfo[j].node == node; j++ ) {
992                                 const EdgeInfo& to = m_edgeInfo[j];
993                                 if ( !to.forward )
994                                         continue;
995
996                                 unsigned tablePosition = ( int ) from.id * m_outDegree[node] + to.id;
997
998                                 if ( table[tablePosition] < 0 )
999                                         continue;
1000
1001                                 if ( from.speed == 0 || to.speed == 0 )
1002                                         continue;
1003                                 if ( m_settings.decceleration == 0 || m_settings.acceleration == 0 )
1004                                         continue;
1005
1006                                 double angle = fmod( ( from.angle - to.angle ) / M_PI * 180.0 + 360.0, 360.0 ) - 180.0;
1007                                 double radius = 1000;
1008                                 if ( fabs( angle ) < 189 ) {
1009                                          // turn radius witht he assumption that the resolution is at least 5m
1010                                         radius = sin( fabs( angle / 180.0 * M_PI ) / 2 ) / cos( fabs( angle / 180.0 * M_PI ) / 2 ) * std::min( 5.0, std::min( from.length, to.length ) ) / 2.0;
1011                                 }
1012                                 double maxVelocity = std::min( from.speed, to.speed );
1013                                 if ( radius < 1000 ) // NAN and inf not possible
1014                                         maxVelocity = std::min( maxVelocity, sqrt( m_settings.tangentialAcceleration * radius ) * 3.6 ); // turn radius and maximum tangential acceleration limit turning speed
1015
1016                                 if ( m_settings.highways[to.type].pedestrian && fabs( angle ) < 180 - 45 )
1017                                         maxVelocity = std::min( maxVelocity, ( double ) m_settings.pedestrian );
1018
1019                                 {
1020                                         int otherDirections = 0;
1021                                         int startType = from.type;
1022                                         bool equal = false;
1023                                         bool skip = true;
1024
1025                                         if ( angle < 0 && angle > -180 + 45 ) {
1026                                                 if ( m_settings.highways[from.type].otherLeftPenalty )
1027                                                         skip = false;
1028                                                 else if ( m_settings.highways[from.type].otherLeftEqual )
1029                                                         equal = true;
1030                                         } else if ( angle > 0 && angle < 180 - 45 ) {
1031                                                 if ( m_settings.highways[from.type].otherRightPenalty )
1032                                                         skip = false;
1033                                                 else if ( m_settings.highways[from.type].otherRightEqual )
1034                                                         equal = true;
1035                                         } else {
1036                                                 if ( m_settings.highways[from.type].otherStraightPenalty )
1037                                                         skip = false;
1038                                                 else if ( m_settings.highways[from.type].otherStraightEqual )
1039                                                         equal = true;
1040                                         }
1041
1042                                         if ( !skip ) {
1043                                                 if ( !equal )
1044                                                         startType++;
1045                                                 else
1046                                                         otherDirections--; // exclude your own origin
1047
1048                                                 if ( to.type >= startType && to.backward )
1049                                                         otherDirections--; // exclude your target
1050
1051                                                 for ( unsigned type = 0; type < histogram.size(); type++ ) {
1052                                                         if ( m_settings.highways[type].priority > m_settings.highways[from.type].priority )
1053                                                                 otherDirections += histogram[type];
1054                                                 }
1055
1056                                                 if ( otherDirections >= 1 )
1057                                                         maxVelocity = std::min( maxVelocity, ( double ) m_settings.otherCars );
1058                                         }
1059                                 }
1060
1061                                 // the time it takes to deccelerate vs the travel time assumed on the edge
1062                                 double decceleratingPenalty = ( from.speed - maxVelocity ) * ( from.speed - maxVelocity ) / ( 2 * from.speed * m_settings.decceleration * 3.6 );
1063                                 // the time it takes to accelerate vs the travel time assumed on the edge
1064                                 double acceleratingPenalty = ( to.speed - maxVelocity ) * ( to.speed - maxVelocity ) / ( 2 * to.speed * m_settings.acceleration * 3.6 );
1065
1066                                 table[tablePosition] = decceleratingPenalty + acceleratingPenalty;
1067                                 if ( angle < 0 && angle > -180 + 45 )
1068                                         table[tablePosition] += m_settings.highways[to.type].leftPenalty;
1069                                 if ( angle > 0 && angle < 180 - 45 )
1070                                         table[tablePosition] += m_settings.highways[to.type].rightPenalty;
1071                                 //if ( tables[position + from.id + m_inDegree[node] * to.id] > m_statistics.maxTurningPenalty ) {
1072                                 //      qDebug() << angle << radius << from.speed << to.speed << maxVelocity;
1073                                 //      qDebug() << from.length << to.length;
1074                                 //}
1075                                 m_statistics.maxTurningPenalty = std::max( m_statistics.maxTurningPenalty, table[tablePosition] );
1076                                 if ( angle < 0 && angle > -180 + 45 ) {
1077                                         leftSum += table[tablePosition];
1078                                         left++;
1079                                 } else if ( angle > 0 && angle < 180 - 45 ) {
1080                                         rightSum += table[tablePosition];
1081                                         right++;
1082                                 } else {
1083                                         straightSum += table[tablePosition];
1084                                         straight++;
1085                                 }
1086                         }
1087                 }
1088
1089                 for ( unsigned i = 0; i < table.size(); i++ )
1090                         penaltyData << table[i];
1091         }
1092
1093
1094         m_statistics.numberOfTurningPenalties = table.size();
1095         m_statistics.averageLeftPenalty = leftSum / left;
1096         m_statistics.averageRightPenalty = rightSum / right;
1097         m_statistics.averageStraightPenalty = straightSum / straight;
1098         qDebug() << "OSM Importer: computed turning penalties:" << time.restart() << "ms";
1099
1100         return true;
1101 }
1102
1103 void OSMImporter::readWay( OSMImporter::Way* way, const IEntityReader::Way& inputWay ) {
1104         way->direction = Way::NotSure;
1105         way->maximumSpeed = -1;
1106         way->type = -1;
1107         way->roundabout = false;
1108         way->name.clear();
1109         way->namePriority = m_settings.languageSettings.size();
1110         way->ref.clear();
1111         way->placeType = Place::None;
1112         way->placeName.clear();
1113         way->usefull = false;
1114         way->access = true;
1115         way->accessPriority = m_settings.accessList.size();
1116         way->addFixed = 0;
1117         way->addPercentage = 0;
1118
1119         for ( unsigned tag = 0; tag < inputWay.tags.size(); tag++ ) {
1120                 int key = inputWay.tags[tag].key;
1121                 QString value = inputWay.tags[tag].value;
1122
1123                 if ( key < WayTags::MaxTag ) {
1124                         switch ( WayTags::Key( key ) ) {
1125                         case WayTags::Oneway:
1126                                 {
1127                                         if ( value== "no" || value == "false" || value == "0" )
1128                                                 way->direction = Way::Bidirectional;
1129                                         else if ( value == "yes" || value == "true" || value == "1" )
1130                                                 way->direction = Way::Oneway;
1131                                         else if ( value == "-1" )
1132                                                 way->direction = Way::Opposite;
1133                                         break;
1134                                 }
1135                         case WayTags::Junction:
1136                                 {
1137                                         if ( value == "roundabout" ) {
1138                                                 if ( way->direction == Way::NotSure ) {
1139                                                         way->direction = Way::Oneway;
1140                                                         way->roundabout = true;
1141                                                 }
1142                                         }
1143                                         break;
1144                                 }
1145                         case WayTags::Highway:
1146                                 {
1147                                         if ( value == "motorway" ) {
1148                                                 if ( way->direction == Way::NotSure )
1149                                                         way->direction = Way::Oneway;
1150                                         } else if ( value =="motorway_link" ) {
1151                                                 if ( way->direction == Way::NotSure )
1152                                                         way->direction = Way::Oneway;
1153                                         }
1154
1155                                         for ( int type = 0; type < m_settings.highways.size(); type++ ) {
1156                                                 if ( value == m_settings.highways[type].value ) {
1157                                                         way->type = type;
1158                                                         way->usefull = true;
1159                                                 }
1160                                         }
1161                                         break;
1162                                 }
1163                         case WayTags::Ref:
1164                                 {
1165                                         way->ref = value;
1166                                         break;
1167                                 }
1168                         case WayTags::PlaceName:
1169                                 {
1170                                         way->placeName = value;
1171                                         break;
1172                                 }
1173                         case WayTags::Place:
1174                                 {
1175                                         way->placeType = parsePlaceType( value );
1176                                         break;
1177                                 }
1178                         case WayTags::MaxSpeed:
1179                                 {
1180                                         int index = -1;
1181                                         double factor = 1.609344;
1182                                         for ( unsigned i = 0; index == -1 && i < m_mphStrings.size(); i++ )
1183                                                 index = value.lastIndexOf( m_mphStrings[i] );
1184
1185                                         if ( index == -1 )
1186                                                 factor = 1;
1187
1188                                         for ( unsigned i = 0; index == -1 && i < m_kmhStrings.size(); i++ )
1189                                                 index = value.lastIndexOf( m_kmhStrings[i] );
1190
1191                                         if( index == -1 )
1192                                                 index = value.size();
1193                                         bool ok = true;
1194                                         double maxspeed = value.left( index ).toDouble( &ok );
1195                                         if ( ok ) {
1196                                                 way->maximumSpeed = maxspeed * factor;
1197                                                 //qDebug() << value << index << value.left( index ) << way->maximumSpeed;
1198                                                 m_statistics.numberOfMaxspeed++;
1199                                         }
1200                                         break;
1201                                 }
1202                         case WayTags::MaxTag:
1203                                 assert( false );
1204                         }
1205
1206                         continue;
1207                 }
1208
1209                 key -= WayTags::MaxTag;
1210                 if ( key < m_settings.languageSettings.size() ) {
1211                         if ( key < way->namePriority ) {
1212                                 way->namePriority = key;
1213                                 way->name = value;
1214                         }
1215
1216                         continue;
1217                 }
1218
1219                 key -= m_settings.languageSettings.size();
1220                 if ( key < m_settings.accessList.size() ) {
1221                                 if ( key < way->accessPriority ) {
1222                                         if ( value == "private" || value == "no" || value == "agricultural" || value == "forestry" || value == "delivery" ) {
1223                                                 way->access = false;
1224                                                 way->accessPriority = key;
1225                                         } else if ( value == "yes" || value == "designated" || value == "official" || value == "permissive" ) {
1226                                                 way->access = true;
1227                                                 way->accessPriority = key;
1228                                         }
1229                                 }
1230
1231                         continue;
1232                 }
1233         }
1234
1235         // rescan tags to apply modificators
1236         for ( unsigned tag = 0; tag < inputWay.tags.size(); tag++ ) {
1237                 int key = inputWay.tags[tag].key;
1238                 QString value = inputWay.tags[tag].value;
1239
1240                 for ( unsigned modificator = 0; modificator < m_wayModificatorIDs.size(); modificator++ ) {
1241                         if ( m_wayModificatorIDs[modificator] != key )
1242                                 continue;
1243
1244                         const MoNav::WayModificator& mod = m_settings.wayModificators[modificator];
1245                         if ( mod.checkValue && mod.value != value )
1246                                 continue;
1247
1248                         switch ( mod.type ) {
1249                         case MoNav::WayModifyFixed:
1250                                 way->addFixed += mod.modificatorValue.toInt();
1251                                 break;
1252                         case MoNav::WayModifyPercentage:
1253                                 way->addPercentage = std::min( way->addPercentage, mod.modificatorValue.toInt() );
1254                                 break;
1255                         case MoNav::WayAccess:
1256                                 way->access = mod.modificatorValue.toBool();
1257                                 break;
1258                         case MoNav::WayOneway:
1259                                 if ( mod.modificatorValue.toBool() )
1260                                         way->direction = Way::Oneway;
1261                                 else
1262                                         way->direction = Way::Bidirectional;
1263                                 break;
1264                         }
1265                 }
1266         }
1267 }
1268
1269 void OSMImporter::readNode( OSMImporter::Node* node, const IEntityReader::Node& inputNode ) {
1270         node->name.clear();
1271         node->namePriority = m_settings.languageSettings.size();
1272         node->type = Place::None;
1273         node->population = -1;
1274         node->penalty = 0;
1275         node->access = true;
1276         node->accessPriority = m_settings.accessList.size();
1277
1278         for ( unsigned tag = 0; tag < inputNode.tags.size(); tag++ ) {
1279                 int key = inputNode.tags[tag].key;
1280                 QString value = inputNode.tags[tag].value;
1281
1282                 if ( key < NodeTags::MaxTag ) {
1283                         switch ( NodeTags::Key( key ) ) {
1284                         case NodeTags::Place:
1285                                 {
1286                                         node->type = parsePlaceType( value );
1287                                         break;
1288                                 }
1289                         case NodeTags::Population:
1290                                 {
1291                                         bool ok;
1292                                         int population = value.toInt( &ok );
1293                                         if ( ok )
1294                                                 node->population = population;
1295                                         break;
1296                                 }
1297                         case NodeTags::Barrier:
1298                                 {
1299                                         if ( node->accessPriority == m_settings.accessList.size() )
1300                                                 node->access = false;
1301                                         break;
1302                                 }
1303                         case NodeTags::MaxTag:
1304                                 assert( false );
1305                         }
1306
1307                         continue;
1308                 }
1309
1310                 key -= NodeTags::MaxTag;
1311                 if ( key < m_settings.languageSettings.size() ) {
1312                         if ( key < node->namePriority ) {
1313                                 node->namePriority = key;
1314                                 node->name = value;
1315                         }
1316
1317                         continue;
1318                 }
1319
1320                 key -= m_settings.languageSettings.size();
1321                 if ( key < m_settings.accessList.size() ) {
1322                                 if ( key < node->accessPriority ) {
1323                                         if ( value == "private" || value == "no" || value == "agricultural" || value == "forestry" || value == "delivery" ) {
1324                                                 node->access = false;
1325                                                 node->accessPriority = key;
1326                                         } else if ( value == "yes" || value == "designated" || value == "official" || value == "permissive" ) {
1327                                                 node->access = true;
1328                                                 node->accessPriority = key;
1329                                         }
1330                                 }
1331
1332                         continue;
1333                 }
1334         }
1335
1336         // rescan tags to apply modificators
1337         for ( unsigned tag = 0; tag < inputNode.tags.size(); tag++ ) {
1338                 int key = inputNode.tags[tag].key;
1339                 QString value = inputNode.tags[tag].value;
1340
1341                 for ( unsigned modificator = 0; modificator < m_nodeModificatorIDs.size(); modificator++ ) {
1342                         if ( m_nodeModificatorIDs[modificator] != key )
1343                                 continue;
1344
1345                         const MoNav::NodeModificator& mod = m_settings.nodeModificators[modificator];
1346                         if ( mod.checkValue && mod.value != value )
1347                                 continue;
1348
1349                         switch ( mod.type ) {
1350                         case MoNav::NodeModifyFixed:
1351                                 node->penalty += mod.modificatorValue.toInt();
1352                                 break;
1353                         case MoNav::NodeAccess:
1354                                 node->access = mod.modificatorValue.toBool();
1355                                 break;
1356                         }
1357                 }
1358         }
1359 }
1360
1361 void OSMImporter::readRelation( Relation* relation, const IEntityReader::Relation& inputRelation )
1362 {
1363         relation->type = Relation::TypeNone;
1364         relation->restriction.access = true;
1365         relation->restriction.from = std::numeric_limits< unsigned >::max();
1366         relation->restriction.to = std::numeric_limits< unsigned >::max();;
1367         relation->restriction.via = std::numeric_limits< unsigned >::max();
1368         relation->restriction.type = Restriction::None;
1369
1370         for ( unsigned tag = 0; tag < inputRelation.tags.size(); tag++ ) {
1371                 int key = inputRelation.tags[tag].key;
1372                 QString value = inputRelation.tags[tag].value;
1373
1374                 if ( key < RelationTags::MaxTag ) {
1375                         switch ( RelationTags::Key( key ) ) {
1376                         case RelationTags::Type:
1377                                 {
1378                                         if ( value == "restriction" )
1379                                                 relation->type = Relation::TypeRestriction;
1380                                         break;
1381                                 }
1382                         case RelationTags::Except:
1383                                 {
1384                                         QStringList accessTypes = value.split( ';' );
1385                                         foreach( QString access, m_settings.accessList ) {
1386                                                 if ( accessTypes.contains( access ) )
1387                                                         relation->restriction.access = false;
1388                                         }
1389                                         break;
1390                                 }
1391                         case RelationTags::Restriction:
1392                                 {
1393                                         if ( value.startsWith( "no" ) )
1394                                                 relation->restriction.type = Restriction::No;
1395                                         else if ( value.startsWith( "only" ) )
1396                                                 relation->restriction.type = Restriction::Only;
1397                                         break;
1398                                 }
1399                         case RelationTags::MaxTag:
1400                                 assert( false );
1401                         }
1402
1403                         continue;
1404                 }
1405
1406         }
1407
1408         for ( unsigned i = 0; i < inputRelation.members.size(); i++ ) {
1409                 const IEntityReader::RelationMember& member = inputRelation.members[i];
1410                 if ( member.type == IEntityReader::RelationMember::Way && member.role == "from" )
1411                         relation->restriction.from = member.ref;
1412                 else if ( member.type == IEntityReader::RelationMember::Way && member.role == "to" )
1413                         relation->restriction.to = member.ref;
1414                 else if ( member.type == IEntityReader::RelationMember::Node && member.role == "via" )
1415                         relation->restriction.via = member.ref;
1416         }
1417 }
1418
1419 OSMImporter::Place::Type OSMImporter::parsePlaceType( const QString& type )
1420 {
1421         if ( type == "city" )
1422                 return Place::City;
1423         if ( type == "town" )
1424                 return Place::Town;
1425         if ( type == "village" )
1426                 return Place::Village;
1427         if ( type == "hamlet" )
1428                 return Place::Hamlet;
1429         if ( type == "suburb" )
1430                 return Place::Suburb;
1431         return Place::None;
1432 }
1433
1434 bool OSMImporter::SetIDMap( const std::vector< NodeID >& idMap )
1435 {
1436         FileStream idMapData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_id_map" );
1437
1438         if ( !idMapData.open( QIODevice::WriteOnly ) )
1439                 return false;
1440
1441         idMapData << unsigned( idMap.size() );
1442         for ( NodeID i = 0; i < ( NodeID ) idMap.size(); i++ )
1443                 idMapData << idMap[i];
1444
1445         return true;
1446 }
1447
1448 bool OSMImporter::GetIDMap( std::vector< NodeID >* idMap )
1449 {
1450         FileStream idMapData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_id_map" );
1451
1452         if ( !idMapData.open( QIODevice::ReadOnly ) )
1453                 return false;
1454
1455         unsigned numNodes;
1456
1457         idMapData >> numNodes;
1458         idMap->resize( numNodes );
1459
1460         for ( NodeID i = 0; i < ( NodeID ) numNodes; i++ ) {
1461                 unsigned temp;
1462                 idMapData >> temp;
1463                 ( *idMap )[i] = temp;
1464         }
1465
1466         if ( idMapData.status() == QDataStream::ReadPastEnd )
1467                 return false;
1468
1469         return true;
1470 }
1471
1472 bool OSMImporter::SetEdgeIDMap( const std::vector< NodeID >& idMap )
1473 {
1474         FileStream idMapData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_edge_id_map" );
1475
1476         if ( !idMapData.open( QIODevice::WriteOnly ) )
1477                 return false;
1478
1479         idMapData << unsigned( idMap.size() );
1480         for ( NodeID i = 0; i < ( NodeID ) idMap.size(); i++ )
1481                 idMapData << idMap[i];
1482
1483         return true;
1484 }
1485
1486 bool OSMImporter::GetEdgeIDMap( std::vector< NodeID >* idMap )
1487 {
1488         FileStream idMapData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_edge_id_map" );
1489
1490         if ( !idMapData.open( QIODevice::ReadOnly ) )
1491                 return false;
1492
1493         unsigned numEdges;
1494
1495         idMapData >> numEdges;
1496         idMap->resize( numEdges );
1497
1498         for ( NodeID i = 0; i < ( NodeID ) numEdges; i++ ) {
1499                 unsigned temp;
1500                 idMapData >> temp;
1501                 ( *idMap )[i] = temp;
1502         }
1503
1504         if ( idMapData.status() == QDataStream::ReadPastEnd )
1505                 return false;
1506
1507         return true;
1508 }
1509
1510 bool OSMImporter::GetRoutingEdges( std::vector< RoutingEdge >* data )
1511 {
1512         FileStream mappedEdgesData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_mapped_edges" );
1513
1514         if ( !mappedEdgesData.open( QIODevice::ReadOnly ) )
1515                 return false;
1516
1517         std::vector< int > nodeOutDegree;
1518         while ( true ) {
1519                 unsigned source, target, nameID, refID, type;
1520                 unsigned pathID, pathLength;
1521                 unsigned addressID, addressLength;
1522                 bool bidirectional;
1523                 double seconds;
1524                 qint8 edgeIDAtSource, edgeIDAtTarget;
1525
1526                 mappedEdgesData >> source >> target >> bidirectional >> seconds;
1527                 mappedEdgesData >> nameID >> refID >> type;
1528                 mappedEdgesData >> pathID >> pathLength;
1529                 mappedEdgesData >> addressID >> addressLength;
1530                 mappedEdgesData >> edgeIDAtSource >> edgeIDAtTarget;
1531
1532                 if ( mappedEdgesData.status() == QDataStream::ReadPastEnd )
1533                         break;
1534
1535                 RoutingEdge edge;
1536                 edge.source = source;
1537                 edge.target = target;
1538                 edge.bidirectional = bidirectional;
1539                 edge.distance = seconds;
1540                 edge.nameID = refID;
1541                 edge.type = type;
1542                 edge.pathID = pathID;
1543                 edge.pathLength = pathLength;
1544                 edge.edgeIDAtSource = edgeIDAtSource;
1545                 edge.edgeIDAtTarget = edgeIDAtTarget;
1546
1547                 data->push_back( edge );
1548
1549                 if ( source >= nodeOutDegree.size() )
1550                         nodeOutDegree.resize( source + 1, 0 );
1551                 if ( target >= nodeOutDegree.size() )
1552                         nodeOutDegree.resize( target + 1, 0 );
1553                 nodeOutDegree[source]++;
1554                 if ( bidirectional )
1555                         nodeOutDegree[target]++;
1556         }
1557
1558         for ( unsigned edge = 0; edge < data->size(); edge++ ) {
1559                 int branches = nodeOutDegree[data->at( edge ).target];
1560                 branches -= data->at( edge ).bidirectional ? 1 : 0;
1561                 ( *data )[edge].branchingPossible = branches > 1;
1562         }
1563
1564         return true;
1565 }
1566
1567 bool OSMImporter::GetRoutingNodes( std::vector< RoutingNode >* data )
1568 {
1569         FileStream routingCoordinatesData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_routing_coordinates" );
1570
1571         if ( !routingCoordinatesData.open( QIODevice::ReadOnly ) )
1572                 return false;
1573
1574         while ( true ) {
1575                 UnsignedCoordinate coordinate;
1576                 routingCoordinatesData >> coordinate.x >> coordinate.y;
1577                 if ( routingCoordinatesData.status() == QDataStream::ReadPastEnd )
1578                         break;
1579                 RoutingNode node;
1580                 node.coordinate = coordinate;
1581                 data->push_back( node );
1582         }
1583
1584         return true;
1585 }
1586
1587 bool OSMImporter::GetRoutingEdgePaths( std::vector< RoutingNode >* data )
1588 {
1589         FileStream edgePathsData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_paths" );
1590
1591         if ( !edgePathsData.open( QIODevice::ReadOnly ) )
1592                 return false;
1593
1594         while ( true ) {
1595                 UnsignedCoordinate coordinate;
1596                 edgePathsData >> coordinate.x >> coordinate.y;
1597                 if ( edgePathsData.status() == QDataStream::ReadPastEnd )
1598                         break;
1599                 RoutingNode node;
1600                 node.coordinate = coordinate;
1601                 data->push_back( node );
1602         }
1603         return true;
1604 }
1605
1606 bool OSMImporter::GetRoutingWayNames( std::vector< QString >* data )
1607 {
1608         FileStream wayRefsData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_way_refs" );
1609
1610         if ( !wayRefsData.open( QIODevice::ReadOnly ) )
1611                 return false;
1612
1613         while ( true ) {
1614                 QString ref;
1615                 wayRefsData >> ref;
1616                 if ( wayRefsData.status() == QDataStream::ReadPastEnd )
1617                         break;
1618                 data->push_back( ref );
1619         }
1620         return true;
1621 }
1622
1623 bool OSMImporter::GetRoutingWayTypes( std::vector< QString >* data )
1624 {
1625         FileStream wayTypesData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_way_types" );
1626
1627         if ( !wayTypesData.open( QIODevice::ReadOnly ) )
1628                 return false;
1629
1630         while ( true ) {
1631                 QString type;
1632                 wayTypesData >> type;
1633                 if ( wayTypesData.status() == QDataStream::ReadPastEnd )
1634                         break;
1635                 data->push_back( type );
1636         }
1637         return true;
1638 }
1639
1640 bool OSMImporter::GetRoutingPenalties( std::vector< char >* inDegree, std::vector< char >* outDegree, std::vector< double >* penalties )
1641 {
1642         QString filename = fileInDirectory( m_outputDirectory, "OSM Importer" );
1643
1644         FileStream penaltyData( filename + "_penalties" );
1645
1646         if ( !penaltyData.open( QIODevice::ReadOnly ) )
1647                 return false;
1648
1649         while ( true ) {
1650                 int in, out;
1651                 penaltyData >> in >> out;
1652                 if ( penaltyData.status() == QDataStream::ReadPastEnd )
1653                         break;
1654                 unsigned oldPosition = penalties->size();
1655                 for ( int i = 0; i < in; i++ ) {
1656                         for ( int j = 0; j < out; j++ ) {
1657                                 double penalty;
1658                                 penaltyData >> penalty;
1659                                 penalties->push_back( penalty );
1660                         }
1661                 }
1662                 if ( penaltyData.status() == QDataStream::ReadPastEnd ) {
1663                         penalties->resize( oldPosition );
1664                         qCritical() << "OSM Importer: Corrupt Penalty Data";
1665                         return false;
1666                 }
1667                 inDegree->push_back( in );
1668                 outDegree->push_back( out );
1669         }
1670
1671         return true;
1672 }
1673
1674 bool OSMImporter::GetAddressData( std::vector< Place >* dataPlaces, std::vector< Address >* dataAddresses, std::vector< UnsignedCoordinate >* dataWayBuffer, std::vector< QString >* addressNames )
1675 {
1676         QString filename = fileInDirectory( m_outputDirectory, "OSM Importer" );
1677
1678         FileStream mappedEdgesData( filename + "_mapped_edges" );
1679         FileStream routingCoordinatesData( filename + "_routing_coordinates" );
1680         FileStream placesData( filename + "_places" );
1681         FileStream edgeAddressData( filename + "_address" );
1682         FileStream edgePathsData( filename + "_paths" );
1683
1684         if ( !mappedEdgesData.open( QIODevice::ReadOnly ) )
1685                 return false;
1686         if ( !routingCoordinatesData.open( QIODevice::ReadOnly ) )
1687                 return false;
1688         if ( !placesData.open( QIODevice::ReadOnly ) )
1689                 return false;
1690         if ( !edgeAddressData.open( QIODevice::ReadOnly ) )
1691                 return false;
1692         if ( !edgePathsData.open( QIODevice::ReadOnly ) )
1693                 return false;
1694
1695         std::vector< UnsignedCoordinate > coordinates;
1696         while ( true ) {
1697                 UnsignedCoordinate node;
1698                 routingCoordinatesData >> node.x >> node.y;
1699                 if ( routingCoordinatesData.status() == QDataStream::ReadPastEnd )
1700                         break;
1701                 coordinates.push_back( node );
1702         }
1703
1704         while ( true ) {
1705                 GPSCoordinate gps;
1706                 unsigned type;
1707                 QString name;
1708                 unsigned population;
1709                 placesData >> gps.latitude >> gps.longitude >> type >> population >> name;
1710
1711                 if ( placesData.status() == QDataStream::ReadPastEnd )
1712                         break;
1713
1714                 Place place;
1715                 place.name = name;
1716                 place.population = population;
1717                 place.coordinate = UnsignedCoordinate( gps );
1718                 place.type = ( Place::Type ) type;
1719                 dataPlaces->push_back( place );
1720         }
1721
1722         std::vector< unsigned > edgeAddress;
1723         while ( true ) {
1724                 unsigned place;
1725                 edgeAddressData >> place;
1726                 if ( edgeAddressData.status() == QDataStream::ReadPastEnd )
1727                         break;
1728                 edgeAddress.push_back( place );
1729         }
1730
1731         std::vector< UnsignedCoordinate > edgePaths;
1732         while ( true ) {
1733                 UnsignedCoordinate coordinate;
1734                 edgePathsData >> coordinate.x >> coordinate.y;
1735                 if ( edgePathsData.status() == QDataStream::ReadPastEnd )
1736                         break;
1737                 edgePaths.push_back( coordinate );
1738         }
1739
1740         long long numberOfEdges = 0;
1741         long long numberOfAddressPlaces = 0;
1742
1743         while ( true ) {
1744                 unsigned source, target, nameID, refID, type;
1745                 unsigned pathID, pathLength;
1746                 unsigned addressID, addressLength;
1747                 bool bidirectional;
1748                 double seconds;
1749                 qint8 edgeIDAtSource, edgeIDAtTarget;
1750
1751                 mappedEdgesData >> source >> target >> bidirectional >> seconds;
1752                 mappedEdgesData >> nameID >> refID >> type;
1753                 mappedEdgesData >> pathID >> pathLength;
1754                 mappedEdgesData >> addressID >> addressLength;
1755                 mappedEdgesData >> edgeIDAtSource >> edgeIDAtTarget;
1756                 if ( mappedEdgesData.status() == QDataStream::ReadPastEnd )
1757                         break;
1758
1759                 if ( nameID == 0 || addressLength == 0 )
1760                         continue;
1761
1762                 Address newAddress;
1763                 newAddress.name = nameID;
1764                 newAddress.pathID = dataWayBuffer->size();
1765
1766                 dataWayBuffer->push_back( coordinates[source] );
1767                 for ( unsigned i = 0; i < pathLength; i++ )
1768                         dataWayBuffer->push_back( edgePaths[i + pathID] );
1769                 dataWayBuffer->push_back( coordinates[target] );
1770
1771                 newAddress.pathLength = pathLength + 2;
1772                 numberOfEdges++;
1773
1774                 for ( unsigned i = 0; i < addressLength; i++ ) {
1775                         newAddress.nearPlace = edgeAddress[i + addressID];
1776                         dataAddresses->push_back( newAddress );
1777
1778                         numberOfAddressPlaces++;
1779                 }
1780
1781         }
1782
1783         FileStream wayNamesData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_way_names" );
1784
1785         if ( !wayNamesData.open( QIODevice::ReadOnly ) )
1786                 return false;
1787
1788         while ( true ) {
1789                 QString name;
1790                 wayNamesData >> name;
1791                 if ( wayNamesData.status() == QDataStream::ReadPastEnd )
1792                         break;
1793                 addressNames->push_back( name );
1794         }
1795
1796         qDebug() << "OSM Importer: edges:" << numberOfEdges;
1797         qDebug() << "OSM Importer: address entries:" << numberOfAddressPlaces;
1798         qDebug() << "OSM Importer: address entries per way:" << ( double ) numberOfAddressPlaces / numberOfEdges;
1799         qDebug() << "OSM Importer: coordinates:" << dataWayBuffer->size();
1800         return true;
1801 }
1802
1803 bool OSMImporter::GetBoundingBox( BoundingBox* box )
1804 {
1805         FileStream boundingBoxData( fileInDirectory( m_outputDirectory, "OSM Importer" ) + "_bounding_box" );
1806
1807         if ( !boundingBoxData.open( QIODevice::ReadOnly ) )
1808                 return false;
1809
1810         GPSCoordinate minGPS, maxGPS;
1811
1812         boundingBoxData >> minGPS.latitude >> minGPS.longitude >> maxGPS.latitude >> maxGPS.longitude;
1813
1814         if ( boundingBoxData.status() == QDataStream::ReadPastEnd ) {
1815                 qCritical() << "error reading bounding box";
1816                 return false;
1817         }
1818
1819         box->min = UnsignedCoordinate( minGPS );
1820         box->max = UnsignedCoordinate( maxGPS );
1821         if ( box->min.x > box->max.x )
1822                 std::swap( box->min.x, box->max.x );
1823         if ( box->min.y > box->max.y )
1824                 std::swap( box->min.y, box->max.y );
1825
1826         return true;
1827 }
1828
1829 void OSMImporter::DeleteTemporaryFiles()
1830 {
1831         QString filename = fileInDirectory( m_outputDirectory, "OSM Importer" );
1832         QFile::remove( filename + "_address" );
1833         QFile::remove( filename + "_all_nodes" );
1834         QFile::remove( filename + "_bounding_box" );
1835         QFile::remove( filename + "_city_outlines" );
1836         QFile::remove( filename + "_edge_id_map" );
1837         QFile::remove( filename + "_edges" );
1838         QFile::remove( filename + "_id_map" );
1839         QFile::remove( filename + "_mapped_edges" );
1840         QFile::remove( filename + "_oneway_edges" );
1841         QFile::remove( filename + "_paths" );
1842         QFile::remove( filename + "_penalties" );
1843         QFile::remove( filename + "_places" );
1844         QFile::remove( filename + "_restrictions" );
1845         QFile::remove( filename + "_routing_coordinates" );
1846         QFile::remove( filename + "_way_names" );
1847         QFile::remove( filename + "_way_refs" );
1848         QFile::remove( filename + "_way_types" );
1849 }
1850
1851 Q_EXPORT_PLUGIN2( osmimporter, OSMImporter )