mp-tres.mpiv /size: 6498 b    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=mp-tres.mpiv,
3%D        version=2017.11.08,
4%D          title=\CONTEXT\ \METAPOST\ graphics,
5%D       subtitle=Pseudo 3D,
6%D         author=Alan Braslau,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
12%C details.
13
14%D This module provides simple 3D->2D projections. The code is an adaption of code
15%D by Urs Oswald, Dr.sc.math.\ ETH as presented in:
16%D
17%D \starttyping
18%D http://www.ursoswald.ch/metapost/tutorial.html.
19%D \stoptyping
20%D
21%D We need a bit more so it got extended.
22
23if known context_three : endinput ; fi ;
24
25boolean context_three ; context_three := true ;
26
27pair mfun_three_xy ; % this avoids the costly save and allocate
28pair mfun_three_yz ;
29pair mfun_three_zx ;
30
31transform Txy ;
32
33def setTxy(expr ori, ang) =
34    begingroup
35        save P, t ;
36        pair P[] ;
37        transform t ;
38
39        P0 = ori ;                                  % origin in MetaPost coordinates (bp)
40        P1 = (left rotated ang) scaled (cosd ang) ; % x axis (in mathematical coordinates)
41
42        % A sort of "cavalier projection".
43
44        % t: maps mathematical 2D coordinates onto MetaPost coordinates.
45
46        t := identity shifted P0 ; % Note: no shift when P0 = origin!
47
48        % Txy: maps the x-y plane of 3D space onto MetaPost coordinates,
49        % z is the vertical (MetaPost y).
50
51        % Txy:=identity
52        %   reflectedabout((0,0), (1,1))
53        %     yscaled ypart P1
54        %       slanted (xpart P1/ypart P1)
55        %         transformed t ;
56
57        % Alternatively, defined via Pxy:
58
59        % Pxy is the projection of the 3D plane z=0 onto the mathematical 2D coordinates.
60        % Pxy is determined by  3  e q u a t i o n s  describing
61        % how (1,0), (0,1), and (0,0) are mapped
62
63        save      Pxy ;
64        transform Pxy ;
65           P1 = (1,0) transformed Pxy ;   % Pxy: (1,0) --> P1
66        (1,0) = (0,1) transformed Pxy ;   %      (0,1) --> (1,0)
67        (0,0) = (0,0) transformed Pxy ;   %      (0,0) --> (0,0)
68
69        % mathematical 2D coordinates --> MetaPost coordinates
70
71        Txy := Pxy transformed t ;
72    endgroup
73enddef ;
74
75setTxy(origin,60) ;
76
77%D We already define triplet (as rgbcolor synonym) in in \type {mp-tool.mpiv}:
78
79let Xpart = redpart ;
80let Ypart = greenpart ;
81let Zpart = bluepart ;
82
83primarydef p Xscaled q =
84  (q*Xpart p, Ypart p, Zpart p)
85enddef ;
86
87primarydef p Yscaled q =
88  (Xpart p, q*Ypart p, Zpart p)
89enddef ;
90
91primarydef p Zscaled q =
92  (Xpart p, Ypart p, q*Zpart p)
93enddef ;
94
95primarydef p XYZscaled q =
96  (q*Xpart p,q*Ypart p,q*Zpart p)
97enddef ;
98
99vardef projection primary t =
100    (if triplet t :
101        (Xpart t, Ypart t) transformed Txy shifted (0,Zpart t)
102     elseif pair t :
103        t transformed Txy
104     else :
105        origin transformed Txy
106     fi)
107enddef ;
108
109vardef Abs primary p =
110    if triplet p :
111        sqrt((Xpart p)**2+(Ypart p)**2+(Zpart p)**2)
112    else :
113        length p
114    fi
115enddef ;
116
117vardef Unitvector primary z =
118    z/Abs z
119enddef ;
120
121primarydef p dotproduct q =
122    ((Xpart p)*(Xpart q) + (Ypart p)*(Ypart q) + (Zpart p)*(Zpart q))
123enddef ;
124
125primarydef p crossproduct q =
126    (
127        (Ypart p)*(Zpart q) - (Zpart p)*(Ypart q),
128        (Zpart p)*(Xpart q) - (Xpart p)*(Zpart q),
129        (Xpart p)*(Ypart q) - (Ypart p)*(Xpart q)
130    )
131enddef ;
132
133primarydef p rotatedaboutX q =
134    hide (
135        mfun_three_yz := (Ypart p, Zpart p) ;
136        mfun_three_yz := mfun_three_yz rotated q ;
137    )
138    (Xpart p, xpart mfun_three_yz, ypart mfun_three_yz)
139enddef ;
140
141primarydef p rotatedaboutY q =
142    hide(
143        mfun_three_zx := (Zpart p, Xpart p) ;
144        mfun_three_zx := mfun_three_zx rotated q ;
145    )
146    (ypart mfun_three_zx, Ypart p, xpart mfun_three_zx)
147enddef ;
148
149primarydef p rotatedaboutZ q =
150    hide (
151        mfun_three_xy := (Xpart p, Ypart p) ;
152        mfun_three_xy := mfun_three_xy rotated q ;
153    )
154    (xpart mfun_three_xy, ypart mfun_three_xy, Zpart p)
155enddef ;
156
157%D We can use a rotation about an arbitrary direction t ... (easy)
158
159% primarydef p rotatedabout(expr t, a) =
160% enddef ;
161
162vardef draw_vector@# (expr v, s) text t =
163    if triplet v :
164        drawarrow projection(Origin) -- projection(v) t ;
165        if string s :
166            label@#(s, projection(v)) t ;
167        fi
168    fi
169enddef ;
170
171%D Transform a (2D) path to a 3D plane
172
173def XYpath primary p =
174    (for i=0 upto (length p) if cycle p: -1 fi :
175        if i>0 : .. fi
176        projection (xpart point i of p,
177                    ypart point i of p,
178                    0)
179        ..controls
180        projection (xpart postcontrol i of p,
181                    ypart postcontrol i of p,
182                    0)
183        and
184        projection (xpart precontrol (i+1) of p,
185                    ypart precontrol (i+1) of p,
186                    0)
187        endfor if cycle p: ..cycle fi)
188enddef ;
189
190def XZpath primary p =
191    (for i=0 upto (length p) if cycle p: -1 fi :
192        if i>0 : .. fi
193        projection (xpart point i of p,
194                    0,
195                    ypart point i of p)
196        ..controls
197        projection (xpart postcontrol i of p,
198                    0,
199                    ypart postcontrol i of p)
200        and
201        projection (xpart precontrol (i+1) of p,
202                    0,
203                    ypart precontrol (i+1) of p)
204        endfor if cycle p: ..cycle fi)
205enddef ;
206
207def YZpath primary p =
208    (for i=0 upto (length p) if cycle p: -1 fi :
209        if i>0 : .. fi
210        projection (0,
211                    xpart point i of p,
212                    ypart point i of p)
213        ..controls
214        projection (0,
215                    xpart postcontrol i of p,
216                    ypart postcontrol i of p)
217        and
218        projection (0,
219                    xpart precontrol (i+1) of p,
220                    ypart precontrol (i+1) of p)
221        endfor if cycle p: ..cycle fi)
222enddef ;
223
224%D Some constants...
225
226triplet Origin, Xunitvector, Yunitvector, Zunitvector ;
227
228Origin      := (0,0,0) ;
229Xunitvector := (1,0,0) ;
230Yunitvector := (0,1,0) ;
231Zunitvector := (0,0,1) ;
232
233%D We could do but don't:
234
235% let normalxpart = xpart ;
236% let normalypart = ypart ;
237
238% vardef xpart expr p = if triplet p : redpart   else : normalxpart fi p enddef ;
239% vardef ypart expr p = if triplet p : greenpart else : normalypart fi p enddef ;
240% vardef zpart expr p =                bluepart                        p enddef ;
241
242