/*ScianFilters.c
  Eric Pepke
  Oct 3, 1991
  Stuff for Filters
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianLists.h"
#include "ScianIcons.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianVisWindows.h"
#include "ScianButtons.h"
#include "ScianSliders.h"
#include "ScianTextBoxes.h"
#include "ScianTitleBoxes.h"
#include "ScianControls.h"
#include "ScianDatasets.h"
#include "ScianErrors.h"
#include "ScianColors.h"
#include "ScianDialogs.h"
#include "ScianStyle.h"
#include "ScianSpaces.h"
#include "ScianIDs.h"
#include "ScianArrays.h"
#include "ScianMethods.h"
#include "ScianDepend.h"
#include "ScianFilters.h"
#include "ScianObjFunctions.h"

ObjPtr filterClass;
ObjPtr orthoSlicerClass, vectorJoinerClass, fixedSlicerClass;
ObjPtr registeredEasyFilters;
static Bool justAdding = false;		/*True iff we're just adding controls*/ 

/****************************************************************************/
/*                             Vector Joiner                                */
/****************************************************************************/

static ObjPtr InitVectorJoiner(joiner, dataset, desFlags, desTopDim, desSpatDim, desNComponents)
ObjPtr joiner, dataset;
long desFlags;
int desTopDim, desSpatDim, desNComponents;
/*Initializes a vector joiner
	joiner		the joiner
	dataset		the dataset to slice
	desFlags	the desired flags of the result
	desTopDim	the desired topological dimension
	desSpatDim	the desired spatial dimension
	desNComponents	the desired number of components

Returns ObjTrue if successful, ObjFalse if not
*/
{
    long sourceInfo;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    real *elements;
    int k;
    ObjPtr dataForm;
    ThingListPtr runner;

    /*Can only deal with a list of datasets*/
    if (!IsList(dataset))
    {
	return ObjFalse;
    }

#if 0
    /*Look through the datasets, checking forms*/

    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    /*Check the info*/
    if (sourceInfo & DS_UNSTRUCTURED ||
	!(sourceInfo & DS_HASFIELD))
    {
	return ObjFalse;
    }

    if (desFlags & DS_UNSTRUCTURED ||
	!(desFlags & DS_HASFIELD))
    {
	return ObjFalse;
    }

    if (sourceInfo & (DS_VECTOR) != desFlags & (DS_VECTOR))
    {
	return ObjFalse;
    }

    /*Check the topological dimension*/
    if (desTopDim >= 0 && desTopDim >= sourceTop)
    {
	return ObjFalse;
    }
    if (desTopDim < 0) desTopDim = sourceTop - 1;

    /*Check the spatial dimension*/
    if (desSpatDim >= 0 && desSpatDim != sourceSpatial)
    {
	return ObjFalse;
    }
    if (desSpatDim < 0) desSpatDim = sourceSpatial;

    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
    }
    else
    {
	sourceNComponents = 1;
    }
    if (desNComponents >= 0 && sourceNComponents != desNComponents)
    {
	return ObjFalse;
    }
    if (desNComponents < 0) desNComponents = sourceNComponents;

    /*OK now*/

    /*Choose an icon*/
    switch(desTopDim)
    {
	case 0:
	case 1:
	    icon = sourceInfo & DS_VECTOR ? icon1DVector : icon1DScalar;
	    break;
	case 2:
	    icon = sourceInfo & DS_VECTOR ? icon2DVector : icon2DScalar;
	    break;
	case 3:
	    icon = sourceInfo & DS_VECTOR ? icon3DVector : icon3DScalar;
	    break;
	default:
	    icon = sourceInfo & DS_VECTOR ? icon4DVector : icon4DScalar;
	    break;
    }

    icon = NewObject(icon, 0);
    SetVar(slicer, DEFAULTICON, icon);

    SetVar(icon, FORMAT, GetVar(slicer, NAME));
    SetVar(slicer, NAME, GetVar(dataset, NAME));
    SetVar(icon, NAME, GetVar(dataset, NAME));

    /*Set the dataset*/
    SetVar(slicer, MAINDATASET, dataset);

    /*Create the DIMVALUES*/
    dimValues = NewRealArray(1, (long) sourceTop);
    elements = ELEMENTS(dimValues);
    for (k = 0; k < sourceTop; ++k)
    {
	elements[k] = (k >= desTopDim) ? 0.0: -1.0;
    }
    SetVar(slicer, DIMVALUES, dimValues);
#endif
    return ObjTrue;
}

static ObjPtr AllVectorJoiners(joinerClass, datasets)
ObjPtr joinerClass, datasets;
/*Returns a list of all possible vector joiners that can be made with dataset, or null*/
{
    long sourceInfo;
    long desFlags;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    int desTop, desSpatial, desNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    real *elements;
    int k;
    ObjPtr retVal;
    ObjPtr dataset;
    ThingListPtr listPtr;

    /*Cannot deal with anything other than a list of datasets*/
    if (!IsList(datasets))
    {
	return NULLOBJ;
    }

    listPtr = LISTOF(datasets);
    if (!listPtr)
    {
	return NULLOBJ;
    }

    dataset = listPtr -> thing;

    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    desFlags = sourceInfo;

    desSpatial = sourceSpatial;
    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
    }
    else
    {
	sourceNComponents = 1;
    }
    desNComponents = sourceNComponents;

    desTop = sourceTop;
    retVal = NULLOBJ;
    {
	ObjPtr joiner;

	joiner = NewObject(joinerClass, 0);
	if (IsTrue(InitFilter(joiner, datasets, desFlags, desTop, desSpatial, desNComponents)))
	{
	    if (!retVal)
	    {
		retVal = NewList();
	    }
	    PrefixList(retVal, joiner);
	}
    }

    return retVal;
}

/****************************************************************************/
/*                              Ortho Slicer                                */
/****************************************************************************/

static ObjPtr InitOrthoSlicer(slicer, dataset, desFlags, desTopDim, desSpatDim, desNComponents)
ObjPtr slicer, dataset;
long desFlags;
int desTopDim, desSpatDim, desNComponents;
/*Initializes ann ortho slicer
	slicer		the slicer
	dataset		the dataset to slice
	desFlags	the desired flags of the result
	desTopDim	the desired topological dimension
	desSpatDim	the desired spatial dimension
	desNComponents	the desired number of components

Returns ObjTrue if successful, ObjFalse if not
*/
{
    long sourceInfo;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    ObjPtr formDims;
    real *elements;
    int k;

    /*Cannot deal with a list of datasets*/
    if (IsList(dataset))
    {
	return ObjFalse;
    }

    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    /*Check the info*/
    if (sourceInfo & DS_UNSTRUCTURED ||
	!(sourceInfo & DS_HASFIELD))
    {
	return ObjFalse;
    }

    if (desFlags & DS_UNSTRUCTURED ||
	!(desFlags & DS_HASFIELD))
    {
	return ObjFalse;
    }
    if ((sourceInfo & (DS_VECTOR)) != (desFlags & (DS_VECTOR)))
    {
	return ObjFalse;
    }

    /*Check the topological dimension*/
    if (desTopDim >= 0 && desTopDim >= sourceTop)
    {
	return ObjFalse;
    }
    if (desTopDim < 0) desTopDim = sourceTop - 1;

    /*Check the spatial dimension*/
    if (desSpatDim >= 0 && desSpatDim != sourceSpatial)
    {
	return ObjFalse;
    }
    if (desSpatDim < 0) desSpatDim = sourceSpatial;

    /*See if any of the dimensions is degenerate*/
    formDims = GetDatasetFormDims(dataset);
    if (!formDims)
    {
	return ObjFalse;
    }
    elements = ELEMENTS(formDims);

    for (k = 0; k < DIMS(formDims)[0]; ++k)
    {
	if (elements[k] < 1.5)
	{
	    return ObjFalse;
	}
    }

    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
	SetVar(slicer, NCOMPONENTS, var);
    }
    else
    {
	sourceNComponents = 1;
    }
    if (desNComponents >= 0 && (sourceNComponents != desNComponents))
    {
	return ObjFalse;
    }
    if (desNComponents < 0) desNComponents = sourceNComponents;

    /*OK now*/

    /*Choose an icon*/
    switch(desTopDim)
    {
	case 0:
	case 1:
	    icon = sourceInfo & DS_VECTOR ? icon1DVector : icon1DScalar;
	    break;
	case 2:
	    icon = sourceInfo & DS_VECTOR ? icon2DVector : icon2DScalar;
	    break;
	case 3:
	    icon = sourceInfo & DS_VECTOR ? icon3DVector : icon3DScalar;
	    break;
	default:
	    icon = sourceInfo & DS_VECTOR ? icon4DVector : icon4DScalar;
	    break;
    }

    icon = NewObject(icon, 0);
    SetVar(slicer, DEFAULTICON, icon);

    SetVar(icon, FORMAT, GetVar(slicer, NAME));
    SetVar(slicer, NAME, GetVar(dataset, NAME));
    SetVar(icon, NAME, GetVar(dataset, NAME));

    /*Set the dataset*/
    SetVar(slicer, MAINDATASET, dataset);

    /*Create the DIMVALUES*/
    dimValues = NewRealArray(1, (long) sourceTop);
    elements = ELEMENTS(dimValues);
    for (k = 0; k < sourceTop; ++k)
    {
	elements[k] = (k >= desTopDim) ? 0.0: -1.0;
    }
    SetVar(slicer, DIMVALUES, dimValues);

    return ObjTrue;
}

