天天看点

瞎研究之—JTS库使用样例

一、基础数据样例

1.1 geom基础数据

1.1.1 创建点缓冲为圆

//利用Monte Carlo方法近似计算PI
    公式: ① M/N = PI*R*R/4R*R  (落在圆内点的个数为M,所有点的个数为N)
          ② PI = 4M/N
//创建圆
static Geometry createCircle(){
  Geometry centrePt = geomFact.createPoint(new Coordinate(0.5, 0.5));
  return centrePt.buffer(0.5, 20);
}

PreparedGeometry.class 相对于Geometry.class
    1. 优化了对特定几何操作的重复调用性能
    2. 优化了部分方法其他依赖于Geometry
    3. 调用时线程安全的,PreparedGeometry的实现类目标就是供给多线程使用           

1.1.2 创建点、线,判断相交包含

//1. WKT读取Geometry
Geometry g1 = new WKTReader().read("LINESTRING (0 0, 10 10, 20 20)");
//2.点创建线
Coordinate[] coordinates = new Coordinate[]{new Coordinate(0, 0),
      new Coordinate(10, 10), new Coordinate(20, 20)};
Geometry g2 = new GeometryFactory().createLineString(coordinates);
//3.线相交 g1 intersection g2: MULTILINESTRING ((0 0, 10 10), (10 10, 20 20))
Geometry g3 = g1.intersection(g2);
//4.线包含点 Point within g1: true
Geometry point = new GeometryFactory().createPoint(new Coordinate(1,1));
g1.contains(point)           

1.1.3 推荐的数据创建格式

//依据GeometryFactory 创建geo数据
GeometryFactory fact = new GeometryFactory();
Point p1 = fact.createPoint(new Coordinate(0,0));

MultiPoint mpt = fact.createMultiPointFromCoords(new Coordinate[] 
                { new Coordinate(0,0), new Coordinate(1,1) } );           

1.1.4 基础类扩展

// 基于扩展实现的例子

1. ExtendedCoordinate类是对Coordiante的扩展 extends, (x,y,z) -> (x,y,z,m)
2. ExtendedCoordinateSequence实现CoordianteSequence接口 implements, Coordinate更有效的存储压缩方式
3. ExtendedCoordinateSequenceFactory工厂类

//扩展矩形框,若coordinates中点在框内无反应,若在框外则扩展
// minx = x<minx ? x : min  maxx = x>maxx ? x : maxx
public Envelope expandEnvelope(Envelope env){
    for (int i = 0; i < coordinates.length; i++ ) {
      env.expandToInclude(coordinates[i]);
    }
    return env;
}           

1.1.5 设置精度计算相交

// Geometry计算精度
// floating 结果double类型
PrecisionModel pm = new PrecisionModel()
// floating-single 结果取小数点后6位
PrecisionModel pm = new PrecisionModel(PrecisionModel.FLOATING_SINGLE)
// fixed类型 结果取定义的精确位, 1为默认值,代表整数
PrecisionModel pm = new PrecisionModel(1)    
    
GeometryFactory fact = new GeometryFactory(pm);
WKTReader wktRdr = new WKTReader(fact);
Geometry C = A.intersection(B);

// 由于精度的不同,图形相交可能会出现不同结果,面有可能退化为点、线           

1.1.6 WKT数据创建几何

GeometryFactory fact = new GeometryFactory();
WKTReader wktRdr = new WKTReader(fact);

String wktA = "POLYGON((40 100, 40 20, 120 20, 120 100, 40 100))";
String wktB = "LINESTRING(20 80, 80 60, 100 140)";
Geometry A = wktRdr.read(wktA);
Geometry B = wktRdr.read(wktB);
// A相交于B
Geometry C = A.intersection(B);
// 暂时不清楚intersectionMatrix 作用
IntersectionMatrix itersectionMatrix = A.relate(B)           
1.2 i读取KML数据,处理
//io.gml2 整体为读取KML数据
1. KMLReader kml格式读取类, 利用XMLReader读取kml文件
2. KMLHandler Xml读取过程中的start
3. FixingGeometryFactory 类,粗暴修复LinearRing(没有闭合的点,直接闭合)

读取KML可参考, 可用dom4j构建           
1.3 linerref.LinearRefExample(未完,类作用未知)
LengthIndexedLine.class 类的作用未知,等待研究
    1. extractLine()
    2. indicesOf()
    3. extractPoint()           
1.4 操作运算

1.4.1 几何间距离计算

//Geometry 距离计算
GeometryFactory fact = new GeometryFactory();
WKTReader wktRdr = new WKTReader(fact);

Geometry A = wktRdr.read(wktA);
Geometry B = wktRdr.read(wktB);
// 距离计算类声明
DistanceOp distOp = new DistanceOp(A, B);
// A、B图形间的距离
double distance = distOp.distance();
// A、B图形间最近的线,生成(x1 y1,x2 y2)=> (x1,y1)属于A (x2,y2)属于B
Coordinate[] closestPt = distOp.nearestPoints();
LineString closestPtLine = fact.createLineString(closestPt);
// 计算线的长度 (方法:循环 + 勾股定理)
closestPtLine.getLength();           

1.4.2 线合并

// 创建linerString线集合
Collection lines = new ArrayList();
LineMerger lineMerger = new LineMerger();
lineMerger.add(lineStrings);
// 集合中的线,合并为新的线集合
Collection mergedLineStrings = lineMerger.getMergedLineStrings();           

合并入下图,合并规则:

  • 合并线数据都是节点化的(它们仅有端点接触,线段不能相互交叉)
  • 若要合并的线段方向不同,最终节点方向依据服从多数点的原则

![_1_4_2_LinerMeger_]()

瞎研究之—JTS库使用样例

1.4.3 polygonize(多边形器,将线转化为面)

