CCL Home Page
Up Directory CCL transfor.c
/* transfor.c
 * RasMol2 Molecular Graphics
 * Roger Sayle, October 1994
 * Version 2.5
 */
#include "rasmol.h"

#ifdef IBMPC
#include 
#endif
#ifdef APPLEMAC
#ifdef __CONDITIONALMACROS__
#include 
#else
#include 
#endif
#include 
#endif
#include 
#include 

#define TRANSFORM
#include "transfor.h"
#include "molecule.h"
#include "command.h"
#include "abstree.h"
#include "render.h"
#include "graphics.h"


typedef struct {
		short col;
		short shade;
		unsigned char r;
		unsigned char g;
		unsigned char b;
	      } ShadeRef;


#define CPKMAX  16
static ShadeRef CPKShade[] = {
     { 0, 0, 200, 200, 200 },       /*  0 Light Grey   */
     { 0, 0, 143, 143, 255 },       /*  1 Sky Blue     */
     { 0, 0, 240,   0,   0 },       /*  2 Red          */
     { 0, 0, 255, 200,  50 },       /*  3 Yellow       */
     { 0, 0, 255, 255, 255 },       /*  4 White        */
     { 0, 0, 255, 192, 203 },       /*  5 Pink         */
     { 0, 0, 218, 165,  32 },       /*  6 Golden Rod   */
     { 0, 0,   0,   0, 255 },       /*  7 Blue         */
     { 0, 0, 255, 165,   0 },       /*  8 Orange       */
     { 0, 0, 128, 128, 144 },       /*  9 Dark Grey    */
     { 0, 0, 165,  42,  42 },       /* 10 Brown        */
     { 0, 0, 160,  32, 240 },       /* 11 Purple       */
     { 0, 0, 255,  20, 147 },       /* 12 Deep Pink    */
     { 0, 0,   0, 255,   0 },       /* 13 Green        */
     { 0, 0, 178,  34,  34 },       /* 14 Fire Brick   */
     { 0, 0,  34, 139,  34 } };     /* 15 Forest Green */


static ShadeRef Shapely[] = {
     { 0, 0, 140, 255, 140 },    /* ALA */
     { 0, 0, 255, 255, 255 },    /* GLY */
     { 0, 0,  69,  94,  69 },    /* LEU */
     { 0, 0, 255, 112,  66 },    /* SER */
     { 0, 0, 255, 140, 255 },    /* VAL */
     { 0, 0, 184,  76,   0 },    /* THR */
     { 0, 0,  71,  71, 184 },    /* LYS */
     { 0, 0, 160,   0,  66 },    /* ASP */
     { 0, 0,   0,  76,   0 },    /* ILE */
     { 0, 0, 255, 124, 112 },    /* ASN */
     { 0, 0, 102,   0,   0 },    /* GLU */
     { 0, 0,  82,  82,  82 },    /* PRO */
     { 0, 0,   0,   0, 124 },    /* ARG */
     { 0, 0,  83,  76,  66 },    /* PHE */
     { 0, 0, 255,  76,  76 },    /* GLN */
     { 0, 0, 140, 112,  76 },    /* TYR */
     { 0, 0, 112, 112, 255 },    /* HIS */
     { 0, 0, 255, 255, 112 },    /* CYS */
     { 0, 0, 184, 160,  66 },    /* MET */
     { 0, 0,  79,  70,   0 },    /* TRP */

     { 0, 0, 255,   0, 255 },    /* ASX */
     { 0, 0, 255,   0, 255 },    /* GLX */
     { 0, 0, 255,   0, 255 },    /* PCA */
     { 0, 0, 255,   0, 255 },    /* HYP */

     { 0, 0, 160, 160, 255 },    /*   A */
     { 0, 0, 255, 140,  75 },    /*   C */
     { 0, 0, 255, 112, 112 },    /*   G */
     { 0, 0, 160, 255, 160 },    /*   T */

     { 0, 0, 184, 184, 184 },    /* 28 -> BackBone */
     { 0, 0,  94,   0,  94 },    /* 29 -> Special  */
     { 0, 0, 255,   0, 255 } };  /* 30 -> Default  */

     
static ShadeRef AminoShade[] = {
     { 0, 0, 230,  10,  10 },    /*  0  ASP, GLU      */
     { 0, 0,  20,  90, 255 },    /*  1  LYS, ARG      */
     { 0, 0, 130, 130, 210 },    /*  2  HIS           */
     { 0, 0, 250, 150,   0 },    /*  3  SER, THR      */
     { 0, 0,   0, 220, 220 },    /*  4  ASN, GLN      */
     { 0, 0, 230, 230,   0 },    /*  5  CYS, MET      */
     { 0, 0, 200, 200, 200 },    /*  6  ALA           */
     { 0, 0, 235, 235, 235 },    /*  7  GLY           */
     { 0, 0,  15, 130,  15 },    /*  8  LEU, VAL, ILE */
     { 0, 0,  50,  50, 170 },    /*  9  PHE, TYR      */
     { 0, 0, 180,  90, 180 },    /* 10  TRP           */
     { 0, 0, 220, 150, 130 },    /* 11  PRO, PCA, HYP */
     { 0, 0, 190, 160, 110 } };  /* 12  Others        */

static int AminoIndex[] = {
      6, /*ALA*/   7, /*GLY*/   8, /*LEU*/   3,  /*SER*/
      8, /*VAL*/   3, /*THR*/   1, /*LYS*/   0,  /*ASP*/
      8, /*ILE*/   4, /*ASN*/   0, /*GLU*/  11,  /*PRO*/
      1, /*ARG*/   9, /*PHE*/   4, /*GLN*/   9,  /*TYR*/
      2, /*HIS*/   5, /*CYS*/   5, /*MET*/  10,  /*TRP*/
      4, /*ASX*/   4, /*GLX*/  11, /*PCA*/  11   /*HYP*/
			  };

static ShadeRef HBondShade[] = {
     { 0, 0, 255, 255, 255 },    /* 0  Offset =  2   */
     { 0, 0, 255,   0, 255 },    /* 1  Offset =  3   */
     { 0, 0, 255,   0,   0 },    /* 2  Offset =  4   */
     { 0, 0, 255, 165,   0 },    /* 3  Offset =  5   */
     { 0, 0,   0, 255, 255 },    /* 4  Offset = -3   */
     { 0, 0,   0, 255,   0 },    /* 5  Offset = -4   */
     { 0, 0, 255, 255,   0 } };  /* 6  Others        */


static ShadeRef StructShade[] = {
     { 0, 0, 255, 255, 255 },    /* 0  Default     */
     { 0, 0, 240,   0, 128 },    /* 1  Alpha Helix */
     { 0, 0, 255, 255,   0 },    /* 2  Beta Sheet  */
     { 0, 0,  96, 128, 255 } };  /* 3  Turn        */

