趣味编程:心形曲线

news2025/1/6 14:47:56

目录

 1.序言

2.代码展示

3.代码详解

3.1 头文件包含

3.2 绘制坐标轴函数 

3.3 main 函数主体部分

4. 小结


 1.序言

2025年的第一篇博客就用这个笛卡尔心形图开篇吧,寓意着新年大家能够有心有所属,祝诸位程序猿 / 程序媛 能够早点遇到自己的另一半。 

2.代码展示

#define _CRT_SECURE_NO_WARNINGS

#include <graphics.h>
#include <conio.h>
#include <math.h>

#define WIDTH	640					// 窗口宽度
#define HEIGHT	480					// 窗口高度
#define PI		3.14159265			// π
#define DISPLAY 3					// 展示出来动圆与定圆的交点及心脏线当前所在点的尺寸
#define ARROW	5					// 箭头的尺寸
#define COPIES	600					// 份数,看要获得心形线上的多少个点
#define SECONDS 5					// 跑完一圈的秒数
using namespace std;

// 画坐标抽
void drawCoordinateAxis()
{
	setlinecolor(DARKGRAY);
	line(WIDTH / 2, HEIGHT / 10, WIDTH / 2, HEIGHT / 10 * 9);
	line(WIDTH / 2, HEIGHT / 10, WIDTH / 2 + ARROW, HEIGHT / 10 + ARROW);
	line(WIDTH / 2, HEIGHT / 10, WIDTH / 2 - ARROW, HEIGHT / 10 + ARROW);

	line(WIDTH / 5, HEIGHT / 2, WIDTH / 5 * 4, HEIGHT / 2);
	line(WIDTH / 5 * 4, HEIGHT / 2, WIDTH / 5 * 4 - ARROW, HEIGHT / 2 - ARROW);
	line(WIDTH / 5 * 4, HEIGHT / 2, WIDTH / 5 * 4 - ARROW, HEIGHT / 2 + ARROW);
}

int main()
{
	initgraph(WIDTH, HEIGHT);
	BeginBatchDraw();
	setlinecolor(BLUE);

	// 画坐标轴,定圆
	double r = min(WIDTH, HEIGHT) / 9;
	circle(WIDTH / 2, HEIGHT / 2, r);
	drawCoordinateAxis();

	setrop2(R2_XORPEN);

	double lastX = WIDTH / 2.0, lastY = HEIGHT / 2 - r;					// 上一个心形线的点的 x,y 值,初始值为 y 轴正方向上距原点 a 个单位长度的点
	for (double a = 0; !_kbhit(); a += PI / COPIES * 2)					// a 为当前弧度
	{
		double x = cos(3.0 / 2.0 * PI + a) * 2 * r + WIDTH / 2;			// 动圆这一个循环的圆心的 x 值
		double y = sin(3.0 / 2.0 * PI + a) * 2 * r + HEIGHT / 2;		// 动圆这一个循环的圆心的 y 值
		double FixedPoint_X = cos(PI / 2.0 + a * 2) * r + x;			// 当前循环动圆的定点对应的 x 值
		double FixedPoint_Y = sin(PI / 2.0 + a * 2) * r + y;			// 当前循环动圆的定点对应的 y 值
		double Contact_X = cos(PI / 2.0 + a) * r + x;					// 当前循环两圆切点在动圆上对应的 x 值
		double Contact_Y = sin(PI / 2.0 + a) * r + y;					// 当前循环两圆切点在动圆上对应的 y 值

		// 画出心形线,只用画这一个循环的点和上一个循环的点的线就行
		setrop2(R2_COPYPEN);
		setlinecolor(YELLOW);
		line(lastX, lastY, FixedPoint_X, FixedPoint_Y);
		setrop2(R2_XORPEN);
		lastX = FixedPoint_X;
		lastY = FixedPoint_Y;

		// 动圆与定圆的切点
		setfillcolor(GREEN);
		solidcircle(Contact_X, Contact_Y, DISPLAY);

		// 心形线当前点
		setfillcolor(LIGHTRED);
		solidcircle(lastX, lastY, DISPLAY);

		// 动圆
		setlinecolor(BLUE);
		circle(x, y, r);

		FlushBatchDraw();
		Sleep((double)(1000 * SECONDS) / (double)COPIES + 0.5);

		// 消除动圆
		setlinecolor(BLUE);
		circle(x, y, r);

		// 消除动圆与定圆的交点
		setfillcolor(GREEN);
		solidcircle(Contact_X, Contact_Y, DISPLAY);

		// 消除心形线当前所在点
		setfillcolor(LIGHTRED);
		solidcircle(lastX, lastY, DISPLAY);
	}

	_getch();
	EndBatchDraw();
	return 0;
}

