diff options
Diffstat (limited to 'Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex')
-rw-r--r-- | Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex | 717 |
1 files changed, 717 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex b/Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex new file mode 100644 index 00000000000..568d7184f91 --- /dev/null +++ b/Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex @@ -0,0 +1,717 @@ +%# -*- coding: utf-8 -*- +% xiantu.tex +% asymptotebyexample 的一章,最基础的画图知识 + +\chapter{赵爽的弦图} +\label{chap:xiantu} +\nocite{quanjing} + +赵爽博士是位老知识分子,研究兴趣是天文历法与算学,一生精研《周髀算经》。不过 +赵老爷子年轻的时候书籍都是手写,最近才紧跟时代潮流用上了电脑。现在他要修订他 +研究《周髀算经》的札记,决定使用 \LaTeX{} 来排版。 + +现在他遇到一个难题,就是他要画出笔记中讲解勾股定理的一幅弦图。听人介绍,几经 +比较之后,他决定使用现在炒得火热的 \Asy{}。 + +赵博士的原图是手画的,线框多有不直不准的,\autoref{fig:xiantuancient} 就是旧 +年据手稿做的雕版图,赵博士并不满意。赵爽博士理想中的图,线条要平整美观,文字 +要清楚整齐,图形还要上色:朱实自然得用红色,黄实也该用黄色,以与注文一致—— +就是\autoref{fig:xiantu} 的样子。 + +\begin{figure} + \centering + \includegraphics[height=\textheight-2\baselineskip]{xiantu-ancient.pdf} + \caption{旧年做的雕版} + \label{fig:xiantuancient} +\end{figure} +\begin{figure} + \centering + \includegraphics{xiantu.pdf} + \caption{理想中的新版本} + \label{fig:xiantu} +\end{figure} + +计议已定,赵博士要开始正式的绘图了。 + +\section{绘图环境} + +\Asy{} 的安装并不复杂,在 Windows 下面就是下载运行那个安装包,在 Linux 下面一 +般也只需要下载对应的压缩包,解压就可以使用了。哦,赵博士用的就是 Windows。 + +点图标运行 \Asy{},就出现了交互式\index{交互式}的命令行,提示符是一个 +\verb=>=。输入命令: +\begin{lstlisting} +draw((0,0) -- (3cm,4cm)); // `\color{comment}一条直线` +\end{lstlisting} +赵博士装的 GSView 立即弹了出来,里面已经画出一条倾斜的直线。再输入 +|quit|\index{quit@\lstinline=quit=},程序退出,并留下了一个叫做 +\verb=out.eps= 的图形文件, +小菜一碟。 + +这里稍稍解释一下上面的一句代码。|draw|\index{draw@\lstinline=draw=} 是画线的 +命令,更准确地说,是 \Asy{} 中的函数\index{函数}:它带有一个参数\index{参数} +|(0,0) -- (3cm,4cm)|,参数外面是圆括号,整个命令以分号结束。里面的 +|(0,0) -- (3cm,4cm)| 是由两个坐标\index{坐标}连接而成的直线,坐标是在直角坐标 +系下的,可以带单位 |mm|, |cm|, |pt|, |bp|, |inch|, |inches|,% +\index{mm@\lstinline=mm=}\index{cm@\lstinline=cm=}\index{pt@\lstinline=pt=}% +\index{bp@\lstinline=bp=}\index{inch@\lstinline=inch=}% +\index{inches@\lstinline=inches=}% +其意义与在\TeX{} 中的一样,如果不带单位,则默认为 |bp|。行末以 |//| 开头的是 +注释,另有一种在 |/* */| 之间的注释\index{注释},与 C 语言相同。 + +\index{编译} +不过赵博士写书讲求胸有成竹方才下笔,因此他更愿意使用更一种方式:打开一个文本 +编辑器,把上面的绘图命令都录入完毕,保存为一个名为 \verb=line.asy= 的文件,最 +后把这个文件拖动到 \Asy{} 的图标上面,就完成了整个作图。 + +赵博士的小侄子不屑于这种快捷图标的编译方式,他直接进入命令行,输入 +\verb=asy=,就进入了 \Asy{} 的交互环境;要是输入 \verb=asy line=,就画出了刚 +才的保存的直线。 + + +\section{直线与绘图命令} +\label{sec:linedraw} + +弦图的图形其实很简单,都是直线、方块、三角形这些,而且为了计算的简便,所有长 +度也都是整数值。那么,首先就是在 \Asy{} 中来画直线。 + +\index{画线} +正如前面试验的时候做的那样,一条直线就是用 |--|\index{--@\lstinline=--=} 把坐 +标连起来,再使用 |draw| 命令,直线就画出来了。事实上,可以用 |--| 把坐标点连 +成折线: +\begin{lstlisting} +draw( (0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm) ); +\end{asy} +\end{figure} + +像这样把坐标用 |--| 连结起来的,就成为一条路径\index{路径}。把直线而稍做修改 +,在后面连上一个特殊的坐标 |cycle|\index{cycle@\lstinline=cycle=},就可以得到 +一条首尾相接的闭路径\index{路径!闭路径}。如: +\begin{lstlisting} +draw( (0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm) -- cycle ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm) -- cycle ); +\end{asy} +\end{figure} + +画一条路径可以使用不同的颜色、粗细的笔,这只要给 |draw| 命令多加一个画笔 +\index{画笔}参数(多个参数用逗号分开): +\begin{lstlisting} +draw((0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm), darkblue+1mm); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw((0,0) -- (1cm,0) -- (2cm,0.5cm) -- (1cm,1cm) -- (0,1cm), darkblue+1mm); +\end{asy} +\end{figure} +这里 |darkblue| 是颜色,|1mm| 是线的粗细。|darkblue+1mm| 即指一毫米宽的深 +蓝色粗线。(可用的颜色\index{颜色}名称可以参考 \cite{asyman}) + +赵博士画的是“勾三股四弦五”的红色三角形,这很容易: +\begin{lstlisting} +draw( (0,0) -- (4cm,0) -- (0,3cm) -- cycle, red+0.5mm ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0) -- (4cm,0) -- (0,3cm) -- cycle, red+0.5mm ); +\end{asy} +\end{figure} + +\index{填充} +不过现在还需要的是实心的三角形,因此就需要一个新的绘图命令 +|fill|\index{fill@\lstinline=fill=},即填充。于是,红色三角形就成为 +\begin{lstlisting} +fill( (0,0) -- (4cm,0) -- (0,3cm) -- cycle, red ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +fill( (0,0) -- (4cm,0) -- (0,3cm) -- cycle, red ); +\end{asy} +\end{figure} + +但这样一来三角形的颜色就太重了,而且边界也不清楚。因此似乎应该先用浅红色填充 +一遍,然后再用深红色勾边。好在可以使用一个命令 +|filldraw|\index{filldraw@\lstinline=filldraw=} 同时完成这两件事情,这样就不 +需要把一条路径写两遍了。即有: +\begin{lstlisting} +filldraw((0,0) -- (4cm,0) -- (0,3cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +filldraw((0,0) -- (4cm,0) -- (0,3cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +\end{asy} +\end{figure} +这里可以简单地直接写两个参数 |palered, red+0.5mm|,不过为了清晰起见还是使用 +“$\text{键}=\text{值}$”的写法,明确表示出填充的画笔和描线的画笔。 + +现在,赵博士的整个弦图的框架就呼之欲出了,就是画出四个三角形 +(\autoref{fig:xiantuskeleton}): +\begin{lstlisting} +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +\end{lstlisting} +\begin{figure} +\centering +\begin{asy} +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +filldraw( (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=palered, drawpen=red+0.5mm); +\end{asy} +\caption{弦图的初步框架}\label{fig:xiantuskeleton} +\end{figure} + +还应该画出弦图的中间的“黄实”,用黄色填充。这部分是一个正方形,可以使用现成 +的 \lstinline[mathescape]|box($\text{角点}$, $\text{角点}$)| +\index{box@\lstinline=box=} 命令来产生矩形的路径,因而填充正中间的正方形就可 +以用: +\begin{lstlisting} +fill( box((3cm,3cm), (4cm,4cm)), yellow ); +\end{lstlisting} +这个填充的命令应该放在画线之前(以免覆盖描的红线)。 + +回顾前面的代码,赵博士觉得连续地写四个 |filldraw| 命令太重复了。他读了 \Asy{} +的文档 \cite{asyman},才知道多条路径可以用符号 |^^|\index{^@\lstinline=^^=} +连起来,一起使用,于是立即着手改进原来的代码。 + +而且,由于还打算在图的后面画出参考网格,图形的颜色还应该设置为半透明\index{透 +明}的。好在这并不难实现,只要稍稍改动一下填充的画笔,使用 +\lstinline[mathescape]|opacity($\text{数值}$)| +\index{opacity@\lstinline=opacity=} +来设定有一定不透明度(取值为 $0\sim1$)的画笔,并把它加在原来的画笔上。于是赵 +博士最后写出了这样的代码: +\begin{lstlisting} +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +\end{lstlisting} +至此,弦图的主要框架(\autoref{fig:xiantuskeleton2})就此完成。 +\begin{figure}[H] +\centering +\begin{asy} +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +\end{asy} +\caption{弦图的进一步优化的框架}\label{fig:xiantuskeleton2} +\end{figure} + + +\section{图形变换与功能模块的使用} + +然后是画作为长度参考的网格。其实网格一开始就该在图中画出来,这样后面画图准确 +与否才能看得清楚。不过现在赵博士是重作旧图,图样已定,网格就搁在弦图的主要图 +形后面才画了。 + +按说这个网格是十分简单的,无非就是画一些灰色的纵横细线。比如这个 $3\times3$ +的网格: +\begin{lstlisting} +draw( (0,0) -- (3cm,0) + ^^ (0,1cm) -- (3cm,1cm) + ^^ (0,2cm) -- (3cm,2cm) + ^^ (0,3cm) -- (3cm,3cm), + gray ); +draw( (0,0) -- (0,3cm) + ^^ (1cm,0) -- (1cm,3cm) + ^^ (2cm,0) -- (2cm,3cm) + ^^ (3cm,0) -- (3cm,3cm), + gray ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0) -- (3cm,0) + ^^ (0,1cm) -- (3cm,1cm) + ^^ (0,2cm) -- (3cm,2cm) + ^^ (0,3cm) -- (3cm,3cm), + gray ); +draw( (0,0) -- (0,3cm) + ^^ (1cm,0) -- (1cm,3cm) + ^^ (2cm,0) -- (2cm,3cm) + ^^ (3cm,0) -- (3cm,3cm), + gray ); +\end{asy} +\end{figure} + +可无疑这个办法显得太麻烦了,赵博士要画的是 $7\times7$ 的网格,就要分别画出 +$16$ 条直线。这样的代码不仅不好写,而且容易出错,修改一下也很麻烦。 + +赵博士看到了手册 \cite{asyman} 中讲循环语句的用法,似乎可以完成这件事。可是以 +赵博士的年龄,再去看什么编程什么变量的,命令不能一条一条执行下来,很不习惯, +头脑就往往转不清楚。 + +\index{模块!math@\prgname{math}} +于是赵博士就去论坛上咨询,一些人劝他去用几行循环语句,甚至有人已经把完整的函 +数做好了。但有一个结果特别引人注目,有人指出,在 \prgname{math} 模块中已经定 +义好了一个 |grid| 函数,只要拿来用就可以了。赵博士立即精神大振,来看这个 +|grid| 函数:\index{grid@\lstinline=grid=} +\begin{lstlisting} +picture grid(int Nx, int Ny, pen p=currentpen) +\end{lstlisting} +这个是在 \prgname{math} 模块中 |grid| 函数的原型。\index{原型}它说明 |grid| +函数有 |Nx|, |Ny| 两个整数类型的必需参数,一个可选的画笔,并且返回一个 +|picture|(图)\index{picture@\lstinline=picture=}类型的对象。 + +\index{导入}\index{模块!导入} +要使用模块的功能,需要在绘图之前导入这个模块,这只要使用 +\index{import@\lstinline=import=} +\begin{lstlisting} +import `模块名`; +\end{lstlisting} +因此,要使用 \prgname{math} 模块中的 |grid| 函数,只要在代码中写 +\begin{lstlisting} +import math; +\end{lstlisting} +就可以了。 + +|grid| 函数的行为看起来很奇怪,调用它会在一个单独的图上画出一个 +|Nx|${}\times{}$|Ny| 的网格,网格的左下角在原点,间距为 $1$。要使用 |grid| 函 +数画的图形,要使用 \lstinline[mathescape]|add($\text{图}$)| +\index{add@\lstinline=add=} 命令,把这个图形加在当前的图上: +\begin{lstlisting} +import math; +add(grid(10,10,gray)); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +import math; +add(grid(10,10,gray)); +\end{asy} +\end{figure} +不过直接这样做的结果是只能得到一个小得已经看不清的网格。因此,必须对图形进行放缩。 + +\index{变换}\index{仿射变换} +\index{变换!平移}\index{变换!旋转}\index{变换!放缩} +\index{变换!错切}\index{变换!反射} +\Asy{} 提供了平移、旋转、放缩、倾斜、反射等各种的仿射变换,来对坐标、路径、图 +形等元素进行变换(严格的函数原型参考 \cite{asyman}): +\index{shift@\lstinline=shift=} +\index{scale@\lstinline=scale=} +\index{xscale@\lstinline=xscale=} +\index{yscale@\lstinline=yscale=} +\index{rotate@\lstinline=rotate=} +\index{slant@\lstinline=slant=} +\index{reflect@\lstinline=reflect=} +\begin{lstlisting} +shift(`坐标`) // `\color{comment}按坐标平移` +shift(x, y) // `\color{comment}按` (x, y) `\color{comment}平移` +scale(`倍数`) // `\color{comment}按倍数放缩` +xscale(`倍数`) // `\color{comment}$x$ 轴方向按倍数放缩` +yscale(`倍数`) // `\color{comment}$y$ 轴方向按倍数放缩` +scale(x, y) // `\color{comment}在 $x$ 轴、$y$ 轴方向分别按倍数` x, y `\color{comment}放缩` +rotate(`角度`, z=(0,0)) // `\color{comment}按角度绕中心` z`\color{comment}(默认为原点,逆时针)旋转` +slant(`因子`) // `\color{comment}按一定因子向右倾斜` +reflect(a, b) // `\color{comment}相对直线` a--b `\color{comment}反射` +\end{lstlisting} +使用一个变换就是把这个变换乘在被变换对象的左边。例如一个放缩一个单位正方形: +\begin{lstlisting} +draw( scale(2cm) * box((0,0), (1,1)) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( scale(2cm) * box((0,0), (1,1)) ); +\end{asy} +\end{figure} +这样的变换可以连续地做下去,例如 +\begin{lstlisting} +draw( rotate(90) * slant(0.3) * scale(1cm) * box((0,0), (1,1)) ); +\end{lstlisting} +就是把一个单位正方形先放大,再倾斜,再旋转 $90^\circ$: +\begin{figure}[H] +\centering +\begin{asy} +draw( rotate(90) * slant(0.3) * scale(1cm) * box((0,0), (1,1)) ); +\end{asy} +\end{figure} + +有了这些变换,画出一个合适大小的网格就不再是什么难事了: +\begin{lstlisting} +import math; +add( scale(5mm) * grid(4, 4, gray) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +import math; +add( scale(5mm) * grid(4, 4, gray) ); +\end{asy} +\end{figure} + +赵博士的弦图有两个网格,不仅要大小合适,而且其中一个需要进行旋转和平移。平移 +的位置很明显,但旋转仍然需要一些计算。当然这难不倒精研天文算学多年的赵博士, +这里弦实($5\times5$ 的正方形)可以看作是顺时针旋转得到的,从朱实的三角形容易 +看出旋转的角度正好是 $\arctan(3/4)$。\Asy{} 中也可以方便地调用返回角度的反三 +角函数 |aTan|\index{aTan@\lstinline=aTan=} 来计算这个角度。更详细的数学函数列 +表,参看 \cite{asyman}。 + +于是,赵博士弦图中的网格,就可以这样方便地画出来了 +(\autoref{fig:xiantugrid}): +\begin{lstlisting} +// `\color{comment}网格` +import math; +add( scale(1cm) * grid(7, 7, gray) ); +add( shift(0,3cm) * rotate(-aTan(3/4)) * scale(1cm) * grid(5, 5, gray) ); +// `\color{comment}弦图主体` +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +\end{lstlisting} +\begin{figure}[htbp] +\centering +\begin{asy} +// 网格 +import math; +add( scale(1cm) * grid(7, 7, gray) ); +add( shift(0,3cm) * rotate(-aTan(3/4)) * scale(1cm) * grid(5, 5, gray) ); +// 弦图主体 +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +\end{asy} +\caption{带网格的弦图草图} +\label{fig:xiantugrid} +\end{figure} + + +\section{标注文字} + +\index{标注}\index{标签} +现在要进行的是文字的标注。按照勾股定理的约定,赵博士打算在一个红色三角形内标 +注“朱实”,在黄色矩形处标注“黄实”,并为拼得的整个大矩形标注“弦实”;在另 +一红色三角形的三边标注“勾三”、“股四”、“弦五”的尺寸;最后在图形两侧加上 +说明的文字。 + +在标注文字之前,对于中文标签\index{标签!中文标签},应该先定义好中文环境和字体 +。\Asy{} 会调用 \LaTeX{} 来进行标签的处理,因而需要设置的就是 \LaTeX{} 的编译 +引擎\index{LaTeX@\LaTeX!引擎}与一般的中文 \LaTeX{} 文件导言区。在这里,赵博士决定使 +用 \XeTeX{}\index{XeTeX@\XeTeX} 引擎与 +\prgname{xeCJK}\index{xeCJK@\prgname{xeCJK}} 宏包来处理中文。为此,在 \Asy{} +源文件中,他使用了下面的设置代码: +\begin{lstlisting} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); +\end{lstlisting} +这里第一行是设置编译时所用的 \TeX{} 引擎。后面 +|usepackage|\index{usepackage@\lstinline=usepackage=} 命令就是 \LaTeX{} 中的 +\texcode|\usepackage| 命令的一个包装形式,里面的字符串参数就是宏包名;而 +|texpreamble|\index{texpreamble@\lstinline=texpreamble=} 命令则把接收的参数直 +接放进 \LaTeX{} 的导言区。 + +进行上述设置后,就可以正确使用中文标签了。标注的命令很简单,就是 +|label|\index{label@\lstinline=label=},参数正是标签文字和标签的位置。例如: +\begin{lstlisting} +draw( (0,0) -- (1cm,1cm) -- (2cm,0) ); +label( "`\color{string}中间`", (1cm,0cm) ); +\end{lstlisting} +就得到 +\begin{figure}[H] +\centering +\begin{asy} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); +draw( (0,0) -- (1cm,1cm) -- (2cm,0) ); +label( "中间", (1cm,0cm) ); +\end{asy} +\end{figure} + +可以在标签中使用任意的 \LaTeX{} 代码,包括数学公式,例如: +\begin{lstlisting} +label("$x = \sin\alpha$", (0,0)); +\end{lstlisting} +就会正确地得到 $x = \sin\alpha$ 的标签。 + +现在,我们可以给弦图加上“朱实”、“黄实”和“弦实”的标签了。在前面的框架代 +码后面加上 +\begin{lstlisting} +label("`\color{string}朱实`", (2cm,4cm)); +label("`\color{string}黄实`", (3.5cm,3.5cm)); +label("`\color{string}弦实`", (5cm,4cm)); +\end{lstlisting} +以及设置字体的代码,就得到\autoref{fig:xiantupartlabel} 的结果。 +\begin{figure} +\centering +\begin{asy} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); +import math; +add( scale(1cm) * grid(7, 7, gray) ); +add( shift(0,3cm) * rotate(-aTan(3/4)) * scale(1cm) * grid(5, 5, gray) ); +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +label("朱实", (2cm,4cm)); +label("黄实", (3.5cm,3.5cm)); +label("弦实", (5cm,4cm)); +\end{asy} +\caption{带部分标注的弦图}\label{fig:xiantupartlabel} +\end{figure} + +下面则是要给三角形的三边进行标注。 + +\index{标签!路径上的标签} +与前面在一个点处标注不同,这里实际是给一条路径(直线)标注标签。因此,想要得 +到的是距离这条路径的中点一定方向距离加一个标签,而不是简单地取路径上的一点作 +为标签的位置。好在 \Asy{} 确实也提供了这样的功能,仍然使用 |label| 命令,基本 +语法是:\index{label@\lstinline=label=} +\begin{lstlisting} +label(`标签`, `路径`) +\end{lstlisting} +这里默认会在路径中间的右侧(沿着路径行进方向)加标签。例如: +\begin{lstlisting} +draw( (0,0) -- (4cm,2cm), linewidth(0.5mm) ); +label("粗线条", (0,0) -- (4cm,2cm)); +\end{lstlisting} +(其中的 |linewidth|\index{linewidth@\lstinline=linewidth=} 函数用来表示具有 +一定线宽\index{线宽}的画笔)这段代码将得到 +\begin{figure}[H] +\centering +\begin{asy} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); +draw( (0,0) -- (4cm,2cm), linewidth(0.5mm) ); +label("粗线条", (0,0) -- (4cm,2cm)); +\end{asy} +\end{figure} + +现在,赵博士就可以给三角形的三边加上“勾三”、“股四”、“弦五”的标签了,只 +要稍稍注意一下标签摆放的默认方向: +\begin{lstlisting} +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +label( "勾三", (4cm,3cm) -- (4cm,0) ); +label( "股四", (0,3cm) -- (4cm,3cm) ); +label( "弦五", (4cm,0) -- (0,3cm) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); +label( "勾三", (4cm,3cm) -- (4cm,0) ); +label( "股四", (0,3cm) -- (4cm,3cm) ); +label( "弦五", (4cm,0) -- (0,3cm) ); +\end{asy} +\end{figure} + +不过,为了得到正确的标签位置,不得不把原来逆时针画的线用顺时针方向重写,这多 +少让赵博士有些恼火:为什么不能在路径的左边标注标签呢?确实可以,很简单,只要 +给 |label| 命令再加上 |align=LeftSide|\index{align@\lstinline=align=} +\index{LeftSide@\lstinline=LeftSide=} 选项(或者简单地只用 |LeftSide|)就指定 +了在左边放置对齐。同理,还有向右对齐的 +|RightSide|\index{RightSide@\lstinline=RightSide=},在中间对齐的 +|Center|\index{Center@\lstinline=Center=} 以及一般意义的相对方向 +\lstinline[mathescape]|Relative($\text{方向}$)|。% +\index{Relative@\lstinline=Relative=}% +例如: +\begin{lstlisting} +draw( (0,0) -- (4cm,2cm), blue, Arrow ); +label( "LeftSide", (0,0) -- (4cm,2cm), align=LeftSide ); +label( "RightSide", (0,0) -- (4cm,2cm), align=RightSide ); +label( "Center", (0,0) -- (4cm,2cm), align=Center ); + +draw( (6cm,0)--(8cm,2cm), blue, Arrow ); +label( "E", (6cm,0)--(8cm,2cm), Relative(E) ); +label( "S", (6cm,0)--(8cm,2cm), Relative(S) ); +label( "W", (6cm,0)--(8cm,2cm), Relative(W) ); +label( "N", (6cm,0)--(8cm,2cm), Relative(N) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0) -- (4cm,2cm), blue, Arrow ); +label( "LeftSide", (0,0) -- (4cm,2cm), align=LeftSide ); +label( "RightSide", (0,0) -- (4cm,2cm), align=RightSide ); +label( "Center", (0,0) -- (4cm,2cm), align=Center ); + +draw( (6cm,0)--(8cm,2cm), blue, Arrow ); +label( "E", (6cm,0)--(8cm,2cm), Relative(E) ); +label( "S", (6cm,0)--(8cm,2cm), Relative(S) ); +label( "W", (6cm,0)--(8cm,2cm), Relative(W) ); +label( "N", (6cm,0)--(8cm,2cm), Relative(N) ); +\end{asy} +\end{figure} +|E|, |S|, |W|, |N|\index{E@\lstinline=E=}\index{S@\lstinline=S=} +\index{W@\lstinline=W=}\index{N@\lstinline=N=} 分别是东南西北四个罗盘方向,% +\index{罗盘方向}用在 |Relative| 函数里面就表示相对于路径方向的四个方向。为明 +确,这里用 |Arrow|\index{Arrow@\lstinline=Arrow=} 选项在画线时加了箭头。 +\index{箭头} + +不过,这样的标签还是不能令赵博士满意。赵博士给三角形加标签,还希望标签随着三 +角形的边作旋转,使标签沿着边排列。为此,赵博士不得不又仔细查看了 +\cite{asyman},在讲标注文字一节(label)他找到了一个构造标签的更高级的办法, +即不仅仅是使用一个简单的字符串,而是使用\index{Label@\lstinline=Label=} +\begin{lstlisting} +Label(`标签`) +\end{lstlisting} +函数进行构造。里面的“标签”参数仍然可以是原来的字符串,或是通过这个函数构造 +出来的高级的标签。这个函数可以带许多可选的其他参数,如 +\lstinline[mathescape]|position=$\text{位置}$| +\index{position@\lstinline=position=} 的参数就可以指定标签放在路径中点之外的 +其他地方;而 \lstinline[mathescape]|embed=$\text{嵌入变换方式}$| +\index{embed@\lstinline=embed=} 的参数则可以解决标签自动旋转的问题。 + +这里暂且放下 |position| 参数。只来看 |embed| 参数的一个特例:% +\lstinline[mathescape]|Rotate($\text{方向}$)|% +\index{Rotate@\lstinline=Rotate=}。这个参数会让标签向着给定的方向旋转,如: +\begin{lstlisting} +draw( (0,0)--(4cm,2cm), blue, Arrow ); +label( Label("Rotate", Rotate((4,2))), + (0,0)--(4cm,2cm) ); +\end{lstlisting} +\begin{figure}[H] +\centering +\begin{asy} +draw( (0,0)--(4cm,2cm), blue, Arrow ); +label( Label("Rotate", Rotate((4,2))), + (0,0)--(4cm,2cm) ); +\end{asy} +\end{figure} +这里坐标 $(4,2)$ 正是这条直线的绘制方向。 + +终于,使用了上面的全部功能,赵博士完成了全部的图形标注工作 +(\autoref{fig:xiantulabel}): +\begin{lstlisting} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); + +import math; +add( scale(1cm) * grid(7, 7, gray) ); +add( shift(0,3cm) * rotate(-aTan(3/4)) * scale(1cm) * grid(5, 5, gray) ); + +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); + +label("朱实", (2cm,4cm)); +label("黄实", (3.5cm,3.5cm)); +label("弦实", (5cm,4cm)); +label( Label("勾三",Rotate(S)), (4cm,0)--(4cm,3cm), LeftSide ); +label( Label("股四",Rotate(E)), (4cm,3cm)--(0,3cm), LeftSide ); +label( Label("弦五",Rotate((4,-3))), (0,3cm)--(4cm,0), LeftSide ); +\end{lstlisting} +\begin{figure}[htbp] +\centering +\begin{asy} +settings.tex = "xelatex"; +usepackage("xeCJK"); +texpreamble("\setCJKmainfont{SimSun}"); + +import math; +add( scale(1cm) * grid(7, 7, gray) ); +add( shift(0,3cm) * rotate(-aTan(3/4)) * scale(1cm) * grid(5, 5, gray) ); + +fill( box((3cm,3cm), (4cm,4cm)), opacity(0.5)+yellow ); +filldraw( (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle + ^^ (7cm,4cm) -- (4cm,4cm) -- (4cm,0) -- cycle + ^^ (3cm,7cm) -- (3cm,4cm) -- (7cm,4cm) -- cycle + ^^ (0,3cm) -- (3cm,3cm) -- (3cm,7cm) -- cycle, + fillpen=opacity(0.1)+red, drawpen=red+0.5mm ); + +label("朱实", (2cm,4cm)); +label("黄实", (3.5cm,3.5cm)); +label("弦实", (5cm,4cm)); +label( Label("勾三",Rotate(S)), (4cm,0)--(4cm,3cm), LeftSide ); +label( Label("股四",Rotate(E)), (4cm,3cm)--(0,3cm), LeftSide ); +label( Label("弦五",Rotate((4,-3))), (0,3cm)--(4cm,0), LeftSide ); +\end{asy} +\caption{带标注的完整弦图} +\label{fig:xiantulabel} +\end{figure} + + +\section*{习题} + +\begin{enumerate} + \item 查阅参考手册 \cite{asyman},看看都有哪些颜色可用。看看你的系统中安装 + 了哪些中文字体。然后修改\autoref{fig:xiantulabel},使用另一种你喜欢的字体 + 进行标注;并且将“朱实”、“黄实”和“弦实”分别用红、黄、橙色标注。 + + \item 查阅参考手册 \cite{asyman},看看 |draw|、|fill|、|label| 等命令都可以 + 带哪些可选的参数,并自己举例子试验一下效果。 + + \item 代码 +\begin{lstlisting} +path zhushi = (4cm,0) -- (4cm,3cm) -- (0,3cm) -- cycle; +\end{lstlisting} + 可以把一个三角形的路径保存在变量 |zhushi| 中,以后就可以使用 + |draw(zhushi)| 这样的命令对此路径进行操作了\footnote{关于变量定义和使用的 + 详细内容,参考后面的章节或手册 \cite{asyman}。}。 + + 考虑如何利用平移和旋转变换,只定义一个三角形的路径,就把弦图中的四个红色 + 三角形都画出来。 + + \item 查阅手册 \cite{asyman} 和 \Asy{} 自带的例子,研究模块 + \prgname{roundedpath} 的用法。并利用它尝试画出下面的图形: +\begin{figure}[H] +\centering +\begin{asy} +import roundedpath; +pen thick = linewidth(0.8pt); +path p = (0,0) -- (0,2cm) -- (1cm,3.25cm) -- (2cm,2cm) -- (2cm,0) + -- (0,2cm) -- (2cm, 2cm) -- (0,0) -- (2cm,0); +draw(roundedpath(p, 8pt), thick); +\end{asy} +\end{figure} + + 看看 \Asy{} 中还有什么用法简单而又有趣的模块。 + + \item (较难)研究在 \LaTeX{} 里中文直排的方法,尽量精确地复现出赵博士理想 + 中的弦图效果(\autoref{fig:xiantu})。 +\end{enumerate} + +\endinput + +% vim:tw=77: + |