GIS工具类

1.maven依赖

		<dependency>
			<groupId>org.geotools</groupId>
			<artifactId>gt-geojson</artifactId>
			<version>21.0</version>
		</dependency>
		<dependency>
			<groupId>org.locationtech.jts</groupId>
			<artifactId>jts-core</artifactId>
			<version>1.18.2</version>
		</dependency>
		 <dependency>
            <groupId>com.vividsolutions</groupId>
            <artifactId>jts</artifactId>
            <version>1.13</version>
        </dependency>

2.rest接口及参数

2.1参数对象

@ApiModel("坐标转换参数")
public class CoordinateTransformBO {
    @ApiModelProperty(value = "经度",required = true)
    private Double lon;
    @ApiModelProperty(value = "纬度",required = true)
    private Double lat;
    @ApiModelProperty(value = "转换方式",required = true,example = "BD2WGS、GCJ2BD")
    private String type;

    public Double getLon() {
        return lon;
    }

    public void setLon(Double lon) {
        this.lon = lon;
    }

    public Double getLat() {
        return lat;
    }

    public void setLat(Double lat) {
        this.lat = lat;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}
@ApiModel("辖区参数")
public class GeomBO {
    @ApiModelProperty(value = "wkt格式空间字段")
    private String geometry ;

    @ApiModelProperty(value = "geomJson格式空间字段")
    private String geomJson ;

    public String getGeometry() {
        return geometry;
    }

    public void setGeometry(String geometry) {
        this.geometry = geometry;
    }

    public String getGeomJson() {
        return geomJson;
    }

    public void setGeomJson(String geomJson) {
        this.geomJson = geomJson;
    }
}
@ApiModel("区域坐标抽稀参数")
public class GeomSimplifyBO {
    @ApiModelProperty(value = "空间字段",required = true)
    private String geometry ;
    @ApiModelProperty(value = "抽稀距离",required = true,example = "0.0003")
    private Double tolerance;

    public String getGeometry() {
        return geometry;
    }

    public void setGeometry(String geometry) {
        this.geometry = geometry;
    }

    public Double getTolerance() {
        return tolerance;
    }

    public void setTolerance(Double tolerance) {
        this.tolerance = tolerance;
    }
}
@ApiModel("区域坐标转换参数")
public class GeomTransformBO {
    @ApiModelProperty(value = "空间字段")
    private String geometry ;
    @ApiModelProperty(value = "转换方式")
    private String type;

    public String getGeometry() {
        return geometry;
    }

    public void setGeometry(String geometry) {
        this.geometry = geometry;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}
/**
* 转换类型枚举
*/
public enum GisTransformTypeEnum {
    BD2WGS("BD2WGS", "百度坐标系(BD-09)转WGS(WGS84)坐标"),
    WGS2BD("WGS2BD", "WGS(WGS84)坐标转百度坐标系(BD-09)"),
    GCJ2BD("GCJ2BD", "火星坐标系(GCJ-02)转百度坐标系(BD-09)"),
    BD2GCJ("BD2GCJ", "百度坐标系(BD-09)转火星坐标系(GCJ-02)"),
    WGS2GCJ("WGS2GCJ", "WGS(WGS84)坐标转火星坐标系(GCJ02)"),
    GCJ2WGS("GCJ2WGS", "火星坐标系(GCJ02)转WGS(WGS84)坐标"),
    WGS2MCT("WGS2MCT", "WGS(WGS84)坐标转墨卡托投影坐标(3857)"),
    MCT2WGS("MCT2WGS", "墨卡托投影坐标(3857)转WGS(WGS84)坐标"),
    BD2MCT("BD2MCT", "百度坐标系(BD-09)转墨卡托投影坐标(3857)"),
    MCT2BD("MCT2BD", "墨卡托投影坐标(3857)转百度坐标系(BD-09)"),
    GCJ2MCT("GCJ2MCT", "火星坐标系(GCJ-02)转墨卡托投影坐标(3857)"),
    MCT2GCJ("MCT2GCJ", "墨卡托投影坐标(3857)转火星坐标系(GCJ-02)"),
    ;
    private String name;
    private String description;

    GisTransformTypeEnum(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public String getName() {
        return name;
    }

}
//经纬度点位类
public class Point {
    private double lon;
    private double lat;

    public Point(double lon, double lat) {
        this.lon = lon;
        this.lat = lat;
    }

    public double getLon() {
        return lon;
    }

    public double getLat() {
        return lat;
    }
}

2.2 工具调用service

部分引入包名被删除,自行修改添加即可

package gis.svc.gis;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vividsolutions.jts.geom.*;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.geo.GeoPoint;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;


/**
 * @Author 
 * @Description
 * @Date 2023/6/1 16:17
 */
@Service
public class GisToolService  {

