Introduction to GeoTools – GeoTools简介

最后修改: 2017年 9月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll go through the basics of the GeoTools open source Java library – for working with geospatial data. This library provides compliant methods for implementing Geographic Information Systems (GIS) and implements and supports many Open Geospatial Consortium (OGC) standards.

在本文中,我们将介绍GeoTools开源Java库–用于处理地理空间数据的基础知识。该库为实现地理信息系统(GIS)提供了符合要求的方法,并实现和支持许多开放地理空间联盟(OGC)标准。

As the OGC develops new standards, they’re implemented by the GeoTools, which makes it quite handy for geospatial work.

随着OGC开发新的标准,它们被GeoTools实施,这使得它对地理空间工作相当方便。

2. Dependencies

2.依赖性

We’ll need to add the GeoTools dependencies to our pom.xml file. Since these dependencies are not hosted on Maven Central, we also need to declare their repositories so that Maven can download them:

我们需要在pom.xml文件中添加GeoTools的依赖项。由于这些依赖项不在Maven中心托管,我们还需要声明它们的仓库,以便Maven能够下载它们。

<repositories>
    <repository>
        <id>osgeo</id>
        <name>Open Source Geospatial Foundation Repository</name>
        <url>http://download.osgeo.org/webdav/geotools/</url>
    </repository>
    <repository>
        <id>opengeo</id>
        <name>OpenGeo Maven Repository</name>
        <url>http://repo.opengeo.org</url>
    </repository>
</repositories>

After that, we can add our dependencies:

之后,我们可以添加我们的依赖性。

<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-shapefile</artifactId>
    <version>15.2</version>
</dependency>
<dependency>
    <groupId>org.geotools</groupId>
    <artifactId>gt-epsg-hsql</artifactId>
    <version>15.2</version>
</dependency>

3. GIS and Shapefiles

3.地理信息系统和形状文件

To have any practical use of the GeoTools library, we’ll need to know a few things about geographic information systems and shapefiles.

要想实际使用GeoTools库,我们需要了解一些关于地理信息系统和shapefiles的事情。

3.1. GIS

3.1. GIS

If we want to work with geographical data, we’ll need a geographic information system (GIS). This system can be used to present, capture, store, manipulate, analyze, or manage geographical data.

如果我们想处理地理数据,我们就需要一个地理信息系统(GIS)。这个系统可以用来展示、捕获、存储、操作、分析或管理地理数据

Some portion of the geographical data is spatial – it references concrete locations on earth. The spatial data is usually accompanied by the attribute data. Attribute data can be any additional information about each of the spatial features.

地理数据的某些部分是空间性的–它引用了地球上的具体位置。空间数据通常伴随着属性数据。属性数据可以是关于每个空间特征的任何附加信息。

An example of geographical data would be cities. The actual location of the cities is the spatial data. Additional data such as the city name and population would make up the attribute data.

地理数据的一个例子是城市。城市的实际位置是空间数据。额外的数据,如城市名称和人口将构成属性数据。

3.2. Shapefiles

3.2.Shapefiles

Different formats are available for working with geospatial data. Raster and vector are the two primary data types.

有不同的格式可用于处理地理空间数据。栅格和矢量是两种主要的数据类型。

In this article, we’re going to see how to work with the vector data type. This data type can be represented as points, lines, or polygons.

在这篇文章中,我们将看到如何使用矢量数据类型e。这种数据类型可以用点、线或多边形来表示。

To store vector data in a file, we will use a shapefile. This file format is used when working with the geospatial vector data type. Also, it is compatible with a wide range of GIS software.

为了在文件中存储矢量数据,我们将使用shapefile。这种文件格式是在处理地理空间矢量数据类型时使用的。而且,它与广泛的GIS软件兼容。

We can use GeoTools to add features like cities, schools, and landmarks to shapefiles.

我们可以使用GeoTools将城市、学校和地标等特征添加到shapefiles

4. Creating Features

4.创建功能

The GeoTools documentation specifies that a feature is anything that can be drawn on a map, like a city or some landmark. And, as we mentioned, once created, features can then be saved into files called shapefiles.

GeoTools文档规定,特征是可以在地图上绘制的任何东西,比如一个城市或一些地标。而且,正如我们所提到的,一旦创建,特征就可以被保存到称为shapefiles的文件中。

4.1. Keeping Geospatial Data

4.1.保存地理空间数据

Before creating a feature, we need to know its geospatial data or the longitude and latitude coordinates of its location on earth. As for attribute data, we need to know the name of the feature we want to create.

在创建一个特征之前,我们需要知道它的地理空间数据或它在地球上的经纬度坐标。至于属性数据,我们需要知道我们要创建的特征的名称。

This information can be found on the web. Some sites like simplemaps.com or maxmind.com offer free databases with geospatial data.

这些信息可以在网上找到。一些网站,如simplemaps.commaxmind.com提供含有地理空间数据的免费数据库。

