GeoUtils.java 5.34 KB
package com.bsth.util;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;

/**
 * Created by panzhao on 2016/12/23.
 */
public class GeoUtils {

    private final static double EARTHRADIUS = 6378137;

    private static GeometryFactory geometryFactory = new GeometryFactory();

    public static double getDistance(Point p1, Point p2) {
        double lng1 = getLoop(p1.getY(), -180, 180), lat1 = getRange(
                p1.getX(), -74, 74);
        double lng2 = getLoop(p2.getY(), -180, 180), lat2 = getRange(
                p2.getX(), -74, 74);

        double x1, x2, y1, y2;
        x1 = degreeToRad(lng1);
        y1 = degreeToRad(lat1);
        x2 = degreeToRad(lng2);
        y2 = degreeToRad(lat2);
        return EARTHRADIUS
                * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1)
                * Math.cos(y2) * Math.cos(x2 - x1)));
    }

    private static double getLoop(double v, double a, double b) {
        while (v > b) {
            v -= b - a;
        }
        while (v < a) {
            v += b - a;
        }
        return v;
    }

    private static double getRange(double v, double a, double b) {
        v = Math.min(Math.max(v, a), b);
        return v;
    }

    private static double degreeToRad(double degree) {
        return Math.PI * degree / 180;
    }

    /**
     * 计算点 到 线的距离
     * @param line
     * @param p
     * @return
     */
    public static double getDistanceFromLine(LineString line, Point p){
        Point s = line.getStartPoint();
        Point e = line.getEndPoint();
        return getDistanceFromLine(s, e, p);
    }

    public static double getDistanceFromLine(Point s, Point e, Point p){
        double d1 = getDistance(s, p);
        double d2 = getDistance(p, e);
        double d3 = getDistance(s, e);
        double distance = 0;

        double alpha = Math.acos((d1*d1 + d3*d3 - d2*d2)/(2*d1*d3));
        double beta = Math.acos((d2*d2 + d3*d3 - d1*d1)/(2*d2*d3));

        if(alpha> Math.PI/2) {
            distance = d1;
        }
        else if(beta > Math.PI/2) {
            distance = d2;
        }
        else {
            distance = Math.sin(alpha) * d1;
        }
        return distance;
    }

    /**
     * 计算2条直线的最短距离
     * @param p1
     * @param p2
     * @param p3
     * @param p4
     * @return
     */
    public static double getDistanceLineToLine(Point p1, Point p2, Point p3, Point p4){
        double distance;
        double x1 = p1.getX(); //A点坐标(x1,y1,z1)
        double y1 = p1.getY();
        double z1 = 0;
        double x2 = p2.getX(); //B点坐标(x2,y2,z2)
        double y2 = p2.getY();
        double z2 = 0;
        double x3 = p3.getX(); //C点坐标(x3,y3,z3)
        double y3 = p3.getY();
        double z3 = 0;
        double x4 = p4.getX(); //D点坐标(x4,y4,z4)
        double y4 = p4.getY();
        double z4 = 0;

        double a = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1);
        double b = -((x2-x1)*(x4-x3)+(y2-y1)*(y4-y3)+(z2-z1)*(z4-z3));
        double c = -((x1-x2)*(x1-x3)+(y1-y2)*(y1-y3)+(z1-z2)*(z1-z3));

        double d = -((x2-x1)*(x4-x3)+(y2-y1)*(y4-y3)+(z2-z1)*(z4-z3));
        double e = (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3)+(z4-z3)*(z4-z3);
        double f = -((x1-x3)*(x4-x3)+(y1-y3)*(y4-y3)+(z1-z3)*(z4-z3));

        //平行
        if ((a*e-b*d)==0&&(b*d-a*e)==0)
        {
            double d1 = getDistance(p1, p3);
            double d2 = getDistance(p1, p4);
            distance = (d1<d2)?d1:d2;
            return distance;
        }

        double s = (b*f-e*c)/(a*e-b*d);
        double t = (a*f-d*c)/(b*d-a*e);

        //说明P点落在线段AB上,Q点落在线段CD上
        if(0<=s&&s<=1&&0<=t&&t<=1)
        {
            //2条线段的公垂线段PQ;
            //P点坐标
            double X = x1+s*(x2-x1);
            double Y = y1+s*(y2-y1);
            double Z = z1+s*(z2-z1);
            //Q点坐标
            double U = x3+t*(x4-x3);
            double V = y3+t*(y4-y3);
            double W = z3+t*(z4-z3);
            Point p = geometryFactory.createPoint(new Coordinate(X, Y, Z));
            Point q = geometryFactory.createPoint(new Coordinate(U, V, W));
            distance = getDistance(p, q);
        }
        else
        {
            double d1 = getDistanceFromLine(p3,p4,p1);
            double d2 = getDistanceFromLine(p3,p4,p2);
            double d3 = getDistanceFromLine(p1,p2,p3);
            double d4 = getDistanceFromLine(p1,p2,p4);
            distance = (d1<d2)?d1:d2;
            distance = (distance<d3)?distance:d3;
            distance = (distance<d4)?distance:d4;
        }

        return distance;
    }

    /**
     * 计算点 到 线的垂直交点
     * @param lp1
     * @param lp2
     * @param p
     * @return
     */
    public static Point perpendularPoint(Point lp1, Point lp2, Point p){
        double a = lp1.getX() - lp2.getX(), b = lp2.getY() - lp1.getY(), c = lp1.getY() * lp2.getX() - lp2.getY() * lp1.getX();
        double lon = (Math.pow(b, 2) * p.getY() - a * b * p.getX() - a * c) / (Math.pow(a, 2) + Math.pow(b, 2));
        double lat = (Math.pow(a, 2) * p.getX() - a * b * p.getY() - b * c) / (Math.pow(a, 2) + Math.pow(b, 2));

        return geometryFactory.createPoint(new Coordinate(lat, lon));
    }
}