	//坐标转换
    public Point transform(CoordinateTransformBO coordinateTransformBO) throws Exception {
        if (coordinateTransformBO == null || coordinateTransformBO.getLon() == null || coordinateTransformBO.getLat() == null || StringUtils.isBlank(coordinateTransformBO.getType())) {
            throw new Exception("缺少必填参数");
        }
        Point point = new Point(coordinateTransformBO.getLon(), coordinateTransformBO.getLat());
        return transformByType(point, coordinateTransformBO.getType());
    }

	//坐标抽稀
    public String simplify(GeomSimplifyBO geomSimplifyBO) throws Exception {
        if (geomSimplifyBO == null || StringUtils.isBlank(geomSimplifyBO.getGeometry()) || geomSimplifyBO.getTolerance() == null || geomSimplifyBO.getTolerance() < 0) {
            throw new Exception("缺少必填参数");
        }
        return RarefyUtil.simplifyByGeom(geomSimplifyBO.getGeometry(), geomSimplifyBO.getTolerance()).toString();
    }

  //获取多边形内心
    public GeoPoint getCenterPoint(GeomBO geomBO) throws Exception {
        if (geomBO == null || StringUtils.isBlank(geomBO.getGeometry())) {
            throw new Exception("缺少必填参数");
        }
        return GisUtil.getCenterPointByGeometry(geomBO.getGeometry());
    }

	//区域坐标转换
    public String wktTransform(GeomTransformBO geomTransformBO) throws Exception {
        if (geomTransformBO == null || StringUtils.isBlank(geomTransformBO.getGeometry()) || StringUtils.isBlank(geomTransformBO.getType())) {
            throw new Exception("缺少必填参数!");
        }
        Geometry geom = GisUtil.getGeomByStr(geomTransformBO.getGeometry());
        if (geom != null) {
            if (geom instanceof com.vividsolutions.jts.geom.Point) {
                com.vividsolutions.jts.geom.Point p = (com.vividsolutions.jts.geom.Point) geom;
                Point point = transformByType(new Point(p.getX(), p.getY()), geomTransformBO.getType());
                return GisUtil.geometryFactory.createPoint(new Coordinate(point.getLon(), point.getLat())).toString();
            } else if (geom instanceof Polygon) {
                Polygon polygon = (Polygon) geom;
                return transformPolygon(polygon.getCoordinates(), geomTransformBO.getType()).toString();
            } else if (geom instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) geom;
                Polygon[] polygons = new Polygon[multiPolygon.getNumGeometries()];
                for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                    Geometry geometryN = multiPolygon.getGeometryN(i);
                    Coordinate[] coordinates = geometryN.getCoordinates();
                    Polygon polygon = transformPolygon(coordinates, geomTransformBO.getType());
                    polygons[i] = polygon;
                }
                return GisUtil.geometryFactory.createMultiPolygon(polygons).toString();
            } else if (geom instanceof LineString) {
                LineString lineString = (LineString) geom;
                Coordinate[] coordinates = lineString.getCoordinates();
                Coordinate[] newCoordinates = transformCoordinate(coordinates, geomTransformBO.getType());
                return GisUtil.geometryFactory.createLineString(newCoordinates).toString();
            } else if (geom instanceof MultiLineString) {
                MultiLineString multiLineString = (MultiLineString) geom;
                LineString[] lineStrings = new LineString[multiLineString.getNumGeometries()];
                for (int i = 0; i < multiLineString.getNumGeometries(); i++) {
                    Geometry geometryN = multiLineString.getGeometryN(i);
                    Coordinate[] coordinates = geometryN.getCoordinates();
                    Coordinate[] newCoordinates = transformCoordinate(coordinates, geomTransformBO.getType());
                    lineStrings[i] = GisUtil.geometryFactory.createLineString(newCoordinates);
                }
                return GisUtil.geometryFactory.createMultiLineString(lineStrings).toString();
            }
        }
        return null;
    }

    private Coordinate[] transformCoordinate(Coordinate[] coordinates, String type) throws Exception {
        if (coordinates != null && coordinates.length > 0) {
            Coordinate[] newCoordinates = new Coordinate[coordinates.length];
            for (int i = 0; i < coordinates.length; i++) {
                Coordinate coordinate = coordinates[i];
                Point p = new Point(coordinate.x, coordinate.y);
                Point newPoint = transformByType(p, type);
                Coordinate c = new Coordinate(newPoint.getLon(), newPoint.getLat());
                newCoordinates[i] = c;
            }
            return newCoordinates;
        }
        return null;
    }

    private Polygon transformPolygon(Coordinate[] coordinates, String type) throws Exception {
        Coordinate[] newCoordinates = transformCoordinate(coordinates, type);
        if (newCoordinates != null && newCoordinates.length > 0) {
            return GisUtil.geometryFactory.createPolygon(newCoordinates);
        }
        return null;
    }

