技术研究之Geotools

标签: 无 分类: 未分类 创建时间:2024-01-16 04:51:09 更新时间:2024-11-23 02:04:26

前沿

在java中使用 geotool 工具,首先就是要先把这个依赖下载下来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 <!-- geotools-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>${geotools-version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>${geotools-version}</version>
</dependency>
<!-- geotools-geojson核心包 -->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson-core</artifactId>
<version>${geotools-version}</version>
</dependency>
<dependency>
<groupId>org.geotools.xsd</groupId>
<artifactId>gt-xsd-kml</artifactId>
<version>${geotools-version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools-version}</version>
</dependency>


<repositories>
<repository>
<id>osgeo</id>
<name>Open Source Geospatial Foundation Repository</name>
<url>https://repo.osgeo.org/repository/release/</url>
</repository>
<repository>
<id>osgeo-snapshot</id>
<name>OSGeo Snapshot Repository</name>
<url>https://repo.osgeo.org/repository/snapshot/</url>
</repository>
</repositories>

参考文章:
【1】.填坑:Maven工程引用GeoTools依赖 将GeoTools对应的编译版本下载下来,并利用《填坑:IDEA导入Maven工程无法下载依赖项》方法,将依赖的jar包注册到本地仓库中。如果你配置了阿里的镜像,可以在自己的maven配置文件修改一下,直接从GeoTools的远程库中下载。
【2】.GeoTools依赖使用Maven下载失败解决办法记录 方法一:直接去官网下载,然后手动拷贝到本地仓库对应位置,然后点击idea中右侧的重新加载maven项目。方法二(推荐):在pom.xml中加入osgeo的仓库地址(注意setting中阿里云镜像的参数应为central):方法三:在Maven的settings.xml中阿里镜像同级位置添加osgeo仓库地址,(osgeo-snapshot、GeoSolutions也可参考下面的方法,此方法貌似不对,但是能解决一部分人jar下载失败的问题)

1.kml转geojson

为了将 kml 转成 geojson ,我用了这两个库,结果就是很多的问题,首先就是引入的问题。

2.shape转geojson

3.通过坐标点生成LineString

4.生成缓冲区

根据 geojson 格式的线数据,生成缓冲区,经过长时间的尝试,最后我还是搞定了代码,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 创建buffer
private String createBuff(String xcgj){
StringWriter writer=new StringWriter();
try {
GeoJSONReader reader=new GeoJSONReader(xcgj);
SimpleFeatureCollection featureCollection = reader.getFeatures();

// 要素类型
SimpleFeatureType featureType = DataUtilities.createType("MultiPolygon",
"the_geom:MultiPolygon:srid=4326," +
"name:String");

// 遍历要素进行处理
SimpleFeatureIterator features = featureCollection.features();
List<SimpleFeature> targetFeatures=new ArrayList<>();
while (features.hasNext()) {
SimpleFeature feature = features.next();
// 获取要素几何图形
Geometry defaultGeometry =(Geometry) feature.getDefaultGeometry();
// 生成缓冲区
Geometry buff=defaultGeometry.buffer(buff_distance);
// 创建 feature 工厂
SimpleFeatureBuilder featureBuilder=new SimpleFeatureBuilder(featureType);
// 新建feature
SimpleFeature buffFeature=featureBuilder.buildFeature(feature.getID());
// 添加全部的属性,这个其实没有用
buffFeature.setAttributes(feature.getAttributes());
// 设置图形
buffFeature.setDefaultGeometry(buff);
// 加入最后的要素集合
targetFeatures.add(buffFeature);
}
// 要素集迭代器用完记得关闭
features.close();
// 将新生成的 featureCoolection 转为 GeoJSON
SimpleFeatureCollection targetCollection=new ListFeatureCollection(featureType,targetFeatures);
FeatureJSON featureJSON=new FeatureJSON();
featureJSON.writeFeatureCollection(targetCollection,writer);
}catch (Exception e){
log.error("createBuff",e);
}
return writer.toString();
}

这里有一个问题,如果线有交叉的时候,生成的buffer就会出现空洞的情况,但是在arcgis中却没有产生空洞。

最后我还是用了一个 凸壳分析 (ConvexHull),将这个破洞补上了。

1
2
3
4
// 生成缓冲区
Geometry buff=defaultGeometry.buffer(buff_distance);
// 为了解决空洞的问题,取最小外包矩形。
buff=buff.convexHull();
参考文章:
【1】.GeoTools解析GeoJson为要素集(FeatureCollection)含嵌套数组属性 这里有所有的要素类型,遍历要素属性,获取指定属性信息功能。
【2】.gis地理数据处理:geotools将多个线段生成buffer并融合成多边形 这里使用 geometry.buffer(distance) 创建了buffer。
【3】.读写shp等空间数据,进行geometry、SimpleFeature等转换的工具类 这里有 simplefeature 转为 geometry 的方法
【4】.【geotool】wkt、geojson、geometry互相转换
【5】.GeoTools 构建线的缓冲区 BufferOp bufOp = new BufferOp(gfLineString)
【6】.Geotools创建Feature的两种方式 1.SimpleFeatureBuilder方式创建;2.getFeatureWriter方式创建;
【7】.【geotools随笔】FeatureType的创建与修改 这里我参考了 DataUtilities.createType 的创建。
【8】.GeoTools:Shapefile创建 这里其实也有 SimpleFeatureType 接口的说明。ShapefileDataStoreFactory类、ShapefileDataStore类、创建Shapefile文件实示例
【9】.计算JTS缓冲区面积(Java)
【10】.JTS (Java Topology Suite) 开发教程 联合分析 (Union)、凸壳分析 (ConvexHull)、差异分析 (Difference)、对称差异分析 (SymDifference)、构建不规则三角网 (TIN)、几何体致密化 (Densify)
【11】.JTS的buffer支持CAP的样式
【12】.JTS Geometry Operations(二) Buffer,返回的结果是一个Polygon或者 MultiPolygon,注意:bufOp.setEndCapStyle 缓冲样式的设置,总共有三种CAP_ROUND,CAP_BUTT,CAP_SQUARE 对应如下三种情况

5.计算面积

计算面积的方法很简单,就是使用 getArea() 方法获取面积

1
2
3
Geometry defaultGeometry =(Geometry) feature.getDefaultGeometry();
defaultGeometry.setSRID(4326);
result=defaultGeometry.getArea();

计算投影坐标系,就是将 4326 的坐标系转为了 3857 坐标系,然后计算了面积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 方法一
*/
Geometry defaultGeometry =(Geometry) feature.getDefaultGeometry();
defaultGeometry.setSRID(4326);

// 这里是以OGC WKT形式定义的是World Mercator投影,网页地图一般使用该投影
final String strWKTMercator = "PROJCS[\"World_Mercator\","
+ "GEOGCS[\"GCS_WGS_1984\","
+ "DATUM[\"WGS_1984\","
+ "SPHEROID[\"WGS_1984\",6378137,298.257223563]],"
+ "PRIMEM[\"Greenwich\",0],"
+ "UNIT[\"Degree\",0.017453292519943295]],"
+ "PROJECTION[\"Mercator_1SP\"],"
+ "PARAMETER[\"False_Easting\",0],"
+ "PARAMETER[\"False_Northing\",0],"
+ "PARAMETER[\"Central_Meridian\",0],"
+ "PARAMETER[\"latitude_of_origin\",0],"
+ "UNIT[\"Meter\",1]]";
CoordinateReferenceSystem mercatroCRS = CRS.parseWKT(strWKTMercator);
// 做投影转换,将WCG84坐标转换成世界墨卡托投影转
MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, mercatroCRS);
defaultGeometry= JTS.transform(defaultGeometry, transform);
double area=defaultGeometry.getArea();


