This answer was converted to its own PGF and its own TikZ library ext.transformations.mirror
as part of my tikz-ext
ensions package.
A generalization: We want to mirror at every possible axis.
But first, a few special cases.
Mirroring along an axis parallel to the x or the y (canvas) axis.
This is doable relative easily as seen in the other answers, as we only need to double the shifting and swapping the direction of the orthogonal axis:
\def\pgftransformxmirror#1{%
\pgfmathparse{2*(#1)}%
\pgftransformcm{-1}{0}{0}{1}{\pgfqpoint{+\pgfmathresult pt}{+0pt}}}
\def\pgftransformymirror#1{%
\pgfmathparse{2*(#1)}%
\pgftransformcm{1}{0}{0}{-1}{\pgfqpoint{+0pt}{+\pgfmathresult pt}}}
The TikZ keys xmirror
and ymirror
are wrapper for these PGF macros. They accept
- a dimension (with units) which is directly used as the x or y value.
- a value (without units) which is thrown into
\pgfpointxy
. Note that the transformation is still applied to the canvas system!
- a coordinate wrapped in
( … )
which is evaluated and its x or y value is forwarded to the PGF macros. Note that this also only applies to a transformation of the canvas. Mirroring the coordinate (0, 2)
at (0, 1)
does not necessary lead to the (unmirrored) coordinate (0, 0)
.
Mirroring along an axis through the origin.
The formula for this transformation is taken from Wikipedia’s page Transformation matrix (section Reflection) and is
or in TeX:
\def\pgftransformmirror#1{%
\pgfpointnormalised{#1}%
\pgf@xa=\pgf@sys@tonumber\pgf@y\pgf@x
\pgf@xb=\pgf@sys@tonumber\pgf@x\pgf@x
\pgf@yb=\pgf@sys@tonumber\pgf@y\pgf@y
\multiply\pgf@xa2\relax
\pgf@xc=-\pgf@yb\advance\pgf@xc\pgf@xb
\pgf@yc=-\pgf@xb\advance\pgf@yc\pgf@yb
\edef\pgf@temp{{\the\pgf@xc}{+\the\pgf@xa}{+\the\pgf@xa}{+\the\pgf@yc}}%
\expandafter\pgf@transformcm\pgf@temp{\pgfpointorigin}}
At the start of the definition the point #1
is normalized (that reflects the fraction) and at the end of the calculations
\pgf@xa
holds the normalized value 2lxly,
\pgf@xc
holds the normalized value lx2 – ly2 and
\pgf@yc
holds the normalized value ly2 – lx2.
Finally: Mirroring along any axis.
This formula is loosely based on another Wikipedia article, namely Spiegelungsmatrix (yes, that’s German) and the transformation is reduced to
- shifting to one of the points on the axis,
- mirroring along an axis to the origin and
- shifting the origin back.
The TikZ key mirror
can deal with both the cases “axis through origin” and “any axis”.
If it encounters --
in its argument, the code for any axis is executed, otherwise it is assumed to be a coordinate and the code for an axis through the origin is executed.
Possible Improvements
While the xmirror
and ymirror
cases are very basic simplifcations of the general reflection, the difference between reflection along any axis and an axis through the origin isn’t that big after all, maybe these two cases can be consolidated under one macro.
Using built-in transformations.
In response to Turion's comment, I've also implemented a version that only uses existing transformations (shifting, rotating, −1-scaling, rotating back, shifting back).
The macros and keys for this are available with a capital Mirror
instead of mirror
.
All macros and keys are explained in the respective section of the manual.
Code
\documentclass[tikz]{standalone}
\usetikzlibrary{
backgrounds,
ext.transformations.mirror % https://ctan.org/pkg/tikz-ext
}
\tikzset{every picture/.append style={gridded, line join=round, line cap=round}}
\begin{document}
\begin{tikzpicture}
\draw[thick] (1,1) -- (0,0) -- (1,2);
\draw[ultra thick, red] (2,0) coordinate (@1) -- node[above,sloped] {Mirror} (2,3) coordinate (@2);
\begin{scope}[mirror=(@1)--(@2)]
\draw[thick, blue] (1,1) -- (0,0) -- (1,2);
\path[transform shape] (@1) -- node[above,sloped] {Mirror} (@2);
\end{scope}
\end{tikzpicture}
\begin{tikzpicture}
\draw[thick] (1,1) -- (0,0) -- (1,2);
\draw[ultra thick, red] (2,0) coordinate (@1) -- node[above,sloped] {Mirror} (2,3) coordinate (@2);
\begin{scope}[xmirror=2]
\draw[thick, blue] (1,1) -- (0,0) -- (1,2);
\path[transform shape] (@1) -- node[above,sloped] {Mirror} (@2);
\end{scope}
\end{tikzpicture}
\begin{tikzpicture}\pgfmathsetseed{7}
\draw[thick] (1,1) -- (0,0) -- (1,2);
\draw[ultra thick, red] (5*rand,5*rand) coordinate (@1) -- node[above,sloped] {Mirror} (5*rand,5*rand) coordinate (@2);
\begin{scope}[mirror=(@1)--(@2)]
\draw[thick, blue] (1,1) -- (0,0) -- (1,2);
\path[transform shape] (@1) -- node[above,sloped] {Mirror} (@2);
\end{scope}
\end{tikzpicture}
\end{document}
Output