Have a map with dted and mbTile

725
4
Jump to solution
08-20-2019 01:13 PM
ThomasDumont-Goyette
New Contributor II

I’m trying to have a map with dted and mbtiles file. Here’s the sample “raster-layer-file” modified to have a mbTile file with the dted.  If you run this example everything is fine except the dted is on top of the mbTile and I would like the opposite in order to put some transparency on the mbTile and see the relief of the dted under it. If you switch line 79 and 80 to have rasterLayer added to the map first, it doesn’t work anymore. Only the dted is shown and you can’t zoom out very far and the north and south are locked on the dted.

public class MainActivity extends AppCompatActivity {

  private MapView mMapView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // retrieve the MapView from layout
    mMapView = (MapView) findViewById(R.id.mapView);

    // define permission to request
    String[] reqPermission = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE };
    int requestCode = 2;
    // For API level 23+ request permission at runtime
    if (ContextCompat.checkSelfPermission(MainActivity.this,
        reqPermission[0]) == PackageManager.PERMISSION_GRANTED) {
      final RasterLayer rasterLayer = loadRaster();
      final Layer mbtileLayer = loadMbTile();
      // create a Map with imagery basemap
      ArcGISMap map = new ArcGISMap(new Basemap());
      // add the map to a map view
      mMapView.setMap(map);
      // add layers to map
79    map.getOperationalLayers().add(mbtileLayer);
80    map.getOperationalLayers().add(rasterLayer);
    } else {
      // request permission
      ActivityCompat.requestPermissions(MainActivity.this, reqPermission, requestCode);
    }
  }

  /**
   * Using values stored in strings.xml, builds path to Shasta.tif.
   *
   * @return the path to raster file
   */
  private String buildRasterPath() {
    // get sdcard resource name
    File extStorDir = Environment.getExternalStorageDirectory();
    // get the directory
    String extSDCardDirName =
        this.getResources().getString(R.string.raster_folder) + "/dted/W074";
    // get raster filename
    String filename = "N45";
    // create the full path to the raster file
    return extStorDir.getAbsolutePath()
        + File.separator
        + extSDCardDirName
        + File.separator
        + filename
        + ".DT2";
  }

  /**
   * Loads Shasta.tif as a Raster and adds it to a new RasterLayer. The RasterLayer is then added
   * to the map as an operational layer. Map viewpoint is then set based on the Raster's geometry.
   */
  private RasterLayer loadRaster() {
    // create a raster from a local raster file
    Raster raster = new Raster(buildRasterPath());
    // create a raster layer
    final RasterLayer rasterLayer = new RasterLayer(raster);
    // add renderer
    rasterLayer.setRasterRenderer(new HillshadeRenderer(35, 143, 8));

    rasterLayer.addDoneLoadingListener(new Runnable() {
      @Override
      public void run() {
        mMapView.setViewpointGeometryAsync(rasterLayer.getFullExtent(), 50);
      }
    });

    return rasterLayer;
  }

  private Layer loadMbTile()
  {
    return buildMbTileLayer();
  }

  private Layer buildMbTileLayer()
  {
    // get sdcard resource name
    File extStorDir = Environment.getExternalStorageDirectory();
    // get the directory
    String extSDCardDirName =
        this.getResources().getString(R.string.raster_folder) + "/mbtiles";
    // get mbTile filename
    String filename = "Rheinmetall";
    // create the full path to the mbTile file
    String path = extStorDir.getAbsolutePath()
                            + File.separator
                            + extSDCardDirName
                            + File.separator
                            + filename
                            + ".mbtiles";

    final SQLiteDatabase database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY, null);

    final Envelope envWGS = new Envelope(-180.0, -85.05112877980659, 180.0, 85.05112877980659, SpatialReferences.getWgs84());
    Envelope envWeb = (Envelope) GeometryEngine.project(envWGS, SpatialReferences.getWebMercator());

    final Point origin = new Point(envWeb.getXMin(), envWeb.getYMax(), envWeb.getSpatialReference());

    final List<LevelOfDetail> levelOfDetail = new ArrayList<>();
    for(int i = 0; i < 100; i++)
      levelOfDetail.add(new LevelOfDetail(i, 156543.032 / Math.pow(2, i), 554678932 / Math.pow(2, i)));

    final TileInfo tileInfo = new TileInfo(96, TileInfo.ImageFormat.JPG, levelOfDetail, origin, envWeb.getSpatialReference(), 256, 256);

    return new ImageTiledLayer(tileInfo, envWeb)
    {
      @Override
      protected byte[] getTile(final TileKey tileKey)
      {
        final int nRows = (1 << tileKey.getLevel());
        final int tmsRow = nRows - 1 - tileKey.getRow();

        final Cursor imageCur = database.rawQuery(
            "SELECT tile_data FROM tiles WHERE zoom_level = " + Integer.toString(tileKey.getLevel()) +
                " AND tile_column = " + Integer.toString(tileKey.getColumn()) +
                " AND tile_row = " + Integer.toString(tmsRow), null);

        if(imageCur.moveToFirst())
        {
          final byte[] blob = imageCur.getBlob(0);
          imageCur.close();
          return blob;
        }

        imageCur.close();
        return null;
      }
    };
  }
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
ThomasDumont-Goyette
New Contributor II

I found the solution. Instead of doing ArcGISMap map = new ArcGISMap(new Basemap()); we need to do:

ArcGISMap map = new ArcGISMap(SpatialReferences.getWebMercator());
map.setBasemap(new Basemap());

View solution in original post

0 Kudos
4 Replies
XuemingWu
Esri Contributor

The spatial reference of the map is determined by the first layer added to the map. In your example it is the mbTile layer whose spatial reference is web mercator that defines the spatial reference of the map. A raster layer can be auto-reprojected when added to the map. So the dted raster is also displayed on the map. When you switch line 79 and 80, the dted raster layer becomes the first layer added to the map and determines the spatial reference of the map. And the mbTile layer becomes the second layers of the map. However, an ImageTiledLayer can't be reprojected. Its tiling scheme is precooked. When its spatial reference differs from the map's spatial reference it can't be displayed. You can check what spatial reference of the dted raster layer is. But looks like it is not web mercator.

ThomasDumont-Goyette
New Contributor II

Thanks a lot for the explanation. I checked the spatial reference of the raster layer and it is null. Is there a way to set the spatial reference?

0 Kudos
ThomasDumont-Goyette
New Contributor II

I found the solution. Instead of doing ArcGISMap map = new ArcGISMap(new Basemap()); we need to do:

ArcGISMap map = new ArcGISMap(SpatialReferences.getWebMercator());
map.setBasemap(new Basemap());

View solution in original post

0 Kudos
XuemingWu
Esri Contributor

Nice

0 Kudos