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

来源:互联网 发布:mac电脑excel内存不足 编辑:程序博客网 时间:2024/05/24 06:41

需求是要将一个面用线将其分割成两块或多块的面。这个面包括多路径面的极端情况。
在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()这个方法中完成。

原创粉丝点击