/*ScianVisSticks.c
  October 7, 1992
  Eric Pepke
  Stick visualization object in SciAn*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianWindows.h"
#include "ScianTextBoxes.h"
#include "ScianButtons.h"
#include "ScianTitleBoxes.h"
#include "ScianObjWindows.h"
#include "ScianIcons.h"
#include "ScianColors.h"
#include "ScianControls.h"
#include "ScianLists.h"
#include "ScianSliders.h"
#include "ScianIDs.h"
#include "ScianDatasets.h"
#include "ScianPictures.h"
#include "ScianDialogs.h"
#include "ScianErrors.h"
#include "ScianComplexControls.h"
#include "ScianMethods.h"
#include "ScianStyle.h"
#include "ScianVisObjects.h"
#include "ScianVisSticks.h"
#include "ScianDraw.h"
#include "ScianTemplates.h"
#include "ScianTemplateHelper.h"
#include "ScianTimers.h"
#include "ScianSpaces.h"
#include "ScianEvents.h"

/*Stick visualization flags*/
#define SF_SHOWBONDS	1
#define SF_SHOWBASE	2

#define SELJACKSIZE	0.8

ObjPtr visSticks;	/*Class for stick object*/

static ObjPtr ShowDetailedBondsButton(button)
ObjPtr button;
/*Changed value for a button to show detailed bonds*/
{
    ObjPtr sticks;
    ObjPtr residues;
    TwoReals *residueElements;
    long nResidues;
    long k, residueBeginning;
    long ac;
    ObjPtr portionSelected;
    real *psElements;
    ObjPtr sticksDataset;
    ObjPtr showHow;
    real *showHowElements;

    sticks = GetObjectVar("ShowDetailedBondsButton", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    portionSelected = GetVar(sticks, PORTIONSELECTED);
    if (!portionSelected)
    {
	return ObjFalse;
    }
    psElements = (real *) ELEMENTS(portionSelected);

    showHow = GetArrayVar("ShowDetailedBondsButton", sticks, SHOWATOMSHOW);
    if (!showHow)
    {
	return ObjFalse;
    }
    showHowElements = (real *) ELEMENTS(showHow);

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    residues = GetArrayVar("ShowDetailedBondsButton", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (!residues)
    {
	return ObjFalse;
    }
    residueElements = (TwoReals *) ELEMENTS(residues);
    nResidues = DIMS(residues)[0];

    /*Go through the residues*/
    residueBeginning = 0;
    for (k = 0; k < nResidues; ++k)
    {
	Bool isSelected;

	isSelected = false;
	for (ac = residueBeginning; ac < (int) residueElements[k][0]; ++ac)
	{
	    if (psElements[ac] > 0.5)
	    {
		isSelected = true;
		break;
	    }
	}

	if (isSelected)
	{
	    long sh;
	    for (ac = residueBeginning; ac < residueElements[k][0]; ++ac)
	    {
		sh = showHowElements[ac];
		sh |= SF_SHOWBONDS;
		showHowElements[ac] = sh;
	    }
	}

	residueBeginning = residueElements[k][0] + 1;
    }
    SetVar(sticks, SHOWATOMSHOW, showHow);
    ImInvalid(sticks);
    return ObjFalse;
}

static ObjPtr HideDetailedBondsButton(button)
ObjPtr button;
/*Changed value for a button to hide detailed bonds*/
{
    ObjPtr sticks;
    ObjPtr residues;
    TwoReals *residueElements;
    long nResidues;
    long k, residueBeginning;
    long ac;
    ObjPtr portionSelected;
    real *psElements;
    ObjPtr sticksDataset;
    ObjPtr showHow;
    real *showHowElements;

    sticks = GetObjectVar("HideDetailedBondsButton", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    portionSelected = GetVar(sticks, PORTIONSELECTED);
    if (!portionSelected)
    {
	return ObjFalse;
    }
    psElements = (real *) ELEMENTS(portionSelected);

    showHow = GetArrayVar("HideDetailedBondsButton", sticks, SHOWATOMSHOW);
    if (!showHow)
    {
	return ObjFalse;
    }
    showHowElements = (real *) ELEMENTS(showHow);

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    residues = GetArrayVar("HideDetailedBondsButton", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (!residues)
    {
	return ObjFalse;
    }
    residueElements = (TwoReals *) ELEMENTS(residues);
    nResidues = DIMS(residues)[0];

    /*Go through the residues*/
    residueBeginning = 0;
    for (k = 0; k < nResidues; ++k)
    {
	Bool isSelected;

	isSelected = false;
	for (ac = residueBeginning; ac < (int) residueElements[k][0]; ++ac)
	{
	    if (psElements[ac] > 0.5)
	    {
		isSelected = true;
		break;
	    }
	}

	if (isSelected)
	{
	    long sh;
	    for (ac = residueBeginning; ac < residueElements[k][0]; ++ac)
	    {
		sh = showHowElements[ac];
		sh &= ~SF_SHOWBONDS;
		showHowElements[ac] = sh;
	    }
	}

	residueBeginning = residueElements[k][0] + 1;
    }
    SetVar(sticks, SHOWATOMSHOW, showHow);
    ImInvalid(sticks);
    return ObjFalse;
}

static ObjPtr ShowResidueBasesButton(button)
ObjPtr button;
/*Changed value for a button to show residue bases*/
{
    ObjPtr sticks;
    ObjPtr residues;
    TwoReals *residueElements;
    long nResidues;
    long k, residueBeginning;
    long ac;
    ObjPtr portionSelected;
    real *psElements;
    ObjPtr sticksDataset;
    ObjPtr showHow;
    real *showHowElements;

    sticks = GetObjectVar("ShowResidueBasesButton", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    portionSelected = GetVar(sticks, PORTIONSELECTED);
    if (!portionSelected)
    {
	return ObjFalse;
    }
    psElements = (real *) ELEMENTS(portionSelected);

    showHow = GetArrayVar("ShowResidueBasesButton", sticks, SHOWATOMSHOW);
    if (!showHow)
    {
	return ObjFalse;
    }
    showHowElements = (real *) ELEMENTS(showHow);

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    residues = GetArrayVar("ShowResidueBasesButton", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (!residues)
    {
	return ObjFalse;
    }
    residueElements = (TwoReals *) ELEMENTS(residues);
    nResidues = DIMS(residues)[0];

    /*Go through the residues*/
    residueBeginning = 0;
    for (k = 0; k < nResidues; ++k)
    {
	Bool isSelected;

	isSelected = false;
	for (ac = residueBeginning; ac < (int) residueElements[k][0]; ++ac)
	{
	    if (psElements[ac] > 0.5)
	    {
		isSelected = true;
		break;
	    }
	}

	if (isSelected)
	{
	    long sh;
	    for (ac = residueBeginning; ac < residueElements[k][0]; ++ac)
	    {
		sh = showHowElements[ac];
		sh |= SF_SHOWBASE;
		showHowElements[ac] = sh;
	    }
	}

	residueBeginning = residueElements[k][0] + 1;
    }
    SetVar(sticks, SHOWATOMSHOW, showHow);
    ImInvalid(sticks);
    return ObjFalse;
}

static ObjPtr HideResidueBasesButton(button)
ObjPtr button;
/*Changed value for a button to hide residue bases*/
{
    ObjPtr sticks;
    ObjPtr residues;
    TwoReals *residueElements;
    long nResidues;
    long k, residueBeginning;
    long ac;
    ObjPtr portionSelected;
    real *psElements;
    ObjPtr sticksDataset;
    ObjPtr showHow;
    real *showHowElements;

    sticks = GetObjectVar("HideResidueBasesButton", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    portionSelected = GetVar(sticks, PORTIONSELECTED);
    if (!portionSelected)
    {
	return ObjFalse;
    }
    psElements = (real *) ELEMENTS(portionSelected);

    showHow = GetArrayVar("HideResidueBasesButton", sticks, SHOWATOMSHOW);
    if (!showHow)
    {
	return ObjFalse;
    }
    showHowElements = (real *) ELEMENTS(showHow);

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    residues = GetArrayVar("HideResidueBasesButton", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (!residues)
    {
	return ObjFalse;
    }
    residueElements = (TwoReals *) ELEMENTS(residues);
    nResidues = DIMS(residues)[0];

    /*Go through the residues*/
    residueBeginning = 0;
    for (k = 0; k < nResidues; ++k)
    {
	Bool isSelected;

	isSelected = false;
	for (ac = residueBeginning; ac < (int) residueElements[k][0]; ++ac)
	{
	    if (psElements[ac] > 0.5)
	    {
		isSelected = true;
		break;
	    }
	}

	if (isSelected)
	{
	    long sh;
	    for (ac = residueBeginning; ac < residueElements[k][0]; ++ac)
	    {
		sh = showHowElements[ac];
		sh &= ~SF_SHOWBASE;
		showHowElements[ac] = sh;
	    }
	}

	residueBeginning = residueElements[k][0] + 1;
    }
    SetVar(sticks, SHOWATOMSHOW, showHow);
    ImInvalid(sticks);
    return ObjFalse;
}

static ObjPtr FillInSelection(button)
ObjPtr button;
/*Changed value for a button to fill in the selection*/
{
    real *elements;
    ObjPtr var;
    long size;
    long k;
    ObjPtr sticks;
    long first, last;

    sticks = GetObjectVar("DeselectAllAtoms", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    var = GetVar(sticks, PORTIONSELECTED);
    if (!var)
    {
	return ObjFalse;
    }

    size = DIMS(var)[0];
    elements = (real *) ELEMENTS(var);

    first = -1;
    for (k = 0; k < size; ++k)
    {
	if (elements[k] > 0.5)
	{
	    if (first == -1) first = k;
	    last = k;
	}
    }

    if (first > -1)
    {
	var = NewRealArray(1, size);
	elements = (real *) ELEMENTS(var);
	for (k = first; k <= last; ++k)
	{
	    elements[k] = 1.0;
	}
	
	SetVar(sticks, PORTIONSELECTED, var);
	ImInvalid(sticks);
    }
    return ObjTrue;
}

static ObjPtr DeselectAllAtoms(button)
ObjPtr button;
/*Changed value for a button to deselect all atoms*/
{
    ObjPtr sticks;

    sticks = GetObjectVar("DeselectAllAtoms", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    SetVar(sticks, PORTIONSELECTED, NULLOBJ);
    ImInvalid(sticks);
    return ObjTrue;
}

static ObjPtr SelectAllAtoms(button)
ObjPtr button;
/*Changed value for a button to select all atoms*/
{
    real *elements;
    ObjPtr var;
    long size;
    long k;
    ObjPtr sticks;

    sticks = GetObjectVar("SelectAllAtoms", button, REPOBJ);
    if (!sticks)
    {
	return ObjFalse;
    }

    /*Have to create it*/
    var = GetArrayVar("SelectAllAtoms", sticks, SHOWATOMSHOW);
    if (!var)
    {
	return ObjFalse;
    }
    size = DIMS(var)[0];
    var = NewRealArray(1, size);
    elements = (real *) ELEMENTS(var);
    for (k = 0; k < size; ++k)
    {
	elements[k] = 1.0;
    }
    SetVar(sticks, PORTIONSELECTED, var);
    ImInvalid(sticks);
    return ObjTrue;
}

static ObjPtr AddSticksControls(sticks, panelContents)
ObjPtr sticks, panelContents;
/*Adds controls to a sticks object*/
{
    ObjPtr button;

    button = TemplateButton(VisSticksTemplate, "Show Detailed Bonds");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, ShowDetailedBondsButton);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button shows the detailed bonds of the selected atoms."));

    button = TemplateButton(VisSticksTemplate, "Show Residue Bases");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, ShowResidueBasesButton);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button shows the residue bases of the selected atoms."));

    button = TemplateButton(VisSticksTemplate, "Hide Detailed Bonds");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, HideDetailedBondsButton);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button hides the detailed bonds of the selected atoms."));

    button = TemplateButton(VisSticksTemplate, "Hide Residue Bases");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, HideResidueBasesButton);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button hides the residue bases of the selected atoms."));

    button = TemplateButton(VisSticksTemplate, "Select All Atoms");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, SelectAllAtoms);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button selects all the atoms in the structure."));

    button = TemplateButton(VisSticksTemplate, "Deselect All Atoms");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, DeselectAllAtoms);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button deselects all the atoms in the structure."));

    button = TemplateButton(VisSticksTemplate, "Fill In Selection");
    PrefixList(panelContents, button);
    SetVar(button, PARENT, panelContents);
    SetVar(button, REPOBJ, sticks);
    SetMethod(button, CHANGEDVALUE, FillInSelection);
    SetVar(button, HELPSTRING, NewString(
	"Pressing this button fills in the selection you have made.  An easy \
way to select a range of objects is to select one on either side of the range \
and press this button."));

    return ObjTrue;
}

static long nStickDraws = 0;
static double stickTime;

#undef SHOWN
#define SHOWN(k, f) (((int) (showAtomsHow[(k)])) & (f))

static ObjPtr PickSticks(sticks)
ObjPtr sticks;
/*Picks some points in sticks*/
{
#ifdef GRAPHICS
    ObjPtr sticksDataset;
    ObjPtr edges;
    real baseColor[3];		/*Base color of the object*/
    float bc[3];		/*Base color of the object*/
    ObjPtr var;
    long k, maxK;
    long index1, index2;
    float position1[3], position2[3], midPosition[3];
    ObjPtr colorObj;
    TwoReals *elements;
    real *showAtomsHow;
    TwoReals *residues;
    int nResidues;

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    edges = GetDatasetKEdges(sticksDataset, 1);
    if (!edges)
    {
	return ObjFalse;
    }

    SetCurForm(FORMFIELD, sticksDataset);

    var = GetVar(sticks, LINEWIDTH);
    if (var)
    {
	int width;
	width = GetReal(var);
	if (width < 1) width = 1;
	SetLineWidth(width);
    }

    /*Get the show atoms how*/
    var = GetArrayVar("PickSticks", sticks, SHOWATOMSHOW);
    if (var)
    {
	showAtomsHow = (real *) ELEMENTS(var);
    }
    else
    {
	return ObjFalse;
    }

    /*Get the residues for alpha carbon*/
    var = GetArrayVar("PickSticks", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (var)
    {
	residues = (TwoReals *) ELEMENTS(var);
	nResidues = DIMS(var)[0];
    }
    else
    {
	residues = 0;
    }

    /*Now draw the picture*/
    maxK = DIMS(edges)[0];
    elements = ELEMENTS(edges);

    /*Draw bonds with split sticks*/
    for (k = 0; k < maxK; ++k)
    {
	index1 = elements[k][0];
	index2 = elements[k][1];

	/*Get positions*/
	if (SHOWN(index1, SF_SHOWBONDS) ||
	    SHOWN(index2, SF_SHOWBONDS))
	{
	    position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
	    position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
	    position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);

	    position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
	    position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
	    position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);

	    midPosition[0] = (position1[0] + position2[0]) * 0.5;    
	    midPosition[1] = (position1[1] + position2[1]) * 0.5;    
	    midPosition[2] = (position1[2] + position2[2]) * 0.5;
	}

	if (SHOWN(index1, SF_SHOWBONDS))
	{
	    /*Do 1 to mid*/
	    PickVertex(index1);
#ifdef V3FISBUGGED
	    move(position1[0], position1[1], position1[2]);
	    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
	    bgnline();
	    v3f(position1);
	    v3f(midPosition);
	    endline();
#endif
	}

	if (SHOWN(index2, SF_SHOWBONDS))
	{
	    /*Do mid to end*/
	    PickVertex(index2);

#ifdef V3FISBUGGED
	    move(position2[0], position2[1], position2[2]);
	    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
	    bgnline();
	    v3f(midPosition);
	    v3f(position2);
	    endline();
#endif
	}
    }

    /*Draw carbon chain*/
    if (residues)
    {
	for (k = 1; k < nResidues; ++k)
	{
	    index1 = residues[k - 1][1];
	    index2 = residues[k][1];

	    /*Get positions*/
	    if (SHOWN(index1, SF_SHOWBASE) ||
		SHOWN(index2, SF_SHOWBASE))
	    {
		position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
		position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
		position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);

		position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
		position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
		position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);

		midPosition[0] = (position1[0] + position2[0]) * 0.5;    
		midPosition[1] = (position1[1] + position2[1]) * 0.5;    
		midPosition[2] = (position1[2] + position2[2]) * 0.5;
	    }

	    if (SHOWN(index1, SF_SHOWBASE))
	    {
		/*Do 1 to mid*/
		PickVertex(index1);
#ifdef V3FISBUGGED
		move(position1[0], position1[1], position1[2]);
		draw(midPosition[0], midPosition[1], midPosition[2]);
#else
		bgnline();
		v3f(position1);
		v3f(midPosition);
		endline();
#endif
	    }

	    if (SHOWN(index2, SF_SHOWBASE))
	    {
		/*Do mid to end*/
		PickVertex(index2);
#ifdef V3FISBUGGED
		move(position2[0], position2[1], position2[2]);
		draw(midPosition[0], midPosition[1], midPosition[2]);
#else
		bgnline();
		v3f(midPosition);
		v3f(position2);
		endline();
#endif
	    }
	}
    }
#endif
}

static ObjPtr MakeSticksAppearance(sticks)
ObjPtr sticks;
/*Makes a stick's appearance*/
{
    SetVar(sticks, APPEARANCE, ObjTrue);
    ImInvalid(sticks);
    return ObjFalse;
}

static ObjPtr BeginStuffingSticks(sticks)
ObjPtr sticks;
/*Begins stuffing sel points from sticks*/
{
    ObjPtr sticksDataset;

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    SetCurForm(FORMFIELD, sticksDataset);
    return ObjTrue;
}

static ObjPtr StuffSticksSelPoint(sticks, index, x, y, z)
ObjPtr sticks;
long index;
real *x, *y, *z;
/*Get a particular selection point for a sticks object, stuff it in x, y, z*/
{
    *x = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index);
    *y = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index);
    *z = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index);

    return ObjTrue;
}

