Logo Search packages:      
Sourcecode: pymol version File versions

RepCartoon.c

/* 
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. 
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information. 
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* Cameron Mura
-* 
-*
Z* -------------------------------------------------------------------
*/

#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"

#include"Base.h"
#include"OOMac.h"
#include"RepCartoon.h"
#include"Color.h"
#include"Setting.h"
#include"Word.h"
#include"Scene.h"
#include"main.h"
#include"Feedback.h"
#include"CGO.h"
#include"Extrude.h"

typedef struct RepCartoon {
  Rep R; /* must be first! */
  CGO *ray,*std;

} RepCartoon;

#include"ObjectMolecule.h"

#define ESCAPE_MAX 500

void RepCartoonFree(RepCartoon *I);

void RepCartoonFree(RepCartoon *I)
{
  if(I->ray)
    CGOFree(I->ray);
  if(I->std)
    CGOFree(I->std);
  RepPurge(&I->R);
  OOFreeP(I);
}

static void RepCartoonRender(RepCartoon *I,RenderInfo *info)
{
  CRay *ray = info->ray;
  Picking **pick = info->pick;
  register PyMOLGlobals *G=I->R.G;
  if(ray) {
    PRINTFD(G,FB_RepCartoon)
      " RepCartoonRender: rendering raytracable...\n"
      ENDFD;
    
    if(I->ray)  
      CGORenderRay(I->ray,ray,NULL,I->R.cs->Setting,
                   I->R.obj->Setting
                   );
    else if(I->std)
      CGORenderRay(I->std,ray,NULL,I->R.cs->Setting,
                   I->R.obj->Setting);    
  } else if(G->HaveGUI && G->ValidContext) {
    if(pick) {
      if(I->std) {
        CGORenderGLPicking(I->std,pick,&I->R.context,
                            I->R.cs->Setting,I->R.obj->Setting);
      }
    } else {
      int use_dlst;
      use_dlst = (int)SettingGet(G,cSetting_use_display_lists);
      if(use_dlst&&I->R.displayList) {
        glCallList(I->R.displayList);
      } else { 
        
        if(use_dlst) {
          if(!I->R.displayList) {
            I->R.displayList = glGenLists(1);
            if(I->R.displayList) {
              glNewList(I->R.displayList,GL_COMPILE_AND_EXECUTE);
            }
          }
        }
        
        PRINTFD(G,FB_RepCartoon)
          " RepCartoonRender: rendering GL...\n"
          ENDFD;
        
        if(I->std) 
          CGORenderGL(I->std,NULL,I->R.cs->Setting,
                      I->R.obj->Setting,info);
        
        if(use_dlst&&I->R.displayList) {
          glEndList();
        }
      }
    }
  }
}

static float smooth(float x,float power)
{

  if(x<=0.5) {
    if(x<=0.0) x=0.0;
    return ((float)(0.5*pow(2.0*x,power)));    
  } else {
    if(x>=1.0) x=1.0;
    return ((float)(1.0-(0.5*pow(2*(1.0-x),power))));
  }
}

#define NUCLEIC_NORMAL0 "C2"
#define NUCLEIC_NORMAL1 "C3*"
#define NUCLEIC_NORMAL2 "C3'"

#define MAX_RING_ATOM 10

/* atix must contain n_atom + 1 elements, with the first atom repeated at the end */

