Java使用Graphics2D画波浪线的艰辛之路

 需求是根据飞机的线路情况,需要画直线,双直线,波浪线,虚线,连连接航路

其他都好说,这波浪线尤其不好画

 

搜了一圈,基本都是建议使用drawArc方法画圆弧拼接波浪线,但是及其麻烦,效果如下,并不理想

 

 

在群里问了下大佬的建议,改变思路

 

那么接下来,开始研究下怎么画

1.已知条件,是飞机的两个点

先画出直线看看

代码:

 public static void main(String[] args) throws IOException {
        BufferedImage res = null;
        res = new BufferedImage(500, 500,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = res.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setBackground(Color.black);
        g.clearRect(0, 0, 500, 500);


        int x1=200,y1=100;
        int x2=400,y2=400;
        g.drawLine(x1,y1,x2,y2);

        String imageDir = "D:\\出图测试\\波浪";

        ImageInfoUtil.write(res, imageDir, "test.png");

    }
    public static void write(BufferedImage subimage, String centerImageDir, String fileName) throws IOException {
        FileOutputStream pointOut = null;
        try {
            File f = new File(centerImageDir);
            if(!f.isDirectory()){
                f.mkdirs();
            }
            pointOut = new FileOutputStream(centerImageDir+File.separator+fileName);//输出图片的地址
            ImageIO.write(subimage, "png", pointOut);
        }finally {
            if(pointOut!=null){
                pointOut.close();
            }
        }
    }

 效果:

2.根据直线求平行线

草稿:

 代码:

public static void main(String[] args) throws IOException {
        BufferedImage res = null;
        res = new BufferedImage(500, 500,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = res.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setBackground(Color.black);
        g.clearRect(0, 0, 500, 500);


        int x1=200,y1=100;
        int x2=400,y2=400;
        g.drawLine(x1,y1,x2,y2);

        int[] ps= parallelLines(x1,y1,x2,y2,3);
        g.setColor(Color.green);
        g.drawLine(ps[0],ps[1],ps[2],ps[3]);
        g.drawLine(ps[4],ps[5],ps[6],ps[7]);

        String imageDir = "D:\\出图测试\\波浪";

        ImageInfoUtil.write(res, imageDir, "test.png");

    }
    public static void write(BufferedImage subimage, String centerImageDir, String fileName) throws IOException {
        FileOutputStream pointOut = null;
        try {
            File f = new File(centerImageDir);
            if(!f.isDirectory()){
                f.mkdirs();
            }
            pointOut = new FileOutputStream(centerImageDir+File.separator+fileName);//输出图片的地址
            ImageIO.write(subimage, "png", pointOut);
        }finally {
            if(pointOut!=null){
                pointOut.close();
            }
        }
    }



    /**
     * 根据两点一直线和距离,算出两天平行线
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param l
     * @return
     */
    public static int[] parallelLines(int x1, int y1, int x2, int y2,int l) {
        int m = y2-y1;
        int n = x2-x1;
        double p = Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2));
        double t = p/n;
        double s=m/p;
        double c = n/p;
        double ry=l*c;
        double rx=l*s;

        int x3 = (int) (x2-rx);
        int x4=(int)(x1-rx);

        int y3 = (int) (y2+ry);
        int y4=(int)(y1+ry);



        int x5 = (int) (x2+rx);
        int x6=(int)(x1+rx);

        int y5 = (int) (y2-ry);
        int y6=(int)(y1-ry);

        return new int[]{x3,y3,x4,y4,x5,y5,x6,y6};
    }

效果

 3.以已知两点为首尾,两平行线上取点,进行连接为折线(需要用到直线公式计算斜率这不贴草稿了)

代码:稍微封装了一下


