Java判断Geometry点是否在线Geometry LineString上
Posted 程序媛一枚~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java判断Geometry点是否在线Geometry LineString上相关的知识,希望对你有一定的参考价值。
这篇博客将实现一个简单的算法,判断地图上的一个点是否在已知的一条线上;首先地球为球面,经纬度为double类型保留有6~14位小数,直接的求距离不太合适。
Geometry point Geometry lineString
尝试了 lineString.intersects(point)、lineString.contains(point)、point.within(lineString) 都不起作用;
这里Amap提供了一个思路:求距离误差在分辨率的范围内就认为点在线上;
1. 效果图
效果图如下:分别为距离误差在分辨率大小、1/10分辨率、1/100分辨率、1/500分辨率就认为在点在线上。
可以看到距离误差越大,更多的点会被包括进来;
2. 源码
package com.demo.process;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import java.io.IOException;
/*************************************
*Class Name: GeometryUtil
*Description: <几何相关的操作类>
*@author: Seminar
*@since 1.0.0
*************************************/
public class GeometryUtil {
// 地球半径
private static final double EARTH_RADIUS = 6378137;
private static GeometryFactory gf = new GeometryFactory();
/**
* wkt 转geometry
*
* @param wkt
* @return
* @throws ParseException
*/
public static Geometry wkt2Geo(String wkt) throws ParseException {
WKTReader reader = new WKTReader(gf);
Geometry geom = reader.read(wkt);
return geom;
}
/**
* 计算两个点之间的距离
*
* @param p1
* @param p2
* @return
*/
public static double distance(Point p1, Point p2) {
return distance(p1.getCoordinate(), p2.getCoordinate());
}
private static double haverSin(double theta) {
double v = Math.sin(theta / 2);
return v * v;
}
/**
* 计算球面两点距离
*
* @param p1
* @param p2
* @return
*/
public static double distance(Coordinate p1, Coordinate p2) {
// 用haversine公式计算球面两点间的距离。
// 经纬度转换成弧度
double lat1 = Math.toRadians(p1.y);
double lon1 = Math.toRadians(p1.x);
double lat2 = Math.toRadians(p2.y);
double lon2 = Math.toRadians(p2.x);
// 差值
double vLon = Math.abs(lon1 - lon2);
double vLat = Math.abs(lat1 - lat2);
// h is the great circle distance in radians, great
// circle就是一个球体上的切面,它的圆心即是球心的一个周长最大的圆。
double h = haverSin(vLat) + Math.cos(lat1) * Math.cos(lat2) * haverSin(vLon);
double distance = 2 * EARTH_RADIUS * Math.asin(Math.sqrt(h));
return distance;
}
/**
* 判断点是否在线上
*
* @param a 点A
* @param start 线起点start
* @param end 线终点end
* @param resolution 误差范围m
* @return
*/
public static boolean isPointOnSegment(Point a, Point start, Point end, double resolution) {
boolean flag = false;
double startAdis = distance(a, start);
double endADis = distance(a, end);
double dis = distance(start, end);
if (startAdis + endADis >= dis - resolution && startAdis + endADis <= dis + resolution) {
return true;
}
return flag;
}
public static void main(String[] args) throws ParseException, IOException {
// 线几何
String lineString = "LINESTRING (117.18292236328126 40.16208338164619, 119.01489257812501 39.48284540453334)";
// 多点几何
String multPoints = "MULTIPOINT ((118.23143005371095 39.64059509088577),(118.23143005371095 39.64006632964757),(118.23143005371095 39.639537564366705),(118.23211669921876 39.77476948529546),(118.23211669921876 39.77424175134451))";
Geometry line = wkt2Geo(lineString);
Geometry mulpoint = wkt2Geo(multPoints);
double resolution = 305.7481;
for (Coordinate coordinate : mulpoint.getCoordinates()) {
// 判断点是否在线上
Point point = gf.createPoint(coordinate);
// 判断点是否在线上 geom.intersects(point)、point.within(geom) 这俩方法都不管用,以1/20分辨率当作误差范围
if (isPointOnSegment(point, gf.createPoint(line.getCoordinates()[0]), gf.createPoint(line.getCoordinates()[1]), resolution)) {
System.out.println(point.getCoordinate() + " on line");
} else {
System.err.println(point.getCoordinate() + " not on line");
}
}
}
}
参考
以上是关于Java判断Geometry点是否在线Geometry LineString上的主要内容,如果未能解决你的问题,请参考以下文章
Esri geometry api java 学习文档 线多线 (Polyline)