36

I am new to TikZ and reading its manual now. For the sake of exercises, I want to draw Batman's logo as follows:

enter image description here

Using TikZ, how to draw an elliptical arc starting from point A to point B with the origin as its center?

\documentclass{article}
\usepackage{tikz}


\usepackage[active,tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\PreviewBorder=12pt


\begin{document}
\begin{tikzpicture}

    \filldraw[fill opacity=0.5,fill=yellow] (0,0) ellipse (7.0 and 4.3);
    \draw[line width=5mm] (0,0) ellipse (6.5 and 3.8);
    \draw[line width=2pt,dashed,white] (0,0) ellipse (6.0 and 3.3);

    \draw[line width=2pt]   
                            (0,2.7) -- (0.5,2.7) -- (1,3.25) 
                            .. controls (1.2,1.3) and (1.3,1.0) .. 
                            (2.0,1.0) 
                            .. controls (3.0,1.0) and (3.0,2.2) .. 
                            (2,3.1);

    %How to draw an elliptical arc from (2,3.1) to (3.2,-2.8)?
    %\draw ()   arc ();

    \draw[line width=2pt] 
            (3.2,-2.8) 
            .. controls (4,-2) and (4,0) ..
            (2.2,-1.8)
            .. controls (1.5,-1) and (1,-1) ..
            (0,-3.2);
\end{tikzpicture}
\end{document}

Note: Horizontal and vertical radii are given.

Bonus question: Instead of drawing the left part by using the same method as I did for the right part, how to use reflection technique to get a complete Batman's logo?

  • Sort of vaguely related: http://tex.stackexchange.com/q/15972/86 – Andrew Stacey Mar 09 '12 at 12:38
  • @AndrewStacey: Is there a simpler way for beginners like me? – kiss my armpit Mar 09 '12 at 12:39
  • percusse has answered in the meantime, but I was thinking that Will Hunting's answer would be easy to adapt to this situation since in that answer the centre is explicitly calculated and then the arc drawn between two of the points. You already have the centre, so don't need to compute it. The only bit missing is whether it is possible to deform it to an ellipse rather than a circle. – Andrew Stacey Mar 09 '12 at 12:44

3 Answers3

44

I would use a slightly lower level PGF (Portable Graphics Format) command \pgfpatharcto for this and I have guessed the 11cm by eyeballing. For the bonus I created a scope where I defined the x unit vector to be (-1,0) so whatever is drawn inside, the horizontal coordinate will be reversed. Hence, I can literally copy the right part code into left part except the arc command which accepts absolute coordinates (unless there is any coordinate transformation is going on).

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \filldraw[fill opacity=0.5,fill=yellow] (0,0) ellipse (7.0 and 4.3);
    \draw[line width=5mm] (0,0) ellipse (6.5 and 3.8);
    \draw[line width=2pt,dashed,white] (0,0) ellipse (6.0 and 3.3);

    \draw[line width=2pt]   (0,2.7) -- (0.5,2.7) -- (1,3.25) 
                            .. controls (1.2,1.3) and (1.3,1.0) .. 
                            (2.0,1.0) .. controls (3.0,1.0) and (3.0,2.2) .. (2,3.1);
    \draw[line width=2pt] 
            (3.2,-2.8) .. controls (4,-2) and (4,0) .. (2.2,-1.8)
            .. controls (1.5,-1) and (1,-1) ..(0,-3.2);

    \pgfsetlinewidth{2pt}
    \pgfmoveto{\pgfpoint{2cm}{3.1cm}}
    \pgfpatharcto{6cm}{3.3cm}{0}{0}{0}{\pgfpoint{3.2cm}{-2.8cm}}\pgfusepath{stroke};

\begin{scope}[x=-1cm]
    \draw[line width=2pt]   (0,2.7) -- (0.5,2.7) -- (1,3.25) 
                            .. controls (1.2,1.3) and (1.3,1.0) .. 
                            (2.0,1.0) .. controls (3.0,1.0) and (3.0,2.2) .. (2,3.1);
    \draw[line width=2pt] 
            (3.2,-2.8) .. controls (4,-2) and (4,0) .. (2.2,-1.8)
            .. controls (1.5,-1) and (1,-1) ..(0,-3.2);
\end{scope}
    \pgfsetlinewidth{2pt}
    \pgfmoveto{\pgfpoint{-2cm}{3.1cm}}
    \pgfpatharcto{6cm}{3.3cm}{0}{0}{1}{\pgfpoint{-3.2cm}{-2.8cm}}\pgfusepath{stroke};
\end{tikzpicture}
\end{document}

enter image description here

EDIT2 : Filling the curve was much difficult with the code above so making a continuous path seemed easier since Damien already provided the necessary coordinates. There is simply no complication other than renaming the commands. The \pgfpathcurveto is equivalent to \draw (coord1) ..controls (support1) and (support2) .. (coord2) except that you have to move to (coord1) first. After the coordinate transformation, it is again a matter of copy-paste.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

    \filldraw[fill opacity=0.5,fill=yellow] (0,0) ellipse (7.0 and 4.3);
    \draw[line width=5mm] (0,0) ellipse (6.5 and 3.8);
    \draw[line width=2pt,dashed,white] (0,0) ellipse (6.0 and 3.3);

\pgfsetlinewidth{2pt}
\pgfpathmoveto{\pgfpoint{0}{2.7cm}}
\pgfpathlineto{\pgfpoint{0.5cm}{2.7cm}}
\pgfpathlineto{\pgfpoint{1cm}{3.25cm}}
\pgfpathcurveto{\pgfpoint{1.2cm}{1.3cm}}{\pgfpoint{1.3cm}{1cm}}{\pgfpoint{2cm}{1cm}}
\pgfpathcurveto{\pgfpoint{3cm}{1cm}}{\pgfpoint{3cm}{2.2cm}}{\pgfpoint{2cm}{3.1cm}}
\pgfpatharcto{6cm}{3.3cm}{0}{0}{0}{\pgfpoint{3.2cm}{-2.8cm}}
\pgfpathcurveto{\pgfpoint{4cm}{-2cm}}{\pgfpoint{4cm}{0}}{\pgfpoint{2.2cm}{-1.8cm}}
\pgfpathcurveto{\pgfpoint{1.5cm}{-1cm}}{\pgfpoint{1cm}{-1cm}}{\pgfpoint{0cm}{-3.2cm}}
\pgftransformcm{-1}{0}{0}{1}{\pgfpointorigin} % This is the coordinate change from x to -x
\pgfpathcurveto{\pgfpoint{1cm}{-1cm}}{\pgfpoint{1.5cm}{-1cm}}{\pgfpoint{2.2cm}{-1.8cm}}
\pgfpathcurveto{\pgfpoint{4cm}{0cm}}{\pgfpoint{4cm}{-2cm}}{\pgfpoint{3.2cm}{-2.8cm}}
\pgfpatharcto{6cm}{3.3cm}{0}{0}{1}{\pgfpoint{2cm}{3.1cm}}
\pgfpathcurveto{\pgfpoint{3cm}{2.2cm}}{\pgfpoint{3cm}{1cm}}{\pgfpoint{2cm}{1cm}}
\pgfpathcurveto{\pgfpoint{1.3cm}{1cm}}{\pgfpoint{1.2cm}{1.3cm}}{\pgfpoint{1cm}{3.25cm}}
\pgfpathlineto{\pgfpoint{0.5cm}{2.7cm}}
\pgfpathclose
\pgfusepath{fill,stroke}   


\end{tikzpicture}
\end{document}

EDIT3 Alfred, join this curve nicely will ya? So we draw one half and carry on backwards for a proper line join at the tail and fill.

enter image description here

percusse
  • 157,807
  • 19
    Admit it: you had this already coded and were just waiting for someone to post a question. Right? – Andrew Stacey Mar 09 '12 at 12:45
  • @AndrewStacey Hahaha, actually I was trying to fix this answer while this was posted. – percusse Mar 09 '12 at 12:49
  • 6
    Holy TikZ, Batman! Awesome answer! :) – Paulo Cereda Mar 09 '12 at 12:50
  • @PauloCereda Thank you! Actually the hard part is Damien's work. The rest is simply two arcs :) – percusse Mar 09 '12 at 13:14
  • 3
    It does seem fit for the shape library to create a pure shape with prober anchors etc. Who don't need a \node[batman] {Bat me up};... – nickpapior Mar 09 '12 at 13:51
  • 1
    @zeroth: http://meta.tex.stackexchange.com/a/2352/86 – Andrew Stacey Mar 09 '12 at 15:01
  • And using the path primitives like that should make it really easy to adapt to a node shape. percusse, to the TikZ-mobile. – Andrew Stacey Mar 09 '12 at 15:03
  • @AndrewStacey I am a fan of the superhero library already! Thanks for the meta-list, I will have it in the back of my head for further addings. – nickpapior Mar 09 '12 at 15:40
  • @percusse This proves it! TikZ can do almost everything.:-) – azetina Mar 09 '12 at 16:09
  • @percusse Little mistake you forgot the last line \pgfpathlineto{\pgfqpoint{0 cm}{2.7 cm}} before the end. I made a batman shape but I have two little problems. I will ask a new question. – Alain Matthes Mar 09 '12 at 17:57
  • @Altermundus I have used the \pgfpathclose command which connects it to the first point just as the -- cycle; command does. As I always do, I will definitely look into your questions when you write them up :) – percusse Mar 09 '12 at 20:59
  • @percusse Yes you are right ( I had not seen this line and I removed it with my code, sorry) and finally it's better to use \pgfpathcloset o close the path. I used always this method with pgfornament. – Alain Matthes Mar 09 '12 at 21:33
  • @azetina: See http://tex.stackexchange.com/a/47541/9467, using PSTricks is more compact and easier. – kiss my armpit Mar 10 '12 at 23:37
