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 + -
显示快捷键?