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

Electric potential 4

等電位面を分かりやすくし、電気力線も表示できるようにしました。
しかし、電気力線の本数がおかしくなる・・・
Get Adobe Flash player
by Nicolas 06 Jul 2012
/**
 * Copyright Nicolas ( http://wonderfl.net/user/Nicolas )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/pJf7
 */

// forked from Nicolas's Electric potential 3
// forked from Nicolas's Electric potential 2
// forked from Nicolas's Electric potential
/*
電位を計算して3次元表示する教材。

画面下部の赤丸(正電荷)・青丸(負電荷)をドラッグして緑の四角の中に入れると、
上の画面が変更されます。
上の画面はマウスドラッグで視点変更、↑↓キーでカメラ距離変更できます。

2012.6.29 マテリアルを変更し、高電位を赤、低電位を青で表示するようにしました。
*/

package 
{
    import flash.geom.Matrix;
    import flash.display.Shape;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.Graphics;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import org.papervision3d.core.geom.renderables.Vertex3D;
    import com.bit101.components.*;
    [SWF(width="465",height="465",backgroundColor="#CCCCCC")]
    public class Main extends Sprite
    {
        private var canvas:canvas3D;
        private var charges:Array;
        private var bd:BitmapData = new BitmapData(150, 150, false, 0xFFFFFF);
        private var bm:Bitmap = new Bitmap(bd);
        private var vc:ValueColor = new ValueColor();
        private var lineShape:Shape = new Shape();
        
        private var lineNum:int = 8;
        private var checkBox:CheckBox; 
        
        public function Main()
        {
            //3Dキャンバス
            canvas = new canvas3D(465, 300, bd);
            addChild(canvas);
            
            //2Dフィールド
            var field2D:Sprite = new Sprite();
            var fg:Graphics = field2D.graphics;
            fg.lineStyle(2, 0x00CC99);
            fg.drawRect(-75, -75, 150, 150);
            field2D.x = 225; field2D.y = 380;
            
            //ビットマップ
            addChild(bm);
            bm.x = field2D.x - 75;
            bm.y = field2D.y - 75;
            
            addChild(lineShape);
            lineShape.x = field2D.x;
            lineShape.y = field2D.y;
            
            addChild(field2D);
           
            //電荷
            charges = [
                new PCharge(), new PCharge(), new PCharge(), new PCharge(),
                new NCharge(), new NCharge(), new NCharge(), new NCharge(),
            ];
            for (var i:int = 0; i < charges.length; i++)
            {
                var c:Charge = charges[i] as Charge;
                c.lineNum = lineNum;
                c.x = -90;
                c.y = 20 * i - 65;
                field2D.addChild(c);
                c.addEventListener(Event.CHANGE, changeHandler);
            }
           
           checkBox = new CheckBox(stage, 320, 320, "line");
           checkBox.addEventListener(MouseEvent.CLICK, changeHandler);
        }
        
        private function changeHandler(e:Event):void
        {
            var vertices:Array = canvas.v;
            for (var i:int = 0; i < vertices.length; i++)
            {
                var v:Vertex3D = vertices[i];
                var tempV:Number = 0;
                for (var j:int = 0; j < charges.length; j++)
                {
                    var c:Charge = charges[j];
                    
                    //2Dフィールドの座標を3Dキャンバスの座標に対応させる
                    var cx:Number = c.x / 150 * 500;
                    var cy:Number = -c.y / 150 * 500;
                    
                    //電位を計算
                    if(c.x > -75 && c.y > -75 && c.x < 75 && c.y < 75)
                    tempV += 500 * c.q / Math.sqrt((v.x - cx)*(v.x - cx) + (v.z - cy)*(v.z - cy));
                }
                if (tempV > 300) tempV = 300;
                if (tempV < -300) tempV = -300;
                v.y = tempV;
            }
            
            for (var jj:int = 0; jj < bd.height; jj++) {
                for (var ii:int = 0; ii < bd.width; ii++) {
                    tempV = 0;
                    for (var n:int = 0; n < charges.length; n++) {
                        c = charges[n];
                        if(c.x > -75 && c.y > -75 && c.x < 75 && c.y < 75) {
                           tempV += 100 * c.q / Math.sqrt((ii - c.x - 75)*(ii - c.x - 75) + (jj - c.y - 75)*(jj - c.y - 75));
                        }
                    }
                    tempV = Math.round(tempV/10)*10;
                    bd.setPixel(ii, jj, vc.getColor(tempV));
                }

            }
            if(checkBox.selected) drawLine();
            else lineShape.graphics.clear();
        }
        
        //電気力線を描きます。(オイラー法)
        private function drawLine():void {
            var g:Graphics = lineShape.graphics;
            g.clear();
            g.lineStyle(1, 0x000000);
            var r:Number = 4;
            initLineNum();
            
            for each (var c:Charge in charges) {
                if(c.x > -75 && c.y > -75 && c.x < 75 && c.y < 75) {
                    start: for (var i:int = 0; i < c.lineStartAngles.length; i++) {
                        if(isNaN(c.lineStartAngles[i])) continue start;
                        
                        var tempX:Number = c.x + r * Math.cos(c.lineStartAngles[i]);
                        var tempY:Number = c.y + r * Math.sin(c.lineStartAngles[i]);
                        g.moveTo(tempX, tempY);
                        
                        var num:int = 0;
                        
                        drawing: while(tempX > -75 && tempY > -75 && tempX < 75 && tempY < 75) {
                            //無限ループって怖くね?
                            if(++num > 200000) break;
                            
                            var E:Number = 0;
                            var Ex:Number = 0;
                            var Ey:Number = 0;
                            var angle:Number = 0;
                            for each (var cc:Charge in charges) {
                                if(cc.x < -75 || cc.y < -75 || cc.x > 75 || cc.y > 75) continue;
                                
                                var distanceSquare:Number = ((cc.x - tempX)*(cc.x - tempX) + (cc.y - tempY)*(cc.y - tempY));
                                angle = Math.atan2(tempY - cc.y, tempX - cc.x);
                                
                                //電気力線が電荷に入ったら、ループ終了          
                                if(distanceSquare + 1 < r * r) {
                                    var step:Number = 2 * Math.PI / lineNum;
                                    for (var j:int = - lineNum / 2; j < lineNum / 2; j++) {
                                        if (step * (j - 0.5) < angle && angle <= step * (j + 0.5)) {
                                            cc.lineStartAngles[j] = NaN;
                                        }
                                    }
                                    break drawing;
                                }

                                E = 1 * cc.q / distanceSquare;
                             if (c is PCharge) {       
                                    Ex += E * Math.cos(angle);
                                    Ey += E * Math.sin(angle);
                             } else {
                                 Ex -= E * Math.cos(angle);
                                    Ey -= E * Math.sin(angle);
                             }

                            }
        
                            var nextX:Number = tempX += Ex;
                            var nextY:Number = tempY += Ey;
                            g.lineTo(nextX, nextY);
                            tempX = nextX;
                            tempY = nextY;
                        }
                    }
                }
                
            }
            
            bd.draw(lineShape, mat);

        }
        private var mat:Matrix = new Matrix(1, 0, 0, 1, 75, 75);
        
        //各電荷から出る電気力線の本数を初期値に戻します
        private function initLineNum():void {
            for each (var c:Charge in charges) {
                c.lineNum = lineNum;
                c.lineStartAngles = [];
                var step:Number = 2 * Math.PI / lineNum;
                for (var i:int = 0; i < lineNum; i++) {
                    c.lineStartAngles.push(i * step); 
                }
            }
        }

    }
}

