 /*
  * Khoros: $Id$
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id$";
#endif

 /*
  * $Log$
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as to the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including, for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>  		     General Utility Routines
 >>>>
 >>>>			transfer_mapcol_to_xcolors()
 >>>>			spc_set_image_and_maps()
 >>>>			print_current_xcolors()
 >>>>			perform_map_function()
 >>>>			find_min_max_col_data()
 >>>>			norm_data()
 >>>>			normalize_col_data()
 >>>>			shift_col_data()
 >>>>			save_unused_classnum()
 >>>>			set_new_classname()
 >>>>			find_unused_classnums()
 >>>>			striptext()
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/

#include "spectrum.h"


/****************************************************************
*
* Routine Name: transfer_mapcol_to_xcolors()
*
*      Purpose: takes a column of the map data and transfers it to
* 		the red, green, or blue band of the xvdisplay xcolors array. 
*
*        Input: column    - number of the map data column to be transferred
*		colorband - one of SpcRed, SpcBlue, or SpcGreen.
*       Output: none
*
*   Written By: Danielle Argiro
*
****************************************************************/

int transfer_mapcol_to_xcolors(column, colorband)
float *column;
int  colorband;
{
     int i;

     if (colorband == SpcRed)
     {
         for (i = 0; i < spc_map_rownum; i++)
             xvdisplay->xcolors[i].red = ((unsigned short) 
					  column[i]) << 8;
     }
     else if (colorband == SpcBlue)
     {
         for (i = 0; i < spc_map_rownum; i++)
             xvdisplay->xcolors[i].blue = ((unsigned short) 
					   column[i]) << 8;
     }
     else if (colorband == SpcGreen)
     {
         for (i = 0; i < spc_map_rownum; i++)
             xvdisplay->xcolors[i].green = ((unsigned short) 
					    column[i]) << 8;
     }
     return(true);
}


/****************************************************************
*
* Routine Name: spc_set_image_and_maps()
*      Purpose: sets the global image (spc_image)
*		and the global map data (spc_maps).
*        Input: none
*       Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

spc_set_image_and_maps()
{
   /*
    *   save the map data for our own use - don't want
    *   it to represent the image colormap.  set image header fields
    *   dealing w/ map data to values we want.  set our global variables
    *   according to image info.
    */

    int   i;
    char  temp[MaxLength];
    float *map;
    float **create_ramp_map(), **get_rgb_map();

    map = (float *) spc_image->maps;

    spc_max_colors = 256;
    spc_map_contents = spc_image->ispare1;
    spc_map_rownum   = spc_image->map_col_size;
    spc_map_colnum  = spc_image->ispare2;

    if (spc_map_colnum == 0) 
    {
	if (spc_image->map_scheme == VFF_MS_NONE)
	    spc_map = create_ramp_map();

	else if (((spc_image->map_scheme == VFF_MS_ONEPERBAND) || 
		  (spc_image->map_scheme == VFF_MS_SHARED)) &&
		  (spc_image->map_enable == VFF_MAP_OPTIONAL) )
	    spc_map = create_ramp_map();

	else 
        {
	    sprintf(temp, "Spectrum cannot work with images that contain FORCED maps.  See vmsquish(1) and vmapdata(1) to convert images to a format that can be used by Spectrum.");
	    xvf_error_wait(temp, "Spectrum", NULL);
	    return;
	}
    }
    else 
    {
        spc_map = read_normal_map(spc_map_rownum, spc_map_colnum, map); 
    }

    spc_image->maps = NULL;
    spc_image->map_row_size = 0;
    spc_image->map_col_size = 0;
    spc_image->color_space_model = VFF_CM_NONE;
    spc_image->map_scheme = VFF_MS_NONE;
    spc_image->map_enable = VFF_MAP_OPTIONAL;

    spc_map_contents = SpcMeanVectors | SpcClass;

    find_min_max_col_data(spc_map[0], spc_map_rownum, &red_min, &red_max);
    if (current_red_col != NULL) free(current_red_col);
    current_red_col = (float *) malloc(spc_map_rownum * sizeof(float));
    for (i = 0; i < spc_map_rownum; i++)
        current_red_col[i] = spc_map[0][i];
    norm_red_col = copy_column(current_red_col);
    norm_data(norm_red_col, SpcRed);

	
    find_min_max_col_data(spc_map[1], spc_map_rownum, &green_min, &green_max);
    if (current_green_col != NULL) free(current_green_col);
    current_green_col = (float *) malloc(spc_map_rownum * sizeof(float));
    for (i = 0; i < spc_map_rownum; i++)
        current_green_col[i] = spc_map[1][i];
    norm_green_col = copy_column(current_green_col);
    norm_data(norm_green_col, SpcGreen);

    
    find_min_max_col_data(spc_map[2], spc_map_rownum, &blue_min, &blue_max);
    if (current_blue_col != NULL) free(current_blue_col);
    current_blue_col = (float *) malloc(spc_map_rownum * sizeof(float));
    for (i = 0; i < spc_map_rownum; i++)
        current_blue_col[i] = spc_map[2][i];
    norm_blue_col = copy_column(current_blue_col);
    norm_data(norm_blue_col, SpcBlue);

}


