笛卡尔与心形线故事_笛卡尔的故事

笛卡尔与心形线故事_笛卡尔的故事说明写这篇文章是某天看到这样一个公式r=a(1-cosθ),我上网搜了下,原来是笛卡尔心形线的极坐标方程,这个方程里的确有一个浪漫又悲情的爱情故事,感兴趣的朋友可以点这里看看,而至于这个故事是真是假,这并不重要。而这篇文章的目的是要用前端的方式,画出笛卡尔心形线。本来我想,这么经典的公式,网上应该已经有人实现过了的吧。我搜了搜,不得不佩服网友们,有Java实现的,有C#…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

说明

写这篇文章是因为某天看到这样一个公式 r=a(1-cosθ) ,我上网搜了下,原来是笛卡尔心形线的极坐标方程,这个方程里面的确有一个浪漫又悲情的爱情故事,感兴趣的朋友可以点这里看看,而至于这个故事是真是假,这 并不重要。

而这篇文章的目的是要用前端的方式,画出笛卡尔心形线。
本来我想,这么经典的公式,网上应该已经有人实现过了吧。
我搜了搜,不得不佩服网友们,有 Java 实现的有 C# 实现的也有 canvas 实现的还能用 ECharts 画 ,可以学习学习。

好的,开始正文!
先来了解下心形线

心形线,是一个圆上的固定一点在它绕着与其相切且半径相同的另外一个圆周滚动时所形成的轨迹,因其形状像心形而得名。

这里写图片描述

因为 canvas 是直角坐标系的,所以先来看

平面直角坐标系 画法

先贴出网上搜来的 心形线的平面直角坐标系方程表达式
分别为 x^2+y^2+a*x=a*sqrt(x^2+y^2)x^2+y^2-a*x=a*sqrt(x^2+y^2

为什么会有两个方程表达式?
因为心形线的水平方向 和 垂直方向 对应的方程表达式不同,而用相同的方程表达式画的心形线,把每个点的 x 坐标和 y 坐标交换下,又会改变方向,所以会有两个方程表达式。
这里写图片描述

好了,开始画吧,看看这位朋友的做法
思路
根据方程表达式得到所有点的坐标,然后把每个点连接起来,然后填充,最后就行成一个心形了。

参数方程

x=a*(2*sin(t)+sin(2*t))
y=a*(2*cos(t)+cos(2*t))

x,y 分别表示一个点的 x 坐标 和 y 坐标,
a:是一个常数,用来控制心形的大小,
t :代表 弧度
t 的取值范围:-pi<=t<=pi 或 0<=t<=2*pi

代码

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas width="400" height="400"></canvas>
<script> var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.lineWidth = 3; // 将画布的原点(0,0),移动到(200,200) // 移动原点是为了能让整个心形显示出来 context.translate(200,200); // t 代表弧度 var t=0; // maxt 代表 t 的最大值 var maxt = 2*Math.PI; // vt 代表 t 的增量 var vt = 0.01; // 需要循环的次数 var maxi = Math.ceil(maxt/vt); // 保存所有点的坐标的数组 var pointArr=[]; // x 用来暂时保存每次循环得到的 x 坐标 var x=0; // y 用来暂时保存每次循环得到的 y 坐标 var y=0; // 根据方程得到所有点的坐标 for(var i=0;i<=maxi;i++){ 
 // x=a*(2*sin(t)+sin(2*t)) x=50*(2*Math.sin(t)+Math.sin(2*t)); // y=a*(2*cos(t)+cos(2*t)) y=50*(2*Math.cos(t)+Math.cos(2*t)); t+=vt; pointArr.push([x,y]); } // 根据点的坐标,画出心形线 context.moveTo(pointArr[0][0],pointArr[0][1]); draw(); function draw(){ 
 context.fillStyle='#c00'; // 把每个点连接起来 for(var i=1;i<pointArr.length;i++){ 
 x = pointArr[i][0]; y = pointArr[i][1]; context.lineTo(x,y); } context.fill(); } </script>
</body>
</html>

效果图
这里写图片描述