static ShadeRef PotentialShade[] = {
     { 0, 0, 255,   0,   0 },    /* 0  Red     25 < V       */
     { 0, 0, 255, 165,   0 },    /* 1  Orange  10 < V <  25 */
     { 0, 0, 255, 255,   0 },    /* 2  Yellow   3 < V <  10 */
     { 0, 0,   0, 255,   0 },    /* 3  Green    0 < V <   3 */
     { 0, 0,   0, 255, 255 },    /* 4  Cyan    -3 < V <   0 */
     { 0, 0,   0,   0, 255 },    /* 5  Blue   -10 < V <  -3 */
     { 0, 0, 160,  32, 240 },    /* 6  Purple -25 < V < -10 */
     { 0, 0, 255, 255, 255 } };  /* 7  White        V < -25 */


/* Macros for commonly used loops */
#define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
		     for(group=chain->glist;group;group=group->gnext)    \
		     for(ptr=group->alist;ptr;ptr=ptr->anext)
#define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext) 
#define ForEachBack  for(chain=Database->clist;chain;chain=chain->cnext) \
		     for(bptr=chain->blist;bptr;bptr=bptr->bnext)

#define MatchChar(a,b)   (((a)=='#')||((a)==(b)))
#define RootSix          2.44948974278


static ShadeRef ScaleRef[MAXSHADE];
static int MaskColour[MAXMASK];
static int MaskShade[MAXMASK];
static int ScaleCount;
static int LastShade;

static Real LastRX,LastRY,LastRZ;
static Real Zoom;



void DetermineClipping()
{
    register int temp;
    register int max;

    max = 0;
    if( DrawAtoms && (MaxAtomRadius>max) )  max = MaxAtomRadius;
    if( DrawBonds && (MaxBondRadius>max) )  max = MaxBondRadius;
       
    temp = ImageRadius + max;
    UseScreenClip = (XOffset=XRange) ||
		    (YOffset=YRange);
}



void SetRadiusValue( rad )
    int rad;
{
    register int irad,change;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( !Database )
	return;

    irad = (int)(Scale*rad);
    MaxAtomRadius = 0;
    DrawAtoms = False;
    change = False;

    ForEachAtom
	if( ptr->flag & SelectFlag )
	{   if( irad>MaxAtomRadius )
		MaxAtomRadius = irad;
	    ptr->flag |= SphereFlag;
	    ptr->radius = rad;
	    ptr->irad = irad;
	    change = True;
	} else if( ptr->flag & SphereFlag )
	{   DrawAtoms = True;
	    if( ptr->irad>MaxAtomRadius )
		MaxAtomRadius = ptr->irad;
	}

    if( change )
    {   DrawAtoms = True;
	DetermineClipping();
	VoxelsClean = False;
	BucketFlag = False;
    }
}

void SetRadiusTemperature()
{
    register int rad,irad,change;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( !Database )
	return;

    MaxAtomRadius = 0;
    DrawAtoms = False;
    change = False;

    ForEachAtom
	if( (ptr->flag&SelectFlag) && (ptr->temp>0) )
	{   rad = (5*ptr->temp)>>1;
	    if( rad>500 ) rad = 500;

	    irad = (int)(Scale*rad);
	    if( irad>MaxAtomRadius )
		MaxAtomRadius = irad;
	    ptr->flag |= SphereFlag;
	    ptr->radius = rad;
	    ptr->irad = irad;
	    change = True;
	} else if( ptr->flag & SphereFlag )
	{   DrawAtoms = True;
	    if( ptr->irad>MaxAtomRadius )
		MaxAtomRadius = ptr->irad;
	}

    if( change )
    {   DrawAtoms = True;
	DetermineClipping();
	VoxelsClean = False;
	BucketFlag = False;
    }
}


void SetVanWaalRadius()
{
    register int rad,change;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int elem;

    if( !Database )
	return;

    MaxAtomRadius = 0;
    DrawAtoms = False;
    change = False;

    ForEachAtom
	if( ptr->flag&SelectFlag )
	{   elem = GetElemNumber(ptr);
	    rad = ElemVDWRadius(elem);
	    ptr->irad = (int)(Scale*rad);
	    ptr->radius = rad;
	    change = True;

	    ptr->flag |=SphereFlag;
	    if( ptr->irad>MaxAtomRadius )
		MaxAtomRadius = ptr->irad;
	} else if( ptr->flag&SphereFlag )
	{   DrawAtoms = True;
	    if( ptr->irad>MaxAtomRadius )
		MaxAtomRadius = ptr->irad;
	}

    if( change )
    {   DrawAtoms = True;
	DetermineClipping();
	VoxelsClean = False;
	BucketFlag = False;
    }
}


void DisableSpacefill()
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( !Database || !DrawAtoms )
	return;

    MaxAtomRadius = 0;
    DrawAtoms = False;
    
    ForEachAtom
	if( !(ptr->flag&SelectFlag) )
	{   if( ptr->flag&SphereFlag )
	    {   if( ptr->irad>MaxAtomRadius )
		    MaxAtomRadius = ptr->irad;
		DrawAtoms = True;
	    }
	} else if( ptr->flag&SphereFlag )
	    ptr->flag &= ~SphereFlag;

    DetermineClipping();
    VoxelsClean = False;
    BucketFlag = False;
}



void EnableWireFrame( depth, rad )
    int depth, rad;
{
    register Bond __far *bptr;
    register int flag, irad;

    if( !Database )
	return;

    DrawBonds = False;
    MaxBondRadius = 0;
    irad = (int)(Scale*rad);

    ForEachBond
    {   flag = ZoneBoth? bptr->dstatom->flag & bptr->srcatom->flag
		       : bptr->dstatom->flag | bptr->srcatom->flag;

	if( flag&SelectFlag )
	{   DrawBonds = True;
	    bptr->flag &= ~DrawBondFlag;
	    if( !depth )
	    {   if( irad>MaxBondRadius )
		    MaxBondRadius = irad;
		bptr->flag |= CylinderFlag;
		bptr->radius = rad;
		bptr->irad = irad;
	    } else bptr->flag |= WireFlag;
	} else if( bptr->flag&DrawBondFlag )
	{    DrawBonds = True;
	     if( bptr->flag&CylinderFlag )
		 if( bptr->irad>MaxBondRadius )
		     MaxBondRadius = bptr->irad;
	}
    }
    DetermineClipping();
}


void DisableWireFrame()
{
    register Bond __far *bptr;
    register int flag;

    if( !Database || !DrawBonds )
	return;

    DrawBonds = False;
    MaxBondRadius = 0;

    ForEachBond
    {   flag = ZoneBoth? bptr->dstatom->flag & bptr->srcatom->flag
		       : bptr->dstatom->flag | bptr->srcatom->flag;

	if( flag&SelectFlag )
	{   bptr->flag &= ~DrawBondFlag;
	} else if( bptr->flag&DrawBondFlag )
	{   DrawBonds = True;
	    if( bptr->flag&CylinderFlag )
		if( bptr->irad>MaxBondRadius )
		    MaxBondRadius = bptr->irad;
	}
    }
    DetermineClipping();
}


