Offline Map

3173
11
Jump to solution
07-23-2017 06:54 AM
Kai_Wellmann
New Contributor II

What is the best way to generate an offline Map. I only need a basemap without any layers displayed (Basemap* basemap = Basemap::topographic(this)) which i can take offline or is it possible to download a whole area like germany? I read the Create an offline map—ArcGIS Runtime SDK for Qt | ArcGIS for Developers  but couldn't find any samples. 

1 Solution

Accepted Solutions
LucasDanzinger
Esri Frequent Contributor

Kai-

A couple of things might be going on.

1) Can you try adding one of the basemaps from this list? http://www.arcgis.com/home/group.html?id=3a890be7a4b046c7840dc4a0446c5b31&start=1&view=list&sortOrde... These basemaps support the "export tiles" REST endpoint, which is required to take the basemap offline. Many basemaps auto-redirect to the appropriate export tiles version of the service (for example, if you add the regular World Imagery and try to take that offline, it will automatically switch to use the World Imagery (for export) service), but it seems we missed Nat Geo in that list.

2) I may have led you astray with the suggestion to use the constructor with the credential in it. Instead, you should use the AuthenticationManager. The AuthenticationManager is basically a singleton class that emits a signal whenever a new authentication challenge comes through. If you create a Map that is private, but don't provide a credential, the AuthenticationManager will emit a signal indicating that a credential is required, and you can then create the credential and set it there. What this will do is add the credential to the credential cache, so that the API can automatically start using that credential for further authentication challenges. Here is the doc for this class AuthenticationManager Class | ArcGIS for Developers , and here is a sample of using the AuthenticationView QML toolkit control to handle most of it for you arcgis-runtime-samples-qt/ArcGISRuntimeSDKQt_CppSamples/CloudAndPortal/TokenAuthentication at master... 

View solution in original post

0 Kudos
11 Replies
LucasDanzinger
Esri Frequent Contributor

We don't have a sample for that yet. However, you should be able to create an OfflineMapTask object from a Map and optional Credentials. Once you do that, call createDefaultGenerateOfflineMapParameters and pass in your extent OfflineMapTask Class | ArcGIS for Developers . This will create your parameters for the job.

Finally, call generateOfflineMap, pass in the parameters you just created, and start the job object that is returned. OfflineMapTask Class | ArcGIS for Developers 

0 Kudos
Kai_Wellmann
New Contributor II

Many thanks for your advice. I have modified the ExportTiles sample and have used the recommended classes. But every time when I call the exportTileCacheFromCorners function I get the following error:

 

Job failed. Job error 6 Illegal state. The online map must have an item property which is its online portal item

 

 

What is the reason for this error?

 

 

I have included some code snippets.

 

 

 

void ExportTiles::componentComplete()

{

  QQuickItem::componentComplete();

  GenerateOfflineMapJob *job;

  m_cre=new Credential("User","Password ");

 

  // find QML MapView component

  m_mapView = findChild<MapQuickView*>("mapView");

 

  ArcGISTiledLayer* tiledLayer = new ArcGISTiledLayer(m_serviceUrl);  //http://sampleserver6.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer

  Basemap* basemap = new Basemap(tiledLayer, this);

  m_map = new Map(basemap, this);

 

 

  // set an initial viewpoint

  Envelope env(12362601, 936021, 10187678, 2567213, SpatialReference(3857));

 

  Viewpoint viewpoint(env);

  m_map->setInitialViewpoint(viewpoint);

 

 

  // set map on the map view

  m_mapView->setMap(m_map);

 

 

}

 

void ExportTiles::exportTileCacheFromCorners(double xCorner1, double yCorner1, double xCorner2, double yCorner2, QString dataPath)

