/*
 * Copyright (C) 1997-2009, R3vis Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
 *
 * Original Contributor:
 *   Wes Bethel, R3vis Corporation, Marin County, California
 *   http://www.r3vis.com/
 * Additional Contributor(s):
 *
 * The OpenRM project is located at http://openrm.sourceforge.net/.
 */
/*
 * $Id: rmverrplot.c,v 1.6 2007/07/22 17:37:17 wes Exp $
 * Version: $Name: v180-alpha-02 $
 * $Revision: 1.6 $
 * $Log: rmverrplot.c,v $
 * Revision 1.6  2007/07/22 17:37:17  wes
 * Adding usrData and usrCallback parameters to all rmv routines
 *
 * Revision 1.5  2005/02/19 16:09:13  wes
 * Distro sync and consolidation.
 *
 * Revision 1.4  2005/01/23 17:11:02  wes
 * Copyright updated to 2005.
 *
 * Revision 1.3  2004/01/17 04:09:26  wes
 * Updated copyright line for 2004.
 *
 * Revision 1.2  2003/02/02 02:07:23  wes
 * Updated copyright to 2003.
 *
 * Revision 1.1.1.1  2003/01/28 02:15:23  wes
 * Manual rebuild of rm150 repository.
 *
 * Revision 1.6  2003/01/16 22:21:20  wes
 * Updated all source files to reflect new organization of header files:
 * all header files formerly located in include/rmaux, include/rmi, include/rmv
 * are now located in include/rm.
 *
 * Revision 1.5  2002/04/30 19:40:00  wes
 * Updated copyright dates.
 *
 * Revision 1.4  2001/03/31 17:10:08  wes
 * v1.4.0-alpha-2 checkin.
 *
 * Revision 1.3  2000/08/28 01:34:30  wes
 * No signficant changes.
 *
 * Revision 1.2  2000/04/20 16:17:45  wes
 * JDB modifications: code rearrangement, additional docs.
 *
 * Revision 1.1  2000/04/17 00:05:23  wes
 * Lots of documentation updates, courtesy of jdb.
 *
 * Revision 1.1.1.1  2000/02/28 21:29:40  wes
 * OpenRM 1.2 Checkin
 *
 * Revision 1.1.1.1  2000/02/28 17:18:48  wes
 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
 *
 */

#include <rm/rm.h>
#include <rm/rmv.h>
#include "rmvprivt.h"

/*
 * ----------------------------------------------------
 * @Name rmvI2ErrorPlot
 @pstart
 RMenum rmvI2ErrorPlot (RMvertex2D (*appgridfunc)(int i),
                        float (*appu1func)(int i),
			float (*appu2func)(int i),
			float (*appl1func)(int i),
			float (*appl2func)(int i),
			float (*appdata2func)(int i),
			RMvisMap *vmap,
			int axis_offset_flag,
			int npts,
			RMenum linewidth,
			RMenum linestyle,
			RMnode *n)
 @pend

 @astart

 RMvertex2D (*appgridfunc)(int i) - a handle to a caller-supplied
    function that returns an RMvertex2D (x, y) corresponding to the
    grid point (i) (input).

 float (*appu1func)(int i) - a handle to caller-supplied function that
    returns a lower bound float for the upper pair at the grid point
    (i) (input).
			
 float (*appu2func)(int i) - a handle to caller-supplied function that
    returns a upper bound float for the upper pair at the grid point
    (i) (input).
			
 float (*appl1func)(int i) - a handle to caller-supplied function that
    returns a lower bound float for the lower pair at the grid point
    (i) (input).
			
 float (*appl2func)(int i) - a handle to caller-supplied function that
    returns a upper bound float for the lower pair at the grid point
    (i) (input).
			
 float (*appdata2func)(int i) - a handle to a caller-supplied function
    that returns a scalar value for the grid point (i).  This value is
    used in conjunction with the RMvismap to compute vertex color.
			
 RMvisMap *vmap - a handle to an RMvisMap object (input).
			
 int axis_offset_flag - an RMenum specifying in which axis to
    offset the glyph.  Must be one of RMV_XAXIS_OFFSET,
    RMV_YAXIS_OFFSET (input).
			
 int npts - int specifying number of grid data points (input).
			
 RMenum linewidth_enum - an RMenum specifying the line width.  Must be
    one of RM_LINEWIDTH_NARROW, RM_LINEWIDTH_MEDIUM,
    RM_LINEWIDTH_HEAVY, or RM_LINEWIDTH_[1..8] (input).

 RMenum linestyle_enum - an RMenum specifying the lline style.  Must
    be one of RM_LINES_SOLID, RM_LINES_DASHED, RM_LINES_DOTTED,
    RM_LINES_DOT_DASH, or RM_LINES_DASH_DASH_DOT (input).

 RMnode *n - a handle to an RMnode (modified).
 @aend

 @dstart

 Creates an "error bar" plot for indicating data ranges.  Pairs of
 error bars are plotted from the four caller-supplied functions, {u1,
 u2, l1, l2}.  These functions return a data value for a given grid
 point and indicate a pair of data ranges {[l1..l2], [u1..u2]}.  The
 secondary data function can be used with the RMvisMap to color the
 error bars.

 Upon success, RM_CHILL is returned to the caller and the error plot
 geometry has been added to the RMnode.  Otherwise, RM_WHACKED is
 returned.

 @dend
 * ----------------------------------------------------
 */
