msdn画圆弧函数_精确之美——用TikZ画硬盘示意图

序言

备考某等级考试的时候,在教材中碰到了几个一直不太理解的、关于硬盘的概念:磁道、柱面号、扇区。然而教材没有配图,无法直观地了解这些概念的物理形态。维基百科的硬盘[1]词条页中倒是有一副不错的示意图,我截图搬运了过来

2118099c-cd1f-eb11-8da9-e4434bdf6706.png

机械硬盘示意图

原图是一张 SVG 图片,本质上是一堆指令——也就是所谓的语绘啦。我是一个语绘爱好者,也想试试看能否用代码画一幅差不多的图出来。

在旧文《程序员特有的画图方式——语绘工具小入门》[2]中,我演示过几款写代码画图的工具,但它们都不适合用来绘制几何图形,所以这次它们没有用武之地。

本来我想试试用MetaPost[3]来画的,但鉴于“入门”了太多次,这次还是换点新花样吧。这一次,我用 LaTeX+TikZ 来画。

TikZ 是什么及光速入门

著名的压泡面神器、麻将桌脚垫《TAOCP》的作者发明了TeX[4],知名的Raft 竞品Paxos 算法的作者在此基础上创造了LaTeX[5],它们都是程序员简历论文排版的好帮手。而 TikZ 则是如虎添翼地在 LaTeX 中实现了简单易懂的绘图功能的一个红包宏包(macro package,TeX 的术语)。简而言之,TikZ 自定义了一套“语言”,可以在用 LaTeX 编写的文档中画出各种图形。

百闻不如一见,我演示一下如何用 TikZ 画一条线段、一个圆,以及一段圆弧。先将下列的代码保存到一个文件three_in_one.tex

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows}
\begin{document}
\begin{tikzpicture}[scale=2]
%% 画一条从原点指向(1, 1)的线段
\draw (0, 0) -- (1, 1);
%% 画一个以(1, 1)为圆心,半径为2的圆。
\draw (1, 1) circle (2);
%% 画一段以原点为圆心,半径为1,张开角度为30度的圆弧。
\draw (1, 0) arc (0:30:1);
\end{tikzpicture}
\end{document}

再使用xelatex将其编译成 PDF 文件(xelatex可以通过安装 TeXLive 2020 获得)

xelatex three_in_one.tex

此时便得到了three_in_one.pdf文件。为了可以在文章中显示,我用 ImageMagick 将其转换为 PNG 文件

convert three_in_one.pdf /tmp/three_in_one.png

最终的图片如下

2218099c-cd1f-eb11-8da9-e4434bdf6706.png

简单,就像画一匹马一样简单。

2318099c-cd1f-eb11-8da9-e4434bdf6706.jpeg

现在该来试试用 TikZ 复刻维基百科上的硬盘示意图了。

来点同心圆

在原图中最引人注目的,当属那十几个同心圆了。简单起见,我只画六个圆。这六个圆的半径相差1pt(pt是 TikZ 默认的长度单位),从3pt一直递增到8pt,它们的圆心都在坐标原点(0, 0)上。

%% 为了节省篇幅,只给出TikZ部分的代码。
\begin{tikzpicture}
\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);
\end{tikzpicture}

2418099c-cd1f-eb11-8da9-e4434bdf6706.png

来点等分线

原图中有 12 根线段,将每一个圆等分成了全等的 12 份。从前一节的内容可知,要用\draw命令绘制线段,需要的是线段两端的坐标,那么这批坐标要怎么计算呢?尽管可以用三角函数计算出这些点的笛卡尔坐标,但在 TikZ 中可以用更方便的极坐标来指定这些点。

以原图中从 X 轴开始逆时针旋转遇到的第一条线段为例,它在半径为3pt的圆上的点的坐标为(30:3)(30 是极坐标中的角度,3 是半径长度),而在半径为8pt的圆上的点的坐标为(30:8),因此可以用\draw (30:3) -- (30:8)来画出这根线段。

2618099c-cd1f-eb11-8da9-e4434bdf6706.png

通过调整其中的角度可以画出剩余的其它线段。

