# Length, surface, and coordinates of a tikz-pgf path

I need to perform computations on the points that belong to a tikz-pgf path. More specifically, I want to know how many points have a y coordinate exceeding a given value, and I want to calculate numerically the surface (integral) of the area below the path.

Alternatively (or additionally): is there a way to evaluate the length of a path and the enclosed surface?

-
When defining a decoration, there is a macro that stores the length of the path. So there is some code in TikZ that can calculate the length of a path. However, I do not know how to access it outside of a decoration definition. – Caramdir Jun 6 '11 at 20:34
What do you think of as being a tikz-pgf path? Can you give a pseudo-code of what you would like to be able to do? – Loop Space Jun 6 '11 at 20:41
@Caramdir: interesting... I also noted that I can save a path with the intersection name path option: I get a macro called \tikz@intersect@path@name@<name>, but then using this information is not trivial at all... – Marco Lombardi Jun 6 '11 at 20:42
@Marco: you can save the internal representation of the path, is that what you mean? \path[save path=\mypath] path-construction; will do that. Then you can reuse it as you like. As part of my calligraphy package, I'm currently writing a set of routines that will manipulate these paths (such as translating them or reversing them). But the best way to save it depends on how you want to use it, which is why I asked for pseudo-code. – Loop Space Jun 6 '11 at 21:17
@Marco: No, save path is not documented. I only learnt about it from searching through the TikZ/PGF code for examples of \pgfsyssoftpath@getcurrentpath (which is documented). To use the path with the normal TikZ options, you would need to write a wrapper macro. But that wouldn't be very hard to do. I'll have a go later today if I get a moment. – Loop Space Jun 7 '11 at 6:54

Here is a proof-of-concept integration macro. The results are given in pt² (divide by 806.56 to get 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}


The curvto integration calculation has an issue with orientations (for example the area of a circle comes out as -r²π; I chose the negative sign to make integrals over plots work) and large intermediate values (integrating the above example to 1.1 is already too much).

-
I wrote a LuaTeX-implementation of the code. It can (currently) be found at bazaar.launchpad.net/~tex-sx/tex-sx/development/view/head:/…. – Caramdir Jun 8 '11 at 4:29

Right, here's something along the lines of an answer. I was implementing some of this stuff as part of the TeX-SX calligraphy package that involved manipulating soft paths and I'd begun spinning off the soft path manipulation into its own package file anyway. Here seems as good a place to record that as any!

The relevant file is spath.dtx and is available from the TeX-SX package project. Also useful is the file spath_test.tex because I haven't written any documentation yet! To produce the style file, run tex spath.dtx (if there were any documentation you'd get that from pdflatex spath.dtx).

It's an object-oriented approach, using Till Tantau's OO implementation that is bundled with PGF (so you might need the most recent version of PGF for it to work). Here's some sample code:

\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}


We begin by defining a path using normal TikZ commands and saving it as \tmppath. Then we define a new instance of the spath class and initialise it with \tmppath. We do various manipulations on it, and find out some facts about it, before finally using it. The last two, \mypath.use path with tikz(options) and \mypath.use path, are the actual rendering commands. The first uses the same methods as TikZ for rendering the path so can take any TikZ options (I don't guarantee 100% that they will all work, but they should). The second uses the underlying PGF system so takes one of the basic options: stroke or fill.

This doesn't really qualify as an answer to your question as none of the things that you ask for are implemented (note that length refers to the number of commands in the soft path, not the path length). But it wouldn't be hard to adapt either of the two already-given answers to this setting. It does answer the question in the comments about reusing a path, though.

-
Great, the commands you mention are indeed very useful to manipulate paths, something that I missed from TikZ. Are you thinking of adding them to TikZ development too? It would be useful to have them integrated in this system. – Marco Lombardi Jun 8 '11 at 13:07

As a partial answer to my own question, here is a simple macro that allows one to perform a given operation on the points of a path previously saved using the path name mechanism.

\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


This macro could be used, for example, together with the code

  \newcount\mycount
\mycount=0