/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/

#include <dxconfig.h>


#include <stdio.h>
#include <math.h>
#include <string.h>
#include <dx/dx.h>


#define TRUE 			1
#define FALSE 			0


typedef struct
{
    int			npos;
    int			ncons;
    Array		pos;
    Array		cons;
} GridOutputs;

static Error grid_point ();
static Error grid_line ();
static Error grid_rectangle ();
static Error grid_crosshair ();
static Error grid_ellipse ();
static Error grid_brick ();
static Error generate_crosshair_pos ();
static Error generate_ellipse_pos ();
static Error generate_crosshair_cons ();
static Error generate_ellipse_cons ();
static Error generate_field ();
/* CLEANUP FOR apos AND acons FOR ALL FUNCTIONS OCCURS IN generate_field() */

extern int _dxfGrid (float *point, char *structure, float *shape, int *density, 
          int dim, Object *outo)
{

    if (! strcmp (structure, "point"))
    {
	if (! grid_point (point, dim, outo))
	{
	    return (ERROR);
	}
    }
    else if (! strcmp (structure, "line"))
    {
	if (! grid_line (point, shape, density, dim, outo))
	{
	    return (ERROR);
	}
    }

    else if (! strcmp (structure, "rectangle"))
    {
	if (! grid_rectangle (point, shape, density, dim, outo))
	{
	    return (ERROR);
	}
    }

    else if (! strcmp (structure, "crosshair"))
    {
	if (! grid_crosshair (point, shape, density, dim, outo))
	{
	    return (ERROR);
	}
    }

    else if (! strcmp (structure, "ellipse"))
    {
	if (! grid_ellipse (point, shape, density, dim, outo))
	{
	    return (ERROR);
	}
    }

    else		/* brick */
    {
	if (! grid_brick (point, shape, density, dim, outo))
	{
	    return (ERROR);
	}
    }

    return (OK);
}

static Error grid_point (point, dim, outo)
    float		*point;
    Object		*outo;
    int                 dim;
{
    Array		apos;
    float		*pos;
    Field		f = NULL;
    int                 RETURN_CODE = ERROR;

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * First, generate the positions.
     */

    apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, dim);

    if (! DXAddArrayData (apos, 0, 1, (Pointer) point)) {
	DXDebug("G","DXAddArrayData for point.");
	goto cleanup;
    }



    if (! (f = DXNewField ())) {
	DXDebug("G","DXNewField for point.");
	goto cleanup;
    }

    if (! (DXSetComponentValue (f, "positions", (Object) apos))) {
	DXDebug("G","DXSetComponentValue for point.");
	goto cleanup;
    }

    apos = NULL;

    if (! DXChangedComponentValues (f, "positions")) {
	DXDebug("G","ChangedComponentValue for point.");
	goto cleanup;
    }

    if (! DXEndField (f)) {
	DXDebug("G","DXEndField for point.");
	goto cleanup;
    }

    *outo = (Object) f;

    f = NULL;
    RETURN_CODE = OK;

cleanup:
    DXDelete((Object) apos);
    DXDelete((Object) f);
    return RETURN_CODE;

}

