概述:GeoTools 是一个开源 (LGPL) Java 代码库,它为操作地理空间数据提供符合标准的方法,例如实现地理信息系统。GeoTools 库数据结构基于开放地理空间联盟 (OGC) 规范。 官网地址: www.geotools.org/ 常用maven库地址: repo.osgeo.org/repository/… maven.geo-solutions.it/

  • arcgrid
  • geotiff
  • grassraster
  • image ( JPEG TIFF GIF PNG)
  • imageio-ext-gdal
  • imagemosaic
  • imagepyramid
  • matlab
  • 矢量数据格式

  • geojson
  • shapefile
  • 数据库支持

  • mysql
  • oracle
  • postgis
  • sqlserver
  • elastic search
  • Geotools使用

  • 读取shp格式
  • public static void readShpFile(String shpPath) {
           File shpFile = new File(shpPath);
           try {
               ShapefileDataStore shapefileDataStore = new ShapefileDataStore(shpFile.toURI().toURL());
               // 设置编码,防止属性的中文字符出现乱码
               shapefileDataStore.setCharset(Charset.forName("UTF-8"));
               // 这个typeNamae不传递,默认是文件名称
               FeatureSource featuresource = shapefileDataStore.getFeatureSource(shapefileDataStore.getTypeNames()[0]);
               // 读取bbox
               ReferencedEnvelope bbox  =featuresource.getBounds();
               // 读取投影
               CoordinateReferenceSystem crs = featuresource.getSchema().getCoordinateReferenceSystem();
               // 特征总数
               int count = featuresource.getCount(Query.ALL);
               // 获取当前数据的geometry类型(点、线、面)
               GeometryType geometryType = featuresource.getSchema().getGeometryDescriptor().getType();
               // 读取要素
               SimpleFeatureCollection simpleFeatureCollection = (SimpleFeatureCollection) featuresource.getFeatures();
               // 获取当前矢量数据有哪些属性字段值
               List<AttributeDescriptor> attributes = simpleFeatureCollection.getSchema().getAttributeDescriptors();
               // 拿到迭代器
               SimpleFeatureIterator simpleFeatureIterator = simpleFeatureCollection.features();
               // 遍历每一个要素
               while(simpleFeatureIterator.hasNext()) {
                   SimpleFeature simpleFeature = simpleFeatureIterator.next();
                   // java8新特性流api
                   attributes.stream().forEach((a) -> {
                       // 依次读取这个shape中每一个属性值,当然这个属性值,可以处理其它业务
                       System.out.println(a.getLocalName() + ":" + simpleFeature.getAttribute(a.getLocalName()));
           } catch (IOException e) {
               e.printStackTrace();
           System.out.println("读取完成!");
    
  • 读取wkb格式
  • ex : 0000010300000001000000A4000000B98D06F0163C5E408D28ED0DBE684440B98D06F0163C5E408D28ED0DBE684440B98D06F0163C5E408D28ED0DBE684440B98D06F0163C5E408D28ED0DBE684440075F984C153C5E4029C

    WKBReader wkbReader = new WKBReader();
    Geometry geometry = wkbReader.read(WKBReader.hexToBytes(tokens[i]));
    
  • 读取wkt
  • MultiPolygon ( ((10 10, 10 20, 20 20, 20 15, 10 10)), ((60 60, 70 70, 80 60, 60 60 )) )

    WKTReader wktReader = new WKTReader();
    Geometry geometry = wktReader.read(wktStr);
    
  • 读取geojson
  • {"type":"Feature","crs":{"type":"name","properties":{"name":"EPSG:2380"}},"geometry":{"type":"MultiPolygon","coordinates":[[[[646398.9535,3267941.9664],[649558.7196,3267895.3528],[649674.763,3265683.4124],[646387.8773,3265827.4858],[646398.9535,3267941.9664]]]]},"properties":{"Id":0}}

    public static void readGeoJson(String jsonPath) throws IOException {
           File file = new File(jsonPath);
           FileInputStream fileInputStream = new FileInputStream(file);
           // 这里可能存在问题,如果是超大文件怎么办,一次性读入会不会报内存
           // 解决方案是不是对大文件进行拆分
           GeoJSONReader geoJSONReader = new GeoJSONReader(fileInputStream);
           SimpleFeatureCollection featureCollection = geoJSONReader.getFeatures();
           SimpleFeatureIterator iterator = featureCollection.features();
           List<AttributeDescriptor> attributes = featureCollection.getSchema().getAttributeDescriptors();
           while (iterator.hasNext()) {
               SimpleFeature simpleFeature = iterator.next();
               System.out.println();
               attributes.stream().forEach((a) -> {
                   // 依次读取这个shape中每一个属性值,当然这个属性值,可以处理其它业务
                   System.out.println(a.getLocalName() + ":" + simpleFeature.getAttribute(a.getLocalName()));
           fileInputStream.close();
           System.out.println("读取JSON完毕!");
    
  • 遍历要素及属性
  • SimpleFeatureCollection simpleFeatureCollection = (SimpleFeatureCollection) featuresource.getFeatures();
    // 获取当前矢量数据有哪些属性字段值
    List<AttributeDescriptor> attributes = simpleFeatureCollection.getSchema().getAttributeDescriptors();
    // 拿到迭代器
    SimpleFeatureIterator simpleFeatureIterator = simpleFeatureCollection.features();
    // 遍历每一个要素
    while(simpleFeatureIterator.hasNext()) {
       SimpleFeature simpleFeature = simpleFeatureIterator.next();
       // java8新特性流api
       attributes.stream().forEach((a) -> {
           // 依次读取这个shape中每一个属性值,当然这个属性值,可以处理其它业务
           System.out.println(a.getLocalName() + ":" + simpleFeature.getAttribute(a.getLocalName()));
    
  • 新增要素(创建图层) 1.构造TYPE(定义数据的坐标参考、属性字段)
  • public static SimpleFeatureType createType(Class<?> c, String layerName) {
         SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
         builder.setCRS(DefaultGeographicCRS.WGS84);
         builder.add("FID",String.class);
         // 需要注意的是几何字段的属性名称是固定的
         builder.add("the_geom", c);
         // 设置了图层的名字
         builder.setName(layerName);
         SimpleFeatureType simpleFeatureType = builder.buildFeatureType();
         return simpleFeatureType;
    

    Class的取值可以是:几何(Point.class,Polygon.class,MultiPolygon.class),属性(String.class,Integer.class, Double.class) 2.根据TYPE构建单个要素

    SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(simpleFeatureType);
    WKTReader wktReader = new WKTReader();
    Geometry geometry = wktReader.read(wktStr);
    // 这里的添加顺序和上面TYPE的时候保持一致
    featureBuilder.add("1");
    featureBuilder.add(geometry);
    SimpleFeature feature = featureBuilder.buildFeature(null);
    

    3.创建FeatureCollection

     List<SimpleFeature> features = new ArrayList<>();
     // 只需要将上面步骤的单个要素放入循环中创建更多的要素
     features.add(feature);
     SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
    

    4.导出为shp

    // 生成shpfile
    File shpFile = new File(shpPath);
    ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
    // 创造shpstore需要的参数
    Map<String, Serializable> params = new HashMap<>();
    params.put("url", shpFile.toURI().toURL());
    params.put("create spatial index", Boolean.TRUE);
    ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
    newDataStore.createSchema(simpleFeatureType);
    Transaction transaction = new DefaultTransaction("create");
    String typeName = newDataStore.getTypeNames()[0];
    SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
    SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
    SimpleFeatureCollection collection = new ListFeatureCollection(simpleFeatureType, features);
    featureStore.setTransaction(transaction);
    featureStore.addFeatures(collection);
    featureStore.setTransaction(transaction);
    transaction.commit();
    transaction.close();
    我们看到创建ShapefileDataStore 的时候传递了一个params ,那么这些参数可以传递那些值呢?可以看看源码, 可以看到里面内置了很多参数可用,我们上面使用的就是其中的两个参数。

    public static final Param URLP = new Param("url", URL.class, "url to a .shp file", true, (Object)null, new KVP(new Object[]{"ext", "shp"}));
    public static final Param NAMESPACEP = new Param("namespace", URI.class, "uri to a the namespace", false, (Object)null, new KVP(new Object[]{"level", "advanced"}));
    public static final Param MEMORY_MAPPED = new Param
    
    
    
    
        
    ("memory mapped buffer", Boolean.class, "enable/disable the use of memory-mapped io", false, false, new KVP(new Object[]{"level", "advanced"}));
    public static final Param CACHE_MEMORY_MAPS = new Param("cache and reuse memory maps", Boolean.class, "only memory map a file one, then cache and reuse the map", false, true, new KVP(new Object[]{"level", "advanced"}));
    public static final Param FILE_TYPE = new Param("filetype", String.class, "Discriminator for directory stores", false, "shapefile", new KVP(new Object[]{"level", "program"}));
    public static final Param CREATE_SPATIAL_INDEX = new Param("create spatial index", Boolean.class, "enable/disable the automatic creation of spatial index", false, true, new KVP(new Object[]{"level", "advanced"}));
    public static final Param DBFCHARSET = new Param("charset", Charset.class, "character used to decode strings from the DBF file", false, Charset.forName("ISO-8859-1"), new KVP(new Object[]{"level", "advanced"})) {
    public static final Param FSTYPE = new Param("fstype", String.class, "Enable using a setting of 'shape'.", false, "shape", new KVP(new Object[]{"level", "advanced", "options", Arrays.asList("shape-ng", "shape", "index")}));
    public static final Param DBFTIMEZONE = new Param("timezone", TimeZone.class, "time zone used to read dates from the DBF file", false, TimeZone.getDefault(), new KVP(new Object[]{"level", "advanced"})) {
    public static final Param ENABLE_SPATIAL_INDEX = new Param("enable spatial index", Boolean.class, "enable/disable the use of spatial index for local shapefiles", false, true, new KVP(new Object[]{"level", "advanced"}));
    
  • 读取TIFF
  • public static Coverage readTiff(String tiffPath) throws IOException {
         File f = new File(tiffPath);
         ParameterValue<OverviewPolicy> policy = AbstractGridFormat.OVERVIEW_POLICY.createValue();
         policy.setValue(OverviewPolicy.IGNORE);
         ParameterValue<String> gridsize = AbstractGridFormat.SUGGESTED_TILE_SIZE.createValue();
         ParameterValue<Boolean> useJaiRead = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
         useJaiRead.setValue(true);
         GridCoverage2D image = new GeoTiffReader(f).read(new GeneralParameterValue[]{policy, gridsize, useJaiRead});
         return image;
    
  • 生成TIFF
  • File file = new File(outTiffPath);
    GeoTiffWriter geoTiffWriter = new GeoTiffWriter(file);
    final GeoTiffFormat format = new GeoTiffFormat();
    final GeoTiffWriteParams wp = new GeoTiffWriteParams();
    // 设置写出参数
    wp.setCompressionMode(GeoTiffWriteParams.MODE_DEFAULT);
    wp.setTilingMode(GeoToolsWriteParams.MODE_DEFAULT);
    ParameterValueGroup paramWrite = format.getWriteParameters();
    paramWrite.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp);
    geoTiffWriter.write((GridCoverage) coverage, paramWrite.values().toArray(new GeneralParameterValue[4]) );
    geoTiffWriter.dispose();
    
  • 通过掩膜提取
  • private static Coverage clipImageToFeatureSource() throws IOException, FactoryException, MismatchedDimensionException, TransformException {
       SimpleFeatureCollection collection = CommonMethod.readFeatureCollection("E:\\data\\shp\\mask.shp");
       FeatureIterator<SimpleFeature> iterator = collection.features();
       List<Geometry> all = new ArrayList<Geometry>();
       try {
           while (iterator.hasNext()) {
               SimpleFeature feature = iterator.next();
               Geometry geometry = (Geometry) feature.getDefaultGeometry();
               all.add(geometry);
       } finally {
           if (iterator != null) {
               iterator.close();
       Coverage coverage = readTiff();
       Coverage clippedCoverage = null;
       if (all.size() > 0) {
           CoverageProcessor processor = new CoverageProcessor();
           ParameterValueGroup params = processor.getOperation("CoverageCrop")
                   .getParameters();
           params.parameter("Source").setValue(coverage);
           GeometryFactory factory = JTSFactoryFinder.getGeometryFactory(null);
           Geometry[] a = all.toArray(new Geometry[0]);
           GeometryCollection c = new GeometryCollection(a, factory);
           Envelope envelope = all.get(0).getEnvelopeInternal();
           double x1 = envelope.getMinX();
           double y1 = envelope.getMinY();
           double x2 = envelope.getMaxX();
           double y2 = envelope.getMaxY();
           ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(x1,x2, y1, y2, coverage.getCoordinateReferenceSystem());
           params.parameter("ENVELOPE").setValue(referencedEnvelope);
           params.parameter("ROI").setValue(c);
           params.parameter("ForceMosaic").setValue(true);
           clippedCoverage = processor.doOperation(params);
       if (all.size() == 0){
           System.out.println("Crop by shapefile requested but no simple features matched extent!");
       return clippedCoverage;
    

    提取文件拓扑关系: 运行结果:

    过滤器(属性查询,空间查询)

    // 得到图层所有要素
    SimpleFeatureCollection collection = readFeatureCollection(shpPath);
    // 通过过滤器进行筛选
    SimpleFeatureCollection newCollection = collection.subCollection(filter);
    

    得到过滤器的两种方式:

    // 直接书写筛选条件
    Filter filter =  CQL.toFilter("POP_RANK >= 5");
    
    // 使用工厂构造过滤器
    FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
    // greater表示大于
    Filter filter = ff.greater(ff.property("POP_RANK"), ff.literal(5));
    

    其它比较关系(非常多,可以进入类里面去查看支持那些关系比较): 它的查询原理与属性查询相同,知识表达式需要写成空间表达式。

    // 相交
    Filter filter =  CQL.toFilter( "INTERSECTS(the_geom," + wkt + ")");
    // 在10公里以内
    Filter filter =  CQL.toFilter( "DWITHIN(the_geom," + wkt + ", 10, kilometers)");
    

    完整代码:

    SimpleFeatureCollection china = readFeatureCollection("E:\\data\\shp\\china.shp");
    SimpleFeatureCollection cities = readFeatureCollection("E:\\data\\shp\\cities.shp");
    SimpleFeatureIterator chinaIterator = china.features();
    Geometry geometry  = null;
    while (chinaIterator.hasNext()) {
        SimpleFeature next = chinaIterator.next();
         geometry = (Geometry) next.getDefaultGeometry();
    Filter filter = getSpatialFilter(geometry);
    SimpleFeatureCollection subCollection = cities.subCollection(filter);
    

    更多用法参考: docs.geotools.org/stable/user…

    public static void clip() {
         SimpleFeatureCollection china = readFeatureCollection("E:\\data\\shp\\china.shp");
         SimpleFeatureCollection countries = readFeatureCollection("E:\\data\\shp\\countries.shp");
         SimpleFeature next =
    
    
    
    
        
     china.features().next();
         Geometry geometry = (Geometry) next.getDefaultGeometry();
         ClippedFeatureCollection clippedFeatureCollection = new ClippedFeatureCollection(countries, geometry, true);
         SimpleFeatureIterator clipedFeatures = clippedFeatureCollection.features();
         int gcount = 0;
         while (clipedFeatures.hasNext()) {
             SimpleFeature feature = clipedFeatures.next();
             Collection<Property> properties = feature.getProperties();
             Iterator<Property> iterator = properties.iterator();
             while (iterator.hasNext()) {
                 Property property = iterator.next();
                 System.out.println(property.getName() + "  " + property.getValue());
             gcount ++;
         System.out.println("裁剪后还剩下的元素!" + gcount);
    
    public static void buffer() throws IOException, FactoryException {
        SimpleFeatureCollection cities = readFeatureCollection("E:\\data\\shp\\cities.shp");
        List<SimpleFeature> bufferResult = new ArrayList<>();
        SimpleFeatureIterator iterator = cities.features();
        SimpleFeatureType type = CommonMethod.createType(Polygon.class, "citesBuffer");
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
        while (iterator.hasNext()) {
            SimpleFeature simpleFeature = iterator.next();
            Geometry geometry = (Geometry) simpleFeature.getDefaultGeometry();
            Geometry buffer = geometry.buffer(10);
            featureBuilder.add("1");
            featureBuilder.add(buffer);
            SimpleFeature bufferSimpleFeature = featureBuilder.buildFeature(null);
            bufferResult.add(bufferSimpleFeature);
        SimpleFeatureCollection collection = new ListFeatureCollection(type, bufferResult);
        CommonMethod.createShp("E:\\data\\shp\\citiesBuffer.shp", collection);
    
  • 合并同类图层
  • public static void union() throws IOException {
         SimpleFeatureCollection featureCollectionP1 = readFeatureCollection("E:\\data\\shp\\countries_part1.shp");
         SimpleFeatureCollection featureCollectionP2 = readFeatureCollection("E:\\data\\shp\\countries_part2.shp");
         List<SimpleFeature> features = new ArrayList<>();
         SimpleFeatureIterator iterator1 = featureCollectionP1.features();
         SimpleFeatureIterator iterator2 = featureCollectionP2.features();
         while (iterator1.hasNext()) {
             SimpleFeature simpleFeature = iterator1.next();
             features.add(simpleFeature);
         while (iterator2.hasNext()) {
             SimpleFeature simpleFeature = iterator2.next();
             features.add(simpleFeature);
         SimpleFeatureCollection collection = new ListFeatureCollection(featureCollectionP1.getSchema(), features);
         CommonMethod.createShp("E:\\data\\shp\\countries_union.shp", collection);
    
  • 多个多边形合并成一个
  • public static void merge() throws IOException {
        SimpleFeatureCollection collection = readFeatureCollection("E:\\data\\shp\\countries_mergedata.shp");
        SimpleFeatureIterator features = collection.features();
        List<Polygon> polygons = new ArrayList<>();
        while (features.hasNext()) {
            SimpleFeature simpleFeature = features.next();
            Geometry defaultGeometry = (Geometry) simpleFeature.getDefaultGeometry();
            Geometry union = defaultGeometry.union();
            polygons.add((Polygon) union);
        Polygon[] ps = polygons.toArray(new Polygon[polygons.size()]);
        MultiPolygon multiPolygon = new MultiPolygon(ps, new GeometryFactory());
        Geometry union = multiPolygon.union();
        SimpleFeatureType type = CommonMethod.createType(MultiPolygon.class, "countriesMerge");
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        builder.add("1");
        builder.add(union);
        SimpleFeature simpleFeature = builder.buildFeature(null);
        List<SimpleFeature> featureList = new ArrayList<>();
        featureList.add(simpleFeature);
        SimpleFeatureCollection simpleFeatureCollection = new ListFeatureCollection(type, featureList);
        // 生成矢量数据
        CommonMethod.createShp("E:\\data\\shp\\countriesMerge.shp", simpleFeatureCollection);
    
    public static void erase() throws IOException {
        SimpleFeatureCollection subCollection = readFeatureCollection("E:\\data\\shp\\countries_differenceData.shp");
        SimpleFeatureCollection collection = readFeatureCollection("E:\\data\\shp\\countriesMerge.shp");
        SimpleFeatureIterator subFeatures = subCollection.features();
        SimpleFeatureIterator features = collection.features();
        Geometry subGeometry = null;
        while (subFeatures.hasNext()) {
            SimpleFeature simpleFeature = subFeatures.next();
            subGeometry = (Geometry) simpleFeature.getDefaultGeometry();
        Geometry geometry = null;
        while (features.hasNext()) {
            SimpleFeature simpleFeature = features.next();
            geometry = (Geometry) simpleFeature.getDefaultGeometry();
        Geometry difference = geometry.difference(subGeometry);
        SimpleFeatureType type = CommonMethod.createType(MultiPolygon.class, "countriesDifference");
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        builder.add("1");
        builder.add(difference);
        SimpleFeature simpleFeature = builder.buildFeature(null);
        List<SimpleFeature> featureList = new ArrayList<>();
        featureList.add(simpleFeature);
        SimpleFeatureCollection simpleFeatureCollection = new ListFeatureCollection(type, featureList);
        // 生成矢量数据
        CommonMethod.createShp("E:\\data\\shp\\countriesDifference.shp", simpleFeatureCollection);
    

    擦除中间部分,相当于减法

    public static void intersect() throws IOException {
        SimpleFeatureCollection intersectCollection = readFeatureCollection("E:\\data\\shp\\countries_intersect.shp");
        SimpleFeatureCollection countries = readFeatureCollection("E:\\data\\shp\\countries.shp");
        SimpleFeatureIterator features = intersectCollection.features();
        SimpleFeatureIterator countriesFeatures = countries.features();
        List<Polygon> polygons = new ArrayList<Polygon>();
        Geometry other = null;
        while (features.hasNext()) {
            SimpleFeature next = features.next();
            other = (Geometry) next.getDefaultGeometry();
            other =  other.buffer(0);
        List<Geometry> geometries = new ArrayList<>();
        // 一个一个求交集,合并成一个大图层求交集会报错,还不清楚什么原因
        while (countriesFeatures.hasNext()) {
            SimpleFeature next = countriesFeatures.next();
            Geometry defaultGeometry = (Geometry) next.getDefaultGeometry();
            if (defaultGeometry instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) defaultGeometry;
                int numGeometries = multiPolygon.getNumGeometries();
                for (int i = 0; i < numGeometries; i ++) {
                    Geometry geometryN = multiPolygon.getGeometryN(i);
                    boolean valid = geometryN.isValid();
                    System.out.println("======>" + valid);
                    polygons.add((Polygon) multiPolygon.getGeometryN(i));
                    try {
                        Geometry intersection = other.intersection(geometryN);
                        geometries.add(intersection);
                    } catch (Exception e) {
                        Property fid = next.getProperty("FID");
                        System.out.println(fid.getValue());
            } else  {
                Geometry union = defaultGeometry.union();
                polygons.add((Polygon) union);
        SimpleFeatureType type = CommonMethod.createType(MultiPolygon.class, "countriesIntersection");
        SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
        List<SimpleFeature> featureList = new ArrayList<>();
        for (int i = 0; i < geometries.size(); i ++) {
            builder.add("1"
    
    
    
    
        
    );
            builder.add(geometries.get(i));
            SimpleFeature simpleFeature = builder.buildFeature(null);
            featureList.add(simpleFeature);
        SimpleFeatureCollection simpleFeatureCollection = new ListFeatureCollection(type, featureList);
        // 生成矢量数据
        CommonMethod.createShp("E:\\data\\shp\\countriesIntersection.shp", simpleFeatureCollection);
    

    拓扑关系: 运行结果:

  • 得到坐标系的方式
  • // 方式一得到WGS84
    CoordinateReferenceSystem targetCRS = DefaultGeographicCRS.WGS84;
    // 方式二
    CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4490");
    

    坐标系EPSG查询网址: epsg.io/

    public static void projTransForm() throws FactoryException, IOException {
        File file = new File("E:\\data\\shp\\single.shp");
        FileDataStore store = FileDataStoreFinder.getDataStore(file);
        FeatureSource featureSource = store.getFeatureSource();
        SimpleFeatureType type = (SimpleFeatureType) featureSource.getSchema();
        // 源坐标
        CoordinateReferenceSystem sourceCRS = type.getCoordinateReferenceSystem();
        // 目标坐标
        CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4490");
        // allow for some error due to different datums
        boolean lenient = true;
        MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, lenient);
        // 重新写文件
        // 获取到要素集合
        SimpleFeatureCollection featureCollection = (SimpleFeatureCollection) featureSource.getFeatures();
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        Map<String, Serializable> create = new HashMap<>();
        File  newShpFile = new File("E:\\data\\shp\\resingle.shp");
        create.put("url", newShpFile.toURI().toURL());
        create.put("create spatial index", Boolean.TRUE);
        DataStore dataStore = dataStoreFactory.createNewDataStore(create);
        SimpleFeatureType featureType = SimpleFeatureTypeBuilder.retype(type, targetCRS);
        dataStore.createSchema(featureType);
        // Get the name of the new Shapefile, which will be used to open the FeatureWriter
        String createdName = dataStore.getTypeNames()[0];
        Transaction transaction = new DefaultTransaction("Reproject");
        try (FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
                     dataStore.getFeatureWriterAppend(createdName, transaction);
             SimpleFeatureIterator iterator = featureCollection.features()) {
            while (iterator.hasNext()) {
                // copy the contents of each feature and transform the geometry
                SimpleFeature feature = iterator.next();
                SimpleFeature copy = writer.next();
                copy.setAttributes(feature.getAttributes());
                Geometry geometry = (Geometry) feature.getDefaultGeometry();
                Geometry geometry2 = JTS.transform(geometry, transform);
                copy.setDefaultGeometry(geometry2);
                writer.write();
            transaction.commit();
            writer.close();
        } catch (Exception problem) {
            problem.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
    

    主要使用的是MapContent + sld样式,但是有个致命的问题就是图例和标题用它非常难以实现,还需要进一步研究。 在生成地图之前我们先介绍一下SLD样式,它是一个XML文件定义了图层渲染的方式。一个完整的SLD文件如下:

    <?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
    <sld:StyledLayerDescriptor version="1.0.0" xmlns:sld="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xlink="http://www.w3.org/1999/xlink">
        <sld:NamedLayer>
        <sld:Name>countries</sld:Name>
        <sld:UserStyle>
          <sld:Name>Style1</sld:Name>
          <sld:FeatureTypeStyle>
            <sld:FeatureTypeName>countries</sld:FeatureTypeName>
            <sld:Rule>
              <sld:Name>countries</sld:Name>
              <sld:Title>countries</sld:Title>
              <sld:PolygonSymbolizer>
                <sld:Fill>
                  <sld:CssParameter name="fill">#97DBF2</sld:CssParameter>
                  <sld:CssParameter name="fill-opacity">1</sld:CssParameter>
                </sld:Fill>
              </sld:PolygonSymbolizer>
              <sld:TextSymbolizer>
                <sld:Label>
                  <ogc:PropertyName>LONG_NAME</ogc:PropertyName>
                </sld:Label>
                <sld:Font>
                  <sld:CssParameter name="font-family">????</sld:CssParameter>
                  <sld:CssParameter name="font-family">0</sld:CssParameter>
                  <sld:CssParameter name="font-size">14</sld:CssParameter>
                  <sld:CssParameter name="font-style">normal</sld:CssParameter>
                  <sld:CssParameter name="font-weight">normal</sld:CssParameter>
                </sld:Font>
                <sld:Fill>
                  <sld:CssParameter name="fill">#000000</sld:CssParameter>
                  <sld:CssParameter name="fill-opacity">1.0</sld:CssParameter>
                </sld:Fill>
              </sld:TextSymbolizer>
            </sld:Rule>
          </sld:FeatureTypeStyle>
        </sld:UserStyle>
      </sld:NamedLayer>
    </sld:StyledLayerDescriptor>
    

    大致解释一下: sld:Name 定义了图层的名字 sld:PolygonSymbolizer 定义面要素的填充方式颜色等,如果是点图层则是sld:PointSymbolizer, 如果线要素sld:LineSymbolizer. sld:sld:TextSymbolizer 定义了文本的样式 读取样式:

    StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
    SLDParser stylereader = new SLDParser(styleFactory, sldFile.toURI().toURL());
    Style[] stylearray = stylereader.readXML();
    

    更多样式相关: docs.geotools.org/latest/user… 其实我们不用手写这些样式文件,如果样式多手写效率非常低,我们可以先在Arcgis中调出想要的地图样式,在借助插件ArcGIS_SLD_Converter就可以导出样式。 使用方式:blog.csdn.net/qq_43259860…

    public static MapContent map = new MapContent();
    // 添加图层
    public static void addShapeLayer(String shpPath, String sldPath){
      try{
          File file = new File(shpPath);
          ShapefileDataStore shpDataStore = null;
          shpDataStore = new ShapefileDataStore(file.toURI().toURL());
          //设置编码
          Charset charset = Charset.forName("GB18030");
          shpDataStore.setCharset(charset);
          String typeName = shpDataStore.getTypeNames()[0];
          SimpleFeatureSource featureSource = null;
          featureSource = shpDataStore.getFeatureSource (typeName);
          //SLD的方式
          File sldFile = new File(sldPath);
          StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
          SLDParser stylereader = new SLDParser(styleFactory, sldFile.toURI().toURL());
          Style[] stylearray = stylereader.readXML();
          Style style = stylearray[0];
          Layer layer = new FeatureLayer(featureSource, style);
          map.addLayer(layer);
      catch(Exception e){
          e.printStackTrace();
    
    // 导出地图
    public static void getMapContent(Map paras, String imgPath){
       try{
           double[] bbox = (double[]) paras.get("bbox");
           double x1 = bbox[0], y1 = bbox[1], x2 = bbox[2], y2 = bbox[3
    
    
    
    
        
    ];
           int width = (int) paras.get("width"), height=(int) paras.get("height");
           // 设置输出范围
           CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
           ReferencedEnvelope mapArea = new ReferencedEnvelope(x1, x2, y1, y2, crs);
           // 初始化渲染器
           StreamingRenderer sr = new StreamingRenderer();
           sr.setMapContent(map);
           // 初始化输出图像
           BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
           Graphics g = bi.getGraphics();
           ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
           ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
           Rectangle rect = new Rectangle(0, 0, width, height);
           // 绘制地图
           sr.paint((Graphics2D) g, rect, mapArea);
           //将BufferedImage变量写入文件中。
           ImageIO.write(bi,"png",new File(imgPath));
       catch(Exception e){
           e.printStackTrace();
    

    运行结果:

    因为有朋友需要,在这里补充一下CommonMethod 说明一下,里面构造要素用的是最简单的方法直接写死的,需要按自己的需求改一改。

    package com.example.gis.utils;
    import org.geotools.data.DefaultTransaction;
    import org.geotools.data.FeatureSource;
    import org.geotools.data.Transaction;
    import org.geotools.data.shapefile.ShapefileDataStore;
    import org.geotools.data.shapefile.ShapefileDataStoreFactory;
    import org.geotools.data.simple.SimpleFeatureCollection;
    import org.geotools.data.simple.SimpleFeatureSource;
    import org.geotools.data.simple.SimpleFeatureStore;
    import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
    import org.geotools.referencing.crs.DefaultGeographicCRS;
    import org.opengis.feature.simple.SimpleFeatureType;
    import java.io.*;
    import java.net.MalformedURLException;
    import java.nio.charset.Charset;
    import java.util.HashMap;
    import java.util.Map;
    public class CommonMethod {
        public static SimpleFeatureType createType(Class<?> c, String layerName) {
            SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
            builder.setCRS(DefaultGeographicCRS.WGS84);
            builder.add("FID",String.class);
            builder.add("the_geom", c);
            // 设置了图层的名字
            builder.setName(layerName);
            SimpleFeatureType simpleFeatureType = builder.buildFeatureType();
            return simpleFeatureType;
        public static void createShp(String shpPath, SimpleFeatureCollection collection) throws IOException {
            File shpFile = new File(shpPath);
            ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
            SimpleFeatureType simpleFeatureType = collection.getSchema();
            // 创造shpstore需要的参数
            Map<String, Serializable> params = new HashMap<>();
            params.put("url", shpFile.toURI().toURL());
            params.put("create spatial index", Boolean.TRUE);
            ShapefileDataStore newDataStore =
                    (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
            newDataStore.createSchema(simpleFeatureType);
            Transaction transaction = new DefaultTransaction("create");
            String typeName = newDataStore.getTypeNames()[0];
            SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
            featureStore.setTransaction(transaction);
            featureStore.addFeatures(collection);
            featureStore.setTransaction(transaction);
            transaction.commit();
            transaction.close();
        public static SimpleFeatureCollection readFeatureCollection(String shpPath) {
            SimpleFeatureCollection featureCollection = null;
            File shpFile = new File(shpPath);
            try {
                ShapefileDataStore shapefileDataStore = new ShapefileDataStore(shpFile.toURI().toURL());
                // 设置编码,防止属性的中文字符出现乱码
                shapefileDataStore.setCharset(Charset.forName("UTF-8"));
                // 这个typeNamae不传递,默认是文件名称
                FeatureSource featuresource = shapefileDataStore.getFeatureSource(shapefileDataStore.getTypeNames()[0]);
                featureCollection = (SimpleFeatureCollection) featuresource.getFeatures();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            return featureCollection;
    复制代码
  • 私信