 /*
  * Khoros: $Id: ldem2viff.c,v 1.1 1991/05/10 15:43:29 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: ldem2viff.c,v 1.1 1991/05/10 15:43:29 khoros Exp $";
#endif

 /*
  * $Log: ldem2viff.c,v $
 * Revision 1.1  1991/05/10  15:43:29  khoros
 * Initial revision
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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 too 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 */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: ldem2viff.c
 >>>>
 >>>>      Program Name: dem2viff
 >>>>
 >>>> Date Last Updated: Tue Apr  9 12:30:34 1991 
 >>>>
 >>>>          Routines: ldem2viff - the library call for dem2viff
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
#include "file_formats/dem.h"
/* -library_includes_end */


/****************************************************************
*
* Routine Name: ldem2viff - library call for dem2viff
*
* Purpose:
*    
*    Convert DEM format data to VIFF format.
*    
*    
* Input:
*    
*         1.  viffimage -- a double pointer to a structure of
*                          type xvimage.  Only a pointer is
*                          needed, the structure should not be
*                          malloced.
*         2.  demimage  -- a pointer to a structure of type
*                          demimage.  This structure should be
*                          allocated and should contain the DEM
*                          data.
*         3.  location  -- a flag which tells this routine if the
*                          output viff data should have implicit
*                          (0) or explicit (1) location data.
*         4.  sfactor   -- an integer which gives the ratio by
*                          which the DEM data should be
*                          subsampled before being written to
*                          the viff image.
*    
*    
* Output:
*    
*         1.  viffimage -- upon exit this double pointer will
*                          point to a struture of type xvimage
*                          that is allocated and filled with the
*                          viff data.
*    
*         viffimage is modified to point to the output  structure,  so
*         be careful that you do not overwrite an important pointer.
*    
*    
*
* Written By: Per Lysne
*    
*    
****************************************************************/


/* -library_def */
int ldem2viff(xv_img, dem_img, loc_flag, scale_factor)
struct xvimage **xv_img;
struct demimage *dem_img;
int loc_flag, scale_factor;
/* -library_def_end */