/****************************************************************
*
* Routine Name: print_current_xcolors()
*
*      Purpose: prints out the current values for Red, Green, and Blue
*		in the xvdisplay->xcolors array (for debugging only).
*
*        Input: none
*       Output: none
*
*   Written By: Danielle Argiro
*
**************************************************************/

print_current_xcolors()
{
    int j;

    fprintf(stderr, "\n    RED\t\tGREEN\t\tBLUE\n\n");
    for (j = 0; j < spc_map_rownum; j++)
    {
        fprintf(stderr, "%d:\t%d\t\t%d\t\t%d\n", j,
                        xvdisplay->xcolors[j].red,
                        xvdisplay->xcolors[j].green,
                        xvdisplay->xcolors[j].blue);

    }
}


/****************************************************************
*
* Routine Name: perform_map_function()
*      Purpose: when the user provides a function of map columns
*		to be used as the Red, Green, or Blue bands, performs
*		the operation and updates the xcolor array accordingly.
*
*        Input: colorband - SpcRed, SpcGreen, or SpcBlue
*               var_list - list of variables involved in function: M0, M1, etc
*               var_num  - size of var list
*       Output: resulting new column of info
*   Written By: Danielle Argiro
*
****************************************************************/

float *perform_map_function(colorband, var_list, var_num) 
int   colorband;
char **var_list;
int   var_num;
{
     int i, *cols; 
     float *new_column;
     float val;
     char temp[MaxLength], *func, *init_string;

     cols = (int *) malloc(var_num * sizeof(int));
     new_column = (float *) malloc (spc_map_rownum * sizeof(float));

     for(i = 0; i < var_num; i++)
     {
        sprintf(temp, var_list[i]);
        cols[i] = atoi(&temp[1]);
     }

     if (colorband == SpcRed) init_string = xvf_strcpy("Red(");
     else if (colorband == SpcGreen) init_string = xvf_strcpy("Green(");
     else if (colorband == SpcBlue) init_string = xvf_strcpy("Blue(");
     
     for (i = 0; i < spc_map_rownum; i++)
     {
	  func = create_function_call(i, cols, var_num, init_string);
          xve_eval_float(SpcId,  func, &val, temp);
	  new_column[i] = val;
     }

     free(cols);
     return(new_column);
}


