About GeoTools

GeoTools is an open source (LGPL) Java code library which provides standards compliant methods for the manipulation of geospatial data, for example to implement Geographic Information Systems (GIS). The GeoTools library implements Open Geospatial Consortium (OGC) specifications as they are developed.

走进 GeoTools

GeoTools 的架构图如下,我们了解 GeoTools 的架构以及各个jar包所构成的库栈,能够帮助我们更加清晰的了解和学习 GeoTools 的各个模块,并且还能够帮助我们在项目里面选择适合我们的库。

../_images/geotools.png ../_images/geotools.png

这张架构图遵循了软件工程领域里面架构图设计标准,由下而上,第一层是基础设施,上层建筑依赖于基础设施。

比如:你如果想使用 Referencing 模块里的 gt-opengis gt-referencing gt-metadata 内容,那么当你使用 data 模块的时候, gt-main jts gt-opengis gt-referencing gt-opengis gt-metadata ,上面 Referencing 的内容也是会引用到的。

GeoTools 常用模块的功能列表:

ModulePurpose gt-render Implements of Java2D rendering engine to draw a map gt-jdbc Implements for accessing spatial database gt-main Implements for accessing spatial data gt-xml Implements of common spatial XML formats gt-cql Implements of Common Query Language for filters gt-main Interfaces for working with spatial information. Implements filter, feature, etc… Definition and implementation of Geometry gt-coverage Implementation for accessing raster information gt-referencing Implementation of co-ordinate location and transformation gt-metadata Implementation of identification and description gt-opengis Definition of interfaces for common spatial concepts

GeoTools 提供插件来支持额外的数据格式、不同的坐标参考系统权限等等。

除此之外, GeoTools 团队在 GeoTools 的基础上实现了一些扩展,当然了,这些扩展是为了提供一些额外的功能。这些扩展是相互独立的,我们可以直接在项目中使用。

../_images/extension.png ../_images/extension.png

JARExtension gt-graph Work with graph and network traversals gt-validation Quality assurance for spatial data gt-wms Web Map Server client gt-xsd Parsing/Encoding for common OGC schemas gt-brewer Generation of styles using color brewer

GeoTools 团队 为了支持 GeoTools 中的XML模块,将几个XML模式打包成JAR形式,方便开发者进行调用。

JARSchema net.opengis.ows open web services schema net.opengis.wfs web feature service net.opengis.wps web processing service schema net.opengis.wcs web coverage service schema net.opengis.wfs web feature service schema org.w3.xlink XLink schema

XSD解析器通过一系列XSD插件使用这些工具。这些插件指示如何使用Eclipse XSD库解析和编码额外的内容来解析XML模式文档,并提供“绑定”,显示如何解析和编码Java类,如String、Date、URL和Geometry。

JARBindings gt-xsd-core Basic types defined by XML schema gt-xsd-fes filter 2.0 gt-xsd-filter filter (used by OGC CAT and WFS) gt-xsd-kml keyhole markup language gt-xsd-wfs web feature service gt-xsd-wps web processing service gt-xsd-gml3 geographic markup language 3 gt-xsd-gml2 geographic markup language 2 gt-xsd-ows open web services gt-xsd-wcs web coverage service gt-xsd-wms web map service gt-xsd-sld style layer descriptor

以下是 GeoTools 不支持的扩展,你也可以使用Maven下载它们来使用。

