目标
我想绘制中心不被某些路径剪裁的完整节点。
该解决方案如何可能发挥作用?
为了更好地理解,我将分两个步骤来描述:
- 绘制前裁剪——“修剪”每个中心超出范围的节点,
- 绘制完整节点(其中心不被路径剪切),即没有任何剪切。
这可能吗?
问题的底部有两页文档,第一页是正常剪辑,第二页是我想要实现的(但需要手动剪辑 - 在这种情况下很容易,但通常并不简单,所以显示的代码显然不是我想要的)。
分解
值得补充的是,该问题可以分解为:
- 多边形近似(针对非多边形路径),
- 多边形中的点问题。
这里的关键是能够迭代路径中的点和曲线。我在手册中寻找它,但没有找到多少运气(或者,像往常一样,我搜索错了)。
例子
\documentclass{minimal}
\usepackage[utf8]{inputenc}
\usepackage[paperwidth=6.25cm,paperheight=6.25cm,margin=0pt]{geometry}
\usepackage{ifthen}
\usepackage{tikz}
\begin{document}
\parindent=0pt
\pagestyle{empty}
\begin{tikzpicture}[remember picture,overlay]
\node at (current page.center) {%
\begin{tikzpicture}[overlay]
\clip[draw] (0.35,0) circle (3.45);
\foreach \y in {-3,-2,...,3}
\foreach \x in {-3,-2,...,3} {
\node[draw] at (\x,\y) {};
\draw[fill] (\x,\y) circle (0.1pt);
}
\end{tikzpicture}
};
\end{tikzpicture}
\newpage
\begin{tikzpicture}[remember picture,overlay]
\node at (current page.center) {%
\begin{tikzpicture}[overlay]
\draw (0.35,0) circle (3.45);
\foreach \y in {-3,-2,...,3}
\foreach \x in {-3,-2,...,3} {
\pgfmathsetmacro{\radiusc}{3.45^2 - (\x - 0.35)^2 - (\y - 0)^2}
\ifthenelse{\lengthtest{\radiusc pt>0pt}\OR\lengthtest{\radiusc pt=0pt}}{
\node[draw] at (\x,\y) {};
\draw[fill] (\x,\y) circle (0.1pt);
}{}
}
\end{tikzpicture}
};
\end{tikzpicture}
\end{document}
答案1
这是一个原型。困难在于(据我所知)裁剪根本不由 TeX 处理,而是由最终的文档格式完成的(因此实际上由文档查看器完成)。因此,如果通过通常的方式进行裁剪,TeX 不知道哪些会被裁剪,哪些不会被裁剪,因此无法使用该信息。这意味着我们必须模拟裁剪。为此,我使用了库。intersections
这个想法是,如果我们有一条封闭的路径,那么如果一条射线从该点开始并以“无穷大”结束,与该路径相交的次数为奇数,则该点位于该路径内。这并非 100% 准确:切线是有问题的,就像“无穷大”一样。因此,我们希望“无穷大”是“很远很远”的,并且我们希望通过某种方式选择射线以避免切线。我将“很远很远”设置为 10 厘米(尽管这很容易修改),对于射线,我已将其设置为您(用户)选择某个“中心点”,然后如果继续沿正确的方向前进,所有射线都会通过该点。通过改变该点,应该可以找到一个(对于有限数量的节点)避免所有切线的点。
最后一个问题是如何实现是否应该绘制节点的决定。这很困难,因为如果我们已经在处理节点,那么转过身说“实际上,忘掉它”就有点棘手了。设置了太多不同的组和事物,我很难弄清楚如何取消和关闭它们。相反,我放置了一个命令,它\ifinside
看起来好像需要两个参数。第一个是要考虑的坐标,第二个是如果坐标在剪切路径内(也可以很容易地有一个\ifoutside
)要包含的代码。作为奖励,坐标保留为“当前坐标”,因此不必在参数中重新指定它。(这也可以修改,而且我认为考虑的坐标是最后提到的坐标的变体会很有用。)
综合以上内容,我们得到以下代码:
\documentclass{article}
%\url{}
\usepackage{tikz}
\usetikzlibrary{intersections,calc}
\makeatletter
\newdimen\clipper@sx
\newdimen\clipper@sy
\newdimen\clipper@ex
\newdimen\clipper@ey
\newdimen\clipper@len
\def\ifinside#1{%
\pgfextra{%
\tikz@scan@one@point\pgfutil@firstofone#1
\clipper@sx=\pgf@x\relax
\clipper@sy=\pgf@y\relax
\pgfmathsetlength{\clipper@ex}{(\clipper@sx - \pgfkeysvalueof{/tikz/clipper/centre point x})}%
\pgfmathsetlength{\clipper@ey}{(\clipper@sy - \pgfkeysvalueof{/tikz/clipper/centre point y})}%
\pgfmathsetlength{\clipper@len}{veclen(\clipper@ex,\clipper@ey)}%
\pgfmathsetlength{\clipper@ex}{\clipper@sx + 10cm / \clipper@len * \clipper@ex}%
\pgfmathsetlength{\clipper@ey}{\clipper@sy + 10cm / \clipper@len * \clipper@ey}%
\edef\tikz@intersect@path@name@radius{\noexpand\pgfsyssoftpath@movetotoken{\the\clipper@sx}{\the\clipper@sy}\noexpand\pgfsyssoftpath@linetotoken{\the\clipper@ex}{\the\clipper@ey}}%
\tikzset{name intersections={of=clipper@path and radius, total=\clipper@total}}%
\ifodd\clipper@total
\let\clipper@next=\pgfutil@firstofone
\else
\let\clipper@next=\pgfutil@gobble
\fi
\tikz@lastx=\clipper@sx
\tikz@lasty=\clipper@sy
}\clipper@next%
}
\tikzset{
clipper/.style={
name path=clipper@path,
set clipper centre={#1},
},
clipper/centre point x/.initial={0.1},
clipper/centre point y/.initial={0.1},
set clipper centre/.code={%
\def\clipper@temp{#1}%
\ifx\clipper@temp\pgfutil@empty
\else
\tikz@scan@one@point\pgfutil@firstofone#1%
\edef\tikz@marshal{\noexpand\tikzset{%
clipper/centre point x=\the\pgf@x,
clipper/centre point y=\the\pgf@y,
}}%
\tikz@marshal
\fi
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[red,thick,clipper={(0.1,0.1)}] (0,0) circle[radius=3cm];
\foreach \nx in {-4,-3.5,...,4} {
\foreach \ny in {-4,-3.5,...,4} {
\fill[green] (\nx,\ny) circle[radius=1pt];
\path \ifinside{(\nx,\ny)}{node[draw] {a}};
}
}
\end{tikzpicture}
\end{document}
结果:
我没有严格测试过,但这个理论没有错!而且,慢的。但接下来必须以合理的准确度来完成这一任务。