几何编辑从原理上和属性编辑是一样的,但是鉴于ArcGIS Android API自带示例中的AttributeEditor这个例子写得比较复杂,不利于表现API最精髓的部分,因此这里再就如何在客户端更改要素的几何属性,并通过Feature Layer保存到服务器做一个例子。
要进行几何编辑分为两个步骤,其一:在客户端修改几何对象的节点坐标;其二:将更新过的几何对象提交到服务器。
让我们首先考虑第一步,如何修改一个客户端的几何对象。让我们先新建一个工程名为“AgsEditFeatureLayer”,在这个工程默认的Activity中加入MapView和必要的图层:
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="fill_parent" android:layout_height="fill_parent"
initExtent="-10868502.895856911 4470034.144641369
-10837928.084542884 4492965.25312689">
url="http://services.arcgisonline.com/ArcGIS/rest
/services/World_Topo_Map/MapServer" />
url= "http://sampleserver3.arcgisonline.com/ArcGIS/rest
/services/Petroleum/KSFields/MapServer" />
"@+id/fLayer"
url= "http://sampleserver3.arcgisonline.com/ArcGIS/rest
/services/Petroleum/KSFields/FeatureServer/0"
mode="selection" />
"@+id/gLayer"/>
我希望用户可以在屏幕上通过长按操作来选择一个需要编辑的几何对象,因此,我需要在长按的事件中进行实现“选择要素”这个操作:
public class AgsEditFeatureLayer extends Activity {
MapView map = null;
ArcGISFeatureLayer fLayer = null;
GraphicsLayer gLayer = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
map = (MapView) findViewById(R.id.map);
fLayer = (ArcGISFeatureLayer) findViewById(R.id.fLayer);
gLayer = (GraphicsLayer) findViewById(R.id.gLayer);
SimpleFillSymbol fSymbol = new SimpleFillSymbol(Color.YELLOW);
fSymbol.setOutline(new SimpleLineSymbol(Color.RED, 2));
fLayer.setSelectionSymbol(fSymbol);
SimpleFillSymbol gSymbol = new SimpleFillSymbol(Color.BLACK);
gSymbol.setOutline(new SimpleLineSymbol(Color.RED, 2));
gLayer.setRenderer(new SimpleRenderer(gSymbol));
map.setOnLongPressListener(new OnLongPressListener() {
public void onLongPress(float x, float y) {
Point pt = map.toMapPoint(new Point(x, y));
Query q = new Query();
q.setReturnGeometry(true);
q.setGeometry(pt);
q.setInSpatialReference(map.getSpatialReference());
q.setSpatialRelationship(SpatialRelationship.INTERSECTS);
fLayer.selectFeatures(q, SELECTION_METHOD.NEW, null);
}
});
}
}
当执行了selectFeatures这个方法之后,实际上程序向ArcGIS Server发送了一个空间查询,得到结果后将查询的结果绘制到fLayer这个ArcGISFeatureLayer上,实际上也就是在这个GraphicsLayer上添加了一个Graphic(图 32中的)。
图 34 在Feature Layer上选择一个要素
下一步,我们需要做的是可以让用户通过触屏操作来改变这个Graphic的几何形状。我们可以把这个过程简化一些,比如只允许用户改变已经存在的节点。改变时的几何形状我们绘制在另外一个GraphicsLayer上,名为gLayer,所以上面的代码我们先稍作修改,在选中要素的时候同时先把这个要素复制到gLayer上,你可以把这段修改过的选择要素代码和上面高亮的没有修改的代码做下比较:
fLayer.selectFeatures(q, SELECTION_METHOD.NEW, new CallbackListener (){
public void onCallback(FeatureSet fs) {
gLayer.clear();
gLayer.addGraphics(fs.getGraphics());
gLayer.postInvalidate();
}
public void onError(Throwable t) {
t.printStackTrace();
}
});
为了对几何对象进行编辑,我们继承MapOnTouchListener定义了一个新的监听,并在这个监听中封装了编辑几何对象的逻辑,然后将这个监听绑定到MapView对象上:
map.setOnTouchListener(new MyMapOnTouchListener(this, map, fLayer, gLayer));
public class MyMapOnTouchListener extends MapOnTouchListener {
private Context context = null;
private MapView map = null;
private ArcGISFeatureLayer fLayer = null;
private GraphicsLayer gLayer = null;
private Graphic g = null;
private int editIndex = -1;
public MyMapOnTouchListener(Context context, MapView map,
ArcGISFeatureLayer fLayer, GraphicsLayer gLayer) {
super(context, map);
this.context = context;
this.map = map;
this.fLayer = fLayer;
this.gLayer = gLayer;
}
@Override
public boolean onDragPointerMove(MotionEvent from, MotionEvent to) {
Graphic[] gs = gLayer.getGraphics();
if(gs==null || gs.length==0){
return false;
}
Graphic g = gs[0];
Polygon pg = (Polygon)g.getGeometry();
if (editIndex<0) {//此时需要获取编辑的节点序号
Point ptClick = map.toMapPoint(from.getX(), from.getY());
Proximity2DResult pr = GeometryEngine.getNearestVertex(pg, ptClick);
editIndex = pr.getVertexIndex();
}
if(g!=null && editIndex>=0){
Point ptTo = map.toMapPoint(to.getX(), to.getY());
pg.setPoint(editIndex, ptTo);//改变指定节点的坐标
}
gLayer.postInvalidate();
return true;
}
@Override
public boolean onDragPointerUp(MotionEvent from, MotionEvent to) {
editIndex = -1;
gLayer.postInvalidate();
return true;
}
}
这样,当我在屏幕上拖动的时候,刚才被我选中的多边形就可以被编辑,比如在图 35中我们就编辑了3个节点的位置,导致这个多边形的形状很是奇怪,其实,这个看起来简单的多边形有77个节点,节点间的距离是很密集的。
图 35 通过屏幕事件编辑几何形状
好,这个时候在客户端的工作就完成了,现在我们需要进行第二步,就是将在客户端所做的编辑提交到ArcGIS Server上去。这里,我们加入一个按钮,当点击这个按钮的时候程序将执行下面的提交操作:
buttonApply.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
fLayer.applyEdits(null, null, gLayer.getGraphics(),
new CallbackListener () {
public void onCallback(FeatureEditResult[][] results) {
System.out.println("Updated");
}
public void onError(Throwable t) {
t.printStackTrace();
}
});
}
});
如果你留意一下LogCat中的日志,就会看到这样的详细:
02-21 14:18:02.358: DEBUG/ArcGIS.ThreadPool(736): Updated Features:1
没错,这表示编辑提交成功,当然,你也可以在applyEdits方法的CallbackListener中加入更进一步的处理。只要提交成功,再刷新一下动态底图,就能看到更新后的结果:
图 36 几何编辑后的动态服务效果