7

If I compile this file:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[domain=-1:1,scale=5,samples=1000]
  \draw plot (\x,{sqrt(-1/2-\x*\x+sqrt(1/4+2*\x*\x))});
  \draw plot (\x,{-sqrt(-1/2-\x*\x+sqrt(1/4+2*\x*\x))});
\end{tikzpicture}
\end{document}

I get this:

enter image description here

Is it possible to avoid that gap on the right? I know that it has to do with the fact that that curve has a vertical tangent at that point. On the other hand, I know how to draw it without problems; all I need is to use a parametric way of describing the curve. But sooner or later I will want to draw a curve for which no such description is know to me, and I would like to know how to deal with that problem then.

2 Answers2

5

I'd argue this is due to TeX/PGFMath's imprecision, if we do

\documentclass[tikz]{standalone}
\tikzset{declare function={infty(\x)=sqrt(-1/2-\x*\x+sqrt(1/4+2*\x*\x));}}
\begin{document}
\tikz[domain=-1:1, scale=5, samples=100]
  \draw plot ([/utils/exec=\pgfmathparse{infty(\x)}\typeout{\x => \pgfmathresult}]
              \x,{ infty(\x)});
\end{document}

the log file will contain

-1.0     => 0.00000
-0.998   => 0.03646
-0.996   => 0.05157
-0.994   => 0.06300
-0.992   => 0.07252
-0.99    => 0.08099
  ⋮           ⋮
-0.00655 => 0.00447
-0.00455 => 0.00000
-0.00255 => 0.00000
-0.00055 => 0.00000
 0.00145 => 0.00000
 0.00345 => 0.00447
  ⋮           ⋮
 0.9909  => 0.07733
 0.9929  => 0.06841
 0.9949  => 0.05805
 0.9969  => 0.04538
 0.9989  => 0.02701

Dividing the range -1:1 in 1001 pieces is not a good exercise for PGFMath/TeX.

The quickest fix for this would be to use samples at as such:

\tikz[domain=-1:1, scale=5, samples at={-500,...,500}]
  \draw plot (\x/500,{ infty(\x/500)});

TeX/\foreach is very good at incrementing an integer:

-1.0     => 0.00000
-0.99799 => 0.03660
-0.99599 => 0.05157
-0.99399 => 0.06300
  ⋮           ⋮
-0.006   => 0.00447
-0.004   => 0.00000
-0.002   => 0.00000
 0.0     => 0.00000  ← symmetry!
 0.002   => 0.00000
 0.004   => 0.00000
 0.006   => 0.00447
  ⋮           ⋮
 0.99199 => 0.07266
 0.99399 => 0.06300
 0.99599 => 0.05157
 0.99799 => 0.03660
 1.0     => 0.00000

As with all things computer, even TeX works in powers of 2, so a number like 1025 work, too. (With a sample count of n the domain will be divided into n − 1 parts.)

You can also side-step the problem by concatenating another plot with domain 1:-1 so that the point at x = 1 will be calculated explicitly and ending the path with -- cycle to get back to (-1, 0).


Of course, there's the fpu library, gnuplot and other external tools.

But I've also added a bit complexer solution that draws your symbol cleaner, in my opinion – and with less points!

Code

\documentclass[tikz]{standalone}
\tikzset{declare function={infty(\x)=sqrt(-1/2-\x*\x+sqrt(1/4+2*\x*\x));}}
\begin{document}
\tikz[domain=-1:1, scale=5]
  \draw plot[domain=-1:1, samples at={-500,...,500}] (\x/500,{ infty(\x/500)})
     -- plot[domain=1:-1, samples at={500,...,-500}] (\x/500,{-infty(\x/500)}) -- cycle;

\tikz[domain=-1:1, scale=5, samples=1025]{ \draw plot (\x, { infty(\x)}); \draw plot (\x, {-infty(\x)}); }

\tikz[scale=5, samples=1000] \draw plot[domain=-1:1] (\x, { infty(\x)}) -- plot[domain=1:-1] (\x, {-infty(\x)}) -- cycle;

\tikz[scale=5] \draw plot[domain=-1:0, samples at={-500,...,-300,-295,-290,...,0}] (\x/500, { infty(\x/500)}) -- plot[domain= 0:1, samples at={0, 5,..., 300, 301, 302,..., 500}] (\x/500, {-infty(\x/500)}) -- plot[domain= 1:0, samples at={ 500,..., 300, 295, 290,...,0}] (\x/500, { infty(\x/500)}) -- plot[domain=0:-1, samples at={0,-5,...,-300,-301,-302,...,-500}] (\x/500, {-infty(\x/500)}) -- cycle; \end{document}

Output

(The detail is in the crossing.)

1, 2: enter image description here

3: enter image description here

4: enter image description here

Qrrbrbirlbel
  • 119,821
  • 1
    Compilation times: 5.3s, 4.8s, 4.7s and 3.0s. There is more room for optimization because the path is doubly symmetric but maybe external would be much easier application. – Qrrbrbirlbel Oct 27 '22 at 19:38
4

For what it's worth, here is how you might tackle this in Metapost, using the OP's function instead of the parametric equation and exploiting the symmetry of the lemniscate curve.

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);
vardef f(expr x) = sqrt(-1/2 - x * x + sqrt(1/4 + 2 * x * x)) enddef;
numeric s; s = 1/8;
path limb;

limb = origin for x = s step s until 1: .. (x, f(x)) endfor {down}; limb := limb scaled 128;

path lemniscate; lemniscate = limb & reverse limb reflectedabout(left, right) & limb reflectedabout(up, down) & reverse limb rotated 180 & cycle;

draw limb withpen pencircle scaled 2 withcolor 7/8[red, white]; drawarrow lemniscate withcolor 2/3 blue; endfig; \end{mplibcode} \end{document}

Compile this with lualatex to get:

enter image description here

The idea here is to use the function to create the limb of the curve in the first quadrant (shown in pink), and then splice together three transformed copies of this limb to make the complete curve (shown as the blue arrow).

Thruston
  • 42,268