10

Consider the following MWE:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc,backgrounds}
\tikzset{
    kolben/.style={
        append after command={
            \pgfextra{
                \node[fill=white,draw,minimum width=1.5cm,minimum height=1.3cm] (a) at (\tikzlastnode) {};
                \draw ($(a.north west)!.4!(a.south west)$) -- ($(a.north east)!.4!(a.south east)$);
                \draw ($(a.north west)!.35!(a.south west)$) -- ($(a.north east)!.35!(a.south east)$);
                \draw ($(a.north west)!.3!(a.south west)$) -- ($(a.north east)!.3!(a.south east)$);
                \draw ([yshift=-.2cm]$(a.north west)!.5!(a.south east)$) circle(.07);


            }
        }
    }
}
\begin{document}
\foreach \n in {0,1,...,36}
{
    \begin{tikzpicture}
        \pgfmathsetmacro{\x}{10*\n}
        \pgfmathsetmacro{\d}{(100/36)*\n}
        \useasboundingbox (-2,-2) rectangle (2,6);
%       \draw (0,0) circle(1);
            \begin{pgfonlayer}{background}
                \draw[rotate=\x] (0,.5) arc(90:270:.5) -- cycle;
            \end{pgfonlayer}
            \path (\x:1) -- ([yshift=3cm]0,{sin(\x)}) node[above,kolben] {};
                    \draw[double distance=15mm] (0,1.48) -- (0,4.78);
                            \fill[red!\d] ([xshift=-7.45mm]0,4.78) rectangle ([xshift=-.1mm]a.north east);
                        \draw[double distance=1mm] (0,0) -- (\x:1);
                        \draw[shorten >= -.5cm,double distance=1mm] (\x:1) -- (a);  
            \draw (\x:1) -- ([yshift=3cm]0,{sin(\x)}) node[above,kolben] {};
                \fill[black,radius=.1] (\x:1) circle;
            \draw[->,red,ultra thick] (1.5,2.5) -- ([xshift=.75cm]a.north east);
            \ifnum\n>9
            \pgfmathsetmacro{\aa}{.5*\d}
                \fill[blue!\aa] ([xshift=-7.45mm]0,4.78) rectangle ([xshift=-.1mm]a.north east);
                    \fill[white] (1.3,2.5) rectangle ([xshift=.95cm]a.north east);
                \draw[<-,red,ultra thick] ([xshift=.75cm]a.south east) -- (1.5,4.8);
            \fi
            \ifnum\n>27
            \pgfmathsetmacro{\aa}{.2*\d}
                \fill[gray!\aa] ([xshift=-7.45mm]0,4.78) rectangle ([xshift=-.1mm]a.north east);
                \fill[white] (1.3,1) rectangle ([yshift=2.1cm,xshift=.95cm]a.north east);
                \draw[->,red,ultra thick] (1.5,1.5) -- ([xshift=.75cm]a.north east);
            \fi
    \end{tikzpicture}
}
\end{document}

How can be the code improved (especially the part with the arrows)?

enter image description here

Milo
  • 9,440
current_user
  • 5,235
  • 2
    Should the arrow denote the lateral speed of or the force on the piston? If so the arrow should be longest when the piston is in the middle of the cylinder in case of the speed. The force on the piston wouldn't be that easy... If the arrow should only display displacement, you should only take two reference points (currently you're using 3), and measure only the actual path (you always include the vertical size of the piston). – Skillmon Aug 28 '18 at 18:11
  • 1
    +1 You could of course avoid the xshift if you do \draw[->,red,ultra thick] (1.5,1.5) -- (1.5,1.5 |- a.north east); and so on. –  Aug 28 '18 at 18:21
  • @Skillmon: Yeah, you're right, this is a good point. The arrow just shows the motion of the piston, not the force. – current_user Aug 28 '18 at 18:23
  • 1
    And the colour of the gas seems odd. For a four stroke engine, you'll need to draw two turns of the crank. During the induction stroke the colour should be blue and (almost) constant, during the compression stroke the colour should get warmer, then you get really hot during expansion (and combustion) and afterwards during the exhaustion you can either use grey or get cooler again. – Skillmon Aug 28 '18 at 19:00
  • @Skillmon: Yeah, you're right, but I wanted to keep things simple, you know? I don't think that anybody wants to deal with a long, messy source code, especially by such a sort of questions … ;) – current_user Aug 28 '18 at 20:20

1 Answers1

8

I would probably do something like this:

\documentclass[tikz]{standalone}
\usetikzlibrary{backgrounds}