When we know the longitude and latitude of a city, we can easily store them in some object. We can use a Map object that will hold the city name and a list of its coordinates.

当我们知道一个城市的经度和纬度时,我们可以很容易地将它们存储在某个对象中。我们可以使用一个Map对象,它将保存城市名称和它的坐标列表。

Let’s create a helper method to ease the storing of data inside our Map object:

让我们创建一个辅助方法,以方便在我们的Map对象中存储数据。

private static void addToLocationMap(
  String name,
  double lat,
  double lng,
  Map<String, List<Double>> locations) {
    List<Double> coordinates = new ArrayList<>();

    coordinates.add(lat);
    coordinates.add(lng);
    locations.put(name, coordinates);
}

Now let’s fill in our Map object:

现在让我们填入我们的Map对象。

Map<String, List<Double>> locations = new HashMap<>();

addToLocationMap("Bangkok", 13.752222, 100.493889, locations);
addToLocationMap("New York", 53.083333, -0.15, locations);
addToLocationMap("Cape Town", -33.925278, 18.423889, locations);
addToLocationMap("Sydney", -33.859972, 151.211111, locations);
addToLocationMap("Ottawa", 45.420833, -75.69, locations);
addToLocationMap("Cairo", 30.07708, 31.285909, locations);

If we download some CSV database that contains this data, we can easily create a reader to retrieve the data instead of keeping it in an object like here.

如果我们下载一些包含这些数据的CSV数据库,我们可以很容易地创建一个阅读器来检索数据,而不是像这里一样把它保存在一个对象中。

4.2. Defining Feature Types

4.2.定义特征类型

So, now we have a map of cities. To be able to create features with this data, we’ll need to define their type first. GeoTools offers two ways of defining feature types.

所以,现在我们有了一张城市地图。为了能够用这些数据创建特征,我们需要先定义它们的类型。GeoTools提供了两种定义特征类型的方法。

One way is to use the createType method of the DataUtilites class:

一种方法是使用DataUtilites类的createType方法。

SimpleFeatureType TYPE = DataUtilities.createType(
  "Location", "location:Point:srid=4326," + "name:String");

Another way is to use a SimpleFeatureTypeBuilder, which provides more flexibility. For example, we can set the Coordinate Reference System for the type, and we can set a maximum length for the name field:

另一种方法是使用SimpleFeatureTypeBuilder,它提供了更多的灵活性。例如,我们可以为该类型设置坐标参考系统,我们可以为名称字段设置最大长度。

SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("Location");
builder.setCRS(DefaultGeographicCRS.WGS84);

builder
  .add("Location", Point.class);
  .length(15)
  .add("Name", String.class);

SimpleFeatureType CITY = builder.buildFeatureType();

Both types store the same information. The location of the city is stored as a Point, and the name of the city is stored as a String.

两种类型都存储相同的信息。城市的位置被存储为Point,而城市的名称被存储为String

You probably noticed that the type variables TYPE and CITY are named with all capital letters, like constants. Type variables should be treated as final variables and should not be changed after they are created, so this way of naming can be used to indicate just that.

你可能注意到,类型变量TYPECITY是用所有大写字母命名的,像常量一样。类型变量应该被视为最终的变量,在它们被创建后不应该被改变,所以这种命名方式可以用来表示这一点。

4.3. Feature Creation and Feature Collections

4.3.特征创建和特征集合

Once we have the feature type defined and we have an object that has the data needed to create features, we can start creating them with their builder.

一旦我们定义了特征类型,并且有了一个拥有创建特征所需数据的对象,我们就可以开始用其构建器来创建它们。

Let’s instantiate a SimpleFeatureBuilder providing our feature type:

让我们实例化一个SimpleFeatureBuilder,提供我们的特征类型。

SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(CITY);

We’ll also need a collection to store all the created feature objects:

我们还需要一个集合来存储所有创建的特征对象。

DefaultFeatureCollection collection = new DefaultFeatureCollection();

Since we declared in our feature type to hold a Point for the location, we’ll need to create points for our cities based on their coordinates. We can do this with the GeoTools’s JTSGeometryFactoryFinder:

由于我们在我们的特征类型中声明要为位置持有一个Point,我们将需要根据城市的坐标为其创建点。我们可以用GeoTools的JTSGeometryFactoryFinder来做这个。

GeometryFactory geometryFactory
  = JTSFactoryFinder.getGeometryFactory(null);

Note that we can also use other Geometry classes like Line and Polygon.

请注意,我们也可以使用其他Geometry类,如LinePolygon

We can create a function that will help us put features in the collection:

我们可以创建一个函数,帮助我们把特征放到集合中。