/****************************************************************
*
* Routine Name: norm_data()
*      Purpose: front end to normalization routine -
*		takes care of normalizing Locally, Globally, or 
*		non-automatic normalizing.
*        Input: col_data     - the column of map data
*		colorband    - one of SpcRed, SpcGreen, SpcBlue
*       Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

int norm_data(col_data, colorband)
float *col_data;
int    colorband;
{
	int   status;
	float min, max, mean, stddev, colormin, colormax;
	char  temp[MaxLength];


	/* 
	 * find min & max of column data and save values 
         */

	if (spc_norm_type == SpcNormLocal)
	{
	    if (spc_norm_method == SpcNormWithinColors)
	    {
	        find_min_max_col_data(col_data, spc_map_rownum, &min, &max);
	        if (((max <= spc_max_colors) && (min >= 0)) && 
		    (spc_norm_time != SpcNormAlways)) return(true);
	    }
	    else if (spc_norm_method == SpcNormWithinStdDev)
	    {
	        find_min_max_col_data(col_data, spc_map_rownum, &colormin, &colormax);
	        mean_stddev(spc_map_rownum, col_data, spc_count, 
			    &mean, &stddev);
	        min = mean - (2*stddev);
	        max = mean + (2*stddev);
	        if (((colormax <= max) && (colormin >= min)) && 
		    (spc_norm_time != SpcNormAlways)) return(true);
	    }

            normalize_col_data(col_data, min, max);
	}
	else if (spc_norm_type == SpcNormGlobal)
	{
	    if (spc_norm_method == SpcNormWithinColors)
            {
	        find_min_max_col_data(current_red_col, spc_map_rownum, &min, &max);
	        set_global_min_max(min, max, SpcRed);
	        find_min_max_col_data(current_green_col, spc_map_rownum, &min, &max);
	        set_global_min_max(min, max, SpcGreen);
	        find_min_max_col_data(current_blue_col, spc_map_rownum, &min, &max);
	        set_global_min_max(min, max, SpcBlue);
    
	        if (((spc_max <= spc_max_colors) && (spc_min >= 0)) && 
		    (spc_norm_time != SpcNormAlways)) return(true);
	    }
	    else if (spc_norm_method == SpcNormWithinStdDev)
            {
		mean_stddev(spc_map_rownum, current_red_col, spc_count,
                            &mean, &stddev);
		min = mean - (2*stddev);
                max = mean + (2*stddev);
	        set_global_min_max(min, max, SpcRed);

		mean_stddev(spc_map_rownum, current_green_col, spc_count,
                            &mean, &stddev);
		min = mean - (2*stddev);
                max = mean + (2*stddev);
	        set_global_min_max(min, max, SpcGreen);

		mean_stddev(spc_map_rownum, current_blue_col, spc_count,
                            &mean, &stddev);
		min = mean - (2*stddev);
                max = mean + (2*stddev);
	        set_global_min_max(min, max, SpcBlue);

	        if (((spc_max <= spc_max_colors) && (spc_min >= 0)) && 
		    (spc_norm_time != SpcNormAlways)) return(true);
	    }
	    normalize_col_data(col_data, spc_min, spc_max);

	}
        else
        {
	    find_min_max_col_data(col_data, spc_map_rownum, &min, &max);
	    if (((max <= spc_max_colors) && (min >= 0)) && 
		(spc_norm_time != SpcNormAlways)) return(true);

            sprintf(temp, "Your new column of map data lies outside the range of 0 - %d. Please indicate whether you prefer to normalize (NORM), or redefine your function (CANCEL).", spc_max_colors);
            status = xvf_warn_wait(temp, "Spectrum", "NORM", "CANCEL");

            if (status == 0) 
		return(false);
	    else if (status == 1)
                normalize_col_data(col_data, min, max);
	}
	return(true);
}

/****************************************************************
*
* Routine Name: set_global_min_max()
*      Purpose: sets global min & max for use with global normalization
*        Input: min - the minimum value of part. column
*		max - the maximum value of part. column
*	Output: none
*   Written By: Danielle Argiro
*
****************************************************************/
set_global_min_max(min, max, colorband)
float min, max;
int  colorband;
{
	if (colorband == SpcRed)
	{
	   red_min = min; red_max = max;
	}
	 
	else if (colorband == SpcGreen)
	{
           green_min = min; green_max = max;
	}
         
	else if (colorband == SpcBlue)
	{
           blue_min = min; blue_max = max;
	}
	spc_min = MIN(red_min, blue_min);
	spc_min = MIN(green_min, spc_min);
	spc_max = MAX(red_max, blue_max);
	spc_max = MAX(green_max, spc_max);
}

