Protein* SetDihedrals (int numResidues, const int type[],
      const char pred[], const double phi[], const double psi[]) {
   int i, j, k, l, m, n;
   double v0[4], v1[4], v2[4], v3[4], v4[4], pos[4];
     double mainpos[4]={0.0,0.0,0.0,0.0};
   double a[4][4], b[4][4], c[4][4], d[4][4], e[4][4], f[4][4], g[4][4];
   #if WRITEPDBFILE
   FILE *fp;
   const char outfile[14] = "StandardHelix.pdb";
   #endif
   Protein* result=new Protein;
   int currentResidueIndex=-1;
   Protein::ResidueCreator proteinCreator(result);
     Protein::SecondaryStructure::StructureType currentStructureType=Protein::SecondaryStructure::NONE;
   char chainId[2], pc;
   char elementName[2];
   int residueIndex;
   char* atomNamePtr;


   if(numResidues <= 0) return result;
   #if WRITEPDBFILE
   fp = fopen(outfile, "w");
   if (fp == 0) {
      printf("unable to open file %s\n", outfile);
      assert (fp != 0);
      }
   #endif
  n = 1;
  identity4(a);

//  Standard amino acids have CA at the origin and N at -residue_d2,
//  so translate to put N at the origin. Standard amino acids also
//  have C in the xy plane, but not necessarily carbonyl O.

    for (i = -1; i < numResidues+1; ++i)
    {
        if(i==-1||i==numResidues)
        {
            const char* residuePdbName;
            if (i == -1)
            {
                j = 0;
                residuePdbName="ACE";
            }
            else
            {
                j = 14;
                residuePdbName="NME";
            }
            Protein::SecondaryStructure::StructureType newStructureType;
            newStructureType=Protein::SecondaryStructure::COIL;
            if(newStructureType!=currentStructureType)
            {
                proteinCreator.newSecondaryStructure(newStructureType);
                currentStructureType=newStructureType;
            }
            proteinCreator.newResidue(residuePdbName,i+1);
            for (k = 0; k <  numbAtoms[j]; ++k)
            {
                for (m = 0; m < 3; ++m)
                    pos[m] = residueAtomPos[j][k][m] + mainpos[m];
                pos[1] += 1;
                pos[0] -= 0.8;
                #if WRITEPDBFILE
                fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
                        n, residueAtomName[j][k], residuePdbName,
                        i+1, pos[0], pos[1], pos[2], 0., 0.);
                #endif
                ++n;
                atomNamePtr=residueAtomName[j][k];
                while(isspace(*atomNamePtr))
                    ++atomNamePtr;
                elementName[0]=*atomNamePtr;
                ++atomNamePtr;
                elementName[1]='\0';
                proteinCreator.addAtom(elementName, n-1 ,Position(pos), atomNamePtr);
            }
        }
        else
        {
            j = type[i];
            pc = pred[i];
            Protein::SecondaryStructure::StructureType newStructureType;
            if (pc == 'C')
                newStructureType=Protein::SecondaryStructure::COIL;
            else if (pc == 'H')
                newStructureType=Protein::SecondaryStructure::ALPHA_HELIX;
            else if (pc == 'E')
                newStructureType=Protein::SecondaryStructure::BETA_STRAND;
            else
            {
                printf("Unknown secondary structure type.\n");
                exit(-1);
            }
            if(newStructureType!=currentStructureType)
            {
                proteinCreator.newSecondaryStructure(newStructureType);
                currentStructureType=newStructureType;
            }
            proteinCreator.newResidue(Protein::Residue::abbreviatedNames[j],i+1);

            translate4d(residued2[j], 0., 0., b);
            matmult4(a, b, c);
            rotX4(PI-StandardPhi[j], b);
            //   printf("StandardPhi[%d] = %f\n", j, StandardPhi[j]);
            matmult4(c, b, f);              // f is for the amide H

            //  First do NH

            if(j == 16)
                l = 1; 
            else
                l = 2;
            for (k = 0; k < l; ++k)
            {
                for (m = 0; m < 3; ++m)
                    v0[m] = residueAtomPos[j][k][m];
                v0[3] = 1.;
                if(k == 0) matrix_vector4(c, v0, mainpos);
                else  matrix_vector4(f, v0, mainpos);
                #if WRITEPDBFILE
                fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
                        n, residueAtomName[j][k], Protein::Residue::abbreviatedNames[j],
                        i+1, mainpos[0], mainpos[1], mainpos[2], 0., 0.);
                #endif
                ++n;

                atomNamePtr=residueAtomName[j][k];
                while(isspace(*atomNamePtr))
                    ++atomNamePtr;
                elementName[0]=*atomNamePtr;
                ++atomNamePtr;
                elementName[1]='\0';
                proteinCreator.addAtom(elementName, n-1 ,Position(mainpos), atomNamePtr);
                //  printf("%d %4s %4s %4s\n",
                //            n-1, elementName, atomNamePtr, residueAtomName[j][k]);
            }
            rotX4(phi[i], b);
            matmult4(c, b, a);              // a continuing backbone
            rotZ4(StandardAlpha[j], b);
            matmult4(a, b, c);
            rotX4(psi[i], b);
            matmult4(c, b, d);              // d is to help continue backbone
            rotX4(StandardPsi[j], b);      // to bring O to plane of next N and CA
            matmult4(d, b, g);
            rotZ4(-StandardAlpha[j], b);
            matmult4(g, b, e);              // e is for carbonyl oxygen

            //  Now do rest of atoms

            for (k = l; k <  numbAtoms[j]; ++k)
            {
                for (m = 0; m < 3; ++m)
                    v0[m] = residueAtomPos[j][k][m];
                v0[3] = 1.;
                if (k == l+3)
                    matrix_vector4(e, v0, pos);
                else
                    matrix_vector4(a, v0, pos);
                #if WRITEPDBFILE
                fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
                        n, residueAtomName[j][k], Protein::Residue::abbreviatedNames[j],
                        i+1, pos[0], pos[1], pos[2], 0., 0.);
                #endif
                ++n;
                atomNamePtr=residueAtomName[j][k];
                while(isspace(*atomNamePtr))
                    ++atomNamePtr;
                elementName[0]=*atomNamePtr;
                ++atomNamePtr;
                elementName[1]='\0';
                proteinCreator.addAtom(elementName, n-1 ,Position(pos), atomNamePtr);
            }
            // Now build up rest of main chain effect on matrix a

            translate4d(residued3[j], 0., 0., b);
            matmult4(d, b, c);
            rotZ4(StandardBeta[j], b);
            matmult4(c, b, d);
            translate4d(1.325, 0., 0., b);
            matmult4(d, b, c);
            rotX4(PI, b);
            matmult4(c, b, d);
            rotZ4(StandardGamma[j], b);
            matmult4(d, b, a);
            //   printf("Alpha %f  Beta %f  Gamma %f\n", 180*StandardAlpha[j]/PI,
            //      180*StandardBeta[j]/PI, 180*StandardGamma[j]/PI);
        }
    }

  #if WRITEPDBFILE
  fclose(fp);
  #endif
  proteinCreator.finishProtein();
  SetStandardHelix();
  return result;
  }
