 /*
  * Khoros: $Id: ldlg2viff.c,v 1.2 1991/12/18 09:49:05 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: ldlg2viff.c,v 1.2 1991/12/18 09:49:05 dkhoros Exp $";
#endif

 /*
  * $Log: ldlg2viff.c,v $
 * Revision 1.2  1991/12/18  09:49:05  dkhoros
 * HellPatch3
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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: ldlg2viff.c
 >>>>
 >>>>      Program Name: dlg2viff
 >>>>
 >>>> Date Last Updated: Tue Apr  9 12:53:37 1991 
 >>>>
 >>>>          Routines: ldlg2viff - the library call for dlg2viff
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
#include "file_formats/dlg.h"

#define max(a,b)\
        ((((double)a<0.0 ? (double)-(a) : (double)a)  <    \
          ((double)b<0.0 ? (double)-(b) : (double)b)) ? (double)b : (double)a)
 
#define min(a,b)\
        ((((double)a<0.0 ? (double)-(a) : (double)a)  <    \
          ((double)b<0.0 ? (double)-(b) : (double)b)) ? (double)a : (double)b)

extern int dlg_line();
extern int dlg_point();

int ldlg2viff();
static int do_nodes();
static int assign_node_attribs();
static int plot_node();
static int do_lines();
static int assign_line_attribs();
static int plot_line();
static int count_attrib();
static int search_for_attrib();
static int add_attrib();
/* -library_includes_end */


/****************************************************************
*
* Routine Name: ldlg2viff - library call for dlg2viff
*
* Purpose:
*    
*    Convert a DLG format vector file to VIFF format.
*    
*    
* Input:
*    
*    1.  dlgimg - a pointer to a dlgimage structure.  This
*                 structure should not be allocated as it
*                 will be in the library.
*    2.  rows   - the number of rows in the xvimage that the
*                 dlg data is to be rasterized and stored
*                 to.
*    3.  cols   - the number of columns in the xvimage that
*                 the dlg data is to be rasterized and
*                 stored to.
*    4.  loc_flag  - an integer flag which specifies the
*                 type of locations to be written with the
*                 output files.  0=no location data,
*                 1=sparse location data, 2=full location
*                 data.
*    
*    
* Output:
*    
*    1.  xv_img1  - a double pointer to the xvimage structure
*                 that is returned for the first DLG category
*    2.  xv_img1  - a double pointer to the xvimage structure
*                 that is returned for the second DLG category
*    3.  xv_img1  - a double pointer to the xvimage structure
*                 that is returned for the third DLG category
*    4.  xv_img1  - a double pointer to the xvimage structure
*                 that is returned for the fourth DLG category
*    
*    This function returns 1 on success and 0 on failure.
*    
*    
*
* Written By: Per Lysne
*    
*    
****************************************************************/


/* -library_def */
int
ldlg2viff (dlgimg, rows, cols, loc_flag,
           xv_img1, xv_img2, xv_img3, xv_img4)
struct dlgimage *dlgimg;
int rows, cols, loc_flag;
struct xvimage **xv_img1, **xv_img2, **xv_img3, **xv_img4;
/* -library_def_end */

