ArcGIS for Android 100.3.0(13):shp文件的加载,查询和编辑

ArcGIS Runtime 100.2.0的正式发布带来个更多移动端的处理地图的能力,例如支持WMS图层、支持海图(ENC)图层,再如基于场景相机(Camera)的视域分析。同时还提供了新的统计查询API(总和,平均值,计数,最小值,最大值,标准差或方差)。而今天要描述的重点是ArcGIS Runtime 100.2.0对Shapefile数据格式的支持,当然ArcGIS Runtime 100.2.0还增加了对OGC GeoPackage格式的支持。

对于Shapfile这一文件格式,ArcGIS Runtime SDK for Android 在100.2.0系列中推出了两大重磅利好消息:

(1) 实现对本地 Shapfile 文件的加载、显示和查询
(2) 实现对本地 Shapefile 文件的编辑,即增删改操作
毋庸置疑,对于广大的ArcGIS移动端爱好者而言,支持Shapefile编辑操作绝对是一则振奋人心的好消息。

Shapefile文件的加载

这里写图片描述

加载shp文件,数据量大的时候,加载速度比较慢。

shp文件 必须有least three files (.shp, .shx, .dbf) 如果有prj文件那就更好。位置准确。

在安卓端加载Shapefile文件的关键是ShapefileFeatureTable(com.esri.arcgisruntime.data.ShapefileFeatureTable)。
相比于.geodatabase文件,Shapefile文件的缺点在于只是单图层,且没有符号化,当然可以通过移动端的可视化API进行处理。

shp文件加载方式1

 /**
     * 加载shp方式1
     */
    private void loadShapefile1() {
        // 构建ShapefileFeatureTable,引入本地存储的shapefile文件
        ShapefileFeatureTable shapefileFeatureTable = new ShapefileFeatureTable(shpPath);
        shapefileFeatureTable.loadAsync();
        // 构建featureLayerr
        mFeatureLayer = new FeatureLayer(shapefileFeatureTable);
        // 设置Shapefile文件的渲染方式
        SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 1.0f);
        SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.YELLOW, lineSymbol);
        SimpleRenderer renderer = new SimpleRenderer(fillSymbol);
        mFeatureLayer.setRenderer(renderer);

        //设置选中颜色
        mFeatureLayer.setSelectionWidth(5);
        mFeatureLayer.setSelectionColor(Color.GREEN);

        mMapView.setViewpointGeometryAsync(mFeatureLayer.getFullExtent());
        // 添加到地图的业务图层组中
        mArcGISMap.getOperationalLayers().add(mFeatureLayer);
    }

shp文件加载方式2

    /**
     * 查询shp方式2
     */
    private void loadShapefile2() {
        mShapefileFeatureTable = new ShapefileFeatureTable(shpPath);
        mShapefileFeatureTable.loadAsync();
        mShapefileFeatureTable.addDoneLoadingListener(new Runnable() {
            @Override
            public void run() {
                GeometryType gt = mShapefileFeatureTable.getGeometryType();
                String name = mShapefileFeatureTable.getTableName();
                mFeatureLayer = new FeatureLayer(mShapefileFeatureTable);
                if (mFeatureLayer.getFullExtent() != null) {
                    mMapView.setViewpointGeometryAsync(mFeatureLayer.getFullExtent());
                } else {
                    mFeatureLayer.addDoneLoadingListener(new Runnable() {
                        @Override
                        public void run() {
                            mMapView.setViewpointGeometryAsync(mFeatureLayer.getFullExtent());
                        }
                    });
                }
                mArcGISMap.getOperationalLayers().add(mFeatureLayer);
            }
        });


        SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 1.0f);
        SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.YELLOW, lineSymbol);
        SimpleRenderer renderer = new SimpleRenderer(fillSymbol);
        mFeatureLayer.setRenderer(renderer);
        //设置选中颜色
        mFeatureLayer.setSelectionWidth(5);
        mFeatureLayer.setSelectionColor(Color.GREEN);
    }

