ArcGIS For Android 利用线对面进行分割

需求是要将一个面用线将其分割成两块或多块的面。这个面包括多路径面的极端情况。
在ArcGIS For Android提供的API中 GeometryEngine工具类中未有Segment这个方法,在官网查阅中发现在最新的100.0.0版本中是有这个方法的,但是项目中使用的是10.2.8的版本,Eris在这两个版本变化很大,要换SDK十分麻烦,要更换和地图有关的所有地方,所以只能自己动手去写这个分割逻辑。

具体代码

private void previousSegmentation(Geometry gonGeo, Geometry lineGeo) {
    // 这个面的集合用来做遍历
    List<Geometry> gonGraphics = new ArrayList<Geometry>();
    // 取线的最后一个点 判断是否穿过面
    MultiPath multiPath = (MultiPath) lineGeo;
    MultiPath multiPathGon = (MultiPath) gonGeo;
    boolean isIsland = false;

    Point pointLast = multiPath.getPoint(multiPath.getPointCount() - 1);
    Point pointFirst = multiPath.getPoint(0);
    // 判断分割首要条件为线与面相交,并且线的第一个点与最后一个点不和面相交
    if (!GeometryEngine.intersects(gonGeo, pointFirst, mMapView.getSpatialReference())
            && !GeometryEngine.intersects(gonGeo, pointLast, mMapView.getSpatialReference())
            && GeometryEngine.intersects(gonGeo, lineGeo, mMapView.getSpatialReference())
            ) {
        // 遍历多路径 生成面集合
        SegmentIterator segmentIterator = multiPathGon.querySegmentIterator();
        while (segmentIterator.nextPath()) {
            Polygon polygonPath = new Polygon();
            while (segmentIterator.hasNextSegment()) {
                polygonPath.addSegment(segmentIterator.nextSegment(), false);
            }
            polygonPath.removePoint(polygonPath.getPointCount() - 1);
            gonGraphics.add(polygonPath);
        }
        if (gonGraphics.size() > 1) {
            // 对自身集合遍历 判断是否是环岛面
            for (int i = 0; i < gonGraphics.size(); i++) {
                for (int j = 0; j < gonGraphics.size(); j++) {
                    if (i != j && GeometryEngine.contains(gonGraphics.get(i),
                            gonGraphics.get(j), mMapView.getSpatialReference())) {
                        isIsland = true;
                        break;
                    }
                }
            }
        }
        if (isIsland) { // 如果是环岛面
            List<List<Geometry>> doubleGeo = new ArrayList<List<Geometry>>();
            // 第一步 区分大面和小面
            // 对面集合进行按面积大小的冒泡排序
            for (int k = 0; k < gonGraphics.size(); k++) {
                for (int z = 0; z < gonGraphics.size() - 1 - k; z++) {
                    double index = Math.abs(gonGraphics.get(z).calculateArea2D());
                    double index1 = Math.abs(gonGraphics.get(z + 1).calculateArea2D());
                    if (index < index1) {
                        gonGraphics.add(z, gonGraphics.get(z + 1));
                        gonGraphics.remove(z + 2);
                    }
                }
            }
            // 对面进行分组
            for (int i = 0; i < gonGraphics.size(); i++) {
                List<Geometry> singleGeo = new ArrayList<Geometry>();
                if (gonGraphics.get(i).calculateArea2D() > 0) {// 环岛小面的面积是负数
                    for (int j = 0; j < gonGraphics.size(); j++) {
                        if (i != j && GeometryEngine.contains(gonGraphics.get(i),
                                gonGraphics.get(j), mMapView.getSpatialReference())) {
                            if (singleGeo.isEmpty()) {// 如果暂时没有面 则是未放入大面
                                singleGeo.add(gonGraphics.get(i));// 取到大面
                            }
                            singleGeo.add(gonGraphics.get(j));// 取到被包含的小面
                        }
                    }
                    if (singleGeo.isEmpty()) {// 是空的情况 就是单一的普通的面
                        singleGeo.add(gonGraphics.get(i));
                    }// 不是空的情况 就是有环岛的面
                    doubleGeo.add(singleGeo);
                }
            }
            // 存放结果的集合
            List<Geometry> result = new ArrayList<Geometry>();
            for (int a = 0; a < doubleGeo.size(); a++) {
                List<Geometry> smallGeo = new ArrayList<Geometry>();
                List<Geometry> geometries = doubleGeo.get(a);
                Geometry bigGeo = new Polygon();
                for (int i = 0; i < geometries.size(); i++) {
                    if (i == 0) {
                        bigGeo = geometries.get(i);// 取到大面
                    } else {
                        smallGeo.add(geometries.get(i));// 加入小面
                    }
                }
                // 第二步 大面作分割
                List<Geometry> bigGeos = new ArrayList<Geometry>();
                bigGeos.add(bigGeo);
                bigGeos = segmentation(bigGeo, lineGeo, bigGeos);
                // 第三步 小面作分割
                List<List<Geometry>> smallData = new ArrayList<List<Geometry>>();
                for (int i = 0; i < smallGeo.size(); i++) {
                    List<Geometry> smallGeos = new ArrayList<Geometry>();// 存储一个小面分割后的面集合
                    smallGeos.add(smallGeo.get(i));// 加入当前需要被分割的小面
                    smallGeos = segmentation(smallGeo.get(i), lineGeo, smallGeos);// 获取分割后的结果
                    smallData.add(smallGeos);
                }
                // 第四步 大面和小面的集合作差
                for (int i = 0; i < bigGeos.size(); i++) {
                    Geometry big = bigGeos.get(i);
                    for (int j = 0; j < smallData.size(); j++) { // 循环小面的二维集合
                        for (int k = 0; k < smallData.get(j).size(); k++) {// 遍历小面的一个集合的面
                            big = GeometryEngine.difference(big, smallData.get(j).get(k), mMapView.getSpatialReference());
                        }
                    }
                    // 一个大面遍历完所有小面后 加入结果集合
                    if (((MultiPath) big).getPointCount() != 0) {// 判断是否是空图形
                        result.add(big);
                    }
                }
            }
            segmentationOver(result);
        } else {
            List<Geometry> segmentation = segmentation(gonGeo, lineGeo, gonGraphics);
            // 分割操作完成后
            segmentationOver(segmentation);
        }
    } else {
        ToastUtil.showShort(this, "需要画一条穿过面的线");
        editGraphicsLayer.removeGraphic(graphicsSelected.get(1).getUid());
        highGraphicsLayer.removeAll();
        graphicsSelected.clear();
        allDisSelector();
    }
}