static ObjPtr AllOrthoSlicers(slicerClass, datasets)
ObjPtr slicerClass, datasets;
/*Returns a list of all possible slicers that can be made with datasets, or null*/
{
    long sourceInfo;
    long desFlags;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    int desTop, desSpatial, desNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    real *elements;
    int k;
    ObjPtr retVal;
    ThingListPtr runner;

    for (runner = LISTOF(datasets); runner; runner = runner -> next)
    {
	ObjPtr dataset;
	dataset = runner -> thing;
    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    /*Check the info*/
    if (sourceInfo & DS_UNSTRUCTURED ||
	!(sourceInfo & DS_HASFIELD))
    {
	continue;
    }

    desFlags = sourceInfo;

    /*Check the topological dimension*/
    if (sourceTop <= 0)
    {
	continue;
    }

    desSpatial = sourceSpatial;
    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
    }
    else
    {
	sourceNComponents = 1;
    }
    desNComponents = sourceNComponents;

    retVal = NULLOBJ;
    for (desTop = 0; desTop < sourceTop; ++desTop)
    {
	ObjPtr slicer;
	slicer = NewObject(orthoSlicerClass, 0);
	if (IsTrue(InitFilter(slicer, dataset, desFlags, desTop, desSpatial, desNComponents)))
	{
	    if (!retVal)
	    {
		retVal = NewList();
	    }
	    PrefixList(retVal, slicer);
	}
    }
    }
    return retVal;
}

static ObjPtr GetOrthoSlicerLongName(slicer)
ObjPtr slicer;
{
    ObjPtr retVal, mainDataset;

    sprintf(tempStr, " %d-D slice", GetTopDim(slicer));
    retVal = NewString(tempStr);
    mainDataset = GetVar(slicer, MAINDATASET);
    if (mainDataset)
    {
	retVal = ConcatStrings(GetLongName(mainDataset), retVal);
    }
    return retVal;
}

static ObjPtr GetOrthoSlicerTopDim(slicer)
ObjPtr slicer;
/*Returns the topological dimension of slicer*/
{
    ObjPtr dimValues;
    int nDimensions, k;
    real *elements;

    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetOrthoSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    nDimensions = 0;
    elements = ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (elements[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }

    return NewInt(nDimensions);
}

static ObjPtr GetOrthoSlicerSpatialDim(slicer)
ObjPtr slicer;
/*Returns the spatial dimension of slicer*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("GetOrthoSlicerSpatialDim", slicer, MAINDATASET);
    if (mainDataset)
    {
	return NewInt(GetSpatialDim(mainDataset));
    }
    else
    {
	return NULLOBJ;
    }
}

static ObjPtr GetOrthoSlicerInfo(slicer)
ObjPtr slicer;
/*Gets info for an ortho slicer*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("GetOrthoSlicerInfo", slicer, MAINDATASET);
    if (mainDataset)
    {
	return NewInt(GetDatasetInfo(mainDataset));
    }
    else
    {
	return NULLOBJ;
    }
}

static ObjPtr MakeOrthoSlicerCPalette(slicer)
ObjPtr slicer;
/*Makes the ortho slicers's CPALETTE*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("MakeOrthoSlicerCPalette", slicer, MAINDATASET);
    if (mainDataset)
    {
	SetVar(slicer, CPALETTE, GetVar(mainDataset, CPALETTE));
	return ObjTrue;
    }
    else
    {
	return ObjFalse;
    }
}

static ObjPtr MakeOrthoSlicerDataForm(slicer)
ObjPtr slicer;
/*Makes an ortho slicer's dataform.*/
{
    ObjPtr mainDataset;

    mainDataset = GetObjectVar("MakeOrthoSlicerDataForm", slicer, MAINDATASET);
    if (mainDataset)
    {
	SetVar(slicer, DATAFORM, GetVar(mainDataset, DATAFORM));
	return ObjTrue;
    }
    else
    {
	return ObjFalse;
    }
}

static ObjPtr MakeOrthoSlicerCurData(slicer)
ObjPtr slicer;
/*Makes an ortho slicers's curdata.  Just a dummy*/
{
    SetVar(slicer, CURDATA, NULLOBJ);
}

static ObjPtr GetOrthoSlicerFormDims(slicer)
ObjPtr slicer;
/*Gets form dims for an ortho slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k;
    real *el1, *el2, *el3;

    mainDataset = GetObjectVar("MakeOrthoSlicerCPalette", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    origDims = GetDatasetFormDims(mainDataset);
    if (!origDims)
    {
	return NULLOBJ;
    }

    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetOrthoSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }

    if (nDimensions == 0)
    {
	return NULLOBJ;
    }
    resultDims = NewRealArray(1, (long) nDimensions);
    el2 = ELEMENTS(origDims);
    el3 = ELEMENTS(resultDims);
    nDimensions = 0;
    
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    el3[nDimensions] = el2[k];
	    ++nDimensions;
	}
    }

    return resultDims;
}

static ObjPtr RegisterOrthoSlicerField(slicer, whichField)
ObjPtr slicer;
int whichField;
/*Registers the field for an ortho slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k, d, i, comp;
    real *el1, *el2, *el3;
    long *tempIndices;
    long offset;

    mainDataset = GetObjectVar("MakeOrthoSlicerCPalette", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    /*Let the main dataset register itself*/
    if (!SetCurField(whichField, mainDataset))
    {
	return ObjFalse;
    }

    /*Now edit it, based on dimValues*/
    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetOrthoSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    /*Calculate the number of dimensions*/
    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }
    curFields[whichField] . topDim = nDimensions;

    /*Set up some temporary indices for testing*/
    tempIndices = (long *) malloc(DIMS(dimValues)[0] * sizeof(long));
    if (!tempIndices)
    {
	return ObjFalse;
    }
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension.  Make it 0*/
	    tempIndices[k] = 0;
	}
	else
	{
	    /*Not free.*/
	    tempIndices[k] = (long) (el1[k] + 0.5);
	}
    }

    /*Go through the components, editing them*/
    for (comp = 0; comp < curFields[whichField] . nComponents; ++comp)
    {
	/*Get the base offset*/
	offset = GetComponentOffset(whichField, comp, tempIndices);

	/*Nudge up the base ptr by that offset*/
	if (curFields[whichField] . components[comp] . dataCompressed)
	{
	    curFields[whichField] . components[comp] . data . comp += offset;
	}
	else
	{
	    curFields[whichField] . components[comp] . data . unComp += offset;
	}

	/*Make invalid any fixed indices*/
	for (k = 0; k < curFields[whichField] . components[comp] . nIndices; ++k)
	{
	    if (el1[curFields[whichField] . components[comp] . indices[k]] > -0.5)
	    {
		/*Fixed index, already accounted for*/
		curFields[whichField] . components[comp] . indices[k] = -1;
	    }
	    else
	    {
		/*Variable index, have to shift down*/
		d = 0;
		for (i = 0; i < curFields[whichField] . components[comp] . indices[k]; ++i)
		{
		    if (el1[i] < -0.5)
		    {
			++d;
		    }
		}
		curFields[whichField] . components[comp] . indices[k] = d;
	    }
	}
    }
    
    free(tempIndices);
    return ObjTrue;
}

