Java判断Geometry点是否在线Geometry LineString上

Posted 程序媛一枚~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java判断Geometry点是否在线Geometry LineString上相关的知识,希望对你有一定的参考价值。

Java判断Geometry点是否在线上

这篇博客将实现一个简单的算法,判断地图上的一个点是否在已知的一条线上;首先地球为球面,经纬度为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上的主要内容,如果未能解决你的问题,请参考以下文章

MySQL中地理位置数据扩展geometry的使用心得

Esri geometry api java 学习文档 线多线 (Polyline)

百度地图判断点是否在不规则多边形内部

确定point是否在boost :: geometry :: linear_ring会计方向内

mysql 判断 距离

使用Open3D进行PCD拟合平面的Python代码示例