TeX 系統發展的時代,對於圖形處理還比較落後,當時,ps/eps/pdf、jpeg/png 這些圖檔都還不存在,因此這是 TeX 本身的一個盲點,雖然有 Metafont/MetaPost 這些強大的造字、繪圖的程式,但這些工具,一般人恐怕不容易駕馭,因此,可能需要尋求更方便的外來工具。
但 TeX 聰明的地方就是,他本身不能處理的,就預留個位置,讓其他輔助的工具來處理,所以,這也是 TeX 20 幾歲了,還是能和新的工具配合的原因。圖形倒是還好,因為有方便的巨集及繪圖工具來處理,只要能畫的出圖來,一切都好說,而繪圖的技巧就和 TeX/LaTeX 本身的排版技巧不算是直接相關了。
我們使用的圖檔,基本上分成兩大類,一是向量圖,不會因縮放而失真,一是點陣圖,會因為縮放而失真,但視使用場合,並不是所有的圖檔都適合製作成向量圖的。不管是哪一種圖形格式,都是數位化的結果,在電腦裡頭儲存的都是數字,只不過解釋過程不同而已。由於製作高品質的文件通常都使用向量圖,因此,我們將會把重點放在向量圖,尤其是 eps/pdf 格式。
這種圖形應該是佔最多數的,使用也最廣泛。他是使用自然的方式來儲存數位資料,把圖形所佔的頁面想像成是許多很細小的方格子所組成,每一個小格子就代表了一個圖素(pixel),這個圖素可能代表者各種不同的顏色,只要單位小格子愈多(解析度愈高),我們人類眼睛就會分辨不出其中的各小格式間的區隔,於是影像就可以平滑的顯示出來了。
我們平常常見的圖檔格式,例如:jpeg, gif, bmp, ico, xpm, png, psd, tiff
等等都是屬於點陣圖檔。由於他是由固定大小的圖素實際數位化儲存的,所以如果他們放大或縮小,我們的眼睛就會分辨出不同,甚至放得更大些,還可以看得出「格子」出來(這會造成所謂的鋸齒狀,jaggies),原來的影像就因此失真了。
向量圖檔儲存的並不是實際各種圖素的資訊,而只是儲存數學運算的基本描述,顯像時再馬上計算出結果來顯示。例如,以一個圓形圖來說,他的圖檔可能只有儲存圓心所在、圓的半徑、顏色索引值等資料,要顯示時,馬上計算,然後顯像(在螢幕或印表機上,最後顯像當然仍是要轉成點陣圖的),但由於每放大、縮小時都會重新計算過,所以,就不會造成失真了。當然,這會更秏電腦資源,但以目前的電腦軟、硬體進步的情形,這些消秏都可以控制在可被忍受的範圍。
目前最常見到的向量圖檔,應該就是 eps/pdf, svg
等圖檔,向量字型也是屬於特殊格式的一種向量圖。一般比較規律性結構的圖,會比較適合使用向量圖,自然界的實體影像可能就比較適合使用點陣圖了,但科技不會把腳步停下來,將來的數位化會是怎麼樣的情形就只能用我們的想像力去填補了。
繪圖的工具實在是太多了,這裡不可能一一介紹,只能擇要的簡單說明。我們的重點是排版,因此要知道的是圖形怎麼安置於版面裡頭才會使整個版面協調一致,而不是在繪圖教學。就請大家自行選個順手的繪圖軟體去熟悉,這類工具,大概都是一理通百理通,畫筆怎麼用簡單,要畫出像樣的圖出來會比較困難。
這是安裝 TeX/LaTeX 系統,不管是哪一種的發行版本都會附上的,但可能會有不易入門的感覺,一旦抓到到了訣竅,這是不假外求的工具。因此,在這篇文章裡頭,會對這些原生的繪圖工具多做一些說明。這裡所提到的原生繪圖工具,另外一個好處就是可以使用 CJK 環境,意思當然就是說可以在圖中插入中文及 LaTeX 排版後的結果,這恐怕是許多使用者希望的功能,但一般 GUI 式的繪圖工具就常常無法完整支援了。
目前 Knuth 教授編寫 TAOCP 使用的繪圖工具就是 MetaPost,我們這裡就不探討 Metafont,在語法上 MetaPost 和 Metafont 是類同的。由於 MetaPost 所產生的 eps 圖檔,不管是 latex 或是 pdflatex 都可以順利引用,所以將會在第 9.5 節獨立做進一步的說明。
當然,以上的任一個工具,要詳細說明的話,都可以寫成一本獨立的書,所以,在這裡只能簡單的介紹,沒有提到的部份,可以參考他們的使用手冊。Metafont 及 MetaPost 則可以另參考 Knuth 教授所寫的 The Metafontbook。
我們也可以從其他的外來繪圖工具來繪製圖形,然後再引入圖檔即可,這樣一來就可以使用自己熟悉的繪圖工具。繪圖的話,當然是以向量圖為優先考慮,因為他不會因為縮放而失真。但像一些照片類的圖檔,就不太適合使用向量圖了。
以下列出的都是 free 的繪圖工具,一般用途上,功能上不見得會輸商業產品,但使用界面上就不一定比商業產品方便。以下只做簡單的介紹,至於操作方法,請直接參考其中的使用手冊的說明。種類很多,請別眼花撩亂了,就選個一、二種去熟悉他吧!畫筆可能很多種,但畫圖「心法」只有一種。
http://www.gnuplot.info/
http://www.fnal.gov/docs/products/gnuplot/tutorial/
http://cips02.physik.uni-bonn.de/~baehren/tex/gnuplot.html
http://www.gnu.org/software/plotutils/
http://www.xfig.org/
如果你的平台無法編譯 xfig,可以試試 Java 的 jfig:
http://tech-www.informatik.uni-hamburg.de/applets/javafig/
http://bourbon.cs.umd.edu/tgif
http://plasma-gate.weizmann.ac.il/Grace/
http://www.lysator.liu.se/~alla/dia/dia.html
http://ipe.compgeom.org/
http://sketch.sourceforge.net/index.html
http://www.gimp.org/
http://w3.mecanica.upm.es/metapost/metagraf.php
http://www.openoffice.org/
http://www.koffice.org/
由於 dvips 只能接受 eps 圖檔及 POSTSCRIPT 指令,而 pdflatex 則只能接受 pdf/jpeg/png 圖檔,dvipdfm[x] 除了可接受 pdf/jpeg/png 圖檔外,大部份情形下,也可以接受 eps 圖檔,但硬生生插入的 POSTSCRIPT 指令,則仍然是無法接受,畢竟他是要生成 pdf 檔的,除非是由 MetaPost 所製作出來的圖檔,不然的話,就得使用轉換工具將他們轉成可被接受的格式,所幸,這方面的工具還算方便。上一節所提到的繪圖工具,在某種程度上也是可以轉換圖檔格式。
http://www.imagemagick.org/
http://netpbm.sourceforge.net/
http://www.pstoedit.net/pstoedit/
http://www.ipv6.tm.uka.de/~bless/ps2eps
系統上安裝 Ghostscript 的話,他也會附上一個 ps2epsi,這個工具也可以利用,但有時會算錯 BoundingBox 就是了。
由於這是 LaTeX 內建的繪圖環境,最能配合 LaTeX 原來的語法及版面配置,因此我們多花一點時間研究,使用時請另外引入 epic package,這樣可使用多一些繪圖功能。要注意的是,LaTeX 的 picture 環境,和座標息息相關,所以,繪圖之前一定腦海裡要有個座標圖來定位,而且要有相對長度的想像。
進入 picture 環境的方式就像進入其他的環境一樣,但他要指定圖形物件的大小:
...
\usepackage{epic}
...
\begin{document}
...
\begin{picture}(寬, 高)(參考原點) % 進入圖形模式
這裡下繪圖指令,形成一個或多個圖形物件,也可以寫入一般文字
讓 latex 去排版。
\end{picture}
...
\end{document}
指定長、寬等度量時,可以加上單位,如果不加單位,事先也沒有指定使用單位,那就是以 pt 為單位,(寬, 高) 是不能省略的,這在座標圖上,就是建立了左下角 (0, 0) 至右上角 (寬, 高) 的參考座標系。(參考原點) 指的是左下角的原點平移至這個位置,往後就以這個點為原點,這個可以省略,省略的話,原點位置就是 (0, 0)。通常我們都會在進入 picture 環境前先加以指定好單位,例如:
...
\unitlenght=1mm % 指定 picture 環境內的度量單位為 mm
\begin{picture}(50, 50) % 要進入 picture 環境前指定
...
這樣在 picture 環境裡頭就無需使用單位,直接寫數字就可以了,而單位就是 mm。
在繪製任何線條之前,我們通常會指定開始的位置,否則通通會從(參考)原點開始畫起。原則上,picture 環境內,有方向性的圖形物件的參考原點,例如直線、箭頭直線,他的移動方式,在繪製了圖形物件後,如果不再指定起始點,那麼,
軸的位置會平移過去,但
軸的位置則維持在原點的位置,這樣說有點抽象,只有請大家試著去畫看看才能體會了,但最好就是指定好各個圖形物件的起始位置,才不容易搞錯。
\put(啟始座標){圖形物件}
\line(向量座標){長度}
\qbezier 指令來畫出來。
\vector(向量座標){長度}
\line 指令的作用及使用方法相同,但限制更嚴格,座標值要在 \line 不同的是向量方向的那一端會多了個箭頭符號。直線和箭頭直線,他們的參考起啟點如果沒有另行指定,那
\circle{半徑}
\put,則圓心是在原點。如果是使用 \circle*{半徑} 則是實心的圓,常常用來畫某個粗點。由於圓是以圓心為參考點,並沒有方向性,所以,並不像直線一樣,
\oval{寬,高}[顯示部份]
\qbezier[曲線總點數]{起點座標}{控制點座標}{終點座標}
http://www.ursoswald.ch/metapost/tutorial/BezierDoc/BezierDoc.pdf
\thicklines
\thinklines 可還原為預設值。
\thinklines
\linethickness{粗細單位}
\framebox(寬, 高)[框內位置]{圖文物件}
\dashbox{虛線線段長度}(寬, 高)[框內位置]{圖文物件}
選定一個座標定點,我們可以使用 \put(座標) 的方式來指定,但如果是有規律性重複出現的圖形物件,這樣一個一個指定,不僅很煩,而且也較耗記憶體,計算也會比較慢。這時可以使用 \multiput 指令,他的語法如下:
\multiput(起啟座標)(座標遞增值){重複次數}{圖形物件}
這裡舉一個例子,畫一個有格子的座標系:
% example25.tex
\documentclass{article}
\usepackage{epic}
\parindent=0pt
\begin{document}
\unitlength=1mm
\begin{picture}(80, 60)
\multiput(5, 0)(5, 0){15}{\line(0, 1){60}} % 畫 15 條直線,每隔 5mm 一條
\multiput(0, 5)(0, 5){11}{\line(1, 0){80}} % 畫 11 條橫線,每隔 5mm 一條
\thicklines
\put(0, 0){\vector(0, 1){60}} % 畫 y 軸
\put(0, 0){\vector(1, 0){80}} % 畫 x 軸
\put(0, 0){\circle*{1}} % 畫圓點,實心粗點
\put(-5, -5){$O(0, 0)$} % 標上原點的座標
\put(-5, 60){$y$} % 標上 y 軸字樣
\put(80, -5){$x$} % 標上 x 軸字樣
\end{picture}
\end{document}
我們來看看這個 multiput 到底做了些什麼事:
\multiput(5, 0)(5, 0){15}{\line(0, 1){60}}
第一個座標 (5, 0) 是啟始座標,接著的 (5, 0) 是遞增值,也就是說 (5, 0), (10, 0), (15, 0)...(75, 0) 會畫後面所接的圖形物件,也就是畫長度為 60mm 的垂直線 15 次。由於我們在
軸及
軸是另外畫帶有箭頭的直線,因此,縱橫軸的部份可以少畫一條直線。
軸為 0 的 \line 就是在畫垂直線,
軸為 0 的則是在畫水平線。試想想看,這些線條如果要由 \put 指令一個一個畫上去的話,會有多煩!
畫這些除了練習外,主要是給初接觸 picture 環境的朋友一個建議,那就是把方格子畫上去,有利於繪圖時找位置,等真正要畫的圖畫好了,再把方格子拿掉。編譯好的例子如下:
http://edt1023.sayya.org/tex/latex123/example25.tex
http://edt1023.sayya.org/tex/latex123/example25.pdf
另外一個簡化座標的方式,就是使用 \shortstack 指令,他的語法如下:
\shortstack[位置]{圖文物件}
這會像疊羅漢一樣的把「圖文物件」疊在一個欄位內,和疊羅漢不同的是,後進的疊在最下面,先進的會被往上堆高,底部的基準線是固定的,高度則是往上增高,各圖文物件由換行符號來換行,也就是說可以由換行符號來決定他們之間的間隔。當然,這要自行注意他的高度,否則會和其上的其他內容重疊。「位置」可為 l, r, c 之一,是指居中,或靠這個欄位的左右邊的意思。
\shortstack 的一個特殊的運用,就是在座標圖上標註縱軸的文字,但這通常是用在中文,因為,一般的慣例,縱軸的說明文,英文的話是沿縱軸由下往上寫,中文的話是由上往下寫。我們把 example25 標上中文,實際要加入的內容為:
...
\put(-7, 20){\shortstack{這\\[-2pt]裡\\[-2pt]是\\[-2pt]縱\\[-2pt]軸}}
\put(30, -6){這裡是橫軸}
...
從這裡,我們也可以發現,把格子畫出來,對於繪圖或加入說明文字時的定位非常方便。請注意,這個例子使用了 CJK 環境,要使用 bg5latex 來編譯。編譯好的例子如下:
http://edt1023.sayya.org/tex/latex123/example26.tex
http://edt1023.sayya.org/tex/latex123/example26.pdf
當然,這樣一來,字間距也得手動去調整了,理想的話是應該將中文字旋轉才比較能符合原來的字間距,意即,橫排時的字間距和行間距,在直排的時候,兩者要互換過來,但是這樣一來,會造成中文是沿著縱軸往上寫的情形,這就不符合慣例了,但這剛好常常用在中英文混合的說明文場合,中英文混合時,是按英文的慣例,沿著縱軸由下往上寫,我們將 example26 修改一下:
...
\put(-7, 20){\rotatebox{90}{這裡是 $y$ $axis$}}
\put(30, -6){這裡是 $x$ $axis$}
...
請注意,數學式子中的額外空白通常會被忽略。編譯好的例子如下:
http://edt1023.sayya.org/tex/latex123/example27.tex
http://edt1023.sayya.org/tex/latex123/example27.pdf
如何恰當的使用,就請大家視需要去調整、運用了。我們甚至可以更進一步的把各別的中文字去分別旋轉後再排上去,而且,通常圖表的說明文字會比正文小一號,就請大家動手練習一下囉!這個 \rotatebox 指令,我們還沒有學到,會在第 9.6.4 小節,頁
裡說明。
請將以上所談到的指令,一一去試著畫幾次,大概就能體會出 picture 環境如何畫圖了。
以下是 epic 所擴充的指令,和 picture 環境配合的話,會使繪圖更得心應手。
\multiputlist(起啟座標)(座標遞增值)[tbrl]{物件1, 物件2
}
\multiput 是針對同一個圖形物件按規律性來置放,這個指令則是針對,不同的圖物形物件按規律性來置放。他是把所有的物件置放在一個 box 中去排列,因此會有 tbrl 的置放位置的選項參數。
\matrixput(起啟座標)(遞增值1){次數1}(遞增值2){次數2}{圖形物件}
\multiput 的兩種置放規律版本,可指定兩種規律來置放同一圖形物件。
\grid(寬, 高)(橫間隔,直間隔)[標註縱橫軸座標起啟值]
\multiput 來畫方格的例子,使用這個 \grid 將更為方便、簡潔。選項的部份,就是在方格外圍標註他的座標值,通常使用 (0, 0) 即可。
\picsquare{圖形物件}
\dottedline[點的形式]{點間距}(座標1)(座標2)
(座標n)
\dashline[延展值]{各點線長}[dash 點間距](座標1)(座標2)
(座標n)
\drawline[延展值](座標1)(座標2)
(座標n)
\dashline 同,負數值會造成類似 dash 線的效果。
\putfile{檔名}{繪圖指令}
\put 一樣。
更詳細的 epic 說明及其實例,可參考 Sunil Podar 所寫的文件 Enhancements to the Picture Environment of LaTeX:
http://www.ntg.nl/doc/podar/picman.pdf
PSTricks 插入了 POSTSCRIPT 的繪圖指令給 dvips 去處理,所以繪圖功能當然比 picture 環境強大,但有一個缺點是 pdflatex/dvipdfm[x] 編譯時會出問題,得由 latex/dvips/ps2pdf 的方式來製作 pdf 檔,或者另外繪製後,利用 graphicx 巨集來引入獨立的圖檔。
所以,如果是要製作 pdf 檔案的話,那麼處理上會比較不方便,而且,如果又是中文的話,那麼所製作出來的中文 pdf 檔,以目前的 PDFLaTeX 的話,對於中文將會沒有 copy&paste&search 的功能。PDFTricks 雖然可以讓 pdflatex 使用 PSTricks,但他是利用了 TeX 系統引用作業系統 shell 的功能,這在非 Unix-like 的作業系統可能會出問題,而且他和 latex/dvipdfm[x] 的相容性並不是很好。如果製作的是英文文件,那倒是沒有關係,反而可以使用 PSTricks 的強大繪圖功能。
PSTricks 除了主要的 pstricks 巨集外,另外還有其他的巨集,專門處理各種不同的特殊繪圖。例如:pst-node 及 ps-tree 可用來畫樹狀圖,pst-grad 可以表現漸層顏色,pst-poly 可以繪製多種的多邊形,pst-gr3d 可以畫 3D 格子圖。通常,一般用途的話,就是引用 pstricks,而他的繪圖環境是包在 pspicture 環境裡頭的,他的預設單位是 1cm,和 picture 環境的 1pt 不同:
...
\usepackage{pstricks}
...
\begin{document}
...
\begin{pspicture}(左下角座標)(右上角座標)
這裡繪圖
\end{pspicture}
...
他的其他專用巨集並不會自動引用 pstricks,所以要自行引入後,再引用專用的巨集,另外,如果要使用顏色的話,由於 pstricks 對顏色的定義和 LaTeX 的巨集會有不相容的情形,因此,我們要引用 David Carlisle 另外寫的 pstcol 這個巨集來修正他。pstcol 會自動引用 color 及 pstricks 這兩個巨集,因此,除非要加入選項參數,引用了 pstcol 就不必引用 color 及 pstricks 了。pstcol 也可以引用和 color 一樣的參數,例如:
...
\usepackage[usenames,dvipsnames]{pstcol}
...
由於篇輻的關係,這裡不準備詳細介紹 PSTricks 的繪圖指令,但 TUGIndia(Indian TeX Users Group) 已經完成了相當不錯的 PSTricks 入門教材,請大家不要錯過:
http://sarovar.org/projects/pstricks/
http://www.tug.org.in/tutorials.html
這個套件一般系統是沒有安裝的,請至 CTAN 下載,下載後解開,如果是在 Unix-like 系統,那執行 make 就可以了,否則請將 pdftricks.sty 拷貝至:
$TEXMF/usr/share/texmf/tex/latex/pstricks 或 $TEXMF/usr/share/texmf/tex/latex/pdftricks 請自行建立目錄 執行 texhash 或 mktexlsr
另外,將 pst2pdf 這個可執行檔,拷貝至執行路徑可及之處就行了。另請注意他的檔案格式,如果是在 Unix-like 系統,則要把他的檔案格式改為 Un*x 系統的規格。
PDFTricks 主要是把 PSTricks 巨集的引用,由 psinputs 環境包起來,而 pspicture 環境,則另外由 pdfdisplay 環境包起來,這樣就可以由 pdflatex 來編譯了。例如:
\documentclass{article}
\usepackage{pdftricks}
\begin{psinputs}
\usepackage[usenames,dvipsnames]{pstcol}
所有 pstricks 的巨集引用,都要被 psinputs 環境包起來
\end{psinputs}
...
\begin{document}
...
\begin{pdfdisplay}
\begin{pspicture}
這裡依正常 pstricks 的指令繪圖
\end{pspicture}
\end{pdfdisplay}
...
\end{document}
這樣就可以由 pdflatex 直接編譯了。要非常注意的是,執行 pdflatex 時,後面要加上 -shell-escape 參數,這個功能,一般的 TeX 系統是關閉的,要打開來讓他可以由 pdflatex 執行當中,停下來等待外部指令的執行完畢後再繼續原來未完成的工作。不過,這個方式不保證能在 Windows 系統中正確執行。
這裡舉一個簡單的例子,同時說明如何使用 PSTricks、PDFTricks 及如何引入外部 gnuplot 製作的 picture 環境文稿的例子:
http://edt1023.sayya.org/tex/latex123/test-pstricks.pdf
http://edt1023.sayya.org/tex/latex123/test-pdftricks.pdf
http://edt1023.sayya.org/tex/latex123/test-pstricks.tex
http://edt1023.sayya.org/tex/latex123/test-pdftricks.tex
http://edt1023.sayya.org/tex/latex123/gnuplot-label.dem
最後一個 tar ball 是原始文稿。latex/dvips/ps2pdf 的編譯的方式如下:
gnuplot gnuplot-label.dem => 產生 gp-test.tex picture 環境文稿 latex test-pstricks.tex dvips -o test-pstricks.ps test-pstricks.dvi ps2pdf test-pstricks.ps
pdflatex 的編譯方式如下,請不要忘了 -shell-escape 參數:
關於這些在 LaTeX 繪圖的例子另請參考 Urs Oswald 所舉的例子及其說明:
http://www.ursoswald.ch/LaTeXGraphics/overview/overview.html
http://www.ursoswald.ch/LaTeXGraphics/overview/latexgraphics.pdf
從這些例子可以發現,picture 環境及 PSTricks 巨集的確是可以拿來繪製精美的圖形的。
MetaPost 除了可以直接繪圖,還可以做一些數學運算後把結果圖形化,所以不必如 picture 環境般的一筆一筆的畫上去,只要能整理出規律出來,就可以使用數學函數的方式來繪圖。在使用上和 picture 環境一樣,要有座標系的觀念。
通常 MetaPost 文稿我們以 .mp 為他的延伸檔名,以便和其他檔案辨別,這個文稿使用任何一種編輯器編輯即可。在英文環境,編譯 MetaPost 文稿的方法可有兩種,中文環境的話,我們會在第 9.5.6 小節討論:
mpost some.mp % 產生 some.1 及 some.log epstopdf some.1 % 產生 some.pdf 圖檔
some.1 就可以直接引入文稿中了。
mptopdf some.mp % 產生 some.1 及 some-1.pdf
這樣也可以產生 some.1,及多出一個 some-1.pdf。但 mptopdf 所產生的 some.1 是真正的 eps 檔,可以直接由 gv/gsview 來閱覽,傳統 mpost 所產生的 some.1 則是使用 MetaPost 的字型表示法,所以 gv/gview 會無法正常閱覽。不過,引進 LaTeX 文稿則沒有什麼差異。
tex mproof some.1 ... some.n % 產生 mproof.dvi dvips mproof.dvi % 產生 mproof.ps
可以接受多個圖檔,看原來的文稿中有幾個圖檔,後面就接幾個圖檔,他會集中所有圖檔顯示在 mproof.dvi 當中,再利用 dvips/dvipdfm[x] 就可以產生 ps/pdf 檔來閱覽,他會加入各個圖檔的檔名及編號。
在談到 MetaPost 文稿的結構前,我們先提一下 MetaPost 使用的度量單位,如果沒有標明的話,他預設是使用 big point(bp),也就是 POSTSCRIPT 規格中所使用的單位,這和 TeX 本身是使用 printer point(pt) 不一樣。這裡我們所談的,主要是用於繪圖,至於他的巨集功能,這裡就不討論了。他的文稿結構如下:
其中的 beginfig(n) 的 n 可以是任何一個數目字,代表經 mpost 編譯過後所輸出的 eps 圖檔的延伸檔名,如果一次要處理多數圖檔,只要使用多個 beginfig...endfig 就可以了,但其內的數字則不可相同,以免圖檔被覆蓋。MetaPost 的指令和 TeX/LaTeX 不同的是前面沒有 \ 來起頭,而且每個敘述最後一定要加個 ; 來結束,否則編譯會出錯,例外是 beginfig、endfig 及 bye/end 這些指示可以不必使用 ; 來結束。
這些資料型態可以儲存固定的繪圖指令組或者是數學運算式,這樣的好處是,可以把一組複雜但又常重複的繪圖指令集或數學運算,宣告成幾個變數來代表,往後要用到時,就使用變數即可,可以讓 MetaPost 的程式碼寫起來更簡潔。
numeric a, b, c, d; % 宣告 a,b,c,d 四個變數為數值型態 a := 9; b := 3*a**2; c := a++b; d := c+-+b; show a, b, c, d; % 把計算結果顯示出來 bye
其中 3*a**2 代表
,a++b 代表
,c+-+b 代表
。MetaPost 不支援科學計數表示法。這可以存成一個檔案,經由 mpost 編譯後會顯示計算結果,也可以由以下的方式來直接輸入計算:
edt1023:~$ mpost This is MetaPost, Version 0.641 (Web2C 7.4.5) **\relax * => 變成一個星號時,就可以輸入各行敘述了 ...
這裡要注意的是,numeric 型態不一定要事先宣告,可以直接使用,但宣告的用意是在消除前面的指定,也就是說,一經宣告就會消除以前所指定的值。所以,直接使用的變數,MetaPost 會把他當做是 numeric 型態。
beginfig(1); u := 1mm; % 指定單位 pair a, b, c, d; % 宣告四個 pair 形態的變數 a := (0, 0); b := (30u, 0); c := (30u, 30u); d := (0, 30u); draw a--b--c--d--a; endfig; bye
這會繪製 30mm 長寬的正方形。也可以使用矩陣的方式來宣告,例如:
pair a[]; % 這等於宣告了 a0, a1, a2, a3... pair a[][]; % 這樣宣告也可以,代表 a00, a01...,a12, a13...
顏色 rgb 值 black (0, 0, 0) white (1, 1, 1) red (1, 0, 0) green (0, 1, 0) blue (0, 0, 1)
在 MetaPost 使用顏色比在 LaTeX 裡頭方便多了,各種顏色的表示,除了原來的 rgb 值的表示法外,也可以在各種預先定義好了的顏色加上其深淺度,例如:
withcolor .6red; withcolor .5white; color A; % 宣告 A 為 color 型態的變數 A := (.3,.8,.2); % 指定 A 的顏色 withcolor A; % 使用顏色 A
通常,我們常常需要把計算出來的數值結果標示在圖上,這時要把他轉換成字串的型態才能標示上去,我們可以使用 decimal() 函數來轉換。因為我們不能把變數值放在標註指令內,否則他將無法進行運算。例如:
u := 1cm; for i=0 upto 10: label.top(decimal(i/10), ((i+1/2)*u,1u)); endfor;
這時,變數尚未計算出來,因此不能當做 label.top() 的參數,需要在結果計算出來後,馬上進行轉換成為字串型態。
MetaPost 的指令,基本上可分成兩大類,繪圖指令(picture command)及標籤指令(label command)。繪圖指令用於繪圖,例如 draw、fill 等等;標籤指令則用於標註文字,例如 label、dotlabel 等等。繪圖指令後面可以再接附加指令(addto command)及修整指令(clip command),例如 withcolor、withpen、clip...to 等等,附加指令及修整指令都是可以省略的;標籤指令接的則是要標註的文字及其位置,這些則不能省略。整體的語法結構算是很緊密的結合在一起,所以這裡就不完整列出來了,但實際使用則還算口語化,從實際例子去熟悉用法,可能會比較容易進入狀況。
棕色的部份就是附加指令,他的意思是設定線條的粗細為 1bp(預設值是 0.5bp),使用的顏色是灰色,並且是虛線,附加指令可以省略全部或一部份的敘述。如果附加指令的部份會使用二次以上的話,也可以將他固定下來,這樣就不必每 draw 時都要去指定,例如:
pair a, b, c; a := (0, 0); b := (1cm, 0); c := (0, 1cm); pickup pencircle scaled 1bp; % 固定線條粗細 draw a--b--c--cycle withcolor .8white dashed withdots;
pair a, b, c; a := (0, 0); b := (1cm, 0); c := (0, 1cm); drawoptions(withpen pencircle scaled 1pt dashed withdots withcolor .8white); draw a--b--c--cycle;
要注意的是,如果有標註文字,這會連圖上的標註文字也使用所指定的顏色。
pair a, b, c; picture dptn; a := (0, 0); b := (1cm, 0); c := (0, 1cm); pickup pencircle scaled 1bp; % 固定線條粗細 dptn := dashpattern(on 6bp off 2bp on 2bp off 2bp); % 指定 dash 的形式 draw a--b--c--cycle withcolor .8white dashed dptn;
dashpattern 的部份,on 表示會顯示出來的線段,off 表示不顯示出來的空白。預設指定的形式是:
evenly := dashpattern(on 3 off 3); withdots := dashpattern(off 2.5 on 0 off 2.5);
這裡的 evenly 及 withdots 就是屬於 picture 型態的變數。
要注意的是,他僅僅著色,不畫線框,要畫線框要另外由 draw 指令來畫。或者改用 filldraw 指令,這樣可以既畫框又填色,只不過,這樣一來都是同一種顏色了,如果框線和所填的顏色要不一樣,就得經過 draw 及 fill 兩道手續。
圓的種類 指令 完整正圓 fullcircle 四分之圓 quartercircle 半圓 halfcircle
draw fullcircle scaled 1cm % 圓心 (0, 0),直徑 1cm 的圓 draw fullcircle scaled 1cm shift (x, y) % 圓心平移至 (x, y) draw fullcircle xscaled a yscaled b % 長短軸各為 a, b 的橢圓
前面曾出現的 with... 附加指令都可以使用。其他如半圓、四分之一圓的使用方法相同。
draw unitsquare scaled 1cm; % 左下角是 (0, 0),寬高 1cm 的正方形 draw unitsquare scaled 1cm rotated 30; % 將正方形逆時針旋轉 30 度 draw unitsquare xscaled 2cm yscaled 1cm; % 寬 2cm,高 1cm 的矩形
而且,也可以使用 shift(x, y) 來平移左下角座標的位置。
top(正上方) ulft(左上角) urt(右上角) lft(左) rt(右) bot(正上方) llft(左下角) lrt(右下角)
由其中的英文字縮寫,應不難明白他們的意思。中央的黑點,代表標註文字時所給的座標位置。所以,我們的文字可以標示在一個定點的八個方位。例如:
label.bot("O(0,0)", (0,0)); % 在原點正下方標示 O(0,0) 字樣
dotlabel.bot("O(0,0)", (0,0)); % 和 label 一樣,但會有個粗黑點
label.bot(btex $O(0,0)$ etex, (0,0)); % O(0,0) 字樣經由 \TeX\ 排版
dotlabel.bot(btex $O(0,0)$ etex, (0,0));
由 " 包圍的,他的文字是由 MetaPost 自行處理,就是一般的文字表現,但由 btex...etex 包圍的,則會交給 TeX 去排版,例如這裡進入數學模式,就會以數學斜體來排版。
這裡舉一個簡單的例子,rgb 三原色及灰階的漸層演色表,順便使用了我們沒有提到的 for loop9.4及調整字型大小的方法(這些會特別用底線標示出來)。
由 mptopdf 執行的結果如下:
http://edt1023.sayya.org/tex/latex123/test-mpcolor.mp
http://edt1023.sayya.org/tex/latex123/test-mpcolor-1.pdf
MetaPost 主要是用在 TeX 文稿,但由於他可以引入 TeX 巨集,也因此表示可以把 LaTeX 的一些指令及巨集引進去,這樣,編譯的時候,該呼叫 tex 的,就會改呼叫 latex。當然,這也表示,我們可以使用 CJK 環境來書寫中文了。
通常會要呼叫 tex 及 latex 的場合,就是要使用他們的排版功能,主要是用於排文數字,可以加入一般的文字,經過 TeX/LaTeX 排版後的漂亮結果,也可以是高品質的數學式子。
" 包住也是可以,但就不經過 TeX 處理了。
verbatimtex
%&latex % 指示由 latex 編譯,而不是預設的 tex
\documentclass{article}
\usepackage{some,packages}
\begin{document}
etex
...
verbatimtex % 以下這段通常不必,但如果有引入其他環境時則不可省略
\end{document} % 這段放在文稿最後即可
etex
這樣一來,包在 btex...etex 之間的文字就可以使用 LaTeX 指令去排版,而 mpost 也會交給 latex 去處理文字的部份。
MetaPost 文稿中,重點當然是畫圖,但是,有時也是要加入一些文字,這在英文是很方便,但在我們的 Big-5 中文就很頭大了,這裡我們使用了一個小工具 b5mp.pl,這個工具主要是引用王佑中[7]先生的 clatex 中的一個函式,把會出問題的 Big-5 中文處理好。然後,我們再加入必要的 LaTeX 及 CJK 環境的結構,最後呼叫 mpost 來編譯他,這個小工具是由 perl 寫的,可以在此下載:
http://edt1023.sayya.org/tex/latex123/b5mp.pl
他的使用方法很簡單,把他當成是 mpost 即可,使不使用 .mp 延伸檔名都沒有關係。如果 fontname 沒有指定,那麼預設是 aming:
b5mp.pl [fontname] your[.mp] => 這樣會產生 your.1 (視圖檔內的編號而定) perldoc b5mp.pl => POD 格式的 b5mp.pl 使用說明
這個 your.1 就可以被引進 LaTeX 文稿裡頭去了。由於這個編譯出來的 eps 檔,含有中文字型資訊,所以 gv 及 gsview 都會無法閱覽,epstopdf 也是無法處理,我們可以使用以下的方法來「預視」:
tex mproof your.1 => 這會產生 mproof.dvi dvips mproof.dvi => 產生 mproof.ps 或 dvipdfm[x] mproof.dvi => 產生 mproof.pdf
這樣就可以去預視了。當然,你的 LaTeX 系統要安裝好 CJK 套件,否則還是會認不得這些中文字型資訊的。mptopdf 除非另做些修改,否則在中文的場合會無法正常使用。我們這裡就綜合舉一個例子:
% test-yi.mp
beginfig(1)
u:=3cm;
path p;
p=(0,1u)..(1u,0)...(0,-1u);
fill p{dir(157)}..(0,0){dir(23)}..{dir(157)}cycle;
draw p..(-1u,0)..cycle;
fill (0,-.6u)..(0.1u,-.5u)..(0,-.4u)..(-.1u,-.5u)..cycle withcolor white;
fill (0,.6u)..(.1u,.5u)..(0,.4u)..(-.1u,.5u)..cycle;
label.bot(btex \Large 仿太極陰陽魚圖 etex,(0,-1.2u));
endfig;
beginfig(2)
a=.7in; b=0.5in;
z0=(0,0); z1=(a,0); z2=(0,b);
z0=.5[z1,z3]=.5[z2,z4];
draw z1..z2..z3..z4..cycle;
drawarrow z0..z1;
drawarrow z0..z2;
label.top(btex \small 橫軸 $x$ etex, .5[z0,z1]);
label.lft(btex \small 縱軸 $y$ etex, .5[z0,z2]);
label.bot(btex \Large 許功蓋測試 etex,(0,-.7u));
endfig;
end;
這裡頭有兩張圖,都有使用到中文,所以我們要使用 b5mp.pl 來代替 mpost 來編譯:
b5mp.pl akai test-yi % 使用 akai 字型,並產生 test-yi.1 及 test-yi.2 tex mproof test-yi.1 test-yi.2 % 產生 mproof.dvi dvips mproof.dvi % 產生 mproof.ps dvipdfmx mproof.dvi % 產生 mproof.pdf
編譯好的例子如下:
http://edt1023.sayya.org/tex/latex123/test-yi.mp
http://edt1023.sayya.org/tex/latex123/mproof.pdf
現在我們再來看看 LaTeX 文稿中要如何引用:
% example28.tex
\documentclass{article}
\usepackage{graphicx,CJK,mflogo}
\parindent=0pt
\ifx\pdfoutput\undefined
\DeclareGraphicsRule{*}{eps}{*}{}
\else
\DeclareGraphicsRule{*}{mps}{*}{}
\fi
\begin{document}
\begin{CJK}{Bg5}{hwmm}
這是一個 \MP\ 文稿中使用中文的例子,經由 {\tt b5mp.pl} 編譯後引入
\LaTeX\ 文稿當中。圖中的「太極陰陽魚」字樣是 \MP\ 文稿中就有,
不是這裡鍵入的。但其實圖檔裡頭並沒有真正的字型,而是引入文稿,
經 {\tt latex} 編譯後,才「合作」真正產生的。
\vspace{10ex}
\begin{figure}[h]
\centering
\includegraphics{test-yi.1}
\caption{太極生兩儀}
\end{figure}
\vspace{10ex}
\begin{figure}[h]
\centering
\includegraphics{test-yi.2}
\caption{英文字是數學斜體}
\end{figure}
\end{CJK}
\end{document}
編譯好的例子如下:
http://edt1023.sayya.org/tex/latex123/example28.tex
http://edt1023.sayya.org/tex/latex123/example28.pdf
這裡只是簡單的介紹了 MetaPost,實際要用的話,複雜一點的圖形,可能會不太足夠,Knuth 教授的 The Metafontbook,這應該最詳細的資料了,其中有些地方會和 MetaPost 不一樣,但整個結構上是相同的,可和系統上就有的 mpman.ps 這個 MetaPost 作者 John D. Hobby 寫的使用手冊相互參照就可以清楚不同的地方。
關於 MetaPost 更多的例子,也另請參考 André Heck 所寫的 Learning MetaPost by Doing 及 Urs Oswald、Vincent Zoonekynd 所舉的實例及其解說,examples.zip 檔是 metapost.html 網頁的原始碼,收錄在 CTAN 中:
http://remote.science.uva.nl/~heck/Courses/mptut.pdf
http://www.ursoswald.ch/metapost/tutorial.pdf
http://tex.loria.fr/prod-graph/zoonekynd/metapost/metapost.html
ftp://ctan.unsw.edu.au/tex-archive/info/metapost/examples.zip
http://www.topology.org/tex/conc/mp/mp.zip
最後一個 mp.zip 是 Alan U. Kennington 所著 differential geometry reconstructed: a unified systematic framework 一書中使用 MetaPost 繪圖的實例原始碼。
這裡我們使用 graphicx package 來說明,他會自動引入 graphics package,這兩個 package,主要是一些指令的參數用法不同,由於 graphicx 的參數用法彈性較大,而且也和 LaTeX 的一些參數的形式較符合,因此,我們就以 graphicx 來說明,引入巨集時就引用 graphicx 就可以了。這一節所說的是外來的圖檔及 MetaPost 圖檔,而非由 picture 環境或 PSTricks 巨集所繪製的圖檔。
講繪圖工具講了老半天,到底有了圖檔,要如何引進文稿裡頭呢?就是使用 graphicx package 的 \includegraphics 指令:
...
\usepackage{graphicx}
...
\begin{document}
...
\begin{figure} % 進入浮動環境
\includegraphics[選項參數]{圖檔名稱}
...
\caption{這裡加入圖的標題} % 圖號會自動編號
\label{這裡加入引用圖檔時的文字標誌} % 一定要在 caption 之後
\end{figure}
...
這樣就行了,就這麼簡單!不使用浮動環境也是可以的。通常目前的 graphicx 巨集會自動判斷圖檔格式,所以延伸檔名可以不必寫上。但如果引入的圖檔是 MetaPost 所產生的,那要附上延伸檔名,通常是數目字,例如 some-graphic.1,但這在 pdflatex 可能會有誤認檔案格式的情形發生,所以,要讓他知道這是 MetaPost 所產生的 mps 圖檔。因此,如果文稿中有引用 MetaPost 的圖檔,最保險的方式是:
\documentclass{article}
\usepackage{graphicx}
\ifx\pdfoutput\undefined
\DeclareGraphicsRule{*}{eps}{*}{}
\else
\DeclareGraphicsRule{*}{mps}{*}{}
\fi
\begin{document}
...
\includegraphics{mpost-image.1}
...
\end{document}
有一個 ifpdf 巨集,做的也是同樣的事情。這樣的話,使用 pdflatex 編譯時會把認不得的圖檔,當做是 mps;而使用 latex 編譯時,會把認不得的圖檔,當做是 eps。另外一個方法,就是把 *.1 改延伸檔名為 *.mps,這樣 latex/pdflatex 都會認得他。
也可以在引用 graphicx 時加入檔案格式選項參數,指定圖檔格式,但這裡不建議這麼做,這樣有可能會使用文稿的彈性降低,如果不想改來改去,比較理想的方式是去修改 graphicx 的相關設定檔,但一般使用者恐怕也是搞不清楚這些設定檔要如何編修,因此還是使用條件式的判斷來暫時解決這個問題。
如果圖檔中有 jpeg/png 圖檔,這在 latex/dvips 是無法處理的,可使用 convert 把他轉成 eps 格式。在這種情形下,如果要讓 latex/pdflatex 都能正常運作的話,可能要準備兩種格式(eps/pdf)的圖檔了,然後,圖檔名稱不指定延伸檔名,讓執行程式各取所需。
有時使用圖檔時如果會有無法判斷 BoundingBox 值的情形,在這種情形下,可以使用 dvipdfm 所附的 ebb 這支小工具來產生必要的 BoundingBox 值。
我們還沒談到 \includegraphics 選項參數的部份。這個選項參數很多,功能很強大。這些選項參數可以有多個,各選項間以逗點來分隔,他的值的設定是使用等號(請注意,我們這裡談的是 graphicx 巨集,而不是 graphics,這在參數使用上不同)。
通常,這是會加上 clip 參數,作用是在修剪引入的圖檔的四周,但不是很好控制,所以建議圖檔由圖形處理或轉換程式去處理過後再引入會比較好控制。不加 clip 參數,加個星號 \includegraphics* 作用是一樣的。
一般如果是 eps/ps 檔,可以使用編輯器去修改他的 BoundingBox 值,無需用到這些不好控制的參數,如何抓到座標值呢?使用 gv 或 gsview 把圖檔載入後,將游標置於圖中所要的位置,這些軟體就會顯示所在處的座標,然後就可以依自己需要去修改他了。
\includegraphics[trim=7 7 7 7, clip]{some}
這會除去 some 這個圖檔的四周 7bp 的寬度。請注意,圖檔盡量不要加延伸檔名,讓系統自己去判斷,這樣文稿會比較有彈性。
如果圖檔很多,一個比較方便的方法就是在目前工作目錄下,新開一個子目錄來專門置放圖檔,這樣在文件的維護上也會比較好維護。他的語法如下:
\graphicspath{{路徑一}{路徑二}{路徑三}...}
\graphicspath{{images/}} % 縱使只有一個子目錄,也不可省略大括號
\graphicspath{{:images:}} % Mac 系統的表示法
LaTeX 系統預設找圖檔的路徑是 TeX 預設會去找的路徑及目前的工作目錄(通常目前的工作目錄會先找)。或者,也可以修改 TEXINPUTS 變數的值(會較有效率,也較省記憶體),例如,以 unix-like 系統下的 sh shell 為例:
TEXINPUTS = "images/:" ; export TEXINPUTS
這樣會首先搜尋目前工作目錄下的 images 這個子目錄,找不到的話,才會去 TeX 預設的搜尋目錄去找,這樣一來就會很有效率,而且會較省記憶體。所以,這個方法比較建議使用。
當然,也可以直接在 \includegraphics{} 的參數裡頭就直接把路徑寫進去,但這是最不建議的方法,不管效率或是文稿可攜性都會很差。
我們常常會需要某些圖文在特別的情況下旋轉一下,\rotatebox 這個指令,其實我們前面舉的例子當中就曾使用過,我們現在來看看詳細的使用方法:
\rotatebox[選項參數]{角度}{圖文物件}
角度和 \includegraphics 的 angle 選項參數一樣,但使用方法則簡化了,直接寫上數值即可,當然預設是逆時針方向旋轉。選項參數的部份可以有三個小選項:
旋轉不限於簡單的圖文物件,甚至一整個表格、圖形環境都可以拿來轉。要注意的是,編譯成 *.dvi 檔的話,有可能 dvi viewer 會不支援旋轉效果的解讀,此時要把他由 dvips 來轉成 ps 檔,或直接使用 pdflatex 編譯成 pdf 檔,再來預視。
\scalebox{水平縮放倍數}[垂直縮放倍數]{圖文物件}
\reflectbox{圖文物件}
\scalebox{-1}[1]{圖文物件} 的意思,會得到鏡射的效果。
\resizebox{寬度}{高度}{圖文物件}
\resizebox*{寬度}{總高度}{圖文物件}
\resizebox*{}{}{},他的作用是會把深度(depth,基線以下的稱為深度,基線以上的稱為高度 height,兩者之和稱為總高度,totalheight)也考慮進去,否則只考慮高度,但深度不一定會有,這時 height 就等於 totalheight。基線、深度等術語的意義,請複習一下第 3.3.1 小節,頁
。
我們在表格及圖形的章節裡花了比重不少的篇幅,主要的用意是想打破 LaTeX 所能使用領域的刻板印象,個人還覺得這些內容實在還不夠,但要硬塞入這篇入門級的文件,已經不恰當,時間、能力允許的話,希望將來有機會另外專文來做更詳細一點的介紹。
Compiled by Edward G.J. Lee (2004-03-07)