【GIS系列】GeoTools简介及工具类分享

本文将对GeoTools相关概念进行介绍,同时会给大家分享我工作中用到的工具类及使用方法。

作者:后端小肥肠

目录

1.前言

2. GeoTools简介

3. Geotools使用示例

3.1. 开发环境搭建

3.1.1. 所需版本和工具

3.1.2. pom依赖

3.1.3. 示例代码

4. 工具类介绍

4.1. 读取shp工具类

4.1.1 准备数据

4.1.2. 部分方法

4.1.3. 完整工具类代码

4.2. 坐标转换工具类

4.2.1. 准备数据

4.2.2. 完整工具类代码

5. 结语

6. 参考链接 


1.前言

GeoTools是一个功能强大的开源GIS工具库,为地理空间数据处理和分析提供了丰富的功能和便利的接口。无论您是GIS专业人士还是对地理空间数据感兴趣的开发人员,掌握GeoTools都是必不可少的。本文将从基本概念入手,介绍GeoTools的功能和使用方法,并重点分享一些实用的工具类和技巧,希望能为您在GIS应用开发中提供帮助和启发。

2. GeoTools简介

GeoTools是一个开源的Java库,用于处理和分析地理空间数据。它提供了一系列用于读取、写入、处理和可视化地理空间数据的工具和API。以下是与GeoTools相关的一些重要概念:

  1. 地理空间数据(Geospatial Data): GeoTools主要用于处理地理空间数据,这包括地图、地形、卫星影像、矢量数据等地理信息。这些数据通常具有地理坐标信息和地理属性信息。

  2. 地理坐标系统(Geographic Coordinate System,GCS): 地理坐标系统是用于在地球上定位点的一种方法。GeoTools支持多种地理坐标系统,包括经纬度坐标系统等。

  3. 投影坐标系统(Projected Coordinate System,PCS): 投影坐标系统是将地球表面的地理坐标投影到平面上的一种方法。GeoTools提供了许多常用的投影方法和投影坐标系统的支持。

  4. 数据格式(Data Formats): GeoTools支持多种地理空间数据格式,如Shapefile、GeoJSON、KML、GML等,可以方便地读取和写入这些数据格式。

  5. 空间分析(Spatial Analysis): GeoTools提供了丰富的空间分析功能,包括缓冲区分析、空间查询、空间叠加分析等,可以帮助用户进行地理空间数据的处理和分析。

总的来说,GeoTools是一个功能丰富的GIS工具库,提供了丰富的功能和工具,可以帮助用户处理和分析各种地理空间数据,并构建地理空间应用。

3. Geotools使用示例

3.1. 开发环境搭建

3.1.1. 所需版本和工具
依赖版本
Spring Boot2.6.14
GeoTools4.4.18
java1.8以上
ArcGis10.8

我这里用的不是GeoTools的最新版本,需要最新版本的同学可登录GeoTools的官网(GeoTools The Open Source Java GIS Toolkit — GeoTools)查看最新版本和其使用规则。

如上图所示,最新版本的GeoTools跟java11适配。