RMenum
rmvI2ErrorPlot (RMvertex2D (*appgridfunc)(int i, void *usrData),
		void *appGridUsrData,
	        float (*appu1func)(int i, void *usrData),
		void *appDataUsrData,
	        float (*appu2func)(int i, void *usrData),
		void *appData2UsrData,
	        float (*appl1func)(int i, void *usrData),
		void *appData3UsrData,
	        float (*appl2func)(int i, void *usrData),
		void *appData4UsrData,
	        float (*appdata2func)(int i, void *usrData),
		void *appData5UsrData,
	        RMvisMap *vmap,
	        int axis_offset_flag,
	        int npts,
	        RMenum linewidth,
	        RMenum linestyle,
	        RMnode *n)
{
    int          i, j = 0;
    RMprimitive *t;
    RMvertex2D  *v;
    RMcolor4D   *c;

    /* error check on functions, etc. */
    {
	int s1, s2, s3, s4, s5, s6, s7;

	s1 = RM_ASSERT((void *)n, "rmvI2ErrorPlot error: NULL RMnode for return parameter");
	s2 = RM_ASSERT((void *)appgridfunc, "rmvI2ErrorPlot error: NULL app grid callback");
	s3 = RM_ASSERT((void *)appu1func, "rmvI2ErrorPlot error: NULL app u1 callback ");
	s4 = RM_ASSERT((void *)appu2func, "rmvI2ErrorPlot error: NULL app u2 callback ");
	s5 = RM_ASSERT((void *)appl1func, "rmvI2ErrorPlot error: NULL app l1 callback ");
	s6 = RM_ASSERT((void *)appl2func, "rmvI2ErrorPlot error: NULL app l2 callback ");
	s7 = RM_CHILL;
	if (!(((vmap != NULL) && (appdata2func != NULL)) || ((vmap == NULL) && (appdata2func == NULL))))
	    s7 = RM_ASSERT((void *)NULL,"rmvI2ErrorPlot error: the vismap and secondary data callback function must BOTH be NULL or defined.");

	if ((s1 == RM_WHACKED) || (s2 == RM_WHACKED) || (s3 == RM_WHACKED) || (s4 == RM_WHACKED) || (s5 == RM_WHACKED) || (s6 == RM_WHACKED) || (s7 == RM_WHACKED))
	    return(RM_WHACKED);
    }
    
    v = rmVertex2DNew(npts * 4);
    t = rmPrimitiveNew(RM_LINES);

    if (vmap != NULL)
        c = rmColor4DNew(npts * 2);
    else
	c = NULL;

    /* do the upper part */
    for (i = 0; i < npts; i++)
    {
	float      maxs, uppers;
	RMvertex2D base;

	base = (*appgridfunc)(i, appGridUsrData);
	maxs = (*appu1func)(i, appDataUsrData);
	uppers = (*appu2func)(i, appData2UsrData);

	v[j] = base;
	v[j + 1] = base;

	switch (axis_offset_flag)
	   {
	   case RMV_XAXIS_OFFSET:
	      v[j].x += uppers;
	      v[j + 1].x += maxs;
	      break;
	      
	   case RMV_YAXIS_OFFSET:
	      v[j].y += uppers;
	      v[j + 1].y += maxs;
	      break;
	      
	   default: /* bogus axis offset enum */
	      break;
	   }

	j += 2;
	
	if (c)
	{
	    int   k;
	    float d2;

	    d2 = (*appdata2func)(i, appData5UsrData);
	    k = rmVismapIndexFromData(vmap, d2);
	    rmVismapGetColor4D(vmap, k, (c + i));
	}
    }

    /* do the lower part */
    for (i = 0; i < npts; i++)
    {
	float      mins, lowers;
	RMvertex2D base;
	
	base = (*appgridfunc)(i, appGridUsrData);
	mins = (*appl1func)(i, appData3UsrData);
	lowers = (*appl2func)(i, appData4UsrData);
	
	v[j] = base;
	v[j + 1] = base;

	switch (axis_offset_flag)
	   {
	   case RMV_XAXIS_OFFSET:
	      v[j].x += lowers;
	      v[j + 1].x += mins;
	      break;
	      
	   case RMV_YAXIS_OFFSET:
	      v[j].y += lowers;
	      v[j + 1].y += mins;
	      break;
	      
	   default: /* bogus axis offset enum */
	      break;
	   }

	if (c)
	{
	    int   k;
	    float d2;

	    d2 = (*appdata2func)(i, appData5UsrData);
	    k = rmVismapIndexFromData(vmap, d2);
	    rmVismapGetColor4D(vmap, k, (c + i + npts));
	}
	j += 2;
    }
    rmPrimitiveSetVertex2D(t, (npts * 4), v, RM_COPY_DATA, NULL);

    if (c)
    {
        rmPrimitiveSetColor4D(t, (npts * 2), c, RM_COPY_DATA, NULL);
	rmColor4DDelete(c);
    }
    rmNodeSetLineWidth(n, linewidth);
    rmNodeSetLineStyle(n, linestyle);

    /* now, add the new primitive onto the node */
    rmNodeAddPrimitive(n, t);
    rmVertex2DDelete(v);

    return(RM_CHILL);
}
/* EOF */