static void do_ring(PyMOLGlobals *G,int n_atom, int *atix, ObjectMolecule *obj, 
                    CoordSet *cs, float width, CGO *cgo, int ring_color, int ring_mode,
                    float ladder_radius, int ladder_color, int ladder_mode, int finder,
                    int sc_helper, int *nuc_flag, int na_mode, float ring_alpha, 
                    float alpha, int *marked, float *moved, float ring_radius)
{
  float *v_i[MAX_RING_ATOM];
  float *col[MAX_RING_ATOM];
  float n_up[MAX_RING_ATOM][3];
  float n_dn[MAX_RING_ATOM][3];
  AtomInfoType *ai_i[MAX_RING_ATOM];
  int have_all = true;
  int all_marked = true;
  AtomInfoType *ai;
  int have_C4 = -1;
  int have_C4_prime = -1;
  int have_C_number = -1;
  int nf = false;

  width *= 0.5F;
  if(!ring_mode)
    finder = 0;
  /* first, make sure all atoms have known coordinates */
  {
    int a,i;
    for(i=0;i<=n_atom;i++) {
      int a1 = atix[i];
      int have_atom = false;
      if(nuc_flag[a1])
        nf=true;
      if(obj->DiscreteFlag) {
        if(cs==obj->DiscreteCSet[a1]) 
          a=obj->DiscreteAtmToIdx[a1];
        else 
          a=-1;
      } else 
        a=cs->AtmToIdx[a1];
      if(a>=0) {
        ai = obj->AtomInfo+a1;
        if(ai->visRep[cRepCartoon]) {
          ai_i[i] = ai;
          col[i] = ColorGet(G,ai->color);
          v_i[i]=cs->Coord+3*a;
          have_atom = true;
          if(WordMatchExact(G,"C4",ai->name,1))
            have_C4 = a1;
          if(WordMatchExact(G,"C4'",ai->name,1)||
             WordMatchExact(G,"C4*",ai->name,1))
            have_C4_prime = a1;
          if(((ai->name[0]=='C')||(ai->name[0]=='c'))&&
             ((ai->name[1]>='0')&&(ai->name[1]<='9')))
            have_C_number = a1;
        }
        if(!marked[a1])
          all_marked=false;
      }
      if(!have_atom) {
        have_all=false;
        break;
      }
    }
  }
  
  if(n_atom && have_all && (!all_marked)) {
    if(ladder_mode) {
      int i;
      int a1;
      AtomInfoType *ai2;
      register AtomInfoType *atomInfo = obj->AtomInfo;
      register int mem0,mem1,mem2,mem3,mem4,mem5,mem6,mem7;
      register int *neighbor = obj->Neighbor;
      int nbr[7];
      int sugar_at=-1,base_at=-1;
      int phos3_at=-1,phos5_at=-1;
      int o3_at=-1,o5_at=-1,c1_at=-1;
      int purine_flag = false;
      int c1 = -1, c1_linked = -1;
      int c2 = -1, c2_linked = -1;
      int c3 = -1, c3_linked = -1;
      int c4 = -1, c4_linked = -1;
      int c5 = -1, c5_linked = -1;

      if(n_atom==5) { /* going from the sugar to the base */
        for(i=0;i<n_atom;i++) {
          a1 = atix[i];
          if(!nf) nf = nuc_flag[a1];
          ai = atomInfo+a1;
          if((ai->protons == cAN_C) && (!marked[a1]) && 
             (WordMatchExact(G,"C3*",ai->name,1)||
              WordMatchExact(G,"C3'",ai->name,1))) {
            sugar_at = a1;
            mem0 = a1;
            nbr[0]= neighbor[mem0]+1;
            while((mem1 = neighbor[nbr[0]])>=0) {
              if((atomInfo[mem1].protons==cAN_O) &&
                 (!marked[mem1])) {  
                ai = atomInfo+mem1;
                if(WordMatchExact(G,"O3*",ai->name,1)||
                   WordMatchExact(G,"O3'",ai->name,1))
                  o3_at = mem1;
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (!marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_P)) { 
                    phos3_at = mem2;
                  }
                  nbr[1]+=2;
                }
              }
                
              if((atomInfo[mem1].protons==cAN_C) &&
                 (!marked[mem1])) {
                ai2 = atomInfo+mem1;  
                if(WordMatchExact(G,NUCLEIC_NORMAL1,ai2->name,1)||
                   WordMatchExact(G,NUCLEIC_NORMAL2,ai2->name,1))
                  sugar_at = mem1;
                  
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (!marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_C)) { 
                    ai = atomInfo+mem2;
                    if(WordMatchExact(G,"C1*",ai->name,1)||
                       WordMatchExact(G,"C1'",ai->name,1))
                      c1_at = mem2;
                    nbr[2] = neighbor[mem2]+1;
                    while((mem3 = neighbor[nbr[2]])>=0) {
                      if((mem3!=mem1)&&(mem3!=mem0)) {
                        if((atomInfo[mem3].protons==cAN_O) &&
                           (!marked[mem3])) {  
                          ai = atomInfo+mem3;
                          if(WordMatchExact(G,"O5*",ai->name,1)||
                             WordMatchExact(G,"O5'",ai->name,1))
                            o5_at = mem3;
                  
                          nbr[3] = neighbor[mem3]+1;
                          while((mem4 = neighbor[nbr[3]])>=0) {
                            if((mem4!=mem2)&& (!marked[mem4]) && 
                               (atomInfo[mem4].protons==cAN_P)) { 
                              phos5_at = mem4;
                            }
                            nbr[3]+=2;
                          }
                        }
                        if(atomInfo[mem3].protons==cAN_N) {
                            
                          if(ring_mode) {
                            ai2 = atomInfo + mem3;
                            if((!marked[mem3]) && (WordMatchExact(G,"N1",ai2->name,1)||
                                                 WordMatchExact(G,"N9",ai2->name,1))) {
                              base_at = mem3;
                              if(ring_mode!=3) {
                                ladder_radius = width * 1.5;
                              } else {
                                ladder_radius = width * 3;
                              }
                            }
                          } else {
                            nbr[3] = neighbor[mem3]+1;
                            while((mem4 = neighbor[nbr[3]])>=0) {
                              if((mem4!=mem2)&&(mem4!=mem1)&&(mem4!=mem0)&&
                                 (atomInfo[mem4].protons==cAN_C)) { 
                                  
                                nbr[4] = neighbor[mem4]+1;              
                                while((mem5 = neighbor[nbr[4]])>=0) {
                                  if((mem5!=mem3)&&(mem5!=mem2)&&(mem5!=mem1)&&(mem5!=mem0)&&
                                     (atomInfo[mem5].protons==cAN_N)&&(marked[mem5])) { /* must be in a mapped ring */
                                    /* clear flag here */
                                    purine_flag = false;
                                      
                                    nbr[5] = neighbor[mem5]+1;              
                                    while((mem6 = neighbor[nbr[5]])>=0) {
                                      if((mem6!=mem4)&&(mem6!=mem3)&&(mem6!=mem2)&&
                                         (mem6!=mem1)&&(mem6!=mem0)&&
                                         (atomInfo[mem6].protons==cAN_C)&&(marked[mem6])) { 
                                        nbr[6] = neighbor[mem6]+1;              
                                        while((mem7 = neighbor[nbr[6]])>=0) {
                                          ai2 = atomInfo + mem7;
                                          if((mem7!=mem5)&&(mem7!=mem4)&&(mem7!=mem3)&&(mem7!=mem2)&&
                                             (mem7!=mem2)&&(mem7!=mem1)&&(mem7!=mem0)&&
                                             (ai2->protons==cAN_N)&&(marked[mem7]))   {
                                            if(WordMatchExact(G,"N1",ai2->name,1)) {
                                              /* and set flag */
                                              base_at = mem7;
                                              purine_flag = true;
                                            }
                                          }
                                          nbr[6]+=2;
                                        }
                                      }
                                      nbr[5]+=2;
                                    }
                                      
                                    if(!purine_flag) {
                                      ai2 = atomInfo + mem5;
                                      if(marked[mem5] && WordMatchExact(G,"N3",ai2->name,1)) {
                                        base_at = mem5;
                                      }
                                    }
                                  }
                                  nbr[4]+=2;
                                }
                              }
                              nbr[3]+=2;                          
                            }
                          }
                        }
                      }
                      nbr[2]+=2;                          
                    }
                  }
                  nbr[1]+=2;                          
                }
              }
              nbr[0]+=2;                          
            }
          }
        }
      } else if((!ring_mode)&&(n_atom==6)) { /* going from the base to the sugar */
        
        for(i=0;i<n_atom;i++) {
          a1 = atix[i];
          if(!nf) nf = nuc_flag[a1];
          ai = atomInfo+a1;

          /* base-hunting */

          if((ai->protons == cAN_N) && (!marked[a1]) &&
             (WordMatchExact(G,"N1",ai->name,1)||
              WordMatchExact(G,"N3",ai->name,1))) {
            mem0 = a1;
            nbr[0]= neighbor[mem0]+1;
            while((mem1 = neighbor[nbr[0]])>=0) {
              if((atomInfo[mem1].protons==cAN_C) && 
                 (!marked[mem1])) {  
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (!marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_N)) { 
                    nbr[2] = neighbor[mem2]+1;
                    while((mem3 = neighbor[nbr[2]])>=0) {
                      if((mem3!=mem1)&&(mem3!=mem0)&&
                         (atomInfo[mem3].protons==cAN_C)) {
                        nbr[3] = neighbor[mem3]+1;
                        while((mem4 = neighbor[nbr[3]])>=0) {
                          if((mem4!=mem2)&&(mem4!=mem1)&&(mem4!=mem0)) {
                            if((atomInfo[mem4].protons==cAN_N)) { /* purine case */
                              nbr[4] = neighbor[mem4]+1;              
                              while((mem5 = neighbor[nbr[4]])>=0) {
                                if((mem5!=mem3)&&(mem5!=mem2)&&(mem5!=mem1)&&(mem5!=mem0)&&
                                   (marked[mem5])&& 
                                   (atomInfo[mem5].protons==cAN_C)) {
                                  nbr[5] = neighbor[mem5]+1;              
                                  while((mem6 = neighbor[nbr[5]])>=0) {
                                    if((mem6!=mem4)&&(mem6!=mem3)&&(mem6!=mem2)&&
                                       (mem6!=mem1)&&(mem6!=mem0)&&
                                       ((atomInfo[mem6].protons==cAN_C)||
                                        (atomInfo[mem6].protons==cAN_O))
                                       &&(marked[mem6])) { 
                                      nbr[6] = neighbor[mem6]+1;              
                                      while((mem7 = neighbor[nbr[6]])>=0) {
                                        ai2 = atomInfo + mem7;
                                        if((mem7!=mem5)&&(mem7!=mem4)&&(mem7!=mem3)&&(mem7!=mem2)&&
                                           (mem7!=mem2)&&(mem7!=mem1)&&(mem7!=mem0)&&
                                           (ai2->protons==cAN_C)&&(marked[mem7]))   {
                                          if(WordMatchExact(G,NUCLEIC_NORMAL1,ai2->name,1)||
                                             WordMatchExact(G,NUCLEIC_NORMAL2,ai2->name,1)) {
                                            base_at = a1;
                                            sugar_at = mem7;
                                          }
                                        }
                                        nbr[6]+=2;
                                      }
                                    }
                                    nbr[5]+=2;
                                  }
                                }
                                nbr[4]+=2;
                              }
                            } else if(((atomInfo[mem4].protons==cAN_C)||
                                       (atomInfo[mem4].protons==cAN_O))&&
                                      (marked[mem4])) { /* pyrimidine case */
                              
                              nbr[4] = neighbor[mem4]+1;              
                              while((mem5 = neighbor[nbr[4]])>=0) {
                                ai2 = atomInfo + mem5;
                                if((mem5!=mem3)&&(mem5!=mem2)&&(mem5!=mem1)&&(mem5!=mem0)&&
                                   (ai2->protons==cAN_C)&&(marked[mem5])) {
                                  if(WordMatchExact(G,NUCLEIC_NORMAL1,ai2->name,1)||
                                     WordMatchExact(G,NUCLEIC_NORMAL2,ai2->name,1)) {
                                    base_at = a1;
                                    sugar_at = mem5;
                                  }
                                }
                                nbr[4]+=2;
                              } 
                            }
                          }
                          nbr[3]+=2;                          
                        }
                      }
                      nbr[2]+=2;                          
                    }
                  }
                  nbr[1]+=2;                          
                }
              }
              nbr[0]+=2;                         
            }
          }
        }
      }
      if(n_atom==6) {
        
        for(i=0;i<n_atom;i++) { 
          a1 = atix[i];
          ai = atomInfo+a1;

          
          /* glycosylation hunting */
          
          if((ai->protons == cAN_C) && (!marked[a1])) { /* unmarked C in ring */
            mem0 = a1;
            nbr[0]= neighbor[mem0]+1;
            while((mem1 = neighbor[nbr[0]])>=0) {
              if((atomInfo[mem1].protons==cAN_C) && /* exocyclic C */
                 (!marked[mem1])) {  
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (!marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_O)) { /* exocyclic O */
                    nbr[2] = neighbor[mem2]+1;
                    while((mem3 = neighbor[nbr[2]])>=0) {
                      if((mem3!=mem1)&&(mem3!=mem0)&&
                         (marked[mem3])&&
                         (atomInfo[mem3].protons==cAN_C)) { /* cyclic C */
                        if(WordMatchExact(G,"C5",ai->name,1)&&
                           WordMatchExact(G,"C6",atomInfo[mem1].name,1)) {
                          printf("found c5\n");
                          c5_linked = mem3;
                          c5 = mem0;
                        }
                      }
                      nbr[2]+=2;
                    }
                  }
                  nbr[1]+=2;
                }
              } else if((atomInfo[mem1].protons==cAN_O) && /* exocyclic O */
                        (!marked[mem1])) {  
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_C)) { /* cyclic C */
                    /* cyclic C */
                    if(WordMatchExact(G,"C1",ai->name,1)) {
                      c1_linked = mem2;
                      c1 = mem0;
                    } else if(WordMatchExact(G,"C2",ai->name,1)) {
                      c2_linked = mem2;
                      c2 = mem0;
                    } else if(WordMatchExact(G,"C3",ai->name,1)) {
                      c3_linked = mem2;
                      c3 = mem0;
                    } else if(WordMatchExact(G,"C4",ai->name,1)) {
                      c4_linked = mem2;
                      c4 = mem0;
                    }
                  } else if((mem2!=mem0)&& (!marked[mem2]) && 
                            (atomInfo[mem2].protons==cAN_C)) { /* exocyclic C */
                    nbr[2] = neighbor[mem2]+1;
                    while((mem3 = neighbor[nbr[2]])>=0) {
                      if((mem3!=mem1)&&(mem3!=mem0)&&
                         (marked[mem3])&&
                         (atomInfo[mem3].protons==cAN_C)) { /* cyclic C */
                        if(WordMatchExact(G,"C5",atomInfo[mem3].name,1)&&
                           WordMatchExact(G,"C6",atomInfo[mem2].name,1)) {
                          c5 = mem0;
                          c5_linked = mem3;
                        }
                      } else if((mem3!=mem1)&&(mem3!=mem0)&&
                                (!marked[mem3])&&
                                (atomInfo[mem3].protons==cAN_C)) { /* exocyclic */
                        if(WordMatchExact(G,"C1",ai->name,1)&&
                           WordMatchExact(G,"CA",atomInfo[mem3].name,1)) {
                          c1 = mem0;
                          c1_linked = mem3;
                        }
                      }
                      nbr[2]+=2;
                    }
                  }
                  nbr[1]+=2;
                }
              } else if((atomInfo[mem1].protons==cAN_N) && /* exocyclic N */
                        (!marked[mem1])) {  
                nbr[1] = neighbor[mem1]+1;
                while((mem2 = neighbor[nbr[1]])>=0) {
                  if((mem2!=mem0)&& (!marked[mem2]) && 
                     (atomInfo[mem2].protons==cAN_C)) { /* exocyclic C */
                    nbr[2] = neighbor[mem2]+1;
                    while((mem3 = neighbor[nbr[2]])>=0) {
                      if((mem3!=mem1)&&(mem3!=mem0)&&
                         (!marked[mem3])&&
                         (atomInfo[mem3].protons==cAN_C)) { /* exocyclic */
                        nbr[3] = neighbor[mem3]+1;
                        while((mem4 = neighbor[nbr[3]])>=0) {
                          if((mem4!=mem2)&&(mem3!=mem1)&&
                             (!marked[mem4])&&
                             (atomInfo[mem4].protons==cAN_C)) { /* exocyclic */
                            if(WordMatchExact(G,"C1",ai->name,1)&&
                               WordMatchExact(G,"CA",atomInfo[mem4].name,1)) {
                              c1 = mem0;
                              c1_linked = mem4;
                             }
                          }
                          nbr[3]+=2;}
                      }
                      nbr[2]+=2;
                    }
                  }
                  nbr[1]+=2;
                }
              }
              nbr[0]+=2;
            }
          }
        }
      }

      if(sugar_at>=0) { /* still need to find the phosphates... */
        int c3_index = -1;
        ai = atomInfo + sugar_at;
        if(WordMatchExact(G,"C3*",ai->name,1)||
           WordMatchExact(G,"C3'",ai->name,1)) {
          c3_index = sugar_at;
        } else {
          mem0 = sugar_at;
          nbr[0]= neighbor[mem0]+1;
          while((mem1 = neighbor[nbr[0]])>=0) {
            if((atomInfo[mem1].protons==cAN_C) &&
               (!marked[mem1])) {  
              ai = atomInfo + mem1;
              if(!(WordMatchExact(G,"C3*",ai->name,1)||
                   WordMatchExact(G,"C3'",ai->name,1))) {
                c3_index = mem1;
              }
            }
            nbr[0]+=2;
          }
        }

        if(c3_index>=0) { /* now we know where we are... */

          mem0 = c3_index;
          nbr[0]= neighbor[mem0]+1;
          while((mem1 = neighbor[nbr[0]])>=0) {
            if((atomInfo[mem1].protons==cAN_O) &&
               (!marked[mem1])) {  
              ai = atomInfo+mem1;
              if(WordMatchExact(G,"O3*",ai->name,1)||
                 WordMatchExact(G,"O3'",ai->name,1))
                o3_at = mem1;
              nbr[1] = neighbor[mem1]+1;
              while((mem2 = neighbor[nbr[1]])>=0) {
                if((mem2!=mem0)&& (!marked[mem2]) && 
                   (atomInfo[mem2].protons==cAN_P)) { 
                  phos3_at = mem2;
                }
                nbr[1]+=2;
              }
            }
            if((atomInfo[mem1].protons==cAN_C) && (marked[mem1])) {

              nbr[1] = neighbor[mem1]+1;
              while((mem2 = neighbor[nbr[1]])>=0) {

                if((mem2!=mem0)&&(!marked[mem2]) && 
                   (atomInfo[mem2].protons==cAN_C)) { 
                  ai = atomInfo+mem2;
                  if(WordMatchExact(G,"C1*",ai->name,1)||
                     WordMatchExact(G,"C1'",ai->name,1))
                    c1_at = mem2;

                  nbr[2] = neighbor[mem2]+1;
                  while((mem3 = neighbor[nbr[2]])>=0) {
                    if((mem3!=mem1)&&(mem3!=mem0)&&
                       (atomInfo[mem3].protons==cAN_O)&&
                       (!marked[mem3])) {  
                      ai = atomInfo+mem3;
                      if(WordMatchExact(G,"O5*",ai->name,1)||
                         WordMatchExact(G,"O5'",ai->name,1))
                        o5_at = mem3;
                      nbr[3] = neighbor[mem3]+1;
                      while((mem4 = neighbor[nbr[3]])>=0) {
                        if((mem4!=mem2)&& (!marked[mem4]) && 
                           (atomInfo[mem4].protons==cAN_P)) { 
                          phos5_at = mem4;
                        }
                        nbr[3]+=2;
                      }
                    }
                    nbr[2]+=2;
                  }
                }
                nbr[1]+=2;
              }
            }
            nbr[0]+=2;
          }
        }         
      }
      /* glycosylation connectors */
      if(1) {
        if((ring_mode)&&(finder>=3)) {
          if(finder>=3) {
            int b;
            float glyco_radius;
            switch(ring_mode) {
            case 3:
            case 4:
              glyco_radius = width * 3;
              break;
            case 5:
              glyco_radius = ladder_radius;
              break;
            default:
              glyco_radius = width * 1.5;
              break;
            }

            if((alpha!=1.0F)||(ring_alpha!=alpha))
              CGOAlpha(cgo,alpha);

            for(b=0;b<5;b++) {
              int g1=-1, g2 = -1;
              switch(b) {
              case 0: g1 = c1; g2 = c1_linked; break;
              case 1: g1 = c2; g2 = c2_linked; break;
              case 2: g1 = c3; g2 = c3_linked; break;
              case 3: g1 = c4; g2 = c4_linked; break;
              case 4: g1 = c5; g2 = c5_linked; break;
              }

              if((g1>=0) && (g2>=0)) {
                AtomInfoType *g1_ai = atomInfo + g1;
                AtomInfoType *g2_ai = atomInfo + g2;
                if((g1_ai->visRep[cRepCartoon]) && 
                   (g2_ai->visRep[cRepCartoon]) &&
                   ((!sc_helper)||!(g1_ai->visRep[cRepLine]||
                                    g1_ai->visRep[cRepCyl]||
                                    g1_ai->visRep[cRepSphere]))) {
                
                  float *g1p,*g2p;
                  float *color;
                  float avg[3];
                  
                  {
                    int g1_x,g2_x;
                    
                    if(obj->DiscreteFlag) {
                      if(cs==obj->DiscreteCSet[g1] &&
                         cs==obj->DiscreteCSet[g2]) {
                        g1_x=obj->DiscreteAtmToIdx[g1];
                        g2_x=obj->DiscreteAtmToIdx[g2];
                      } else {
                        g1_x = -1;
                        g2_x = -1;
                      }
                    } else {
                      g1_x=cs->AtmToIdx[g1];
                      g2_x=cs->AtmToIdx[g2];
                    }
                    g1p = cs->Coord+3*g1_x;
                    g2p = cs->Coord+3*g2_x;
                  }
                  
                  if(!((!((ring_mode==0)||(ring_mode==4)||(ring_mode==5)))||
                       (!marked[g2]))) {
                    g2p = moved + 3*g2;
                  }
                  if((ring_mode==0)||(ring_mode==4)||(ring_mode==5)) { /* ring center */
                    int i;
                    /* compute average coordinate and mark atoms so that ring is only drawn once */
                    zero3f(avg);
                    for(i=0;i<n_atom;i++) {
                      add3f(avg,v_i[i],avg);
                    }
                    scale3f(avg,1.0F/n_atom,avg);
                    g1p = avg;
                  }
                  
                  if(!g1_ai->masked)
                    CGOPickColor(cgo,g1,cPickableAtom);
                
                  if(ladder_color>=0) {
                    color=ColorGet(G,ladder_color);
                    CGOCustomCylinderv(cgo,g1p,
                                       g2p,
                                       glyco_radius,
                                       color,
                                       color,
                                       2.0F,2.0F);
                  } else {
                    CGOCustomCylinderv(cgo,g1p,
                                       g2p,
                                       glyco_radius,
                                       ColorGet(G,g1_ai->color),
                                       ColorGet(G,g2_ai->color),
                                       2.0F,2.0F);
                  }
                }
              }
            }
          }
        }
      }

      /* see if any of the neighbors are confirmed nucleic acids... */
      if(sugar_at>=0) {
        if(!nf) {
          mem0 = sugar_at;
          nbr[0]= neighbor[mem0]+1;
          while((!nf)&&(mem1 = neighbor[nbr[0]])>=0) {
            if(!nf) nf=nuc_flag[mem1];
            nbr[1] = neighbor[mem1]+1;
            while((!nf)&&(mem2 = neighbor[nbr[1]])>=0) {
              if(mem2!=mem0) {
                if(!nf) nf=nuc_flag[mem2];
                nbr[2] = neighbor[mem2]+1;
                while((!nf)&&(mem3 = neighbor[nbr[2]])>=0) {
                  if((mem3!=mem1)&&(mem3!=mem0)) {
                    if(!nf) nf=nuc_flag[mem3];                    
                    nbr[3] = neighbor[mem3]+1;
                    while((mem4 = neighbor[nbr[3]])>=0) {
                      if(mem4!=mem2) {
                        if(!nf) nf=nuc_flag[mem4];                    
                        nbr[4] = neighbor[mem4]+1;
                        while((mem5 = neighbor[nbr[4]])>=0) {
                          if(mem5!=mem3) {
                            if(!nf) nf=nuc_flag[mem5];                    
                          }
                          nbr[4]+=2;
                        }
                      }
                      nbr[3]+=2;
                    }
                  }
                  nbr[2]+=2;
                }
              }
              nbr[1]+=2;
            }
            nbr[0]+=2;
          }
        }

        if(nf) {
          if((ring_mode)&&((finder==1)||(finder>=3))) {
            if((c1_at>=0)&&(base_at>=0)) {
              int save_at = sugar_at;
              sugar_at = c1_at;
              {
                AtomInfoType *sug_ai = atomInfo + sugar_at;
                AtomInfoType *bas_ai = atomInfo + base_at;
                if((sug_ai->visRep[cRepCartoon]) && 
                   (bas_ai->visRep[cRepCartoon]) &&
                   ((!sc_helper)||!(bas_ai->visRep[cRepLine]||
                                    bas_ai->visRep[cRepCyl]||
                                    bas_ai->visRep[cRepSphere]))) {
                  
                  int sug,bas;
                  float *color;
                  if(obj->DiscreteFlag) {
                    if(cs==obj->DiscreteCSet[sugar_at] &&
                       cs==obj->DiscreteCSet[base_at]) {
                      sug=obj->DiscreteAtmToIdx[sugar_at];
                      bas=obj->DiscreteAtmToIdx[base_at];
                    } else {
                      sug = -1;
                      bas = -1;
                    }
                  } else {
                    sug=cs->AtmToIdx[sugar_at];
                    bas=cs->AtmToIdx[base_at];
                  }
                  
                  if((sug>=0)&&(bas>=0)) {
                    if(!bas_ai->masked)
                      CGOPickColor(cgo,base_at,cPickableAtom);
                    if(ladder_color>=0) {
                      color=ColorGet(G,ladder_color);
                      CGOCustomCylinderv(cgo,cs->Coord+3*sug,
                                         cs->Coord+3*bas,
                                         ladder_radius,
                                         color,
                                         color,
                                         2.0F,2.0F);
                    } else {
                      CGOCustomCylinderv(cgo,cs->Coord+3*sug,
                                         cs->Coord+3*bas,
                                         ladder_radius,
                                         ColorGet(G,sug_ai->color),
                                         ColorGet(G,bas_ai->color),
                                         2.0F,2.0F);
                    }
                  }
                }
              }
              base_at = save_at;
              sugar_at = save_at;
            }
          }
          if((base_at>=0)&&(sugar_at>=0)) {
            AtomInfoType *sug_ai = atomInfo + sugar_at;
            AtomInfoType *bas_ai = atomInfo + base_at;
            if((sug_ai->visRep[cRepCartoon]) && 
               (bas_ai->visRep[cRepCartoon]) &&
               ((!sc_helper)||!(bas_ai->visRep[cRepLine]||
                                bas_ai->visRep[cRepCyl]||
                                bas_ai->visRep[cRepSphere]))) {
              
              int sug,bas;
              float *color;
              float *v_outer, tmp[3],outer[3];
              if(obj->DiscreteFlag) {
                if(cs==obj->DiscreteCSet[sugar_at] &&
                   cs==obj->DiscreteCSet[base_at]) {
                  sug=obj->DiscreteAtmToIdx[sugar_at];
                  bas=obj->DiscreteAtmToIdx[base_at];
                } else {
                  sug = -1;
                  bas = -1;
                }
              } else {
                sug=cs->AtmToIdx[sugar_at];
                bas=cs->AtmToIdx[base_at];
              }
            
              if((sug>=0)&&(bas>=0)) {
                int p3,p5;
                v_outer = cs->Coord+3*sug;
              
                if((o3_at>=0)&&(phos3_at<0))
                  phos3_at = o3_at;
                if((o5_at>=0)&&(phos5_at<0))
                  phos5_at = o5_at;
                if((na_mode!=1)&&(phos3_at>=0)&&(phos5_at>=0)) {
                
                  if(obj->DiscreteFlag) {
                    if(cs==obj->DiscreteCSet[phos3_at] &&
                       cs==obj->DiscreteCSet[phos5_at]) {
                      p3=obj->DiscreteAtmToIdx[phos3_at];
                      p5=obj->DiscreteAtmToIdx[phos5_at];
                    } else {
                      p3 = -1;
                      p5 = -1;
                    }
                  } else {
                    p3=cs->AtmToIdx[phos3_at];
                    p5=cs->AtmToIdx[phos5_at];
                  }
                  if((p3>=0)&&(p5>=0)) {
                    if(ring_mode) {
                      scale3f(cs->Coord+3*p5,0.333333F,outer);
                      scale3f(cs->Coord+3*p3,0.666667F,tmp);
                    } else {
                      scale3f(cs->Coord+3*p3,0.5F,outer);
                      scale3f(cs->Coord+3*p5,0.5F,tmp);
                    }
                    add3f(tmp,outer,outer);
                    v_outer = outer;
                  }
                }
                if(!bas_ai->masked)
                  CGOPickColor(cgo,base_at,cPickableAtom);
                if(ladder_color>=0) {
                  color=ColorGet(G,ladder_color);
                  CGOCustomCylinderv(cgo,v_outer,
                                     cs->Coord+3*bas,
                                     ladder_radius,
                                     color,
                                     color,
                                     2.0F,2.0F);
                } else {
                  CGOCustomCylinderv(cgo,v_outer,
                                     cs->Coord+3*bas,
                                     ladder_radius,
                                     ColorGet(G,sug_ai->color),
                                     ColorGet(G,bas_ai->color),
                                     2.0F,2.0F);
                }
              }
            }
          }
        }
      }
    }
    if((!ring_mode)||(finder==2)) {
      if(ladder_mode) { /* mark sure all rings traversed are mark */
        int i;
        for(i=0;i<=n_atom;i++) {
          marked[atix[i]] = true;
        }
      }
    }
    if((!nf)&&((have_C4_prime>=0)||(have_C4>=0))) {
      int nbr[9];
      register int *neighbor = obj->Neighbor;
      register int mem0,mem1,mem2,mem3,mem4,mem5,mem6,mem7,mem8,mem9;
      /* see if any of the neighbors are confirmed nucleic acids... */
      if(have_C4_prime>=0) 
        mem0 = have_C4_prime;
      else if(have_C4>=0)
        mem0 = have_C4;
      else
        mem0 = -1;
      if(mem0>=1) {
        nbr[0]= neighbor[mem0]+1;
        while((!nf)&&(mem1 = neighbor[nbr[0]])>=0) {
          if(!nf) nf=nuc_flag[mem1];
          nbr[1] = neighbor[mem1]+1;
          while((!nf)&&(mem2 = neighbor[nbr[1]])>=0) {
            if(mem2!=mem0) {
              if(!nf) nf=nuc_flag[mem2];
              nbr[2] = neighbor[mem2]+1;
              while((!nf)&&(mem3 = neighbor[nbr[2]])>=0) {
                if((mem3!=mem1)&&(mem3!=mem0)) {
                  if(!nf) nf=nuc_flag[mem3];                    
                  nbr[3] = neighbor[mem3]+1;
                  while((mem4 = neighbor[nbr[3]])>=0) {
                    if(mem4!=mem2) {
                      if(!nf) nf=nuc_flag[mem4];                    
                      nbr[4] = neighbor[mem4]+1;
                      while((mem5 = neighbor[nbr[4]])>=0) {
                        if(mem5!=mem3) {
                          if(!nf) nf=nuc_flag[mem5];                    
                          nbr[5] = neighbor[mem5]+1;
                          while((mem6 = neighbor[nbr[5]])>=0) {
                            if(mem6!=mem4) {
                              if(!nf) nf=nuc_flag[mem6];                    
                              nbr[6] = neighbor[mem6]+1;
                              while((mem7 = neighbor[nbr[6]])>=0) {
                                if(mem7!=mem5) {
                                  if(!nf) nf=nuc_flag[mem7];                    
                                  nbr[7] = neighbor[mem7]+1;
                                  while((mem8 = neighbor[nbr[7]])>=0) {
                                    if(mem8!=mem6) {
                                      if(!nf) nf=nuc_flag[mem8];                    
                                      nbr[8] = neighbor[mem8]+1;
                                      while((mem9 = neighbor[nbr[8]])>=0) {
                                        if(mem9!=mem7) {
                                          if(!nf) nf=nuc_flag[mem9];                    
                                        }
                                        nbr[8]+=2;
                                      }
                                    }
                                    nbr[7]+=2;
                                  }
                                }
                                nbr[6]+=2;
                              }
                            }
                            nbr[5]+=2;
                          }
                        }
                        nbr[4]+=2;
                      }
                    }
                    nbr[3]+=2;
                  }
                }
                nbr[2]+=2;
              }
            }
            nbr[1]+=2;
          }
          nbr[0]+=2;
        }
      }
    }
    if(n_atom) { /* store center of ring */

      float avg[3];
      float avg_col[3];
      int i;
      float up[3],upi[3];
      float vc0[3],vc1[3];
      float *color = NULL;
      /* compute average coordinate and mark atoms so that ring is only drawn once */
      zero3f(avg);
      zero3f(avg_col);

      for(i=0;i<n_atom;i++) {
        add3f(avg,v_i[i],avg);
        add3f(avg_col,col[i],avg_col);
        marked[atix[i]] = true;
      }

      scale3f(avg,1.0F/n_atom,avg);
      scale3f(avg_col,1.0F/n_atom,avg_col);

      for(i=0;i<n_atom;i++) {
        float *v_moved = moved + atix[i]*3;
        copy3f(avg, v_moved); /* store ring center for later use */
      }
     
      if((nf||(!ladder_mode)||(finder>=3)) && 
         ring_mode && 
         (((finder==1)&&((have_C4>=0)||(have_C4_prime>=0)))||
          ((finder==2)&&((have_C4>=0)))||
          ((finder==3)&&((have_C_number>=0)))|| 
          ((finder==4)))) {
        
        
        if((alpha!=1.0F)||(ring_alpha!=alpha))
          CGOAlpha(cgo,ring_alpha);
        
        if(ring_color>=0) {
          color=ColorGet(G,ring_color);
        } else {
          color=avg_col;
        }
        
        CGOColorv(cgo,color);
        
        if((ring_mode==4)||(ring_mode==5)) { /* spherical ring  */
          float radius = ring_radius;
          if(radius<0.0F) {
            radius = 0.0F;
            if(ring_mode==4) {
              for(i=0;i<n_atom;i++) {
                float dist = diff3f(avg,v_i[i]);
                if(radius<dist) radius = dist;
              }
            } else {
              radius = ladder_radius;
            }
          }
            
          if(n_atom) {
            add3f(avg_col,col[i],avg_col);
            if(!ai_i[0]->masked)
              CGOPickColor(cgo,atix[0],cPickableAtom);
            CGOSphere(cgo,avg,radius);
          }
          
        } else {
      
          /* clear the normals */

          for(i=0;i<=n_atom;i++) {
            zero3f(n_up[i]);
            zero3f(n_dn[i]);
          }

          /* compute average normals */

          {
            float acc[3];
            int ii;

            zero3f(acc);
            for(i=0;i<n_atom;i++) {
              ii=i+1;
              subtract3f(v_i[i],avg,vc0);
              subtract3f(v_i[ii],avg,vc1);
              cross_product3f(vc0,vc1,up);
              add3f(up,n_up[i],n_up[i]);
              add3f(up,n_up[ii],n_dn[ii]);
              if(!i) {
                add3f(up,n_up[n_atom],n_up[n_atom]);
              } else if(ii==n_atom) {
                add3f(up,n_up[0],n_up[0]);
              }
              add3f(up,acc,acc);
            }
            normalize3f(up);
            scale3f(up,-1.0F,upi);
          }

          for(i=0;i<=n_atom;i++) {
            normalize3f(n_up[i]);
            scale3f(n_up[i],-1.0F,n_dn[i]);
          }

          {
            int ii;
            float mid[3];
            float up_add[3];
            float ct[3],cb[3];
            float v0t[3],v0b[3];
            float v1t[3],v1b[3];
            float out[3];

            CGOBegin(cgo,GL_TRIANGLES);
        
            for(i=0;i<n_atom;i++) {
              ii=i+1;
              average3f(v_i[ii],v_i[i],mid);

              subtract3f(mid,avg,out); /* compute outward-facing normal */
              normalize3f(out);

              scale3f(up,width,up_add);

              add3f(avg, up_add, ct);
              subtract3f(avg, up_add, cb);

              add3f(v_i[i], up_add, v0t);
              subtract3f(v_i[i], up_add, v0b);

              add3f(v_i[ii], up_add, v1t);
              subtract3f(v_i[ii], up_add, v1b);
        
              CGONormalv(cgo,up);
              if(ring_color<0) CGOColorv(cgo,color);
              CGOPickColor(cgo,atix[i],cPickableAtom); /* TODO: masking for cartoons! */
              CGOVertexv(cgo,ct);
              CGONormalv(cgo,n_up[i]);
              if(ring_color<0) CGOColorv(cgo,col[i]);
              CGOPickColor(cgo,atix[i],cPickableAtom);
              CGOVertexv(cgo,v0t);
              CGONormalv(cgo,n_up[ii]);
              if(ring_color<0) CGOColorv(cgo,col[ii]);
              CGOPickColor(cgo,atix[ii],cPickableAtom);
              CGOVertexv(cgo,v1t);
        
              if(ring_mode>1) {
                CGONormalv(cgo,out);

                if(ring_color<0) CGOColorv(cgo,col[i]);
                CGOPickColor(cgo,atix[i],cPickableAtom);
                CGOVertexv(cgo,v0t);
                CGOVertexv(cgo,v0b);
                if(ring_color<0) CGOColorv(cgo,col[ii]);
                CGOPickColor(cgo,atix[ii],cPickableAtom);
                CGOVertexv(cgo,v1t);
                CGOVertexv(cgo,v1t);
                if(ring_color<0) CGOColorv(cgo,col[i]);
                CGOPickColor(cgo,atix[i],cPickableAtom);  
                CGOVertexv(cgo,v0b);
                if(ring_color<0) CGOColorv(cgo,col[ii]);
                CGOPickColor(cgo,atix[ii],cPickableAtom);
                CGOVertexv(cgo,v1b);
              }
        
              CGONormalv(cgo,upi);
              if(ring_color<0) CGOColorv(cgo,color);
              CGOPickColor(cgo,atix[i],cPickableAtom);
              CGOVertexv(cgo,cb);
              CGONormalv(cgo,n_dn[ii]);
              if(ring_color<0) CGOColorv(cgo,col[ii]);
              CGOPickColor(cgo,atix[ii],cPickableAtom);
              CGOVertexv(cgo,v1b);
              CGONormalv(cgo,n_dn[i]);
              if(ring_color<0) CGOColorv(cgo,col[i]);
              CGOPickColor(cgo,atix[i],cPickableAtom);
              CGOVertexv(cgo,v0b);
        
            }
            CGOEnd(cgo);

            if((alpha!=1.0F)||(ring_alpha!=alpha))
              CGOAlpha(cgo,alpha);

            if(ring_mode==1) {
              for(i=0;i<n_atom;i++) {
                ii=i+1;
                CGOPickColor(cgo,atix[i],cPickableAtom);
                if(ring_color<0) {
                  CGOSausage(cgo,v_i[i], v_i[ii], width, col[i],col[ii]);
                } else {
                  CGOSausage(cgo,v_i[i], v_i[ii], width, color,color);
                }
              }
            } else if(ring_mode==3) {
              for(i=0;i<n_atom;i++) {
                ii=i+1;
                CGOPickColor(cgo,atix[i],cPickableAtom);
                if(ring_color<0) {
                  CGOSausage(cgo,v_i[i], v_i[ii], 3*width, col[i],col[ii]);
                } else {
                  CGOSausage(cgo,v_i[i], v_i[ii], 3*width, color,color);
                }
              }
            }
          }
        }
      }
    }
  }
}


