我需要对属于 tikz-pgf 路径的点进行计算。更具体地说,我想知道有多少个点的 y 坐标超过给定值,并且我想用数字计算路径下方区域的表面(积分)。
或者(或另外):有没有办法评估路径和封闭表面的长度?
答案1
这是一个概念验证集成宏。结果以 pt² 为单位(除以 806.56 可得到 cm²)。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations}
\makeatletter
\def\integrate#1{{
% Use the facilities in the decoration library to break the path into
% simple chunks.
\pgf@decorate@parsesoftpath#1\parsedpath
\gdef\area{0}
\xdef\length{\pgf@decorate@totalpathlength}
\let\pgf@decorate@inputsegmentobject@moveto\relax
\let\pgf@decorate@inputsegmentobject@lineto\tsx@integrate@lineto
\let\pgf@decorate@inputsegmentobject@curveto\tsx@integrate@curveto
\parsedpath
}}
\def\tsx@integrate@lineto#1#2#3{
#2
\pgf@xa\pgf@x
\pgf@ya\pgf@y
#3
\pgf@xb\pgf@x
\pgf@yb\pgf@y
\pgfmathparse{\area + (\the\pgf@xb-\the\pgf@xa)*0.5*(\the\pgf@ya + \the\pgf@yb)}
\xdef\area{\pgfmathresult}
}
\def\tsx@integrate@curveto#1#2#3#4#5{
#2
\pgf@xa\pgf@x
\pgf@ya\pgf@y
#3
\pgf@xb\pgf@x
\pgf@yb\pgf@y
#4
\pgf@xc\pgf@x
\pgf@yc\pgf@y
#5
% Use Green's theorem to calculate the area: ∫_D dA = -∫_{∂D} y dx.
% This probably does not work in all cases.
% Also this has the problem that there are larger numbers in between.
% Probably should use Lua for that.
\pgfmathparse{\area +
% integral over the curve
%(3 Subscript[x, 3] (Subscript[y, 1] + Subscript[y, 2] - 2 Subscript[y, 4]) - 3 Subscript[x, 2] (-2 Subscript[y, 1] + Subscript[y, 3] + Subscript[y, 4]) - Subscript[x, 1] (10 Subscript[y, 1] + 6 Subscript[y, 2] + 3 Subscript[y, 3] + Subscript[y, 4]) + Subscript[x, 4] (Subscript[y, 1] + 3 Subscript[y, 2] + 6 Subscript[y, 3] + 10 Subscript[y, 4]))/20
+(3*\pgf@xc*(\pgf@ya + \pgf@yb -2*\pgf@y) - 3*\pgf@xb*(-2*\pgf@ya + \pgf@yc + \pgf@y) - \pgf@xa*(10*\pgf@ya + 6*\pgf@yb + 3*\pgf@yc + \pgf@y) + \pgf@x*(\pgf@ya + 3*\pgf@yb + 6*\pgf@yc + 10*\pgf@y))/20
% integral over the line between the endpoints
-(\pgf@y*(\pgf@xa - \pgf@x) + 0.5*(\pgf@x-\pgf@xa)*(\pgf@y-\pgf@ya))
% area between that line and the x-axis
-(\pgf@x-\pgf@xa)*0.5*(\pgf@ya + \pgf@y)
}
\xdef\area{\pgfmathresult}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[save path=\mypath] plot[domain=0:1,smooth] (\x,{\x*\x});
\integrate{\mypath}
\show\area
\show\length
\end{tikzpicture}
\end{document}
curvto 积分计算存在方向问题(例如圆的面积为 -r²π;我选择负号来使图上的积分起作用)和较大的中间值(将上述示例积分为 1.1 已经太多了)。
答案2
好的,下面是一些类似于答案的内容。我正在将其中的一些内容作为 TeX-SX 书法包的一部分来实现,该包涉及操纵软路径,并且我已经开始将软路径操纵分离到其自己的包文件中。这里似乎是记录这一点的最佳地点!
相关文件spath.dtx
可从TeX-SX 包项目。该文件也很有用,spath_test.tex
因为我还没有写任何文档!要生成样式文件,请运行tex spath.dtx
(如果有任何文档,您可以从中获取pdflatex spath.dtx
)。
这是一种面向对象的方法,使用与 PGF 捆绑在一起的 Till Tantau 的 OO 实现(因此您可能需要最新版本的 PGF 才能使其工作)。以下是一些示例代码:
\documentclass{article}
\usepackage{tikz}
\usepackage{spath}
\begin{document}
\begin{tikzpicture}
\path[save path=\tmppath] (0,0) -- (1,1) (2,1) .. controls (3,1) and (4,2) .. (5,2);
\show\tmppath
\pgfoonew \mypath =new spath(\tmppath)
\mypath.show(path)
\mypath.length()
\mypath.initial point()
\mypath.show(initial point)
\mypath.final point()
\mypath.show(final point)
\mypath.show(length)
\mypath.translate path(\trpath,1cm,1cm)
\mypath.show(path)
\trpath.show(path)
\mypath.concatenate(\catpath,\trpath)
\catpath.show(path)
\mypath.weld(,\trpath)
\mypath.show(path)
\mypath.use path with tikz(draw,red,line width=.5cm)
\mypath.use path(stroke)
\end{tikzpicture}
\end{document}
我们首先使用常规 TikZ 命令定义一条路径并将其保存为\tmppath
。然后我们定义该类的新实例spath
并用 对其进行初始化\tmppath
。在最终使用它之前,我们对它进行各种操作,并找出一些有关它的事实。最后两个,\mypath.use path with tikz(options)
和\mypath.use path
,是实际的渲染命令。第一个使用与 TikZ 相同的方法来渲染路径,因此可以采用任何 TikZ 选项(我不能 100% 保证它们都能正常工作,但它们应该可以)。第二个使用底层 PGF 系统,因此采用基本选项之一:stroke
或fill
。
这实际上不能作为您问题的答案,因为您要求的任何事情都没有实现(请注意,这length
是指软路径中的命令数量,而不是路径长度)。但将两个已经给出的答案中的任何一个适应此设置并不难。它做不过,请回答评论中有关重复使用路径的问题。
答案3
作为我自己的问题的部分答案,这里有一个简单的宏,允许人们使用路径名机制对先前保存的路径上的点执行给定的操作。
\makeatletter
\def\everypathpoint#1#2{%
\begingroup
\expandafter\let\expandafter\pgfsyssoftpath@movetotoken\csname #2\endcsname
\expandafter\let\expandafter\pgfsyssoftpath@linetotoken\csname #2\endcsname
\expandafter\show\csname #2\endcsname
\@nameuse{tikz@intersect@path@name@#1}%
\endgroup
}%
\makeatother
例如,此宏可以与代码一起使用
\newcount\mycount
\mycount=0
\def\myaction#1#2{\ifdim #2>0.5cm\global\advance\mycount by 1\fi}%
\draw[thick, name path=f] plot (\x, \y{\x});
\everypathpoint{f}{myaction}%
此代码仅计算路径中给定值以上的点数,但允许任何其他操作(包括面积计算)。路径可以包含的元素数量还有待观察(我敢打赌,比我在这里考虑的最小元素 moveto 和 lineto 要多)。