home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Educational / RasMol / Source / repres.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-10  |  39.3 KB  |  1,338 lines

  1. /* repres.c
  2.  * RasMol2 Molecular Graphics
  3.  * Roger Sayle, August 1995
  4.  * Version 2.6
  5.  */
  6. #include "rasmol.h"
  7.  
  8. #ifdef IBMPC
  9. #include <windows.h>
  10. #include <malloc.h>
  11. #endif
  12. #ifdef APPLEMAC
  13. #include <Types.h>
  14. #include <Errors.h>
  15. #ifdef __CONDITIONALMACROS__
  16. #include <Printing.h>
  17. #else
  18. #include <PrintTraps.h>
  19. #endif
  20. #endif
  21. #ifndef sun386
  22. #include <stdlib.h>
  23. #endif
  24.  
  25. #include <string.h>
  26. #include <ctype.h>
  27. #include <stdio.h>
  28. #include <math.h>
  29.  
  30. #define REPRES
  31. #include "molecule.h"
  32. #include "graphics.h"
  33. #include "repres.h"
  34. #include "render.h"
  35. #include "command.h"
  36. #include "abstree.h"
  37. #include "transfor.h"
  38. #include "pixutils.h"
  39.  
  40.  
  41. typedef struct { int dx, dy, dz; } DotVector;
  42. typedef struct {
  43.         DotVector __far *probe;
  44.         DotVector __far *dots;
  45.         int count;
  46.     } ElemDotStruct;
  47.  
  48.  
  49. static ElemDotStruct __far *ElemDots;
  50. static Atom __far *Exclude;
  51. static Monitor *FreeMonit;
  52. static Label *FreeLabel;
  53.  
  54.  
  55.  
  56. #define ForEachAtom  for(chain=Database->clist;chain;chain=chain->cnext) \
  57.                      for(group=chain->glist;group;group=group->gnext)    \
  58.                      for(aptr=group->alist;aptr;aptr=aptr->anext)
  59. #define ForEachBond  for(bptr=Database->blist;bptr;bptr=bptr->bnext)
  60. #define ForEachBack  for(chain=Database->clist;chain;chain=chain->cnext) \
  61.                      for(bptr=chain->blist;bptr;bptr=bptr->bnext)
  62.  
  63.  
  64. static void FatalRepresError(ptr)
  65.     char *ptr;
  66. {
  67.     char buffer[80];
  68.  
  69.     sprintf(buffer,"Renderer Error: Unable to allocate %s!",ptr);
  70.     RasMolFatalExit(buffer);
  71. }
  72.  
  73.  
  74. /*============================*/
  75. /*  Label Handling Functions  */
  76. /*============================*/
  77.  
  78.  
  79. static void ResetLabels()
  80. {
  81.     register Label *ptr;
  82.  
  83.     while( LabelList )
  84.     {   ptr = LabelList;
  85.         LabelList = ptr->next;
  86.         ptr->next = FreeLabel;
  87.         free(ptr->label);
  88.         FreeLabel = ptr;
  89.     }
  90. }
  91.  
  92.  
  93. void DeleteLabel( label )
  94.     Label *label;
  95. {
  96.     register Label **ptr;
  97.  
  98.     if( label->refcount == 1 )
  99.     {   ptr = &LabelList;
  100.         while( *ptr != label )
  101.         ptr = &(*ptr)->next;
  102.  
  103.         *ptr = label->next;
  104.         label->next = FreeLabel;
  105.         free(label->label);
  106.         FreeLabel = label;
  107.     } else label->refcount--;
  108. }
  109.  
  110.  
  111. int DeleteLabels()
  112. {
  113.     register Chain __far *chain;
  114.     register Group __far *group;
  115.     register Atom __far *aptr;
  116.     register int result;
  117.  
  118.     if( !Database )
  119.         return( True );
  120.  
  121.     result = True;
  122.  
  123.     ForEachAtom
  124.         if( aptr->flag & SelectFlag )
  125.         {   if( aptr->label )
  126.             {   DeleteLabel( (Label*)aptr->label );
  127.                 aptr->label = (void*)0;
  128.             }
  129.             result = False;
  130.         }
  131.     DrawLabels = LabelList? True : False;
  132.     return( result );
  133. }
  134.  
  135.  
  136. Label *CreateLabel( text, len )
  137.     char *text;  int len;
  138. {
  139.     register Label *ptr;
  140.  
  141.     /* Test for existing label */
  142.     for( ptr=LabelList; ptr; ptr=ptr->next )
  143.         if( !strcmp(ptr->label,text) )
  144.             return( ptr );
  145.  
  146.     if( FreeLabel )
  147.     {   ptr = FreeLabel;  FreeLabel = ptr->next;
  148.     } else if( !(ptr=(Label*)malloc(sizeof(Label))) )
  149.         FatalRepresError("label");
  150.  
  151.     ptr->label = (char*)malloc(len+1);
  152.     if( !ptr->label ) FatalRepresError("label");
  153.     strcpy(ptr->label,text);
  154.  
  155.     ptr->next = LabelList;
  156.     ptr->refcount = 0;
  157.     LabelList = ptr;
  158.     return( ptr );
  159. }
  160.  
  161.  
  162. void DefineLabels( label )
  163.     char *label;
  164. {
  165.     register Chain __far *chain;
  166.     register Group __far *group;
  167.     register Atom __far *aptr;
  168.     register Label *ptr;
  169.     register char *cptr;
  170.     register int len;
  171.  
  172.  
  173.     if( !Database ) return;
  174.     if( DeleteLabels() )
  175.         return;
  176.  
  177.     len = 0;
  178.     for( cptr=label; *cptr; cptr++ )
  179.         len++;
  180.  
  181.     /* Strip trailing spaces */
  182.     while( len && cptr[-1]==' ' )
  183.     {   cptr--;  len--;
  184.         *cptr = '\0';
  185.     }
  186.  
  187.     if( !len )
  188.         return;
  189.  
  190.     ptr = CreateLabel(label,len);
  191.     DrawLabels = True;
  192.  
  193.     ForEachAtom
  194.         if( aptr->flag & SelectFlag )
  195.         {   aptr->label = ptr;
  196.             ptr->refcount++;
  197.         }
  198. }
  199.  
  200.  
  201. void DefaultLabels( enable )
  202.     int enable;
  203. {
  204.     register Chain __far *chain;
  205.     register Group __far *group;
  206.     register Atom __far *aptr;
  207.     register Label *label1;
  208.     register Label *label2;
  209.  
  210.     if( !Database )
  211.         return;
  212.  
  213.     label1 = (Label*)0;
  214.     label2 = (Label*)0;
  215.  
  216.     if( MainGroupCount > 1 )
  217.     {   ForEachAtom
  218.             if( IsAlphaCarbon(aptr->refno) || IsSugarPhosphate(aptr->refno) )
  219.             {   if( aptr->flag & SelectFlag )
  220.                 {   if( enable )
  221.                     {   if( InfoChainCount > 1 )
  222.                         {   if( isdigit(chain->ident) )
  223.                             {   if( !label1 )
  224.                                     label1 = CreateLabel("%n%r:%c",7);
  225.                                 aptr->label = label1;
  226.                                 label1->refcount++;
  227.                             } else
  228.                             {   if( !label2 )
  229.                                     label2 = CreateLabel("%n%r%c",6);
  230.                                 aptr->label = label2;
  231.                                 label2->refcount++;
  232.                             }
  233.                         } else
  234.                         {   if( !label1 )
  235.                                 label1 = CreateLabel("%n%r",4);
  236.                             aptr->label = label1;
  237.                             label1->refcount++;
  238.                         }
  239.                     } else if( aptr->label )
  240.                     {   DeleteLabel( (Label*)aptr->label );
  241.                         aptr->label = (Label*)0;
  242.                     }
  243.                     ReDrawFlag |= RFRefresh;
  244.                 }
  245.                 break;
  246.             }
  247.  
  248.     } else /* Small Molecule! */
  249.         ForEachAtom
  250.             if( (aptr->flag&SelectFlag) && (aptr->elemno!=6)
  251.                                         && (aptr->elemno!=1) )
  252.             {   if( enable )
  253.                 {   if( !label1 )
  254.                         label1 = CreateLabel("%e",2);
  255.                     aptr->label = label1;
  256.                     label1->refcount++;
  257.                 } else if( aptr->label )
  258.                 {   DeleteLabel( (Label*)aptr->label );
  259.                     aptr->label = (Label*)0;
  260.                 }
  261.                 ReDrawFlag |= RFRefresh;
  262.             }
  263.  
  264.     DrawLabels = LabelList? True : False;
  265. }
  266.  
  267.  
  268. void DisplayLabels()
  269. {
  270.     register Chain __far *chain;
  271.     register Group __far *group;
  272.     register Atom __far *aptr;
  273.     register Label *label;
  274.     register int col,z;
  275.  
  276.     auto char buffer[256];
  277.  
  278.  
  279.     if( !Database )
  280.         return;
  281.  
  282.     if( !UseSlabPlane )
  283.     {   z = ImageRadius + ZOffset;
  284.     } else z = SlabValue - 1;
  285.  
  286.     ForEachAtom
  287.         if( aptr->label )
  288.         {   /* Peform Label Slabbing! */
  289.             if( !ZValid(aptr->z) )
  290.                 continue;
  291.  
  292.             label = (Label*)aptr->label;
  293.             FormatLabel(chain,group,aptr,label->label,buffer);
  294.  
  295.             if( !UseLabelCol )
  296.             {   /* Depth-cue atom labels */
  297.                 /* col = aptr->col + (ColorDepth*                  */
  298.                 /*       (aptr->z+ImageRadius-ZOffset))/ImageSize; */
  299.                 col = aptr->col + (ColourMask>>1);
  300.             } else col = LabelCol;
  301.  
  302.             /* (aptr->z+2) + ((aptr->flag & SphereFlag)?aptr->irad:0); */
  303.             DisplayString(aptr->x+4,aptr->y,z,buffer,col);
  304.         }
  305. }
  306.  
  307.  
  308. /*==============================*/
  309. /*  Monitor Handling Functions  */
  310. /*==============================*/
  311.  
  312. #ifdef FUNCPROTO
  313. /* Function Prototype */
  314. void AddMonitors( Atom __far*, Atom __far* );
  315. #endif
  316.  
  317. void DeleteMonitors()
  318. {
  319.     register Monitor *ptr;
  320.  
  321.     while( MonitList )
  322.     {   ptr = MonitList;
  323.         if( ptr->col )
  324.             Shade[Colour2Shade(ptr->col)].refcount--;
  325.  
  326.         MonitList = ptr->next;
  327.         ptr->next = FreeMonit;
  328.         FreeMonit = ptr;
  329.     }
  330. }
  331.  
  332.  
  333. void AddMonitors( src, dst )
  334.     Atom __far *src, __far *dst;
  335. {
  336.     register Monitor **prev;
  337.     register Monitor *ptr;
  338.     register Long dx,dy,dz;
  339.     register Long dist;
  340.  
  341.     /* Delete an already existing monitor! */
  342.     for( prev=&MonitList; (ptr=*prev); prev=&ptr->next )
  343.          if( ((ptr->src==src) && (ptr->dst==dst)) ||
  344.              ((ptr->src==dst) && (ptr->dst==src)) )
  345.          {   if( ptr->col )
  346.                  Shade[Colour2Shade(ptr->col)].refcount--;
  347.  
  348.              *prev = ptr->next;
  349.              ptr->next = FreeMonit;
  350.              FreeMonit = ptr;
  351.              return;
  352.          }
  353.  
  354.  
  355.     /* Create a new monitor! */
  356.     if( FreeMonit )
  357.     {   ptr = FreeMonit;  FreeMonit = ptr->next;
  358.     } else if( !(ptr=(Monitor*)malloc(sizeof(Monitor))) )
  359.         FatalRepresError("monitor");
  360.  
  361.     dx = src->xorg - dst->xorg;
  362.     dy = src->yorg - dst->yorg;
  363.     dz = src->zorg - dst->zorg;
  364.  
  365.     /* ptr->dist = 100.0*CalcDistance(src,dst) */
  366.     dist = isqrt( dx*dx + dy*dy + dz*dz );
  367.     ptr->dist = (unsigned short)((dist<<1)/5);
  368.  
  369.     ptr->src = src;
  370.     ptr->dst = dst;
  371.     ptr->col = 0;
  372.  
  373.     ptr->next = MonitList;
  374.     MonitList = ptr;
  375. }
  376.  
  377.  
  378. void CreateMonitor( src, dst )
  379.     Long src, dst;
  380. {
  381.     register Chain __far *chain;
  382.     register Group __far *group;
  383.     register Atom __far *aptr;
  384.     register Atom __far *sptr;
  385.     register Atom __far *dptr;
  386.     register int done;
  387.     char buffer[20];
  388.  
  389.     if( src == dst )
  390.     {   if( !CommandActive )
  391.             WriteChar('\n');
  392.         WriteString("Error: Duplicate atom serial numbers!\n");
  393.         CommandActive = False;
  394.         return;
  395.     }
  396.  
  397.     done = False;
  398.     sptr = (Atom __far*)0;
  399.     dptr = (Atom __far*)0;
  400.  
  401.     for( chain=Database->clist; chain && !done; chain=chain->cnext )
  402.         for( group=chain->glist; group && !done; group=group->gnext )
  403.             for( aptr=group->alist; aptr; aptr=aptr->anext )
  404.             {   if( aptr->serno == src )
  405.                 {   sptr = aptr;
  406.                     if( dptr )
  407.                     {   done = True;
  408.                         break;
  409.                     }
  410.                 } else if( aptr->serno == dst )
  411.                 {   dptr = aptr;
  412.                     if( sptr )
  413.                     {   done = True;
  414.                         break;
  415.                     }
  416.                 }
  417.             }
  418.  
  419.     if( !done )
  420.     {   if( !CommandActive )
  421.             WriteChar('\n');
  422.         WriteString("Error: Atom serial number");
  423.         if( sptr )
  424.         {   sprintf(buffer," %d",dst);
  425.         } else if( dptr )
  426.         {   sprintf(buffer," %d",src);
  427.         } else sprintf(buffer,"s %d and %d",src,dst);
  428.         WriteString(buffer); WriteString(" not found!\n");
  429.         CommandActive = False;
  430.  
  431.     } else AddMonitors( sptr, dptr );
  432. }
  433.  
  434.  
  435. void DisplayMonitors()
  436. {
  437.     register Atom __far *s;
  438.     register Atom __far *d;
  439.     register Monitor *ptr;
  440.     register int x,y,z;
  441.     register int sc,dc;
  442.     register int col;
  443.  
  444.     register char *cptr;
  445.     register int dist;
  446.     char buffer[10];
  447.  
  448.     if( !Database )
  449.         return;
  450.  
  451.     if( !UseSlabPlane )
  452.     {   z = ImageRadius + ZOffset;
  453.     } else z = SlabValue-1;
  454.     buffer[9] = '\0';
  455.     buffer[6] = '.';
  456.  
  457.     for( ptr=MonitList; ptr; ptr=ptr->next )
  458.     {   s = ptr->src;
  459.         d = ptr->dst;
  460.  
  461.         if( !ptr->col )
  462.         {   sc = s->col;
  463.             dc = d->col;
  464.         } else sc = dc = ptr->col;
  465.  
  466.         ClipDashVector(s->x,s->y,s->z,d->x,d->y,d->z,sc,dc);
  467.  
  468.         if( DrawMonitDistance )
  469.             if( ZValid( (s->z+d->z)/2 ) )
  470.             {   x = (s->x+d->x)/2;
  471.                 y = (s->y+d->y)/2;
  472.  
  473.                 if( !UseLabelCol )
  474.                 {   /* Use Source atom colour! */
  475.                     col = sc + (ColourMask>>1);
  476.                 } else col = LabelCol;
  477.  
  478.                 dist = ptr->dist;
  479.                 buffer[8] = (dist%10)+'0';  dist /= 10;
  480.                 buffer[7] = (dist%10)+'0';
  481.                 cptr = &buffer[5];
  482.  
  483.                 if( dist > 9 )
  484.                 {   do {
  485.                        dist /= 10;
  486.                        *cptr-- = (dist%10)+'0';
  487.                     } while( dist > 9 );
  488.                     cptr++;
  489.                 } else *cptr = '0';
  490.  
  491.                 DisplayString(x+4,y,z,cptr,col);
  492.             }
  493.     }
  494. }
  495.  
  496.  
  497. /*=========================*/
  498. /*  Dot Surface Functions  */
  499. /*=========================*/
  500.  
  501. #ifdef FUNCPROTO
  502. /* Function Prototype */
  503. static void AddDot( Long, Long, Long, int );
  504. static void CheckVDWDot( Long, Long, Long, int );
  505. static int TestSolventDot( Long, Long, Long );
  506. #endif
  507.  
  508.  
  509. void DeleteSurface()
  510. {
  511.     register DotStruct __far *ptr;
  512.     register int shade;
  513.     register int i;
  514.  
  515.     while( DotPtr )
  516.     {   for( i=0; i<DotPtr->count; i++ )
  517.         {   shade = Colour2Shade(DotPtr->col[i]);
  518.             Shade[shade].refcount--;
  519.         }
  520.  
  521.         ptr = DotPtr->next;
  522.         _ffree( DotPtr );
  523.         DotPtr = ptr;
  524.     }
  525.     DrawDots = False;
  526. }
  527.  
  528.  
  529. static void AddDot( x, y, z, col )
  530.     Long x, y, z; int col;
  531. {
  532.     register DotStruct __far *ptr;
  533.     register int i, shade;
  534.  
  535.     if( !DotPtr || (DotPtr->count==DotMax) )
  536.     {   ptr = (DotStruct __far*)_fmalloc(sizeof(DotStruct));
  537.         if( !ptr ) FatalRepresError("dot surface");
  538.  
  539.         ptr->next = DotPtr;
  540.         ptr->count = 0;
  541.         DotPtr = ptr;
  542.     } else ptr = DotPtr;
  543.  
  544.     shade = Colour2Shade(col);
  545.     Shade[shade].refcount++;
  546.  
  547.     i = ptr->count++;
  548.     ptr->col[i] = col;
  549.     ptr->xpos[i] = x;
  550.     ptr->ypos[i] = y;
  551.     ptr->zpos[i] = z;
  552.     DrawDots = True;
  553. }
  554.  
  555.  
  556. static void CheckVDWDot( x, y, z, col )
  557.     Long x, y, z; int col;
  558. {
  559.     register Item __far *item;
  560.     register Atom __far *aptr;
  561.     register int ix,iy,iz;
  562.     register int dx,dy,dz;
  563.     register Long dist;
  564.     register Long rad;
  565.     register int i;
  566.  
  567.  
  568.     ix = (int)((x+Offset)*IVoxRatio);
  569.     iy = (int)((y+Offset)*IVoxRatio);
  570.     iz = (int)((z+Offset)*IVoxRatio);
  571.  
  572.     i = VOXORDER2*ix + VOXORDER*iy + iz;
  573.     for( item=HashTable[i]; item; item=item->list )
  574.         if( item->data != Exclude )
  575.         {   aptr = item->data;
  576.             if( !ProbeRadius )
  577.             {   rad = ElemVDWRadius(aptr->elemno);
  578.             } else rad = ProbeRadius;
  579.             rad = rad*rad;
  580.  
  581.             /* Optimized Test! */
  582.             dx = (int)(aptr->xorg - x);
  583.             if( (dist=(Long)dx*dx) < rad )
  584.             {   dy = (int)(aptr->yorg - y);
  585.                 if( (dist+=(Long)dy*dy) < rad )
  586.                 {   dz = (int)(aptr->zorg - z);
  587.                     if( (dist+=(Long)dz*dz) < rad )
  588.                         return;
  589.                 }
  590.             }
  591.         }
  592.     AddDot( x, y, z, col );
  593. }
  594.  
  595.  
  596. static int TestSolventDot( x, y, z )
  597.     Long x, y, z;
  598. {
  599.     register Item __far *item;
  600.     register Atom __far *aptr;
  601.     register int lx,ly,lz;
  602.     register int hx,hy,hz;
  603.     register int dx,dy,dz;
  604.     register int ix,iy,iz;
  605.     register Long dist;
  606.     register Long rad;
  607.     register int i;
  608.  
  609.     dist = Offset-ProbeRadius;
  610.     lx = (int)((x+dist)*IVoxRatio);
  611.     if( lx >= VOXORDER ) return( True );
  612.     ly = (int)((y+dist)*IVoxRatio);
  613.     if( ly >= VOXORDER ) return( True );
  614.     lz = (int)((z+dist)*IVoxRatio);
  615.     if( lz >= VOXORDER ) return( True );
  616.  
  617.     dist = Offset+ProbeRadius;
  618.     hx = (int)((x+dist)*IVoxRatio);
  619.     if( hx < 0 ) return( True );
  620.     hy = (int)((y+dist)*IVoxRatio);
  621.     if( hy < 0 ) return( True );
  622.     hz = (int)((z+dist)*IVoxRatio);
  623.     if( hz < 0 ) return( True );
  624.  
  625.     if( lx < 0 ) lx = 0;  if( hx >= VOXORDER ) hx = VOXORDER-1;
  626.     if( ly < 0 ) ly = 0;  if( hy >= VOXORDER ) hy = VOXORDER-1;
  627.     if( lz < 0 ) lz = 0;  if( hz >= VOXORDER ) hz = VOXORDER-1;
  628.  
  629.     for( ix=lx; ix<=hx; ix++ )
  630.        for( iy=ly; iy<=hy; iy++ )
  631.           for( iz=lz; iz<=hz; iz++ )
  632.           {   i = VOXORDER2*ix + VOXORDER*iy + iz;
  633.               for( item=HashTable[i]; item; item=item->list )
  634.                   if( item->data != Exclude )
  635.                   {   aptr = item->data;
  636.                       rad = ElemVDWRadius(aptr->elemno);
  637.                       rad = (rad+ProbeRadius)*(rad+ProbeRadius);
  638.  
  639.                       /* Optimized Test! */
  640.                       dx = (int)(aptr->xorg - x);
  641.                       if( (dist=(Long)dx*dx) < rad )
  642.                       {   dy = (int)(aptr->yorg - y);
  643.                           if( (dist+=(Long)dy*dy) < rad )
  644.                           {   dz = (int)(aptr->zorg - z);
  645.                               if( (dist+=(Long)dz*dz) < rad )
  646.                                   return( False );
  647.                           }
  648.                       }
  649.                   }
  650.           }
  651.     return( True );
  652. }
  653.  
  654.  
  655. static void InitElemDots()
  656. {
  657.     register int i,size;
  658.  
  659.     size = MAXELEMNO*sizeof(ElemDotStruct);
  660.     ElemDots = (ElemDotStruct __far*)_fmalloc(size);
  661.     if( !ElemDots ) FatalRepresError("dot vector table");
  662.  
  663.     for( i=0; i<MAXELEMNO; i++ )
  664.         ElemDots[i].count = 0;
  665. }
  666.  
  667.  
  668. static void AddElemDots( elem, density )
  669.     int elem, density;
  670. {
  671.     register DotVector __far *ptr;
  672.     register DotVector __far *probe;
  673.     register Real x, y, z, p, q, xy;
  674.     register int equat,vert,horz;
  675.     register int rad,count;
  676.     register int i,j,k;
  677.     register int temp;
  678.  
  679.  
  680.     if( SolventDots || !ProbeRadius )
  681.     {   rad = ElemVDWRadius(elem);
  682.     } else rad = ProbeRadius;
  683.  
  684.     count = (int)(((Long)density*rad*rad)/((Long)250*250));
  685.     ptr = (DotVector __far*)_fmalloc(count*sizeof(DotVector));
  686.     if( !ptr ) FatalRepresError("dot vectors");
  687.  
  688.     if( SolventDots )
  689.     {   probe = (DotVector __far*)_fmalloc(count*sizeof(DotVector));
  690.         if( !probe ) FatalRepresError("probe vectors");
  691.         temp = rad + ProbeRadius;
  692.     } else probe = NULL;
  693.  
  694.     equat = (int)sqrt(PI*count);
  695.     if( !(vert=equat>>1) )
  696.         vert = 1;
  697.  
  698.     i = 0;
  699.     for( j=0; (i<count) && (j<vert); j++ )
  700.     {   p = (PI*j)/(Real)vert;
  701.         z = cos(p);  xy = sin(p);
  702.         horz = (int)(equat*xy);
  703.         if( !horz ) horz = 1;
  704.  
  705.         for( k=0; (i<count) && (k<horz); k++ )
  706.         {   q = (2.0*PI*k)/(Real)horz;
  707.             x = xy*sin(q);
  708.             y = xy*cos(q);
  709.  
  710.             ptr[i].dx = (int)(rad*x);
  711.             ptr[i].dy = (int)(rad*y);
  712.             ptr[i].dz = (int)(rad*z);
  713.             if( probe )
  714.             {   probe[i].dx = (int)(temp*x);
  715.                 probe[i].dy = (int)(temp*y);
  716.                 probe[i].dz = (int)(temp*z);
  717.             }
  718.             i++;
  719.         }
  720.     }
  721.     ElemDots[elem].probe = probe;
  722.     ElemDots[elem].dots = ptr;
  723.     ElemDots[elem].count = i;
  724. }
  725.  
  726.  
  727. static void FreeElemDots()
  728. {
  729.     register int i;
  730.  
  731.     for( i=0; i<MAXELEMNO; i++ )
  732.         if( ElemDots[i].count )
  733.             _ffree( ElemDots[i].dots );
  734.     _ffree( ElemDots );
  735. }
  736.  
  737.  
  738. void CalculateSurface( density )
  739.     int density;
  740. {
  741.     register DotVector __far *probe;
  742.     register DotVector __far *ptr;
  743.     register Chain __far *chain;
  744.     register Group __far *group;
  745.     register Atom __far *aptr;
  746.     register int i,count;
  747.     register int elem;
  748.  
  749.     if( !Database )
  750.         return;
  751.  
  752.     DeleteSurface();
  753.     ResetVoxelData();
  754.  
  755.     InitElemDots();
  756.     CreateVoxelData( AllAtomFlag );
  757.     VoxelsClean = False;
  758.  
  759.     ForEachAtom
  760.         if( aptr->flag & SelectFlag )
  761.         {   elem = aptr->elemno;
  762.             if( !ElemDots[elem].count )
  763.                 AddElemDots(elem,density);
  764.  
  765.             Exclude = aptr;
  766.             ptr = ElemDots[elem].dots;
  767.             probe = ElemDots[elem].probe;
  768.             count = ElemDots[elem].count;
  769.             if( SolventDots )
  770.             {   for( i=0; i<count; i++ )
  771.                     if( TestSolventDot( aptr->xorg + probe[i].dx,
  772.                                         aptr->yorg + probe[i].dy,
  773.                                         aptr->zorg + probe[i].dz ) )
  774.                         AddDot( aptr->xorg + ptr[i].dx,
  775.                                 aptr->yorg + ptr[i].dy,
  776.                                 aptr->zorg + ptr[i].dz,
  777.                                 aptr->col );
  778.             } else
  779.                 for( i=0; i<count; i++ )
  780.                     CheckVDWDot( aptr->xorg + ptr[i].dx,
  781.                                  aptr->yorg + ptr[i].dy,
  782.                                  aptr->zorg + ptr[i].dz,
  783.                                  aptr->col);
  784.         }
  785.  
  786.     FreeElemDots();
  787. }
  788.  
  789.  
  790. void DisplaySurface()
  791. {
  792.     register DotStruct __far *ptr;
  793.     register int xi,yi,zi;
  794.     register Real x,y,z;
  795.     register int i;
  796.  
  797.     for( ptr=DotPtr; ptr; ptr=ptr->next )
  798.         for( i=0; i<ptr->count; i++ )
  799.         {   x = ptr->xpos[i];
  800.             y = ptr->ypos[i];
  801.             z = ptr->zpos[i];
  802.  
  803.             xi = (int)(x*MatX[0]+y*MatX[1]+z*MatX[2])+XOffset;
  804.             if( XValid(xi) )
  805.             {   yi = (int)(x*MatY[0]+y*MatY[1]+z*MatY[2])+YOffset;
  806.                 if( YValid(yi) )
  807.                 {   zi = (int)(x*MatZ[0]+y*MatZ[1]+z*MatZ[2])+ZOffset;
  808.                     if( ZValid(zi) )
  809.                         PlotDeepPoint(xi,yi,zi,ptr->col[i]);
  810.                 }
  811.             }
  812.         }
  813. }
  814.  
  815.  
  816. /*==============================*/
  817. /*  Ribbon & Cartoon Functions  */
  818. /*==============================*/
  819.  
  820.  
  821. static void CalculateVInten( ptr )
  822.     Knot *ptr;
  823. {
  824.     register Real inten;
  825.  
  826.     if( !ptr->vsize )
  827.         ptr->vsize = isqrt( (Long)ptr->vnx*ptr->vnx +
  828.                             (Long)ptr->vny*ptr->vny +
  829.                             (Long)ptr->vnz*ptr->vnz ) + 1;
  830.  
  831. #ifdef ORIGINAL
  832. #ifdef INVERT
  833.     inten = ptr->vnx - ptr->vny + ptr->vnz + ptr->vnz;
  834. #else
  835.     inten = ptr->vnx + ptr->vny + ptr->vnz + ptr->vnz;
  836. #endif
  837.     inten /= ptr->vsize*RootSix;
  838. #else
  839.     inten = (Real)ptr->vnz/ptr->vsize;
  840. #endif
  841.  
  842.     if( ptr->vnz < 0 ) inten = -inten;
  843.  
  844.     if( inten > 0.0 )
  845.     {   ptr->vinten = (char)(ColourMask*inten);
  846.     } else ptr->vinten = 0;
  847. }
  848.  
  849.  
  850. static void CalculateHInten( ptr )
  851.     Knot *ptr;
  852. {
  853.     register Real inten;
  854.  
  855.     /* The intensity of the sides of a protein cartoon
  856.      * may be calculated using ptr->cx,cy,cz and this
  857.      * should save interpolating ptr->hnx,hny,hnz!
  858.      */
  859.  
  860.     if( !ptr->hsize )
  861.         ptr->hsize = isqrt( (Long)ptr->hnx*ptr->hnx +
  862.                             (Long)ptr->hny*ptr->hny +
  863.                             (Long)ptr->hnz*ptr->hnz ) + 1;
  864.  
  865. #ifdef ORIGINAL
  866. #ifdef INVERT
  867.     inten = ptr->hnx - ptr->hny + ptr->hnz + ptr->hnz;
  868. #else
  869.     inten = ptr->hnx + ptr->hny + ptr->hnz + ptr->hnz;
  870. #endif
  871.     inten /= ptr->hsize*RootSix;
  872. #else
  873.     inten = (Real)ptr->hnz / ptr->hsize;
  874. #endif
  875.     if( ptr->hnz < 0 ) inten = -inten;
  876.  
  877.     if( inten > 0.0 )
  878.     {   ptr->hinten = (char)(ColourMask*inten);
  879.     } else ptr->hinten = 0;
  880. }
  881.  
  882.  
  883. void DisplayRibbon( chain )
  884.     Chain  __far *chain;
  885. {
  886.     register Group __far *group;
  887.     register Atom __far *captr;
  888.     register Atom __far *o1ptr;
  889.     register Atom __far *o2ptr;
  890.     register Atom __far *next;
  891.  
  892.     register int prev,wide;
  893.     register int col1,col2;
  894.     register int bx,by,bz;
  895.     register int dx,dy,dz;
  896.     register int arrow;
  897.     register int size;
  898.  
  899.     static Knot mid1, mid2, mid3;
  900.     static Knot knot1, knot2;
  901.  
  902.     prev = False;
  903.     group = chain->glist;
  904.     if( IsAmino(group->refno) )
  905.     {   captr = FindGroupAtom(group,1);
  906.     } else captr = FindGroupAtom(group,7);
  907.  
  908.     while( group->gnext )
  909.     {   if( IsAmino(group->gnext->refno) )
  910.         {   next = FindGroupAtom(group->gnext,1);
  911.             o1ptr = FindGroupAtom(group,3);
  912.         } else /* Nucleic Acid */
  913.         {   next = FindGroupAtom(group->gnext,7);
  914.             o1ptr = FindGroupAtom(group->gnext,10);
  915.         }
  916.  
  917.         /* When not to have a control point! */
  918.         if( !next || !captr || !o1ptr || (next->flag&BreakFlag) ||
  919.             !((group->flag|group->gnext->flag)&DrawKnotFlag) )
  920.         {   group = group->gnext;
  921.             captr = next;
  922.             prev = False;
  923.             continue;
  924.         }
  925.  
  926.         knot2.tx = next->x - captr->x;
  927.         knot2.ty = next->y - captr->y;
  928.         knot2.tz = next->z - captr->z;
  929.  
  930.         if( IsAmino(group->refno) )
  931.         {   bx = o1ptr->x - captr->x;
  932.             by = o1ptr->y - captr->y;
  933.             bz = o1ptr->z - captr->z;
  934.  
  935.         } else if( !FindGroupAtom(group,17) &&
  936.                    (o2ptr=FindGroupAtom(group,8)) )
  937.         {   /* Deoxyribonucleic Acid */
  938.             o2ptr = FindGroupAtom(group,8);
  939.             bx = (o1ptr->x + o2ptr->x)/2 - captr->x;
  940.             by = (o1ptr->y + o2ptr->y)/2 - captr->y;
  941.             bz = (o1ptr->z + o2ptr->z)/2 - captr->z;
  942.  
  943.         } else /* Ribonucleic Acid */
  944.         {   bx = o1ptr->x - captr->x;
  945.             by = o1ptr->y - captr->y;
  946.             bz = o1ptr->z - captr->z;
  947.         }
  948.  
  949.         knot2.px = (captr->x + next->x)/2;
  950.         knot2.py = (captr->y + next->y)/2;
  951.         knot2.pz = (captr->z + next->z)/2;
  952.  
  953.         /* c := a x b */
  954.         knot2.vnx = knot2.ty*bz - knot2.tz*by;
  955.         knot2.vny = knot2.tz*bx - knot2.tx*bz;
  956.         knot2.vnz = knot2.tx*by - knot2.ty*bx;
  957.  
  958.         if( (group->struc&group->gnext->struc) & HelixFlag )
  959.         {   /* Compensate for narrowing of helices! */
  960.             size = isqrt((Long)knot2.vnx*knot2.vnx +
  961.                          (Long)knot2.vny*knot2.vny +
  962.                          (Long)knot2.vnz*knot2.vnz);
  963.             knot2.vsize = size;
  964.  
  965.             if( size )
  966.             {   /* 1.00 Angstrom Displacement */
  967.                 wide = (int)(250*Scale);
  968. #ifdef INVERT
  969.                 knot2.px += (int)(((Long)wide*knot2.vnx)/size);
  970.                 knot2.py += (int)(((Long)wide*knot2.vny)/size);
  971.                 knot2.pz += (int)(((Long)wide*knot2.vnz)/size);
  972. #else
  973.                 knot2.px -= (int)(((Long)wide*knot2.vnx)/size);
  974.                 knot2.py -= (int)(((Long)wide*knot2.vny)/size);
  975.                 knot2.pz -= (int)(((Long)wide*knot2.vnz)/size);
  976. #endif
  977.             }
  978.         } else knot2.vsize = 0;
  979.  
  980.         if( !(group->flag&group->gnext->flag&TraceFlag) )
  981.         {   /* d := c x a */
  982.             dx = (int)(((Long)knot2.vny*knot2.tz -
  983.                         (Long)knot2.vnz*knot2.ty)/96);
  984.             dy = (int)(((Long)knot2.vnz*knot2.tx -
  985.                         (Long)knot2.vnx*knot2.tz)/96);
  986.             dz = (int)(((Long)knot2.vnx*knot2.ty -
  987.                         (Long)knot2.vny*knot2.tx)/96);
  988.  
  989.             knot2.hsize = isqrt((Long)dx*dx + (Long)dy*dy + (Long)dz*dz);
  990.  
  991.             /* Handle Carbonyl Oxygen Flip */
  992.             if( prev && (((Long)knot1.hnx*dx +
  993.                           (Long)knot1.hny*dy +
  994.                           (Long)knot1.hnz*dz)<0) )
  995.             {   knot2.hnx = -dx;   knot2.vnx = -knot2.vnx;
  996.                 knot2.hny = -dy;   knot2.vny = -knot2.vny;
  997.                 knot2.hnz = -dz;   knot2.vnz = -knot2.vnz;
  998.             } else
  999.             {   knot2.hnx = dx;
  1000.                 knot2.hny = dy;
  1001.                 knot2.hnz = dz;
  1002.             }
  1003.  
  1004.             arrow = False;
  1005.             if( group->flag&CartoonFlag )
  1006.             {   if( DrawBetaArrows && (group->struc&SheetFlag) &&
  1007.                     !(group->gnext->struc&SheetFlag) )
  1008.                 {   wide = (3*group->width)>>1;
  1009.                     arrow = True;
  1010.                 } else wide = group->width;
  1011.             } else if( group->flag & WideKnotFlag )
  1012.             {   /* Average Ribbon Width */
  1013.                 if( group->gnext->flag & WideKnotFlag )
  1014.                 {   wide = (group->width+group->gnext->width)>>1;
  1015.                 } else if( group->gnext->flag & CartoonFlag )
  1016.                 {   wide = group->gnext->width;
  1017.                 } else wide = group->width;
  1018.             } else wide = group->gnext->width;
  1019.  
  1020.             /* Set Ribbon Width */
  1021.             wide = (int)(wide*Scale);
  1022.  
  1023.             if( knot2.hsize && !arrow )
  1024.             {   size = knot2.hsize;
  1025.                 knot2.wx = (int)(((Long)wide*knot2.hnx)/size);
  1026.                 knot2.wy = (int)(((Long)wide*knot2.hny)/size);
  1027.                 knot2.wz = (int)(((Long)wide*knot2.hnz)/size);
  1028.                 knot2.wide = (short)wide;
  1029.             } else
  1030.             {   knot2.wide = 0;
  1031.                 knot2.wx = 0;
  1032.                 knot2.wy = 0;
  1033.                 knot2.wz = 0;
  1034.             }
  1035.  
  1036.             if( group->flag & CartoonFlag )
  1037.                 if( prev && (knot1.wide!=wide) && knot1.hsize )
  1038.                 {   size = knot1.hsize;
  1039.                     knot1.wx = (int)(((Long)wide*knot1.hnx)/size);
  1040.                     knot1.wy = (int)(((Long)wide*knot1.hny)/size);
  1041.                     knot1.wz = (int)(((Long)wide*knot1.hnz)/size);
  1042.                 }
  1043.  
  1044.             if( (group->flag|group->gnext->flag)&CartoonFlag )
  1045.             {   CalculateVInten( &knot2 );
  1046.                 CalculateHInten( &knot2 );
  1047.  
  1048.                 size = knot2.vsize;
  1049.                 wide = (int)(CartoonHeight*Scale);
  1050.                 knot2.hx = (int)(((Long)wide*knot2.vnx)/size);
  1051.                 knot2.hy = (int)(((Long)wide*knot2.vny)/size);
  1052.                 knot2.hz = (int)(((Long)wide*knot2.vnz)/size);
  1053.             } else if( (group->flag|group->gnext->flag)&RibbonFlag )
  1054.                 CalculateVInten( &knot2 );
  1055.         }
  1056.  
  1057.         if( !(col1 = group->col1) )
  1058.             col1 = captr->col;
  1059.  
  1060.         if( prev )
  1061.         {   /* Approximate spline segment with plane! */
  1062.             /* SolidRibbon( &knot1, &knot2, col1 );   */
  1063.  
  1064.             /* Calculate Hermite Spline Points */
  1065.             mid1.px = (int)(((Long)54*knot1.px + (Long)9*knot1.tx +
  1066.                              (Long)10*knot2.px - (Long)3*knot2.tx)/64);
  1067.             mid1.py = (int)(((Long)54*knot1.py + (Long)9*knot1.ty +
  1068.                              (Long)10*knot2.py - (Long)3*knot2.ty)/64);
  1069.             mid1.pz = (int)(((Long)54*knot1.pz + (Long)9*knot1.tz +
  1070.                              (Long)10*knot2.pz - (Long)3*knot2.tz)/64);
  1071.  
  1072.             mid2.px = (int)(((Long)4*knot1.px + knot1.tx +
  1073.                              (Long)4*knot2.px - knot2.tx)/8);
  1074.             mid2.py = (int)(((Long)4*knot1.py + knot1.ty +
  1075.                              (Long)4*knot2.py - knot2.ty)/8);
  1076.             mid2.pz = (int)(((Long)4*knot1.pz + knot1.tz +
  1077.                              (Long)4*knot2.pz - knot2.tz)/8);
  1078.  
  1079.             mid3.px = (int)(((Long)10*knot1.px + (Long)3*knot1.tx +
  1080.                              (Long)54*knot2.px - (Long)9*knot2.tx)/64);
  1081.             mid3.py = (int)(((Long)10*knot1.py + (Long)3*knot1.ty +
  1082.                              (Long)54*knot2.py - (Long)9*knot2.ty)/64);
  1083.             mid3.pz = (int)(((Long)10*knot1.pz + (Long)3*knot1.tz +
  1084.                              (Long)54*knot2.pz - (Long)9*knot2.tz)/64);
  1085.  
  1086.             if( group->flag & TraceFlag )
  1087.             {   wide = (int)(group->width*Scale);
  1088.                 ClipCylinder( knot1.px, knot1.py, knot1.pz,
  1089.                               mid1.px, mid1.py, mid1.pz,
  1090.                               col1, col1, wide );
  1091.                 ClipCylinder( mid1.px, mid1.py, mid1.pz,
  1092.                               mid2.px, mid2.py, mid2.pz,
  1093.                               col1, col1, wide );
  1094.                 ClipCylinder( mid2.px, mid2.py, mid2.pz,
  1095.                               mid3.px, mid3.py, mid3.pz,
  1096.                               col1, col1, wide );
  1097.                 ClipCylinder( mid3.px, mid3.py, mid3.pz,
  1098.                               knot2.px, knot2.py, knot2.pz,
  1099.                               col1, col1, wide );
  1100.             } else
  1101.             {   /* Calculate Hermite Spline Widths */
  1102.                 mid1.wx = (27*knot1.wx + 5*knot2.wx)/32;
  1103.                 mid1.wy = (27*knot1.wy + 5*knot2.wy)/32;
  1104.                 mid1.wz = (27*knot1.wz + 5*knot2.wz)/32;
  1105.  
  1106.                 mid2.wx = (knot1.wx + knot2.wx)/2;
  1107.                 mid2.wy = (knot1.wy + knot2.wy)/2;
  1108.                 mid2.wz = (knot1.wz + knot2.wz)/2;
  1109.  
  1110.                 mid3.wx = (5*knot1.wx + 27*knot2.wx)/32;
  1111.                 mid3.wy = (5*knot1.wy + 27*knot2.wy)/32;
  1112.                 mid3.wz = (5*knot1.wz + 27*knot2.wz)/32;
  1113.  
  1114.                 /* Draw the Spline Segments */
  1115.                 if( group->flag & (StrandFlag|DashStrandFlag) )
  1116.                 {   if( !(col2 = group->col2) )
  1117.                         col2 = captr->col;
  1118.                     if( group->flag & StrandFlag )
  1119.                     {   StrandRibbon( &knot1, &mid1,  col1, col2 );
  1120.                         StrandRibbon( &mid1,  &mid2,  col1, col2 );
  1121.                         StrandRibbon( &mid2,  &mid3,  col1, col2 );
  1122.                         StrandRibbon( &mid3,  &knot2, col1, col2 );
  1123.                     } else /* group->flag & DashStrandFlag */
  1124.                     {   DashRibbon( &knot1, &mid1,  col1, col2 );
  1125.                         DashRibbon( &mid1,  &mid2,  col1, col2 );
  1126.                         DashRibbon( &mid2,  &mid3,  col1, col2 );
  1127.                         DashRibbon( &mid3,  &knot2, col1, col2 );
  1128.                     }
  1129.                 } else /* Ribbon or Cartoon! */
  1130.                 {   mid1.vsize = 0;
  1131.                     mid1.vnx = (int)(((Long)27*knot1.vnx +
  1132.                                       (Long) 5*knot2.vnx)/32);
  1133.                     mid1.vny = (int)(((Long)27*knot1.vny +
  1134.                                       (Long) 5*knot2.vny)/32);
  1135.                     mid1.vnz = (int)(((Long)27*knot1.vnz +
  1136.                                       (Long) 5*knot2.vnz)/32);
  1137.                     CalculateVInten( &mid1 );
  1138.  
  1139.                     mid2.vsize = 0;
  1140.                     mid2.vnx = (knot1.vnx + knot2.vnx)/2;
  1141.                     mid2.vny = (knot1.vny + knot2.vny)/2;
  1142.                     mid2.vnz = (knot1.vnz + knot2.vnz)/2;
  1143.                     CalculateVInten( &mid2 );
  1144.  
  1145.                     mid3.vsize = 0;
  1146.                     mid3.vnx = (int)(((Long) 5*knot1.vnx +
  1147.                                       (Long)27*knot2.vnx)/32);
  1148.                     mid3.vny = (int)(((Long) 5*knot1.vny +
  1149.                                       (Long)27*knot2.vny)/32);
  1150.                     mid3.vnz = (int)(((Long) 5*knot1.vnz +
  1151.                                       (Long)27*knot2.vnz)/32);
  1152.                     CalculateVInten( &mid3 );
  1153.  
  1154.                     if( group->flag & RibbonFlag )
  1155.                     {   SolidRibbon( &knot1, &mid1,  col1 );
  1156.                         SolidRibbon( &mid1,  &mid2,  col1 );
  1157.                         SolidRibbon( &mid2,  &mid3,  col1 );
  1158.                         SolidRibbon( &mid3,  &knot2, col1 );
  1159.                     } else /* Cartoon! */
  1160.                     {   /* Calculate Spline Heights */
  1161.                         wide = (int)(CartoonHeight*Scale);
  1162.  
  1163.                         size = mid1.vsize;
  1164.                         mid1.hx = (int)(((Long)wide*mid1.vnx)/size);
  1165.                         mid1.hy = (int)(((Long)wide*mid1.vny)/size);
  1166.                         mid1.hz = (int)(((Long)wide*mid1.vnz)/size);
  1167.  
  1168.                         size = mid2.vsize;
  1169.                         mid2.hx = (int)(((Long)wide*mid2.vnx)/size);
  1170.                         mid2.hy = (int)(((Long)wide*mid2.vny)/size);
  1171.                         mid2.hz = (int)(((Long)wide*mid2.vnz)/size);
  1172.  
  1173.                         size = mid3.vsize;
  1174.                         mid3.hx = (int)(((Long)wide*mid3.vnx)/size);
  1175.                         mid3.hy = (int)(((Long)wide*mid3.vny)/size);
  1176.                         mid3.hz = (int)(((Long)wide*mid3.vnz)/size);
  1177.  
  1178.                         /* Calculate Surface Intensity */
  1179.                         mid1.hsize = 0;
  1180.                         mid1.hnx = (int)(((Long)27*knot1.hnx +
  1181.                                           (Long) 5*knot2.hnx)/32);
  1182.                         mid1.hny = (int)(((Long)27*knot1.hny +
  1183.                                           (Long) 5*knot2.hny)/32);
  1184.                         mid1.hnz = (int)(((Long)27*knot1.hnz +
  1185.                                           (Long) 5*knot2.hnz)/32);
  1186.                         CalculateHInten( &mid1 );
  1187.  
  1188.                         mid2.hsize = 0;
  1189.                         mid2.hnx = (knot1.hnx + knot2.hnx)/2;
  1190.                         mid2.hny = (knot1.hny + knot2.hny)/2;
  1191.                         mid2.hnz = (knot1.hnz + knot2.hnz)/2;
  1192.                         CalculateHInten( &mid2 );
  1193.  
  1194.                         mid3.hsize = 0;
  1195.                         mid3.hnx = (int)(((Long) 5*knot1.hnx +
  1196.                                           (Long)27*knot2.hnx)/32);
  1197.                         mid3.hny = (int)(((Long) 5*knot1.hny +
  1198.                                           (Long)27*knot2.hny)/32);
  1199.                         mid3.hnz = (int)(((Long) 5*knot1.hnz +
  1200.                                           (Long)27*knot2.hnz)/32);
  1201.                         CalculateHInten( &mid3 );
  1202.  
  1203.                         RectRibbon( &knot1, &mid1,  col1 );
  1204.                         RectRibbon( &mid1,  &mid2,  col1 );
  1205.                         RectRibbon( &mid2,  &mid3,  col1 );
  1206.                         RectRibbon( &mid3,  &knot2, col1 );
  1207.                     }
  1208.                 }
  1209.             }
  1210.         } else if( group == chain->glist )
  1211.         {   knot1 = knot2;
  1212.             knot1.px = captr->x;
  1213.             knot1.py = captr->y;
  1214.             knot1.pz = captr->z;
  1215.  
  1216.             if( group->flag & RibbonFlag )
  1217.             {   SolidRibbon( &knot1, &knot2, col1 );
  1218.             } else if( group->flag & RibbonFlag )
  1219.             {   RectRibbon( &knot1, &knot2, col1 );
  1220.             } else if( group->flag & StrandFlag )
  1221.             {   if( !(col2 = group->col2) )
  1222.                     col2 = captr->col;
  1223.                 StrandRibbon( &knot1,  &knot2, col1, col2 );
  1224.             } else if( group->flag & DashStrandFlag )
  1225.             {   if( !(col2 = group->col2) )
  1226.                     col2 = captr->col;
  1227.                 DashRibbon( &knot1,  &knot2, col1, col2 );
  1228.             } else if( group->flag & TraceFlag )
  1229.                 ClipCylinder( knot1.px, knot1.py, knot1.pz,
  1230.                               knot2.px, knot2.py, knot2.pz,
  1231.                               col1, col1, (int)(group->width*Scale) );
  1232.             prev = True;
  1233.         } else prev = True;
  1234.         group = group->gnext;
  1235.         captr = next;
  1236.  
  1237.         knot1 = knot2;
  1238.     }
  1239.  
  1240.     if( prev )
  1241.     {   if( !(col1 = group->col1) )
  1242.             col1 = captr->col;
  1243.  
  1244.         if( group->flag & CartoonFlag )
  1245.         {   /* Test for arrow head! */
  1246.             if( DrawBetaArrows && (group->struc&SheetFlag) )
  1247.             {   wide = (3*group->width)>>1;
  1248.                 knot2.px = captr->x + (knot2.tx/2);
  1249.                 knot2.py = captr->y + (knot2.ty/2);
  1250.                 knot2.pz = captr->z + (knot2.tz/2);
  1251.  
  1252.                 arrow = True;
  1253.             } else
  1254.             {   wide = group->width;
  1255.                 knot2.px = captr->x;
  1256.                 knot2.py = captr->y;
  1257.                 knot2.pz = captr->z;
  1258.                 arrow = False;
  1259.             }
  1260.  
  1261.             wide = (int)(Scale*wide);
  1262.             if( (knot1.wide!=wide) && knot1.hsize )
  1263.             {   size = knot1.hsize;
  1264.                 knot1.wx = (int)(((Long)wide*knot1.hnx)/size);
  1265.                 knot1.wy = (int)(((Long)wide*knot1.hny)/size);
  1266.                 knot1.wz = (int)(((Long)wide*knot1.hnz)/size);
  1267.  
  1268.                 if( !arrow )
  1269.                 {   knot2.wx = knot1.wx;
  1270.                     knot2.wy = knot1.wy;
  1271.                     knot2.wz = knot1.wz;
  1272.                 } else
  1273.                 {   knot2.wx = 0;
  1274.                     knot2.wy = 0;
  1275.                     knot2.wz = 0;
  1276.                 }
  1277.             } else if( arrow )
  1278.             {   knot2.wx = 0;
  1279.                 knot2.wy = 0;
  1280.                 knot2.wz = 0;
  1281.             }
  1282.  
  1283.             RectRibbon( &knot1, &knot2, col1 );
  1284.         } else /* !Cartoon */
  1285.         {   knot2.px = captr->x;
  1286.             knot2.py = captr->y;
  1287.             knot2.pz = captr->z;
  1288.  
  1289.             if( group->flag & RibbonFlag )
  1290.             {   SolidRibbon( &knot1, &knot2, col1 );
  1291.             } else if( group->flag & StrandFlag )
  1292.             {   if( !(col2 = group->col2) )
  1293.                     col2 = captr->col;
  1294.                 StrandRibbon( &knot1,  &knot2, col1, col2 );
  1295.             } else if( group->flag & DashStrandFlag )
  1296.             {   if( !(col2 = group->col2) )
  1297.                     col2 = captr->col;
  1298.                 DashRibbon( &knot1,  &knot2, col1, col2 );
  1299.             } else if( group->flag & TraceFlag )
  1300.                 ClipCylinder( knot1.px, knot1.py, knot1.pz,
  1301.                               knot2.px, knot2.py, knot2.pz,
  1302.                               col1, col1, (int)(group->width*Scale) );
  1303.         }
  1304.     }
  1305. }
  1306.  
  1307.  
  1308.  
  1309. void ResetRepres()
  1310. {
  1311.     DeleteSurface();
  1312.     DeleteMonitors();
  1313.     SolventDots = False;
  1314.     ProbeRadius = 0;
  1315.  
  1316.     DrawLabels = False;
  1317.     ResetLabels();
  1318.  
  1319.     DrawMonitDistance = True;
  1320.     DrawBetaArrows = True;
  1321.     CartoonHeight = 100;
  1322. }
  1323.  
  1324.  
  1325. void InitialiseRepres()
  1326. {
  1327.     DotPtr = (DotStruct __far*)0;
  1328.     MonitList = (Monitor __far*)0;
  1329.     LabelList = (void*)0;
  1330.  
  1331.     FreeMonit = (Monitor __far*)0;
  1332.     FreeLabel = (void*)0;
  1333.  
  1334.     ResetRepres();
  1335. }
  1336.  
  1337.  
  1338.