/* -library_code */
{
    int x, y;
    int i, j, xv_rows, xv_cols, dem_rows, dem_cols, index;
    int loc_type, loc_dim;
    float *imagedata, *x_loc_ptr, *y_loc_ptr, elevation;
    float xres, yres;
    float x_base, y_base;
    float northing, base_northing, northing_range, min_northing, max_northing;
    float tmp_min, tmp_max;
    struct xvimage *new_img, *createimage();

    /*
     * Error check the inputs.
     */
    if (dem_img == NULL) {
        fprintf (stderr, "error in ldem2viff: bad DEM image input\n");
        return (0);
    }
    if ((loc_flag != 0) && (loc_flag != 1)) {
        fprintf (stderr, "error in ldem2viff: bad location flag input\n");
        return (0);
    }
    if (scale_factor <= 0) {
        fprintf (stderr, "error in ldem2viff: bad scaling factor input\n");
        return (0);
    }

    /*
     * Check important information about the DEM data.
     */
    if (dem_img->pattern != 1) {
        fprintf(stderr,"error in ldem2viff: DEM data must be evenly sampled\n");
        exit (0);
    }
    if ((dem_img->reference != 0) && (dem_img->reference != 1)) {
        fprintf (stderr, "error in ldem2viff: DEM data must use either ");
        fprintf (stderr, "geographic or utm coordinate system\n");
        exit (0);
    }

    /*
     * Check that the coordinates in the DEM data are given in units 
     * we understand.
     */
    if (dem_img->reference == 0) { /* 1-degree DEM */
        if (dem_img->groundunit != ARC_SECONDS) {
            fprintf (stderr, "error in ldem2viff: 1-degree DEM data must ");
            fprintf (stderr, "have coordinates given in arc seconds\n");
            return (0);
        }
    }
    else { /* 7.5-minute DEM */
        if (dem_img->groundunit != METERS) {
            fprintf (stderr, "error in ldem2viff: 7.5-minute DEM data must ");
            fprintf (stderr, "have coordinates given in meters\n");
            return (0);
        }
    }

    /*
     * Check that the elevations are given in units that we understand.
     */
    if (dem_img->reference == 0) { /* 1-degree DEM */
        if (dem_img->elevationunit != METERS) {
            fprintf (stderr, "error in ldem2viff: 1-degree DEM data must ");
            fprintf (stderr, "have elevations given in meters\n");
            return (0);
        }
    }
    else { /* 7.5-minute DEM */
        if (dem_img->elevationunit != METERS) {
            fprintf (stderr, "error in ldem2viff: 7.5-minute DEM data must ");
            fprintf (stderr, "have elevations given in meters\n");
            return (0);
        }
    }

    /*
     * Set the location type for the output image.
     */
    if (loc_flag == 0) {
        loc_type = VFF_LOC_IMPLICIT;
        loc_dim = 0;
    }
    else {
        loc_type = VFF_LOC_EXPLICIT;
        loc_dim = 2;
    }

    /*
     * If the zone is set to 0, the the data is from a 1-degree DEM file,
     * otherwise the data is from a 7.5-minute DEM file.  I am going to
     * keep the code for both files ENTIRELY separate.  This might seem
     * like a waste of space, since a lot of the code will be the same,
     * but I believe this will make life much easier for anyone who needs
     * to modify this program.
     */
    if (dem_img->zone == 0) { /* 1-degree DEM data */

        /*
         * Determine the size of the output image.  Since the array of
         * samples in a 1-degree DEM is a square, we can drop it straight
         * in to the viff image.  The number of rows is given by the number
         * of points in the first profile, while the number of columns is
         * given by the nubmer of profiles in the data.
         */
        dem_rows = dem_img->data[0]->numrows;
        dem_cols = dem_img->numcolumns;
        xv_rows = (int) (dem_rows/scale_factor);
        xv_cols = (int) (dem_cols/scale_factor);

        /*
         * Create the output image for the DEM data.
         */
        new_img = createimage (xv_rows, xv_cols, VFF_TYP_FLOAT, 1, 
                              1, "", 0, 0,
                              VFF_MS_NONE, VFF_MAPTYP_NONE, loc_type, loc_dim);
        if (new_img == NULL) {
            fprintf (stderr, "error in ldem2viff: createimage failed\n");
            return (0);
        }
        bzero (new_img->imagedata, xv_rows*xv_cols*sizeof(float));
        if (loc_type == VFF_LOC_EXPLICIT)
            bzero (new_img->location, xv_rows*xv_cols*loc_dim*sizeof(float));

        /*
         * Copy the header comment from the DEM into the viff header.
         */
        strncpy (new_img->comment, dem_img->name, 144);

        /* 
         * Copy the pixel size from the DEM to the viff.
         */
        new_img->pixsizx = (float) dem_img->xres;
        new_img->pixsizy = (float) dem_img->yres;

        /*
         * Set the trash field in the new image to 0.  This will denote
         * that the data in this image is given in geographical coordinates.
         */
        new_img->trash[0] = 0;

        /*
         * Some useful values.
         */
        imagedata = (float *) new_img->imagedata;
        x_loc_ptr = new_img->location;
        y_loc_ptr = &(new_img->location [xv_rows * xv_cols]);
        xres = (float) dem_img->xres;
        yres = (float) dem_img->yres;
        x_base = (float) dem_img->data[0]->xground;
        y_base = (float) dem_img->data[0]->yground;

        /*
         * Transfer the elevation data from the dem image to the xv image.
         * The index 'i' is going backwards because the data in the DEM is
         * ordered from west to east, but we are writing the image from
         * east to west.
         */
        index = 0;
        for (i=xv_rows-1; i>=0; i=i-1 ) {
            for (j=0; j<xv_cols; j++) {

                /*
                 * Multiply the elevation data by the z-resolution and add
                 * the base elevation before storing it in the viff image.
                 */
                x = j*scale_factor;
                y = i*scale_factor;

                elevation = (float) dem_img->data[x]->data[y];
                elevation = elevation + (float)dem_img->data[x]->elevation;

                imagedata[index] = elevation;

                /*
                 * Set the explicit location of each data point if the flag
                 * location is set.
                 */
                if (loc_flag != 0) {
                    x_loc_ptr[index] = (float)(x * xres + x_base);
                    y_loc_ptr[index] = (float)(y * yres + y_base);
                }

                index = index+1;
            }
        }
    }

    else { /* 7.5-minute DEM data */

        /*
         * Set some useful variables.
         */
        dem_cols = dem_img->numcolumns;
        xres = (float) dem_img->xres;
        yres = (float) dem_img->yres;

        /*
         * Find the minimum and maximum northings in the file by looping
         * through each of the profiles.
         */
        min_northing = dem_img->data[0]->yground;
        max_northing = min_northing + (dem_img->data[0]->numrows-1) * yres;
        for (i=1; i<dem_cols; i++) {
            tmp_min = dem_img->data[i]->yground;
            tmp_max = tmp_min + (dem_img->data[i]->numrows-1) * yres;
            if (tmp_min < min_northing)
                min_northing = tmp_min;
            if (tmp_max > max_northing)
               max_northing = tmp_max;
        }

        /*
         * Determine the number of rows in the DEM data by dividing the
         * range of the data by the resolution of each sample.  The number
         * of columns is still given in the DEM header.
         */
        dem_rows = (int) ((max_northing - min_northing)/(yres)) + 1;
        dem_cols = dem_img->numcolumns;
        xv_rows = (int) (dem_rows/scale_factor);
        xv_cols = (int) (dem_cols/scale_factor);
  
        /*
         * Create the output image for the DEM data.
         */
        new_img = createimage (xv_rows, xv_cols, VFF_TYP_FLOAT, 1, 
                              1, "", 0, 0,
                              VFF_MS_NONE, VFF_MAPTYP_NONE, loc_type, loc_dim);
        if (new_img == NULL) {
            fprintf (stderr, "error in ldem2viff: createimage failed\n");
            return (0);
        }
        bzero (new_img->imagedata, xv_rows*xv_cols*sizeof(float));
        if (loc_type == VFF_LOC_EXPLICIT)
            bzero (new_img->location, xv_rows*xv_cols*loc_dim*sizeof(float));

        /*
         * Copy the header comment from the DEM into the viff header.
         */
        strncpy (new_img->comment, dem_img->name, 144);

        /* 
         * Copy the pixel size from the DEM to the viff.
         */
        new_img->pixsizx = (float) dem_img->xres;
        new_img->pixsizy = (float) dem_img->yres;

        /*
         * Set the trash field in the new image to the utm zone code.
         * This will denote that the data in this image is given in utm
         * coordinates.
         */
        new_img->trash[0] = (char) dem_img->zone;

        /*
         * Some useful values.
         */
        imagedata = (float *) new_img->imagedata;
        x_loc_ptr = new_img->location;
        y_loc_ptr = &(new_img->location [xv_rows * xv_cols]);
        xres = (float) dem_img->xres;
        yres = (float) dem_img->yres;
        x_base = (float) dem_img->data[0]->xground;
        y_base = (float) dem_img->data[0]->yground;
        northing_range = max_northing - min_northing;
       

        /*
         * Transfer the DEM data into the viff image.  Remember that the
         * DEM image is not a square in this case, so it is not so easy to
         * determine where to place each pixel in the viff image.
         */
        for (x=0; x<dem_cols; x += scale_factor) {
 
            /*
             * Northing of the southern most point in the profile.
             */
            base_northing = dem_img->data[x]->yground;

            for (y=0; y<dem_img->data[x]->numrows; y += scale_factor) {

                /*
                 * Get the elevation out of the DEM image.
                 */
                elevation = (float) dem_img->data[x]->data[y];
                elevation = elevation + dem_img->data[x]->elevation;

                /*
                 *
                 *
                 */
                northing = (y * yres) + base_northing;
                i = (int) (((northing-min_northing)/northing_range) * xv_rows);
                i = xv_rows -i;
                j = (int) (x/scale_factor);

                /*
                 * Store the elevation in the viff image.
                 */
                index = j + i*xv_cols;
                imagedata[index] = elevation;

                /*
                 * Set the explicit location of each data point if the
                 * location flag is set.
                 */
                if (loc_flag != 0) {
                    x_loc_ptr[index] = x * xres + x_base;
                    y_loc_ptr[index] = y * yres + y_base;
                }
            }
        }
    }

    /*
     * Transfer the data from the dem image to the viff image.  The value
     * dem->numcolumns gives the number of columns in the file.  The value
     * dem->data[0]->numrows gives the number of data points in the first
     * column.  I am assuming the later is the same for all of the columns,
     * which is only true for 1-degree DEM data.
     */

    /*
     * Return the viff image containing the DEM data.
     */
    *xv_img = new_img;
    return (1);
}
/* -library_code_end */