static ObjPtr RegisterOrthoSlicerForm(slicer, whichField)
ObjPtr slicer;
int whichField;
/*Registers the form for an ortho slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k, d, i, comp;
    real *el1, *el2, *el3;
    long *tempIndices;
    long offset;

    mainDataset = GetObjectVar("MakeOrthoSlicerCPalette", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    /*Let the main dataset register itself*/
    if (!SetCurForm(whichField, mainDataset))
    {
	return ObjFalse;
    }

    /*Now edit it, based on dimValues*/
    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetOrthoSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    /*Calculate the number of dimensions*/
    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }
    curFields[whichField] . topDim = nDimensions;

    /*Set up some temporary indices for testing*/
    tempIndices = (long *) malloc(DIMS(dimValues)[0] * sizeof(long));
    if (!tempIndices)
    {
	return ObjFalse;
    }
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension.  Make it 0*/
	    tempIndices[k] = 0;
	}
	else
	{
	    /*Not free.*/
	    tempIndices[k] = (long) (el1[k] + 0.5);
	}
    }

    /*Go through the components, editing them*/
    for (comp = 0; comp < curFields[whichField] . nComponents; ++comp)
    {
	/*Get the base offset*/
	offset = GetComponentOffset(whichField, comp, tempIndices);
	
	/*Nudge up the base ptr by that offset*/
	if (curFields[whichField] . components[comp] . dataCompressed)
	{
	    curFields[whichField] . components[comp] . data . comp += offset;
	}
	else
	{
	    curFields[whichField] . components[comp] . data . unComp += offset;
	}

	/*Make invalid any fixed indices*/
	for (k = 0; k < curFields[whichField] . components[comp] . nIndices; ++k)
	{
	    if (el1[curFields[whichField] . components[comp] . indices[k]] > -0.5)
	    {
		/*Fixed index, already accounted for*/
		curFields[whichField] . components[comp] . indices[k] = -1;
	    }
	    else
	    {
		/*Variable index, have to shift down*/
		d = 0;
		for (i = 0; i < curFields[whichField] . components[comp] . indices[k]; ++i)
		{
		    if (el1[i] < -0.5)
		    {
			++d;
		    }
		}
		curFields[whichField] . components[comp] . indices[k] = d;
	    }
	}
    }
    
    free(tempIndices);
    return ObjTrue;
}

static ObjPtr ChangeOrthoSlice(slider)
ObjPtr slider;
/*Changes an ortho slice based on a slider*/
{
    ObjPtr slicer, var;
    real value;
    int whichDimension;
    real *el1; 

    slicer = GetObjectVar("ChangeOrthoSlice", slider, REPOBJ);
    if (!slicer)
    {
	return NULLOBJ;
    }

    var = GetValue(slider);
    if (!var)
    {
	return NULLOBJ;
    }
    value = GetReal(var);

    var = GetIntVar("ChangeOrthoSlice", slider, WHICHDIMENSION);
    if (!var)
    {
	return ObjFalse;
    }
    whichDimension = GetInt(var);

    var = GetArrayVar("ChangeOrthoSlice", slicer, DIMVALUES);
    if (!var)
    {
	return ObjFalse;
    }
    el1 = ELEMENTS(var);

    /*Change the dimension to be the value*/
    var = NewRealArray(1, DIMS(var)[0]);
    CArray2Array(var, el1);
    el1 = ELEMENTS(var);
    el1[whichDimension] = value;
    SetVar(slicer, DIMVALUES, var);

    DatasetChanged(slicer);
    return ObjTrue;
}

void DoNegativeError()
/*Whines at the user about a negative error*/
{
    WinInfoPtr errWindow;
    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, "The number may not be less than zero.", 0, 0, "");
    SetVar((ObjPtr) errWindow, HELPSTRING,
	NewString("You have entered a negative number where only nonnegative numbers are \
acceptable.  Please enter a nonnegative number and try again."));
}

void DoInvalidDimError()
/*Whines at the user about an invalid dimension error*/
{
    WinInfoPtr errWindow;
    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, "The number must correspond to a free topological dimension.", 0, 0, "");
    SetVar((ObjPtr) errWindow, HELPSTRING,
	NewString("The number you have entered specifies a topological dimension which \
is already controlled by a slider.  One topological dimension may not be controlled by more than \
one slider.  Please enter the number of a currently free dimension and try again."));
}

void DoTooBigDimError()
/*Whines at the user about a too big dimension error*/
{
    WinInfoPtr errWindow;
    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, "The number you have entered exceeds the number of topological dimensions.", 0, 0, "");
    SetVar((ObjPtr) errWindow, HELPSTRING,
	NewString("The number you have entered exceeds the maximum number of \
topolological dimensions in the dataset.  Please enter the number of a currently free dimension and try again."));
}

static ObjPtr ChangeSliderDimension(textBox)
ObjPtr textBox;
/*Changes the dimension a slider textBox represents controls*/
{
    ObjPtr var, slider, slicer, origDims, mainDataset;
    int oldValue, newValue;
    real *el1, *el2;

    var = GetValue(textBox);
    if (!var)
    {
	return ObjFalse;
    }

    if (!ParseInteger(&newValue, GetString(var)))
    {
	DoTask(DoNumberError);
	return ObjFalse;
    }

    if (newValue < 0)
    {
	DoTask(DoNegativeError);
	return ObjFalse;
    }

    slider = GetObjectVar("ChangeSliderDimension", textBox, REPOBJ);
    if (!slider)
    {
	return ObjFalse;
    }

    var = GetIntVar("ChangeSliderDimension", slider, WHICHDIMENSION);
    if (!var)
    {
	return ObjFalse;
    }
    oldValue = GetInt(var);

    if (oldValue == newValue)
    {
	return ObjFalse;
    }

    slicer = GetObjectVar("ChangeSliderDimension", slider, REPOBJ);
    if (!slicer)
    {
	return ObjFalse;
    }

    mainDataset = GetObjectVar("ChangeSliderDimension", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return ObjFalse;
    }

    origDims = GetDatasetFormDims(mainDataset);
    if (!origDims)
    {
	return ObjFalse;
    }

    var = GetArrayVar("ChangeSliderDimension", slicer, DIMVALUES);
    if (!var)
    {
	return ObjFalse;
    }
    el1 = ELEMENTS(var);

    if (newValue >= DIMS(var)[0])
    {
	DoTask(DoTooBigDimError);
	return ObjFalse;
    }

    /*See if the new value is set*/
    if (el1[newValue] > -0.5)
    {
	DoTask(DoInvalidDimError);
	return ObjFalse;
    }

    /*Edit the dim values*/
    var = NewRealArray(1, DIMS(var)[0]);
    CArray2Array(var, el1);
    el1 = ELEMENTS(var);
    el1[oldValue] = -1.0;
    el1[newValue] = 0.0;

    SetVar(slicer, DIMVALUES, var);
    SetVar(slider, WHICHDIMENSION, NewInt(newValue));
    SetSliderValue(slider, 0.0);

    el2 = ELEMENTS(origDims);
    SetSliderRange(slider, el2[newValue] - 1.0, 0.0, 1.0);

    DatasetChanged(slicer);
    return ObjTrue;
}


static ObjPtr ChangeSliderAxis(radio)
ObjPtr radio;
/*Changes an axis for a slider based on a radio group*/
{
    ObjPtr var, slider, slicer, origDims, mainDataset;
    int oldValue, newValue;
    real *el1, *el2;

    var = GetValue(radio);
    if (!var)
    {
	return ObjFalse;
    }

    newValue = GetInt(var);

    if (newValue < 0)
    {
	DoTask(DoNegativeError);
	return ObjFalse;
    }

    slider = GetObjectVar("ChangeSliderAxis", radio, REPOBJ);
    if (!slider)
    {
	return ObjFalse;
    }

    var = GetIntVar("ChangeSliderAxis", slider, WHICHDIMENSION);
    if (!var)
    {
	return ObjFalse;
    }
    oldValue = GetInt(var);

    if (oldValue == newValue)
    {
	return ObjFalse;
    }

    slicer = GetObjectVar("ChangeSliderAxis", slider, REPOBJ);
    if (!slicer)
    {
	return ObjFalse;
    }

    mainDataset = GetObjectVar("ChangeSliderAxis", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return ObjFalse;
    }

    origDims = GetDatasetFormDims(mainDataset);
    if (!origDims)
    {
	return ObjFalse;
    }

    var = GetArrayVar("ChangeSliderAxis", slicer, DIMVALUES);
    if (!var)
    {
	return ObjFalse;
    }
    el1 = ELEMENTS(var);

    /*Edit the dim values*/
    var = NewRealArray(1, DIMS(var)[0]);
    CArray2Array(var, el1);
    el1 = ELEMENTS(var);
    el1[oldValue] = -1.0;
    el1[newValue] = 0.0;

    SetVar(slicer, DIMVALUES, var);
    SetVar(slider, WHICHDIMENSION, NewInt(newValue));
    SetSliderValue(slider, 0.0);

    el2 = ELEMENTS(origDims);
    SetSliderRange(slider, el2[newValue] - 1.0, 0.0, 1.0);

    DatasetChanged(slicer);
    return ObjTrue;
}

