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