\begin{tikzpicture}
\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);
\end{tikzpicture}

2818099c-cd1f-eb11-8da9-e4434bdf6706.png

来张色图

原图大致的骨架已经画完了,现在来尝试给它上色。在 TikZ 中,可以用\fill命令给一段封闭的曲线上色。比如用\fill[red] (0, 0) -- (1, 0) -- (1, 1) -- (0, 1) -- cycle可以将左下角在原点、边长为1pt的正方形涂成红色。

先给原图中的区域 B 上色。区域 B 是一个扇形,它由两根长度为8pt的半径和一段夹角为 30 度的圆弧构成。要描述这段封闭曲线,可以借助入门一节中介绍的arc命令。

\begin{tikzpicture}
%% 给区域B上色。
\fill[blue] (0, 0) -- (30:8) arc (30:60:8) -- cycle;

\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);
\end{tikzpicture}

2b18099c-cd1f-eb11-8da9-e4434bdf6706.png

\fill命令那一行最后的cycle的意思,是让曲线回到起点组成一个封闭的形状。另外,\fill命令需要写在\draw命令之前,是为了避免蓝色颜料将区域内的圆弧给盖住了。

对于区域 C 和区域 D,方法是一样的,只是描述封闭曲线的坐标不同罢了。

\begin{tikzpicture}
%% 给区域B上色。
\fill[blue] (0, 0) -- (30:8) arc (30:60:8) -- cycle;
%% 给区域C上色。
\fill[purple] (30:4) -- (30:5) arc (30:60:5) -- (60:4) -- (60:4) arc (60:30:4);
%% 给区域D上色。
\fill[green] (240:6) -- (240:7) arc (240:330:7) -- (330:6) -- (330:6) arc (330:240:6);

\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);
\end{tikzpicture}

2e18099c-cd1f-eb11-8da9-e4434bdf6706.png

给环形上色

聪明的读者也许已经发现了,区域 A 的环形没办法用这种方式来描述。不过没关系,只要将其视为上下半两部分,再分别上色即可。

\begin{tikzpicture}
%% 环的上半部分
\fill[red] (4, 0) -- (5, 0) arc (0:180:5) -- (-4, 0) -- (-4, 0) arc (180:0:4);
%% 环的下半部分
\fill[red] (4, 0) -- (5, 0) arc (360:180:5) -- (-4, 0) -- (-4, 0) arc (180:360:4);
%% 给区域B上色。
\fill[blue] (0, 0) -- (30:8) arc (30:60:8) -- cycle;
%% 给区域C上色。
\fill[purple] (30:4) -- (30:5) arc (30:60:5) -- (60:4) -- (60:4) arc (60:30:4);
%% 给区域D上色。
\fill[green] (240:6) -- (240:7) arc (240:330:7) -- (330:6) -- (330:6) arc (330:240:6);

\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);
\end{tikzpicture}

3018099c-cd1f-eb11-8da9-e4434bdf6706.png

润色一下

用 macOS 的“数码测色计”看了一下原图中各个区域的颜色的 RGB 值,区域 A 大概是(236, 133, 130)、区域 B 大概是(122, 127, 237)、区域 C 大概是(131, 132, 139)、区域 D 大概是(0, 151, 27)。接下来我让 TikZ 以这四种指定的颜色填充图中的四个区域,先用 LaTeX 的\definecolor命令定义四个新的颜色的名字。

%% 下列四行代码置于document环境之前
\definecolor{areaA}{RGB}{236,133,130}
\definecolor{areaB}{RGB}{122,127,237}
\definecolor{areaC}{RGB}{131,32,139}
\definecolor{areaD}{RGB}{0,151,27}

再替换掉\fill命令中的颜色名即可

\begin{tikzpicture}
%% 环的上半部分
\fill[areaA] (4, 0) -- (5, 0) arc (0:180:5) -- (-4, 0) -- (-4, 0) arc (180:0:4);
%% 环的下半部分
\fill[areaA] (4, 0) -- (5, 0) arc (360:180:5) -- (-4, 0) -- (-4, 0) arc (180:360:4);
%% 给区域B上色。
\fill[areaB] (0, 0) -- (30:8) arc (30:60:8) -- cycle;
%% 给区域C上色。
\fill[areaC] (30:4) -- (30:5) arc (30:60:5) -- (60:4) -- (60:4) arc (60:30:4);
%% 给区域D上色。
\fill[areaD] (240:6) -- (240:7) arc (240:330:7) -- (330:6) -- (330:6) arc (330:240:6);