shp文件的查询*

shp文件查询方式1:selectFeaturesAsync

 /**
     * 查询shp方式1:selectFeaturesAsync
     */
    private void queryBySelectFeaturesAsync() {
        mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, mMapView) {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {

                mFeatureLayer.clearSelection();

                final Point clickPoint = mMapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())));
                int tolerance = 1;
                double mapTolerance = tolerance * mMapView.getUnitsPerDensityIndependentPixel();
                SpatialReference spatialReference = mMapView.getSpatialReference();
                Envelope envelope = new Envelope(clickPoint.getX() - mapTolerance, clickPoint.getY() - mapTolerance,
                        clickPoint.getX() + mapTolerance, clickPoint.getY() + mapTolerance, spatialReference);
                QueryParameters query = new QueryParameters();
                query.setGeometry(envelope);
                query.setSpatialRelationship(QueryParameters.SpatialRelationship.WITHIN);
                final ListenableFuture<FeatureQueryResult> future = mFeatureLayer.selectFeaturesAsync(query, FeatureLayer.SelectionMode.NEW);
                future.addDoneListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            FeatureQueryResult result = future.get();
                            //mFeatureLayer.getFeatureTable().deleteFeaturesAsync(result);
                            Iterator<Feature> iterator = result.iterator();

                            int counter = 0;
                            while (iterator.hasNext()) {
                                counter++;
                                Feature feature = iterator.next();

                                Map<String, Object> attributes = feature.getAttributes();
                                for (String key : attributes.keySet()) {
                                    Log.e("xyh" + key, String.valueOf(attributes.get(key)));
                                }

                                //高亮显示选中区域
                                mFeatureLayer.selectFeature(feature);
                                Geometry geometry = feature.getGeometry();
                                mMapView.setViewpointGeometryAsync(geometry.getExtent());

                                //也可以通过添加graphic高亮显示选中区域
                                //
                                //                                SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 3);
                                //                                SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.RED, lineSymbol);
                                //
                                //                                if (mGraphicsOverlay != null) {
                                //                                    ListenableList<Graphic> graphics = mGraphicsOverlay.getGraphics();
                                //                                    if (graphics.size() > 0) {
                                //                                        graphics.removeAll(graphics);
                                //                                    }
                                //                                }
                                //                                Graphic graphic = new Graphic(geometry, fillSymbol);
                                //                                mGraphicsOverlay.getGraphics().add(graphic);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
                return super.onSingleTapConfirmed(e);
            }
        });
    }

shp文件查询方式2:queryFeaturesAsync

 /**
     * 查询shp方式2:queryFeaturesAsync
     */
    public void queryByQueryFeaturesAsync() {
        mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, mMapView) {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent v) {
                android.graphics.Point screenPoint = new android.graphics.Point(Math.round(v.getX()), Math.round(v.getY()));
                Point clickPoint = mMapView.screenToLocation(screenPoint);

                QueryParameters query = new QueryParameters();
                query.setGeometry(clickPoint);// 设置空间几何对象
                FeatureTable mTable = mFeatureLayer.getFeatureTable();//得到查询属性表
                final ListenableFuture<FeatureQueryResult> featureQueryResult = mTable.queryFeaturesAsync(query);
                featureQueryResult.addDoneListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            FeatureQueryResult result = featureQueryResult.get();
                            Iterator<Feature> iterator = result.iterator();

                            int counter = 0;
                            while (iterator.hasNext()) {
                                counter++;
                                Feature feature = iterator.next();

                                Map<String, Object> attributes = feature.getAttributes();
                                for (String key : attributes.keySet()) {
                                    Log.e("xyh" + key, String.valueOf(attributes.get(key)));
                                }


                                //高亮显示选中区域
                                Geometry geometry = feature.getGeometry();
                                mMapView.setViewpointGeometryAsync(geometry.getExtent());

                                SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 3);
                                SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.RED, lineSymbol);

                                if (mGraphicsOverlay != null) {
                                    ListenableList<Graphic> graphics = mGraphicsOverlay.getGraphics();
                                    if (graphics.size() > 0) {
                                        graphics.removeAll(graphics);
                                    }
                                }
                                Graphic graphic = new Graphic(geometry, fillSymbol);
                                mGraphicsOverlay.getGraphics().add(graphic);
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
                return true;
            }
        });
    }