void EnableBackBone( depth, rad )
    int depth, rad;
{
    register Chain __far *chain;
    register Bond __far *bptr;
    register int flag,irad;

    if( !Database )
	return;

    irad = (int)(Scale*rad);

    ForEachBack
    {   flag = ZoneBoth? bptr->dstatom->flag & bptr->srcatom->flag
		       : bptr->dstatom->flag | bptr->srcatom->flag;

	if( flag&SelectFlag )
	{   bptr->flag &= ~DrawBondFlag;
	    if( !depth )
	    {   bptr->flag |= CylinderFlag;
		bptr->radius = rad;
		bptr->irad = irad;
	    } else bptr->flag |= WireFlag;
	} 
    }
    DetermineClipping();
}


void DisableBackBone()
{
    register Chain __far *chain;
    register Bond __far *bptr;

    if( !Database )
	return;

    if( ZoneBoth )
    {   ForEachBack
	    if( (bptr->dstatom->flag&bptr->srcatom->flag) & SelectFlag )
		bptr->flag &= ~DrawBondFlag;
    } else ForEachBack
	if( (bptr->dstatom->flag|bptr->srcatom->flag) & SelectFlag )
	    bptr->flag &= ~DrawBondFlag;
    DetermineClipping();
}


void SetHBondStatus( hbonds, enable, rad )
    int hbonds, enable, rad;
{
    register HBond __far *list;
    register HBond __far *ptr;
    register Atom __far *src;
    register Atom __far *dst;
    register int flag, irad;

    if( !Database )
	return;

    if( hbonds )
    {   if( enable && (InfoHBondCount<0) )
	    CalcHydrogenBonds();
	list = Database->hlist;
    } else 
    {   if( enable && (InfoSSBondCount<0) )
	    FindDisulphideBridges();
	list = Database->slist;
    }

    irad = (int)(Scale*rad);
    for( ptr=list; ptr; ptr=ptr->hnext )
    {   src = ptr->src;  dst = ptr->dst;

	flag = ZoneBoth? src->flag&dst->flag : src->flag|dst->flag;
	if( flag & SelectFlag ) 
	{   ptr->flag &= ~DrawBondFlag;
	    if( enable )
	    {   if( rad )
		{   ptr->flag |= CylinderFlag;
		    ptr->radius = rad;
		    ptr->irad = irad;
		} else ptr->flag |= WireFlag;
	    }
	}
    }
}


void SetRibbonStatus( enable, flag, width )
    int enable, flag, width;
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( !Database )
	return;

    /* Ribbons already disabled! */
    if( !enable && !DrawRibbon )
	return;

    if( InfoHelixCount<0 )
	DetermineStructure();

    DrawRibbon = False;
    for( chain=Database->clist; chain; chain=chain->cnext )
	for( group=chain->glist; group; group=group->gnext )
	    if( enable )
	    {   if( group->flag & (RibbonFlag|StrandFlag) )
		    DrawRibbon = True;
		
		for( ptr=group->alist; ptr; ptr=ptr->anext )
		    if( IsAlphaCarbon(ptr->refno) )
		    {   if( ptr->flag&SelectFlag )
			{   group->flag &= ~(RibbonFlag|StrandFlag);
			    group->flag |= flag;
			    if( !width )
			    {   if( group->struc & (HelixFlag|SheetFlag) )
				{      group->width = 380;
				} else group->width = 100;
			    } else group->width = width;
			    DrawRibbon = True;
			}
			break;

		    } else if( IsSugarPhosphate(ptr->refno) )
		    {   if( ptr->flag&SelectFlag )
			{   group->width = width? width : 720;
			    group->flag |= flag;
			    DrawRibbon = True;
			}
			break;
		    }


	    } else  /* Disable Ribbon */
		if( group->flag & (RibbonFlag|StrandFlag) )
		{   for( ptr=group->alist; ptr; ptr=ptr->anext )
			if( IsAlphaCarbon(ptr->refno) ||
			    IsSugarPhosphate(ptr->refno) )
			{   if( ptr->flag&SelectFlag )
				group->flag &= ~(RibbonFlag|StrandFlag);
			    break;
			}
		    if( group->flag & (RibbonFlag|StrandFlag) ) 
			DrawRibbon = True;
		}
}


void SelectZone( mask )
    int mask;
{
    register Bond __far *bptr;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( !Database )
	return;

    SelectCount = 0;
    ForEachAtom
	if( ptr->flag & mask )
	{   ptr->flag |= SelectFlag;
	    SelectCount++;
	} else ptr->flag &= ~SelectFlag;
    DisplaySelectCount();

    if( ZoneBoth )
    {   ForEachBond
	   if( (bptr->srcatom->flag&bptr->dstatom->flag) & SelectFlag )
	   {   bptr->flag |= SelectFlag;
	   } else bptr->flag &= ~SelectFlag;
    } else
	ForEachBond
	   if( (bptr->srcatom->flag|bptr->dstatom->flag) & SelectFlag )
	   {   bptr->flag |= SelectFlag;
	   } else bptr->flag &= ~SelectFlag;

}


void RestrictZone( mask )
    int mask;
{
    register Bond __far *bptr;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int flag;

    if( !Database )
	return;

    DrawAtoms = False;   MaxAtomRadius = 0;
    DrawBonds = False;   MaxBondRadius = 0;
    
    SelectCount = 0;
    ForEachAtom
	if( ptr->flag & mask )
	{   ptr->flag |= SelectFlag;
	    SelectCount++;

	    if( ptr->flag & SphereFlag )
	    {   DrawAtoms = True;
		if( ptr->irad>MaxAtomRadius )
		    MaxAtomRadius = ptr->irad;
	    }
	} else ptr->flag &= ~(SelectFlag|SphereFlag);
    DisplaySelectCount();
    
    ForEachBond
    {   /* Ignore ZoneBoth setting! */
	flag = bptr->dstatom->flag & bptr->srcatom->flag;
	if( flag & SelectFlag )
	{   bptr->flag |= SelectFlag;
	    if( bptr->flag&DrawBondFlag )
	    {   DrawBonds = True;
		if( bptr->flag & CylinderFlag )
		    if( bptr->irad>MaxBondRadius )
			MaxBondRadius = bptr->irad;
	    } 
	} else bptr->flag &= ~(SelectFlag|DrawBondFlag);
    }

    DetermineClipping();
    VoxelsClean = False;
    BucketFlag = False;
}



int DefineShade( r, g, b )
    unsigned char r, g, b;
{
    register int d,dr,dg,db;
    register int dist,best;
    register int i;

    /* Already defined! */
    for( i=0; i1 )
    {   if( y&1 ) { result *= x; y--; }
	else { result *= result; y>>=1; }
    }
    return( result );
}


void DefineColourMap()
{
    register Real diffuse;
    register Real temp, inten;
    register int col, r, g, b;
    register int i, j, k;

    for( i=0; iflag&SelectFlag) && bptr->col )
	    {   Shade[Colour2Shade(bptr->col)].refcount--;
		bptr->col = 0;
	    }
}


