如何使用 Tikz 绘制(和绘制)平面中一系列点的 Voronoi 区域?如果这些点在 3D 空间中怎么办?
答案1
这是使用 TikZ 的一个解决方案。
\documentclass[preview, border=7mm]{standalone}
\usepackage{xinttools} % for the \xintFor***
\usepackage{tikz}
\usetikzlibrary{calc}
\def\biglen{20cm} % playing role of infinity (should be < .25\maxdimen)
% define the "half plane" to be clipped (#1 = half the distance between cells)
\tikzset{
half plane/.style={ to path={
($(\tikztostart)!.5!(\tikztotarget)!#1!(\tikztotarget)!\biglen!90:(\tikztotarget)$)
-- ($(\tikztostart)!.5!(\tikztotarget)!#1!(\tikztotarget)!\biglen!-90:(\tikztotarget)$)
-- ([turn]0,2*\biglen) -- ([turn]0,2*\biglen) -- cycle}},
half plane/.default={1pt}
}
\def\n{23} % number of random points
\def\maxxy{4} % random points are in [-\maxxy,\maxxy]x[-\maxxy,\maxxy]
\begin{document}
\begin{tikzpicture}
% generate random points
\pgfmathsetseed{1908} % init random with the year Voronoi published his paper ;)
\def\pts{}
\xintFor* #1 in {\xintSeq {1}{\n}} \do{
\pgfmathsetmacro{\ptx}{.9*\maxxy*rand} % random x in [-.9\maxxy,.9\maxxy]
\pgfmathsetmacro{\pty}{.9*\maxxy*rand} % random y in [-.9\maxxy,.9\maxxy]
\edef\pts{\pts, (\ptx,\pty)} % stock the random point
}
% draw the points and their cells
\xintForpair #1#2 in \pts \do{
\edef\pta{#1,#2}
\begin{scope}
\xintForpair \#3#4 in \pts \do{
\edef\ptb{#3,#4}
\ifx\pta\ptb\relax % check if (#1,#2) == (#3,#4) ?
\tikzstyle{myclip}=[];
\else
\tikzstyle{myclip}=[clip];
\fi;
\path[myclip] (#3,#4) to[half plane] (#1,#2);
}
\clip (-\maxxy,-\maxxy) rectangle (\maxxy,\maxxy); % last clip
\pgfmathsetmacro{\randhue}{rnd}
\definecolor{randcolor}{hsb}{\randhue,.5,1}
\fill[randcolor] (#1,#2) circle (4*\biglen); % fill the cell with random color
\fill[draw=red,very thick] (#1,#2) circle (1.4pt); % and draw the point
\end{scope}
}
\pgfresetboundingbox
\draw (-\maxxy,-\maxxy) rectangle (\maxxy,\maxxy);
\end{tikzpicture}
\end{document}
关于代码的一些评论:
- 给定两点 A 和 B,靠近 A 的点构成一个半平面,由垂直平分线,且含有 A。
- 因此,为了构建 A 的 Voronoi 单元,我们可以在 B 经过所有其他点(不同于 A)时取所有半平面的交点。
- 在代码中,通过剪切充当“半平面”角色的大矩形来实现此交点。
- 我无法使用,
\foreach
因为在这样的循环内进行剪辑在循环外不可用(\foreach
创建一个组)。所以我通过使用来克服这个问题\xintFor
。