    private Point transformByType(Point point, String type) throws Exception {
        switch (GisTransformTypeEnum.valueOf(type)) {
            case BD2GCJ:
                return TransformUtils.bd09toGcj02(point);
            case GCJ2BD:
                return TransformUtils.gcj02toBd09(point);
            case WGS2BD:
                return TransformUtils.wgs84toBd09(point);
            case BD2WGS:
                return TransformUtils.bd09toWgs84(point);
            case WGS2GCJ:
                return TransformUtils.wgs84toGcj02(point);
            case GCJ2WGS:
                return TransformUtils.gcj02toWgs84(point);
            case WGS2MCT:
                return TransformUtils.wgs84ToMercator(point);
            case MCT2WGS:
                return TransformUtils.mercatorToWgs84(point);
            case BD2MCT:
                return TransformUtils.wgs84ToMercator(TransformUtils.bd09toWgs84(point));
            case MCT2BD:
                return TransformUtils.wgs84toBd09(TransformUtils.mercatorToWgs84(point));
            case GCJ2MCT:
                return TransformUtils.wgs84ToMercator(TransformUtils.gcj02toWgs84(point));
            case MCT2GCJ:
                return TransformUtils.wgs84toGcj02(TransformUtils.mercatorToWgs84(point));
            default:
                throw new Exception("暂不支持的转换类型:" + type);
        }
    }

	//wkt转geomJson
    public GeomBO wktToGeomJson(GeomBO geomBO) throws Exception {
        if (geomBO != null && StringUtils.isNotBlank(geomBO.getGeometry())) {
            Geometry geometry = LayerFactory.getReader().read(geomBO.getGeometry());
            if (geometry != null) {
                JSONObject geometryJson = new JSONObject();
                if (geometry instanceof GeometryCollection) {
                    JSONArray geometryCollectionArray = new JSONArray();
                    GeometryCollection geometryCollection = (GeometryCollection) geometry;
                    for (int i = 0; i < geometryCollection.getNumGeometries(); i++) {
                        Geometry geometryN = geometryCollection.getGeometryN(i);
                        JSONArray geometryJsonArray = getGeometryJsonArray(geometryN.getCoordinates());
                        geometryCollectionArray.add(geometryJsonArray);
                    }
                    geometryJson.put("coordinates", geometryCollectionArray);
                } else {
                    JSONArray geometryArray = getGeometryJsonArray(geometry.getCoordinates());
                    geometryJson.put("coordinates", geometryArray);
                }
                geometryJson.put("type", geometry.getGeometryType());
                JSONObject featureJson = new JSONObject();
                featureJson.put("geometry", geometryJson);
                featureJson.put("type", "Feature");
                geomBO.setGeomJson(featureJson.toJSONString());
            }
        }
        return geomBO;
    }

    private JSONArray getGeometryJsonArray(Coordinate[] coordinates) {
        JSONArray geometryArray = new JSONArray();
        if (coordinates != null && coordinates.length > 0) {
            for (int i = 0; i < coordinates.length; i++) {
                Coordinate coordinate = coordinates[i];
                JSONArray coordinateArray = new JSONArray();
                coordinateArray.add(coordinate.x);
                coordinateArray.add(coordinate.y);
                geometryArray.add(coordinateArray);
            }
        }
        return geometryArray;
    }

	//geomJson转wkt
    public JSONArray geomJsonToWkt(GeomBO geomBO) throws Exception {
        JSONArray jsonArray = new JSONArray();
        if (geomBO != null && StringUtils.isNotBlank(geomBO.getGeomJson())) {
            JSONObject dataJson = JSONObject.parseObject(geomBO.getGeomJson());
            if (dataJson != null) {
                String type = dataJson.getString("type");
                if ("FeatureCollection".equals(type)) {
                    JSONArray features = dataJson.getJSONArray("features");
                    for (Object feature : features) {
                        JSONObject jsonObject = analyzeFeature(feature);
                        jsonArray.add(jsonObject);
                    }
                } else if ("Feature".equals(type)) {
                    JSONObject jsonObject = analyzeFeature(geomBO.getGeomJson());
                    jsonArray.add(jsonObject);
                } else {
                    JSONObject jsonObject = new JSONObject();
                    GeometryJSON geometryJSON = new GeometryJSON();
                    org.locationtech.jts.geom.Geometry geometry = geometryJSON.read(geomBO.getGeomJson());
                    jsonObject.put("geometry", geometry.toString());
                }
            }
        }
        return jsonArray;
    }