/* -library_code */
{
    int catno, err;
    int loc_type, loc_dim;
    short *maps;
    struct xvimage *xvimg, *createimage();
    int *attriblist, numattribs, i;
    double utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge;
    void dlg_convert_coords();

    /*
     * Use the file to ground projection paramters to make sure the units
     * are all given in utm.
     */
    dlg_convert_coords (dlgimg);

    /*
     * Extract the utm coordinates of the corners of the area of coverage
     * from the dlg image.  Since the utm area is a quad rather than a
     * perfect square, make sure that the square we define is large
     * enough to hold the quad.
     */
    utm_west_edge =
        min (dlgimg->corners[SW][INTERNAL_X], dlgimg->corners[NW][INTERNAL_X]);
    utm_south_edge =
        min (dlgimg->corners[SW][INTERNAL_Y], dlgimg->corners[SE][INTERNAL_Y]);
    utm_east_edge =
        max (dlgimg->corners[NE][INTERNAL_X], dlgimg->corners[SE][INTERNAL_X]);
    utm_north_edge =
        max (dlgimg->corners[NW][INTERNAL_Y], dlgimg->corners[NE][INTERNAL_Y]);

    /*
     * Process each category in the dlg file separately.
     */
    for (catno=0; catno<dlgimg->num_categories; catno++) {

        /*
         * Create a list of all of the attribute pairs in the dlg category.
         * This is done so that we know how many image bands this category
         * will need.
         */
        attriblist=NULL;
        numattribs=0;
        if (count_attrib(&(dlgimg->categories[catno]),&attriblist,
                           &numattribs)==0){
            fprintf (stderr, "error in ldlg2viff - ");
            fprintf (stderr, "call to count_attrib failed\n");
            return (0);
        }

        /*
         * These variables will be used to create the new image.
         */
        if (loc_flag == 0) {
            loc_type = VFF_LOC_IMPLICIT;
            loc_dim = 0;
        }
        else {
            loc_type = VFF_LOC_EXPLICIT;
            loc_dim = 2;
        }

        /*
         * Create the image that will be the output for this band.
         */
        xvimg = createimage (rows, cols, VFF_TYP_BIT, 1,
                          numattribs + 1, "bit image from dlg2viff", 2, 1,
                          VFF_MS_ONEPERBAND, VFF_MAPTYP_2_BYTE,
                          loc_type, loc_dim);
        if (xvimg == NULL) {
            fprintf (stderr, "error in ldlg2viff - createimage failed ");
            fprintf (stderr, "cat. no. %d\n", catno);
            return (0);
        }
        bzero (xvimg->imagedata, rows*cols*(numattribs+1)/8);

        /* 
         * Write the attributes for each band into its map.  Remember
         * that the first band is reserved for nodes with no attributes.
         */
        maps = (short *) xvimg->maps;
        maps[0]=0;
        maps[1]=0;
        for (i=0; i<numattribs; i++) {
            maps[2*i+2]=attriblist[2*i];
            maps[2*i+3]=attriblist[2*i+1];
        }

        /*
         * Process all of the nodes for this category.
         */
        err = do_nodes (dlgimg, xvimg, catno);
        if (err != 1) {
            fprintf (stderr, "error in ldlg2viff - ");
            fprintf (stderr, "call to do_nodes failed for cat. %d\n", catno);
            return (0);
        }

        /*
         * Process all of the lines for this category.
         */
        err = do_lines (dlgimg, xvimg, catno);
        if (err != 1) {
            fprintf (stderr, "error in ldlg2viff - ");
            fprintf (stderr, "call to do_lines failed for cat. %d\n", catno);
            return (0);
        }

        /*
         * Assign all of the locations in the image.
         */
        if (loc_flag != 0) {
            err = assign_locations (xvimg,
                                   utm_west_edge, utm_south_edge,
                                   utm_east_edge, utm_north_edge);
            if (err != 1) {
                fprintf(stderr,"error in ldlg2viff: assign_locations failed\n");
                return (0);
            }
        }

        /*
         * If sparse locations were requested, then thin out the locations
         * corresponding to no data.
         */
        if (loc_flag == 1) {
            if (!cut_locations(xvimg)) {
                fprintf (stderr, "error in ldlg2viff: cut_locations failed\n");
                return (0);
            }
        }

        /*
         * Decide which of the six image outputs this category belongs to
         * and assign it.
         */
        if (catno == 0) {
            *xv_img1 = xvimg;
        }
        else if (catno == 1) {
            *xv_img2 = xvimg;
        }
        else if (catno == 2) {
            *xv_img3 = xvimg;
        }
        else if (catno == 3) {
            *xv_img4 = xvimg;
        }
        else {
            fprintf (stderr, "error in ldlg2viff: bad category number!\n");
            return (0);
        }
    }

    return (1);
}



