# Draw an ellipse from the two focus points (foci) and the sum of the distances from foci to border

I have two nodes that I want and foci and I know what the sum of the distances should be (a constant times the distance between the focus nodes).

The way I know of drawing ellipses takes as parameters the center point and the major and minor axis.

I want to define another function (myellipse?) that takes as parameters the two nodes and the constant multiplier.

This is how I'm drawing them currently, doing all calculations by hand (example not perfect):

\draw [rotate around={-15:(1.8,0.5)}] (1.8,0.5) ellipse (2 and 1);

-
related: tex.stackexchange.com/questions/71548/… the command in my answer also works for ellipses –  cmhughes Oct 2 '12 at 23:23
@cmhughes I do not see how you connect this question with your answer... –  Paul Gaborit Oct 3 '12 at 0:35
@PaulGaborit the \pgfpatharcto can be drawn along an ellipse with an xradius and yradius –  cmhughes Oct 3 '12 at 3:36
@cmhughes You are right about \pgfpatharcto. But, here, the request is how to know (to calculate?) the first point, the target point, the center, the radii and the angle of rotation... –  Paul Gaborit Oct 3 '12 at 6:51

Third Edit: A simpler solution without node or memoization... The result is the same as the second edit (see below) but without labels.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand\ellipsebyfoci[4]{% options, focus pt1, focus pt2, cste
\path[#1] let \p1=(#2), \p2=(#3), \p3=($(\p1)!.5!(\p2)$)
in \pgfextra{
\pgfmathsetmacro{\angle}{atan2(\x2-\x1,\y2-\y1)}
\pgfmathsetmacro{\focal}{veclen(\x2-\x1,\y2-\y1)/2/1cm}
\pgfmathsetmacro{\lentotcm}{\focal*2*#4}
\pgfmathsetmacro{\axeone}{(\lentotcm - 2 * \focal)/2+\focal}
\pgfmathsetmacro{\axetwo}{sqrt((\lentotcm/2)*(\lentotcm/2)-\focal*\focal}
}
}

\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (5,3);
\ellipsebyfoci{draw,fill=cyan!50}{a}{b}{1.4}
\begin{scope}
\ellipsebyfoci{clip}{a}{b}{1.4}
\ellipsebyfoci{draw,fill=orange!50,name=ell 2}{0,0}{3,5}{1.05}
\fill[red] (a) circle(2pt);
\fill[red] (b) circle(2pt);
\end{scope}
\end{tikzpicture}
\end{document}


Second Edit: Here is a solution with an example of clipped ellipse (using my answer to Best way to draw scaled polygons in tikz just to memoize path of ellipse node).

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes.geometric,decorations.pathreplacing}

\makeatletter
% to produce automaticaly homothetic paths
\newcounter{homothetypoints} % number of vertices of path
\tikzset{
% homothety is a family...
homothety/.style={homothety/.cd,#1,/tikz/.cd},
% ...with some keys
homothety={
% parameters
scale/.store in=\homothety@scale,% scale of current homothetic transformation
center/.store in=\homothety@center,% center of current homothetic transformation
name/.store in=\homothety@name,% prefix for named vertices
% default values
scale=1,
center={0,0},
name=homothety,
% initialization
init memoize homothetic path/.code={
\xdef#1{}
\setcounter{homothetypoints}{0}
},
% incrementation
% a style to store an homothetic transformation of current path into #1 macro
store in/.style={
init memoize homothetic path=#1,
/tikz/postaction={
decorate,
decoration={
show path construction,
moveto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentfirst)$)}
% name this vertex
\coordinate[homothety/++](\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentfirst)$);
},
lineto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 -- ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
% name this vertex
\coordinate[homothety/++] (\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$);
},
curveto code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1
.. controls ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentsupporta)$)
and ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentsupportb)$)
.. ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
% name this vertex
\coordinate[homothety/++] (\homothety@name-\arabic{homothetypoints})
at ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$);
},
closepath code={
% apply homothetic transformation to this segment and add result to #1
\xdef#1{#1 -- cycle ($(\homothety@center)!\homothety@scale!(\tikzinputsegmentlast)$)}
},
},
},
},
},
}
\makeatother