private static Function<Map.Entry<String, List<Double>>, SimpleFeature>
  toFeature(SimpleFeatureType CITY, GeometryFactory geometryFactory) {
    return location -> {
        Point point = geometryFactory.createPoint(
           new Coordinate(location.getValue()
             .get(0), location.getValue().get(1)));

        SimpleFeatureBuilder featureBuilder
          = new SimpleFeatureBuilder(CITY);
        featureBuilder.add(point);
        featureBuilder.add(location.getKey());
        return featureBuilder.buildFeature(null);
    };
}

Once we have the builder and the collection, by using the previously created function, we can create features and store them in our collection:

一旦我们有了构建器和集合,通过使用之前创建的函数,我们就可以创建特征并将其存储在我们的集合中

locations.entrySet().stream()
  .map(toFeature(CITY, geometryFactory))
  .forEach(collection::add);

The collection now contains all the features created based on our Map object that held the geospatial data.

该集合现在包含了基于我们持有地理空间数据的Map对象而创建的所有特征。

5. Creating a DataStore

5.创建一个数据存储

GeoTools contains a DataStore API that is used to represent a source of geospatial data. This source can be a file, a database, or some service that returns data. We can use a DataStoreFactory to create our DataStore, which will contain our features.

GeoTools包含一个DataStore API,用于表示地理空间数据的来源。这个来源可以是一个文件、一个数据库,或者一些返回数据的服务。我们可以使用DataStoreFactory来创建我们的DataStore,它将包含我们的特征。

Let’s set the file that will contain the features:

让我们来设置将包含特征的文件。

File shapeFile = new File(
  new File(".").getAbsolutePath() + "shapefile.shp");

Now, let’s set the parameters that we are going to use to tell the DataStoreFactory which file to use and indicate that we need to store a spatial index when we create our DataStore:

现在,让我们来设置参数,我们要用这些参数来告诉DataStoreFactory要使用哪个文件,并指出我们在创建DataStore时需要存储一个空间索引。

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

Let’s create the DataStoreFactory using the parameters we just created, and use that factory to create the DataStore:

让我们使用刚才创建的参数创建DataStoreFactory,并使用该工厂创建DataStore

ShapefileDataStoreFactory dataStoreFactory
  = new ShapefileDataStoreFactory();

ShapefileDataStore dataStore 
  = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
dataStore.createSchema(CITY);

6. Writing to a Shapefile

6.写到Shapefile

The last step that we need to do is to write our data to a shapefile. To do this safely, we are going to use the Transaction interface that is a part of the GeoTools API.

我们需要做的最后一步是将我们的数据写入shapefile。为了安全地做到这一点,我们将使用Transactioninterface,这是GeoToolsAPI的一部分。

This interface gives us the possibility to easily commit our the changes to the file. It also provides a way to perform a rollback of the unsuccessful changes if some problem occurs while writing to the file:

这个接口让我们可以轻松地commit我们对文件的修改。它还提供了一种方法来执行回滚不成功的更改,如果在向文件写入时发生一些问题的话

Transaction transaction = new DefaultTransaction("create");

String typeName = dataStore.getTypeNames()[0];
SimpleFeatureSource featureSource
  = dataStore.getFeatureSource(typeName);

if (featureSource instanceof SimpleFeatureStore) {
    SimpleFeatureStore featureStore
      = (SimpleFeatureStore) featureSource;

    featureStore.setTransaction(transaction);
    try {
        featureStore.addFeatures(collection);
        transaction.commit();

    } catch (Exception problem) {
        transaction.rollback();
    } finally {
        transaction.close();
    }
}

The SimpleFeatureSource is used to read features, and the SimpleFeatureStore is used for read/write access. It is specified in the GeoTools documentation that using the instanceof method for checking if we can write to the file is the right way to do so.

SimpleFeatureSource用于读取特征,而SimpleFeatureStore用于读写访问。在GeoTools文档中规定,使用instanceof方法来检查我们是否可以写入文件是正确的方法。

This shapefile can later be opened with any GIS viewer that has shapefile support.

这个shapefile以后可以用任何支持shapefile的GIS查看器打开。

7. Conclusion

7.结论

In this article, we saw how we can make use of the GeoTools library to do some very interesting geo-spatial work.

在这篇文章中,我们看到了如何利用GeoTools库来做一些非常有趣的地理空间工作。

Although the example was simple, it can be extended and used for creating rich shapefiles for various purposes.

虽然这个例子很简单,但它可以被扩展并用于创建丰富的shapefiles,用于各种目的。

We should have in mind that GeoTools is a vibrant library, and this article just serves as a basic introduction to the library. Also, GeoTools is not limited to creating vector data types only – it can also be used to create or to work with raster data types.

我们应该记住,GeoTools是一个充满活力的库,这篇文章只是作为对该库的基本介绍。另外,GeoTools不仅限于创建矢量数据类型–它还可以用来创建或处理光栅数据类型。

You can find the full example code used in this article in our GitHub project. This is a Maven project, so you should be able to import it and run it as it is.

你可以在我们的GitHub项目中找到本文使用的完整示例代码。这是一个Maven项目,所以你应该可以导入它并按原样运行。