package com.cm.common.utils.point;

import java.awt.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: PointUtil
 * @Description: 点工具类
 * @Author: WangGeng
 * @Date: 2019-08-09 22:43
 * @Version: 1.0
 **/
public class PointUtil {

    private static final double EARTH_RADIUS = 637_1393.00D;
    private static final double RADIAN = Math.PI / 180.00D;
    private static final double HALF = 0.5D;

    /**
     * 点在多边形内
     *
     * @param point
     * @param points
     * @return
     */
    public static boolean isPointInPoly(Point point, List<Point> points) {
        int N = points.size();
        //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        boolean boundOrVertex = true;
        //cross points count of x
        int intersectCount = 0;
        //浮点类型计算时候与0比较时候的容差
        double precision = 2e-10;
        //neighbour bound vertices
        Point p1, p2;
        //当前点
        Point p = point;
        //left vertex
        p1 = points.get(0);
        //check all rays
        for (int i = 1; i <= N; ++i) {
            if (p.equals(p1)) {
                //p is an vertex
                return boundOrVertex;
            }
            //right vertex
            p2 = points.get(i % N);
            //ray is outside of our interests
            if (p.getX() < Math.min(p1.getX(), p2.getX()) || p.getX() > Math.max(p1.getX(), p2.getX())) {
                p1 = p2;
                continue;//next ray left point
            }
            //ray is crossing over by the algorithm (common part of)
            if (p.getX() > Math.min(p1.getX(), p2.getX()) && p.getX() < Math.max(p1.getX(), p2.getX())) {
                //x is before of ray
                if (p.getY() <= Math.max(p1.getY(), p2.getY())) {
                    //overlies on a horizontal ray
                    if (p1.getX() == p2.getX() && p.getY() >= Math.min(p1.getY(), p2.getY())) {
                        return boundOrVertex;
                    }
                    //ray is vertical
                    if (p1.getY() == p2.getY()) {
                        //overlies on a vertical ray
                        if (p1.getY() == p.getY()) {
                            return boundOrVertex;
                        } else {
                            //before ray
                            ++intersectCount;
                        }
                    } else {
                        //cross point on the left side
                        //cross point of y
                        double xinters = (p.getX() - p1.getX()) * (p2.getY() - p1.getY()) / (p2.getX() - p1.getX()) + p1.getY();
                        //overlies on a ray
                        if (Math.abs(p.getY() - xinters) < precision) {
                            return boundOrVertex;
                        }
                        //before ray
                        if (p.getY() < xinters) {
                            ++intersectCount;
                        }
                    }
                }
            } else {
                //special case when ray is crossing through the vertex
                //p crossing over p2
                if (p.getX() == p2.getX() && p.getY() <= p2.getY()) {
                    //next vertex
                    Point p3 = points.get((i + 1) % N);
                    //p.x lies between p1.x & p3.x
                    if (p.getX() >= Math.min(p1.getX(), p3.getX()) && p.getX() <= Math.max(p1.getX(), p3.getX())) {
                        ++intersectCount;
                    } else {
                        intersectCount += 2;
                    }
                }
            }
            //next ray left point
            p1 = p2;
        }
        if (intersectCount % 2 == 0) {
            //偶数在多边形外
            return false;
        } else {
            //奇数在多边形内
            return true;
        }
    }

    /**
     * 判断是否在圆形内
     * <p>
     * 判断点与圆心之间的距离和圆半径的关系
     *
     * @param p
     * @param c
     * @return
     */
    public static int distencePC(Point p, Circle c) {
        int s;
        double d2 = Math.hypot((p.getX() - c.getPoint().getX()), (p.getY() - c.getPoint().getY()));
        double r = c.getR();
        if (d2 > r) {
            // 圆外
            s = -1;
        } else if (d2 < r) {
            // 圆内
            s = 1;
        } else {
            // 圆上
            s = 0;
        }
        return s;
    }

    /**
     * 计算距离，Point的x为纬度，y为经度
     *
     * @param point1
     * @param point2
     * @return
     */
    public static double getDistance(Point point1, Point point2) {
        double lat1 = point1.getX();
        double lon1 = point1.getY();
        double lat2 = point2.getX();
        double lon2 = point2.getY();
        double x, y, a, b, distance;

        lat1 *= RADIAN;
        lat2 *= RADIAN;
        x = lat1 - lat2;
        y = lon1 - lon2;
        y *= RADIAN;
        a = Math.sin(x * HALF);
        b = Math.sin(y * HALF);
        distance = EARTH_RADIUS * Math.asin(Math.sqrt(a * a + Math.cos(lat1) * Math.cos(lat2) * b * b)) / HALF;
        return new BigDecimal(distance).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    public static void main(String[] args) {
        Point point = new Point(111.770495, 40.871839);
        List<Point> points = new ArrayList<>();
        points.add(new Point(111.76776160830235, 40.87164162798379));
        points.add(new Point(111.76940775314925, 40.868854144474206));
        points.add(new Point(111.77202968235643, 40.86936472871906));
        points.add(new Point(111.77072713936697, 40.87228340534707));

        System.out.println(PointUtil.getDistance(new Point(111.76776160830235, 40.87164162798379), new Point(111.76940775314925, 40.868854144474206)));

    }

}
