geotools shp文件读取,然后分片取出

最近有一个需求,需要去做大量空间数据的相交检验,如果每一个图形都去读取出来与剩下的图形去对比,太耗费时间和性能,一起做了很多不必要的相交。
为了稍微提升一些速度,借鉴了在空间数据处理分任务时的,片区划分的方法,将与一个片区的取出来单独处理,这样会减少单次数据处理的量。 而且避免了很多相隔较远的数据的也需要去做相交比对的这种必要的操作。

下面就将我的做法分享出来

1.先贴pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>gis_data_fragment</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>7</source>
                    <target>7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-main</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-opengis</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-metadata</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-referencing</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-epsg-hsql</artifactId>
            <version>28.2</version>
        </dependency>
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-swing</artifactId>
            <version>28.2</version>
        </dependency>



        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.locationtech.jts</groupId>
            <artifactId>jts-core</artifactId>
            <version>1.19.0</version>
        </dependency>

        <dependency>
            <groupId>si.uom</groupId>
            <artifactId>si-quantity</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>si.uom</groupId>
            <artifactId>si-units</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>si.uom</groupId>
            <artifactId>si-units-java8</artifactId>
            <version>0.7.1</version>
        </dependency>
        <dependency>
            <groupId>tech.units</groupId>
            <artifactId>indriya</artifactId>
            <version>2.0.4</version>
        </dependency>
        <dependency>
            <groupId>javax.measure</groupId>
            <artifactId>unit-api</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>tech.uom.lib</groupId>
            <artifactId>uom-lib-common</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>systems.uom</groupId>
            <artifactId>systems-common</artifactId>
            <version>2.0.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>



    </dependencies>
    <repositories>
        <repository>
            <id>osgeo</id>
            <name>Open Source Geospatial Foundation Repository</name>
            <url>https://repo.osgeo.org/repository/release/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>
   
</project>

2. shp 文件读取的方法 ,同时获取到数据的范围,方便后面计算分片

引入的jar包