26

enter image description here

\documentclass[pstricks,border={-8.5mm -5.5mm -8.5mm -5.0mm}]{standalone}
\usepackage{pst-eucl}
\usepackage{pst-grad}
\usepackage{graphicx}

\newpsstyle{A}
{
    fillstyle=gradient,
    gradbegin=red,
    gradend=yellow,
    gradangle=30,
    gradmidpoint=0.5,
    linestyle=none
}

\newpsstyle{B}{
    fillstyle=gradient,
    gradbegin=darkgray,
    gradend=black,
    gradangle=45,
    gradmidpoint=1,
    linestyle=none  
}


\psset
{
    runit=\psunit,
    fillstyle=solid,
    PointName=none,
    PointSymbol=none,
}

\pstVerb
{
    /theta 72 def
    /Major 6.0 def
    /Minor 3.3 def
}

\def\DeclareNodes
{
    \pstGeonode
        (0,-8){Bottom}
        (0,8){Top}
        (0,0){center}
        (0,2.7){A}
        (0.5,2.7){B}
        (1,3.25){C}
        (1.2,1.3){D}
        (1.3,1.0){E}
        (2.0,1.0){F}
        (3.0,1.0){G}
        (3.0,2.2){H}
        (!Minor Major theta PtoC){I}
        (!Minor Major theta neg PtoC){J}
        (4,-2){K}
        (4,0){L}
        (2.2,-1.8){M}
        (1.5,-1){N}
        (1,-1){O}
        (0,-3.2){P}
    \pstOrtSym{Bottom}{Top}{B,C,D,E,F,G,H,I,J,K,L,M,N,O}
}