//redisplay event handler
void Display::redisplay()
{
  int i = 0;
	 //4d rendering
  GLdouble hypercube[16][5] = {
		//front four vertices
		{-1.0, -1.0, 1.0, 1.0, 1.0},
		{ 1.0, -1.0, 1.0, 1.0, 1.0},
		{ 1.0,  1.0, 1.0, 1.0, 1.0},
		{-1.0,  1.0, 1.0, 1.0, 1.0},
		//back four vertices
		{-1.0, -1.0, -1.0, 1.0, 1.0},
		{ 1.0, -1.0, -1.0, 1.0, 1.0},
		{ 1.0,  1.0, -1.0, 1.0, 1.0},
		{-1.0,  1.0, -1.0, 1.0, 1.0},
		//same in 4d (back square)
		//front four vertices
		{-1.0, -1.0, 1.0, -1.0, 1.0},
		{ 1.0, -1.0, 1.0, -1.0, 1.0},
		{ 1.0,  1.0, 1.0, -1.0, 1.0},
		{-1.0,  1.0, 1.0, -1.0, 1.0},
		//back four vertices
		{-1.0, -1.0, -1.0, -1.0, 1.0},
		{ 1.0, -1.0, -1.0, -1.0, 1.0},
		{ 1.0,  1.0, -1.0, -1.0, 1.0},
		{-1.0,  1.0, -1.0, -1.0, 1.0},
	};

  GLdouble transformedHypercube[16][5];

  GLdouble modelview4d[5][5] = {
	  {1.0, 0.0, 0.0, 0.0, 0.0},
	  {0.0, 1.0, 0.0, 0.0, 0.0},
	  {0.0, 0.0, 1.0, 0.0, 0.0},
	  {0.0, 0.0, 0.0, 1.0, 0.0},
	  {0.0, 0.0, 0.0, 0.0, 1.0},
  };
  GLdouble projection[5][5] = {
	  {1.0, 0.0, 0.0, 0.0, 0.0},
	  {0.0, 1.0, 0.0, 0.0, 0.0},
	  {0.0, 0.0, 1.0, 0.0, 0.0},
	  {0.0, 0.0, 0.0, 1.0, 0.0},
	  {0.0, 0.0, 0.0, 0.0, 0.0},
  };
  
  
  //rotate and tranlsate
  if(_freeLook)
    translate4d(modelview4d, _eye);

  rotate4d(modelview4d, _theta[0], 0);
  rotate4d(modelview4d, _theta[1], 1);
  rotate4d(modelview4d, _theta[2], 2);
  rotate4d(modelview4d, _theta[3], 3);

  if(!_freeLook)
    translate4d(modelview4d, _eye);



  translate4d(modelview4d, _d);
  //printMatrix(modelview4d);
  //transform hypercube
  for(i = 0; i < 16; ++i){   
    matrixCoordinateProduct(modelview4d, hypercube[i], transformedHypercube[i]);  
  }

  //set 4d projection matrix
  projection[4][3] = 1.0 / _frustum[6];


  //project into 3d
  for(i = 0; i < 16; ++i){   
    matrixCoordinateProduct(projection, transformedHypercube[i], transformedHypercube[i]);
    
  }

  //perspective division
  for(i = 0; i < 16; ++i){   
    perspectiveDivision(transformedHypercube[i]);
    printCoordinate(transformedHypercube[i]);
  }

  //give to OpenGL
  
  
  glClearColor(0.0, 0.0, .0, 0.0);
  glClearDepth(1.0);
  glClear(GL_COLOR_BUFFER_BIT );
  glClear(GL_DEPTH_BUFFER_BIT);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  //render the hypercube in 3d
  
  drawWireHypercube(transformedHypercube) ;

  //set the camera matrix (V)
  //Translation before rotation is free looking.  Rotation before
  //translation is fixed looking.
  //*old note
  //[Note that is is important to rotate before translating.  This 
  //gives the effect that camera is rotating rather than the world.]
  //create the viewing volume

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(_frustum[0], _frustum[1], _frustum[2], _frustum[3], _frustum[4], _frustum[5]);

  glutSwapBuffers(); 
}
void SetStandardHelix() {
   int numResidues = 9, type[9] = {8, 8, 8, 8, 8, 8, 8, 8, 8};
   double phi[9], psi[9], head[3], tail[3], diff[3];
   int i, j, k, l, m, n;
   double v0[4], v1[4], v2[4], v3[4], v4[4], pos[4];
   double mainpos[4]={0.0,0.0,0.0,0.0};
   double a[4][4], b[4][4], c[4][4], d[4][4], e[4][4], f[4][4], g[4][4];
   double chainN[9][3];
   double chainCA[9][3];
   double chainC[9][3];
   double center[9][3];
   double axis[3], plane[3], dd, radius;
   #if WRITEHELIXFILE
   FILE *fp;
   const char outfile[34] = "StandardHelix.pdb";
   #endif
   char chainId[2], pc;
   char elementName[2];
   int residueIndex;
   char* atomNamePtr;


   for (i = 0; i < numResidues; ++i) {
      phi[i] = -60.*PI/180.;
      psi[i] = -45.*PI/180.;
      }
   #if WRITEHELIXFILE
   fp = fopen(outfile, "w");
   if (fp == 0) {
      printf("unable to open file %s\n", outfile);
      }
   #endif
   n = 1;
   identity4(a);

//  Standard amino acids have CA at the origin and N at -residue_d2,
//  so translate to put N at the origin. Standard amino acids also
//  have C in the xy plane, but not necessarily carbonyl O.

   for (i = 0; i < numResidues; ++i)
         {
         j = type[i];

         translate4d(residued2[j], 0., 0., b);
         matmult4(a, b, c);
         rotX4(PI-StandardPhi[j], b);
         //   printf("StandardPhi[%d] = %f\n", j, StandardPhi[j]);
         matmult4(c, b, f);              // f is for the amide H

         //  First do NH

         l = 2;
         for (k = 0; k < l; ++k)
         {
             for (m = 0; m < 3; ++m)
                 v0[m] = residueAtomPos[j][k][m];
             v0[3] = 1.;
             if(k == 0) {
                matrix_vector4(c, v0, mainpos);
                for (m = 0; m < 3; ++m) 
                   chainN[i][m] = mainpos[m];
                }
             else  matrix_vector4(f, v0, mainpos);
             #if WRITEHELIXFILE
             fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
                     n, residueAtomName[j][k], Protein::Residue::abbreviatedNames[j],
                     i+1, mainpos[0], mainpos[1], mainpos[2], 0., 0.);
             #endif
             ++n;

         }
         rotX4(phi[i], b);
         matmult4(c, b, a);              // a continuing backbone
         rotZ4(StandardAlpha[j], b);
         matmult4(a, b, c);
         rotX4(psi[i], b);
         matmult4(c, b, d);              // d is to help continue backbone
         rotX4(StandardPsi[j], b);      // to bring O to plane of next N and CA
         matmult4(d, b, g);
         rotZ4(-StandardAlpha[j], b);
         matmult4(g, b, e);              // e is for carbonyl oxygen

         //  Now do rest of atoms

         for (k = l; k <  numbAtoms[j]; ++k)
             {
             for (m = 0; m < 3; ++m)
                 v0[m] = residueAtomPos[j][k][m];
             v0[3] = 1.;
             if (k == l+3)
                 matrix_vector4(e, v0, pos);
             else
                 matrix_vector4(a, v0, pos);
	     if(k == 2)
	        for (m = 0; m < 3; ++m)
		   chainCA[i][m] = pos[m];
	     if(k == 4)
		for (m = 0; m < 3; ++m)
		   chainC[i][m] = pos[m];
             #if WRITEHELIXFILE
             fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
                     n, residueAtomName[j][k], Protein::Residue::abbreviatedNames[j],
                     i+1, pos[0], pos[1], pos[2], 0., 0.);
             #endif
             ++n;
             }
         // Now build up rest of main chain effect on matrix a

         translate4d(residued3[j], 0., 0., b);
         matmult4(d, b, c);
         rotZ4(StandardBeta[j], b);
         matmult4(c, b, d);
         translate4d(1.325, 0., 0., b);
         matmult4(d, b, c);
         rotX4(PI, b);
         matmult4(c, b, d);
         rotZ4(StandardGamma[j], b);
         matmult4(d, b, a);
         //   printf("Alpha %f  Beta %f  Gamma %f\n", 180*StandardAlpha[j]/PI,
         //      180*StandardBeta[j]/PI, 180*StandardGamma[j]/PI);
         }  
   for (i = 1; i < numResidues-1; ++i) {
      for(m = 0; m < 3; ++m) {
         v0[m] = chainN[i-1][m] - chainN[i][m];
	 v1[m] = chainN[i+1][m] - chainN[i][m];
	 }
      normalize(v0);
      normalize(v1);
      for(m = 0; m < 3; ++m)
         center[i][m] = v0[m] + v1[m];
      normalize(center[i]);
      }
   cross(center[1], center[2], axis);
   normalize(axis);
   cross(axis, center[2], plane);
   dd = dot(plane, chainN[2]) - dot(plane, chainN[1]) ;
   radius = dd/dot(plane,center[1]);
   for(m = 0; m < 3; ++m) {
      tail[m] = chainN[1][m] + radius*center[1][m];
      head[m] = chainN[7][m] + radius*center[7][m];
      diff[m] = (head[m] - tail[m])/6.;
      tail[m] -= diff[m];
      }
   for(m = 0; m < 3; ++m) {
     v0[m] = chainN[0][m] - chainCA[0][m];
     v1[m] = chainC[0][m] - chainCA[0][m];
     }
   normalize(v0);
   normalize(v1);
   dd = dot(v0, v1);
   for(m = 0; m < 3; ++m)
      v1[m] -= dd*v0[m];
   normalize(v1);
   cross(v0, v1, v2);
   normalize(v2);
   saxis[0] = dot(v0, diff);
   saxis[1] = dot(v1, diff);
   saxis[2] = dot(v2, diff);
   stail[0] = dot(v0, tail);
   stail[1] = dot(v1, tail);
   stail[2] = dot(v2, tail);
   cross(saxis, stail, ptail);
   normalize(ptail);
   dtail= sqrt( stail[0]*stail[0] + stail[1]*stail[1] + stail[2]*stail[2] );
   daxis= sqrt( saxis[0]*saxis[0] + saxis[1]*saxis[1] + saxis[2]*saxis[2] );
   for(m = 0; m < 3; ++m)
      ptail[m] = dtail*ptail[m];