import org.geotools.data.DefaultTransaction;
import org.geotools.data.FeatureStore;
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.SimpleFeatureIterator;
import org.geotools.data.store.ContentFeatureCollection;
import org.geotools.data.store.ContentFeatureSource;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.factory.FactoryFinder;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.operation.union.UnaryUnionOp;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.util.*;
// 地址就是这种  ./src/main/data/shp/pewg.shp,当然也可以直接选一个硬盘上的地址
//传入shp文件的地址,读取数据,获取数据范围
    private void readSHP(String url) {
        //创建一个file对象
        File file = new File(url);
        ReferencedEnvelope bounds = new ReferencedEnvelope();
        try {
            ShapefileDataStore dataStore = new ShapefileDataStore(file.toURI().toURL());
            ContentFeatureSource featureSource = dataStore.getFeatureSource();
            ContentFeatureCollection features = featureSource.getFeatures();
            SimpleFeatureIterator featureIterator = features.features();

            //创建一个shp文件中的所有MultiPolygon的集合
            ArrayList<MultiPolygon> multiPolygons = new ArrayList<>();

           
            while (featureIterator.hasNext()) {
                SimpleFeature feature = featureIterator.next();
                multiPolygons.add((MultiPolygon) feature.getDefaultGeometry());
             }
            //1.获取数据范围
            bounds = featureSource.getBounds();
            //2.根据数据范围,进行数据分片,得到分片的分为
            Polygon[] polygons = partition(bounds, 15, 15);//对shp范围进行分区
            //3.将分片与数据相交,得到每一小片相交的数据
            dataIntersectionDetection(polygons, multiPolygons);
            // polygonsAddToSHP(polygons); // 将切片图形写入shp文件
            dataStore.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.根据数据范围,计算分片的数量

/*
     *根据范围数据,计算分片
     * bounds: 范围
     * divisionsX:横向分割数
     * divisionsY: 纵向分割数
     * */
    private Polygon[] partition(ReferencedEnvelope bounds, int divisionsX, int divisionsY) throws IOException {
        //最大最小的经纬度点
        Coordinate bottomLeft = new Coordinate(
                keep9DecimalPlaces(bounds.getMinX()),
                keep9DecimalPlaces(bounds.getMinY())); // 左下角
        Coordinate topRight = new Coordinate(
                keep9DecimalPlaces(bounds.getMaxX()),
                keep9DecimalPlaces(bounds.getMaxY())); // 右上角
        double minX = bottomLeft.x;
        double minY = bottomLeft.y;
        double maxX = topRight.x;
        double maxY = topRight.y;

        //大矩形范围
        Coordinate[] rectangleRadius = {
                bottomLeft,
                new Coordinate(bottomLeft.x, topRight.y),
                topRight,
                new Coordinate(topRight.x, bottomLeft.y),
                bottomLeft
        };

        // 将大矩形横向和纵向划分为10等分和5等分
        int numDivisionsX = divisionsX;
        int numDivisionsY = divisionsY;

        // 存放划分好的小矩形的数组
        double[][][] dividedRectangles = new double[numDivisionsX][numDivisionsY][4];

        // 计算横向和纵向的步长
        double xStep = (maxX - minX) / numDivisionsX;
        double yStep = (maxY - minY) / numDivisionsY;

        // 划分大矩形并将每个小矩形的四个顶点坐标存放到数组中
        for (int i = 0; i < numDivisionsX; i++) {
            for (int j = 0; j < numDivisionsY; j++) {
                double x1 = (minX + i * xStep);
                double y1 = (minY + j * yStep);
                double x2 = (minX + (i + 1) * xStep);
                double y2 = (minY + (j + 1) * yStep);
                //dividedRectangles[i][j] = new double[]{x1, y1, x2, y2};
                dividedRectangles[i][j] = new double[]{
                        keep9DecimalPlaces(x1),
                        keep9DecimalPlaces(y1),
                        keep9DecimalPlaces(x2),
                        keep9DecimalPlaces(y2)
                };
            }
        }

        //将划分的小矩形添加到MultiPolygon中
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
        Polygon[] polygons = new Polygon[numDivisionsX * numDivisionsY];
        int index = 0;
        for (double[][] row : dividedRectangles) {
            for (double[] rectangle : row) {
                Coordinate[] coordinate = {
                        new Coordinate(rectangle[0], rectangle[1]),
                        new Coordinate(rectangle[2], rectangle[1]),
                        new Coordinate(rectangle[2], rectangle[3]),
                        new Coordinate(rectangle[0], rectangle[3]),
                        new Coordinate(rectangle[0], rectangle[1]),
                };
                Polygon polygon = geometryFactory.createPolygon(coordinate);
                polygons[index] = polygon;
                ++index;
            }
        }

        return polygons;
    }

4.将分片数据与原始数据进行相交,将每一片相交的元素数据存到一个集合中

/*
     * 将分片数据和原始数据传入方法
     * */
    private void dataIntersectionDetection(Polygon[] polygons, ArrayList<MultiPolygon> multiPolygons) throws IOException {
        // 将相交的数据存到一个大集合中
        ArrayList<ArrayList<MultiPolygon>> bigList = new ArrayList<>();

        for (int j = 0; j < polygons.length; j++) {
            //将每个相交的数据存到一个小集合
            ArrayList<MultiPolygon> smallList = new ArrayList<>();
            for (int m = 0; m < multiPolygons.size(); m++) {
                Polygon polygon = polygons[j];
                MultiPolygon multiPolygon = multiPolygons.get(m);
                boolean intersects = polygon.intersects(multiPolygon);// 是否相交
                if (intersects) {// 将相交的数据,保存到一个集合中
                    smallList.add(multiPolygon);
                }
            }
            bigList.add(smallList);
        }

        /*// 将分片相交好的数据写入shp文件
        for (int i = 0; i < bigList.size(); i++) {
            if (bigList.get(i).isEmpty()) {// 为空的数据不写入
                continue;
            }
            multiPolygonsAddToSHP(bigList.get(i), i);
        }*/
    }

最后在分享几个 将 图形数据 写入shp文件的方法,方便进行数据验证和查看

 //将多个Polygon添加到shp
    private void polygonsAddToSHP(Polygon[] polygons) throws IOException {
        // 创建Shapefile的DataStore
        File newFile = new File("src/main/data/shp/partition.shp");
        Map<String, Serializable> params = new HashMap<>();
        params.put("url", newFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);

        // 定义FeatureType
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.setName("Polygon");
        typeBuilder.setSRS("EPSG:4490");//设置坐标系
        typeBuilder.add("the_geom", Polygon.class); // 将数据写入shp文件中 一定要是 the_geom
        typeBuilder.add("num", Integer.class);//添加一个num 用于取数据
        SimpleFeatureType featureType = typeBuilder.buildFeatureType();

        // 将FeatureType写入DataStore
        dataStore.createSchema(featureType);

        // 开启事务
        Transaction transaction = new DefaultTransaction("create");

        // 获取FeatureStore
        String typeName = dataStore.getTypeNames()[0];
        FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);

        // 创建FeatureList
        List<SimpleFeature> featureList = new LinkedList<>();
        for (int i = 0; i < polygons.length; i++) {
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
            featureBuilder.add(polygons[i]);
            featureBuilder.add(i);
            SimpleFeature feature = featureBuilder.buildFeature(null);
            featureList.add(feature);
        }

        try {
            // 添加FeatureList到Shapefile
            ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, featureList);
            featureStore.setTransaction(transaction);
            featureStore.addFeatures(featureCollection);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
            dataStore.dispose();
        }

    }

    //将一个MultiPolygon添加到shp
    private void multiPolygonAddToSHP(MultiPolygon multiPolygon) throws IOException {
        // 创建Shapefile的DataStore
        File newFile = new File("src/main/data/shp/multiPolygon1.shp");
        Map<String, Serializable> params = new HashMap<>();
        params.put("url", newFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);

        // 定义FeatureType
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.setName("MultiPolygon");
        typeBuilder.setSRS("EPSG:4490");//设置坐标系
        typeBuilder.add("the_geom", MultiPolygon.class); // 将数据写入shp文件中 一定要是 the_geom
        //typeBuilder.add("num", Integer.class);//添加一个num 用于取数据
        SimpleFeatureType featureType = typeBuilder.buildFeatureType();

        // 将FeatureType写入DataStore
        dataStore.createSchema(featureType);

        // 开启事务
        Transaction transaction = new DefaultTransaction("create");

        // 获取FeatureStore
        String typeName = dataStore.getTypeNames()[0];
        FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);

        // 创建Feature
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
        featureBuilder.add(multiPolygon);
        SimpleFeature feature = featureBuilder.buildFeature(null);
        try {
            // 添加FeatureList到Shapefile
            ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, feature);
            featureStore.setTransaction(transaction);
            featureStore.addFeatures(featureCollection);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
            dataStore.dispose();
        }
    }

    // 将多个MultiPolygon添加到shp,生成多个shp
    private void multiPolygonsAddToSHP(ArrayList<MultiPolygon> multiPolygons, Integer num) throws IOException {
        // 创建Shapefile的DataStore
        File newFile = new File("src/main/data/shp/number/multiPolygons" + num + ".shp");
        Map<String, Serializable> params = new HashMap<>();
        params.put("url", newFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);

        // 定义FeatureType
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.setName("Polygon");
        typeBuilder.setSRS("EPSG:4490");//设置坐标系
        typeBuilder.add("the_geom", MultiPolygon.class); // 将数据写入shp文件中 一定要是 the_geom
        SimpleFeatureType featureType = typeBuilder.buildFeatureType();

        // 将FeatureType写入DataStore
        dataStore.createSchema(featureType);

        // 开启事务
        Transaction transaction = new DefaultTransaction("create");

        // 获取FeatureStore
        String typeName = dataStore.getTypeNames()[0];
        FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);

        // 创建FeatureList
        List<SimpleFeature> featureList = new LinkedList<>();
        for (int i = 0; i < multiPolygons.size(); i++) {
            SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
            featureBuilder.add(multiPolygons.get(i));
            SimpleFeature feature = featureBuilder.buildFeature(null);
            featureList.add(feature);
        }

        try {
            // 添加FeatureList到Shapefile
            ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, featureList);
            featureStore.setTransaction(transaction);
            featureStore.addFeatures(featureCollection);
            transaction.commit();
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
        } finally {
            transaction.close();
            dataStore.dispose();
        }
    }

    //将多个MultiPolygon合并为一个
    private MultiPolygon mergeMultiPolygons(List<MultiPolygon> multiPolygons) {
        // 合并的时间根据数据复杂程度,时间可能会长达几分钟。
        UnaryUnionOp unaryUnionOp = new UnaryUnionOp(multiPolygons);
        return (MultiPolygon) unaryUnionOp.union();
    }

    // 保留9位小数,经纬度保留9未小数,精度约为0.0001米=0.1毫米
    private double keep9DecimalPlaces(double d) {
        DecimalFormat df = new DecimalFormat("#.#########");
        return Double.parseDouble(df.format(d));
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容