UnsupportedPurpose gt-swt Standard widget toolkit interactive map gt-swing Swing interactive map gt-oracle retired oracle support gt-postgis retired PostGIS support gt-db2 retired db2 support gt-wps Web Processing Service client gt-process Job system for spatial data
  • 在POM文件中,首先添加以下内容:
  •     <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <geotools.version>24-SNAPSHOT</geotools.version>
        </properties>
  • 然后在POM文件的 <repositories> 标签中,添加以下依赖,该依赖是 GeoTools 官方的依赖远程仓库位置:
  •  <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>
  • 在POM文件中添加以下依赖:
  • <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.1</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-shapefile</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-swing</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.locationtech.jts/jts-core -->
            <dependency>
                <groupId>org.locationtech.jts</groupId>
                <artifactId>jts-core</artifactId>
                <version>1.16.1</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.geotools/gt-main -->
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-main</artifactId>
                <version>22-RC</version>
            </dependency>
    </dependencies>
  • 在你的Spring Boot工程中新建 QuickStrat 类,并添加以下代码:
  • import org.geotools.data.FileDataStore;
    import org.geotools.data.FileDataStoreFinder;
    import org.geotools.data.simple.SimpleFeatureSource;
    import org.geotools.map.FeatureLayer;
    import org.geotools.map.Layer;
    import org.geotools.map.MapContent;
    import org.geotools.styling.SLD;
    import org.geotools.styling.Style;
    import org.geotools.swing.JMapFrame;
    import org.geotools.swing.data.JFileDataStoreChooser;

    import java.io.File;

    /**
     * @Author Wangb
     * @Date 20/11/2021 下午6:54.
     * @Description
     */
    public class Quickstart {

        /**
         * GeoTools Quickstart demo application. Prompts the user for a shapefile and displays its
         * contents on the screen in a map frame
         */
        public static void main(String[] args) throws Exception {
            // display a data store file chooser dialog for shapefiles
            File file = JFileDataStoreChooser.showOpenFile("shp", null);
            if (file == null) {
                return;
            }

            FileDataStore store = FileDataStoreFinder.getDataStore(file);
            SimpleFeatureSource featureSource = store.getFeatureSource();

            // Create a map content and add our shapefile to it
            MapContent map = new MapContent();
            map.setTitle("Quickstart");

            Style style = SLD.createSimpleStyle(featureSource.getSchema());
            Layer layer = new FeatureLayer(featureSource, style);
            map.addLayer(layer);

            // Now display the map
            JMapFrame.showMap(map);
        }
    }

    在该网站 http://www.naturalearthdata.com/downloads/50m-cultural-vectors/ ,根据自己的喜好来下载一个矢量数据文件。

    在下图的窗口中勾选你刚才下载、并解压文件后的位置。

    http://docs.geotools.org/stable/userguide/_downloads/d4bcf8751cc3f33a9fb673902a960e53/locations.csv

  • 在你的IDE中键入以下代码:
  • package com.geovis.bin.utils.gis.geotools;


    import com.vividsolutions.jts.geom.Coordinate;
    import com.vividsolutions.jts.geom.GeometryFactory;
    import com.vividsolutions.jts.geom.Point;
    import org.geotools.data.DataUtilities;
    import org.geotools.data.DefaultTransaction;
    import org.geotools.data.Transaction;
    import org.geotools.data.collection.ListFeatureCollection;
    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.SchemaException;
    import org.geotools.feature.simple.SimpleFeatureBuilder;
    import org.geotools.geometry.jts.JTSFactoryFinder;
    import org.geotools.swing.data.JFileDataStoreChooser;
    import org.opengis.feature.simple.SimpleFeature;
    import org.opengis.feature.simple.SimpleFeatureType;
    import javax.swing.*;
    import java.io.*;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**
     * This example reads data for point locations and associated attributes from a comma separated text
     * (CSV) file and exports them as a new shapefile. It illustrates how to build a feature type.
     *
     * <p>Note: to keep things simple in the code below the input file should not have additional spaces
     * or tabs between fields.
     */

    /**
     * @Author Wangb
     * @Date 20/11/2021 下午9:32.
     * @Description
     */
    public class Csv2Shape {
        public static void csv2Shape() throws IOException, SchemaException, ClassNotFoundException, UnsupportedLookAndFeelException, InstantiationException, IllegalAccessException {
            // Set cross-platform look & feel for compatability
            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

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

            /**
             * We use the DataUtilities class to create a FeatureType that will describe the data in our
             * shapefile.
             *
             * See also the createFeatureType method below for another, more flexible approach.
             */
            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);

            /*
             * A list to collect features as we create them.
             */
            List<SimpleFeature> features = new ArrayList<>();

            /*
             * GeometryFactory will be used to create the geometry attribute of each feature,
             * using a Point object for the location.
             */
            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()) {
                    //skip blank lines
                    if (line.trim().length() > 0) {
                        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);
                    }
                }
            }
            /*
             * Get an output file name and create the new 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);


            /*
             * 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();
            /*
             * The Shapefile format has a couple limitations:
             * - "the_geom" is always first, and used for the geometry attribute name
             * - "the_geom" must be of type Point, MultiPoint, MuiltiLineString, MultiPolygon
             * - Attribute names are limited in length
             * - Not all data types are supported (example Timestamp represented as Date)
             *
             * Each data store has different limitations so check the resulting SimpleFeatureType.
             */
            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();
                }
    //            success!
                System.exit(0);
            } else {
                System.out.println(typeName + " does not support read/write access");
                System.exit(1);
            }
        }


        /**
         * Prompt the user for the name and path to use for the output shapefile
         *
         * @param csvFile the input csv file used to create a default shapefile name
         * @return name and path for the shapefile as a new File object
         */
        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;
        }

        public static void main(String[] args) throws Exception {
            csv2Shape();
        }

    }



  • 运行该代码,会弹出对话框,需要你选择下载并解压后的 location.csv 文件

    从shp文件读取要素集

       /**
         * 获取shp几何对象集合
         *
         * @param fileUrl 文件地址
         * @return 几何集合
         */
        public static List<Geometry> getGeometryList(String fileUrl) throws IOException {
            List<Geometry> geometryList = new ArrayList<>();
            ShapefileReader r = null;
            try {
                r = new ShapefileReader(new ShpFiles(fileUrl), false, false, new GeometryFactory());
                while (r.hasNext()) {
                    Geometry shape = (Geometry) r.nextRecord().shape();
                    ShapeType shapeType = r.getHeader().getShapeType();
                    double x1 = r.getHeader().maxX();
                    double y1 = r.getHeader().maxY();
                    double x2 = r.getHeader().minX();
                    double y2 = r.getHeader().minY();

                    geometryList.add(shape);
                }
            } catch (Exception e) {
                if (r != null) {
                    r.close();
                }
                e.printStackTrace();
            }

            return geometryList;
        }

    运行结果如下:

  •