/****************************************************************
*
* Routine Name: find_max_min_col_data()
*      Purpose: finds the maximum & minimum values 
*		in a column of map data
*        Input: col_data - the column of map data
*       Output: max - the maximum value
*		min - the minimum value
*   Written By: Danielle Argiro
*
****************************************************************/
find_min_max_col_data(col_data, length, min, max)
float *col_data;
int    length;
float *min;
float *max;
{
	int i;

	*max = col_data[0];  *min = col_data[0];

	for (i = 1; i < length; i++)
	{
	     if (col_data[i] < *min) *min = col_data[i];
	     if (col_data[i] > *max) *max = col_data[i];
	}
}


/****************************************************************
*
* Routine Name: find_max_min_row_data()
*      Purpose: finds the maximum & minimum values 
*		in a row of map data
*        Input: row_data - the column of map data
*       Output: max - the maximum value
*		min - the minimum value
*   Written By: Danielle Argiro
*
****************************************************************/
find_min_max_row_data(row_data, min, max)
float *row_data;
float *min;
float *max;
{
	int i;

	*max = row_data[0];  *min = row_data[0];

	for (i = 1; i < spc_map_colnum; i++)
	{
	     if (row_data[i] < *min) *min = row_data[i];
	     if (row_data[i] > *max) *max = row_data[i];
	}
}

/****************************************************************
*
* Routine Name: normalize_col_data
*      Purpose: normalizes a column of map data to be
*		between 0 and spc_max_colors
*	 Input: col_data - the column of map data
*		datamin  - minimum value found in column of map data
*		datamax  - maximum value found in column of map data
*       Output: normalized column of map data
*   Written By: Danielle Argiro
*
****************************************************************/

normalize_col_data(col_data, datamin, datamax)
float *col_data;
float datamin, datamax;
{
	int i;
	float colormin = 0.0;
	float colormax = (float) spc_max_colors-1;

	if (datamax == datamin) datamax +=0.01;

	/* normalize the data */ 
	for (i = 0; i < spc_map_rownum; i++)
	{
	    col_data[i] = ((col_data[i] - datamin)/(datamax - datamin)) *
			  (colormax - colormin) + colormin;
	    if (spc_norm_method == SpcNormWithinStdDev) 
	    {
	        if ( col_data [i] > colormax ) col_data [i] = colormax;
                if ( col_data [i] < colormin ) col_data [i] = colormin;
	    }

	}
}


/****************************************************************
*
* Routine Name: shift_col_data
*      Purpose: shifts a column of map data to be
*		between 0 and spc_max_colors
*	 Input: col_data - the column of map data
*       Output: shifted column of map data
*   Written By: Danielle Argiro
*
****************************************************************/

shift_col_data(col_data, datamin, datamax)
float *col_data;
float datamin, datamax;
{
	int i;
	float diff;
	float colormin = 0.0;
	float colormax = (float) spc_max_colors-1;

	if ((datamin - datamax) > colormax)
	{
	   fprintf(stderr, "shift_col_data:\n");
	   fprintf(stderr, "data not within range to shift\n");
	   return;
	}
	
	if (datamin < colormin)
	{
	   diff = colormin - datamin;
	   for (i = 0; i < spc_map_rownum; i++)
	       col_data[i] = col_data[i] + diff;
	}

	else if (datamin > colormax)
	{
	   diff = datamax - colormax;
	   for (i = 0; i < spc_map_rownum; i++)
	       col_data[i] = col_data[i] - diff;
	}
}


/****************************************************************
*
* Routine Name: save_unused_classnum
*      Purpose: saves the unused classnum for use when the
*		next class is added
*	 Input: none
*       Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

save_unused_classnum(class)
int  class;
{
	if (spc_unused_classnums == NULL)
	{
  	    spc_unused_classnums = (int *) malloc (sizeof(int));
	    spc_num_unused_classnums = 1;
	    spc_unused_classnums[0] = class;
	}
	else 
	{
	    spc_unused_classnums = (int *) realloc(spc_unused_classnums,
					   (spc_num_unused_classnums +1) *
					    sizeof(int));
	    spc_unused_classnums[spc_num_unused_classnums++] = class;
	}
}


/****************************************************************
*
* Routine Name: set_new_classname
*      Purpose: Prompts for new classname, checks if its already
*		been used, and changes the text widget accordingly.
*
*	 Input: none
*       Output: none
*   Written By: Danielle Argiro
*
****************************************************************/