/****************************************************************
*
* Routine: do_nodes
*
* Purpose: This function plots all of the nodes in a single category
*          of a dlg file.
*
*   Input: A pointer to a dlgimage structure, a pointer to an xvimage
*          structure, and a pointer to a dlgcategory structure within
*          the dlgimage.
*
*  Output: The nodes will be plotted in the xvimage.  Returns 1 on
*          success and 0 on failure.
*
*  Author: Per Lysne  9/8/90
*
****************************************************************/
static int
do_nodes (dlgimg, xvimg, catno)
struct dlgimage *dlgimg;
struct xvimage *xvimg;
int catno;
{
int rows, cols;
    int err, band, attrib, nodeno;
    int majorattrib, minorattrib;
    int *file_attriblist, file_attribno, *node_attriblist, node_attribno;
    double arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge;
    double utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge;
    char *bandptr;
    struct dlgcategory *catptr;
    struct dlgnode *nodeptr;

    if (dlgimg == NULL) {
        fprintf (stderr, "error in do_nodes - ");
        fprintf (stderr, "bad dlg image entered\n");
        return (0);
    }
    if (xvimg == NULL) {
        fprintf (stderr, "error in do_nodes - ");
        fprintf (stderr, "bad xv image entered\n");
        return (0);
    }
    if (catno<0 || catno>=dlgimg->num_categories) {
        fprintf (stderr, "error in do_nodes - ");
        fprintf (stderr, "bad cat. number entered\n");
        return (0);
    }

    /*
     * Extract the lon-lat coordinates of the corners of the area of
     * coverage from the dlg image and convert them to arc-seconds.
     */
    arc_west_edge = 
        min (dlgimg->corners[SW][LONGITUDE], dlgimg->corners[NW][LONGITUDE]);
    arc_west_edge = arc_west_edge * 60.0 * 60.0;
    arc_south_edge =
        min (dlgimg->corners[SW][LATITUDE], dlgimg->corners[SE][LATITUDE]);
    arc_south_edge = arc_south_edge * 60.0 * 60.0;
    arc_east_edge =
        max (dlgimg->corners[NE][LONGITUDE], dlgimg->corners[SE][LONGITUDE]);
    arc_east_edge = arc_east_edge *60.0 * 60.0;
    arc_north_edge =
        max (dlgimg->corners[NW][LATITUDE], dlgimg->corners[NE][LATITUDE]);
    arc_north_edge = arc_north_edge *60.0 * 60.0;

    /*
     * Extract the utm coordinates of the corners of the area of coverage
     * from the dlg image.  Since the utm area is a quad rather than a
     * perfect square, make sure that the square we define is large
     * enough to hold the quad.
     */
    utm_west_edge =
        min (dlgimg->corners[SW][INTERNAL_X], dlgimg->corners[NW][INTERNAL_X]);
    utm_south_edge =
        min (dlgimg->corners[SW][INTERNAL_Y], dlgimg->corners[SE][INTERNAL_Y]);
    utm_east_edge =
        max (dlgimg->corners[NE][INTERNAL_X], dlgimg->corners[SE][INTERNAL_X]);
    utm_north_edge =
        max (dlgimg->corners[NW][INTERNAL_Y], dlgimg->corners[NE][INTERNAL_Y]);

    rows=xvimg->number_of_rows;
    cols=xvimg->number_of_cols;
    /*
     * Get a list of all of the attributes in this category.  This will
     * be used to tell which attribute goes in which band.
     */
    file_attriblist=NULL;
    file_attribno=0;
    catptr = &(dlgimg->categories[catno]);
    err = count_attrib (catptr, &file_attriblist, &file_attribno);
    if (err != 1) {
        fprintf (stderr, "error in do_nodes - ");
        fprintf (stderr, "call to count_attrib failed\n");
    }

    /*
     * Repeat this loop for each node in the category.
     */
    for (nodeno=0; nodeno<catptr->act_nodes; nodeno++) {
        nodeptr = catptr->nodes[nodeno];

        /*
         * Get a list of attributes associated with this node so we
         * know which bands to plot it in.
         */
        node_attriblist=NULL;
        node_attribno=0;
        err = assign_node_attribs (dlgimg, catptr, nodeptr,
                                   &node_attriblist, &node_attribno);
        if (err != 1) {
            fprintf (stderr, "error in do_nodes - ");
            fprintf (stderr, "call to assign_node_attribs failed\n");
            return (0);
        }
   
        /*
         * If we couldn't assign any attributes to the node, then plot it
         * in band 0.
         */
        if (node_attribno == 0) {
            err = plot_node (
                  utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge,
                  arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                  rows, cols,
                  xvimg->imagedata, nodeptr);
            if (err != 1) {
                fprintf (stderr,"error in ldlg2viff - plot_node failed ");
                fprintf (stderr, "for node no. %d\n", nodeno);
                return (0);
            }
        }

        /*
         * If we could assign attributes, go through the list and plot the
         * node in the appropriate bands.
         */
        for (attrib=0; attrib<node_attribno; attrib++) {
            majorattrib = node_attriblist[attrib*2];
            minorattrib = node_attriblist[attrib*2 +1];

            /*
             * Decide which bands to plot the node in.
             */
            band = search_for_attrib(&file_attriblist, &file_attribno,
                                     majorattrib, minorattrib);
            if (band < 0) {
                fprintf (stderr, "error in do_nodes - ");
                fprintf (stderr, "error in node attributes list\n");
            }
            band = band/2;

            /*
             * Increment band by one because band 0 is reserved for things
             * with no attributes.
             */
            band = band+1;

            /*
             * Plot the node in the desired band.  Remember that it is a bit
             * image, so rows and cols must be divided by 8.
             */
            bandptr = xvimg->imagedata + band*rows*((cols+7)/8);
            err = plot_node (
                  utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge,
                  arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                  xvimg->number_of_rows, xvimg->number_of_cols,
                  bandptr, nodeptr);
            if (err != 1) {
                fprintf (stderr,"error in ldlg2viff - plot_node failed ");
                fprintf (stderr, "for node no. %d\n", nodeno);
                return (0);
            }
        }

        if (node_attriblist != NULL) free (node_attriblist);
    }

    if (file_attriblist != NULL) free (file_attriblist);
    return (1);
}



