2013年10月23日水曜日

Tikzでばねを描く

随分前にinkscapeを使って高校物理の問題集に出てくるようなばねの描き方についてのエントリを書きましたが,あれはinkscapeの使い方をあまりよくわかっていない時期に書いたので必要以上に手順が面倒になっています.

Tikzではばねが簡単に描けるので,今回はその紹介をします.
TeX - LaTeX Stack Exchangeというサイトの
Coil path decoration without straight segmentというページを参考にしました.
Tikzでばねを描く際にはパスの装飾を行うdecorationsというライブラリのcoil decorationを使用すればよいのですが,segment lengthの値がうまく設定出来ていない場合には直線的なセグメントが出来てしまいます.上記のページにその不具合を修正したgluon decorationが紹介されていたので,それを拝借してcoil decorationと比較してみました.gluonは勿論QCDのファインマン・ダイアグラムに出てくるgluonです.


通常のcoil decorationでは右端部分に直線的なセグメントが残っています.
gluon decorationではそれが解消されているのが見て取れます.

\documentclass[10pt]{jsarticle}
\usepackage[dvipdfmx]{graphicx}
\PassOptionsToPackage{svgnames}{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings,decorations.pathmorphing}

%修正されたコイル gluonとして使う
\makeatletter
\pgfdeclaredecoration{gluon}{initial}
{
  \state{initial}[
    width=+0pt,
    next state=coil,
    persistent precomputation={
      \pgfmathsetmacro\matchinglength{
        (ceil(\pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength) - \pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength) > 0.5
        ? (\pgfdecoratedinputsegmentlength - 2 * \pgfdecorationsegmentaspect * \pgfdecorationsegmentamplitude) / (floor(\pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength) + 0.499)
        : (\pgfdecoratedinputsegmentlength - 2 * \pgfdecorationsegmentaspect * \pgfdecorationsegmentamplitude) / (ceil(\pgfdecoratedinputsegmentlength / \pgfdecorationsegmentlength) + 0.499)
      }
      \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
    },
  ]{}
  \state{coil}[
    switch if less than=%
      0.5\pgfdecorationsegmentlength%
      +\pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude%
      +\pgfdecorationsegmentaspect\pgfdecorationsegmentamplitude to last,
    width=+\pgfdecorationsegmentlength,
  ]
  {
    \pgfpathcurveto
    {\pgfpoint@oncoil{0    }{ 0.555}{ 1}}
    {\pgfpoint@oncoil{0.445}{ 1    }{ 2}}
    {\pgfpoint@oncoil{1    }{ 1    }{ 3}}
    \pgfpathcurveto
    {\pgfpoint@oncoil{1.555}{ 1    }{ 4}}
    {\pgfpoint@oncoil{2    }{ 0.555}{ 5}}
    {\pgfpoint@oncoil{2    }{ 0    }{ 6}}
    \pgfpathcurveto
    {\pgfpoint@oncoil{2    }{-0.555}{ 7}}
    {\pgfpoint@oncoil{1.555}{-1    }{ 8}}
    {\pgfpoint@oncoil{1    }{-1    }{ 9}}
    \pgfpathcurveto
    {\pgfpoint@oncoil{0.445}{-1    }{10}}
    {\pgfpoint@oncoil{0    }{-0.555}{11}}
    {\pgfpoint@oncoil{0    }{ 0    }{12}}
  }
  \state{last}[next state=final]
  {
    \pgfpathcurveto
    {\pgfpoint@oncoil{0    }{ 0.555}{1}}
    {\pgfpoint@oncoil{0.445}{ 1    }{2}}
    {\pgfpoint@oncoil{1    }{ 1    }{3}}
    \pgfpathcurveto
    {\pgfpoint@oncoil{1.555}{ 1    }{4}}
    {\pgfpoint@oncoil{2    }{ 0.555}{5}}
    {\pgfpoint@oncoil{2    }{ 0    }{6}}
  }
  \state{final}{}
}


