In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

pdbファイルを読み込んで分子構造を表示

原子の色はセンスが悪いです。
データは「フタル酸ジ-2-エチルヘキシル」です。
http://www3.u-toyama.ac.jp/kihara/cc/index.html
にあったので使用しています。
(HP上に「データの利用については制限を設けません」とあったので利用しています)

たぶん他のPDB(Protein Data Bank)データも読むことができます。
ここにWEB素材として使用できる形のものがあります。(原子の画像等)
http://programmingatelier.net/flex4_51/flex4_5107.html
Get Adobe Flash player
by hi.kurosawa 26 Apr 2011
    Embed
/**
 * Copyright hi.kurosawa ( http://wonderfl.net/user/hi.kurosawa )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3Bn2
 */

//================================================
//分子構造の表示
//
// http://programmingatelier.net/
//
package 
{
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.net.URLLoader;
    import flash.net.URLLoaderDataFormat;
    import flash.system.LoaderContext;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.geom.ColorTransform;
    import mx.utils.StringUtil;
    import org.papervision3d.materials.*;  
    import org.papervision3d.objects.primitives.*;  
    import org.papervision3d.objects.*;
    import org.papervision3d.lights.*;
    import org.papervision3d.materials.shadematerials.*;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.materials.special.CompositeMaterial;
    import org.papervision3d.view.*;
    import org.papervision3d.core.geom.Lines3D;
    import org.papervision3d.core.geom.renderables.Line3D;  
    import org.papervision3d.core.geom.renderables.Vertex3D;  
    import org.papervision3d.materials.special.LineMaterial;  
    import org.papervision3d.typography.fonts.HelveticaMedium;
    import org.papervision3d.materials.special.Letter3DMaterial;
    import org.papervision3d.typography.Text3D;
    import org.papervision3d.typography.fonts.HelveticaBold;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import org.papervision3d.core.math.Number3D;
    import flash.system.Security;
    import flash.utils.ByteArray;
    import flash.geom.Point;
    import flash.geom.Rectangle;


    public class Molecule extends     BasicView
    {
        //使用画像定義(黒白の原子のイメージ)
        private var bmAtom:Bitmap;
        private var bmdAtom:BitmapData;
        private var loader:Loader;
        private static var filePath:String = "http://programmingatelier.net/publicSwf/data/Atom.png";
        //3D形状の配置領域
        private var rootNode:DisplayObject3D;
        //データのあるパス
        private var strDatUrl:String;
        //表示Atom配列、カメラ移動時の向きの調整用
        private var arrObj:Array;

        //PDB読み込み原子と結合線データ
        private var arrAtom:Array;
            //Typ:ATOM/HETATM,nam:名称,id:NO,x,y,z:原子の座標値*100
        private var arrConect:Array;
            //StrCon:開始点側原子ID, EndCon:終点側原子ID
        private     var kakudo0:Number;
        private     var kakudo1:Number;
        private     var kakudo2:Number;
       
        public function Molecule():void {
            arrObj = new Array();
            arrAtom = new Array();
            arrConect = new Array();
            Security.loadPolicyFile("http://programmingatelier.net/publicSwf/crossdomain.xml");
            loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete, false, 0, true);
            loader.load(new URLRequest(filePath), new LoaderContext(true));
        }
        private function complete(evt:Event):void {
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, complete);
            bmAtom = Bitmap(loader.content);
            bmdAtom = bmAtom.bitmapData;
            
           var urlLoader:URLLoader = new URLLoader();
            urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
            urlLoader.addEventListener(Event.COMPLETE, onCompUrlLoad);
            //http://www3.u-toyama.ac.jp/kihara/cc/index.html
            //http://www3.u-toyama.ac.jp/kihara/cc/pdb/c1-15-3/index.html
            //フタル酸ジ-2-エチルヘキシル
            //HP上に「データの利用については制限を設けません」とあったので利用しています
            urlLoader.load(new URLRequest("http://programmingatelier.net/publicSwf/data/c0013.pdb"));
        }
        //読み込み完了
        private function onCompUrlLoad(event:Event):void {
            var urlLoader:URLLoader = event.currentTarget as URLLoader;
            var bytArra:ByteArray = urlLoader.data as ByteArray;
            fncChkData(bytArra);    //データ処理、表示処理
        }
        //読み込みデータ処理、表示処理==============================================
        private function fncChkData(bytArra:ByteArray):void {
            var minX:Number = 0, maxX:Number = 0, minY:Number = 0;
            var maxY:Number = 0, minZ:Number = 0, maxZ:Number = 0;
            arrConect = new Array();
            arrAtom = new Array();
            arrObj = new Array();

            try {
                //改行の変更
                var strData:String = bytArra.toString();
                var arrDat:Array = strData.split("\r\n");    //Windowsの改行対応
                strData = arrDat.join("\n");
                arrDat = strData.split("\n");    //行の分解
                
                for (var i:int = 0; i < arrDat.length; i++) {    //1行ごとの処理
                    //原子
                    if (arrDat[i].indexOf("ATOM") == 0 || arrDat[i].indexOf("HETATM") == 0) {
                        arrAtom.push( {
                            Typ:StringUtil.trim(arrDat[i].substr( 0, 6 )),
                            nam:StringUtil.trim(arrDat[i].substr( 11, 5 )),
                            id:int(arrDat[i].substr( 6, 5 )),
                            x:Number(arrDat[i].substr( 30, 8 ))*100.0,
                            y:Number(arrDat[i].substr( 38, 8 ))*100.0,
                            z:Number(arrDat[i].substr( 46 ,8 ))*100.0
                        });
                        //原子の配置領域を求める
                        var ii:Number = arrAtom.length - 1;
                        if (arrAtom.length == 1) {
                            minX = arrAtom[ii].x;
                            maxX = arrAtom[ii].x;
                            minY = arrAtom[ii].y;
                            maxY = arrAtom[ii].y;
                            minZ = arrAtom[ii].z;
                            maxZ = arrAtom[ii].z;
                        } else {
                            if(minX > arrAtom[ii].x) {minX = arrAtom[ii].x;}
                            if(maxX < arrAtom[ii].x) {maxX = arrAtom[ii].x;}
                            if(minY > arrAtom[ii].y) {minY = arrAtom[ii].y;}
                            if(maxY < arrAtom[ii].y) {maxY = arrAtom[ii].y;}
                            if(minZ > arrAtom[ii].z) {minZ = arrAtom[ii].z;}
                            if(maxZ < arrAtom[ii].z) {maxZ = arrAtom[ii].z;}
                        }
                    }
                    //結合線
                    else if (arrDat[i].indexOf("CONECT") == 0) {
                        var s:String = arrDat[i].substr( 6, 5 );
                        var s0:String = arrDat[i];
                        var iStrCon:int = int(arrDat[i].substr( 6, 5 ));
                        for (var j:int = 11; j < arrDat[i].length; j += 5) {
                            var s2:String = arrDat[i].substr( j, 5 );
                            var iEndCon:int = int(arrDat[i].substr( j, 5 ));
                            //結合のデータは始点・終点を逆にして2本あるので片方をセット
                            if(iStrCon<iEndCon) {    
                                arrConect.push( { StrCon:iStrCon, EndCon:iEndCon } );
                            }
                        }
                    }
                }
            }
            catch(e:*) {
                return;
            }
            //中心座標
            var dx:Number = (minX + maxX) / 2.0;
            var dy:Number = (minY + maxY) / 2.0;
            var dz:Number = (minZ + maxZ) / 2.0;
            //表示
            fncDispAtom(dx,dy,dz);
        }            
        //原子結合線表示
        //dx,dy,dz:中心座標
        private function fncDispAtom(dx:Number, dy:Number, dz:Number):void {
            //3D形状の配置領域作成
            rootNode = new DisplayObject3D();
            this.scene.addChild(rootNode);

            rootNode.x = 0;
            //原子の表示
            for (var k:int = 0; k < arrAtom.length; k++) {
                var r:Number=30;
                var ic:uint = 0x0000ff;
                var s:String = arrAtom[k].nam.substr(0, 1);
                if (s == "H") {
                    r = 15;
                    ic = 0x00ffff;
                } else if (s == "C") {
                    ic = 0x008800;
                }
                rootNode.addChild(mkAtom(arrAtom[k].nam,
                        (arrAtom[k].x-dx), (arrAtom[k].y-dy), (arrAtom[k].z-dz), r, ic,0xff00ff));
            }
            //結合線の表示
            for (var l:int = 0; l < arrConect.length; l++) {
                var id1:int = getAtomID(arrConect[l].StrCon);
                var id2:int = getAtomID(arrConect[l].EndCon);
                if (id1 >= 0 && id2 >= 0) {
                    var r1:Number = 30;
                    var r2:Number = 30;
                    var s1:String = arrAtom[id1].nam.substr(0, 1);
                    if (s1 == "H") {
                        r1 = 15;
                    }
                    var s2:String = arrAtom[id2].nam.substr(0, 1);
                    if (s2 == "H") {
                        r2 = 15;
                    }
                    rootNode.addChild(mkLine(
                        (arrAtom[id1].x-dx) , (arrAtom[id1].y-dy) , (arrAtom[id1].z-dz) ,
                        (arrAtom[id2].x - dx) , (arrAtom[id2].y - dy) , (arrAtom[id2].z - dz),
                        r1, r2, 0x888888));
                }
            }
            //onSlChmg();
            kakudo0 = 0;
            kakudo1 = 0;
            kakudo2 = 0;
            addEventListener(Event.ENTER_FRAME, onFrame);
        }
        private function onFrame(e:Event):void
        {
            kakudo0 += 0.3;
            kakudo1++;
            if (kakudo1 >= 360) { kakudo1 = 0; }
            if (kakudo0 >= 360) { kakudo0 -= 360; }
            kakudo2 = Math.sin(kakudo0 * Math.PI / 180) * 80;
            
            onSlChmg();
            
        }
        //結合線の両端に付く原子を求める
        // iCon:原子のID
        // 戻り値:arrAtomの位置(-1:対応する原子なし)
        private function getAtomID(iCon:int):int {
            for (var i:int; i < arrAtom.length; i++) {
                if (iCon == arrAtom[i].id) { return i;}
            }
            return -1;
        }
        //原子の表示
        // nam:表示する名称
        // x,y,z:表示位置
        // r:半径
        // uiAtomCol:原子の色
        // uiNameCol:表示名称の色
        // 戻り値:オブジェクト
        private function mkAtom(nam:String, x:Number, y:Number, z:Number, r:Number, 
                uiAtomCol:uint,uiNameCol:uint):DisplayObject3D {
            var objNode:DisplayObject3D=new DisplayObject3D();
            //原子
            var objPlane:Plane;
            //イメージをコピーする:色の変更のため
            var bw:Number = bmAtom.width;
            var bh:Number = bmAtom.height;
            var bmd:BitmapData = new BitmapData( bw, bh, true, 0 );
            bmd.copyPixels( bmdAtom, new Rectangle( 0, 0, bw, bh ), new Point( 0, 0 ) );
            var bmp:Bitmap = new Bitmap( bmd );
            var matrAtom:BitmapMaterial = new BitmapMaterial(bmp.bitmapData,true);
            matrAtom.smooth = true;
            matrAtom.oneSide = true;
            //matrAtom.doubleSided = true;  //裏表示
            objPlane = new Plane(matrAtom, r * 2, r * 2, 1, 1);
            objNode.addChild(objPlane);
            var ir:uint = uiAtomCol / (256 * 256);    //カラーをRGBに分解
            var ig:uint = (uiAtomCol / (256))-ir*256;
            var ib:uint = uiAtomCol % 256;
            //イメージの黒色部分を指定カラーに変更
            objPlane.material.bitmap.colorTransform(objPlane.material.bitmap.rect, 
                    new ColorTransform(1.0,1.0,1.0,1.0, ir, ig, ib,0));
            
            //名称の表示
            var LMaterial:Letter3DMaterial = new Letter3DMaterial(uiNameCol , 1);
            //LMaterial.doubleSided = true;  //裏表示
            var fnt:HelveticaBold = new HelveticaBold();
            var word:Text3D = new Text3D(nam, fnt , LMaterial);
            word.z = -10.0;        //手前に表示
            word.x = 10.0+nam.length*10.0;
            word.y = 20.0;
            word.scale = 0.5;
            objNode.addChild(word);

            //(原子+名称)の位置
            objNode.x = x;
            objNode.y = y;
            objNode.z = z;
            //表示処理用の配列にセット
            arrObj.push(objNode);
            return objNode;
        }
        //結合線
        // x1,y1,z1,x2,y2,z3:結合線の始終点
        // r1,r2:付く原子の半径(半径分表示線分を短くする)
        // ic:カラー
        private function mkLine(x1:Number, y1:Number, z1:Number,
                                x2:Number, y2:Number, z2:Number,
                                r1:Number, r2:Number, ic:uint):Lines3D {
            //ラインの単位ベクトルを求める
            var dx:Number = x2 - x1;
            var dy:Number = y2 - y1;
            var dz:Number = z2 - z1;
            var dd:Number = Math.sqrt(dx * dx + dy * dy + dz * dz);
            if (dd > 0.0) {
                dx = dx / dd;
                dy = dy / dd;
                dz = dz / dd;
            }
            //線を引く
            var lm:LineMaterial = new LineMaterial(ic);  
            var lines3D:Lines3D = new Lines3D();
            var startV:Vertex3D = new Vertex3D(x1+r1*dx, y1+r1*dy, z1+r1*dz);  
            var endV:Vertex3D = new Vertex3D(x2-r2*dx, y2-r2*dy, z2-r2*dz);  
            var line:Line3D = new Line3D(lines3D, lm, 5, startV, endV);  
            lines3D.addLine(line);
            return lines3D;
        }
        //Sliderの値変更:カメラの位置セット、形状表示
        private function onSlChmg():void {
            //カメラ位置
            var kyori:Number = 800;//原点・カメラの距離
            //高さ方向の角度(ラジアン)
            var ang1:Number =  kakudo2 * Math.PI / 180.0;    
            //方向(ラジアン)
            var ang2:Number = (kakudo1-180) * Math.PI / 180.0;    
            var x:Number=kyori*Math.cos(ang1)*Math.sin(ang2);
            var y:Number=kyori*Math.cos(ang1)*Math.cos(ang2);
            var z:Number = kyori*Math.sin(ang1);
            this.camera.x = x;
            this.camera.z = y;
            this.camera.y = z;
            
            //原子(Plenで表示)を正面を向かせる。
            for (var i:int = 0; i < arrObj.length; i++) {
                //lookAtで原子をカメラに向けると文字等がうまく表示されない
                //arrObjAtom[i].lookAt( bv.camera );
                //arrObjAtom[i].yaw(180);
                arrObj[i].rotationX = kakudo2;
                arrObj[i].rotationY = kakudo1;
            }
            //描画処理
            this.renderer.renderScene( this.scene , this.camera , this.viewport );
        }
    }
}