public class DTest {
    public static void main(String[] args) throws IOException {
        BufferedImage res = null;
        res = new BufferedImage(500, 500,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = res.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setBackground(Color.black);
        g.clearRect(0, 0, 500, 500);


        int x1=200,y1=100;
        int x2=400,y2=400;
        g.drawLine(x1,y1,x2,y2);

        int[] ps= CoordinateUtil.parallelLines(x1,y1,x2,y2,3);
        g.setColor(Color.green);
        g.drawLine(ps[0],ps[1],ps[2],ps[3]);
        g.drawLine(ps[4],ps[5],ps[6],ps[7]);



        g.setColor(Color.red);

        int x3 = ps[0];
        int y3 = ps[1];
        int x4 = ps[2];
        int y4 = ps[3];
        int[] y34=null;
        int[] x34=null;


        int x5 = ps[4];
        int y5=  ps[5];
        int x6 = ps[6];
        int y6 = ps[7];
        int[] y56=null;
        int[] x56=null;





        if(x1==x2){
            y34 = CoordinateUtil.numbers(y3,y4);
            x34 = new int[y34.length];
            for (int i = 0; i < x34.length; i++) {
                x34[i]=x3;

            }
            y56 = CoordinateUtil.numbers(y5,y6);
            x56 = new int[y56.length];
            for (int i = 0; i < x56.length; i++) {
                x56[i]=x5;
            }
        }else{

            x34 = CoordinateUtil.numbers(x3,x4);
            double k34=CoordinateUtil.K(y3,y4,x3,x4);
            double b34=CoordinateUtil.B(y3,x3,k34);
            y34 = CoordinateUtil.pointY(x34,k34,b34);



            x56 = CoordinateUtil.numbers(x5,x6);
            double k56=CoordinateUtil.K(y5,y6,x5,x6);
            double b56=CoordinateUtil.B(y5,x5,k56);
            y56 = CoordinateUtil.pointY(x56,k56,b56);
        }

        CoordinateUtil.XY[] xy34=new  CoordinateUtil.XY[y34.length];
        CoordinateUtil.XY[] xy56=new  CoordinateUtil.XY[y56.length];
        for (int i = 0; i < y34.length; i++) {
            xy34[i] = new CoordinateUtil.XY(x34[i],y34[i]);
        }

        for (int i = 0; i < y56.length; i++) {
            xy56[i]=new CoordinateUtil.XY(x56[i],y56[i]);
        }


        CoordinateUtil.XY[] polys = CoordinateUtil.polyXYs(new CoordinateUtil.XY(x1,y1),new CoordinateUtil.XY(x2,y2),xy34,xy56,3);


        int[]  polyX = new int[polys.length];
        int[]  polyY = new int[polys.length];

        for (int i = 0; i < polys.length; i++) {
            polyX[i]=polys[i].x;
            polyY[i]=polys[i].y;
        }


        g.drawPolyline(polyX, polyY, polyX.length);


        String imageDir = "D:\\出图测试\\波浪";

        ImageInfoUtil.write(res, imageDir, "test.png");

    }
    public static void write(BufferedImage subimage, String centerImageDir, String fileName) throws IOException {
        FileOutputStream pointOut = null;
        try {
            File f = new File(centerImageDir);
            if(!f.isDirectory()){
                f.mkdirs();
            }
            pointOut = new FileOutputStream(centerImageDir+File.separator+fileName);//输出图片的地址
            ImageIO.write(subimage, "png", pointOut);
        }finally {
            if(pointOut!=null){
                pointOut.close();
            }
        }
    }




}
public class CoordinateUtil {


    /**
     * 根据两个值,获取中间所有数
     * 包含首尾
     * @param x1
     * @param x2
     * @return
     */
    public static int[] numbers(int x1, int x2) {
        int max = Math.max(x1, x2);
        int min = Math.min(x1, x2);
        int index=0;
        int [] px = new int[max-min+1];
        for (int i = min; i <= max; i++) {
            px[index]=i;
            index++;
        }
        return px;
    }


    /**
     * 求常量B
     * @param y
     * @param x
     * @param k
     * @return
     */
    public static double B(int y, int x, double k) {
        double b = new BigDecimal(String.valueOf(y)).subtract(new BigDecimal(new BigDecimal(String.valueOf(k)).multiply(new BigDecimal(String.valueOf(x))).doubleValue())).doubleValue();
        return b;
    }

    /**
     * 求斜率k
     * @param y1
     * @param y2
     * @param x1
     * @param x2
     * @return
     */
    public static double K(int y1, int y2, int x1, int x2) {
        if(x2 - x1==0){
            throw new RuntimeException("x2与x1相等,没有斜率");
        }
        double k = new BigDecimal(String.valueOf(y2 - y1)).divide(new BigDecimal(String.valueOf(x2 - x1)),5, BigDecimal.ROUND_HALF_UP).doubleValue();
        return k;
    }

    /**
     * 根据两点一直线和距离,算出两天平行线
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @param l
     * @return
     */
    public static int[] parallelLines(int x1, int y1, int x2, int y2,int l) {
        int m = y2-y1;
        int n = x2-x1;
        double p = Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2));
        double t = p/n;
        double s=m/p;
        double c = n/p;
        double ry=l*c;
        double rx=l*s;

        int x3 = (int) (x2-rx);
        int x4=(int)(x1-rx);

        int y3 = (int) (y2+ry);
        int y4=(int)(y1+ry);



        int x5 = (int) (x2+rx);
        int x6=(int)(x1+rx);

        int y5 = (int) (y2-ry);
        int y6=(int)(y1-ry);

        return new int[]{x3,y3,x4,y4,x5,y5,x6,y6};
    }

    /**
     * 根据中间两点取首位点
     * @param xy1 首
     * @param xy2 尾
     * @param xy34 平行线1
     * @param xy56 平行线2
     * @param interval 波浪间隔
     * @return
     */
    public static XY[] polyXYs(XY xy1, XY xy2, XY[] xy34, XY[] xy56,int interval) {
        if(xy34.length!= xy56.length){
            throw  new RuntimeException("两条平行线长度应相同");
        }
        List<XY> xyList = new ArrayList<>();
        xyList.add(xy1);
        int lg=1;
        for (int i = interval; i < xy34.length; i+=interval) {
            if(i>xy34.length){
                break;
            }
            if(lg%2==1){
                xyList.add(xy34[i]);
            }else{
                xyList.add(xy56[i]);
            }
            lg++;
        }
        xyList.add(xy2);
        return xyList.toArray(new XY[xyList.size()]);
    }

    public static class XY{
        public int x;
        public int y;

        public XY(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    /**
     * y=kx+b
     * @param px
     * @param k
     * @param b
     * @return
     */
    public static int[] pointY(int[] px, double k, double b) {
        int[] py = new int[px.length];
        for (int i = 0; i < px.length; i++) {
            py[i]=new BigDecimal(k).multiply(new BigDecimal(px[i])).add(new BigDecimal(b)).intValue();
        }
        return py;
    }
}

效果:

 

去掉辅助的平行线和直线看看,对比一下效果还不错

 

代码未整理封装,有空再说

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值