1. 概要

この記事では、地理空間データを操作するためのGeoToolsオープンソースJavaライブラリの基本について説明します。 このライブラリは、地理情報システム(GIS)を実装するための準拠した方法を提供し、多くのOpen Geospatial Consortium(OGC)標準を実装およびサポートします。

OGCが新しい標準を開発すると、それらはGeoToolsによって実装されるため、地理空間作業に非常に便利です。

2. 依存関係

GeoToolsの依存関係をpom.xmlファイルに追加する必要があります。 これらの依存関係はMavenCentralでホストされていないため、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>

その後、依存関係を追加できます。

<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とシェープファイル

GeoToolsライブラリを実際に使用するには、地理情報システムとシェープファイルについていくつか知っておく必要があります。

3.1. GIS

地理データを処理する場合は、地理情報システム(GIS)が必要です。 このシステムはを使用して、地理データを表示、キャプチャ、保存、操作、分析、または管理できます。

地理データの一部は空間的であり、地球上の具体的な場所を参照しています。 空間データには通常、属性データが付随しています。 属性データは、各空間機能に関する追加情報にすることができます。

地理データの例は都市です。 都市の実際の場所は空間データです。 都市名や人口などの追加データが属性データを構成します。

3.2. シェープファイル

地理空間データの操作には、さまざまな形式を使用できます。 ラスターとベクトルは、2つの主要なデータ型です。

この記事では、ベクターデータtyp eを操作する方法を説明します。 このデータ型は、ポイント、ライン、またはポリゴンとして表すことができます。

ベクトルデータをファイルに保存するには、shapefileを使用します。 このファイル形式は、地理空間ベクトルデータ型を操作するときに使用されます。 また、幅広いGISソフトウェアと互換性があります。

GeoToolsを使用して、都市、学校、ランドマークなどの機能をシェープファイルに追加できます。

4. 機能の作成

GeoTools のドキュメントでは、都市やランドマークなど、地図上に描画できるものなら何でも機能が指定されています。 そして、前述したように、作成された機能は、shapefilesというファイルに保存できます。

4.1. 地理空間データの保持

フィーチャを作成する前に、その地理空間データ、または地球上のその場所の経度と緯度の座標を知る必要があります。属性データについては、作成するフィーチャの名前を知る必要があります。

この情報はウェブ上で見つけることができます。 simplemaps.commaxmind.comなどの一部のサイトでは、地理空間データを含む無料のデータベースを提供しています。

都市の経度と緯度がわかれば、それらを簡単にオブジェクトに保存できます。 都市名とその座標のリストを保持するMapオブジェクトを使用できます。

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);
}

次に、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);

このデータを含むCSVデータベースをダウンロードすると、このようなオブジェクトにデータを保持する代わりに、データを取得するためのリーダーを簡単に作成できます。

4.2. 機能タイプの定義

これで、都市の地図ができました。 このデータを使用してフィーチャを作成できるようにするには、最初にそれらのタイプを定義する必要があります。 GeoToolsには、フィーチャタイプを定義する2つの方法があります。

1つの方法は、DataUtilitesクラスのcreateTypeメソッドを使用することです。

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

もう1つの方法は、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();

どちらのタイプも同じ情報を格納します。都市の場所はポイントとして格納され、都市の名前は文字列として格納されます。

型変数TYPECITYは、定数のようにすべて大文字で名前が付けられていることに気付いたと思います。 タイプ変数は最終変数として扱われる必要があり、作成後に変更されないようにする必要があります。したがって、この命名方法を使用して、それを示すことができます。

4.3. 機能の作成と機能のコレクション

フィーチャタイプを定義し、フィーチャの作成に必要なデータを含むオブジェクトを取得したら、ビルダーを使用してそれらの作成を開始できます。

機能タイプを提供するSimpleFeatureBuilderをインスタンス化してみましょう。

SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(CITY);

作成されたすべてのフィーチャオブジェクトを保存するためのコレクションも必要です。

DefaultFeatureCollection collection = new DefaultFeatureCollection();

フィーチャタイプで場所のポイントを保持することを宣言したため、座標に基づいて都市のポイントを作成する必要があります。 これは、GeoToolsのJTSGeometryFactoryFinderで実行できます。

GeometryFactory geometryFactory
  = JTSFactoryFinder.getGeometryFactory(null);

LineやPolygonなどの他のGeometryクラスも使用できることに注意してください。

コレクションに機能を追加するのに役立つ関数を作成できます。

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);
    };
}

ビルダーとコレクションを取得したら、以前に作成した関数を使用して、機能を作成し、コレクションに保存できます。

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

コレクションには、地理空間データを保持するMapオブジェクトに基づいて作成されたすべての機能が含まれるようになりました。

5. データストアの作成

GeoTools には、地理空間データのソースを表すために使用される DataStoreAPIが含まれています。 このソースは、ファイル、データベース、またはデータを返すサービスの場合があります。 DataStoreFactory を使用して、機能を含むDataStoreを作成できます。

機能を含むファイルを設定しましょう:

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

次に、使用するファイルを DataStoreFactory に通知し、 DataStoreを作成するときに空間インデックスを格納する必要があることを示すために使用するパラメーターを設定しましょう。

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

作成したパラメータを使用してDataStoreFactoryを作成し、そのファクトリを使用してDataStoreを作成しましょう。

ShapefileDataStoreFactory dataStoreFactory
  = new ShapefileDataStoreFactory();

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

6. シェープファイルへの書き込み

最後のステップは、データをshapefileに書き込むことです。 これを安全に行うために、 GeoToolsAPIの一部であるトランザクションインターフェース使用します。

このインターフェースにより、ファイルへの変更を簡単にコミットすることができます。 また、ファイルへの書き込み中に何らかの問題が発生した場合に失敗した変更のロールバックを実行する方法も提供します。

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();
    }
}

SimpleFeatureSource は機能の読み取りに使用され、SimpleFeatureStoreは読み取り/書き込みアクセスに使用されます。 GeoTools のドキュメントでは、instanceofメソッドを使用してファイルに書き込めるかどうかを確認するのが正しい方法であると指定されています。

このshapefileは、shapefileをサポートする任意のGISビューアで後で開くことができます。

7. 結論

この記事では、 GeoTools ライブラリを使用して、非常に興味深い地理空間作業を行う方法を説明しました。

この例は単純ですが、拡張して、さまざまな目的でリッチなシェープファイルを作成するために使用できます。

GeoTools は活気に満ちたライブラリであり、この記事はライブラリの基本的な紹介にすぎないことを覚えておく必要があります。 また、 GeoTools は、ベクトルデータ型の作成だけに限定されるものではなく、ラスターデータ型の作成または操作にも使用できます。

この記事で使用されている完全なサンプルコードは、GitHubプロジェクトにあります。 これはMavenプロジェクトなので、インポートしてそのまま実行できるはずです。