Java determines whether a Geometry point is on the Geometry LineString

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;
insert image description here

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

Guess you like

Origin blog.csdn.net/qq_40985985/article/details/119000819