java画图板之平面山水画(一)

前期准备

    在上次的博客中,我们已经用java了解并制作了画图板,可以在上面添加绘制椭圆、曲线、填充、改变颜色等功能,在之后的版本中会进行修改。
    今天要做的是通过递归的方式绘制山脉。

具体步骤

1、窗体的设计

    这一部分没有什么需要具体描述的,步骤按照前一个博客中的进行设计就好。需要注意的是窗体背景的设置需要用到Panel组件,直接set是没有用的。

public class background {

	public void showbg() {
		JFrame bg = new JFrame();
		// 设置窗体基本属性
		bg.setTitle("地球平原");
		bg.setSize(800, 600);
		bg.setLocationRelativeTo(null);
		// 窗体关闭时结束程序
		bg.setDefaultCloseOperation(bg.EXIT_ON_CLOSE);
		// 设置背景颜色,直接设置没有用,需要用Panel组件
		Color bgcolor = new Color(255, 255, 255);
		bg.getContentPane().setBackground(bgcolor);

		// 设置布局,放在可见前才显示
		FlowLayout flow = new FlowLayout();
		bg.setLayout(flow);
		
		// 设置可见,并获取画布对象
		bg.setVisible(true);
		Graphics g = bg.getGraphics();
		// 设置鼠标监听器
		MouseListener mouselistener = new MouseListener();
		bg.addMouseListener(mouselistener);
	}

	public static void main(String args[]) {
		background bg = new background();
		bg.showbg();
	}
}

2、山脉的绘制

    这部分是整个绘制的重点,比较考验递归的思维。

  • 大致思路是取一条水平横线,计算横线两个端点(记为P,Q)的中点M’,将中点向上或者向下平移一段距离,得到新的点M。
    ----将P和M两点作为新的端点重复上述过程
    ----将M和Q两点也作为新的端点重复上述过程
    最终将所得的所有点连起来,这样我们就会得到一条折线,只要对变化时的参数进行控制,就会呈现山脉的效果。
  • 整个的迭代过程类似于一个满二叉树。times为二叉树的总层数,timescounter为这一次调用函数时所在的那一层。
        public void showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter) {
        double midx, midy;
        //计算中点坐标
        midx = (startx + endx) / 2;
        midy = (starty + endy) / 2 + (Math.random() * 2 - 1)/*正负号*/ * range;
        if (timescounter++ == times) {
        	//画山脉轮廓
            g.drawLine((int) startx, (int) starty, (int) midx, (int) midy);
            g.drawLine((int) midx, (int) midy, (int) endx, (int) endy);
        } else {
        	//随着相邻两个点的横坐标距离减少,纵坐标随机起伏范围也要减小
            range *= rate;
            //递归
            showmt(startx, starty, midx, midy, mtcolor, range, timescounter);
            showmt(midx, midy, endx, endy, mtcolor, range, timescounter);
        }
    }

    如果我们对变换时的参数不加控制,就会使得画出的直线类似于噪声的声波,杂乱无章。要画出比较像山脉的图案:

  • 首先,要设置中点上下偏移的范围range,保证不会出现山峰过高或过矮
  • 其次,为了使得山脉更平滑,加入了参数rate∈(0,1),随着timescounter的增加,range*=rate,相邻两点间的高度起伏就不会太大,否则就会如下图所示
    不设置rate
  • 最后timescounter对于每一次函数调用来说都是唯一且独立的,所以一定要放在参数中传入,使得其他函数的调用不会影响到这次函数调用的timescounter。times的值不要太小,会没有山脉的感觉;也不要太大,计算机会处理的很慢。(关于提升绘画速度的会在下一次博客中提到)

3、添加监听器

public class MouseListener implements java.awt.event.MouseListener, ActionListener {

	Graphics g;

	public void setGraphics(Graphics g) {
		this.g = g;
	}

	public void mouseClicked(MouseEvent e) {
	//绘制山脉
		mountain mountain = new mountain();
		mountain.setGraphics(g);
		//此处为伪代码,颜色和位置根据需要修改
		Color mtcolor = new Color( ,,);
		mountain.showmt(0, starty, 800, endy, mtcolor, 100, 1);
		// showmt(double startx, double starty, double endx, double endy, Color mtcolor, double range, double timescounter)
		}
	
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void actionPerformed(ActionEvent e) {	
	}

}

运行结果

  最终画出来应该是这样的轮廓
山脉轮廓

武汉加油!中国加油!

下集预告

    只有轮廓?
    一座山没感觉?
    递归次数多了画图太慢?
    且听下回分解。
    链接:java画图板之平面山水画(二)(附源码)

发布了9 篇原创文章 · 获赞 6 · 访问量 294

猜你喜欢

转载自blog.csdn.net/qq_43348021/article/details/104346805
今日推荐