summaryrefslogtreecommitdiff
path: root/graphics/metaplot/axes.mp
blob: 1782a0b77c709dc32a6a32780723c5facd51554f (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
% AXES: Axis/grid-tick formatter, for the METAPLOT package.
% Copyright(C) 2004, Brooks Moses
% 
%   This work may be distributed and/or modified under the
%   conditions of the LaTeX Project Public License, either
%   version 1.3 of this license or (at your option) any
%   later version.
%   The latest version of the license is in
%      http://www.latex-project.org/lppl.txt
%   and version 1.3 or later is part of all distributions of
%   LaTeX version 2003/06/01 or later.
% 
%   This work has the LPPL maintenance status "author-maintained".
%
% Version 0.9.
%
% The n < 1.0 release number indicates that this is a beta release;
% the author at present makes no assurances that the command syntax
% will remain unchanged between this and the final Version 1.0
% release.
%
% Bug reports, feature requests, and all other suggestions should
% be directed to Brooks Moses, bmoses@stanford.edu.


input format

% axes_tick(pair tickorigin,
%           numeric ticklength,
%           pair tickdir)
%
% Draws a grid tick, located on tickorigin, in the direction indicated by
% tickdir, with length ticklength.

def axes_tick(expr tickorigin, ticklength, tickdir) =
  begingroup
  interim linecap := butt;
  save theaxistick; picture theaxistick; theaxistick := nullpicture;
  addto theaxistick doublepath ((0,0)--(ticklength * unitvector(tickdir)));

  theaxistick shifted tickorigin
  endgroup
enddef;


% axes_ticklabeled(pair tickorigin,
%                  numeric ticklength,
%                  numeric tickspace,
%                  pair tickdir,
%                  picture ticklabel)
%
% Draws a grid tick, located on tickorigin, in the direction indicated by
% tickdir, with length ticklength.  In addition, ticklabel is placed as
% a label such that its center is along the line of the tick, and the
% bounding box is a distance tickspace from the end of the tick.

def axes_ticklabeled(expr tickorigin, ticklength, tickspace, tickdir, ticklabel) =
  begingroup
  interim linecap := butt;
  save tickunitvector; pair tickunitvector;
  tickunitvector := unitvector(tickdir);
  
  % We calculate an intersection point between the bbox of ticklabel
  % and a ray extending from center(ticklabel) in the direction of 
  % tickdir (approximated by a line guaranteed to be long enough to 
  % exit the bbox), in the coordinates of ticklabel.  Thus, shifting
  % ticklabel by the negative of this amount will put this intersection
  % point at (0,0).
  
  save thelabelshift; pair thelabelshift;
  thelabelshift =
    (center(ticklabel) -- (center(ticklabel)
      - tickunitvector * (xpart(urcorner ticklabel - llcorner ticklabel)
                          + ypart(urcorner ticklabel - llcorner ticklabel))))
     intersectionpoint (llcorner ticklabel -- lrcorner ticklabel
                         -- urcorner ticklabel -- ulcorner ticklabel -- cycle);
  
  save thetick; picture thetick; thetick := nullpicture;
  addto thetick doublepath ((0,0)--(ticklength * tickunitvector));
  addto thetick also ticklabel
    shifted ((ticklength + tickspace)*tickunitvector - thelabelshift);

  thetick shifted tickorigin
  endgroup
enddef;


% axes_ticknumbered(pair tickorigin,
%                   numeric ticklength,
%                   numeric tickspace,
%                   pair tickdir,
%                   numeric tickvalue)
%                   string ticklabelformat)
%
% Draws a grid tick with a formatted number (tickvalue) as the label,
% according to the format given in ticklabelformat, with the remainder
% of the syntax identical to axes_ticklabeled.

def axes_ticknumbered(expr tickorigin, ticklength, tickspace, tickdir,
                      tickvalue, ticklabelformat) =
  axes_ticklabeled(tickorigin, ticklength, tickspace, tickdir,
                   format(ticklabelformat, tickvalue))    
enddef;


% axes_tickrow(pair startpoint,
%              pair endpoint,
%              numeric ticklength,
%              pair tickdir,
%              numeric ntickspaces)
%
% Draws a row of ntickspaces+1 grid ticks (that is, ticks with ntickspaces
% spaces between them) from startpoint to endpoint, with parameters given
% by ticklength and tickdir.

