package com.yeechart.dotMatrix.canvas;

import java.awt.geom.Point2D;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 绘制图形
 */
public class DotMatrixDrawShapeUtil {


    /**
     * 绘制 直/虚 直线
     *
     * @param largeMatrix 点阵画布
     * @param lineWidth   直/虚 的宽度
     * @param lineSegment 虚线段 的长度  (绘制直线时此处的长度会被无视掉)
     * @param interval    直/虚 的间隔 （0为绘制的是直线，非0则是虚线）
     * @param startRow    直/虚 的起始行
     * @param startColumn 直/虚 的起始列
     * @param endColumn   直/虚 的结束列
     */
    public static void drawLine(int[][] largeMatrix, int lineWidth, int lineSegment, int interval, int startRow, int startColumn, int endColumn) {

        //线条数组
        int[][] lineMatrix = new int[lineWidth][endColumn - startColumn];


        for (int i = 0; i < lineMatrix.length; i++) {

            for (int j = 0; j < lineMatrix[0].length; j++) {

                int value = 0;

                if (interval > 0 && lineSegment > 0) {
                    //表示绘制的为虚线

                    int part = j % (lineSegment + interval);

                    if (part < lineSegment) {
                        value = 1;
                    } else {
                        value = 0;
                    }

                } else {
                    //表示绘制的为直线
                    value = 1;
                }

                lineMatrix[i][j] = value;

            }

        }


        DotMatrixCanvasUtil.mergeDotMatrices(largeMatrix, lineMatrix, startRow, startColumn);//,new int[]{1,1,1,1}


    }


    /**
     * 绘制 直/虚 竖线
     *
     * @param largeMatrix 点阵画布
     * @param lineWidth   直/虚 的宽度
     * @param lineSegment 虚线段 的长度  (绘制直线时此处的长度会被无视掉)
     * @param interval    直/虚 的间隔 （0为绘制的是直线，非0则是虚线）
     * @param startRow    直/虚 的起始行
     * @param startColumn 直/虚 的起始列
     * @param endRow      直/虚 的结束行
     */
    public static void drawVerticalLine(int[][] largeMatrix, int lineWidth, int lineSegment, int interval, int startRow, int startColumn, int endRow) {

        //线条数组
        int[][] lineMatrix = new int[endRow - startRow][lineWidth];


        for (int i = 0; i < lineMatrix.length; i++) {

            for (int j = 0; j < lineMatrix[0].length; j++) {

                int value = 0;

                if (interval > 0 && lineSegment > 0) {
                    //表示绘制的为虚线

                    int part = i % (lineSegment + interval);

                    if (part < lineSegment) {
                        value = 1;
                    } else {
                        value = 0;
                    }

                } else {
                    //表示绘制的为直线
                    value = 1;
                }

                lineMatrix[i][j] = value;

            }

        }


        DotMatrixCanvasUtil.mergeDotMatrices(largeMatrix, lineMatrix, startRow, startColumn);//,new int[]{1,1,1,1}

    }