3.代码详解

3.1 头文件包含
  • 包含了<graphic.h>头文件,这是用于图形绘制相关操作的库
  • <conio.h>头文件提供了一些控制台输入输出相关的函数,例如:_kbit_getch 等,用于检测键盘输入以及获取字符等操作。
  • <math.h>头文件包含数学相关的函数,像 sin ,cos 等三角函数在这里都会被用到。

3.2 绘制坐标轴函数 
// 画坐标抽
void drawCoordinateAxis()
{
    setlinecolor(DARKGRAY);
    line(WIDTH / 2, HEIGHT / 10, WIDTH / 2, HEIGHT / 10 * 9);
    line(WIDTH / 2, HEIGHT / 10, WIDTH / 2 + ARROW, HEIGHT / 10 + ARROW);
    line(WIDTH / 2, HEIGHT / 10, WIDTH / 2 - ARROW, HEIGHT / 10 + ARROW);

    line(WIDTH / 5, HEIGHT / 2, WIDTH / 5 * 4, HEIGHT / 2);
    line(WIDTH / 5 * 4, HEIGHT / 2, WIDTH / 5 * 4 - ARROW, HEIGHT / 2 - ARROW);
    line(WIDTH / 5 * 4, HEIGHT / 2, WIDTH / 5 * 4 - ARROW, HEIGHT / 2 + ARROW);
}

这个函数的功能是绘制坐标轴。首先通过 setlinecolor(DARKGRAY)设置线条颜色为深灰色,然后绘制纵轴:

  • 从窗口高度的十分之一位置到十分之九位置绘制一条垂直的直线作为纵轴主体(line(WIDTH)/ 2,HEIGHT / 10,HEIGHT / 10 * 9)
  • 接着在纵轴顶端绘制向上和向下的箭头,通过两条斜线来实现

 在绘制横轴:

  • 从窗口的五分之一位置到五分之四位置绘制一条水平的直线作为横轴主体。(line(WIDTH / 5,HEIGHT / 2,WIDTH / 5 *4,HEIGHT / 2))
  • 最后在横轴有段绘制向左或向右的箭头
3.3 main 函数主体部分
  • 初始化图形窗口与相关设置