\tikzset{
    relative to node/.style={
        shift={(#1.center)},
        x={(#1.east)},
        y={(#1.north)},
    },
    kolben/.pic={
        \node[fill=white,draw,minimum width=1.5cm,minimum height=1.3cm] (-a) at (0,0.2) {};
        \begin{scope}[relative to node=-a]
            \draw (-1,0.2) -- ++(2,0);
            \draw (-1,0.3) -- ++(2,0);
            \draw (-1,0.4) -- ++(2,0);
        \end{scope}
        \draw (0,0) circle(0.07) coordinate (-pivot);
    }
}
\begin{document}
\foreach \x [evaluate=\x as \case using {int(mod(\x/90,4))}, evaluate=\x as \d using {10/36*\x}] in {0,10,...,359}
{
    \begin{tikzpicture}
        \useasboundingbox (-2,-2) rectangle (2,6);

        \pic (kolben) at (0,{3+sin(\x)}) {kolben};
            \fill[black,radius=.1] (\x:1) circle;

        \begin{pgfonlayer}{background}
            \draw[double distance=15mm] (0,1.45) -- (0,4.85);
            \draw[rotate=\x] (0,.5) arc(90:270:.5) -- cycle;
            \draw[double distance=1mm] (0,0) -- (\x:1);
            \draw[double distance=1mm] (\x:1) -- (kolben-pivot);  
        \end{pgfonlayer}

        \node[anchor=base] at (1.25,3) {$ x $};
        \ifnum\x=0
            \fill[red] (1,3) circle (1.5pt);
        \else
            \ifnum\x=180
                \fill[red] (1,3) circle (1.5pt);
            \else
                \draw[->,red,ultra thick] (1,3) -- +(0,{sin(\x)});
            \fi
        \fi

        \node[anchor=base] at (1.75,3) {$ \dot{x} $};
        \ifnum\x=90
            \fill[blue] (1.5,3) circle (1.5pt);
        \else
            \ifnum\x=270
                \fill[blue] (1.5,3) circle (1.5pt);
            \else
                \draw[->,blue,ultra thick] (1.5,3) -- +(0,{cos(\x)});
            \fi
        \fi

        \ifcase\case
            \draw[line width=14.9mm,red!\d] (kolben-a.north) -- (0,4.85);
        \or
            \pgfmathsetmacro{\aa}{.5*\d}
            \draw[line width=14.9mm,blue!\aa] (kolben-a.north) -- (0,4.85);
        \or
            \pgfmathsetmacro{\aa}{.5*\d}
            \draw[line width=14.9mm,blue!\aa] (kolben-a.north) -- (0,4.85);
        \or
            \pgfmathsetmacro{\aa}{.2*\d}
            \draw[line width=14.9mm,gray!\aa] (kolben-a.north) -- (0,4.85);
        \fi

    \end{tikzpicture}
}
\end{document}

The changes that I made:

  • I used \x in degrees, so that you can get the animation as smooth as you wish, up to one degree stepsize, by only changing the second entry in the foreach list;
  • I split the animation in four cases (quadrants) in which the gas color is changed (I have not touched the actual colors as I wouldn't know what to do with them anyway);
  • I drew the arrows continuously from one point, I think it is distracting if the starting point of the arrow changes;
  • I added a physical quantity to the arrows, because if there is no idea behind annotations, you might as well omit them;
  • I changed the kolben style to a pic, because if \pgfextra is not needed, you probably shouldn't use it.
  • The rest of the changes are probably personal coding preferences, and don't really add to the functionality, but you can always learn from seeing different code do the same thing :)

The result of course:

enter image description here

Edit
Just for fun, some small aesthetic improvements, and an attempt to display the states of the engine as described by Skillmon:

enter image description here

Code:

\documentclass[tikz]{standalone}
\usetikzlibrary{shapes}

\tikzset{
    relative to node/.style={
        shift={(#1.center)},
        x={(#1.east)},
        y={(#1.north)},
    },
    kolben/.pic={
        \node[fill=white,draw,minimum width=1.5cm,minimum height=1.3cm] (-a) at (0,0.2) {};
        \begin{scope}[relative to node=-a]
            \draw (-1,0.2) -- ++(2,0);
            \draw (-1,0.3) -- ++(2,0);
            \draw (-1,0.4) -- ++(2,0);
        \end{scope}
        \draw (0,0) circle(0.07);
    },
    valve/.pic={
        \draw[fill=white] (-0.175,0) -- (-0.125,0.05) -- (-0.05,0.05) -- (-0.05,0.15) -- (-0.075,0.15) -- (-0.075,0.2) -- (0.075,0.2) -- (0.075,0.15) -- (0.05,0.15) -- (0.05,0.05) -- (0.125,0.05) -- (0.175,0) -- cycle;
    },
    cylinder/.pic={
        \draw (-0.75,1.55) -- (-0.8,1.55) -- (-0.8,5.05) -- (-0.5,5.05) -- (-0.55,5) -- (-0.75,5) -- cycle;
        \draw (-0.25,5.05) -- (-0.2,5) -- (0.2,5) -- (0.25,5.05) -- cycle;
        \draw[xscale=-1] (-0.75,1.55) -- (-0.8,1.55) -- (-0.8,5.05) -- (-0.5,5.05) -- (-0.55,5) -- (-0.75,5) -- cycle;
    },
    crank/.pic={
        \draw[fill=white,rounded corners=1mm] (90:0.75) arc (90:270:0.75) -- (0,-0.1) [rounded corners=0mm] -- (1,-0.1) arc (-90:90:0.1) [rounded corners=1mm] -- (0,0.1) -- cycle (1,0) circle (0.05);
    }
}

\begin{document}
\foreach \phase [
    evaluate=\phase as \x using {int(mod(\phase + 90,360))},
    evaluate=\phase as \case using {int(mod(\phase/180,4))},
    evaluate=\x as \d using {40*sin(\x)+50},
] in {0,5,...,719}{
    \begin{tikzpicture}
        \useasboundingbox (-2,-2) rectangle (2,6);

        \coordinate (pivot) at (0,{3+sin(\x)});
        \coordinate (piston-top) at (0,{3+sin(\x)+1.3/2+0.2});

        \ifcase\case
            \colorlet{gascolor}{blue!10}
            \pgfmathsetmacro\valveone{1}
            \pgfmathsetmacro\valvetwo{0}
        \or
            \colorlet{gascolor}{blue!\d}
            \pgfmathsetmacro\valveone{0}
            \pgfmathsetmacro\valvetwo{0}
        \or
            \colorlet{gascolor}{red!\d}
            \pgfmathsetmacro\valveone{0}
            \pgfmathsetmacro\valvetwo{0}
        \or
            \colorlet{gascolor}{gray!10}
            \pgfmathsetmacro\valveone{0}
            \pgfmathsetmacro\valvetwo{1}
        \fi

        \draw[line width=14.9mm,gascolor] (piston-top) -- (0,5);

        \pic (cylinder) at (0,0) {cylinder};

        \pic (valve1) at (-0.375,{5-0.1*\valveone}) {valve};
        \pic (valve2) at (0.375,{5-0.1*\valvetwo}) {valve};


        \draw[double distance=2mm-\pgflinewidth,line cap=round] (\x:1) -- (pivot);  

        \pic[rotate=\x] (crank) at (0,0) {crank};
        \pic (kolben) at (pivot) {kolben};

        \node[anchor=base] at (1.25,3) {$ x $};
        \ifnum\x=0
            \fill[red] (1,3) circle (1.5pt);
        \else
            \ifnum\x=180
                \fill[red] (1,3) circle (1.5pt);
            \else
                \draw[->,red,ultra thick] (1,3) -- +(0,{sin(\x)});
            \fi
        \fi

        \node[anchor=base] at (1.75,3) {$ \dot{x} $};
        \ifnum\x=90
            \fill[blue] (1.5,3) circle (1.5pt);
        \else
            \ifnum\x=270
                \fill[blue] (1.5,3) circle (1.5pt);
            \else
                \draw[->,blue,ultra thick] (1.5,3) -- +(0,{cos(\x)});
            \fi
        \fi

        \ifnum\phase=360
            \begin{scope}
                \clip (-7.5mm,5cm-0.5\pgflinewidth) rectangle (7.5mm,3cm);
                \node[starburst,starburst point height=3mm,inner color=yellow,outer color=red,draw=orange] at (0,5) {};
            \end{scope}
        \fi

    \end{tikzpicture}
}
\end{document}
Max
  • 9,733
  • 3
  • 28
  • 35
  • 2
    Looks really good, but for a four stroke engine the angle should be between 0 and 720 degrees and the colour quadrants in the intervals [0,180), [180,360), [360,540) and [540,720). – Skillmon Aug 28 '18 at 20:29
  • 1
    I just tried to make that myself but your edit is way better than what I created. (sadly I can't upvote twice) – Skillmon Aug 29 '18 at 09:56
  • 1
    Oh, and since the stroke is very long this is likely to be a Diesel engine, so the ignition wouldn't be started by a spark plug but it would be self igniting. But I guess that isn't important. (And if one wants to be very precise there is the possibility of valve overlapping, start of ignition and delay in ignition) – Skillmon Aug 29 '18 at 10:34
  • 1
    @Skillmon If you want, you can take my code and add those details, I would be very interested in the result. And I think the OP too. – Max Aug 29 '18 at 10:59
  • 1
    This would depend on the use of the graphic. Is it just to demonstrate the basics of a four stroke engine? If so this seems enough. If it should demonstrate all the possibilities of variations in the process, OP should be able to think of them himself (and a visualization of all those parameters and their effects would take way more than this single animation). You've done an excellent job, lets just keep it this way. – Skillmon Aug 29 '18 at 12:01