static ObjPtr AddOrthoSlicerControls(slicer, panelContents)
ObjPtr slicer;
ObjPtr panelContents;
/*Makes a new control window to control an ortho slicer*/
{
    ObjPtr var;
    ObjPtr parent;
    long info;
    ObjPtr textBox, checkBox, icon, titleBox, radio, controlField, name, button, slider;
    ObjPtr origDims, dimValues, mainDataset;
    real *el1, *el2;
    int i, k, y;
    int nDimensions;
    int left, right, bottom, top;
    char *s;
    ObjPtr contents;
    WinInfoPtr dialog;

    mainDataset = GetObjectVar("ShowOrthoSlicerControls", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return ObjFalse;
    }
    origDims = GetDatasetFormDims(mainDataset);
    if (!origDims)
    {
	return ObjFalse;
    }

    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetOrthoSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return ObjFalse;
    }

    left = MINORBORDER;
    right = CWINWIDTH - 2 * CORRALBORDER - CWINCORRALWIDTH - MINORBORDER;
    bottom = MINORBORDER;
    top = CWINHEIGHT - MINORBORDER;

    /*Determine if a control field is neccessary*/
    nDimensions = 0;
    el1 = ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] > -0.5)
	{
	    /*Fixed dimension*/
	    ++nDimensions;
	}
    }

    if (nDimensions * (SLIDERWIDTH + BIGSCALESLOP + OSAXISWIDTH + MINORBORDER) >
		(right - left) ||
	TITLEBOXTOP + MINORBORDER + DIMS(origDims)[0] * (CHECKBOXHEIGHT + CHECKBOXSPACING) >
		(top - bottom))
    {
	/*Create a control field*/
	int scrollBars;

	right = (right - left - 2 - MINORBORDER);
	left = MINORBORDER;
	bottom = - (top - bottom - 2 - MINORBORDER);
	top = -MINORBORDER;
	scrollBars = 0;	

	if (nDimensions * (SLIDERWIDTH + BIGSCALESLOP + OSAXISWIDTH + MINORBORDER) >
		(right - left))
	{
	    scrollBars |= BARBOTTOM;
	    bottom += BARWIDTH + CORRALBARBORDER;
	}
	if (TITLEBOXTOP + MINORBORDER + DIMS(origDims)[0] * (CHECKBOXHEIGHT + CHECKBOXSPACING) >
		(top - bottom))
	{
	    scrollBars |= BARRIGHT;
	    right -= BARWIDTH + CORRALBARBORDER;
	}
	if ((0 == scrollBars & BARRIGHT) &&
	    (nDimensions * (SLIDERWIDTH + BIGSCALESLOP + OSAXISWIDTH + MINORBORDER) >
		(right - left)))
	{
	    scrollBars |= BARRIGHT;
	    right -= BARWIDTH + CORRALBARBORDER;
	}

	controlField = NewControlField(MINORBORDER,
			CWINWIDTH - 2 * CORRALBORDER - CWINCORRALWIDTH - MINORBORDER,
			MINORBORDER, CWINHEIGHT - MINORBORDER,
			 "Dimension controls", OBJECTSFROMTOP | scrollBars);	
	if (!controlField)
	{
	    return ObjFalse;
	}
	PrefixList(panelContents, controlField);
	SetVar(controlField, PARENT, panelContents);
	SetVar(controlField, BACKGROUND, NewInt(UIBACKGROUND));
	SetVar(controlField, BORDERTYPE, NewInt(1));
	contents = GetVar(controlField, CONTENTS);
	parent = controlField;
    }
    else
    {
	/*No control field is needed*/
	controlField = NULLOBJ;
	contents = panelContents;
	parent = panelContents;
    }


    /*Create the control groups*/
    nDimensions = 0;
    el2 = ELEMENTS(origDims);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] > -0.5)
	{
	    /*Fixed dimension, emit a series of controls*/
	    char tempName[200], tempValue[50];

	    right = left + BIGSCALESLOP + SLIDERWIDTH;

	    /*Create the slice text box*/
	    sprintf(tempName, "Slice Text %d", nDimensions);

	    textBox = NewTextBox(left, right,
				top - TEXTBOXHEIGHT, top,
				0, tempName, "Slice");
	    SetVar(textBox, PARENT, parent);
	    PrefixList(contents, textBox);
	    SetTextAlign(textBox, CENTERALIGN);

	    /*Create the slider*/
	    sprintf(tempName, "Slice %d", nDimensions);
	    slider = NewSlider(left + BIGSCALESLOP, right,
		    bottom + EDITBOXHEIGHT + MINORBORDER, top - TEXTBOXHEIGHT - MINORBORDER,
		    SCALE, tempName);
	    PrefixList(contents, slider);
	    SetVar(slider, PARENT, parent);
	    SetSliderRange(slider, el2[k] - 1.0, 0.0, 1.0);
	    SetSliderScale(slider, 5.0, 1.0, 0.0, "%g");
	    SetSliderValue(slider, el1[k]);
 	    SetVar(slider, WHICHDIMENSION, NewInt(k));
	    SetVar(slider, REPOBJ, slicer);
	    SetMethod(slider, CHANGEDVALUE, ChangeOrthoSlice);

	    /*Create the slider readout*/
	    sprintf(tempName, "Slice Readout %d", nDimensions);
	    sprintf(tempValue, "%d", (int) (el1[k] + 0.5));
	    textBox = NewTextBox(left, right,
		bottom, bottom + EDITBOXHEIGHT,
		EDITABLE + WITH_PIT + ONE_LINE, tempName, tempValue);
	    SetVar(textBox, PARENT, parent);
	    PrefixList(contents, textBox);
	    SetTextAlign(textBox, RIGHTALIGN);
	    SliderReadout(slider, textBox);

	    /*Create the title box for the axis*/
	    left = right + MINORBORDER;
	    right = left + OSAXISWIDTH;

	    titleBox = NewTitleBox(left, right,
			top - MINORBORDER - TITLEBOXTOP - DIMS(origDims)[0] * (CHECKBOXHEIGHT + CHECKBOXSPACING) - MINORBORDER + CHECKBOXSPACING, top, 
			"Across");
	    SetVar(titleBox, PARENT, parent);
	    PrefixList(contents, titleBox);

	    /*Make the radio group of buttons*/
	    sprintf(tempName, "Axis Radio %d", nDimensions);
	    radio = NewRadioButtonGroup(tempName);
	    SetVar(radio, PARENT, parent);
	    PrefixList(contents, radio);
	    SetVar(radio, REPOBJ, slider);
	    y = top - TITLEBOXTOP - MINORBORDER;
	    for (i = 0; i < DIMS(origDims)[0]; ++i)
	    {
		if (i <= 10)
		{
		    sprintf(tempName, "%c axis (%d)", i + 'i', i);
		}
		else
		{
		    sprintf(tempName, "Axis %d", i);
		}
		checkBox = NewRadioButton(left + MINORBORDER, right - MINORBORDER,
			y - CHECKBOXHEIGHT, y, tempName);
		y -= CHECKBOXHEIGHT + CHECKBOXSPACING;
		AddRadioButton(radio, checkBox);
	    }

	    /*Give it an initial value*/
	    SetValue(radio, NewInt(k));
	    SetMethod(radio, CHANGEDVALUE, ChangeSliderAxis);

	    left = right + MAJORBORDER;
	    ++nDimensions;
	}
    }

    if (controlField)
    {
	RecalcScroll(controlField);
    }

    return ObjTrue;
}

/****************************************************************************/
/*                              Fixed Slicer                                */
/****************************************************************************/

static ObjPtr InitFixedSlicer(slicer, dataset, desFlags, desTopDim, desSpatDim, desNComponents)
ObjPtr slicer, dataset;
long desFlags;
int desTopDim, desSpatDim, desNComponents;
/*Initializes a fixed slicer
	slicer		the slicer
	dataset		the dataset to slice
	desFlags	the desired flags of the result
	desTopDim	the desired topological dimension
	desSpatDim	the desired spatial dimension
	desNComponents	the desired number of components

Returns ObjTrue if successful, ObjFalse if not
*/
{
    long sourceInfo;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    ObjPtr formDims;
    real *elements, *elements2;
    int k, validDims;

    /*Cannot deal with a list of datasets*/
    if (IsList(dataset))
    {
	return ObjFalse;
    }

    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    /*Check the info*/
    if (sourceInfo & DS_UNSTRUCTURED ||
	!(sourceInfo & DS_HASFIELD))
    {
	return ObjFalse;
    }

    if (desFlags & DS_UNSTRUCTURED ||
	!(desFlags & DS_HASFIELD))
    {
	return ObjFalse;
    }
    if ((sourceInfo & (DS_VECTOR)) != (desFlags & (DS_VECTOR)))
    {
	return ObjFalse;
    }

    /*Check the topological dimension*/
    if (desTopDim >= 0 && desTopDim >= sourceTop)
    {
	return ObjFalse;
    }

    /*Check the spatial dimension*/
    if (desSpatDim >= 0 && desSpatDim != sourceSpatial)
    {
	return ObjFalse;
    }
    if (desSpatDim < 0) desSpatDim = sourceSpatial;

    /*See how many of the dimensions are degenerate*/
    formDims = GetDatasetFormDims(dataset);
    if (!formDims)
    {
	return ObjFalse;
    }
    elements = ELEMENTS(formDims);

    validDims = 0;
    for (k = 0; k < DIMS(formDims)[0]; ++k)
    {
	if (elements[k] >= 1.5)
	{
	    ++validDims;
	}
    }

    if (desTopDim < 0)
    {
	desTopDim = validDims;
    }
    else if (desTopDim != validDims)
    {
	return ObjFalse;
    }
    if (desTopDim >= sourceTop)
    {
	return ObjFalse;
    }

    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
	SetVar(slicer, NCOMPONENTS, var);
    }
    else
    {
	sourceNComponents = 1;
    }
    if (desNComponents >= 0 && (sourceNComponents != desNComponents))
    {
	return ObjFalse;
    }
    if (desNComponents < 0) desNComponents = sourceNComponents;

    /*OK now*/

    /*Choose an icon*/
    switch(desTopDim)
    {
	case 0:
	case 1:
	    icon = sourceInfo & DS_VECTOR ? icon1DVector : icon1DScalar;
	    break;
	case 2:
	    icon = sourceInfo & DS_VECTOR ? icon2DVector : icon2DScalar;
	    break;
	case 3:
	    icon = sourceInfo & DS_VECTOR ? icon3DVector : icon3DScalar;
	    break;
	default:
	    icon = sourceInfo & DS_VECTOR ? icon4DVector : icon4DScalar;
	    break;
    }

    icon = NewObject(icon, 0);
    SetVar(slicer, DEFAULTICON, icon);

    SetVar(icon, FORMAT, GetVar(slicer, NAME));
    SetVar(slicer, NAME, GetVar(dataset, NAME));
    SetVar(icon, NAME, GetVar(dataset, NAME));

    /*Set the dataset*/
    SetVar(slicer, MAINDATASET, dataset);

    /*Create the DIMVALUES*/
    dimValues = NewRealArray(1, (long) sourceTop);
    elements = ELEMENTS(dimValues);
    elements2 = ELEMENTS(formDims);
    for (k = 0; k < sourceTop; ++k)
    {
	elements[k] = (elements2[k] < 1.5) ? 0.0: -1.0;
    }
    SetVar(slicer, DIMVALUES, dimValues);

    return ObjTrue;
}

