In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

# SuperEllipse

@author Andre Michelle
by AndreMichelle 22 Oct 2009
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;

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 );

}
}
}

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 vertsNum: 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;

for( ; i < n ; ++i )
{
qi = i << 2;

graphics.moveTo( x0 = projectedVerts[ pi ], y0 = projectedVerts[ ++pi ] );

graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );

graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );

graphics.lineTo( projectedVerts[ pi ], projectedVerts[ ++pi ] );

graphics.lineTo( x0, y0 );
}
}

/*
BUILDING GEOMETRY
*/
private function _init(): void
{
vertsNum = ( ( _n >> 1 ) + 1 ) * _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 );

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;
}

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 - 1;
}
else
{
quads[++qi] = ( j - 1 ) * _n;
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;
}