static Error grid_line (point, shape, density, dim, outo)
    float		*point;
    float		*shape;
    int			*density, dim;
    Object		*outo;
{
    int			count[1];
    float		origin[3];
    float		delta[3];
    Array		apos;
    Array		acons;
    float		*pos;
    int			*cons;
    float		tmp;

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (density == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input density");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * Determine the number of positions and connections to generate.
     */

    count[0] = density[0];

    if (count[0] < 0)
    {
	DXErrorReturn (ERROR_BAD_PARAMETER, "density must be positive integers");
    }

    else if (count[0] == 0)
    {
	/*
	 * Empty grid.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, dim);
	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 2);
	if (! generate_field ("lines", apos, acons, outo))
	    return ERROR;
    }

    else if (count[0] == 1)
    {
	/*
	 * Single point.
	 */

	if (! grid_point (point, dim, outo))
	    return ERROR;
    }

    else 		/* (count[0] > 1) */
    {
	/*
	 * Now generate the origin point.
	 */

	origin[0] = point[0] - shape[0];
	origin[1] = point[1] - shape[1];
	if (dim==3) origin[2] = point[2] - shape[2];

	/*
	 * Now generate the delta.
	 */

	tmp =  2.0 / (count[0] - 1);		
	delta[0] = tmp * shape[0];
	delta[1] = tmp * shape[1];
	if (dim==3) delta[2] = tmp * shape[2];

	/*
	 * First, generate the positions.
	 */

	apos = (Array) DXNewRegularArray (TYPE_FLOAT, dim, count[0], 
				 (Pointer) origin, (Pointer) (delta + 0));

	/* 
	 * Next, generate the connections.
	 */

	acons = (Array) DXNewPathArray (count[0]);

	if (! generate_field ("lines", apos, acons, outo))
	    return ERROR;
    }

    return (OK);
} 

static Error grid_rectangle (point, shape, density, dim, outo)
    float		*point;
    float		*shape;
    int			*density;
    Object		*outo;
    int                 dim;
{
    int			count[2];
    float		origin[3], zero_origin[3];
    float		delta[6];
    Array		apos = NULL, apos0 = NULL, apos1 = NULL;
    Array		acons = NULL, acons0 = NULL, acons1 = NULL;
    float		*pos;
    int			*cons;
    float		tmp;
    float		t_shape[3];
    int			t_density[1];

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (density == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input density");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * Set up the zero origin for use in product arrays.
     */

    zero_origin[0] = zero_origin[1] = zero_origin[2] = 0.0;

    /*
     * Determine the number of positions and connections to generate.
     */

    count[0] = density[0];
    count[1] = density[1];

    if ((count[0] < 0) || (count[1] < 0))
    {
	DXErrorReturn (ERROR_BAD_PARAMETER, "density must be positive integers");
    }

    else if ((count[0] == 0) || (count[1] == 0))
    {
	/*
	 * Empty grid.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, dim);
	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 4);
	if (! generate_field ("quads", apos, acons, outo))
	    return ERROR;
    }

    else if (count[0] == 1)
    {
	/*
	 * Single line.
	 */

	t_shape[0] = shape[3];
	t_shape[1] = shape[4];
	t_shape[2] = shape[5];
	t_density[0] = density[1];

	if (! grid_line (point, t_shape, t_density, dim, outo))
	    return ERROR;
    }

    else if (count[1] == 1)
    {
	/*
	 * Single line.
	 */

	t_shape[0] = shape[0];
	t_shape[1] = shape[1];
	t_shape[2] = shape[2];
	t_density[0] = density[0];

	if (! grid_line (point, t_shape, t_density, dim, outo))
	    return ERROR;
    }

    else		/* both counts > 1 */
    {
	/*
	 * Now generate the origin point.
	 */

	origin[0] = point[0] - shape[0] - shape[3];
	origin[1] = point[1] - shape[1] - shape[4];
	origin[2] = point[2] - shape[2] - shape[5];

	/*
	 * Now generate the delta.
	 */

	tmp =  2.0 / (count[0] - 1);		
	delta[0] = tmp * shape[0];
	delta[1] = tmp * shape[1];
	delta[2] = tmp * shape[2];

	tmp =  2.0 / (count[1] - 1);		
	delta[3] = tmp * shape[3];
	delta[4] = tmp * shape[4];
	delta[5] = tmp * shape[5];

	/*
	 * First, generate the positions.
	 */

	apos0 = (Array) DXNewRegularArray (TYPE_FLOAT, dim, count[0], 
				 (Pointer) origin, (Pointer) (delta + 0));
	if (!apos0)
	    return ERROR;

	apos1 = (Array) DXNewRegularArray (TYPE_FLOAT, dim, count[1], 
				 (Pointer) zero_origin, (Pointer) (delta + 3));
	if (!apos1) {
	    DXDelete((Object) apos0);
	    return ERROR;
	}

	apos  = (Array) DXNewProductArray (2, apos0, apos1);

	/* 
	 * Next, generate the connections.
	 */

	acons0 = (Array) DXNewPathArray (count[0]);
	if (!acons0)
	    return ERROR;

	acons1 = (Array) DXNewPathArray (count[1]);
	if (!acons1) {
	    DXDelete((Object) acons0);
	    return ERROR;
	}

	acons  = (Array) DXNewMeshArray (2, acons0, acons1);

	/* create rectangle field for outo, if error DXDelete() apos and acons */
	if (! generate_field ("quads", apos, acons, outo))
	    return ERROR;
    }

    return (OK);
}

static Error grid_crosshair (point, shape, density, dim, outo)
    float		*point;
    float		*shape;
    int			*density;
    Object		*outo;
{
    int			count[3];
    float		origin[9];
    float		delta[9];
    Array		apos;
    Array		acons;
    float		*pos;
    int			*cons;
    float		tmp;
    float		line_shape[3];
    int			line_density[1];

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (density == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input density");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * Determine the number of positions and connections to generate.
     */

    count[0] = density[0];
    count[1] = density[1];
    count[2] = density[2];

    if ((count[0] <= 0) || (count[1] <= 0) || (count[2] <= 0))
    {
	DXErrorReturn (ERROR_BAD_PARAMETER, "density must be positive integers");
    } else if ((count[0] == 1) && (count[1] == 1) && (count[2] == 1)) {
	/*
	 *  Single Point - call grid_line and you are done
	 */
	 line_shape[0] = 1;
	 line_shape[1] = 1;
	 line_shape[2] = 1;
	 line_density[0] = 1;
	 if (!grid_line(point, line_shape, line_density, dim, outo))
	    return ERROR;

    }

    else		/* some count > 1 */
    {
	/*
	 * Ensure that all counts are odd numbers so that the crosshair
	 * may be centered about the origin.
	 */

	if (count[0] % 2 == 0)
	    (count[0])++;
	if (count[1] % 2 == 0)
	    (count[1])++;
	if (count[2] % 2 == 0)
	    (count[2])++;

	/*
	 * First, generate the positions.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, 3);

	if (! DXAddArrayData (apos, 0, count[0] + count[1] + count[2] - 2, 
			    (Pointer) NULL))
            return ERROR;			       

	/*
	 * Set up the positions array.
	 */

	if (! (pos = (float *) DXGetArrayData (apos)))
	    return ERROR;

	/*
	 * Now generate the origin points.
	 */

	origin[0] = point[0] - shape[0];
	origin[1] = point[1] - shape[1];
	origin[2] = point[2] - shape[2];

	origin[3] = point[0] - shape[3];
	origin[4] = point[1] - shape[4];
	origin[5] = point[2] - shape[5];

	origin[6] = point[0] - shape[6];
	origin[7] = point[1] - shape[7];
	origin[8] = point[2] - shape[8];

	/*
	 * Now generate the delta.
	 */

	if (count[0] == 1)
	    tmp = 0;
	else
	    tmp =  2.0 / (count[0] - 1);		
	delta[0] = tmp * shape[0];
	delta[1] = tmp * shape[1];
	delta[2] = tmp * shape[2];

	if (count[1] == 1)
	    tmp = 0;
	else
	    tmp =  2.0 / (count[1] - 1);		
	delta[3] = tmp * shape[3];
	delta[4] = tmp * shape[4];
	delta[5] = tmp * shape[5];

	if (count[2] == 1)
	    tmp = 0;
	else
	    tmp =  2.0 / (count[2] - 1);		
	delta[6] = tmp * shape[6];
	delta[7] = tmp * shape[7];
	delta[8] = tmp * shape[8];

	if (! generate_crosshair_pos (pos, point, count, origin, delta))
	    return ERROR;
	
	/* 
	 * Next, generate the connections.
	 */

	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 2);

	if (! DXAddArrayData (acons, 0, count[0] + count[1] + count[2] - 3,
	    (Pointer) NULL))
	    return ERROR;				   

	/*
	 * Set up the connections array.
	 */

	if (! (cons = (int *) DXGetArrayData (acons)))
	    return ERROR;

	if (! generate_crosshair_cons (cons, count))
	    return ERROR;

	if (! generate_field ("lines", apos, acons, outo))
	    return ERROR;
    }

    return (OK);
}

static Error grid_ellipse (point, shape, density, dim, outo)
    float		*point;
    float		*shape;
    int			*density;
    Object		*outo;
    int                 dim;
{
    int			count[1];
    Array		apos;
    Array		acons;
    float		*pos;
    int			*cons;
    float		tmp;

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (density == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input density");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * Determine the number of positions and connections to generate.
     */

    count[0] = density[0];

    if (count[0] < 0)
    {
	DXErrorReturn (ERROR_BAD_PARAMETER, "density must be positive integers");
    }

    else if (count[0] == 0)
    {
	/*
	 * Empty grid.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, dim);
	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 2);
	if (! generate_field ("lines", apos, acons, outo))
	    return ERROR;
    }

    else 		/* (count[0] > 0) */
    {
	/*
	 * First, generate the positions.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, dim);

	if (! DXAddArrayData (apos, 0, count[0], (Pointer) NULL))
	    return ERROR;

	/*
	 * Set up the positions array.
	 */

	if (! (pos = (float *) DXGetArrayData (apos)))
	    return ERROR;

	if (! generate_ellipse_pos (pos, point, shape, count, dim))
	    return ERROR;
	
	/* 
	 * Next, generate the connections.
	 */

	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 2);

	if (count[0] == 1)
	{
	    if (! grid_point (point, dim, outo))
		 return ERROR;
	}

	else
	{
	    if (! DXAddArrayData (acons, 0, count[0], (Pointer) NULL))
		 return ERROR;

	    /*
	     * Set up the connections array.
	     */

	    if (! (cons = (int *) DXGetArrayData (acons)))
		 return ERROR;

	    if (! generate_ellipse_cons (cons, count))
		 return ERROR;

	    if (! generate_field ("lines", apos, acons, outo))
		 return ERROR;
	}
    }

    return (OK);
} 

static Error grid_brick (point, shape, density, dim, outo)
    float		*point;
    float		*shape;
    int			*density;
    Object		*outo;
{
    int			count[3];
    float		origin[3], zero_origin[3];
    float		delta[9];
    Array		apos = NULL, apos0 = NULL, apos1 = NULL, apos2 = NULL;
    Array		acons = NULL,acons0 = NULL,acons1 = NULL,acons2 = NULL;
    float		*pos;
    int			*cons;
    float		tmp;
    float		t_shape[9];
    int			t_density[3];

    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (density == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input density");
    if (outo == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input outo");

    /*
     * Set up the zero origin for use in product arrays.
     */

    zero_origin[0] = zero_origin[1] = zero_origin[2] = 0.0;

    /*
     * Determine the number of positions and connections to generate.
     */

    count[0] = density[0];
    count[1] = density[1];
    count[2] = density[2];

    if ((count[0] < 0) || (count[1] < 0) || (count[2] < 0))
    {
	DXErrorReturn (ERROR_BAD_PARAMETER, "density must be positive integers");
    }

    else if ((count[0] == 0) || (count[1] == 0) || (count[2] == 0))
    {
	/*
	 * Empty grid.
	 */

	apos = DXNewArray (TYPE_FLOAT, CATEGORY_REAL, 1, 3);
	acons = DXNewArray (TYPE_INT, CATEGORY_REAL, 1, 8);
	if (! generate_field ("cubes", apos, acons, outo))
	    return ERROR;
    }

    else if (count[0] == 1)
    {
	/*
	 * Single rectangle.
	 */

	t_shape[0] = shape[3];
	t_shape[1] = shape[4];
	t_shape[2] = shape[5];
	t_shape[3] = shape[6];
	t_shape[4] = shape[7];
	t_shape[5] = shape[8];
	t_density[0] = density[1];
	t_density[1] = density[2];

	if (! grid_rectangle (point, t_shape, t_density, dim, outo))
	     return ERROR;
    }

    else if (count[1] == 1)
    {
	/*
	 * Single rectangle.
	 */

	t_shape[0] = shape[0];
	t_shape[1] = shape[1];
	t_shape[2] = shape[2];
	t_shape[3] = shape[6];
	t_shape[4] = shape[7];
	t_shape[5] = shape[8];
	t_density[0] = density[0];
	t_density[1] = density[2];

	if (! grid_rectangle (point, t_shape, t_density, dim, outo))
	    return ERROR;
    }

    else if (count[2] == 1)
    {
	/*
	 * Single rectangle.
	 */

	t_shape[0] = shape[0];
	t_shape[1] = shape[1];
	t_shape[2] = shape[2];
	t_shape[3] = shape[3];
	t_shape[4] = shape[4];
	t_shape[5] = shape[5];
	t_density[0] = density[0];
	t_density[1] = density[1];

	if (! grid_rectangle (point, t_shape, t_density, dim, outo))
	    return ERROR;
    }

    else		/* all counts > 1 */
    {
	/*
	 * Now generate the origin point.
	 */

	origin[0] = point[0] - shape[0] - shape[3] - shape[6];
	origin[1] = point[1] - shape[1] - shape[4] - shape[7];
	origin[2] = point[2] - shape[2] - shape[5] - shape[8];

	/*
	 * Now generate the delta.
	 */

	tmp =  2.0 / (count[0] - 1);		
	delta[0] = tmp * shape[0];
	delta[1] = tmp * shape[1];
	delta[2] = tmp * shape[2];

	tmp =  2.0 / (count[1] - 1);		
	delta[3] = tmp * shape[3];
	delta[4] = tmp * shape[4];
	delta[5] = tmp * shape[5];

	tmp =  2.0 / (count[2] - 1);		
	delta[6] = tmp * shape[6];
	delta[7] = tmp * shape[7];
	delta[8] = tmp * shape[8];

	/*
	 * First, generate the positions.
	 */

	apos0 = (Array) DXNewRegularArray (TYPE_FLOAT, 3, count[0], 
				 (Pointer) origin, (Pointer) (delta + 0));
	if (!apos0) 
	    return ERROR;

	apos1 = (Array) DXNewRegularArray (TYPE_FLOAT, 3, count[1], 
				 (Pointer) zero_origin, (Pointer) (delta + 3));
	if (!apos1) {
	    DXDelete((Object) apos0);
	    return ERROR;
	}

	apos2 = (Array) DXNewRegularArray (TYPE_FLOAT, 3, count[2], 
				 (Pointer) zero_origin, (Pointer) (delta + 6));
	if (!apos2) {
	    DXDelete((Object) apos0);
	    DXDelete((Object) apos1);
	    return ERROR;
	}

	apos  = (Array) DXNewProductArray (3, apos0, apos1, apos2);

	/* 
	 * Next, generate the connections.
	 */

	acons0 = (Array) DXNewPathArray (count[0]);
	if (!acons0) 
	    return ERROR;

	acons1 = (Array) DXNewPathArray (count[1]);
	if (!acons1) {
	    DXDelete((Object) acons0);
	    return ERROR;
	}

	acons2 = (Array) DXNewPathArray (count[2]);
	if (!acons2) {
	    DXDelete((Object) acons0);
	    DXDelete((Object) acons1);
	    return ERROR;
	}

	acons  = (Array) DXNewMeshArray (3, acons0, acons1, acons2);

	/* create brick field for outo, if error, DXDelete() apos and acons */
	if (! generate_field ("cubes", apos, acons, outo))
	    return ERROR;
    }

    return (OK);
}


static Error generate_crosshair_pos (pos, point, count, origin, delta)
    float		*pos;
    float		*point;
    int			*count;
    float		*origin;
    float		*delta;
{
    int			i;
    int			index;
    int			midcount;

    if (pos == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input pos");
    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (count == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input count");
    if (origin == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input origin");
    if (delta == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input delta");

    /*
     * Assumes that count[0] >= 1, count[1] >= 1, count[2] >= 1.
     */

    if (count[0] % 2 == 0)
	(count[0])++;
    if (count[1] % 2 == 0)
	(count[1])++;
    if (count[2] % 2 == 0)
	(count[2])++;

    pos[0] = point[0];
    pos[1] = point[1];
    pos[2] = point[2];

    index = 3;

    midcount = (count[0] - 1) / 2;

    for (i = 0; i < count[0]; i++)
    {
	if (i != midcount)
	{
	    pos[index]     = origin[0] + i * delta[0];
	    pos[index + 1] = origin[1] + i * delta[1];
	    pos[index + 2] = origin[2] + i * delta[2];

	    index += 3;
	}
    }

    midcount = (count[1] - 1) / 2;

    for (i = 0; i < count[1]; i++)
    {
	if (i != midcount)
	{
	    pos[index]     = origin[3] + i * delta[3];
	    pos[index + 1] = origin[4] + i * delta[4];
	    pos[index + 2] = origin[5] + i * delta[5];

	    index += 3;
	}
    }

    midcount = (count[2] - 1) / 2;

    for (i = 0; i < count[2]; i++)
    {
	if (i != midcount)
	{
	    pos[index]     = origin[6] + i * delta[6];
	    pos[index + 1] = origin[7] + i * delta[7];
	    pos[index + 2] = origin[8] + i * delta[8];

	    index += 3;
	}
    }

    return (OK);
}

static Error generate_ellipse_pos (pos, point, shape, count, dim)
    float		*pos;
    float		*point;
    float		*shape;
    int			*count;
{
    double		delta;
    int			i;
    int			index;
    float		cosval;
    float		sinval;

    if (pos == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input pos");
    if (point == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input point");
    if (shape == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input shape");
    if (count == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input count");

    /*
     * Assumes that the two vectors which form "shape" are orthogonal.
     */

    delta = (double) (2.0 * M_PI / count[0]);

    for (i = 0; i < count[0]; i++)
    {
	index = dim * i;
	cosval = (float) cos (i * delta);
	sinval = (float) sin (i * delta);

	pos[index    ] = point[0] + shape[0] * cosval + shape[3] * sinval;
	pos[index + 1] = point[1] + shape[1] * cosval + shape[4] * sinval;
        if (dim==3)
	 pos[index + 2] = point[2] + shape[2] * cosval + shape[5] * sinval;
    }

    return (OK);
}

static Error generate_crosshair_cons (cons, count)
    int			*cons;
    int			*count;
{
    int			i;
    int			index;
    int			midcount;
    int			pos;
    int			inloop;

    if (cons == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input cons");
    if (count == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input count");

    /* 
     * This assumes that count[0] >= 1, count[1] >= 1, and count[2] >= 1.
     */

    if (count[0] % 2 == 0)
	(count[0])++;
    if (count[1] % 2 == 0)
	(count[1])++;
    if (count[2] % 2 == 0)
	(count[2])++;

    index = 0;
    pos = 1;
    inloop = FALSE;

    midcount = (count[0] - 1) / 2;

    for (i = 0; i < count[0] - 1; i++)
    {
	inloop = TRUE;

	if (i == midcount - 1)
	{
	    cons[index    ] = pos;
	    cons[index + 1] = 0;
	}

	else if (i == midcount)
	{
	    cons[index    ] = 0;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	else
	{
	    cons[index    ] = pos;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	index += 2;
    }

    if (inloop)
	pos++;

    inloop = FALSE;

    midcount = (count[1] - 1) / 2;

    for (i = 0; i < count[1] - 1; i++)
    {
	inloop = TRUE;

	if (i == midcount - 1)
	{
	    cons[index    ] = pos;
	    cons[index + 1] = 0;
	}

	else if (i == midcount)
	{
	    cons[index    ] = 0;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	else
	{
	    cons[index    ] = pos;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	index += 2;
    }

    if (inloop)
	pos++;

    midcount = (count[2] - 1) / 2;

    for (i = 0; i < count[2] - 1; i++)
    {
	if (i == midcount - 1)
	{
	    cons[index    ] = pos;
	    cons[index + 1] = 0;
	}

	else if (i == midcount)
	{
	    cons[index    ] = 0;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	else
	{
	    cons[index    ] = pos;
	    cons[index + 1] = pos + 1;
	    pos++;
	}

	index += 2;
    }

    return (OK);
}

static Error generate_ellipse_cons (cons, count)
    int			*cons;
    int			*count;
{
    int			i;
    int			index;

    if (cons == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input cons");
    if (count == NULL)
	DXErrorReturn (ERROR_BAD_PARAMETER, "missing input count");

    /* 
     * This assumes that count[0] > 1.
     */

    for (i = 0; i < count[0]; i++)
    {
	index = 2 * i;

	cons[index    ] = i;
	cons[index + 1] = ((i + 1 == count[0]) ? 0 : i + 1);
    }

    return (OK);
}

static Error generate_field (element_type, apos, acons, outo)
    char		*element_type;
    Array		apos;
    Array		acons;
    Object		*outo;
{
    Field		f = NULL;
    int                 RETURN_CODE = ERROR;

    if (element_type == NULL) {
	DXSetError(ERROR_BAD_PARAMETER, "missing input element_type");
	goto cleanup;
    }
    if (apos == NULL) {
	DXDebug("G","apos is null in generate_field");
	goto cleanup;
    }
    if (acons == NULL) {
	DXDebug("G","acons is null in generate_field");
	goto cleanup;
    }
    if (outo == NULL) {
	DXSetError(ERROR_BAD_PARAMETER, "missing input outo");
	goto cleanup;
    }

    if (! (f = DXNewField ())) {
	DXDebug("G","DXNewField in generate_field");
	goto cleanup;
    }

    if (! (DXSetComponentValue (f, "positions", (Object) apos))) {
	DXDebug("G","DXSetComponentValue for apos in generate_field");
	goto cleanup;
    }
    apos = NULL;

    if (! (DXSetComponentValue (f, "connections", (Object) acons))) {
	DXDebug("G","DXSetComponentValue for acons in generate_field");
	goto cleanup;
    }
    acons = NULL;

    if (! (DXSetComponentAttribute (f, "connections", "element type",
			          (Object) DXNewString (element_type)))) {
	DXDebug("G","DXSetComponentAttribute for acons in generate_field");
	goto cleanup;				   
    }

    if (! DXChangedComponentValues (f, "positions")) {
	DXDebug("G","DXChangedComponentValues for positions in generate_field");
	goto cleanup;
    }
    if (! DXChangedComponentValues (f, "connections")) {
	DXDebug("G","DXChangedComponentValues for connections in generate_field");
	goto cleanup;
    }

    if (! DXEndField (f)) {
	DXDebug("G","DXEndField in generate_field");
	goto cleanup;
    }

    *outo = (Object) f;

    f = NULL;
    RETURN_CODE = OK;

cleanup:
    DXDelete((Object) apos);
    DXDelete((Object) acons);
    DXDelete((Object) f);
    return RETURN_CODE;

}
