summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/metapost/mp3d/tb57roegel.ltx
blob: 9ff0153aeacb80d6ec4d9bd96f46f23be32a28e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
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}