/*************************************************************************** * RasMol 2.7.1 * * * * RasMol * * Molecular Graphics Visualisation Tool * * 22 June 1999 * * * * Based on RasMol 2.6 by Roger Sayle * * Biomolecular Structures Group, Glaxo Wellcome Research & Development, * * Stevenage, Hertfordshire, UK * * Version 2.6, August 1995, Version 2.6.4, December 1998 * * Copyright (C) Roger Sayle 1992-1999 * * * * and Based on Mods by Arne Mueller * * Version 2.6x1, May 1998 * * Copyright (C) Arne Mueller 1998 * * * * Version 2.7.0, 2.7.1 Mods by Herbert J. Bernstein * * Bernstein + Sons, P.O. Box 177, Bellport, NY, USA * * yaya@bernstein-plus-sons.com * * 2.7.0 March 1999, 2.7.1 June 1999 * * Copyright (C) Herbert J. Bernstein 1998-1999 * * * * Please read the file NOTICE for important notices which apply to this * * package. If you are not going to make changes to RasMol, you are not * * only permitted to freely make copies and distribute them, you are * * encouraged to do so, provided you do the following: * * * 1. Either include the complete documentation, especially the file * * NOTICE, with what you distribute or provide a clear indication * * where people can get a copy of the documentation; and * * * 2. Please give credit where credit is due citing the version and * * original authors properly; and * * * 3. Please do not give anyone the impression that the original * * authors are providing a warranty of any kind. * * * * If you would like to use major pieces of RasMol in some other program, * * make modifications to RasMol, or in some other way make what a lawyer * * would call a "derived work", you are not only permitted to do so, you * * are encouraged to do so. In addition to the things we discussed above, * * please do the following: * * * 4. Please explain in your documentation how what you did differs * * from this version of RasMol; and * * * 5. Please make your modified source code available. * * * * This version of RasMol is not in the public domain, but it is given * * freely to the community in the hopes of advancing science. If you make * * changes, please make them in a responsible manner, and please offer us * * the opportunity to include those changes in future versions of RasMol. * ***************************************************************************/ /* abstree.c */ #include "rasmol.h" #ifdef IBMPC #include #endif #ifndef sun386 #include #endif #include #if defined(IBMPC) || defined(VMS) || defined(APPLEMAC) #include "string_case.h" #else #include #endif #include #include #include #define ABSTREE #include "molecule.h" #include "abstree.h" #include "transfor.h" /* Macros for commonly used loops */ #define ForEachAtom for(chain=Database->clist;chain;chain=chain->cnext) \ for(group=chain->glist;group;group=group->gnext) \ for(aptr=group->alist;aptr;aptr=aptr->anext) #define BitAcidic 0x001 #define BitAliphatic 0x002 #define BitAromatic 0x004 #define BitBasic 0x008 #define BitBuried 0x010 #define BitCyclic 0x020 #define BitHydrophobic 0x040 #define BitMedium 0x080 #define BitNeutral 0x100 #define BitSmall 0x200 #define BitCharged 0x009 #define BitNotLarge 0x280 /* Acyclic = !Cyclic */ /* Large = !Medium && !Small */ /* Polar = !Hydrophobic */ /* Surface = !Buried */ static int AminoProp[] = { /*ALA*/ BitAliphatic | BitBuried | BitHydrophobic | BitNeutral | BitSmall, /*GLY*/ BitAliphatic | BitHydrophobic | BitNeutral | BitSmall, /*LEU*/ BitAliphatic | BitBuried | BitHydrophobic | BitNeutral, /*SER*/ BitNeutral | BitSmall, /*VAL*/ BitAliphatic | BitBuried | BitHydrophobic | BitMedium | BitNeutral, /*THR*/ BitMedium | BitNeutral, /*LYS*/ BitBasic, /*ASP*/ BitAcidic | BitMedium, /*ILE*/ BitAliphatic | BitBuried | BitHydrophobic | BitNeutral, /*ASN*/ BitMedium | BitNeutral, /*GLU*/ BitAcidic, /*PRO*/ BitCyclic | BitHydrophobic | BitMedium | BitNeutral, /*ARG*/ BitBasic, /*PHE*/ BitAromatic | BitBuried | BitCyclic | BitHydrophobic | BitNeutral, /*GLN*/ BitNeutral, /*TYR*/ BitAromatic | BitCyclic | BitNeutral, /*HIS*/ BitAromatic | BitBasic | BitCyclic | BitNeutral, /*CYS*/ BitBuried | BitMedium | BitNeutral, /*MET*/ BitBuried | BitHydrophobic | BitNeutral, /*TRP*/ BitAromatic | BitBuried | BitCyclic | BitHydrophobic | BitNeutral, /*ASX*/ BitMedium | BitNeutral, /*GLX*/ BitNeutral, /*PCA*/ BitCyclic | BitHydrophobic | BitMedium | BitNeutral, /*HYP*/ BitCyclic | BitMedium | BitNeutral }; #define AminoCodeMax 28 static char *AminoCode = "AGLSVTKDINEPRFQYHCMWBZPPACGTX"; #define ExprPool 16 #define SetPool 4 typedef struct _SymEntry { struct _SymEntry __far *lft; struct _SymEntry __far *rgt; AtomSet __far *defn; char *ident; } SymEntry; static SymEntry __far *SymbolTable; static SymEntry __far *FreeEntry; static AtomSet __far *FreeSet; static Expr *FreeExpr; static Expr FalseExpr; static Expr TrueExpr; /*=======================*/ /* Function Prototypes */ /*=======================*/ static AtomSet __far *SetInsert( AtomSet __far*, Atom __far* ); static int IsWithinRadius( AtomSet __far*, Long ); static int IsSetMember( AtomSet __far* ); static void DeleteSymEntry( SymEntry __far* ); static void FatalExprError( char *ptr ) { char buffer[80]; sprintf(buffer,"Expression Error: %s!",ptr); RasMolFatalExit(buffer); } static AtomSet __far *SetInsert( AtomSet __far *ptr, Atom __far *item ) { register AtomSet __far *temp; register int i; if( ptr && (ptr->countdata[ptr->count] = item; ptr->count++; return ptr; } if( !FreeSet ) { temp = (AtomSet __far*)_fmalloc( SetPool*sizeof(AtomSet) ); if( !temp ) FatalExprError("Memory allocation failed"); for( i=1; inext = FreeSet; FreeSet = temp++; } } else { temp = FreeSet; FreeSet = temp->next; } temp->data[0] = item; temp->next = ptr; temp->count = 1; return temp; } static int IsWithinRadius( AtomSet __far *ptr, Long limit ) { register Atom __far *aptr; register Long dx,dy,dz; register Long dist; register int i; while( ptr ) { for( i=0; icount; i++ ) { aptr = ptr->data[i]; dx = QAtom->xorg-aptr->xorg; if( (dist=dx*dx)>limit ) continue; dy = QAtom->yorg-aptr->yorg; if( (dist+=dy*dy)>limit ) continue; dz = QAtom->zorg-aptr->zorg; if( (dist+=dz*dz)>limit ) continue; return True; } ptr = ptr->next; } return False; } static int IsSetMember( AtomSet __far *ptr ) { register int i; while( ptr ) { for( i=0; icount; i++ ) if( ptr->data[i] == QAtom ) return True; ptr = ptr->next; } return False; } void DeleteAtomSet( AtomSet __far *ptr ) { register AtomSet __far *temp; if( ptr ) { temp = ptr; while( temp->next ) temp = temp->next; temp->next = FreeSet; FreeSet = ptr; } } Expr *AllocateNode( void ) { register Expr *ptr; register int i; if( !FreeExpr ) { ptr = (Expr*)malloc( ExprPool*sizeof(Expr) ); if( !ptr ) FatalExprError("Memory allocation failed"); for( i=1; irgt.ptr = FreeExpr; FreeExpr = ptr++; } } else { ptr = FreeExpr; FreeExpr = ptr->rgt.ptr; } ptr->rgt.ptr = NULL; ptr->lft.ptr = NULL; return ptr; } void DeAllocateExpr( Expr *expr ) { if( !expr ) return; if( (expr == &FalseExpr) || (expr == &TrueExpr) ) return; if( expr->type!=OpWithin ) { if( !(expr->type&(OpLftProp|OpLftVal)) ) DeAllocateExpr( expr->lft.ptr ); if( !(expr->type&(OpRgtProp|OpRgtVal)) ) DeAllocateExpr( expr->rgt.ptr ); } else DeleteAtomSet( expr->rgt.set ); expr->rgt.ptr = FreeExpr; FreeExpr = expr; } int GetElemNumber( Group __far *group, Atom __far *aptr ) { register char ch1,ch2; register char *ptr; ptr = ElemDesc[aptr->refno]; if( IsCoenzyme(group->refno) ) { /* Exceptions to PDB Atom Naming! */ ch1 = ' '; } else { ch1 = ToUpper(ptr[0]); /* Handle HG, HD etc.. in Amino Acids! */ if( (ch1=='H') && IsProtein(group->refno) ) return 1; } ch2 = ToUpper(ptr[1]); switch( ch1 ) { case(' '): switch( ch2 ) { case('B'): return( 5 ); case('C'): return( 6 ); case('D'): return( 1 ); case('F'): return( 9 ); case('H'): return( 1 ); case('I'): return( 53 ); case('K'): return( 19 ); case('L'): return( 1 ); case('N'): return( 7 ); case('O'): return( 8 ); case('P'): return( 15 ); case('S'): return( 16 ); case('U'): return( 92 ); case('V'): return( 23 ); case('W'): return( 74 ); case('Y'): return( 39 ); } break; case('A'): switch( ch2 ) { case('C'): return( 89 ); case('G'): return( 47 ); case('L'): return( 13 ); case('M'): return( 95 ); case('R'): return( 18 ); case('S'): return( 33 ); case('T'): return( 85 ); case('U'): return( 79 ); } break; case('B'): switch( ch2 ) { case(' '): return( 5 ); case('A'): return( 56 ); case('E'): return( 4 ); case('I'): return( 83 ); case('K'): return( 97 ); case('R'): return( 35 ); } break; case('C'): switch( ch2 ) { case(' '): return( 6 ); case('A'): return( 20 ); case('D'): return( 48 ); case('E'): return( 58 ); case('F'): return( 98 ); case('L'): return( 17 ); case('M'): return( 96 ); case('O'): return( 27 ); case('R'): return( 24 ); case('S'): return( 55 ); case('U'): return( 29 ); } break; case('D'): if( ch2==' ' ) { return( 1 ); } else if( ch2=='Y' ) { return( 66 ); } else if( ch2=='U' ) return( 0 ); break; case('E'): if( ch2=='R' ) { return( 68 ); } else if( ch2=='S' ) { return( 99 ); } else if( ch2=='U' ) return( 63 ); break; case('F'): if( ch2==' ' ) { return( 9 ); } else if( ch2=='E' ) { return( 26 ); } else if( ch2=='M' ) { return( 100 ); } else if( ch2=='R' ) return( 87 ); break; case('G'): if( ch2=='A' ) { return( 31 ); } else if( ch2=='D' ) { return( 64 ); } else if( ch2=='E' ) return( 32 ); break; case('H'): if( ch2==' ' ) { return( 1 ); } else if( ch2=='E' ) { return( 2 ); } else if( ch2=='F' ) { return( 72 ); } else if( ch2=='G' ) { return( 80 ); } else if( ch2=='O' ) return( 67 ); break; case('I'): if( ch2==' ' ) { return( 53 ); } else if( ch2=='N' ) { return( 49 ); } else if( ch2=='R' ) return( 77 ); break; case('K'): if( ch2==' ' ) { return( 19 ); } else if( ch2=='R' ) return( 36 ); break; case('L'): switch( ch2 ) { case('A'): return( 57 ); case('I'): return( 3 ); case('P'): return( 0 ); case('R'): return( 103 ); case('W'): return( 103 ); case('U'): return( 71 ); } break; case('M'): if( ch2=='D' ) { return( 101 ); } else if( ch2=='G' ) { return( 12 ); } else if( ch2=='N' ) { return( 25 ); } else if( ch2=='O' ) return( 42 ); break; case('N'): switch( ch2 ) { case(' '): return( 7 ); case('A'): return( 11 ); case('B'): return( 41 ); case('D'): return( 60 ); case('E'): return( 10 ); case('I'): return( 28 ); case('O'): return( 102 ); case('P'): return( 93 ); } break; case('O'): if( ch2==' ' ) { return( 8 ); } else if( ch2=='S' ) return( 76 ); break; case('P'): switch( ch2 ) { case(' '): return( 15 ); case('A'): return( 91 ); case('B'): return( 82 ); case('D'): return( 46 ); case('M'): return( 61 ); case('O'): return( 84 ); case('R'): return( 59 ); case('T'): return( 78 ); case('U'): return( 94 ); } break; case('R'): switch( ch2 ) { case('A'): return( 88 ); case('B'): return( 37 ); case('E'): return( 75 ); case('H'): return( 45 ); case('N'): return( 86 ); case('U'): return( 44 ); } break; case('S'): switch( ch2 ) { case(' '): return( 16 ); case('B'): return( 51 ); case('C'): return( 21 ); case('E'): return( 34 ); case('I'): return( 14 ); case('M'): return( 62 ); case('N'): return( 50 ); case('R'): return( 38 ); } break; case('T'): switch( ch2 ) { case(' '): return( 1 ); case('A'): return( 73 ); case('B'): return( 65 ); case('C'): return( 43 ); case('E'): return( 52 ); case('H'): return( 90 ); case('I'): return( 22 ); case('L'): return( 81 ); case('M'): return( 69 ); } break; case('U'): if( ch2==' ' ) return( 92 ); break; case('V'): if( ch2==' ' ) return( 23 ); break; case('W'): if( ch2==' ' ) return( 74 ); break; case('X'): if( ch2=='E' ) return( 54 ); break; case('Y'): if( ch2==' ' ) { return( 39 ); } else if( ch2=='B' ) return( 70 ); break; case('Z'): if( ch2=='N' ) { return( 30 ); } else if( ch2=='R' ) return( 40 ); break; } /* Numeric Prefix! */ if( (ch1>='0') && (ch1<='9') ) ch1 = ch2; /* If all else fails! */ switch( ch1 ) { case('B'): return( 5 ); case('C'): return( 6 ); case('D'): return( 1 ); case('F'): return( 9 ); case('H'): return( 1 ); case('I'): return( 53 ); case('K'): return( 19 ); case('L'): return( 1 ); case('N'): return( 7 ); case('O'): return( 8 ); case('P'): return( 15 ); case('S'): return( 16 ); case('U'): return( 92 ); case('V'): return( 23 ); case('W'): return( 74 ); case('Y'): return( 39 ); } return 0; } int ElemVDWRadius( int elem ) { if( !HasHydrogen ) switch( elem ) { case 6: return VDWCarbon; case 7: return VDWNitrogen; case 8: return VDWOxygen; case 16: return VDWSulphur; } return Element[elem].vdwrad; } static int EvaluateProperty( int prop ) { switch( prop ) { case( PropIdent ): return( (int)QAtom->serno ); case( PropXCord ): return( (int)QAtom->xorg ); case( PropYCord ): return( (int)QAtom->yorg ); case( PropZCord ): return( (int)QAtom->zorg ); case( PropTemp ): return( QAtom->temp ); case( PropName ): return( QAtom->refno ); case( PropResId ): return( QGroup->serno ); case( PropResName ): return( QGroup->refno ); case( PropChain ): return( QChain->ident ); case( PropSelect ): return( QAtom->flag&SelectFlag ); case( PropElemNo ): return( QAtom->elemno ); case( PropModel ): return( (int)QChain->model ); case( PropAltl ): return( (int)QAtom->altl ); case( PropRad ): if( QAtom->flag&SphereFlag ) { return( QAtom->radius ); } else return( 0 ); /* Predicates stored in flags */ case( PredBonded ): return( !(QAtom->flag&NonBondFlag) ); case( PredHydrogen ): return( QAtom->flag&HydrogenFlag ); case( PredHetero ): return( QAtom->flag&HeteroFlag ); case( PredCystine ): return( QGroup->flag&CystineFlag ); case( PredHelix ): return( QGroup->struc&HelixFlag ); case( PredSheet ): return( QGroup->struc&SheetFlag ); case( PredTurn ): return( QGroup->struc&TurnFlag ); case( PredCisBond ): return( QGroup->flag&CisBondFlag ); /* Residue type predicates */ case( PredDNA ): return( IsDNA(QGroup->refno) ); case( PredRNA ): return( IsRNA(QGroup->refno) ); case( PredNucleic ): return( IsNucleo(QGroup->refno) ); case( PredProtein ): return( IsProtein(QGroup->refno) ); case( PredAmino ): return( IsAmino(QGroup->refno) ); case( PredWater ): return( IsWater(QGroup->refno) ); case( PredSolvent ): return( IsSolvent(QGroup->refno) ); case( PredIon ): return( IsIon(QGroup->refno) ); /* General Predicates */ case( PredAlpha ): return( IsAmino(QGroup->refno) && IsAlphaCarbon(QAtom->refno) ); case( PredMainChain ): return( (IsAmino(QGroup->refno) && IsAminoBackbone(QAtom->refno)) || (IsNucleo(QGroup->refno) && IsNucleicBackbone(QAtom->refno)) ); case( PredSidechain ): return( IsAmino(QGroup->refno) && !IsAminoBackbone(QAtom->refno) ); case( PredLigand ): return( (QAtom->flag&HeteroFlag) && !IsSolvent(QGroup->refno) ); /* Nucleic Acid Classifications */ case( PredAT ): return( IsAdenine(QGroup->refno) || IsThymine(QGroup->refno) ); case( PredCG ): return( IsCytosine(QGroup->refno) || IsGuanine(QGroup->refno) ); case( PredPyrimidine ): return( IsPyrimidine(QGroup->refno) ); case( PredPurine ): return( IsPurine(QGroup->refno) ); /* Amino Acid Classifications */ case( PredAcidic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitAcidic ); case( PredAcyclic ): return( IsAmino(QGroup->refno) && !(AminoProp[QGroup->refno]&BitCyclic) ); case( PredAliphatic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitAliphatic ); case( PredAromatic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitAromatic ); case( PredBasic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitBasic ); case( PredBuried ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitBuried ); case( PredCharged ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitCharged ); case( PredCyclic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitCyclic ); case( PredHydrophobic ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitHydrophobic ); case( PredLarge ): return( IsAmino(QGroup->refno) && !(AminoProp[QGroup->refno]&BitNotLarge) ); case( PredMedium ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitMedium ); case( PredNeutral ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitNeutral ); case( PredPolar ): return( IsAmino(QGroup->refno) && !(AminoProp[QGroup->refno]&BitHydrophobic) ); case( PredSmall ): return( IsAmino(QGroup->refno) && AminoProp[QGroup->refno]&BitSmall ); case( PredSurface ): return( IsAmino(QGroup->refno) && !(AminoProp[QGroup->refno]&BitBuried) ); } return True; } int EvaluateExpr( Expr *expr ) { register int lft, rgt; if( !expr ) return True; if( expr->type==OpWithin ) { if( expr->lft.limit ) { return( IsWithinRadius(expr->rgt.set,expr->lft.limit) ); } else return( IsSetMember(expr->rgt.set) ); } else if( expr->type==OpMember ) return( IsSetMember(expr->rgt.set) ); if( expr->type & OpLftVal ) { lft = expr->lft.val; } else if( expr->type & OpLftProp ) { lft = EvaluateProperty( expr->lft.val ); } else lft = EvaluateExpr( expr->lft.ptr ); if( OpCode(expr)==OpConst ) return( lft ); if( (OpCode(expr)==OpAnd) && !lft ) return False; if( (OpCode(expr)==OpOr) && lft ) return True; if( OpCode(expr)==OpNot ) return( !lft ); if( expr->type & OpRgtVal ) { rgt = expr->rgt.val; } else if( expr->type & OpRgtProp ) { rgt = EvaluateProperty( expr->rgt.val ); } else rgt = EvaluateExpr( expr->rgt.ptr ); switch( OpCode(expr) ) { case(OpOr): case(OpAnd): return( rgt ); case(OpLess): return( lftrgt ); case(OpEqual): return( lft==rgt ); case(OpNotEq): return( lft!=rgt ); case(OpLessEq): return( lft<=rgt ); case(OpMoreEq): return( lft>=rgt ); } return True; } AtomSet __far *BuildAtomSet( Expr *expr ) { register AtomSet __far *ptr; ptr = (AtomSet __far*)0; if( Database ) for( QChain=Database->clist; QChain; QChain=QChain->cnext ) for( QGroup=QChain->glist; QGroup; QGroup=QGroup->gnext ) for( QAtom=QGroup->alist; QAtom; QAtom=QAtom->anext ) if( EvaluateExpr(expr) ) ptr = SetInsert( ptr, QAtom ); return ptr; } int DefineSetExpr( char *ident, Expr *expr ) { register SymEntry __far * __far *prev; register SymEntry __far *ptr; register AtomSet __far *set; register int result; /* Avoid Compiler Warning! */ ptr = (SymEntry __far*)0; result = True; prev = &SymbolTable; while( *prev ) { ptr = *prev; result = strcmp(ident,ptr->ident); if( !result ) break; /* Entry Exists! */ prev = (result<0)? &(ptr->lft) : &(ptr->rgt); } if( result ) { if( FreeEntry ) { ptr = FreeEntry; FreeEntry = ptr->rgt; } else /* Allocate SymEntry! */ { ptr = (SymEntry __far*)_fmalloc(sizeof(SymEntry)); if( !ptr ) return False; } *prev = ptr; ptr->ident = ident; ptr->defn = (void __far*)0; ptr->lft = (void __far*)0; ptr->rgt = (void __far*)0; } else free(ident); if( expr ) { set = BuildAtomSet(expr); if( ptr->defn ) DeleteAtomSet(ptr->defn); DeAllocateExpr(expr); ptr->defn = set; } else ptr->defn = (void __far*)0; return True; } Expr *LookUpSetExpr( char *ident ) { register SymEntry __far *ptr; register Expr *expr; register int result; result = True; ptr = SymbolTable; while( ptr ) { result = strcmp(ident,ptr->ident); if( !result ) break; /* Entry Exists! */ ptr = (result<0)? ptr->lft : ptr->rgt; } if( !result ) { expr = AllocateNode(); expr->type = OpMember; expr->rgt.set = ptr->defn; } else expr = (Expr*)0; return expr; } static int ElemCompare( char *ident, char *elem ) { while( *elem ) if( *elem++ != *ident++ ) return False; /* Handle Plurals */ if( (ident[0]=='S') && !ident[1] ) return( (elem[-1]!='S') && (elem[-1]!='Y') ); return !*ident; } Expr *LookUpElement( char *ident ) { register Expr *expr; register int elem; for( elem=1; elemtype = OpEqual|OpLftProp|OpRgtVal; expr->lft.val = PropElemNo; expr->rgt.val = elem; } else expr = (Expr*)0; return expr; } static int MatchWildName( char *src, char *dst, int size, int len ) { register int i, left; left = size; while( *dst==' ' ) { dst++; left--; } for( i=0; itype = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropResName; tmp1->rgt.val = j; tmp2 = AllocateNode(); tmp2->type = OpOr; tmp2->lft.ptr = tmp1; tmp2->rgt.ptr = wild; wild = tmp2; } QueryExpr = wild; } else ch = *ptr++; /* Parse Residue Number */ if( ch != '*' ) { if( ch == '-' ) { ch = *ptr++; neg = True; } else neg = False; if( isdigit(ch) ) { i = ch-'0'; while( isdigit(*ptr) ) i = 10*i + (*ptr++)-'0'; tmp1 = AllocateNode(); tmp1->type = OpEqual | OpLftProp | OpRgtVal; tmp1->rgt.val = neg? -i : i; tmp1->lft.val = PropResId; if( QueryExpr != &TrueExpr ) { tmp2 = AllocateNode(); tmp2->type = OpAnd; tmp2->rgt.ptr = QueryExpr; tmp2->lft.ptr = tmp1; QueryExpr = tmp2; } else QueryExpr = tmp1; ch = *ptr++; } else if( neg ) return False; } else ch = *ptr++; } /* Parse Chain Ident */ if( ch==':' ) ch = *ptr++; if( isalnum(ch) ) { ch = ToUpper(ch); tmp1 = AllocateNode(); tmp1->type = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropChain; tmp1->rgt.val = ch; if( QueryExpr != &TrueExpr ) { tmp2 = AllocateNode(); tmp2->type = OpAnd; tmp2->rgt.ptr = QueryExpr; tmp2->lft.ptr = tmp1; QueryExpr = tmp2; } else QueryExpr = tmp1; ch = *ptr++; } else if( (ch=='?') || (ch=='%') || (ch=='*') ) ch = *ptr++; /* Parse Model Number */ if( ch == ':' || ch =='/' ) { ch = *ptr++; if( isdigit(ch) ) { i = ch-'0'; while( isdigit(*ptr) ) i = 10*i + (*ptr++)-'0'; tmp1 = AllocateNode(); tmp1->type = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropModel; tmp1->rgt.val = i; if( QueryExpr != &TrueExpr ) { tmp2 = AllocateNode(); tmp2->type = OpAnd; tmp2->rgt.ptr = QueryExpr; tmp2->lft.ptr = tmp1; QueryExpr = tmp2; } else QueryExpr = tmp1; ch = *ptr++; } else return False; } /* Parse Atom Name */ if( ch == '.' ) { ch = *ptr++; if( ch!='*' ) { for( i=0; i<4; i++ ) if( isalnum(ch) || ch=='\'' || ch=='*' ) { NameBuf[i] = ToUpper(ch); ch = *ptr++; } else if( (ch=='?') || (ch=='%') || (ch=='#') ) { NameBuf[i] = '?'; ch = *ptr++; } else break; if( !i ) return False; wild = &FalseExpr; for( j=0; jtype = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropName; tmp1->rgt.val = j; tmp2 = AllocateNode(); tmp2->type = OpOr; tmp2->lft.ptr = tmp1; tmp2->rgt.ptr = wild; wild = tmp2; } if( (QueryExpr == &TrueExpr) || (wild == &FalseExpr) ) { DeAllocateExpr(QueryExpr); QueryExpr=wild; } else { tmp1 = AllocateNode(); tmp1->type = OpAnd; tmp1->lft.ptr = QueryExpr; tmp1->rgt.ptr = wild; QueryExpr = tmp1; } } else ch = *ptr++; } /* Parse Trailing Alternate Conformation Identifier */ if( ch ==';' ) { ch = *ptr++; if( isalnum(ch) || ch=='\'' || ch=='*' ) { NameBuf[0] = ToUpper(ch); ch = *ptr++; } else if( (ch=='?') || (ch=='%') || (ch=='#') ) { NameBuf[0] = '?'; ch = *ptr++; } else return False; tmp1 = AllocateNode(); tmp1->type = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropAltl; tmp1->rgt.val = NameBuf[0]; if( QueryExpr != &TrueExpr ) { tmp2 = AllocateNode(); tmp2->type = OpAnd; tmp2->rgt.ptr = QueryExpr; tmp2->lft.ptr = tmp1; QueryExpr = tmp2; } else QueryExpr = tmp1; } /* Parse Trailing Model Number */ if( ch =='/' ) { ch = *ptr++; if( isdigit(ch) ) { i = ch-'0'; while( isdigit(*ptr) ) i = 10*i + (*ptr++)-'0'; tmp1 = AllocateNode(); tmp1->type = OpEqual | OpLftProp | OpRgtVal; tmp1->lft.val = PropModel; tmp1->rgt.val = i; if( QueryExpr != &TrueExpr ) { tmp2 = AllocateNode(); tmp2->type = OpAnd; tmp2->rgt.ptr = QueryExpr; tmp2->lft.ptr = tmp1; QueryExpr = tmp2; } else QueryExpr = tmp1; ch = *ptr++; } else return False; } *orig = --ptr; return( !ch || isspace(ch) || ispunct(ch) ); } static char *FormatInteger( char *ptr, Long value ) { auto char buffer[10]; register char *tmp; if( value<0 ) { value = -value; *ptr++ = '-'; } if( value>9 ) { tmp = buffer; while( value>9 ) { *tmp++ = (char)(value%10) + '0'; value /= 10; } *ptr++ = (char)value + '0'; do { tmp--; *ptr++ = *tmp; } while( tmp != buffer ); } else *ptr++ = (char)value + '0'; return ptr; } void FormatLabel( Chain __far *chain, Group __far *group, Atom __far *aptr, char *label, char *ptr ) { register char ch; register int i,j; while( *label ) { ch = *label++; if( ch=='%' ) { ch = *label++; switch( ch ) { case('a'): /* Atom Name */ i = aptr->refno; for( j=0; j<4; j++ ) if( ElemDesc[i][j]!=' ' ) *ptr++ = ElemDesc[i][j]; break; case('b'): /* Temperature/B-factor */ case('B'): case('t'): case('T'): ptr = FormatInteger(ptr,aptr->temp); break; case('c'): /* Chain Identifier */ case('C'): case('s'): case('S'): *ptr++ = chain->ident; break; case('e'): case('E'): /* Element Type */ i = aptr->elemno; *ptr++ = Element[i].symbol[0]; if( Element[i].symbol[1]!=' ' ) *ptr++ = Element[i].symbol[1]; break; case('i'): case('I'): /* Atom Number */ ptr = FormatInteger(ptr,(int)aptr->serno); break; case('m'): /* Amino (Nucliec) Acid Code */ if( group->refno <= AminoCodeMax ) { *ptr++ = AminoCode[group->refno]; } else *ptr++ = '?'; break; case('n'): case('N'): /* Residue Name */ i = group->refno; for( j=0; j<3; j++ ) if( Residue[i][j]!=' ' ) *ptr++ = Residue[i][j]; break; case('r'): case('R'): /* Residue Number */ ptr = FormatInteger(ptr,group->serno); break; case('A'): /* Alternate Conformation ID */ if( !(aptr->altl == ' ') && !(aptr->altl == '\0')) { *ptr++ = ';'; *ptr++ = aptr->altl; } break; case('M'): /* NMR Model Number */ if ( aptr->model ) { *ptr++ = '/'; ptr = FormatInteger(ptr,(int)aptr->model); } break; case('%'): *ptr++ = '%'; break; } } else if( (ch>=' ') && (ch<='~') ) *ptr++ = ch; } *ptr = '\0'; } static void DeleteSymEntry( SymEntry __far *ptr ) { if( ptr->lft ) DeleteSymEntry( ptr->lft ); if( ptr->rgt ) DeleteSymEntry( ptr->rgt ); if( ptr->defn ) DeleteAtomSet( ptr->defn ); free( ptr->ident ); ptr->rgt = FreeEntry; FreeEntry = ptr; } void ResetSymbolTable( void ) { if( SymbolTable ) { DeleteSymEntry(SymbolTable); SymbolTable = (void __far*)0; } } double CalcDistance( Atom __far *atm1, Atom __far *atm2 ) { register Long dx,dy,dz; register double dist2; dx = atm1->xorg - atm2->xorg; dy = atm1->yorg - atm2->yorg; dz = atm1->zorg - atm2->zorg; if( dx || dy || dz ) { dist2 = dx*dx + dy*dy + dz*dz; return( sqrt(dist2)/250.0 ); } else return 0.0; } double CalcAngle( Atom __far *atm1, Atom __far *atm2, Atom __far *atm3 ) { register double ulen2,vlen2; register double ux,uy,uz; register double vx,vy,vz; register double temp; ux = atm1->xorg - atm2->xorg; uy = atm1->yorg - atm2->yorg; uz = atm1->zorg - atm2->zorg; if( !ux && !uy && !uz ) return 0.0; ulen2 = ux*ux + uy*uy + uz*uz; vx = atm3->xorg - atm2->xorg; vy = atm3->yorg - atm2->yorg; vz = atm3->zorg - atm2->zorg; if( !vx && !vy && !vz ) return 0.0; vlen2 = vx*vx + vy*vy + vz*vz; temp = (ux*vx + uy*vy + uz*vz)/sqrt(ulen2*vlen2); return Rad2Deg*acos(temp); } double CalcTorsion( Atom __far *atm1, Atom __far *atm2, Atom __far *atm3, Atom __far *atm4 ) { register double ax, ay, az; register double bx, by, bz; register double cx, cy, cz; register double px, py, pz; register double qx, qy, qz; register double cosom,sgn,om; register double rx, ry, rz; register double plen,qlen; ax = atm2->xorg - atm1->xorg; ay = atm2->yorg - atm1->yorg; az = atm2->zorg - atm1->zorg; if( !ax && !ay && !az ) return 0.0; bx = atm3->xorg - atm2->xorg; by = atm3->yorg - atm2->yorg; bz = atm3->zorg - atm2->zorg; if( !bx && !by && !bz ) return 0.0; cx = atm4->xorg - atm3->xorg; cy = atm4->yorg - atm3->yorg; cz = atm4->zorg - atm3->zorg; if( !cx && !cy && !cz ) return 0.0; #ifdef INVERT ay = -ay; by = -by; cy = -cy; az = -az; bz = -bz; cz = -cz; #else az = -az; bz = -bz; cz = -cz; #endif px = ay*bz - az*by; py = az*bx - ax*bz; pz = ax*by - ay*bx; qx = by*cz - bz*cy; qy = bz*cx - bx*cz; qz = bx*cy - by*cx; plen = px*px + py*py + pz*pz; qlen = qx*qx + qy*qy + qz*qz; cosom = (px*qx+py*qy+pz*qz)/sqrt(plen*qlen); if( cosom > 1.0 ) { return 0.0; } else if( cosom < -1.0 ) return 180.0; om = -Rad2Deg*acos(cosom); rx = py*qz - pz*qy; ry = pz*qx - px*qz; rz = px*qy - py*qx; if (ax*rx+ay*ry+az*rz > 0.) return -om; return om; } double CalcDihedral( Atom __far *atm1, Atom __far *atm2, Atom __far *atm3, Atom __far *atm4 ) { return( 180.0 - CalcTorsion(atm1,atm2,atm3,atm4) ); } /* Note: curr == prev->gnext! */ double CalcPhiAngle( Group __far *prev, Group __far *curr ) { Atom __far *prevc; Atom __far *currca; Atom __far *currc; Atom __far *currn; if( !(prevc = FindGroupAtom(prev,2)) ) return 360.0; if( !(currca = FindGroupAtom(curr,1)) ) return 360.0; if( !(currc = FindGroupAtom(curr,2)) ) return 360.0; if( !(currn = FindGroupAtom(curr,0)) ) return 360.0; return CalcTorsion(prevc,currn,currca,currc); } /* Note: next == curr->gnext! */ double CalcPsiAngle( Group __far *curr, Group __far *next ) { Atom __far *nextn; Atom __far *currca; Atom __far *currc; Atom __far *currn; if( !(nextn = FindGroupAtom(next,0)) ) return 360.0; if( !(currca = FindGroupAtom(curr,1)) ) return 360.0; if( !(currc = FindGroupAtom(curr,2)) ) return 360.0; if( !(currn = FindGroupAtom(curr,0)) ) return 360.0; return CalcTorsion(currn,currca,currc,nextn); } /* Note: prev == prev->gnext! */ double CalcOmegaAngle( Group __far *prev, Group __far *curr ) { Atom __far *prevc; Atom __far *prevca; Atom __far *currn; Atom __far *currca; if( !(prevca = FindGroupAtom(prev,1)) ) return 360.0; if( !(prevc = FindGroupAtom(prev,2)) ) return 360.0; if( !(currn = FindGroupAtom(curr,0)) ) return 360.0; if( !(currca = FindGroupAtom(curr,1)) ) return 360.0; return( CalcTorsion(prevca,prevc,currn,currca) ); } void InitialiseAbstree( void ) { FalseExpr.type = OpConst | OpLftVal | OpRgtVal; FalseExpr.rgt.val = FalseExpr.lft.val = 0; TrueExpr.type = OpConst | OpLftVal | OpRgtVal; TrueExpr.rgt.val = TrueExpr.lft.val = 1; QChain = (void __far*)0; QGroup = (void __far*)0; QAtom = (void __far*)0; SymbolTable = (void __far*)0; FreeEntry = (void __far*)0; FreeSet = (void __far*)0; FreeExpr = NULL; } /* returns a string with a description of the current object (atom) */ /* example: "Chain: A Group: T 20 Atom: N3 404" for select == ATM */ char *DescribeObj( AtomRef *ptr, Selection select ) { #define BS 110 #define bs 109 register char *str; static char buffer[BS]; int strucflag=' '; /* needs to be initialised with withespaces, expect the last one */ memset(buffer, ' ', bs * sizeof (char)); /* identification of 'chain' */ if( select == CHN || select == GRP || select == ATM || select == CRD){ if( ptr->chn->ident!=' ' ){ sprintf(&buffer[0], "Chain: %c", ptr->chn->ident); } buffer[8] = '\0'; } /* identification of 'group' */ if( select == GRP || select == ATM || select == CRD){ str = Residue[ptr->grp->refno]; if( ptr->atm->flag&HeteroFlag ){ strcpy(&buffer[8], " Hetero: "); } else{ strcpy(&buffer[8], " Group: "); } sprintf(&buffer[18], "%c%c%c %3d", str[0],str[1],str[2],ptr->grp->serno); if( IsAmino(ptr->grp->refno) ){ strucflag = Helix3Flag|Helix4Flag|Helix5Flag; if( ptr->grp->struc&strucflag ) strucflag = 'H'; else if( ptr->grp->struc&SheetFlag ) strucflag = 'S'; else if( ptr->grp->struc&TurnFlag ) strucflag = 'T'; else strucflag = 'C'; sprintf(&buffer[25], " (%c)", (char)strucflag); } else{ sprintf(&buffer[25], " ", (char)strucflag); } } /* identification of 'atom' */ if( select == ATM || select == CRD ){ char *eptr; str = ElemDesc[ptr->atm->refno]; strcpy(&buffer[29]," Atom: "); if ( (ptr->atm->altl == ' ') || (ptr->atm->altl == '\0') ) { sprintf(&buffer[37], "%c%c%c%c %5d ", str[0], str[1], str[2], str[3], ptr->atm->serno ); } else { sprintf(&buffer[37], "%c%c%c%c;%c %5d ", str[0], str[1], str[2], str[3] ,ptr->atm->altl, ptr->atm->serno ); } if ( ptr->atm->model ) { buffer[49] = '/'; FormatInteger(&buffer[50],(int)ptr->atm->model); } else { buffer[49] = '\0'; } eptr = buffer+strlen(buffer); if( select == CRD ){ register double x, y, z; x = (double)(ptr->atm->xorg + OrigCX)/250.0 +(double)(ptr->atm->xtrl)/10000.0; y = (double)(ptr->atm->yorg + OrigCY)/250.0 +(double)(ptr->atm->ytrl)/10000.0; z = (double)(ptr->atm->zorg + OrigCZ)/250.0 +(double)(ptr->atm->ztrl)/10000.0; #ifdef INVERT sprintf(eptr, "\n Coordinates: %9.3f %9.3f %9.3f\n",x,-y,-z); #else sprintf(eptr, "\n Coordinates: %9.3f %9.3f %9.3f\n",x,y,-z); #endif } } buffer[bs] = '\0'; /* to be sure to terminate the string */ return buffer; }