CS4 (Gumbo) Molfile Molecule Viewer Sem#4

February 24, 2009

Intro

This is seminar #4, of a series of free seminars given this semester at NKU on Papervision3D and CS4. It demonstrates how to create a molfile molecule viewer in CS4 (Gumbo). Click the image below to see a demo.

CS4 Molecule for a Molfile

CS4 Molecule from a Molfile

Source

Demo

YouTube

Discussion

This is now my second version of a 3D molecule viewer. The first version was written in Papervision3D and was about 1400 lines of code and required that you rewrite the molfile into xml, and didn’t show bonds. This version is in CS4 (Gumbo or Flex 4) and is only about 350 lines of code, has bonds (single, double, triple, aromatic) and parses the molfile directly.

It took me a day to write this application(from 4 to 11), and that was with breaks: playing with the kids, gym, Shakespeare club, an ice cream float party, and several episodes of Hawaii-5-0 and Enterprise. Yeah, this is the life!

Molfile Parser

Parsing the Molefile was much easier than I thought it was going to be. Here is how you do it:

  • You just bring the molfile into Flex 4 using http services command (just as you would an XML file but with no e4x format)

<mx:HTTPService id=”molService” url=”assets/0420.mol”
result=”initMoleFile(event)” />

  • Then you convert it to a string, take out the special characters, split the contents, stuff it into an array, and remove all empty array elements.

// Convert to string
myString=molService.lastResult.toString();

//Remove special characters
myString = myString.split(“\n”).join(” “);
myString = myString.split(“\r”).join(” “);

//Stuff into an Array
myArray = myString.split(/ /);

//Filter out bland array elements
myArray = myArray.filter(filterMe);
function filterMe(element:String, index:int, array:Array):Boolean{
return (element != “” ); }

  • After you’ve stuffed your molefile into an array, you need to know where to go in that array so you can start counting off the data elements.Where do you go? Go to the version number of the molfile. So run a forEach and grab it’s index value.

myArray.forEach(myStart);

function myStart(element:String, index:int, array:Array):void{
if(element == “V2000″||element == “V3000″){
myStartVert=index;}

The index value of the version number is the heart of your molfile parser. Above we allow for versions V2000 or V3000. This index value will take you to any piece of data that you need in order to display your molecule. From this point on, its just a big counting game, everything is referenced to your version index value.

Atom File

To display your model you need an atom shape that can change size, color, and fill based upon the atom type.

The atom color, type, and radius were previously handled in an earlier version of the molecule viewer, created in Papervision3D (video, source).

And the atom shape and fill were handled in a previous post in this blog on 3D Lines in CS4 using drawPath.

By combining these two programs you can come up with a suitable atom. To do this:

  • Place the atom switch case from the PV3D Viewer into the Ball class created in the 3D Lines post, then change the ball class to Atom along with its constructor and class names.
  • In the switch case change the myColor value from grabbing a jpg to equaling a color value for all possible atoms:

case “H”:
//myColor = “colors/white.jpg”;
myColor = 0xffffff;
radius = 25;

  • In the Constructor function change it to receive only one parameter type, which is the letter of your atom: H, C, O…

public function init(type:String):void{…

  • Finally, change the fill method to gradient fill so your atoms looks cool.

graphics.beginGradientFill(myType, [myColor, 0x000022],[1,1], [1, 40]);

Now that your atom subclass is completed, it’s time to start building molecules.

Creating Molecules and Bonds

There are two parts to creating molecules: placing atoms in 3D, and creating their bonds. The first part of a molfile gives you the atom position values, and the second part give the bond relationships (which atoms are connected to which) and types.

Placing Atoms

Essentially all you have to do is replace the random placement of circles from the post on drawPaths to the atomic positions found in your molfile.

atom.xpos = myArray[myStartVert+1 +j*16] * myScale – offsetx;
atom.ypos = myArray[myStartVert+2 +j*16] * myScale – offsety;
atom.zpos = myArray[myStartVert+3 +j*16] * myScale – offsetz;

myHolder.addChild(atom);

You get to those positions by counting 1 position forward for x, 2 for y, and 3 for z, from the version number index, as shown above.

The offset is just an average of the molecular positions and gives you the ability to spin your molecule around its center. Everything else pretty much follows what was done in the drawPaths post.

Creating Bonds

Creating bonds is easy as well, with one big conceptual change from the drawPaths post. Double processing is eliminated by just duplicating the atom and placing it into a marks array. The lines follow the duplicated atom in the marks array and the other atom which exist in the atoms array are used for sorting.

atoms.push(atom);
marks.push(atom);

The big problem (in creating bonds) was figuring out how to create double, triple, and aromatic bonds. And it turns out to be just a big counting game, coupled with offsetting lines. It starts with figuring out what type of bond you have and using that information in a switch case.

The information for what type of bond you have is carried in the second part of your molfile which starts at

startBondArray=myStartVert+myNumAtoms*16+1

Adding 2 to this number gives you the bond type location (OK once again it’s a big counting game – check out the molfile description under the read more button to see the molfile structure – I know it well).

So, each time you create a double, triple, or aromatic bond you have to keep track of where all the data is in your array. This was accomplished by adding the following counting tracker to your command and data arrays:

commands[2*k+2*dB+4*tB+2*aB]

mydata[4*k+4*dB+8*tB+4*aB]

which are needed to for the drawPath command shown below

myHolder.graphics.drawPath(commands, mydata);

The variables dB, tB, and aB are iterated (by one) each time you create a double, triple, or aromatic bond respectively. These values are then zeroed after each molecular drawing iteration and the process is restarted on each onEnterFrame tick.

Creating the bond offsets was not very sophisticated as shown below:

mydata[4*k+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x-bond2Sep;
mydata[4*k+1+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y-bond2Sep;

mydata[4*k+4+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].x+bond2Sep;
mydata[4*k+5+4*dB+8*tB+4*aB] = marks[myArray[startBondArray+7*k]-1].y+bond2Sep;

You just subtract or add an offset value (bond2Sep) as shown above for the double bond case.

Which Way Should We Go!

In going through this, I found some molfiles on the web that were not well formed and would not work with this parser. That’s always the problem with parsers. The errors were easy to fix and many times just meant adding or subtracting an extra zero. But your end user can’t do that…

I really think XML is the best way to go. That way you can target nodes and forget about counting. You can go even a step farther with XML and include chemical bonding information which would enable you to run chemical simulations. Wouldn’t that be cool!

To see all the code, download it from the source link above or click the button below:

Read the rest of this entry »


Follow

Get every new post delivered to your Inbox.