GeoTools使用--使用jts的线自相交重新绘制多边形

多边形线、面的自相交问题一直是个头疼的问题!网上的处理方式有多种,Polygonizer使用线从新绘制是一种,但会漏掉中间的孔洞。昨天突然想到一个巧妙的解决方法。程序员不多说,直接上代码了。巧妙方法来了_

处理前:
GeoTools使用--使用jts的线自相交重新绘制多边形_第1张图片

处理后:
GeoTools使用--使用jts的线自相交重新绘制多边形_第2张图片

工具类代码:

package com.vx.utils;

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.operation.valid.IsValidOp;
import com.vividsolutions.jts.operation.valid.TopologyValidationError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolygonUtil {

    private static Logger logger= LoggerFactory.getLogger(PolygonUtil.class);

    private static PrecisionModel precisionModel = new PrecisionModel(1);
    private static GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 0);



    public static Geometry conventPolygon(String geometryStr) {
        Geometry geometry1 = JTSNewUtil.geometry(geometryStr);
        if(geometry1 instanceof MultiPolygon){
            int numGeometries = geometry1.getNumGeometries();
            Geometry multiPolygon=geometry1.getFactory().createMultiPolygon(new Polygon[]{});
            for(int i=0;i<numGeometries;i++){
                Geometry geometryN = geometry1.getGeometryN(i);
                Geometry polygon = getPolygonByInteriorPoint((Polygon) geometryN);
                multiPolygon= multiPolygon.union(polygon);
            }
            geometry1=multiPolygon;
        }else if(geometry1 instanceof  Polygon){
            geometry1 =  getPolygonByInteriorPoint((Polygon) geometry1);
        }
        return geometry1;
    }

    /**
     * 使用jts的两线相交方法解决线的自相交问题
     * @param geometry1
     * @return
     */
    private static Geometry getPolygonByInteriorPoint(Polygon geometry1) {
        IsValidOp isValidOp = new IsValidOp(geometry1);
        TopologyValidationError validationError = isValidOp.getValidationError();
        //如果为空,说明没有自相交的线
        if(validationError==null){
          return geometry1;
        }
        LineString exteriorRing = geometry1.getExteriorRing();
        Coordinate[] coordinates = exteriorRing.intersection(exteriorRing).getCoordinates();
        //使用点集合重新生成面
        Geometry polygon1=coordinates2Polygon(coordinates);
        //对内部点进行重新挖空
        int numInteriorRing = geometry1.getNumInteriorRing();
        for(int i=0;i<numInteriorRing;i++){
            LineString interiorRingN = geometry1.getInteriorRingN(i);
            Polygon interiorPolygon = geometry1.getFactory().createPolygon(interiorRingN.getCoordinates());
//            polygon1= JTSNewUtilGDAL.tailor(polygon1,interiorPolygon);
            polygon1= polygon1.difference(interiorPolygon);
        }
        return polygon1;
    }

    /**
     * 遍历所有的点集合,将他们压如栈中,同时判断栈中是否有相同点,如果有就祛除栈中的点生成局部面。
     * 通过这种方式,可以达到遍历一次点,就可以矫正面的线的相交的问题
     * 
     * 终极奥义就是 压栈--出栈 !!!!
     * @param coordinates
     * @return
     */
    private static Geometry coordinates2Polygon(Coordinate[] coordinates) {
        Geometry resultPolygon = null;
        Stack<Coordinate> coordinateStack=new Stack();
        Coordinate lastCoord=null;
        Coordinate nowDouble=null;
        for(int i=0;i<coordinates.length;i++){
            nowDouble=coordinates[i];
            //因为传入的点集合,有连续两个点坐标一样的点,这样的点需要提出。没有中间点的两个点怎么能组合成面呢 ^_^
            if(lastCoord!=null && nowDouble.equals(lastCoord)){
                continue;
            }
            lastCoord=nowDouble;

            //判断栈中是否已经包含相同的点,如果有,就可以提取相同点到相同点之间的所有点,组合成局部面
            if(coordinateStack.contains(nowDouble)){
                List<Coordinate> topoCoords=new ArrayList<>();
                topoCoords.add(nowDouble);
                Coordinate pop ;
                do {
                    pop=coordinateStack.pop();
                    topoCoords.add(pop);
                }while (!pop.equals(nowDouble));
                //将交点再放回栈中
                coordinateStack.push(nowDouble);
                //生成局部面
                resultPolygon = coordinateToPolygon(resultPolygon, topoCoords);
            }else {
                coordinateStack.push(nowDouble);
            }
        }
        if(coordinateStack.size()>1){
            resultPolygon= coordinateToPolygon(resultPolygon, coordinateStack) ;
        }
        return resultPolygon;
    }

    /**
     *  点组合成面
     * @param resultPolygon
     * @param topoCoords
     * @return
     */
    private static Geometry coordinateToPolygon(Geometry resultPolygon,List topoCoords) {
    	//小于四个点的不进行处理,因为组织一个面最少4个点(收尾两个点坐标一致)
    	if(topoCoords.size()<4){
    		return resultPolygon;
    	}
        Geometry polygon=  geometryFactory.createPolygon((Coordinate[]) topoCoords.toArray(new Coordinate[]{})).buffer(0);
        if(resultPolygon==null){
            resultPolygon=polygon;
        }else {
//            resultPolygon=JTSNewUtilGDAL.symDifference(resultPolygon, (Polygon) polygon);
            resultPolygon=resultPolygon.symDifference(polygon);
        }
        return resultPolygon;
    }
}

(如果有问题请留言,如果对你有帮助,请点赞!)

你可能感兴趣的:(geotools,jts,geotools)