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

Perfect Shuffle Visualization Ex

@see http://wonderfl.net/code/2733fb8d3d956ad68601f145c753de4d3be8c889
底面半径r, 高さhの円錐を展開すると、
半径R=√(r^2+h^2), 角度2πr/R [rad]の扇になる。
このとき、座標(r(1-t)cosθ,r(1-t)sinθ,ht)のうつる先は
(0,0,0)→(0,0), (r,0,0)→(R,0)とすると
(Rtcos(θ*r/R),Rtsin(θ*r/R))となる。
Get Adobe Flash player
by uwi 18 Jan 2010
/**
 * Copyright uwi ( http://wonderfl.net/user/uwi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iq7n
 */

package {
    import org.papervision3d.view.BasicView;
    import org.papervision3d.core.math.*;
    import org.papervision3d.core.geom.*;
    import org.papervision3d.core.geom.renderables.*;
    import org.papervision3d.core.proto.*;
    import org.papervision3d.materials.special.*;
    import org.papervision3d.materials.*;
    import org.papervision3d.objects.primitives.*;
    import flash.display.*;
    import flash.text.TextField;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import net.hires.debug.Stats;
    import com.bit101.components.*;
    import org.libspark.betweenas3.*;
    import org.libspark.betweenas3.tweens.*;
    import flash.filters.*;
    import frocessing.color.ColorHSV;
    
    // @see http://wonderfl.net/code/2733fb8d3d956ad68601f145c753de4d3be8c889
    // 底面半径r, 高さhの円錐を展開すると、
    // 半径R=√(r^2+h^2), 角度2πr/R [rad]の扇になる。
    // このとき、座標(r(1-t)cosθ,r(1-t)sinθ,ht)のうつる先は
    // (0,0,0)→(0,0), (r,0,0)→(R,0)とすると
    // (Rtcos(θ*r/R),Rtsin(θ*r/R))となる。
    [SWF(backgroundColor="0x000000", frameRate="60")]
    public class PV3D extends BasicView {
        private const R : Number = 100; // 底面半径
        private const H : Number = 200; // 高さ
        private const F : Number = Math.sqrt(R * R + H * H);
        private var _corn : Cylinder; // 球面
        
        private var _froms : Array;
        private var _tos : Array;
        private var _tween : ITween = null;
        
        private var _tf : TextField;
        
        public function PV3D() {
            Wonderfl.capture_delay(10);
            
            graphics.beginFill(0x000000);
            graphics.drawRect(0, 0, 475, 475);
            graphics.endFill();
            
            super(0, 0, true, false);
            
            // デバッグ用
            _tf = new TextField();
            _tf.textColor = 0xffffff;
            _tf.width = 400;
            _tf.height = 465;
//            addChild(_tf);
            
            // 円錐の初期化・配置
//            var mat : MaterialObject3D = new WireframeMaterial(0xffffff, 0.5);
            var mat : MaterialObject3D = new BitmapMaterial(drawPerfectShuffle(300, 200, 30), true);
            mat.oneSide = false;
            _corn = new Cylinder(mat, R, H, 20, 20, 0, false, false);
            scene.addChild(_corn);
            
            var v : Vertex3D;
            var i : uint;
            _froms = [];
            _tos = [];
            for(i = 0;i < _corn.geometry.vertices.length;i++){
                v = _corn.geometry.vertices[i];
                _froms.push({x : v.x, y : v.y, z : v.z});
                var theta : Number = Math.atan2(v.z, v.x) + Math.PI;
                var t : Number = (v.y - H / 2) / H;
                _tos.push({ 
                    x : F * t * Math.cos(theta * R / F),
                    z : F * t * Math.sin(theta * R / F),
                    y : H / 2
                });
            }
            
            var btn : PushButton = new PushButton(this, 360, 0, "retry", function(e : MouseEvent) : void { init(); });
            
            // カメラの配置
            _camera = new SphereCamera(new Number3D(0, 0, 0), 350, new Number3D(0, 0, 1), new Number3D(0, 1, 0));
            
            init();
            
            startRendering();
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            
//            addChild(new Stats());
        }
        
        // 初期化
        private function init() : void
        {
            if(_tween != null)_tween.stop();
            
            var tweens : Array = [];
            var i : uint;
            for(i = 0;i < _corn.geometry.vertices.length;i++){
                var v : Vertex3D = _corn.geometry.vertices[i];
                tweens.push(
                BetweenAS3.delay(
                        BetweenAS3.tween(v, _froms[i], _tos[i], 5.0)
                        ,0.3 * ((i + 9) % 20)
                        )
                        );
            }
            _tween = BetweenAS3.parallelTweens(tweens);
            _tween.play();
        }
        
        private var _prevX : Number = 0;
        private var _prevY : Number = 0; 
        
        // マウスを移動したときの動作
        private function onMouseMove(e : MouseEvent) : void
        {
//            camera.orbit(stage.mouseY * 0.5, -stage.mouseX * 0.5);
            if(e.buttonDown){
                // ボタンをおしている状態のときのみカメラを移動
                if(_prevX != 0 && _prevY != 0){
                    var sc : SphereCamera = SphereCamera(camera);
                    // 直前との差分だけ移動
                    sc.move((stage.mouseX - _prevX) * 0.005, (stage.mouseY - _prevY) * 0.005);
                }
                _prevX = stage.mouseX;
                _prevY = stage.mouseY;
            }else{
                _prevX = 0;
                _prevY = 0;
            }
        }
        
        // 毎フレームの動作
        override protected function onRenderTick(e : Event = null) : void
        {
            super.onRenderTick(e);
        }
        
        private function drawPerfectShuffle(w : Number, h : Number, size : uint) : BitmapData
        {
            var W : Number = w / 5;
            var H : Number = h / size;
            
            var num:int;
            var s:Sprite = new Sprite();
            for (var i:int = 0; i < size; i++) {
                num = i;
                s.graphics.lineStyle(4, new ColorHSV(i * 270 / size, .7).value, .7);
                s.graphics.moveTo(0, num * H);
                for (var j:int = 0; j < 5; j++) {
                    if (num < size / 2) {
                        num = num * 2 + 1;
                    } else {
                        num = (num - size / 2) * 2;
                    }
                    s.graphics.lineTo(j * W + W, num * H);
                }
            }
//            s.filters = [new BlurFilter(2, 2)];
            
            var ret : BitmapData = new BitmapData(w, h, true, 0x000000);
            ret.draw(s);
            return ret;
        }
              
        private function tr(...o : Array) : void
        {
            _tf.appendText(o + "\n");
            _tf.scrollV = _tf.maxScrollV;
        }
    }
}
import org.papervision3d.core.math.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
// 球面上を動き、球の中心を見るカメラ
class SphereCamera extends Camera3D
{
    private var _O : DisplayObject3D; // 球の中心
    public var _front : Number3D; // カメラの前の向きの単位ベクトル
//    private var _right : Number3D;
    public var _up : Number3D; // カメラの上の向きの単位ベクトル
    private var _R : Number; // 球の半径
    
