bool ContractionHierarchiesClient::LoadData() { QString filename = fileInDirectory( m_directory,"Contraction Hierarchies" ); UnloadData(); if ( !m_graph.loadGraph( filename, 1024 * 1024 * 4 ) ) return false; m_namesFile.setFileName( filename + "_names" ); if ( !openQFile( &m_namesFile, QIODevice::ReadOnly ) ) return false; m_names = ( const char* ) m_namesFile.map( 0, m_namesFile.size() ); if ( m_names == NULL ) return false; m_namesFile.close(); m_heapForward = new Heap( m_graph.numberOfNodes() ); m_heapBackward = new Heap( m_graph.numberOfNodes() ); QFile typeFile( filename + "_types" ); if ( !openQFile( &typeFile, QIODevice::ReadOnly ) ) return false; QByteArray buffer = typeFile.readAll(); QString types = QString::fromUtf8( buffer.constData() ); m_types = types.split( ';' ); return true; }
bool UnicodeTournamentTrieClient::LoadData() { UnloadData(); QString filename = fileInDirectory( directory, "Unicode Tournament Trie" ); trieFile = new QFile( filename + "_main" ); subTrieFile = new QFile( filename + "_sub" ); dataFile = new QFile( filename + "_ways" ); if ( !openQFile( trieFile, QIODevice::ReadOnly ) ) return false; if ( !openQFile( subTrieFile, QIODevice::ReadOnly ) ) return false; if ( !openQFile( dataFile, QIODevice::ReadOnly ) ) return false; trieData = ( char* ) trieFile->map( 0, trieFile->size() ); subTrieData = ( char* ) subTrieFile->map( 0, subTrieFile->size() ); if ( trieData == NULL ) { qDebug( "Failed to Memory Map trie data" ); return false; } if ( subTrieData == NULL ) { qDebug( "Failed to Memory Map sub trie data" ); return false; } return true; }
bool OSMRendererClient::load() { if ( m_advancedSettings == NULL ) m_advancedSettings = new OSMRSettingsDialog(); advancedSettingsChanged(); network = new QNetworkAccessManager( this ); diskCache = new QNetworkDiskCache( this ); QString cacheDir = QDesktopServices::storageLocation( QDesktopServices::CacheLocation ); if ( cacheDir == "" ) { cacheDir = QDesktopServices::storageLocation( QDesktopServices::TempLocation ); QDir dir( cacheDir ); dir.mkdir( "osmrenderer" ); dir.cd( "osmrenderer" ); cacheDir = dir.path(); } qDebug() << "set disk cache to: " << cacheDir; diskCache->setCacheDirectory( cacheDir ); network->setCache( diskCache ); connect( network, SIGNAL(finished(QNetworkReply*)), this, SLOT(finished(QNetworkReply*)) ); tileSize = 256; QFile settingsFile( fileInDirectory( m_directory, "OSM Renderer" ) + "_settings" ); if ( !openQFile( &settingsFile, QIODevice::ReadOnly ) ) return false; while ( true ) { int zoomLevel; if ( settingsFile.read( ( char* ) &zoomLevel, sizeof( zoomLevel ) ) != sizeof( zoomLevel ) ) break; m_zoomLevels.push_back( zoomLevel ); } return true; }
bool SpeedProfile::loadAccessTree( QString filename ) { QFile treeFile( filename ); if ( !openQFile( &treeFile, QIODevice::ReadOnly ) ) return false; QTextStream stream( &treeFile ); m_accessTree.clear(); QString name; QString parent; // format: // name1 parent1 // name2 parent2 ... // the source node has itself as a parent // a parent has to be defined before its referenced while ( true ) { stream >> name >> parent; if ( stream.status() != QTextStream::Ok ) break; if ( m_accessTree.contains( name ) ) { qCritical() << "Illegal access tree, duplicate entry:" << name; return false; } if ( parent != name && !m_accessTree.contains( parent ) ) { qCritical() << "Illegal access tree, parent not yet defined:" << parent; return false; } m_accessTree[name] = parent; } return true; }
bool MapnikRendererClient::loadTile( int x, int y, int zoom, int /*magnification*/, QPixmap** tile ) { const Box& box = m_boxes[zoom]; if ( x < box.minX || x >= box.maxX ) return false; if ( y < box.minY || y >= box.maxY ) return false; if ( m_fileZoom != zoom ) { m_indexFile->close(); m_tileFile->close(); QString filename = fileInDirectory( m_directory, "Mapnik Renderer" ); m_indexFile->setFileName( filename + QString( "_%1_index" ).arg( zoom ) ); if ( !openQFile( m_indexFile, QIODevice::ReadOnly ) ) return false; m_tileFile->setFileName( filename + QString( "_%1_tiles" ).arg( zoom ) ); if ( !openQFile( m_tileFile, QIODevice::ReadOnly ) ) return false; m_fileZoom = zoom; } qint64 indexPosition = qint64( y - box.minY ) * ( box.maxX - box.minX ) + ( x - box.minX ); m_indexFile->seek( indexPosition * ( sizeof( qint64 ) + sizeof( int ) ) ); qint64 start; int size; m_indexFile->read( ( char* ) &start, sizeof( start ) ); m_indexFile->read( ( char* ) &size, sizeof( size ) ); if ( size == 0 ) return false; m_tileFile->seek( start ); QByteArray data = m_tileFile->read( size ); *tile = new QPixmap( m_tileSize, m_tileSize ); if ( !( *tile )->loadFromData( data, "PNG" ) ) { qDebug() << "Failed to load picture:" << x << y << zoom << " data: (" << start << "-" << start + size << ")"; delete *tile; return false; } return true; }
bool GPSGridClient::LoadData() { UnloadData(); QString filename = fileInDirectory( directory, "GPSGrid" ); QFile configFile( filename + "_config" ); if ( !openQFile( &configFile, QIODevice::ReadOnly ) ) return false; index = new gg::Index( filename + "_index" ); index->SetCacheSize( 1024 * 1024 * cacheSize / 4 ); gridFile = new QFile( filename + "_grid" ); if ( !gridFile->open( QIODevice::ReadOnly ) ) { qCritical() << "failed to open file: " << gridFile->fileName(); return false; } return true; }
bool UnicodeTournamentTrie::Preprocess( IImporter* importer, QString dir ) { QString filename = fileInDirectory( dir, "Unicode Tournament Trie" ); QFile subTrieFile( filename + "_sub" ); QFile wayFile( filename + "_ways" ); if ( !openQFile( &subTrieFile, QIODevice::WriteOnly ) ) return false; if ( !openQFile( &wayFile, QIODevice::WriteOnly ) ) return false; std::vector< IImporter::Place > inputPlaces; std::vector< IImporter::Address > inputAddress; std::vector< UnsignedCoordinate > inputWayBuffer; std::vector< QString > inputWayNames; if ( !importer->GetAddressData( &inputPlaces, &inputAddress, &inputWayBuffer, &inputWayNames ) ) return false; Timer time; std::sort( inputAddress.begin(), inputAddress.end() ); qDebug() << "Unicode Tournament Trie: sorted addresses by importance:" << time.restart() << "ms"; std::vector< UnsignedCoordinate > wayBuffer; std::vector< utt::Node > trie( 1 ); unsigned address = 0; // build address name index QMultiHash< unsigned, unsigned > addressByName; for ( ; address < inputAddress.size(); address++ ) { addressByName.insert( inputAddress[address].name, address ); } // compute way lengths QList< unsigned > uniqueNames = addressByName.uniqueKeys(); std::vector< std::pair< double, unsigned > > wayLengths; for ( unsigned name = 0; name < ( unsigned ) uniqueNames.size(); name++ ) { QList< unsigned > segments = addressByName.values( uniqueNames[name] ); double distance = 0; for( unsigned segment = 0; segment < ( unsigned ) segments.size(); segment++ ) { const IImporter::Address segmentAddress = inputAddress[segment]; for ( unsigned coord = 1; coord < segmentAddress.pathLength; ++coord ) { GPSCoordinate sourceGPS = inputWayBuffer[segmentAddress.pathID + coord - 1].ToProjectedCoordinate().ToGPSCoordinate(); GPSCoordinate targetGPS = inputWayBuffer[segmentAddress.pathID + coord].ToProjectedCoordinate().ToGPSCoordinate(); distance += sourceGPS.ApproximateDistance( targetGPS ); } } wayLengths.push_back( std::pair< double, unsigned >( distance, name ) ); } // sort ways by aggregate lengths std::sort( wayLengths.begin(), wayLengths.end() ); std::vector< unsigned > wayImportance( uniqueNames.size() ); for ( unsigned way = 0; way < wayLengths.size(); way++ ) wayImportance[wayLengths[way].second] = way; wayLengths.clear(); std::vector< utt::Node > subTrie( 1 ); for ( unsigned name = 0; name < ( unsigned ) uniqueNames.size(); name++ ) { QList< unsigned > segments = addressByName.values( uniqueNames[name] ); // build edge connector data structures std::vector< EdgeConnector< UnsignedCoordinate>::Edge > connectorEdges; std::vector< unsigned > resultSegments; std::vector< unsigned > resultSegmentDescriptions; std::vector< bool > resultReversed; for ( unsigned segment = 0; segment < ( unsigned ) segments.size(); segment++ ) { const IImporter::Address& segmentAddress = inputAddress[segments[segment]]; EdgeConnector< UnsignedCoordinate >::Edge newEdge; newEdge.source = inputWayBuffer[segmentAddress.pathID]; newEdge.target = inputWayBuffer[segmentAddress.pathID + segmentAddress.pathLength - 1]; newEdge.reverseable = true; connectorEdges.push_back( newEdge ); } EdgeConnector< UnsignedCoordinate >::run( &resultSegments, &resultSegmentDescriptions, &resultReversed, connectorEdges ); // string places with the same name together unsigned nextID = 0; for ( unsigned segment = 0; segment < resultSegments.size(); segment++ ) { utt::Data subEntry; subEntry.start = wayBuffer.size(); for ( unsigned description = 0; description < resultSegments[segment]; description++ ) { unsigned segmentID = resultSegmentDescriptions[nextID + description]; const IImporter::Address& segmentAddress = inputAddress[segments[segmentID]]; std::vector< UnsignedCoordinate > path; for ( unsigned pathID = 0; pathID < segmentAddress.pathLength; pathID++ ) path.push_back( inputWayBuffer[pathID + segmentAddress.pathID]); if ( resultReversed[segmentID] ) std::reverse( path.begin(), path.end() ); int skipFirst = description == 0 ? 0 : 1; assert( skipFirst == 0 || wayBuffer.back() == path.front() ); wayBuffer.insert( wayBuffer.end(), path.begin() + skipFirst, path.end() ); } utt::PlaceData placeData; placeData.name = inputPlaces[inputAddress[segments[resultSegmentDescriptions[nextID]]].nearPlace].name; subEntry.length = wayBuffer.size() - subEntry.start; insert( &subTrie, wayImportance[name], inputWayNames[uniqueNames[name]], subEntry, placeData ); nextID += resultSegments[segment]; } } writeTrie( &subTrie, subTrieFile ); assert( address == inputAddress.size() ); qDebug() << "Unicode Tournament Trie: build tries and tournament trees:" << time.restart() << "ms"; for ( std::vector< UnsignedCoordinate >::const_iterator i = wayBuffer.begin(), e = wayBuffer.end(); i != e; ++i ) { wayFile.write( ( char* ) &i->x, sizeof( i->x ) ); wayFile.write( ( char* ) &i->y, sizeof( i->y ) ); } qDebug() << "Unicode Tournament Trie: wrote ways:" << time.restart() << "ms"; return true; }
bool TestImporter::parseDDSG( QString filename ) { QString outputPrefix = fileInDirectory( m_outputDirectory, "Test Importer" ); FileStream edgesData( outputPrefix + "_mapped_edges" ); FileStream routingCoordinatesData( outputPrefix + "_routing_coordinates" ); FileStream edgePathsData( outputPrefix + "_paths" ); FileStream wayRefsData( outputPrefix + "_way_refs" ); FileStream wayTypesData( outputPrefix + "_way_types" ); FileStream penaltyData( outputPrefix + "_penalties" ); FileStream boundingBoxData( outputPrefix + "_bounding_box" ); if ( !edgesData.open( QIODevice::WriteOnly ) ) return false; if ( !routingCoordinatesData.open( QIODevice::WriteOnly ) ) return false; if ( !edgePathsData.open( QIODevice::WriteOnly ) ) return false; if ( !wayRefsData.open( QIODevice::WriteOnly ) ) return false; if ( !wayTypesData.open( QIODevice::WriteOnly ) ) return false; if ( !penaltyData.open( QIODevice::WriteOnly ) ) return false; if ( !boundingBoxData.open( QIODevice::WriteOnly ) ) return false; QFile ddsgFile( filename ); if ( !openQFile( &ddsgFile, QIODevice::ReadOnly ) ) return false; QTextStream inputStream( &ddsgFile ); QString id; inputStream >> id; if ( id != "d" ) { qCritical() << "Not a ddsg file"; return false; } wayRefsData << ""; wayTypesData << ""; unsigned nodes; unsigned edges; inputStream >> nodes >> edges; std::vector< SimpleEdge > simpleEdges; qDebug() << "Test Importer:" << "reading" << nodes << " nodes and" << edges << "edges"; for ( unsigned i = 0; i < edges; i++ ) { unsigned from; unsigned to; unsigned weight; unsigned direction; inputStream >> from >> to >> weight >> direction; if ( direction == 3 ) continue; if ( from == to ) continue; SimpleEdge newEdge; newEdge.source = from; newEdge.target = to; newEdge.bidirectional = direction == 1; newEdge.distance = weight / 10.0; newEdge.forward = direction == 1 || direction == 0; newEdge.backward = direction == 2 || direction == 0; if ( from > to ) { std::swap( newEdge.source, newEdge.target ); std::swap( newEdge.forward, newEdge.backward ); } simpleEdges.push_back( newEdge ); } std::sort( simpleEdges.begin(), simpleEdges.end(), SimpleEdge::sortToMerge ); unsigned edgesLeft = 1; for ( unsigned i = 1; i < simpleEdges.size(); i++ ) { SimpleEdge& edge = simpleEdges[i]; SimpleEdge& otherEdge = simpleEdges[edgesLeft - 1]; simpleEdges[edgesLeft++] = edge; if ( edge.source != otherEdge.source ) continue; if ( edge.target != otherEdge.target ) continue; if ( edge.distance != otherEdge.distance ) continue; edgesLeft--; otherEdge.forward |= edge.forward; otherEdge.backward |= edge.backward; } simpleEdges.resize( edgesLeft ); unsigned biEdges = 0; for ( unsigned i = 0; i < simpleEdges.size(); i++ ) { if ( !simpleEdges[i].forward ) { std::swap( simpleEdges[i].source, simpleEdges[i].target ); std::swap( simpleEdges[i].forward, simpleEdges[i].backward ); } simpleEdges[i].bidirectional = simpleEdges[i].forward && simpleEdges[i].backward; biEdges += simpleEdges[i].bidirectional ? 1 : 0; assert( simpleEdges[i].forward ); } qDebug() << "Test Importer:" << biEdges << "bidirectional edges"; qDebug() << "Test Importer:" << edges - biEdges * 2 << "unidirectional edges"; qDebug() << "Test Importer:" << edges - edgesLeft << "edges removed"; std::sort( simpleEdges.begin(), simpleEdges.end() ); std::vector< char > in( nodes, 0 ); std::vector< char > out( nodes, 0 ); std::vector< char > bi( nodes, 0 ); qDebug() << "Test Importer:" << "writing" << simpleEdges.size() << "edges"; for ( unsigned i = 0; i < simpleEdges.size(); i++ ) { edgesData << simpleEdges[i].source << simpleEdges[i].target << simpleEdges[i].bidirectional << simpleEdges[i].distance; edgesData << unsigned( 0 ) << unsigned( 0 ) << unsigned ( 0 ); // name edgesData << unsigned( 0 ) << unsigned( 0 ); // path edgesData << unsigned( 0 ) << unsigned( 0 ); // address edgesData << qint8( out[simpleEdges[i].source]++ ) << qint8( in[simpleEdges[i].target]++ ); if ( simpleEdges[i].bidirectional ) { in[simpleEdges[i].source]++; out[simpleEdges[i].target]++; bi[simpleEdges[i].source]++; bi[simpleEdges[i].target]++; assert( in[simpleEdges[i].source] == out[simpleEdges[i].source] ); assert( in[simpleEdges[i].target] == out[simpleEdges[i].target] ); } } long long penalties = 0; long long uturns = 0; qDebug() << "Test Importer:" << "forbid uturns:" << m_settings.forbidUTurn; qDebug() << "Test Importer:" << "uturn penalty:" << m_settings.uTurnPenalty; for ( unsigned i = 0; i < nodes; i++ ) { routingCoordinatesData << unsigned( 0 ) << unsigned( 0 ); penaltyData << unsigned( in[i] ) << unsigned( out[i] ); for ( int from = 0; from < in[i]; from++ ) { for ( int to = 0; to < out[i]; to++ ) { double penalty = 0; if ( from == to && from < bi[i] ) { uturns++; if ( m_settings.forbidUTurn ) penalty = -1; else penalty = m_settings.uTurnPenalty; } penaltyData << penalty; penalties++; } } } qDebug() << "Test Importer:" << "wrote" << penalties << "penalties"; qDebug() << "Test Importer:" << uturns << "uturns"; return true; }
bool ContractionHierarchies::Preprocess( IImporter* importer, QString dir ) { QString filename = fileInDirectory( dir, "Contraction Hierarchies" ); std::vector< IImporter::RoutingNode > inputNodes; std::vector< IImporter::RoutingEdge > inputEdges; if ( !importer->GetRoutingNodes( &inputNodes ) ) return false; if ( !importer->GetRoutingEdges( &inputEdges ) ) return false; unsigned numEdges = inputEdges.size(); unsigned numNodes = inputNodes.size(); Contractor* contractor = new Contractor( numNodes, inputEdges ); std::vector< IImporter::RoutingEdge >().swap( inputEdges ); contractor->Run(); std::vector< Contractor::Witness > witnessList; contractor->GetWitnessList( witnessList ); std::vector< ContractionCleanup::Edge > contractedEdges; std::vector< ContractionCleanup::Edge > contractedLoops; contractor->GetEdges( &contractedEdges ); contractor->GetLoops( &contractedLoops ); delete contractor; ContractionCleanup* cleanup = new ContractionCleanup( inputNodes.size(), contractedEdges, contractedLoops, witnessList ); std::vector< ContractionCleanup::Edge >().swap( contractedEdges ); std::vector< ContractionCleanup::Edge >().swap( contractedLoops ); std::vector< Contractor::Witness >().swap( witnessList ); cleanup->Run(); std::vector< CompressedGraph::Edge > edges; std::vector< NodeID > map; cleanup->GetData( &edges, &map ); delete cleanup; { std::vector< unsigned > edgeIDs( numEdges ); for ( unsigned edge = 0; edge < edges.size(); edge++ ) { if ( edges[edge].data.shortcut ) continue; unsigned id = 0; unsigned otherEdge = edge; while ( true ) { if ( otherEdge == 0 ) break; otherEdge--; if ( edges[otherEdge].source != edges[edge].source ) break; if ( edges[otherEdge].target != edges[edge].target ) continue; if ( edges[otherEdge].data.shortcut ) continue; id++; } edgeIDs[edges[edge].data.id] = id; } importer->SetEdgeIDMap( edgeIDs ); } std::vector< IRouter::Node > nodes( numNodes ); for ( std::vector< IImporter::RoutingNode >::const_iterator i = inputNodes.begin(), iend = inputNodes.end(); i != iend; i++ ) nodes[map[i - inputNodes.begin()]].coordinate = i->coordinate; std::vector< IImporter::RoutingNode >().swap( inputNodes ); std::vector< IRouter::Node > pathNodes; { std::vector< IImporter::RoutingNode > edgePaths; if ( !importer->GetRoutingEdgePaths( &edgePaths ) ) return false; pathNodes.resize( edgePaths.size() ); for ( unsigned i = 0; i < edgePaths.size(); i++ ) pathNodes[i].coordinate = edgePaths[i].coordinate; } if ( !importer->GetRoutingEdges( &inputEdges ) ) return false; { std::vector< QString > inputNames; if ( !importer->GetRoutingWayNames( &inputNames ) ) return false; QFile nameFile( filename + "_names" ); if ( !openQFile( &nameFile, QIODevice::WriteOnly ) ) return false; std::vector< unsigned > nameMap( inputNames.size() ); for ( unsigned name = 0; name < inputNames.size(); name++ ) { nameMap[name] = nameFile.pos(); QByteArray buffer = inputNames[name].toUtf8(); buffer.push_back( ( char ) 0 ); nameFile.write( buffer ); } nameFile.close(); nameFile.open( QIODevice::ReadOnly ); const char* test = ( const char* ) nameFile.map( 0, nameFile.size() ); for ( unsigned name = 0; name < inputNames.size(); name++ ) { QString testName = QString::fromUtf8( test + nameMap[name] ); assert( testName == inputNames[name] ); } for ( unsigned edge = 0; edge < numEdges; edge++ ) inputEdges[edge].nameID = nameMap[inputEdges[edge].nameID]; } { std::vector< QString > inputTypes; if ( !importer->GetRoutingWayTypes( &inputTypes ) ) return false; QFile typeFile( filename + "_types" ); if ( !openQFile( &typeFile, QIODevice::WriteOnly ) ) return false; QStringList typeList; for ( unsigned type = 0; type < inputTypes.size(); type++ ) typeList.push_back( inputTypes[type] ); typeFile.write( typeList.join( ";" ).toUtf8() ); } for ( std::vector< IImporter::RoutingEdge >::iterator i = inputEdges.begin(), iend = inputEdges.end(); i != iend; i++ ) { i->source = map[i->source]; i->target = map[i->target]; } CompressedGraphBuilder* builder = new CompressedGraphBuilder( 1u << m_settings.blockSize, nodes, edges, inputEdges, pathNodes ); if ( !builder->run( filename, &map ) ) return false; delete builder; importer->SetIDMap( map ); return true; }
bool GPSGrid::Preprocess( IImporter* importer, QString dir ) { QString filename = fileInDirectory( dir, "GPSGrid" ); QFile gridFile( filename + "_grid" ); QFile configFile( filename + "_config" ); if ( !openQFile( &gridFile, QIODevice::WriteOnly ) ) return false; if ( !openQFile( &configFile, QIODevice::WriteOnly ) ) return false; std::vector< IImporter::RoutingNode > inputNodes; std::vector< IImporter::RoutingEdge > inputEdges; std::vector< unsigned > nodeIDs; std::vector< unsigned > edgeIDs; std::vector< IImporter::RoutingNode > edgePaths; if ( !importer->GetRoutingNodes( &inputNodes ) ) return false; if ( !importer->GetRoutingEdges( &inputEdges ) ) return false; if ( !importer->GetIDMap( &nodeIDs ) ) return false; if ( !importer->GetEdgeIDMap( &edgeIDs ) ) return false; if ( !importer->GetRoutingEdgePaths( &edgePaths ) ) return false; static const int width = 32 * 32 * 32; std::vector< GridImportEdge > grid; Timer time; for ( std::vector< IImporter::RoutingEdge >::const_iterator i = inputEdges.begin(); i != inputEdges.end(); ++i ) { std::vector< UnsignedCoordinate > path; path.push_back( inputNodes[i->source].coordinate ); for ( unsigned pathID = 0; pathID < i->pathLength; pathID++ ) path.push_back( edgePaths[pathID + i->pathID].coordinate ); path.push_back( inputNodes[i->target].coordinate ); std::vector< std::pair< unsigned, unsigned > > gridCells; for ( unsigned segment = 1; segment < path.size(); segment++ ) { ProjectedCoordinate sourceCoordinate = path[segment - 1].ToProjectedCoordinate(); ProjectedCoordinate targetCoordinate = path[segment].ToProjectedCoordinate(); sourceCoordinate.x *= width; sourceCoordinate.y *= width; targetCoordinate.x *= width; targetCoordinate.y *= width; NodeID minYGrid = floor( sourceCoordinate.y ); NodeID minXGrid = floor( sourceCoordinate.x ); NodeID maxYGrid = floor( targetCoordinate.y ); NodeID maxXGrid = floor( targetCoordinate.x ); if ( minYGrid > maxYGrid ) std::swap( minYGrid, maxYGrid ); if ( minXGrid > maxXGrid ) std::swap( minXGrid, maxXGrid ); for ( NodeID yGrid = minYGrid; yGrid <= maxYGrid; ++yGrid ) { for ( NodeID xGrid = minXGrid; xGrid <= maxXGrid; ++xGrid ) { if ( !clipEdge( sourceCoordinate, targetCoordinate, ProjectedCoordinate( xGrid, yGrid ), ProjectedCoordinate( xGrid + 1, yGrid + 1 ) ) ) continue; gridCells.push_back( std::pair< unsigned, unsigned >( xGrid, yGrid ) ); } } } std::sort( gridCells.begin(), gridCells.end() ); gridCells.resize( std::unique( gridCells.begin(), gridCells.end() ) - gridCells.begin() ); GridImportEdge clippedEdge; clippedEdge.edge = i - inputEdges.begin(); for ( unsigned cell = 0; cell < gridCells.size(); cell++ ) { clippedEdge.x = gridCells[cell].first; clippedEdge.y = gridCells[cell].second; grid.push_back( clippedEdge ); } } qDebug() << "GPS Grid: distributed edges:" << time.restart() << "ms"; qDebug() << "GPS Grid: overhead:" << grid.size() - inputEdges.size() << "duplicated edges"; qDebug() << "GPS Grid: overhead:" << ( grid.size() - inputEdges.size() ) * 100 / inputEdges.size() << "% duplicated edges"; std::sort( grid.begin(), grid.end() ); qDebug() << "GPS Grid: sorted edges:" << time.restart() << "ms"; std::vector< gg::GridIndex > tempIndex; qint64 position = 0; for ( std::vector< GridImportEdge >::const_iterator edge = grid.begin(); edge != grid.end(); ) { gg::Cell cell; gg::GridIndex entry; entry.x = edge->x; entry.y = edge->y; entry.position = position; tempIndex.push_back( entry ); do { const IImporter::RoutingEdge& originalEdge = inputEdges[edge->edge]; gg::Cell::Edge newEdge; newEdge.source = nodeIDs[originalEdge.source]; newEdge.target = nodeIDs[originalEdge.target]; newEdge.edgeID = edgeIDs[edge->edge]; newEdge.bidirectional = originalEdge.bidirectional; newEdge.pathID = cell.coordinates.size(); newEdge.pathLength = 2 + originalEdge.pathLength; cell.coordinates.push_back( inputNodes[originalEdge.source].coordinate ); for ( unsigned pathID = 0; pathID < originalEdge.pathLength; pathID++ ) cell.coordinates.push_back( edgePaths[pathID + originalEdge.pathID].coordinate ); cell.coordinates.push_back( inputNodes[originalEdge.target].coordinate ); cell.edges.push_back( newEdge ); edge++; } while ( edge != grid.end() && edge->x == entry.x && edge->y == entry.y ); ProjectedCoordinate min( ( double ) entry.x / width, ( double ) entry.y / width ); ProjectedCoordinate max( ( double ) ( entry.x + 1 ) / width, ( double ) ( entry.y + 1 ) / width ); unsigned maxSize = cell.edges.size() * sizeof( gg::Cell::Edge ) * 2 + cell.coordinates.size() * sizeof( UnsignedCoordinate ) * 2 + 100; unsigned char* buffer = new unsigned char[maxSize]; memset( buffer, 0, maxSize ); int size = cell.write( buffer, UnsignedCoordinate( min ), UnsignedCoordinate( max ) ); assert( size < ( int ) maxSize ); #ifndef NDEBUG gg::Cell unpackCell; unpackCell.read( buffer, UnsignedCoordinate( min ), UnsignedCoordinate( max ) ); assert( unpackCell == cell ); #endif gridFile.write( ( const char* ) &size, sizeof( size ) ); gridFile.write( ( const char* ) buffer, size ); delete[] buffer; position += size + sizeof( size ); } qDebug() << "GPS Grid: wrote cells:" << time.restart() << "ms"; gg::Index::Create( filename + "_index", tempIndex ); qDebug() << "GPS Grid: created index:" << time.restart() << "ms"; return true; }
bool MapnikRenderer::Preprocess( IImporter* importer, QString dir ) { QString filename = fileInDirectory( dir, "Mapnik Renderer" ); try { IImporter::BoundingBox box; if ( !importer->GetBoundingBox( &box ) ) return false; std::vector< IImporter::RoutingEdge > inputEdges; std::vector< IImporter::RoutingNode > inputNodes; std::vector< IImporter::RoutingNode > inputPaths; if ( m_settings.deleteTiles ) { if ( !importer->GetRoutingEdges( &inputEdges ) ) { qCritical() << "Mapnik Renderer: failed to read routing edges"; return false; } if ( !importer->GetRoutingNodes( &inputNodes ) ) { qCritical() << "Mapnik Renderer: failed to read routing nodes"; return false; } if ( !importer->GetRoutingEdgePaths( &inputPaths ) ) { qCritical() << "Mapnik Renderer: failed to read routing paths"; } } Timer time; mapnik::datasource_cache::instance().register_datasources( m_settings.plugins.toLatin1().constData() ); QDir fonts( m_settings.fonts ); mapnik::projection projection( "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over" ); mapnik::freetype_engine::register_font( fonts.filePath( "DejaVuSans.ttf" ).toLatin1().constData() ); mapnik::freetype_engine::register_font( fonts.filePath( "DejaVuSans-Bold.ttf" ).toLatin1().constData() ); mapnik::freetype_engine::register_font( fonts.filePath( "DejaVuSans-Oblique.ttf" ).toLatin1().constData() ); mapnik::freetype_engine::register_font( fonts.filePath( "DejaVuSans-BoldOblique.ttf" ).toLatin1().constData() ); qDebug() << "Mapnik Renderer: initialized mapnik connection:" << time.restart() << "ms"; int numThreads = omp_get_max_threads(); qDebug() << "Mapnik Renderer: using" << numThreads << "threads"; qDebug() << "Mapnik Renderer: x: " << box.min.x << "-" << box.max.x; qDebug() << "Mapnik Renderer: y: " << box.min.y << "-" << box.max.y; FileStream configData( filename ); if ( !configData.open( QIODevice::WriteOnly ) ) return false; configData << quint32( m_settings.tileSize ) << quint32( m_settings.zoomLevels.size() ); long long tilesSkipped = 0; long long tiles = 0; long long metaTilesRendered = 0; long long pngcrushSaved = 0; std::vector< ZoomInfo > zoomInfo( m_settings.zoomLevels.size() ); std::vector< MetaTile > tasks; for ( int zoomLevel = 0; zoomLevel < ( int ) m_settings.zoomLevels.size(); zoomLevel++ ) { ZoomInfo& info = zoomInfo[zoomLevel]; int zoom = m_settings.zoomLevels[zoomLevel]; info.minX = box.min.GetTileX( zoom ); info.maxX = box.max.GetTileX( zoom ) + 1; info.minY = box.min.GetTileY( zoom ); info.maxY = box.max.GetTileY( zoom ) + 1; if ( zoom <= m_settings.fullZoom ) { info.minX = info.minY = 0; info.maxX = info.maxY = 1 << zoom; } else { info.minX = std::max( 0 , info.minX - m_settings.tileMargin ); info.maxX = std::min ( 1 << zoom, info.maxX + m_settings.tileMargin ); info.minY = std::max( 0, info.minY - m_settings.tileMargin ); info.maxY = std::min ( 1 << zoom, info.maxY + m_settings.tileMargin ); } tiles += ( info.maxX - info.minX ) * ( info.maxY - info.minY ); qDebug() << "Mapnik Renderer: [" << zoom << "] x:" << info.minX << "-" << info.maxX << "; y:" << info.minY << "-" << info.maxY; configData << quint32( zoom ) << quint32( info.minX ) << quint32( info.maxX ) << quint32( info.minY ) << quint32( info.maxY ); int numberOfTiles = ( info.maxX - info.minX ) * ( info.maxY - info.minY ); IndexElement dummyIndex; dummyIndex.start = dummyIndex.size = 0; info.index.resize( numberOfTiles, dummyIndex ); std::vector< UnsignedCoordinate > path; for ( std::vector< IImporter::RoutingEdge >::const_iterator i = inputEdges.begin(), e = inputEdges.end(); i != e; ++i ) { path.push_back( inputNodes[i->source].coordinate ); for ( int pathID = 0; pathID < i->pathLength; pathID++ ) path.push_back( inputPaths[pathID + i->pathID].coordinate ); path.push_back( inputNodes[i->target].coordinate ); for ( unsigned edge = 0; edge < path.size(); edge++ ) { int sourceX = path[edge].GetTileX( zoom ); int sourceY = path[edge].GetTileY( zoom ); int targetX = path[edge].GetTileX( zoom ); int targetY = path[edge].GetTileY( zoom ); if ( sourceX > targetX ) std::swap( sourceX, targetX ); if ( sourceY > targetY ) std::swap( sourceY, targetY ); sourceX = std::max( sourceX, info.minX ); sourceX = std::min( sourceX, info.maxX - 1 ); sourceY = std::max( sourceY, info.minY ); sourceY = std::min( sourceY, info.maxY - 1 ); targetX = std::max( targetX, info.minX ); targetX = std::min( targetX, info.maxX - 1 ); targetY = std::max( targetY, info.minY ); targetY = std::min( targetY, info.maxY - 1 ); for ( int x = sourceX; x <= targetX; ++x ) for ( int y = sourceY; y <= targetY; ++y ) info.index[( x - info.minX ) + ( y - info.minY ) * ( info.maxX - info.minX )].size = 1; } path.clear(); } info.tilesFile = new QFile( filename + QString( "_%1_tiles" ).arg( zoom ) ); if ( !openQFile( info.tilesFile, QIODevice::WriteOnly ) ) return false; for ( int x = info.minX; x < info.maxX; x+= m_settings.metaTileSize ) { int metaTileSizeX = std::min( m_settings.metaTileSize, info.maxX - x ); for ( int y = info.minY; y < info.maxY; y+= m_settings.metaTileSize ) { int metaTileSizeY = std::min( m_settings.metaTileSize, info.maxY - y ); MetaTile tile; tile.zoom = zoomLevel; tile.x = x; tile.y = y; tile.metaTileSizeX = metaTileSizeX; tile.metaTileSizeY = metaTileSizeY; tasks.push_back( tile ); } } } #pragma omp parallel { int threadID = omp_get_thread_num(); const int metaTileSize = m_settings.metaTileSize * m_settings.tileSize + 2 * m_settings.margin; mapnik::Map map; mapnik::image_32 image( metaTileSize, metaTileSize ); QTemporaryFile tempOut; QTemporaryFile tempIn; mapnik::load_map( map, m_settings.theme.toLocal8Bit().constData() ); #pragma omp for schedule( dynamic ) for ( int i = 0; i < ( int ) tasks.size(); i++ ) { int metaTileSizeX = tasks[i].metaTileSizeX; int metaTileSizeY = tasks[i].metaTileSizeY; int x = tasks[i].x; int y = tasks[i].y; int zoomLevel = tasks[i].zoom; int zoom = m_settings.zoomLevels[zoomLevel]; ZoomInfo& info = zoomInfo[zoomLevel]; map.resize( metaTileSizeX * m_settings.tileSize + 2 * m_settings.margin, metaTileSizeY * m_settings.tileSize + 2 * m_settings.margin ); ProjectedCoordinate drawTopLeft( x - 1.0 * m_settings.margin / m_settings.tileSize, y - 1.0 * m_settings.margin / m_settings.tileSize, zoom ); ProjectedCoordinate drawBottomRight( x + metaTileSizeX + 1.0 * m_settings.margin / m_settings.tileSize, y + metaTileSizeY + 1.0 * m_settings.margin / m_settings.tileSize, zoom ); GPSCoordinate drawTopLeftGPS = drawTopLeft.ToGPSCoordinate(); GPSCoordinate drawBottomRightGPS = drawBottomRight.ToGPSCoordinate(); projection.forward( drawTopLeftGPS.longitude, drawBottomRightGPS.latitude ); projection.forward( drawBottomRightGPS.longitude, drawTopLeftGPS.latitude ); mapnik::box2d<double> boundingBox( drawTopLeftGPS.longitude, drawTopLeftGPS.latitude, drawBottomRightGPS.longitude, drawBottomRightGPS.latitude ); map.zoom_to_box( boundingBox ); mapnik::agg_renderer<mapnik::image_32> renderer( map, image ); renderer.apply(); std::string data; int skipped = 0; int saved = 0; for ( int subX = 0; subX < metaTileSizeX; ++subX ) { for ( int subY = 0; subY < metaTileSizeY; ++subY ) { int indexNumber = ( y + subY - info.minY ) * ( info.maxX - info.minX ) + x + subX - info.minX; mapnik::image_view<mapnik::image_data_32> view = image.get_view( subX * m_settings.tileSize + m_settings.margin, subY * m_settings.tileSize + m_settings.margin, m_settings.tileSize, m_settings.tileSize ); std::string result; if ( !m_settings.deleteTiles || info.index[( x + subX - info.minX ) + ( y + subY - info.minY ) * ( info.maxX - info.minX )].size == 1 ) { if ( m_settings.reduceColors ) result = mapnik::save_to_string( view, "png256" ); else result = mapnik::save_to_string( view, "png" ); if ( m_settings.pngcrush ) { tempOut.open(); tempOut.write( result.data(), result.size() ); tempOut.flush(); tempIn.open(); pclose( popen( ( "pngcrush " + tempOut.fileName() + " " + tempIn.fileName() ).toUtf8().constData(), "r" ) ); QByteArray buffer = tempIn.readAll(); tempIn.close(); tempOut.close(); if ( buffer.size() != 0 && buffer.size() < ( int ) result.size() ) { saved += result.size() - buffer.size(); result.assign( buffer.constData(), buffer.size() ); } } } info.index[indexNumber].start = data.size(); info.index[indexNumber].size = result.size(); data += result; } } qint64 position; #pragma omp critical { position = info.tilesFile->pos(); info.tilesFile->write( data.data(), data.size() ); metaTilesRendered++; tilesSkipped += skipped; pngcrushSaved += saved; qDebug() << "Mapnik Renderer: [" << zoom << "], thread" << threadID << ", metatiles:" << metaTilesRendered << "/" << tasks.size(); } for ( int subX = 0; subX < metaTileSizeX; ++subX ) { for ( int subY = 0; subY < metaTileSizeY; ++subY ) { int indexNumber = ( y + subY - info.minY ) * ( info.maxX - info.minX ) + x + subX - info.minX; info.index[indexNumber].start += position; } } } } for ( int zoomLevel = 0; zoomLevel < ( int ) m_settings.zoomLevels.size(); zoomLevel++ ) { const ZoomInfo& info = zoomInfo[zoomLevel]; int zoom = m_settings.zoomLevels[zoomLevel]; QFile indexFile( filename + QString( "_%1_index" ).arg( zoom ) ); if ( !openQFile( &indexFile, QIODevice::WriteOnly ) ) return false; for ( int i = 0; i < ( int ) info.index.size(); i++ ) { indexFile.write( ( const char* ) &info.index[i].start, sizeof( info.index[i].start ) ); indexFile.write( ( const char* ) &info.index[i].size, sizeof( info.index[i].size ) ); } delete info.tilesFile; } if ( m_settings.deleteTiles ) qDebug() << "Mapnik Renderer: removed" << tilesSkipped << "tiles"; if ( m_settings.pngcrush ) qDebug() << "Mapnik Renderer: PNGcrush saved" << pngcrushSaved / 1024 / 1024 << "MB"; qDebug() << "Mapnik Renderer: finished:" << time.restart() << "ms"; } catch ( const mapnik::config_error & ex ) { qCritical( "Mapnik Renderer: ### Configuration error: %s", ex.what() ); return false; } catch ( const std::exception & ex ) { qCritical( "Mapnik Renderer: ### STD error: %s", ex.what() ); return false; } catch ( ... ) { qCritical( "Mapnik Renderer: ### Unknown error" ); return false; } return true; }