# 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 gtick$t (x1, x2, rough_nticks, logflag, x_tick1, step)

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

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

begin
	log = logflag
	tol = EPSILON$T * 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_norm$t (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)

PIXEL	x1, x2			# range covered by numbers
PIXEL	step			# tick separation
PIXEL	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.

PIXEL procedure gt_linearity (x1, x2)

PIXEL	x1, x2
PIXEL	linearity, difflog
PIXEL	elog$t()

begin
	if (x1 <= 0 || x2 <= 0)
	    difflog = abs (elog$t(x1) - elog$t(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".

PIXEL procedure gt_distance (x, step, nearest_tick)

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

PIXEL	ltick, rtick, absx
PIXEL	fp_fix$t()

begin
	absx = abs (x)

	ltick = fp_fix$t (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