def axes_tickrow(expr startpoint, endpoint,
                      ticklength, tickdir, ntickspaces) =
  begingroup
  save thetickrow; picture thetickrow; thetickrow := nullpicture;
  save tickpoint; pair tickpoint;
  for itick=0 upto ntickspaces:
    tickpoint := (itick/ntickspaces) * (endpoint - startpoint) + startpoint;
    addto thetickrow also
      axes_tick(tickpoint, ticklength, tickdir);
  endfor
  thetickrow
  endgroup
enddef;


% axes_tickrow_numbered(pair startpoint,
%                       pair endpoint,
%                       numeric ticklength,
%                       numeric tickspace,
%                       pair tickdir,
%                       numeric startvalue,
%                       numeric endvalue,
%                       numeric ntickspaces,
%                       string ticklabelformat)
%
% Draws a row of ntickspaces+1 labeled grid ticks (that is, ticks with
% ntickspaces spaces between them) from startpoint to endpoint, with
% parameters given by ticklength, tickspace, and tickdir.  These ticks
% are labeled with numeric values that range from startvalue (at'
% startpoint) to endvalue (at endpoint), according to the format given
% in ticklabelformat.

def axes_tickrow_numbered(expr startpoint, endpoint,
                               ticklength, tickspace, tickdir,
                               startvalue, endvalue, ntickspaces,
                               ticklabelformat) =
  begingroup
  save thetickrow; picture thetickrow; thetickrow := nullpicture;
  save tickpoint; pair tickpoint;
  save tickvalue; numeric tickvalue;
  for itick=0 upto ntickspaces:
    tickpoint := (itick/ntickspaces) * (endpoint - startpoint) + startpoint;
    tickvalue := (itick/ntickspaces) * (endvalue - startvalue) + startvalue;
    addto thetickrow also
      axes_ticknumbered(tickpoint, ticklength, tickspace, tickdir,
                        tickvalue, ticklabelformat);
  endfor
  thetickrow
  endgroup
enddef;


% axes_tickscale(pair startpoint,
%                pair endpoint,
%                numeric ticklength,
%                numeric tickspace,
%                pair tickdir,
%                numeric startvalue,
%                numeric endvalue,
%                numeric tickzero,
%                numeric tickstep,
%                string ticklabelformat)
%
% Draws a row of grid ticks from startpoint to endpoint, arranged
% such that their values increase in steps of size tickstep, and 
% located so that the sequence of grid ticks, if continued to 
% infinity, will include a tick with value tickzero.  The ticks
% will be labeled according to format ticklabelformat, or if 
% ticklabelformat is "", they will be unlabeled.

def axes_tickscale(expr startpoint, endpoint,
                        ticklength, tickspace, tickdir,
                        startvalue, endvalue, tickzero, tickstep,
                        ticklabelformat) =
  begingroup
  % tickepsilon is a small tolerance value to avoid roundoff errors.
  save tickepsilon; numeric tickepsilon;
  tickepsilon = 0.005 * min(1.0, abs(endvalue-startvalue)/tickstep);

  save firstticknumber; numeric firstticknumber;
  save lastticknumber; numeric lastticknumber;  
  firstticknumber = ceiling((min(startvalue,endvalue)-tickzero)/tickstep - tickepsilon);
  lastticknumber = floor((max(startvalue,endvalue)-tickzero)/tickstep + tickepsilon);

  save firsttickvalue; numeric firsttickvalue;
  save lasttickvalue; numeric lasttickvalue;  
  firsttickvalue = firstticknumber * tickstep + tickzero;
  lasttickvalue = lastticknumber * tickstep + tickzero;

  if ticklabelformat="":
    axes_tickrow( 
      ((firsttickvalue-startvalue)/(endvalue-startvalue))[startpoint, endpoint],
      ((lasttickvalue-startvalue)/(endvalue-startvalue))[startpoint, endpoint],
      ticklength, tickdir, lastticknumber - firstticknumber)
  else:
    axes_tickrow_numbered( 
      ((firsttickvalue-startvalue)/(endvalue-startvalue))[startpoint, endpoint],
      ((lasttickvalue-startvalue)/(endvalue-startvalue))[startpoint, endpoint],
      ticklength, tickspace, tickdir, 
      firsttickvalue, lasttickvalue, lastticknumber - firstticknumber,
      ticklabelformat)
  fi
  endgroup
enddef;