samcarter/tikzlings

Replace Bezier curves with lines

Closed this issue · 4 comments

Some Bezier curves react badly to transformations. The idea is to replace them with lines or shapes of other syntax.

Previously I tried to avoid lines because they would not scale nicely, but @ marmot solved this problem (thanks a lot!):

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}
\draw[line width=0.8pt] (0,0) circle(1);
\begin{scope}[xshift=2.5cm,scale=0.5]
\draw[line width=0.8pt] (0,0) circle(1);
\end{scope}
\begin{scope}[xshift=5cm,scale=0.5,transform shape]
\draw[line width=0.8pt] (0,0) circle(1);
\end{scope}
\begin{scope}[xshift=8cm,scale=0.5]
\pgfgettransformentries{\tmpscale}{\tmp}{\tmp}{\tmp}{\tmp}{\tmp}
\draw[line width=\tmpscale*0.8pt] (0,0) circle(1);
\end{scope}
\end{tikzpicture}
\end{document}

I was wondering how you were going to make sure the pig's tail and mouth would scale properly, but this makes a lot of sense. It's not compatible with rotations/reflections though (or other transformations that are too cruel to inflict upon a TikZling), since those also affect the first entry of the transformation matrix. It would be better to use the square root of the absolute value of the determinant of the transformation matrix instead. This is √(| AD − BC |), where (A,B,C,D) are the first four parameters of \pgfgettransformentries.

Here is a demonstration/MWE:

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}

%% Original:
\draw[line width=2pt] (0,0) circle(1) node {Original};

%% Bad:
\begin{scope}[xshift=0cm,yshift=-2cm,scale=0.75,rotate=0,every node/.style=transform shape]
\pgfgettransformentries{\tmpscale}{\tmp}{\tmp}{\tmp}{\tmp}{\tmp}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {Good};
\end{scope}
\begin{scope}[xshift=2cm,yshift=-2cm,scale=0.75,rotate=45,every node/.style=transform shape]
\pgfgettransformentries{\tmpscale}{\tmp}{\tmp}{\tmp}{\tmp}{\tmp}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {Bad};
\end{scope}
\begin{scope}[xshift=4cm,yshift=-2cm,scale=0.75,rotate=90,every node/.style=transform shape]
\pgfgettransformentries{\tmpscale}{\tmp}{\tmp}{\tmp}{\tmp}{\tmp}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {Worse};
\end{scope}
\begin{scope}[xshift=6cm,yshift=-2cm,xscale=-0.75,yscale=0.75,every node/.style=transform shape]
\pgfgettransformentries{\tmpscale}{\tmp}{\tmp}{\tmp}{\tmp}{\tmp}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {Terrible};
\end{scope}

%% Good:
\newcommand*\pgfgetscale[1]{% %% assuming \tmpscaleA etc. are sufficiently unique...
  \pgfgettransformentries{\tmpscaleA}{\tmpscaleB}{\tmpscaleC}{\tmpscaleD}{\tmp}{\tmp}%
  \pgfmathsetmacro{#1}{sqrt(abs(\tmpscaleA*\tmpscaleD-\tmpscaleB*\tmpscaleC))}%
}
\begin{scope}[xshift=0cm,yshift=-4cm,scale=0.75,rotate=0,every node/.style=transform shape]
\pgfgetscale{\tmpscale}t
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {Drawing};
\end{scope}
\begin{scope}[xshift=2cm,yshift=-4cm,scale=0.75,rotate=45,every node/.style=transform shape]
\pgfgetscale{\tmpscale}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {circles};
\end{scope}
\begin{scope}[xshift=4cm,yshift=-4cm,scale=0.75,rotate=90,every node/.style=transform shape]
\pgfgetscale{\tmpscale}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {is};
\end{scope}
\begin{scope}[xshift=6cm,yshift=-4cm,xscale=-0.75,yscale=0.75,every node/.style=transform shape]
\pgfgetscale{\tmpscale}
\draw[line width=\tmpscale*2pt] (0,0) circle(1) node {fun!};
\end{scope}

\end{tikzpicture}
\end{document}

@circumscribe This is a great suggestion! I did a few quick tests and it seems to be doing really well! I'll update the tikzlings as soon as I have some spare time!

I think it should work for all linear transformations. The determinant (AD-BC) of a 2D transformation matrix is the factor by which all areas are scaled. It is 1 for the identity transformation and it is not changed by rotations or shearings. It scales linearly with scalings in one direction and quadratically with uniform scalings (hence the sqrt(…)), and its sign is inverted by reflections through a line (hence the abs(…)).
(Apologies if you already knew this; I don't know your background.)

I'll probably post a second answer to this question (which I just noticed has a comment by you) soonish, since others may also find this useful. [Edit: done!]

Implemented the changes in cfc08b4