各位看官们,大家好,上一回中咱们说的例子是"Math类常用方法介绍",这一回咱们介绍的例子是使用三角函数绘制正弦波。闲话休提,言归正转,让我们一起Talk Android吧!
看官们,我们在前面章回中介绍了Math类中常用的方法,本章回中将做综合的演示,我们主要使用Math类中的三角函数来绘制一个正弦波。
整体思路
使用路径来绘制正弦波,首先需要在路径中添加正弦波上的关键点,我们使用p来作为关键点。它的坐标(px,py)
通过三角函数计算出来,具体的公式如下:
px = cosθ*r
py = sinθ*r.
其中θ为p点到圆心之间直线的夹角,r为p点到圆心的直线距离,为了计算方便,我们将它的长度定义为圆半径的长度.这里的圆心是数学坐标中的圆心,我们需要把手机中的坐标转换为数学坐标。
图形讲解
我们使用下面的图形来做说明,这样便于文字描述,图片是手绘的,目前还没有找到合适的绘图工具(绘制几何图形的工具),如果大家有的话,可以推荐给我。
图片中最外层的坐标轴是手机屏幕,只有x和y两个方向,而且都是正值。位于此坐标轴中的十字坐标是数学坐标。圆心为o,我们以点A为正弦波的起点,它与圆心的距离为半径的2倍,在它们之间有一个辅助圆心O1,它到圆心的距离为半径r。这是x正方向的点,在x轴负方向还有一个辅助圆心O2,它和O1对称。这些辅助点的坐标都写在图中了,大家可以参考。
图中还有个四个辅助角,分别是θ1-4,通过这四个辅助角来计算出正弦波上关键点的坐标。计算方法我们在"整体思路"中介绍过了。为了方便观看,图中所有的辅助点和辅助角都使用红色文字表示。图中虚线就是最后画出的正弦波形。
示例程序
//以三角函数的方法计算坐标来画一个圆
private void drawSin(Canvas canvas) {
//200,300为圆心,半径为100
int oX = 500;
int oY = 800;
//半径,正弦跨越了两个半径
int r = 200;
//右侧起点,对应图中点A
int ax = oX + 2*r;
int ay = oY;
canvas.save();
mPath.moveTo(ax,ay);
//绘制(0-90)度角对应的正弦波形
/*
//不使用路径效果时添加的关键点越多,弧度效果越明显
//添加10度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/18)*r),(float) (oY-Math.sin(Math.PI/18)*r));
//添加20度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/9)*r),(float) (oY-Math.sin(Math.PI/9)*r));
//添加30度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/6)*r),(float) (oY-Math.sin(Math.PI/6)*r));
//添加36度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/5)*r),(float) (oY-Math.sin(Math.PI/5)*r));
//添加45度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/4)*r),(float) (oY-Math.sin(Math.PI/4)*r));
//添加50度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*5/18)*r),(float) (oY-Math.sin(Math.PI*5/18)*r));
//添加60度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/3)*r),(float) (oY-Math.sin(Math.PI/3)*r));
//添加70度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*7/18)*r),(float) (oY-Math.sin(Math.PI*7/18)*r));
//添加75度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*15/36)*r),(float) (oY-Math.sin(Math.PI*15/36)*r));
//添加80度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*8/18)*r),(float) (oY-Math.sin(Math.PI*8/18)*r));
//添加85度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*17/36)*r),(float) (oY-Math.sin(Math.PI*17/36)*r));
//添加90度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/2)*r),(float) (oY-Math.sin(Math.PI/2)*r));
*/
//绘制(0-90)度角对应的正弦波形,圆心为O1,辅助角为θ1
//使用路径圆角效果时只需要添加关键的点就可以达到圆弧效果,添加关键点的数量减少2/3
mPath.moveTo(ax,ay);
//添加10度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/18)*r),(float) (oY-Math.sin(Math.PI/18)*r));
//添加30度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/6)*r),(float) (oY-Math.sin(Math.PI/6)*r));
//添加45度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/4)*r),(float) (oY-Math.sin(Math.PI/4)*r));
//添加60度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/3)*r),(float) (oY-Math.sin(Math.PI/3)*r));
//添加80度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI*8/18)*r),(float) (oY-Math.sin(Math.PI*8/18)*r));
//添加90度角对应的点
mPath.lineTo((float) (oX+r+Math.cos(Math.PI/2)*r),(float) (oY-Math.sin(Math.PI/2)*r));
//绘制(90-180)度角对应的正弦波形,圆心为O1,辅助角为θ2
//添加110度角对应的点(注意余弦和正弦函数使用的夹角=180-110)
mPath.lineTo((float) (oX+r-Math.cos(Math.PI*7/18)*r),(float) (oY-Math.sin(Math.PI*7/18)*r));
//添加130度角对应的点
mPath.lineTo((float) (oX+r-Math.cos(Math.PI*5/18)*r),(float) (oY-Math.sin(Math.PI*5/18)*r));
//添加150度角对应的点
mPath.lineTo((float) (oX+r-Math.cos(Math.PI*3/18)*r),(float) (oY-Math.sin(Math.PI*3/18)*r));
//添加170度角对应的点
mPath.lineTo((float) (oX+r-Math.cos(Math.PI*1/18)*r),(float) (oY-Math.sin(Math.PI*1/18)*r));
//添加180度角对应的点
mPath.lineTo((float) (oX+r-Math.cos(0)*r),(float) (oY-Math.sin(0)*r));
//绘制(180-270)度角对应的正弦波形,此时的圆心坐标为(ox-r,oy),辅助角为θ3.按照(0-90)这个区间的方法来计算角度
//添加10度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI/18)*r),(float) (oY+Math.sin(Math.PI/18)*r));
//添加30度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI/6)*r),(float) (oY+Math.sin(Math.PI/6)*r));
//添加45度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI/4)*r),(float) (oY+Math.sin(Math.PI/4)*r));
//添加60度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI/3)*r),(float) (oY+Math.sin(Math.PI/3)*r));
//添加80度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI*8/18)*r),(float) (oY+Math.sin(Math.PI*8/18)*r));
//添加90度角对应的点
mPath.lineTo((float) (oX-r+Math.cos(Math.PI/2)*r),(float) (oY+Math.sin(Math.PI/2)*r));
//绘制(270-360)度角对应的正弦波形,此时的圆心坐标为(ox-r,oy),辅助角为θ4按照(90-180)这个区间的方法来计算角度
//添加110度角对应的点(注意余弦和正弦函数使用的夹角=180-110)
mPath.lineTo((float) (oX-r-Math.cos(Math.PI*7/18)*r),(float) (oY+Math.sin(Math.PI*7/18)*r));
//添加130度角对应的点
mPath.lineTo((float) (oX-r-Math.cos(Math.PI*5/18)*r),(float) (oY+Math.sin(Math.PI*5/18)*r));
//添加150度角对应的点
mPath.lineTo((float) (oX-r-Math.cos(Math.PI*3/18)*r),(float) (oY+Math.sin(Math.PI*3/18)*r));
//添加170度角对应的点
mPath.lineTo((float) (oX-r-Math.cos(Math.PI*1/18)*r),(float) (oY+Math.sin(Math.PI*1/18)*r));
//添加180度角对应的点
mPath.lineTo((float) (oX-r-Math.cos(0)*r),(float) (oY+Math.sin(0)*r));
//使用路径的圆角效果来画曲线,类的参数为圆角的半径,半径越大圆角的弧形越明显
PathEffect effect = new CornerPathEffect(200);
mArcPaint.setPathEffect(effect);
canvas.drawPath(mPath,mArcPaint);
canvas.restore();
}
上面的示例程序中都添加有详细的注释,方便大家参考。我在这里就不演示程序的运行效果了,建议大家自己动手去实践。
注意事项
在实际编程中,我总结出一些关于Math类中相关方法的使用注意事项,在此写出来和大家分享,欢迎大家在评论区交流与讨论:
- 1.在path中添加的关键点越多,圆弧效果越明显,如果不想添加太多的关键点那么使用路径的圆角效果,这样至少可以减少1/3的点;
- 2.使用坐标时尽量使用float和double,不要使用int,这样更加精确一些,不然可能会导致部分点的坐标相同;
- 3.正弦和余弦方法都有使用条件,就是说它的参数和计算结果(数学中叫值域)都有使用范围,比如30度和150度角的正弦值相等。不同的角度得到相同的值,这会对我们的运算结果产生影响,正弦值在-π/2到π/2区间内有效,余弦值在-π到0之间有效。其它的我们就不一一列出了,可以参考相关的数学知识。
看官们,关于Android中"使用三角函数绘制正弦波"的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!