    private JSONObject analyzeFeature(Object feature) throws IOException {
        JSONObject jsonObject = new JSONObject();
        FeatureJSON featureJSON = new FeatureJSON();
        SimpleFeature simpleFeature = featureJSON.readFeature(feature.toString());
        Collection<Property> properties = simpleFeature.getProperties();
        for (Property property : properties) {
            jsonObject.put(property.getName().toString(), property.getValue());
        }
        if (simpleFeature != null && simpleFeature.getDefaultGeometry() != null) {
            //org.locationtech.jts.geom.GeometryCollection和com.vividsolutions.jts.geom.GeometryCollection格式不一样,
            //统一转成com.vividsolutions.jts.geom.GeometryCollection格式
            String geometryStr = simpleFeature.getDefaultGeometry().toString();
            if (geometryStr.contains("MULTI") || geometryStr.contains("multi") || geometryStr.contains("Multi")) {
                geometryStr = geometryStr.replace(") ,(", "),(").replace(") , (", "),(")
                        .replace("), (", "),(").replace("),(", ")), ((");
            }
            jsonObject.put("geometry", geometryStr);
        }
        return jsonObject;
    }

	//geomJson文件转wkt
    public JSONArray geomJsonToWktByFile(MultipartFile file) throws IOException {
        JSONArray jsonArray = new JSONArray();
        InputStream ins = null;
        try {
            ins = file.getInputStream();
            BufferedReader buffer = new BufferedReader(new InputStreamReader(ins));
            StringBuffer bs = new StringBuffer();
            String l = null;
            while ((l = buffer.readLine()) != null) {
                bs.append(l);
            }
            String jsonStr = bs.toString();
            GeomBO geomBO = new GeomBO();
            geomBO.setGeomJson(jsonStr);
            jsonArray = geomJsonToWkt(geomBO);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (ins != null) {
                ins.close();
            }
        }
        return jsonArray;
    }
}

2.3操作工具类

/**
*坐标转换工具
*/
public class TransformUtils {
    private static Logger log = LoggerFactory.getLogger(TransformUtils.class);

    private static final double X_PI = 3.14159265358979324 * 3000.0 / 180.0;
    // π
    private static final double PI = Math.PI;
    // 长半轴
    private static final double MAJOR_AXIS = 6378245.0;
    // 扁率
    private static final double FLATNESS = 0.00669342162296594323;

    private static final double EARTH_RAD = 6378137.0; //地球半径
    /**
     * 百度坐标系(BD-09)转WGS坐标
     * @param point 百度坐标点
     * @return WGS84坐标数组
     */
    public static Point bd09toWgs84(Point point) {
        Point gcj = bd09toGcj02(point);
        Point wgs84 = gcj02toWgs84(gcj);
        return wgs84;
    }

    /**
     * WGS坐标转百度坐标系(BD-09)
     *
     * @param lng WGS84坐标系的经度
     * @param lat WGS84坐标系的纬度
     * @return 百度坐标数组
     */
    public static Point wgs84toBd09(Point point) {
        Point gcj = wgs84toGcj02(point);
        Point bd09 = gcj02toBd09(gcj);
        return bd09;
    }

    /**
     * 火星坐标系(GCJ-02)转百度坐标系(BD-09)
     * <p>
     * 谷歌、高德——>百度
     *
     * @param lng 火星坐标经度
     * @param lat 火星坐标纬度
     * @return 百度坐标数组
     */
    public static Point gcj02toBd09(Point point) {
        double lon = point.getLon();
        double lat = point.getLat();
        double z = Math.sqrt(lon * lon + lat * lat) + 0.00002 * Math.sin(lat * X_PI);
        double theta = Math.atan2(lat, lon) + 0.000003 * Math.cos(lon * X_PI);
        double bd_lon = z * Math.cos(theta) + 0.0065;
        double bd_lat = z * Math.sin(theta) + 0.006;
        return new Point(bd_lon, bd_lat);
    }

    /**
     * 百度坐标系(BD-09)转火星坐标系(GCJ-02)
     * <p>
     * 百度——>谷歌、高德
     *
     * @param bd_lon 百度坐标纬度
     * @param bd_lat 百度坐标经度
     * @return 火星坐标数组
     */
    public static Point bd09toGcj02(Point point) {
        double x = point.getLon() - 0.0065;
        double y = point.getLat() - 0.006;
        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
        double gg_lon = z * Math.cos(theta);
        double gg_lat = z * Math.sin(theta);
        return new Point(gg_lon,gg_lat);
    }

