LaTeX+Tikzで接線を引いたり、短冊分割したりする話。
2014/08/29
はじめに
LaTeXで図を扱う手段はいくつかあります。
- .pdfファイルとかを挿入
- picture環境
- Asymptote
- Tikz
奥村先生の美文書作成入門(第5版)にはAsymptoteの使い方が載っていたので僕もAsymptoteを習得すべく頑張っていたのですが……妙にWeb上に情報が少ない……TeX Wikiにもあまり載ってない……
何でだろうと思って美文書作成入門(第6版)を見てみたらAsymptoteは載ってなくて代わりにTikzなるものが載ってるではありませんか。
texのソース内で図を書くことができ、しかもかなりのクオリティ。
最新版のTeXが入っているなら、
$ texdoc tikz
とすれば700ページを超えるマニュアルが出てくるはずです。
しかしながら、ベジェ曲線上の点から接線を引くコマンドはなさげだったのでいろいろと試行錯誤してみました。
接線を引いてみよう
まずはサンプル
LaTeX
\documentclass[dvipdfmx]{jsarticle} \usepackage{tikz} \usetikzlibrary{intersections, calc} \begin{document} \begin{tikzpicture}[x=1.5cm,y=1.5cm,>=latex] \def\tangentlength{4cm}; \node(O) at (0,0) [below left]{$O$}; \draw[->] (-0.2,0) -- (4.2,0) node[right]{$x$}; \draw[->] (0,-0.2) -- (0,2.2) node[above]{$y$}; \draw[name path=graph] (0,0) .. controls (2,0) and (2,2) .. (4,2); \path[name path=main] (2.8,0) -- (2.8,2); \path[name path=sub] ($(2.8,0)+(1pt,0)$) -- ($(2.8,2)+(1pt,0)$); \path[name intersections={of=graph and main}]; \coordinate (a) at (intersection-1); \path[name intersections={of=graph and sub}]; \coordinate (b) at (intersection-1); \draw[thick] ($(a)!-\tangentlength/2!(b)$)--($(a)!\tangentlength/2!(b)$); \draw[dashed,help lines] ($(0,0)!(a)!(0,1)$)-| ($(0,0)!(a)!(1,0)$); \end{tikzpicture} \end{document}
出力(実寸ではありません)
説明
接線を引くのは難しそうだったので、(2.8,f(2.8))と(2.8+1pt,f(2.8+1pt))を通る直線を引いています。
まず、交点を求めるためにx=2.8とx=2.8+1ptの2本のパスを引きます。
\path[name path=main] (2.8,0) -- (2.8,2); \path[name path=sub] ($(2.8,0)+(1pt,0)$) -- ($(2.8,2)+(1pt,0)$);
この2本のパスとベジェ曲線の交点を求めるのが次のコード。
\path[name intersections={of=graph and main}]; \coordinate (a) at (intersection-1); \path[name intersections={of=graph and sub}]; \coordinate (b) at (intersection-1);
(a)と(b)を通る、長さ\tangentlengthの直線を引くのが次のコード。
\draw[thick] ($(a)!-\tangentlength/2!(b)$)--($(a)!\tangentlength/2!(b)$);
ちなみに、(a)からx軸とy軸に垂線を下ろすのは、
\draw[dashed,help lines] ($(0,0)!(a)!(0,1)$)-| ($(0,0)!(a)!(1,0)$);
でできました。($(A)!(a)!(B)$)と書くと(a)から(A)--(B)に下ろした垂線の足の座標を出してくれます。
短冊分割をしてみる
まずはサンプル
LaTeX
\documentclass[dvipdfmx]{jsarticle} \usepackage{tikz} \usetikzlibrary{intersections, calc} \begin{document} \begin{tikzpicture}[x=1.5cm,y=1.5cm,>=latex] \def\width{0.1}; \node(O) at (0,0) [below left]{$O$}; \draw[->] (-0.2,0) -- (4.2,0) node[right]{$x$}; \draw[->] (0,-0.2) -- (0,2.2) node[above]{$y$}; \draw[name path=graph] (0,0) .. controls (2,0) and (2,2) .. (4,2); \foreach \x in {0,...,9} { \path[name path global/.expanded=path-\x](2+\width*\x,0) -- (2+\width*\x,2); \path[name intersections={of=graph and path-\x}]; \coordinate (p-\x) at (intersection-1); \filldraw[fill=gray!30,draw=gray] ($(0,0)!(p-\x)!(1,0)$) rectangle ($(p-\x)+(\width,0)$); } \end{tikzpicture} \end{document}
出力(実寸ではありません)
説明
foreachを使って10回ループを回し、そのたびに幅\widthの短冊を書いています。
\foreach \x in {0,...,9} { \path[name path global/.expanded=path-\x](2+\width*\x,0) -- (2+\width*\x,2); \path[name intersections={of=graph and path-\x}]; \coordinate (p-\x) at (intersection-1); \filldraw[fill=gray!30,draw=gray] ($(0,0)!(p-\x)!(1,0)$) rectangle ($(p-\x)+(\width,0)$); }
x=2+\width*\xの直線とベジェ曲線の交点を求め、\filldrawで長方形を書いているだけです。
foreachの使い方が分かればそれほど難しくはないと思います。
追記
foreachの中でパスの名前を変数を用いて設定するときは、
\path[name path global/.expanded=path-\x](2+\width*\x,0) -- (2+\width*\x,2);
のように、global/.expandedをつけないとエラーが出るみたいです。
参考URL:http://tex.stackexchange.com/questions/5242/naming-paths-inside-a-tikz-foreach-loop
おわりに
ベジェ曲線の任意のxに対応するyの値を求める方法が分からなかったので
縦にパスを引いてintersectionを取るという方法に落ち着きました。
もっと良い方法あったら是非教えてください。
今回の教訓としてはAsymptoteを習得しようとして丸2日無駄にしたのでup-to-dateな情報に触れるというのは大事なんだなぁ……と。
おしまい。
参考にしたものとか
- 毎度おなじみTeX Wiki
- naming paths inside a TikZ foreach loop