/**
* 方法二
*/
CoordinateReferenceSystem source = null;
source = CRS.decode("CRS:84");
CoordinateReferenceSystem target = null;
target = CRS.decode("EPSG:3857");
MathTransform transform = null;
transform = CRS.findMathTransform(source, target, true);
Geometry transformGeom= null;
transformGeom = JTS.transform(defaultGeometry, transform);
double area = transformGeom.getArea();

/**
* 方法三,这里的代码有些问题
*/
CoordinateReferenceSystem srcCRS = CRS.decode("EPSG:4326");
CoordinateReferenceSystem crsTarget = CRS.decode("EPSG:3857");
// 投影转换
MathTransform transform = CRS.findMathTransform(crsTarget,srcCRS,true);
Geometry res = JTS.transform(defaultGeometry, transform);
double area=defaultGeometry.getArea();
参考文章:
【1】.java geotools 计算面积 这里直接用 polygon.getArea() 计算的面积。
【2】.利用geoTools计算shp面积
【3】.GIS面积计算
【4】.根据wkt或geometry计算面积(平方米) 这里进行了投影转换,将84坐标转为了3857坐标。
【5】.经纬度坐标和投影坐标的转换
【6】.geotools之坐标转换
【7】.利用geoTools计算shp面积 这里也做了一个坐标变换,使用了shp文件坐标系,转为了 3857 坐标系。
【8】.Class Geometry