static ObjPtr SelectSticksSelPoint(sticks, selPoint, flags)
ObjPtr sticks;
long selPoint;
long flags;
/*Selects a stick selPoint according to flags*/
{
    real *elements;
    ObjPtr var;
    long size;
    long k;

    var = GetVar(sticks, PORTIONSELECTED);
    if (!var)
    {
	/*Have to create it*/
	var = GetArrayVar("SelectSticksSelPoint", sticks, SHOWATOMSHOW);
	if (!var)
	{
	    return ObjFalse;
	}
	size = DIMS(var)[0];
	var = NewRealArray(1, size);
	elements = (real *) ELEMENTS(var);
	for (k = 0; k < size; ++k)
	{
	    elements[k] = 0.0;
	}
	elements[selPoint] = 1.0;
    }
    else
    {
	/*It's already there.*/
	size = DIMS(var)[0];
	elements = (real *) ELEMENTS(var);
	if (flags & F_EXTEND)
	{
	    elements[selPoint] = elements[selPoint] > 0.0 ? 0.0 : 1.0;
	}
	else
	{
	    for (k = 0; k < size; ++k)
	    {
		elements[k] = 0.0;
	    }
	    elements[selPoint] = 1.0;
	}
    }
    SetVar(sticks, PORTIONSELECTED, var);
    return ObjTrue;
}

