第3章 数学基础
在绘制图形和动画时往往需要计算点、线、面之间的关系,这其中包含了很多数学运算。Processing提供了很多数学函数,方便开发者使用。
3.1 数学计算
对于数学计算中常用到的运算,Processing给出了一系列函数,如表3-1所示。
表3-1 数学计算函数表
❑abs(a)返回a的绝对值。
3-1 int a = abs(153); //a赋值为153 int b = abs(-15); //b赋值为15 float c = abs(12.234); //c赋值为12.234 float d = abs(-9.23); //d赋值为9.23
❑ceil(a)向上取整。
3-2 float x = 8.22; int a = ceil(x); //a赋值为9
❑max()取最大值,有两种重载(min类似)。
3-3 int a = max(5, 9); //a赋值为9 int b = max(-4, -12); //b赋值为-4 float c = max(12.3, 230.24); //c赋值为230.24 int[] values = { 9, -4, 362, 21 }; //创建一个整型数组 int d = max(values); //d赋值为362
❑log(a)返回以e为底,a为真数的对数lna。
3-4 // 求lg float a = log(5)/log(10); //a赋值为0.69897
❑dist(x1, y1, x2, y2)返回两点间的距离。
3-5 // 求点(1,1)到点(4,5)间的距离 float d = dist(1,1,4,5); //d赋值为5.0
3.2 三角函数
对于有关三角的常用运算,Processing给出了一系列函数,如表3-2所示。
表3-2 三角函数表
与数学中的不一样,Processing中默认以顺时针方向旋转为正方向,另外用PI表示π。
3-6 float a = PI/6; println(sin(a)); //输出0.5 println(degrees(a)); //输出30.0 println(a); //输出0.5235988
atan和atan2都是反正切函数,它们之间有以下两点不同:
1)参数的填写方式不同。
例如:有两个点p1(x1, y1)和p2(x2, y2),这两个点形成的斜率的弧度计算方法分别是:
3-7 float radian = atan( (y2-y1)/(x2-x1) );
或
3-8 float radian = atan2( y2-y1, x2-x1 );
2)在二、三象限函数的返回结果不同。
3-9 // 在第二象限时 float x = -1.7320508; float y = 1; float tan = atan(y/x); float tan2 = atan2(y/x); println(degrees(tan)); //输出:-30.0 println(degrees(tan2)); //输出:149.9999 3-10 // 在第三象限时 float x = -1.7320508; float y = -1; float tan = atan(y/x); float tan2 = atan2(y/x); println(degrees(tan)); //输出:30.0 println(degrees(tan2)); //输出:-149.9999
结论:为了根据x、y坐标求得正确的角度,建议使用atan2函数。
3.3 功能映射函数
对于有关映射的运算,Processing给出了一系列函数,见表3-3。
表3-3 映射函数表
❑constrain()通过最大值和最小值来约束指定的数。
constrain(amt, low, high) amt: int或float low:最小值 high:最大值
原理:如果amt≥high为真则返回high,如果amt≤low为真则返回low,否则返回amt。
3-11 println(constrain(10,20,80)); //输出20 println(constrain(50,20,80)); //输出50 println(constrain(90,20,80)); //输出90
❑lerp()用于在指定的两数之间线性插值。
lerp(start, stop, amt) start:开始值 stop:结束值 amt:int或float值
插值原理:start+(stop-start)*amt
3-12 float x=lerp(50, 100, 0.1); //将55.0赋值给x float y=lerp(50, 100, 0.5) ; //将75.0赋值给y
❑norm()用于把指定数从指定范围映射到0.0~1.0。
norm(value, start, stop) start:开始值 stop:结束值 value:int或float值
原理:(value-start)/(stop-start)
3-13 float x=norm(60, 50, 100); //将0.2赋值给x float y=norm(45, 50, 100) ; //将-0.1赋值给y float z=norm(110, 50, 100) ; //将1.2赋值给z
❑map()用于把指定数从指定范围映射到另一个范围。
map (value, start1, stop1, start2, stop2) start1:第一个范围开始值 stop1:第一个范围结束值 start2:第二个范围开始值 stop2:第二个范围结束值 value:int或float值
原理:start2+(stop2-start2)*norm(value, start1, stop1)
3-14 float x=map(55, 50, 100,500,1000) ; //将550.0赋值给x float y=map(40, 50, 100,500,1000) ; //将400.0赋值给y float z=map(110, 50, 100,500,1000) ; //将1100赋值给z
3.4 随机数
1.随机数
在Processing中,如果想要获取随机的动画效果,就要用到和随机数相关的函数。
random()函数返回一个从0到指定数值范围内的随机数。
random(float x) x为float类型数值
示例:
3-15 float a=random(20); // a为0~20的一个随机数
重载函数random(float x, float y)可以返回两个指定数值之间的随机数。
random(float x, float y) x为float类型数值 y为float类型数值
示例:
3-16 float a=random(10,20); //a为10~20的一个随机数
当编程人员想获取随机整数时,需要对随机数进行类型转换。
示例:
3-17 int a=(int)random(10,20); //a为10~20的一个随机整数
示例:在大小为400×400的窗口下绘制16个相等的正方形,使它们的颜色呈随机灰度,如图3-1所示。
3-18 void setup() { size(400,400); //窗口大小设置为400×400 } void draw() { for(int i=0; i<4; i++) //第i行 { for(int j=0; j<4; j++) //第j列 { fill(random(255)); //填充颜色为随机灰度 rect(i*100, j*100,100,100); //画出宽和高都为100的矩形 } } delay(100); //延迟100毫秒 }
2.随机数种子
随机数又分为两种,一种是真随机数,另一种是伪随机数。
真随机数是计算机通过对外界信息的采集而获取的。例如,用户敲击键盘的时间,原子的放射性衰变的时间。这些信息都是不可预测的,于是就能获取真随机数。
在Processing中,通过random()函数产生的随机数并不是真正的随机数,它们是“伪随机数”。所获取的伪随机数都是通过向计算机发送一个种子值,然后计算机通过算法计算并返回一个看上去像是随机值的数。实际上,通过这种方法获得的随机数都是可以预测的。
图3-1 随机灰度格子
通过设置随机数种子值就能每次都获取相同的随机数序列。
randomSeed(long x); x为long类型数值
示例:在窗口大小为400×400下绘制16个相等的正方形,使它们同一行灰度相同,不同行呈随机灰度,如图3-2所示。
3-19 void setup() { size(400,400); //窗口大小设置为400×400 } void draw() { for(int i=0; i<4; i++) //第i行 { randomSeed(5); //设置随机数种子 for(int j=0; j<4; j++) //第j列 { fill(random(255)); //填充颜色为随机灰度 rect(i*100, j*100,100,100); //画出宽和高都为100的矩形 } delay(100); //延迟100毫秒 }
图3-2 随机数种子生成相同随机数序列
示例:随机产生几个数,为圆的半径,放入数组,每隔一秒调用一个数组的半径。
float[] a=new float[10]; //定义一个长度为10的浮点型数组 int j=0; void setup() { frameRate(1); //每秒刷新一次画面 for(int i=0; i<10; i++) a[i]=random(100); //把随机生成的数放入数组 } void draw() { background(204); //背景设置为灰色 if(j<10) ellipse(50,50, a[j], a[j]); j++; }