    /**
     * 新贝塞尔曲线算法
     **/
    public static List<int[]> computeBezierCurve(List<int[]> controlPoints) {

        float tension = 1f;

        int[][] points = controlPoints.stream()
                .map(int[]::clone)
                .collect(Collectors.toList())
                .toArray(new int[controlPoints.size()][]);

        Map<String, int[]> circleMap = new LinkedHashMap<>();

//        List<int[]> curvePoints = new ArrayList<>();

        //System.out.println(Arrays.deepToString(points));

        for (int i = 0; i < points.length - 1; i++) {
            Point2D start = new Point2D.Float(points[i][0], points[i][1]);
            Point2D end = new Point2D.Float(points[i + 1][0], points[i + 1][1]);

            // 检查是否为直线
            if (isHLinear(start, end)) {
                // 横向相等
                for (int j = 0; j < Math.abs(end.getY() - start.getY()); j++) {
                    //curvePoints.add(new int[]{(int) start.getX(), (int) (start.getY() + j)});
                    int[] array = new int[]{(int) start.getX(), (int) (start.getY() + j)};
                    circleMap.put(Arrays.toString(array), array);
                }

            } else if (isVLinear(start, end)) {
                // 纵向相等
                for (int j = 0; j < Math.abs(end.getX() - start.getX()); j++) {
//                    curvePoints.add(new int[]{(int) (start.getX() + j), (int) start.getY()});
                    int[] array = new int[]{(int) (start.getX() + j), (int) start.getY()};
                    circleMap.put(Arrays.toString(array), array);
                }
            } else {

                // 判断曲线方向
                boolean isDownward = start.getX() > end.getX();//X越大 高度越小

                // 计算控制点
                Point2D control1;
                Point2D control2;
//                if (isDownward) {
//                    // 从起点到中间点，曲线向下凹
//                    control1 = new Point2D.Float((float) (start.getX() - (end.getY() - start.getY()) / 4 * tension), (float) start.getY());
//                    control2 = new Point2D.Float((float) (end.getX() + (end.getY() - start.getY()) / 4 * tension), (float) end.getY());
//
//                } else {
//                    // 从中间点到终点，曲线向上凸
//                    control1 = new Point2D.Float((float) (start.getX() + (end.getY() - start.getY()) / 4 * tension), (float) start.getY());
//                    control2 = new Point2D.Float((float) (end.getX() - (end.getY() - start.getY()) / 4 * tension), (float) end.getY());
//
//                }
//                System.out.println(control1);
//                System.out.println(control2);
//                curvePoints.add(new int[]{(int) control1.getX(), (int) control1.getY()});
//                curvePoints.add(new int[]{(int) control2.getX(), (int) control2.getY()});

                // 判断曲线方向
//                boolean isDownward = start.getX() > end.getX(); // 如果起点高于终点，曲线向下凹

                // 计算控制点
//                Point2D control1;
//                Point2D control2;
                if (isDownward) {
                    // 从起点到中间点，曲线向下凹
                    control1 = new Point2D.Float((float) (start.getX() - (end.getY() - start.getY()) / 6 * tension), (float) (start.getY() + (end.getY() - start.getY()) / 2 * tension));

                    control2 = new Point2D.Float((float) (end.getX() + (end.getY() - start.getY()) / 6 * tension), (float) (end.getY() - (end.getY() - start.getY()) / 1 * tension));

                } else {
                    // 从中间点到终点，曲线向上凸
                    control1 = new Point2D.Float((float) (start.getX() + (end.getY() - start.getY()) / 6 * tension), (float) (start.getY() + (end.getY() - start.getY()) / 1 * tension));

                    control2 = new Point2D.Float((float) (end.getX() - (end.getY() - start.getY()) / 6 * tension), (float) (end.getY() - (end.getY() - start.getY()) / 2 * tension));

                }

//                if(i == 2){
//                    curvePoints.add(new int[]{(int) control1.getX(), (int) control1.getY()});
////                    curvePoints.add(new int[]{(int) control2.getX(), (int) control2.getY()});
//                    //System.out.println(control1);
//                    System.out.println(control1);
//                }

                // 根据精度生成贝塞尔曲线上的点
                for (float t = 0; t <= 1; t += 0.0001f) {

                    double x = (1 - t) * (1 - t) * (1 - t) * start.getX() + 3 * (1 - t) * (1 - t) * t * control1.getX() + 3 * (1 - t) * t * t * control2.getX() + t * t * t * end.getX();
                    double y = (1 - t) * (1 - t) * (1 - t) * start.getY() + 3 * (1 - t) * (1 - t) * t * control1.getY() + 3 * (1 - t) * t * t * control2.getY() + t * t * t * end.getY();

//                    curvePoints.add(new int[]{(int) x, (int) y});
                    int[] array = new int[]{(int) x, (int) y};
                    circleMap.put(Arrays.toString(array), array);
                }

            }
        }


        return new ArrayList<>(circleMap.values());
    }

    /**
     * 判断是否是横线
     *
     * @param p1
     * @param p2
     * @return
     */
    public static boolean isHLinear(Point2D p1, Point2D p2) {
        return p1.getX() == p2.getX();
    }

    /**
     * 判断 是否是竖线
     *
     * @param p1
     * @param p2
     * @return
     */
    public static boolean isVLinear(Point2D p1, Point2D p2) {
        return p1.getY() == p2.getY();
    }


