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 gonGraphics = new ArrayList();
    // 取线的最后一个点 判断是否穿过面
    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> doubleGeo = new ArrayList>();
            // 第一步 区分大面和小面
            // 对面集合进行按面积大小的冒泡排序
            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 singleGeo = new ArrayList();
                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 result = new ArrayList();
            for (int a = 0; a < doubleGeo.size(); a++) {
                List smallGeo = new ArrayList();
                List 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 bigGeos = new ArrayList();
                bigGeos.add(bigGeo);
                bigGeos = segmentation(bigGeo, lineGeo, bigGeos);
                // 第三步 小面作分割
                List> smallData = new ArrayList>();
                for (int i = 0; i < smallGeo.size(); i++) {
                    List smallGeos = new ArrayList();// 存储一个小面分割后的面集合
                    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 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 segmentation(Geometry gonGeo, Geometry lineGeo, List 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 indexList = new ArrayList();
        List segmentationList = new ArrayList();
        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 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 gonLists = new ArrayList();
    gonLists.add(polygonFirst);
    gonLists.add(polygonSecond);
    return gonLists;
}

这个是分割完的处理工作

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

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

你可能感兴趣的:(android)