/****************************************************************
*
* Routine: assign_node_attribs
*
* Purpose: Creates a list of the attributes belonging to a single node.
*
*   Input: A pointer to a dlgimage, a pointer to a category within that
*          dlgimage, a pointer to a node within that category.
*
*  Output: An array of attributes, and the number of attributes in that
*          array.  Num is the number of pairs of attributes, not of
*          single attributes.  Returns 1 on success and 0 on failure.
*
*  Author: Per Lysne  9/8/90
*
****************************************************************/
static int
assign_node_attribs (dlgimg, catptr, nodeptr, list, num)
struct dlgimage *dlgimg;
struct dlgcategory *catptr;
struct dlgnode *nodeptr;
int **list, *num;
{
    int attrib, err, majorattrib, minorattrib, line, segmentno, found;
    struct dlgline *segmentptr;

    if (dlgimg == NULL) {
        fprintf (stderr, "error in assign_node_attribs - ");
        fprintf (stderr, "bad dlg image input\n");
        return (0);
    }
    if (catptr == NULL) {
        fprintf (stderr, "error in assign_node_attribs - ");
        fprintf (stderr, "bad category input\n");
        return (0);
    }
    if (nodeptr == NULL) {
        fprintf (stderr, "error in assign_node_attribs - ");
        fprintf (stderr, "bad node input\n");
        return (0);
    }
    if (list == NULL) {
        fprintf (stderr, "error in assign_node_attribs - ");
        fprintf (stderr, "bad list pointer input\n");
        return (0);
    }
    if (num == NULL) {
        fprintf (stderr, "error in assign_node_attribs - ");
        fprintf (stderr, "bad number input\n");
        return (0);
    }

    /*
     * Add any attributes associated with the node to the list of
     * the nodes attributes.
     */
    *num=0;
    for (attrib=0; attrib < nodeptr->numattributes; attrib++) {
        majorattrib = nodeptr->majorattributes[attrib];
        minorattrib = nodeptr->minorattributes[attrib];
        err = add_attrib (list, num, majorattrib, minorattrib);
        if (err != 1) {
            fprintf (stderr, "error in assign_node_attribs - ");
            fprintf (stderr, "call to add_attrib failed\n");
            return (0);
        }
    }

    /*
     * Search the segments that begin or end at the node for additional
     * attributes that should be assigned to the node.
     */
    for (line=0; line<nodeptr->numsegments; line++) {
        segmentno = nodeptr->segments[line];
        segmentno = abs(segmentno);
        segmentno = segmentno-1;     /* Lines are #ed from 1, array is from 0 */
        segmentptr = catptr->lines[segmentno];
        for (attrib=0; attrib<segmentptr->numattributes; attrib++) {
            majorattrib = segmentptr->majorattributes[attrib];
            minorattrib = segmentptr->minorattributes[attrib];
            found = search_for_attrib(list, num, majorattrib, minorattrib);
            if (found <= 0) {
                err = add_attrib(list, num, majorattrib, minorattrib);
                if (err != 1) {
                    fprintf (stderr, "error in assign_node_attribs - ");
                    fprintf (stderr, "call to add_attrib failed\n");
                    return (0);
                }
            }
        }
    }

    return (1);
}



/****************************************************************
*
* Routine: plot_node
*
* Purpose: This function plots a point in an image band to represent
*          a node on a dlg map.  The location data IS NOT set here.
*
*   Input: The first eight inputs are give the utm and arc coordinates
*          of the four corners of a square region.  Utm_x_sw gives the
*          x coordinate of the west edge of the region, and arc_west_edge
*          gives the same location in arc-seconds of longitude.  Rows and
*          cols give the size of the image that the node is being plotted
*          in, and band is a pointer to the image.  Nodeptr is a pointer
*          to the dlgnode structure of the node to plot.
*
*  Output: The only output is a point plotted in the band of the image
*          represented by the param. band.  This function returns 1
*          upon success an 0 on failure.
*
* Comment: The inputs are double, and lon-lat coordinates are given in
*          arc-seconds.
*
*  Author: Per Lysne  8/27/90
*
****************************************************************/
static int
plot_node (utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne,
           arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
           rows, cols, band, nodeptr)
double utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne;
double arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge;
int rows, cols;
char *band;
struct dlgnode *nodeptr;
{
    int x_pix, y_pix;
    double x_arc, y_arc;

    if (utm2arc (utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne,
       arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
       nodeptr->x_coordinate, nodeptr->y_coordinate, &x_arc, &y_arc) != 1) {
        fprintf (stderr, "error in plot_node - utm2arc failed\n");
        return (0);
    }

    if (arc2pixel(arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                  rows, cols, x_arc, y_arc, &x_pix, &y_pix) != 1) {
        fprintf (stderr, "error in plot_node - arc2pixel failed\n");
        return (1);
    }

    if (dlg_line (band, rows, cols, x_pix, y_pix, x_pix, y_pix) != 1) {
        fprintf (stderr, "error in plot_node - dlg_line failed\n");
        return (0);
    }

    return (1);
}