/*
   normalize(diff);
   fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
           61, "  C", Protein::Residue::abbreviatedNames[j],
           9, head[0], head[1], head[2], 0., 0.);
   fprintf(fp, "ATOM %6d %4s%4s  %4d    %8.3f%8.3f%8.3f%6.2f%6.2f\n",
           62, "  O", Protein::Residue::abbreviatedNames[j],
           9, tail[0], tail[1], tail[2], 0., 0.);
   cout << "radius  " << radius << "  dd " << dd << "  plane " << *plane <<
      "  center[0] " << *center[1] << "  tail " << *tail << "\n";

   fprintf(stderr, "axis %g %g %g\n", axis[0], axis[1], axis[2]);
   fprintf(stderr, "diff %g %g %g\n", diff[0], diff[1], diff[2]);
   fprintf(stderr, "head %g %g %g\n", head[0], head[1], head[2]);
   fprintf(stderr, "tail %g %g %g\n", tail[0], tail[1], tail[2]);
   fprintf(stderr, "chainN[7] %g %g %g\n", chainN[7][0], chainN[7][1], chainN[7][2]);
   fprintf(stderr, "chainN[1] %g %g %g\n", chainN[1][0], chainN[1][1], chainN[1][2]);
*/
   #if WRITEHELIXFILE
   fclose(fp);
   #endif
   }