# How to draw lemniscate with TikZ

How to draw e.g. the given set (known as Brauer Cassini Ovals)

     { z : |z-a|·|z-b| <= c }


in the complex plane

The question is just about how to draw this (filled or unfilled) curve, not how to the coordinate system or something else.

Is there an easy way to do this with TikZ or do I have to use pstricks / gnuplot / or somethin similar?

I would prefer using TikZ only, because I already have a complex plot done in TikZ, to which I want to add some of those lemniscates.

• Posting a minimal compilable document showing that you've tried to produce the image will increase the likelihood that people will be able/willing to help you and the speed at which they will be able to help you. See minimal working example (MWE) for what needs to go into such a document. Welcome to TeX.SX! Jan 6, 2014 at 3:37
• Also, an image showing your desired result would come in handy as well. :D Jan 6, 2014 at 16:25

This MWE using Asymptote uses cassinioval.asy module to build a Cassini oval as either one or two closed curves, constructed as a polargraph. It is constructed at the origin and then rotated and shifted to the location of foci A and B, see examples 1,2.

% cassini.tex :
%
\begin{filecontents*}{cassinioval.asy}
import graph;

// The polar representation used according to
// A.A. Savelov, "Planar curves" , pp.147--148, Moscow (1960) (In Russian),
//
struct CassiniOval{
// { z : |z-A|·|z-B| <= C }
pair A, B; real C;
int npoints;

real a,c;
transform transf;
real alpha;

guide[] curve;

real rho(real phi){
return c*sqrt(abs(cos(2phi)+sqrt(abs(cos(2phi)^2+(a/c)^4-1))));
};

real rho2(real phi){
return c*sqrt(abs(cos(2phi)-sqrt(abs(cos(2phi)^2+(a/c)^4-1))));
};

guide[] normLscate(){
guide[] g;
guide q;
real xMax=sqrt(a^2+c^2);
real xMin=-xMax;
if(a>=c){// one contour;
g.push(transf*(polargraph(rho,0,2pi,npoints)--cycle));
}else{// two contours;
q=polargraph(rho,-alpha,alpha,npoints)
--reverse(polargraph(rho2,-alpha,alpha,npoints))
--cycle;
g=(transf*q)^^(transf*reflect(N,S)*q);

}
return g;
}

void operator init(pair A, pair B, real C, int npoints=300){
assert(C>0);
this.A=A; this.B=B;  this.C=C;
assert(npoints>1);
this.npoints=npoints;
this.c=arclength(A--B)/2;
this.a=sqrt(C);
transf=shift(A)*rotate(degrees(atan2(B.y-A.y,B.x-A.x)))*shift(c,0);

if(a<c){alpha=asin((a/c)^2)/2;}
curve=normLscate();
}
}
\end{filecontents*}
%
%
\documentclass[10pt,a4paper]{article}
\usepackage{lmodern}
\usepackage{subcaption}
\usepackage[inline]{asymptote}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry}
%
\begin{document}
%
\begin{figure}
\captionsetup[subfigure]{justification=centering}
\centering
\begin{subfigure}{0.49\textwidth}
\begin{asy}
import cassinioval;
size(5cm);
pair A=(-2,0);
pair B=(2,0);
real C=5;

CassiniOval co=CassiniOval(A,B,C);

pen cpen=deepblue;
pen fpen=lightgreen;

fill(co.curve,fpen);
draw(co.curve,cpen);

dot(A,UnFill);
dot(B,UnFill);
label("$A$",A,W);
label("$B$",B,E);

pair Ap=(0,-2);
pair Bp=(0,2);

fpen=lightred+opacity(0.5);
filldraw(CassiniOval(Ap,Bp,C).curve,fpen,cpen);

dot(Ap,UnFill);
dot(Bp,UnFill);
label("$A^\prime$",Ap,W);
label("$B^\prime$",Bp,E);
\end{asy}
%
\caption{Example 1}
\label{fig:1a}
\end{subfigure}
%
\begin{subfigure}{0.49\textwidth}
\begin{asy}
import cassinioval;
size(5cm);
pen cpen=deepblue;
pen fpen=lightgreen+opacity(0.2);

pair A=(-3,-1);
pair B=(2,3);
real C;
CassiniOval co;

for(int i=6;i<16;++i){
C=i;
co=CassiniOval(A,B,C);
filldraw(co.curve,fpen,cpen);
}

dot(A,UnFill);
dot(B,UnFill);
label("$A$",A,W);
label("$B$",B,E);

\end{asy}
%
\caption{Example 2}
\label{fig:1b}
\end{subfigure}
\caption{}
\label{fig:1}
\end{figure}
%
\end{document}
%
% Process:
%
% pdflatex cassini.tex
% asy cassini-*.asy
% pdflatex cassini.tex

• That looks very nice, thank you! But I am not able to include that an existing tikzpicture-environment, am I? So I think I have to extend your example and rewrite my existing tikzpicture, right?
– stg
Jan 6, 2014 at 20:41
• @stg: Yes, feel free to convert it to TikZ. Jan 6, 2014 at 20:47
• I get the following output if I ran asy cassini_*.asy Feb 8, 2019 at 10:35
• An update in Asymptote made it run GhostScript with the -dSAFER option enabled by default, which makes code with opacity (such as this one) fail. The solution in this case is to pass the -nosafe option to asy to make this code work. Feb 8, 2019 at 12:41
• @ S. Venkataraman: Also, check out Ghostscript error when using opacity. Feb 8, 2019 at 16:03

Just for fun: a TikZ version. The strategy is very much as in g.kov's nice answer. The syntax is

\draw[Cassini curve=with centers A and B and constant pi];


where the centers denote the two points and the constant what is called c in the question.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[declare function={%
rhoone(\a,\c,\t)=sqrt(\a^2*cos(2*\t)-sqrt(-2*\a^4 + 64*\c^2 + 2*\a^4*cos(4*\t))/2)/2;
rhotwo(\a,\c,\t)=sqrt(\a^2*cos(2*\t)+sqrt(-2*\a^4 + 64*\c^2+2*\a^4*cos(4*\t))/2)/2;},
Cassini curve/.style args={with centers #1 and #2 and constant #3}{%
insert path={
let \p1=($(#2)-(#1)$),\n1={veclen(\x1,\y1)/1cm},\n2={atan2(\x1,\y1)}
in %\pgfextra{\typeout{#1,#2,#3,\n1,\n2}}
[shift={($(#2)!0.5!(#1)$)}]
plot[variable=\t,domain=0:360,smooth,samples=101]
(\t-\n2+90:{rhotwo(\n1,#3,\t)})
}}]
\path (0,0) coordinate (A) (3,1) coordinate (B) (-2,-2) coordinate (C);
\foreach \X in {A,B,C} {\fill (\X) circle (1pt) node[below]{\X};}
\draw[fill=blue,fill opacity=0.3,Cassini curve=with centers A and B and constant pi];
\draw[fill=red,fill opacity=0.3,Cassini curve=with centers A and C and constant pi];
\end{tikzpicture}
\end{document}