aboutsummaryrefslogtreecommitdiff
path: root/sys/gio/gtickr.x
blob: cd227363547074ae2f9012139a25e710e89110a3 (plain) (blame)
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
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<mach.h>

# GTICK -- Determine the best number and placement of ticks for the interval
# [x1:x2].  If log scaling is in use we try to put the ticks at positions which
# are 1.0 times some power of ten, otherwise we divide the interval an integral
# number of times and place the ticks at the interval boundaries.  The basic
# algorithm is simple, but implementation is tricky due to the quirks of
# floating point computations and the desire to have the algorithm work for all
# X, and all ranges of X.  For example, we might want to plot a large range
# near zero, or a small range where both X1 and X2 have a very large exponent.
#
# N.B.: this is a generic source; it may be preprocessed with the IRAF "generic"
# preprocessor to produce either a single or double precision SPP source file.

procedure gtickr (x1, x2, rough_nticks, logflag, x_tick1, step)

real	x1, x2			# range for which ticks are desired
int	rough_nticks		# approximate number of ticks desired
int	logflag			# nonzero if log scaling in use
real	x_tick1			# x coord of first tick (output)
real	step			# tick spacing along X (output)

real	x, tol
int	ndiv
int	log
#int	nticks
int	expon
real	gt_distance()

begin
	log = logflag
	tol = EPSILONR * 10.0

	# If log, decrease ndiv until an x of 1.0 is obtained.  If an x of 1.0
	# cannot be produced, repeat the calculation once more with ndiv fixed.

	repeat {
	    ndiv = max (1, rough_nticks - 1)

	    repeat {
		if (log == YES)
		    x = 1.0
		else
		    x = abs ((x2 - x1) / ndiv)

		# Scale approximate tick spacing to the range [1-10).  Select
		# a logical tick spacing, given calculated and scaled spacing.

		call fp_normr (x, x, expon)
		if (x < 1.5)
		    x = 1.0
		else if (x < 2.5)
		    x = 2.0
		else if (x < 4.0)
		    x = 2.5
		else if (x < 7.5)
		    x = 5.0
		else {
		    x = 1.0
		    expon = expon + 1
		}

		# Calculate the first tick and the tick increment (step size).
		if (log == YES)
		    step = 1.0
		else
		    step = x * (10.0 ** expon)

		if (gt_distance (x1, step, x_tick1) / step < tol)
		    # x_tick1 = x1
		else if (x1 < x2 && x_tick1 < x1)
		    x_tick1 = x_tick1 + step
		else if (x1 > x2 && x_tick1 > x1)
		    x_tick1 = x_tick1 - step

		if (x1 > x2)
		    step = -step
		ndiv = ndiv - 1

	    } until (abs(abs(x) - 1.0) < tol || log == NO || ndiv == 0)

	    # Terminate if not in log mode, if the tick separation is a power
	    # of ten and there are ndivisions tick marks, or if the tick
	    # separation is one magnitude and there are at least two tick marks
	    # within the range x1:x2.

		#    if (log == NO) {
		#	return
		#    } else if (step == 1.0 || x == 1.0) {
		#	if (step == 1.0)
		#	    nticks = 1
		#	else
		#	    nticks = max (2, rough_nticks - 1)

		#	if (x1 > x2 && x_tick1 + nticks * step >= x2)
		#	    return
		#	else if (x1 < x2 && x_tick1 + nticks * step <= x2)
		#	    return
		#	else
		#	    log = NO
		#    } else
		#	log = NO

	    return
	}
end


# GT_NDIGITS -- Calculate the number of digits of precision needed to label
# ticks in the range x1 to x2 (i.e., if x1=100000 and x2=100001, 7 digits
# will be required, whereas in many cases 1 or 2 is enough).

int procedure gt_ndigits (x1, x2, step)

real	x1, x2			# range covered by numbers
real	step			# tick separation
real	ratio
int	n

begin
	if (x1 == x2)
	    n = 2
	else {
	    ratio = abs ((x1+x2) / (x1-x2)) 
	    n = log10 (max (1.0, ratio)) + 2.0
	}

	return (n)
end


# GT_LINEARITY -- The following function returns a large number if there is
# little difference between a log scale and a linear scale for the range X1
# to X2.  if the linearity of the interval is large, there is no point in
# using a logarithmic scale.

real procedure gt_linearity (x1, x2)

real	x1, x2
real	linearity, difflog
real	elogr()

begin
	if (x1 <= 0 || x2 <= 0)
	    difflog = abs (elogr(x1) - elogr(x2))
	else
	    difflog = abs (log10(x1) - log10(x2))

	if (difflog == 0.0)
	    linearity = 1E10
	else
	    linearity =  1.0 / difflog

	return (linearity)
end


# GT_DISTANCE -- Compute the distance of X from the nearest integral multiple
# of "step".

real procedure gt_distance (x, step, nearest_tick)

real	x			# number to be tested
real	step			# tick separation
real	nearest_tick		# X coord of tick nearest X

real	ltick, rtick, absx
real	fp_fixr()

begin
	absx = abs (x)

	ltick = fp_fixr (absx / step) * step
	rtick = ltick + step

	if (abs(absx - ltick) < abs(rtick - absx)) {
	    if (x < 0)
		nearest_tick = -ltick
	    else
		nearest_tick = ltick
	    return (absx - ltick)

	} else {
	    if (x < 0)
		nearest_tick = -rtick
	    else
		nearest_tick = rtick
	    return (rtick - absx)
	}
end