main.C

Go to the documentation of this file.
00001 /* molecule, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
00002  * Draws molecules, based on coordinates from PDB (Protein Data Base) files.
00003  *
00004  * Permission to use, copy, modify, distribute, and sell this software and its
00005  * documentation for any purpose is hereby granted without fee, provided that
00006  * the above copyright notice appear in all copies and that both that
00007  * copyright notice and this permission notice appear in supporting
00008  * documentation.  No representations are made about the suitability of this
00009  * software for any purpose.  It is provided "as is" without express or 
00010  * implied warranty.
00011  */
00012 
00042 #define countof(x) (sizeof((x))/sizeof((*x)))
00043 
00044 #include <string.h>
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <time.h>
00049 #include <sys/time.h>
00050 
00051 #include <cfloat>
00052 
00053 #include <archon/util/ref.H>
00054 #include <archon/util/time.H>
00055 #include <archon/util/thread.H>
00056 #include <archon/util/color.H>
00057 #include <archon/util/options.H>
00058 #include <archon/util/text.H>
00059 
00060 #include <archon/x3d/proxy/exception.H>
00061 #include <archon/x3d/proxy/proxy.H>
00062 
00063 using namespace Archon::Math;
00064 using namespace Archon::Utilities;
00065 using namespace Archon::X3D::Proxy;
00066 
00067 namespace Archon
00068 {
00069   const char *progname;
00070 
00071   struct AtomKind
00072   {
00073     string name;
00074     float size;
00075     string textureFile;
00076     // Vector3 color;
00077     // Vector3 text_color;
00078     Ref<ChildNode> model; // Filled in when needed first time
00079   };
00080 
00081 
00082 
00083   /* These are the traditional colors used to render these atoms,
00084      and their approximate size in angstroms.
00085   */
00086   static AtomKind allAtomKinds[] =
00087   {
00088     { "H", 1.17,  "h.png" /* Utilities::Color::white,           Utilities::Color::gray          */ },
00089     { "C", 1.75,  "c.png" /* Utilities::Color::gray,            Utilities::Color::white         */ },
00090     { "N", 1.55,  "n.png" /* Utilities::Color::lightsteelblue,  Utilities::Color::slateblue     */ },
00091     { "O", 1.40,  "o.png" /* Utilities::Color::red,             Utilities::Color::lightpink     */ },
00092     { "P", 1.28,  "p.png" /* Utilities::Color::mediumpurple,    Utilities::Color::palevioletred */ },
00093     { "S", 1.80,  "s.png" /* Utilities::Color::yellow,          Utilities::Color::goldenrod     */ },
00094     { "*", 1.40,  "x.png" /* Utilities::Color::green,           Utilities::Color::lightgreen    */ }
00095   };
00096 
00097 
00098   typedef struct
00099   {
00100     int id;             /* sequence number in the PDB file */
00101     const char *label;  /* The atom name */
00102     float x, y, z;      /* position in 3-space (angstroms) */
00103     AtomKind *kind;     /* computed: which style of atom this is */
00104   }
00105   molecule_atom;
00106 
00107   typedef struct
00108   {
00109     int from, to;               /* atom sequence numbers */
00110     int strength;               /* how many bonds are between these two atoms */
00111   }
00112   molecule_bond;
00113 
00114   typedef struct
00115   {
00116     const char *label;          /* description of this compound */
00117     int natoms, atoms_size;
00118     int nbonds, bonds_size;
00119     molecule_atom *atoms;
00120     molecule_bond *bonds;
00121   }
00122   molecule;
00123 
00124   static molecule *mol = 0;
00125 
00126   Ref<Application> application;
00127   Ref<Group> rootGroup;
00128 
00129   Rotation3 rotate_cylinder(Vector3 p1, Vector3 p2)
00130   {
00131     double p, angle;
00132     Vector3 v = p1;
00133     v -= p2;
00134     v.normalize();
00135     p = v[1];
00136     if(p < -1 + DBL_EPSILON*10) return Rotation3::zero(); 
00137     // Parallel same direction as negative y-axis
00138     if(p >  1 - DBL_EPSILON*10)         // Parallel opposite direction as negative y-axis
00139     {
00140       v = Vector3(1,0,0);
00141       angle = M_PI;
00142     }
00143     else
00144     {
00145       v *= Vector3(0,1,0);
00146       v.normalize();
00147       angle = acos(-p);
00148     }
00149     return Rotation3(v, angle);
00150   }
00151 
00152   void tube(double fx, double fy, double fz,
00153             double tx, double ty, double tz,
00154             double thickness, Vector3 &color)
00155   {
00156     Vector3 a(fx, fy, fz);
00157     Vector3 b(tx, ty, tz);
00158 
00159     Ref<Transform> t_tube = Transform::create(application);
00160     t_tube->rotation = rotate_cylinder(a, b);
00161     t_tube->translation = (a+b)/2;
00162 
00163     Ref<Cylinder> cyl = Cylinder::create(application);
00164     cyl->radius = thickness;
00165     cyl->height = dist(a,b);
00166 
00167     Ref<Material> mat = Material::create(application);
00168     mat->diffuseColor = color;
00169 
00170     Ref<Appearance> app = Appearance::create(application);
00171     app->material = mat;
00172 
00173     Ref<Shape> s = Shape::create(application);
00174     s->geometry = cyl;
00175     s->appearance = app;
00176 
00177     t_tube->children.add(s);
00178     rootGroup->children.add(t_tube);
00179   }
00180 
00181 
00182 static AtomKind *get_atom_data(const char *atom_name)
00183 {
00184   AtomKind *d = 0;
00185   char *n = strdup(atom_name);
00186   char *n2 = n;
00187   int L;
00188 
00189   while(!isalpha(*n)) n++;
00190   L = strlen(n);
00191   while(L > 0 && !isalpha(n[L-1])) n[--L] = 0;
00192 
00193   for(unsigned i = 0; i < countof(allAtomKinds); i++)
00194   {
00195     d = &allAtomKinds[i];
00196     if(!strcmp(n, allAtomKinds[i].name.c_str())) break;
00197   }
00198 
00199   free(n2);
00200   return d;
00201 }
00202 
00203 
00204 struct ParseException: Utilities::Exception
00205 {
00206   ParseException(string l, string m): Utilities::Exception(l, m) {}
00207 };
00208 
00209 static molecule_atom *get_atom(molecule_atom *atoms, int natoms, int id)
00210 {
00211   for(int i = 0; i < natoms; i++) if(id == atoms[i].id) return &atoms[i];
00212 
00213   ARCHON_THROW1(ParseException, "Undefined atom id '" + Utilities::Text::toString(id) + "'");
00214 }
00215 
00216 static Ref<ChildNode> buildAtomModel(molecule_atom *atom)
00217 {
00218   /*
00219    * let the molecules have the same relative sizes, but scale
00220    * them to a smaller range, so that the bond-tubes are
00221    * actually visible...
00222    */
00223   double bot = 0.4;
00224   double top = 0.6;
00225   double min = 1.17;
00226   double max = 1.80;
00227   double ratio = (atom->kind->size - min) / (max - min);
00228   double size = bot + (ratio * (top - bot));
00229 
00230   Ref<Sphere> sphere = Sphere::create(application);
00231   sphere->radius = size;
00232 
00233   Ref<Material> material = Material::create(application);
00234   material->diffuseColor = Vector3(1, 1, 1);
00235 
00236   Ref<ImageTexture> texture = ImageTexture::create(application);
00237   //texture->repeatS = false;
00238   //texture->repeatT = false;
00239   texture->url.add(atom->kind->textureFile);
00240 
00241   Ref<TextureTransform> textureTransform = TextureTransform::create(application);
00242   Vector2 scale(4, 2);
00243   scale /= 4.0/3;
00244   textureTransform->scale = scale;
00245   textureTransform->translation = Vector2(0.5/scale[0]-0.5, 0.5/scale[1]-0.5);
00246 
00247   Ref<Appearance> appearance = Appearance::create(application);
00248   appearance->material = material;
00249   appearance->texture = texture;
00250   appearance->textureTransform = textureTransform;
00251 
00252   Ref<Shape> shape = Shape::create(application);
00253   shape->geometry = sphere;
00254   shape->appearance = appearance;
00255 
00256   Ref<Billboard> billboard = Billboard::create(application);
00257   billboard->axisOfRotation = Vector3::zero();
00258   billboard->children.add(shape);
00259 
00260   return billboard;
00261 }
00262 
00263 // Construct the graphical model of the molecule
00264 static void build_molecule()
00265 {
00266   molecule *m = mol;
00267 
00268   for(int i = 0; i < m->nbonds; i++)
00269     {
00270       Vector3 color = Utilities::Color::gray;
00271 
00272       molecule_bond *b = &m->bonds[i];
00273       molecule_atom *from = get_atom(m->atoms, m->natoms, b->from);
00274       molecule_atom *to   = get_atom(m->atoms, m->natoms, b->to);
00275       
00276       float thickness = 0.07 * b->strength;
00277       if(thickness > 0.3) thickness = 0.3;
00278 
00279       tube(from->x, from->y, from->z, to->x, to->y, to->z, thickness, color);
00280     }
00281 
00282   for(int i = 0; i < m->natoms; i++)
00283     {
00284       molecule_atom *atom = &m->atoms[i];
00285 
00286       if(!atom->kind->model) atom->kind->model = buildAtomModel(atom);
00287 
00288       Ref<Transform> t = Transform::create(application);
00289       t->translation = Vector3(atom->x, atom->y, atom->z);
00290       t->children.add(atom->kind->model);
00291 
00292       rootGroup->children.add(t);
00293     }
00294 }
00295 
00296 /* loading */
00297 
00298 static void push_atom(molecule *m, int id, const char *label, float x, float y, float z)
00299 {
00300   m->natoms++;
00301   if(m->atoms_size < m->natoms)
00302     {
00303       m->atoms_size += 20;
00304       m->atoms = (molecule_atom *) realloc (m->atoms,
00305                                             m->atoms_size * sizeof(*m->atoms));
00306     }
00307   m->atoms[m->natoms-1].id = id;
00308   m->atoms[m->natoms-1].label = label;
00309   m->atoms[m->natoms-1].x = x;
00310   m->atoms[m->natoms-1].y = y;
00311   m->atoms[m->natoms-1].z = z;
00312   m->atoms[m->natoms-1].kind = get_atom_data (label);
00313 }
00314 
00315 
00316 static void push_bond(molecule *m, int from, int to)
00317 {
00318   int i;
00319 
00320   for(i = 0; i < m->nbonds; i++)
00321     if ((m->bonds[i].from == from && m->bonds[i].to   == to) ||
00322         (m->bonds[i].to   == from && m->bonds[i].from == to))
00323       {
00324         m->bonds[i].strength++;
00325         return;
00326       }
00327 
00328   m->nbonds++;
00329   if (m->bonds_size < m->nbonds)
00330     {
00331       m->bonds_size += 20;
00332       m->bonds = (molecule_bond *) realloc (m->bonds,
00333                                             m->bonds_size * sizeof(*m->bonds));
00334     }
00335   m->bonds[m->nbonds-1].from = from;
00336   m->bonds[m->nbonds-1].to = to;
00337   m->bonds[m->nbonds-1].strength = 1;
00338 }
00339 
00340 
00341 
00342 /* This function is crap.
00343  */
00344 static void parse_pdb_data(molecule *m, const char *data, string file, int line)
00345 {
00346   const char *s = data;
00347   char *ss;
00348   while (*s)
00349   {
00350     if((!m->label || !*m->label) &&
00351         (!strncmp (s, "HEADER", 6) || !strncmp (s, "COMPND", 6)))
00352     {
00353       char *name = new char[100];
00354       char *n2 = name;
00355       int L = strlen(s);
00356       if (L > 99) L = 99;
00357 
00358       strncpy (n2, s, L);
00359       n2 += 7;
00360       while (isspace(*n2)) n2++;
00361 
00362       ss = strchr (n2, '\n');
00363       if (ss) *ss = 0;
00364       ss = strchr (n2, '\r');
00365       if (ss) *ss = 0;
00366 
00367       ss = n2+strlen(n2)-1;
00368       while (isspace(*ss) && ss > n2) *ss-- = 0;
00369 
00370       if (strlen (n2) > 4 && !strcmp (n2 + strlen(n2) - 4, ".pdb"))
00371         n2[strlen(n2)-4] = 0;
00372 
00373       if (m->label) free ((char *) m->label);
00374       m->label = strdup (n2);
00375       free (name);
00376     }
00377     else if(!strncmp (s, "TITLE ", 6) ||
00378             !strncmp (s, "HEADER", 6) ||
00379             !strncmp (s, "COMPND", 6) ||
00380             !strncmp (s, "AUTHOR", 6) ||
00381             !strncmp (s, "REVDAT", 6) ||
00382             !strncmp (s, "SOURCE", 6) ||
00383             !strncmp (s, "EXPDTA", 6) ||
00384             !strncmp (s, "JRNL  ", 6) ||
00385             !strncmp (s, "REMARK", 6) ||
00386             !strncmp (s, "SEQRES", 6) ||
00387             !strncmp (s, "HET   ", 6) ||
00388             !strncmp (s, "FORMUL", 6) ||
00389             !strncmp (s, "CRYST1", 6) ||
00390             !strncmp (s, "ORIGX1", 6) ||
00391             !strncmp (s, "ORIGX2", 6) ||
00392             !strncmp (s, "ORIGX3", 6) ||
00393             !strncmp (s, "SCALE1", 6) ||
00394             !strncmp (s, "SCALE2", 6) ||
00395             !strncmp (s, "SCALE3", 6) ||
00396             !strncmp (s, "MASTER", 6) ||
00397             !strncmp (s, "KEYWDS", 6) ||
00398             !strncmp (s, "DBREF ", 6) ||
00399             !strncmp (s, "HETNAM", 6) ||
00400             !strncmp (s, "HETSYN", 6) ||
00401             !strncmp (s, "HELIX ", 6) ||
00402             !strncmp (s, "LINK  ", 6) ||
00403             !strncmp (s, "MTRIX1", 6) ||
00404             !strncmp (s, "MTRIX2", 6) ||
00405             !strncmp (s, "MTRIX3", 6) ||
00406             !strncmp (s, "SHEET ", 6) ||
00407             !strncmp (s, "CISPEP", 6) ||
00408             !strncmp (s, "GENERATED BY", 12) ||
00409             !strncmp (s, "TER ", 4) ||
00410             !strncmp (s, "END ", 4) ||
00411             !strncmp (s, "TER\n", 4) ||
00412             !strncmp (s, "END\n", 4) ||
00413             !strncmp (s, "\n", 1))
00414       /* ignored. */;
00415     else if (!strncmp (s, "ATOM   ", 7))
00416     {
00417       int id;
00418       char *name = (char *) calloc (1, 4);
00419       float x = -999, y = -999, z = -999;
00420 
00421       sscanf (s+7, " %d ", &id);
00422 
00423       strncpy (name, s+12, 3);
00424       while (isspace(*name)) name++;
00425       ss = name + strlen(name)-1;
00426       while (isspace(*ss) && ss > name) *ss-- = 0;
00427       sscanf (s + 32, " %f %f %f ", &x, &y, &z);
00428 
00429       push_atom (m, id, name, x, y, z);
00430     }
00431     else if(!strncmp (s, "HETATM ", 7))
00432     {
00433       int id;
00434       char *name = (char *) calloc (1, 4);
00435       float x = -999, y = -999, z = -999;
00436 
00437       sscanf (s+7, " %d ", &id);
00438 
00439       strncpy (name, s+12, 3);
00440       while (isspace(*name)) name++;
00441       ss = name + strlen(name)-1;
00442       while (isspace(*ss) && ss > name) *ss-- = 0;
00443       sscanf (s + 30, " %f %f %f ", &x, &y, &z);
00444 
00445       push_atom (m, id, name, x, y, z);
00446     }
00447     else if (!strncmp (s, "CONECT ", 7))
00448     {
00449       int atoms[11];
00450       int i = sscanf(s + 8, " %d %d %d %d %d %d %d %d %d %d %d %d ",
00451                      &atoms[0], &atoms[1], &atoms[2], &atoms[3], 
00452                      &atoms[4], &atoms[5], &atoms[6], &atoms[7], 
00453                      &atoms[8], &atoms[9], &atoms[10], &atoms[11]);
00454       int j;
00455       for(j = 1; j < i; j++)
00456         if(atoms[j] > 0) push_bond (m, atoms[0], atoms[j]);
00457     }
00458     else
00459     {
00460       char *s1 = strdup (s);
00461       for (ss = s1; *ss && *ss != '\n'; ss++)  /* WHAT??? */;
00462       *ss = 0;
00463       fprintf(stderr, "%s: %s: %d: unrecognised line: %s\n",
00464               progname, file.c_str(), line, s1);
00465     }
00466 
00467     while (*s && *s != '\n') s++;
00468     if(*s == '\n') s++;
00469     line++;
00470   }
00471 }
00472 
00473 
00474 static void parse_pdb_file(molecule *m, string file)
00475 {
00476   FILE *in;
00477   int buf_size = 40960;
00478   char *buf;
00479   int line = 1;
00480 
00481   in = fopen(file.c_str(), "r");
00482   if(!in)
00483   {
00484     char *buf = (char *) malloc(1024 + file.size());
00485     sprintf(buf, "%s: error reading \"%s\"", progname, file.c_str());
00486     perror(buf);
00487     exit (1);
00488   }
00489 
00490   buf = (char *) malloc (buf_size);
00491 
00492   while (fgets (buf, buf_size-1, in))
00493   {
00494     char *s;
00495     for (s = buf; *s; s++)
00496       if (*s == '\r') *s = '\n';
00497     parse_pdb_data (m, buf, file, line++);
00498   }
00499 
00500   free (buf);
00501   fclose (in);
00502 
00503   if(!m->natoms)
00504   {
00505     fprintf(stderr, "%s: file %s contains no atomic coordinates!\n",
00506             progname, file.c_str());
00507     exit (1);
00508   }
00509 
00510   if(!m->nbonds)
00511   {
00512     fprintf(stderr, "%s: warning: file %s contains no atomic bond info.\n",
00513             progname, file.c_str());
00514   }
00515 }
00516 
00517 
00518 typedef struct { char *atom; int count; } atom_and_count;
00519 
00520 /* When listing the components of a molecule, the convention is to put the
00521    carbon atoms first, the hydrogen atoms second, and the other atom types
00522    sorted alphabetically after that (although for some molecules, the usual
00523    order is different: we special-case a few of those.)
00524  */
00525 static int cmp_atoms(const void *aa, const void *bb)
00526 {
00527   const atom_and_count *a = (atom_and_count *) aa;
00528   const atom_and_count *b = (atom_and_count *) bb;
00529   if (!a->atom) return  1;
00530   if (!b->atom) return -1;
00531   if (!strcmp(a->atom, "C")) return -1;
00532   if (!strcmp(b->atom, "C")) return  1;
00533   if (!strcmp(a->atom, "H")) return -1;
00534   if (!strcmp(b->atom, "H")) return  1;
00535   return strcmp (a->atom, b->atom);
00536 }
00537 
00538 /* thanks to Rene Uittenbogaard <ruittenb@wish.nl> */
00539 static void special_case_formula (char *f)
00540 {
00541   if      (!strcmp(f, "H(2)Be"))   strcpy(f, "BeH(2)");
00542   else if (!strcmp(f, "H(3)B"))    strcpy(f, "BH(3)");
00543   else if (!strcmp(f, "H(3)N"))    strcpy(f, "NH(3)");
00544   else if (!strcmp(f, "CHN"))      strcpy(f, "HCN");
00545   else if (!strcmp(f, "CKN"))      strcpy(f, "KCN");
00546   else if (!strcmp(f, "H(4)N(2)")) strcpy(f, "N(2)H(4)");
00547   else if (!strcmp(f, "Cl(3)P"))   strcpy(f, "PCl(3)");
00548   else if (!strcmp(f, "Cl(5)P"))   strcpy(f, "PCl(5)");
00549 }
00550 
00551 static void generate_molecule_formula(molecule *m)
00552 {
00553   char *buf = (char *) malloc (m->natoms * 10);
00554   char *s = buf;
00555   int i;
00556   atom_and_count counts[200];
00557   memset (counts, 0, sizeof(counts));
00558   *s = 0;
00559   for(i = 0; i < m->natoms; i++)
00560   {
00561     int j = 0;
00562     char *a = (char *) m->atoms[i].label;
00563     char *e;
00564     while(!isalpha(*a)) a++;
00565     a = strdup (a);
00566     for(e = a; isalpha(*e); e++);
00567     *e = 0;
00568     while (counts[j].atom && !!strcmp(a, counts[j].atom)) j++;
00569     if (counts[j].atom) free (a);
00570     else counts[j].atom = a;
00571     counts[j].count++;
00572   }
00573 
00574   i = 0;
00575   while (counts[i].atom) i++;
00576   qsort (counts, i, sizeof(*counts), cmp_atoms);
00577 
00578   i = 0;
00579   while(counts[i].atom)
00580   {
00581     strcat (s, counts[i].atom);
00582     free (counts[i].atom);
00583     s += strlen (s);
00584     if(counts[i].count > 1) sprintf (s, "(%d)", counts[i].count);
00585     s += strlen (s);
00586     i++;
00587   }
00588 
00589   special_case_formula (buf);
00590 
00591   if (!m->label) m->label = strdup("");
00592   s = (char *) malloc (strlen (m->label) + strlen (buf) + 2);
00593   strcpy (s, m->label);
00594   strcat (s, "\n");
00595   strcat (s, buf);
00596   free ((char *) m->label);
00597   free (buf);
00598   m->label = s;
00599 }
00600 
00601 
00602 
00603 static void insert_vertical_whitespace (char *string)
00604 {
00605   while (*string)
00606   {
00607     if((string[0] == ',' || string[0] == ';' || string[0] == ':') && string[1] == ' ')
00608       string[0] = ' ', string[1] = '\n';
00609     string++;
00610   }
00611 }
00612 
00613 
00614 void init_molecule(string file)
00615 {
00616   mol = (molecule *)calloc(sizeof (molecule), 1);
00617   parse_pdb_file(mol, file);
00618   generate_molecule_formula(mol);
00619   insert_vertical_whitespace((char *)mol->label);
00620 }
00621 
00622 
00623 
00624 
00625   namespace SaiTestApps
00626   {
00627     namespace Molecule
00628     {
00629       static bool quit = false;
00630 
00631       int main(int argc, const char *argv[])
00632       {
00633         bool   opt_help              = false;
00634         int    opt_corbaEndpointPort = -1; // Auto assign
00635         string opt_serverName        = "archon";
00636         
00637         Options o;
00638 
00639         o.addSwitch("h", "help", opt_help, true,
00640                     "Describe the parameters");
00641         o.addConfig("p", "corba-endpoint-port", opt_corbaEndpointPort, opt_corbaEndpointPort,
00642                     "The TCP/IP port on which the CORBA Orb listens (-1 for auto assign)",
00643                     Options::wantArg_always);
00644         o.addConfig("n", "server-name", opt_serverName, opt_serverName,
00645                     "The name of the server to connect to",
00646                     Options::wantArg_always);
00647         
00648         if(o.processCommandLine(argc, argv))
00649         {
00650           cerr << "Try --help\n";
00651           return 1;
00652         }
00653 
00654         if(opt_help)
00655         {
00656           cout <<
00657             "Test Application for 3D-Console by Brian Kristiansen & Kristian Spangsege\n"
00658             "\n"
00659             "Synopsis: " << argv[0] << " FILE\n"
00660             "\n"
00661             "Available options:\n";
00662           cout << o.list();
00663           return 0;
00664         }
00665 
00666         if(argc < 2 || argc > 2)
00667         {
00668           cerr << "Wrong number of aguments\n";
00669           cerr << "Try --help\n";
00670           return 1;
00671         }
00672 
00673         Ref<Session> session = Session::create("archon", -1);
00674   
00675         application = Application::create(session, Uri());
00676         rootGroup = Group::create(application);
00677   
00678         progname = argv[0];
00679 
00680         init_molecule(argv[1]);
00681         build_molecule();
00682 
00683         application->setRootGroup(rootGroup);
00684         application->launch();
00685 
00686         Archon::Utilities::Time delay(0, 100000000l);
00687         while(!quit)
00688         {
00689           session->beginUpdate();
00690           session->endUpdate();
00691 
00692           Archon::Utilities::Thread::sleep(delay);
00693         }
00694 
00695         return 0;
00696       }
00697     }
00698   }
00699 }
00700 
00701 int main(int argc, const char *argv[]) throw()
00702 {
00703   using namespace std;
00704   using namespace Archon::X3D;
00705 
00706   set_unexpected(Exception::terminal<Proxy::exceptionCatchInfo>);
00707   set_terminate (Exception::terminal<Proxy::exceptionCatchInfo>);
00708 
00709   return Archon::SaiTestApps::Molecule::main(argc, argv);
00710 }

Generated on Sun Jul 30 22:55:41 2006 for Archon by  doxygen 1.4.4