\def\RightPart
{
    \psline(A)(B)(C)
    \psbezier(D)(E)(F)
    \psbezier(G)(H)(I)
    \psellipticarcn[dimen=middle](center)(!Major Minor){(I)}{(J)}
    \psbezier(K)(L)(M)
    \psbezier(N)(O)(P)
}


\def\LeftPart
{
    \psbezier(O')(N')(M')
    \psbezier(L')(K')(J')
    \psellipticarcn[dimen=middle](center)(!Major Minor){(J')}{(I')}
    \psbezier(H')(G')(F')
    \psbezier(E')(D')(C')
    \psline(B')
}


\begin{document}


\begin{pspicture}[showgrid=false](-7.85,-4.85)(7.85,4.80)
    \psellipse[style=A](0,0)(!Major 1 add Minor 1 add)
    \psellipse[style=B](0,0)(!Major 0.75 add Minor 0.75 add)
    \psellipse[style=A](0,0)(!Major 0.25 add Minor 0.25 add)
    \DeclareNodes
    \pscustom*{\RightPart\LeftPart\closepath}
\end{pspicture}


\begin{pspicture}[showgrid=false](-7.85,-4.85)(7.85,4.80)%(-7,-4)(7,4)
    \psellipse[style=A](0,0)(!Major 1 add Minor 1 add)
    \psellipse[style=B](0,0)(!Major 0.75 add Minor 0.75 add)
    \psellipse[style=A](0,0)(!Major 0.25 add Minor 0.25 add)
    \begin{psclip}{\DeclareNodes\pscustom[linewidth=6pt]{\RightPart\LeftPart\closepath}}
        \rput(0,0){\includegraphics[width=2\dimexpr7.85\psunit\relax]{example-grid-100x100pt}}
    \end{psclip}
\end{pspicture}


\end{document}
15

Not really an answer, but only to get an homogeneous version that I can transform for use with pgfornament. I used pgfqpoint but in this case I need to add the unity (cm) for each numbers.

\begin{tikzpicture}
  \pgfsetlinewidth{0.4 pt}
  \pgfpathellipse{\pgfqpoint{0 cm}{0 cm}}
                 {\pgfqpoint{7 cm}{0 cm}}
                 {\pgfqpoint{0 cm}{4.3cm}} 
  \pgfsetfillopacity{.5}  
  \pgfsetfillcolor{yellow}
  \pgfusepath{fill,stroke}   
  \pgfsetlinewidth{30\pgflinewidth}
  \pgfpathellipse{\pgfqpoint{0 cm}{0 cm}}
                 {\pgfqpoint{6.5 cm}{0 cm}}
                 {\pgfqpoint{0 cm}{3.8 cm}}
  \pgfusepath{stroke}
  \pgfsetlinewidth{0.4 pt}       
  \pgfpathmoveto{\pgfqpoint{0 cm}{2.7 cm}}
  \pgfpathlineto{\pgfqpoint{0.5 cm}{2.7 cm}}
  \pgfpathlineto{\pgfqpoint{1 cm}{3.25 cm}}
  \pgfpathcurveto{\pgfqpoint{1.2 cm}{1.3 cm}}
                 {\pgfqpoint{1.3 cm}{1 cm}}
                 {\pgfqpoint{2 cm}{1 cm}}
  \pgfpathcurveto{\pgfqpoint{3 cm}{1 cm}}
                 {\pgfqpoint{3 cm}{2.2 cm}}
                 {\pgfqpoint{2 cm}{3.1 cm}}
  \pgfpatharcto{6 cm}{3.3 cm}{0}{0}{0}
               {\pgfqpoint{3.2 cm}{-2.8 cm}}
  \pgfpathcurveto{\pgfqpoint{4 cm}{-2 cm}}
                 {\pgfqpoint{4 cm}{0 cm}}
                 {\pgfqpoint{2.2 cm}{-1.8 cm}}
  \pgfpathcurveto{\pgfqpoint{1.5 cm}{-1 cm}}
                 {\pgfqpoint{1 cm}{-1 cm}}
                 {\pgfqpoint{0 cm}{-3.2 cm}}
  \pgftransformcm{-1}{0}{0}{1}{\pgfpointorigin}
  \pgfpathcurveto{\pgfqpoint{1 cm}{-1 cm}}
                 {\pgfqpoint{1.5 cm}{-1 cm}}
                 {\pgfqpoint{2.2cm}{-1.8cm}}
  \pgfpathcurveto{\pgfqpoint{4 cm}{0 cm}}
               {\pgfqpoint{4 cm}{-2 cm}}
               {\pgfqpoint{3.2 cm}{-2.8 cm}}
  \pgfpatharcto{6 cm}{3.3 cm}{0}{0}{1}
               {\pgfqpoint{2 cm}{3.1 cm}}
  \pgfpathcurveto{\pgfqpoint{3 cm}{2.2 cm}}
               {\pgfqpoint{3 cm}{1 cm}}
               {\pgfqpoint{2 cm}{1 cm}}
   \pgfpathcurveto{\pgfqpoint{1.3cm}{1 cm}}
               {\pgfqpoint{1.2cm}{1.3 cm}}
               {\pgfqpoint{1 cm}{3.25 cm}}
   \pgfpathlineto{\pgfqpoint{0.5 cm}{2.7 cm}}
   \pgfsetfillopacity{1}  
   \pgfsetfillcolor{black} 
   \pgfusepath{fill,stroke}
\end{tikzpicture} 

The shape : (but I have some problems)

enter image description here

Alain Matthes
  • 95,075