/****************************************************************
*
* Routine: do_lines
*
* Purpose: Plots all of the lines in a single category of a dlg image
*          into a viff image.
*
*   Input: A pointer to a dlgimage, a pointer to a viff image, and
*          a pointer to a category within the dlgimage.
*
*  Output: The lines for this category are plotted into the viff image.
*          Returns 1 on success and 0 on failure.
*
*  Author: Per Lysne  9/8/90
*
****************************************************************/
static int
do_lines (dlgimg, xvimg, catno)
struct dlgimage *dlgimg;
struct xvimage *xvimg;
int catno;
{
int rows, cols;
    int err, band, attrib, lineno;
    int majorattrib, minorattrib;
    int *file_attriblist, file_attribno, *line_attriblist, line_attribno;
    double arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge;
    double utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge;
    char *bandptr;
    struct dlgcategory *catptr;
    struct dlgline *lineptr;


    if (dlgimg == NULL) {
        fprintf (stderr, "error in do_lines - ");
        fprintf (stderr, "bad dlg image entered\n");
        return (0);
    }
    if (xvimg == NULL) {
        fprintf (stderr, "error in do_lines - ");
        fprintf (stderr, "bad xv image entered\n");
        return (0);
    }
    if (catno<0 || catno>=dlgimg->num_categories) {
        fprintf (stderr, "error in do_lines - ");
        fprintf (stderr, "bad cat. number entered\n");
        return (0);
    }

    /*
     * Extract the lon-lat coordinates of the corners of the area of
     * coverage from the dlg image and convert them to arc-seconds.
     */
    arc_west_edge =
        min (dlgimg->corners[SW][LONGITUDE], dlgimg->corners[NW][LONGITUDE]);
    arc_west_edge = arc_west_edge * 60.0 * 60.0;
    arc_south_edge =
        min (dlgimg->corners[SW][LATITUDE], dlgimg->corners[SE][LATITUDE]);
    arc_south_edge = arc_south_edge * 60.0 * 60.0;
    arc_east_edge =
        max (dlgimg->corners[NE][LONGITUDE], dlgimg->corners[SE][LONGITUDE]);
    arc_east_edge = arc_east_edge * 60.0 * 60.0;
    arc_north_edge =
        max (dlgimg->corners[NW][LATITUDE], dlgimg->corners[NE][LATITUDE]);
    arc_north_edge = arc_north_edge * 60.0 * 60.0;

    /*
     * Extract the utm coordinates of the corners of the area of coverage
     * from the dlg image.  Since the utm area is a quad rather than a
     * perfect square, make sure that the square we define is large
     * enough to hold the quad.
     */
    utm_west_edge =
        min (dlgimg->corners[SW][INTERNAL_X], dlgimg->corners[NW][INTERNAL_X]);
    utm_south_edge =
        min (dlgimg->corners[SW][INTERNAL_Y], dlgimg->corners[SE][INTERNAL_Y]);
    utm_east_edge =
        max (dlgimg->corners[NE][INTERNAL_X], dlgimg->corners[SE][INTERNAL_X]);
    utm_north_edge =
        max (dlgimg->corners[NW][INTERNAL_Y], dlgimg->corners[NE][INTERNAL_Y]);

    rows=xvimg->number_of_rows;
    cols=xvimg->number_of_cols;
    /*
     * Get a list of all of the attributes in this category.  This will
     * be used to tell which attribute goes in which band.
     */
    file_attriblist=NULL;
    file_attribno=0;
    catptr = &(dlgimg->categories[catno]);
    err = count_attrib (catptr, &file_attriblist, &file_attribno);
    if (err != 1) {
        fprintf (stderr, "error in do_lines - ");
        fprintf (stderr, "call to count_attrib failed\n");
    }

    /*
     * Repeat this loop for each line in the category.
     */
    for (lineno=0; lineno<catptr->act_lines; lineno++) {
        lineptr = catptr->lines[lineno];

        /*
         * Get a list of attributes associated with this line so we
         * know which bands to plot it in.
         */
        line_attriblist=NULL;
        line_attribno=0;
        err = assign_line_attribs (dlgimg, catptr, lineptr,
                                   &line_attriblist, &line_attribno);
        if (err != 1) {
            fprintf (stderr, "error in do_lines - ");
            fprintf (stderr, "call to assign_line_attribs failed\n");
            return (0);
        }
   
        /*
         * If we couldn't assign any attributes to the line, then plot it
         * in band 0.
         */
        if (line_attribno == 0) {
            err = plot_line (
                  utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge,
                  arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                  rows, cols,
                  xvimg->imagedata, lineptr);
            if (err != 1) {
                fprintf (stderr,"error in ldlg2viff - plot_line failed ");
                fprintf (stderr, "for line no. %d\n", lineno);
                return (0);
            }
        }

        /*
         * If we could assign attributes, go through the list and plot the
         * line in the appropriate bands.
         */
        for (attrib=0; attrib<line_attribno; attrib++) {
            majorattrib = line_attriblist[attrib*2];
            minorattrib = line_attriblist[attrib*2 +1];

            /*
             * Decide which bands to plot the line in.
             */
            band = search_for_attrib(&file_attriblist, &file_attribno,
                                     majorattrib, minorattrib);
            if (band < 0) {
                fprintf (stderr, "error in do_lines - ");
                fprintf (stderr, "error in line attributes list\n");
            }
            band = band/2;

            /*
             * Increment band by one because band 0 is reserved for things
             * with no attributes.
             */
            band = band+1;

            /*
             * Plot the line in the desired band.  Remember that it is a bit
             * image, so rows and cols must be divided by 8.
             */
            bandptr = xvimg->imagedata + band*rows*((cols+7)/8);
            err = plot_line (
                  utm_west_edge, utm_south_edge, utm_east_edge, utm_north_edge,
                  arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                  xvimg->number_of_rows, xvimg->number_of_cols,
                  bandptr, lineptr);
            if (err != 1) {
                fprintf (stderr,"error in ldlg2viff - plot_line failed ");
                fprintf (stderr, "for line no. %d\n", lineno);
                return (0);
            }
        }

        if (line_attriblist != NULL) free (line_attriblist);
    }

    if (file_attriblist != NULL) free (file_attriblist);
    return (1);
}