    /**
     * WGS84转GCJ02(火星坐标系)
     *
     * @param lng WGS84坐标系的经度
     * @param lat WGS84坐标系的纬度
     * @return 火星坐标数组
     */
    public static Point wgs84toGcj02(Point point) {
        if (out_of_china(point.getLon(), point.getLat())) {
            return point;
        }
        double dLat = transformLat(point.getLon()- 105.0, point.getLat() - 35.0);
        double dLon= transformLon(point.getLon() - 105.0, point.getLat() - 35.0);
        double radLat = point.getLat() / 180.0 * PI;
        double magic = Math.sin(radLat);
        magic = 1 - FLATNESS * magic * magic;
        double sqrtmagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((MAJOR_AXIS * (1 - FLATNESS)) / (magic * sqrtmagic) * PI);
        dLon = (dLon * 180.0) / (MAJOR_AXIS / sqrtmagic * Math.cos(radLat) * PI);
        double mgLat = point.getLat() + dLat;
        double mgLng = point.getLon() + dLon;
        return new Point(mgLng, mgLat);
    }

    /**
     * GCJ02(火星坐标系)转GPS84
     *
     * @param lng 火星坐标系的经度
     * @param lat 火星坐标系纬度
     * @return WGS84坐标数组
     */
    public static Point gcj02toWgs84(Point gcj) {
        if (out_of_china(gcj.getLon(), gcj.getLat())) {
            return gcj;
        }
        double dLat = transformLat(gcj.getLon() - 105.0,  gcj.getLat() - 35.0);
        double dLon = transformLon(gcj.getLon() - 105.0,  gcj.getLat() - 35.0);
        double radLat =  gcj.getLat() / 180.0 * PI;
        double magic = Math.sin(radLat);
        magic = 1 - FLATNESS * magic * magic;
        double sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((MAJOR_AXIS * (1 - FLATNESS)) / (magic * sqrtMagic) * PI);
        dLon = (dLon * 180.0) / (MAJOR_AXIS / sqrtMagic * Math.cos(radLat) * PI);
        double mgLat =  gcj.getLat() + dLat;
        double mgLon= gcj.getLon() + dLon;
        return new Point(gcj.getLon() * 2 - mgLon, gcj.getLat() * 2 - mgLat);
    }

    /**
     * 纬度转换
     *
     * @param lng
     * @param lat
     * @return
     */
    public static double transformLat(double lng, double lat) {
        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 经度转换
     *
     * @param lng
     * @param lat
     * @return
     */
    public static double transformLon(double lng, double lat) {
        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }

    /**
     * 判断是否在国内,不在国内不做偏移
     *
     * @param lng
     * @param lat
     * @return
     */
    public static boolean out_of_china(double lng, double lat) {
        if (lng < 72.004 || lng > 137.8347) {
            return true;
        } else if (lat < 0.8293 || lat > 55.8271) {
            return true;
        }
        return false;
    }

    /**
     * WGS坐标转墨卡托
     *
     * @return WGS84坐标数组
     */
    public static Point wgs84ToMercator(Point wgs) {
        Double lon = wgs.getLon()*PI/180*EARTH_RAD;
        Double param =wgs.getLat()*PI/180;
        Double lat = EARTH_RAD / 2 * Math.log((1.0 + Math.sin(param)) / (1.0 - Math.sin(param)));
        return new Point(lon,lat);
    }

    /**
     * WGS坐标转墨卡托
     * @return WGS84坐标数组
     */
    public static Point mercatorToWgs84(Point mercator) {
        Double lon = mercator.getLon()*180/EARTH_RAD;
        Double param =mercator.getLat()*180/EARTH_RAD;
        Double lat = 180 / Math.PI * (2 * Math.atan(Math.exp(param * Math.PI / 180)) - Math.PI / 2);
        return new Point(lon,lat);
    }
}
public class GisUtil {
	 public final static GeometryFactory geometryFactory = new GeometryFactory();

