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

news2025/7/6 12:12:00

文章目录

  • 整体思路
  • 图形讲解
  • 示例程序
  • 注意事项

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/7438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode-每日一题-1710-卡车上的最大单元数(简单,哈希,暴力)

今天的这道题其实很好读懂,因为很容易可以看出来暴力求解,但其实还是隐藏一个hash求解法很巧妙,因为我在很久之前就用过hash解答过这样类似的题,所以这个题也是可以使用的,可以看看我第二个hash解法 目录 暴力效率(效…

SBF vs. 火柴大王

生活中的一切都建立在自信之上。”Ivar Kreuger1929年10月28日,瑞典商人Ivar Kreuger出现在《时代》杂志的封面上。 他是当时美国最受关注的人物之一,因为他富有、有权势、神秘。Kreuger控制着四分之三的火柴生产和销售,在全球35个不同国家拥…

wy的leetcode刷题记录_Day43

wy的leetcode刷题记录_Day40 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间:2022-11-15 前言 今天时间比较多而且题目比较简单,应该能写三四道题。 目录wy的leetcode刷题记录_Day40声明前言1710. 卡车上的最大单元数题目介…

Spectacle源码编译方法

一、简介 Spectacle 是一个用于抓取桌面截图的简单应用程序。它可以抓取整个桌面、单个显示器、当前活动窗口、鼠标所在的窗口或是屏幕上的一块矩形区域的图像。截取的图像可被打印、发送到其他应用程序进行处理、或是直接保存下来。 Spectacle是archlinux wiki中推荐KDE使用…

刘二大人CNN

10.卷积神经网络(基础篇)_哔哩哔哩_bilibili 0、前一部分 卷积层 和 subsampling 叫做Feature Extraction特征提取器,后一部分叫做classification 1、每一个卷积核它的通道数量要求和输入通道是一样的。这种卷积核的总数有多少个和你输出通…

SpringBoot+Vue项目医院挂号系统的设计与实现

文末获取源码 开发语言:Java 使用框架:spring boot 前端技术:JavaScript、Vue 、css3 开发工具:IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库:MySQL 5.7/8.0 数据库管理工具:phpstudy/Navicat JDK版…

2.6 自定义srv python

功能介绍 以自定义数据类型为基础,完成一个节点作为服务器,另一个节点接收传送两个数字到服务端,服务端计算后反馈到客户端进行打印输出 1、工作空间 1.1 创建工作空间lee_ws mkdir -p ~/lee_ws/src cd ~/lee_ws/src/ catkin_init_worksp…

leetcode134.加油站 贪心法求解 (c++版本)

题目描述 题目比较长,明确以下这点就可以 gas数组是当前下标i加油站所能加的油cost数组是从当前下标i加油站到下一加油站所消耗的油那么gas [i]与cost [i] 的大小就决定了车辆能否从当前加油站出发到达下一加油站 上面三点非常重要是能正确做出题目的必须要求 其实…

字符流,编码表,字符流写数据,字符流读数据

文章目录前言字符流编码表字符串中的编码解码问题字符流写数据字符流读数据总结前言 因为近期考试原因,还有自身惰性的问题,小编最近停更了一段时间,随之而来的罪恶感让我又开启了自学与创作之路,学习这么久,自己虽然…

来源稳定的l2逐笔接口数据去哪找?

l2逐笔接口的逐笔数据的最初来源均是从交易所获取,其授予了一些信息服务商L2非展示数据接口转发权限,其中包含了逐笔成交、逐笔委托等数据。使用时,通常是从信息商处购买,比如同花顺、万得、国泰安等等。那么小编认为通过交易所授…

mysql中find_in_set()函数的使用及in()用法详解

MySQL手册中find_in_set函数的语法解释: FIND_IN_SET(str,strlist) str 要查询的字符串 strlist 字段名 参数以”,”分隔 如 (1,2,6,8,10,22) 查询字段(strlist)中包含(str)的结果,返回结果为null或记录 假如字符串str在由N个子链组成的字符串列表strli…

Linux:rpm与yum(内含:1.rpm介绍+2.卸载rpm包+3.安装rpm(应用案例)+4.yum(应用案例))

1.rpm介绍使用: 实例:查看当前系统是否安装了 firefox ,操作如下: 解释: 名称:firefox 版本号:91.11.0-2 使用操作系统:el7.centos.x86_64 表示centos.x的64位系统。 查询软件包是否安装&#…

跨境电商卖家必知的9个圣诞节营销技巧

关键词:跨境电商卖家、圣诞节营销 圣诞节——对跨境电商卖家来说是非常重要的促销节日。根据以往的经验,您或许已经有了初步的促销想法,想知道您今年的跨境电子商务营销策略是否正确?为您整理了跨境电商卖家必须注意的营销技巧&am…

TiDB数据库架构——TiDB Server

TiDB Server架构 TiDB Server 是SQL层,无状态,启动多个TiDBServer,均匀分摊,解析SQL,获取真实数据。 Protocol Layer、:负责客户端的连接。 Parse、Compile:负责SQL语句的解析和编译&#xff…

信息控制信息卷积

🍿*★,*:.☆欢迎您/$:*.★* 🍿 目录 背景

少儿编程 电子学会图形化 scratch编程等级考试四级真题答案解析(判断题)2022年9月

目录 2022年9月scratch编程等级考试四级真题 判断题(共10题,每题2分,共20分) 推荐资料

java学生作业带选课管理系统ssh

1.管理员具有对学校课程信息,教师信息,学生信息增删改查的权限 (1)可以录入学校所开课程,学生信息,教师信息; (2)可以对教师的开课信息进行增加,删除&#xf…

什么是 DeGods NFT 系列?

Nov. 2022, Vincy Data Source: Footprint Analytics - DeGods NFT Collection DeGods 系列有 10,000 个 Solana 铸造头牌的 NFT。 DeGods 持有者拥有访问 DeDAO 的权限和社区。 它在 1 月推出 DUST 协议,允许持有者质押他们的 DeGods NFT 并赚取 DUST。 10 月 …

cmake 工具 三 add_libary, set_target_properties,link_libary, target_link_libary

一起通过一个例子学一下 add_libary, set_target_properties,link_libary, target_link_libary 四个命令 首先创建如下的文件: 其中 build用于cmake编译,防止大量编译的中间文件污染代码文件夹具体可见cmake 构建工具…

手机端宝贝描述中每张图片的宽要在480到1500之间,最大高度为2500, 以下图片不满足

上图是近期小编与一位店主的聊天截图,从截图中我们可以知道,这位店主在使用复制软件来复制宝贝上传时出现了一些问题,下面,小编将上传出现的错误、分析过程及解决方法列示如下,希望能给其他店主一些帮助:查…