6.合并多边形

这里我是将多个 geomtry 合并到一个 list 中,然后进行合并的。这些 geomtry 可能相邻,也可能不相邻。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 try{
Geometry[] geos= xcfwGeomList.toArray(new Geometry[xcfwGeomList.size()]);
GeometryFactory geometryFactory = new GeometryFactory();
GeometryCollection geometryCollection = geometryFactory.createGeometryCollection(geos);
Geometry resultGeom=geometryCollection.union();

// 转为Feature
SimpleFeatureType featureType = DataUtilities.createType("MultiPolygon",
"the_geom:MultiPolygon:srid=4326," +
"name:String");
SimpleFeatureBuilder featureBuilder=new SimpleFeatureBuilder(featureType);
SimpleFeature buffFeature=featureBuilder.buildFeature("10000");
buffFeature.setDefaultGeometry(resultGeom);
StringWriter writer = new StringWriter();
writer.append("{\"type\": \"FeatureCollection\",\"features\":[");
FeatureJSON geojson = new FeatureJSON();
geojson.writeFeature(buffFeature, writer);
writer.append("]}");
// 保存结果
result.put("buffer",writer.toString());
}catch (Exception e){
log.error("getReport",e);
}
参考文章:
【1】.使用Geotools合并多个Geometry成一个图形 1.在geometry数量少的情况下可以直接循环调用geometry的union方法。2.在geometry数量比较多的时候用上面的方法会比较耗时,可以改用GeometryCollection进行合并。
【2】.java List和数组相互转换方法 这是arraylist转换的方法
【3】.GeoTools测试几何合并union 这里有相邻和不相邻的图形合并。
【4】.Geotools中Geometry对象与GeoJson的相互转换
【5】.Java将WKT格式的Geomotry转换成GeoJSON
【6】.JTS-Geometry使用说明 创建多边形:GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();

7.抽稀

自带了抽稀算法,不一定好用。

1
2
3
4
5
Geometry polyline=new GeometryFactory().createLineString(polygonCoordinateList.toArray(new Coordinate[0]));

// 进行抽稀,距离为 5 米
double distance=5*200/Math.PI/6371000;
polyline=DouglasPeuckerSimplifier.simplify(polyline,distance);
参考文章:
【1】.使用Java对轨迹进行抽稀,并生成mvt(Map Vector Tile)瓦片 这里有两种方法,一种就是使用jts算法,一种是自己实现了的道格拉斯算法。
【2】.JTS-Java图形拓扑学习笔记 没啥用
【3】.简化面 arcgis 简化面操作

8.geojson转为shp

采用参考文章1中的代码,基本上都可以实现,我遇到的问题:class org.geotools.data.directory.DirectoryDataStore cannot be cast to class org.geotools.data.shapefile.ShapefileDataStore (org.geotools.data.directory.DirectoryDataStore and org.geotools.data.shapefile.ShapefileDataStore are in unnamed module of loader ‘app’).

【解决方案】
这个问题的解决方案,就是不要传入一个路径,而是应该传入一个以 .shp 文件结尾的文件。

参考文章:
【1】.使用GeoTools进行GeoJSON和Shp的互相转换
【2】.SpatialDataTransformUtil.java 这里的代码可以用,没有关系,基本上都能用。
【3】.JAVA 超详细 将文件夹目录打包为 ZIP 压缩包并下载
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。