Play Route¶
Playback a previously recorded or generated GPS log navigation as input.
Setup¶
Prerequisites¶
Setting your API key token¶
To set your API key token, define it like this:
#define API_TOKEN "YOUR_API_KEY_TOKEN"
replacing YOUR_API_KEY_TOKEN
with your actual API key token text, within the quotes.
This can be done in the main()
function, before the following line:
#if defined(API_TOKEN)
or outside the main()
function, further up, or in a header file.
Although it is also possible to define your API key token as the text value of the GEM_TOKEN
environment variable, this is not recommended, as it is not secure.
Use case¶
Replay a previously recorded GPS log of a real or simulated navigation.
How to use the sample¶
The data.zip
input file should be copied from the directory of this example to the
Data/Res/
directory within the SDK install path. Example: C:\MAGICLANE\Data\Res\
where C:\MAGICLANE\
is the SDK install path.
When you open the sample, you’ll be viewing the scene from above. When the route calculation is completed a simulation will start.
How it works¶
Create an instance of
Environment
and set your API key token:
1int main( int argc, char** argv )
2{
3 std::string projectApiToken = "";
4#define API_TOKEN "YOUR_API_KEY_TOKEN"
5#if defined(API_TOKEN)
6 projectApiToken = std::string( API_TOKEN );
7#endif
8 // Sdk objects can be created & used below this line
9 Environment::SdkSession session(projectApiToken, { argc > 1 ? argv[1] : "" });
The SDK is initialized with your API key token string and the log file path, where to write the application logs. Note that the log file path is not initialized by default, the empty string above, after the API key token, which means that no logs are written. The log file path is initialized with the first command line argument, if any. Create a
gem::MapView
interactive map object, using an OpenGL context for 3D graphics, the SDK environment created above, and a touch event listener for interactive user touch and mouse input, such as pan and zoom.
1gem::SdkSettings().setAllowConnection( false, gem::OffboardListener() );
2
3std::string sdkResrcPath = Environment::GetInstance().GetResourcesPath();
4std::string inputRelativePath = "/Data/Res/";
5std::string inputAbsolutePath = sdkResrcPath + inputRelativePath;
6std::string inputDataArchive = inputAbsolutePath + "data.zip";
7
8MyListener listener( gem::String( argc > 1 ? argv[1] : inputDataArchive) );
9
10// Create an interactive map view
11CTouchEventListener pTouchEventListener;
12gem::StrongPointer<gem::MapView> mapView = gem::MapView::produce(session.produceOpenGLContext(
13 Environment::WindowFrameworks::Available, "PlayRoute", &pTouchEventListener), &listener);
14if ( !mapView )
15{
16 GEM_LOGE( "Error creating gem::MapView: %d", GEM_GET_API_ERROR() );
17 return 0;
18}
19gem::PositionService().addListener( &listener );
MyListener
is a custom class to unpack the archive and play back the GPS log. The instructions are loaded, if found. Then the route is loaded, if found. Finally, the.nmea
GPS position log (pre-recorded navigation) is loaded and set as the data source for the position service:gem::PositionService().setDataSource( dataSrc );
This starts the navigation replay by moving the green position arrow indicator along the route.
1MyListener( const gem::String& dataPath )
2{
3 auto dest = gem::FileSystem().makePath( gem::FileSystem().removeLastComponent( dataPath ), u"tmp/" );
4 gem::FileSystem().createFolder( dest, true );
5 gem::FileSystem().uncompress( dataPath, dest );
6 auto folder = gem::FileSystem().scan( dest, u"inst*.dat" );
7 for( const auto& it : folder.files )
8 {
9 auto pos = it.path.find( '_' );
10 if( pos != -1 )
11 {
12 m_instructions.emplace_back();
13 m_instructions.back().stamp = it.path.toInt( pos + 1 );
14 std::ifstream stream;
15 stream.open( it.path.toStdString().c_str(), std::ios::binary );
16 if( stream.good() )
17 {
18 stream.seekg( 0, std::ios::end );
19 m_instructions.back().inst.reserve( int( stream.tellg() ) );
20 stream.seekg( 0, std::ios::beg );
21 stream.read( m_instructions.back().inst.getBytes<char>(), m_instructions.back().inst.size() );
22 }
23 }
24 }
25 folder = gem::FileSystem().scan( dest, u"route.dat" );
26 if( !folder.files.empty() )
27 {
28 std::ifstream stream;
29 stream.open( folder.files[0].path.toStdString().c_str(), std::ios::binary );
30 if( stream.good() )
31 {
32 stream.seekg( 0, std::ios::end );
33 m_route.reserve( int(stream.tellg()) );
34 stream.seekg( 0, std::ios::beg );
35 stream.read( m_route.getBytes<char>(), m_route.size() );
36 }
37 }
38 folder = gem::FileSystem().scan( dest, u"*.nmea" );
39 if( !folder.files.empty() )
40 {
41 gem::sense::DataSourcePtr dataSrc = gem::sense::GMDataSourceFactory::produceLog( folder.files[0].path );
42 if( dataSrc )
43 {
44 dataSrc->start();
45 gem::PositionService().setDataSource( dataSrc );
46 m_startStamp = gem::Time::getUniversalTime().asInt();
47 }
48 }
49 folder = gem::FileSystem().scan( dest, u"*.style" );
50 if ( !folder.files.empty() )
51 m_stylePath = folder.files[0].path;
52 }
Use the special provided macro to keep the interactive map and wait until the user closes the window.
1 WAIT_UNTIL_WINDOW_CLOSE();
2 return 0;
3}