static ObjPtr AllFixedSlicers(slicerClass, datasets)
ObjPtr slicerClass, datasets;
/*Returns a list of all possible slicers that can be made with datasets, or null*/
{
    long sourceInfo;
    long desFlags;
    ObjPtr var;
    int sourceTop, sourceSpatial, sourceNComponents;
    int desTop, desSpatial, desNComponents;
    ObjPtr icon;
    ObjPtr dimValues;
    real *elements;
    int k;
    ObjPtr retVal;
    ThingListPtr runner;

    for (runner = LISTOF(datasets); runner; runner = runner -> next)
    {
	ObjPtr dataset;
	dataset = runner -> thing;
    sourceInfo = GetDatasetInfo(dataset);
    sourceTop = GetTopDim(dataset);
    sourceSpatial = GetSpatialDim(dataset);

    /*Check the info*/
    if (sourceInfo & DS_UNSTRUCTURED ||
	!(sourceInfo & DS_HASFIELD))
    {
	continue;
    }

    desFlags = sourceInfo;

    /*Check the topological dimension*/
    if (sourceTop <= 0)
    {
	continue;
    }

    desSpatial = sourceSpatial;
    /*Check the n components*/
    var = GetVar(dataset, NCOMPONENTS);
    if (var)
    {
	sourceNComponents = GetInt(var);
    }
    else
    {
	sourceNComponents = 1;
    }
    desNComponents = sourceNComponents;

    retVal = NULLOBJ;
    for (desTop = 0; desTop < sourceTop; ++desTop)
    {
	ObjPtr slicer;
	slicer = NewObject(fixedSlicerClass, 0);
	if (IsTrue(InitFilter(slicer, dataset, desFlags, desTop, desSpatial, desNComponents)))
	{
	    if (!retVal)
	    {
		retVal = NewList();
	    }
	    PrefixList(retVal, slicer);
	}
    }
    }
    return retVal;
}

static ObjPtr GetFixedSlicerLongName(slicer)
ObjPtr slicer;
{
    ObjPtr retVal, mainDataset;

    sprintf(tempStr, "Fixed slice");
    retVal = NewString(tempStr);
    mainDataset = GetVar(slicer, MAINDATASET);
    if (mainDataset)
    {
	retVal = ConcatStrings(GetLongName(mainDataset), retVal);
    }
    return retVal;
}

static ObjPtr GetFixedSlicerTopDim(slicer)
ObjPtr slicer;
/*Returns the topological dimension of slicer*/
{
    ObjPtr dimValues;
    int nDimensions, k;
    real *elements;

    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetFixedSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    nDimensions = 0;
    elements = ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (elements[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }

    return NewInt(nDimensions);
}

static ObjPtr GetFixedSlicerSpatialDim(slicer)
ObjPtr slicer;
/*Returns the spatial dimension of slicer*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("GetFixedSlicerSpatialDim", slicer, MAINDATASET);
    if (mainDataset)
    {
	return NewInt(GetSpatialDim(mainDataset));
    }
    else
    {
	return NULLOBJ;
    }
}

static ObjPtr GetFixedSlicerInfo(slicer)
ObjPtr slicer;
/*Gets info for a fixed slicer*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("GetFixedSlicerInfo", slicer, MAINDATASET);
    if (mainDataset)
    {
	return NewInt(GetDatasetInfo(mainDataset));
    }
    else
    {
	return NULLOBJ;
    }
}

static ObjPtr MakeFixedSlicerCPalette(slicer)
ObjPtr slicer;
/*Makes the fixed slicers's CPALETTE*/
{
    ObjPtr mainDataset;
    mainDataset = GetObjectVar("MakeFixedSlicerCPalette", slicer, MAINDATASET);
    if (mainDataset)
    {
	SetVar(slicer, CPALETTE, GetVar(mainDataset, CPALETTE));
	return ObjTrue;
    }
    else
    {
	return ObjFalse;
    }
}

static ObjPtr MakeFixedSlicerDataForm(slicer)
ObjPtr slicer;
/*Makes a fixed slicer's dataform.*/
{
    ObjPtr mainDataset;

    mainDataset = GetObjectVar("MakeFixedSlicerDataForm", slicer, MAINDATASET);
    if (mainDataset)
    {
	SetVar(slicer, DATAFORM, GetVar(mainDataset, DATAFORM));
	return ObjTrue;
    }
    else
    {
	return ObjFalse;
    }
}

static ObjPtr MakeFixedSlicerCurData(slicer)
ObjPtr slicer;
/*Makes a fixed slicers's curdata.  Just a dummy*/
{
    SetVar(slicer, CURDATA, NULLOBJ);
}

static ObjPtr GetFixedSlicerFormDims(slicer)
ObjPtr slicer;
/*Gets form dims for a fixed slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k;
    real *el1, *el2, *el3;

    mainDataset = GetObjectVar("GetFixedSlicerFormDims", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    origDims = GetDatasetFormDims(mainDataset);
    if (!origDims)
    {
	return NULLOBJ;
    }

    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetFixedSlicerFormDims", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }

    if (nDimensions == 0)
    {
	return NULLOBJ;
    }
    resultDims = NewRealArray(1, (long) nDimensions);
    el2 = ELEMENTS(origDims);
    el3 = ELEMENTS(resultDims);
    nDimensions = 0;
    
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    el3[nDimensions] = el2[k];
	    ++nDimensions;
	}
    }

    return resultDims;
}

static ObjPtr RegisterFixedSlicerField(slicer, whichField)
ObjPtr slicer;
int whichField;
/*Registers the field for a fixed slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k, d, i, comp;
    real *el1, *el2, *el3;
    long *tempIndices;
    long offset;

    mainDataset = GetObjectVar("RegisterFixedSlicerField", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    /*Let the main dataset register itself*/
    if (!SetCurField(whichField, mainDataset))
    {
	return ObjFalse;
    }

    /*Now edit it, based on dimValues*/
    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("GetFixedSlicerTopDim", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    /*Calculate the number of dimensions*/
    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }
    curFields[whichField] . topDim = nDimensions;

    /*Set up some temporary indices for testing*/
    tempIndices = (long *) malloc(DIMS(dimValues)[0] * sizeof(long));
    if (!tempIndices)
    {
	return ObjFalse;
    }
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension.  Make it 0*/
	    tempIndices[k] = 0;
	}
	else
	{
	    /*Not free.*/
	    tempIndices[k] = (long) (el1[k] + 0.5);
	}
    }

    /*Go through the components, editing them*/
    for (comp = 0; comp < curFields[whichField] . nComponents; ++comp)
    {
	/*Get the base offset*/
	offset = GetComponentOffset(whichField, comp, tempIndices);

	/*Nudge up the base ptr by that offset*/
	if (curFields[whichField] . components[comp] . dataCompressed)
	{
	    curFields[whichField] . components[comp] . data . comp += offset;
	}
	else
	{
	    curFields[whichField] . components[comp] . data . unComp += offset;
	}

	/*Make invalid any fixed indices*/
	for (k = 0; k < curFields[whichField] . components[comp] . nIndices; ++k)
	{
	    if (el1[curFields[whichField] . components[comp] . indices[k]] > -0.5)
	    {
		/*Fixed index, already accounted for*/
		curFields[whichField] . components[comp] . indices[k] = -1;
	    }
	    else
	    {
		/*Variable index, have to shift down*/
		d = 0;
		for (i = 0; i < curFields[whichField] . components[comp] . indices[k]; ++i)
		{
		    if (el1[i] < -0.5)
		    {
			++d;
		    }
		}
		curFields[whichField] . components[comp] . indices[k] = d;
	    }
	}
    }
    
    free(tempIndices);
    return ObjTrue;
}