static void nuc_acid(PyMOLGlobals *G, int a,int a1, AtomInfoType *ai, CoordSet *cs, 
                     ObjectMolecule *obj, int na_mode, int *nuc_flag, int set_flags,
                     int *p_a2,int *p_nSeg, float **p_v_o_last,
                     int **p_s, int **p_i, int **p_cc,
                     int *p_nAt, int *p_cur_car, int **p_ss, int *p_putty_flag,
                     float **p_v, float **p_vo)
{
  int a2 = *p_a2;
  int nSeg = *p_nSeg;
  float *v_o_last = *p_v_o_last;
  int *s = *p_s;
  int *i = *p_i;
  int *cc = *p_cc;
  int nAt = *p_nAt;
  int cur_car = *p_cur_car;
  int *ss = *p_ss;
  int putty_flag = *p_putty_flag;
  float *vo = *p_vo;
  float *v = *p_v;

  int a3,a4,st,nd;
  float *v_o,*v_c,*v_n,t0[3];
  float *v1;

  if(a2<0) {
    nSeg++;
    v_o_last = NULL;
  }
  *(s++) = nSeg;
  nAt++;
  *(i++)=a;
  cur_car = ai->cartoon;
  if(cur_car == cCartoon_auto)
    cur_car = cCartoon_tube;
  *ss=3; /* DNA/RNA */

  if(cur_car==cCartoon_putty)
    putty_flag=true;
  
  *(cc++)=cur_car;
  v1 = cs->Coord+3*a;
  *(v++)=*(v1++);
  *(v++)=*(v1++);
  *(v++)=*(v1++);

  if(a2>=0) {
    if(set_flags) {
      if((obj->AtomInfo[a2].protons==cAN_P)&&
         (!nuc_flag[a2])) {
        int *nf = NULL;
        AtomInfoBracketResidueFast(G,obj->AtomInfo,obj->NAtom,a2,&st,&nd);
        
        nf = nuc_flag + st;
        for(a3=st;a3<=nd;a3++) {
          *(nf++)= true;
        }
      }
    } else if((na_mode>=2)&&(!nuc_flag[a2])) { /* just a single nucleotide -- skip */
      cur_car = cCartoon_skip;
      *(cc-2)=cCartoon_skip;
      *(cc-1)=cCartoon_skip;
    }
  }

  a2=a1;
  
  ss++;
  
  v_c = NULL;
  v_n = NULL;
  v_o = NULL;

  
  AtomInfoBracketResidueFast(G,obj->AtomInfo,obj->NAtom,a1,&st,&nd);
  
  {
    int *nf = NULL;
    if(set_flags && v_o_last)
      nf = nuc_flag + st;
    for(a3=st;a3<=nd;a3++) {
      if(nf) 
        *(nf++)= true; /* mark this residue as being part of a nucleic acid chain */
      if(obj->DiscreteFlag) {
        if(cs==obj->DiscreteCSet[a3]) 
          a4=obj->DiscreteAtmToIdx[a3];
        else 
          a4=-1;
      } else 
        a4=cs->AtmToIdx[a3];
      if(a4>=0) {
        if(na_mode==1) {
          if(WordMatchExact(G,NUCLEIC_NORMAL1,obj->AtomInfo[a3].name,1)||
             WordMatchExact(G,NUCLEIC_NORMAL2,obj->AtomInfo[a3].name,1)) {
            v_c = cs->Coord+3*a4;
          }
        } else if(a3==a1) {
          v_c = cs->Coord+3*a4;           
        }
        if(WordMatchExact(G,NUCLEIC_NORMAL0,obj->AtomInfo[a3].name,1)) {
          v_o = cs->Coord+3*a4;
        }
      }
    }
  }
  if(!(v_c&&v_o)) {
    zero3f(vo);
    v_o_last = NULL;
  } else {
    if(v_o_last) {
      add3f(v_o,v_o_last, t0);
      add3f(v_o_last,t0, t0);
      scale3f(t0,0.333333F,t0);
      subtract3f(v_c,t0,vo);
    } else {
      subtract3f(v_c,v_o,vo);
    }
    v_o_last = v_o;
    normalize3f(vo);
  }
  vo+=3;

  *p_a2 = a2;
  *p_nSeg = nSeg;
  *p_v_o_last= v_o_last;
  *p_s = s;
  *p_i = i;
  *p_cc = cc;
  *p_nAt = nAt ;
  *p_cur_car = cur_car;
  *p_ss = ss;
  *p_putty_flag = putty_flag;
  *p_vo = vo;
  *p_v = v;
}

