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


    各位看官们,大家好,上一回中咱们说的例子是"Math类常用方法介绍",这一回咱们介绍的例子是使用三角函数绘制正弦波。闲话休提,言归正转,让我们一起Talk Android吧!

    看官们,我们在前面章回中介绍了Math类中常用的方法,本章回中将做综合的演示,我们主要使用Math类中的三角函数来绘制一个正弦波。

    整体思路

    使用路径来绘制正弦波,首先需要在路径中添加正弦波上的关键点,我们使用p来作为关键点。它的坐标(px,py)通过三角函数计算出来,具体的公式如下:

    px = cosθ*r
    py = sinθ*r.
    
    • 1
    • 2

    其中θ为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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    上面的示例程序中都添加有详细的注释,方便大家参考。我在这里就不演示程序的运行效果了,建议大家自己动手去实践。

    注意事项

    在实际编程中,我总结出一些关于Math类中相关方法的使用注意事项,在此写出来和大家分享,欢迎大家在评论区交流与讨论:

    • 1.在path中添加的关键点越多,圆弧效果越明显,如果不想添加太多的关键点那么使用路径的圆角效果,这样至少可以减少1/3的点;
    • 2.使用坐标时尽量使用float和double,不要使用int,这样更加精确一些,不然可能会导致部分点的坐标相同;
    • 3.正弦和余弦方法都有使用条件,就是说它的参数和计算结果(数学中叫值域)都有使用范围,比如30度和150度角的正弦值相等。不同的角度得到相同的值,这会对我们的运算结果产生影响,正弦值在-π/2到π/2区间内有效,余弦值在-π到0之间有效。其它的我们就不一一列出了,可以参考相关的数学知识。

    看官们,关于Android中"使用三角函数绘制正弦波"的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

  • 相关阅读:
    js中this的原理详解(web前端开发javascript语法基础)
    css主题切换
    常用的git分支管理方法都在这了
    SpringMVC学习
    第16章大数据定制篇-Shell编程
    【毕业设计】基于单片机的蓝牙相机设计与实现 - 物联网 单片机 嵌入式
    紫光同创FPGA图像视频采集系统,提供2套PDS工程源码和技术支持
    算法通过村第十关-并归|黄金笔记|手撕并归排序
    C中结构体和C++类各自对象的大小——C++
    高并发系统 - 接口幂等技术方案,高可用系统架构与技术选型
  • 原文地址:https://blog.csdn.net/talk_8/article/details/127871347