static ObjPtr RegisterFixedSlicerForm(slicer, whichField)
ObjPtr slicer;
int whichField;
/*Registers the form for a fixed slicer*/
{
    ObjPtr mainDataset;
    ObjPtr origDims, resultDims, dimValues;
    int nDimensions, k, d, i, comp;
    real *el1, *el2, *el3;
    long *tempIndices;
    long offset;

    mainDataset = GetObjectVar("RegisterFixedSlicerForm", slicer, MAINDATASET);
    if (!mainDataset)
    {
	return NULLOBJ;
    }

    /*Let the main dataset register itself*/
    if (!SetCurForm(whichField, mainDataset))
    {
	return ObjFalse;
    }

    /*Now edit it, based on dimValues*/
    MakeVar(slicer, DIMVALUES);
    dimValues = GetArrayVar("RegisterFixedSlicerForm", slicer, DIMVALUES);
    if (!dimValues)
    {
	return NULLOBJ;
    }

    /*Calculate the number of dimensions*/
    nDimensions = 0;
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension*/
	    ++nDimensions;
	}
    }
    curFields[whichField] . topDim = nDimensions;

    /*Set up some temporary indices for testing*/
    tempIndices = (long *) malloc(DIMS(dimValues)[0] * sizeof(long));
    if (!tempIndices)
    {
	return ObjFalse;
    }
    el1= ELEMENTS(dimValues);
    for (k = 0; k < DIMS(dimValues)[0]; ++k)
    {
	if (el1[k] < -0.5)
	{
	    /*Free dimension.  Make it 0*/
	    tempIndices[k] = 0;
	}
	else
	{
	    /*Not free.*/
	    tempIndices[k] = (long) (el1[k] + 0.5);
	}
    }

    /*Go through the components, editing them*/
    for (comp = 0; comp < curFields[whichField] . nComponents; ++comp)
    {
	/*Get the base offset*/
	offset = GetComponentOffset(whichField, comp, tempIndices);
	
	/*Nudge up the base ptr by that offset*/
	if (curFields[whichField] . components[comp] . dataCompressed)
	{
	    curFields[whichField] . components[comp] . data . comp += offset;
	}
	else
	{
	    curFields[whichField] . components[comp] . data . unComp += offset;
	}

	/*Make invalid any fixed indices*/
	for (k = 0; k < curFields[whichField] . components[comp] . nIndices; ++k)
	{
	    if (el1[curFields[whichField] . components[comp] . indices[k]] > -0.5)
	    {
		/*Fixed index, already accounted for*/
		curFields[whichField] . components[comp] . indices[k] = -1;
	    }
	    else
	    {
		/*Variable index, have to shift down*/
		d = 0;
		for (i = 0; i < curFields[whichField] . components[comp] . indices[k]; ++i)
		{
		    if (el1[i] < -0.5)
		    {
			++d;
		    }
		}
		curFields[whichField] . components[comp] . indices[k] = d;
	    }
	}
    }
    
    free(tempIndices);
    return ObjTrue;
}

/****************************************************************************/
/*                            General functions                             */
/****************************************************************************/

static ObjPtr CloneFilter(filter)
ObjPtr filter;
/*Clones a filter*/
{
    FuncTyp method;
    ObjPtr newFilter;
    ObjPtr mainDataset;

    newFilter = Clone(filter);
    mainDataset = GetVar(newFilter, MAINDATASET);
    if (mainDataset)
    {
	method = GetMethod(mainDataset, CLONE);
	if (method)
	{
	    mainDataset = (*method)(mainDataset);
	    method = GetMethod(newFilter, SETMAINDATASET);
	    if (method)
	    {
		(*method)(newFilter, mainDataset);
	    }
	}
    }
    return newFilter;
}

void RegisterEasyFilter(filter)
ObjPtr filter;
/*Registers filter*/
{
    PrefixList(registeredEasyFilters, filter);
}

int mdsSerialNumber = 0;

static ObjPtr ShowFilterControls(object, windowName)
ObjPtr object;
char *windowName;
/*Makes a new control window to control a filter object*/
{
    WinInfoPtr controlWindow;
    ObjPtr var;
    ObjPtr panel;
    ObjPtr contents;
    FuncTyp method;
    WinInfoPtr dialogExists;

    dialogExists = DialogExists((WinInfoPtr) object, NewString("Controls"));
    controlWindow = GetDialog((WinInfoPtr) object, NewString("Controls"), windowName, 
	FCWINWIDTH, FCWINHEIGHT, FCWINWIDTH, FCWINHEIGHT, WINFIXEDSIZE + WINDBUF);
    
    if (!dialogExists)
    {
	int left, right, bottom, top;
	SetVar((ObjPtr) controlWindow, REPOBJ, object);

	/*Add in help string*/
	SetVar((ObjPtr) controlWindow, HELPSTRING,
	    NewString("This window shows controls for a dataset filter.  \
Use Help In Context and click on the various controls to find out what they do.  \
Click on a different icon to choose a different set of attributes."));

	/*Add in a panel*/
	panel = NewPanel(greyPanelClass, 0, FCWINWIDTH, 0, FCWINHEIGHT);
	if (!panel)
	{
	    return ObjFalse;
	}
	contents = GetVar((ObjPtr) controlWindow, CONTENTS);
	PrefixList(contents, panel);
	SetVar(panel, PARENT, (ObjPtr) controlWindow);
	ContentsExpectWindowSize(controlWindow, FCWINWIDTH, FCWINHEIGHT);

	contents = GetListVar("ShowFilterControls", panel, CONTENTS);
	SetVar(contents, PARENT, panel);

	/*Give the object a chance to add controls*/
	method = GetMethod(object, ADDCONTROLS);
	if (method)
	{
	    justAdding = true;
	    (*method)(object, contents);
	    justAdding = false;
	}
    }

    return (ObjPtr) controlWindow;
}

static ObjPtr GetFilterMinMax(object)
ObjPtr object;
/*Gets a filter's min and max*/
{
    ObjPtr mainDataset;
    MakeVar(object, MAINDATASET);
    mainDataset = GetVar(object, MAINDATASET);
    MakeVar(mainDataset, MINMAX);
    SetVar(object, MINMAX, GetVar(mainDataset, MINMAX));
    return ObjTrue;
}

ObjPtr datasetsToModify = NULLOBJ;

void SetupModifyList()
/*Sets up a list of objects to modify*/
{
    EmptyList(datasetsToModify);
}

ObjPtr ModifyDataset(object)
ObjPtr object;
/*Modifies the dataset (actually just sticks it on the list)*/
{
    PrefixList(datasetsToModify, object);
}

void ModifyDatasets()
{
    DoObjFunction(OF_MODIFY);
}

ObjPtr AllEasyFilters(list)
ObjPtr list;
/*Returns all the easy filters for the elements in list*/
{
    ObjPtr allFilters;
    ThingListPtr runner;

    allFilters = NULLOBJ;

    runner = LISTOF(registeredEasyFilters);
    while (runner)
    {
	ObjPtr filters;
	filters = AllFilters(runner -> thing, list);
	if (filters)
	{
	    if (!allFilters)
	    {
		allFilters = NewList();
	    }
	    AppendList(allFilters, filters);
	}
	runner = runner -> next;
    }
    return allFilters;
}