/**
 * 分割操作
 *
 * @param gonGeo      传入需要分割的面
 * @param lineGeo     传入画出的线
 * @param gonGraphics 存有需要分割的面的集合  用于返回分割完后的面集
 */
private List<Geometry> segmentation(Geometry gonGeo, Geometry lineGeo, List<Geometry> gonGraphics) {
    // 第一次相交操作 取得相交之后的线段
    Geometry intersect = GeometryEngine.intersect(gonGeo, lineGeo, mMapView.getSpatialReference());
    MultiPath intersectMulti = (MultiPath) intersect;
    // 线的路径
    for (int i = 0; i < intersectMulti.getPathCount(); i++) {
        int pathStart = intersectMulti.getPathStart(i);
        int pathEnd = intersectMulti.getPathEnd(i);
        Polyline polyline = new Polyline();
        // 完成一个路径的遍历
        for (int j = pathStart; j < pathEnd - 1; j++) {
            Line line = new Line();
            line.setStart(intersectMulti.getPoint(j));
            line.setEnd(intersectMulti.getPoint(j + 1));
            polyline.addSegment(line, false);
        }
        // 拿路径去和面集合遍历
        List<Integer> indexList = new ArrayList<Integer>();
        List<Geometry> segmentationList = new ArrayList<Geometry>();
        for (int j = 0; j < gonGraphics.size(); j++) {
            if (GeometryEngine.intersects(gonGraphics.get(j), polyline, mMapView.getSpatialReference())) {
                Geometry intersectLine = GeometryEngine.intersect(gonGraphics.get(j), polyline, mMapView.getSpatialReference());
                // 分割
                if (((MultiPath) intersectLine).getPointCount() >= 2) {
                    segmentationList.addAll(CalculateUtil.segmentation(gonGraphics.get(j), intersectLine, mMapView));
                    // 这个面被处理过后 就记录下标
                    indexList.add(j);
                }
            }
        }
        // 加入本次处理后的两个面
        gonGraphics.addAll(segmentationList);
        // 处理过的面的下标 去掉
        for (int j = 0; j < indexList.size(); j++) {
            gonGraphics.remove(indexList.get(indexList.size() - j - 1).intValue());
        }
    }
    return gonGraphics;
}

