
我家的那條河
前言
最近工作上需要用到geotools工具進(jìn)行開發(fā),發(fā)現(xiàn)資料真的少得可憐,可能很少人用吧。后來發(fā)現(xiàn)這個(gè)工具類對于簡單的地理信息處理還是蠻厲害,高難度(縫隙檢測、道路線壓蓋面之類,這些可以用arcpy或者ArcEngine)的就壓根沒有對應(yīng)的api了。本著既然用過了就總結(jié)一下,萬一以后遇到就直接可以用了唄。
正文
1、 從shp文件讀取要素集
這里主要是針對shp文件,操作類似于Java連接數(shù)據(jù)庫,比如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數(shù)據(jù)源
DataStore dataStore = factory.createNewDataStore(params);
// 設(shè)置編碼后可以正確讀取
((ShapefileDataStore) dataStore).setCharset(Charset.forName("GBK"));
//根據(jù)圖層名稱來獲取要素的source
SimpleFeatureStore featureSource = (SimpleFeatureStore) dataStore.getFeatureSource(dataStore.getTypeNames()[0]);
return featureSource;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
2、輸出要素到shp文件
輸出文件就相當(dāng)于我們平時(shí)定義好自己的表結(jié)構(gòu),然后獲取連接數(shù)據(jù)庫的連接,將表數(shù)據(jù)插入到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);//將圖層表頭設(shè)置給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、遍歷要素集
這里的遍歷是用迭代器來實(shí)現(xiàn)的,所以務(wù)必記得遍歷完之后需要關(guān)閉數(shù)據(jù)連接,不然會報(bào)警告的。
SimpleFeatureCollection features = sourceFeatureStore.getFeatures();
SimpleFeatureIterator iterator = features.features();
while (iterator .hasNext()) {
SimpleFeature next = iterator.next();
Object geom = next.getAttribute(geometryPropertyName);
}
iterator.close();
5、按條件查詢要素集
這里類似于mybatis的查詢數(shù)據(jù)庫,這里可以實(shí)現(xiàn)空間檢索,也就是說通過經(jīng)緯度圖形,可以找到與它有相交的周邊的所有要素。
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、構(gòu)建或獲取要素幾何圖形
一、SimpleFeatureBuilder方式創(chuàng)建
//創(chuàng)建GeometryFactory工廠
GeometryFactory geometryFactory = new GeometryFactory();
SimpleFeatureCollection collection =null;
//獲取類型
SimpleFeatureType TYPE = featureSource.getSchema();
System.out.println(TYPE);
//創(chuàng)建要素集合
List<SimpleFeature> features = new ArrayList<>();
//創(chuàng)建要素模板
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
//創(chuàng)建要素并添加道集合
double latitude = Double.parseDouble("39.9");
double longitude = Double.parseDouble("116.3");
String name ="beijing";
int number = Integer.parseInt("16");
//創(chuàng)建一個(gè)點(diǎn)geometry
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
//添加的數(shù)據(jù)一定按照SimpleFeatureType給的字段順序進(jìn)行賦值
//添加name屬性
featureBuilder.add(name);
//添加number屬性
featureBuilder.add(number);
//添加geometry屬性
featureBuilder.add(point);
//構(gòu)建要素
SimpleFeature feature = featureBuilder.buildFeature(null);
Note:featureBuilder添加的數(shù)據(jù)一定按照SimpleFeatureType給的字段順序進(jìn)行賦值!?。。。。。。。。?/p>
二、getFeatureWriter方式創(chuàng)建
SimpleFeatureSource featureSource = null;
//根據(jù)圖層名稱來獲取要素的source
featureSource = shpDataStore.getFeatureSource (typeName);
//根據(jù)參數(shù)創(chuàng)建shape存儲空間
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
SimpleFeatureType sft = featureSource.getSchema();
//創(chuàng)建要素模板
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
//設(shè)置坐標(biāo)系
tb.setCRS(DefaultGeographicCRS.WGS84);
tb.setName("shapefile");
//創(chuàng)建
ds.createSchema(tb.buildFeatureType());
//設(shè)置編碼
ds.setCharset(charset);
//設(shè)置Writer,并設(shè)置為自動提交
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
//循環(huán)寫入要素
while (itertor.hasNext())
{
//獲取要寫入的要素
SimpleFeature feature = itertor.next();
//將要寫入位置
SimpleFeature featureBuf = writer.next();
//設(shè)置寫入要素所有屬性
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);
}
//將所有數(shù)據(jù)寫入
writer.write();
//關(guān)閉寫入流
writer.close();
itertor.close();
}
catch(Exception e){
e.printStackTrace();
}
總結(jié):
兩種都差不多,個(gè)人感覺第二種方式創(chuàng)建更為靈活一點(diǎn),關(guān)于第一種必須保證寫入字段的Value的順序,第二種是采用Key,value方式更為保險(xiǎn)安全,第一種可讀性更為好點(diǎn)。
7、獲取幾何圖形邊界
沒啥好講的,就是為了直接掉API
Geometry geometry = reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");
Geometry boundary = geometry.getBoundary();
8、JWT幾何關(guān)系
幾何信息和拓?fù)潢P(guān)系是地理信息系統(tǒng)中描述地理要素的空間位置和空間關(guān)系的不可缺少的基本信息。其中幾何信息主要涉及幾何目標(biāo)的坐標(biāo)位置、方向、角度、距離和面積等信息,它通常用解析幾何的方法來分析。而空間關(guān)系信息主要涉及幾何關(guān)系的“相連”、“相鄰”、“包含”等信息,它通常用拓?fù)潢P(guān)系或拓?fù)浣Y(jié)構(gòu)的方法來分析。拓?fù)潢P(guān)系是明確定的
| 幾何關(guān)系 | 說明 |
|---|---|
| 相等(Equals): | 幾何形狀拓?fù)渖舷嗟取?/td> |
| 脫節(jié)(Disjoint): | 幾何形狀沒有共有的點(diǎn)。 |
| 相交(Intersects): | 幾何形狀至少有一個(gè)共有點(diǎn)(區(qū)別于脫節(jié)) |
| 接觸(Touches): | 幾何形狀有至少一個(gè)公共的邊界點(diǎn),但是沒有內(nèi)部點(diǎn)。 |
| 交叉(Crosses): | 幾何形狀共享一些但不是所有的內(nèi)部點(diǎn)。 |
| 內(nèi)含(Within): | 幾何形狀A(yù)的線都在幾何形狀B內(nèi)部。 |
| 包含(Contains): | 幾何形狀B的線都在幾何形狀A(yù)內(nèi)部(區(qū)別于內(nèi)含) |
| 重疊(Overlaps): | 幾何形狀共享一部分但不是所有的公共點(diǎn),而且相交處有他們自己相同的區(qū)域。 |
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 二元比較集合。二元比較以兩個(gè)幾何對象作為參數(shù),返回一個(gè)Boolean類型的值,
* 來指明這兩個(gè)幾何對象是否具有指定的空間關(guān)系。支持的空間關(guān)系包括:
* 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.
* 兩個(gè)幾何對象是否是重疊的
* @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
* 幾何對象沒有交點(diǎn)(相鄰)
* @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.
* 至少一個(gè)公共點(diǎn)(相交)
* @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);//相交點(diǎn)
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創(chuàng)建Feature的兩種方式
一、SimpleFeatureBuilder方式創(chuàng)建
//創(chuàng)建GeometryFactory工廠
GeometryFactory geometryFactory = new GeometryFactory();
SimpleFeatureCollection collection =null;
//獲取類型
SimpleFeatureType TYPE = featureSource.getSchema();
System.out.println(TYPE);
//創(chuàng)建要素集合
List<SimpleFeature> features = new ArrayList<>();
//創(chuàng)建要素模板
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
//創(chuàng)建要素并添加道集合
double latitude = Double.parseDouble("39.9");
double longitude = Double.parseDouble("116.3");
String name ="beijing";
int number = Integer.parseInt("16");
//創(chuàng)建一個(gè)點(diǎn)geometry
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
//添加的數(shù)據(jù)一定按照SimpleFeatureType給的字段順序進(jìn)行賦值
//添加name屬性
featureBuilder.add(name);
//添加number屬性
featureBuilder.add(number);
//添加geometry屬性
featureBuilder.add(point);
//構(gòu)建要素
SimpleFeature feature = featureBuilder.buildFeature(null);
Note:featureBuilder添加的數(shù)據(jù)一定按照SimpleFeatureType給的字段順序進(jìn)行賦值?。。。。。。。。。?br> 二、getFeatureWriter方式創(chuàng)建
SimpleFeatureSource featureSource = null;
//根據(jù)圖層名稱來獲取要素的source
featureSource = shpDataStore.getFeatureSource (typeName);
//根據(jù)參數(shù)創(chuàng)建shape存儲空間
ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
SimpleFeatureType sft = featureSource.getSchema();
//創(chuàng)建要素模板
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
//設(shè)置坐標(biāo)系
tb.setCRS(DefaultGeographicCRS.WGS84);
tb.setName("shapefile");
//創(chuàng)建
ds.createSchema(tb.buildFeatureType());
//設(shè)置編碼
ds.setCharset(charset);
//設(shè)置Writer,并設(shè)置為自動提交
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
//循環(huán)寫入要素
while (itertor.hasNext())
{
//獲取要寫入的要素
SimpleFeature feature = itertor.next();
//將要寫入位置
SimpleFeature featureBuf = writer.next();
//設(shè)置寫入要素所有屬性
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);
}
//將所有數(shù)據(jù)寫入
writer.write();
//關(guān)閉寫入流
writer.close();
itertor.close();
}
catch(Exception e){
e.printStackTrace();
}
總結(jié):
兩種都差不多,個(gè)人感覺第二種方式創(chuàng)建更為靈活一點(diǎn),關(guān)于第一種必須保證寫入字段的Value的順序,第二種是采用Key,value方式更為保險(xiǎn)安全,第一種可讀性更為好點(diǎn)。
參考文章
https://blog.csdn.net/weixin_40184249/article/details/84480652
http://www.aiuxian.com/article/p-455672.html