void ColourBondAttrib( r, g, b )
    int r, g, b;
{
    register Bond __far *bptr;
    register int shade,col;

    if( Database )
    {   ForEachBond
	    if( (bptr->flag&SelectFlag) && bptr->col )
		Shade[Colour2Shade(bptr->col)].refcount--;

	shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
	col = Shade2Colour(shade);

	ForEachBond
	    if( bptr->flag&SelectFlag )
	    {   Shade[shade].refcount++;
		bptr->col = col;
	    }
    }
}


void ColourBackNone()
{
    register Chain __far *chain;
    register Bond __far *bptr;
    register int flag;

    if( Database )
	ForEachBack
	{   flag = ZoneBoth? bptr->dstatom->flag & bptr->srcatom->flag
			   : bptr->dstatom->flag | bptr->srcatom->flag;

	    if( flag&SelectFlag )
	    {   bptr->flag |= SelectFlag;
		if( bptr->col )
		{   Shade[Colour2Shade(bptr->col)].refcount--;
		    bptr->col = 0;
		}
	    } else bptr->flag &= ~SelectFlag;
	}
}


void ColourBackAttrib( r, g, b )
    int r, g, b;
{
    register int shade,col;
    register Chain __far *chain;
    register Bond __far *bptr;

    if( Database )
    {   ColourBackNone();
	shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
	col = Shade2Colour(shade);

	ForEachBack
	    if( bptr->flag&SelectFlag )
	    {   Shade[shade].refcount++;
		bptr->col = col;
	    }
    }
}


void ColourHBondNone( hbonds )
    int hbonds;
{
    register HBond __far *list;
    register HBond __far *ptr;
    register Atom __far *src;
    register Atom __far *dst;

    if( !Database )
	return;

    list = hbonds? Database->hlist : Database->slist;

    if( ZoneBoth )
    {   for( ptr=list; ptr; ptr=ptr->hnext )
	{   src = ptr->src;  dst = ptr->dst;

	    if( (src->flag&dst->flag) & SelectFlag )
	    {   ptr->flag |= SelectFlag;
		if( ptr->col )
		{   Shade[Colour2Shade(ptr->col)].refcount--;
		    ptr->col = 0;
		}
	    } else ptr->flag &= ~SelectFlag;
	}
    } else
	for( ptr=list; ptr; ptr=ptr->hnext )
	{   src = ptr->src;  dst = ptr->dst;

	    if( (src->flag|dst->flag) & SelectFlag )
	    {   ptr->flag |= SelectFlag;
		if( ptr->col )
		{   Shade[Colour2Shade(ptr->col)].refcount--;
		    ptr->col = 0;
		}
	    } else ptr->flag &= ~SelectFlag;
	}
}

void ColourHBondType()
{
    register HBond __far *ptr;
    register ShadeRef *ref;
    register int i;

    if( !Database ) return;
    for( i=0; i<7; i++ )
	HBondShade[i].col = 0;

    if( InfoHBondCount<0 )
    {   CalcHydrogenBonds();
    } else ColourHBondNone( True );

    for( ptr=Database->hlist; ptr; ptr=ptr->hnext )
	if( ptr->flag & SelectFlag )
	{   switch( ptr->offset )
	    {   case(  2 ):  ref = HBondShade;     break;
		case(  3 ):  ref = HBondShade+1;   break;
		case(  4 ):  ref = HBondShade+2;   break;
		case(  5 ):  ref = HBondShade+3;   break;
		case( -3 ):  ref = HBondShade+4;   break;
		case( -4 ):  ref = HBondShade+5;   break;
		default:     ref = HBondShade+6;   break;
	    }

	    if( !ref->col )
	    {   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		ref->col = Shade2Colour(ref->shade);
	    }
	    Shade[ref->shade].refcount++;
	    ptr->col = (Byte)ref->col;
	}
}


void ColourHBondAttrib( hbonds, r, g, b )
    int hbonds, r, g, b;
{
    register HBond __far *list;
    register HBond __far *ptr;
    register int col,shade;

    if( !Database )
	return;

    if( hbonds )
    {   if( InfoHBondCount<0 )
	{   CalcHydrogenBonds();
	} else ColourHBondNone(True);
    } else
	if( InfoSSBondCount<0 )
	{   FindDisulphideBridges();
	} else ColourHBondNone(False);


    shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
    col = Shade2Colour(shade);

    list = hbonds? Database->hlist : Database->slist;
    for( ptr=list; ptr; ptr=ptr->hnext )
	if( ptr->flag & SelectFlag )
	{   Shade[shade].refcount++;
	    ptr->col = col;
	}
}


void ColourRibbonNone( flag )
    int flag;
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *aptr;

    if( !Database )
	return;

    if( InfoHelixCount<0 )
	return;

    for( chain=Database->clist; chain; chain=chain->cnext )
	for( group=chain->glist; group; group=group->gnext )
	    if( (aptr=FindGroupAtom(group,1)) && (aptr->flag&SelectFlag) )
	    {   if( (flag&RibColInside) && group->col1 )
		{   Shade[Colour2Shade(group->col1)].refcount--;
		    group->col1 = 0;
		}
		if( (flag&RibColOutside) && group->col2 )
		{   Shade[Colour2Shade(group->col2)].refcount--;
		    group->col2 = 0;
		}
	    }
}


void ColourRibbonAttrib( flag, r, g, b )
    int flag, r, g, b;
{
    register int shade, col;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *aptr;

    if( Database )
    {   if( InfoHelixCount >= 0 )
	{   ColourRibbonNone( flag );
	} else DetermineStructure();

	shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
	col = Shade2Colour(shade);

	for( chain=Database->clist; chain; chain=chain->cnext )
	    for( group=chain->glist; group; group=group->gnext )
		if( (aptr=FindGroupAtom(group,1)) 
		    && (aptr->flag&SelectFlag) )
		{   if( flag & RibColInside )
		    {   Shade[shade].refcount++;
			group->col1 = col;
		    }
		    if( flag & RibColOutside )
		    {   Shade[shade].refcount++;
			group->col2 = col;
		    }
		}
    }
}


void ColourDotsAttrib( r, g, b )
    int r, g, b;
{
    register DotStruct __far *ptr;
    register int i,shade,col;

    if( Database )
    {   for( ptr=DotPtr; ptr; ptr=ptr->next )
	    for( i=0; icount; i++ )
	    {    shade = Colour2Shade(ptr->col[i]);
		 Shade[shade].refcount--;
	    }

	shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
	col = Shade2Colour(shade);
	for( ptr=DotPtr; ptr; ptr=ptr->next )
	    for( i=0; icount; i++ )
	    {   Shade[shade].refcount++;
		ptr->col[i] = col;
	    }
    }
}