    public function SphereCamera(O : Number3D, R : Number, front : Number3D, up : Number3D) : void
    {
        _O = new DisplayObject3D();
        _O.x = O.x;
        _O.y = O.y;
        _O.z = O.z;
        _R = R;
        _front = front.clone();
        _front.normalize();
        _up = up.clone();
        _up.normalize();
        
        update1();
    }
    
    // カメラの右方向へx[rad], 上方向へy[rad]回転させる
    public function move(x : Number, y : Number) : void
    {
        // X方向の移動
        _front = applyQuaternion([_front], _up, -x)[0];
        
        // Y方向の移動
        var right : Number3D = Number3D.cross(_up, _front);
        right.normalize();
        var ret : Array = applyQuaternion([_front, _up], right, y);
        _front = ret[0];
        _up = ret[1];
        
        update1();
    }
    
    private function update1() : void
    {
        this.x = _front.x * -_R + _O.x;
        this.y = _front.y * -_R + _O.y;
        this.z = _front.z * -_R + _O.z;
        this.lookAt(_O, _up);
    }
    
    // axisを軸にangle回転させる変換を、srcsの要素それぞれに適用する。
    public static function applyQuaternion(srcs : Array, axis : Number3D, angle : Number) : Array
    {
        var q : Quaternion = Quaternion.createFromAxisAngle(
            axis.x / axis.modulo, 
            axis.y / axis.modulo, 
            axis.z / axis.modulo,
            angle
            );
        var qc : Quaternion = Quaternion.conjugate(q);
        
        var ret : Array = [];
        for each(var src : Number3D in srcs){
            var qSrc : Quaternion = new Quaternion(src.x, src.y, src.z, 0);
            var qDst : Quaternion = Quaternion.multiply(qc, qSrc);
            qDst.mult(q);
            ret.push(new Number3D(qDst.x, qDst.y, qDst.z));
        }
        return ret;
    }
    
}