\begin{document}
\begin{tikzpicture}
%coil
 \begin{scope}
  \coordinate (sprright) at (0,0);
  \coordinate (sprleft) at ($(sprright)+(-2.5,0)$);
  \draw[decoration={coil,aspect=0.3,amplitude=0.3cm,segment length=1.75mm,}]
  decorate {(sprleft)-- (sprright)}; %ばね   
  \node[right=3] at (sprright){通常のcoil decoration};
  \end{scope}

%gluon
 \begin{scope}[shift={(0,-1)}]
  \coordinate (sprright) at (0,0);
  \coordinate (sprleft) at ($(sprright)+(-2.5,0)$);
  \draw[decoration={gluon,aspect=0.3,amplitude=0.3cm,segment length=1.75mm,}]
  decorate {(sprleft)-- (sprright)}; %ばね   
 \node[right=3] at (sprright){gluon decoration};
  \end{scope}

 \begin{scope}[shift={(0,-2)}]
  \coordinate (sprright) at (0,0);
  \coordinate (sprleft) at ($(sprright)+(-2.5,0)$);
  \draw[decoration={gluon,aspect=0.3,amplitude=0.3cm,segment length=1.75mm,}]
  (sprleft) -- +(-0.2,0) decorate {(sprleft)-- (sprright)}-- (sprright)-- ++(0.2,0); %ばね   
 \draw ($(sprleft)+(-0.2,0.2)$)--($(sprleft)+(-0.2,-0.2)$);
  \node[right=3] at (sprright){gluon decorationに端を付け加えたもの};
  \end{scope}
\end{tikzpicture}
\end{document}

Tikzの練習 電圧計

最近Tikzの練習をしています.
TeXのマクロなどを書いたことがないので,悪戦苦闘中です.
今回は電圧計の目盛りを作図してみました.

\documentclass[10pt]{article}
\usepackage[dvipdfmx]{graphicx}
\PassOptionsToPackage{svgnames}{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
\draw (0,0)--(3,0)-- ++(70:2.5)-- ++(-3,0)--cycle; %外枠
\coordinate (p) at ($(1.5,0)+(70:0.7)$);
\draw[thick] (p)--($(p)+(0,1)$);
\node (V) at ($(p)+(70:0.3)$){\scriptsize $\underline{\mathrm{V}}$};
\fill ($(p)+(-0.17,0)$) -- ($(p)+(0.17,0)$) -- ($(p)+(0,0.13)$)--cycle;

\coordinate (q) at ($(70:0.4)+(0.65,0)$);
\begin{scope}[shift=(q),scale=1.2]
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%% 電圧計の目盛り
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \renewcommand*{\r}{0.7}%円の半径
 \renewcommand*{\l}{0.3}%長い目盛りの長さ
 \renewcommand*{\t}{0.15}%短い目盛りの長さ

 \pgfmathparse{cos(70)}
 \let\c\pgfmathresult

 \pgfmathparse{sin(70)}
 \let\d\pgfmathresult

 \pgftransformcm{1}{0}{\c}{\d}{}%座標軸の回転とシフト
%x軸とy軸の成す角が70度の斜交座標系に座標系を変更する

 \foreach \i in {0,1,2,..., 20}
 {
 \pgfmathparse{30+6*\i}
 \let\th\pgfmathresult

 % 変数\iが5の倍数のときのみ長い目盛りを使う.
 \pgfmathparse{int(mod(\i,5))}
 \let\imod\pgfmathresult
 \ifnum\imod=0
 \pgfmathparse{\r+\l}
 \let\length\pgfmathresult
 \draw[thin] (\th:\r)--(\th:\length);
 \else
 \pgfmathparse{\r+\t}
 \let\length\pgfmathresult
 \draw[thin] (\th:\r)--(\th:\length);
 \fi
 }
\end{scope}
\end{tikzpicture}
\end{document}


使い回しをしない変数をあまり多く定義したくないのですが,座標に直接\pgfmathparseを使って記述したりするとエラーが頻出するので,エラーを避けつつようやく望みの出力に漕ぎ着けたような状況です.電圧計の目盛りはscope環境で括って,後でshiftさせているのですが望みの位置に出力されず,微調整をしているのが気になるところです.
変数を\renewcommandや\letで定義していますが,何を使うのが推奨されるのか,また再定義してしまうとtikzpicture環境外で問題が生じないのかが気になっています.