\newcommand\ellipsebyfoci[4]{% options, focus pt1, focus pt2, cste
\path let \p1=(#2), \p2=(#3), \p3=($(\p1)!.5!(\p2)$)
in \pgfextra{
\pgfmathsetmacro{\angle}{atan2(\x2-\x1,\y2-\y1)}
\pgfmathsetmacro{\focal}{veclen(\x2-\x1,\y2-\y1)/2/1cm}
\pgfmathsetmacro{\lentotcm}{\focal*2*#4}
\pgfmathsetmacro{\axeone}{(\lentotcm - 2 * \focal)/2+\focal}
\pgfmathsetmacro{\axetwo}{sqrt((\lentotcm/2)*(\lentotcm/2)-\focal*\focal}
}
(\p3) node[#1,inner sep=0,rotate=\angle,ellipse,minimum width=2*\axeone cm,minimum height=2*\axetwo cm]{};
}

\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (5,3);
\ellipsebyfoci{draw,fill=cyan!50,name=ell 1,homothety={store in=\mypath}}{a}{b}{1.4}
\node[fill=white] at (ell 1.south){1.4};
\begin{scope}
\clip \mypath;
\ellipsebyfoci{draw,fill=orange!50,name=ell 2}{0,0}{3,5}{1.05}
\node[fill=white] at (ell 2.south){1.05};
\fill[red] (a) circle(2pt);
\fill[red] (b) circle(2pt);
\end{scope}
\end{tikzpicture}
\end{document}


First Edit: Here is a solution with the constant multiplier as required (see below for explanations).

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes.geometric}
\begin{document}

\newcommand\ellipsebyfoci[4]{% options, focus pt1, focus pt2, cste
\path let \p1=(#2), \p2=(#3), \p3=($(\p1)!.5!(\p2)$)
in \pgfextra{
\pgfmathsetmacro{\angle}{atan2(\x2-\x1,\y2-\y1)}
\pgfmathsetmacro{\focal}{veclen(\x2-\x1,\y2-\y1)/2/1cm}
\pgfmathsetmacro{\lentotcm}{\focal*2*#4}
\pgfmathsetmacro{\axeone}{(\lentotcm - 2 * \focal)/2+\focal}
\pgfmathsetmacro{\axetwo}{sqrt((\lentotcm/2)*(\lentotcm/2)-\focal*\focal}
}
(\p3) node[#1,inner sep=0,rotate=\angle,ellipse,minimum width=2*\axeone cm,minimum height=2*\axetwo cm]{};
}

\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (5,3);
\ellipsebyfoci{draw,fill=cyan!50,name=ell 1}{a}{b}{1.4}
\node[fill=white] at (ell 1.south){1.4};
\ellipsebyfoci{draw,fill=orange!50,name=ell 2}{a}{b}{1.05}
\node[fill=white] at (ell 2.south){1.05};
\fill[red] (a) circle(2pt);
\fill[red] (b) circle(2pt);
\end{tikzpicture}
\end{document}


First answer: Here is a solution with a node shaped as ellipse (via shapes.geometric library).

I define the \ellipsebyfoci macro with four arguments:

1. options for the ellipse (to draw it, to fill it, etc.),
2. first focus pt,
3. second focus pt,
4. sum of distance between foci and border.

All calculations are in centimeters to avoid overflows (! Dimension too large.).

The code:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes.geometric}

\newcommand\ellipsebyfoci[4]{% options, focus pt1, focus pt2, sum
\path let \p1=(#2), \p2=(#3), \p3=($(\p1)!.5!(\p2)$)
in \pgfextra{
\pgfmathsetmacro{\angle}{atan2(\x2-\x1,\y2-\y1)}
\pgfmathsetmacro{\focal}{veclen(\x2-\x1,\y2-\y1)/2/1cm}
\pgfmathsetmacro{\lentotcm}{#4/1cm}
\pgfmathsetmacro{\axeone}{(\lentotcm - 2 * \focal)/2+\focal}
\pgfmathsetmacro{\axetwo}{sqrt((\lentotcm/2)*(\lentotcm/2)-\focal*\focal}
}
(\p3) node[#1,inner sep=0,rotate=\angle,ellipse,minimum width=2*\axeone cm,minimum height=2*\axetwo cm]{};
}

\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (7,3);

\fill[red] (a) circle(2pt);
\fill[red] (b) circle(2pt);

\ellipsebyfoci{draw,fill=orange,fill opacity=.1}{a}{b}{8cm}
\end{tikzpicture}
\end{document}

-
Nice! I had a version with the constant multiplier working as well. I did not know how to to use 'let', I like your solution. I ended up incorporating options in my solution with optional parameters. Thanks! –  Mig Oct 3 '12 at 4:01
Also, with your solution I'm able to name the node, cool! Extra question: How do I use the named nodes to clip a few ellipses and fill their intersection? –  Mig Oct 3 '12 at 20:23
You can apply the clip option (without draw or fill operations) to an ellipse. –  Paul Gaborit Oct 3 '12 at 20:31
Yes, I tried that, but apparently the clipping doesn't hold outside of the command. Could you add an example? –  Mig Oct 3 '12 at 21:18
@Mig You are right: clip action can't be applied to a node! A solution can use tex.stackexchange.com/a/72753/14500 to memoize ellipse path then to reuse it as clip. –  Paul Gaborit Oct 3 '12 at 21:52

I got what I wanted! Not sure if there is a better way to do it though...

\makeatletter
\newcommand*{\myellipse}[3]{
% Bigger axis: #3
% Smaller axis: sqrt([#3]ˆ2 - |uv|ˆ2)
\coordinate (midpoint) at ($(#1)!0.5!(#2)$) {};

% Calculate angle
\pgfmathanglebetweenpoints{\pgfpointanchor{#1}{center}}
{\pgfpointanchor{#2}{center}}
\let\angle\pgfmathresult % save result in \angle

% calculate distance
\pgfpointdiff{\pgfpointanchor{#1}{center}}
{\pgfpointanchor{#2}{center}}
\pgf@xa=\pgf@x % no need to use a new dimen
\pgf@ya=\pgf@y
\pgfmathparse{veclen(\pgf@xa,\pgf@ya)/28.45274} %  to convert from                      % pt to cm
\let\uv\pgfmathresult % save the result in \uv

\draw [rotate around={\angle:(midpoint)}]
(midpoint) ellipse ({#3} and {sqrt((#3)*(#3) - (\uv)*(\uv))});
}
\makeatother

-
joli ( pretty ) –  rpapa Oct 3 '12 at 7:13

this example is not a complete answer but just an outline of a point by point calculation of the ellipse from Tikz tools, this is certainly not optimal

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{intersections}

\begin{document}
\begin{tikzpicture}

\begin{scope}[rotate=15]
\def\entraxe{200}
\draw (0,0)coordinate(A) -- (\entraxe/100,0)coordinate(B);
\foreach \rr in {101,102,103,...,299}{
\path[red,name path =circleA] (A) circle (\rr/100);
\path[blue,name path =circleB] (B) circle ({(400-\rr)/100});
\path[dashed,name intersections={of=circleA and circleB}];
\draw (intersection-1) circle (0.01cm);
\draw (intersection-2) circle (0.01cm);
}
\end{scope}

\end{tikzpicture}
\end{document}


-