import flash.geom.Matrix3D;
import flash.display.BitmapData;

import flash.display.Graphics;
import flash.events.Event;
import flash.events.KeyboardEvent;
import org.papervision3d.view.BasicView;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.core.math.Matrix3D;
class canvas3D extends BasicView
{
    public var v:Array;
    private var r:Number = 1200;
    private var theta:Number = 60;
    private var phi:Number = -90;
    private var mouseDownX:Number;
    private var mouseDownY:Number;
    public function canvas3D(w:uint, h:uint, texture:BitmapData) 
    {
        super(w, h, false);
        
        var g:Graphics = this.graphics;
        g.beginFill(0x000000);
        g.drawRect(0, 0, w, h);
        g.endFill();
        
        var m:BitmapMaterial = new BitmapMaterial(texture);
        m.doubleSided = true;
        var field:Plane = new Plane(m, 500, 500, 20, 20);
        field.transformVertices(org.papervision3d.core.math.Matrix3D.rotationX(Math.PI / 2));
        scene.addChild(field);
        
        setCameraPosition(r, theta, phi);
        camera.zoom = 80;
        startRendering();
        
        v = field.geometry.vertices;
        
        addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void 
        {
            addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void 
            {
                //マウスダウン位置を記録
                mouseDownX = mouseX;
                mouseDownY = mouseY;
                addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
            });
            stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void 
            {
                removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
            });
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
        });
    }
    
    /**
     * カメラの位置を極座標から直交座標に変換する。
     * @param    $r
     * @param    $theta
     * @param    $phi
     */
    private function setCameraPosition($r:Number, $theta:Number, $phi:Number):void {
        var thetaRad:Number = $theta / 180 * Math.PI;
        var phiRad:Number = $phi / 180 * Math.PI;
        camera.x = -$r * Math.sin(thetaRad) * Math.cos(phiRad);
        camera.y = $r * Math.cos(thetaRad);
        camera.z = $r * Math.sin(thetaRad) * Math.sin(phiRad);
    }
    
    /**
     * ドラッグ量を角度に変換し、カメラの位置を設定する。
     * @param    e
     */
    private function mouseMoveHandler(e:MouseEvent):void 
    {
        if (e.buttonDown) {
            phi += e.stageX - mouseDownX;
            theta -= e.stageY - mouseDownY;
            if (theta > 179) theta = 179;
            if (theta < 1) theta = 1;
            if (phi < -180) phi = -179;
            if (phi > 0) phi = -1;
            
            setCameraPosition(r, theta, phi);//直交座標に変換
            
            mouseDownX = e.stageX;
            mouseDownY = e.stageY;
        }
    }
    
    /**
     * カメラの中心からの距離を設定する。↑:近づく、↓:遠ざかる。
     * @param    e
     */
    private function keyDownHandler(e:KeyboardEvent):void 
    {
        switch(e.keyCode)
        {
            case 38:
                r -= 50;
                setCameraPosition(r, theta, phi);
            break;
            
            case 40:
                r += 50;
                setCameraPosition(r, theta, phi);
            break;
        }
    }
}

