# Drawing the three altitudes of a triangle with TikZ; incorrect orthocenter

You probably know that if you draw all three altitudes of a triangle, they will meet at a single point, the orthocenter.

I'm trying to draw a picture that shows the intersecting altitudes with TikZ and letting TikZ do most of the job for me. I'm using TikZ's coordinate calculation capabilities for that.

Here is the code:

\documentclass{report}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[scale=2]
\coordinate (A) at (0,0);
\coordinate (B) at (1,2.5);
\coordinate (C) at (4,0);
\draw (A) -- (B) -- (C) -- cycle;
\draw (B) -- ($(A)!(B)!(C)$) ++(90:0.2) -- ++(0:0.2) -- +(-90:0.2);
\draw (A) -- ($(B)!(A)!(C)$) ++(-39.806:0.2) -- ++(50.194:-0.2) -- +(-39.806:-0.2);
\draw (C) -- ($(A)!(C)!(B)$) ++(68.2:-0.2) -- ++(-21.8:0.2) -- +(68.2:0.2);
\end{tikzpicture}
\end{document}


Here is the result:

Upon very close inspection (e.g., if you view the resulting pdf file with a pdf-reader and zoom in as close as possible) you can see that the three altitudes do not meet at a single point but instead meet in pairs, producing three distinct intersections.

Here's an image of the "intersection point" at 1600%

I also tried with different line widths, i.e. I used [very thin] on the whole {tikzpicture} environment but the problem persists.

I feel the reason for this inaccuracy might be due to numeric precision to which TikZ calculations are limited. However, I am still wondering if anyone has encountered this problem or knows of a solution? Or maybe that's the wrong method to draw altitudes?

P. S. while not a very big problem it still feels disappointing to know your pictures only look correct when not zoomed in on.

• Did you try with scale=1 ? – percusse Jul 21 '15 at 14:54
• I added an image of the resulting intersection with your code. I hope it's OK. – Gonzalo Medina Jul 21 '15 at 14:56
• @percusse The problem persists with scale=1. – Gonzalo Medina Jul 21 '15 at 14:57
• @Gonzalo Medina: yes, that's a useful addition. @percusse: The problem was initially discovered with scale=1. – Rokas Jul 21 '15 at 14:59
• This seems like a duplicate of Calculating right angle triangle side inside LaTeX? See the excellent answer by Alain Mathes. – Gonzalo Medina Jul 21 '15 at 15:06

This is, indeed, due to some inaccuracies in PGF, and can actually been seen in the manual in the section on coordinate calculations. More specifically it appears to be down to the the \pgfpointnormalised command which has been around for years (i.e., prior to the math engine) but has never been updated.

Armed with an alternative definition, the altitudes intersect with considerably more accuracy:

\documentclass[varwidth,border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,spy}
\makeatletter
\def\pgfmathpointnormalised#1{%
\pgf@process{#1}%
\pgfmathatantwo{\the\pgf@y}{\the\pgf@x}%
\let\pgf@tmp=\pgfmathresult%
\pgfmathcos@{\pgf@tmp}\pgf@x=\pgfmathresult pt\relax%
\pgfmathsin@{\pgf@tmp}\pgf@y=\pgfmathresult pt\relax%
}
\begin{document}
\begin{tikzpicture}[x=2cm,y=2cm,
spy using outlines={circle, magnification=10, size=2cm, connect spies}]
\path (0,0) coordinate (A) (1,2.5) coordinate (B) (4,0) coordinate (C);
\draw (A) -- (B) -- (C) -- cycle;
\draw [red, opacity=0.5, very thin]
(A) -- ($(B)!(A)!(C)$) (B) -- ($(A)!(B)!(C)$) (C) -- ($(A)!(C)!(B)$);
\spy [red] on (1,1.2) in node at (3.5,1.5);
\end{tikzpicture}

\begin{tikzpicture}[x=2cm,y=2cm,
spy using outlines={circle, magnification=10, size=2cm, connect spies}]
\let\pgfpointnormalised=\pgfmathpointnormalised
\path  (0,0) coordinate (A) (1,2.5) coordinate (B) (4,0) coordinate (C);
\draw (A) -- (B) -- (C) -- cycle;
\draw [blue, opacity=0.5, very thin]
(A) -- ($(B)!(A)!(C)$) (B) -- ($(A)!(B)!(C)$) (C) -- ($(A)!(C)!(B)$);
\spy [blue] on (1,1.2) in node at (3.5,1.5);
\end{tikzpicture}
\end{document}