void ProcessModifyList()
/*Creates a window containing modifications for the selected icons*/
{
    WinInfoPtr newWindow;
    int l, r, b, t;
    int bw;
    ObjPtr objList;
    ObjPtr panel, contents, corral, button;
    ObjPtr allFilters;
    ThingListPtr runner;

    /*Go through the possible filters*/
    allFilters = AllEasyFilters(datasetsToModify);

    if (!allFilters)
    {
	/*No filters*/
	WinInfoPtr errWindow;
	if (IsList(datasetsToModify) && LISTOF(datasetsToModify) && 
	    LISTOF(datasetsToModify) -> next)
	{
	    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0,
	    "There is no modifier which can modify the selected data sets together.",
	    0, 0, "Oh well");
	    SetVar((ObjPtr) errWindow, HELPSTRING,
		NewString("You have tried to modify a group of datasets.  There is no \
modifier which is capable of taking all the datasets you have selected and producing a single \
dataset as a result.  This may be because the datasets have dimensions or components which \
are incompatible with each other.  Show controls on the datasets and check their \
properties with the requirements of the dataset modifiers listed in the manual."));
	}
	else
	{
	    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0,
	    "There is no modifier which can modify the selected data set.",
	    0, 0, "Oh well");
	    SetVar((ObjPtr) errWindow, HELPSTRING,
		NewString("You have tried to modify a single datasets.  There is no \
modifier which is capable of modifying it to produce another dataset as a result.  \
Show controls on the dataset and check its \
properties with the requirements of the dataset modifiers listed in the manual."));
	}
	EmptyList(datasetsToModify);
	return;
    }

    /*Create the window*/
    sprintf(tempStr, "Modified Datasets %d", ++mdsSerialNumber); 
    newWindow = NewObjWindow(NULLOBJ, tempStr, WINDBUF + WINZBUF,
		MODWINWIDTH, MODWINHEIGHT, SCRWIDTH, SCRHEIGHT);

    /*Put in a panel*/
    panel = NewPanel(greyPanelClass, 0, MODWINWIDTH, 0, MODWINHEIGHT);
    SetVar(panel, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
				     STICKYBOTTOM + STICKYTOP));
    ContentsExpectWindowSize(newWindow, MODWINWIDTH, MODWINHEIGHT);

    contents = GetVar((ObjPtr) newWindow, CONTENTS);
    PrefixList(contents, panel);
    SetVar(panel, PARENT, (ObjPtr) newWindow);

    /*Put in buttons and an icon corral*/
    contents = GetListVar("NewDatasetsWindow", panel, CONTENTS);
    if (!contents)
    {
	return;
    }
    /*Make an icon corral*/
    corral = NewIconCorral(NULLOBJ, l + MINORBORDER, r - MINORBORDER, b + 3 * MINORBORDER + 2 * BUTTONHEIGHT, t - MINORBORDER, BARRIGHT + BARBOTTOM);
    SetVar(corral, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
				     STICKYBOTTOM + STICKYTOP));
    SetVar(corral, NAME, NewString("Modifiers Corral"));
    SetVar((ObjPtr) newWindow, CORRAL, corral);
    SetVar(corral, TOPDOWN, ObjTrue);
    SetVar(corral, HELPSTRING,
	NewString("This corral contains icons for all the possible modifications \
of a dataset or group of datasets.  You can visualize, show the controls of, or modify the datasets by selecting \
some of them and pressing the buttons at the bottom of the window.  You can delete \
datasets by choosing Delete from the Object menu."));
    PrefixList(contents, corral);
    SetVar(corral, PARENT, panel);

    l += MINORBORDER;
    r -= MINORBORDER;
    b += 2 * MINORBORDER + BUTTONHEIGHT;
    t = b + BUTTONHEIGHT;
    bw = (r - l - MINORBORDER) / 2;

    /*Make a visualize button*/
    button = NewFunctionButton(newWindow,
		l, l + bw,
		b, b + BUTTONHEIGHT, OF_VISUALIZE); 
    if (button)
    {
	SetVar(button, PARENT, panel);
	SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + STICKYLEFT + FLOATINGRIGHT));
	PrefixList(contents, button);
    }

    /*Make a visualize as... button*/
    button = NewFunctionButton(newWindow,
		r - bw, r,
		b, b + BUTTONHEIGHT, OF_VISUALIZE_AS); 
    if (button)
    {
	SetVar(button, PARENT, panel);
	SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + FLOATINGLEFT + STICKYRIGHT));
	PrefixList(contents, button);
    }

    t = b - MINORBORDER;
    b = t - BUTTONHEIGHT;

    /*Make a show controls button*/
    button = NewFunctionButton(newWindow,
		l, l + bw, 
		b, b + BUTTONHEIGHT, OF_SHOW_CONTROLS); 
    if (button)
    {
	SetVar(button, PARENT, panel);
	SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + STICKYLEFT + FLOATINGRIGHT));
	PrefixList(contents, button);
    }

    /*Make a modify button*/
    button = NewFunctionButton(newWindow, r - bw, 
		r,
		b, b + BUTTONHEIGHT, OF_MODIFY);
    if (button)
    {
	SetVar(button, PARENT, panel);
	SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + FLOATINGLEFT + STICKYRIGHT));
	PrefixList(contents, button);
    }

    /*Put allFilters in the corral*/
    runner = LISTOF(allFilters);

    while(runner)
    {
	ObjPtr icon, name;
	FuncTyp method;
	
	icon = GetVar(runner -> thing, DEFAULTICON);
	if (!icon)
	{
	    icon = NewIcon(0, 0, ICONQUESTION, "?");
	}
	else
	{
	    icon = NewObject(icon, 0L);
	}
	method = GetMethodSurely("ModifyDatasets", runner -> thing, GETLONGNAME);
	if (method)
	{
	    name = (*method)(runner -> thing);
	    SetVar(icon, NAME, name);
	}

	SetVar(icon, ICONLOC, NULLOBJ);
	SetVar(icon, REPOBJ, runner -> thing);
	SetVar(icon, CORRAL, corral);
	DropIconSeriesInCorral(corral, icon);

	runner = runner -> next;
    }

    EmptyModifyList();
}

void EmptyModifyList()
{
    EmptyList(datasetsToModify);
}

ObjPtr InitFilter(filter, dataset, desFlags, desTopDim, desSpatDim, desNComponents)
ObjPtr filter, dataset;
long desFlags;
int desTopDim, desSpatDim, desNComponents;
/*Initializes a filter*/
{
    FuncTyp method;
    method = GetMethod(filter, INITFILTER);
    if (method)
    {
	return (*method)(filter, dataset, desFlags, desTopDim, desSpatDim, desNComponents);
    }
    else
    {
	return ObjFalse;
    }
}

ObjPtr NewFilter(filterClass, dataset, desFlags, desTopDim, desSpatDim, desNComponents)
ObjPtr filterClass, dataset;
long desFlags;
int desTopDim, desSpatDim, desNComponents;
/*Makes a new filter and initializes it*/
{
    ObjPtr filter;

    filter = NewObject(filterClass, 0L);
    if (IsTrue(InitFilter(filter, dataset, desFlags, desTopDim, desSpatDim, desNComponents)))
    {
	return filter;
    }
    else
    {
	return NULLOBJ;
    }
}

ObjPtr AllFilters(filterClass, dataset)
ObjPtr filterClass, dataset;
/*Returns all the filters that can modify dataset*/
{
    FuncTyp method;
    method = GetMethod(filterClass, ALLFILTERS);
    if (method)
    {
	return (*method)(filterClass, dataset);
    }
    else
    {
	return ObjFalse;
    }
}

ObjPtr MakeFilterTimeSteps(filter)
ObjPtr filter;
/*Makes a filter's TIMESTEPS*/
{
    ObjPtr dataset;

    MakeVar(filter, MAINDATASET);
    dataset = GetVar(filter, MAINDATASET);
    if (dataset)
    {
	SetVar(filter, TIMESTEPS, GetVar(dataset, TIMESTEPS));
    }
    return ObjTrue;
}

ObjPtr MakeFilterTimeFormat(filter)
ObjPtr filter;
/*Makes a filter's TIMEFORMAT*/
{
    ObjPtr dataset;

    MakeVar(filter, MAINDATASET);
    dataset = GetVar(filter, MAINDATASET);
    if (dataset)
    {
	MakeVar(dataset, TIMEFORMAT);
	SetVar(filter, TIMEFORMAT, GetVar(dataset, TIMEFORMAT));
    }
    return ObjTrue;
}

static ObjPtr MakeFilterXName(filter)
ObjPtr filter;
/*Makes a filter's XNAME*/
{
    ObjPtr mainDataset;

    MakeVar(filter, MAINDATASET);
    mainDataset = GetVar(filter, MAINDATASET);

    if (mainDataset)
    {
	MakeVar(mainDataset, XNAME);
	SetVar(filter, XNAME, GetVar(mainDataset, XNAME));
    }
    else
    {
	SetVar(filter, XNAME, NULLOBJ);
    }
}

static ObjPtr MakeFilterYName(filter)
ObjPtr filter;
/*Makes a filter's YNAME*/
{
    ObjPtr mainDataset;

    MakeVar(filter, MAINDATASET);
    mainDataset = GetVar(filter, MAINDATASET);

    if (mainDataset)
    {
	MakeVar(mainDataset, YNAME);
	SetVar(filter, YNAME, GetVar(mainDataset, YNAME));
    }
    else
    {
	SetVar(filter, YNAME, NULLOBJ);
    }
}

