# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<gki.h>
include	"imd.h"

define	DEF_YRES	8192	# default height of device pixel in GKI units
define	ZSTEP		4	# bit to be tested (step function width)


# IMD_PUTCELLARRAY -- Draw a cell array, i.e., two dimensional array of pixels
# (greylevels or colors).  The algorithm used here maps 8 bits in into 1 bit
# out, using a step function lookup table.  The result is a band-contoured
# image, where the spacing and width of the contour bands decreases as the
# rate of change of intensity in the input cell array increases.

procedure imd_putcellarray (m, nx, ny, ax1,ay1, ax2,ay2)

short	m[nx,ny]		# cell array
int	nx, ny			# number of pixels in X and Y
int	ax1, ay1		# lower left corner of output window
int	ax2, ay2		# upper right corner of output window

bool	ttygetb()
include	"imd.com"

begin
	if (ttygetb (g_tty, "BI"))
	    call imd_bcell (m, nx, ny, ax1,ay1, ax2,ay2)
	else
	    call imd_mcell (m, nx, ny, ax1,ay1, ax2,ay2)
end


# IMD_BCELL -- Put cell array, optimized for a bitmap device.  In this case,
# to get the maximum resolution at maximum efficiency it is desirable for the
# main loop to be over device pixels, mapping the device pixel into the
# nearest line of the input cell array.

procedure imd_bcell (m, nx, ny, ax1,ay1, ax2,ay2)

short	m[nx,ny]		# cell array
int	nx, ny			# number of pixels in X and Y
int	ax1, ay1		# lower left corner of output window
int	ax2, ay2		# upper right corner of output window

real	dx, dy
int	my, i1, i2, v, i, j, k
include	"imd.com"
int	and()

begin
	# Count drawing instruction, set polyline width to 1 for max y-res.
	g_ndraw = g_ndraw + 1
	call idk_linewidth (g_out, 1)
	IMD_WIDTH(g_kt) = 0

	# Determine the width of a cell array pixel in GKI units.
	dx = real (ax2 - ax1) / nx

	# Determine the height of a device pixel in GKI units.
	if (IMD_YRES(g_kt) <= 0)
	    dy = GKI_MAXNDC / DEF_YRES
	else
	    dy = max (1.0, real(GKI_MAXNDC) / real(IMD_YRES(g_kt)))

	# Process the cell array.  The outer loop runs over device pixels in Y;
	# each iteration writes one line of the output raster.  The inner loop
	# runs down a line of the cell array.

	k = 0
	for (my = ay1 + dy/2;  my < ay2;  my = k * dy + ay1) {
	    j = max(1, min(ny, int (real(my-ay1) / real(ay2-ay1) * (ny-1)) + 1))
	    my = min (my, int (ay2 - dy/2))

	    for (i=1;  i <= nx;  ) {
		do i = i, nx {
		    v = m[i,j]
		    if (and (v, ZSTEP) != 0)
			break
		}

		if (i <= nx) {
		    i1 = i
		    i2 = nx
		    do i = i1 + 1, nx {
			v = m[i,j]
			if (and (v, ZSTEP) == 0) {
			    i2 = i
			    break
			}
		    }

		    # The following decreases the length of dark line segments
		    # to make features more visible.

		    if (i2 - i1 >= 2)
			if (i1 > 1 && i2 < nx) {
			    i1 = i1 + 1
			    i2 = i2 - 1
			}

		    # Draw the line segment.
		    call idk_move (g_out, int ((i1-1) * dx + ax1), my)
		    call idk_draw (g_out, int (i2 * dx + ax1), my)

		    if (i2 >= nx)
			i = nx + 1
		}
	    }

	    k = k + 1
	}
end


# IMD_MCELL -- Put cell array, optimized for a metafile device.  In this case,
# it is prohibitively expensive to draw into each resolvable line of the
# output device.  It is better to set the linewidth to the width of a cell
# array pixel, output the minimum number of drawing instructions, and let the
# metafile device widen the lines.

procedure imd_mcell (m, nx, ny, ax1,ay1, ax2,ay2)

short	m[nx,ny]		# cell array
int	nx, ny			# number of pixels in X and Y
int	ax1, ay1		# lower left corner of output window
int	ax2, ay2		# upper right corner of output window

real	dx, dy
int	yres, my, i1, i2, v, i, j
include	"imd.com"
int	and()

begin
	# Count drawing instruction, clobber saved polyline width.
	g_ndraw = g_ndraw + 1
	IMD_WIDTH(g_kt) = 0

	# Determine the width and height of a cell array pixel in GKI units.
	dx = real (ax2 - ax1) / nx
	dy = real (ay2 - ay1) / ny

	# Set the IDK line width to the height of a pixel in the cell array.
	yres = IMD_YRES(g_kt)
	if (yres <= 0)
	    yres = DEF_YRES
	call idk_linewidth (g_out,
	    max (1, nint (dy / (real(GKI_MAXNDC) / real(yres)))))

	# Process the cell array.  The outer loop runs over lines of the input
	# cell array; each iteration writes only one line of the output raster,
	# but the width of the line is adjusted to the height of a pixel in
	# the cell array (the resolution of the cell array should not exceed
	# that of the device).

	for (j=1;  j <= ny;  j=j+1) {
	    my = int ((j - 0.5) * dy) + ay1

	    for (i=1;  i <= nx;  ) {
		do i = i, nx {
		    v = m[i,j]
		    if (and (v, ZSTEP) != 0)
			break
		}

		if (i <= nx) {
		    i1 = i
		    i2 = nx
		    do i = i + 1, nx {
			v = m[i,j]
			if (and (v, ZSTEP) == 0) {
			    i2 = i
			    break
			}
		    }

		    # The following decreases the length of dark line segments
		    # to make features more visible.

		    if (i2 - i1 >= 2)
			if (i1 > 1 && i2 < nx) {
			    i1 = i1 + 1
			    i2 = i2 - 1
			}

		    # Draw the line segment.
		    call idk_move (g_out, int ((i1-1) * dx + ax1), my)
		    call idk_draw (g_out, int (i2 * dx + ax1), my)

		    if (i2 >= nx)
			i = nx + 1
		}
	    }
	}
end
