package com.scpyun.platform.jilinsscgsdp.utils;


import com.scpyun.base.core.utils.UnifyLogger;

import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
/**
 *
 * @Title:  PolygonUtil
 * @Package PolygonUtil.java
 * @Description: copy By scp-grid
 * @author:  guojiucoder
 * @date:   2024/7/31 14:10
 * @version V1.0.0
 *
 */

public class PolygonUtil {


    /**
     * 判断多边形1是否在多边形2内部。true在内部，false不在内部
     *
     * @param GardenPolygon 网格范围
     * @param ResidentialPolygon 小区范围
     * @return
     */
    public static boolean isPolygonInPolygon(List<Point2D.Double> GardenPolygon, List<Point2D.Double> ResidentialPolygon) {
        // 如果多边形1的某一个点不在多边形2内部，则多边形1不在多边形2内部
        for (Point2D.Double pointPolygon1 : GardenPolygon) {
            if(!isPointInPoly(pointPolygon1,ResidentialPolygon)){
                UnifyLogger.parent("isPolygonInPolygon111",UnifyLogger.Level.INFO);
                return false;
            }
        }

        // 如果多边形1和多边形2的某条边有交点，则多边形1不在多边形2内部
        for (int i = 0; i < GardenPolygon.size(); i++) {
            // p1-p2多边形1的一条边
            Point2D.Double p1 = GardenPolygon.get(i);
            Point2D.Double p2;
            if (i < GardenPolygon.size() - 1) {
                p2 = GardenPolygon.get(i + 1);
            } else {
                p2 = GardenPolygon.get(0);
            }

            // p3-p4多边形2的一条边
            for (int j = 0; j < ResidentialPolygon.size(); j++) {
                Point2D.Double p3 = ResidentialPolygon.get(j);
                Point2D.Double p4;
                if (j < ResidentialPolygon.size() - 1) {
                    p4 = ResidentialPolygon.get(j + 1);
                } else {
                    p4 = ResidentialPolygon.get(0);
                }

                if (isIntersect(p1, p2, p3, p4)) {
                    UnifyLogger.parent("isPolygonInPolygon222",UnifyLogger.Level.INFO);
                    return false;
                }
            }
        }

        return true;
    }


    /**
     * 返回p1-p2，p3-p4两条线段是否有交点。true有，false没有
     *
     * @param p1
     * @param p2
     * @param p3
     * @param p4
     * @return
     */
    public static boolean isIntersect(Point2D.Double p1, Point2D.Double p2, Point2D.Double p3, Point2D.Double p4) {
        boolean flag = false;
        double d = (p2.getX() - p1.getX()) * (p4.getY() - p3.getY())
                - (p2.getY() - p1.getY()) * (p4.getX() - p3.getX());
        if (d != 0) {
            double r = ((p1.getY() - p3.getY()) * (p4.getX() - p3.getX())
                    - (p1.getX() - p3.getX()) * (p4.getY() - p3.getY())) / d;
            double s = ((p1.getY() - p3.getY()) * (p2.getX() - p1.getX())
                    - (p1.getX() - p3.getX()) * (p2.getY() - p1.getY())) / d;
            if ((r >= 0) && (r <= 1) && (s >= 0) && (s <= 1)) {
                flag = true;
            }
        }
        return flag;
    }


    /**
     * 返回一个点是否在一个多边形区域内。true在，false不在。如果点位于多边形的顶点或边上，不算做点在多边形内，返回false
     *
     * @param point   点
     * @param polygon 多边形
     * @return
     */
    public static boolean isPointInPoly(Point2D.Double point, List<Point2D.Double> polygon) {
        assertParams(point, polygon);

        GeneralPath p = new GeneralPath();
        Point2D.Double first = polygon.get(0);
        p.moveTo(first.x, first.y);
        int size = polygon.size();
        for (int i = 1; i < size; i++) {
            Point2D.Double pa = polygon.get(i);
            p.lineTo(pa.x, pa.y);
        }
        p.lineTo(first.x, first.y);
        p.closePath();
        return p.contains(point);
//                p.contains(point);
    }