static ObjPtr MakeFilterZName(filter)
ObjPtr filter;
/*Makes a filter's ZNAME*/
{
    ObjPtr mainDataset;

    MakeVar(filter, MAINDATASET);
    mainDataset = GetVar(filter, MAINDATASET);

    if (mainDataset)
    {
	MakeVar(mainDataset, ZNAME);
	SetVar(filter, ZNAME, GetVar(mainDataset, ZNAME));
    }
    else
    {
	SetVar(filter, ZNAME, NULLOBJ);
    }
}

void InitFilters()
/*Initializes the filters*/
{
    ObjPtr icon;

    datasetsToModify = NewList();
    AddToReferenceList(datasetsToModify);

    registeredEasyFilters = NewList();
    AddToReferenceList(registeredEasyFilters);

    SetMethod(datasetClass, MODIFY, ModifyDataset);
    filterClass = NewObject(datasetClass, 0);
    AddToReferenceList(filterClass);
    SetMethod(filterClass, CLONE, CloneFilter);
/*    SetMethod(filterClass, NEWCTLWINDOW, ShowFilterControls);*/
    SetMethod(filterClass, SHOWCONTROLS, NewControlWindow);
    SetMethod(filterClass, MINMAX, GetFilterMinMax);
    DeclareIndirectDependency(filterClass, TIMESTEPS, MAINDATASET, TIMESTEPS);
    SetMethod(filterClass, TIMESTEPS, MakeFilterTimeSteps);
    DeclareIndirectDependency(filterClass, TIMEFORMAT, MAINDATASET, TIMEFORMAT);
    SetMethod(filterClass, TIMEFORMAT, MakeFilterTimeFormat);
    SetMethod(filterClass, XNAME, MakeFilterXName);
    SetMethod(filterClass, YNAME, MakeFilterYName);
    SetMethod(filterClass, ZNAME, MakeFilterZName);

    /*Orthogonal slicer filter*/
    orthoSlicerClass = NewObject(filterClass, 0);
    SetVar(orthoSlicerClass, NAME, NewString("Ortho Slice"));
    SetMethod(orthoSlicerClass, INITFILTER, InitOrthoSlicer);
    SetMethod(orthoSlicerClass, GETDATASETINFO, GetOrthoSlicerInfo);
    SetMethod(orthoSlicerClass, GETTOPDIM, GetOrthoSlicerTopDim);
    SetMethod(orthoSlicerClass, GETSPATIALDIM, GetOrthoSlicerSpatialDim);
    SetMethod(orthoSlicerClass, GETFORMDIMS, GetOrthoSlicerFormDims);
    SetMethod(orthoSlicerClass, REGISTERFIELD, RegisterOrthoSlicerField);
    SetMethod(orthoSlicerClass, REGISTERFORM, RegisterOrthoSlicerForm);
    SetMethod(orthoSlicerClass, ADDCONTROLS, AddOrthoSlicerControls);
    SetMethod(orthoSlicerClass, GETLONGNAME, GetOrthoSlicerLongName);
    SetMethod(orthoSlicerClass, ALLFILTERS, AllOrthoSlicers);
    icon = NewIcon(0, 0, ICONSLICE, "Slice");
    SetVar(orthoSlicerClass, CONTROLICON, icon);

    DeclareDependency(orthoSlicerClass, CPALETTE, MAINDATASET);
    DeclareIndirectDependency(orthoSlicerClass, CPALETTE, MAINDATASET, CPALETTE);
    SetMethod(orthoSlicerClass, CPALETTE, MakeOrthoSlicerCPalette);

    DeclareDependency(orthoSlicerClass, DATAFORM, MAINDATASET);
    DeclareIndirectDependency(orthoSlicerClass, DATAFORM, MAINDATASET, DATAFORM);
    SetMethod(orthoSlicerClass, DATAFORM, MakeOrthoSlicerDataForm);

    DeclareDependency(orthoSlicerClass, CURDATA, MAINDATASET);
    DeclareDependency(orthoSlicerClass, CURDATA, DIMVALUES);
    DeclareIndirectDependency(orthoSlicerClass, CURDATA, MAINDATASET, CURDATA);
    SetMethod(orthoSlicerClass, CURDATA, MakeOrthoSlicerCurData);

    RegisterEasyFilter(orthoSlicerClass);

    /*Fixed slicer filter*/
    fixedSlicerClass = NewObject(filterClass, 0);
    SetVar(fixedSlicerClass, NAME, NewString("Fixed Slice"));
    SetMethod(fixedSlicerClass, INITFILTER, InitFixedSlicer);
    SetMethod(fixedSlicerClass, GETDATASETINFO, GetFixedSlicerInfo);
    SetMethod(fixedSlicerClass, GETTOPDIM, GetFixedSlicerTopDim);
    SetMethod(fixedSlicerClass, GETSPATIALDIM, GetFixedSlicerSpatialDim);
    SetMethod(fixedSlicerClass, GETFORMDIMS, GetFixedSlicerFormDims);
    SetMethod(fixedSlicerClass, REGISTERFIELD, RegisterFixedSlicerField);
    SetMethod(fixedSlicerClass, REGISTERFORM, RegisterFixedSlicerForm);
    SetMethod(fixedSlicerClass, GETLONGNAME, GetFixedSlicerLongName);
    SetMethod(fixedSlicerClass, ALLFILTERS, AllFixedSlicers);
    icon = NewIcon(0, 0, ICONSLICE, "Slice");
    SetVar(fixedSlicerClass, CONTROLICON, icon);

    DeclareDependency(fixedSlicerClass, CPALETTE, MAINDATASET);
    DeclareIndirectDependency(fixedSlicerClass, CPALETTE, MAINDATASET, CPALETTE);
    SetMethod(fixedSlicerClass, CPALETTE, MakeFixedSlicerCPalette);

    DeclareDependency(fixedSlicerClass, DATAFORM, MAINDATASET);
    DeclareIndirectDependency(fixedSlicerClass, DATAFORM, MAINDATASET, DATAFORM);
    SetMethod(fixedSlicerClass, DATAFORM, MakeFixedSlicerDataForm);

    DeclareDependency(fixedSlicerClass, CURDATA, MAINDATASET);
    DeclareDependency(fixedSlicerClass, CURDATA, DIMVALUES);
    DeclareIndirectDependency(fixedSlicerClass, CURDATA, MAINDATASET, CURDATA);
    SetMethod(fixedSlicerClass, CURDATA, MakeFixedSlicerCurData);

    RegisterEasyFilter(fixedSlicerClass);


    /*Vector joiner filter*/
    vectorJoinerClass = NewObject(filterClass, 0);
    SetVar(vectorJoinerClass, NAME, NewString("Vector Joiner"));
    SetMethod(vectorJoinerClass, INITFILTER, InitVectorJoiner);
    SetMethod(vectorJoinerClass, ALLFILTERS, AllVectorJoiners);
#if 0
    SetMethod(orthoSlicerClass, GETDATASETINFO, GetOrthoSlicerInfo);
    SetMethod(orthoSlicerClass, GETTOPDIM, GetOrthoSlicerTopDim);
    SetMethod(orthoSlicerClass, GETSPATIALDIM, GetOrthoSlicerSpatialDim);
    SetMethod(orthoSlicerClass, GETFORMDIMS, GetOrthoSlicerFormDims);
    SetMethod(orthoSlicerClass, REGISTERFIELD, RegisterOrthoSlicerField);
    SetMethod(orthoSlicerClass, REGISTERFORM, RegisterOrthoSlicerForm);
    SetMethod(orthoSlicerClass, ADDCONTROLS, AddOrthoSlicerControls);
    SetMethod(vectorJoinerClass, GETLONGNAME, GetOrthoSlicerLongName);
    icon = NewIcon(0, 0, ICONSLICE, "Slice");
    SetVar(orthoSlicerClass, CONTROLICON, icon);

    DeclareDependency(orthoSlicerClass, CPALETTE, MAINDATASET);
    DeclareIndirectDependency(orthoSlicerClass, CPALETTE, MAINDATASET, CPALETTE);
    SetMethod(orthoSlicerClass, CPALETTE, MakeOrthoSlicerCPalette);

    DeclareDependency(orthoSlicerClass, DATAFORM, MAINDATASET);
    DeclareIndirectDependency(orthoSlicerClass, DATAFORM, MAINDATASET, DATAFORM);
    SetMethod(orthoSlicerClass, DATAFORM, MakeOrthoSlicerDataForm);

    DeclareDependency(orthoSlicerClass, CURDATA, MAINDATASET);
    DeclareDependency(orthoSlicerClass, CURDATA, DIMVALUES);
    DeclareIndirectDependency(orthoSlicerClass, CURDATA, MAINDATASET, CURDATA);
    SetMethod(orthoSlicerClass, CURDATA, MakeOrthoSlicerCurData);
#endif

#if 0
    RegisterEasyFilter(vectorJoinerClass);
#endif

}

void KillFilters()
/*Kills the filters*/
{
    DeleteThing(filterClass);
    DeleteThing(registeredEasyFilters);
    DeleteThing(datasetsToModify);
}