Collection lines = new ArrayList();
lines.add(read("LINESTRING (0 0 , 10 10)")); // isolated edge
lines.add(read("LINESTRING (185 221, 100 100)")); //dangling edge
lines.add(read("LINESTRING (185 221, 88 275, 180 316)"));
lines.add(read("LINESTRING (185 221, 292 281, 180 316)"));
lines.add(read("LINESTRING (189 98, 83 187, 185 221)"));
lines.add(read("LINESTRING (189 98, 325 168, 185 221)"));
polygonizer.add(lines);
// 返回面集合
Collection polys = polygonizer.getPolygons();
// 数据第1,2条均属于dangling lines
Collection dangles = polygonizer.getDangles();
Collection cuts = polygonizer.getCutEdges();           
瞎研究之—JTS库使用样例
1.5 precision.EnhancedPrecisionOp
// enhanced precision techniques to reduce the likelihood of robustness problems.
// 增强类方法可以增强计算的鲁棒性(极少发生,至少样例在作者电脑上并没有发生错误!!!)
Geometry result = EnhancedPrecisionOp.intersection(g1, g2);           
1.6 technique

1.6.1 线自相交判断

// 线自相交判断(必须是cross<线段两端穿出> 而非touch<线段一端在线内,一端穿出> LineRing也检测不到),很值得去研究,里面的算法实现

LineString line1 = (LineString) (rdr.read("LINESTRING (0 0, 10 10, 20 20)"));
// 输出结果相交点
showSelfIntersections(line1);

public static Geometry lineStringSelfIntersections(LineString line){
    // getEndPoints 获取线的端点,输出为Geometry中Coordinate大小为 (2*线条数)的点
    // LineString 输出为2 , MultiLineString 输出为2n
    Geometry lineEndPts = getEndPoints(line);
    // union输出原子化(noded)的线段
    Geometry nodedLine = line.union(lineEndPts);
    Geometry nodedEndPts = getEndPoints(nodedLine);
    Geometry selfIntersections = nodedEndPts.difference(lineEndPts);
    return selfIntersections;
}           

1.6.2 PolygonUnionUsingBuffer

// 图形取并集计算(合取)
Geometry[] geom = new Geometry[3];
geom[0] = rdr.read("POLYGON (( 100 180, 100 260, 180 260, 180 180, 100 180 ))");
geom[1] = rdr.read("POLYGON (( 80 140, 80 200, 200 200, 200 140, 80 140 ))");
geom[2] = rdr.read("POLYGON (( 160 160, 160 240, 240 240, 240 160, 160 160 ))");

GeometryFactory fact = geom[0].getFactory();
Geometry geomColl = fact.createGeometryCollection(geom);
Geometry union = geomColl.buffer(0.0);

// but 代码中不推荐使用buffer来合取,推荐使用 Geometry.union(), 但是为了增加健壮性,最好使用EnhancedPrecisionOp
// but 文档中说buffer速度会更快           

1.6.3 使用PreparedGeometry优化空间搜索

// 2. 查询200000个点在 100个圆中的相交
// 1. 在1*1的范围内创建了100个圆平均分配(10*10)
// 创建索引STRtree
SpatialIndex index = new STRtree();
// 圆插入索引
index.insert(geom.getEnvelopeInternal(), PreparedGeometryFactory.prepare(geom));

// 检索
public List intersects(Geometry g){
    List result = new ArrayList();
    List candidates = query(g); //核心,先算索引,然后做相交计算 比直接计算相交快了10倍
    for (Iterator it = candidates.iterator(); it.hasNext(); ) {
        PreparedGeometry prepGeom = (PreparedGeometry) it.next();
        if (prepGeom.intersects(g)) {
            result.add(prepGeom);
        }
    }
    return result;
}

// STRtree查询
public List query(Geometry g){
    return index.query(g.getEnvelopeInternal());
}           
1.7 其他注意事项

1.7.1 Geometry.union() 不支持 GEOMETRYCOLLECTION类型,

  • union支持线与点的计算,输出线、点的数组(核心算法 OverlayOp.class -> computeOverlay() )
  • 支持面与线的计算,输出面、线、点
  • 线之间的union不会merge,会生成多线

1.7.2 geom.getEnvelopeInternal() 计算图形外接矩形,初始化的Envelope

public void setToNull() {
  minx = 0;
  maxx = -1;
  miny = 0;
  maxy = -1;
}           

二、数据转换geojson

2.1 GeoJson读写
1. geojson数据格式的七种类型:Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon、GeometryCollection           

三、 JTS空间库索引

3.1 STRtree

3.1.1 STRtree创建后封底

STRtree strTree =  new STRTree();
strTree.insert(Envelop, Object);

// 如果调用了strTree.size()、query()、item、remove等 STRtree就会封底
// 再次insert会报错, Cannot insert item into an STR packed R-tree after if has been built.           

四、 JTS库使用注意事项

4.1 WKTReader读取几何形状,与Geometry判断
//WTKReader读取解析矢量数据,只做了简单检查,一下图形都可以构建成功
WKTReader rdr = new WKTReader();
Polygon polygon = (Polygon) (rdr.read("POLYGON ((100 10, -100 10, -100 -10, 100 -10, 100                     10))"));
LineString lineString = (LineString) (rdr.read("LINESTRING (100 10, -100 10, -100 -10,                         100 -10, 60 20, 100 10)"));
LinearRing linearRing = (LinearRing) (rdr.read("LINEARRING (100 10, -100 10, -100 -10,                         100 -10, 60 20, 100 10)"));

// 但是很多图形不符合OGC SFS标准,标准验证如下
System.out.println(polygon.isValid()); //true
System.out.println(lineString.isValid()); //true
System.out.println(linearRing.isValid()); //false           

继续阅读