int main()
{
    initgraph(WIDTH, HEIGHT);
    BeginBatchDraw();
    setlinecolor(BLUE);

首先通过 initgraph(WIDTH,HIGHT) 初始化一个指定宽度和高度(由前面宏定义 WIDTHHEIGHT 确定)。接着调用 BeginBatchDraw() 开始批量绘图模式,这种模式可以减少图形绘制过程中的闪烁现象,提高显示效果。追后通过 setlinecolor(BLUE)设置后续绘制线条的颜色为蓝色。

  • 设置绘图模式与初始化相关变量 
    setrop2(R2_XORPEN);
    double lastX = WIDTH / 2.0, lastY = HEIGHT / 2 - r;                  // 上一个心形线的点的 x,y 值,初始值为 y 轴正方向上距原点 a 个单位长度的点

通过 setrop2(R2_XORPEN) 设置绘图的光栅操作模式后为异或模式(XOR),这种模式在后续绘制图形是可以方便地实现图形的叠加和擦除效果。然后初始化 lastX lastY ,它们用于记录上一个绘制的心形线点的坐标,初始值设定为在 y 轴正方向上距离原点定圆半径 r 长度的点坐标(也就是心形线起始点在 y轴 正半轴上的情况)。

  • 循环绘制心形线及相关图形
    for (double a = 0;!_kbhit(); a += PI / COPIES * 2)                  // a 为当前弧度
    {
        double x = cos(3.0 / 2.0 * PI + a) * 2 * r + WIDTH / 2;          // 动圆这一个循环的圆心的 x 值
        double y = sin(3.0 / 2.0 * PI + a) * 2 * r + HEIGHT / 2;          // 动圆这一个循环的圆心的 y 值
        double FixedPoint_X = cos(PI / 2.0 + a * 2) * r + x;              // 当前循环动圆的定点对应的 x 值
        double FixedPoint_Y = sin(PI / 2.0 + a * 2) * r + y;              // 当前循环动圆的定点对应的 y 值
        double Contact_X = cos(PI / 2.0 + a) * r + x;                    // 当前循环两圆切点在动圆上对应的 x 值
        double Contact_Y = sin(PI / 2.0 + a) * r + y;                    // 当前循环两圆切点在动圆上对应的 y 值

这是一个关键的循环,循环条件是!_kbhit(),即只要没有键盘按键按下就一直循环,每次循环中a(代表弧度)按一定的增量(PI / COPIES * 2,也就是将整个圆周按照COPIES份进行细分,每次增加对应的弧度值)增加。
在循环内:

  • 首先根据当前弧度a计算动圆在这一时刻的圆心坐标(x, y),这里利用三角函数结合定圆半径r以及窗口中心坐标来计算,动圆的圆心运动轨迹是围绕着一个特定的路径(从代码中的三角函数表达式可以看出是符合一定规律的圆形轨迹,且与最终要绘制的心形线相关)。
  • 接着计算当前循环下动圆的定点坐标(FixedPoint_X, FixedPoint_Y),这个定点是与绘制心形线相关的一个关键位置点,通过特定的三角函数关系结合动圆圆心坐标和定圆半径计算得出。
  • 然后计算当前循环两圆切点在动圆上对应的坐标(Contact_X, Contact_Y),同样是基于三角函数、动圆圆心坐标以及定圆半径来确定。
        // 画出心形线,只用画这一个循环的点和上一个循环的点的线就行
        setrop2(R2_COPYPEN);
        setlinecolor(YELLOW);
        line(lastX, lastY, FixedPoint_X, FixedPoint_Y);
        setrop2(R2_XORPEN);
        lastX = FixedPoint_X;
        lastY = FixedPoint_Y;

先将绘图模式切换为R2_COPYPEN正常的绘制模式,直接绘制图形),设置线条颜色为黄色,然后通过line函数绘制从上一个心形线点(坐标(lastX, lastY))到当前循环计算出的心形线点(坐标(FixedPoint_X, FixedPoint_Y))的线段,这样逐步绘制线段就可以呈现出心形线的形状。绘制完后再切换回R2_XORPEN模式,并且更新lastXlastY为当前绘制的心形线点坐标,用于下一次循环绘制时作为上一个点的坐标。

4. 小结

以上便是本篇博客的所有内容了,最后,祝大家新的一年,愿你我笑容灿烂如花,生活甜蜜如蜜糖。过去的遗憾就让它过去,未来的美好我们一同迎接。跨年之夜,祝你我岁岁平安,事事顺心,步步高升。

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

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

相关文章

跳跃表(跳表)是什么

为什么要有跳表 正常链表只能一个一个往下走但是如果我直到我的目标位置就在链表的中部但是我还得一步一步走过去很浪费时间&#xff0c;所以跳表就是在正常链表的基础上添加了多步跳跃的指针。 什么是跳表 跳表&#xff08;Skip List&#xff09;是一种概率型的数据结构&am…

如何逐步操作vCenter修改DNS服务器?

在vSphere 7中有一个新功能&#xff0c;它允许管理员更改vCenter Server Appliance的FQDN和IP。因此本文将介绍如何轻松让vCenter修改DNS服务器。 vCenter修改DNS以及修改vCenter IP地址 与在部署 vCenter Server Appliance 后&#xff0c;您可以根据需要修改其 DNS 设置和 IP…

支持图片生成、语音转文本和文本转语音节点,支持导出和导入应用,MaxKB知识库问答系统v1.9版本发布

2025年1月3日&#xff0c;MaxKB开源知识库问答系统正式发布v1.9版本。 在v1.9社区版中&#xff0c;应用方面&#xff0c;MaxKB新增图片生成节点、文本转语音节点、语音转文本节点&#xff0c;支持用户提问时上传音频文件&#xff0c;支持导出和导入应用&#xff1b;知识库方面…

WebGL 实践(一)开发环境搭建

WebGL 是一种基于 JavaScript 的 API&#xff0c;用于在浏览器中渲染 2D和3D 图形&#xff0c;很多场景都能用&#xff0c;例如游戏开发、数据可视化、在线教育和虚拟现实等应用领域。 零、基础知识 相关基础知识很重要&#xff0c;如果会html、JavaScript等技术掌握起来会更…

商米电子秤服务插件

概述 SunmiScaleUTS封装商米电子秤服务模块&#xff0c;支持商米旗下S2, S2CC, S2L CC等设备&#xff0c;设备应用于超市、菜市场、水果店等,用于测量商品的重量,帮助实现快捷、准确、公正的交易等一系列商业场景。 功能说明 SDK插件下载 一. 电子秤参数 型号:S2, S2CC, …

【开源监控工具】Uptime Kuma:几分钟设置实时监控你的网站性能

文章目录 前言1.关于Uptime Kuma2.安装Docker3.本地部署Uptime Kuma4.使用Uptime Kuma5.cpolar内网穿透工具安装6.创建远程连接公网地址7.固定Uptime Kuma公网地址 前言 大家好&#xff01;如果你是网站运维人员或者管理着多个站点&#xff0c;那么今天我要介绍的一款工具绝对…

ubuntu操作系统安装SSH服务

1、更新仓库 sudo apt-get update 2、安装SSH服务 #安装SSH服务 apt-get install openssh-server#启用SSH服务 service ssh start#查看SSH服务运行状态 service ssh status 3、修改SSH配置文件 sudo vi /etc/ssh/sshd_config 4、开启ssh端口 sudo ufw allow ssh 5、重启SSH…

二、github基础

Github基础 备用github.com网站一、用户界面-Overview&#xff08;概览&#xff09;1用户信息2 导航栏3 热门仓库4 贡献设置5贡献活动6搜索和筛选7自定义收藏8贡献统计9最近活动10其他链接 二、用户界面-Repositories&#xff08;仓库&#xff09;1 libusb_stm322 savedata3 Fi…

Flink源码解析之:如何根据JobGraph生成ExecutionGraph

Flink源码解析之&#xff1a;如何根据JobGraph生成ExecutionGraph 在上一篇Flink源码解析中&#xff0c;我们介绍了Flink如何根据StreamGraph生成JobGraph的流程&#xff0c;并着重分析了其算子链的合并过程和JobGraph的构造流程。 对于StreamGraph和JobGraph的生成来说&…

mysqll连接用时太长解决方法

1、连接用时太长分析 从客户端连接mysql服务器&#xff0c;时间长达10几秒&#xff0c;此为mysql的dns的反向解析造成&#xff0c;在局域网内如果都是用ip连接&#xff0c;可以通过在配置文件中添加skip-name-resolve&#xff0c;取消此功能&#xff0c;取消后&#xff0c;就不…

LLM(十二)| DeepSeek-V3 技术报告深度解读——开源模型的巅峰之作

近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的发展突飞猛进&#xff0c;逐步缩小了与通用人工智能&#xff08;AGI&#xff09;的差距。DeepSeek-AI 团队最新发布的 DeepSeek-V3&#xff0c;作为一款强大的混合专家模型&#xff08;Mixture-of-Experts, MoE&a…

办公 三之 Excel 数据限定录入与格式变换

开始-----条件格式------管理规则 IF($A4"永久",1,0) //如果A4包含永久&#xff0c;条件格式如下&#xff1a; OR($D5<60,$E5<60,$F5<60) 求取任意科目不及格数据 AND($D5<60,$E5<60,$F5<60) 若所有科目都不及格 显示为红色 IF($H4<EDATE…

【深度学习】多目标融合算法—样本Loss提权

目录 一、引言 二、样本Loss提权 2.1 技术原理 2.2 技术优缺点 三、总结 一、引言 在朴素的深度学习ctr预估模型中&#xff08;如DNN&#xff09;&#xff0c;通常以一个行为为预估目标&#xff0c;比如通过ctr预估点击率。但实际推荐系统业务场景中&#xff0c;更多是多…

mapbox进阶,添加路径规划控件

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️MapboxDirections 控件二、🍀添加路径规划控件1. ☘️实现思路2. ☘️…

日志聚类算法 Drain 的实践与改良

在现实场景中&#xff0c;业务程序输出的日志往往规模庞大并且类型纷繁复杂。我们在查询和查看这些日志时&#xff0c;平铺的日志列表会让我们目不暇接&#xff0c;难以快速聚焦找到重要的日志条目。 在观测云中&#xff0c;我们在日志页面提供了聚类分析功能&#xff0c;可以…

uniapp--HBuilder开发

提示&#xff1a;本文为学习内容&#xff0c;若有错误&#xff0c;请联系作者&#xff0c;谦虚受教。 文章目录 前言一、下载HBuilder二、添加modbus相关库1.下载nodejs2.下载modbus库3.项目添加modbus库 三、HBuilder相关功能语句1.文件夹说明2.消息信息框3.开关按钮4.选中按钮…

Unity 3D柱状图效果

1.单个柱状效果展示 2.从上到下渐变透明材质Shader Shader "Unlit/NewUnlitShader" {Properties{_MainTex ("Texture", 2D) "white" {}_Color("Color",Color) (1,1,1,1)_Alpha("Alpha",Range(0,1) ) 0.2_Alpha2("…

JavaScript的数据类型及检测方式

目录 一、JS数据类型 1.基本数据类型 2.引用数据类型 二、堆和栈 三、数据类型检测 1.typeof 2.instanceof 3.constructor 4.Object.prototype.toString.call() JavaScript 中的数据类型主要分为两大类&#xff1a;原始数据类型(也称基本数据类型)和引用数据类型。 一…

电脑中缺失的nvrtc64_90.dll文件如何修复?

一、文件丢失问题 案例&#xff1a;nvrtc64_90.dll文件缺失 问题分析&#xff1a; nvrtc64_90.dll是NVIDIA CUDA Runtime Compilation库的一部分&#xff0c;通常与NVIDIA的CUDA Toolkit或相关驱动程序一起安装。如果该文件丢失&#xff0c;可能会导致基于CUDA的应用程序&…

GIT 企业级开发学习 1

本节主要命令&#xff1a; git init ls 不能列出 .git ls -a 列出 .git 1. 初始化 Git 仓库 git init • 初始化一个新的 Git 仓库&#xff0c;在当前目录下生成一个 .git 隐藏文件夹&#xff0c;用于存储版本控制信息。 2. 查看隐藏文件 ls -a • 使用 ls -a 显示隐藏文件…