一起Talk Android吧(第四百一十三回:使用三角函数绘制正弦波)

Posted talk_8

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起Talk Android吧(第四百一十三回:使用三角函数绘制正弦波)相关的知识,希望对你有一定的参考价值。

文章目录

各位看官们,大家好,上一回中咱们说的例子是"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中"使用三角函数绘制正弦波"的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

以上是关于一起Talk Android吧(第四百一十三回:使用三角函数绘制正弦波)的主要内容,如果未能解决你的问题,请参考以下文章

一起Talk Android吧(第五百一十三回:Java中的byte数组与int变量相互转换)

一起Talk Android吧(第四百一十回:绘制曲线)

一起Talk Android吧(第四百一十八回:制作时钟)

一起Talk Android吧(第四百一十一回:绘制文字)

一起Talk Android吧(第四百一十六回:绘制正弦波总结)

一起Talk Android吧(第四百一十九回:让时钟走起来)