    private static void assertParams(Point2D.Double point, List<Point2D.Double> polygon) {
        if (null == point || null == polygon) {
            throw new IllegalArgumentException("参数不能为空");
        }
        if (polygon.size() < 3) {
            throw new IllegalArgumentException("多边形点数需要大于等于3");
        }

    }
    public static void main(String[] args) {
        Point2D.Double p2 = new Point2D.Double(123.38818984282496,41.67334029162058);
        Point2D.Double p3 = new Point2D.Double(123.39019214282312,41.673342239390955);
        Point2D.Double p4 = new Point2D.Double(123.39324094838676,41.67351534821381);
        Point2D.Double p5 = new Point2D.Double(123.38987593350951,41.676076104241545);
        List<Point2D.Double> list = new ArrayList<>();
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.add(p5);
        Point2D.Double p11 = new Point2D.Double(123.38445174602192,41.67532029576498);
        Point2D.Double p12 = new Point2D.Double(123.38818984282496,41.67334029162058);
        Point2D.Double p13 = new Point2D.Double(123.38987593350951,41.676076104241545);
        Point2D.Double p14 = new Point2D.Double(123.38636039184222,41.67725270884028);
        List<Point2D.Double> list2 = new ArrayList<>();
        list2.add(p11);
        list2.add(p12);
        list2.add(p13);
        list2.add(p14);
        for (Point2D.Double pointPolygon1 : list) {
//            System.out.println(p);
            if(!NEWIsPtInPoly(pointPolygon1,list2)){
                System.out.println(111);
            }
        }


//
//        System.out.println(NEWIsPtInPoly(p11,list));
//        if(!NEWIsPtInPoly(p11,list)){
//            System.out.println(111);
//        }else {
//            System.out.println(222);
//        }
        // false
//        System.out.println(ShieldUtil.isPolygonInPolygon
//                (Arrays.asList(p11, p12, p13, p14), Arrays.asList(p2, p3, p4, p5, p6, p7, p8, p9)));
    }


    /**
     * 判断点是否在多边形内
     * @param point 检测点
     * @param pts   多边形的顶点
     * @return      点在多边形内返回true,否则返回false
     */
    public static boolean NEWIsPtInPoly(Point2D.Double point, List<Point2D.Double> pts){

        int N = pts.size();
        boolean boundOrVertex = false; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回false
        int intersectCount = 0;//cross points count of x
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
        Point2D.Double p1, p2;//neighbour bound vertices
        Point2D.Double p = point; //当前点

        p1 = pts.get(0);//left vertex
        for(int i = 1; i <= N; ++i){//check all rays
            if(p.equals(p1)){
                return boundOrVertex;//p is an vertex
            }

            p2 = pts.get(i % N);//right vertex
            if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){//ray is outside of our interests
                p1 = p2;
                continue;//next ray left point
            }

            if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){//ray is crossing over by the algorithm (common part of)
                if(p.y <= Math.max(p1.y, p2.y)){//x is before of ray
                    if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){//overlies on a horizontal ray
                        return boundOrVertex;
                    }

                    if(p1.y == p2.y){//ray is vertical
                        if(p1.y == p.y){//overlies on a vertical ray
                            return boundOrVertex;
                        }else{//before ray
                            ++intersectCount;
                        }
                    }else{//cross point on the left side
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y
                        if(Math.abs(p.y - xinters) < precision){//overlies on a ray
                            return boundOrVertex;
                        }
                        if(p.y < xinters){//before ray
                            ++intersectCount;
                        }
                    }
                }
            }else{//special case when ray is crossing through the vertex
                if(p.x == p2.x && p.y <= p2.y){//p crossing over p2
                    Point2D.Double p3 = pts.get((i+1) % N); //next vertex
                    if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){//p.x lies between p1.x & p3.x
                        ++intersectCount;
                    }else{
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;//next ray left point
        }

        if(intersectCount % 2 == 0){//偶数在多边形外
            return false;
        } else { //奇数在多边形内
            return true;
        }

    }
}