 	public static GeoPoint getCenterPointByGeometry(String wkt) throws ParseException {
        Geometry geom = new WKTReader(geometryFactory).read(wkt);
        return getGeomCenterPoint(geom);
    }
	public static GeoPoint getGeomCenterPoint(Geometry geom) {
        if (geom == null) {
            return null;
        }
        if (geom instanceof MultiPolygon) {
            //判断是否多边形
            //先默认第一个最大
            int index = 0;
            if (geom.getNumGeometries() > 1) {
                //找出最大的面积
                //记录第一个面积大小
                double area = geom.getGeometryN(0).getArea();
                System.out.println(area);
                for (int i = 1; i < geom.getNumGeometries(); i++) {
                    if (geom.getGeometryN(i).getArea() > area) {
                        area = geom.getGeometryN(i).getArea();
                        index = i;
                    }
                }
            }
            return new GeoPoint(geom.getGeometryN(index).getInteriorPoint().getY(),geom.getGeometryN(index).getInteriorPoint().getX());
        } else if (geom instanceof Polygon) {
            return new GeoPoint(geom.getInteriorPoint().getY(),geom.getInteriorPoint().getX());
        }
        return null;
    }
	public static Geometry getGeomByStr(String geomStr) {
        if (StringUtils.isBlank(geomStr)) {
            return null;
        }
        WKTReader reader = new WKTReader(geometryFactory);
        try {
            return reader.read(geomStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}
/**
 * @Author 
 * @Description 抽稀工具类
 * @Date 2023/6/2 14:34
 */
public class RarefyUtil {
    private static Logger logger = LoggerFactory.getLogger(RarefyUtil.class);
    private static final GeometryFactory geometryFactory = new GeometryFactory();
    private static final WKTReader wktReader = new WKTReader(geometryFactory);

    public static Geometry simplifyByGeom(String geom, double tolerance) throws ParseException {
        return simplifyByGeom(wktReader.read(geom), tolerance);
    }

    /**
     * 方法说明: 将空间对象,按照一定的距离进行抽稀
     *
     * @param geom      空间对象
     * @param tolerance 抽稀距离
     * @return com.vividsolutions.jts.geom.Geometry
     * @date 2023/6/2 14:50
     * @author 
     */
    public static Geometry simplifyByGeom(Geometry geom, double tolerance) throws ParseException {
        if (geom == null || geom.isEmpty()) {
            return geom;
        } else if (geom instanceof Point) {
            return geom;
        } else if (geom instanceof MultiLineString) {
            MultiLineString multiLine =(MultiLineString)geom;
            LineString[] lines = new LineString[multiLine.getNumGeometries()];
            for (int i = 0; i < multiLine.getNumGeometries(); i++) {
                LineString lineString = (LineString) multiLine.getGeometryN(i);
                lines[i] = (LineString) simplifyByGeom(lineString, tolerance);
            }
            return geom.getFactory().createMultiLineString(lines);
        } else if (geom instanceof LineString) {
            LineString line = (LineString) geom;
            Coordinate[] coords = line.getCoordinates();
            if (coords.length <= 2) {
                return line;
            }
            List<Coordinate> simplify = simplify(coords, tolerance);
            return geom.getFactory().createLineString(simplify.toArray(new Coordinate[simplify.size()]));
        } else if (geom instanceof Polygon) {
            Polygon poly = (Polygon) geom;
            Coordinate[] coordinates = poly.getCoordinates();
            //取出最后一个点
            Coordinate lastCoordinate = coordinates[coordinates.length - 1];
            List<Coordinate> coordinateList = new ArrayList<>();
            //闭合多边形,coordinateList的首尾点是同一个
            for (int i = 0; i < coordinates.length - 1; i++) {
                //取出多边形的所有散点,不包含最后一个点
                coordinateList.add(coordinates[i]);
            }
            List<Coordinate> simplify = simplify(coordinateList, tolerance);
            //抽稀之后,无法形成闭合多边形,返回原有多边形
            if(simplify.size()<3){
                //返回的是一条直线,重新抽稀,按照最大距离点抽稀,
                simplify = maxDistanceSimplify(coordinateList);
            }
            //抽稀完成,将最后一个点加回去,形成闭合多边形
            simplify.add(lastCoordinate);
            return geom.getFactory().createPolygon(simplify.toArray(new Coordinate[simplify.size()]));
        } else if (geom instanceof MultiPolygon) {
            MultiPolygon multiPoly = (MultiPolygon) geom;
            Polygon[] polys = new Polygon[multiPoly.getNumGeometries()];
            for (int i = 0; i < multiPoly.getNumGeometries(); i++) {
                Polygon poly = (Polygon) multiPoly.getGeometryN(i);
                polys[i] = (Polygon) simplifyByGeom(poly, tolerance);
            }
            return geom.getFactory().createMultiPolygon(polys);
        } else {
            throw new IllegalArgumentException("Unsupported geometry type: " + geom.getClass());
        }
    }

    private static List<Coordinate> maxDistanceSimplify(List<Coordinate> points) {
        List<Coordinate> result = new ArrayList<>();
        int n = points.size();
        if (n < 3) {
            return points; // 如果点的数量小于3,无法抽稀,直接返回原点集
        }
        // 找到距离起点和终点最远的点,默认为中间点
        Coordinate maxDistanceCoordinate=points.get(n/2+1);
        double maxDistance = 0;
        for (int i = 1; i < n - 1; i++) {
            double distance = perpendicularDistance(points.get(i), points.get(0), points.get(n - 1));
            if (distance > maxDistance) {
                maxDistanceCoordinate = points.get(i);
                maxDistance = distance;
            }
        }
        result.add(points.get(0));
        result.add(maxDistanceCoordinate);
        result.add(points.get(n - 1));
        return result;
    }

    /**
     * 方法说明: 计算曲线中的每个点到曲线首尾点所在直线的距离
     *
     * @param p
     * @param p1
     * @param p2
     * @return double
     * @date 2023/6/2 14:51
     * @author 
     */
    private static double perpendicularDistance2(Coordinate p, Coordinate p1, Coordinate p2) {
        double area = Math.abs(0.5 * ((p1.x - p.x) * (p2.y - p.y) - (p2.x - p.x) * (p1.y - p.y)));
        double base = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
        return area / base;
    }

    /**
     * 方法说明: 按坐标点抽稀
     *
     * @param points    坐标点
     * @param tolerance 距离
     * @return java.util.List<com.vividsolutions.jts.geom.Coordinate>
     * @date 2023/6/2 14:54
     * @author 
     */
    public static List<Coordinate> simplify(Coordinate[] points, double tolerance) {
        int n = points.length;
        boolean[] keep = new boolean[n];
        keep[0] = keep[n - 1] = true;
        simplify(points, keep, 0, n - 1, tolerance);
        List<Coordinate> result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (keep[i]) {
                result.add(points[i]);
            }
        }
        return result;
    }

    /**
     * 方法说明: 抽希算法
     *
     * @param points    坐标点
     * @param keep      是否保留
     * @param start     开始位置索引
     * @param end       结束位置索引
     * @param tolerance 距离
     * @return void
     * @date 2023/6/2 14:56
     * @author 
     */
    private static void simplify(Coordinate[] points, boolean[] keep, int start, int end, double tolerance) {
        if (end <= start + 1) {
            return;
        }
        double maxDistance = 0;
        int index = 0;
        Coordinate p1 = points[start];
        Coordinate p2 = points[end];
        for (int i = start + 1; i < end; i++) {
            Coordinate p = points[i];
            double distance = perpendicularDistance(p, p1, p2);
            if (distance > maxDistance) {
                maxDistance = distance;
                index = i;
            }
        }
        if (maxDistance > tolerance) {
            keep[index] = true;
            simplify(points, keep, start, index, tolerance);
            simplify(points, keep, index, end, tolerance);
        }
    }

    /**
     * 方法说明: 道格拉斯抽希算法
     *
     * @param points    坐标点
     * @param tolerance 距离
     * @return java.util.List<com.vividsolutions.jts.geom.Coordinate>
     * @date 2023/6/2 14:57
     * @author 
     */
    public static List<Coordinate> simplify(List<Coordinate> points, double tolerance) {
        List<Coordinate> result = new ArrayList<>();
        int n = points.size();
        if (n < 3) {
            return points; // 如果点的数量小于3,无法抽稀,直接返回原点集
        }
        // 找到距离起点和终点最远的点
        int index = 0;
        double maxDistance = 0;
        for (int i = 1; i < n - 1; i++) {
            double distance = perpendicularDistance(points.get(i), points.get(0), points.get(n - 1));
            if (distance > maxDistance) {
                index = i;
                maxDistance = distance;
            }
        }
        // 如果最远点与起点或终点重合,则直接返回原点集
        if (maxDistance <= tolerance) {
            //最大距离小于目标值,说明符合抽稀的规则,取首尾点(抽稀)
            result.add(points.get(0));
            result.add(points.get(n - 1));
        } else {
            // 分割成左右两部分,对每部分进行抽稀
            List<Coordinate> leftPoints = new ArrayList<>();
            for (int i = 0; i <= index; i++) {
                leftPoints.add(points.get(i));
            }
            List<Coordinate> rightPoints = new ArrayList<>();
            for (int i = index; i < n; i++) {
                rightPoints.add(points.get(i));
            }
            List<Coordinate> leftResult = simplify(leftPoints, tolerance);
            List<Coordinate> rightResult = simplify(rightPoints, tolerance);
            // 合并左右两部分的抽稀结果
            result.addAll(leftResult.subList(0, leftResult.size() - 1));
            result.addAll(rightResult);
        }
        return result;
    }


    /**
     * 方法说明: 计算点p到直线ab的垂直距离
     *
     * @param p
     * @param a
     * @param b
     * @return double
     * @date 2023/6/2 14:58
     * @author 
     */
    private static double perpendicularDistance(Coordinate p, Coordinate a, Coordinate b) {
        double x = p.x;
        double y = p.y;
        double x1 = a.x;
        double y1 = a.y;
        double x2 = b.x;
        double y2 = b.y;
        double dx = x2 - x1;
        double dy = y2 - y1;
        double d = dx * dx + dy * dy;
        double u = ((x - x1) * dx + (y - y1) * dy) / d;
        double px, py;
        if (u < 0) {
            px = x1;
            py = y1;
        } else if (u > 1) {
            px = x2;
            py = y2;
        } else {
            px = x1 + u * dx;
            py = y1 + u * dy;
        }
        return Math.sqrt((x - px) * (x - px) + (y - py) * (y - py));
    }
}
软件简介: MAPGIS6.5实用工具,集成若干MAPGIS6.5不具有的实用功能,简单易用。 普通版有以下特色功能: 1、精确制图功能(类似于AutoCAD)。画线、移动、复制图元时,都可以输入距离和角度,还可以捕捉端点(按SHIFT)、中点(按CTRL)、交点(按SPACE)、垂足(按ALT)等,F2为正交开关,CTRL+D为线段单选开关。 2、滚轮缩放功能。向前滚动图形放大,向后滚动图形缩小,按下滚轮图形平移。 3、格式刷功能。点、线、区都可以运用格式刷进行修改和编辑。 4、查询图元功能。自动查找文本、属性、子图、颜色等。 5、参数拾取功能。拾取点、线、区参数作为当前编辑参数。 6、等距排列功能。文本或图例都可以进行横向、纵向的等距离自动排列。 7、快速制表功能。利用画水平线、竖直线以及捕足功能,输入距离移动、复制、拉伸线条功能,可以快速绘制各种表格。 8、测量距离功能。测量直线段或多段折线的距离或长度,可以使用捕捉功能。 9、测量面积功能。测量面积不需要造区,按顺序点击拐点即可,也可选择一条闭合的线段,即可测量面积。可以直接测量线图元的方位角。 10、测量角度功能。选择直线段可以测量该线段的的方位角及象限角。 11、面积换算功能。直接将测量出来的图上面积转换为实际面积。 12、面积标注功能。点击某块区域,自动标注该区域的面积,可带引线标注。 13、坐标标注功能。在图上单击某个点,即可标出该点的图上坐标或实际坐标值,可带引线标注。 14、比例造线功能。确定比例尺后,输入以米为单位的数据时,可以自动转换为图上距离,不需要人工换算,同时可以输入距离和角度。 15、线段拉伸功能。能够将线段进行拉伸,所有选中的线节点将同时拉伸,同时可以输入距离和角度。 16、线段切除功能。互相相交的线段,选择其中一条,可以切除另外一条线段在该线段两侧的部分,也可以切除夹在两条线段中间的部分。 17、线段交会功能。选择两条不平行的线段,可以使其相交于某一点,已经相交的两条线段,可以切除交点任意一侧的部分。 18、线段炸开功能。将多段线在节点处分开,生成若干条线段。 19、线段旋转功能。输入一个角度值,并确定一个旋转基点,即可精确旋转一条线段。 20、改线长度功能。选项择一条线段,可以直接修改该线段的长度值。 21、属性编辑功能。采用电子表格的方式对图元属性进编辑,与excel、acsses能够直接互相复制、粘贴,并且能够实现图形联动、属性联动等操作。 22、属性提取功能。输入属性提取条件,能够将点、线、区中符合条件的图元提取到新的文件中。 23、属性标注功能。选择某个字段,可以将该字段的属性值标注在图元的相应位置上。 24、属性动态显示。选择某个点线区文件,可以将某个字段或所有字段的属性值,随着鼠标的移动,适时动态地显示出来。 25、ID关联功能。将点线区相应位置上的图元ID修改为同一属性值,排序后能够将点线区对应的属性值进行批量拷贝。 26、删除指定图元。可以根据图元ID能及图元属性有条件地对图元批量删除。 27、删除重叠图元。自动搜索互相重叠的图元,删除多余的重叠图元。 28、匹配图例参数。选择某个图例,可以将该图例的参数及属性值全部赋给相应的图元。 29、自动生成样槽。选择两条节点数相同的平行线段,能够自动生成黑白相间的样槽。 30、批量替换注释。输入若干条需要替换的注释,可以一次性进行替换,并自动保存替换数据,下次或打开另外一张图时仍可使用,不需要重新输入。 31、整图栽剪功能。不需要生成单独的栽剪框文件,只要选择工程文件中任一条封闭的线就会自动对工程中的所有可见文件进行栽剪,栽剪后的文件自动保存在新建的目录中,每次栽剪都会生成一个新的目录,栽剪后的文件名与原文件名一致。 32、CAD转MapGis。本功能可以将AutoCAD格式的图形文件转换成MapGis格式的图形文件,能将CAD中的充填图案直接转换成MapGis中的区图元,而且能将CAD中的内部块、多行文本直接转出,不需要在CAD中分解。完全按照CAD中的图层分层转出所有可见图元,颜色、线型自动转换,不需要对照表,所有操作全自动。并能够将CASS中生成的地物编码转为MapGis图元属性。 33、Excel转MapGis。本功能可以将 Microsoft Office Excel 电子表格文件中的各种表格直接转换成MapGis格式的点、线、面文件。 34、自动画柱状图。本功能可以将保存在 Microsoft Office Excel 电子表格文件中的钻孔数据绘制成钻孔柱
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值