{

  // create an envelope from the QML rectangle corners

  auto corner1 = m_mapView->screenToLocation(xCorner1, yCorner1);

  auto corner2 = m_mapView->screenToLocation(xCorner2, yCorner2);

  auto extent = Envelope(corner1, corner2);

  auto tileCacheExtent = GeometryEngine::project(extent, SpatialReference::webMercator());

  Envelope env(12362601, 936021, 10187678, 2567213, SpatialReference(3857));

 

  // create the task with the url and load it

  m_task=new OfflineMapTask(m_map,m_cre);

 

 

 

  connect(m_task, &OfflineMapTask::createDefaultGenerateOfflineMapParametersCompleted, this, [this, env](QUuid, GenerateOfflineMapParameters parameters)

  {

      m_parameters=parameters;

      m_parameters.setAreaOfInterest(env);

     GenerateOfflineMapJob *job=m_task->generateOfflineMap(m_parameters,"/home/user/tmp");

      if (job)

      {

          connect(job,&GenerateOfflineMapJob::jobStatusChanged,job,[job,this]()

          {

              QList<JobMessage> msg;

              JobStatus status=job->jobStatus();

 

              switch (job->jobStatus()) {

                case JobStatus::Failed:

                  msg=job->messages();

                  for (int i=0;i<msg.count();i++)

                  {

                      qDebug() << msg.message();

                  }

                  emit updateStatus("Export failed");

                  emit hideWindow(5000, false);

                  break;

                case JobStatus::NotStarted:

                  emit updateStatus("Job not started");

                  break;

                case JobStatus::Paused:

                  emit updateStatus("Job paused");

                  break;

                case JobStatus::Started:

                  emit updateStatus("In progress...");

                  break;

                case JobStatus::Succeeded:

                  emit updateStatus("Adding TPK...");

                  emit hideWindow(1500, true);

                  //displayOutputTileCache(job->result());

                  break;

                default:

                  break;

                }

 

          });

         bool rueck=job->start();

 

      }

      else

         {

           emit updateStatus("Export failed");

           emit hideWindow(5000, false);

         }

 

 

  });

  TaskWatcher tw=m_task->createDefaultGenerateOfflineMapParameters(env);

 

 

}

0 Kudos
LucasDanzinger
Esri Frequent Contributor

Kai-

I believe the issue is that you are creating the map programmatically in your application code, but the OfflineMapTask is designed to take a web map saved in ArcGIS Online/Portal and take all of its layers offline. Instead of building up the map programmatically, can you instead create the map in ArcGIS Online/Portal, and then try to take that offline?

Thanks,

Luke

0 Kudos
Kai_Wellmann
New Contributor II

Hi Luke,

I created two maps on the arcgis portal and I set them to offline. The  first Basemap is National Geographic and the other one is Openstreetmap. I used the OfflineMapTask. With the National Geographic Basemap I get the following Error  "User does not have permissions to access 'natgeo_world_map.mapserver'." " and with the other map I get this Error "Unsupported layer type" "Layer type is not supported for taking offline" Openstreetmap. A tmp folder is generated which contains a package.info and a p13 folder which contains a mobile_map.mmap file. I have only a developer account and i am planning to use the lite licence. Is it possible that my liecence dosen't allow to download offline maps (mmpk or tpks).

0 Kudos
LucasDanzinger
Esri Frequent Contributor

Kai-

A couple of things might be going on.

1) Can you try adding one of the basemaps from this list? http://www.arcgis.com/home/group.html?id=3a890be7a4b046c7840dc4a0446c5b31&start=1&view=list&sortOrde... These basemaps support the "export tiles" REST endpoint, which is required to take the basemap offline. Many basemaps auto-redirect to the appropriate export tiles version of the service (for example, if you add the regular World Imagery and try to take that offline, it will automatically switch to use the World Imagery (for export) service), but it seems we missed Nat Geo in that list.

2) I may have led you astray with the suggestion to use the constructor with the credential in it. Instead, you should use the AuthenticationManager. The AuthenticationManager is basically a singleton class that emits a signal whenever a new authentication challenge comes through. If you create a Map that is private, but don't provide a credential, the AuthenticationManager will emit a signal indicating that a credential is required, and you can then create the credential and set it there. What this will do is add the credential to the credential cache, so that the API can automatically start using that credential for further authentication challenges. Here is the doc for this class AuthenticationManager Class | ArcGIS for Developers , and here is a sample of using the AuthenticationView QML toolkit control to handle most of it for you arcgis-runtime-samples-qt/ArcGISRuntimeSDKQt_CppSamples/CloudAndPortal/TokenAuthentication at master... 

0 Kudos
Kai_Wellmann
New Contributor II

Hi Luke, If I want to use one of the recommended Basemaps I get an error, when I try to save the map:

You can not add the National Geographic World Map (for Export) layer to the map because you do not have permission to use this layer.
0 Kudos
LucasDanzinger
Esri Frequent Contributor

That might be related to the issue - I tried with a few different accounts and can add those basemaps to the map viewer and save them. What account are you using? 

0 Kudos
Kai_Wellmann
New Contributor II

It is a developer account.(ArcGIS Online Public Account)

0 Kudos
LucasDanzinger
Esri Frequent Contributor

A "developer account" should work (I tested with one), because it is an organizational subscription that has access to subscriber content and has credits. A "public account" is different, however, and will not have access to this content and does not have credits. As a test, maybe try creating an account here and see if that works? ArcGIS for Developers 

0 Kudos