shp文件查询方式3:identifyLayerAsync

 private void queryByIdentify() {
        mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this,mMapView) {
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                android.graphics.Point screenPoint = new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY()));
                final ListenableFuture<IdentifyLayerResult> identifyLayerResultListenableFuture = mMapView.identifyLayerAsync(
                        mFeatureLayer, screenPoint, 12, false, 10);
                identifyLayerResultListenableFuture.addDoneListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            IdentifyLayerResult identifyLayerResult = identifyLayerResultListenableFuture.get();
                            String name = identifyLayerResult.getLayerContent().getName();
                            List<GeoElement> elements = identifyLayerResult.getElements();
                            for (GeoElement element : elements) {
                                Map<String, Object> attributes = element.getAttributes();
                                Geometry geometry = element.getGeometry();

                                //高亮显示选中区域
                                mMapView.setViewpointGeometryAsync(geometry.getExtent());

                                SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 3);
                                SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.RED, lineSymbol);

                                if (mGraphicsOverlay != null) {
                                    ListenableList<Graphic> graphics = mGraphicsOverlay.getGraphics();
                                    if (graphics.size() > 0) {
                                        graphics.removeAll(graphics);
                                    }
                                }
                                Graphic graphic = new Graphic(geometry, fillSymbol);
                                mGraphicsOverlay.getGraphics().add(graphic);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        }
                    }
                });
                return super.onSingleTapConfirmed(e);
            }
        });
    }

Shapefile文件的编辑

只要具备移动端文件的读写能力,便可以轻松的通过FeatureLayer的相关方法进行空间数据的编辑(添加、修改、删除)。

1.添加要素

mShapefileFeatureTable.addFeatureAsync(feature);

   /**
     * 增加要素
     */
    public void addFeatureToShp() {

        // 调用isEditable和canAdd方法判断文件是否支持编辑操作,是否可添加要素;否,则抛出信息
        if (mShapefileFeatureTable.isEditable() && mShapefileFeatureTable.canAdd()) {

            // 构建新增几何
            Point mapPoint = new Point(140.0, 39.0, SpatialReference.create(4326));

            // 构建待增加的Feature对象,设置几何,设置属性
            Feature feature = mShapefileFeatureTable.createFeature();
            feature.setGeometry(mapPoint);
            feature.getAttributes().put("NAME", "测试点");

            // 调用addFeatureAsync方法增加要素
            final ListenableFuture<Void> addFeatureOper = mShapefileFeatureTable.addFeatureAsync(feature);

            // 在操作完成的监听事件中判断操作是否成功
            addFeatureOper.addDoneListener(new Runnable() {
                @Override
                public void run() {
                    try {
                        addFeatureOper.get();
                        if (addFeatureOper.isDone()) {
                            Log.e("xyh:", "Feature added!");
                        }
                    } catch (InterruptedException interruptedExceptionException) {
                        // 处理异常
                    } catch (ExecutionException executionException) {
                        // 处理异常
                    }
                }
            });
        } else {
            Log.e("xyh:", "The Shapefile cann't be edited");
        }
    }

2.删除

mShapefileFeatureTable.deleteFeatureAsync(feature);

3.更新

mShapefileFeatureTable.updateFeatureAsync(feature);

下面来看个整体Shapefile文件的编辑的案例,这是参考网上找的一篇比较好的博客。

https://blog.csdn.net/allenlu2008/article/details/78863055

