我从业以来,很长有很多时间都在研究gis。不过是开源的还是收费的,多少多会看。现在又看了国内收费的ucmap for android ,说说我的感受吧。目前来说这是我用过接口最奇怪的,怎么说呢。就是跟一般习惯是不一样的。刚开始你会很纳闷,后面我会解释一下。我先声明,只代表个人观点,只是使用者观点。
1,官网
直接百度搜索ucmap即可,打开他们公司官网。下载开发包。
UCMap(V6.6.0)Android.7z:下载开发包,然后是他们公司的官网的论坛,有帖子申请实用码,说是3个月。说起试用码,我就要吐槽了。这个试用码是指定机器的,麻烦。这个码还有问题,我用了不到3个月。demo弹出来的码居然变了,跟我之前申请用的居然不一样了。因为我也做过一些注册码机制类似。这种形式最不好用。说到这里,因为我手机的机器码变了,现在没有码,这篇博客就不贴相关地图的界面,因为会崩溃,也没什么用。
UCMap(V7.0.0)Android.7z:最新版本android的开发包sdk 7.0已经不用试用码(之前的版本都需要)。现在做成跟arcgis 一样,有水印和法律声明。自已下载开发包,里面pdf以及demo,还有接口中文说明都有。这点是比较好的。
这里我就要说一下国内的另外一家超图公司的,那个试用码是3个月,不指定机器。而且是发送到申请邮箱。就是方便。
还有一家arcgis for android。国外的最大型的,开发gis都知道。这个更好,不用码,只不过有水印,还有版权声明。这个形式也挺好的。这个我只是总结现象。
至于开发包就大家自已去下载吧。
2,加载地图
这是一个官方提供的加载地图的形式。我贴一下主要代码:
mapView = (MapView) findViewById(R.id.mapView); mapView.setListener(new IMapViewListener() { @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { MapControl mapControl = mapView.getMapControl(); mapControl.showScaleBar(8, getResources().getDisplayMetrics().xdpi / 2.54f, 10, mapControl.getHeight() - 10, Color.BLACK, Color.RED, 3, 20); if (mapControl.getMap() == null) { String path = Environment.getExternalStorageDirectory().getPath(); if (!new File(path + "/" + workspace + "/map.ini").exists())//这里检查是否具有这个地图,没有则新建 App.getInstance().createMap(path + "/" + workspace); mapControl.loadMap(path + "/" + workspace + "/map.ini", (byte) 0);//装载地图 mapControl.setPanTool(); } } });这是一个离线地图,看以看出这个是加载根目录下面的bj2文件夹下面的map.ini。如果你测试出现崩溃或者没有地图,那么你自已留意吧。
这个数据是shp数据转换出来的数据库。我们看加载文件就知道。map.ini其实是个配置文件,用记事本打开就知道。有点长,下面我就展示部分。
[Map]
labelColor=0,0,0
LabelStyleCount=0
XMin=116.275146484375
YMin=39.864261627197266
XMax=116.45286494082686
YMax=39.97161865234375
LayerCount=23
[FixedShapefileLayer]0 省界_region 5
MinScale=0.0
MaxScale=0.0
Valid=1
Visible=1
Name=省界_region
Selectable=1
ScaleSymbols=0
[SimpleRenderer]
[FillSymbol]
FillColor_255=153,153,0
OutlineWidth=0.0
OutlineColor_255=153,153,0
然后我们可以在这里找到map.dat 。官方开发包里面都有,不要问我哪里来的数据。bj2文件下面。
用一个可视化sqlite工具打开
这里可以看出每一条数据,都是有一个范围xmin,ymin,xmax,ymax。然后是data,这个就是一系列坐标在里面。大家都知道一个线,面都是由很多坐标组成,那么都在里面了。然后外面是个范围。
研究这个呢?一定要对shp数据文件结构比较了解。这个shp里面东西。相当于把shp数据转换成这个表。
还有还有dbf属性文件转换成一张表的。其实在里面都能找到。
2,加载shp
说起加载shp,应该都是gis当中必备基础功能。上面都看到我解释那个map.ini和map.dat 其实就是shp文件转换出来,有桌面端工具转,也可以用java代码直接转。生成那两个东西。
mapView = (MapView) findViewById(R.id.mapView); mapView.setListener(new IMapViewListener() { @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { MapControl mapControl = mapView.getMapControl(); mapControl.showScaleBar(8, getResources().getDisplayMetrics().xdpi / 2.54f, 10, mapControl.getHeight() - 10, Color.BLACK, Color.RED, 3, 20); if (mapControl.getMap() == null) { String path = Environment.getExternalStorageDirectory().getPath(); if (!new File(path + "/shape/map.ini").exists()) App.getInstance().createMap(path + "/shape"); mapControl.loadMap(path + "/shape/map.ini", (byte) 0); String pathname = path + "/shape/DLTB.shp"; ShapefileLayer slayer = ShapefileLayer.createFromSHP( (short) mapControl.getMap().getLayerCount(), pathname, 100000, 0, true, true, new SimpleRenderer("", "", new FillSymbol(0xFF00FF00, null)), "GBK"); if (slayer != null) { mapControl.getMap().addLayer(slayer); mapControl.getDisplay().getDisplayTransformation().setVisibleBounds(mapControl.getFullExtent()); mapControl.rewriteIni(); mapControl.refresh(); } //经测试,这个没有调用是很卡顿的 //将当前的地图工具设置为移动地图工具 mapControl.setPanTool(); } } });第一次加载和转一定会卡在哪里,要做进度条的。因为那都是耗时。在动一下程序就无响应了。
其实有耐心的人,都看到了这个两个类基本上是一样的。第一个是直接加载转换好的shp,一个是在android端写代码加载。
那为什么分两个类,都是继承mapview这个类呢。这就是难用地方之一。所有加载地图都是这样写的
mapView.setListener(new IMapViewListener() { @Override public void onSizeChanged(int w, int h, int oldw, int oldh) { MapControl mapControl = mapView.getMapControl(); mapControl.showScaleBar(8, getResources().getDisplayMetrics().xdpi / 2.54f, 10, mapControl.getHeight() - 10, Color.BLACK, Color.RED, 3, 20); if (mapControl.getMap() == null) { mapControl.setPanTool(); } } });这个mapcontrol也是很重要的。自已体会吧。
3,加载谷歌在线地图
这个是demo 1里面功能。
public class MyMapView extends MapView { GPSCustomDraw gpsCustomDraw; public MyMapView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (this.isInEditMode()) return; MapControl mapControl=getMapControl(); gpsCustomDraw = new GPSCustomDraw(mapControl); //以下代码会在地图窗口的左下角显示一个比例尺符号,具体参数说明请参考doc //getResources().getDisplayMetrics().xdpi 获取了屏幕的横向dpi,乘以2.54可以得到1厘米有多少个像素点 mapControl.showScaleBar(8, getResources().getDisplayMetrics().xdpi/2.54f, 10, mapControl.getHeight()-10, Color.BLACK,Color.RED,3,20); if (mapControl.getMap()==null) { String path=Environment.getExternalStorageDirectory().getPath(); MapLoader.loadMapXML(mapControl, path+"/OpenSourceMap.xml"); //MapLoader.loadMapXML(mapControl,Environment.getExternalStorageDirectory().getPath()+"/cache/OpenSourceMapWithLocal.xml",null,1,0.00001f,true); mapControl.setCustomDraw(gpsCustomDraw); mapControl.setPanTool(); ((OpenSourceMapLayer)mapControl.getMap().getLayer(0)).openZoomInMode(); mapControl.refresh(); } } public void close() { if(gpsCustomDraw != null){ gpsCustomDraw.close(); } } }activity调用如下:
package cn.creable.android.demo.activity; import java.util.Vector; import cn.creable.android.demo.CopyFileManage; import cn.creable.android.demo.R; import cn.creable.android.demo.online.GPSCustomDraw; import cn.creable.android.demo.online.MyMapView; import cn.creable.android.demo.online.PathTool; import cn.creable.android.demo.online.PointTool; import cn.creable.gridgis.controls.App; import cn.creable.gridgis.controls.CustomDrawGeometrySelector; import cn.creable.gridgis.controls.ICustomDraw; import cn.creable.gridgis.controls.ICustomDrawDataCenter; import cn.creable.gridgis.controls.MapView; import cn.creable.gridgis.geometry.IEnvelope; import cn.creable.gridgis.geometry.IPoint; import cn.creable.gridgis.geometry.Point; import cn.creable.ucmap.ILocalSearchListener; import cn.creable.ucmap.IPathSearchListener; import cn.creable.ucmap.MapLoader; import cn.creable.ucmap.OpenSourceMapLayer; import cn.creable.ucmap.OpenSourceMapLayer.Path; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; public class MapMainActivity extends Activity { MyMapView mapView; ProgressDialog dlg; Activity act; PathTool pathTool; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String path = Environment.getExternalStorageDirectory().getPath(); CopyFileManage.copyAssetsFiletoDirectory(getAssets(), "xml", path); setContentView(R.layout.map_main); pathTool = null; act = this; mapView = (MyMapView) findViewById(R.id.mapView); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(Menu.NONE, Menu.NONE, 0, "装入地图"); menu.add(Menu.NONE, Menu.NONE, 1, "放大地图"); menu.add(Menu.NONE, Menu.NONE, 2, "缩小地图"); menu.add(Menu.NONE, Menu.NONE, 3, "平移地图"); menu.add(Menu.NONE, Menu.NONE, 12, "点击查询坐标"); menu.add(Menu.NONE, Menu.NONE, 10, "用代码控制视图"); menu.add(Menu.NONE, Menu.NONE, 11, "查看gps点"); menu.add(Menu.NONE, Menu.NONE, 4, "关键字查询"); menu.add(Menu.NONE, Menu.NONE, 5, "路径查询"); menu.add(Menu.NONE, Menu.NONE, 6, "切换地图数据源"); menu.add(Menu.NONE, Menu.NONE, 7, "切换地图模式"); menu.add(Menu.NONE, Menu.NONE, 8, "退出"); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: //装入地图 MapLoader.loadMapXML(mapView.getMapControl(), "/sdcard/OpenSourceMap.xml"); mapView.getMapControl().setCustomDraw(new GPSCustomDraw(mapView.getMapControl())); mapView.getMapControl().setPanTool(); break; case 1: //放大地图 mapView.getMapControl().setZoomInTool(); break; case 2: //缩小地图 mapView.getMapControl().setZoomOutTool(); break; case 3: //平移地图 mapView.getMapControl().setPanTool(); break; case 10://用代码视图控制 { mapView.getMapControl().getDisplay().getDisplayTransformation().setZoom(10);//直接设置显示比例尺,实现放大到想要的比例,如果仅仅需要居中,可以注释掉这一行 //以下代码实现以(117,30)为中心居中 OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); Point pt = oslayer.fromLonLat(117, 30); Point offset = oslayer.getOffset(117, 30); pt.setX(pt.getX() + offset.getX()); pt.setY(pt.getY() + offset.getY()); IEnvelope env = mapView.getMapControl().getExtent();//TODO:注意,如果你需要移动中心点时并setZoom,getExtent必须在setZoom之后调用才行 env.centerAt(pt); mapView.getMapControl().refresh(env); break; } case 4: //关键字查询 if (mapView.getMapControl().getMap().getLayerCount() > 0) { OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); oslayer.setLocalSearchListener(new ILocalSearchListener() { @Override public void localSearchFinished(Vector pois) { if (pois == null) return; int size = pois.size(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < size; ++i) { OpenSourceMapLayer.POI poi = (OpenSourceMapLayer.POI) pois.get(i); sb.append(poi.title); sb.append("\n"); } sb.deleteCharAt(sb.length() - 1); //利用Toast显示查询到的信息点的名字 Bundle b = new Bundle(); b.putString("string", sb.toString()); Message msg = new Message(); msg.what = 1; msg.setData(b); handler.sendMessage(msg); sb = null; } }); oslayer.localSearch("南京,中山", 0); //显示等待界面 dlg = new ProgressDialog(act); dlg.setProgressStyle(ProgressDialog.STYLE_SPINNER); dlg.setTitle("提示"); dlg.setMessage("正在进行关键字查询,请稍后"); dlg.setIcon(R.drawable.icon); dlg.setIndeterminate(false); dlg.setCancelable(true); dlg.setButton("取消 ", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); oslayer.cancel(); } }); dlg.show(); } break; case 5: //路径查询 if (mapView.getMapControl().getMap().getLayerCount() > 0) { OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); if (pathTool == null) { pathTool = new PathTool(mapView.getMapControl(), oslayer, act); mapView.getMapControl().addCustomDraw(pathTool); } mapView.getMapControl().setCurrentTool(pathTool); mapView.getMapControl().refresh(); } break; case 6: //切换地图数据源 if (mapView.getMapControl().getMap().getLayerCount() > 0) { OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); switch (oslayer.getMapMode()) { case GOOGLE: oslayer.setMapMode(1); break; case BING: oslayer.setMapMode(0); break; } mapView.getMapControl().refresh(); } break; case 7: //切换地图模式 if (mapView.getMapControl().getMap().getLayerCount() > 0) { OpenSourceMapLayer oslayer = (OpenSourceMapLayer) mapView.getMapControl().getMap().getLayer(0); switch (oslayer.getMode()) { case 0: oslayer.setMode(1); break; case 1: oslayer.setMode(0); break; } mapView.getMapControl().refresh(); } break; case 8: //退出 System.exit(0); break; case 11: ICustomDraw draw = mapView.getMapControl().getCustomDraw(); if (draw != null && draw instanceof ICustomDrawDataCenter) { CustomDrawGeometrySelector s = new CustomDrawGeometrySelector(mapView.getMapControl(), (ICustomDrawDataCenter) draw); s.setOffset(0, 60); mapView.getMapControl().setCurrentTool(s); } break; case 12: mapView.getMapControl().setCurrentTool(new PointTool(mapView.getMapControl())); break; } return super.onOptionsItemSelected(item); } private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1: //关闭等待界面 dlg.cancel(); dlg = null; //利用Toast显示查询的结果 Toast.makeText(App.getInstance(), msg.getData().getString("string"), Toast.LENGTH_SHORT).show(); break; } } }; @Override protected void onDestroy(){ if(mapView != null && mapView.getMapControl() != null){ mapView.getMapControl().closeMap(); mapView.close(); } super.onDestroy(); } }自已看怎样放配置文件吧:就是谷歌地址解析的文件。
官方demo 有所说明,怎么放在sd卡存储目录。
还有加载天地图,demo里面没有,暂时不知道怎么实现。
4,demo4 功能
这里面功能主要是对shp转换出来的sql进行编辑了。我写很多注释。
menuGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapter, View view, int cmd, long arg3) { menuDialog.dismiss(); switch (cmd) { case 0://添加要素 { AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setTitle("请选择图层:"); layers.clear(); Vector<String> strs = new Vector<String>(); //查找当前所有的图层 int count = mapView.getMapControl().getMap().getLayerCount(); for (int i = 0; i < count; ++i) { ILayer layer = mapView.getMapControl().getMap().getLayer(i); if (layer instanceof ShapefileLayer) { strs.addElement(layer.getName()); layers.addElement((ShapefileLayer) layer); } } String[] layerNames = new String[strs.size()]; strs.copyInto(layerNames); strs = null; //弹出图层选择的列表对话框 builder.setSingleChoiceItems(layerNames, -1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); //添加要素工具,可以利用该地图工具实现添加点、线、面要素的功能 AddFeatureTool tool = new AddFeatureTool(mapView.getMapControl(), layers.elementAt(which)); editTool = tool; //设置偏移量,将用户输入的光标从手指下面移动到其他的地方,这样避免光标被用户手指挡住的问题 //就是捕捉上面一个按钮 tool.setOffset(0, 60); //开启捕捉功能 tool.openSnap(); //设置编辑监听器 IEditListener 的监听回调 editTool.setListener(act); //设置当前地图工具 mapView.getMapControl().setCurrentTool(tool); } }); AlertDialog dialog = builder.create(); dialog.show(); break; } case 1: //添加要素 打点 { AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setTitle("请选择图层:"); layers.clear(); Vector<String> strs = new Vector<String>(); //查找当前所有的图层 int count = mapView.getMapControl().getMap().getLayerCount(); for (int i = 0; i < count; ++i) { ILayer layer = mapView.getMapControl().getMap().getLayer(i); if (layer instanceof ShapefileLayer) { strs.addElement(layer.getName()); layers.addElement((ShapefileLayer) layer); } } String[] layerNames = new String[strs.size()]; strs.copyInto(layerNames); strs = null; //弹出图层选择的列表对话框 builder.setSingleChoiceItems(layerNames, -1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); //添加要素工具,可以利用该地图工具实现添加点、线、面要素的功能 AddFeatureTool2 tool = new AddFeatureTool2(mapView.getMapControl(), layers.elementAt(which), ((BitmapDrawable) App.getInstance().getResources().getDrawable(R.drawable.cross)).getBitmap()); editTool = tool; //设置编辑监听器 IEditListener 的监听回调 editTool.setListener(act); //设置当前地图工具 mapView.getMapControl().setCurrentTool(tool); //重画,将缓冲在内存中的地图再次绘制到屏幕上 mapView.getMapControl().repaint(); } }); AlertDialog dialog = builder.create(); dialog.show(); break; } case 2: //删除要素 { //删除要素工具,利用本工具可以删除矢量地图上的任何要素 DeleteFeatureTool tool = new DeleteFeatureTool(mapView.getMapControl()); //设置偏移量,将用户输入的光标从手指下面移动到其他的地方,这样避免光标被用户手指挡住的问题 //就是捕捉上面一个按钮 tool.selector.setOffset(0, 80); editTool = tool; //设置编辑监听器 IEditListener 的监听回调 editTool.setListener(act); //设置当前地图工具 mapView.getMapControl().setCurrentTool(tool); break; } case 3: //提交编辑 { editTool.submit(); break; } case 4: //修改节点 { //编辑要素工具,使用本工具可以实现对点、线、面地图要素的编辑 EditFeatureTool editTool = null; if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof EditFeatureTool) { //获取地图当前的地图工具 editTool = (EditFeatureTool) mapView.getMapControl().getCurrentTool(); } else { editTool = new EditFeatureTool(mapView.getMapControl()); //设置一个编辑要素工具 mapView.getMapControl().setCurrentTool(editTool); } //设置偏移量,设置放大镜的偏移量 editTool.selector.setOffset(0, 80); //设置编辑类型 Type_MoveNode移动节点 editTool.setType(EditFeatureTool.Type_MoveNode); //IEditListener 的监听回调 editTool.setListener(act); break; } case 5: //添加节点 { //编辑要素工具,使用本工具可以实现对点、线、面地图要素的编辑 EditFeatureTool editTool = null; if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof EditFeatureTool) { //获取地图当前的地图工具 editTool = (EditFeatureTool) mapView.getMapControl().getCurrentTool(); } else { editTool = new EditFeatureTool(mapView.getMapControl()); //设置一个编辑要素工具 mapView.getMapControl().setCurrentTool(editTool); } //设置偏移量,设置放大镜的偏移量 editTool.selector.setOffset(0, 80); //设置编辑类型 Type_AddNode 添加节点 editTool.setType(EditFeatureTool.Type_AddNode); break; } case 6: //删除节点 { //编辑要素工具,使用本工具可以实现对点、线、面地图要素的编辑 EditFeatureTool editTool = null; if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof EditFeatureTool) { //获取地图当前的地图工具 editTool = (EditFeatureTool) mapView.getMapControl().getCurrentTool(); } else { editTool = new EditFeatureTool(mapView.getMapControl()); //设置一个编辑要素工具 mapView.getMapControl().setCurrentTool(editTool); } //设置偏移量,设置放大镜的偏移量 editTool.selector.setOffset(0, 80); //设置编辑类型 Type_DeleteNode 删除节点 editTool.setType(EditFeatureTool.Type_DeleteNode); break; } case 7: //整体移动 { //将前三个层设置为不可选择 int layerCount = mapView.getMapControl().getMap().getLayerCount(); if (layerCount > 3) layerCount = 3; for (int i = 0; i < layerCount; ++i) { ShapefileLayer layer = null; if (mapView.getMapControl().getMap().getLayer(i) instanceof ShapefileLayer) layer = (ShapefileLayer) mapView.getMapControl().getMap().getLayer(i); if (layer != null) { //设置是否可以选择 false不可选择 layer.setSelectable(false); } } //编辑要素工具,使用本工具可以实现对点、线、面地图要素的编辑 EditFeatureTool tool = new EditFeatureTool(mapView.getMapControl()); //设置编辑类型 Type_Move 整体移动 tool.setType(EditFeatureTool.Type_Move); //设置当前地图工具 mapView.getMapControl().setCurrentTool(tool); break; } case 8: //undo { boolean ret = false; if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof IEditTool) ret = ((IEditTool) (mapView.getMapControl().getCurrentTool())).undo(); if (ret == false) { ShapefileLayer.undo(); mapView.getMapControl().refresh(); } break; } case 9: //redo { boolean ret = false; if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof IEditTool) ret = ((IEditTool) (mapView.getMapControl().getCurrentTool())).redo(); if (ret == false) { ShapefileLayer.redo(); mapView.getMapControl().refresh(); } break; } case 10://修改属性 { //编辑属性,只是闪烁 EditFeatureAttTool tool = new EditFeatureAttTool(mapView.getMapControl()); tool.selector.setOffset(0, 80); editTool = tool; editTool.setListener(act); mapView.getMapControl().setCurrentTool(tool); break; } case 11://地图浏览 //将当前的地图工具设置为移动地图工具 mapView.getMapControl().setPanTool(); break; case 12: //导出地图 { AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setTitle("请选择图层:"); layers.clear(); Vector<String> strs = new Vector<String>(); int count = mapView.getMapControl().getMap().getLayerCount(); for (int i = 0; i < count; ++i) { ILayer layer = mapView.getMapControl().getMap().getLayer(i); if (layer instanceof ShapefileLayer) { strs.addElement(layer.getName()); layers.addElement((ShapefileLayer) layer); } } String[] layerNames = new String[strs.size()]; strs.copyInto(layerNames); strs = null; //对话框对那个图层列表进行选择导出 builder.setSingleChoiceItems(layerNames, -1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); //导出到根目录 layers.elementAt(which).outputToShapefile("/sdcard/"); Toast.makeText(act, "导出完成!", Toast.LENGTH_LONG).show(); } }); AlertDialog dialog = builder.create(); dialog.show(); break; } case 13://开启捕捉 if (editTool instanceof AddFeatureTool) { ((AddFeatureTool) editTool).openSnap(); } else if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof EditFeatureTool) { ((EditFeatureTool) mapView.getMapControl().getCurrentTool()).openSnap(); } break; case 14://关闭捕捉 if (editTool instanceof AddFeatureTool) { ((AddFeatureTool) editTool).closeSnap(); } else if (mapView.getMapControl().getCurrentTool() != null && mapView.getMapControl().getCurrentTool() instanceof EditFeatureTool) { ((EditFeatureTool) mapView.getMapControl().getCurrentTool()).closeSnap(); } break; case 15://信息工具 //信息工具,用于显示地图要素的详细属性信息 //如果是shp文件,那就是dbf属性信息 InfoTool tool = new InfoTool(mapView.getMapControl(), new IInfoToolListener() { @Override public void notify(MapControl mapControl, IFeatureLayer flayer, IFeature ft, String[] fields, String[] values) { if (ft.getShape().getGeometryType() == GeometryType.Polygon) { //以下代码实现 仅仅闪烁面要素边框的效果 Polygon pg = (Polygon) ft.getShape(); LinearRing ring = (LinearRing) pg.getExteriorRing(); LineString line = new LineString(ring.getPoints());//根据面的边框构造一个线 LineSymbol ls = new LineSymbol(3, 0xFFFF0000);//构造一个线样式 Vector<IGeometry> geos = new Vector<IGeometry>(); geos.add(line); Vector<ISymbol> syms = new Vector<ISymbol>(); syms.add(ls); mapControl.flashFeatures(geos, syms, 10);//调用闪烁接口,并只闪烁10次,如果需要无限制的闪烁,请将10改成-1 } else mapControl.flashFeatures(flayer, ft.getOid());//闪烁被选中的地图要素 //显示地图要素的属性 StringBuilder sb = new StringBuilder(); for (int i = 0; i < fields.length; ++i) { sb.append(fields[i]); sb.append(":"); sb.append(values[i]); sb.append("\n"); } sb.deleteCharAt(sb.length() - 1); //利用Toast显示地图要素的属性 if (myt != null) { myt.cancel(); myt = null; } myt = new MyToast(App.getInstance().getApplicationContext()); myt.setText(sb.toString()); myt.show(); //Toast.makeText(App.getInstance(), sb.toString(), Toast.LENGTH_SHORT).show(); sb = null; } }); tool.selector.setOffset(0, 80); mapView.getMapControl().setCurrentTool(tool); break; case 16://投影变换 //这个被注释掉的是大地2000投影的定义 //String CGCS2000_3_Degree_GK_Zone_40="+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs"; String proj1 = ProjectFactory.createWGS84(); String proj2 = ProjectFactory.createGaussKruger(114, 0, ProjectFactory.ellps_xian1980, 500000, "m"); SpatialReference sr = new SpatialReference(proj1, proj2); sr.addPoint(new Point(113.82133, 23.27463)); sr.addPoint(new Point(113.82233, 23.27563)); sr.addPoint(new Point(113.82333, 23.27663)); sr.addPoint(new Point(113.82433, 23.27763)); double[] result = sr.pj1Topj2(); String msg = String.format("经纬度点(113.82133,23.27463)转换到3度带高斯80坐标系之后的坐标为(%f,%f)", result[0], result[1]); Toast.makeText(App.getInstance(), msg, Toast.LENGTH_LONG).show(); break; case 17://测距离 MeasureTool mtool = new MeasureTool(mapView.getMapControl(), 0); mtool.setListener(new IMeasureToolListener() { @Override public void notify(int type, double value) { Toast.makeText(App.getInstance(), String.format("距离为:%f米", value), Toast.LENGTH_LONG).show(); } }); mtool.selector.setOffset(0, 80); mapView.getMapControl().setCurrentTool(mtool); break; case 18://测面积 MeasureTool mtool1 = new MeasureTool(mapView.getMapControl(), 1); mtool1.setListener(new IMeasureToolListener() { @Override public void notify(int type, double value) { Toast.makeText(App.getInstance(), String.format("面积为:%f平方米", value), Toast.LENGTH_LONG).show(); } }); mtool1.selector.setOffset(0, 80); mapView.getMapControl().setCurrentTool(mtool1); break; case 19: //专题图 { //缩放到能够看到专题图效果的比例尺 mapView.getMapControl().getDisplay().getDisplayTransformation().setZoom(0.00805f); //将第三个图层“县界”的renderer替换为MyRenderer IShapefileLayer layer = (IShapefileLayer) mapView.getMapControl().getMap().getLayer(2); MyRenderer renderer = new MyRenderer(layer); IFeatureLayer flayer = (IFeatureLayer) layer; flayer.setRenderer(renderer); mapView.getMapControl().refresh();//刷新地图 break; } case 20://图层控制 //其实就是图层的筛选而已 //遍历当前地图的所有图层 int cur = -1; IMap map = mapView.getMapControl().getMap(); int size = map.getLayerCount(); layers2.clear(); //float curZoom=mapView.getMapControl().getDisplay().getDisplayTransformation().getZoom(); ILayer layer = null; for (int i = 0; i < size; ++i) { layer = map.getLayer(i); //if (layer.getMinimumScale()<curZoom && curZoom<layer.getMaximumScale())//只有图层的显示比例范围包含了当前显示比例,才可以控制该图层是否可见 { layers2.add(layer); } } size = layers2.size(); //if (size==0) super.onOptionsItemSelected(item); //将图层的名字和图层是否可见,复制进2个数组里,供显示对话框使用 String[] layerNames = new String[size]; visible = new boolean[size]; for (int i = 0; i < size; ++i) { layer = layers2.get(i); layerNames[i] = layer.getName(); visible[i] = layer.getVisible(); } //显示一个对话框,供用户控制图层 AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setIcon(R.drawable.icon); builder.setTitle("图层控制"); builder.setMultiChoiceItems(layerNames, visible, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { visible[which] = isChecked;//保存用户的选择 } }); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { int size = visible.length; for (int i = 0; i < size; ++i) {//重新设置每个可以被控制的图层的可见性 layers2.get(i).setVisible(visible[i]); } mapView.getMapControl().refresh();//刷新地图立即看到效果 } }); builder.setNegativeButton("取消", null);//取消按钮什么事都不做 builder.create().show(); break; case 21: System.exit(0); break; } } } ); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add("menu"); return super.onCreateOptionsMenu(menu); } private SimpleAdapter getMenuAdapter(String[] menuNameArray, int[] imageResourceArray) { ArrayList<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>(); for (int i = 0; i < menuNameArray.length; i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("itemImage", imageResourceArray[i]); map.put("itemText", menuNameArray[i]); data.add(map); } SimpleAdapter simperAdapter = new SimpleAdapter(this, data, R.layout.menu_item, new String[]{"itemImage", "itemText"}, new int[]{R.id.item_image, R.id.item_text}); return simperAdapter; } private Vector<EditText> ets = new Vector<EditText>(); private LinearLayout.LayoutParams LP_FF = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); private LinearLayout.LayoutParams LP_FW = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); private LinearLayout.LayoutParams LP_WW = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); private void showModifyDialog(String[] fields, String[] values) { ScrollView sv = new ScrollView(this); sv.setLayoutParams(LP_FF); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); sv.addView(layout); TextView tv; EditText et; RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(400, LayoutParams.WRAP_CONTENT); //lp.setMargins(70, 0, 0, 0); int count = fields.length; ets.clear(); for (int i = 0; i < count; ++i) { tv = new TextView(act); tv.setText(fields[i]); tv.setTextAppearance(act, android.R.style.TextAppearance_Medium); layout.addView(tv); et = new EditText(act); et.setLayoutParams(lp); et.setSingleLine(true); et.setTextAppearance(act, android.R.style.TextAppearance_Medium); et.setTextColor(0xFF000000); if (values != null) et.setText(values[i]); layout.addView(et); ets.addElement(et); } AlertDialog.Builder builder = new AlertDialog.Builder(act); builder.setView(sv).setTitle("修改属性").setIcon(R.drawable.icon) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { int count = ets.size(); String[] values = new String[count]; for (int i = 0; i < count; ++i) { values[i] = ets.elementAt(i).getText().toString(); } ft.setValues(values); editTool.confirm(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { editTool.cancel(); } }); builder.create().show(); } //地图接口回调 @Override public void onAddFeature(IFeature ft, ILayer layer) { this.ft = ft; IFeatureLayer flayer = (IFeatureLayer) layer; this.showModifyDialog(flayer.getFeatureClass().getFields(), ft.getValues()); } //地图接口回调 @Override public void onDeleteFeature(IFeature ft, ILayer layer) { editTool.confirm(); //不提示,直接删除要素 } //地图接口回调 @Override public void onUpdateFeature(IFeature ft, ILayer layer) { IMapTool mt = mapView.getMapControl().getCurrentTool(); if (mt == null) return; if (!(mt instanceof EditFeatureTool)) { this.ft = ft; IFeatureLayer flayer = (IFeatureLayer) layer; this.showModifyDialog(flayer.getFeatureClass().getFields(), ft.getValues()); } else { //移动线上的节点之后,这里一起移动点图层上的对应的点要素 ILayer lyr = mapView.getMapControl().getMap().getLayer("点"); if (lyr != null && lyr instanceof ShapefileLayer) { EditFeatureTool eTool = (EditFeatureTool) mt; ShapefileLayer sLayer = (ShapefileLayer) lyr; //使用selectFeature函数查询点击处的点要素 IFeature oldFeature = sLayer.selectFeature(mapView.getMapControl().getDisplay().getDisplayTransformation(), eTool.selector.getX(), eTool.selector.getY(), 10); if (oldFeature == null) return; IFeature newFeature = oldFeature.clone(true, false);//这里仅仅克隆一个具有相同shape的新要素 if (eTool.newFeature.getShape() instanceof LineString) { LineString line = (LineString) eTool.newFeature.getShape(); IPoint pt = line.getPoint(eTool.nodeIndex);//获取移动之后的节点位置(地图坐标) IPoint newPoint = (IPoint) newFeature.getShape(); newPoint.setX(pt.getX()); newPoint.setY(pt.getY());//将这个新要素的坐标移动到上述节点位置上 sLayer.updateFeature(oldFeature, newFeature, true, false);//更新点要素位置 } } } }
怎么编辑,选中图斑,导出shp,查询属性等等。
5,权限
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />还有注意你的application一定是这个
android:name="cn.creable.gridgis.controls.App"要么你就写一个application继承上面那个。
6,说一下注意事项
如果你的两个界面都是有地图控件,那么销毁界面时候,地图资源记得要释放。不然另外一个地图界面还是一样的数据。
我建议大家下载demo进行运行,然后查看代码,对照接口中文注释,然后看pdf。
大家有没有看过arcgis for android 和超图supmap 的sdk 都是有着版本更新非常大变化。重构幅度很大。
加载shp思路基本都是转换成自已一种格式,进行范围和坐标管理显示。有些是进行R树查询。
其实有个很大难点就是绘制很大的shp文件,怎么做算法查找和显示。
大家对gis这些开发上思路也可以评论一下。