博客首篇:控制台上“画”个五角星玩玩

刚开始学习语言的时候,老师都很喜欢让我们在控制台上使用“*”来输出某些图形,比如:三角形、菱形、方块什么的,这主要能让我们能更好地理解循环的语法和逻辑思维能力。

这些图形基本上都是直线的,所以在控制台上可以很方便地进行输出,不知道有没有人想过在控制台上输出一条有斜率的斜线呢?

在 AWT 上使用 Graphics 对象来做这些事的话是相当简单的,其中有内置的 drawLine 方法,告诉它 4 个点的坐标就可以很方便地在界面上画出一条斜线,但是在控制台我们如何做到这些呢?

闲着没事的时候,写了一个在控制台上输出五角星的小程序,不过这里面有点小小的 bug,bug 是什么、究竟在什么地方呢?先买个关子吧,我弄了好久头都大了不想去想了,如果发现的话或者是解决了的话,别忘记告诉我哦~~

顺便谨以此文作为博客的开篇祝贺!撒花~~

 Test.java 测试类

public class  Test {
    
public static void
 main(String[] args) {
        
// 画一个半径为10,旋转为0,空白为全身空格,填充为★的五角星

        Pentagram pen = new Pentagram(100' ''' );
        
// 在控制台上输出这个五角星

        Draw.printCanvas(pen.getPentagram());
    }

Pentagram.java 五角星类

public class  Pentagram {
    
private final char FILL_CHAR;   // 填充字符

