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

笛卡尔与心形线故事_笛卡尔的故事说明写这篇文章是某天看到这样一个公式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也可以,复杂点 用贝塞尔曲线也能画出来,大家不妨去试试,说不定又有什么新发现呢。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 第三篇 从EXCEL电子表格到数据库

    第三篇 从EXCEL电子表格到数据库

    2021年9月10日
    47
  • js特殊符号正则表达式_js正则表达式判断特殊字符

    js特殊符号正则表达式_js正则表达式判断特殊字符JavaScript正则表达式功能:搜索、替换、判断JavaScript正则表达式格式:/正则表达式主体/修饰符JavaScript正则表达式的修饰符:i:忽略大小写g:全局匹配m:多行匹配JavaScript中正则表达式应用场景:搜索功能(字符串方法)search()方法参数为字符串或者是正则表达式返回结果为匹配成功的索引值,如果没有,返回-1替换功能(字符串方法)r…

    2025年11月12日
    5
  • 安卓四大组件面试题_android常见面试题

    安卓四大组件面试题_android常见面试题1、Activity与Fragment之间常见的几种通信方式答:1.使用Bundle:在activity中建一个bundle,把要传的值存入bundle,然后通过fragment的setArguments(bundle)传到fragment,在fragment中,用getArguments接收。这个方法能保证在fragment销毁重建后依然能获取到传递过来的数据。2.采用接口回调的方式。3.EventBus。2.谈谈Android中几种LaunchMode的特点和应用场景?

    2022年8月26日
    8
  • IDEA如何使用热部署方式启动项目?

    IDEA如何使用热部署方式启动项目?热部署可以使的修改代码后,无须重启服务器,就可以加载更改的代码。具体步骤一、开启IDEA的自动编译(静态编译)操作步骤:打开顶部工具栏File->Settings->DefaultSettings->Build->Compiler然后勾选Buildprojectautomatically。二、开启IDEA的自动编译(动态编译…

    2022年5月21日
    114
  • SFM原理简介「建议收藏」

    SFM原理简介「建议收藏」StructureFromMotionSFM简介通过相机的移动来确定目标的空间和几何关系,是三维重建的一种常见方法。它与Kinect这种3D摄像头最大的不同在于,它只需要普通的RGB摄像头即可,因此成本更低廉,且受环境约束较小,在室内和室外均能使用。SFM基本原理小孔相机模型在计算机视觉中,最常用的相机模型就是小孔成像模型,它将相机的透镜组简化为一个小孔…

    2022年6月20日
    31
  • html自动写对联,HTML 实现网站对联广告位

    html自动写对联,HTML 实现网站对联广告位分享一个对联广告位的代码 网站通用 留着存放 哪天说不定用到了 html 代码 放到固定的位置 css 样式代码 index wall left width 350px height 528px position absolute top 120px margin left 366px background url https eimg smzdm com 201912 23 5e00

    2025年12月6日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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