int set_new_classname(entry_ptr)
LegendEntry *entry_ptr;
{
        int  i; 
        char temp[MaxLength], *get_new_classname();
        Arg  arg[MaxArgs];

	/* assign new text */
	free(entry_ptr->legend_ptr->text);
	entry_ptr->legend_ptr->text = get_new_classname();

	/*
         *  replace old class name w/ new one 
         */
	XtDestroyWidget(entry_ptr->textwid); 
	i = 0;
	XtSetArg(arg[i], XtNfromVert, entry_ptr->RGBwid);	i++;
	XtSetArg(arg[i], XtNfromHoriz, entry_ptr->colorbox);	i++;
        XtSetArg(arg[i], XtNlabel, entry_ptr->legend_ptr->text); i++;
	XtSetArg(arg[i], XtNwidth, xvf_font_width*35);   	i++;
	XtSetArg(arg[i], XtNheight, xvf_font_height);		i++;
	XtSetArg(arg[i], XtNresizable, False);                  i++;
	XtSetArg(arg[i], XtNborderWidth, 1);			i++;
	if (xvf_font != NULL)
        {
            XtSetArg(arg[i],XtNfont, xvf_font);                 i++;
        }
 	sprintf(temp, "lgd_text_%d.%d", display_ptr->widcount, 
		entry_ptr->widrepcount);
	entry_ptr->textwid = XtCreateManagedWidget(temp, commandWidgetClass, 
					entry_ptr->back,arg,i);

	XtAddCallback(entry_ptr->textwid, XtNcallback, legend_textwid_cb, 
		      entry_ptr);

	entry_ptr->widrepcount++;
	return(true);
}


/****************************************************************
*
* Routine Name: striptext
*      Purpose: strips a text string of capital letters & whitespace
*	 Input: string
*       Output: stripped string
*   Written By: Danielle Argiro
*
****************************************************************/
char *striptext(string)
char *string;
{
	char *stripped, *xvf_lower();
	char temp[MaxLength];
	int  i, j;
	int tolower();

	j = 0;
	for (i = 0; i < xvf_strlen(string); i++)
	{
	    if (string[i] != ' ' && string[i] != '\t' && string[i] != '\n')
		temp[j++] = string[i];
	}
	temp[j] = '\0';
	stripped = xvf_lower(temp);
	return(stripped);

}

/****************************************************************
*
* Routine Name: find_unused_classnums
*      Purpose: finds class numbers that are not used
*	 Input: max_classnum  (largest class number)
*       Output: spc_unused_classnums array
*   Written By: Danielle Argiro
*
****************************************************************/
find_unused_classnums(max_classnum)
int max_classnum;
{
	legend_list *legend_ptr;
	int classnum, found;

	classnum = 0;
	
	for (classnum = max_classnum; classnum > 0; classnum--)
	{
	    found = false;
	    legend_ptr = spc_legend_list;
	    while ((legend_ptr != NULL) & !found)
	    {
	        if (legend_ptr->class == classnum) found = true;
		legend_ptr = legend_ptr->next;
	    }
	    if (!found) save_unused_classnum(classnum);
	}
}

/****************************************************************
*
* Routine Name: get_new_classname
*      Purpose: gets a new name for the class
*        Input: none
*       Output: new name
*   Written By: Danielle Argiro
*
****************************************************************/
char *get_new_classname()
{
	legend_list *legend_ptr;
	char *label = "Changing title of class", temp[MaxLength];
        char **answers, **prompts, *response, *button = "OK", *striptext();
	int num_prompts = 1, size = 35;

	prompts = (char **) calloc(1, sizeof(char *));
	answers = (char **) calloc(1, sizeof(char *));
	prompts[0] = xvf_strcpy("Enter new title:");
	answers[0] = (char *) calloc (1, (MaxLength * sizeof(char)));

	/* prompt for class name */
	response = xvf_query_wait(label,prompts,button,
				  answers,num_prompts, size);
	if (response == NULL) return(NULL);

	/* make sure that name is not already used */
	legend_ptr = spc_legend_list;
	while (legend_ptr != NULL)
	{
	    if (legend_ptr->text != NULL) 
	    {
	        if (strcmp(striptext(legend_ptr->text), striptext(response))==0)
	        {
	            sprintf(temp, "There is already a class named, '%s'.  Please provide a distinct name.", legend_ptr->text);
	            xvf_error_wait(temp, "Spectrum", NULL);
	            return(false);
	        }
	    }
	    legend_ptr = legend_ptr->next;
	}

	return(xvf_strcpy(response));
}

