基于Java的简易函数图像绘制程序设计

[日期:2023-10-17] 作者:信息技术 次浏览 [字体: ]

2024届5班 史哲予  指导教师:旷勇

程序设计就像一扇充满魔力的大门,只需要一把钥匙,你就可以创造一个属于自己的世界,而这扇门的钥匙就是一门可以与电脑对话的程序设计语言。对我而言,程序设计最大的魅力在于无论是使用电脑时的个性化需求,或是日常学习中所涉及的知识点,它都可以与之完美契合!而当程序在你眼前完美运行时,你的愉悦之情也是难以替代的。于是,设计编写各种有趣实用的程序成为了我的兴趣之一。

Java当前最流行的程序设计语言之一。它的特点显而易见:简单、面向对象、安全、高性能以及跨平台等。它可以在各种电脑、手机、移动设备、终端,以及各种操作系统上成功运行。凭借着现代信息技术的飞速发展,Java被大范围地使用。大型应用程序、Web及服务器后台处理、大数据技术、集成开发工具等都由它开发。在尖端领域,Java造就了Maestro火星探测器控制器、世界上最快的图形分析引擎之一(PGX)以及耗资30亿美元的集成基因组浏览器(IGB)。当然,还有最受欢迎的游戏Minecraft。

有了这样一个强大的程序开发设计平台,我们就可以开启今天的函数图像可视化进程了。函数通常由两个变量(Variable)组成,自变量(Argument)和因变量(Dependent variable)。如:y=x,表示了因变量与自变量的“相等关系”。各个自变量都有对应的因变量。函数图像(Function image)即是以x与y为坐标的点在平面直角坐标系中组成的图像。数学课上,函数图像的绘制只需三步:列表、描点、连接。使用同样的方式在电脑上更能轻而易举地实现确定三个因素:解析式、自变量的取值范围以及步长通过循环结构绘制图像即可。接下来我们就来进行算法分析…...

首先,我们需要以窗口几何中心为原点,向右、上方为正方向建立一个直角坐标系。接下来,通过循环绘制,需要在程序里创建四个变量:xo,yo,x,y。这些变量分别表示初始x,y值,改变后的x,y值。它们可以组成两组坐标,两组坐标用线段来连接就构成了一段函数图像。其中,xo与x是随着循环直接变化的变量,xo的初值默认为-10800,而x则是xo按单位步长Δx自增后的值。即:x = xo + Δx (Δx>0)。

x与xo、y与yo是函数图像坐标系对应计算机窗口坐标系的偏移值。由于在Java绘图中,窗口的坐标系是以左上角为原点,向右、下方为正方向,而数学中函数的坐标都是相对于原点即窗口中心的,而且以右、上为正方向。因此,这里我们要使用ORIGIN_X和ORIGIN_Y两个常量(Const)对坐标系的偏移量进行修正,将函数图像坐标系映射到计算机窗口坐标系中。

xo初始化为最小,即-10800,并计算出yo。然后在自变量的取值范围内,从小到大以最小单位长度为步长列举x,计算出y。以(xo,yo)至(x,y)画线段,完成后将xo,yo的值分别用x,y替代,进入下一次迭代,思路如图所示。

 

接下来开始代码编写。我所使用的是IntelliJ IDEA来进行开发,配置环境为JDK 11.0.12。按照惯例配置好开发环境项目结构等。首先,要显示出图像,窗口是必备的。Java提供了JFrame类,创建自己的窗口就需要继承自JFrame,也就是将自己的类作为一个拥有JFrame所有功能和属性的对象。然后声明窗口宽和高,并重写(Override)JFrame提供的paint方法以绘制函数图像。

现在我们已经拥有了自己的窗口,我们可以对窗口进行优化。直角坐标系的绘制可以分为三步:找到原点并画出坐标轴、画出标尺、画出格子。全部都可以通过调用drawLine方法画直线完成。原点坐标即(W/2,H/2),而坐标轴即画直线y = H/2 和x = W/2,标尺则可以用给定长度(如40px)在对应位置画线段来实现。但是这两步要等到最后做,必须要先画格子,这样才不会把坐标轴遮住。为了不干扰坐标轴和函数图像,格子可以更改为浅一点的颜色,同时,与标尺重合画出坐标轴的刻度。

现在窗口已经完工。但是运行程序需要一个main方法,也就是主线程(Main Thread)。我们直接在下面创建main方法,先生成窗口对象,然后设置大小、位置、可见性等属性值,然后运行。一个简单的直角坐标系就这样完成了!

接下来是实现任意函数图像的绘制。在paint方法中使用一个循环,循环参数i的初始值设置为-10800。在i≤10800时,i循环每执行一次,i都要自增,然后按相应函数表达式进行运算、绘图。

最大的难点在于步长。在Java绘图中,各个点的坐标只能为整数(Integer)。步长被限制在一个像素(1px)以外,导致曲线太不精确,弧度太大就会变成一个个锯齿状的“台阶”。但实际上我们可以利用编程语言的不同的变量类型来巧妙解决这个问题。当你给一个int变量赋值为小数时,Java会自动将这个值取整。在这一点的帮助下,我们可以在一开始就定义一个小数变量arc来表示自变量。每一次循环开始,arc赋值为PI×i÷360。注意,这里的PI只是为了让i的值自动转化为更小的双精度小数类型(Double)。理论上,“360”替换成更大的数,绘图的精度也就会越高。但由于i的取值范围不会变,所以,把360改成更大的数反而会让电脑不堪重负,并且只画出小部分图像,一味追求高精度并没有多大实际意义。       

到现在,我们的函数绘制已经完成了。但是我们可以发现,由于我们进行了奇幻的操作,函数画出来的图像很小。所以需要加上一个小变量:

private static int SCALE_X = 40;  private static int SCALE_Y = 40;)由它们来控制图像的缩放。这就像一次函数中的k值一样,直接在arc到x,y的值转换前先将×进行适当的缩放就行了。核心代码及绘制的正弦函数图像如下。

         


       ( y = sin x函数图像)

最后,我们还可以为这个程序增添一些拓展功能。让这个窗口实现KeyListener接口,重写方法还可以实现用键盘来控制图像位置(改动ORIGIN_...和SCALE_…即可)。由于在绘图时容易出现掉帧,用双缓存技术可以更好地绘制图像,即将所有图像先画到一个Image上,再将它画到窗口上,掉帧的问题就这样迎刃而解了!感兴趣的同学可以联系我阅读完整源代码了解一下。