LoginSignup
9
3

More than 5 years have passed since last update.

MetaPost (luamplib, gmp) で☃

Last updated at Posted at 2018-12-02

これは「TeX & LaTeX Advent Calendar 2018」の 3 日目の記事です.2 日目は puripuri2100 さん,4 日目は golden_lucky さんです.

はじめに

LuaTeX-ja に関わっている関係で,私は LaTeX で文書を作る時はほぼすべて LuaLaTeX を使用しています.

その際に図をどうやって作るか,ということはいつも問題になります.(u)pLaTeX + dvipdfmx を主に使っていたときには 初等数学プリント作成マクロ emath を主に使用していました(今でも周囲にはそういう人がちらほらいます).また,今から始めるというのであれば PGF/TikZ(TeX Wiki 内の記事)を使う,というのがメジャーな選択肢となるのでしょう.

さて,LuaTeX には 内部に MetaPost ライブラリが含まれており,さらにそれを TeX から扱うためのパッケージとして luamplib パッケージというものが制作されています1.これを利用しない手はないではないか……ということで,私は専ら MetaPost を図の作成に用いるようになりました.

luamplib パッケージの使い方

基本的な使い方

基本的には \usepackage で読み込み,mplibcode 環境内に MetaPost コードを記述するだけです.点につけるラベルなど,TeX コードを記述したい場合は btex ... etex で囲んだり,textext() を使ったりします.

test.tex
\documentclass{article}
\usepackage{luamplib}
\begin{document}
Hello, MetaPost! \vrule
\begin{mplibcode}
  beginfig(1);
  pickup pencircle scaled 0.25mm;
  draw (0,0)..(0,5mm)..(1cm,5mm)..(5mm,0mm)..(-5mm,0)..cycle;
  dotlabel.lrt(btex $P_1$ etex, (0,0));
  endfig;
\end{mplibcode}
\vrule HOGEHOGE
\end{document}

test.png

ラベルに日本語を使いたい場合,LuaTeX-ja パッケージをいつもどおり読み込むだけで問題ありません(LuaTeX-ja 側で何か特別なことをしているのでもありません).

LuaJITTeX 使用時の注意

Lua 5.2/5.3 の代わりに LuaJIT を利用した LuaJITTeX で luamplib パッケージを読み込もうとすると,以下のようなエラーが発生します.これは LuaJITTeX において lfs が定義済みなのになぜか読み込み済みライブラリとしてマークされていないことによるようです.

module 'lfs' not found:
        no field package.preload['lfs']
        [kpse lua searcher] file not found: 'lfs'
        [kpse C searcher] file not found: 'lfs'
stack traceback:
        [C]: in function 'require'
        ...texlive/2018/texmf-dist/tex/luatex/luamplib/luamplib.lua:48: in main chunk
        [C]: in function 'require'
        [\directlua]:1: in main chunk.
l.22 \directlua{require("luamplib")}

?

どうやら luamplib.lua 中の 48 行目を以下のように書き換えれば良いようです:

local lfs   = lfs or require ('lfs') --  元は local lfs   = require ('lfs')

\everymplib, \everyendmplib

mplibcode 環境内に毎回 beginfig ... endfig や,図中で使いたい各種マクロを繰り返し書くのは面倒です.luamplib パッケージでは \everymplib, \everyendmplib を使って,mplibcode 環境の開始・終了に自動で挿入される MetaPost コードを指定できます.例えば,毎回自動で beginfig, endfig を追加させることにし,さらに領域を斜線で塗るマクロ hatch を入れると次のようになります.

test2.tex
\documentclass{article}
\usepackage{luamplib}
\everymplib{beginfig(1);
  def hatch(expr p)=
  begingroup
    save pct, x, y; picture pct[];
    numeric xl, xu, yl, yu;
    pct1 := currentpicture; currentpicture := nullpicture;
    draw p;
    (xl, yl) = llcorner currentpicture; (xu, yu) = urcorner currentpicture;
    currentpicture := nullpicture;
    pickup pencircle scaled 0.125mm;
    for i = xl-xu step 1.5mm until yu-yl:
      draw (xl, i+yl)--(xu, i+yl+(xu-xl));
    endfor;
    clip currentpicture to p;
    pct2 := currentpicture; currentpicture := pct1; draw pct2;
  endgroup;
enddef;
}
\everyendmplib{endfig;}
\begin{document}
\begin{mplibcode}
  path p; p:=(0,0)--(0,5mm)..(1cm,2mm){dir -50}..(5mm,-3cm)--(2cm,0mm)--cycle;
  hatch(p); pickup pencircle scaled 0.25mm; draw p;
\end{mplibcode}
\end{document}

寸法・色の指定