/****************************************************************
*
* Routine Name: copy_column()
*      Purpose: copies a column of data
*        Input: column - column of data
*       Output: new column
*   Written By: Danielle Argiro
*
****************************************************************/
float *copy_column(column)
float *column;
{
	int i;
	float *new_col;
	
	new_col = (float *) malloc(spc_map_rownum * sizeof(float));
	for (i = 0; i < spc_map_rownum; i++)
	    new_col[i] = column[i];
	return(new_col);
}


/****************************************************************
*
* Routine Name: find_legend_from_text()
*      Purpose: given some text, returns the legend node it is
*		associated with
*        Input: text - text to key on
*       Output: legend_ptr
*   Written By: Danielle Argiro
*
****************************************************************/
legend_list *find_legend_from_text(text)
char *text;
{
	legend_list *legend_ptr;

	legend_ptr = spc_legend_list;
	while (legend_ptr != NULL)
	{
	   if (strcmp(legend_ptr->text, text) == 0) 
		return(legend_ptr);
  	   legend_ptr = legend_ptr->next;
	}
	return(legend_ptr);
}


/****************************************************************
*
* Routine Name: get_cluster(widget)
*      Purpose: gets cluster number from cursor position in 
*		image or zoom box		
*        Input: widget - image or zoom box
*       Output: cluster number
*   Written By: Danielle Argiro & Mark Young
*
****************************************************************/
int get_cluster(widget, x, y)
Widget widget;
int    x, y;
{
	int i, xpos, ypos, cluster, found;
	double value;
	Dimension xoffset, yoffset;
	Arg arg[MaxArgs];

	if (widget == plot_workspace)
	{
             if (xvd_query_position(widget, &xpos, &ypos, True))
	 	cluster = -1;
             i = 0;
             XtSetArg(arg[i], XtNxoffset, &xoffset);  i++;
             XtSetArg(arg[i], XtNyoffset, &yoffset);  i++;
             XtGetValues(xvdisplay->raster, arg, i);

	     if ((x == -1) || (y == -1))
	     {
		x = xpos;
	 	y = ypos;
	     }
             x += xoffset;
             y += yoffset;

	     found  = false;  i = 0;
             while (i < spc_unique_values && !found)
             {
                 if ((ABS(x - spc_x_dcs[i]) < 3) && (ABS(y - spc_y_dcs[i]) < 3))
                     found = true;
                 else i++;
             }
             if (!found) cluster = -1;
	     else cluster = i;
	}
	else if (widget == zoom->raster)
	{
	    get_zoom_position(widget, zoom, &x, &y);
	    if ((x == -1) || (y == -1)) return(-1);
	    xvd_query_value(xvdisplay, x, y, &value, NULL, NULL);
            cluster = (int) value;
	}
	else if (widget == xvdisplay->raster)
	{
            if (xvd_query_position(widget, &xpos, &ypos, True))
		cluster = -1;
            i = 0;
            XtSetArg(arg[i], XtNxoffset, &xoffset);  i++;
            XtSetArg(arg[i], XtNyoffset, &yoffset);  i++;
            XtGetValues(xvdisplay->raster, arg, i);

	    if ((x == -1) || (y == -1))
	    {
		x = xpos;
		y = ypos;
	    }
            x += xoffset;
            y += yoffset;

            xvd_query_value(xvdisplay, x, y, &value, NULL, NULL);
            cluster = (int) value;

	}
        return(cluster);
}