/* Coulomb's Law */
int CalculatePotential( x, y, z )
    Long x, y, z;
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register Long dx,dy,dz;
    register Long result;
    register Card dist;
    register Card max;


    /* Calculated charges have b-values < 0.0     */
    /* if( MinFun(MinMainTemp,MinHetaTemp) >= 0 ) */
    /*     CalculateCharges();                    */

    /* 8.0 Angstrom Cut Off */
    max = (Long)2000*2000;

    result = 0;
    ForEachAtom
    {   dx = ptr->xorg-x;
	if( (dist=dx*dx) < max )
	{   dy = ptr->yorg - y;
	    if( (dist+=dy*dy) < max )
	    {   dz = ptr->zorg - z;
		if( (dist+=dz*dz) < max )
		    result += ((Long)ptr->temp<<12) / isqrt(dist);
	    }
	}
    }
    /* Dielectric Constant = 10.0 */
    /* (332.0*250.0)/(10.0*100.0) */
    result = ((Long)result*83) >> 12;
    return( (int)result );
}


void ColourDotsPotential()
{
    register DotStruct __far *ptr;
    register int i,shade,result;
    register ShadeRef *ref;

    if( Database )
    {   for( i=0; i<8; i++ )
	    PotentialShade[i].col = 0;

	/* Colour Dots None! */
	for( ptr=DotPtr; ptr; ptr=ptr->next )
	    for( i=0; icount; i++ )
	    {    shade = Colour2Shade(ptr->col[i]);
		 Shade[shade].refcount--;
	    }

	for( ptr=DotPtr; ptr; ptr=ptr->next )
	    for( i=0; icount; i++ )
	    {   result = CalculatePotential( ptr->xpos[i],
					     ptr->ypos[i],
					     ptr->zpos[i] );

		/* Determine Colour Bucket */
		if( result >= 0 )
		{   if( result > 10 )
		    {      if( result > 24 )
			   {      ref = PotentialShade + 0;
			   } else ref = PotentialShade + 1;
		    } else if( result > 3 )
			   {      ref = PotentialShade + 2;
			   } else ref = PotentialShade + 3;
		} else 
		    if( result > -10 )
		    {      if( result > -3 )
			   {      ref = PotentialShade + 4;
			   } else ref = PotentialShade + 5;
		    } else if( result > -24 )
			   {      ref = PotentialShade + 6;
			   } else ref = PotentialShade + 7;

		if( !ref->col )
		{   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		    ref->col = Shade2Colour(ref->shade);
		}
		Shade[ref->shade].refcount++;
		ptr->col[i] = ref->col;
	    }
    }
}


static void ResetColourAttrib()
{
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    ForEachAtom
	if( (ptr->flag&SelectFlag) && ptr->col )
	    Shade[Colour2Shade(ptr->col)].refcount--;
}


void MonoColourAttrib( r, g, b )
    int r, g, b;
{
    register int shade,col;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;

    if( Database )
    {   ResetColourAttrib();
	shade = DefineShade((Byte)r,(Byte)g,(Byte)b);
	col = Shade2Colour(shade);

	ForEachAtom
	    if( ptr->flag&SelectFlag )
	    {   Shade[shade].refcount++;
		ptr->col = col;
	    }
    }
}


void ScaleColourAttrib( attr )
    int attr;
{
    register ShadeRef *ref;
    register int count, attrno, factor;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register Long temp;
    register int i;

    if( !Database ) return;

    switch( attr )
    {   case(ChainAttr):   attrno = InfoChainCount;   
			   factor = 1;
			   break;

	case(GroupAttr):   factor = MinMainRes;
			   attrno = MaxMainRes;
			   if( HetaGroups && HetaGroupCount )
			   {   if( MinHetaRes < factor )
				   factor = MinHetaRes;
			       if( MaxHetaRes > attrno )
				   attrno = MaxHetaRes;
			   } 
			   attrno -= (factor-1);
			   break;

	case(ChargeAttr):
	case(TempAttr):    factor = MinMainTemp;
			   attrno = MaxMainTemp;
			   if( HetaGroups && HetaGroupCount )
			   {   if( MinHetaTemp < factor )
				   factor = MinHetaTemp;
			       if( MaxHetaTemp > attrno )
				   attrno = MaxHetaTemp;
			   }
			   attrno -= (factor-1);
			   break;

	default:           return;
    }

    if( attrno<2 )
    {   MonoColourAttrib(255,255,255);
	return;
    }

    ResetColourAttrib();
    ScaleColourMap(attrno);

    switch( attr )
    {    case(ChainAttr):
		 count = 0;
		 for( chain=Database->clist; chain; chain=chain->cnext )
		 {   ref = &(ScaleRef[(count*ScaleCount)/attrno]);
		     if( !(ref->col && Shade[ref->shade].refcount) )
		     {   ref->shade = DefineShade(ref->r,ref->g,ref->b);
			 ref->col = Shade2Colour(ref->shade);
		     }
		     for( group=chain->glist; group; group=group->gnext )
			 for( ptr=group->alist; ptr; ptr=ptr->anext )
			     if( ptr->flag&SelectFlag )
			     {   Shade[ref->shade].refcount++;
				 ptr->col = ref->col;
			     }
		     count++;
		 }
		 break;


	 case(GroupAttr):
		 for( chain=Database->clist; chain; chain=chain->cnext )
		     for( group=chain->glist; group; group=group->gnext )
		     {   temp = (Long)ScaleCount*(group->serno-factor);
			 i = (int)(temp/attrno);

			 if( i >= ScaleCount )
			 {   ref = ScaleRef + (ScaleCount-1);
			 } else if( i >= 0 )
			 {   ref = ScaleRef + i;
			 } else ref = ScaleRef;

			 if( !(ref->col && Shade[ref->shade].refcount) )
			 {   ref->shade = DefineShade(ref->r,ref->g,ref->b);
			     ref->col = Shade2Colour(ref->shade);
			 }

			 for( ptr=group->alist; ptr; ptr=ptr->anext )
			     if( ptr->flag&SelectFlag )
			     {   Shade[ref->shade].refcount++;
				 ptr->col = ref->col;
			     }
		     }
		 break;


	 case(TempAttr):
		 ForEachAtom
		     if( ptr->flag&SelectFlag )
		     {   i = (int)(((Long)ScaleCount*(ptr->temp-factor))
				    /attrno);

			 if( i >= ScaleCount )
			 {   ref = ScaleRef + (ScaleCount-1);
			 } else if( i >= 0 )
			 {   ref = ScaleRef + i;
			 } else ref = ScaleRef;

			 if( !(ref->col && Shade[ref->shade].refcount) )
			 {   ref->shade = DefineShade(ref->r,ref->g,ref->b);
			     ref->col = Shade2Colour(ref->shade);
			 }
			 Shade[ref->shade].refcount++;
			 ptr->col = ref->col;
		     }
		 break;

	case(ChargeAttr):
		ForEachAtom
		     if( ptr->flag&SelectFlag )
		     {   i = (int)(((Long)ScaleCount*(ptr->temp-factor))
				    /attrno);

			 if( i <= 0 )
			 {   ref = ScaleRef + (ScaleCount-1);
			 } else if( i < ScaleCount )
			 {   ref = ScaleRef + ((ScaleCount-1)-i);
			 } else ref = ScaleRef;

			 if( !(ref->col && Shade[ref->shade].refcount) )
			 {   ref->shade = DefineShade(ref->r,ref->g,ref->b);
			     ref->col = Shade2Colour(ref->shade);
			 }
			 Shade[ref->shade].refcount++;
			 ptr->col = ref->col;
		     }
		 break;
    }
}



