# Is it a limited numerical precision of Tikz or I don't understand the transformation?

I'm using a (-n active) nonlinear transformation of the form

x \mapsto (x + a * sin x), y \mapsto y

The problem is that the points with x = nπ, for n an integer, should be fixed points of the transformation, since sin(nπ) = 0. Applying the transformation to the following objects seems to show a deviation from what is expected by this reasoning.

The transformation is applied to a grid and the function y = f(x) = x while the another identical grid and function is left out the transformation for comparison. The code and the result are below. I'd ask you to look at the points where the intersection is expected. It doesn't seem to happen. The second picture is from the last point of intersection of the red and blue lines.

Is it the limitation of the numeric precision? How can I improve it?

\documentclass[tikz,border=3mm]{standalone}
\usepgfmodule{nonlineartransformations}

\makeatletter
\def\mytransformation{%
\pgfmathsetmacro{\myX}{\pgf@x + (10)*sin(\pgf@x) }
\pgfmathsetmacro{\myY}{\pgf@y}
\setlength{\pgf@x}{\myX pt}
\setlength{\pgf@y}{\myY pt}
}
\makeatother

\begin{document}
\begin{tikzpicture}

\begin{scope}
\pgftransformnonlinear{\mytransformation}
\draw [red] (0,0) grid [xstep=.5*pi, ystep=-1] (23,23);
\draw [red, thick] (0,0) -- (20,20);
\end{scope}

\draw [blue, dashed,] (0,0) grid [step=.5*pi] (23,23);
\draw [blue, thick] (0,0) -- (20,20);

\end{tikzpicture}
\end{document}


Let's break it down:

1. PGFmath assumee the parameters to sin, cos, etc. to be in degrees, not radians, so we need to convert those either with the deg function or the r postfix operator: sin(deg(x) or sin(x r).

2. TikZ/PGF/TeX internally is working with pt where 1 cm = 28.45274 pt. So even if we convert the radians to degrees we're totally off.

3. TikZ/PGF uses various coordinate systems. The most important ones are

• the canvas coordinate system where we're using actual length: (10mm, -3em)
• the xyz coordinate system (though, we often use only x and y) where we're using scalar value: (2, 2*pi+3/2).

Both coordinate systems also have a polar version (<angle>:<value>) but these can be converted to the ones with x and y values easily.

How does the xyz cordinate system knows how long a value like 2 or 2*pi+3/2 is on the paper? It uses another transformation layer and the values given to the keys x, y and z. By default, these are x = 1cm (meaning 1 cm in the direction to the right on the canvas) and y = 1m (up).

This is something that PGF provides on its layer.

So we devide the \pgf@x by 1cm and convert that to degrees and we're done?

Not quite. For once, we can access the value of 1cm by using \pgf@xx which we can use to divide \pgf@x by but then we are in the xyz coordinate system. We need to get back to the canvas coordinate system by multiplying the sine with \pgf@xx which brings me to this formula you oughta want to use:

\def\mytransformation{%
\pgfmathsetlength\pgf@x{\pgf@x + 10*\pgf@xx*sin(\pgf@x/\pgf@xx r)}%
}


That is, convert the canvas x value back to its xyz x value, convert that to degrees, take the sine of it and then multiply it back into the canvas coordinate system (and then your factor of 10).

Now, if you use a more complex xyz coordinate system, let's just say x = {(1cm, 1cm)}, i.e. the x axis has an angle of 45° on the paper and the length of √2 both

• \pgf@xx (the length of a unit on the x axis in x direction) and
• \pgf@xy (the length of a unit on the x axis in y direction)

will be set to 28.45274pt.
(And yes, there's also \pgf@yy, \pgf@yx, \pgf@zx and \pgf@zy.)

I have no clue how your transformation should look like then. (At that point, it's a math problem I believe.)

If you check the examples in the manual about nonlinear transformations you'll notice that it only uses coordinates in the canvas coordinate system. The \polartransformation example even uses

\draw (0pt,0mm) grid [xstep=10pt, ystep=5mm] (90pt, 20mm);


Notice the 90pt! This will be 90° for the quarter circle it'll draw. (Or 3.16314cm, i.e (3.16314, 2) in the xyz coordinate system. Somewhat close to π, but purely by accident – and we were looking for π/2 anyway.)

I've added the plot

\draw[dashed, ultra thick] plot[smooth,samples=100,domain=0:20] ({\x + 10 * sin(\x r)}, \x);


for comparison. Depending on your actual task, this might just be an easier way to draw lines that abide to any(?) transformation.

And if you really want to plot something, use .

## Code

\documentclass[tikz,border=3mm]{standalone}
\usepgfmodule{nonlineartransformations}
\makeatletter
\def\mytransformation{%
\pgfmathsetlength\pgf@x{\pgf@x + 10*\pgf@xx*sin(\pgf@x/\pgf@xx r)}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[x=.5cm]% for fun
\foreach \x in {-3,...,10}
\path (0:\x*pi) node[below]{$\x\pi$}                   edge[help lines, very thin]         + (up:20) edge + (up:2pt)
++ (0:.5*pi) node[below]{$\pgfmathprint{\x+.5}\pi$} edge[help lines, very thin, dotted] + (up:20) edge + (up:1pt);
\draw[dashed, ultra thick] plot[smooth,samples=100,domain=0:20] ({\x + 10 * sin(\x r)}, \x);
\foreach \sh in {-10,0,10}
\draw[shift=(0:\sh)] (0,0) -- (20,20);
\begin{scope}
\pgftransformnonlinear{\mytransformation}
\draw [thick, red] (0,0) -- (20,20);
\end{scope}
\end{tikzpicture}
\end{document}


• Thanks you very much for this answer. Iaccept it now although I don't think I'm now able to understand it completely these days. But I'll certainly return to it. Jul 30 at 22:53
• This output doesn't seem correct. For 0<=x<=pi, sin(x) is positive so x+sin(x)>=0. For x>pi, sin(x)>=-1 and so x+sin(x)>3.14-1=2.14.
– DJP
Jul 31 at 0:45
• I'm seeing: x \mapsto (x + sin x), y \mapsto y.
– DJP
Jul 31 at 0:46
• @DJP OP has 10 in their MWE, so I'm using that. If you remove the 10* from both the plot as well as from the \mytransformation we're getting this output. Jul 31 at 0:49
• Ah, okay, I see the 10 in the code and that output you linked to looks similar to what i just plotted in a CAS.
– DJP
Jul 31 at 0:52