    /**
     * 绘制出 指定的圆角矩形
     *
     * @param width
     * @param height
     * @param cornerRadius 0为不圆角
     * @return
     */
    public static int[][] createRoundedRectangularArray(int width, int height, int cornerRadius) {
        int[][] grid = new int[height][width];

        // 绘制矩形
        for (int i = 0; i < height; i++) {
            Arrays.fill(grid[i], 1);
        }

        // 圆角算法：剔除不在圆弧曲线的点
        int radius = cornerRadius;
        int centerX = cornerRadius;
        int centerY = cornerRadius;

        for (int y = 0; y <= radius; y++) {
            for (int x = 0; x <= radius; x++) {
                if (distance(x, y, centerX, centerY) > radius) {
                    // 左上角
                    grid[y][x] = 0;
                    // 右上角
                    grid[y][width - x - 1] = 0;
                    // 左下角
                    grid[height - y - 1][x] = 0;
                    // 右下角
                    grid[height - y - 1][width - x - 1] = 0;
                }
            }
        }

        return grid;
    }

    /**
     * 计算出起点坐标和终点坐标之间的圆弧范围
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @return
     */
    public static double distance(int x1, int y1, int x2, int y2) {
        int dx = x1 - x2;
        int dy = y1 - y2;
        return Math.sqrt(dx * dx + dy * dy);
    }


    /**
     * 绘制 圆形 点阵数组
     *
     * @param radius 圆得半径
     * @return
     */
    public static int[][] createCustomRadiusArray(int radius) {
        int[][] grid = new int[radius * 2][radius * 2];

        int centerX = radius; // 圆心 x 坐标
        int centerY = radius; // 圆心 y 坐标

        int xStart = 0;
        int xEnd = Math.min(radius * 2 - 1, centerX + radius);
        int yStart = 0;
        int yEnd = Math.min(radius * 2 - 1, centerY + radius);

        double sqrRadius = radius * radius;

        for (int y = yStart; y <= yEnd; y++) {
            for (int x = xStart; x <= xEnd; x++) {
                double distanceSqr = (x - centerX) * (x - centerX) + (y - centerY) * (y - centerY);
                if (distanceSqr <= sqrRadius) {
                    grid[y][x] = 1;
                }
            }
        }

        return grid;
    }


    /**
     * 绘制出 指定的 底部为弧形的 三角形
     *
     * @param width        三
     * @param height
     * @param cornerRadius 弧线的半径
     * @return
     */
    public static int[][] createCustomTriangleArray(int width, int height, int cornerRadius) {
        int[][] grid = new int[height][width];

        // 绘制三角形
        int top = 0; // 三角形顶部位置
        int bottom = height - 1; // 三角形底部位置

        // 绘制等腰三角形
        for (int i = top; i <= bottom; i++) {
            int rowStart = (width - i) / 2; // 当前行的起始位置
            int rowEnd = rowStart + i; // 当前行的结束位置

            for (int j = rowStart; j <= rowEnd; j++) {
                grid[i][j] = 1; // 填充等腰三角形内部
            }
        }

        //得出底部的左右两个点
        int start = 0;
        int end = 0;
        for (int i = 0; i < grid[0].length; i++) {
            if (grid[height - 1][i] == 1) {
                if (start == 0) {
                    start = i;
                } else {
                    end = i;
                }
            }
        }

        //算出圆弧的圆点
        double midX = (height + height) / 2.0; // AB线中点 x 坐标为两点中点的 x 坐标
        double midY = (start + end) / 2.0; // AB线中点 y 坐标为两点中点的 y 坐标  限定此点为圆点的Y轴

        double centerX = (int) (midX + Math.sqrt((cornerRadius * cornerRadius) - (end - midY) * (end - midY)));//使用勾股定理xzp

        //替换圆弧内的点
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                // 判断当前点是否在圆弧范围内
                if (Math.sqrt(Math.pow(i - centerX, 2) + Math.pow(j - midY, 2)) < cornerRadius) {
                    grid[i][j] = 0; // 设置为0，表示在圆弧内部
                }
            }
        }

        return grid;
    }

}
