Java determines whether a Geometry point is online
This blog will implement a simple algorithm to determine whether a point on the map is on a known line; first of all, the earth is a sphere, and the latitude and longitude is a double type with 6 to 14 decimal places reserved, which is not suitable for direct distance calculation.
Geometry point Geometry lineString
Tried lineString.intersects(point), lineString.contains(point), point.within(lineString) but it doesn't work;
Here Amap provides an idea: if the distance error is within the range of resolution, the point is considered to be on the line;
1. Rendering
The effect diagram is as follows: the distance error is considered to be on the point line at the resolution size, 1/10 resolution, 1/100 resolution, and 1/500 resolution.
It can be seen that the larger the distance error, the more points will be included;
2. Source code
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");
}
}
}
}
refer to
- AutoNavi Map Mathematical Calculation Library
- AutoNavi Map Web JS API Example Study Notes (15) - Geometric Calculation (Distance/Area Calculation, Relationship Judgment)
- https://stackoverflow.com/questions/30925042/projecting-a-point-onto-a-path/30934704#30934704
- https://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment