【Java】GeoTools-Feature Tutorial

介绍

今天我们来使用GeoTools来创建一个features
本文包括:

  • 创建一个FeatureType、FeatureCollection和Features
  • 使用GeometryFactory构建点
  • 写出Shapefile
  • 设置投影

CSV2SHP

首先我们需要一个CSV文件,内容如下

LAT, LON, CITY, NUMBER
46.066667, 11.116667, Trento, 140
44.9441, -93.0852, St Paul, 125
13.752222, 100.493889, Bangkok, 150
45.420833, -75.69, Ottawa, 200
44.9801, -93.251867, Minneapolis, 350
46.519833, 6.6335, Lausanne, 560
48.428611, -123.365556, Victoria, 721
-33.925278, 18.423889, Cape Town, 550
-33.859972, 151.211111, Sydney, 436
41.383333, 2.183333, Barcelona, 914
39.739167, -104.984722, Denver, 869
52.95, -1.133333, Nottingham, 800
45.52, -122.681944, Portland, 840
37.5667,129.681944,Seoul,473
50.733992,7.099814,Bonn,700,201

将其命名为location.csv并保存,这就是我们的数据了~

添加以下依赖到我们的项目

 <dependencies>
  <dependency>
   <groupId>org.geotools</groupId>
   <artifactId>gt-shapefile</artifactId>
   <version>${geotools.version}</version>
  </dependency>
  <dependency>
   <groupId>org.geotools</groupId>
   <artifactId>gt-epsg-hsql</artifactId>
   <version>${geotools.version}</version>
  </dependency>
 </dependencies>
  <repositories>
    <repository>
      <id>osgeo</id>
      <name>OSGeo Release Repository</name>
      <url>https://repo.osgeo.org/repository/release/</url>
      <snapshots><enabled>false</enabled></snapshots>
      <releases><enabled>true</enabled></releases>
    </repository>
    <repository>
      <id>osgeo-snapshot</id>
      <name>OSGeo Snapshot Repository</name>
      <url>https://repo.osgeo.org/repository/snapshot/</url>
      <snapshots><enabled>true</enabled></snapshots>
      <releases><enabled>false</enabled></releases>
    </repository>
  </repositories>

这里就正式开始写代码啦
按照教程,创建一个Shapefile总共分为4步

  1. 创建一个FeatureType
  2. 创建Feature
  3. 从FeatureCollection中创建shapefile
  4. 将Feature写入shapefile

我们一步一步来
做一下准备工作,使用一个文件选择器将csv文件导入进来

    File file = JFileDataStoreChooser.showOpenFile("csv", null);
        if (file == null) {
            return;
        }

然后就可以创建FeatureType了,FeatureType是用来描述要写入shapefile的csv文件的数据的

final SimpleFeatureType TYPE =
                DataUtilities.createType(
                        "Location",
                        "the_geom:Point:srid=4326,"
                                + // <- the geometry attribute: Point type
                                "name:String,"
                                + // <- a String attribute
                                "number:Integer" // a number attribute
                        );
        System.out.println("TYPE:" + TYPE);

这里的DataUtilities.createType()是一个用来创建FeatureType的静态方法,详情如下

static SimpleFeatureType	createType​(String typeName, String typeSpec)	

这是一个创建FeatureType的方法(好像说了句废话),其本质还是使用了SimpleFeatureTypeBuilder这个类来构造的FeatureType,第一个参数是FeatureType的name,第二个参数以逗号分隔创建了feature的字段和类型。
详情还有些不同,感兴趣可以去看看源码

这里我们就使用createType方法创建了一个点的FeatureType,并添加了两个属性字段

第二步是创建Features
我们读取CSV文件,并将其中的每一条记录都创建要素
大概为两个步骤

  1. 使用GeometryFactory创建新的点
  2. 使用SimpleFeatureBuilder创建要素
    代码如下
 /*
         * 创建一个要素的集合
         */
        List<SimpleFeature> features = new ArrayList<>();

        /*
         * GeometryFactory 将会创建geometry属性为每个要素
         */
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();

        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            /* First line of the data file is the header */
            String line = reader.readLine();
            System.out.println("Header: " + line);

            for (line = reader.readLine(); line != null; line = reader.readLine()) {
                if (line.trim().length() > 0) { // skip blank lines
                    String[] tokens = line.split("\\,");

                    double latitude = Double.parseDouble(tokens[0]);
                    double longitude = Double.parseDouble(tokens[1]);
                    String name = tokens[2].trim();
                    int number = Integer.parseInt(tokens[3].trim());

                    /* Longitude (= x coord) first ! */
                    Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));

                    featureBuilder.add(point);
                    featureBuilder.add(name);
                    featureBuilder.add(number);
                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    features.add(feature);
                }
            }
        }

