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
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <mach.h>
include <gio.h>
include "glabax.h"
# GLB_GETTICK -- Get the position and type of the next tick on an axis.
# Ticks are accessed sequentially. There are three types of tick scalings,
# LINEAR, LOG, and ELOG. The tick scaling need not necessarily agree with
# the WCS scaling, hence linear tick scaling might be used on a nonlinear
# coordinate system. If the scaling is linear then the first tick need not
# fall at the endpoint of the axis. If log (or elog) scaling is in use then
# the axis will have been rounded out to a decade and the first tick will
# necessarily fall on the axis endpoint. The scalings are described by the
# following parameters:
#
# (variables)
# nleft number of minor ticks left to next major tick
# step(x,y) displacement between minor ticks (world coords)
#
# (constants)
# tick1(x,y) world coords of the first tick on an axis
# nminor number of minor ticks between major ticks
# istep(x,y) initial step (actual step may differ)
# kstep(x,y) adjustment to step at major ticks
#
# KSTEP is unity if the scaling is linear. The log scalings have a KSTEP of
# either 10.0 or 0.1. A negative KSTEP value is used to flag ELOG scaling.
# ELOG, or extended range log scaling, is a log scaling which is defined for
# X <=0 as well as x > 0. This function is logarithmic for values less than
# -10 or greater than 10, and linear in the range [-10:+10]. This complicates
# tick computation because the usual 8 minor ticks per decade characteristic
# of log scaling are not appropriate in the linear regime. If the scaling
# is ELOG then we ignore NMINOR and ISTEP in the linear range, changing the
# values of these parameters temporarily to reflect 4 minor ticks with a tick
# spacing of 2.0.
#
# (Note to the reader: don't feel discouraged if you don't understand this
# (stuff, it is so complicated I don't understand it either! Having to deal
# (with linear, log, and elog scaling with both major and minor ticks,
# (sometimes no minor ticks, with the axis starting at any part of the scale
# (seems an inherently difficult problem to program compactly. Barring
# (programming each case separately, the best approach I could come up with was
# (to walkthrough the code separately for each case, from all initial
# (conditions, until it works for all cases. If you have problems determine
# (the initial conditions (the case) and do a similar walkthough. Of course,
# (if you make a change affecting one case, you may well make the code fail for
# (a different case.
int procedure glb_gettick (gp, ax, x, y, major_tick)
pointer gp # graphics descriptor
pointer ax # axis descriptor
real x, y # coordinates of next tick (output)
int major_tick # YES if next tick is a major tick
int i, axis, wcs, w, scaling, nminor, expon
real kstep, step, astep, ten, sx, sy, tolerance, pos, norm_pos
bool glb_eq()
define logscale_ 91
begin
if (AX_DRAWTICKS(ax) == NO)
return (EOF)
tolerance = TOL
scaling = AX_SCALING(ax)
nminor = AX_NMINOR(ax)
kstep = AX_KSTEP(ax)
if (AX_HORIZONTAL(ax) == YES)
axis = 1
else
axis = 2
# Count down a minor tick. If nleft is negative then we are being
# called for the first time for this axis.
if (AX_NLEFT(ax) < 0) {
# Initialize everything and return coords of the first tick.
AX_KSTEP(ax) = AX_IKSTEP(ax)
AX_NLEFT(ax) = AX_INLEFT(ax)
do i = 1, 2 {
AX_POS(ax,i) = AX_TICK1(ax,i)
AX_STEP(ax,i) = AX_ISTEP(ax,i)
}
step = AX_STEP(ax,axis)
astep = abs (step)
if (AX_NLEFT(ax) == 0) {
# Note that there may not be any minor ticks.
major_tick = YES
AX_NLEFT(ax) = nminor
if (nminor > 0)
if (scaling == ELOG && (astep >= .99 && astep < 2.0)) {
# Elog scaling in linear region.
AX_NLEFT(ax) = 4
if (step < 0)
step = -2.0
else
step = 2.0
AX_STEP(ax,axis) = step
}
} else {
AX_NLEFT(ax) = AX_NLEFT(ax) - 1
major_tick = NO
}
# Elog scaling in linear region. KSTEP must be inverted as we
# pass through the origin. This normally occurs upon entry to the
# linear region, but if we start out at +/- 10 we must set KSTEP
# to its linear value during setup.
if (scaling == ELOG && glb_eq(step,2.0))
AX_KSTEP(ax) = -10.0
} else {
# All ticks after the first tick.
do i = 1, 2
AX_POS(ax,i) = AX_POS(ax,i) + AX_STEP(ax,i)
AX_NLEFT(ax) = AX_NLEFT(ax) - 1
# If we are log scaling the ticks will never have more than 2
# digits of precision. Try to correct for the accumulation of
# error by rounding. When log scaling the error increases by
# a factor of ten in each decade and can get quite large if
# the log scale covers a large range.
if (scaling != LINEAR) {
pos = AX_POS(ax,axis)
call fp_normr (pos, norm_pos, expon)
pos = nint (norm_pos * 10.0) / 10.0
pos = pos * (10.0 ** expon)
AX_POS(ax,axis) = pos
}
if (AX_NLEFT(ax) < 0) {
# Next tick is a major tick. If log scaling we must reset
# the tick parameters for the next decade.
major_tick = YES
AX_NLEFT(ax) = nminor
# The following handles the special case of ELOG scaling in
# the linear regime when the number of minor ticks is zero.
# The step size in such a case is 9 to some power in the log
# region and +/- 10 in the linear region.
if (scaling == ELOG && nminor == 0) {
pos = AX_POS(ax,axis)
if (step < 0)
ten = -10.
else
ten = 10.
if (glb_eq (pos, 10.0)) {
if (glb_eq (step, 10.0)) {
if (step < 0)
AX_STEP(ax,axis) = -9.
else
AX_STEP(ax,axis) = 9.
goto logscale_
} else
step = ten
} else if (glb_eq (pos, 0.0)) {
step = ten
if (pos / step < 0)
AX_KSTEP(ax) = -0.1
else
AX_KSTEP(ax) = -10.0
} else
goto logscale_
AX_STEP(ax,axis) = step
} else if (scaling != LINEAR) {
# Adjust the tick step by the kstep factor, provided we
# are not at the origin in ELOG scaling (the step is 1
# on either side of the origin for ELOG scaling). Reset
# the step size to 1.0 if ELOG scaling and just coming out
# of the linear regime.
logscale_
step = AX_STEP(ax,axis)
if (scaling != ELOG || abs(AX_POS(ax,axis)) > 0.1) {
if (scaling == ELOG && glb_eq (step, 2.0))
AX_STEP(ax,axis) = step / 2.0
do i = 1, 2
AX_STEP(ax,i) = AX_STEP(ax,i) * abs (AX_KSTEP(ax))
}
# Adjust the step size to 2.0 if ELOG scaling and in the
# linear regime (initial step size of 1).
step = AX_STEP(ax,axis)
if (scaling == ELOG && glb_eq(step,1.0)) {
if (step < 0)
step = -2.0
else
step = 2.0
AX_STEP(ax,axis) = step
}
# If elog scaling and we have just entered the linear
# regime, adjust the number of ticks and the KSTEP factor.
if (scaling == ELOG && glb_eq(step,2.0)) {
# Elog scaling in linear region. KSTEP must be
# inverted as we pass through the origin.
if (abs(AX_POS(ax,axis)) > 0.1)
AX_KSTEP(ax) = -10.0
if (nminor > 0)
AX_NLEFT(ax) = 4
}
}
} else
major_tick = NO
}
x = AX_POS(ax,1)
y = AX_POS(ax,2)
# Return EOF if tick falls beyond end of axis. The comparison is made
# in NDC coords to avoid having to check if the WCS is increasing or
# decreasing and to avoid the problems of comparing unnormalized
# floating point numbers.
wcs = GP_WCS(gp)
w = GP_WCSPTR(gp,wcs)
call gctran (gp, x,y, sx,sy, wcs, 0)
if (sx - WCS_SX2(w) > tolerance || sy - WCS_SY2(w) > tolerance)
return (EOF)
else
return (OK)
end
# GLB_EQ -- Compare two (near normalized) floating point numbers for
# equality, using the absolute value of the first argument.
bool procedure glb_eq (a, b)
real a # compare absolute value of this number
real b # to this positive number
begin
return (abs (abs(a) - b) < 0.1)
end
|