最主要的方法:

 public static List<Geometry> segmentation(Geometry gonGeo, Geometry intersect,MapView mapView) {
    // 获得路径
    MultiPath gonMulti = (MultiPath) gonGeo;
    MultiPath lineMulti = (MultiPath) intersect;
    Polygon polygonFirst = new Polygon();
    Polygon polygonSecond = new Polygon();
    int start = 0;
    int end = 0;
    // 线的顺序和面的顺序是否反向
    boolean isReverse = false;
    // 记录交点所在的下标
    int[] index = new int[2];
    int count = 0;
    // 用交点去遍历面的线 取得 各个交点所在的线的下标
    for (int j = 0; j < lineMulti.getPointCount(); j++) {
        Point point = lineMulti.getPoint(j);
        for (int i = 0; i < gonMulti.getPointCount(); i++) {
            Point pointFirst = gonMulti.getPoint(i);
            Point pointSecond;
            if (i + 1 == gonMulti.getPointCount()) {
                pointSecond = gonMulti.getPoint(0);
            } else {
                pointSecond = gonMulti.getPoint(i + 1);
            }
            Line lineInGon = new Line();
            lineInGon.setStart(pointFirst);
            lineInGon.setEnd(pointSecond);
            // 面的线
            Polyline polyline = new Polyline();
            polyline.addSegment(lineInGon, false);
            if (GeometryEngine.intersects(point, polyline, mapView.getSpatialReference())) {
                if(count<2){
                    index[count] = i;
                    count++;
                }
            }
        }
    }
    // 取到交点下标后 排序
    if (index[0] < index[1]) {
        start = index[0];
        end = index[1];
        isReverse = false;
    } else if (index[0] > index[1]) {
        start = index[1];
        end = index[0];
        isReverse = true;
    } else if (index[0] == index[1]) {
        start = index[0];
        end = index[1];
    }
    for (int i = 0; i < gonMulti.getPointCount(); i++) {
        if (start == end) {  // 交点在同一个线上
            if (i != start) {
                Line line = new Line();
                line.setStart(gonMulti.getPoint(i));
                if (i + 1 == gonMulti.getPointCount()) {
                    line.setEnd(gonMulti.getPoint(0));
                } else {
                    line.setEnd(gonMulti.getPoint(i + 1));
                }
                polygonFirst.addSegment(line, false);
            }
            if (i == start) {
                double distance1 = GeometryEngine.distance(gonMulti.getPoint(i), lineMulti.getPoint(0), mapView.getSpatialReference());
                double distance2 = GeometryEngine.distance(gonMulti.getPoint(i), lineMulti.getPoint(lineMulti.getPointCount() - 1), mapView.getSpatialReference());
                // 判断是否反向
                isReverse = distance1 > distance2;
                // 第一个面的点
                Line line = new Line();
                if (isReverse) {
                    line.setStart(gonMulti.getPoint(i));
                    line.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                } else {
                    line.setStart(gonMulti.getPoint(i));
                    line.setEnd(lineMulti.getPoint(0));
                }
                polygonFirst.addSegment(line, false);
                // 加入面中的线段
                if (isReverse) {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineFirst = new Line();
                        lineFirst.setStart(lineMulti.getPoint(lineMulti.getPointCount() - k - 1));
                        lineFirst.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - k - 2));
                        polygonFirst.addSegment(lineFirst, false);
                    }
                } else {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineFirst = new Line();
                        lineFirst.setStart(lineMulti.getPoint(k));
                        lineFirst.setEnd(lineMulti.getPoint(k + 1));
                        polygonFirst.addSegment(lineFirst, false);
                    }
                }
                // 加入穿过之后的线
                Line lineAfter = new Line();
                if (i + 1 == gonMulti.getPointCount()) {
                    if (isReverse) {
                        lineAfter.setStart(lineMulti.getPoint(0));
                        lineAfter.setEnd(gonMulti.getPoint(0));
                    } else {
                        lineAfter.setStart(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                        lineAfter.setEnd(gonMulti.getPoint(0));
                    }
                } else {
                    if (isReverse) {
                        lineAfter.setStart(lineMulti.getPoint(0));
                        lineAfter.setEnd(gonMulti.getPoint(i + 1));
                    } else {
                        lineAfter.setStart(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                        lineAfter.setEnd(gonMulti.getPoint(i + 1));
                    }
                }
                polygonFirst.addSegment(lineAfter, false);
                // 第二个面的闭合
                Line lineSecond = new Line();
                lineSecond.setStart(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                lineSecond.setEnd(lineMulti.getPoint(0));
                polygonSecond.addSegment(lineSecond, false);
                for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                    Line line1 = new Line();
                    line1.setStart(lineMulti.getPoint(k));
                    line1.setEnd(lineMulti.getPoint(k + 1));
                    polygonSecond.addSegment(line1, false);
                }
            }
        } else {  // 交点不在同一个线上
            if (i < start) {  // 小于第一个交点的点连接至第一个交点
                Line line = new Line();
                line.setStart(gonMulti.getPoint(i));
                line.setEnd(gonMulti.getPoint(i + 1));
                polygonFirst.addSegment(line, false);
            }
            if (i == start) { // 等于则连接第一个交点 这个要加三个路径
                Line line = new Line();
                if (isReverse) {
                    line.setStart(gonMulti.getPoint(i));
                    line.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                } else {
                    line.setStart(gonMulti.getPoint(i));
                    line.setEnd(lineMulti.getPoint(0));
                }
                polygonFirst.addSegment(line, false);
                // 加入面中的线段
                if (isReverse) {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineFirst = new Line();
                        lineFirst.setStart(lineMulti.getPoint(lineMulti.getPointCount() - k - 1));
                        lineFirst.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - k - 2));
                        polygonFirst.addSegment(lineFirst, false);
                    }
                } else {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineFirst = new Line();
                        lineFirst.setStart(lineMulti.getPoint(k));
                        lineFirst.setEnd(lineMulti.getPoint(k + 1));
                        polygonFirst.addSegment(lineFirst, false);
                    }
                }
                // 第二个面加入
                Line lineSecond = new Line();
                if (isReverse) {
                    lineSecond.setStart(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                    lineSecond.setEnd(gonMulti.getPoint(i + 1));
                } else {
                    lineSecond.setStart(lineMulti.getPoint(0));
                    lineSecond.setEnd(gonMulti.getPoint(i + 1));
                }
                polygonSecond.addSegment(lineSecond, false);
            }
            if (i > start && i < end) { // 在两个交点之间的时候
                Line line = new Line();
                line.setStart(gonMulti.getPoint(i));
                line.setEnd(gonMulti.getPoint(i + 1));
                polygonSecond.addSegment(line, false);
            }
            if (i == end) {
                Line line = new Line();
                line.setStart(gonMulti.getPoint(i));
                if (isReverse) {
                    line.setEnd(lineMulti.getPoint(0));
                } else {
                    line.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                }
                polygonSecond.addSegment(line, false);
                // 反向加入面中的线
                if (isReverse) {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineSecond = new Line();
                        lineSecond.setStart(lineMulti.getPoint(k));
                        lineSecond.setEnd(lineMulti.getPoint(k + 1));
                        polygonSecond.addSegment(lineSecond, false);
                    }
                } else {
                    for (int k = 0; k < lineMulti.getPointCount() - 1; k++) {
                        Line lineSecond = new Line();
                        lineSecond.setStart(lineMulti.getPoint(lineMulti.getPointCount() - k - 1));
                        lineSecond.setEnd(lineMulti.getPoint(lineMulti.getPointCount() - k - 2));
                        polygonSecond.addSegment(lineSecond, false);
                    }
                }
                // 第一个面的线
                Line lineFirst = new Line();
                if (isReverse) {
                    lineFirst.setStart(lineMulti.getPoint(0));
                } else {
                    lineFirst.setStart(lineMulti.getPoint(lineMulti.getPointCount() - 1));
                }
                if (i + 1 == gonMulti.getPointCount()) {
                    lineFirst.setEnd(gonMulti.getPoint(0));
                } else {
                    lineFirst.setEnd(gonMulti.getPoint(i + 1));

                }
                polygonFirst.addSegment(lineFirst, false);

            }
            if (i > end) {    // 这里完成第一个面的路径
                Line line = new Line();
                line.setStart(gonMulti.getPoint(i));
                if (i + 1 == gonMulti.getPointCount()) {    // 超出下标则到0点去
                    line.setEnd(gonMulti.getPoint(0));
                } else {
                    line.setEnd(gonMulti.getPoint(i + 1));
                }
                polygonFirst.addSegment(line, false);
            }
        }
    }
    polygonFirst.removePoint(polygonFirst.getPointCount() - 1);
    polygonSecond.removePoint(polygonSecond.getPointCount() - 1);
    List<Geometry> gonLists = new ArrayList<Geometry>();
    gonLists.add(polygonFirst);
    gonLists.add(polygonSecond);
    return gonLists;
}

