美文网首页geotoolsgeotoolsgeotools
geotools学习(二)要素

geotools学习(二)要素

作者: MrSwilder | 来源:发表于2019-10-28 11:17 被阅读0次

    要素教程

    欢迎

    您应该在运行本工作簿之前完成GeoTools的快速入门。我们需要确保您有一个使用GeoTools jar及其所有依赖项的环境。对于那些只使用maven的,我们将在每个部分开始时提供所需的依赖项
    本工作簿采用了一种新的“代码优先”方法。我们已经尽了一切努力使这些例子既可视化又以代码为中心。我们已经包括了一些背景材料,解释了概念和想法,如果你感兴趣

    CSV2SHP

    我们今年正在尝试引入新功能;我们将从从头开始构建一个shapefile开始,这样您就可以看到创建特性的每一个细节,而不是阅读一个shapefile并在一个人工练习中将其分解。

    教程包含以下内容:
        1.创建一个FeatureType, FeatureCollection 和Features
        2.使用GeometryFactory来构建点
        3.输出一个shapefile文件
        4.投影
    

    在本教程的最后,您将能够创建自己的自定义shapefile。

    csv数据

    1.创建一个txt文件并拷贝下面数据进去

    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,2016
    

    2.或者下载 locations.csv.
    3.添加一些其他的点,如你的家乡

    依赖

    请确保您的pom.xml包含以下内容:

    <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>maven2-repository.dev.java.net</id>
              <name>Java.net repository</name>
              <url>http://download.java.net/maven/2</url>
          </repository>
          <repository>
              <id>osgeo</id>
              <name>Open Source Geospatial Foundation Repository</name>
              <url>http://download.osgeo.org/webdav/geotools/</url>
          </repository>
          <repository>
            <snapshots>
              <enabled>true</enabled>
            </snapshots>
            <id>boundless</id>
            <name>Boundless Maven Repository</name>
            <url>http://repo.boundlessgeo.com/main</url>
          </repository>
      </repositories>
    

    注意,上面提到的jar将引入大量其他依赖项(例如hsql数据库驱动程序)

    主程序

    1.请创建一个包org.geotools.tutorial.feature 和类 Csv2Shape.java .
    2.粘贴复制下面代码

    package org.geotools.tutorial.feature;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.swing.UIManager;
    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.simple.SimpleFeatureBuilder;
    import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
    import org.geotools.geometry.jts.JTSFactoryFinder;
    import org.geotools.referencing.crs.DefaultGeographicCRS;
    import org.geotools.swing.data.JFileDataStoreChooser;
    import org.locationtech.jts.geom.Coordinate;
    import org.locationtech.jts.geom.GeometryFactory;
    import org.locationtech.jts.geom.Point;
    import org.opengis.feature.simple.SimpleFeature;
    import org.opengis.feature.simple.SimpleFeatureType;
    
    /**
     * 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.
     */
    public class Csv2Shape {
    
        public static void main(String[] args) throws Exception {
            // Set cross-platform look & feel for compatability
            UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
    
            File file = JFileDataStoreChooser.showOpenFile("csv", null);
            if (file == null) {
                return;
            }
    

    现在,我们将在小节中查看主要方法的其余部分

    创建一个FeatureType

    根据csv中的数据创建一个FeatureType并写入shapefile
    这是DataUtilities 类

     /*
             * 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);
    
    创建features

    我们现在可以读取CSV文件并为每个记录创建一个特性。请注意以下事项:
    1.使用GeometryFactory创建新点
    2.使用SimpleFeatureBuilder创建特性(SimpleFeature对象)

      * 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()) {
                    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);
                    }
                }
            }
    
    从要素集中创建一个shapefile

    注意点:
    1.使用DataStoreFactory和一个参数来表示我们需要一个空间索引
    2.使用createSchema(SimpleFeatureType)方法来设置shapefile(我们将在下一节中创建getNewShapeFile方法)

      /*
             * 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);
    
    把要素写入shapefile文件中

    注意事项:
    1.通过确认FeatureSource对象实现了FeatureStore方法,我们可以检查是否具有读写访问权限
    2.花点时间检查一下shapefile与我们的模板(SimpleFeatureType类型)的匹配程度。比较这个输出,看看它们有什么不同
    3.我们使用的SimpleFeatureStore需要一个FeatureCollection 对象,因此我们将特性列表包装在ListFeatureCollection中
    4.使用transaction.commit()可以一次安全地写出这些特性

       /*
             * 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();
                }
                System.exit(0); // success!
            } else {
                System.out.println(typeName + " does not support read/write access");
                System.exit(1);
            }
        }
    

    这就完成了主方法。

    提示输出shapefile

    这个方法提示用户选择shapefile输出位置,文件名为csv的文件名

    /**
         * 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;
        }
    
    运行程序

    当你运行程序时,会提醒你:
    1.选择csv文件的位置
    2.选择输出的shp文件的位置

    另外尝试

    另一种构建SimpleFeatureType的方法
    尽管上面使用的DataUtilities 类提供了一种快速且简单的方法来构建一个简单的featuretype。对于任何实际的应用程序,您都希望使用更灵活的SimpleFeatureTypeBuilder。
    下面是如何使用SimpleFeatureTypeBuilder来完成相同的结果:

       /**
         * Here is how you can use a SimpleFeatureType builder to create the schema for your shapefile
         * dynamically.
         *
         * <p>This method is an improvement on the code used in the main method above (where we used
         * DataUtilities.createFeatureType) because we can set a Coordinate Reference System for the
         * FeatureType and a a maximum field length for the 'name' field dddd
         */
        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;
        }
    

    注意使用大写常量来保存SimpleFeatureType。因为SimpleFeatureType类是不可变的,所以将它们作为最终变量进行跟踪可以帮助您记住,一旦创建它们,就不能修改它们。
    使用这个方法,我们的SimpleFeatureType包含一个CoordinateReferenceSystem,因此不需要调用forceSchemaCRS来生成.prj文件。另外,我们现在将Name字段限制为15个字符。

    其他尝试的

    1.修改代码从数据文件头读取特征属性名,而不是在应用程序中硬编码:

    LAT, LON, CITY, NUMBER
    

    您应该能够使用SimpleFeatureTypeBuilder。
    2.使用几何缓冲区方法创建基于每个城市的人口规模的圆圈

    Polygon polygon = location.buffer( 0.1 );
    

    3.:编写一个快速的CSVReader很容易,就像我们在这里所做的;但要写出一篇能够正确处理引号的好文章就比较难了。JavaCSV是一个开放源码库,用于读取带有各种选项的CSV文件
    4.为了快速找到相关依赖,我们可以访问 http://mvnrepository.com/.
    这样的站点将直接提供一个maven依赖项,您可以将其剪切并粘贴到pom.xml中。

    <dependency>
      <groupId>net.sourceforge.javacsv</groupId>
      <artifactId>javacsv</artifactId>
      <version>2.0</version>
    </dependency>
    

    5.使用相同的技术从其他结构化文件格式(如GeoJson)的数据创建shapefile
    6.地球刚刚经历了一场流星风暴——在全球范围内产生了100个不同大小的圆。你的城市看到了吗?
    从模型或分析中生成一个shapefile是一种常见的用法。
    7.读一下shapefile支持的其他几何类:线性特征的MultiLineString和区域特征的MultiPolygon,然后修改这个例子来使用它们

    Feature

    Feature是可以画在地图上的东西。严格的定义是,一个特征是现实世界中的东西——风景的特征——珠穆朗玛峰,埃菲尔铁塔,甚至是像你的大姨妈爱丽丝那样四处走动的东西。
    向Java开发人员解释这个概念很容易——特性就是对象。

    与java对象一样,特性可以包含一些关于它们所代表的真实世界的信息。这些信息被组织到属性中,就像Java信息被组织到字段中一样。

    时你有两个有很多共同点的特征。洛杉矶的LAX机场和悉尼的SYD机场。因为这两个特性有一些共同点,所以最好将它们组合在一起——在Java中,我们将创建一个名为Airport的类。在地图上,我们将创建一个名为Airport的功能类型。

    尽管Java不支持它,但早期的编程语言使用了一个原型系统(而不是类系统),它支持许多“一次性”对象。你会发现这种情况在绘制地图时相当普遍——因为埃菲尔铁塔有多少座?你偶尔也会发现相同的现实世界的事物以不同的方式表现出来(埃菲尔铁塔可以是一个地标,也可以是一座塔,这取决于背景)。

    这里有一个方便的备忘单:


    image.png

    特性模型实际上比我们Java程序员习惯的要疯狂一点,因为它认为属性和操作都是特性的“属性”。也许,当Java获得闭包时,我们就可以迎头赶上了

    对我来说,真正有趣的事情是,地图制作者们早在15世纪就开始整理这些东西了,而且他们也变得像现在的程序员一样极客。因此,尽管我们很乐意教他们关于面向对象编程的知识,但他们已经有了丰富的思想来描述这个世界。好的一面是,地图制作者开始使用UML图。

    FeatureClass

    在GeoTools中,我们有一个由GeoAPI项目提供的特性、特性类型和属性的接口。一般来说,GeoAPI提供了一个非常严格的接口,而GeoTools将提供一个类。


    image.png

    一个Feature 通常只有简单的属性(字符串、整数、日期等),而没有对其他特性或数据结构的引用,比如List<Date>。满足这一需求的Features 是如此常见,以至于我们创建了一个子类来表示它们,这个子类叫做SimpleFeature。

    在Java级别,GeoTools提供的特性API与Java .util类似。使用Map——它是一个用于保存信息的Java数据结构。您可以通过键查找属性值;键的列表是由FeatureType提供的。

    Geometry

    feature和object的另一个区别是,feature具有某种形式的位置信息(如果没有,我们就不能在地图上绘制它)。位置信息将由存储在属性中的几何图形(或形状)捕获。

    image.png

    我们利用JTS拓扑套件(JTS)来表示几何图形。JTS库提供了一种优秀的几何图形实现——并且因为拥有递归首字母缩写而获得极客的分数!JTS是一个令人惊奇的库,它提供了所有的硬图理论,让您以高效的方式处理几何。

    下面是一个使用文本(WKT)格式创建点的示例

    GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
    
    WKTReader reader = new WKTReader( geometryFactory );
    Point point = (Point) reader.read("POINT (1 1)");
    
    

    您还可以直接使用GeometryFactory手动创建一个点。

    GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
    
    Coordinate coord = new Coordinate( 1, 1 );
    Point point = geometryFactory.createPoint( coord );
    

    DataStore

    我们在《快速起步》中已经遇到了数据存储。DataStore API用于表示包含空间数据的文件、数据库或服务。该API有两个移动部分,如下所示。


    image.png

    FeatureSource用于读取features,而FeatureStore子类用于读写访问。

    判断一个文件是否可以在GeoTools中写入的方法是使用instanceof 检查

    String typeNames = dataStore.getTypeNames()[0];
    SimpleFeatureSource source = store.getfeatureSource( typeName );
    if( source instanceof SimpleFeatureStore){
       SimpleFeatureStore store = (SimpleFeatureStore) source; // write access!
       store.addFeatures( featureCollection );
       store.removeFeatures( filter ); // filter is like SQL WHERE
       store.modifyFeature( attribute, value, filter );
    }
    

    我们决定将写访问作为一个子类(而不是isWritable方法)来处理,以避免方法被使用。

    相关文章

      网友评论

        本文标题:geotools学习(二)要素

        本文链接:https://www.haomeiwen.com/subject/gmbvvctx.html