我想在庞加莱圆盘模型用于双曲几何。tikz 是否有内置或附加包可以实现这一点?例如,如果有用于绘制的函数就好了萨凯里四边形或者兰伯特四边形或渐近三角形。
(在我迄今为止的短暂使用中,tkz-euclide这个包对于欧几里得几何来说看起来非常好,现在我正在寻找它的双曲类似物。)
答案1
这是另一个 TikZ 解决方案。给定庞加莱平面或圆盘上的两个点,它会在它们之间绘制测地线。它通过定义一条(复杂的!)to
路径来实现这一点,该路径计算出圆和角度,然后绘制正确的圆弧。它有一些基本的错误检查,看看它是否应该画一条直线,但它会检查精确的条件而不是在 TeX 的精度范围内,所以如果你的点几乎一个在另一个之上(或者在相同的半径上),以至于测地线在所有意图和目的上都是直的,那么这个代码可能无法及时检测到,最终除以比它应该更小的东西(事实上,我必须小心如何分解计算,因为有些方法在部分阶段给出了大数字)。
\documentclass{article}
%\url{https://tex.stackexchange.com/a/19168/86}
\thispagestyle{empty}
\usepackage{tikz}
\usetikzlibrary{calc}
\makeatletter
\def\hyper@x#1,#2\relax{#1}
\def\hyper@y#1,#2\relax{#2}
\def\hyper@coords#1{#1}
\newif\ifhyper@vertical
\def\hyper@computer#1#2{%
\edef\hyper@toscan{(#1)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@sx{\the\pgf@x}
\edef\hyper@sy{\the\pgf@y}
\edef\hyper@toscan{(#2)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@ex{\the\pgf@x}
\edef\hyper@ey{\the\pgf@y}
\pgfmathsetmacro{\hyper@mx}{(\hyper@ex + \hyper@sx)/2}
\pgfmathsetmacro{\hyper@my}{(\hyper@ey + \hyper@sy)/2}
\pgfmathsetmacro{\hyper@dx}{\hyper@ex - \hyper@sx}
\pgfmathparse{\hyper@dx == 0 ? "\noexpand\hyper@verticaltrue" : "\noexpand\hyper@verticalfalse"}
\pgfmathresult
\ifhyper@vertical
\edef\hyper@cmd{-- (\tikztotarget)}
\else
\pgfmathsetmacro{\hyper@dy}{\hyper@ey - \hyper@sy}
\pgfmathsetmacro{\hyper@t}{\hyper@my/\hyper@dx}
\pgfmathsetmacro{\hyper@cx}{\hyper@mx + \hyper@t * \hyper@dy}
\pgfmathsetmacro{\hyper@radius}{veclen(\hyper@cx - \hyper@sx, \hyper@sy)}
\pgfmathsetmacro{\hyper@sangle}{180 - atan2(\hyper@sy,\hyper@cx-\hyper@sx)}
\pgfmathsetmacro{\hyper@eangle}{180 - atan2(\hyper@ey,\hyper@cx-\hyper@ex)}
\edef\hyper@cmd{arc[radius=\hyper@radius pt, start angle=\hyper@sangle, end angle=\hyper@eangle]}
\fi
}
\def\hyper@disc@computer#1#2{%
\edef\hyper@toscan{(#1)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@sx{\the\pgf@x}
\edef\hyper@sy{\the\pgf@y}
\edef\hyper@toscan{(#2)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@ex{\the\pgf@x}
\edef\hyper@ey{\the\pgf@y}
\pgfmathsetmacro{\hyper@det}{\hyper@sx * \hyper@ey - \hyper@sy * \hyper@ex}
\pgfmathparse{\hyper@det == 0 ? "\noexpand\hyper@verticaltrue" : "\noexpand\hyper@verticalfalse"}
\pgfmathresult
\ifhyper@vertical
\edef\hyper@cmd{-- (\tikztotarget)}
\else
\pgfmathsetmacro{\hyper@mx}{(\hyper@ex + \hyper@sx)/2}
\pgfmathsetmacro{\hyper@my}{(\hyper@ey + \hyper@sy)/2}
\pgfmathsetmacro{\hyper@dx}{\hyper@ex - \hyper@sx}
\pgfmathsetmacro{\hyper@dy}{\hyper@ey - \hyper@sy}
\pgfmathsetmacro{\hyper@dradius}{\pgfkeysvalueof{/tikz/hyperbolic disc radius}}
\pgfmathsetmacro{\hyper@t}{((\hyper@dradius)^2 - \hyper@sx * \hyper@ex - \hyper@sy * \hyper@ey)/(2 * (\hyper@sx * \hyper@ey - \hyper@sy * \hyper@ex))}
\pgfmathsetmacro{\hyper@radius}{sqrt((\hyper@t)^2 + .25) * veclen(\hyper@dx,\hyper@dy)}
\pgfmathsetmacro{\hyper@cx}{\hyper@mx + \hyper@t * \hyper@dy}
\pgfmathsetmacro{\hyper@cy}{\hyper@my - \hyper@t * \hyper@dx}
\pgfmathsetmacro{\hyper@sangle}{atan2(\hyper@sy-\hyper@cy,\hyper@sx - \hyper@cx)}
\pgfmathsetmacro{\hyper@eangle}{atan2(\hyper@ey-\hyper@cy,\hyper@ex - \hyper@cx)}
\pgfmathsetmacro{\hyper@eangle}{\hyper@eangle > \hyper@sangle + 180 ? \hyper@eangle - 360 : \hyper@eangle}
\edef\hyper@cmd{arc[radius=\hyper@radius pt, start angle=\hyper@sangle, end angle=\hyper@eangle]}
\fi
}
\def\hyper@plane@tangent#1#2{%
\edef\hyper@toscan{(#1)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@sx{\the\pgf@x}
\edef\hyper@sy{\the\pgf@y}
\edef\hyper@toscan{(#2)}
\tikz@scan@one@point\hyper@coords\hyper@toscan
\edef\hyper@ex{\the\pgf@x}
\edef\hyper@ey{\the\pgf@y}
% The difference between the end and start defines the tangent
% vector
\pgfmathsetmacro{\hyper@ex}{\hyper@ex - \hyper@sx}
\pgfmathsetmacro{\hyper@ey}{\hyper@ey - \hyper@sy}
% If we're straight up ...
\pgfmathparse{\hyper@ex == 0 ? "\noexpand\hyper@verticaltrue" : "\noexpand\hyper@verticalfalse"}
\pgfmathresult
\ifhyper@vertical
% Need to set length here, rescale to cm first
% User \hyper@ey here as that remembers the sign
\pgfmathsetmacro{\hyper@d}{\hyper@ey/1cm}
\pgfmathsetmacro{\hyper@radius}{\hyper@sy * exp(\hyper@d) - \hyper@sy}
\edef\hyper@cmd{-- ++(0,\hyper@radius pt)}
\else
% Set length
\pgfmathsetmacro{\hyper@d}{\hyper@ex > 0 ? veclen(\hyper@ex,\hyper@ey) : -veclen(\hyper@ex,\hyper@ey)}
% Radius of arc
\pgfmathsetmacro{\hyper@radius}{abs(\hyper@sy * \hyper@d / \hyper@ex)}
% Starting angle
\pgfmathsetmacro{\hyper@sangle}{90 + atan(\hyper@ey/\hyper@ex)}
% Ending angle, check if given
\pgfkeysgetvalue{/tikz/hyperbolic plane target angle}{\hyper@eangle}
\ifx\hyper@eangle\pgfutil@empty
% rescale into cm to avoid Big Numbers
\pgfmathsetmacro{\hyper@d}{\hyper@d/1cm}
\pgfmathsetmacro{\hyper@ey}{\hyper@ey/1cm}
\pgfmathsetmacro{\hyper@tanhd}{tanh(\hyper@d)}
\pgfmathsetmacro{\hyper@eangle}{acos((\hyper@d * \hyper@tanhd - \hyper@ey)/(\hyper@d - \hyper@ey * \hyper@tanhd))}
%
\fi
\edef\hyper@cmd{arc[radius=\hyper@radius pt, start angle=\hyper@sangle, end angle=\hyper@eangle]}
\fi
}
\tikzset{%
hyperbolic disc radius/.initial={1cm},
hyperbolic plane/.style={
to path={
\pgfextra{\hyper@computer\tikztostart\tikztotarget}
\hyper@cmd
}
},
hyperbolic plane tangent/.style={
to path={
\pgfextra{\hyper@plane@tangent\tikztostart\tikztotarget}
\hyper@cmd
}
},
hyperbolic disc/.style={
to path={
\pgfextra{\hyper@disc@computer\tikztostart\tikztotarget}
\hyper@cmd
}
},
hyperbolic plane target angle/.initial={},
}
\makeatother
\begin{document}
\begin{tikzpicture}[every to/.style={hyperbolic plane}]
\fill[blue] (0,1) \foreach \k in {0,...,7} { to ++(\k * 45:2)};
\coordinate (b) at (1,2);
\coordinate (a) at (3,4);
\fill (a) circle[radius=2pt];
\fill (b) circle[radius=2pt];
\draw (-2,0) -- (6,0);
\draw (a) to (b);
\end{tikzpicture}
\begin{tikzpicture}[hyperbolic disc radius=2cm,
every to/.style={hyperbolic disc}]
\draw (0,0) circle[radius=\pgfkeysvalueof{/tikz/hyperbolic disc radius}];
\pgfmathsetmacro{\hyperrad}{1/(2*sin(22.5))}
\fill[blue] (-112.5:\hyperrad) \foreach \k in {0,...,7} { to ++(\k * 45:1)};
\coordinate (b) at (1.2,.3);
\coordinate (a) at (.8,-.4);
\fill (a) circle[radius=2pt];
\fill (b) circle[radius=2pt];
\draw (a) to (b);
\end{tikzpicture}
\begin{tikzpicture}[every to/.style={hyperbolic plane tangent}]
\draw (1,2) circle[radius=2pt] to ++(1,1) circle[radius=4pt];
\draw[red] (-1,2) circle[radius=2pt] to[hyperbolic plane target angle=0] ++(-60:2) circle[radius=4pt];
\draw (0,1) circle[radius=2pt] \foreach \k in {0,...,7} { to ++(\k * 45:1)};
\draw[thick,gray,<->] let \p{east}=(current bounding box.east), \p{west}=(current bounding box.west) in (\x{east},0) -- (\x{west},0);
\end{tikzpicture}
\end{document}
结果:
一个不错的扩展是能够从某个点开始沿特定方向绘制一条特定长度的圆弧。这是欧几里得的双曲版本\draw (1,0) -- ++(45:2);
。
答案2
这是非常基本的解决方案。它完成了(部分)工作。从示例中可以看出,的用法\hgline
显而易见。欢迎提出改进建议。
\documentclass[]{minimal}
\usepackage{tikz}
\begin{document}
\newcommand{\hgline}[2]{
\pgfmathsetmacro{\thetaone}{#1}
\pgfmathsetmacro{\thetatwo}{#2}
\pgfmathsetmacro{\theta}{(\thetaone+\thetatwo)/2}
\pgfmathsetmacro{\phi}{abs(\thetaone-\thetatwo)/2}
\pgfmathsetmacro{\close}{less(abs(\phi-90),0.0001)}
\ifdim \close pt = 1pt
\draw[blue] (\theta+180:1) -- (\theta:1);
\else
\pgfmathsetmacro{\R}{tan(\phi)}
\pgfmathsetmacro{\distance}{sqrt(1+\R^2)}
\draw[blue] (\theta:\distance) circle (\R);
\fi
}
\begin{tikzpicture}
\draw (0,0) circle (1);
\clip (0,0) circle (1);
\hgline{30}{-30}
\hgline{180}{270}
\hgline{30}{120}
\hgline{0}{180}
\end{tikzpicture}
\end{document}
结果是
答案3
tkz-euklide
下面是通过两个给定点绘制双曲线的示例:
\documentclass{article}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}[scale=3]
\tkzDefPoint(0,0){O}
\tkzDefPoint(1,0){A}
\tkzDrawCircle(O,A)
\tkzDefPoint(0.3,-0.25){z1}
\tkzDefPoint(-0.5,-0.5){z2}
\tkzClipCircle(O,A)
\tkzDefCircle[orthogonal through=z1 and z2](O,A)
\tkzGetPoints{G}{g}
\tkzDrawCircle(G,g)
\tkzDrawPoints[color=black,fill=red,size=12](z1,z2)
\tkzLabelPoints(z1,z2)
\end{tikzpicture}
\end{document}
结果如下:
答案4
可能不是。我在 Google 上搜索了“latex 双曲几何”,搜索结果最多的就是这个页面。有很多关于用 latex 编写的双曲几何的论文,但我没有找到双曲几何的软件包。
但我认为,如果足够努力,这些事情可以在 TikZ 中实现。