triangle fractall

by Cheshir forked from flash on 2014-12-24 (diff: 157)
let's do this http://2.bp.blogspot.com/-58NYJwX1hHw/TteOnR72WGI/AAAAAAAAA-w/0OrOFZrCQ24/s640/Mountain+Fractal.jpg
♥0 | Line 189 | Modified 2015-01-23 02:03:47 | MIT License
play

ActionScript3 source code

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

// forked from Cheshir's flash on 2014-12-24
package {
    import flash.filters.GlowFilter;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.events.Event;
    import flash.text.TextField;
    // let's do this http://www.flashandmath.com/advanced/simple3d/
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        
        private var multyY_1:Number = Math.random()-.5;    // this values must set facture of fractall       // funny but 0 height steel be 0
        private var multyY_2:Number = Math.random()-.5;    // разрывы возникают, так как треугольники переворачиваются, и у разных сторон
        private var multyY_3:Number = Math.random()-.5;    // оказываются разные значения
        
        private var isRotate:Boolean = false;
        private var needPointDraw:Boolean = false;
        private var canvas:Sprite = new Sprite();            //
        
        private var vertexArray:Array = [new Point3D(120,Math.random()*-180,0), new Point3D(-100,Math.random()*100,100), new Point3D(-100,Math.random()*100,-100),
                new Point3D(120,Math.random()*120,-200), new Point3D(120,Math.random()*120,200)];
        private var facesArray:Array = [[0,1,2,0],[2,3,0,0],[0,1,4,0]];    // last value is iteration of this face
        
        // face hold iteration value, i need find in facesArray all faces where (iterate == nowIterate), and make them fractall ! 
        private var nowIterate:int = 0;
     //   private var sequenceFace:Array = [0,1,2,0,0,1,0,2,3,5,6,7,8,0,1,2,3,0,1,0,0];    // 2 iteration // old age
        private var maxIterate:int = 3;  // 3 iteration normal implementation.    
        
        public function FlashTest() {
            drawGrid();    // I need more time... 15 minutes I did not get
            
            addChild(coordinates);
            addChild(canvas);
            stage.addEventListener(Event.ENTER_FRAME, rotate);
            
            var timeUpdate:Timer = new Timer(50);
            timeUpdate.addEventListener(TimerEvent.TIMER, nextFace);
            timeUpdate.start();
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, startRotate);
            stage.addEventListener(MouseEvent.MOUSE_UP, stopRotate);
            
            trace.textColor = 0xffee00;
            trace.filters = [new GlowFilter(0)];
            trace.x = 30;
            trace.y = 30;
            addChild(trace);
        }
        private var trace:TextField = new TextField();
        private var nowFace:int = 0;
        private function nextFace(e:TimerEvent):void{
            nowFace = findFace(nowIterate);
            if(nowFace >= 0){
                fractallFace(facesArray[nowFace], nowFace);
            } else if(nowIterate < maxIterate){
                nowIterate++;
            }
            trace.text = 'total faces: '+facesArray.length.toString();
            //fractallFace(facesArray[sequenceFace[faceI]],sequenceFace[faceI]);
            //if(faceI<sequenceFace.length)
            //    faceI++;
        }
        private function findFace(iterate:int=0):int {
            for(var i:int = 0; i<facesArray.length; i++){
                if(facesArray[i][3] == iterate){
                    return i;
                }
            }
            return -1;
        }

        
        private function approximatelyEqual(a:Number, b:Number, error:Number = 0.1):Boolean{
            if(a==b) return true;
            if(a>b){
                if(a-b > error) return true;
            } else {
                if(b-a > error) return true;
            }
            return false;
        }

        private function startRotate(e:MouseEvent):void{isRotate = true;}
        private function stopRotate(e:MouseEvent):void{isRotate = false;}
        private var speedZ:Number = 0;
        private var speedY:Number = 0;
        private var mX:Number = 0;
        private var mY:Number = 0;
        private function rotate(e:Event):void{
            if(isRotate){
                speedZ = (mY - mouseY)/100;
                speedY = (mouseX - mX)/100;
                theta += speedZ;
                phi += speedY;
            }
            mX = mouseX;
            mY = mouseY;
            canvas.graphics.clear();
            for(var i:int=0; i<vertexArray.length; i++){
                drawPoint(vertexArray[i]);    
            }
            for(i=0; i<facesArray.length; i++){
                drawFace(facesArray[i]);
            }
            drawGrid();
        }
        
        // this must make this http://2.bp.blogspot.com/-58NYJwX1hHw/TteOnR72WGI/AAAAAAAAA-w/0OrOFZrCQ24/s640/Mountain+Fractal.jpg 1 time
        private function fractallFace(face:Array, faceId:uint):void{
            // одна грань должна превратиться в 4
            // первым делом нужно добавить новую точку (всего их будет 3)
            // за высоту отвечает Y остальные точки должны быть строго по середине                // in this case Y = 0 and multy is not work...
            var id_1:int = vertexArray.length;    // будущие id новых точек
            var id_2:int = id_1+1;
            var id_3:int = id_2+1;
            var id_a:int = face[0];    // id старых точек на грани
            var id_b:int = face[1];
            var id_c:int = face[2];                    
            var nextIterate:int = face[3]+1; // это определенно более сглаженно, но блин (((
            var p_1:Point3D = new Point3D((vertexArray[face[0]].x+vertexArray[face[1]].x)/2, getNewY(vertexArray[face[0]], vertexArray[face[1]], multyY_1), (vertexArray[face[0]].z+vertexArray[face[1]].z)/2);
            var p_2:Point3D = new Point3D((vertexArray[face[1]].x+vertexArray[face[2]].x)/2, getNewY(vertexArray[face[1]], vertexArray[face[2]], multyY_2), (vertexArray[face[1]].z+vertexArray[face[2]].z)/2);
            var p_3:Point3D = new Point3D((vertexArray[face[2]].x+vertexArray[face[0]].x)/2, getNewY(vertexArray[face[2]], vertexArray[face[0]], multyY_3), (vertexArray[face[2]].z+vertexArray[face[0]].z)/2);
            vertexArray.push(p_1, p_2, p_3);
            facesArray.splice(faceId,1); // delete old face
            facesArray.push( [ id_2, id_3, id_1, nextIterate ], [id_a, id_1, id_3, nextIterate], [id_1, id_b, id_2, nextIterate ],
            [id_3, id_2, id_c, nextIterate] ); 
            
            // abc - to - a13 - 32c - 1b2 - 231
            // where 1 in ab, 2 in bc, 3 in ca
        }
        private function getNewY(pointA:Point3D, pointB:Point3D, multy:Number):Number{
            var length:Number = Math.sqrt(Math.pow(pointA.x-pointB.x, 2) + Math.pow(pointA.z-pointB.z, 2));
            return (pointA.y+pointB.y)/2 + length*multy ;
        }
        
        private var coordinates:Sprite = new Sprite();
        public function drawGrid():void{  
            coordinates.graphics.clear();
            var w:Number = stage.stageWidth;
            var h:Number = stage.stageHeight;
            var point_0:Point3D = new Point3D(0,0,0);
            point_0.calcVisual(theta, phi);
            var point_X:Point3D = new Point3D(100,0,0);
            var point_Y:Point3D = new Point3D(0,100,0);
            var point_Z:Point3D = new Point3D(0,0,100);
            point_X.calcVisual(theta, phi);
            point_Y.calcVisual(theta, phi);
            point_Z.calcVisual(theta, phi);
            this.graphics.beginFill(0xcccccc);
            this.graphics.drawRect(0,0,w,h);
            this.graphics.endFill();
            
            coordinates.graphics.lineStyle(1,0xdd3333,0.4);
            coordinates.graphics.moveTo(point_0.visualX, point_0.visualY);
            coordinates.graphics.lineTo(point_X.visualX, point_X.visualY);
            coordinates.graphics.lineStyle(1,0x33dd33,0.4);
            coordinates.graphics.moveTo(point_0.visualX, point_0.visualY);
            coordinates.graphics.lineTo(point_Y.visualX, point_Y.visualY);
            coordinates.graphics.lineStyle(1,0x3333dd,0.4);
            coordinates.graphics.moveTo(point_0.visualX, point_0.visualY);
            coordinates.graphics.lineTo(point_Z.visualX, point_Z.visualY);
    
            canvas.x = w/2; canvas.y = h/2;
            coordinates.x = 100; coordinates.y = 100;
        }
        // Создание подписей
        private function createSignature(x:Number,y:Number,signature:String,scale:Number = 1.5):void{
            var sig:TextField = new TextField();
            sig.text = signature;
            sig.textColor = 0xdd3333;
            sig.scaleX = sig.scaleY = scale;
            sig.autoSize = 'left';
            sig.x = x;
            sig.y = y;
            addChild(sig);
        }
        private var theta:Number = 0;
        private var phi:Number = 0;
        private function drawPoint(p:Point3D):void{
            if(needPointDraw){
                canvas.graphics.beginFill(0x33dd33+p.z*0xdd);    // I can draw point, but I need calculate offset before;
            // похоже, что это позволяет производить сещение для осей Y и Z и это выглядит правильно, но ось Х у меня выпадает
            p.calcVisual(theta,phi);  
            canvas.graphics.drawCircle(p.visualX, p.visualY, 3);
            canvas.graphics.endFill();
            } else {
                p.calcVisual(theta,phi);
            }
        }
        private var averageY:Number=0;
        private function drawFace(face:Array):void{
            averageY = (vertexArray[face[0]].y + vertexArray[face[1]].y + vertexArray[face[2]].y)/3;
            canvas.graphics.beginFill(averageY,0.4);    // z-sorting? phhhhfffff!....
            canvas.graphics.lineStyle(1,0x333333);
            canvas.graphics.moveTo(vertexArray[face[0]].visualX, vertexArray[face[0]].visualY);
            canvas.graphics.lineTo(vertexArray[face[1]].visualX, vertexArray[face[1]].visualY);
            canvas.graphics.lineTo(vertexArray[face[2]].visualX, vertexArray[face[2]].visualY);
            canvas.graphics.endFill();
        }
    }
}
import flash.geom.Point;

Class {
    class Point3D extends Point{
        public var visualX:Number;
        public var visualY:Number;
        public var z:Number;
        public var color:uint;
        public function Point3D(x:Number=0, y:Number=0, z:Number=0, color:uint=0xdd3333){
            this.x = x; this.color = color;
            this.y = y;
            this.z = z;
        }
        // нужно бы еще создать точку схождения...
        public function calcVisual(theta:Number, phi:Number):void{
            this.visualX = x*Math.cos(theta)*Math.sin(phi) + y*Math.sin(theta)*Math.sin(phi) + z*Math.cos(phi);
            this.visualY = -x*Math.sin(theta)+y*Math.cos(theta);
        }
    }
}