% % \begin{funclist} % \item A \go % BBBBBBBBBBBBBBBBBB % good luck good luck good luck good luck good luck good luck good luck good luck % good luck good luck good luck good luck good luck good luck good luck good luck % good luck good luck good luck good luck good luck good luck good luck good luck % % \item BBB \go % DDDDDDDDDDDDDD BBBBBBBBBBBBBBBBBB sd good luck % good luck good luck good luck good luck good luck good luck good luck good luck % good luck good luck good luck good luck good luck good luck good luck good luck % \end{funclist} % % \begin{lstlisting} % size(10cm); % path a=(0,0)--(1,1); % draw(a,red); % //抄录代码环境 % //comments % \end{lstlisting} % \include{preamble_newnew} \usepackage{hyperref} \usepackage{graphicx} \usepackage{wasysym} \newlength{\deffboxsep} \setlength{\deffboxsep}{\fboxsep} \newcommand{\qref}[1]{~\framebox{\bfseries 问题\ref{#1}}~} \newcommand{\myfig}[1]{\par{ \setlength{\fboxsep}{0pt} \centering\colorbox{yellow!10!white}{ \parbox{0.9\textwidth}{\vspace{-2mm}\begin{center}\colorbox{white}{\includegraphics{figures/#1}}\end{center}\vspace{-2mm}} }\\\rule{0.92\textwidth}{0.3pt}\\[-3mm] \setlength{\fboxsep}{\deffboxsep} }} \begin{document} \title{\bfseries Asymptote中的常见问题(FAQ)} \author{译者:goodluck@bbs.ctex.org} \maketitle \begin{center} \colorbox{gray!30!white}{\parbox{0.9\textwidth}{ {\bfseries 说明:} \begin{itemize} \item 英文原版FAQ请参见 \url{http://asymptote.sourceforge.net/FAQ/}。 \item 对应1.57版时的FAQ,不过FAQ随版本变动不大\raisebox{-1pt}{\Large\smiley}。 \item 直译意译结合,尽量保持原意;为避免混淆,有些词比如picture等有时没有翻译。 \item 为了方便理解,能生成图的代码都附有其生成的图形。 \item 排版细节上,有些不一致的地方,请读者见谅。 \item 脚注为译者的一些理解,仅供参考。 \item 由于译者谁水平有限,翻译不准甚至错误的地方在所难免,欢迎大家指正。 \item 重点感谢CTEX论坛上 cvgmt 和 milksea 提供的资源以及有益讨论和帮助。 \end{itemize} }} \end{center} \section{\label{Q1}关于Asymptote} \subsection{\label{Q1.1}什么是Asymptote} Asymptote是一种为了绘制技术图形而设计的矢量图语言,其灵感来自MetaPost,它具有IEEE标准的浮点数支持、原生的三维图形支持、 灰度/RGB/CMYK等不同色彩指定方式以及类似C++的语法。与MetaPost不同,Asymptote原生的支持多段路径 (因此不局限于单连通区域)、填充图案、Gouraud 着色(shading)以及PostScript图像。 \subsection{\label{Q1.2}如何获得Asymptote?} 完整的源代码以及基于Linux、MacOS X以及微软Windows平台的二进制代码都可以在网址 \url{http://asymptote.sourceforge.net/}找到。许多Linux发行版(比如RedHat和Debian) 已经包含有Asymptote软件包(进一步信息请参考你所使用发行版的文档)。 \subsection{\label{Q1.3}我在哪里能问关于Asymptote的问题?} 如果您有疑问,请尝试从这个“常见问题”寻找答案,如果不行的话可以参考扩展文档 \url{http://asymptote.sourceforge.net/doc/}或搜索论坛: \url{http://sourceforge.net/forum/forum.php?forum_id=409349}。 \subsection{\label{Q1.4}为什么选择Asymptote\protect\footnotemark 作为名字?} \footnotetext{译者注:asymptote在英语中为“渐近线”的意思。} 因为它还不是一个完美的图形包,但是我们确实希望它渐进的趋于完美…… \subsection{\label{Q1.5}在Asymptote的内部源代码中,camp这个名字指的是什么?} 那是我们在Asymptote这个项目中最初取的一个测试用的名字,它代表“C's Answer to MetaPost”\footnote{% 译者注:翻译成中文就是“MetaPost问题的C语言答案”}(Asymptote的灵感来源于MetaPost语言)。 不过,我们最终决定用Asymptote这个名字,因为它更好的强调了这个语言的数学及图形本质。 \section{\label{Q2}关于安装和设置的问题} \subsection{\label{Q2.1}能在MacOS X上安装Asymptote吗?} 很简单,从~\url{http://sourceforge.net/project/showfiles.php?group_id=120000}获取源代码并直接编译即可。 我们推荐您首先将您的GNU readline库更新到最新,除非您不需要readline提供的交互式支持(安装时configure会自动 检测并禁用过时的readline库版本)。Marius Schamschula也维护着一个适用于各种MacOS X平台的二进制包 \url{http://www.hmug.org/pub/MacOS_X/X/Applications/Publishing/asymptote}。 \subsection{\label{Q2.2}当我用二进制包在MAC OS上安装Asymptote时,为什么得到这样一个错误:Bad CPU type in executable?} 这意味着要么你的二进制包是适用于另一MAC体系结构的,要么(根据Marius Schamschula的解释)是你缺少某个库。 最简单的解决办法是直接从官方源~\url{http://sourceforge.net/project/showfiles.php?group_id=120000}获得 并编译源代码。 \subsection{\label{Q2.3}当我用./configure --enable-gc=system进行配置时,为什么得到这个错误: can't locate file for: -lgccpp ?} 这说明你系统里的Boehm垃圾回收器版本不完整。请根据INSTALL文件中的指令去做:从~\url{http://www.hpl.hp.com/personal/Hans_Boehm/gc/gc_source} 获得最新的gc版本,并把它放到Asymptote源代码目录的最上层,然后 ./configure (不要加 --enable-gc=system 选项)。 \subsection{\label{Q2.4}如果出现这个错误怎么办:Error: pdfetex (file pdftex.cfg): cannot open config files...texinfo.tex appears to be broken} 只需把~\url{http://asymptote.sourceforge.net/asymptote.pdf}放到doc目录下然后重复执行make all。 或者如果你不想创建本地文档,只需进行 make install-asy。 \subsection{\label{Q2.5}如果得到这个错误怎么办:! Undefined control sequence. l.6 @copying?} 要么升级你的texinfo包,要么按\qref{Q2.4}中的方法简单处理。 \subsection{\label{Q2.6}能把Asymptote集成到 LaTeX 中吗?} 可以,请参考例子latexusage.tex。Dario Teixeira 也写了一个关于此话题的详细指导。你可以从 \url{http://dario.dse.nl/projects/asylatex/}下载到。 Philippe Ivaldi 为Emacs用户提供了一个Asymptote模式~\url{http://asymptote.sourceforge.net/doc/Editing-modes.html},它 包含一个lasy-mode,允许用户一次编译一个~\verb|\begin{asy}...\end{asy}|~环境并查看结果。 \subsection{\label{Q2.7}能把Asymptote集成到latex或pdflatex 中吗?} 是的,自从1.14版本起,Asymptote就开始支持latex和pdflatex(EPS/PDF和内嵌模式都支持),如例子 latexusage.tex中所示: \begin{verbatim} pdflatex latexusage asy latexusage pdflatex latexusage \end{verbatim} \subsection{\label{Q2.8}当我安装Asymptote的rpm二进制包时是否需要tkinter包?} 不需要tkinter包,除非你想尝试图形界面xasy。请尝试 \begin{verbatim} rpm -Uvh --nodeps asymptote-x.xx-1.i386.rpm \end{verbatim} 其中 x.xx 代表版本号。 \subsection{\label{Q2.9}路径 \%USERPROFILE\%$\backslash$.asy$\backslash$config.asy 是什么意思?} 那是微软Windows对用户配置目录的引用。这个实在没什么需要了解的,只需要把你的配置命令 写入文件config.asy并将该文件放入一个新的目录~\verb|%USERPROFILE%\.asy|~中即可。 \subsection{\label{Q2.10}当我尝试设置 settings.dir="C:$\backslash$asymptote$\backslash$"; 时为什么得到错误 "string not terminated"?} 这里反斜杠是一个转义字符,因此 \verb|\"| 解释为引号本身,导致字符串没有结束的双引号,幸运的是,反斜杠是 用双引号定界的字符串中唯一的转义字符。这里,最后的那个反斜杠是不需要的,但如果你确实需要一个反斜杠,可以 这样写:\verb|settings.dir="C:\asymptote"+'\\';|。 \subsection{\label{Q2.11}在微软Windows下我如何改变环境变量,比如,要如何改变默认的PostScript查看器?} 其实在你的config.asy文件中设置相应的Asymptote配置变量会更容易一些。如果要改变Windows环境变量,可按如下步骤: \begin{itemize} \item 右击“我的电脑” \item 从弹出菜单中选择属性 \item 单击“高级”标签 \item 单击”环境变量“按钮 \end{itemize} \subsection{\label{Q2.12}在微软Windows XP下,为什么我得到这样的错误:"Invalid Parameter - 432x432"?} 这意味着ImageMagick没有安装正确,你在使用的是MSDOS的covert程序而不是ImageMagick中的convert。 也有可能虽然你正确安装了ImageMagick却是在一个现有的MSDOS窗口中运行的Asymptote。如果是这种情况, 只需打开一个新窗口重试。如果还不行,请检查如下命令 \begin{verbatim} convert --version \end{verbatim} 是否返回类似这样的信息: Version: ImageMagick 6.2.8 06/27/06 Q16 http://www.imagemagick.org 。 \subsection{\label{Q2.13}微软Windows下装有MikTeX,为什么当试图画一个label时Asymptote没反应了?} 这有可能意味着latex和dvips不在你的默认路径中,尝试将如下行加入到你的config.asy文件中: \begin{verbatim} import settings; latex="C:\texmf\miktex\bin\latex.exe"; dvips="C:\texmf\miktex\bin\dvips.exe"; \end{verbatim} \section{\label{Q3}关于路径(path)的问题} \subsection{\label{Q3.1}当我为path tesnsion 指定一个整数值时,为什么会出现语法错误?} 这里发生的是,如下一句 \begin{lstlisting} draw((0,0)..tension 2..(0,50)..(100,100)); \end{lstlisting} 被理解为 \begin{lstlisting} draw((0,0)..tension 2. .(0,50)..(100,100)); \end{lstlisting} 因此2后面的第一个~.~被当成了小数点。整数的tension值之后加个空格就好了。 \begin{lstlisting} draw((0,0)..tension 2 ..(0,50)..(100,100)); \end{lstlisting} \subsection{\label{Q3.2}点不应该保持一样大小吗?} 文档中提到:\\ “plain模块中定义的dot命令画的点具有由pen参数明确指定的线宽或者是默认线宽乘以一个 缩放因子dotfactor(默认值为6)。”\\ 因此,当你使用默认画笔(pen)时,点的尺寸为 6*linewidth,但是当你指定具有明确线宽的画笔时, 你得到的点的大小就是你指定线宽。如果你希望第一种情况和第二种情况的行为一样,可以设置 dotfactor=1。 \section{\label{Q4}关于标注(labels)的问题} \subsection{\label{Q4.1}如何在标注中使用希腊字母,比如~$\omega$} 在(La)TeX中,希腊字母可以在数学模式中实现,通过在其英文名称前加一个反斜杠得到。 因此,$\omega$~符号使用~\verb|"$\omega$"|~得到。两个美元符号之间的任何东西都被当做 公式看待。大写希腊字母通过把其名称首字母大写得到:\\ \myfig{4-1} \begin{lstlisting} label("$\omega$",(0,0)); label("$\Omega$",(20,0)); \end{lstlisting} \subsection{\label{Q4.2}Asymptote可以使用矩阵作为标注吗?} 当然可以! \myfig{4-2} \begin{lstlisting} usepackage("amsmath"); label("$\begin{matrix} 1 & 2 \\\ 1 & 1 \end{matrix}$",(0,0)); \end{lstlisting} \subsection{\label{Q4.3}我如何让Asymptote加载指定LaTeX宏包,比如mathptmx?} 把如下一句加到你的文件开头即可: \begin{lstlisting} usepackage("mathptmx"); \end{lstlisting} 注意:如果想对文本使用Adobe Times Roman字体的话,你还应该加上: \begin{lstlisting} defaultpen(TimesRoman()); \end{lstlisting} \subsection{\label{Q4.4}Asymptote的标注中如何使用国际字体?} 请参考~\url{http://asymptote.sourceforge.net/doc/unicode.html}。 \subsection{\label{Q4.5}我如何使用Fourier字体?} \begin{lstlisting} usepackage("fourier"); defaultpen(font("T1","fut\textfamilyextension","m","n")); \end{lstlisting} \subsection{\label{Q4.6}有没有办法改变小数点的的外观,比如不用点而用逗号?} 只需正确设定系统的locale\footnote{译者注:locale是Linux/UNIX系统下的术语,用于 语言、日期、货币等的本土化设置。}。这是两个例子(在UNIX的bash shell下): \begin{verbatim} echo "label(format(0.5));" | LC_NUMERIC=it_IT asy -V - LC_NUMERIC=it_IT asy -V lineargraph \end{verbatim} \subsection{\label{Q4.7}我要如何才能将标注旋转,同时让它的已填充边框保持同步旋转呢?} \myfig{4-7} \begin{lstlisting} frame f; label(f,"This is some text",white,Fill(blue)); add(rotate(65)*f); \end{lstlisting} \subsection{\label{Q4.8}我如何旋转三维图中的标注?} 你需要首先将triple类型投影为pair类型,像这样: \myfig{4-8} \begin{lstlisting} import three; size(100,100); draw(rotate(90,project(Z))*"A",O--X); \end{lstlisting} \subsection{\label{Q4.9}我如何画一些固定尺寸的正方形和圆并把标注放在它们的中心?} 固定尺寸的对象应该画在独立的picture上,然后再把它们添加到currentpicture上。 这是一种方法(也可参考~\url{ http://asymptote.sourceforge.net/gallery/subpictures.asy} 和~\url{http://asymptote.sourceforge.net/gallery/mosquito.asy}): \myfig{4-9} \begin{lstlisting} real u=2cm; picture square; draw(square,scale(u)*shift(-0.5,-0.5)*unitsquare); picture circle; draw(circle,scale(0.5u)*unitcircle); void add(picture pic=currentpicture, Label L, picture object, pair z) { add(pic,object,z); label(pic,L,z); } add("square",square,(0,0)); add("circle",circle,(5cm,0)); \end{lstlisting} \subsection{\label{Q4.10}二元算符 * 可以用一个因子来缩放画笔的颜色,这个缩放因子必须小于1吗?} 缩放因子可以大于1,但是您因该记住rgb颜色分量到1就饱和了。\\ 尝试如下代码你就很快明白是怎么回事了: \begin{lstlisting} write(cyan); write(0.8*cyan); write(1.5*cyan); \end{lstlisting} 要得到浅一些的 \verb|cyan| 颜色你可以用 \verb|white+cyan|,这将产生 \verb|rgb(0.5,1,1)|。 如果你想让某种颜色更浅的话,就直接指定rgb颜色吧,例如 \verb|rgb(0.9,1,1)|。 令外,在cmyk颜色空间里,饱和度是与色调分开来独立处理的,这样更方便: \verb|0.1*Cyan| 浅, \verb|0.9*Cyan| 深。你也可以这么写~\verb|0.1*(red+cmyk)|。 \subsection{\label{Q4.11}为什么在我的locale下,逗号小数点后的空白那么大?} LaTeX把逗号当成标点而不是当成小数点。解决办法就是在文件开头加载 icomma 包: \begin{lstlisting} usepackage("icomma"); \end{lstlisting} \subsection{\label{Q4.12}如何阻止 texpreamble("$\backslash$usepackage[pdflatex]\{hyperref\}") 改变页面尺寸?} \begin{lstlisting} texpreamble("\\usepackage[pdftex,setpagesize=false]{hyperref}"); \end{lstlisting} \section{\label{Q5}关于箭头的问题} \subsection{\label{Q5.1}我如何在一条路径上的任何位置处画两个箭头?} 假设至少一个箭头被填充,你可以这样做: \myfig{5-1a} \begin{lstlisting} size(200); path g = (0,0)..(1,3)..(3,0); draw(g,Arrow(Relative(0.9))); add(arrow(g,invisible,FillDraw(black),Relative(0.5))); add(arrow(reverse(g),invisible,FillDraw(white,black),Relative(0.9))); \end{lstlisting} 如果两个箭头都使用填充类型 \verb|NoFill|,你就需要在 plain\_arrows.asy中建一个特定版本的 ~\verb|arrow| 程序了: \begin{lstlisting} void arrow(frame f, arrowhead arrowhead=DefaultHead, path g, pen p=currentpen, real size=0, real angle=arrowangle, filltype filltype=arrowhead.defaultfilltype, position position=EndPoint, bool forwards=true, margin margin=NoMargin, bool center=false); \end{lstlisting} \subsection{\label{Q5.2}我如何反转一个箭头头\protect\footnote{译者注:呵呵,没写错,指箭头的头部,即 arrowhead。}的方向?} 只需简单的将路径的方向反转即可。 \myfig{5-2} \begin{lstlisting} path g=((0,0)--(5cm,0)); draw(reverse(g),Arrow(Relative(0.55))); \end{lstlisting} \subsection{\label{Q5.3}我如何改变所有箭头的大小?} 要指定箭头尺寸,你可以给每个画图属性 \verb|Arrow| 指定一个实型尺寸参数。 如果想全局的改变,可以如下重载依赖画笔的 \verb|arrowsize| 函数: \begin{lstlisting} arrowsize=new real(pen p=currentpen) {return 2mm;}; \end{lstlisting} \subsection{\label{Q5.4}我能创建其它的箭头头类型吗?} 你可以这样创建自定义的箭头头(进一步的例子请参看plain\_arrows.asy中预定义的箭头头类型): \myfig{5-4} \begin{lstlisting} arrowhead DotHead; DotHead.head=new path(path g, position position=EndPoint, pen p=currentpen, real size=0, real angle=0) { if(size == 0) size=DotHead.size(p); bool relative=position.relative; real position=position.position.x; if(relative) position=reltime(g,position); path r=subpath(g,position,0.0); pair x=point(r,0); real t=arctime(r,size); pair y=point(r,t); return circle(0.5(x+y),0.5size); }; size(100); draw((0,0)..(1,1)..(2,0),Arrow(DotHead)); dot((2,0),red); \end{lstlisting} 如果你将自定义的箭头头类型提交到论坛或补丁跟踪系统中,我们会考虑 把它们包括在以后的版本中。 \section{\label{Q6}二维坐标图的问题} \subsection{\label{Q6.1}沿着$x$轴的正向,如何能让刻度(ticks)标在$x$轴的右侧而刻度的标注标在左侧 \protect\footnote{译者注:这里的左右得这样理解,即观察者的身体要与$x$轴平行}?} \myfig{6-1} \begin{lstlisting} import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis("$x$",RightTicks(Label(align=left))); yaxis("$y$",RightTicks); \end{lstlisting} \subsection{\label{Q6.2}如何重定位$x$轴标注到沿轴长度3/4处?} \myfig{6-2} \begin{lstlisting} import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis(Label("$x$",0.75),LeftTicks); yaxis("$y$",RightTicks); \end{lstlisting} \subsection{\label{Q6.3}如何向下移动$x$轴标注10bp?} \myfig{6-3} \begin{lstlisting} import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis(shift(0,-10)*"$x$",LeftTicks); yaxis("$y$",RightTicks); \end{lstlisting} \subsection{\label{Q6.4}我能对坐标轴、轴标注和刻度标注用不同的画笔吗?} 当然可以: \myfig{6-4} \begin{lstlisting} import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis(Label("$x$",MidPoint,red),Bottom,blue,LeftTicks(green)); yaxis("$y$",Left,RightTicks); \end{lstlisting} \subsection{\label{Q6.5}如何更改轴标注的字体?} \myfig{6-5} \begin{lstlisting} import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis("x",Bottom,Courier("m","n"),LeftTicks); yaxis("$y$",Left,RightTicks); \end{lstlisting} \subsection{\label{Q6.6}如何改变坐标轴上的刻度标注的字体类型?} 刻度标注默认在TeX的数学模式中排版,因此要使用其它字体,你需要重载默认的刻度格式: \myfig{6-6} \begin{lstlisting} import graph; size(300,200,IgnoreAspect); xlimits(-50,50); ylimits(0,100); xaxis("$x$",Bottom,LeftTicks("%.4g",Courier("m","n")+fontsize(12))); yaxis("$y$",Left,RightTicks); \end{lstlisting} \subsection{\label{Q6.7}如何阻止轴标注重叠在彼此之上?} %Question 6.7. How can I prevent axes tick labels from rendering on top of each other? 你可以: (1) 为 \verb|LeftTicks/RightTicks/Ticsk| 指定参数 \verb|beginlabel=false| 和$/$或 \verb|endlabel=false|; (2) 手动去掉指定刻度及其标注(手动去画;关于 \verb|NoZero| 的定义请参看 \url{http://asymptote.svn.sourceforge.net/viewvc/asymptote/trunk/asymptote/base/graph.asy}): \myfig{6-7b} \begin{lstlisting} import graph; size(10cm); real f(real x) {return x^2;} draw(graph(f,-2,2)); xaxis(Ticks(NoZero)); yaxis(Ticks(NoZero)); label("$0$",(0,0),SW); \end{lstlisting} (3) 去掉指定刻度标注并手动画(关于~\verb|NoZeroFormat|~的定义请参考 \url{http://asymptote.svn.sourceforge.net/viewvc/asymptote/trunk/asymptote/base/graph.asy} \myfig{6-7c} \begin{lstlisting} import graph; size(10cm); real f(real x) {return x^2;} draw(graph(f,-2,2)); xaxis(Ticks(NoZeroFormat)); yaxis(Ticks(NoZeroFormat)); label("$0$",(0,0),SW); \end{lstlisting} (4) 使用图形界面 xasy 来移动重叠的标注。 (5) 改变~\verb|Label|~的参数~\verb|LeftTicsk|,\verb|RgihtTicks|,\verb|Ticks|~为: \begin{lstlisting} Label(currentpen+overwrite(Move)) \end{lstlisting} 办法(5)会移动可能和前面画的标注的重叠的标注。\verb|overwrite|~的其它可用的参数 为~\verb|Allow|(允许标注重叠,默认设置),\verb|Suppress|(重叠的标注根本不画出), \verb|SuppressQuiet|~和\verb|MoveQuiet|。最后两个产生和相应没有~\verb|Quiet|~的 参数同样的结果,只是不再提示哪些标注重叠了。请看 \url{See: http://asymptote.sourceforge.net/doc/Pens.html}。 若是用户指定~\verb|tick|~数组的情况下,可以通过改变数组元素顺序来改变哪些标注 被禁止(suppressed)或移动。 \subsection{\label{Q6.8}如何在不考虑标注和图例的情况下使得所画图的区域具有固定大小?} 你可以: (1) 指定一个明确的单位(\verb|unitsize|),这将对任何对尺寸的调用有效: \begin{lstlisting} unitsize(x=1cm,y=2cm); \end{lstlisting} (2) 明确告诉Asymptote,让它把画图区域映射到指定大小: \myfig{6-8b} \begin{lstlisting} import graph; real[] x={0,1,2,3}; real[] y=x^2; draw(graph(x,y),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); size(5cm,5cm,point(SW),point(NE)); label("$f_\mathrm{T}$",point(N),2N); \end{lstlisting} (3) 以用户坐标指定点的位置,相当于给定图像大小: \myfig{6-8c} \begin{lstlisting} given picture size: import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); fixedscaling((-1.5,-0.5),(1.5,3.5)); \end{lstlisting} 在这个例子中,用户坐标(-1.5,-0.5)位于图的左下角,(1.5,3.5)为右上角。 可以使用这个选项来确保多个图具有相同的缩放以及相同的最终尺寸(只需 保证传给 \verb|fixedscaling()| 的两个坐标给所有标注留有足够的空间即可)。 还可参考 \url{http://asymptote.sourceforge.net/doc/Frames-and-pictures.html}。 \subsection{\label{Q6.9}如何在 $[0,1]\times[0,2]$ 范围内画一个函数 $f(x)$,而且还不用去管 $f(x)$ 是否会达到图的边界?} 在画图前调用一下带有 \verb|Crop| 选项 \verb|limits| 函数即可: \myfig{6-9} \begin{lstlisting} import graph; size(250,200,IgnoreAspect); draw(graph(exp,-1,1),red); limits((0,0),(1,2),Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); \end{lstlisting} 还可参考 \url{http://asymptote.sourceforge.net/doc/graph.html}。 \subsection{\label{Q6.10}可以自定义调色板吗?} 是的,你可以产生你自己的 \verb|pen[]| 数组。例如: \begin{lstlisting} int NColors=32768; pen[] MyPalette=new pen[NColors]; real step=1/(NColors-1.0); // Start at black: rgb(0,0,0) // End at yellow: rgb(1,1,0) for(int i=0; i < NColors; ++i) { real rgval=i*step; MyPalette[i]=rgb(rgval,rgval,0.0); } \end{lstlisting} \subsection{\label{Q6.11}有没有简单的方法可以画出漂亮的阶乘函数图?} 以下例子给出的是连续函数,并用两种不同方法标出了 $x$ 的整数值:\\ (译者注:下面例子中的上图对应方法一,下图对应方法二。) \myfig{6-11a} \myfig{6-11b} \begin{lstlisting} import graph; size(200,200,IgnoreAspect); real factorial(real t) {return gamma(t+1);} scale(Linear,Log); // 画阶乘函数图。 draw(graph(factorial,0,10)); // 方法 1: 只画结点,把线隐藏 pair F(int t) {return (t,factorial(t));} // 从 0 到 10 的阶乘图 pair[] z=sequence(F,11); // 译者注:下面的 above=true 参数处在原 FAQ 中给的是 Below ,但编译不通过。 draw(graph(z),invisible,marker(scale(0.8mm)*unitcircle,blue,Fill,above=true)); // 方法 2: 非作图程序要指定明确的缩放 (scaling): pair dotloc(int t) {return Scale(F(t));} pair[] dotlocs=sequence(dotloc,11); dot(dotlocs); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); \end{lstlisting} \subsection{\label{Q6.12}在一个有自己尺寸的图(picture)中,如何单独指定某个特定长度而不被缩放?} 这里有一个简单的方法来实现\footnote{译者注:注意箭头及两端的小线段的尺寸不随size而改变。}: \myfig{6-12} \begin{lstlisting} size(12cm,0); void distance(picture pic=currentpicture, pair A, pair B, Label L="", real n=0, pen p=currentpen) { real d=3mm; path g=A--B; transform T=shift(-n*d*unit(B-A)*I); pic.add(new void(frame f, transform t) { picture opic; path G=T*t*g; draw(opic,Label(L,Center,UnFill(1)),G,p,Arrows(NoFill),Bars,PenMargins); add(f,opic.fit()); }); pic.addBox(min(g),max(g),T*min(p),T*max(p)); } pair A=(0,0), B=(3,3); dot(A); dot(B); distance(A,B,"$\ell$",1); \end{lstlisting} \subsection{\label{Q6.13}如何使 $y$ 显示以2为底的对数值?} 参考例子 \url{http://asymptote.sourceforge.net/gallery/2Dgraphs/log2graph.asy}。 \subsection{\label{Q6.14}如何在同一张图中对齐两个坐标图的 $x$ 轴?} 如果将要对齐的两个轴具有同样的比例(scale)及尺寸,例子中给出了一个简单的方法, 请参见 \url{http://asymptote.sourceforge.net/gallery/2D graphs/alignedaxis.asy}。 下面给出的是一个对齐任意两个轴的更一般的方法。对第二个picture调用 \verb|fit| 使之适合基于第一个picture的水平比例的框架(frame): \myfig{6-14} \begin{lstlisting} import graph; real width=15cm; real aspect=0.3; picture pic1,pic2; size(pic1,width,aspect*width,IgnoreAspect); size(pic2,width,aspect*width,IgnoreAspect); scale(pic1,false); scale(pic2,false); real xmin1=6; real xmax1=9; real xmin2=8; real xmax2=16; real a1=1; real a2=0.001; real f1(real x) {return a1*sin(x/2*pi);} real f2(real x) {return a2*sin(x/4*pi);} draw(pic1,graph(pic1,f1,xmin1,xmax1)); draw(pic2,graph(pic2,f2,xmin2,xmax2)); xaxis(pic1,Bottom,LeftTicks()); yaxis(pic1,"$f_1(x)$",Left,RightTicks); xaxis(pic2,"$x$",Bottom,LeftTicks(Step=4)); yaxis(pic2,"$f_2(x)$",Left,RightTicks); yequals(pic1,0,Dotted); yequals(pic2,0,Dotted); pair min1=point(pic1,SW); pair max1=point(pic1,NE); pair min2=point(pic2,SW); pair max2=point(pic2,NE); real scale=(max1.x-min1.x)/(max2.x-min2.x); real shift=min1.x/scale-min2.x; transform t1=pic1.calculateTransform(); transform t2=pic2.calculateTransform(); transform T=xscale(scale*t1.xx)*yscale(t2.yy); add(pic1.fit()); //译者注:下面 truepoint 处在原 FAQ 中为 framepoint ,但是编译不通过。 real height=truepoint(N).y-truepoint(S).y; add(shift(0,-height)*(shift(shift)*pic2).fit(T)); \end{lstlisting} \subsection{\label{Q6.15}如何改变$y$轴的方向使得负值出现在$y$轴的上部?} 以下是一个简单的例子(还可参考例子 \url{http://asymptote.sourceforge.net/gallery/2D graphs/diatom.asy} 或文档中对 \verb|Linear(-1)| 的讨论): \myfig{6-15} \begin{lstlisting} import graph; size(250,200,IgnoreAspect); scale(Linear,Linear(-1)); draw(graph(log,0.1,10),red); xaxis("$x$",LeftTicks); yaxis("$y$",RightTicks); \end{lstlisting} \subsection{\label{Q6.16}如何用一个定义了不同位置处颜色的函数填充一条路径?} 一般函数着色(shading)仅被PDF支持,而不被PostScript支持,因而必须等到我们 开发出直接的PDF代码后才行。 目前一个近似的处理方法就是划分出一个比较细的网格并根据不同位置处的颜色 定义一个数组 \verb|pen[][]| 然后再利用 \verb|latticeshade| 调用这个数组来着色。 \subsection{\label{Q6.17}有没有办法画一个没有显式给出的函数,比如 $(y-2)^2=x-1$ ?} 可以,使用参数形式: \begin{lstlisting} y=t x=(t-2)^2+1 \end{lstlisting} 参见例子 \url{http://asymptote.sourceforge.net/gallery/2Dgraphs/parametricgraph.asy}。 \subsection{\label{Q6.18}可以反转或拉伸一个轴吗?} \verb|Linear| 通过一个实型的缩放参数来拉伸(或反转)坐标轴。要看到坐标轴拉伸的效果, 须确保在图像的 \verb|size| 命令中没有指定 \verb|IgnoreAspect|。 第二轴\footnote{译者注:主轴指下面的横轴和左边的纵轴,第二轴指上面的横轴和右边的纵轴。} 和主轴有着相同的长度,因此拉伸没有效果。但是仍然可以通过 \verb|Linear(-1)| 来进行反转。 \subsection{\label{Q6.19}为什么我不能用 UnFill 选项来画一个具有空心标记(marker)的图?} \verb|UnFill| 在这儿不起作用是因为它只影响那个一开始就已经把标记画上去了且是未被 添加到 \verb|currentpicture| 上之前的局部框架(local frame)。 \myfig{6-19} \begin{lstlisting} import graph; size(10cm,0); pair[] z={(0,0),(0.5,0.5),(1,1)}; path g=graph(z); draw(shift(0,.5)*g,marker(scale(5)*unitcircle,FillDraw(white))); //译者注:可以比较一下以下几句的效果。 //draw(shift(0,.5)*g,marker(scale(5)*unitcircle)); //draw(shift(0,.5)*g,marker(scale(5)*unitcircle,Fill)); //draw(shift(0,.5)*g,marker(scale(5)*unitcircle,UnFill)); xaxis(BottomTop,LeftTicks); yaxis(LeftRight,RightTicks); \end{lstlisting} \subsection{\label{Q6.20}如何强制令几个图象使用同一个调色板范围(比如整个0-255的灰度范围)?} 调色板的颜色空间是一系列颜色的范围,这个范围作为一个参数可以被指定,比如它可以为 \verb|Full|, \verb|Automatic| 或一个显式指定的范围 \verb|Range(pair min, pair max)|。 这里,\verb|Full| 指定函数在抽样区间内从最小值变到到最大值的范围,而 \verb|Automatic| 则会自动选择 合适的上下限。 \section{\label{Q7}关于编程的问题} \subsection{\label{Q7.1}Asymptote是一个解释器还是一个编译器?} Asymptote把它的命令编译成自己的虚拟机代码,然后它就在虚拟机上运行这个虚拟机代码来产生PostScript代码。 \subsection{\label{Q7.2}frame和picture之间的区别是什么?} frame 是使用PostScript坐标来画图的画布。对一些延迟画图程序,在frame上画图 有时是必须的,而一般说来使用picture来画图会更方便。请参考\qref{Q8.8}。 \subsection{\label{Q7.3}path和guide之间的区别是什么?} 一条path是一条具有确定端点坐标的三次样条曲线。 一条guide是一条未解释的三次样条曲线(一系列三次样条曲线的节点和控制点)。 guide类似path,不同的是对guide来说三次样条曲线是延迟到画图的时候(这时才被解释成path) 才计算;这样,两条具有自由端点条件的guide便可以平滑的接到一起。 \subsection{\label{Q7.4}如何方便的声明并初始化一个picture的数组?} 你可以自己写一个如下的程序: \begin{lstlisting} picture[] picture(int n) { picture[] pic; for(int i=0; i < n; ++i) { pic[i]=new picture; size(pic[i],19cm,0); } return pic; } picture[] pic=picture(6); \end{lstlisting} \subsection{\label{Q7.5}有没有办法定义一个一般性的处理数组的函数(也就是说对任何类型的数组都行)?} 一般类型尚未实现。但是至少目前你可以这样写: \begin{lstlisting} typedef string T; include F; \end{lstlisting} \begin{lstlisting} typedef real T; include F; \end{lstlisting} 其中 F.asy 中包含类似如下的类型定义的代码: \begin{lstlisting} T[] operator $(T A, T B) {return new T[] {A,B};} \end{lstlisting} \subsection{\label{Q7.6}有没有办法在定义一个结构之前声明它,例如结构A中执行某种对结构B的操作但是结构B中包含A类型的成员?} Asymptote不支持数据类型的提前声明。然而你可以嵌套结构,以便两个类型对两个结构体定义中的某些部分都可见。例如: \begin{lstlisting} struct B { typedef void someroutine(B b); static struct A { someroutine routine; void init(someroutine routine) { this.routine=routine; } } A a=new A; string test="Testing"; } typedef B.A A; A operator init() {return new A;} B operator init() {return new B;} A a; a.init(new void(B b){write(b.test);}); B b; a.routine(b); \end{lstlisting} \subsection{\label{Q7.7}for循环中的静态变量是在什么地方分配 \protect\footnote{译者注:所谓“分配(allocate)”指被分配内存地址,被分配地址标志着一个变量的诞生。}的?} 在下面例子中 \begin{lstlisting} void f() { for(int i=0; i < 3; ++i) { static int n; ++n; write(n); } } f(); // 输出 1, 2, 3 f(); // 输出 4, 5, 6 ,此行为译者添加 \end{lstlisting} 其中的 \verb|static| 限定词意味着变量 \verb|n| 不只是在 \verb|for| 循环外面分配的, 而且还是在函数之外。如果你多次调用 \verb|f| 就会清楚,仍然只有一个 \verb|n| 的实例。 一个变量的“级别(level)”(被分配的地方)和它的“作用域(scope)”(通过变量名能够引用它的范围)是没有关系的。 花括号括起来的部分只影响一个变量的作用域而不影响它的级别。 在顶级代码\footnote{译者注(未必正确,仅供参考):Asymptote中“级别”的含义与C++中并不一样,需要注意。Asymptote中静态变量是在它的上一级 代码中分配的,且译者发现不同的级别是由于在函数或结构体内定义产生的,但是象 \verb|for| 循环等的花括号并不会改变在其 中定义的静态变量的级别;而在C++中,静态变量似乎就是在紧包围其定义的花括号内分配的,因而类似C++代码(假设位于顶级的 \verb|main| 函数中) \verb|for(int i=0; i<3; ++i) \{ static int n; ++n; printf("\%d ",n); \}| 则输出1 2 3。}中静态修饰符 \verb|static| 没有意义, 它会产生警告然后被忽略: \begin{lstlisting} for(int i=0; i < 3; ++i) { static int n; ++n; write(n); } // 输出关于顶级静态修饰符的警告,然后输出 1, 1, 1 \end{lstlisting} 自从1.22版本,循环体中分配的非静态变量在每个循环中都是重新分配的。这只有在比较 晦涩的代码中才需要注意,比如循环中的变量被在循环体内定义的一个函数访问的情况: \begin{lstlisting} int f(); for(int i=0; i < 10; ++i) { int j=10*i; if(i == 5) f=new int() {return j;}; } write(f()); // 输出 50 \end{lstlisting} 循环体中的变量最多存活到那一循环的结束,除非它们被一个函数定义引用而被延长生命期,就像上面的代码那样。 在一个函数体内,变量至少存活到函数被调用完,不过由于函数定义或内存垃圾收集程序其生命期可能会被延长。 如果一个变量是在文件的顶级或交互式提示符下定义的,那么它至少存活到文件末尾或那次交互运行的结束。 \subsection{\label{Q7.8}有没有asy程序的调试器?} 有的,Asymptote有一个基于行的调试器: \url{http://asymptote.sourceforge.net/doc/Debugger}。 \subsection{\label{Q7.9}你们接受Asymptote的补丁吗?} 接受。事实上我们希望用户能提交包含新特性的补丁(到 \url{http://sourceforge.net/tracker/?atid=685685&group_id=120000}。), 而不是只靠我们来完成所有代码。有大家参与开发才会更快! \section{\label{Q8}关于Asymptote和MetaPost之间区别的问题} \subsection{\label{Q8.1}Asymptote中什么与MetaPost中的插值算符 c[a,b] 等价?} \begin{lstlisting} interp(a,b,c); \end{lstlisting} \subsection{\label{Q8.2}图的缩放在Asymptote和MetaPost中有何不同?} Asymptote提供了一种可选的便利方式来自动缩放到给定的图片尺寸,而MetaPost只支持手动缩放。 Asymptote延迟绘制将要画在图上的对象,并且它区分真实尺寸对象和需要根据图尺寸进行缩放的对象。 由此产生的线性规划问题通过单纯形方法\footnote{译者注:“单纯形方法(simplex method)”是一种有效 求解线性规划(linear programming)问题的数学方法。}解出。 关于既包含用户坐标又包含真实尺寸(PostScript)坐标的延迟绘制的例子,可以 参考 \url{http://asymptote.sourceforge.net/gallery/dimension.asy}。 \subsection{\label{Q8.3}如何避免图的自动缩放?} 如果你真的喜欢MetaPost方法的手动(硬线的)缩放的话,你可以: (1) 对整个图使用默认尺寸 \verb|size(0,0)| 并手动处理所有缩放,就像在MetaPost中一样。 (2) 画一个独立的图 \verb|pic| 并执行 \verb|add(pic.fit())|。 (3) 使用 \verb|frame|。 \subsection{\label{Q8.4}与MetaPost中的 ... 命令等价的是什么?} 连接符 \verb|::| 是 \verb|tension atleast 1| 的宏: \myfig{8-4} \begin{lstlisting} size(100); pair z0=(0,0); pair z1=(1,0.25); pair z2=(2,0); draw(z0{up}::z1{right}::z2{down}); \end{lstlisting} \subsection{\label{Q8.5}与MetaPost中的pickup命令等价的是什么?} 只需写,比如: \begin{lstlisting} currentpen=red; \end{lstlisting} \subsection{\label{Q8.6}与MetaPost中的whatever命令等价的是什么?} Asymptote并不隐含求解线性方程组因此没有表示未知的 \verb|whatever| 概念。 这种功能当然可以添加上(既然 \verb|=| 表示赋值,也许使用记号 \verb|?=|)。 然而,MetaPost中 \verb|whatever| 的大部分用法都已被 math.asy 中的的函数所包括了, 像 \verb|extension|: \begin{lstlisting} pair extension(pair P, pair Q, pair p, pair q); \end{lstlisting} 它返回线段PQ及pq的延长线的交点。我们发现使用像 \verb|extension| 这样的程序意义更明确, 对新用户不致产生迷惑。但是如果有人能证实确实有必要添加类似 \verb|whatever| 的功能, 我们是可以考虑的。与此同时,你总是可以使用明确的内置线性方程组求解程序来求解的, 内置方法使用的是LU分解算法。 \subsection{\label{Q8.7}对于含有三个线性方程且具有三个未知量: horiz, verti, whatever 的线性方程组, MetaPost 中的方程 lray - horiz*v - verti*u = whatever*( LightSource - R ); 在 Asymptote 的对应的做法是什么呢?} 既然 \verb|horiz*v+verti*u| 张开一个平面,你可以用 \begin{lstlisting} real intersect(vector P, vector Q, vector n, vector Z); \end{lstlisting} 来找出相应于直线 \verb|lray-whatever*(LightSource - R)| 的交点时刻\footnote{译者注:Asymptote中的术语“time”,这里暂译为“时刻”。} 然后再从中获取三个要求的值。(你仍将需要用内置显式线性求解程序来解一个 $2\times 2$ 方程组来得到 \verb|horiz| 和 \verb|verti|。) \subsection{\label{Q8.8}在MetaPost中,可以通过定义一个单位 u 并明确乘在每个坐标上的方法来实现所画的图形在不同的图中具有相同的尺寸。 在Asymptote中有没有更好的办法来实现?} 有的,Asymptote有更好的办法:你肯定不想手动缩放所有的坐标。要让用户坐标代表1cm的倍数,只需: \myfig{8-8a} \begin{lstlisting} unitsize(1cm); draw(unitsquare); \end{lstlisting} 你也可以指定不同的 $x$ 和 $y$ 单位: \myfig{8-8b} \begin{lstlisting} unitsize(x=1cm,y=2cm); draw(unitsquare); \end{lstlisting} 另一个方法是把你的固定尺寸的对象画到框架上再把它添加到 \verb|currentpicture| 上: \myfig{8-8c} \begin{lstlisting} path p=(0,0)--(1,0); frame object; draw(object,scale(100)*p); add(object); add(object,(0,-10)); \end{lstlisting} 为了理解 \verb|frame| 和 \verb|picture| 的区别,请尝试如下代码\footnote{译者注:这里 代码最后的那句 \verb|add(object,(0,-10));| 中,虽然参数中的 \verb|object|是一个 \verb|picture|型对象, 但是实际添加的却是 \verb|object.fit()|,也就是说是一个 \verb|frame| 对象,所以这里的比较才有意义。从 手册中 \verb|add| 函数的原型中可以看出,只要指定了位置参数(\verb|pair| 类型),那么不管被添加的是 \verb|picture|还是 \verb|frame|,其实都是按 \verb|frame| 方式的PostScript坐标处理的。}: \myfig{8-8d} ~\\[-5mm] \begin{lstlisting} size(300,300); path p=(0,0)--(1,0); picture object; draw(object,scale(100)*p); add(object); add(object,(0,-10)); // 添加真实尺寸对象到 currentpicture \end{lstlisting} \subsection{\label{Q8.9}在MetaPost中可以通过先生成一个图再将其裁剪成一个围绕其中心的固定大小的矩形来制作填充用的图案,在Asymptote中如何实现?} 如果你正在像在MetaPost中那样使用 \verb|currentpicture| (使用PostScript坐标直接画)的话, 你只需简单的这样做: \myfig{8-9a} \begin{lstlisting} fill((0,0)--(100,100)--(200,0)--cycle); pair center(picture pic=currentpicture) {return 0.5*(pic.min()+pic.max());} real height=100; real width=100; pair delta=0.5(width,height); pair c=center(); clip(box(c-delta,c+delta)); \end{lstlisting} 然而,使用PostScript坐标画图通常是不方便的。以下是Asymptote使用延迟画图方式来实现的方法: \myfig{8-9b} \begin{lstlisting} size(200,100); //译者注:这里原来是 size(200,0); 但得到的结果与上面的不一样。 fill((0,0)--(1,1)--(2,0)--cycle); void clip(picture pic=currentpicture, real width, real height) { pic.clip(new void (frame f, transform) { pair center=0.5(min(f)+max(f)); pair delta=0.5(width,height); clip(f,box(center-delta,center+delta)); }); } clip(100,100); \end{lstlisting} 还可参考文档中关于填充(tiling)的讨论 \url{http://asymptote.sourceforge.net/doc/Pens.html}。 \section{\label{Q9}关于输出的问题} \subsection{\label{Q9.1}当处理完一个asy文件后如何禁止对PS查看器的自动调用?} 事实上默认是不自动调用的,除非你恰好是在用微软Windows(因为那样正是大部分Windows用户所希望的)。 Windows用户可以通过命令行选项 -noV 来禁止它,或者把如下代码放入 config.asy 文件中: \begin{lstlisting} import settings; interactiveView=false; batchView=false; \end{lstlisting} 请参考 \url{http://asymptote.sourceforge.net/doc/Options.html}。 \subsection{\label{Q9.2}如何输出成jpeg图像?} 如果你已正确安装 ImageMagick 软件包中的 covert 程序,只需输入 \begin{verbatim} asy -f jpg test.asy \end{verbatim} \subsection{\label{Q9.3}我能否嵌入位图(照片)并指定位置以及对其缩放?} 把它们转换成eps格式并使用 \verb|graphic(string)| 函数,就像一个标注: \begin{lstlisting} label(graphic("file"),(0,0)); \end{lstlisting} 请参考例子 \url{http://asymptote.sourceforge.net/gallery/orthocenter.asy} 和 \url{http://asymptote.sourceforge.net/doc/label.html}。 \subsection{\label{Q9.4}Asymptote是否支持直接PDF输出?} 目前,当使用 \verb|-f pdf| 选项时是支持PDF转换的,支持透明、注记以及嵌入视频和u3d图像。 然而,我们计划最终实现直接的PDF输出,以支持那些在PostScript中不能用的特性(比如根据一般函数的着色处理)。 \subsection{\label{Q9.5}如何制作光栅扫描格式(比如png、giff等)的高质量的大图?} 尝试使用一些选项来转换,主要是 \verb|-geometry| 和 \verb|-density|。例如: \begin{verbatim} convert -geometry 1000x3000 example.eps example.png \end{verbatim} 应该给出你想要的像素。 你也可以如下改变图像的默认分辨率: \begin{verbatim} convert -geometry 1000x3000 -density 300 -units PixelsPerInch example.eps example.png \end{verbatim} 这样不改变图像的像素数,只是给出一个每个像素应该显示多大的提示。 如果你用了 \verb|-density| 却没有用 \verb|-geometry| 选项, convert 程序将保持图像尺寸不变 (因此一个 4cm$\times$3cm 的eps图将产生一个4cm$\times$3cm 的png图)。 \subsection{\label{Q9.6}用Asymptote可以生成多页文档吗?} 可以,只需调用 \verb|newpage()| 函数。用 slide.asy 来制作高质量的幻灯片时就这么使用(比Prosper更方便使用)。 \end{document}