mplibcode環境で描かれる図は,周囲の文字色の影響は受けません(無指定時はいつも黒).mplibcode 環境内で寸法や色を指定するには,それぞれ \mpdim, \mpcolor 命令を使用します.color パッケージや xcolor パッケージを読み込んでいる場合には,\mpcolor の引数には \color で指定可能な色指定をそのまま記述できます.xcolor パッケージを読み込んでいると「現在の色」を . で表現できるので,\mpcolor{.} を活用することで周囲の文字色と同じ色にすることができます.

test3.tex
\documentclass{article}
\usepackage{luamplib}
\usepackage{xcolor}% 自動では読まない
\begin{document}
M\textcolor{red}{xyz%
\begin{mplibcode}
  beginfig(1);
  u:=0.5\mpdim{4ex}+2mm; v:=\mpdim{4em};
  fill (0,0)--(2v,0)--(2v,u)--cycle ; %無指定時は黒
  fill (0,0)--(2v,0)--(2v,.5u)--cycle withcolor \mpcolor{.}; % 周囲の文字色
  fill (0,0)--(1v,0)--(0,1u)--cycle withcolor \mpcolor{red!90!black};
  fill (0,0)--(.8v,0)--(0,.8u)--cycle withcolor \mpcolor{blue!80!black};
  fill (0,0)--(.6v,0)--(0,.6u)--cycle withcolor \mpcolor{green!70!black};
  endfig;
\end{mplibcode}
aa}
\end{document}

test3.png

なお,\mpcolor で指定した色に対しては withcolor blue+0.5\mpcolor{red!90!black} のように演算を行うことはできません.

本題:scmpsnowman パッケージ

さて,luamplib パッケージの使い方を紹介するだけでは記事としておもしろくありません.日本の(一部の)TeX ユーザには☃(ゆきだるま)が流行しているので,それを使ってなにかやることにしました.

LaTeX 上でゆきだるまを描く手法として,aminophen さんの scsnowman パッケージ(GitHub リポジトリ開発者による紹介記事1紹介記事2)が知られています.このパッケージは TikZ による実装だったので,MetaPost (luamplib) に移植してみました.

ネタで作ったものなので,大元の scsnowman パッケージレポジトリの個人フォーク→その中の一ブランチ→さらに下位フォルダ,というひっそりとした箇所においています.

動作環境

想定する環境は TeX Live 2018 上の LuaLaTeX ですが,(u)pLaTeX/pdfLaTeX/XeLaTeX でも動くかもしれません(後述).以下のパッケージが必要です.

  • luamplib パッケージ(LuaLaTeX 下のみ),gmp パッケージ(その他)
  • xcolor パッケージ
  • keyval パッケージ(本家と同様,オプション引数の解釈のため.LuaTeX-ja を使っているならすでに入っている)
  • etoolbox パッケージ(LuaTeX-ja を使っているならすでに入っている)

基本的な使い方

まず,scmpsnowman-normal.def, scmpsnowman.sty, scmpsym-base.sty を TeX が参照できるディレクトリに配置しておきます.

LaTeX ソース内からは,通常通り \usepackage で読み込み,本家 scsnowman パッケージと同様にゆきだるまを置きたい場所で \scsnowman 命令を実行するだけです.

sample1.tex
\documentclass{ltjsarticle} % LuaLaTeX 文書
\usepackage{scmpsnowman}
\begin{document}
これはゆきだるま\scsnowman です.
\end{document}

sample1.png

下のサンプルのように,本家と同じ書式で各種オプションを指定できるようにしています.\scsnowman 命令以外の動作確認はほとんどしていません.

sample2.tex
\documentclass{ltjsarticle}
\usepackage[svgnames]{xcolor}
\usepackage{scmpsnowman}
\usepackage{mflogo} % MetaPost ロゴ
\scsnowmandefault{hat=Green,arms=Brown,snow=SkyBlue} % デフォルト指定
\begin{document}
\MP\scsnowman[muffler=Red,,adjustbaseline]を描けます.
\end{document}

sample2.png

(2018-12-04 追記)上記 sample1.tex, sample2.tex では LuaTeX-ja のクラスファイルを使いましたが,その必要はありません.例えば以下の例のように.

