summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/support/asymptote-by-example/src/xiantu.tex
diff options
context:
space:
mode:
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.tex717
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:
+