可以看到,这里读取了CSV文件中的数据,并且使用GeometryFactory的createPoint方法创建了点,使用第一步中创建的FeatureType创建了一个featureBuilder来创建要素,featureBuilder通过添加点和他的属性,最后使用buildFeature方法来创建出一个要素,我们将这个创建出的要素添加到要素集合中。

第三步为通过FeatureCollection来创建shapefile
大概步骤为

  1. 使用DataStoreFactory和参数来确定要创建的shapefile的存储地址
  2. 使用createSchema方法来设置shapefile的类型
    代码如下
		File newFile = getNewShapeFile(file);

        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();

        Map<String, Serializable> params = new HashMap<>();
        params.put("url", newFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);

        ShapefileDataStore newDataStore =
                (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);

        /*
         * TYPE is used as a template to describe the file contents
         */
        newDataStore.createSchema(TYPE);

这里使用了一个getNewShapeFile的方法来为新的shapefile文件创建文件
然后使用ShapefiledataStorefactorycreateNewdataStore方法来定位创建shapefile的位置
最后使用了ShapefileDataStorecreateSchema方法确定shapefile的累心
再加上getNewShapeFile方法的代码

 private static File getNewShapeFile(File csvFile) {
        String path = csvFile.getAbsolutePath();
        String newPath = path.substring(0, path.length() - 4) + ".shp";

        JFileDataStoreChooser chooser = new JFileDataStoreChooser("shp");
        chooser.setDialogTitle("Save shapefile");
        chooser.setSelectedFile(new File(newPath));

        int returnVal = chooser.showSaveDialog(null);

        if (returnVal != JFileDataStoreChooser.APPROVE_OPTION) {
            // the user cancelled the dialog
            System.exit(0);
        }

        File newFile = chooser.getSelectedFile();
        if (newFile.equals(csvFile)) {
            System.out.println("Error: cannot replace " + csvFile);
            System.exit(0);
        }

        return newFile;
    }

最后第四步,就是将feature数据写入到shapefile中了
主要包含下面几步

  1. 检查我们是否有写入和读取的权限
  2. 检查shapefile文件的类型和我们要素的类型的匹配程度

代码如下

 		/*
         * Write the features to the shapefile
         */
        Transaction transaction = new DefaultTransaction("create");

        String typeName = newDataStore.getTypeNames()[0];
        SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
        SimpleFeatureType SHAPE_TYPE = featureSource.getSchema();
        /*
         * ShapeFile格式有一些限制:
         * - "the_geom" 永远是第一个,作为几何体属性的名称
         * - "the_geom" 的类型必须是 Point, MultiPoint, MuiltiLineString, MultiPolygon
         * - 属性名称的长度是有限制的
         * - 不是所有的数据类型都支持(例如日期类型)
         *
         * 每个数据存储都有不同的限制
         */
        System.out.println("SHAPE:" + SHAPE_TYPE);

        if (featureSource instanceof SimpleFeatureStore) {
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
            /*
             * SimpleFeatureStore has a method to add features from a
             * SimpleFeatureCollection object, so we use the ListFeatureCollection
             * class to wrap our list of features.
             */
            SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
            featureStore.setTransaction(transaction);
            try {
                featureStore.addFeatures(collection);
                transaction.commit();
            } catch (Exception problem) {
                problem.printStackTrace();
                transaction.rollback();
            } finally {
                transaction.close();
            }
            System.exit(0); // success!
        } else {
            System.out.println(typeName + " does not support read/write access");
            System.exit(1);
        }
    }

其上呢,大概的过程是这样的,首先创建了一个create的事务,用来执行将feature写入shapefile
然后提取了shapefile的属性,来确保和要写入的要素属于同一个
确保之后呢,就将第二部创建的要素集合转化为FeatureCollection的类型,再将该几个添加到featureStore中,最后再由事务提交,就完成了写入工作啦~

一些尝试

使用SimpleFeatureType来创建FeatureType

上面也已经说过了,其实DataUtilities的createType也是使用的SimpleFeatureType这个类来创建的FeatureType,具体样例如下

    private static SimpleFeatureType createFeatureType() {

        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName("Location");
        builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference system

        // add attributes in order
        builder.add("the_geom", Point.class);
        builder.length(15).add("Name", String.class); // <- 15 chars width for name field
        builder.add("number", Integer.class);

        // build the type
        final SimpleFeatureType LOCATION = builder.buildFeatureType();

        return LOCATION;
    }

结语

到这里就结束了,还挺长的,其实原文还有对shapefile的介绍,想了解可以看看原文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值