static ObjPtr DrawSticks(sticks)
ObjPtr sticks;
/*Draws the sticks*/
{
#ifdef GRAPHICS
    ObjPtr sticksDataset;
    ObjPtr edges;
    real baseColor[3];		/*Base color of the object*/
    float bc[3];		/*Base color of the object*/
    ObjPtr var;
    ObjPtr picture;
    ObjPtr colors;
    long k, maxK;
    long index1, index2;
    float position1[3], position2[3], midPosition[3];
    ObjPtr colorObj;
    TwoReals *elements;
    Bool equalForm;
    long colorIndex;
    real sample;
    Bool depthCue;
    real *showAtomsHow;
    TwoReals *residues;
    int nResidues;

#ifdef BENCHMARK
    if (nStickDraws)
    {
	if ((nStickDraws & 127) == 0)
	{
	    double temp;
	    temp = Clock();
	    printf("%lg frames per second\n", 128 / (temp - stickTime));
	    stickTime = temp;
	}
	++nStickDraws;
    }
    else
    {
	stickTime = Clock();
	++nStickDraws;
    }
#endif

    sticksDataset = GetVar(sticks, STICKSFIELD);
    if (!sticksDataset)
    {
	return ObjFalse;
    }

    edges = GetDatasetKEdges(sticksDataset, 1);
    if (!edges)
    {
	return ObjFalse;
    }

    SetCurForm(FORMFIELD, sticksDataset);

    MakeVar(sticks, COLOROBJ);
    colorObj = GetVar(sticks, COLOROBJ);
    if (!GetPredicate(sticks, COLORS))
    {
	colorObj = NULLOBJ;
    }

    MakeVar(sticks, CPALETTE);
    colors = GetVar(sticks, CPALETTE);
    if (!colors)
    {
	return ObjFalse;
    }

    depthCue = GetPredicate(sticks, DEPTHCUELINES);
    PrepareToDraw(false, depthCue ? DEPTHCUELIGHT : NOLIGHT, MONOCOLOR, colors);

    var = GetVar(sticks, LINEWIDTH);
    if (var)
    {
	int width;
	width = GetReal(var);
	if (width < 1) width = 1;
	SetLineWidth(width);
    }

    if (rgbp && GetPredicate(sticks, ANTIALIASLINES))
    {
	linesmooth(SML_ON);
	blendfunction(BF_SA, BF_MSA);
	subpixel(TRUE);
    }

    /*Get the show atoms how*/
    var = GetArrayVar("DrawSticks", sticks, SHOWATOMSHOW);
    if (var)
    {
	showAtomsHow = (real *) ELEMENTS(var);
    }
    else
    {
	return ObjFalse;
    }

    /*Get the residues for alpha carbon*/
    var = GetArrayVar("DrawSticks", GetVar(sticksDataset, DATAFORM), RESIDUES);
    if (var)
    {
	residues = (TwoReals *) ELEMENTS(var);
	nResidues = DIMS(var)[0];
    }
    else
    {
	residues = 0;
    }

    /*Now draw the picture*/
    maxK = DIMS(edges)[0];
    elements = ELEMENTS(edges);
    if (colorObj)
    {
	SetCurField(FIELD1, colorObj);
	if (colorObj == sticksDataset)
	{
	    equalForm = true;
	}
	else
	{
	    SetCurForm(FIELD2, colorObj);
	    equalForm = IdenticalFields(FORMFIELD, FIELD2);
	} 

	if (depthCue)
	{
	    if (equalForm)
	    {
		if (rgbp)
		{
		    /*Draw bonds with split sticks*/
		    for (k = 0; k < maxK; ++k)
		    {
			index1 = elements[k][0];
			index2 = elements[k][1];
    
			/*Get positions*/
			if (SHOWN(index1, SF_SHOWBONDS) ||
			    SHOWN(index2, SF_SHOWBONDS))
			{
			    position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
			    position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
			    position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);
	
			    position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
			    position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
			    position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);
	
			    midPosition[0] = (position1[0] + position2[0]) * 0.5;    
			    midPosition[1] = (position1[1] + position2[1]) * 0.5;    
			    midPosition[2] = (position1[2] + position2[2]) * 0.5;
			}

			/*Do 1 to mid*/
			if (SHOWN(index1, SF_SHOWBONDS))
			{
			    sample = SELECTFIELDCOMPONENT(FIELD1, 0, &index1);
			    colorIndex = GetRealColorIndex(sample);
			    lRGBrange(0, 0, 0,
				    curColors[colorIndex][0],
				    curColors[colorIndex][1],
				    curColors[colorIndex][2], curZMin, curZMax);
#ifdef V3FISBUGGED
			    move(position1[0], position1[1], position1[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
			    bgnline();
			    v3f(position1);
			    v3f(midPosition);
			    endline();
#endif
			}
    
			/*Do mid to end*/
			if (SHOWN(index2, SF_SHOWBONDS))
			{
			    sample = SELECTFIELDCOMPONENT(FIELD1, 0, &index2);
			    colorIndex = GetRealColorIndex(sample);
			    lRGBrange(0, 0, 0,
				    curColors[colorIndex][0],
				    curColors[colorIndex][1],
				    curColors[colorIndex][2], curZMin, curZMax);
#ifdef V3FISBUGGED
			    move(position2[0], position2[1], position2[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
			    bgnline();
			    v3f(midPosition);
			    v3f(position2);
			    endline();
#endif
			}
		    }

		    /*Draw carbon chain*/
		    if (residues)
		    {
			colorIndex = GetRealColorIndex(6.0);
			lRGBrange(0, 0, 0,
				curColors[colorIndex][0],
				curColors[colorIndex][1],
				curColors[colorIndex][2], curZMin, curZMax);
			for (k = 1; k < nResidues; ++k)
			{
			    index1 = residues[k - 1][1];
			    index2 = residues[k][1];

			    /*Get positions*/
			    if (SHOWN(index1, SF_SHOWBASE) ||
				SHOWN(index2, SF_SHOWBASE))
			    {
				position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
				position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
				position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);
	    
				position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
				position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
				position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);
	    
				midPosition[0] = (position1[0] + position2[0]) * 0.5;    
				midPosition[1] = (position1[1] + position2[1]) * 0.5;    
				midPosition[2] = (position1[2] + position2[2]) * 0.5;
			    }
    
			    if (SHOWN(index1, SF_SHOWBASE))
			    {
				/*Do 1 to mid*/
#ifdef V3FISBUGGED
			    move(position1[0], position1[1], position1[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
				bgnline();
				v3f(position1);
				v3f(midPosition);
				endline();
#endif
			    }
    
			    if (SHOWN(index2, SF_SHOWBASE))
			    {
				/*Do mid to end*/
#ifdef V3FISBUGGED
			    move(position2[0], position2[1], position2[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
				bgnline();
				v3f(midPosition);
				v3f(position2);
				endline();
#endif
			    }
			}
		    }
		}
		else
		{
		}
	    }
	}
	else
	{
	    if (equalForm)
	    {
		if (rgbp)
		{
		    /*Draw presuming split sticks*/
		    for (k = 0; k < maxK; ++k)
		    {
			index1 = elements[k][0];
			index2 = elements[k][1];
    
			/*Get positions*/
			if (SHOWN(index1, SF_SHOWBONDS) ||
			    SHOWN(index2, SF_SHOWBONDS))
			{
			    position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
			    position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
			    position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);
	
			    position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
			    position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
			    position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);
	
			    midPosition[0] = (position1[0] + position2[0]) * 0.5;    
			    midPosition[1] = (position1[1] + position2[1]) * 0.5;    
			    midPosition[2] = (position1[2] + position2[2]) * 0.5;
			}

			if (SHOWN(index1, SF_SHOWBONDS))
			{
			    /*Do 1 to mid*/
			    sample = SELECTFIELDCOMPONENT(FIELD1, 0, &index1);
			    colorIndex = GetRealColorIndex(sample);
			    c3s(curColors[colorIndex]);
#ifdef V3FISBUGGED
			    move(position1[0], position1[1], position1[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
			    bgnline();
			    v3f(position1);
			    v3f(midPosition);
			    endline();
#endif
			}

			if (SHOWN(index2, SF_SHOWBONDS))
			{
			    /*Do mid to end*/
			    sample = SELECTFIELDCOMPONENT(FIELD1, 0, &index2);
			    colorIndex = GetRealColorIndex(sample);
			    c3s(curColors[colorIndex]);
#ifdef V3FISBUGGED
			    move(position2[0], position2[1], position2[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
			    bgnline();
			    v3f(midPosition);
			    v3f(position2);
			    endline();
#endif
			}
		    }

		    /*Draw carbon chain*/
		    if (residues)
		    {
			c3s(curColors[GetRealColorIndex(6.0)]);
			for (k = 1; k < nResidues; ++k)
			{
			    index1 = residues[k - 1][1];
			    index2 = residues[k][1];

			    /*Get positions*/
			    if (SHOWN(index1, SF_SHOWBASE) ||
				SHOWN(index2, SF_SHOWBASE))
			    {
				position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index1);
				position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index1);
				position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index1);
	    
				position2[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &index2);
				position2[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &index2);
				position2[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &index2);
	    
				midPosition[0] = (position1[0] + position2[0]) * 0.5;    
				midPosition[1] = (position1[1] + position2[1]) * 0.5;    
				midPosition[2] = (position1[2] + position2[2]) * 0.5;
			    }
    

			    if (SHOWN(index1, SF_SHOWBASE))
			    {
				/*Do 1 to mid*/
#ifdef V3FISBUGGED
			    move(position1[0], position1[1], position1[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
				bgnline();
				v3f(position1);
				v3f(midPosition);
				move(position1[0], position1[1], position1[2]);
				draw(midPosition[0], midPosition[1], midPosition[2]);
				endline();
#endif
			    }
    
			    if (SHOWN(index2, SF_SHOWBASE))
			    {
				/*Do mid to end*/
#ifdef V3FISBUGGED
			    move(position2[0], position2[1], position2[2]);
			    draw(midPosition[0], midPosition[1], midPosition[2]);
#else
				bgnline();
				v3f(midPosition);
				v3f(position2);
				endline();
#endif
			    }
			}
		    }
		}
		else
		{
		}
	    }
	}
    }
    else
    {
	var = GetVar(sticks, BASECOLOR);
	if (var)
	{
	    Array2CArray(baseColor, var);
	}
	else
	{
	    baseColor[0] = 1.0;
	    baseColor[1] = 1.0;
	    baseColor[2] = 1.0;
	}
	COPY3(bc, baseColor);
    
	/*Color everything with base color*/
	c3f(baseColor);
    }

    SetLineWidth(1);
    linesmooth(SML_OFF);
    blendfunction(BF_ONE, BF_ZERO);
    subpixel(FALSE);

    if (var = GetVar(sticks, PORTIONSELECTED))
    {
	/*A portion is selected.  Draw some dots*/
	long dim;
	real *flags;

	dim = DIMS(var)[0];
	flags = (real *) ELEMENTS(var);

	SetUIColor(UIWHITE);
	for (k = 0; k < dim; ++k)
	{
	    if (flags[k] > 0.0)
	    {
		position1[0] = SELECTFIELDCOMPONENT(FORMFIELD, 0, &k);
		position1[1] = SELECTFIELDCOMPONENT(FORMFIELD, 1, &k);
		position1[2] = SELECTFIELDCOMPONENT(FORMFIELD, 2, &k);

		/*Draw a small jack*/
#ifdef V3FISBUGGED
		move(position1[0] - SELJACKSIZE / 2, position1[1], position1[2]);
		draw(position1[0] + SELJACKSIZE / 2, position1[1], position1[2]);

		move(position1[0], position1[1] - SELJACKSIZE / 2, position1[2]);
		draw(position1[0], position1[1] + SELJACKSIZE / 2, position1[2]);

		move(position1[0], position1[1], position1[2] - SELJACKSIZE / 2);
		draw(position1[0], position1[1], position1[2] + SELJACKSIZE / 2);
#else
		bgnline();
		position2[0] = position1[0] - SELJACKSIZE / 2;
		position2[1] = position1[1];
		position2[2] = position1[2];
		v3f(position2);
		position2[0] += SELJACKSIZE;
		v3f(position2);
		endline();

		bgnline();
		position2[0] = position1[0];
		position2[1] = position1[1] - SELJACKSIZE / 2;
		position2[2] = position1[2];
		v3f(position2);
		position2[1] += SELJACKSIZE;
		v3f(position2);
		endline();

		bgnline();
		position2[0] = position1[0];
		position2[1] = position1[1];
		position2[2] = position1[2] - SELJACKSIZE / 2;
		v3f(position2);
		position2[2] += SELJACKSIZE;
		v3f(position2);
		endline();
#endif
	    }
	}
    }

    DoneDrawing();
#endif
    return ObjTrue;
}

static ObjPtr SticksInit(sticks)
ObjPtr sticks;
/*Initializes a sticks object*/
{
    ObjPtr colorObj;
    ObjPtr pointsField;
    ObjPtr sizeObj;
    ObjPtr showAtomsHow;
    ObjPtr residues;

    MakeVar(sticks, STICKSFIELD);
    SetVar(sticks, COLOROBJ, colorObj = GetVar(sticks, STICKSFIELD));
    if (colorObj)
    {
	SetVar(sticks, COLORS, ObjTrue);
    }

    /*Make a SHOWATOMSHOW*/
    SetCurField(FIELD1, colorObj);
    if (CountTraversalDims(FIELD1) != 1)
    {
	ReportError("SticksInit", "Incompatible field");
    }
    else
    {
	long dim, k;
	GetTraversalDims(FIELD1, &dim);
	showAtomsHow = NewRealArray(1, dim);
	for (k = 0; k < dim; ++k)
	{
	    ((real *) ELEMENTS(showAtomsHow))[k] = (real) SF_SHOWBASE;
	}
	SetVar(sticks, SHOWATOMSHOW, showAtomsHow);
    }

    return ObjTrue;
}

static ObjPtr SetSticksMainDataset(visObj, dataSet)
ObjPtr visObj, dataSet;
/*Sets the main data set of visObj to dataSet*/
{
    SetVar(visObj, MAINDATASET, dataSet);
    SetVar(visObj, STICKSFIELD, dataSet);
    return ObjTrue;
}

void InitSticks()
/*Initializes sticks visualization object*/
{
    ObjPtr icon;

    /*Class for a sticks*/
    visSticks = NewObject(visLines, 0);
    AddToReferenceList(visSticks);
    SetVar(visSticks, NAME, NewString("Sticks"));
    SetMethod(visSticks, INITIALIZE, SticksInit);
    SetVar(visSticks, DEFAULTICON, icon = NewObject(visIcon, 0));
    SetMethod(visSticks, PICKPOINT, PickSticks);
    SetVar(icon, WHICHICON, NewInt(ICONSTICKS));
    SetVar(icon, NAME, NewString("Sticks"));
    SetVar(icon, HELPSTRING,
	NewString("This icon represents a stick display object.  \
This object can show sticks for just about any data field."));
    SetMethod(visSticks, DRAW, DrawSticks);
    SetMethod(visSticks, STUFFSELPOINT, StuffSticksSelPoint);
    SetMethod(visSticks, BEGINSTUFFING, BeginStuffingSticks);
    SetMethod(visSticks, SELECTSELPOINT, SelectSticksSelPoint);
    SetMethod(visSticks, APPEARANCE, MakeSticksAppearance);
    DeclareDependency(visSticks, APPEARANCE, PORTIONSELECTED);

    SetMethod(visSticks, SETMAINDATASET, SetSticksMainDataset);
    SetVar(visSticks, STYLE, NewInt(0));

    SetMethod(visSticks, ADDCONTROLS, AddSticksControls);
    icon = NewIcon(0, 0, ICONSTICKS, "Sticks");
    SetVar(icon, HELPSTRING,
	NewString("Click on this icon to see a panel of controls for the stick object."));
    SetVar(visSticks, CONTROLICON, icon);

#ifndef RELEASE
    DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_UNSTRUCTURED, 1, 3, 1, visSticks);
    DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_UNSTRUCTURED, 1, 2, 1, visSticks);
#endif
}

void KillSticks()
/*Kills sticks visualization*/
{
    DeleteThing(visSticks);
}
