ArcGIS for Android 加载基础底图

基础底图

移动地图程序的基础,在于“一张图”,外业调绘、导航类、成果展示、统计应用等都需要一张基本的底图来支撑。往往底图的好坏决定了整个移动地图的根基。

加载在线基础底图

在线基础底图包括传统GIS(ArcGIS Server)和WebGIS(Online & Portal)。使用方式上确实不同,传统GIS是通过Layer直接对接地图服务(ArcGIS Server发布的)。WebGIS是同过ArcGISMap来对接WebMap。

1.传统GIS

对于一直使用ArcGIS Server发布地图服务的,可以直接使用地图服务(Layer)来加载在线的地图服务(ArcGIS Server)。

// 在线地图网址
// String web_url = "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer";String url = "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer";
ArcGISTiledLayer arcGISTiledLayer = new ArcGISTiledLayer(url);
Basemap basemap = new Basemap(arcGISTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(basemap);
mMapView.setMap(arcGISMap);// 长春 - 初始化范围(仅仅是本图层)Envelope targetExtent = new Envelope(13909984.0, 5437387.0, 13986734.0, 5458866.0,SpatialReferences.getWebMercator());Viewpoint initViewpoint = new Viewpoint(targetExtent);mMapView.getMap().setInitialViewpoint(initViewpoint);/*// 设置初始化范围(tpk图层)
Envelope targetExtent = new Envelope(-302859.47,-183912.51,349580.85,261109.45,SpatialReference.create(21481));
Viewpoint initViewpoint = new Viewpoint(targetExtent);
mapView.getMap().setInitialViewpoint(initViewpoint);
*/

2.WebGIS(Online & Portal)

通过Online或者Portal可以便捷快速的制作出更简洁智能的地图资源,用以表达我们的目的,对于移动端而言这些Web Map可以直接应用。

 String url = "http://www.arcgis.com/home/webmap/viewer.html?webmap=55c1665bcd064552944a9e8296271ec3";ArcGISMap arcGISMap = new ArcGISMap(url);mMapView.setMap(arcGISMap);Basemap basemap = arcGISMap.getBasemap(); //获取底图LayerList operationalLayers = arcGISMap.getOperationalLayers(); //获取业务图层

3.在线矢量切片:ArcGISVectorTiledLayer

String url = "https://www.arcgis.com/home/item.html?id=e19e9330bf08490ca8353d76b5e2e658";
ArcGISVectorTiledLayer arcGISVectorTiledLayer = new ArcGISVectorTiledLayer(url);
Basemap basemap = new Basemap(arcGISVectorTiledLayer);
ArcGISMap arcGISMap = new ArcGISMap(basemap);
mMapView.setMap(arcGISMap);
Viewpoint vp = new Viewpoint(47.606726, -122.335564, 72223.819286);
arcGISMap.setInitialViewpoint(vp);

加载离线基础底图

离线基础底图最传统的方式是直接拷贝ArcGIS Server服务的切片成果,存在的问题是无论使用松散型还是紧凑型都包含太多碎小文件,部署不便。

TPK文件便是为了解决多碎小文件问题。但是依然存在文件太大的问题,动辄十G甚至几十G。而矢量切片(VTPK)在于解决文件太大的问题。

1.TPK

       String map_path = null;// 加载tpk地图(大于api 24---android 7)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){map_path =getExternalFilesDir("/TPK/dlst.tpk").getPath();} else {map_path = Environment.getExternalStorageDirectory().getAbsolutePath() +     "/TPK/dlst.tpk";}TileCache titleCache = new TileCache(map_path);ArcGISTiledLayer arcGISTiledLayer = new ArcGISTiledLayer(titleCache);Basemap basemap = new Basemap(arcGISTiledLayer);ArcGISMap arcGISMap = new ArcGISMap(basemap);mMapView.setMap(arcGISMap);

加载多个TPK数据:

       // TPK 底图String map_path1 = null;String map_path2 = null;// 加载tpk地图(大于api 24---android 7)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){map_path1 =getExternalFilesDir("/TPK/2021.tpk").getPath();map_path2 =getExternalFilesDir("/TPK/lw.tpk").getPath();} else {map_path1 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/TPK/2021.tpk";map_path2 =getExternalFilesDir("/TPK/lw.tpk").getPath();}TileCache titleCache1 = new TileCache(map_path1);TileCache titleCache2 = new TileCache(map_path2);// 创建Layer列表,用来存放多个tpk数据List baseLayers = new ArrayList<>();ArcGISTiledLayer arcGISTiledLayer1 = new ArcGISTiledLayer(titleCache1);ArcGISTiledLayer arcGISTiledLayer2 = new ArcGISTiledLayer(titleCache2);baseLayers.add(arcGISTiledLayer1);baseLayers.add(arcGISTiledLayer2);Basemap basemap= new Basemap(baseLayers,null);ArcGISMap arcGISMap = new ArcGISMap();arcGISMap.setBasemap(basemap);// 设置最小比例尺arcGISMap.setMinScale(1500000);// 设置最大比例尺arcGISMap.setMaxScale(5000);mapView.setMap(arcGISMap);

2.矢量切片:VTPK

String path = "/sdcard/Hymn/basemap/dzzhdjfb.vtpk";
ArcGISVectorTiledLayer mainArcGISVectorTiledLayer = new ArcGISVectorTiledLayer(path);
Basemap mainBasemap = new Basemap(mainArcGISVectorTiledLayer);
ArcGISMap mainArcGISMap = new ArcGISMap(mainBasemap);
mMapView.setMap(mainArcGISMap);

3.MMPK(Basemap)

通过ArcGIS Pro可以制作包含基础底图(Basemap)的MMPK,MMPK文件解析后,基础底图(Basemap)中的图层会解析为MobileBasemapLayer,只提供浏览功能。当然,亚洲字符的支持情况在安卓端不是特别好。

String path = "/sdcard/Hymn/basemap/MobileBasemapLayer.mmpk";final MobileMapPackage mobileMapPackage = new MobileMapPackage(path);mobileMapPackage.loadAsync();mobileMapPackage.addDoneLoadingListener(new Runnable() {@Overridepublic void run() {LoadStatus loadStatus = mobileMapPackage.getLoadStatus();if (loadStatus == LoadStatus.LOADED) {List maps = mobileMapPackage.getMaps();ArcGISMap arcGISMap = maps.get(0);Basemap basemap = arcGISMap.getBasemap();LayerList operationalLayers = arcGISMap.getOperationalLayers();mMapView.setMap(arcGISMap);}}});

底图的切换

在Runtime100里,MapView是通过ArcGISMap类来完成图层的管理。

ArcGISMap类是将底图和业务图层分开的,对于底图,ArcGISMap里用了Baemap类来进行管理。

上面已经介绍了加载底图,现在就讲讲底图的切换。

如果我们要切换底图时候,仅需要给ArcGISMap类重新赋值一个底图即可。

 Basemap basemap = new Basemap(layer);arcGISMap.setBasemap(basemap);

布局:



Activity:

public class ChangeBasemapActivity extends AppCompatActivity {@BindView(R.id.mapview)MapView mMapview;@BindView(R.id.fl_content)FrameLayout mFlContent;@BindView(R.id.listview)ListView mListview;@BindView(R.id.drawer_layout)DrawerLayout mDrawerLayout;private ArcGISMap mArcGISMap;private String[] mNavigationDrawerItemTitles;private ActionBarDrawerToggle mDrawerToggle;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_change_basemap);ButterKnife.bind(this);//侧滑页面数据mNavigationDrawerItemTitles = getResources().getStringArray(R.array.basemap_types);if (getSupportActionBar() != null) {getSupportActionBar().setDisplayHomeAsUpEnabled(true);getSupportActionBar().setHomeButtonEnabled(true);getSupportActionBar().setTitle("底图切换");}mArcGISMap = new ArcGISMap(Basemap.Type.TOPOGRAPHIC, 47.6047381, -122.3334255, 12);mMapview.setMap(mArcGISMap);addDrawerItems();setupDrawer();}private void addDrawerItems() {ArrayAdapter mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,mNavigationDrawerItemTitles);mListview.setAdapter(mAdapter);mListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView adapterView, View view, int position, long id) {selectBasemap(position);}});}/*** Set up the navigation drawer*/private void setupDrawer() {mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {/** Called when a drawer has settled in a completely open state. */public void onDrawerOpened(View drawerView) {super.onDrawerOpened(drawerView);//getSupportActionBar().setTitle(mActivityTitle);invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()}/** Called when a drawer has settled in a completely closed state. */public void onDrawerClosed(View view) {super.onDrawerClosed(view);invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()}};mDrawerToggle.setDrawerIndicatorEnabled(true);mDrawerLayout.addDrawerListener(mDrawerToggle);}/*** Select the Basemap item based on position in the navigation drawer** @param position order int in navigation drawer*/private void selectBasemap(int position) {// update selected item and title, then close the drawermListview.setItemChecked(position, true);mDrawerLayout.closeDrawer(mListview);// if-else is used because this sample is used elsewhere as a Library moduleif (position == 0) {// position 0 = StreetsmArcGISMap.setBasemap(Basemap.createStreets());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);} else if (position == 1) {// position 1 = Navigation VectormArcGISMap.setBasemap(Basemap.createNavigationVector());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);} else if (position == 2) {// position 2 = TopographicmArcGISMap.setBasemap(Basemap.createTopographic());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);} else if (position == 3) {// position 3 = Topographic VectormArcGISMap.setBasemap(Basemap.createTopographicVector());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);} else if (position == 4) {// position 3 = Gray CanvasmArcGISMap.setBasemap(Basemap.createLightGrayCanvas());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);} else if (position == 5) {// position 3 = Gray Canvas VectormArcGISMap.setBasemap(Basemap.createLightGrayCanvasVector());getSupportActionBar().setTitle(mNavigationDrawerItemTitles[position]);}}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Activate the navigation drawer togglereturn (mDrawerToggle.onOptionsItemSelected(item)) || super.onOptionsItemSelected(item);}@Overrideprotected void onPostCreate(Bundle savedInstanceState) {super.onPostCreate(savedInstanceState);mDrawerToggle.syncState();}@Overridepublic void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);mDrawerToggle.onConfigurationChanged(newConfig);}@Overrideprotected void onResume() {super.onResume();mMapview.resume();}@Overrideprotected void onPause() {super.onPause();mMapview.pause();}@Overrideprotected void onDestroy() {super.onDestroy();mMapview.dispose();}}

遍历mapview上加载的基础图层(.tpk、.tpkx) 

 // 获取地图上加载基础图层(底图)LayerList layers =  mapView.getMap().getBasemap().getBaseLayers();// 遍历layersfor (Layer layer:layers) {if (layer instanceof ArcGISTiledLayer) {ArcGISTiledLayer arcGISTiledLayer = (ArcGISTiledLayer) layer;System.out.println(arcGISTiledLayer.getName());}}

加载三维地图 

注意:最好使用arcgis-android:100.5.0及以上,否则没法加载离线xxx.slpk文件

activity_main.xml:

    

MainActivity.java:

      mSceneView = findViewById(R.id.sceneView);//mSceneView.setAttributionTextVisible(false);  //去掉Esri logo// 网络地图String brest_buildings = " http://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/Buildings_Brest/SceneServer";// add a scene service to the scene for viewing buildingsArcGISSceneLayer sceneLayer = new ArcGISSceneLayer(brest_buildings);ArcGISScene scene = new ArcGISScene();scene.setBasemap(Basemap.createImagery());scene.getOperationalLayers().add(sceneLayer);mSceneView.setScene(scene);
        // 本地地图mSceneView = findViewById(R.id.sceneView);ArcGISScene scene = new ArcGISScene(Basemap.createImagery());mSceneView.setScene(scene);// 路径 \Android\data\com.chy.a2dand3d\files\ThreedData\xxx.slpkfinal IntegratedMeshLayer gironaIntegratedMeshLayer = new IntegratedMeshLayer(getExternalFilesDir("ThreedData") + getString(R.string.meshlayer));scene.getOperationalLayers().add(gironaIntegratedMeshLayer);gironaIntegratedMeshLayer.addDoneLoadingListener(new Runnable() {@Overridepublic void run() {mSceneView.setViewpointAsync(new Viewpoint(gironaIntegratedMeshLayer.getFullExtent()));}});

 设置三维场景视角镜头:

        /*** 设置三维场景视角镜头(camera)* @parm latitude 纬度* @parm longitude 经度* @parm altitude 海拔高度* @parm heading 镜头水平朝向 - 0度表示指北,从0度逐渐增加,镜头顺时针旋转,360度回到0度 指北* @parm pitch 镜头垂直朝向 - 0度表示垂直俯视地球,从0度逐渐增加,镜头沿其水平朝向,从俯 视地球朝天空旋转,360度回到0度俯视地球* @parm roll 旋转* */Camera camera = new Camera(43.88, 125.35, 200, 0, 0, 0);mSceneView.setViewpointCamera(camera);

控制三维垂直视角在一定角度内: 

/*** 三维地图垂直视角监听方法* */private void sceneViewListener(){mSceneView.setOnTouchListener(new DefaultSceneViewOnTouchListener(mSceneView){private  float touchY=0f;// 触摸屏幕的y值坐标private  float currentY=0f;// 当前手指滑动y值坐标@Overridepublic boolean onTouch(View view,MotionEvent motionEvent) {if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){touchY = motionEvent.getY();}return super.onTouch(view,motionEvent);}@Overridepublic boolean onTwoPointerPitch(MotionEvent motionEvent,double pitchDelta) {// 获取当前滑动的y值坐标if (motionEvent.getAction() == MotionEvent.ACTION_MOVE){currentY = motionEvent.getY();}// 求差值float dirDis = touchY - currentY;// 向上滑动if (dirDis > 0 && Math.abs(dirDis) >= 20){// 获取当前三维地图CameraCamera camera = mSceneView.getCurrentViewpointCamera();// 垂直视角角度大于等于80禁止继续扩大角度if (camera.getPitch() >= 80){return false;}}// 向下滑动if (dirDis <= 0 && Math.abs(dirDis) >= 20){// 开启垂直视角角度变化return super.onTwoPointerPitch(motionEvent,pitchDelta);}return super.onTwoPointerPitch(motionEvent,pitchDelta);}});}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部