这个是分割完的处理工作

    private void segmentationOver(List<Geometry> gonGraphics) {  editGraphicsLayer.removeGraphic(graphicsSelected.get(0).getUid());
    editGraphicsLayer.removeGraphic(graphicsSelected.get(1).getUid());
    highGraphicsLayer.removeAll();
    graphicsSelected.clear();
    allDisSelector();
}

editGraphicsLayer 是当前编辑的图层对象.
highGraphicsLayer 是用来高亮的图层对象.
allDisSelector 是我用来取消要素高亮的方法.
难点主要是在于点集是有顺序的,需要判断线切入面的交点顺序和原来面的点集顺序是是否是相同的,
这个判断在segmentation()这个方法中完成。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ArcGIS for Android是一个用于在Android平台上进行地理信息系统(GIS)开发的工具。它提供了一套API和库,使开发者能够在Android设备上创建和展示地图、进行地理数据分析和可视化等操作。根据引用\[1\],Esri在最近几年对ArcGIS for Android进行了大量的改进和提升,为GIS开发者和工作者提供了更多便利。最新版本的ArcGIS Runtime API for Android是100.12.0,其中最大的改进是增加了一个Geotrigger API,可以实时监控GIS数据并在满足指定条件时接收通知,例如设备进入或离开区域时。这个功能相当于自带了一个实时监控当前位置并进行地理位置判断的地理围栏Geofencing。 根据引用\[2\]和\[3\],在Android Studio中开发ArcGIS项目有两种方式。一种是在线引用ArcGIS库,另一种是将ArcGIS Runtime SDK for Android下载到本地并进行引用。对于在线引用,可以在项目的build.gradle文件中添加依赖项implementation 'com.esri.arcgisruntime:arcgis-android:100.10.0'来引用ArcGIS库。 总之,ArcGIS for Android是一个功能强大的GIS开发工具,可以帮助开发者在Android平台上构建各种地理信息应用程序。 #### 引用[.reference_title] - *1* *3* [arcgis for android(一)配置Android Sutdio环境](https://blog.csdn.net/HB_Programmer/article/details/119967868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [ArcGIS for AndroidAndroid Studio开发ArcGIS项目)](https://blog.csdn.net/qq_40820382/article/details/103962702)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值