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;
}
Esempio n. 2
0
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;
}