我家的那条河
前言
最近工作上需要用到geotools工具进行开发,发现资料真的少得可怜,可能很少人用吧。后来发现这个工具类对于简单的地理信息处理还是蛮厉害,高难度(缝隙检测、道路线压盖面之类,这些可以用arcpy或者ArcEngine)的就压根没有对应的api了。本着既然用过了就总结一下,万一以后遇到就直接可以用了呗。
正文
1、 从shp文件读取要素集
这里主要是针对shp文件,操作类似于Java连接数据库,比如mybatis的sqlSession
/**
* 获取源shp的要素
*/
private SimpleFeatureStore getSFeatureSource(String layerShpPath) {
try {
String path = layerShpPath + ".shp";
File file = new File(path);
if (file.exists()) {
Map params = new HashMap();
params.put("url", file.toURI().toURL());
for (Iterator i = DataStoreFinder.getAvailableDataStores(); i.hasNext(); ) {
DataStoreFactorySpi factory = (DataStoreFactorySpi) i.next();
if (factory.canProcess(params)) {
//获取到shp数据源
DataStore dataStore = factory.createNewDataStore(params);
// 设置编码后可以正确读取
((ShapefileDataStore) dataStore).setCharset(Charset.forName("GBK"));
//根据图层名称来获取要素的source
SimpleFeatureStore featureSource = (SimpleFeatureStore) dataStore.getFeatureSource(dataStore.getTypeNames()[0]);
return featureSource;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2、输出要素到shp文件
输出文件就相当于我们平时定义好自己的表结构,然后获取连接数据库的连接,将表数据插入到shp文件中。
/**
* 获取到输出的ds
*
* @param targetFilePath
* @param sourceSchema 指定表映射
* @return
* @throws IOException
*/
public static ShapefileDataStore getOutputDataStore(String targetFilePath, SimpleFeatureType sourceSchema) {
try {
File targetFile = new File(targetFilePath);
if (!targetFile.exists()) {
targetFile.createNewFile();
}
Map<String, Serializable> params1 = new HashMap<String, Serializable>();
params1.put(ShapefileDataStoreFactory.URLP.key, targetFile.toURI().toURL());
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params1);
// create new schema
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName(sourceSchema.getName());
builder.setSuperType((SimpleFeatureType) sourceSchema.getSuper());
//自定义字段名
builder.add("rowId", Integer.class);
builder.add("ruleId", Integer.class);
builder.add("sId", String.class);
builder.add("curFld", String.class);
builder.add("curVal", String.class);
builder.add("refLayCode", String.class);
builder.add("refLayer", String.class);
builder.add("errDesc", String.class);
builder.add(sourceSchema.getDescriptor("the_geom"));
SimpleFeatureType nSchema = builder.buildFeatureType();
ds.createSchema(nSchema);//将图层表头设置给target shape
ds.setCharset(Charset.forName("GBK"));
return ds;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
3、获取要素字段属性
获取shp文件的字段属性可以通过getSchema().getAttributeDescriptors()
来完成。
List<AttributeDescriptor> attrList = sourceFeatureStore.getSchema().getAttributeDescriptors();
for (AttributeDescriptor attr : attrList) {
//字段名
String fieldName = attr.getLocalName();
//字段类型
String typeName = attr.getType().getBinding().getSimpleName();
//字段限制
String restr = attr.getType().getRestrictions().toString();
}
4、遍历要素集
这里的遍历是用迭代器来实现的,所以务必记得遍历完之后需要关闭数据连接,不然会报警告的。
SimpleFeatureCollection features = sourceFeatureStore.getFeatures();
SimpleFeatureIterator iterator = features.features();
while (iterator .hasNext()) {
SimpleFeature next = iterator.next();
Object geom = next.getAttribute(geometryPropertyName);
}
iterator.close();
5、按条件查询要素集
这里类似于mybatis的查询数据库,这里可以实现空间检索,也就是说通过经纬度图形,可以找到与它有相交的周边的所有要素。
Object geom = feature.getAttribute(geometryPropertyName);
Geometry geometry = reader.read(geom.toString());
Geometry boundary = geometry.getBoundary();
Filter filter = ff.intersects(ff.property(geometryPropertyName), ff.literal(boundary));
SimpleFeatureCollection features = sourceFeatureStore.getFeatures();
SimpleFeatureIterator iterator = features.features();
while (iterator.hasNext()) {
SimpleFeature next = iterator.next();
Object geom = next.getAttribute(geometryPropertyName);
}
6、构建或获取要素几何图形
一、SimpleFeatureBuilder方式创建
//创建GeometryFactory工厂
GeometryFactory geometryFactory = new GeometryFactory();
SimpleFeatureCollection collection =null;
//获取类型
SimpleFeatureType TYPE = featureSource.getSchema();
System.out.println(TYPE);
//创建要素集合
List<SimpleFeature> features = new ArrayList<>();
//创建要素模板
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
//创建要素并添加道集合
double latitude = Double.parseDouble("39.9");
double longitude = Double.parseDouble("116.3");
String name ="beijing";
int number = Integer.parseInt("16");
//创建一个点geometry
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
//添加的数据一定按照SimpleFeatureType给的字段顺序进行赋值
//添加name属性
featureBuilder.add(name);
//添加number属性
featureBuilder.add(number);
//添加geometry属性
featureBuilder.add(point);
//构建要素
SimpleFeature feature = featureBuilder.buildFeature(null);
Note:featureBuilder添加的数据一定按照SimpleFeatureType给的字段顺序进行赋值!!!!!!!!!!
二、getFeatureWriter方式创建
SimpleFeatureSource featureSource = null;
//根据图层名称来获取要素的source
featureSource = shpDataStore.getFeatureSource (typeName);
//根据参数创建shape存储空间
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
SimpleFeatureType sft = featureSource.getSchema();
//创建要素模板
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
//设置坐标系
tb.setCRS(DefaultGeographicCRS.WGS84);
tb.setName("shapefile");
//创建
ds.createSchema(tb.buildFeatureType());
//设置编码
ds.setCharset(charset);
//设置Writer,并设置为自动提交
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
//循环写入要素
while (itertor.hasNext())
{
//获取要写入的要素
SimpleFeature feature = itertor.next();
//将要写入位置
SimpleFeature featureBuf = writer.next();
//设置写入要素所有属性
featureBuf.setAttributes(feature.getAttributes());
//获取the_geom属性的值
Geometry geo =(Geometry) feature.getAttribute("the_geom");
Geometry geoBuffer = geoR.calBuffer(geo, 0.1);
System.out.println(geoBuffer);
//重新覆盖the_geom属性的值,这里的geoBuffer必须为Geometry类型
featureBuf.setAttribute("the_geom", geoBuffer);
}
//将所有数据写入
writer.write();
//关闭写入流
writer.close();
itertor.close();
}
catch(Exception e){
e.printStackTrace();
}
总结:
两种都差不多,个人感觉第二种方式创建更为灵活一点,关于第一种必须保证写入字段的Value的顺序,第二种是采用Key,value方式更为保险安全,第一种可读性更为好点。
7、获取几何图形边界
没啥好讲的,就是为了直接掉API
Geometry geometry = reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");
Geometry boundary = geometry.getBoundary();
8、JWT几何关系
几何信息和拓扑关系是地理信息系统中描述地理要素的空间位置和空间关系的不可缺少的基本信息。其中几何信息主要涉及几何目标的坐标位置、方向、角度、距离和面积等信息,它通常用解析几何的方法来分析。而空间关系信息主要涉及几何关系的“相连”、“相邻”、“包含”等信息,它通常用拓扑关系或拓扑结构的方法来分析。拓扑关系是明确定的
几何关系 | 说明 |
---|---|
相等(Equals): | 几何形状拓扑上相等。 |
脱节(Disjoint): | 几何形状没有共有的点。 |
相交(Intersects): | 几何形状至少有一个共有点(区别于脱节) |
接触(Touches): | 几何形状有至少一个公共的边界点,但是没有内部点。 |
交叉(Crosses): | 几何形状共享一些但不是所有的内部点。 |
内含(Within): | 几何形状A的线都在几何形状B内部。 |
包含(Contains): | 几何形状B的线都在几何形状A内部(区别于内含) |
重叠(Overlaps): | 几何形状共享一部分但不是所有的公共点,而且相交处有他们自己相同的区域。 |
package com.mapbar.geo.jts;
import org.geotools.geometry.jts.JTSFactoryFinder;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
/**
* Class GeometryRelated.java
* Description 二元比较集合。二元比较以两个几何对象作为参数,返回一个Boolean类型的值,
* 来指明这两个几何对象是否具有指定的空间关系。支持的空间关系包括:
* equals、disjoint、intersects, touches, crosses, within, contains, overlaps
*/
public class GeometryRelated {
private GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
public Point createPoint(String lon,String lat){
Coordinate coord = new Coordinate(Double.parseDouble(lon), Double.parseDouble(lat));
Point point = geometryFactory.createPoint( coord );
return point;
}
/**
* will return true as the two line strings define exactly the same shape.
* 两个几何对象是否是重叠的
* @return
* @throws ParseException
*/
public boolean equalsGeo() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
LineString geometry2 = (LineString) reader.read("LINESTRING(5 0, 0 0)");
// return geometry1 ==geometry2; false
//check if two geometries are exactly equal; right down to the coordinate level.
// return geometry1.equalsExact(geometry2); false
return geometry1.equals(geometry2);//true
}
/**
* The geometries have no points in common
* 几何对象没有交点(相邻)
* @return
* @throws ParseException
*/
public boolean disjointGeo() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
LineString geometry2 = (LineString) reader.read("LINESTRING(0 1, 0 2)");
return geometry1.disjoint(geometry2);
}
/**
* The geometries have at least one point in common.
* 至少一个公共点(相交)
* @return
* @throws ParseException
*/
public boolean intersectsGeo() throws ParseException{
WKTReader reader = new WKTReader( geometryFactory );
LineString geometry1 = (LineString) reader.read("LINESTRING(0 0, 2 0, 5 0)");
LineString geometry2 = (LineString) reader.read("LINESTRING(0 0, 0 2)");
Geometry interPoint = geometry1.intersection(geometry2);//相交点
System.out.println(interPoint.toText());//输出 POINT (0 0)
return geometry1.intersects(geometry2);
}
/**
* @param args
* @throws ParseException
*/
public static void main(String[] args) throws ParseException {
GeometryRelated gr = new GeometryRelated();
System.out.println(gr.equalsGeo());
System.out.println(gr.disjointGeo());
System.out.println(gr.intersectsGeo());
}
}
9、Geotools创建Feature的两种方式
一、SimpleFeatureBuilder方式创建
//创建GeometryFactory工厂
GeometryFactory geometryFactory = new GeometryFactory();
SimpleFeatureCollection collection =null;
//获取类型
SimpleFeatureType TYPE = featureSource.getSchema();
System.out.println(TYPE);
//创建要素集合
List<SimpleFeature> features = new ArrayList<>();
//创建要素模板
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
//创建要素并添加道集合
double latitude = Double.parseDouble("39.9");
double longitude = Double.parseDouble("116.3");
String name ="beijing";
int number = Integer.parseInt("16");
//创建一个点geometry
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
//添加的数据一定按照SimpleFeatureType给的字段顺序进行赋值
//添加name属性
featureBuilder.add(name);
//添加number属性
featureBuilder.add(number);
//添加geometry属性
featureBuilder.add(point);
//构建要素
SimpleFeature feature = featureBuilder.buildFeature(null);
Note:featureBuilder添加的数据一定按照SimpleFeatureType给的字段顺序进行赋值!!!!!!!!!!
二、getFeatureWriter方式创建
SimpleFeatureSource featureSource = null;
//根据图层名称来获取要素的source
featureSource = shpDataStore.getFeatureSource (typeName);
//根据参数创建shape存储空间
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
SimpleFeatureType sft = featureSource.getSchema();
//创建要素模板
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
//设置坐标系
tb.setCRS(DefaultGeographicCRS.WGS84);
tb.setName("shapefile");
//创建
ds.createSchema(tb.buildFeatureType());
//设置编码
ds.setCharset(charset);
//设置Writer,并设置为自动提交
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
//循环写入要素
while (itertor.hasNext())
{
//获取要写入的要素
SimpleFeature feature = itertor.next();
//将要写入位置
SimpleFeature featureBuf = writer.next();
//设置写入要素所有属性
featureBuf.setAttributes(feature.getAttributes());
//获取the_geom属性的值
Geometry geo =(Geometry) feature.getAttribute("the_geom");
Geometry geoBuffer = geoR.calBuffer(geo, 0.1);
System.out.println(geoBuffer);
//重新覆盖the_geom属性的值,这里的geoBuffer必须为Geometry类型
featureBuf.setAttribute("the_geom", geoBuffer);
}
//将所有数据写入
writer.write();
//关闭写入流
writer.close();
itertor.close();
}
catch(Exception e){
e.printStackTrace();
}
总结:
两种都差不多,个人感觉第二种方式创建更为灵活一点,关于第一种必须保证写入字段的Value的顺序,第二种是采用Key,value方式更为保险安全,第一种可读性更为好点。
参考文章
https://blog.csdn.net/weixin_40184249/article/details/84480652
http://www.aiuxian.com/article/p-455672.html