    private final char SPACE_CHAR;  // 空档字符
    private final int R;            // 五角星的外接圆半径
    private final float ROTATION;   // 五角星逆时针旋转角度
    private final int X;            // 用于生成画图数组
    private final int Y;            // 用于生成画图数组
    
    
/**

     * 构造一个Pentagram对象
     * 
@param  radius 五角星的半径
     * 
@param
 rotation 五角星的逆时针旋转度数
     * 
@param
 spaceChar 画布上空白处填充字符
     * 
@param
 fillChar 画布上线条部分填充字符
     
*/

    
public Pentagram(int radius, float rotation, char spaceChar, char  fillChar) {
        
this.R =
 radius;
        
this.ROTATION =
 rotation;
        
this.FILL_CHAR =
 fillChar;
        
this.SPACE_CHAR =
 spaceChar;
        
this.X = 2 * R + 1
;
        
this.Y = 2 * R + 1
;
    }
    

    
public char
[][] getPentagram() {
        
char[][] canvas =
 initCanvas();
        Draw draw 
= new
 Draw(FILL_CHAR);
        
//
 设五角星的最右边的一个点为 A,逆时针选取点 B~E
        
//
 通过圆的极坐标公式可以得出:
        
//
 得出以下各点的坐标
        
//
 A 点坐标(0.951R, 0.309R)
        
//
 B 点坐标(0, R)
        
//
 C 点坐标(-0.951R, 0.309R)
        
//
 D 点坐标(-0.588R, -0.809R)
        
//
 E 点坐标(0.588R, -0.809R)
        
        
// 画线段CA

        draw.drawLine(mcos(162* R, msin(162* R, mcos(18* R, msin(18*  R, canvas);
        
// 画线段DA

        draw.drawLine(mcos(234* R, msin(234* R, mcos(18* R, msin(18*  R, canvas);
        
// 画线段CE

        draw.drawLine(mcos(162* R, msin(162* R, mcos(306* R, msin(306*  R, canvas);
        
// 画线段DB

        draw.drawLine(mcos(234* R, msin(234* R, mcos(90* R, msin(90*  R, canvas);
        
// 画线段BE

        draw.drawLine(mcos(90* R, msin(90* R, mcos(306* R, msin(306*  R, canvas);
        
return
 canvas;
    }

    
//
 在方形的字符数组中指定两点画线条
    
// 对图形数组进行初始化,填充空格

    private char [][] initCanvas() {
        
char[][] canvas = new char
[Y][X];
        
for (int i = 0; i < Y; i++
) {
            
for (int j = 0; j < X; j++
) {
                canvas[i][j] 
=
 SPACE_CHAR;
            }
        }
        
return
 canvas;
    }

    
// 根据角度求正弦值,保留两位小数

    private double msin(float  a) {
        
return ((int) (Math.sin(Math.toRadians(a + ROTATION)) * 100)) / 100.0
;
    }

    
// 根据角度求余弦值,保留两位小数

    private double mcos(float  a) {
        
return ((int) (Math.cos(Math.toRadians(a + ROTATION)) * 100)) / 100.0
;
    }
}

 

Draw.java 画图工具类

public class  Draw {   
    
    
private char
 fillChar;
    
    
public Draw(char
 fillChar) {        
        
this.fillChar =
 fillChar;
    }

    
/**

     * 根据两个点画线在二维字符数组上画线
     * 
@param  x1
     * 
@param
 y1
     * 
@param
 x2
     * 
@param
 y2
     * 
@param
 canvas
     
*/

    
public void drawLine(double x1, double y1, double x2, double y2, char [][] canvas) {
        
int radius = (canvas.length - 1/ 2
;
        
// 从 x 方向进行填充

        if (x1 >  x2) {
            
double t =
 x1;
            x1 
=
 x2;
            x2 
=
 t;
            t 
=
 y1;
            y1 
=
 y2;
            y2 
=
 t;
        }

        
// 获得直线方程的两个系数

        double a = (y1 - y2) / (x1 -  x2);
        
double b = y1 - a *
 x1;

        
// 根据 x 方向的值求出 y 值,并填充图形

        for (int i = (int) Math.round(x1); i <= (int) Math.round(x2); i++ ) {
            
// 根据直线方程 y = ax + b,求 y

            int y = (int) Math.round(a * i +  b);

            
//
 因为 y 和 i 算出来的结果有可能是负数,
            
//
 为了采用数组来表示坐标,做了以下变换
            
//
 c[R][R] 即为坐标原点
            
//
 c[R][0..R] 为 x 方向的负半轴
            
//
 c[R][R+1..2*R] 为 x 方向的正半轴
            
//
 c[0..R][R] 为 y 方向的正半轴
            
// c[R+1..2*R][R] 为 y 方向的负半轴

            int yy = radius -  y;
            
int xx = radius +
 i;

            yy 
= yy < 0 ? 0
 : yy;
            yy 
= yy > 2 * radius ? 2 *
 radius : yy;
            xx 
= xx < 0 ? 0
 : xx;
            xx 
= xx > 2 * radius ? 2 *
 radius : xx;

            canvas[yy][xx] 
=
 fillChar;
        }

        
// 从 y 方向进行填充,便于减少间距问题产生的字符空档

        if (y1 >  y2) {
            
double t =
 x1;
            x1 
=
 x2;
            x2 
=
 t;
            t 
=
 y1;
            y1 
=
 y2;
            y2 
=
 t;
        }

        
// 根据 y 方向的值求出 x 值,并填充图形

        for (int i = (int) Math.round(y1); i <= (int) Math.round(y2); i++ ) {
            
// 根据 x = (y - b) / a,求 x

            int y = (int) Math.round((i - b) /  a);

            
int yy = radius -
 i;
            
int xx = radius +
 y;

            yy 
= yy < 0 ? 0
 : yy;
            yy 
= yy > 2 * radius ? 2 *
 radius : yy;
            xx 
= xx < 0 ? 0
 : xx;
            xx 
= xx > 2 * radius ? 2 *
 radius : xx;

            canvas[yy][xx] 
=
 fillChar;
        }
    }
    
    
/**

     * 将画完图之后的画布输出到控制台上
     * 
@param  canvas
     
*/

    
public static void printCanvas(char [][] canvas) {
        
for (int i = 0; i < canvas.length; i++
) {
            
for (int j = 0; j < canvas[i].length; j++
) {
                System.out.print(canvas[i][j]);
            }
            System.out.println();
        }
    }
}

下图是一个半径为 20,旋转度为 0 度的五角星控制台输出。

下图是一个半径为 20,旋转度为 15 度的五角星控制台输出。

相关推荐

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

火龙果被占用了

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值