molecule.c

来自「开发linux应用-用gtk+和gdk开发linux图形用户界面应用--的实例」· C语言 代码 · 共 990 行 · 第 1/2 页

C
990
字号
/* * File: molecule.c * Auth: Eric Harlow * * Linux GUI app. development */#include <gtk/gtk.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include "atom.h"#include "matrix3d.h"typedef struct {    GdkDrawable *pixmap;    GdkGC *gc;} typGraphics;typedef struct {    typAtom *atom1;    /* --- First atom in the bond --- */    typAtom *atom2;    /* --- Second atom in the bond --- */    int bPainted;      /* --- painted. --- */} typBond;/* * Prototypes. */int ShowLines ();int ShowLabels ();int ShowRGB ();void QSortMolecules (typAtom *atomlist, int *sortindex, int lo0, int hi0);void MoleculeRepaint ();GdkGC *GetAtomColor (typAtom *atom);void SortMolecules (typAtom *atomlist, int *sortindex);void FindBB ();char *GetNextValue (char *sTmp, int *nIndex1);typMatrix3D *NewMatrix3D ();void DrawMolecule (typGraphics *g);void DrawBond (typGraphics *g, typAtom *atom1, typAtom *atom2);char *FindDigit (char *szBuffer);char *ExtractDigit (char *sTmp, int *pnValue);void SetAtomColor (typAtom *atom, typGraphics *g);typGraphics *NewGraphics ();void paint (typGraphics *g);int mouseDrag (int x, int y);#define    MAX_ATOMS 500#define    MAX_BONDS 500    /* --- Matrices --- */    typMatrix3D *mat = NULL;    typMatrix3D *amat = NULL;    typMatrix3D *tmat = NULL;    /* --- Bounding box --- */    double    xmin, xmax, ymin, ymax, zmin, zmax;        /* --- Molecule items --- */    int    nAtoms = 0;    int    nBonds = 0;    typAtom atomlist[MAX_ATOMS];    typBond bondlist[MAX_BONDS];    int sortindex[MAX_ATOMS];    /* --- Fonts, colors, drawing area --- */    GdkGC *penBlack = NULL;    GdkGC *penBlue = NULL;    GdkGC *penRed = NULL;    GdkGC *penGreen = NULL;    GdkGC *penGray = NULL;    GdkGC *penDarkGray = NULL;    GdkGC *penWhite = NULL;    GdkGC *penYellow = NULL;    GdkGC *penOrange = NULL;    GtkWidget *drawing_area;    GdkFont *font;    /* --- Misc. --- */    typGraphics *g = NULL;    int    prevx;    int    prevy;    int nMoleculeRadius = 2;    int nScreenWidth = 200;    int nScreenHeight = 200;/* * GetPen * * Get a GdkGC (pen) based on the colors passed  * in.  This is used to change the color of the  * items being drawn. * * nRed - Red component of pen * nGreen - Green component of pen * nBlue - Blue component of pen */GdkGC *GetPen (int nRed, int nGreen, int nBlue){    GdkColor *c;    GdkGC *gc;    c = (GdkColor *) g_malloc (sizeof (GdkColor));    c->red = nRed;    c->green = nGreen;    c->blue = nBlue;    gdk_color_alloc (gdk_colormap_get_system (), c);    gc = gdk_gc_new (g->pixmap);    gdk_gc_set_foreground (gc, c);    return (gc);}/* * Init3d  * * Initialize the 3d items that we'll need to draw */void Init3d (){static int bInit = 0;    /* --- Already initialized --- */    if (bInit) return;    bInit = TRUE;    /* --- Create new matrices --- */    mat = NewMatrix3D ();    amat = NewMatrix3D ();    tmat = NewMatrix3D ();    /* --- Create pens for drawing --- */    penBlack = GetPen (0, 0, 0);    penRed = GetPen (0xffff, 0, 0);    penGreen = GetPen (0, 0xffff, 0);    penBlue = GetPen (0, 0, 0xffff);    penGray = GetPen (0xafff, 0xafff, 0xafff);    penDarkGray = GetPen (0x6fff, 0x6fff, 0x6fff);    penYellow = GetPen (0xffff, 0xffff, 0x0000);    penOrange = GetPen (0xffff, 0x99ff, 0x0000);    penWhite = GetPen (0xffff, 0xffff, 0xffff);    /* --- Get a font --- */    font = gdk_font_load ("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*");    if (font == NULL) {        printf ("NULL font, trying another\n");        font = gdk_font_load ("-adobe-helvetica-*-120-*-*-*-*-*-*");    }}/* * ReadMolecule * * Read in a .pdb molecule with the given filename. * Store the information in the data structures  * defined. */void ReadMolecule (char *sFilename){    FILE *fp;    char buffer[120];    float x, y, z;    int nIndex1;    int nIndex2;    char szName[120];    char *sTmp;    typAtom *atom;    char szTmp[20];    Init3d ();    nAtoms = 0;    nBonds = 0;    /* --- Reset matrices if reading in new file --- */    if (mat) {        unit (mat);        unit (amat);        unit (tmat);    }    nMoleculeRadius = 2;    /* --- Open the file for reading --- */    fp = fopen (sFilename, "r");    /* --- Read in a line from the file --- */    while (fgets (buffer, sizeof (buffer), fp)) {        /* --- Why it's an 'atom' --- */        if (strncmp (buffer, "ATOM", 4) == 0) {            /* --- Read in the atom based on the known file               *      structure              */            strncpy (szName, &buffer[12], 4);            szName[4] = 0;            strncpy (szTmp, &buffer[30], 8);            szTmp[8] = 0;            x = atof (szTmp);            strncpy (szTmp, &buffer[38], 8);            szTmp[8] = 0;            y = atof (szTmp);            strncpy (szTmp, &buffer[46], 8);            szTmp[8] = 0;            z = atof (szTmp);            /* --- Atoms are base 1 - index first. --- */            nAtoms++;            /* --- Populate the data structure --- */            atom = &atomlist[nAtoms];            atom->x = x;            atom->y = y;            atom->z = z;            atom->szName = strdup (szName);            atom->bondList = NULL;            sortindex[nAtoms-1] = nAtoms;                    /* --- Does this describe a bond? --- */        } else if (strncmp (buffer, "CONECT", 6) == 0) {            /* --- Get the first bond atom --- */            sTmp = GetNextValue (&buffer[6], &nIndex1);            /* --- Get the next bond atom --- */            while (sTmp = GetNextValue (sTmp, &nIndex2)) {                /* --- This bond is this nIndex1 to nIndex2 --- */                bondlist[nBonds].atom1 = &atomlist[nIndex1];                bondlist[nBonds].atom2 = &atomlist[nIndex2];                /* --- Of course the atom should know which                  *   bonds it is a part of.                 */                atomlist[nIndex1].bondList =                      g_slist_append (atomlist[nIndex1].bondList,                                       &bondlist[nBonds]);                /* --- Both atoms should know... --- */                atomlist[nIndex2].bondList =                      g_slist_append (atomlist[nIndex2].bondList,                                       &bondlist[nBonds]);                /* --- Just another bond.. James Bond. --- */                nBonds++;            }        }    }    /* --- Find bounding box --- */    FindBB ();    /* --- Sort the molecules --- */    SortMolecules (atomlist, sortindex);    MoleculeRepaint ();}/* * FindBB * * Find the minimum bounding box that would fit all the  * atoms in the molecule */void FindBB (){    int        i;    typAtom    *atom;    /* --- At first, the box consisted of a single atom --- */    /* --- Atoms start at 1 --- */    atom = &atomlist[1];    xmin = atom->x;    xmax = atom->x;    ymin = atom->y;    ymax = atom->y;    zmin = atom->z;    zmax = atom->z;    /* --- Then we added a whole bunch of them --- */    for (i = 2; i <= nAtoms; i++) {        atom = &atomlist[i];        if (atom->x < xmin) xmin = atom->x;        if (atom->x > xmax) xmax = atom->x;        if (atom->y < ymin) ymin = atom->y;        if (atom->y > ymax) ymax = atom->y;        if (atom->z < zmin) zmin = atom->z;        if (atom->z > zmax) zmax = atom->z;    }    /* --- And now we have our bounding box. --- */}   /* * TransformPoints * * Take the atoms and rotate them to their displayed * position so they can be drawn.   * * mat - The matrix used to calculate the new atom position */void TransformPoints (typMatrix3D *mat){    int    i;    for (i = 1; i <= nAtoms; i++) {        Transform (mat, &atomlist [i]);    }}/* * paint * * paint the screen */void paint (typGraphics *g){    double xfac;    double f1;    double f2;    /* --- What's the range (delta x, delta y, delta z) --- */    double xw = xmax - xmin;    double yw = ymax - ymin;    double zw = zmax - zmin;    /* --- Make sure everything is allocated --- */    Init3d ();    /* --- Calculate the factor to scale the molecule --- */    if (yw > xw) xw = yw;    if (zw > xw) xw = zw;    f1 = nScreenWidth / xw;    f2 = nScreenHeight / xw;    xfac = .7 * (f1 < f2 ? f1 : f2);    /* --- First make the matrix the unit matrix --- */    unit (mat);    /* --- Translate it around the origin.  This moves the       *     molecule to be centered around the axis as we're      *     moving it based on the half of the bounding box width     */    translate (mat, -(xmin + xmax) / 2,                   -(ymin + ymax) / 2,                   -(zmin + zmax) / 2);    /* --- Rotate the image around the axis.  amat is the       *     matrix that represents how much to rotate the      *     molecule.     */    mult (mat, amat);    /* --- Scale the molecule based on the screen width --- */    scale3 (mat, xfac, -xfac, 16 * xfac / nScreenWidth);    /* --- Translate the molecule out based on the screen width and height --- */    translate (mat, nScreenWidth / 2, nScreenHeight / 2, 10);    /* --- Calculate the new position of all the points --- */    TransformPoints (mat);    /* --- Draw the molecule based on translated coordinates --- */    DrawMolecule (g);}/*  * SortMolecules * * Call the sorting function */void SortMolecules (typAtom *atomlist, int *sortindex){    QSortMolecules (atomlist, sortindex, 0, nAtoms-1);}/* * QSortMolecules * * This is just a quicksort of the atoms in the molecule.  * * Note: Rather than sort the atomlist itself, the sortindex * is the item being sorted.  Manipulating integers is just * quick than moving structures around in memory - especially * since we have to do this in real time over and over again. * * atomlist - list of atoms to sort * sortlist - index of indexes. */void QSortMolecules (typAtom *atomlist, int *sortindex, int lo0, int hi0) {    int    nTmp;    int    lo = lo0;    int    hi = hi0;    int    mid;        if (hi0 > lo0) {        mid = atomlist[sortindex[(lo0 + hi0) / 2]].tz;        while (lo <= hi) {            while (lo < hi0 && atomlist[sortindex[lo]].tz < mid) {                lo++;            }            while (hi > lo0 && atomlist[sortindex[hi]].tz > mid) {                hi--;            }            if (lo <= hi) {                nTmp = sortindex[lo];                sortindex[lo] = sortindex[hi];                sortindex[hi] = nTmp;                lo++;                hi--;            }        }        if (lo0 < hi) QSortMolecules (atomlist, sortindex, lo0, hi);        if (lo < hi0) QSortMolecules (atomlist, sortindex, lo, hi0);    }}/* * DrawMolecule * * Draw the molecule.  'nuff said. */void DrawMolecule (typGraphics *g){    int nIndex;    int nDiameter;    typBond *bond;    GSList *list;    typAtom *atom;    int i;    GdkGC *pen;    /* --- Make sure everything's ready --- */    Init3d ();    /* --- Sort the molecules --- */    SortMolecules (atomlist, sortindex);    /* --- Get the molecule diameter --- */    nDiameter = nMoleculeRadius + nMoleculeRadius;    /* --- If we're showing bonds --- */    if (ShowLines()) {        /* --- Clear out the flag that indicates that this          *     particular bond has been painted.         */        for (i = 0; i < nBonds; i++) {            bondlist[i].bPainted = FALSE;        }    }    /* --- Display all the atoms in the list --- */    for (i = 0; i < nAtoms; i++) {        /* --- Use the sort list - draw from farthest back          *     moving up.         */        nIndex = sortindex[i];        /* --- Get the atom the index refers to --- */        atom = &atomlist[nIndex];

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?