• Thanks! This is exactly the answer I was anticipating. I inserted your code into my documents to fix the diagrams and it works perfectly. Sadly, though, I have not the slightest idea about what exactly the fix does and why it works. Also, it would be nice if this fix were included in TikZ source code but it seems to me no one is actively working on TikZ anymore. – Rokas Jul 24 '15 at 15:53
• @Rokas \pgfpointnormalised simply converts a 2D-coordinate to a unit-vector (i.e. same angle but with length 1pt). It is used in the calculation of orthogonal projections (and in a bunch of other places). The original version was very fast, but a bit inaccurate (maybe only to around 1 degree) and the inaccuracies were magnified with subsequent calculations, the version I put in above is orders of magnitude slower but comparatively more accurate. You could put in a feature request or a bug report here so it doesn't get forgotten. – Mark Wibrow Jul 25 '15 at 17:52
• @Mark Wibrow: submitted a feature request, ticket #96. – Rokas Jul 26 '15 at 9:48
• 3 year later, I notice that this error has not been fixed so far (29 Sep 2018)! why is that? – Black Mild Sep 29 '18 at 13:37
• This has been fixed upstream: sourceforge.net/p/pgf/git/ci/… – Henri Menke Feb 28 '19 at 8:00

For comparison, here's one way to construct and draw altitudes in Metapost; the orthocenter looks correct even when zoomed in.

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

u = 2cm;

z1 = origin;
z2 = (1u,2.5u);
z3 = (4u,0);

z4 = whatever[z2,z3]; z4-z1 = whatever * (z3-z2) rotated 90;
z5 = whatever[z3,z1]; z5-z2 = whatever * (z1-z3) rotated 90;
z6 = whatever[z1,z2]; z6-z3 = whatever * (z2-z1) rotated 90;

drawoptions(withcolor .7 white);
draw unitsquare scaled 1/8u rotated angle (z2-z3) shifted z4;
draw unitsquare scaled 1/8u rotated angle (z3-z1) shifted z5;
draw unitsquare scaled 1/8u rotated angle (z1-z2) shifted z6;

drawoptions(withcolor .7 blue);
draw z1--z4;
draw z2--z5;
draw z3--z6;

drawoptions();
draw z1--z2--z3--cycle;

endfig;
end.


Another comparison, with pstricks, and its module pst-eucl: Euler's nine-point circle (adapted from pst-eucl documentation):

    \documentclass[12pt, pdf, x11names]{article}%

\usepackage{pst-eucl}
\usepackage{auto-pst-pdf}

\begin{document}

\psset{unit=2,dotsize = 2pt}
\begin{pspicture}(-3,-1.5)(3,2.5)
\psset{PointSymbol=none}
\pstTriangle(-2,-1){A}(1,2){B}(2,-1){C}
{% local modification of parameters
\psset{linestyle=none, PointSymbolB=none, PointNameB=none}
\pstMediatorAB[PosAngle=180]{A}{B}{K}{KP}
\pstMediatorAB[PosAngle=-140]{C}{A}{J}{JP}
\pstMediatorAB[PosAngle=75]{B}{C}{I}{IP}
}% fin
\pstInterLL[PosAngle=-120]{I}{IP}{J}{JP}{O}
{% local modification of parameters
\psset{nodesep=-.8, linecolor=DarkSeaGreen3}
\pstLineAB{O}{I}\pstLineAB{O}{J}\pstLineAB{O}{K}
}% end
{ \psset{CodeFig, CodeFigColor=LightSteelBlue2, CodeFigStyle=solid, linewidth=0.6pt, RightAngleSize=0.125}
\pstProjection{B}{A}{C}
\pstProjection{B}{C}{A}
\pstProjection{A}{C}{B}}
\pstInterLL{A}{A'}{B}{B'}{H}
% Euler circle (centre is the midpoint of [OH])
\pstMiddleAB[PointSymbol=*, PointName=\omega, PosAngle=0]{O}{H}{omega}
\pstCircleOA[linecolor=Coral2, linestyle=dashed, dash=3.5mm 1.5mm]{omega}{B'}
\psset{PointName=none}
% Passe through the midpoints of the segments joining the orthocentre to vertices
\pstMiddleAB{H}{A}{AH}\pstMiddleAB{H}{B}{BH}\pstMiddleAB{H}{C}{CH}
\psset{linestyle=none}%
\psset{SegmentSymbol=pstslash}\pstSegmentMark{H}{AH}\pstSegmentMark{AH}{A}
\psset{SegmentSymbol=pstslashh}\pstSegmentMark{H}{BH}\pstSegmentMark{BH}{B}
\psset{SegmentSymbol=pstslashhh}\pstSegmentMark{H}{CH}\pstSegmentMark{CH}{C}
\end{pspicture}

\end{document}


6400 × zoom:

• @sergej: Done. I translated the comments into English. Thanks. – Bernard Jul 25 '15 at 9:38