/****************************************************************
*
* Routine: assign_line_attribs
*
* Purpose: Creates a list of all of the attributes of a single line
*          records in a dlg file.
*
*   Input: A dlgimage, a pointer to a category within the dlgimage,
*          a pointer to a line within that category.
*
*  Output: An array of attributes, and the number of PAIRS of
*          attributes in the list.  Returns 1 on success and 0 on
*          failures.
*
*  Author: Per Lysne  9/8/90
*
****************************************************************/
static int
assign_line_attribs (dlgimg, catptr, lineptr, list, num)
struct dlgimage *dlgimg;
struct dlgcategory *catptr;
struct dlgline *lineptr;
int **list, *num;
{
    int attrib, err, majorattrib, minorattrib;
    int rightarea, leftarea;
    struct dlgarea *rightareaptr, *leftareaptr;

    if (dlgimg == NULL) {
        fprintf (stderr, "error in assign_line_attribs - ");
        fprintf (stderr, "bad dlg image input\n");
        return (0);
    }
    if (catptr == NULL) {
        fprintf (stderr, "error in assign_line_attribs - ");
        fprintf (stderr, "bad category input\n");
        return (0);
    }
    if (lineptr == NULL) {
        fprintf (stderr, "error in assign_line_attribs - ");
        fprintf (stderr, "bad line input\n");
        return (0);
    }
    if (list == NULL) {
        fprintf (stderr, "error in assign_line_attribs - ");
        fprintf (stderr, "bad list pointer input\n");
        return (0);
    }
    if (num == NULL) {
        fprintf (stderr, "error in assign_line_attribs - ");
        fprintf (stderr, "bad number input\n");
        return (0);
    }

    /*
     * Add any attributes associated with the line to the list of
     * the lines attributes.
     */
    *num=0;
    for (attrib=0; attrib < lineptr->numattributes; attrib++) {
        majorattrib = lineptr->majorattributes[attrib];
        minorattrib = lineptr->minorattributes[attrib];
        err = add_attrib (list, num, majorattrib, minorattrib);
        if (err != 1) {
            fprintf (stderr, "error in assign_line_attribs - ");
            fprintf (stderr, "call to add_attrib failed\n");
            return (0);
        }
    }

    /*
     * Search the areas to the right and left of the line for additional
     * attributes that should be assigned to the line.  Include a
     * work-around which checks to see if the right or left area referenced
     * by the line record actually exists in the file.  Some dlg files I
     * have seen do not meet this condition.
     */
    rightarea = lineptr->rightarea;
    rightarea = abs(rightarea);
    if ((0 < rightarea) && (rightarea <= catptr->num_areas)) { 
        rightarea = rightarea-1;
        rightareaptr = catptr->areas[rightarea];
        for (attrib=0; attrib<rightareaptr->numattributes; attrib++) {
            majorattrib = rightareaptr->majorattributes[attrib];
            minorattrib = rightareaptr->minorattributes[attrib];
            err = search_for_attrib (list, num, majorattrib, minorattrib);
            if (err < 0) {
                err = add_attrib (list, num, majorattrib, minorattrib);
                if (err != 1) {
                    fprintf (stderr, "error in assign_line_attribs - ");
                    fprintf (stderr, "call to add_attrib failed\n");
                }
            }
        }
    }

    leftarea = lineptr->leftarea;
    leftarea = abs(leftarea);
    if ((0 < leftarea) && (leftarea <= catptr->num_areas)) {
        leftarea = leftarea-1;
        leftareaptr = catptr->areas[leftarea];
        for (attrib=0; attrib<leftareaptr->numattributes; attrib++) {
            majorattrib = leftareaptr->majorattributes[attrib];
            minorattrib = leftareaptr->minorattributes[attrib];
            err = search_for_attrib (list, num, majorattrib, minorattrib);
            if (err < 0) {
                err = add_attrib (list, num, majorattrib, minorattrib);
                if (err != 1) {
                    fprintf (stderr, "error in assign_line_attribs - ");
                    fprintf (stderr, "call to add_attrib failed\n");
                }
            }
        }
    }

    return (1);
}



/****************************************************************
*
* Routine: plot_line
*
* Purpose: This routine plots a line from a dlg line record into an
*          image.
*
*   Input: The four corners of the dlg area of coverage in both utm and
*          arc.  The number of row and columns in the image to plot in.
*          A pointer to the image band to plot in, and a pointer to the
*          dlgline stucture of the line to plot.
*
*  Output: A dlg line plotted in an image.  Returns 1 on success and 0
*          on failure.
*
*  Author: Per Lysne  9/10/90
*
****************************************************************/
static int
plot_line (utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne,
           arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge, 
           rows, cols, band, lineptr)
double utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne;
double arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge;
int rows, cols;
char *band;
struct dlgline *lineptr;
{
    int err, numc;
    int x_start_pix, y_start_pix, x_end_pix, y_end_pix;
    double x_start_utm, y_start_utm, x_end_utm, y_end_utm;
    double x_start_arc, y_start_arc, x_end_arc, y_end_arc;

    x_start_utm = lineptr->x_coordinates[0];
    y_start_utm = lineptr->y_coordinates[0];
    err = utm2arc (utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne,
                   arc_west_edge, arc_south_edge, arc_east_edge, arc_north_edge,
                   x_start_utm, y_start_utm, &x_start_arc, &y_start_arc);
    if (err != 1) {
        fprintf (stderr, "error in plot_line - utm2arc failed for ");
        fprintf (stderr, "coord. pair no. 0\n");
        return (0);
    }

    err = arc2pixel(arc_west_edge,arc_south_edge,arc_east_edge,arc_north_edge,
                    rows, cols, x_start_arc, y_start_arc,
                    &x_start_pix, &y_start_pix);
    if (err != 1) {
        fprintf (stderr, "error in plot_line - arc2pixel failed for ");
        fprintf (stderr, "coord. pair no. 0\n");
        return (1);
    }

    for (numc=1; numc<lineptr->numcoordinates; numc++) {
        x_end_utm = lineptr->x_coordinates[numc];
        y_end_utm = lineptr->y_coordinates[numc];

        err = utm2arc (utm_x_sw, utm_y_sw, utm_x_ne, utm_y_ne,
                      arc_west_edge,arc_south_edge,arc_east_edge,arc_north_edge,
                       x_end_utm, y_end_utm, &x_end_arc, &y_end_arc);
        if (err != 1) {
            fprintf (stderr, "error in plot_line - utm2arc failed for ");
            fprintf (stderr, "coord. pair no. %d\n", numc);
            return (0);
        }

        err=arc2pixel(arc_west_edge,arc_south_edge,arc_east_edge,arc_north_edge,
                        rows, cols, x_end_arc, y_end_arc,
                        &x_end_pix, &y_end_pix);
        if (err != 1) {
            fprintf (stderr, "error in plot_line - arc2pixel failed for ");
            fprintf (stderr, "coord. pair no. %d\n", numc);
            return (1);
        }

        err = dlg_line (band, rows, cols, x_start_pix, y_start_pix,
                        x_end_pix, y_end_pix);
        if (err != 1) {
            fprintf (stderr, "error in plot_line - dlg_line failed ");
            fprintf (stderr, "for line ending at node %d\n", numc);
            return (0);
        }

        x_start_pix = x_end_pix;
        y_start_pix = y_end_pix;
    }

    return (1);
}



/****************************************************************
*
* Routine: count_attrib
*
* Purpose: To count all of the attributes belonging to a single
*          category within a dlg file.
*
*   Input: A category within a dlgimage.
*
*  Output: A list of attributes, and the number of pairs of attributes
*          in the list.
*
*  Author: Per Lysne   10/7/90
*
****************************************************************/
static int
count_attrib (category, list, count)
struct dlgcategory *category;
int **list;
int *count;
{
    int nodecount, areacount, linecount, attribcount;
    int majorattrib, minorattrib;
    struct dlgnode *nodeptr;
    struct dlgarea *areaptr;
    struct dlgline *lineptr;

    if (category == NULL) {
        fprintf (stderr, "error in count_attrib - ");
        fprintf (stderr, "bad category was input\n");
        return (0);
    }
    if (list == NULL) {
        fprintf (stderr, "error in count_attrib - ");
        fprintf (stderr, "bad pointer list was input\n");
        return (0);
    }
    if (count == NULL) {
        fprintf (stderr, "error in count_attrib - ");
        fprintf (stderr, "bad count was input\n");
        return (0);
    }

    /*
     * Set count of attributes to 0 (we haven't found any yet!) and set the
     * list of attributes to be empty.
     */
    *count=0;
    *list=NULL;
 
    /*
     * This loop goes through each node in this category.
     */
    for (nodecount=0; nodecount<category->act_nodes; nodecount++) {

        /*
         * This loop goes through each attribute for the current node.
         */
        nodeptr = category->nodes[nodecount];
        for (attribcount=0; attribcount<nodeptr->numattributes; attribcount++) {
            majorattrib = nodeptr->majorattributes[attribcount];
            minorattrib = nodeptr->minorattributes[attribcount];

            /*
             * If the attribute is not already on the list, then add it.
             */
            if ( search_for_attrib(list, count, majorattrib, minorattrib)
                == -1) {
                if ( add_attrib(list, count, majorattrib, minorattrib) 
                    == -1) {
                  fprintf (stderr, 
                  "error in count_attrib - could not add attrib to list\n");
                  return (0);
                }
            }
        }
    }

    /*
     * This loop goes through each area in this category.
     */
    for (areacount=0; areacount<category->act_areas; areacount++) {

        /*
         * This loop goes through each attribute for the current area.
         */
        areaptr = category->areas[areacount];
        for (attribcount=0; attribcount<areaptr->numattributes; attribcount++) {
            majorattrib = areaptr->majorattributes[attribcount];
            minorattrib = areaptr->minorattributes[attribcount];

            /*
             * If the attribute in not on the list, add it.
             */
            if ( search_for_attrib(list, count, majorattrib, minorattrib)
                == -1) {
                if ( add_attrib(list, count, majorattrib, minorattrib) 
                    == -1) {
                  fprintf (stderr, 
                  "error in count_attrib - could not add attrib to list\n");
                  return (0);
                }
            }
        }
    }

    /*
     * This loop goes through each line in this category.
     */
    for (linecount=0; linecount<category->act_lines; linecount++) {

        /*
         * This loop goes through each attribute for the current line.
         */
        lineptr = category->lines[linecount];
        for (attribcount=0; attribcount<lineptr->numattributes; attribcount++) {
            majorattrib = lineptr->majorattributes[attribcount];
            minorattrib = lineptr->minorattributes[attribcount];

            /*
             * If the attribute is not on the list, add it.
             */
            if ( search_for_attrib(list, count, majorattrib, minorattrib)
                == -1) {
                if ( add_attrib(list, count, majorattrib, minorattrib) 
                    == -1) {
                  fprintf (stderr, 
                  "error in count_attrib - could not add attrib to list\n");
                  return (0);
                }
            }
        }
    }

    return (1);
}