import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
class Charge extends Sprite
{
    public var q:Number = 0;
    public var lineNum:int = 0;
    public var lineStartAngles:Array = [];
    private var ev:Event = new Event(Event.CHANGE);
    public function Charge()
    {
        init();
    }
    
    private function init():void
    {        
        buttonMode = true;
        addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { 
            startDrag(); 
        } );
        addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void { 
            stopDrag(); 
            if(y < -75) y = -75;
            dispatchEvent(ev);
        } );
    }
}

import flash.display.Sprite;
class PCharge extends Charge
{
    public function PCharge()
    {
        q = 10;
        var g:Graphics = this.graphics;
        g.beginFill(0xFF0000);
        g.lineStyle(1, 0x0);
        g.drawCircle(0, 0, 6);
        g.endFill();
        g.lineStyle(2, 0xFFFFFF);
        g.moveTo(-3, 0);
        g.lineTo(3, 0);
        g.moveTo(0, -3);
        g.lineTo(0, 3);
    }
}

import flash.display.Sprite;
class NCharge extends Charge
{
    public function NCharge()
    {
        q = -10;
        var g:Graphics = this.graphics;
        g.beginFill(0x0000FF);
        g.lineStyle(1, 0x0);
        g.drawCircle(0, 0, 6);
        g.endFill();
        g.lineStyle(2, 0xFFFFFF);
        g.moveTo(-3, 0);
        g.lineTo(3, 0);
    }
}


import frocessing.color.ColorHSV;
class ValueColor {
    private var hsv:ColorHSV = new ColorHSV();
    public var max:Number = 100;
    
    public function ValueColor(){}
    public function getColor(v:Number):uint {
        if(v < 0) {
            hsv.h = 240;
            hsv.s = - v / max;
        } else {
            hsv.h = 0;
            hsv.s = v / max;
        }
        return hsv.toRGB().value;
    }
}