forked from: papervision3dで地形と等高線を表示

by wunggao forked from papervision3dで地形と等高線を表示 (diff: 329)
 * papervision3dで地形と等高線を表示。
* 地形データは「標高データ 立山カルデラ周辺](http://www.vector.co.jp/soft/data/home/se021130.html)
* を利用させていただいている。
* シフトキーを押しながら、画面をクリックすると、等高線が表示される。
* ドラッグで、カメラ位置を変更できる。
♥0 | Line 323 | Modified 2010-08-27 12:05:17 | MIT License
play

ActionScript3 source code

/**
 * Copyright wunggao ( http://wonderfl.net/user/wunggao )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/690x
 */

// forked from termat's papervision3dで地形と等高線を表示
/*
 * papervision3dで地形と等高線を表示。
 * 地形データは「標高データ 立山カルデラ周辺](http://www.vector.co.jp/soft/data/home/se021130.html)
 * を利用させていただいている。
 * シフトキーを押しながら、画面をクリックすると、等高線が表示される。
 * ドラッグで、カメラ位置を変更できる。
 */
package 
{

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.geom.ColorTransform;
    import flash.system.Security;
    import org.papervision3d.core.geom.Lines3D;
    import org.papervision3d.core.geom.renderables.Line3D;
    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.materials.special.LineMaterial;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.core.geom.TriangleMesh3D;
    import org.papervision3d.core.geom.renderables.Vertex3D;
    import org.papervision3d.core.geom.renderables.Triangle3D;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.core.math.NumberUV;
    import org.papervision3d.materials.utils.MaterialsList;
        
   [SWF(width = "500", height = "500", backgroundColor = "0x000000", fps = "30")] 
    public class Mountain extends BasicView
    {
        private var loader:URLLoader;
        private var node:Array;
        private var elem:Vector.<Array>;
        private var map:Vector.<Array>;
        private var mx:int;
        private var my:int;
        private var rangeZ:Number;
        private var minZ:Number;
        private var mesh:TriangleMesh3D;
        private var rootNode:DisplayObject3D;
        private var contour:DisplayObject3D;    
        private var isPress:Boolean=false;
        private var cameraPitch:Number = 61.75;
        private var cameraYaw:Number = 21;
        private var cameraTarget:DisplayObject3D = DisplayObject3D.ZERO;
        private var preX:Number;
        private var preY:Number;

        public function Mountain():void{
            super(500, 500, false, false);
            rootNode = new DisplayObject3D();
            scene.addChild(rootNode);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.addEventListener(Event.ENTER_FRAME, update);
            /*5iVESTAR.ORGさん(http://5ivestar.org/blog/)のプロキシを利用させていただいている。*/
            Security.loadPolicyFile("http://termat.sakura.ne.jp/crossdomain.xml");
            loader = new URLLoader();
            loader.addEventListener(Event.COMPLETE,onCompleted);
            loader.load(new URLRequest("http://termat.sakura.ne.jp/air/data.csv"));
        }
    
        private function update(e:Event):void {
            if (!isPress) {
                cameraYaw += 2;
                cameraYaw %= 360;
                camera.orbit(cameraPitch, cameraYaw, true, cameraTarget);
            }
        }
        
        private function onMouseDown(e:MouseEvent):void{
            isPress = true;
            preX = e.stageX;
            preY = e.stageY;
            if (e.shiftKey) {
                if (contour == null) {
                    contour = new DisplayObject3D();
                    rootNode.addChild(contour);
                    var num:Number = Math.round(minZ / 10) * 10;
                    for (; num < minZ + rangeZ; num += 10) {
                        if (num % 200 == 0) {
                            drawContour(num);
                        }
                    }
                }else {
                    if (contour.parent == rootNode) {
                        rootNode.removeChild(contour);
                    }else {
                        rootNode.addChild(contour);
                    }
                }
            }
        }
 
        private function onMouseUp(e:MouseEvent):void{
            isPress = false;
        }
 
        private function onMouseMove(e:MouseEvent):void{
            if(isPress){
                cameraPitch += (e.stageY - preY) * 0.25;
                cameraYaw += (e.stageX - preX) * 0.25;
                cameraPitch %= 360;
                cameraYaw %= 360;
                cameraPitch = cameraPitch > 0 ? cameraPitch : 0.0001;
                cameraPitch = cameraPitch < 180 ? cameraPitch : 179.9999;
                preX = e.stageX;
                preY = e.stageY;
                camera.orbit(cameraPitch, cameraYaw, true, cameraTarget);
            }
        }
        
        private function onCompleted(e:Event):void {
            node = new Array();
            var data:Array = parseCSV(loader.data);
            my = (data[0] as Array).length;
            mx = data.length;
            var maxZ:Number = -1e12;
            minZ = 1e12;
            var centerX:Number = mx * 100 / 2;
            var centerY:Number = my * 100 / 2;
            for (var i:int = 0; i < data.length; i++) {
                for (var j:int = 0; j < data[i].length; j++) {
                    var z:Number = parseFloat(data[i][j]);
                    var p:Vertex3D = new Vertex3D(i * 100 - centerX, z, (my-j-1) * 100 - centerY);
                    node.push(p);
                    minZ = Math.min(minZ, z);
                    maxZ = Math.max(maxZ, z);
                }
            }
            camera.z = -my * 100 * 1.2;
            rangeZ = maxZ - minZ;
            createMap();
            mesh = new TriangleMesh3D(new ColorMaterial( 0x006699, 1 ), node, new Array(), null );
            rootNode.addChild(mesh);
            for (i = 0; i < elem.length; i++) {
                createTriMesh(node[elem[i][0]], node[elem[i][1]], node[elem[i][2]]);
            }
            startRendering();
        }
        
        private function parseCSV(str:String):Array {
            str = (str.split("\r\n")).join("\n");
            str = (str.split("\r")).join("\n");
            var data:Array = new Array();
            var tmp:Array = str.split("\n");
            var l:Number = tmp.length;
            for(var i:Number=0; i<l; i++){
                data.push(tmp[i].split(","));
            }
            if(data[data.length-1].length == 1 && data[data.length-1][0] == ""){data.pop();}
            return data;
        }
        
        private function createTriMesh(p0:Vertex3D, p1:Vertex3D, p2:Vertex3D):void {
            var col:Number = getColor( ((p0.y + p1.y + p2.y) / 3.0 - minZ) / rangeZ);
            var mat:ColorMaterial = new ColorMaterial(col, 1.0);
            var tri:TriangleMesh3D = new TriangleMesh3D( null, [ p0, p1, p2 ], [] );
            mesh.geometry.faces.push( new Triangle3D( tri, [ p0, p1, p2 ], mat, [new NumberUV( 0.5, 1 ), new NumberUV( 0, 0 ), new NumberUV( 1, 0 )] ));
            tri.geometry.ready = true;
        }
        
        private function getColor(v:Number):Number {
            var r:Number = Math.round( -238.0 * v * v + 493.0 * v);
            var g:Number = Math.round(480.0 * v * v - 480.0 * v + 255.0);
            var b:Number = Math.round(462*v*v-207*v);
            if (r > 255) r = 255;
            if (g > 255) g = 255;
            if (b > 255) b = 255;
            if (b < 0) b = 0;
            return (r<<16)+(g<<8)+b;
        }
        
        private function drawContour(val:Number):void {
            var lm:LineMaterial = new LineMaterial(0xff0000,0.9);
            var lines:Lines3D = new Lines3D(lm);
            var count:int = 0;
            for (var i:int = 0; i < elem.length; i++) {
                var d:Array = new Array(node[elem[i][0]], node[elem[i][1]], node[elem[i][2]]);
                var p:Array = sort(new Array(0, 1, 2), d);
                if (val >= p[0].y) {
                    if (val > p[2].y) {
                        continue;
                    }else {
                        var a:Vertex3D;
                        var b:Vertex3D;
                        var line:Line3D;
                        if(val>=p[1].y){
                            a = getPoint(p[0], p[2], val);
                            b = getPoint(p[1], p[2], val);
                            if (a == null || b == null) continue;
                            line = new Line3D(lines, lm, 0.5, a, b);
                            lines.addLine(line);
                            count++;
                        }else{
                            a = getPoint(p[0], p[2], val);
                            b = getPoint(p[0], p[1], val);
                            if(a==null||b==null)continue;
                            line = new Line3D(lines, lm, 0.5, a, b);
                            lines.addLine(line);
                            count++;
                        }
                    }
                }else{
                    continue;
                }
            }
            if (count > 0) contour.addChild(lines);
        }
        
        private function sort(it:Array,d:Array):Array{
            for (var i:int = 1; i < it.length; i++) {
                if (d[it[i]].y < d[it[i - 1]].y) {
                    var t:int=it[i-1];
                    it[i-1]=it[i];
                    it[i]=t;
                    return sort(it,d);
                }
            }
            return new Array(d[it[0]],d[it[1]],d[it[2]]);
        }
        
        private function getPoint(small:Vertex3D,large:Vertex3D,val:Number):Vertex3D{
            if(small.y==large.y)return null;
            var rr:Number=(val-small.y)/(large.y-small.y);
            var x:Number=small.x;
            var z:Number=small.z;        
            var xx:Number=(large.x-x)*rr+x;
            var zz:Number=(large.z-z)*rr+z;
            var l10:Number=Math.sqrt(Math.pow(xx-x, 2)+Math.pow(zz-z, 2));
            var l11:Number=Math.sqrt(Math.pow(xx-large.x, 2)+Math.pow(zz-large.z, 2));
            var ret:Vertex3D = new Vertex3D();
            var i:int;
            if (l10 == 0) {
                ret.x = small.x;
                ret.y = small.y;
                ret.z = small.z;
            }else if (l10 == 1) {
                ret.x = large.x;
                ret.y = large.y;
                ret.z = large.z;
            }else{
                var r0:Number=1/l10;
                var r1:Number=1/l11;
                ret.x = xx;
                ret.z = zz;
                ret.y = val;
            }
            return ret;
        }
        
        private function createMap():void {
            elem = new Vector.<Array>();
            map = new Vector.<Array>();
            var id:int = 0;
            for (var i:int = 0; i < mx; i++) {
                for (var j:int = 0; j < my; j++) {
                    if (i < mx - 1 && j < my - 1) {
                        var i0:Array=new Array(i*my+j,(i+1)*my+j+1,(i+1)*my+j);
                        var i1:Array=new Array(i*my+j,i*my+j+1,(i+1)*my+j+1);
                        elem.push(i0);
                        elem.push(i1);
                    }else{
                        continue;
                    }
                    if (i == mx - 1 || j == my - 1) continue;
                    var j0:Array;
                    var j1:Array;
                    if(i==0){
                        if(j==0){
                            j0=new Array(id+1,id+my*2-1,-1);
                            id++;
                            map.push(j0);
                            j1=new Array(-1,id+1,id-1);
                            map.push(j1);
                            id++;
                        }else if(j==my-2){
                            j0=new Array(id+1,id+my*2-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(-1,-1,id-1);
                            map.push(j1);
                            id++;
                        }else{
                            j0=new Array(id+1,id+my*2-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(-1,id+1,id-1);
                            map.push(j1);
                            id++;
                        }
                    }else if(i==mx-2){
                        if(j==0){
                            j0 = new Array(id + 1, -1, -1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),id+1,id-1);
                            map.push(j1);
                            id++;
                        }else if(j==my-2){
                            j0=new Array(id+1,-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),-1,id-1);
                            map.push(j1);
                            id++;
                        }else{
                            j0=new Array(id+1,-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),id+1,id-1);
                            map.push(j1);
                            id++;
                        }
                    }else{
                        if(j==0){
                            j0=new Array(id+1,id+my*2-1,-1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),id+1,id-1);
                            map.push(j1);
                            id++;
                        }else if(j==my-2){
                            j0=new Array(id+1,id+my*2-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),-1,id-1);
                            map.push(j1);
                            id++;
                        }else{
                            j0=new Array(id+1,id+my*2-1,id-1);
                            id++;
                            map.push(j0);
                            j1=new Array(id-(my*2-1),id+1,id-1);
                            map.push(j1);
                            id++;
                        }
                    }
                }
            }
        }
    }
}