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 GPSGridClient::GetNearestEdge( Result* result, const UnsignedCoordinate& coordinate, double radius, double headingPenalty, double heading ) { const GPSCoordinate gps = coordinate.ToProjectedCoordinate().ToGPSCoordinate(); const GPSCoordinate gpsMoved( gps.latitude, gps.longitude + 1 ); const double unsigned_per_meter = (( double ) UnsignedCoordinate( ProjectedCoordinate( gpsMoved ) ).x - coordinate.x ) / gps.ApproximateDistance( gpsMoved ); // Convert radius and headingPenalty from meters to unsigned^2. double gridRadius = unsigned_per_meter * radius; double gridRadius2 = gridRadius * gridRadius; double gridHeadingPenalty = unsigned_per_meter * headingPenalty; double gridHeadingPenalty2 = gridHeadingPenalty * gridHeadingPenalty; // Convert heading from 'degrees from North' to 'radians from x-axis' // (clockwise, [0, 0] is topleft corner, [1, 1] is bottomright corner). heading = fmod( ( heading + 270 ) * 2.0 * M_PI / 360.0, 2 * M_PI ); static const int width = 32 * 32 * 32; ProjectedCoordinate position = coordinate.ToProjectedCoordinate(); NodeID yGrid = floor( position.y * width ); NodeID xGrid = floor( position.x * width ); // Set the distance to the nearest edge initially to infinity. result->gridDistance2 = 1e20; QVector< UnsignedCoordinate > path; checkCell( result, &path, xGrid - 1, yGrid - 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid - 1, yGrid, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid - 1, yGrid + 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid, yGrid - 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid, yGrid, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid, yGrid + 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid + 1, yGrid - 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid + 1, yGrid, coordinate, gridRadius2, gridHeadingPenalty2, heading ); checkCell( result, &path, xGrid + 1, yGrid + 1, coordinate, gridRadius2, gridHeadingPenalty2, heading ); if ( path.empty() ) return false; double length = 0; double lengthToNearest = 0; for ( int pathID = 1; pathID < path.size(); pathID++ ) { UnsignedCoordinate sourceCoord = path[pathID - 1]; UnsignedCoordinate targetCoord = path[pathID]; double xDiff = ( double ) sourceCoord.x - targetCoord.x; double yDiff = ( double ) sourceCoord.y - targetCoord.y; double distance = sqrt( xDiff * xDiff + yDiff * yDiff ); length += distance; if ( pathID < ( int ) result->previousWayCoordinates ) lengthToNearest += distance; else if ( pathID == ( int ) result->previousWayCoordinates ) lengthToNearest += result->percentage * distance; } if ( length == 0 ) result->percentage = 0; else result->percentage = lengthToNearest / length; return true; }