sample0.tex
\documentclass{minimal}
\usepackage{scmpsnowman}\listfiles
\begin{document}\scsnowman\end{document}
%  *File List*
%  minimal.cls    2001/05/25 Standard LaTeX minimal class
% scmpsnowman.sty    2018-12-02 Snowman variants using MetaPost
% etoolbox.sty    2018/08/19 v2.5f e-TeX tools for LaTeX (JAW)
%   xcolor.sty    2016/05/11 v2.12 LaTeX color extensions (UK)
%    color.cfg    2016/01/02 v1.6 sample color configuration
%   luatex.def    2018/01/08 v1.0l Graphics/color driver for luatex
% scmpsym-base.sty    2018-12-02 Base for emoji variants using MetaPost
% luamplib.sty    2018/09/27 v2.12.5 mplib package for LuaTeX
%   keyval.sty    2014/10/28 v1.15 key=value parser (DPC)
% scmpsnowman-normal.def
% supp-pdf.mkii
%  ***********

なお supp-pdf.mkii は luatex.def から読み込まれるようです.(追記ここまで)

非 LuaLaTeX 環境((u)pLaTeX/pdfLaTeX/XeLaTeX)

LuaLaTeX でない環境では,もちろん luamplib パッケージを使うことはできません.その代わりに,同様の「LaTeX ソース中に MetaPost コードを記述する」機能を提供するパッケージの一つに gmp パッケージがあります.scmpsnowman パッケージは,LuaLaTeX でない環境で読み込まれた場合には自動的に gmp パッケージを読み込みます.

gmp パッケージは,mpost 環境の中に書かれた内容を外部ファイルに書き出し,shell-escape が有効なら(パッケージ側にも shellescape オプションを渡す必要があります),その機能を使って MetaPost を実行する,という方式を取っています.shell-escape が無効の場合は sh sample3+mp.sh などとしてあとから自分で MetaPost 実行(など)を行うシェルスクリプトを自分で実行する必要があります.

ということで,LuaLaTeX でない環境下で scmpsnowman パッケージを使う場合には以下のようなソースを記述することになります.しかし shell-escape を有効にするのはセキュリティ的によろしくないので,非 LuaLaTeX 環境下では MetaPost をわざわざ使う意味は薄いように思います.☃☃☃おとなしく本家 scsnowman パッケージを使いましょう☃☃☃

sample3.tex
%#! ptex2pdf -l -ot '-shell-escape' sample3.tex
\documentclass[dvipdfmx]{minimal}
\usepackage[shellescape]{gmp}
\usepackage{scmpsnowman}
\begin{document}
This is a snowman:
\scsnowman[adjustbaseline,scale=2,hat,muffler=red,arms=blue]
\end{document}

gmp パッケージ下での色の指定

gmp パッケージでは \mpdim 命令で TeX の寸法を指定することができます2が,\mpcolor に対応する命令はありません.そこで,scmpsnowman パッケージ中では,luamplib の実装と似た(?)感じで適当に実装しています.

luamplib の \mpcolor 命令を使うと,withcolor \mpcolor{blue} は最終的には次の形になるようです(しっかり確かめたわけではありませんが):

withcolor 1 withprescript "MPlibOverrideColor=0 0 1 rg 0 0 1 RG"

LuaTeX 内蔵の MetaPost ライブラリでなく,本来の MetaPost ソースで同じような指定を考えてみます.

a.mp
beginfig(1);
draw (0,0)--(1,0) withcolor 1 withprescript "0 0 1 setrgbcolor";
draw (0,0)--(2,0) withcolor 1 withprescript "0 0 1 setrgbcolor";
endfig;
end.

上の a.mp を MetaPost に処理させると,次のような PostScript ファイル a.1 が出来上がります.withprescript による色指定の後に,withcolor 1 による 1 setgray が来てしまい,結果として最初のパスにおける withprescript による色指定は無効になってしまいます.

a.1
%!PS
% (省略)
%%Page: 1 1
0 0 1 setrgbcolor
 1 setgray 0 0.5 dtransform truncate idtransform setlinewidth pop [] 0 setdash
 1 setlinecap 1 setlinejoin 10 setmiterlimit
newpath 0 0 moveto
1 0 lineto stroke
0 0 1 setrgbcolor
newpath 0 0 moveto
2 0 lineto stroke
showpage
%%EOF

そのため,gmp パッケージを使う際には,パスの色指定のところで withoutcolor \mpcolor{blue} のように記述(\mpcolorwithprescript ... に最終的に展開)するようにしています3


  1. もとは ConTeXt 中のコードを plain TeX や LaTeX でも扱えるように変更を加えたものだそうです. 

  2. 実は,gmp パッケージが \mpdim 命令を先に実装し,luamplib パッケージがそれに触発されて \mpdim 命令を追加したという順番です. 

  3. xcolor パッケージの色指定から PostScript 形式の指定への変換では,dvips.def, dvipdfmx.def, xetex.def にある \c@lor@to@ps 命令を使って行っています.しかし pdftex.def にはこの命令がないので,PDF における色指定を PostScript 形式のそれに変換する処理を scmpsym-base.sty 中に適当に作りました. 

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3