平面直角坐标系 画法 (空心心形)

上面的代码是画一个实心的心形,当然我们也可以画空心的,只需要做出一点点的修改就可以。
我们只需要改改 draw() 函数就好,把原来的 fill() 方法,改为 stroke() 方法,并且把 strokeStyle 设置了颜色就行了。

function draw(){ 

//context.fillStyle='#c00';
context.strokeStyle='#c00';
// 把每个点连接起来
for(var i=1;i<pointArr.length;i++){ 

x = pointArr[i][0];
y = pointArr[i][1];
context.lineTo(x,y);
}
//context.fill();
context.stroke();
}

这里写图片描述

极坐标系画法

极坐标系是这样的
这里写图片描述
极坐标系中确定一个点的位置,靠的是极点(图中点O),和 角度 来确定的。
更多关于极坐标系的知识,可以看看这里

看看这位朋友的做法
思路
根据极坐标方程 r=a(1+sinθ) ,得到 r ,以 r 作为半径,根据 r 连续的去画圆弧,画完一圈后,心形就出来了。

心形线 极坐标方程
r=a(1+sinθ)

代码

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas width="400" height="400"></canvas>
<script> var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); // 将画布的原点(0,0),移动到(200,100) // 移动原点是为了能让整个心形显示出来 context.translate(200, 100); // 画心形 draw(); function draw() { 
 // 画圆弧时,圆的半径 var r = 0; // start 代表画弧线时的 起始角 var start = 0; // end 代表画弧线时的 结束角 var end = 0; // 一个常数,用来控制心形的大小 var a = 100; context.fillStyle = '#e21f27'; //连续的画圆弧 for (var q = 0; q < 500; q++) { 
 start += Math.PI * 2 / 500; // 当 结束角 是 Math.PI * 2 时也就是已经画了一圈了,心形就出来了 end = start + Math.PI * 2 / 500; // 根据极坐标方程 r=a(1+sinθ),得到 r(半径) r = a * (1 + Math.sin(start)); // 画弧线 context.arc(0, 0, r, start, end, false); } context.fill(); } </script>
</body>
</html>

效果图
这里写图片描述

极坐标系 画法 (空心心形)

用极坐标系 画法,画空心心形,也是一样的需要改改 draw() 函数,把原来的 fill() 方法,改为 stroke() 方法,并且把 strokeStyle 设置了颜色就行了。

function draw() { 

var r = 0;
var start = 0;
var end = 0;
var a = 100;
//context.fillStyle = '#e21f27';
context.strokeStyle = '#e21f27';
for (var i = 0; i < 500; i++) { 

start += Math.PI * 2 / 500;
end = start + Math.PI * 2 / 500;
r = a * (1 + Math.sin(start)); 
context.arc(0, 0, r, start, end, false);
}
//context.fill();
// 改用 stroke() 方法
context.stroke();   
}

这里写图片描述

可能你会觉得这样的心形并不好看。
看看这个参数方程吧!

x=16 * (sin(t)) ^ 3;
y=13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)。

根据这个参数方程,用上面说的平面直角坐标系的画法,把代码里的方程换一下,就可以画出这样的心形。
这里写图片描述

代码

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas width="400" height="400"></canvas>
<script> var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.lineWidth = 3; // 将画布的原点(0,0),移动到(200,200) // 移动原点是为了能让整个心形显示出来 context.translate(200,200); // t 代表弧度 var t=0; // vt 代表 t 的增量 var vt = 0.01; // maxt 代表 t 的最大值 var maxt = 2*Math.PI; // 需要循环的次数 var maxi = Math.ceil(maxt/vt); // 保存所有点的坐标的数组 var pointArr=[]; // 控制心形大小 var size = 10; // x 用来暂时保存每次循环得到的 x 坐标 var x=0; // y 用来暂时保存每次循环得到的 y 坐标 var y=0; // 根据方程得到所有点的坐标 for(var i=0;i<=maxi;i++){ 
 // x=16 * (sin(t)) ^ 3; var x = 16 * Math.pow(Math.sin(t),3); // y=13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t) var y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) -2 * Math.cos(3 * t)- Math.cos(4 * t); t+=vt; pointArr.push([x*size,-y*size]); } // 根据点的坐标,画出心形线 context.moveTo(pointArr[0][0],pointArr[0][1]); draw(); function draw(){ 
 context.fillStyle='#c00'; // 把每个点连接起来 for(var i=1;i<pointArr.length;i++){ 
 x = pointArr[i][0]; y = pointArr[i][1]; context.lineTo(x,y); } context.fill(); } </script>