\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);
\end{tikzpicture}

3318099c-cd1f-eb11-8da9-e4434bdf6706.png

图文并茂

剩下的需要复刻的东西就是原图中的文字以及标注用的线了。线很容易画,只要规定了坐标后用\draw命令即可。比如说,我可以把四条线定义如下,其中的坐标和线段的长度纯粹是个人偏好

\draw (75:4.5) -- (75:9);
\draw (40:7.5) -- (40:9);
\draw (50:4.5) -- (50:9);
\draw (285:6.5) -- (285:9);

3518099c-cd1f-eb11-8da9-e4434bdf6706.png

线画完了,再到每一根线的“终点”标上文字说明,这需要用到 TikZ 的node功能。用法很简单,就是在需要标注文字的坐标后,紧跟着关键字node,以及一段用花括号包裹的文本即可

\documentclass{standalone}
\usepackage{tikz}
\usepackage{xeCJK}
\setCJKmainfont{Songti TC}
\usetikzlibrary{shapes.geometric, arrows}
\definecolor{areaA}{RGB}{236,133,130}
\definecolor{areaB}{RGB}{122,127,237}
\definecolor{areaC}{RGB}{131,32,139}
\definecolor{areaD}{RGB}{0,151,27}
\begin{document}
\begin{tikzpicture}
%% 环的上半部分
\fill[areaA] (4, 0) -- (5, 0) arc (0:180:5) -- (-4, 0) -- (-4, 0) arc (180:0:4);
%% 环的下半部分
\fill[areaA] (4, 0) -- (5, 0) arc (360:180:5) -- (-4, 0) -- (-4, 0) arc (180:360:4);
%% 给区域B上色。
\fill[areaB] (0, 0) -- (30:8) arc (30:60:8) -- cycle;
%% 给区域C上色。
\fill[areaC] (30:4) -- (30:5) arc (30:60:5) -- (60:4) -- (60:4) arc (60:30:4);
%% 给区域D上色。
\fill[areaD] (240:6) -- (240:7) arc (240:330:7) -- (330:6) -- (330:6) arc (330:240:6);

\draw (0, 0) circle (3);
\draw (0, 0) circle (4);
\draw (0, 0) circle (5);
\draw (0, 0) circle (6);
\draw (0, 0) circle (7);
\draw (0, 0) circle (8);

\draw (0:3) -- (0:8);
\draw (30:3) -- (30:8);
\draw (60:3) -- (60:8);
\draw (90:3) -- (90:8);
\draw (120:3) -- (120:8);
\draw (150:3) -- (150:8);
\draw (180:3) -- (180:8);
\draw (210:3) -- (210:8);
\draw (240:3) -- (240:8);
\draw (270:3) -- (270:8);
\draw (300:3) -- (300:8);
\draw (330:3) -- (330:8);

\draw (75:4.5) -- (75:9) node {磁道};
\draw (40:7.5) -- (40:9) node {扇面};
\draw (50:4.5) -- (50:9) node {扇区};
\draw (285:6.5) -- (285:9) node {簇};
\end{tikzpicture}
\end{document}

3718099c-cd1f-eb11-8da9-e4434bdf6706.png

需要留意的是,我在源代码开头的位置,引入了xeCJK宏包(\usepackage{xeCJK}),并且指定了中文内容用的字体为宋体(\setCJKmainfont{Songti TC}),这样才能成功编译。

至此,复刻算是完成了。

后记

本文只是管中窥豹,TikZ 还可以画出其它更复杂更美轮美奂的图形,有兴趣的读者可以移步这里[6]观赏。此外,TikZ 也可以“编程”,比如下面的两行代码便足矣画出上文中 12 行代码才完成的等分线

