SuperEllipse
@author Andre Michelle
package
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Utils3D;
import flash.geom.Vector3D;
/**
* @author Andre Michelle
*/
[SWF(width='465',height='490',frameRate='50',backgroundColor='0x0')]
public class SuperEllipse extends Sprite
{
private const proj: PerspectiveProjection = new PerspectiveProjection();
private const ellipse: SuperEllipseGeometry = new SuperEllipseGeometry( 24 ); // PLAY HERE (RESOLUTION)
private const matrix: Matrix3D = new Matrix3D();
private const shape: Shape = new Shape();
public function SuperEllipse()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.addEventListener( Event.RESIZE, resize );
stage.addEventListener( Event.ENTER_FRAME, enterFrame );
addChild( shape );
resize( null );
}
private function resize( event: Event ): void
{
shape.x = int( stage.stageWidth * .5 );
shape.y = int( stage.stageHeight * .5 );
}
private function enterFrame( event: Event ): void
{
// DEFINITELY PLAY HERE!!! (SUPER ELLIPSE PARAMETERS)
// CAUTION VALUES BELOW ZERO ARE POSSIBLE, BUT BLOW UP THE GEOMETRY (NO CLIPPING)
ellipse.modify( 1.0, 1.0 );
matrix.identity();
matrix.appendScale( 64.0, 64.0, 64.0 );
matrix.appendRotation( shape.mouseX * .5, Vector3D.Y_AXIS );
matrix.appendRotation(-shape.mouseY * .5, Vector3D.X_AXIS );
matrix.appendTranslation( 0.0, 0.0, 128.0 );
matrix.transformVectors( ellipse.wVerts, ellipse.tVerts );
proj.fieldOfView = 75.0;
Utils3D.projectVectors( proj.toMatrix3D(), ellipse.tVerts, ellipse.projectedVerts, ellipse.uvts );
ellipse.drawQuadStrip( shape.graphics );
}
}
}
import flash.display.Graphics;
/**
* http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/superellipse/
*/
class SuperEllipseGeometry
{
private const TWOPI: Number = Math.PI * 2.0;
private const PID2: Number = Math.PI * 0.5;
private var _n: int;
private var _p: P;
public var wVerts: Vector.<Number>;
public var tVerts: Vector.<Number>;
public var uvts: Vector.<Number>;
public var projectedVerts: Vector.<Number>;
public var quadsNum: int;
public var vertsNum: int;
public var quads: Vector.<int>;
public function SuperEllipseGeometry( n: int )
{
_n = n;
_init();
}
public function modify( power1: Number, power2: Number ): void
{
var tmp: Number;
var i: int = -1;
var p: P = _p;
var x: Number;
var y: Number;
var z: Number;
while( p )
{
if( 0.0 == p.abs_ct1 )
tmp = 0.0;
else
tmp = p.sgn_ct1 * Math.pow( p.abs_ct1, power1 );
if( 0.0 == p.abs_ct2 )
x = 0.0;
else
x = tmp * p.sgn_ct2 * Math.pow( p.abs_ct2, power2 );
if( 0.0 == p.abs_st1 )
y = 0.0;
else
y = p.sgn_st1 * Math.pow( p.abs_st1, power1 );
if( 0.0 == p.abs_st2 )
z = 0.0;
else
z = tmp * p.sgn_st2 * Math.pow( p.abs_st2, power2 );
wVerts[ ++i ] = x;
wVerts[ ++i ] = y;
wVerts[ ++i ] = z;
p = p.next;
}
}
public function drawQuadStrip( graphics: Graphics ): void
{
graphics.clear();
graphics.lineStyle( 0, 0xFFFFFF, 0.5 );
var qi: int;
var pi: int;
var x0: Number;
var y0: Number;
var i: int = 0;
var n: int = quadsNum;
for( ; i < n ; ++i )
{
qi = i << 2;
pi = quads[qi] << 1;
graphics.moveTo( x0 = projectedVerts[ pi ], y0 = projectedVerts[ ++pi ] );
pi = quads[++qi] << 1;
graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );
pi = quads[++qi] << 1;
graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );
pi = quads[++qi] << 1;
graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );
graphics.lineTo( x0, y0 );
}
}
/*
BUILDING GEOMETRY
*/
private function _init(): void
{
vertsNum = ( ( _n >> 1 ) + 1 ) * _n;
quadsNum = vertsNum - _n;
wVerts = new Vector.<Number>( vertsNum * 3, true );
tVerts = new Vector.<Number>( vertsNum * 3, true );
uvts = new Vector.<Number>( vertsNum * 3, true );
projectedVerts = new Vector.<Number>( vertsNum * 2, true );
quads = new Vector.<int>( quadsNum << 2, true );
var i: int;
var j: int;
var nh: int = _n >> 1;
var t1: Number;
var t2: Number;
var iInv: Number = 1.0 / _n;
var pn: Number = TWOPI / _n;
var uvi: int = -1;
var ct1: Number;
var ct2: Number;
var st1: Number;
var st2: Number;
var qi: int = -1;
var jn: int;
var p: P;
for( j = 0 ; j <= nh ; ++j )
{
t1 = j * pn - PID2;
for( i = 0 ; i < _n ; ++i )
{
if( i == 0 )
t2 = 0.0;
else
t2 = i * pn;
if( null == p )
p = _p = new P();
else
p = p.next = new P();
ct1 = Math.cos( t1 );
ct2 = Math.cos( t2 );
st1 = Math.sin( t1 );
st2 = Math.sin( t2 );
if( ct1 < 0.0 )
{
p.abs_ct1 = -ct1;
p.sgn_ct1 = -1.0;
}
else
{
p.abs_ct1 = ct1;
p.sgn_ct1 = 1.0;
}
if( ct2 < 0.0 )
{
p.abs_ct2 = -ct2;
p.sgn_ct2 = -1.0;
}
else
{
p.abs_ct2 = ct2;
p.sgn_ct2 = 1.0;
}
if( st1 < 0.0 )
{
p.abs_st1 = -st1;
p.sgn_st1 = -1.0;
}
else
{
p.abs_st1 = st1;
p.sgn_st1 = 1.0;
}
if( st2 < 0.0 )
{
p.abs_st2 = -st2;
p.sgn_st2 = -1.0;
}
else
{
p.abs_st2 = st2;
p.sgn_st2 = 1.0;
}
//-- NOT USED, BUT GO AHEAD > ADD TEXTURES
uvts[ ++uvi ] = i * iInv;
uvts[ ++uvi ] = 2.0 * j * iInv;
uvts[ ++uvi ] = 0.0;
if( j > 0 )
{
jn = j * _n;
if( i > 0 )
{
quads[++qi] = ( j - 1 ) * _n + i - 1;
quads[++qi] = ( j - 1 ) * _n + i;
quads[++qi] = jn + i;
quads[++qi] = jn + i - 1;
}
else
{
quads[++qi] = jn - 1;
quads[++qi] = ( j - 1 ) * _n;
quads[++qi] = jn;
quads[++qi] = ( j + 1 ) * _n - 1;
}
}
}
}
}
}
class P
{
public var abs_ct1: Number;
public var abs_ct2: Number;
public var abs_st1: Number;
public var abs_st2: Number;
public var sgn_ct1: Number;
public var sgn_ct2: Number;
public var sgn_st1: Number;
public var sgn_st2: Number;
public var next: P;
}