static int MatchNumber( len, value, mask )
    int len, value;
    char *mask;
{
    register char digit, template;
    register int result;
    register int i;

    result = True;
    for( i=0; iflag&SelectFlag )
    {   for( i=0; imask;
	    match = True;

	    if( !MatchChar(temp[13],chain->ident) ) match=False;
	    if( !MatchChar(temp[9],ptr->altl) )     match=False;

	    /* Atom Name */
	    if( match )
	    {   name = ElemDesc[ptr->refno];
		if( !MatchChar(temp[5],name[0]) ) match=False;
		if( !MatchChar(temp[6],name[1]) ) match=False;
		if( !MatchChar(temp[7],name[2]) ) match=False;
		if( !MatchChar(temp[8],name[3]) ) match=False;
	    }

	    /* Group Name */
	    if( match )
	    {   name = Residue[group->refno];
		if( !MatchChar(temp[10],name[0]) ) match=False;
		if( !MatchChar(temp[11],name[1]) ) match=False;
		if( !MatchChar(temp[12],name[2]) ) match=False;
	    }


	    if( match && (mptr->flags&SerNoFlag) )
		match = MatchNumber(4,ptr->serno,&temp[0]);
	    if( match && (mptr->flags&ResNoFlag) )
		match = MatchNumber(3,group->serno,&temp[14]);
	    if( match ) break;
	}

	if( fields&MaskColourFlag )
	{   if( match )
	    {   if( MaskShade[i] == -1 )
		{   MaskShade[i] = DefineShade(mptr->r,mptr->g,mptr->b);
		    MaskColour[i] = Shade2Colour(MaskShade[i]);
		}
		Shade[MaskShade[i]].refcount++;
		ptr->col = MaskColour[i];
	    } else
	    {   shade = DefineShade(255,255,255);
		ptr->col = Shade2Colour(shade);
		Shade[shade].refcount++;
	    }
	}

	if( fields&MaskRadiusFlag )
	{   rad = match? mptr->radius : 375;
	    ptr->irad = (int)(Scale*rad);
	    ptr->flag |= SphereFlag;
	    ptr->radius = rad;

	    if( ptr->irad>MaxAtomRadius )
		MaxAtomRadius = ptr->irad;
	    change = True;
	}
    } else if( ptr->flag&SphereFlag )
    {   DrawAtoms = True;
	if( ptr->irad>MaxAtomRadius )
	    MaxAtomRadius = ptr->irad;
    }

    if( change )
    {   DrawAtoms = True;
	DetermineClipping();
	VoxelsClean = False;
	BucketFlag = False;
    }
}


void CPKColourAttrib()
{
    register ShadeRef *ref;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int i;

    if( !Database ) return;
    for( i=0; iflag&SelectFlag )
	{   i = GetElemNumber( ptr );
	    ref = CPKShade + Element[i].cpkcol;

	    if( !ref->col )
	    {   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		ref->col = Shade2Colour(ref->shade);
	    }
	    Shade[ref->shade].refcount++;
	    ptr->col = ref->col;
	}
}


void AminoColourAttrib()
{
    register ShadeRef *ref;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int i;

    if( !Database ) return;
    for( i=0; i<13; i++ )
	AminoShade[i].col = 0;
    ResetColourAttrib();

    ForEachAtom
	if( ptr->flag&SelectFlag )
	{   if( IsAmino(group->refno) )
	    {   ref = AminoShade + AminoIndex[group->refno];
	    } else ref = AminoShade+12;

	    if( !ref->col )
	    {   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		ref->col = Shade2Colour(ref->shade);
	    }
	    Shade[ref->shade].refcount++;
	    ptr->col = ref->col;
	}
}


void ShapelyColourAttrib()
{
    register ShadeRef *ref;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int i;

    if( !Database ) return;
    for( i=0; i<30; i++ )
	Shapely[i].col = 0;
    ResetColourAttrib();

    ForEachAtom
	if( ptr->flag&SelectFlag )
	{   if( IsAminoNucleo(group->refno) )
	    {   ref = Shapely + group->refno;
	    } else ref = Shapely+30;

/*  Original Colour Scheme
 *
 *  ref = &(Shapely[26]);
 *  if( IsNucleo(group->refno) )
 *  {   ref = Shapely + group->refno;
 *  } else if( IsShapelyBackbone(ptr->refno) )
 *  {   ref = &(Shapely[24]);
 *  } else if( IsShapelySpecial(ptr->refno) )
 *  {   ref = &(Shapely[25]);
 *  } else if( IsAmino(group->refno) )
 *      ref = Shapely + group->refno;
 */

	    if( !ref->col )
	    {   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		ref->col = Shade2Colour(ref->shade);
	    }
	    Shade[ref->shade].refcount++;
	    ptr->col = ref->col;
	}
}


void StructColourAttrib()
{
    register ShadeRef *ref;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;
    register int i;

    if( !Database )
	return;

    if( InfoHelixCount<0 )
	DetermineStructure();

    for( i=0; i<4; i++ )
	StructShade[i].col = 0;
    ResetColourAttrib();

    ForEachAtom
	if( ptr->flag&SelectFlag )
	{   if( group->struc & HelixFlag )
	    {   ref = StructShade+1;
	    } else if( group->struc & SheetFlag )
	    {   ref = StructShade+2;
	    } else if( group->struc & TurnFlag )
	    {   ref = StructShade+3;
	    } else ref = StructShade;

	    if( !ref->col )
	    {   ref->shade = DefineShade( ref->r, ref->g, ref->b );
		ref->col = Shade2Colour(ref->shade);
	    }
	    Shade[ref->shade].refcount++;
	    ptr->col = ref->col;
	}
}



int IsCPKColour( ptr )
    Atom __far *ptr;
{
    register ShadeRef *cpk;
    register ShadeDesc *col;
    register int elem;

    elem = GetElemNumber( ptr );
    cpk = CPKShade + Element[elem].cpkcol;
    col = Shade + Colour2Shade(ptr->col);
    return( (col->r==cpk->r) && 
	    (col->g==cpk->g) && 
	    (col->b==cpk->b) );
}


int IsVDWRadius( ptr )
    Atom __far *ptr;
{
    register int elem, rad;

    if( ptr->flag & SphereFlag )
    {   elem = GetElemNumber( ptr );
	rad = ElemVDWRadius( elem );
	return( ptr->radius == rad );
    } else return( False );
}



