use zlib compression for fonts
[PyX/mjg.git] / manual / graphics.tex
blob2bb3220fa215f4fa818bf07bbe86106697f0798c
1 \chapter{Basic graphics}
3 \sectionauthor{J\"org Lehmann}{joergl@users.sourceforge.net}
5 \label{graphics}
7 \section{Introduction}
9 The path module allows one to construct PostScript-like
10 \textit{paths}, which are one of the main building blocks for the
11 generation of drawings. A PostScript path is an arbitrary shape built
12 up of straight lines, arc segments and cubic Bezier curves. Such a
13 path does not have to be connected but may also consist of multiple
14 connected segments, which will be called \textit{sub paths} in the
15 following.
17 Usually, a path is constructed by passing a list of the path
18 primitives \class{moveto}, \class{lineto}, \class{curveto}, etc., to the
19 constructor of the \class{path} class. The following code snippet, for
20 instance, defines a path \var{p} that consists of a straight line
21 from the point $(0, 0)$ to the point $(1, 1)$
22 \begin{verbatim}
23 from pyx import *
24 p = path.path(path.moveto(0, 0), path.lineto(1, 1))
25 \end{verbatim}
26 Equivalently, one can also use the predefined \class{path} subclass
27 \class{line} and write
28 \begin{verbatim}
29 p = path.line(0, 0, 1, 1)
30 \end{verbatim}
32 While you can already do some geometrical operations with the
33 just created path (see next section), we need another \PyX{} object
34 in order to be actually able to draw the path, namely
35 an instance of the \class{canvas} class. By convention, we use
36 the name \var{c} for this instance:
37 \begin{verbatim}
38 c = canvas.canvas()
39 \end{verbatim}
40 In order to draw the path on the canvas, we use the \method{stroke()} method
41 of the \class{canvas} class, i.e.,
42 \begin{verbatim}
43 c.stroke(p)
44 c.writeEPSfile("line")
45 \end{verbatim}
46 To complete the example, we have added a \method{writeEPSfile()} call,
47 which writes the contents of the canvas into the given file.
49 Let us as second example define a path which consists of more than
50 one sub path:
51 \begin{verbatim}
52 cross = path.path(path.moveto(0, 0), path.rlineto(1, 1),
53 path.moveto(1, 0), path.rlineto(-1, 1))
54 \end{verbatim}
55 The first sub path is again a straight line from $(0, 0)$ to $(1, 1)$,
56 with the only difference that we now have used the \class{rlineto}
57 class, whose arguments count relative from the last point in the path.
58 The second \class{moveto} instance opens a new sub path starting at the
59 point $(1, 0)$ and ending at $(0, 1)$. Note that although both lines
60 intersect at the point $(1/2, 1/2)$, they count as separate sub paths.
61 The general rule is that each occurence of \class{moveto} opens a new
62 sub path. This means that if one wants to draw a rectangle, one should
63 not use
64 \begin{verbatim}
65 # wrong: do not use moveto when you want a single sub path
66 rect1 = path.path(path.moveto(0, 0), path.lineto(0, 1),
67 path.moveto(1, 0), path.lineto(1, 1),
68 path.moveto(1, 1), path.lineto(1, 1),
69 path.moveto(0, 1), path.lineto(0, 0))
70 \end{verbatim}
71 which would construct a rectangle consisting of four disconnected
72 sub paths. Instead the correct way of defining a rectangle is
73 \begin{verbatim}
74 # correct: a rectangle consisting of a single closed sub path
75 rect2 = path.path(path.moveto(0, 0), path.lineto(0, 1),
76 path.lineto(1, 1), path.lineto(1, 0),
77 path.closepath())
78 \end{verbatim}
80 \begin{figure}
81 \centerline{\includegraphics{rects}}
82 \caption{Not closed (left) and closed (midlle) rectangle. Filling a
83 path (right) always closes it automatically.}
84 \label{fig:rects}
85 \end{figure}
86 Note that for the last straight line of the rectangle (from $(0, 1)$
87 back to the origin at $(0, 0)$)) we have used \class{closepath}. This
88 directive adds a straight line from the current point to the first
89 point of the current sub path and furthermore \textit{closes} the sub
90 path, i.e., it joins the beginning and the end of the line segment.
91 The difference can be appreciated in Fig.~\ref{fig:rects}, where
92 also a filled (and at the same time stroked) rectangle is shown.
93 The corresponding code looks like
94 \begin{verbatim}
95 c.stroke(rect1, [deco.filled([color.grey(0.95)])])
96 \end{verbatim}
97 The important point to remember here is that when filling a path,
98 PostScript automatically closes it. More details on the available
99 path elements can be found in Sect.~\ref{path:pathel}.
101 XXX more on styles and attributes and reference to corresponding section
103 Of course, rectangles are also predefined in \PyX{}, so above we could
104 have as well written
105 \begin{verbatim}
106 rect2 = path.rect(0, 0, 1, 1)
107 \end{verbatim}
108 Here, the first two arguments specify the origin of the rectangle
109 while the second two arguments define its width and height,
110 respectively. For more details on the predefined paths, we
111 refer the reader to Sect.~\ref{path:predefined}.
113 \section{Path operations}
115 Often, one not only wants to stroke or fill a path on the canvas
116 but before do some geometrical operations with it. For instance, one
117 might want to intersect one path with another one and the split the
118 paths at the intersection points and then join the segments together
119 in a new way. \PyX{} supports such tasks by means of a number
120 of path methods, which we will introduce in the following.
122 Suppose you want to draw the radii to the intersection points of a
123 circle with a straight line. This task can be done using the following
124 code which gives the result shown in Fig.~\ref{fig:radii}
125 \verbatiminput{radii.py}
126 \begin{figure}
127 \centerline{\includegraphics{radii}}
128 %\caption{}
129 \label{fig:radii}
130 \end{figure}
131 Passing another path, here \var{line}, to the \method{intersect()} method
132 of \var{circle}, we obtain a tuple of parameter values of the
133 intersection points. The first element of the tuple is a list of
134 parameter values for the path whose \method{intersect()} method we have
135 called, the second element is the corresponding list for the path
136 passed as argument to this method. In the present example, we only
137 need one list of parameter values, namely \var{isects_circle}.
138 Iterating over the elements of this list, we draw the radii, using the
139 \method{at()} path method to obtain the point corresponding to the
140 parameter value.
142 Another powerful feature of \PyX{} is its ability to split paths at a
143 given set of parameters. For instance, in order to fill in the
144 previous example the segment of the circle delimited by the straight
145 line (cf.\ Fig.~\ref{fig:radii2}), you first have to construct a path
146 corresponding to the outline of this segment. The following code
147 snippet does yield this \var{segment}
148 \begin{verbatim}
149 arc1, arc2 = circle.split(isects_circle)
150 arc = arc1.arclen()<arc2.arclen() and arc1 or arc2
152 isects_line.sort()
153 line1, line2, line3 = line.split(isects_line)
155 segment = line2 << arc
156 \end{verbatim}
157 \begin{figure}
158 \centerline{\includegraphics{radii2}}
159 %\caption{}
160 \label{fig:radii2}
161 \end{figure}
162 Here, we first split the circle using the \method{split()} method passing
163 the list of parameters obtained above. Since the circle is closed,
164 this yields two arc segments. We then use the \method{arclen()}, which
165 returns the arc length of the path, to find the shorter of the two
166 arcs. Before splitting the line, we have to take into account that
167 the \method{split()} method only accepts a sorted list of parameters.
168 Finally, we join the straight line and the arc segment. For
169 this, we make use of the \verb|<<| operator, which not only adds
170 the paths (which could be done using \samp{line2 + arc}), but also
171 joins the last sub path of \var{line2} and the first one of
172 \var{arc}. Thus, \var{segment} consists of only a single sub path
173 and filling works as expected.
175 An important issue when operating on paths is the parametrisation
176 used. Internally, \PyX{} uses a parametrisation which uses an interval
177 of length $1$ for each path element of a path. For instance, for a
178 simple straight line, the possible parameter values range from $0$ to
179 $1$, corresponding to the first and last point, respectively, of the
180 line. Appending another straight line, would extend this range to a
181 maximal value of $2$. You can always query this maximal value using
182 the \method{range()} method of the \class{path} class.
184 However, the situation becomes more complicated if more complex
185 objects like a circle are involved. Then, one could be tempted to
186 assume that again the parameter value range from $0$ to $1$, because
187 the predefined circle consists just of one \class{arc} together with a
188 \class{closepath} element. However, as a simple \samp{path.circle(0,
189 0, 1).range()} will tell, this is not the case: the actual range is
190 much larger. The reason for this behaviour lies in the internal path
191 handling of \PyX: Before performing any non-trivial geometrical
192 operation with a path, it will automatically be converted into an
193 instance of the \class{normpath} class (see also
194 Sect.~\ref{path:normpath}). These so generated paths are already
195 separated in their sub paths and only contain straight lines and
196 B\'ezier curve segments. Thus, as is easily imaginable, they are much
197 simpler to deal with.
199 A unique way of accessing a point on the path is to use the arc length
200 of the path segment from the first point of the path to the given
201 point. Thus, all \PyX{} path methods that accept a parameter value
202 also allow the user to pass an arc length. For instance,
203 \begin{verbatim}
204 from math import pi
206 pt1 = path.circle(0, 0, 1).at(arclen=pi)
207 pt2 = path.circle(0, 0, 1).at(arclen=3*pi/2)
209 c.stroke(path.path(path.moveto(*pt1), path.lineto(*pt2)))
210 \end{verbatim}
211 will draw a straight line from a point at angle $180$ degrees (in
212 radians $\pi$) to another point at angle $270$ degrees (in radians
213 $3\pi/2$) on the unit circle.
215 More information on the available path methods can be found
216 in Sect.~\ref{path:path}.
218 \section{Attributes: Styles and Decorations}
220 XXX to be done