summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx')
-rw-r--r--Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx1149
1 files changed, 1149 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx b/Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx
new file mode 100644
index 00000000000..9ff0153aeac
--- /dev/null
+++ b/Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx
@@ -0,0 +1,1149 @@
+% D. Roegel, 25/2/1997 : first draft
+% 26/2/1997
+% 23/4/1997 : appendix, types added
+% 24/4/1997 : better formatting of appendix
+% 25/4/1997 : two columns
+% 27/4/1997 : some improvements
+% 28/4/1997 : changes to take new syntax into account
+% 30/4/1997 : cleaning and additions
+% 1/5/1997 : ltugboat macros
+% addition of appendix b
+% all overfull hboxes removed; this needed a lot
+% of rephrasing!
+% lots of cleaning
+% 2/5/1997 : extension of future part
+% 12/5/1997 : several small improvements to take Ulrik Vieth's
+% comments into account.
+% 17/5/1997 : some corrections to take modifications in
+% the source code into account
+% 18/5/1997 : commas in the syntax have been put in \texttt
+% some renamings in order to get rid of the overfull
+% hboxes resulting from the comma changes ...
+% 29/5/1997 : some renamings of ``object'' into ``obj'' to
+% be in accordance with the code (version 0.993)
+% some reformatting of pieces of code with respect
+% to the indentation
+% 19/6/1997 : - the `future' part has been corrected with respect
+% to the general algorithm for drawing the faces
+% (thanks to Dominique Larchey)
+% - reference to the ``LaTeX Graphics Companion''
+% 11/2/1998 : - description of draw_contours and contour_width
+% - acknowledgment of Denis Barbier and Boguslaw
+% Jackowski
+% - one_image changed to an_image at the beginning
+% of the paper, in order to avoid being misleading
+% by comparison with the real one_image macro
+% - a few more lines describing the parameters of
+% one_image
+% - ghostscript -> Ghostscript
+% - footnote added to explain why Ghostscript
+% has not been used to generate the excerpts
+% of the images.
+% - some lines to explain why the color type
+% was not used for 3d vectors
+% 12/2/1998 : - rewording to avoid overfull hboxes
+% 19/2/1998 : - minor ``english'' editing (RF)
+% and file sent to author for review (mb)
+% 04/03/1998: - EM fonts removed/ not to be used this issue
+% 04/08/1998: - TUB-specific inputs modified for portability to
+% CTAN archives (mb)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\documentclass[nonumber,harvardcite]{ltugboat}
+\usepackage{mflogo}
+
+\usepackage{url}
+\usepackage[dvips]{graphicx}
+
+\newcommand{\AVN}{\meta{avn}}
+\newcommand{\LVN}{\meta{lvn}}
+\newcommand{\APN}{\meta{apn}}
+\newcommand{\LPN}{\meta{lpn}}
+\newcommand{\AFN}{\meta{afn}}
+\newcommand{\LFN}{\meta{lfn}}
+\newcommand{\CN}{\meta{cl}}
+\newcommand{\IN}{\meta{obj}}
+\newcommand{\VL}{\meta{vl}}
+\newcommand{\VSL}{\meta{vsl}}
+\newcommand{\HEXCOL}{\meta{hc}}
+\newcommand{\COL}{\meta{col}}
+\newcommand{\STR}{\meta{str}}
+\newcommand{\PAIR}{\meta{pair}}
+\newcommand{\NUM}{\meta{num}}
+\newcommand{\BOOL}{\meta{bool}}
+
+\newcommand{\tc}{\texttt{,}}
+
+\newenvironment{todo}{\begin{bfseries}}{\end{bfseries}}
+
+%% this command is already defined in ltugboat.cls and is more robust
+%% I think....
+%\newcommand\meta[1]{$\langle$\mbox{\textit{#1}}$\rangle$}
+%%% the following is the ltugboat.cls definition
+%\DeclareRobustCommand\meta[1]{%
+% \ensuremath{\langle}\emph{#1}\ensuremath{\rangle}}
+
+\let\m=\meta % <-- this command is never used.
+
+%%%%%TUGboat production-specific files
+\vol 18, 4. % volume, issue.
+\issueseqno=57 % sequential issue number
+\issdate December 1997. % month, year of publication
+\setcounter{page}{274}
+\NoBlackBoxes
+\PrelimDraftfalse
+
+\widowpenalty=10000
+\clubpenalty=10000
+\renewcommand{\topfraction}{0.9}
+\renewcommand{\bottomfraction}{0.5}
+\renewcommand{\floatpagefraction}{0.8}
+\renewcommand{\textfraction}{0.1}
+\setcounter{bottomnumber}{2}
+\setcounter{totalnumber}{4}
+\renewcommand{\dbltopfraction}{0.9}
+\renewcommand{\dblfloatpagefraction}{0.8}
+\pretolerance=500
+\tolerance=1000
+\hbadness=3000
+\vbadness=3000
+\hyphenpenalty=400
+%%%%%%%END of TUGboat production-specific files
+
+\begin{document}
+
+\sectitle{Graphics Applications}
+
+\title{Creating 3D animations with \MP}
+\author{Denis Roegel}
+\address{CRIN (Centre de Recherche en Informatique de Nancy)\\
+ B\^atiment LORIA\\
+ BP 239\\
+ 54506 Vand\oe uvre-l\`es-Nancy\\
+ FRANCE}
+\netaddress{roegel@loria.fr}
+\personalURL{http://www.loria.fr/~roegel}
+
+
+
+\maketitle
+
+\begin{abstract}
+\MP{} can be used to create animations. We show here an example
+of animation of polyhedra, introducing the \texttt{3d} package.
+\end{abstract}
+
+\section{Introduction}
+
+%%%RF 1998/02/19: N-forms of cite
+\MP{} (\citeN{hobby1992}; see also the description in
+\shortciteN{Goossens:LGC97})
+is a drawing language very similar to \MF,
+but whose output is \PS. \MP{} is especially suited for geometrical
+and technical drawings, where a drawing can naturally be decomposed
+in several parts, related in some logical way.
+%%%RF 1998/02/19: active voice for passive
+Knuth is using \MP{} for the revisions of and additions to
+\emph{The Art Of Computer Programming}~\cite{knuth1997},
+and it is or will be a component of every standard \TeX{} distribution.
+
+Unfortunately, \MP{} is still quite bare and the user is only offered
+%%%RF 1998/02/19: revamped a bit
+the raw power\Dash a little bit like the \TeX{} user who only has
+plain \TeX{} at his/her disposal. The lack of libraries is certainly
+due to the infancy of \MP{} (which came in the public domain at the
+beginning of 1995) and thus to the small number of its users.
+
+In this paper, we present a way to produce animations using \MP.
+The technique is quite general and we illustrate it through the \texttt{3d}
+package.
+
+\section{Animations}
+
+The World Wide Web has accustomed us to various animations,
+especially \texttt{java} animations.
+Common components of web pages are animated GIF images.
+
+Producing animations in \MP{} is actually quite easy. A number of
+$n$ images will be computed and their sequence produces the animation.
+The animation will be similar to a movie, with no interaction. More precisely,
+if \verb|an_image(|$i$\verb|)|
+produces a picture parameterized by $i$,
+it suffices to wrap this macro
+between \verb|beginfig| and \verb|endfig|:
+
+\begin{verbatim}
+def one_image_out(expr i)=
+ beginfig(<figure number>);
+ an_image(i);
+ endfig;
+enddef;
+\end{verbatim}
+
+\noindent and to loop over \verb|one_image_out|:
+
+\begin{verbatim}
+for j:=1 upto 100:one_image_out(j);endfor;
+\end{verbatim}
+
+Assuming that \verb|<figure number>|
+is equal to the parameter of \verb|an_image|,
+the compilation of this program will produce
+a hundred files with extensions \verb|.1|, \verb|.2|, \ldots, \verb|.100|.
+All these files are \PS{} files and all we need to do is to find a way
+to collate them in one piece. How to do this depends on the operating
+system. On UNIX for instance, one can use \texttt{Ghostscript}
+to transform a \PS{} file
+into \texttt{ppm} and then transform each \texttt{ppm} file into
+GIF with \texttt{ppmtogif}. These programs are part of the
+\texttt{NETPBM} package~\cite{netpbm}. Finally, a program such as
+\texttt{gifmerge}~\cite{gifmerge}
+creates an animated GIF file (GIF89A)
+out of the hundred individual simple GIFs.
+However, various details must be taken care of. For instance,
+%%%RF 1998/02/19: reorganised around `grabbed'->`needed'
+only a part of \texttt{Ghostscript}'s output is needed
+and selection can be made with \texttt{pnmcut}.
+%(which is also part of \texttt{NETPBM}).
+
+The whole process of creating an animation out of \MP's outputs can
+be summed up in a shell script, similar to the one
+in figure~\ref{animation-script}. As we will see, this script (including
+the arguments of \texttt{awk} and \texttt{pnmcut}) can be generated
+automatically by \MP{} itself.
+
+%%fig 1
+\begin{figure*}
+\begin{verbatim}
+#! /bin/sh
+
+/bin/rm -f animpoly.log
+for i in `ls animpoly.*| grep 'animpoly.[0-9]'`;do
+echo $i
+echo '=============='
+# shift each picture so that it lies in the page:
+awk < $i '{print} /^%%Page: /{print "172 153 translate\n"}' > $i.ps
+# produce ppm format:
+gs -sDEVICE=ppmraw -sPAPERSIZE=a4 -dNOPAUSE -r36 -sOutputFile=$i.ppm -q -- $i.ps
+/bin/rm -f $i.ps
+# produce gif:
+ppmquant 32 $i.ppm | pnmcut 15 99 141 307 | ppmtogif > `expr $i.ppm : '\(.*\)ppm'`gif
+/bin/rm -f $i.ppm
+done
+/bin/rm -f animpoly.gif
+# merge the gif files:
+gifmerge -10 -l1000 animpoly.*.gif > animpoly.gif
+/bin/rm -f animpoly.*.gif
+\end{verbatim}
+\caption{Script created by \MP{} (with some additional comments)}
+\label{animation-script}
+\end{figure*}
+
+
+\section{Objects in space}
+
+\subsection{Introduction}
+
+The author applied this idea to the animation of objects
+in space. The macros in the \texttt{3d.mp} package\footnote{On CTAN,
+under \texttt{graphics/metapost/macros/3d}. The code is documented
+with \texttt{MFT}~\cite{knuth1989}
+and illustrated with \MP. This paper describes version 1.0 of the macros.}
+provide a basis for the
+representation of three-dimensional objects. The basic components of
+the objects are the points or the vectors. Both are stored as triplets.
+More precisely, we have three
+arrays\footnote{\MP{} has a few simple types such as \texttt{numeric},
+\texttt{boolean}, \texttt{string}, \texttt{path}, \ldots.
+It also has pairs (\texttt{pair}) and triples (\texttt{color}). We might
+have cheated and stored points as colors, but instead, we found it
+interesting to illustrate a construction equivalent
+to \textsc{Pascal}'s records or C's structures. In \MP, instead of
+having a list or an array of structures, we use several lists or arrays,
+so that a record is a cross-section over several arrays.}
+of type \verb|numeric|:
+
+\begin{verbatim}
+numeric vect[]x,vect[]y,vect[]z;
+\end{verbatim}
+
+Vector $i$'s components are \verb|vect[|$i$\verb|]x|, \verb|vect[|$i$\verb|]y|
+and \verb|vect[|$i$\verb|]z|. It is then straightforward to define the usual
+operations on vectors using this convention. For instance,
+vector addition is defined as:
+
+\begin{verbatim}
+def vect_sum(expr k,i,j)=
+ vect[k]x:=vect[i]x+vect[j]x;
+ vect[k]y:=vect[i]y+vect[j]y;
+ vect[k]z:=vect[i]z+vect[j]z;
+enddef;
+\end{verbatim}
+
+Often, we need some scratch vectors or vectors local to a macro.
+A simple vector allocation mechanism solves the problem: we use a stack
+of vectors and we reserve and free vectors only on top of the stack.
+For instance, the allocation of a vector is defined by:
+
+\begin{verbatim}
+def new_vect=incr(last_vect_) enddef;
+\end{verbatim}
+
+\noindent where \verb|last_vect_| is the index of the top of the stack.
+Hence, a vector is manipulated by its index on the stack.
+Writing \verb|v:=new_vect;| lets \verb|v| be the index of the newly allocated
+vector.
+
+Freeing a vector is also easy and is only allowed at the top of the stack:
+
+\begin{verbatim}
+def free_vect(expr i)=
+ if i=last_vect_:
+ last_vect_:=last_vect_-1;
+ else: errmessage("Vector " &
+ decimal i & " can't be freed!");
+ fi;
+enddef;
+\end{verbatim}
+
+How these macros are used is made explicit in the \verb|vect_rotate| macro
+which does a rotation of a vector \verb|v| around a vector \verb|axis|
+by an angle \verb|alpha|. This rotation is illustrated
+in figure~\ref{vector-rotation}.
+$\vec{v}$ is written as the sum of $\vec{h}$ and $\vec{a}$ where
+$\vec{h} \perp \vec{a}$. If $\vec{b}$ is
+$\overrightarrow{axis}/{\|\overrightarrow{axis}\|}$, $\vec{c}$ is computed
+as the vector product of $\vec{b}$ and $\vec{a}$ and $\vec{a}$ is then
+rotated in a simple way resulting in $\vec{f}$.
+
+The vectors declared with \verb|new_vect| are freed in the inverse order.
+The \verb|vect_rotate| macro makes use of a few other macros:
+\verb|vect_mod| computes the modulus of a vector; \verb|vect_dprod(a,b)| is
+the dot product of vectors \texttt{a} and \texttt{b}; \verb|vect_mult(b,a,x)|
+lets vector \texttt{b} equal vector \texttt{a} multiplied by the scalar
+\texttt{x}; \verb|vect_sum| and \verb|vect_diff| compute as their first
+argument the sum or the difference of the two other vectors;
+\verb|vect_prod(c,a,b)| lets vector \texttt{c} equal the vectorial
+product of vectors \texttt{a} and \texttt{b}. These macros are
+described in appendix A.
+
+%% fig2
+\begin{figure*}
+\begin{center}
+\includegraphics{vect-fig.9}\hspace{1cm}\includegraphics{vect-fig.10}
+\end{center}
+\caption{Vector rotation}\label{vector-rotation}
+\end{figure*}
+
+\begin{verbatim}
+vardef vect_rotate(expr v,axis,alpha)=
+ save v_a,v_b,v_c,v_d,v_e,v_f;
+ v_a:=new_vect;v_b:=new_vect;
+ v_c:=new_vect;v_d:=new_vect;
+ v_e:=new_vect;v_f:=new_vect;
+ v_g:=new_vect;v_h:=new_vect;
+ vect_mult(v_b,axis,1/vect_mod(axis));
+ vect_mult(v_h,v_b,vect_dprod(v_b,v));
+ vect_diff(v_a,v,v_h);
+ vect_prod(v_c,v_b,v_a);
+ vect_mult(v_d,v_a,cosd(alpha));
+ vect_mult(v_e,v_c,sind(alpha));
+ vect_sum(v_f,v_d,v_e);
+ vect_sum(v,v_f,v_h);
+ free_vect(v_h);free_vect(v_g);
+ free_vect(v_f);free_vect(v_e);
+ free_vect(v_d);free_vect(v_c);
+ free_vect(v_b);free_vect(v_a);
+enddef;
+\end{verbatim}
+
+The \verb|3d| package defines other macros in order to set the observer,
+%%%RF 1998/02/19: was `to manipulate'
+to compute a reference matrix, etc. Provision is given for
+manipulating objects.
+
+\subsection{Objects and classes}
+
+The \texttt{3d} package understands a notion of \emph{class}.
+A \emph{class} is a parameterized object. For instance, we have the class
+of regular tetrahedra, the class of regular cubes, etc. Our classes
+%%%RF 1998/02/19: `first level of genericity'->... abstraction
+are the lowest level of abstraction and classes can not be composed.
+They can only be \emph{instanciated}. When we need a specific tetrahedron,
+we call a generic function to create a tetrahedron, but with an identifier
+specific to one instance.
+
+A class is a set of vertices in space, together with a way to draw
+faces, and therefore edges.
+The author's focus was to manipulate (and later animate) polyhedra.
+As an example, the \verb|poly.mp| package provides the definition of
+each of the five regular convex polyhedra.
+
+%%%RF 1998/02/19: `is defining'->defines, etc, `both macros'->`each macro'
+Each class consists of two macros: one defines the points,
+the other calls the first macro and defines the faces.
+Each macro has a parameter which is a string identifying
+the particular instance of that class.
+
+\tolerance=4500
+The points of a regular tetrahedron are defined in
+\verb|set_tetrahedron_points|,
+%%%RF 1998/02/19: second half sentence rewritten
+an example of the general macro name \verb|set_|\meta{class}\verb|_points|.
+Five points are defined, four of
+them with \verb|set_obj_point|, a macro which defines points \emph{local}
+to an object. The first four points are the vertices and the fifth
+is the center of the tetrahedron. \verb|set_obj_point|'s first parameter
+is the point number and the other three are the cartesian coordinates.
+The first three points are in a plane and the fourth is obtained with
+the \verb|new_face_point| macro, which folds a face
+%%%RF 1998/02/19: tagged reference sentence on to end in parens
+(see the description in appendix A for more details).
+The \verb|new_face_point| macro
+is used with the angle \verb|an| which is computed in advance.
+Once the four points are set, the object is normalized, which means
+that it is centered with respect to the list of vertices given
+as parameter (here \verb|1,2,3,4|) and the last vertex is put on a sphere
+of radius 1, centered on the origin. Therefore, point 5 is the center
+of the tetrahedron, and the tetrahedron is set symmetrically
+with respect to the origin.
+
+\tolerance=1000
+%%%RF 1998/02/19: was `are hence inscriptible'
+All five convex regular polyhedra are defined in this way and may
+therefore be inscribed in a sphere of radius 1.
+
+\begin{verbatim}
+def set_tetrahedron_points(expr inst)=
+ set_obj_point(1,0,0,0);
+ set_obj_point(2,1,0,0);
+ set_obj_point(3,cosd(60),sind(60),0);
+ sinan=1/sqrt(3);
+ cosan=sqrt(1-sinan**2);
+ an=180-2*angle((cosan,sinan));
+ new_face_point(4,1,2,3,an);
+ normalize_obj(inst)(1,2,3,4);
+ set_obj_point(5,0,0,0);
+enddef;
+\end{verbatim}
+
+The second macro, \verb|def_tetrahedron| defines the number of points and
+faces of the instance, calls the previous macro and defines the faces
+with the macro \verb|set_obj_face|.
+The first argument of that macro is a \emph{local}
+face number, the second is a list of vertices such that the list goes clockwise
+when the face is visible. The last argument is the color of the face in RGB.
+
+\begin{verbatim}
+vardef def_tetrahedron(expr inst)=
+ new_obj_points(inst,5);
+ new_obj_faces(inst,4);
+ set_tetrahedron_points(inst);
+ set_obj_face(1,"1,2,4","b4fefe");
+ set_obj_face(2,"2,3,4","b49bc0");
+ set_obj_face(3,"1,4,3","b4c8fe");
+ set_obj_face(4,"1,3,2","b4fe40");
+enddef;
+\end{verbatim}
+
+The result of the drawing is:
+
+\begin{center}
+\includegraphics{tetra.ps}
+\end{center}
+
+A more complex example is the icosahedron which is defined below.
+
+\begin{verbatim}
+def set_icosahedron_points(expr inst)=
+ set_obj_point(1,0,0,0);
+ set_obj_point(2,1,0,0);
+ set_obj_point(3,cosd(60),sind(60),0);
+ cosan=1-8/3*cosd(36)*cosd(36);
+ sinan=sqrt(1-cosan*cosan);
+ an=180-angle((cosan,sinan));
+ new_face_point(4,1,2,3,an);
+ new_face_point(5,2,3,1,an);
+ new_face_point(6,3,1,2,an);
+ new_face_point(7,2,4,3,an);
+ new_face_point(8,3,5,1,an);
+ new_face_point(9,1,6,2,an);
+ new_face_point(10,3,4,7,an);
+ new_face_point(11,3,7,5,an);
+ new_face_point(12,1,8,6,an);
+ % 1 and 10 are opposite vertices
+ normalize_obj(inst)(1,10);
+ % center of icosahedron
+ set_obj_point(13,0,0,0);
+enddef;
+\end{verbatim}
+
+\begin{verbatim}
+vardef def_icosahedron(expr inst)=
+ save cosan,sinan,an;
+ new_obj_points(inst,13);
+ new_obj_faces(inst,20);
+ set_icosahedron_points(inst);
+ set_obj_face(1,"3,2,1","b40000");
+ set_obj_face(2,"2,3,4","ff0fa1");
+ set_obj_face(3,"3,7,4","b49b49");
+ set_obj_face(4,"3,5,7","b49bc0");
+ set_obj_face(5,"3,1,5","b4c8fe");
+ set_obj_face(6,"1,8,5","b4fefe");
+ set_obj_face(7,"1,6,8","b4fe40");
+ set_obj_face(8,"1,2,6","45d040");
+ set_obj_face(9,"2,9,6","45a114");
+ set_obj_face(10,"2,4,9","45a1d4");
+ set_obj_face(11,"9,4,10","4569d4");
+ set_obj_face(12,"4,7,10","112da1");
+ set_obj_face(13,"7,5,11","b4fefe");
+ set_obj_face(14,"5,8,11","b49bc0");
+ set_obj_face(15,"8,6,12","45a114");
+ set_obj_face(16,"6,9,12","b49b49");
+ set_obj_face(17,"8,12,11","b40000");
+ set_obj_face(18,"7,11,10","45a1d4");
+ set_obj_face(19,"12,10,11","b4c8fe");
+ set_obj_face(20,"9,10,12","ff0fa1");
+enddef;
+\end{verbatim}
+
+Since all points of the objects are stored in a unique global array,
+they are internally
+accessed by the local numbers and an offset defined by the
+macro \verb|new_obj_points|.
+The icosahedron example shows a systematic use of the
+\verb|new_face_point| macro to compute a point on an adjacent face.
+Displaying such an icosahedron results in the figure~\ref{icosahedron}.
+%% fig3
+\begin{figure}[h]
+\begin{center}
+\includegraphics{icosa.ps}
+\end{center}
+\caption{An icosahedron}\label{icosahedron}
+\end{figure}
+
+The other three regular convex polyhedra are:
+\begin{center}
+\includegraphics{cube.ps}
+\end{center}
+
+\begin{center}
+\includegraphics{octa.ps}\hfill\includegraphics{dodeca.ps}
+\end{center}
+
+The dodecahedron code is a bit special, since the vertices are built
+using ten additional points corresponding to face centers. These points
+are defined as an array of variables \verb|fc1| through \verb|fc10|
+with \verb|new_points(fc)(10)|.
+\verb|free_points(fc)(10)| frees them when they are no longer
+necessary. An excerpt of the dodecahedron code is:
+
+\begin{verbatim}
+def set_dodecahedron_points(expr inst)=
+ new_points(fc)(10);% face centers
+ set_point(fc1,0,0,0);
+ set_obj_point(1,1,0,0);
+ set_obj_point(2,cosd(72),sind(72),0);
+ rotate_in_plane(3,fc1,1,2);
+ ...
+ free_points(fc)(10);
+enddef;
+\end{verbatim}
+
+
+Finally, wire drawings can be obtained by setting the boolean
+\verb|filled_faces| to false:
+
+\begin{center}
+\includegraphics{icosa-w.ps}
+\end{center}
+
+\subsection{Animating objects}
+
+The animation of one or several objects involves the object(s) and an observer.
+The animation is a set of images and from an image to the next one,
+the observer as well as the objects can move. For instance
+the macro \verb|one_image| in \verb|3d.mp| is:
+
+\begin{verbatim}
+def one_image(expr name,i,a,rd,ang)=
+ beginfig(i);
+ set_point(Obs,
+ -rd*cosd(a*ang),-rd*sind(a*ang),1);
+ Obs_phi:=90;Obs_dist:=2;
+ % fix point 1 of object |name|
+ point_of_view_obj(name,1,Obs_phi);
+ draw_obj(name);
+ rotate_obj_pv(name,1,vect_I,ang);
+ % show the rotation point
+ draw_point(name,1);
+ draw_axes(red,green,blue);
+ endfig;
+enddef;
+\end{verbatim}
+
+The parameters of this macro are a name of an object (\verb|name|),
+an image index (\verb|i|), and three values defining the position
+of the observer.
+The observer (\verb|Obs| is a global point and set with \verb|set_point|,
+not with \verb|set_obj_point|)
+follows a circle of radius \verb|rd|.
+%%%RF 1998/02/19: reversed `usually is'
+The parameter \verb|a|, which is usually a function of \verb|i|,
+determines the number of rotation steps
+of the observer, each step being a rotation of angle \verb|ang|.
+The distance between the observer and the
+projection plane is $2$ (see figure~\ref{proj-screen}).
+
+%% fig4
+\begin{figure*}
+\begin{center}
+ \includegraphics{vect-fig.8}
+\end{center}
+\caption{Projection on the screen}\label{proj-screen}
+\end{figure*}
+
+%% fig5
+\begin{figure*}
+\begin{center}
+ \includegraphics{vect-fig.16}
+\end{center}
+\caption{Orientation of the observer}\label{obs-orientation}
+\end{figure*}
+
+
+The orientation of the observer is defined by three angles
+(see figure~\ref{obs-orientation}). The \verb|Obs_phi| angle
+is given and the two others are computed with a call to
+\verb|point_of_view_obj(name,1,Obs_phi)| which constrains the observer
+to look towards point 1 of object \verb|name|. Therefore, this
+point will seem fixed on the animation and \verb|draw_point(name,1)|
+draws it later so that this feature can be observed.
+There is nothing special about that point, except that it
+remains fix when the object is rotated. The object is drawn
+with \verb|draw_obj(name)| and
+%%%RF 1998/02/19: `does rotate'->rotates -- these arguments aren't
+%%% described here, which seems wrong, but i don't think
+%%% it's easy to do better....
+\verb|rotate_obj_pv| rotates the object \verb|name|
+by \verb|ang| degrees around an axis going through point 1
+and directed by vector \verb|vect_I| ($\vec{\imath}$).
+The reference vectors ($\vec\imath$,
+$\vec\jmath$ and $\vec k$) are drawn in red, green and blue with
+\verb|draw_axes|.
+
+Finally, a complete animation of an icosahedron is obtained
+with
+
+\begin{verbatim}
+animate_object("icosahedron",1,100,100);
+\end{verbatim}
+
+%%%RF 1998/02/19: `and this'->`which'
+\noindent which generates files \verb|anim.101|,
+%%%RF 1998/02/19: `if ... is'->`from ...'
+\ldots, \verb|anim.200| from the main file \verb|anim.mp|.
+The first parameter of \verb|animate_object| is the name of the object
+to animate, the second and third parameters are minimal and maximal
+values of the index loop and the fourth parameter is an offset added
+to the index loop in order to get the file extension, which must lie
+in the interval $0..4096$.
+
+After each image is drawn, the values of the current bounding box
+are used to compute the bounding box of the sequence of images.
+The internal values \verb|xmin_|, \verb|ymin_|, \verb|xmax_|
+and \verb|ymax_| hold the minimal and maximal values of the coordinates
+of the past images' corners.
+They are updated just before each image is shipped out.
+
+\subsection{Putting the pieces together}
+
+Once all the views have been computed, they can be used separately
+(see for instance the five views of figure~\ref{anim-five-views})
+or more interestingly, they can be merged.
+This task is made almost straightforward by \MP{} itself.
+Indeed, every time \verb|animate_object| is used, a shell script
+named \verb|create_animation.sh|
+is generated, as a side-effect of a call to
+\verb|show_animation_bbox|. The script is
+similar to that shown in figure~\ref{animation-script}.
+This script uses the values
+computed for the global bounding box of the sequence of images,
+for these values are necessary in order to extract the right parts
+of the images and get correct alignments; the parts are extracted
+with \texttt{pnmcut}.\footnote{One might think of using
+\texttt{Ghostscript} for generating an excerpt of an image,
+but if \texttt{Ghostscript} is used to generate the bounding box
+of an image, it will in general not be possible to have a good alignment
+between all images. The sizes of the excerpts are only known when all images
+have been produced.}
+If you have the programs
+used in this script (\texttt{Ghostscript}, etc.), you can just run
+it with \verb|sh create_animation.sh| on UNIX. You may need
+to adapt it to your needs, and for that purpose, you can modify the macro
+\verb|write_script| in \verb|3d.mp|.
+
+Some examples are included in the \verb|3d| distribution, and they
+can be viewed for instance with \texttt{netscape} or
+special programs such as \verb|xanim|.
+
+%% fig6
+\begin{figure*}
+\includegraphics[scale=0.5]{anim.1}\hfill
+\includegraphics[scale=0.5]{anim.2}\hfill
+\includegraphics[scale=0.5]{anim.3}\hfill
+\includegraphics[scale=0.5]{anim.4}\hfill
+\includegraphics[scale=0.5]{anim.5}
+
+\caption{Five views of an animation}\label{anim-five-views}
+\end{figure*}
+
+\section{Future}
+
+It is quite easy to improve and extend the \verb|3d| macros but the
+author decided to go no further for the moment. Other objects can
+be implemented easily and new algorithms can be added. For instance
+in order to take light sources or shadows into account, one can compute
+the angles under which a face gets its light, and the angle under which
+this very face is seen, in order to decide how much darker or lighter
+it must be rendered. Another problem is to represent
+overlapping objects correctly. In the current implementation, each
+object is drawn
+independently from the other objects, so that the overlapping may be wrong.
+One solution is to sort all the faces according to their distance
+to the observer and, if two faces can not be ordered, to split them.
+Then, the faces can be drawn starting with the most distant, and
+ending with the closest one.
+Appendix B explains the internal representation of the objects and
+shows that this algorithm can be implemented without much surgery to
+the present code.
+
+\section{Acknowledgments}
+
+Thanks to John Hobby who always answers all my queries on the \MF{} mailing
+list. Thanks to Alain Filbois who helped me with the shell script
+syntax, to Thomas Lambolais and Thomas Genet who gave some feedback
+on this work, and to Dominique Larchey who pointed out a shortcoming
+in the conclusion. Thanks to Denis Barbier who
+was one of the first users of these
+macros and contributed the animated crayons in the distribution. Thanks to
+Bogus\l aw Jackowski who made valuable comments on some peculiarities of
+the code.
+And finally, special thanks to Ulrik Vieth who not only
+pushed me to polish my code and this paper more than I had first intended,
+but also made it possible to use \MP{} under \texttt{web2c}.
+
+\bibliography{paper}
+
+\appendix
+
+\section{Appendix A\\
+Summary of the \texttt{3d} package}
+
+\subsection{Types}
+
+The commands in the \texttt{3d} package take parameters
+of several different types. The types are described here.
+
+\begin{itemize}
+\item An \AVN{} (\emph{Absolute Vector Number}) is the internal
+number identifying a vector in the \verb|vect| array (an integer).
+\item An \APN{} (\emph{Absolute Point Number}) refers to a vector
+in the same way as an \AVN{} (an integer).
+\item A \LPN{} (\emph{Local Point Number}) is a number identifying a
+point \emph{within} an object (an integer). Two \LPN{}s with the same value
+can correspond to different points in different objects.
+\item An \AFN{} (\emph{Absolute Face Number}) is the internal
+number identifying a face.
+\item A \LFN{} (\emph{Local Face Number}) is a number identifying a face
+\emph{within} an object (an integer). As for points, two \LFN{}s with
+the same value
+can correspond to different faces in different objects.
+\item A \CN{} (\emph{Class}) is a string representing a class,
+for instance \verb|"tetrahedron"|. It may only contain
+letters and underscores.
+\item An \IN{} (\emph{Object}) is a string representing an object, that is
+an instance of a class. Such a string may only contain
+letters and underscores.
+\item A \VL{} (\emph{Vertex List}) is a list
+of integers, where each integer identifies a vertex. For instance, \verb|1,7|
+is the list of vertices 1 and 7.
+\item A \VSL{} (\emph{Vertex String List}) is a string corresponding to a list
+of integers, where each integer identifies a vertex. For instance,
+\verb|"1,2,6,5"| is the list of vertices 1, 2, 6 and 5.
+\item \HEXCOL{} (\emph{Hex Color}) is a string representing a color with
+the three RGB components in hexadecimal and in the range
+$0..255$. For instance, \verb|"b4fe40"|.
+\item \COL{} (\emph{Color}) is a standard \MP{} color
+(a triplet of RGB components in the range $0..1$),
+such as \verb|red|.
+\item \STR{} (\emph{String}) is a string.
+\item \PAIR{} (\emph{Pair}) is a pair of numerics.
+\item \NUM{} (\emph{Numeric}) is a number.
+\item \BOOL{} (\emph{Boolean}) is a boolean.
+\end{itemize}
+
+\subsection{Low level vector commands}
+
+The low level vector commands define the classical operations in vector
+algebra.
+
+\begin{itemize}
+%\item \verb|vect_def(|\AVN\tc$x$\tc$y$\tc$z$\verb|)|; defines vector \AVN{}
+\item \verb|vect_def(|\AVN\tc$x$\tc$y$\tc$z$\verb|)|: defines vector \AVN{}
+as $(x,y,z)$;
+
+%\item \verb|set_point|: synonym of \verb|vect_def|; a point is stored in the
+\item \verb|set_point|; synonym of \verb|vect_def|: a point is stored in the
+same array as vectors.
+
+%\item \verb|set_obj_point(|\LPN\tc$x$\tc$y$\tc$z$\verb|)|;
+\item \verb|set_obj_point(|\LPN\tc$x$\tc$y$\tc$z$\verb|)|:
+this defines the point \LPN{} as $(x,y,z)$;
+
+%\item \verb|vect_def_vect(|\AVN$_1$\tc\AVN$_2$\verb|)|;
+\item \verb|vect_def_vect(|\AVN$_1$\tc\AVN$_2$\verb|)|:
+vector \AVN$_1$ becomes equal to vector \AVN$_2$;
+
+\item \verb|vect_sum(|\AVN$_1$\tc\AVN$_2$\tc\AVN$_3$\verb|)|:
+the vector \AVN$_1$ becomes the sum of vectors \AVN$_2$ and \AVN$_3$.
+
+\item \verb|vect_translate(|\AVN$_1$\tc\AVN$_2$\verb|)|:
+add vector \AVN$_2$
+to vector \AVN$_1$; vector \AVN$_2$ remains unchanged.
+
+\item \verb|vect_diff(|\AVN$_1$\tc\AVN$_2$\tc\AVN$_3$\verb|)|:
+the vector \AVN$_1$
+becomes the difference between vectors \AVN$_2$ and \AVN$_3$.
+
+\item \verb|vect_dprod(|\AVN$_1$\tc\AVN$_2$\verb|)| $\rightarrow $ \NUM{}:
+returns the dot product of vectors \AVN$_1$ and \AVN$_2$.
+
+\item \verb|vect_mod(|\AVN\verb|)| $\rightarrow $ \NUM{}: returns the
+modulus of vector \AVN.
+
+\item \verb|vect_prod(|\AVN$_1$\tc\AVN$_2$\tc\AVN$_3$\verb|)|:
+the vector \AVN$_1$
+becomes the vector product of vectors \AVN$_2$ and \AVN$_3$.
+
+\tolerance=1000
+\item \verb|vect_mult(|\AVN$_1$\tc\AVN$_2$\tc\NUM\verb|)|: \AVN$_1$
+becomes vector \AVN$_2$ scaled by \NUM.
+
+\item \verb|mid_point(|\AVN$_1$\tc\AVN$_2$\tc\AVN$_3$\verb|)|:
+vector (or point) \AVN$_1$ becomes the mid-point of vectors (or of the
+line joining the points)
+\AVN$_2$ and \AVN$_3$.
+
+\item \verb|vect_rotate(|\AVN$_1$\tc\AVN$_2$\tc$a$\verb|)|: vector \AVN$_1$ is
+rotated around vector \AVN$_2$ by the angle $a$.
+\end{itemize}
+
+\tolerance=1000
+\subsection{Operations on objects}
+
+Several operations apply globally on objects:
+
+\begin{itemize}
+\item \verb|assign_obj(|\IN\tc\CN\verb|)|:
+ create \IN{} as an instance of class \CN.
+\item \verb|reset_obj(|\IN\verb|)|: put \IN{} back where it
+ was just after it was initialized.
+\item \verb|put_obj(|\IN\tc\AVN\tc$s$\tc$\psi$\tc$\theta$\tc$\phi$\verb|)|:
+ object \IN{} is scaled by $s$, shifted by vector \AVN{} and
+ oriented with the angles $\psi$, $\theta$, $\phi$,
+ as for the observer orientation (figure~\ref{obs-orientation}).
+\item \verb|rotate_obj_pv(|\IN\tc\LPN\tc\AVN\tc$a$\verb|)|:
+ object \IN{} is rotated
+ around an axis going through local point \LPN{}
+ and directed by vector \AVN; the rotation is by $a$ degrees.
+\item \verb|rotate_obj_abs_pv(|\IN\tc\APN\tc\AVN\tc$a$\verb|)|:\break
+ the object \IN{} is rotated around an axis going through absolute
+ point \APN{} and directed by vector \AVN; the rotation is by $a$ degrees.
+\item \verb|rotate_obj_pp(|\IN\tc\LPN$_1$\tc\LPN$_2$\tc$a$\verb|)|:
+ \IN{} is rotated around an axis going through local points
+ \LPN$_1$ and \LPN$_2$; the rotation is by $a$ degrees.
+\item \verb|translate_obj(|\IN\tc\AVN\verb|)|: object \IN{} is translated
+ by vector \AVN.
+\item \verb|scale_obj(|\IN\tc$v$\verb|)|: object~\IN{}~is~scaled~by~$v$.
+\end{itemize}
+
+\subsection{Building new points in space}
+
+Three macros are especially useful for the definition of regular polyhedra:
+
+\begin{itemize}
+\item \verb|rotate_in_plane(|$k$\tc$o$\tc$i$\tc$j$\verb|)|:
+get point $k$ from point $j$ by rotation
+around point $o$ by an angle $\alpha$ equal to the angle from $i$ to $j$;
+$i$, $j$ and $k$ are of type \LPN, whereas $o$ is of type \APN.
+
+\begin{center}
+ \includegraphics{vect-fig.11}
+\end{center}
+
+\item \verb|new_face_point(|$c$\tc$o$\tc$i$\tc$j$\tc$\alpha$\verb|)|:
+the middle $m$ of points $i$ and $j$ is such that
+$\widehat{(\overrightarrow{om},\overrightarrow{mc})}=\alpha$
+and $\overrightarrow{mc}$ is $\overrightarrow{om}$ rotated around
+$\overrightarrow{ji}$. $c$, $o$, $i$ and $j$ are of type \LPN.
+
+\begin{center}
+ \includegraphics{vect-fig.7}
+\end{center}
+
+\item \verb|new_abs_face_point(|$c$\tc$o$\tc$i$\tc$j$\tc$\alpha$\verb|)|:
+similar to the previous definition, but $c$ and $o$ are of type \APN.
+
+\end{itemize}
+
+\subsection{Drawing points, axes, objects}
+
+\begin{itemize}
+\item \verb|draw_point(|\IN\tc\LPN\verb|)|: draw point \LPN{} in
+ object \IN.
+\item \verb|draw_axes(|\COL$_1$\tc\COL$_2$\tc\COL$_3$\verb|)|:
+ draw vectors $\vec\imath$, $\vec\jmath$ and $\vec{k}$ in colors
+ \COL$_1$, \COL$_2$ and \COL$_3$.
+\item \verb|draw_obj(|\IN\verb|)|: draw object \IN.
+\end{itemize}
+
+\subsection{Setting faces}
+
+\begin{itemize}
+\item \verb|set_face(|\AFN\tc\VSL\tc\HEXCOL\verb|)|:
+set absolute face \AFN{} as
+delimited by the vertex list \VSL{} (local point numbers) and colored by
+color \HEXCOL.
+\item \verb|set_obj_face(|\LFN\tc\VSL\tc\HEXCOL\verb|)|:
+set local face \LFN{} as
+delimited by the vertex list \VSL{} (local point numbers) and colored by
+color \HEXCOL.
+
+\end{itemize}
+
+\break
+
+\subsection{View points, distance}
+
+\begin{itemize}
+\item \verb|compute_reference(|$\psi$\tc$\theta$\tc$\phi$\verb|)|: defines
+the orientation of the observer by the three angles $\psi$,
+$\theta$ and $\phi$. See figure~\ref{obs-orientation}.
+
+\item \verb|point_of_view_obj(|\IN\tc\LPN\tc$\phi$\verb|)|: the orientation
+of the observer is defined as looking local point \LPN{} of object \IN,
+with an angle of $\phi$;
+\item \verb|point_of_view_abs(|\APN\tc$\phi$\verb|)|: the observer's
+orientation is defined as looking absolute point \APN{},
+with an angle of $\phi$;
+\item \verb|obs_distance(|$v$\verb|)(|\IN\tc\LPN\verb|)|: let $v$ equal
+the distance between the observer and local point \LPN{} in object \IN{}.
+\end{itemize}
+
+\subsection{Vector and point allocation}
+
+\begin{itemize}
+\item \verb|new_vect|$\rightarrow $ \AVN{}: return a new vector;
+\item \verb|new_point|: synonym of \verb|new_vect|;
+\item \verb|new_points(|$v$\verb|)(|$n$\verb|)|: defines the absolute points
+ $v_1, \ldots, v_n$, using \verb|new_point|;
+\item \verb|free_vect(|\AVN\verb|)|: free vector \AVN;
+\item \verb|free_point(|\APN\verb|)|: free point \APN;
+\item \verb|free_points(|$v$\verb|)(|$n$\verb|)|: frees the absolute points
+ $v_1, \ldots, v_n$, using \verb|free_point|.
+\end{itemize}
+
+\subsection{Debugging}
+
+\begin{itemize}
+\item \verb|show_vect(|\STR\tc\AVN\verb|)|:
+shows vector \AVN, with string \STR.
+\item \verb|show_point|: synonym of \verb|show_vect|
+\item \verb|show_pair(|\STR\tc\PAIR\verb|)|: this shows a numeric pair,
+ with string \STR.
+\end{itemize}
+
+\subsection{Normalization}
+
+\begin{itemize}
+\item \verb|normalize_obj(|\IN\tc\VL\verb|)|: normalize object \IN{}
+with respect to the list of vertices \VL.
+\end{itemize}
+
+\subsection{Parameters}
+
+\begin{itemize}
+\item \verb|Obs_dist| $\rightarrow$ \NUM: distance between the observer
+ and the projection plane.
+\item \verb|h_field| $\rightarrow$ \NUM: horizontal field of view
+ (default: 100 degrees)
+\item \verb|v_field| $\rightarrow$ \NUM: vertical field of view
+ (default: 70 degrees)
+\item \verb|Obs_phi| $\rightarrow$ \NUM: angle $\phi$ for the orientation
+ of the observer;
+\item \verb|Obs_theta| $\rightarrow$ \NUM: angle $\theta$ for the orientation
+ of the observer;
+\item \verb|Obs_psi| $\rightarrow$ \NUM: angle $\psi$ for the orientation
+ of the observer;
+\item \verb|drawing_scale| $\rightarrow$ \NUM: scale factor applied for
+ drawing;
+\item \verb|filled_faces| $\rightarrow$ \BOOL: if \texttt{true}, the faces
+ are drawn filled; if \texttt{false}, only the edges are drawn,
+ and hidden edges are drawn dashed;
+\item \verb|draw_contours| $\rightarrow$ \BOOL: if \texttt{true}, the contours
+ of the faces are drawn, and the lines have the thickness
+ \verb|contour_width|; if \texttt{false}, the contours are not drawn;
+\item \verb|contour_width| $\rightarrow$ \NUM: dimension used for drawing
+ contours of faces (default: 1pt).
+\end{itemize}
+
+\subsection{Constants}
+
+These values represent constant objects such
+as reference vectors, and should not be changed.
+
+\begin{itemize}
+\item \verb|vect_null| $\rightarrow$ \AVN: internal index for $\vec0$.
+\item \verb|vect_I| $\rightarrow$ \AVN: internal index for $\vec\imath$.
+\item \verb|vect_J| $\rightarrow$ \AVN: internal index for $\vec\jmath$.
+\item \verb|vect_K| $\rightarrow$ \AVN: internal index for $\vec k$.
+\item \verb|point_null| $\rightarrow$ \APN: internal index for $\vec0$.
+\item \verb|Obs| $\rightarrow$ \APN: observer's internal point number.
+\end{itemize}
+
+\subsection{Defining new object points and faces}
+
+\begin{itemize}
+\item \verb|new_obj_points(|\IN\tc\NUM\verb|)|:
+ defines points $1$ to \NUM{} in object \IN; must be used before setting
+ the points;
+\item \verb|new_obj_faces(|\IN\tc\NUM\verb|)|:
+ defines \NUM{} faces in object \IN; must be used before setting
+ the faces;
+\end{itemize}
+
+\subsection{Offsets}
+
+\begin{itemize}
+\item \verb|pnt(|\LPN\verb|)| $\rightarrow$ \APN: returns the absolute point
+number for a given local point index.
+\item \verb|face(|\LFN\verb|)| $\rightarrow$ \AFN: returns the absolute face
+number for a given local face index.
+\end{itemize}
+
+\subsection{Standard classes}
+
+Five standard classes are defined in \texttt{poly.mp}:
+they define the five regular convex polyhedra. For each class \meta{class},
+there are two macros:
+
+\begin{itemize}
+
+\item \verb|set_|\meta{class}\verb|_points|
+ (e.g. \verb|set_cube_points|)
+
+\item \verb|def_|\meta{class} (e.g. \verb|def_cube|)
+
+\end{itemize}
+
+Each of these macros is defined with a parameter which is the instance
+name.
+
+\subsection{Standard animations}
+
+The \texttt{3d} package provides a few standard animations using
+the convex polyhedra. In each of these animations, the observer
+follows a circular path pictured in figure~\ref{observer-motion}.
+Each standard animation is divided into two macros. The first,
+such as \verb|animate_object|, defines the class(es) that are used
+and sets the objects. The second, such as \verb|one_image|, sets
+the observer, draws the object(s) and moves the object(s) and the
+observer. The file \verb|animpoly.mp| gives examples of the use
+of the standard animations.
+
+\iffalse
+\begin{itemize}
+\item \verb|one_image(name,i,a)|
+\item \verb|one_image_two_objects(name_a,name_b,i,a)|
+\item \verb|one_image_three_objects(name_a,name_b,name_c,i,a)|
+\item \verb|one_image_two_identical_objects(name_a,name_b,i,a)|
+\item \verb|animate_object(name,imin,imax,index)|
+\item \verb|animate_two_objects(name_a,name_b,imin,imax,index)|
+\item \verb|animate_three_objects(name_a,name_b,name_c,imin,imax,index)|
+\item \verb|animate_two_identical_objects(name,imin,imax,index)|
+\end{itemize}
+\fi
+
+%% fig7
+\begin{figure*}
+\begin{center}
+ \includegraphics{vect-fig.17}
+\end{center}
+\caption{Motion of the observer}\label{observer-motion}
+\end{figure*}
+
+\section{Appendix B\\
+Coding an object}
+
+In order to extend the \texttt{3d} package, it is necessary to
+understand how the objects are coded. We give here an overview of
+this coding, but the reader is advised to peek in the code to get
+a better understanding on how all the functions interact.
+
+First, an object has a name, for instance \verb|"box"|.
+The macro \verb|box_class| (which can be called with \verb|obj_class_("box")|)
+is the string corresponding to the class of
+\verb|"box"|, for instance \verb|"cube"|.
+The variable \verb|cube_point_offsetbox|, of type \texttt{numeric},
+and obtained with \verb|obj_point_offset_("box")|,
+is equal to the absolute index of the last
+point of the previous object. A cube is defined with $8+1$ points. Assuming
+it was defined after an icosahedron ($12+1$ points) named
+\verb|"ico"|, \verb|cube_point_offsetbox| will be a \verb|numeric|
+equal to $13$. \verb|cube_pointsbox|
+(obtained with \verb|obj_points_("box")|)
+is a macro equal to $9$.
+%(\verb|current_point_offset_| is equal to \verb|cube_point_offsetbox|.)
+The variable \verb|cube_face_offsetbox|,
+similar to \verb|cube_point_offsetbox|,
+obtained with a call to \verb|obj_face_offset_("box")|,
+equals $20$.
+The macro \verb|cube_facesbox|
+(obtained by \verb|obj_faces_("box")|)
+is equal to $6$.
+%(\verb|current_face_offset_| is equal to \verb|cube_face_offsetbox|.)
+
+The \verb|obj_name| macro is extended each time a new object is defined.
+To an absolute face number, it associates an object name. Hence, it is possible
+to go through all faces. \verb|last_point_offset_| and
+\verb|last_face_offset_| are the absolute numbers of the last points and faces
+defined up to now.
+
+\begin{verbatim}
+def obj_name(expr i)=
+ if i<1: elseif i<=20:"ico"
+ elseif i<=26:"box"
+ fi;
+enddef;
+\end{verbatim}
+
+\verb|pnt(i)| gives the absolute vector corresponding to local point $i$.
+\verb|ipnt_(i)| is the absolute point number, that is $i$ plus the number
+of points defined beforehand in other objects.
+\verb|points_[j]| is the absolute vector corresponding to absolute object
+point $j$. Similarly, \verb|face(i)|
+is the absolute face corresponding to local face $i$.
+
+The list of vertices of absolute face number $i$ is \verb|face_points_[i]|.
+The color of absolute face number $i$ is \verb|face_color_[i]|.
+
+
+When the macros \verb|pnt| or \verb|face| are to be used, the calls
+\verb|define_current_point_offset_("box")| and
+\verb|define_current_face_offset_("box")| must be issued.
+
+
+\makesignature
+
+\end{document}
+