void InitialTransform()
{
    register Card dist;
    register Long x, y, z;
    register Long dx, dy, dz;
    register Card ax, ay, az;
    register Chain __far *chain;
    register Group __far *group;
    register Atom __far *ptr;


    dx = MaxX-MinX;   OrigCX = (dx>>1)+MinX;
    dy = MaxY-MinY;   OrigCY = (dy>>1)+MinY;
    dz = MaxZ-MinZ;   OrigCZ = (dz>>1)+MinZ;

    MaxX -= OrigCX;   MinX -= OrigCX;
    MaxY -= OrigCY;   MinY -= OrigCY;
    MaxZ -= OrigCZ;   MinZ -= OrigCZ;

    WorldRadius = 0;
    SideLen = MaxFun(dx,dy);
    if( dz>SideLen ) SideLen = dz;
    SideLen += 1000;  Offset = SideLen>>1;
    XOffset = WRange;  YOffset = HRange;
    ZOffset = 10000;

    ForEachAtom
    {   x = ptr->xorg-OrigCX;   ptr->xorg = x;  ax = (Card)AbsFun(x);
	y = ptr->yorg-OrigCY;   ptr->yorg = y;  ay = (Card)AbsFun(y);
	z = ptr->zorg-OrigCZ;   ptr->zorg = z;  az = (Card)AbsFun(z);
	dist = ax*ax + ay*ay + az*az;
	if( dist>WorldRadius )
	    WorldRadius = dist;
    }

    WorldRadius = (Card)sqrt((double)WorldRadius);
    WorldSize = WorldRadius<<1;
    DScale = 1.0/(WorldSize+1000);

    /* MaxZoom*DScale*Range*500 == 118 */
    MaxZoom = 0.236*(WorldSize+1000)/Range;
    if( MaxZoom < 1.0 )
    {   DScale *= MaxZoom;
	MaxZoom = 1.0;
    }
    ZoomRange = Range;
    MaxZoom -= 1.0;
}


void ReviseInvMatrix()
{
    InvX[0] = IScale*RotX[0];
    InvX[1] = IScale*RotY[0];
    InvX[2] = IScale*RotZ[0];

    InvY[0] = IScale*RotX[1];
    InvY[1] = IScale*RotY[1];
    InvY[2] = IScale*RotZ[1];

    InvZ[0] = IScale*RotX[2];
    InvZ[1] = IScale*RotY[2];
    InvZ[2] = IScale*RotZ[2];
    ShadowTransform();
}


void PrepareTransform()
{
    register Real theta, temp;
    register Real cost, sint;
    register Real x, y, z;
    register Real ncost;

    if( (ReDrawFlag&RFRotateX) && (DialValue[0]!=LastRX) )
    {   theta = PI*(DialValue[0]-LastRX);
	cost = cos(theta);  sint = sin(theta);
	LastRX = DialValue[0];

	y=RotY[0]; z=RotZ[0];
	RotY[0]=cost*y+sint*z; 
	RotZ[0]=cost*z-sint*y;

	y=RotY[1]; z=RotZ[1];
	RotY[1]=cost*y+sint*z;
	RotZ[1]=cost*z-sint*y;

	y=RotY[2]; z=RotZ[2];
	RotY[2]=cost*y+sint*z;
	RotZ[2]=cost*z-sint*y;

	if( CenX || CenY || CenZ )
	{   ncost = 1.0-cost;
	    temp =  CenX*(ncost*RotY[0] + sint*RotZ[0]);
	    temp += CenY*(ncost*RotY[1] + sint*RotZ[1]);
	    temp += CenZ*(ncost*RotY[2] + sint*RotZ[2]);
	    temp = DialValue[5] - (Scale*temp)/YRange;

	    if( temp < -1.0 )
	    {   DialValue[5] = -1.0;
	    } else if( temp > 1.0 )
	    {   DialValue[5] = 1.0;
	    } else DialValue[5] = temp;
	}
    }

    if( (ReDrawFlag&RFRotateY) && (DialValue[1]!=LastRY) )
    {   theta = PI*(DialValue[1]-LastRY);
	cost = cos(theta);  sint = sin(theta);
	LastRY = DialValue[1];

	x=RotX[0]; z=RotZ[0];
	RotX[0]=cost*x+sint*z;
	RotZ[0]=cost*z-sint*x;

	x=RotX[1]; z=RotZ[1];
	RotX[1]=cost*x+sint*z;
	RotZ[1]=cost*z-sint*x;

	x=RotX[2]; z=RotZ[2];
	RotX[2]=cost*x+sint*z;
	RotZ[2]=cost*z-sint*x;

	if( CenX || CenY || CenZ )
	{   ncost = 1.0-cost;
	    temp =  CenX*(ncost*RotX[0] + sint*RotZ[0]);
	    temp += CenY*(ncost*RotX[1] + sint*RotZ[1]);
	    temp += CenZ*(ncost*RotX[2] + sint*RotZ[2]);
	    temp = DialValue[4] - (Scale*temp)/XRange;

	    if( temp < -1.0 )
	    {   DialValue[4] = -1.0;
	    } else if( temp > 1.0 )
	    {   DialValue[4] = 1.0;
	    } else DialValue[4] = temp;
	}
    }

    if( (ReDrawFlag&RFRotateZ) && (DialValue[2]!=LastRZ) )
    {   theta = PI*(DialValue[2]-LastRZ);
	cost = cos(theta);  sint = sin(theta);
	LastRZ = DialValue[2];

	x=RotX[0]; y=RotY[0];
	RotX[0]=cost*x-sint*y;
	RotY[0]=cost*y+sint*x;

	x=RotX[1]; y=RotY[1];
	RotX[1]=cost*x-sint*y;
	RotY[1]=cost*y+sint*x;

	x=RotX[2]; y=RotY[2];
	RotX[2]=cost*x-sint*y;
	RotY[2]=cost*y+sint*x;

	if( CenX || CenY || CenZ )
	{   ncost = 1.0-cost;
	    temp =  CenX*(ncost*RotX[0] - sint*RotY[0]);
	    temp += CenY*(ncost*RotX[1] - sint*RotY[1]);
	    temp += CenZ*(ncost*RotX[2] - sint*RotY[2]);
	    temp = DialValue[4] - (Scale*temp)/XRange;

	    if( temp < -1.0 )
	    {   DialValue[4] = -1.0;
	    } else if( temp > 1.0 )
	    {   DialValue[4] = 1.0;
	    } else DialValue[4] = temp;

	    ncost = 1.0-cost;
	    temp =  CenX*(ncost*RotY[0] + sint*RotX[0]);
	    temp += CenY*(ncost*RotY[1] + sint*RotX[1]);
	    temp += CenZ*(ncost*RotY[2] + sint*RotX[2]);
	    temp = DialValue[5] - (Scale*temp)/YRange;

	    if( temp < -1.0 )
	    {   DialValue[5] = -1.0;
	    } else if( temp > 1.0 )
	    {   DialValue[5] = 1.0;
	    } else DialValue[5] = temp;
	}
    }
}