/*
 * This function searches for a pair of attributes that will be stored in
 * consecutive order in an array of integers.  The inputs are a double 
 * pointer to the integer array to search in, a pointer to the number of
 * pairs of attributes in that array, and the attributes themselves.  The
 * return value will be the index in the array where the first of the
 * attributes is found, or -1 if they are not found.  The array and number
 * do not need a extra level of reference, but to be consistent with the
 * next function "add_attribute", they are given an extra *.
 */
static int
search_for_attrib (list, number, majorattrib, minorattrib) 
int **list, *number;
int majorattrib, minorattrib;
{
    int i;


    if (list == NULL) {
        fprintf (stderr, "error in search_for_attrib - ");
        fprintf (stderr, "bad pointer list was input\n");
        return (0);
    }
    if (number == NULL) {
        fprintf (stderr, "error in search_for_attrib - ");
        fprintf (stderr, "bad count was input\n");
        return (0);
    }

    /* Number is the number of pairs, not the size of the array. */
    for (i=0; i<(*number)*2; i=i+2) {
        if ((*(*list+i) == majorattrib) && (*(*list+i+1) == minorattrib)) {
            return (i);
        }
    }
    return (-1);
}


/*
 * This function adds a pair of attributes to the end of an integer array.
 * This is kind of like a linked list, but instead of adding another link
 * to a chain, the array used is simply re-malloced to be large enough to
 * add another pair of attributes.  The inputs are a double pointer to
 * the integer array to add the attributes to, a pointer to the number
 * of pairs of attributes in the array to start with, and the attributes
 * themselves.  The return value is 1 unless the malloc is unsuccessful and
 * then it is -1.  In this function, a double pointer to the array is
 * needed because the pointer must actually be changed to point to the new
 * array that has been malloced.  Number is passes by reference because it
 * will be incremented in this function.
 */
static int
add_attrib (list, number, majorattrib, minorattrib)
int **list, *number;
int majorattrib, minorattrib;
{
    int *newlist, i;

    if (list == NULL) {
        fprintf (stderr, "error in add_attrib - ");
        fprintf (stderr, "bad pointer list was input\n");
        return (0);
    }
    if (number == NULL) {
        fprintf (stderr, "error in add_attrib - ");
        fprintf (stderr, "bad count was input\n");
        return (0);
    }
    if (*number <  0) {
        fprintf (stderr, "error in add_attrib - ");
        fprintf (stderr, "bad number was input\n");
        return (0);
    }

    /*
     * Malloc the new array to be 2 integers larger than the old array.
     * Remember that number is the number of pairs of attributes, not the
     * total size of the array.
     */
    newlist = (int *) kcalloc ((*number+1)*2, sizeof(int));
    if (newlist == NULL) {
        fprintf (stderr, "error in add_attrib - could not malloc list\n");
        return (-1);
    }

    /*
     * Transfer the attributes from the old array to the new.
     */
    for (i=0; i<(*number)*2; i=i+2) {
        newlist[i] = *(*list+i);
        newlist[i+1] = *(*list+i+1);
    }

    /* 
     * Add the 2 new attributes to the end of the new array.
     */
    newlist[*number*2] = majorattrib;
    newlist[((*number)*2) +1] = minorattrib;

    /*
     * Free the old array and reset the pointer to point to the new array.
     */
    if (*list != NULL) free (*list);
    *list = newlist;
    *number=(*number)+1;

    return (1);
}
/* -library_code_end */