Rep *RepCartoonNew(CoordSet *cs,int state)
{
  PyMOLGlobals *G=cs->State.G;
  ObjectMolecule *obj;
  int a,b,c,f,e,a1,a2,c1,c2,i0,*i,*s,*at,*seg,nAt,*atp,a3,a4=0,*car,*cc,*sstype;
  float *v,*v0,*v1,*v2,*v3,*v4,*v5,*vo,*vn,*va;
  float *p0,*p1,*p2,*p3;
  float *pv=NULL;
  float *pvo=NULL,*pva=NULL;
  float *dv=NULL;
  float *nv=NULL;
  float *tv=NULL;
  float *vc=NULL;
  float *tmp=NULL;
  int last,first,end_flag;
  int *vi,atom_index1,atom_index2;
  float f0,f1,f2,f3,f4,dev;
  float *d,dp;
  float *dl=NULL;
  int nSeg;
  int sampling;
  int *ss,*fp;
  float  power_a = 5;
  float power_b = 5;
  float loop_radius;
  float tube_radius;
  float putty_radius;

  int visFlag;
  CExtrude *ex=NULL,*ex1;
  int n_p,n_pm1,n_pm2;
  int loop_quality,oval_quality,tube_quality, putty_quality;
  float oval_width,oval_length;
  float dumbbell_radius,dumbbell_width,dumbbell_length;
  float throw;
  int st,nd;
  float *v_c,*v_n,*v_o,*v_o_last = NULL;
  float t0[3],t1[3],t2[3],t3[3],t4[3],o0[12],o1[12];
  float max_dot;
  float length,width;
  int cur_car;
  int contFlag,extrudeFlag;
  int cartoon_debug;
  int fancy_helices;
  int fancy_sheets;
  int refine;
  int contigFlag;
  int discrete_colors;
  int cylindrical_helices;
  int last_color,uniform_color;
  int cartoon_color,highlight_color;
  int cartoon_side_chain_helper;
  int ladder_mode,ladder_color;
  float ladder_radius,ring_radius;
  int round_helices;
  int smooth_loops;
  int na_mode;
  int parity;
  float refine_tips;
  float helix_radius;
  float *h_start=NULL,*h_end=NULL;
  float *sampling_tmp;
  int *flag_tmp;
  int smooth_first,smooth_last,smooth_cycles,flat_cycles;
  int trace,trace_mode;
  int skip_to;
  AtomInfoType *ai,*last_ai=NULL;
  float alpha;
  int putty_flag = false;
  float putty_mean=10.0F,putty_stdev=0.0F;
  AtomInfoType *trailing_O3p_ai=NULL;
  int trailing_O3p_a = 0, trailing_O3p_a1=0;
  AtomInfoType *leading_O5p_ai=NULL;
  int leading_O5p_a = 0, leading_O5p_a1=0;
  int *ring_anchor = NULL;
  int ring_mode, ring_finder, ring_finder_eff;
  int n_ring = 0;
  float ring_width;
  int ring_color;
  int loop_cap, tube_cap;
  int *nuc_flag = NULL;
  int nucleic_color = 0;
  float ring_alpha;

  /* THIS IS BY FAR THE WORST ROUTINE IN PYMOL!
   * DEVELOP ON IT ONLY AT EXTREME RISK TO YOUR MENTAL HEALTH */
  
  OOAlloc(G,RepCartoon);
  
  PRINTFD(G,FB_RepCartoon)
    " RepCartoonNew-Debug: entered.\n"
    ENDFD;
      

  obj = cs->Obj;
  visFlag=false;
  for(a=0;a<cs->NIndex;a++) {
    if(obj->AtomInfo[cs->IdxToAtm[a]].visRep[cRepCartoon])
      {
        visFlag=true;
        break;
      }
  }
  if(!visFlag) {
    OOFreeP(I);
    return(NULL); /* skip if not visible */
  }

  RepInit(G,&I->R);
  power_a=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_power);
  power_b=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_power_b);

  cartoon_debug=SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_debug);
  length=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_rect_length);
  width=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_rect_width);
  trace=SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_trace_atoms);
  trace_mode=SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_trace_atoms_mode);

  alpha=1.0F - SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_transparency);
  throw=SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_throw);

  sampling = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_sampling);
  if(sampling<1) sampling=1;
  loop_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_loop_radius);
  if(loop_radius<0.01F) loop_radius=0.01F;
  loop_quality = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_loop_quality);
  if(loop_quality<3) loop_quality=3;
  if(SettingGetGlobal_i(G,cSetting_ray_trace_mode)>0)
    if(loop_quality<12)
      loop_quality *= 2;

  tube_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_tube_radius);
  if(tube_radius<0.01F) tube_radius=0.01F;
  tube_quality = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_tube_quality);
  if(tube_quality<3) tube_quality=3;

  putty_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_putty_radius);
  if(putty_radius<0.01F) putty_radius=0.01F;
  putty_quality = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_putty_quality);
  if(putty_quality<3) putty_quality=3;

  cartoon_color = SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_color);
  cartoon_side_chain_helper = SettingGet_b(G,cs->Setting, obj->Obj.Setting,
                                           cSetting_cartoon_side_chain_helper);

  highlight_color = SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_highlight_color);

  oval_length = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_oval_length);
  oval_width = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_oval_width);
  oval_quality = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_oval_quality);
  if(oval_quality<3) tube_quality=3;

  dumbbell_length = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_dumbbell_length);
  dumbbell_width = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_dumbbell_width);
  dumbbell_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_dumbbell_radius);
  if(dumbbell_radius<0.01F) dumbbell_radius=0.01F;

  fancy_helices = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_fancy_helices);
  fancy_sheets = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_fancy_sheets);
  cylindrical_helices = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_cylindrical_helices);
  refine = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_refine);
  refine_tips = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_refine_tips);

  discrete_colors = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_discrete_colors);
  round_helices = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_round_helices);
  smooth_loops = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_smooth_loops);
  helix_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_helix_radius);

  ring_width = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_width);
  if(ring_width<0.0F) {
    ring_width = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_stick_radius)*0.5F;
  }

  ring_color = SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_color);

  if(ring_color==-1)
    ring_color = cartoon_color;

  smooth_first = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_smooth_first);
  smooth_last = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_smooth_last);
  smooth_cycles = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_smooth_cycles);
  flat_cycles = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_flat_cycles);

  na_mode = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_nucleic_acid_mode);
  nucleic_color = SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_nucleic_acid_color);

  if(nucleic_color==-1)
    nucleic_color = cartoon_color;

  ring_mode = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_mode);
  ring_finder = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_finder);
  ring_alpha =  SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_transparency);

  if(ring_alpha < 0.0F) 
    ring_alpha = alpha;
  else
    ring_alpha = 1.0F - ring_alpha;

  alpha=1.0F - SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_transparency);
  ladder_mode = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ladder_mode); 
  ladder_radius = SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ladder_radius);
  ladder_color = SettingGet_color(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ladder_color);
  ring_radius =  SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_ring_radius);
  
  if(ladder_color==-1)
    ladder_color = cartoon_color;

  ring_finder_eff = ring_finder;
  if((!ring_mode)||(ring_finder==2)) 
    ring_finder_eff = 1;

  tube_cap = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_tube_cap);
  loop_cap = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_loop_cap);

  I->R.fRender=(void (*)(struct Rep *, RenderInfo *))RepCartoonRender;
  I->R.fFree=(void (*)(struct Rep *))RepCartoonFree;
  I->R.fRecolor=NULL;
  I->R.obj=&obj->Obj;
  I->R.cs=cs;
  I->ray=NULL;
  I->std=NULL;
  I->R.context.object = (void*)obj;
  I->R.context.state = state;

  /* find all of the CA points */

  at = Alloc(int,cs->NAtIndex); /* cs index pointers */
  pv = Alloc(float,cs->NAtIndex*3);
  tmp = Alloc(float,cs->NAtIndex*3);
  pvo = Alloc(float,cs->NAtIndex*3); /* orientation vector */
  pva = Alloc(float,cs->NAtIndex*6); /* alternative orientation vectors, two per atom */
  seg = Alloc(int,cs->NAtIndex);
  car = Alloc(int,cs->NAtIndex);
  sstype = Alloc(int,cs->NAtIndex);
  sampling_tmp = Alloc(float,sampling*3);
  flag_tmp = Alloc(int,cs->NAtIndex);
  nuc_flag = Calloc(int,cs->NAtIndex);
  if(ring_mode || ladder_mode) {
    ring_anchor = VLAlloc(int,cs->NAtIndex/10+1);
  }
  i=at;
  v=pv;
  vo=pvo;
  s=seg;
  cc=car;
  ss=sstype;
  fp = flag_tmp;
  nAt = 0;
  nSeg = 0;
  a2=-1;
  parity = 1;

  for(a1=0;a1<cs->NAtIndex;a1++)  {
    if(obj->DiscreteFlag) {
      if(cs==obj->DiscreteCSet[a1]) 
        a=obj->DiscreteAtmToIdx[a1];
      else 
        a=-1;
    } else 
      a=cs->AtmToIdx[a1];
    if(a>=0) {
      ai = obj->AtomInfo+a1;

      if(ai->visRep[cRepCartoon]) {
        if(ring_anchor &&
           (ai->protons!=cAN_H) &&
           ((ring_finder_eff>=3)|| /* all 5-7 atom rings */
            ((ring_finder_eff<=2) && /*  C4-containing rings */
             (WordMatchExact(G,"C4",ai->name,1))) ||
            ((ring_finder_eff==1) && 
             ((WordMatchExact(G,"C4*",ai->name,1)||
               WordMatchExact(G,"C4'",ai->name,1)))))) {
          VLACheck(ring_anchor,int,n_ring);
          ring_anchor[n_ring] = a1;
          n_ring++;
        }
        /*               if(!obj->AtomInfo[a1].hetatm)*/
        if((!ai->alt[0])||
           (ai->alt[0]=='A')) {
          if(trace||(((ai->protons==cAN_C)&&
                      (WordMatch(G,"CA",ai->name,1)<0))&&
                     !AtomInfoSameResidueP(G,last_ai,ai))) { 
            PRINTFD(G,FB_RepCartoon)
              " RepCartoon: found CA in %s; a2 %d\n",ai->resi,a2
              ENDFD;

            if(trailing_O3p_ai&&((na_mode==2)||(na_mode==4))) {

              /*  3' nucleic acid cap */

              nuc_acid(G, trailing_O3p_a, trailing_O3p_a1, trailing_O3p_ai, 
                       cs, obj, na_mode, nuc_flag, false, &a2, &nSeg, &v_o_last, &s, &i, &cc, 
                       &nAt, &cur_car, &ss, &putty_flag, &v, &vo);
              a2=-1;
              trailing_O3p_ai = NULL;
            }

            if(!trace) {
              if(a2>=0) {
                /*
                  if((abs(obj->AtomInfo[a1].resv-obj->AtomInfo[a2].resv)>1)||
                  (obj->AtomInfo[a1].chain[0]!=obj->AtomInfo[a2].chain[0])||
                  (!WordMatch(G,obj->AtomInfo[a1].segi,obj->AtomInfo[a2].segi,1)))*/
                if(!ObjectMoleculeCheckBondSep(obj,a1,a2,3)) /* CA->N->C->CA = 3 bonds */
                  a2=-1;
                  
              }
            } else {
              if(a2>=0) {
                if(!AtomInfoSequential(G,obj->AtomInfo+a2,obj->AtomInfo+a1,trace_mode))
                  a2=-1;
              }
            }
            last_ai = ai;
                
            PRINTFD(G,FB_RepCartoon)
              " RepCartoon: found CA in %s; a2 %d\n",ai->resi,a2
              ENDFD;
                
                
            if(a2<0)
              nSeg++;
            *(s++) = nSeg;
            nAt++;
            *(i++)=a;
            cur_car = ai->cartoon;

            *fp = ai->flags; /* store atom flags */

            if(cartoon_side_chain_helper) {
              if(ai->visRep[cRepLine]||ai->visRep[cRepCyl]||ai->visRep[cRepSphere])
                *fp |= cAtomFlag_no_smooth;
            }
                
            switch (ai->ssType[0]) {
            case 'H':
            case 'h':
              if (cur_car==cCartoon_auto) {
                if(cylindrical_helices) 
                  cur_car = cCartoon_skip_helix;
                else if(fancy_helices)
                  cur_car = cCartoon_dumbbell;
                else
                  cur_car = cCartoon_oval;
              }
              *ss=1; /* helix */
              parity = 0;
              break;
            case 'S':
            case 's':
              if (cur_car==cCartoon_auto) {
                if(fancy_sheets)
                  cur_car = cCartoon_arrow;
                else
                  cur_car = cCartoon_rect;
              }
              *ss=2;
              parity = !parity;
              break;
            default: /* 'L', 'T', 0, etc. */
              if (cur_car==cCartoon_auto) {
                cur_car = cCartoon_loop;
              }
              parity = 0;
              *ss=0;
              break;
            }
                
            *(cc++)=cur_car;
                
            if(cur_car==cCartoon_putty)
              putty_flag=true;
                
            v1 = cs->Coord+3*a;
            *(v++)=*(v1++);
            *(v++)=*(v1++);
            *(v++)=*(v1++);
            a2=a1;
                  
            ss++;

            fp++;

            v_c = NULL;
            v_n = NULL;
            v_o = NULL;
                  
            AtomInfoBracketResidueFast(G,obj->AtomInfo,obj->NAtom,a1,&st,&nd);

            if(obj->DiscreteFlag) {
              if(cs==obj->DiscreteCSet[nd]) 
                skip_to=obj->DiscreteAtmToIdx[nd];
            } else 
              skip_to=cs->AtmToIdx[nd];
                  
            for(a3=st;a3<=nd;a3++) {
                  
              if(obj->DiscreteFlag) {
                if(cs==obj->DiscreteCSet[a3]) 
                  a4=obj->DiscreteAtmToIdx[a3];
                else 
                  a4=-1;
              } else 
                a4=cs->AtmToIdx[a3];
              if(a4>=0) {
                if(WordMatch(G,"C",obj->AtomInfo[a3].name,1)<0) {
                  v_c = cs->Coord+3*a4;         
                } else if(WordMatch(G,"N",obj->AtomInfo[a3].name,1)<0) {
                  v_n = cs->Coord+3*a4;
                } else if(WordMatch(G,"O",obj->AtomInfo[a3].name,1)<0) {
                  v_o = cs->Coord+3*a4;
                }
              }
            }
            if(!(v_c&&v_n&&v_o)) {
              vo[0]=0.0;
              vo[1]=0.0;
              vo[2]=0.0;
              vo+=3;
            } else {
              /* generate orientation vectors...*/

              subtract3f(v_n,v_c,t0);  /* t0 = N<---C */
              normalize3f(t0);
              subtract3f(v_n,v_o,t1);  /* t1 = N<---O */
              normalize3f(t1);
              cross_product3f(t0,t1,vo);
              normalize3f(vo);
              if(parity) {
                invert3f(vo);
              }
              vo+=3;
            }
          } else if((((na_mode!=1)&&(ai->protons==cAN_P) &&
                      (WordMatch(G,"P",ai->name,1)<0) ) ||
                     ((na_mode==1)&&(ai->protons==cAN_C) &&
                      (WordMatchExact(G,NUCLEIC_NORMAL1,ai->name,1) ||
                       WordMatchExact(G,NUCLEIC_NORMAL2,ai->name,1))))
                    && !AtomInfoSameResidueP(G,last_ai,ai)) {
            if(a2>=0) {
              if(!ObjectMoleculeCheckBondSep(obj,a1,a2,6)) { /* six bonds between phosphates */
                
                /*  3' cap */
                
                if(trailing_O3p_ai&&((na_mode==2)||(na_mode==4))) {
                  
                  nuc_acid(G, trailing_O3p_a, trailing_O3p_a1, trailing_O3p_ai, 
                           cs, obj, na_mode, nuc_flag, false, &a2, &nSeg, &v_o_last, &s, &i, &cc, 
                           &nAt, &cur_car, &ss, &putty_flag, &v, &vo);
                }
                a2=-1;
              }
            }
            last_ai = ai;
            trailing_O3p_ai = NULL;

            /*  5' cap */
            
            if(leading_O5p_ai&&(a2<0)&&
               ((na_mode==3)||(na_mode==4))) {
              if((!AtomInfoSameResidueP(G,ai,leading_O5p_ai))&&
                 ObjectMoleculeCheckBondSep(obj,a1,leading_O5p_a1,5)) {
                
                nuc_acid(G, leading_O5p_a, leading_O5p_a1, leading_O5p_ai, 
                         cs, obj, na_mode, nuc_flag, false, &a2, &nSeg, &v_o_last, &s, &i, &cc, 
                         &nAt, &cur_car, &ss, &putty_flag, &v, &vo);
              }
            }

            leading_O5p_ai = NULL;

            /* this is the main nucleic acid cartoon section... */
            
            nuc_acid(G, a, a1, ai, cs, obj, na_mode, nuc_flag, true, &a2, &nSeg, &v_o_last, &s, &i, &cc, 
                     &nAt, &cur_car, &ss, &putty_flag, &v, &vo);

          }  else if((a2>=0)&&
                     last_ai&&
                     (ai->protons==cAN_O)&&
                     (last_ai->protons==cAN_P)&&
                     ((na_mode==2)||(na_mode==4))&&
                     (WordMatchExact(G,"O3'",ai->name,1)||
                      WordMatchExact(G,"O3*",ai->name,1))&&
                     AtomInfoSameResidueP(G,last_ai,ai)&&
                     ObjectMoleculeCheckBondSep(obj,a1,a2,5)) {
            trailing_O3p_ai = ai;
            trailing_O3p_a = a;
            trailing_O3p_a1 = a1;
          }  else if((ai->protons==cAN_O)&&
                     ((na_mode==3)||(na_mode==4))&&
                     (WordMatchExact(G,"O5'",ai->name,1)||
                      WordMatchExact(G,"O5*",ai->name,1))) {
            leading_O5p_ai = ai;
            leading_O5p_a = a;
            leading_O5p_a1 = a1;
          }
          
        }
      }
    }
  }
  
  /* BEGIN 3' cap */
  if(trailing_O3p_ai&&((na_mode==2)||(na_mode==4))) {
    
    nuc_acid(G, trailing_O3p_a, trailing_O3p_a1, trailing_O3p_ai, 
             cs, obj, na_mode, nuc_flag, false, &a2, &nSeg, &v_o_last, &s, &i, &cc, 
             &nAt, &cur_car, &ss, &putty_flag, &v, &vo);
    a2=-1;
    trailing_O3p_ai = NULL;

  }
  
  if(nAt&&putty_flag) {
    double sum=0.0,sumsq=0.0;
    float value;
    int cnt = 0;

    for(a=0;a<obj->NAtom;a++) {
      ai=obj->AtomInfo+a;
      
      if(ai->visRep[cRepCartoon]) {
        value = ai->b;
        sum+=value;
        sumsq+=(value*value);
        cnt++;
      }
    }

    if(cnt) {
      putty_mean = (float)(sum/cnt);
      putty_stdev = (float)sqrt1d((sumsq - (sum*sum/cnt))/(cnt));
    } else {
      putty_mean = 10.0F;
      putty_stdev = 10.0F;
    }
  }

  PRINTFD(G,FB_RepCartoon)
    " RepCartoon-Debug: path outlined, interpolating...\n"
    ENDFD;

  if(nAt) {
    
    /* compute differences and normals */
    
    s=seg;
    v=pv;

    dv = Alloc(float,nAt*3);
    nv = Alloc(float,nAt*3);
    dl = Alloc(float,nAt);
    v1=dv;
    v2=nv;
    d=dl;
    for(a=0;a<(nAt-1);a++)
      {
        PRINTFD(G,FB_RepCartoon)
          " RepCartoon: seg %d *s %d , *(s+1) %d\n",a,*s,*(s+1)
          ENDFD;

        if(*s==*(s+1))
          {
            subtract3f(v+3,v,v1);
            *d = (float)length3f(v1);
            if(*d>R_SMALL4) {
              float d_1;
              d_1 = 1.0F/(*d);
              scale3f(v1,d_1,v2);
            } else if(a)  {
              copy3f(v2-3,v2); 
            } else {
              zero3f(v2);
            }
          }
        else {
          zero3f(v2);   
        }
          
        d++;
        v+=3;
        v1+=3;
        v2+=3;
        s++;
      }
            
    /* compute tangents */
            
    s=seg;
    v=nv;
            
    tv = Alloc(float,nAt*3+6);
    v1=tv;
            
    *(v1++)=*(v++); /* first segment */
    *(v1++)=*(v++);
    *(v1++)=*(v++);
    s++;
            
    for(a=1;a<(nAt-1);a++) {
      if((*s==*(s-1))&&(*s==*(s+1))) {
        add3f(v,(v-3),v1); /* tangent vectors are head-to-tail sums within a segment */
        normalize3f(v1);                   
      } else if(*s==*(s-1)) {
        *(v1)=*(v-3);  /* end a segment */
        *(v1+1)=*(v-2); 
        *(v1+2)=*(v-1); 
      } else if(*s==*(s+1)) {
        *(v1)=*(v);   /* new segment */
        *(v1+1)=*(v+1); 
        *(v1+2)=*(v+2); 
      }
      v+=3;
      v1+=3;
      s++;
    }
    *(v1++)=*(v-3); /* last segment */
    *(v1++)=*(v-2);
    *(v1++)=*(v-1);

    PRINTFD(G,FB_RepCartoon)
      " RepCartoon-Debug: generating coordinate systems...\n"
      ENDFD;
      
    if(round_helices) {
      v1 = NULL;
      v2 = NULL;
      v3 = NULL;
      v4 = NULL;
      v5 = NULL;
      s = seg;
      v = pv;
      ss = sstype;
      vo = pvo;
      v0 = tv;
      last = 0;
      if(nAt>1) {
        for(a=0;a<nAt;a++) {
          if(a) {
            if(*s!=*(s-1)) { /* contiguous helices in disconnected segments */
              v1 = NULL;
              v2 = NULL;
              v3 = NULL;
              v4 = NULL;
              v5 = NULL;
              last = 0;
            }
          }
          v5 = v4;
          v4 = v3;
          v3 = v2;
          v2 = v1;
          if(*ss==1) /* helix */
            v1 = v;
          else { /* early termination ? */
            if(last<2) {
              zero3f(t0);
              if(v2&&v3) {
                subtract3f(v2,v,t0);
                normalize3f(t0);
                subtract3f(v3,v2,t1);
                normalize3f(t1);
                add3f(t1,t0,t0);
                if(v4) {
                  subtract3f(v4,v3,t1);
                  normalize3f(t1);
                  add3f(t1,t0,t0);
                }
                if(v5) {
                  subtract3f(v5,v4,t1);
                  normalize3f(t1);
                  add3f(t1,t0,t0);
                }
                normalize3f(t0);
                cross_product3f(t0,v0-3,vo-3);
                normalize3f(vo-3);
                cross_product3f(t0,v0-6,vo-6);
                normalize3f(vo-6);
                if(v4) {
                  cross_product3f(t0,v0-9,vo-9);
                  normalize3f(vo-9);
                }
                if(v5) {
                  cross_product3f(t0,v0-12,vo-12);
                  normalize3f(vo-12);
                }

                if(v4&&v5) {
                  /* now make sure there's no goofy flip on the end...
                     of a short, tight helix */
                  if(dot_product3f(vo-9,vo-12)<-0.8F)
                    invert3f(vo-12);
                }
              }
            }
            v1 = NULL;
            v2 = NULL;
            v3 = NULL;
            v4 = NULL;
            v5 = NULL;
            last = 0;
          }
          if(v1&&v2&&v3&&v4) {
            add3f(v1,v4,t0);
            add3f(v2,v3,t1);
            scale3f(t0,0.2130F,t0);
            scale3f(t1,0.2870F,t1);

            add3f(t0,t1,t0);
            if(last) { /* 5th CA or later... */
              subtract3f(t2,t0,t1);
              normalize3f(t1);
              cross_product3f(t1,v0,vo);
              normalize3f(vo);
              cross_product3f(t1,v0-3,vo-3);
              normalize3f(vo-3);
              cross_product3f(t1,v0-6,vo-6);
              normalize3f(vo-6);
              if(last==1) { /* 5th */
                cross_product3f(t1,v0-9,vo-9);
                normalize3f(vo-9);
                cross_product3f(t1,v0-12,vo-12);
                normalize3f(vo-12);
              }
            }
            last++;
            copy3f(t0,t2);
          }
          v+=3;
          ss++;
          vo+=3;
          v0+=3;
          s++;
        }
      }
    }
    
    {
      int refine_normals = SettingGet_i(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_refine_normals);
      if(refine_normals<0) { 
        if(obj->NCSet>1) {
          int i,n_set =0;
          for(i=0;i<obj->NCSet;i++)
            if(obj->CSet[i]) {
              n_set++;
              if(n_set>1)
                refine_normals = 0; /* default behavior is to not refine normals for multi-state objects */
            }
        }
      }
      
      if(refine_normals) {
        
        /* first, make sure orientiation vectors are orthogonal to the tangent */
        
        v1 = tv+3;
        vo = pvo+3;
        s = seg+1;
        for(a=1;a<(nAt-1);a++) { 
          if((*s==*(s-1))&&(*s==*(s+1))) { /* only operate on vectors within the cartoon itself --
                                              not the end vectors */
            
            remove_component3f(vo,v1,t0);
            normalize23f(t0,vo);

            /* go on to next vertex */
          }
          v1+=3;
          vo+=3;
          s++;
        }
        
        /* now generate alternative inverted orientation vectors */
        
        va = pva;
        vo = pvo;
        ss = sstype;
        for(a=0;a<nAt;a++) { 
          
          /* original */
          copy3f(vo,va);
          va+=3;
          
          /* inverse */
          copy3f(vo,va);
          if(*ss!=1) invert3f(va); /* for helix, don't allow inversion of normals, 
                                      since that would confuse the inside & outside of the helix  */
          va+=3;
          
          /* go on to next vertex */
          
          vo+=3;
          ss++;
        }

        /* now iterate forward through pairs*/
        
        vo = pvo+3;
        va = pva+6;
        v  = nv+3; /* normals in direction of chain */
        s = seg+1;

        for(a=1;a<(nAt-1);a++) {
          
          if((*s==*(s+1))&&(*s==*(s-1))) { /* only operate within a segment */         
            remove_component3f(vo-3,v-3,o0); /* previous orientation vector */
            normalize3f(o0); /* is now perp to chain direction */

            v1 = va; /* candidate orientation vectors for current CA */

            remove_component3f(v1  ,v-3,o1  ); /* removes chain direction from the two candidates */
            remove_component3f(v1+3,v-3,o1+3);
            normalize3f(o1);
            normalize3f(o1+3);

            max_dot = dot_product3f(o0,o1); 
            v0 = v1;
            
            dp = dot_product3f(o0,o1+3);
            if(dp>max_dot) {
              v0 = v1+3;
              max_dot = dp;
            }
            copy3f(v0,vo); /* updates atom with optimal orientation vector */
          }
          vo+=3;
          va+=6; /* candidate orientation vectors */
          v+=3; /* normal */
          s++;
        }

        /* now soften up the kinks */
        v1 = tv+3;
        va = pva+6;
        vo = pvo+3;
        s = seg+1;
        for(a=1;a<(nAt-1);a++) {
          if((*s==*(s-1))&&(*s==*(s+1))) {
            dp = (dot_product3f(vo,vo+3)*
                  dot_product3f(vo,vo-3));
            if(dp<-0.10F) { /* threshold value -- could be a setting */
              add3f(vo+3,vo-3,t0);
              scale3f(vo,0.001,t1);
              add3f(t1,t0,t0);
              remove_component3f(t0,v1,t0);
              normalize3f(t0);
              if(dot_product3f(vo,t0)<0.0F) {
                subtract3f(vo,t0,t2);
              } else {
                add3f(vo,t0,t2);
              }
              normalize3f(t2);
              dp = 2*(-0.10F-dp);
              if(dp>1.0F)
                dp=1.0F;
              mix3f(vo,t2,dp,t3);
              copy3f(t3,va); /* store modified vector */
              invert3f3f(va,va+3);
            } else {
              copy3f(vo,va); /* keep as is */
            }
          }
          v1+=3;
          vo+=3;
          va+=6;
          s++;
        }

        /* now update */
        va = pva+6;
        vo = pvo+3;
        s = seg+1;
        for(a=1;a<(nAt-1);a++) {
          if((*s==*(s-1))&&(*s==*(s+1))) {
            copy3f(va,vo);
          }
          vo+=3;
          va+=6;
          s++;
        }
      }
    }

    if(SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_flat_sheets)) {
      s = seg;
      cc = car;
      v = pv;
      ss = sstype;
      vo = pvo;
      v0 = tv;
      last = 0;
      first = -1;
      cur_car = *cc;
      end_flag=false;
      if(nAt>1) {
        for(a=0;a<nAt;a++) {
          if(a) {
            if(*s!=*(s-1)) { 
              end_flag=true;
            } else if(*ss!=2) {
              end_flag=true;
            }
            if(a==(nAt-1)) {
              end_flag=1;
            }
          }
          if(end_flag) {
            if ((cur_car!=cCartoon_loop)&&(cur_car!=cCartoon_tube)) {
              
              f=1;
              for(c=0;c<flat_cycles;c++) {
                for(b=first+f;b<=last-f;b++) { /* iterative averaging */
                  zero3f(t0);
                  for(e=-f;e<=f;e++) {
                    add3f(pv+3*(b+e),t0,t0);
                  }
                  scale3f(t0,1.0F/(f*2+1),tmp+b*3);
                }
                for(b=first+f;b<=last-f;b++) {
                  if(!((*(flag_tmp+b)&cAtomFlag_no_smooth))) {
                    copy3f(tmp+b*3,pv+b*3);
                  }
                }
                for(b=first+f;b<=last-f;b++) { 
                  zero3f(t0);
                  for(e=-f;e<=f;e++) {
                    add3f(pvo+3*(b+e),t0,t0);
                  }
                  scale3f(t0,1.0F/(f*2+1),tmp+b*3);
                }
                for(b=first+f;b<=last-f;b++) {
                  copy3f(tmp+b*3,pvo+b*3);
                  /*                  normalize3f(pvo+b*3);*/
                }
                for(b=first+f;b<=last-f;b++) {
                  subtract3f(pv+(b+1)*3,pv+(b-1)*3,tmp+b*3);
                  normalize3f(tmp+b*3);
                  remove_component3f(pvo+b*3,tmp+b*3,pvo+b*3);
                  normalize3f(pvo+b*3);
                }
              }
            }
            first = -1;
            last = -1;
            end_flag=false;
          }
          if(*ss==2) {
            if(first<0)
              first=a;
            cur_car = *cc;
            last = a;
          } 
          v+=3;
          ss++;
          vo+=3;
          v0+=3;
          s++;
          cc++;
        }
      }
    }

    if(smooth_loops) {

      s = seg;
      v = pv;
      ss = sstype;
      vo = pvo;
      v0 = tv;
      last = 0;
      first = -1;
      end_flag=false;
      if(nAt>1) {
        for(a=0;a<nAt;a++) {

          if(a) {
            if(*s!=*(s-1)) { 
              end_flag=true;
            } else if(*ss!=0) {
              end_flag=true;
            }
            if(a==(nAt-1))
              end_flag=1;
          }
          if(end_flag) {

            if(a)
              if(first>0) /* 011130 WLD */
                if(*(seg+first)==*(seg+first-1))
                  first--;

            if(last>0)
              if(*s==*(s-1))
                if(last<(nAt-1)) 
                  last++;

            for(f=smooth_first;f<=smooth_last;f++) {
              for(c=0;c<smooth_cycles;c++) {
                for(b=first+f;b<=last-f;b++) { /* iterative averaging */
                  zero3f(t0);
                  for(e=-f;e<=f;e++) {
                    add3f(pv+3*(b+e),t0,t0);
                  }
                  scale3f(t0,1.0F/(f*2+1),tmp+b*3);
                }
                for(b=first+f;b<=last-f;b++) {
                  if(!(*(flag_tmp+b)&cAtomFlag_no_smooth)) {
                    copy3f(tmp+b*3,pv+b*3);
                  }
                }
                for(b=first+f;b<=last-f;b++) { 
                  zero3f(t0);
                  for(e=-f;e<=f;e++) {
                    add3f(pvo+3*(b+e),t0,t0);
                  }
                  scale3f(t0,1.0F/(f*2+1),tmp+b*3);
                }
                for(b=first+f;b<=last-f;b++) {
                  copy3f(tmp+b*3,pvo+b*3);
                  normalize3f(pvo+b*3);
                }
              }

            }
            first = -1;
            last = -1;
            end_flag=false;
          }
          if(*ss==0) {
            if(first<0)
              first=a;
            last = a;
          } 
          v+=3;
          ss++;
          vo+=3;
          v0+=3;
          s++;
        }
      }
    }
      
    if(smooth_loops ||
       SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_flat_sheets)) {
        
      /* recompute differences and normals */
        
      s=seg;
      v=pv;
      v1=dv;
      v2=nv;
      d=dl;
      for(a=0;a<(nAt-1);a++)
        {
          if(*s==*(s+1))
            {
              float d_1;
              subtract3f(v+3,v,v1);
              *d = (float)length3f(v1);
              if(*d>R_SMALL4) {
                d_1 = 1.0F/(*d);
                scale3f(v1,d_1,v2);
              } else if(a)  {
                copy3f(v2-3,v2); 
              } else {
                zero3f(v2);
              }
            }
          else {
            zero3f(v2); 
          }
          d++;
          v+=3;
          v1+=3;
          v2+=3;
          s++;
        }
      
      
      /* recompute tangents */
        
      s=seg;
      v=nv;
        
      v1=tv;
        
      *(v1++)=*(v++); /* first segment */
      *(v1++)=*(v++);
      *(v1++)=*(v++);
      s++;
        
      for(a=1;a<(nAt-1);a++)
        {
          if((*s==*(s-1))&&(*s==*(s+1)))
            {
              add3f(v,(v-3),v1);
               
              normalize3f(v1);                   
            }
          else if(*s==*(s-1))
            {
              *(v1)=*(v-3);  /* end a segment */
              *(v1+1)=*(v-2); 
              *(v1+2)=*(v-1); 
            }
          else if(*s==*(s+1))
            {
              *(v1)=*(v);   /* new segment */
              *(v1+1)=*(v+1); 
              *(v1+2)=*(v+2); 
            }
          v+=3;
          v1+=3;
          s++;
        }
        
      *(v1++)=*(v-3); /* last segment */
      *(v1++)=*(v-2);
      *(v1++)=*(v-1);

        
      if(SettingGet_f(G,cs->Setting,obj->Obj.Setting,cSetting_cartoon_flat_sheets)) {
        s=seg+1;
        ss = sstype+1;
        v2=tv+3; /* normal */
        for(a=1;a<(nAt-1);a++)
          {
            if((*ss==2)&&(*s==*(s+1))&&(*s==*(s-1))) { /* sheet in same segment */
              if((*ss==*(ss+1))&&(*ss!=*(ss-1))) { /* start, bias forwards */
                scale3f(v2+3,refine_tips,t0);
                add3f(t0,v2,v2);
                normalize3f(v2);
              } else if((*ss!=*(ss+1))&&(*ss==*(ss-1)))  { /* end, bias backwards */
                scale3f(v2-3,refine_tips,t0);
                add3f(t0,v2,v2);
                normalize3f(v2);
              }
            }
            v2+=3;
            s++;
            ss++;
          }

      }

    }
  }

  I->ray = CGONew(G);
  
  if(alpha!=1.0F)
    CGOAlpha(I->ray,alpha);

  /* debugging output */
  if(round_helices) {
    if((cartoon_debug>0.5)&&(cartoon_debug<2.5)) {
      CGOColor(I->ray,1.0,1.0,1.0);
      CGODisable(I->ray,GL_LIGHTING);
      CGOBegin(I->ray,GL_LINE_STRIP);
            
      v1 = NULL;
      v2 = NULL;
      v3 = NULL;
      v4 = NULL;
      v = pv;
      if(nAt>1) {
        CGOBegin(I->ray,GL_LINE_STRIP);
        for(a=0;a<nAt;a++) {
          v4 = v3;
          v3 = v2;
          v2 = v1;
          v1 = v;
          if(v1&&v2&&v3&&v4) {
            add3f(v1,v4,t0);
            add3f(v2,v3,t1);
            /*            scale3f(t0,0.2024,t0);
                          scale3f(t1,0.2727,t1);*/

            scale3f(t0,0.2130F,t0);
            scale3f(t1,0.2870F,t1);

            add3f(t0,t1,t0);
            CGOVertexv(I->ray,t0);
          }
          v+=3;
        }
        CGOEnd(I->ray);
      }
    }
  }

  PRINTFD(G,FB_RepCartoon)
    " RepCartoon-Debug: creating 3D scaffold...\n"
    ENDFD;

  /* okay, we now have enough info to generate smooth interpolations */

  if(nAt>1) {
    ex = ExtrudeNew(G);
    ExtrudeAllocPointsNormalsColors(ex,cs->NIndex*(3*sampling+3));
  }

  /* process cylindrical helices first */

  if((nAt>1)&&cylindrical_helices) {

    /* this is confusing because we're borrowing Extrude's arrays 
     * for convenient storage, but not actually calling Extrude */

    n_p = 0;
    v = ex->p;
    vc = ex->c;
    vn = ex->n; 
    vi = ex->i;

    last_color=-1;
    uniform_color=true;

    v1=pv; /* points */
    v2=tv; /* tangents */
    vo=pvo;
    d = dl;
    s=seg;
    cc=car;
    atp=at; /* cs index pointer */
    a=0;
    contFlag=true;
    cur_car = cCartoon_skip;
    extrudeFlag=false;
    contigFlag=false;

    while(contFlag) {
      if ((*cc)!=cur_car) { /* new cartoon type */
        if(n_p) { /* any cartoon points? */
          extrudeFlag=true;
        } else {
          cur_car = *(cc); /* now: go ahead and switch cartoons */
          n_p = 0;
          v = ex->p;
          vc = ex->c;
          vi = ex->i;
          vn = ex->n;
          last_color=-1;
          uniform_color=true;
        }
      }
      if(a&&!extrudeFlag) {
        if((*s)!=*(s-1)) { /* new segment */
          contigFlag=false;
          if(n_p) { /* any cartoon points? */
            extrudeFlag=true;
          } else {
            n_p = 0;
            v = ex->p;
            vc = ex->c;
            vi = ex->i;
            vn = ex->n;
            last_color=-1;
            uniform_color=true;
          }
        }
      }
      if(!extrudeFlag) {
        if((a<(nAt-1))&&(*s==*(s+1))) { /* working in the same segment... */
          atom_index1 = cs->IdxToAtm[*atp];
          atom_index2 = cs->IdxToAtm[*(atp+1)];
          c1=*(cs->Color+*atp);
          c2=*(cs->Color+*(atp+1));
          
          if(cartoon_color>=0) {
            c1 = (c2 = cartoon_color);
          }

          AtomInfoGetSetting_color(G,obj->AtomInfo + atom_index1, cSetting_cartoon_color, c1, &c1);
          AtomInfoGetSetting_color(G,obj->AtomInfo + atom_index2, cSetting_cartoon_color, c2, &c2);
          
          if(discrete_colors) {
            if(n_p==0) {
              if(contigFlag) {
                if(cur_car!=cCartoon_loop)
                  c2=c1;
                else {
                  if ((*cc+1)==cur_car)
                    c2=c1;
                  else
                    c1=c2;
                }
              } else if((cur_car==cCartoon_loop)&&
                        (*(cc+1)!=cCartoon_loop)) {
                c2=c1;
              }
            } else {
              if((cur_car==cCartoon_loop)&&
                 (*(cc+1)!=cCartoon_loop)) {
                c2=c1;
              }
            }/* not contig */
            
          }
          
          if((*(cc)==*(cc+1))&&(c1!=c2)) 
            uniform_color=false;
          if(last_color>=0) {
            if(c1!=last_color)
              uniform_color=false;
          }
          last_color=c1;
          
          v0 = ColorGet(G,c1);
          *(vc++)=*(v0++);
          *(vc++)=*(v0++);
          *(vc++)=*(v0++);
          *(vi++)=atom_index1;
          
          v0 = ColorGet(G,c2); /* kludge */
          *(vc  )=*(v0++);
          *(vc+1)=*(v0++);
          *(vc+2)=*(v0++);
          *(vi  )=atom_index2;
        } else {
          vc+=3; /* part of kludge */
          vi++;
        }
        if(cur_car==cCartoon_skip_helix) {
          if(!n_p) {
            h_start=v1;
            h_end=v1;
          } else {
            h_end = v1;
          }
          copy3f(v1,v); /* just store coordinates until we have a complete cylinder */
          v+=3;
          n_p++;
        }
        v1+=3;
        v2+=3;
        v3+=3;
        vo+=3;
        d++;
        atp++;
        s++;
        cc++;
      } 
      
      a++;
      if(a==nAt) {
        contFlag=false;
        if(n_p) 
          extrudeFlag=true;
      }
      
      if(extrudeFlag) { /* generate cylinder */
        contigFlag=true;
        if((a<nAt)&&extrudeFlag) {
          if(*(s-1)!=*(s))
            contigFlag=false;
        }
        
        if(n_p>1) {
          atom_index1 = cs->IdxToAtm[*(atp-1)];
          c1=*(cs->Color+*(atp-1));

          if(cartoon_color>=0) {
            c1 = cartoon_color;
          }
          
          AtomInfoGetSetting_color(G,obj->AtomInfo + atom_index1, cSetting_cartoon_color, c1, &c1);

          if(n_p<5) {
            copy3f(ex->p,t3);
            copy3f(v-3,t4);
          } else {
            add3f(ex->p,ex->p+9,t0);
            add3f(ex->p+3,ex->p+6,t1);
            scale3f(t0,0.2130F,t0);
            scale3f(t1,0.2870F,t1);
            add3f(t0,t1,t3);

            add3f(v-3,v-12,t0);
            add3f(v-6,v-9,t1);
            scale3f(t0,0.2130F,t0);
            scale3f(t1,0.2870F,t1);
            add3f(t0,t1,t4);

            /* extend helix to line up with CA */
            subtract3f(t4,t3,t0);
            normalize3f(t0);
            subtract3f(v-3,t3,t1);
            project3f(t1,t0,t4);
            add3f(t3,t4,t4);
            invert3f(t0);
            subtract3f(ex->p,t4,t1);
            project3f(t1,t0,t3);
            add3f(t3,t4,t3);

            /* relocate terminal CA to touch helix, if necessary */
            
            if(h_start&&h_end) {
              subtract3f(h_start,t3,t0);
              f0 = helix_radius-loop_radius*2;
              if(length3f(t0)>f0) {
                normalize3f(t0);
                scale3f(t0,f0,t1);
                add3f(t1,t3,h_start);
              }
              
              subtract3f(h_end,t4,t0);
              if(length3f(t0)>f0) {
                normalize3f(t0);
                scale3f(t0,f0,t1);
                add3f(t1,t4,h_end);
              }
            }
          }

          /* push helix out a tad to consume loop */
          
          subtract3f(t4,t3,t0);
          normalize3f(t0);
          scale3f(t0,loop_radius*2,t0);
          add3f(t0,t4,t4);
          invert3f(t0);
          add3f(t0,t3,t3);

          if(uniform_color) {
            CGOCylinderv(I->ray,t3,t4,helix_radius,ex->c,ex->c);
            
          } else {
            subtract3f(t4,t3,t0);
            n_pm1=n_p-1;
            n_pm2=n_p-2;
            for(b=0;b<n_pm1;b++) {
              if(!b) {
                scale3f(t0,((float)b-0.005F)/n_pm1,t1); /* add small overlap */
              } else {
                scale3f(t0,((float)b)/n_pm1,t1);
              }
              if(b<n_pm2) {
                scale3f(t0,((float)b+1.005F)/n_pm1,t2);
              } else {
                scale3f(t0,((float)b+1)/n_pm1,t2);                
              }
              add3f(t3,t1,t1);
              add3f(t3,t2,t2);
              CGOCustomCylinderv(I->ray,t1,t2,helix_radius,ex->c+(b*3),ex->c+(b+1)*3,
                                 (float)(b ? 0 : cCylCapFlat),
                                 (float)(b == n_pm2 ? cCylCapFlat : 0 ));
            }
          }
        }
        a--; /* undo above... */
        extrudeFlag=false;
        n_p = 0;
        v = ex->p;
        vc = ex->c;
        vi = ex->i;
        vn = ex->n;
        uniform_color=true;
        last_color=-1;
      }
    }
  }
  
  if(nAt>1) 
    {
      n_p = 0;
      v = ex->p;
      vc = ex->c;
      vn = ex->n;
      vi = ex->i;      

      v1=pv; /* points */
      v2=tv; /* tangents */
      vo=pvo;
      d = dl;
      s=seg;
      cc=car;
      atp=at; /* cs index pointer */
      a=0;
      contFlag=true;
      cur_car = cCartoon_skip;
      extrudeFlag=false;
      contigFlag=false;
      
      while(contFlag) {
        

        if ((*cc)!=cur_car) { /* new cartoon type */
          if(n_p) { /* any cartoon points? */
            extrudeFlag=true;
          } else {
            cur_car = *(cc); /* no: go ahead and switch cartoons */
            ExtrudeTruncate(ex,0);
            n_p = 0;
            v = ex->p;
            vc = ex->c;
            vn = ex->n;
            vi = ex->i;
          }
        }

        /* CONFUSION ALERT -- I don't understand the following code (anymore) */

        if(a<(nAt-1)) {
          /* put a setting controlled conditional here.. */
          if (((*(cc+1))!=cur_car)&&(cur_car!=cCartoon_loop)) { /* end of segment */
            if(n_p) { /* any cartoon points? */
              extrudeFlag=true;
            } else {
              cur_car = cCartoon_loop; /* no: go ahead and switch cartoons */
              ExtrudeTruncate(ex,0);
              n_p = 0;
              v = ex->p;
              vc = ex->c;
              vn = ex->n;
              vi = ex->i;
            }
          }
        }
        if((a<(nAt-1))&&!extrudeFlag) {
          if((*s)!=*(s+1)) { /* new segment */
            contigFlag=false;
            if(n_p) { /* any cartoon points? */
              extrudeFlag=true;
            } else {
              ExtrudeTruncate(ex,0);
              n_p = 0;
              v = ex->p;
              vc = ex->c;
              vn = ex->n;
              vi = ex->i;
            }
          }
        }
        if(!extrudeFlag) {
          if((a<(nAt-1))&&(*s==*(s+1))) /* working in the same segment... */
            {
              c1=*(cs->Color+*atp);
              c2=*(cs->Color+*(atp+1));
              atom_index1 = cs->IdxToAtm[*atp];
              atom_index2 = cs->IdxToAtm[*(atp+1)];

              if(cartoon_color>=0) {
                c1 = (c2 = cartoon_color);
              }

              AtomInfoGetSetting_color(G,obj->AtomInfo + atom_index1, cSetting_cartoon_color, c1, &c1);
              AtomInfoGetSetting_color(G,obj->AtomInfo + atom_index2, cSetting_cartoon_color, c2, &c2);

              if(nuc_flag[*atp]||nuc_flag[*(atp+1)]) { /* this is a nucleic acid ribbon */
                if(nucleic_color>=0) {
                  c1 = (c2 = nucleic_color);
                }
              }
              
              if(discrete_colors) {
                if(n_p==0) {
                  if(contigFlag) {
                    if(cur_car!=cCartoon_loop)
                      c2=c1;
                    else {
                      if ((*cc+1)==cur_car)
                        c2=c1;
                      else
                        c1=c2;
                    }
                  } else if((cur_car==cCartoon_loop)&&
                            (*(cc+1)!=cCartoon_loop)) {
                    c2=c1;
                  }
                } else {
                  if((cur_car==cCartoon_loop)&&
                     (*(cc+1)!=cCartoon_loop)) {
                    c2=c1;
                  }
                }/* not contig */
              }
            
              
              dev = throw*(*d);
              for(b=0;b<sampling;b++) /* needs optimization */
                {
                
                  if(n_p==0) {
                  
                    /* provide starting point on first point in segment only... */

                    f0 = ((float)b)/sampling; /* fraction of completion */
                    if(f0<=0.5) {
                      v0 = ColorGet(G,c1);
                      i0 = atom_index1;
                    } else {
                      v0 = ColorGet(G,c2);
                      i0 = atom_index2;
                    }
                    f0 = smooth(f0,power_a); /* bias sampling towards the center of the curve */
                  
                    /* store colors */
                  
                    *(vc++)=*(v0++);
                    *(vc++)=*(v0++);
                    *(vc++)=*(v0++);
                    *(vi++)=i0;
                    /* start of line/cylinder */
                  
                    f1 = 1.0F-f0;
                    f2 = smooth(f0,power_b);
                    f3 = smooth(f1,power_b);
                    f4 = dev*f2*f3; /* displacement magnitude */

                    *(v++)=f1*v1[0]+f0*v1[3]+
                      f4*( f3*v2[0]-f2*v2[3] );

                    *(v++)=f1*v1[1]+f0*v1[4]+
                      f4*( f3*v2[1]-f2*v2[4] );

                    *(v++)=f1*v1[2]+f0*v1[5]+
                      f4*( f3*v2[2]-f2*v2[5] );

                    vn+=9;

                    copy3f(vo,vn-6); /* starter... */

                    n_p++;

                  }

                  f0=((float)b+1)/sampling;
                  if(f0<=0.5) {
                    v0 = ColorGet(G,c1);
                    i0 = atom_index1;
                  } else {
                    v0 = ColorGet(G,c2);
                    i0 = atom_index2;
                  }
                  f0=smooth(f0,power_a); /* bias sampling towards the center of the curve */                
                

                  /* store colors */
                
                  *(vc++)=*(v0++);
                  *(vc++)=*(v0++);
                  *(vc++)=*(v0++);
                  *(vi++)=i0;

                  /* end of line/cylinder */
                
                  f1=1.0F-f0;
                  f2=smooth(f0,power_b);
                  f3=smooth(f1,power_b);
                  f4 = dev*f2*f3; /* displacement magnitude */
                
                  *(v++)=f1*v1[0]+f0*v1[3]+
                    f4*( f3*v2[0]-f2*v2[3] );
                
                  *(v++)=f1*v1[1]+f0*v1[4]+
                    f4*( f3*v2[1]-f2*v2[4] );
                
                  *(v++)=f1*v1[2]+f0*v1[5]+
                    f4*( f3*v2[2]-f2*v2[5] );
                
                  /*                remove_component3f(vo,v2,o0);
                                    remove_component3f(vo+3,v2,o0+3);*/
                
                  vn+=3;
                  *(vn++)=f1*(vo[0]*f2)+f0*(vo[3]*f3);
                  *(vn++)=f1*(vo[1]*f2)+f0*(vo[4]*f3);
                  *(vn++)=f1*(vo[2]*f2)+f0*(vo[5]*f3);                 
                  vn+=3;

                  if(b==sampling-1)
                    copy3f(vo+3,vn-6); /* starter... */                  
                  n_p++;
                
                }

              /* now do a smoothing pass along orientation 
                 vector to smooth helices, etc... */

              c = refine;
              cross_product3f(vn+3-(sampling*9),vn+3-9,t0);

              cross_product3f(vo,vo+3,t0);
              if((sampling>1)&&length3f(t0)>R_SMALL4) {

                normalize3f(t0);
                while(c--) {
                  p0=v-(sampling*3)-3;
                  p1=v-(sampling*3);
                  p2=v-(sampling*3)+3;
                  for(b=0;b<(sampling-1);b++) {
                    f0=dot_product3f(t0,p0);
                    f1=dot_product3f(t0,p1);
                    f2=dot_product3f(t0,p2);
                  
                    f3 = (f2+f0)/2.0F;
                    scale3f(t0,f3-f1,t1);
                    p3 = sampling_tmp+b*3;
                    add3f(t1,p1,p3);
                  
                    p0=p1;
                    p1=p2;
                    p2+=3;
                  }
                  p1=v-(sampling*3);
                  for(b=0;b<(sampling-1);b++) {
                    p3 = sampling_tmp+b*3;
                    copy3f(p3,p1);
                    p1+=3;
                  }
                }
              }
            }
          v1+=3;
          v2+=3;
          v3+=3;
          vo+=3;
          d++;
          atp+=1;
          s++;
          cc++;

        }


        a++;
        if(a==nAt) {
          contFlag=false;
          if(n_p) 
            extrudeFlag=true;
        }
        if(extrudeFlag) {
          contigFlag=true;
          if((a<nAt)&&extrudeFlag) {
            if(*(s-1)!=*(s))
              contigFlag=false;
          }

          if((cur_car!=cCartoon_skip)&&
             (cur_car!=cCartoon_skip_helix)) {
            
            if((cartoon_debug>0.5)&&(cartoon_debug<2.5)) {
              CGOColor(I->ray,0.0,1.0,0.0);

              v = ex->p;
              vn = ex->n+3;
              CGODisable(I->ray,GL_LIGHTING);
              CGOBegin(I->ray,GL_LINES);
              for(b=0;b<n_p;b++) 
                {
                  CGOVertexv(I->ray,v);
                  add3f(v,vn,t0);
                  CGOVertexv(I->ray,t0);
                  v+=3;
                  vn+=9;
                }
              CGOEnd(I->ray);
              CGOEnable(I->ray,GL_LIGHTING);
            }
            

            ExtrudeTruncate(ex,n_p);
            ExtrudeComputeTangents(ex);
          
            /* set up shape */
            switch(cur_car) {
            case cCartoon_tube:
              ExtrudeCircle(ex,tube_quality,tube_radius);
              ExtrudeBuildNormals1f(ex);
              ExtrudeCGOSurfaceTube(ex,I->ray,tube_cap,NULL);
              break;
            case cCartoon_putty:
              ExtrudeCircle(ex,putty_quality,putty_radius);
              ExtrudeBuildNormals1f(ex);
              ExtrudeComputeScaleFactors(ex,obj,0,
                                         putty_mean,putty_stdev,
                                         SettingGet_f(G,cs->Setting,obj->Obj.Setting,
                                                      cSetting_cartoon_putty_scale_power),
                                         SettingGet_f(G,cs->Setting,obj->Obj.Setting,
                                                      cSetting_cartoon_putty_range),
                                         SettingGet_f(G,cs->Setting,obj->Obj.Setting,
                                                      cSetting_cartoon_putty_scale_min),
                                         SettingGet_f(G,cs->Setting,obj->Obj.Setting,
                                                      cSetting_cartoon_putty_scale_max),
                                         sampling/2);

              ExtrudeCGOSurfaceVariableTube(ex,I->ray,1);
              break;
            case cCartoon_loop:
              ExtrudeCircle(ex,loop_quality,loop_radius);
              ExtrudeBuildNormals1f(ex);
              ExtrudeCGOSurfaceTube(ex,I->ray,loop_cap,NULL);
              break;
            case cCartoon_rect:
              if(highlight_color<0) {
                ExtrudeRectangle(ex,width,length,0);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygon(ex,I->ray,1,NULL);
              } else {
                ExtrudeRectangle(ex,width,length,1);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygon(ex,I->ray,0,NULL);
                ExtrudeRectangle(ex,width,length,2);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygon(ex,I->ray,1,ColorGet(G,highlight_color));
              }
              break;
            case cCartoon_oval:
              ExtrudeOval(ex,oval_quality,oval_width,oval_length);
              ExtrudeBuildNormals2f(ex);
              if(highlight_color<0) 
                ExtrudeCGOSurfaceTube(ex,I->ray,1,NULL);
              else 
                ExtrudeCGOSurfaceTube(ex,I->ray,1,ColorGet(G,highlight_color));
              break;
            case cCartoon_arrow:
              ExtrudeRectangle(ex,width,length,0);
              ExtrudeBuildNormals2f(ex);
              if(highlight_color<0) 
                ExtrudeCGOSurfaceStrand(ex,I->ray,sampling,NULL);
              else
                ExtrudeCGOSurfaceStrand(ex,I->ray,sampling,ColorGet(G,highlight_color));                

              /* for PLY files      
                 ExtrudeCircle(ex,loop_quality,loop_radius);
                 ExtrudeBuildNormals1f(ex);
                 ExtrudeCGOSurfaceTube(ex,I->ray,loop_cap,NULL);
              */
              break;
            case cCartoon_dumbbell:
              if(highlight_color<0) {
                ExtrudeDumbbell1(ex,dumbbell_width,dumbbell_length,0);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygonTaper(ex,I->ray,sampling,NULL);
              } else {

                ExtrudeDumbbell1(ex,dumbbell_width,dumbbell_length,1);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygonTaper(ex,I->ray,sampling,NULL);

                ExtrudeDumbbell1(ex,dumbbell_width,dumbbell_length,2);
                ExtrudeBuildNormals2f(ex);
                ExtrudeCGOSurfacePolygonTaper(ex,I->ray,sampling,ColorGet(G,highlight_color));
              }
              /*
                ExtrudeCGOSurfacePolygonX(ex,I->ray,1);*/

              ex1 = ExtrudeCopyPointsNormalsColors(ex);
              ExtrudeDumbbellEdge(ex1,sampling,-1,dumbbell_length);
              ExtrudeComputeTangents(ex1);
              ExtrudeCircle(ex1,loop_quality,dumbbell_radius);
              ExtrudeBuildNormals1f(ex1);

              ExtrudeCGOSurfaceTube(ex1,I->ray,1,NULL);
              ExtrudeFree(ex1);

              ex1 = ExtrudeCopyPointsNormalsColors(ex);
              ExtrudeDumbbellEdge(ex1,sampling,1,dumbbell_length);
              ExtrudeComputeTangents(ex1);
              ExtrudeCircle(ex1,loop_quality,dumbbell_radius);
              ExtrudeBuildNormals1f(ex1);
              ExtrudeCGOSurfaceTube(ex1,I->ray,1,NULL);
              ExtrudeFree(ex1);

              break;
            }
          }
          a--; /* undo above... */
          extrudeFlag=false;
          ExtrudeTruncate(ex,0);
          n_p = 0;
          v = ex->p;
          vc = ex->c;
          vn = ex->n;
        }
      }
    }


  if(nAt>1) {
    if((cartoon_debug>0.5)&&(cartoon_debug<2.5)) {
      CGOColor(I->ray,1.0,1.0,1.0);
      CGODisable(I->ray,GL_LIGHTING);
      CGOBegin(I->ray,GL_LINES);
      v1=pv;
      v2=pvo;
      v3=tv;
      for(a=0;a<nAt;a++) 
        {
          CGOVertexv(I->ray,v1);
          add3f(v1,v2,t0);
          add3f(v2,t0,t0);
          CGOVertexv(I->ray,t0);
          subtract3f(v1,v3,t0);
          CGOVertexv(I->ray,t0);
          add3f(v1,v3,t0);
          CGOVertexv(I->ray,t0);
          v1+=3;
          v2+=3;
          v3+=3;
        }
      CGOEnd(I->ray);

      CGOEnable(I->ray,GL_LIGHTING);
    }
  }
  if(ex) {
    ExtrudeFree(ex); 
  }
  /* draw the rings */

  if(ring_anchor && n_ring) {
    int ring_i;
    int mem[8];
    int nbr[7];
    int *neighbor;
    int *marked = Calloc(int,obj->NAtom);
    float *moved = Calloc(float,obj->NAtom*3);
    
    register int escape_count; 
    register int *atmToIdx = NULL;
    
    if(!obj->DiscreteFlag) atmToIdx = cs->AtmToIdx;

    ObjectMoleculeUpdateNeighbors(obj);
    neighbor = obj->Neighbor;  
    
    escape_count = ESCAPE_MAX; /* don't get bogged down with structures 
                                  that have unreasonable connectivity */
    for(ring_i=0;ring_i<n_ring;ring_i++) {
      mem[0] = ring_anchor[ring_i];
      nbr[0]= neighbor[mem[0]]+1;
      while(((mem[1] = neighbor[nbr[0]])>=0)&&
            ((!atmToIdx)||(atmToIdx[mem[0]]>=0))) {
        nbr[1] = neighbor[mem[1]]+1;
        while(((mem[2] = neighbor[nbr[1]])>=0)&&
              ((!atmToIdx)||(atmToIdx[mem[1]]>=0))) {
          if(mem[2]!=mem[0]) {
            nbr[2] = neighbor[mem[2]]+1;
            while(((mem[3] = neighbor[nbr[2]])>=0)&&
                  ((!atmToIdx)||(atmToIdx[mem[2]]>=0))) {
              if(mem[3]!=mem[1]) {
                nbr[3] = neighbor[mem[3]]+1;
                while(((mem[4] = neighbor[nbr[3]])>=0)&&
                      ((!atmToIdx)||(atmToIdx[mem[3]]>=0))) {
                  if((mem[4]!=mem[2])&&(mem[4]!=mem[1])&&(mem[4]!=mem[0])) {            
                    nbr[4] = neighbor[mem[4]]+1;              
                    while(((mem[5] = neighbor[nbr[4]])>=0)&&
                          ((!atmToIdx)||(atmToIdx[mem[4]]>=0))) {
                      if(!(escape_count--)) goto escape;
                      if((mem[5]!=mem[3])&&(mem[5]!=mem[2])&&(mem[5]!=mem[1])) { 
                        if(mem[5]==mem[0]) { /* five-cycle */
                          /*    printf(" 5: %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)\n",
                                obj->AtomInfo[mem[0]].name,mem[0],
                                obj->AtomInfo[mem[1]].name,mem[1],
                                obj->AtomInfo[mem[2]].name,mem[2],
                                obj->AtomInfo[mem[3]].name,mem[3],
                                obj->AtomInfo[mem[4]].name,mem[4]); */
                          do_ring(G,5,mem,obj, cs, ring_width, I->ray, ring_color, ring_mode,
                                  ladder_radius, ladder_color, ladder_mode, ring_finder,
                                  cartoon_side_chain_helper, nuc_flag, na_mode, 
                                  ring_alpha, alpha, marked, moved, ring_radius);

                        }
                        
                        nbr[5] = neighbor[mem[5]]+1;              
                        while(((mem[6] = neighbor[nbr[5]])>=0)&&
                              ((!atmToIdx)||(atmToIdx[mem[5]]>=0))) {
                          if((mem[6]!=mem[4])&&(mem[6]!=mem[3])&&(mem[6]!=mem[2])&&(mem[6]!=mem[1])) {
                            if(mem[6]==mem[0]) {  /* six-cycle */
                              /* printf(" 6: %s %s %s %s %s %s\n",
                                 obj->AtomInfo[mem[0]].name,
                                 obj->AtomInfo[mem[1]].name,
                                 obj->AtomInfo[mem[2]].name,
                                 obj->AtomInfo[mem[3]].name,
                                 obj->AtomInfo[mem[4]].name,
                                 obj->AtomInfo[mem[5]].name
                                 ); */
                              do_ring(G,6,mem,obj, cs, ring_width, I->ray, ring_color, ring_mode,
                                      ladder_radius, ladder_color, ladder_mode, ring_finder,
                                      cartoon_side_chain_helper, nuc_flag, na_mode, 
                                      ring_alpha, alpha, marked, moved, ring_radius);
                            }
                            nbr[6] = neighbor[mem[6]]+1;              
                            while(((mem[7] = neighbor[nbr[6]])>=0)&&
                                  ((!atmToIdx)||(atmToIdx[mem[6]]>=0))) {
                              if((mem[7]!=mem[5])&&(mem[7]!=mem[4])&&(mem[7]!=mem[3])&&
                                 (mem[7]!=mem[2])&&(mem[7]!=mem[1])) { 
                                if(mem[7]==mem[0]) {
                                  do_ring(G,7,mem,obj, cs, ring_width, I->ray, ring_color, ring_mode,
                                          ladder_radius, ladder_color, ladder_mode, ring_finder,
                                          cartoon_side_chain_helper, nuc_flag, na_mode,
                                          ring_alpha, alpha, marked, moved, ring_radius);
                                }
                              }
                              nbr[6]+=2;
                            }
                          }
                          nbr[5]+=2;                          
                        }
                      }
                      nbr[4]+=2;
                    }
                  }
                  nbr[3]+=2;
                }
              }
              nbr[2]+=2;
            }
          }
          nbr[1]+=2;
        }
        nbr[0]+=2;
      }
    escape:
      escape_count = ESCAPE_MAX; /* don't get bogged down with structures 
                                    that have unreasonable connectivity */
    }
    FreeP(marked);
    FreeP(moved);
  }
  CGOStop(I->ray);
  I->std = CGOSimplify(I->ray,0);
  FreeP(dv);
  FreeP(dl);
  FreeP(tv);
  FreeP(nv);
  FreeP(at);
  FreeP(seg);
  FreeP(pv);
  FreeP(pvo);
  FreeP(pva);
  FreeP(car);
  FreeP(tmp);
  FreeP(sstype);
  FreeP(sampling_tmp);
  FreeP(flag_tmp);
  FreeP(nuc_flag);
  VLAFreeP(ring_anchor);
  return((void*)(struct Rep*)I);
}


  
    

Generated by  Doxygen 1.6.0   Back to index