先看看效果图:

这里写图片描述

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="esrichina.hymn.symbolizeshapefile.MainActivity">

    <com.esri.arcgisruntime.mapping.view.MapView
        android:id="@+id/mapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"></com.esri.arcgisruntime.mapping.view.MapView>

    <android.support.v7.widget.LinearLayoutCompat
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:orientation="vertical">

        <Button
            android:id="@+id/drawButton"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:text="绘制" />
        <Button
            android:id="@+id/saveButton"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:text="保存" />
        <Button
            android:id="@+id/selectButton"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:text="选择" />
        <Button
            android:id="@+id/deleteButton"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:text="删除" />
    </android.support.v7.widget.LinearLayoutCompat>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ArcGISMap mainArcGISMap;

    private FeatureLayer mainShapefileLayer;

    private SketchEditor mainSketchEditor;

    private SketchStyle mainSketchStyle;

    private boolean isSelect = false;

    //底图
    private String url = Environment.getExternalStorageDirectory().getAbsolutePath() + "/测试数据/bxbxbx.tpk";

    //shp文件
    private String shpPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/测试数据/gdtbt.shp";

    private MapView mMapView;

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

        findViews();

        String[] reqPermission = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
        int requestCode = 2;
        if (ContextCompat.checkSelfPermission(this, reqPermission[0]) == PackageManager.PERMISSION_GRANTED) {
            showShapefile();
        } else {
            ActivityCompat.requestPermissions(this, reqPermission, requestCode);
        }
    }


    private void showShapefile() {
        TileCache mainTileCache = new TileCache(url);
        ArcGISTiledLayer arcGISTiledLayer = new ArcGISTiledLayer(mainTileCache);
        Basemap basemap = new Basemap(arcGISTiledLayer);
        mainArcGISMap = new ArcGISMap(basemap);
        mMapView.setMap(mainArcGISMap);

        File file = new File(shpPath);
        if (!file.exists()) {
            Toast.makeText(this, "shp文件", Toast.LENGTH_SHORT).show();
            return;
        }
        final ShapefileFeatureTable shapefileFeatureTable = new ShapefileFeatureTable(shpPath);
        shapefileFeatureTable.loadAsync();
        shapefileFeatureTable.addDoneLoadingListener(new Runnable() {
            @Override
            public void run() {
                GeometryType gt = shapefileFeatureTable.getGeometryType();
                String name = shapefileFeatureTable.getTableName();
                mainShapefileLayer = new FeatureLayer(shapefileFeatureTable);
                if (mainShapefileLayer.getFullExtent() != null) {
                    mMapView.setViewpointGeometryAsync(mainShapefileLayer.getFullExtent());
                } else {
                    mainShapefileLayer.addDoneLoadingListener(new Runnable() {
                        @Override
                        public void run() {
                            mMapView.setViewpointGeometryAsync(mainShapefileLayer.getFullExtent());
                        }
                    });
                }
                mainArcGISMap.getOperationalLayers().add(mainShapefileLayer);
                startDrawing();
            }
        });


        SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 1.0f);
        SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.YELLOW, lineSymbol);
        SimpleRenderer renderer = new SimpleRenderer(fillSymbol);
        mainShapefileLayer.setRenderer(renderer);
        mainShapefileLayer.setSelectionColor(Color.GREEN);
        mainShapefileLayer.setSelectionWidth(5);
    }

    public void startDrawing() {
        try {
            mainSketchEditor = new SketchEditor();
            mainSketchStyle = new SketchStyle();
            mainSketchEditor.setSketchStyle(mainSketchStyle);
            mMapView.setSketchEditor(mainSketchEditor);

            mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, mMapView) {
                @Override
                public boolean onSingleTapConfirmed(MotionEvent e) {
                    if (isSelect == true) {
                        Point clickPoint = mMapView.screenToLocation(new android.graphics.Point(Math.round(e.getX()), Math.round(e.getY())));
                        int tolerance = 1;
                        double mapTolerance = tolerance * mMapView.getUnitsPerDensityIndependentPixel();
                        Envelope envelope = new Envelope(clickPoint.getX() - mapTolerance, clickPoint.getY() - mapTolerance,
                                clickPoint.getX() + mapTolerance, clickPoint.getY() + mapTolerance, mMapView.getSpatialReference());
                        QueryParameters query = new QueryParameters();
                        query.setGeometry(envelope);
                        query.setSpatialRelationship(QueryParameters.SpatialRelationship.WITHIN);
                        final ListenableFuture<FeatureQueryResult> future = mainShapefileLayer.selectFeaturesAsync(query, FeatureLayer.SelectionMode.NEW);

                        future.addDoneListener(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    FeatureQueryResult result = future.get();
                                    //mainShapefileLayer.getFeatureTable().deleteFeaturesAsync(result);
                                    Iterator<Feature> iterator = result.iterator();
                                    Feature feature;

                                    int counter = 0;
                                    while (iterator.hasNext()) {
                                        feature = iterator.next();

                                        Geometry geometry = feature.getGeometry();
                                        mMapView.setViewpointGeometryAsync(geometry.getExtent());

                                        counter++;

                                    }
                                } catch (Exception e) {
                                    e.getCause();
                                }
                            }
                        });
                    }

                    return super.onSingleTapConfirmed(e);
                }
            });
        } catch (Exception e) {
            e.getCause();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.drawButton: //绘制
                isSelect = false;
                mainShapefileLayer.clearSelection();
                mainSketchEditor.stop();
                mainSketchEditor.start(SketchCreationMode.POLYGON);
                break;
            case R.id.saveButton: //把绘制的图形添加到shp
                saveDraw();
                break;
            case R.id.selectButton: //选择要素
                isSelect = true;
                mainSketchEditor.stop();
                break;
            case R.id.deleteButton: //删除要素
                final ListenableFuture<FeatureQueryResult> selectResult = mainShapefileLayer.getSelectedFeaturesAsync();
                selectResult.addDoneListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            mainShapefileLayer.getFeatureTable().deleteFeaturesAsync(selectResult.get());
                        } catch (Exception e) {
                            e.getCause();
                        }
                    }
                });
                break;
        }
    }

    public void saveDraw() {
        if (mainSketchEditor.getGeometry() != null) {
            java.util.Map<String, Object> attributes = new HashMap<String, Object>();
            attributes.put("NAME", "自己画的省份");
            Feature addedFeature = mainShapefileLayer.getFeatureTable().createFeature(attributes, (Polygon) mainSketchEditor.getGeometry());
            final ListenableFuture<Void> addFeatureFuture = mainShapefileLayer.getFeatureTable().addFeatureAsync(addedFeature);
            mainSketchEditor.stop();
        }
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            showShapefile();
        } else {
            // report to user that permission was denied
            Toast.makeText(this, "Shapefile 无法打开,因为存储访问权限被拒绝!", Toast.LENGTH_SHORT).show();
        }
    }

    private void findViews() {
        mMapView = (MapView) findViewById(R.id.mapView);
        Button drawButton = (Button) findViewById(R.id.drawButton);
        Button saveButton = (Button) findViewById(R.id.saveButton);
        Button selectButton = (Button) findViewById(R.id.selectButton);
        Button deleteButton = (Button) findViewById(R.id.deleteButton);

        drawButton.setOnClickListener(this);
        saveButton.setOnClickListener(this);
        selectButton.setOnClickListener(this);
        deleteButton.setOnClickListener(this);
    }

}

上面出现了个SketchEditor

表示草图编辑器,允许用户在地图视图上以交互方式绘制几何图形。

我会在下面的博客详细讲解他的用法。

猜你喜欢

转载自blog.csdn.net/qq_36699930/article/details/82498704