3.1.2. pom依赖
         <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-geojson</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-swing</artifactId>
            <version>${geotools.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
3.1.3. 示例代码

4. 工具类介绍

4.1. 读取shp工具类

4.1.1 准备数据

打开ArcGis绘制面数据,我这里绘制了4490坐标系的几个面要素。

4.1.2. 部分方法

1. 读取shp中的空间要素信息(wkt)

public static List<String> getWktFromShp(String shpPath) {
        List<String> shpList = new ArrayList<>();
        SimpleFeatureCollection simpleFeatureCollection = null;
        try {
            //获取文件
            File file = new File(shpPath);
            // 读取到数据存储中
            FileDataStore dataStore = FileDataStoreFinder.getDataStore(file);
            // 获取特征资源
            SimpleFeatureSource simpleFeatureSource = dataStore.getFeatureSource();
            // 要素集合
            simpleFeatureCollection = simpleFeatureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取要素迭代器
        SimpleFeatureIterator featureIterator = simpleFeatureCollection.features();
        while (featureIterator.hasNext()) {
            // 要素对象
            SimpleFeature feature = featureIterator.next();
            Object geometryText = feature.getDefaultGeometry();
            log.info(geometryText.toString());
            shpList.add(geometryText.toString());

        }
        featureIterator.close();
        return shpList;
    }

2. 运行结果

3. 读取shp文件并将其转换为Geojson

    /**
     * 构造Geojson结构体
     * @param featuresJson
     * @return
     */
    public static JSONObject buildGeoJson(JSONArray featuresJson) {
        JSONObject Geojson = new JSONObject();
        Geojson.put("type", "FeatureCollection");
        Geojson.put("features", featuresJson);
        return Geojson;
    }
 /**
     * 构造Geojson的features部分 单个
     *
     * @param geoObject
     * @param properties
     * @return
     */
    public static JSONObject buildFeature(Map geoObject, Map properties) {
        JSONObject featureObject = new JSONObject();
        Map featureMap = new HashMap();
        featureMap.put("type", "Feature");
        featureMap.putAll(geoObject);
        featureMap.put("properties", properties);
        featureObject.putAll(featureMap);
        return featureObject;
    }
 /**
     * 获取空间信息并构造为Map
     * @param wkt
     * @return
     */
    public static Map getGeoMap(String wkt) {
        Map<String, Object> geoMap = new HashMap<>();
        String json = null;
        try {
            WKTReader reader = new WKTReader();
            Geometry geometry = reader.read(wkt);
            StringWriter writer = new StringWriter();
            GeometryJSON g = new GeometryJSON();
            g.write(geometry, writer);
            geoMap.put("geometry", writer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return geoMap;
    }

 /**
     * 基于shp构造geojson并返回
     *
     * @param shpPath
     * @return
     */
    public static JSONObject buildGeojsonFromShp(String shpPath) {
        JSONArray featureArray = new JSONArray();
//        List<String>shpList=new ArrayList<>();
        SimpleFeatureCollection simpleFeatureCollection = null;
        try {
//            要素合集
            //获取文件
            File file = new File(shpPath);
            // 读取到数据存储中
            ShapefileDataStore dataStore = (ShapefileDataStore) FileDataStoreFinder.getDataStore(file);
            dataStore.setCharset(Charset.forName("GBK"));
            // 获取特征资源
            SimpleFeatureSource simpleFeatureSource = dataStore.getFeatureSource();
            // 要素集合
            simpleFeatureCollection = simpleFeatureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        SimpleFeatureIterator featureIterator = simpleFeatureCollection.features();
//            // 要素数量
        int featureSize = simpleFeatureCollection.size();
//            log.info("要素数量"+featureSize);
        //创建properties  Map
        while (featureIterator.hasNext()) {
            // 要素对象
            SimpleFeature feature = featureIterator.next();
            Collection<Property> propertyCollection = (Collection<Property>) feature.getValue();
            //填充属性map
            Map<String, Object> properMap = new HashMap<>();
            for (Property property : propertyCollection) {
                if (property.getName().toString().equals("the_geom")) {
                    continue;
                }
                properMap.put(property.getName().toString(), property.getValue());
            }
            //获取geo信息
            Object geometryText = feature.getDefaultGeometry();
            Map geoMap = getGeoMap(geometryText.toString());
            JSONObject featureObject = buildFeature(geoMap, properMap);
            featureArray.add(featureObject);
        }
        featureIterator.close();
        JSONObject GeoJson = buildGeoJson(featureArray);

        return GeoJson;
    }

4. 运行结果

4.1.3. 完整工具类代码
import lombok.extern.slf4j.Slf4j;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.geojson.geom.GeometryJSON;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @version 1.0
 * @description: gis工具类
 * @author: chenss
 * @date 2024-03-14 16:19
 */
@Slf4j
public class GisUtil {
    public static void main(String[] args) {
        JSONObject Geojson=buildGeojsonFromShp("D:\\arcgisdata\\mesh4490.shp");
        log.info(Geojson.toJSONString());
//        List<String> wkts = getWktFromShp("D:\\arcgisdata\\mesh4490.shp");
//        for (String wkt : wkts) {
//            log.info(wkt);
//        }
    }

    /**
     * 构造Geojson结构体
     * @param featuresJson
     * @return
     */
    public static JSONObject buildGeoJson(JSONArray featuresJson) {
        JSONObject Geojson = new JSONObject();
        Geojson.put("type", "FeatureCollection");
        Geojson.put("features", featuresJson);
        return Geojson;
    }

    /**
     * 构造Geojson的features部分 单个
     *
     * @param geoObject
     * @param properties
     * @return
     */
    public static JSONObject buildFeature(Map geoObject, Map properties) {
        JSONObject featureObject = new JSONObject();
        Map featureMap = new HashMap();
        featureMap.put("type", "Feature");
        featureMap.putAll(geoObject);
        featureMap.put("properties", properties);
        featureObject.putAll(featureMap);
        return featureObject;
    }

    /**
     * 获取空间信息并构造为Map
     * @param wkt
     * @return
     */
    public static Map getGeoMap(String wkt) {
        Map<String, Object> geoMap = new HashMap<>();
        String json = null;
        try {
            WKTReader reader = new WKTReader();
            Geometry geometry = reader.read(wkt);
            StringWriter writer = new StringWriter();
            GeometryJSON g = new GeometryJSON();
            g.write(geometry, writer);
            geoMap.put("geometry", writer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return geoMap;
    }

    /**
     * 只读取geo信息 wkt
     *
     * @param shpPath
     * @return
     */
    public static List<String> getWktFromShp(String shpPath) {
        List<String> shpList = new ArrayList<>();
        SimpleFeatureCollection simpleFeatureCollection = null;
        try {
            //获取文件
            File file = new File(shpPath);
            // 读取到数据存储中
            FileDataStore dataStore = FileDataStoreFinder.getDataStore(file);
            // 获取特征资源
            SimpleFeatureSource simpleFeatureSource = dataStore.getFeatureSource();
            // 要素集合
            simpleFeatureCollection = simpleFeatureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取要素迭代器
        SimpleFeatureIterator featureIterator = simpleFeatureCollection.features();
        while (featureIterator.hasNext()) {
            // 要素对象
            SimpleFeature feature = featureIterator.next();
            Object geometryText = feature.getDefaultGeometry();
            log.info(geometryText.toString());
            shpList.add(geometryText.toString());

        }
        featureIterator.close();
        return shpList;
    }

    /**
     * 基于shp构造geojson并返回
     *
     * @param shpPath
     * @return
     */
    public static JSONObject buildGeojsonFromShp(String shpPath) {
        JSONArray featureArray = new JSONArray();
//        List<String>shpList=new ArrayList<>();
        SimpleFeatureCollection simpleFeatureCollection = null;
        try {
//            要素合集
            //获取文件
            File file = new File(shpPath);
            // 读取到数据存储中
            ShapefileDataStore dataStore = (ShapefileDataStore) FileDataStoreFinder.getDataStore(file);
            dataStore.setCharset(Charset.forName("GBK"));
            // 获取特征资源
            SimpleFeatureSource simpleFeatureSource = dataStore.getFeatureSource();
            // 要素集合
            simpleFeatureCollection = simpleFeatureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        SimpleFeatureIterator featureIterator = simpleFeatureCollection.features();
//            // 要素数量
        int featureSize = simpleFeatureCollection.size();
//            log.info("要素数量"+featureSize);
        //创建properties  Map
        while (featureIterator.hasNext()) {
            // 要素对象
            SimpleFeature feature = featureIterator.next();
            Collection<Property> propertyCollection = (Collection<Property>) feature.getValue();
            //填充属性map
            Map<String, Object> properMap = new HashMap<>();
            for (Property property : propertyCollection) {
                if (property.getName().toString().equals("the_geom")) {
                    continue;
                }
                properMap.put(property.getName().toString(), property.getValue());
            }
            //获取geo信息
            Object geometryText = feature.getDefaultGeometry();
            Map geoMap = getGeoMap(geometryText.toString());
            JSONObject featureObject = buildFeature(geoMap, properMap);
            featureArray.add(featureObject);
        }
        featureIterator.close();
        JSONObject GeoJson = buildGeoJson(featureArray);

        return GeoJson;
    }

    /**
     * 根据给定的wkt面求出中心点,并以wkt形式返回
     */
    public static String calculateCenter(String wktPolygon) throws ParseException {
        // 创建 WKT 解析器和写入器
        WKTReader reader = new WKTReader(new GeometryFactory());
        WKTWriter writer = new WKTWriter();

        // 解析面的几何对象
        Geometry geometry = reader.read(wktPolygon);

        // 计算面的中心点
        Point center = geometry.getCentroid();

        // 将中心点转换为 WKT 格式
        String wktCenter = writer.write(center);

        return wktCenter;
    }


}

4.2. 坐标转换工具类

我这个坐标转换工具只应用于同椭球(本文示例为2000坐标系-EPSG:4490)坐标投影转换。已云南的投影带为33-35,对应的EPSG为4521、4522、4523。

4.2.1. 准备数据

1. 准备4490、4521、4522、4523的shp

2. 获取.prj中坐标描述信息

3. 将坐标描述信息存放到常量Map中

static final  Map<String,String> projMap=new HashMap();
static {
    projMap.put("4522","PROJCS["CGCS2000_3_Degree_GK_Zone_34",GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",DATUM["D_China_2000",SPHEROID["CGCS2000",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Gauss_Kruger"],PARAMETER["False_Easting",34500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",102.0],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]");
    projMap.put("4490","GEOGCS["China Geodetic Coordinate System 2000",\n" +
            "    DATUM["China_2000",\n" +
            "        SPHEROID["CGCS2000",6378137,298.257222101,\n" +
            "            AUTHORITY["EPSG","1024"]],\n" +
            "        AUTHORITY["EPSG","1043"]],\n" +
            "    PRIMEM["Greenwich",0,\n" +
            "        AUTHORITY["EPSG","8901"]],\n" +
            "    UNIT["degree",0.0174532925199433,\n" +
            "        AUTHORITY["EPSG","9122"]],\n" +
            "    AUTHORITY["EPSG","4490"]]");
    projMap.put("4521","PROJCS["CGCS2000_3_Degree_GK_Zone_33",GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",DATUM["D_China_2000",SPHEROID["CGCS2000",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Gauss_Kruger"],PARAMETER["False_Easting",33500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",99.0],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]");
    projMap.put("4523","PROJCS["CGCS2000_3_Degree_GK_Zone_35",GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",DATUM["D_China_2000",SPHEROID["CGCS2000",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Gauss_Kruger"],PARAMETER["False_Easting",35500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",105.0],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]");
}
4.2.2. 完整工具类代码
import lombok.extern.slf4j.Slf4j;
import org.geotools.data.FeatureWriter;
import org.geotools.data.FileDataStoreFactorySpi;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import java.io.File;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Slf4j
public class ProjTransUtil {
    static final  Map<String,String> projMap=new HashMap();
    static {
        projMap.put("4522","PROJCS[\"CGCS2000_3_Degree_GK_Zone_34\",GEOGCS[\"GCS_China_Geodetic_Coordinate_System_2000\",DATUM[\"D_China_2000\",SPHEROID[\"CGCS2000\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gauss_Kruger\"],PARAMETER[\"False_Easting\",34500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",102.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]");
        projMap.put("4490","GEOGCS[\"China Geodetic Coordinate System 2000\",\n" +
                "    DATUM[\"China_2000\",\n" +
                "        SPHEROID[\"CGCS2000\",6378137,298.257222101,\n" +
                "            AUTHORITY[\"EPSG\",\"1024\"]],\n" +
                "        AUTHORITY[\"EPSG\",\"1043\"]],\n" +
                "    PRIMEM[\"Greenwich\",0,\n" +
                "        AUTHORITY[\"EPSG\",\"8901\"]],\n" +
                "    UNIT[\"degree\",0.0174532925199433,\n" +
                "        AUTHORITY[\"EPSG\",\"9122\"]],\n" +
                "    AUTHORITY[\"EPSG\",\"4490\"]]");
        projMap.put("4521","PROJCS[\"CGCS2000_3_Degree_GK_Zone_33\",GEOGCS[\"GCS_China_Geodetic_Coordinate_System_2000\",DATUM[\"D_China_2000\",SPHEROID[\"CGCS2000\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gauss_Kruger\"],PARAMETER[\"False_Easting\",33500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",99.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]");
        projMap.put("4523","PROJCS[\"CGCS2000_3_Degree_GK_Zone_35\",GEOGCS[\"GCS_China_Geodetic_Coordinate_System_2000\",DATUM[\"D_China_2000\",SPHEROID[\"CGCS2000\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Gauss_Kruger\"],PARAMETER[\"False_Easting\",35500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",105.0],PARAMETER[\"Scale_Factor\",1.0],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]");
    }

    /**
     * 根据传入wkt获取数据坐标系
     * @param wkt
     * @return
     */
    public static String getProj(String wkt){
        String resEpsg="";
        int lonLatStart=-1;
        //根据wkt字符串判断平面坐标位于哪一度带
        try {
            for (int i = 0; i < wkt.length(); i++) {
                if(Integer.valueOf(wkt.charAt(i))>=48&&Integer.valueOf(wkt.charAt(i))<58){
                    lonLatStart=i;
                    break;
                }
            }
            int lonLatEnd=wkt.indexOf(",");
            String projLonLat=wkt.substring(lonLatStart,lonLatEnd);
            String[]lonlat=projLonLat.split(" ");
            String projLon=lonlat[0];
            if(projLon.substring(0,2).equals("33")){
                resEpsg="4521";
            }else if(projLon.substring(0,2).equals("34")){
                resEpsg="4522";
            }else if(projLon.substring(0,2).equals("35")){
                resEpsg="4523";
            }
            else
                return "4490";
        } catch (Exception e) {
            log.info(wkt+"出错");
            log.error(e.getMessage(),e);
        }
        return resEpsg;

    }

    /**
     * 坐标转换
     * @param geom
     * @param sourceEpsg
     * @return
     */
    public static Geometry lonlat2WebMactor(Geometry geom,String sourceEpsg){
        try{
            //这里是以OGC WKT形式定义的是World Mercator投影,网页地图一般使用该投影
            CoordinateReferenceSystem crsSource=CRS.parseWKT(projMap.get(sourceEpsg));
            CoordinateReferenceSystem crsTarget = CRS.parseWKT(projMap.get("4490"));
            // 投影转换
//            MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, crsTarget);
            MathTransform transform = CRS.findMathTransform(crsSource, crsTarget);
            return JTS.transform(geom, transform);
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            log.error(e.getMessage(),e);
            return null;
        }
    }

    /**
     *给定inputshp转换为targetEpsg坐标系,并输出到outputShp位置
     * @param inputShp
     * @param outputShp
     * @param targetEpsg
     * @return
     */
    public static Map projectShape(String inputShp, String outputShp,String targetEpsg){
        Map map = new HashMap();
        try {
            //源shape文件
            ShapefileDataStore shapeDS = (ShapefileDataStore) new ShapefileDataStoreFactory().createDataStore(new File(inputShp).toURI().toURL());
            //创建目标shape文件对象
            Map<String, Serializable> params = new HashMap<String, Serializable>();
            FileDataStoreFactorySpi factory = new ShapefileDataStoreFactory();
            File file=FileUtil.createFileByPath(outputShp);
//            if(!file.exists()){
                params.put(ShapefileDataStoreFactory.URLP.key,file.toURI().toURL());
                ShapefileDataStore ds = (ShapefileDataStore) factory.createNewDataStore(params);
//            Charset charset = Charset.forName("UTF-8");
//            ds.setCharset(charset);
                // 设置属性
                SimpleFeatureSource fs = shapeDS.getFeatureSource(shapeDS.getTypeNames()[0]);
                //下面这行还有其他写法,根据源shape文件的simpleFeatureType可以不用retype,而直接用fs.getSchema设置
//            CoordinateReferenceSystem crs = CRS.parseWKT(strWKTMercator);
                CoordinateReferenceSystem crs = CRS.parseWKT(projMap.get("4490"));
                ds.createSchema(SimpleFeatureTypeBuilder.retype(fs.getSchema(), crs));

                //设置writer
                FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);

                //写记录
                SimpleFeatureIterator it = fs.getFeatures().features();
                try {
                    while (it.hasNext()) {
                        SimpleFeature f = it.next();
                        SimpleFeature fNew = writer.next();
                        fNew.setAttributes(f.getAttributes());
                        Geometry geom = lonlat2WebMactor((Geometry)f.getAttribute("the_geom"),targetEpsg);
                        fNew.setAttribute("the_geom", geom);
                    }
                }
                finally {
                    it.close();
                }
                writer.write();
                writer.close();
                ds.dispose();
                shapeDS.dispose();
//            }
            map.put("status", "success");
            map.put("message", outputShp);
        }
        catch (Exception e) {
            log.error(e.getMessage(),e);
            map.put("status", "failure");
            map.put("message", e.getMessage());
        }
        return map;
    }

//    public static void main(String[] args) {
//        String input="D:\\jsonshp\\test.shp";
//        String output="D:\\jsonshp\\test4490.shp";
//        projectShape(input,output);
//    }

}

5. 结语

本文对GeoTools的基本概念进行了简介,之后介绍了Geotools的工具类及其具体用法。下一篇文章将讲解Postgis+Geotools+MybatisPlus实现数据的读取,写入及前端展示。对Gis开发领域感兴趣的同学可动动你们发财的小手点点关注~

6. 参考链接 

常见2000坐标系对应的EPSG代号 - 知乎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464289.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[VCTF2024纳新赛]-PWN:ezhp_code解析

查看保护 查看ida 简单来说就是创建堆块和删除堆块而已&#xff0c;创建堆块的函数附带有写入函数。 但这里要注意一个程序里面的特殊的地方 在我们创建堆块时&#xff0c;程序会先创建一个0xa0大小堆块&#xff0c;并且这个地方还有个特殊的check_handle函数&#xff0c;如果…

SpringBoot(整合MyBatis + MyBatis-Plus + MyBatisX插件使用)

文章目录 1.整合MyBatis1.需求分析2.数据库表设计3.数据库环境配置1.新建maven项目2.pom.xml 引入依赖3.application.yml 配置数据源4.Application.java 编写启动类5.测试6.配置类切换druid数据源7.测试数据源是否成功切换 4.Mybatis基础配置1.编写映射表的bean2.MonsterMapper…

✅技术社区—通过Canal框架实现MySQL与ElasticSearch的数据同步

Canal 是一个由阿里巴巴开源的&#xff0c;基于 Java 的数据库变更日志解析的中间件&#xff0c;其原理是基于Binlog订阅的方式实现&#xff0c;模拟一个MySQL Slave 订阅Binlog日志&#xff0c;从而实现CDC&#xff0c;主要用于实现 MySQL 数据库的增量数据同步。它主要的使用…

理解计算属性等

计算属性 计算属性的作用是将写在computed内的写了对应的属性名&#xff0c;属性值都是函数&#xff0c;将这属性值的函数调用之后的返回值赋给属性名的变量。因此其实计算属性内的是值&#xff0c;不是方法&#xff0c;因此写插值等语句是只是写变量&#xff0c;而不是调用。且…

第三篇 - 概述- IAB受众和技术标准 - IAB视频广告标准《数字视频和有线电视广告格式指南》

第三篇 - 概述- IAB受众和技术标准​​​​​​​ - 我为什么要翻译介绍美国人工智能科技公司IAB技术标准系列&#xff08;2&#xff09; 本文目录 一、IAB技术实验室简介 二、概述及IAB受众 三、资源- IAB倡导的相关视频广告技术标准 四、案例分享-介绍一家数字化营销服务…

STM32F407_多点电容触摸(GT911)驱动

目录标题 前言1、简单介绍2、触摸芯片与主机的硬件连接3、内部寄存器3.1、控制寄存器&#xff08;0X8040&#xff09;3.2、配置寄存器组&#xff08;0X8047~0X8100&#xff09;3.3、状态寄存器(0x814E)3.4、坐标寄存器(0x8150-0x8177) 4、初始化流程4.1、IIC地址选择4.2、更新G…

OpenHarmony—应用UX设计原则

设计原则 当为多种不同的设备开发应用时&#xff0c;有如下设计原则&#xff1a; 差异性 充分了解所要支持的设备&#xff0c;包括屏幕尺寸、交互方式、使用场景、用户人群等&#xff0c;对设备的特性进行针对性的设计。 一致性 除了要考虑每个设备的特性外&#xff0c;还…

修复 error Delete `␍` prettier/prettier 错误

修复 error Delete ␍ prettier/prettier 错误 问题背景报错信息报错原因解决办法修改CRLF----针对单个文件yarn run lint --fix 一键修复&#xff08;官方提供&#xff09; 问题背景 今天在使用 openapi 自动生成前端接口代码的时候&#xff0c;爆了一个类似 eslint 规范的错…

AtCoder Beginner Contest 345 A - E 题解

A - Leftrightarrow 思路 判断第一个字符是否为&#xff0c;最后一个字符是否为&#xff0c;都满足的话&#xff0c;再判断中间字符是否都为 代码 #include<iostream> using namespace std; #define int long longbool check(string s){int ns.size();if(s[0]!<) …

Elasticsearch 索引库操作 文档操作

索引库就类似数据库表&#xff0c;mapping映射就类似表的结构。要向es中存储数据&#xff0c;必须先创建“库”和“表”。 mapping映射属性 mapping是对索引库中文档的约束&#xff0c;常见的mapping属性包括&#xff1a; type&#xff1a; 字段数据类型&#xff0c;常见的简…

Gogs 创建新的仓库并提交代码

Gogs 创建新的仓库并提交代码 1. 登录2. 仓库 -> 我的仓库3. 创建新的仓库4. 仓库5. Copy6. 公开代码​7. 提交成功 Gogs - gitReferences Gogs 是一款极易搭建的自助 Git 服务。 1. 登录 2. 仓库 -> 我的仓库 3. 创建新的仓库 4. 仓库 5. Copy 6. 公开代码 strongfo…

SpringBoot(RESTful,统一响应结构,输出日志,增删改查功能,分页功能,批量删除,常见bug)【详解】

目录 一、准备工作 1. 前后端分离开发流程 2. 开发规范 1.RESTful请求风格 2.统一响应结果 3.代码中输出日志 二、部门管理&#xff08;增删改查功能&#xff09; 1. 查询部门列表 2. 删除部门 3. 新增部门 4. 修改部门 三、员工管理&#xff08;分页功能和批量删除…

数字后端 EDA 软件分享

数字后端 EDA 软件分享 推荐这几家的EDA工具吧&#xff0c;虽说我也支持国产工具&#xff0c;但是我还是选择了这几家的工具 apache cadence mentor synopsys 下图我现在用的eda环境&#xff0c;利用网上的资源&#xff0c;自己独立在vmware上搭建好的EDA环境 除去pdk&#…

MySQL语法分类 DQL(6)分页查询

为了更好的学习这里给出基本表数据用于查询操作 create table student (id int, name varchar(20), age int, sex varchar(5),address varchar(100),math int,english int );insert into student (id,name,age,sex,address,math,english) values (1,马云,55,男,杭州,66,78),…

Matlab/simulink基于模糊PID智能控制的温度控制系统建模仿真

参考文献 Matlab/simulink基于模糊PID智能控制的温度控制系统建模仿真 该系统主要对某小区换热站的温度控制策略和控制方案进行了设计&#xff0c;其设计内 容主要包括三部分。首先是基于模糊PID智能控制的温度控制系统设计。在温度控制 算法方面&#xff0c;该设计于传统的P…

MySQL实战:监控

监控指标 性能类指标 名称说明QPS数据库每秒处理的请求数量TPS数据库每秒处理的事务数量并发数数据库实例当前并行处理的会话数量连接数连接到数据库会话的数量缓存命中率Innodb的缓存命中率 功能类指标 名称说明可用性数据库是否正常对外提供服务阻塞当前是否有阻塞的会话…

操作系统:malloc与堆区内存管理

malloc是函数而不是系统调用&#xff0c;他的底层是同调调用brk和mmap这两个系统调用实现功能的&#xff0c;具体选择brk还是mmap要看申请的空间大小以及malloc中的阈值&#xff08;一般是128kb&#xff09; 注意申请的空间只有使用才会触发缺页中断映射到物理内存 不理解的话先…

搞机笔记 MI8 dipper

刷回MIUI 之前刷了 lineage-19.1-20220728-nightly-dipper-signed 基于安卓12&#xff0c;实现了以下功能 TWRPmagisk & ROOTmicroG 退回MIUI的原因有&#xff1a; lineage 墓碑 管不住APP后台&#xff0c;太卡了MIUI提供了3GB的虚拟内存lineage 不支持人脸识别lineag…

小蓝的漆房——算法思路

题目链接&#xff1a;1.小蓝的漆房 - 蓝桥云课 (lanqiao.cn) 本题只要是通过枚举的方法&#xff0c;算出涂成每一种颜色所需的天数&#xff0c;最后在所有天数中找出最小值&#xff08;由题可知&#xff0c;最多只有60种颜色&#xff0c;所以可以尝试算出每种颜色所需的时间&am…

在雄安新区买新房要注意什么?有哪些注意事项?

雄安新区新建住宅均价每平方米11735元起&#xff0c;二手房每平方米8950元起。 整体价格非常有优势。 雄安新区房价走势与区域发展直接相关。 而且&#xff0c;雄安新区已经成立五周年了。 2022年&#xff0c;雄安新区多项重点项目将陆续竣工。 雄安新区城市基础设施建设已初具…