\foreach \x in {0,30,60,90,120,150,180,210,240,270,300,330}
\draw (\x:3) -- (\x:8);

TikZ 的更多潜力和乐趣,就由各位读者自己探索吧。

如果你想要和我交流,欢迎点击阅读原文到我的博客上发表评论。

参考资料

[1]

硬盘: https://zh.wikipedia.org/wiki/%E7%A1%AC%E7%9B%98

[2]

《程序员特有的画图方式——语绘工具小入门》: https://liutos.github.io/2020/05/07/%E7%A8%8B%E5%BA%8F%E5%91%98%E7%89%B9%E6%9C%89%E7%9A%84%E7%94%BB%E5%9B%BE%E6%96%B9%E5%BC%8F%E2%80%94%E2%80%94%E8%AF%AD%E7%BB%98%E5%B7%A5%E5%85%B7%E5%B0%8F%E5%85%A5%E9%97%A8/

[3]

MetaPost: https://zh.wikipedia.org/wiki/MetaPost

[4]

TeX: https://zh.wikipedia.org/wiki/TeX

[5]

LaTeX: https://zh.wikipedia.org/wiki/LaTeX

[6]

这里: https://texample.net/tikz/examples/

点击进入留言区

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

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

相关文章

爬虫:验证码识别准确率(Tesseract-OCR)

爬虫:验证码识别准确率(Tesseract-OCR) 现在的网站为了防止人们轻易的获取登陆后的页面信息,在登陆上设置了很多的障碍,验证码就是其中的一种,所谓道高一尺,魔高一丈,人们总能想出办…

【赠书】21世纪科技竞争的核心是超级智能的控制权

这篇文章是根据《崛起的超级智能:互联网大脑如何影响科技未来》的核心观点对21世纪世界科技竞争的判断。《崛起的超级智能》受到张亚勤、刘慈欣、周鸿祎、王飞跃、约翰.翰兹等专家的联合推荐。作者刘锋,2019年7月由中信出版社出版。《崛起的超级智能》主…

MATLAB中的微积分运算(数值符号)

显然这个函数是单词differential(微分)的简写,用于计算微分。实际上准确来说计算的是差商。 如果输入一个长度为n的一维向量,则该函数将会返回长度为n-1的向量,向量的值是原向量相邻元素的差,于是可以计算一…

电脑手写板_点到之处妙笔生花,实用平板电脑手写电容笔推荐

如今随着科技的不断发展,人们生活水平也在逐步地提升。除了手机以外,很多人都会给自己入手一款平板电脑。不管是观看电影还是游戏办公,大尺寸的屏幕都能带来更加清晰的视觉效果。而电容笔的出现,可以说跟平板电脑是一组巧妙的搭配…

图像处理:给验证码图片做降噪处理及数据清洗

上一篇博文:https://blog.csdn.net/qq_40962368/article/details/89312429 图像处理:给验证码图片做降噪处理及数据清洗 在上一篇博文中,tesseract对验证码识别的准确率还是非常低的,改进措施的话,可以从三个方面来考…

X-Brain:如此美丽可爱的大脑工作原理

这个帖子很好地提醒了我,为什么我愿意跟如此美丽可爱的大脑一起工作。因为真正的大脑非常不可爱,长得也难看。我们从外往里看吧。生物学有时似乎非常让人满意,比如你的头上有一个真正的俄罗斯套娃。你有头发,然后是头皮&#xff0…

SpringMVC注解@RequestParam全面解析

