summaryrefslogtreecommitdiff
path: root/metapost/context/base/mpiv/mp-tres.mpiv
blob: 335670a989f1d9db18a477df1ccf330dcf841a00 (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
%D \module
%D   [       file=mp-tres.mpiv,
%D        version=2017.11.08,
%D          title=\CONTEXT\ \METAPOST\ graphics,
%D       subtitle=Pseudo 3D,
%D         author=Alan Braslau,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
%C details.

%D This module provides simple 3D->2D projections. The code is an adaption of code
%D by Urs Oswald, Dr.sc.math.\ ETH as presented in:
%D
%D \starttyping
%D http://www.ursoswald.ch/metapost/tutorial.html.
%D \stoptyping
%D
%D We need a bit more so it got extended.

if known context_three : endinput ; fi ;

boolean context_three ; context_three := true ;

pair mfun_three_xy ; % this avoids the costly save and allocate
pair mfun_three_yz ;
pair mfun_three_zx ;

transform Txy ;

def setTxy(expr ori, ang) =
    begingroup
        save P, t ;
        pair P[] ;
        transform t ;

        P0 = ori ;                                  % origin in MetaPost coordinates (bp)
        P1 = (left rotated ang) scaled (cosd ang) ; % x axis (in mathematical coordinates)

        % A sort of "cavalier projection".

        % t: maps mathematical 2D coordinates onto MetaPost coordinates.

        t := identity shifted P0 ; % Note: no shift when P0 = origin!

        % Txy: maps the x-y plane of 3D space onto MetaPost coordinates,
        % z is the vertical (MetaPost y).

        % Txy:=identity
        %   reflectedabout((0,0), (1,1))
        %     yscaled ypart P1
        %       slanted (xpart P1/ypart P1)
        %         transformed t ;

        % Alternatively, defined via Pxy:

        % Pxy is the projection of the 3D plane z=0 onto the mathematical 2D coordinates.
        % Pxy is determined by  3  e q u a t i o n s  describing
        % how (1,0), (0,1), and (0,0) are mapped

        save      Pxy ;
        transform Pxy ;
           P1 = (1,0) transformed Pxy ;   % Pxy: (1,0) --> P1
        (1,0) = (0,1) transformed Pxy ;   %      (0,1) --> (1,0)
        (0,0) = (0,0) transformed Pxy ;   %      (0,0) --> (0,0)

        % mathematical 2D coordinates --> MetaPost coordinates

        Txy := Pxy transformed t ;
    endgroup
enddef ;

setTxy(origin,60) ;

%D We already define triplet (as rgbcolor synonym) in in \type {mp-tool.mpiv}:

let Xpart = redpart ;
let Ypart = greenpart ;
let Zpart = bluepart ;

primarydef p Xscaled q =
  (q*Xpart p, Ypart p, Zpart p)
enddef ;

primarydef p Yscaled q =
  (Xpart p, q*Ypart p, Zpart p)
enddef ;

primarydef p Zscaled q =
  (Xpart p, Ypart p, q*Zpart p)
enddef ;

primarydef p XYZscaled q =
  (q*Xpart p,q*Ypart p,q*Zpart p)
enddef ;

vardef projection expr t =
    if triplet t :
        (Xpart t, Ypart t) transformed Txy shifted (0,Zpart t)
    elseif pair t :
        t transformed Txy
    else :
        origin transformed Txy
    fi
enddef ;

%D This overloads the plain macro \type {abs} (being \type {length}):

vardef abs primary p =
    if triplet p :
        sqrt((Xpart p)**2+(Ypart p)**2+(Zpart p)**2)
    else :
        length p
    fi
enddef ;

primarydef p dotproduct q =
    ((Xpart p)*(Xpart q) + (Ypart p)*(Ypart q) + (Zpart p)*(Zpart q))
enddef ;

primarydef p crossproduct q =
    (
        (Ypart p)*(Zpart q) - (Zpart p)*(Ypart q),
        (Zpart p)*(Xpart q) - (Xpart p)*(Zpart q),
        (Xpart p)*(Ypart q) - (Ypart p)*(Xpart q)
    )
enddef ;

primarydef p rotatedaboutX q =
    hide (
        mfun_three_yz := (Ypart p, Zpart p) ;
        mfun_three_yz := mfun_three_yz rotated q ;
    )
    (Xpart p, xpart mfun_three_yz, ypart mfun_three_yz)
enddef ;

primarydef p rotatedaboutY q =
    hide(
        mfun_three_zx := (Zpart p, Xpart p) ;
        mfun_three_zx := mfun_three_zx rotated q ;
    )
    (ypart mfun_three_zx, Ypart p, xpart mfun_three_zx)
enddef ;

primarydef p rotatedaboutZ q =
    hide (
        mfun_three_xy := (Xpart p, Ypart p) ;
        mfun_three_xy := mfun_three_xy rotated q ;
    )
    (xpart mfun_three_xy, ypart mfun_three_xy, Zpart p)
enddef ;

%D We can use a rotation about an arbitrary direction t ... (easy)

% primarydef p rotatedabout(expr t, a) =
% enddef ;

vardef draw_vector@# (expr v, s) text t =
    if triplet v :
        drawarrow projection(Origin) -- projection(v) t ;
        if string s :
            label@#(s, projection(v)) t ;
        fi
    fi
enddef ;

%D Some constants...

triplet Origin, Xunitvector, Yunitvector, Zunitvector ;

Origin      := (0,0,0) ;
Xunitvector := (1,0,0) ;
Yunitvector := (0,1,0) ;
Zunitvector := (0,0,1) ;

%D We could do but don't:

% let normalxpart = xpart ;
% let normalypart = ypart ;

% vardef xpart expr p = if triplet p : redpart   else : normalxpart fi p enddef ;
% vardef ypart expr p = if triplet p : greenpart else : normalypart fi p enddef ;
% vardef zpart expr p =                bluepart                        p enddef ;