</body>
</html>

也许我们还可以再做点什么,比如加点动画,看看下面这个吧。
这里写图片描述
这里下载源码,里面已经加了很详细的注释了。

总结

这篇文章主要是说用笛卡尔心形线方程画心形,但是想要画出心形的方式绝对是多种多样的,单纯的用CSS也可以,复杂点 用贝塞尔曲线也能画出来,大家不妨去试试,说不定又有什么新发现呢。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181337.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • java个人微信消息接收_java接口接收json数据

    java个人微信消息接收_java接口接收json数据微信公众平台java服务器认证、接收文本消息和图片消息并实现返回,订阅服务号实现了通过微信接收信息转发至java后台解析并回复的消息的简单功能,贡献出代码希望能给大家一个参考

  • 英雄联盟的搞笑段子_lol幸运召唤师

    英雄联盟的搞笑段子_lol幸运召唤师英雄联盟LOL的搞笑段子  据调查,20%高考考生入场前,都会喊一声德玛西亚监考老师还有30秒到达考场,碾碎他们 考试ing老师本来在中间巡查,正要去右边,一同学突然大喊,中路miss,这孩纸意识不错 监考老师,慢慢的从后往前走,突然冲刺到A君后面,伸手抓向A君裤裆,拿出了他的手机。淡然一笑,firstblood!(一血了) 某考生考前问同学,这次都没学好呢,考试又

  • finalize方法作用_Java finalize

    finalize方法作用_Java finalize关于object类中的finalize()方法。1、在object类中的源代码:protectedvoidfinalize()throwsThrowable{}2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。3、这个方法不需要程序员手动调用,JvM的垃圾回收器负责调用这个方法。4、finalize()方法的执行时机:当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用finalize()方法。5、finalize()方法实际上

  • Word在试图打开文件时遇到错误,请尝试下列方法:检查文档或驱动器的文件权限 确保有足够的内存和磁盘空间 用文本恢器打开文件

    Word在试图打开文件时遇到错误,请尝试下列方法:检查文档或驱动器的文件权限 确保有足够的内存和磁盘空间 用文本恢器打开文件Word在试图打开文件时遇到错误,请尝试下列方法:检查文档或驱动器的文件权限确保有足够的内存和磁盘空间用文本恢器打开文件 。经常在浏览器上直接下载的文档打开就报这个错,也不知道是什么原因,最后发现就是文件的权限。解决方法:右键该文档属性:在解除锁定这里√上就ojbk了。 …

  • SAP 常用的BAPI

    SAP 常用的BAPIBAPI_ALE_MODEL_GETBAPI_BARCODE_SENDLISTBAPI_ANSWER_READMULTIPLEBAPI_APPCOMP_READMULTIPLEBAPI_PROCDIA_READMULTIPLEBAPI_PROCDIA_WRITEMULTIPLEBAPI_DIAVAR_READMULTIPLEBAPI_DIAVAR_WRITEMULTIPLEBAPI_PROCE

  • rabbitmq集群搭建「建议收藏」

    rabbitmq集群搭建「建议收藏」一、基础安装前提:三个节点都主机映射,关防火墙网络,配好yum(后边出错,主机名和映射要对应)1.安装(三个节点)2.mq1启动rabbitmq服务查看状态3.配置界面访问4.使用界面查看(端口15672,默认帐户和密码guest)二、配置rabbitmq集群服务1.先构建erlang集群①复制cookie认证②配置节点加入集群(顺序很重要,解决报错看)123的顺序停止321的顺序启动rabbitmq服务

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号