在SpringMVC后台控制层获取参数的方式主要有两种,一种是request.getParameter("name"),另外一种是用注解RequestParam直接获取。这里主要讲这个注解 一、基本使用,获取提交的参数 后端代码: Java代码 RequestMapping(…

MATLAB(六)数据处理

一、Matlab中的默认数据文件mat文件 例1、把Matlab工作空间中的数据矩阵a、b、c保存到数据文件data1.mat中。 >> a [1, 2, 3] a 1 2 3 >> b [4, 5, 6] b 4 5 6 >> c [7, 8, 9] c 7 8 9 >> save data1 a b c 例2、把例1生…

java怎么安装_Windows、Linux、Mac下安装JDK

前言在知乎上看到很多童鞋在学Java的时候,因为安装jdk时没有正确的配置,会遇到很多问题。所以决定今天写一下jdk在Windows、Mac、Linux下都怎么安装。下载JDK“巧妇难为无米之炊”,所以首先我们要去Oracle官网上下载jdk,Java8下载…

200年历史的神经科学难题,取得重大突破

图片来源:Diogo Matias,Champalimaud基金会来源:中国生物技术网北京时间8月13日,发表在《Nature Neuroscience》上的一项研究,来自葡萄牙里斯本Champalimaud未知中心的研究团队解决了一个长达200年历史的神经科学难题。…

关系数据库SQL之可编程性触发器

前言 前面关系数据库SQL之可编程性函数(用户自定义函数)一文提到关系型数据库提供了可编程性的函数、存储过程、事务、触发器及游标,前文已介绍了函数、存储过程、事务,本文来介绍一下触发器的使用。(还是以前面的银行系统为例) 概…

图像处理:图像特效之油画效果

利用OpenCVpython对图片进行处理产生油画的效果 算法可以分为五步: 1、获取图像的灰度(gray)图片2、设计一个小方框(4x4 or 8x8 or 10x10等),统计每个小方框的像素值3、将0-255的灰度值划分成几个等级,并把第二步处理…

socket模拟http的登陆_python模拟登陆知乎(最新版)

为啥要写这一篇文章呢?(主要是qq群内有人在模拟登陆知乎,一直不成功)然后我抓包看了下,发现知乎登陆页已经改版了,而且难度大大提高了。开始抓包首先内,还是打开知乎首页,然后输入账…

图像识别:利用KNN实现手写数字识别(mnist数据集)

图像识别:利用KNN实现手写数字识别(mnist数据集) 步骤: 1、数据的加载(trainSize和testSize不要设置的太大) 2、k值的设定(不宜过大) 3、KNN的核心:距离的计算 4、k个最近…

一个与生命起源有关的悖论终于得到了解决

来源:原理当Caitlin Cornell低头看显微镜时,她看见黑色的背景下浮现出一些大大的明亮斑点。它们就像微缩的太阳,在深色的太空幕布下闪耀着光芒。Conell回忆起把这些斑点展示给她的导师Sarah Keller时的兴奋,那时她们意识到&#x…

python ffmpy3与FFmpeg的安装

python ffmpy3与FFmpeg的安装 安装命令: pip install ffmpy3 去官网下载FFmpeg,根据自身电脑版本下载相应安装包 http://ffmpeg.org/download.html from ffmpy3 import FFmpeg ff FFmpeg(inputs{test.mp4: None},outputs{output.ts: None}) print(f…

千兆网线8根线定义图_家中的网线断裂/不够长,如何接线才最合适?

网线作为互联网时代不可或缺的主角,更是家装布线和工程施工中的常客。网线相对来说是很脆弱的,特别是一些质量一般的网线,在很多情况下都可能会被弄断,比如老鼠咬、过度拉伸、摆在地下人踩的人多了、电起火烧断、不小心被夹断等等…

中国决定以“六大政策”推动新一代人工智能发展

来源:智造智库以新一代人工智能为代表的新一轮科技革命和产业变革已经呈现出强大的影响力和生命力,人工智能技术对生产、流通、消费等形成高度渗透、跨界融合,新业态、新模式不断涌现,给以往的产业生态、社会分工、行业和企业边界…

第三次站立会议

项目进展:项目主体开始实施,我们在前期分工准备的同时开始讨论连连看的具体式样,开始上网参考其他项目的式样,搜集图片素材,为具有我们特色的连连看项目做准备。 存在问题:搜集素材时组员对项目的风格式样见…

ffmpy3与ffmpeg的简单使用

安装 python ffmpy3与ffmpeg的安装 https://blog.csdn.net/qq_40962368/article/details/90748852 ffmpy3的介绍: https://ffmpy3.readthedocs.io/en/latest/ ffmpy3是一个用于FFmpeg的Python包装器,最初是从ffmpy项目派生出来的。它根据提供的参数及…