void ApplyTransform()
{
    register int temp;
    register Real x, y, z;
    register int oldx,oldy;
    register Chain __far *chain;
    register Group __far *group;
    register HBond __far *hptr;
    register Bond __far *bptr;
    register Atom __far *ptr;


    if( ReDrawFlag & RFMagnify )
    {   if( DialValue[3] <= 0.0 )
	{   Zoom = DialValue[3]+1.0;
	    if( Zoom<0.1 ) Zoom=0.1;
	} else Zoom = (DialValue[3]*MaxZoom) + 1.0;

	Scale = Zoom*DScale*Range;
	ImageSize = (int)(Scale*WorldSize);
	ImageRadius = ImageSize>>1;
	IScale = 1.0/Scale;

	MaxAtomRadius = 0;
	MaxBondRadius = 0;
    }

    if( ReDrawFlag & RFRotate )
    {   PrepareTransform();
	if( UseShadow )
	    ShadowTransform();
    }

    if( ReDrawFlag & (RFRotate|RFMagnify) )
    {   MatX[0] = Scale*RotX[0]; 
	MatX[1] = Scale*RotX[1];
	MatX[2] = Scale*RotX[2];

	MatY[0] = Scale*RotY[0];
	MatY[1] = Scale*RotY[1];
	MatY[2] = Scale*RotY[2];

	MatZ[0] = Scale*RotZ[0];
	MatZ[1] = Scale*RotZ[1];
	MatZ[2] = Scale*RotZ[2];

	if( UseShadow )
	{   InvX[0] = IScale*RotX[0]; 
	    InvX[1] = IScale*RotY[0];
	    InvX[2] = IScale*RotZ[0];

	    InvY[0] = IScale*RotX[1];
	    InvY[1] = IScale*RotY[1];
	    InvY[2] = IScale*RotZ[1];

	    InvZ[0] = IScale*RotX[2];
	    InvZ[1] = IScale*RotY[2];
	    InvZ[2] = IScale*RotZ[2];
	}
    }

    oldx = XOffset;
    oldy = YOffset;
    XOffset = WRange + (int)(DialValue[4]*XRange);
    YOffset = HRange + (int)(DialValue[5]*YRange);

    /* Zoom dependent Translation! */
    /* XOffset = WRange + (int)(DialValue[4]*ImageSize); */
    /* YOffset = HRange + (int)(DialValue[5]*ImageSize); */


    switch( ReDrawFlag )
    {   case(RFTransX):
		if( (temp = XOffset-oldx) ) 
		    ForEachAtom ptr->x += temp;
		break;

	case(RFTransY):
		if( (temp = YOffset-oldy) ) 
		    ForEachAtom ptr->y += temp;
		break;

	case(RFRotateX):
	    ForEachAtom
	    {   x = ptr->xorg; y = ptr->yorg; z = ptr->zorg;
		ptr->y = (int)(x*MatY[0]+y*MatY[1]+z*MatY[2])+YOffset;
		ptr->z = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2])+ZOffset;
	    }
	    break;

	case(RFRotateY):
	    ForEachAtom
	    {   x = ptr->xorg; y = ptr->yorg; z = ptr->zorg;
		ptr->x = (int)(x*MatX[0]+y*MatX[1]+z*MatX[2])+XOffset;
		ptr->z = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2])+ZOffset;
	    }
	    break;

	case(RFRotateZ):
	    ForEachAtom
	    {   x = ptr->xorg; y = ptr->yorg; z = ptr->zorg;
		ptr->x = (int)(x*MatX[0]+y*MatX[1]+z*MatX[2])+XOffset;
		ptr->y = (int)(x*MatY[0]+y*MatY[1]+z*MatY[2])+YOffset;
	    }
	    break;

	default:
	    if( DrawAtoms && (ReDrawFlag&RFMagnify) )
	    {   ForEachAtom 
		{   x = ptr->xorg; y = ptr->yorg; z = ptr->zorg;
		    ptr->x = (int)(x*MatX[0]+y*MatX[1]+z*MatX[2])+XOffset;
		    ptr->y = (int)(x*MatY[0]+y*MatY[1]+z*MatY[2])+YOffset;
		    ptr->z = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2])+ZOffset;
		    if( ptr->flag&SphereFlag )
		    {   ptr->irad = (int)(Scale*ptr->radius);
			if( ptr->irad>MaxAtomRadius )
			    MaxAtomRadius = ptr->irad;
		    }
		}
	    } else
		ForEachAtom 
		{   x = ptr->xorg; y = ptr->yorg; z = ptr->zorg;
		    ptr->x = (int)(x*MatX[0]+y*MatX[1]+z*MatX[2])+XOffset;
		    ptr->y = (int)(x*MatY[0]+y*MatY[1]+z*MatY[2])+YOffset;
		    ptr->z = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2])+ZOffset;
		}

	    if( ReDrawFlag & RFMagnify )
	    {   if( DrawBonds )
		    ForEachBond
			if( bptr->flag&CylinderFlag )
			{   bptr->irad = (int)(Scale*bptr->radius);
			    if( bptr->irad>MaxBondRadius )
			    MaxBondRadius = bptr->irad;
			}

		for( hptr=Database->hlist; hptr; hptr=hptr->hnext )
		    if( hptr->flag&CylinderFlag )
			hptr->irad = (int)(Scale*hptr->radius);

		for( hptr=Database->slist; hptr; hptr=hptr->hnext )
		    if( hptr->flag&CylinderFlag )
			hptr->irad = (int)(Scale*hptr->radius);

		ForEachBack
		    if( bptr->flag&CylinderFlag )
			bptr->irad = (int)(Scale*bptr->radius);
	    }
    }

    DetermineClipping();
    if( UseScreenClip || ReDrawFlag!=RFRotateY )
	BucketFlag = False;
}


void ResetTransform()
{
    RotX[0] = 1.0;  RotX[1] = 0.0;  RotX[2] = 0.0;
    RotY[0] = 0.0;  RotY[1] = 1.0;  RotY[2] = 0.0;
    RotZ[0] = 0.0;  RotZ[1] = 0.0;  RotZ[2] = 1.0;
    LastRX = LastRY = LastRZ = 0.0;
    CenX = CenY = CenZ = 0;
}


void InitialiseTransform()
{
    ColourDepth = DefaultColDepth;
    ColourMask = ColourDepth-1;

#ifdef APPLEMAC
    LastShade = Colour2Shade(LutSize-1);
#else
    LastShade = Colour2Shade(LutSize);
#endif

    ResetColourMap();
    ResetTransform();

    ZoneBoth = True;
    HetaGroups = True;
    Hydrogens = True;
}

Modified: Mon Oct 24 16:00:00 1994 GMT
Page accessed 1193 times since Sat Apr 17 21:38:35 1999 GMT