Konstantin's BLog
Function Viewer
home top contents previous up next

package
{

    //Function Viewer. Copyright (C) 2008 Konstantin Kirillov, Landkey Computers.
    //Demo Version 1.
	//Use monspaced font to read diagrams in comments correctly.
	
	//Was very painful attempt to find this import name: 
	//we were not able to find this path from Docs: 
	import flash.display.Graphics;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	import mx.core.UIComponent;

	/*
		       
	              basis in              
	              base space V
	                 /y            .  y' 
	                /          .    
	      Z,z|     /        .   basis in function's
	         |    /      .      domain space V'
	         |   / a  .
	         |  /  .
	         | /. 
	  -------|----------------- x,X
	         |.
	         |   . 
	         |      . 
	         |         .
	         |            . x'
	         
	
	         f: V' |--> |R
	    
	     We display function "fixed" in base space f(Tv')
	    
	         T =  c   s
	             -s   c
	    
	         c = cos(a)
	         s = sin(a)
	         
	    We also must map 3D function graph to display's screen plane 
	    which can be a Lens transformation:
	    
	         (X,Z) = b*(x,z)/y, b=const;
	    
	    which we approximate by linear transformation L: 
	    
	         (X,Z) = const*(x0+x,z0+z)(1-y/y0) = v0+( c1*x-c2*y , c1*z-c3*y )
	         We are taking v0 = 0.
	         
	         L = c1  -c2   0
	              0  -c3  c1      
	    
	    For better performance, we will store c,s in units of 1/1024
	    as integer numbers.

        Notations in program below:
        frontX,	frontY coordinates on computer display screen.
        (X,Z) = (frontX-centerX, centerY-frontY)
	    
	*/
	
	
	
	public class DrawFunction extends UIComponent
	{
		private var shift:uint = 10;
		private var shift2:int = 1024;
				
		private var cT:int;
		private var sT:int;
		private var c1:int;
		private var c2:int;
		private var c3:int;
				
		public var centerX:int = 0;
		public var centerY:int = 0;
		public var maxX:int;
		public var minX:int;
		public var maxY:int;
		public var minY:int;
		private var maxF:int;
        private var minF:int;
        private var rangeF:int;
        private var scaledF:Boolean;
            
		private var sizeX:int;
		private var sizeY:int;
		
		public var sign:TextField = null;

        //Drawing variables:
        //Front plane (Screen) coordinates:		
        private var frontX:int;
        private var frontY:int;

		public function DrawFunction(posX:int, posY:int, sizeX:int, sizeY:int)
		{
			 //super(posX,posY,"Drag Me", 9, 0xFFFFFF, true,false,null);
			 this.x = posX;
			 this.y = posY;
			 this.sizeX = sizeX;
			 this.sizeY = sizeY;
             centerX = sizeX/2;
             centerY = sizeY*10/15;
             
             //Take startup sample: 
             //(X,Z) ~ (x0+x,z0+z)(y0-y) 
             //        d=y0=x0=-z0 => 
             //        c1 = c2 = d = -c3                            
             c1 =  500;  
             c2 =  500;
             c3 = -500;
                          
             var format:TextFormat = new TextFormat( "Arial", 9, 0xFFFFFF );
             sign = new TextField();
             sign.defaultTextFormat = format;
             sign.autoSize = TextFieldAutoSize.LEFT;
             sign.selectable = false;
             sign.x = centerX+10;
             sign.y = centerY+10;			
             sign.text = "Function: 1000000/(xx+(y+100)(y+100)+10000))-(500000/((x-100)(x-100)+yy+5000))";
             addChild(sign);
             
             scaledF = false;
             //Start with function adjusted with normal basis:
             doWork( 0 );
             //Appr: problem:
             //addChild(sign);
        }

        public function f( xx:int, yy:int ):int 
        {
            var xF:int = (cT*xx - sT*yy)/shift2;
            var yF:int = (sT*xx + cT*yy)/shift2;
            //Bell:
        	//return 1000000/(xF*xF + yF*yF + 10000);
        	return (1000000/(xF*xF + (yF+100)*(yF+100) + 10000)) - ( 500000/((xF-100)*(xF-100) + yF*yF + 5000)) ;        	
        }

        //redrawRotatedFunction
        public function doWork( angle:Number ):void
        {
            rotateFunctionsSpace( angle );
            if( !scaledF ) scaleFunction();
            drawFunctionOnScreen();
        }

        private function rotateFunctionsSpace( angle:Number ):void
        {
        	cT = int(Math.cos(angle)*shift2);
        	sT = int(Math.sin(angle)*shift2); 
        }

        
        private function scaleFunction():void
        {
            //centerX =  mx.core.IFlexDisplayObject.stage.stageWidth;
            //centerX =  IFlexDisplayObject.stage.stageWidth;
            //centerY =  IFlexDisplayObject.stage.stageHeight;
            maxX    =  sizeX/2;
            if( maxX < 1 ) maxX = 20;
            minX    = -maxX;
            maxY    =  sizeY/2;
            if( maxY < 1 ) maxY = 20;
            minY    = -maxY;
            			
            //Scale function:
            maxF = f(0,0);
            minF = maxF;
            var yy:int;
            var xx:int;
            for( yy=maxY; yy>minY; yy-=1 )
            {
                    for( xx=minX; xx<maxX; xx+=4 )
                    {
                    	var zz:int = f(xx,yy);
                        maxF = Math.max(maxF,zz);
                        minF = Math.min(minF,zz);
                    }
            }            			
            rangeF = maxF-minF;
            if( rangeF == 0 ) rangeF = 10;
        	scaledF = true;
        }


		//Draw Funciton on Screen.
		public function drawFunctionOnScreen():void
		{
		    with( this.graphics )
			{
 		        clear();

 		        //Can be good:
 		        //graphics.moveTo(0,0);
                //graphics.beginFill(0,1); //do2 0,1 ?
                //graphics.drawRect(0,0, sizeX, sizeY);
                var yy:int;
                var xx:int;
				for( yy=maxY; yy>minY; yy-=1 )
				{
					for( xx=minX; xx<maxX; xx+=10 )
				    {
                        var zz:int = f(xx,yy)-minF;
                        projectXYZSpaceToFrontPlane(xx,yy,zz*sizeY/rangeF);
                        var fcolor:int = zz*255/rangeF;
                        fcolor = (fcolor<<16)+(255-fcolor);
                        lineStyle( 1, fcolor );
                        moveTo(frontX, frontY);
                        lineTo(frontX+1, frontY);
				    }
				}
				//For base:
				drawCoordinateAxes(this.graphics, 0x0000FF, false);
				//For function:
				drawCoordinateAxes(this.graphics, 0x00FF00, true);
			}
            //Debug:
			//sign.text = "minF=" + minF;

		}
		
        
        private function projectXYZSpaceToFrontPlane( x:int, y:int, z:int ):void
        {
        	/*
        	//Increase speed:
        	var xPart = x*c1;
        	xPart = xPart>0 ? xPart>>>shift : -(Math.abs(xPart)>>>shift);

        	var zPart = z*c1;
        	zPart = zPart>0 ? zPart>>>shift : -(Math.abs(xPart)>>>shift);
        	
        	var yPart = -y*c2;
        	yPart = yPart>0 ? yPart>>>shift : -(Math.abs(yPart)>>>shift);
        	*/

        	var xPart:int =  x*c1 /shift2;
        	var zPart:int =  z*c1 /shift2;
        	var yPart:int = -y*c2 /shift2;
        	
        	frontX = centerX +   xPart + yPart         ;
        	frontY = centerY - (         yPart + zPart);
        	
        } 		


        private function projectFunctionSpaceVSToFrontPlane( x:int, y:int, z:int ):void
        {
        	/*
        	//Increase speed:
        	var xPart = x*c1;
        	xPart = xPart>0 ? xPart>>>shift : -(Math.abs(xPart)>>>shift);

        	var zPart = z*c1;
        	zPart = zPart>0 ? zPart>>>shift : -(Math.abs(xPart)>>>shift);
        	
        	var yPart = -y*c2;
        	yPart = yPart>0 ? yPart>>>shift : -(Math.abs(yPart)>>>shift);
        	*/

            var xF:int = ( cT*x + sT*y)/shift2;
            var yF:int = (-sT*x + cT*y)/shift2;

        	var xPart:int =  xF*c1 /shift2;
        	var zPart:int =  z*c1 /shift2;
        	var yPart:int = -yF*c2 /shift2;
        	
        	frontX = centerX +   xPart + yPart         ;
        	frontY = centerY - (         yPart + zPart);
        	
        } 		
		

		
						
		private function drawCoordinateAxes(g:Graphics, color:int, forFunction:Boolean ):void
		{
			var xx:int;
            var yx:int;
			with(this.graphics) 
			{
               lineStyle( 1, color );
               xx = minX;
               yy = 0;
               projectXYZSpaceToFrontPlane(xx,yy,0 );
               if(forFunction) projectFunctionSpaceVSToFrontPlane(xx,yy,0);
               moveTo(frontX, frontY);
               xx = maxX;
               yy = 0;
               projectXYZSpaceToFrontPlane(xx,yy,0 );
               if(forFunction) projectFunctionSpaceVSToFrontPlane(xx,yy,0);
               lineTo(frontX, frontY);


               xx = 0;
               yy = minY;
               projectXYZSpaceToFrontPlane(xx,yy,0 );
               if(forFunction) projectFunctionSpaceVSToFrontPlane(xx,yy,0);
               moveTo(frontX, frontY);
               xx = 0;
               yy = maxY;
               projectXYZSpaceToFrontPlane(xx,yy,0 );
               if(forFunction) projectFunctionSpaceVSToFrontPlane(xx,yy,0);
               lineTo(frontX, frontY);

                 
               projectXYZSpaceToFrontPlane(0, 0, 0 );
               moveTo(frontX, frontY);
               projectXYZSpaceToFrontPlane(0, 0, sizeY );
               lineTo(frontX, frontY);

                //Variant:   
                //beginFill( 0x0000FF, .5 );
                //drawRect( centerX+minX, centerY-minY, centerX+maxX, centerY-maxY );
           }
		}//drawCoordinateAxes
	
	}//class
}//package

Copyright (C) 2008 Landkey Computers