Moebius
[SWF(width=600, height=600, backgroundColor=0xFF00)]
package{
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.BitmapData;
import flash.display.GraphicsTrianglePath;
import flash.display.GraphicsStroke;
import flash.display.GraphicsSolidFill;
import flash.display.IGraphicsData;
import flash.display.GraphicsBitmapFill;
import flash.display.TriangleCulling;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Utils3D;
import flash.geom.Vector3D;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFormat;
/*[SWF(width=600, height=600, backgroundColor=0xFF00)]*/
public class moebius extends Sprite{
public const W:Number = 100;
public const R:Number = 200;
//private var s:Shape = new Shape();
private var txt:TextField = new TextField();
private var bmp:BitmapData;
private var perspective:Matrix3D = new PerspectiveProjection().toMatrix3D();
private var sTransform:Matrix3D = new Matrix3D();
private var triangles:GraphicsTrianglePath = new GraphicsTrianglePath(new Vector.<Number>(), new Vector.<int>(), new Vector.<Number>(), TriangleCulling.NEGATIVE);
private var trianglesBack:GraphicsTrianglePath = new GraphicsTrianglePath(triangles.vertices, triangles.indices, triangles.uvtData, TriangleCulling.POSITIVE);
private var stroke:GraphicsStroke = new GraphicsStroke(NaN, false, "normal", "none", "round", 3, new GraphicsSolidFill(0x000000));
private var vertices3D:Vector.<Number> = new Vector.<Number>();
private var vertices3DTransformed:Vector.<Number> = new Vector.<Number>();
private var gData:Vector.<IGraphicsData>;
public function moebius(){
createMoebius(R, W, 100, 20, triangles, vertices3D);
sTransform.appendTranslation(0, 0, (W+R)*2);
sTransform.transformVectors(vertices3D, vertices3DTransformed);
this.x = stage.stageWidth/2;
this.y = stage.stageHeight/2;
/*addChild(s);*/
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
txt.text = "π = 3.14159265358979323846 - ";
txt.setTextFormat(new TextFormat("Palace Script MT", W, 0xFF0000, true));
txt.autoSize = "left";
bmp = new BitmapData(txt.width, txt.height, false, 0xFFFF00);
bmp.draw(txt);
bmp.fillRect(new Rectangle(0, 0, bmp.width, 4), 0xFF0000);
bmp.fillRect(new Rectangle(0, bmp.height-4, bmp.width, 4), 0xFF0000);
gData = Vector.<IGraphicsData>([stroke, new GraphicsBitmapFill(bmp, null, false, true), trianglesBack, triangles]);
draw();
}
private function draw():void{
Utils3D.projectVectors(perspective, vertices3DTransformed, triangles.vertices, triangles.uvtData);
/*s.*/graphics.clear();
/*s.*/graphics.drawGraphicsData(gData);
}
private function onMouseMove(e:MouseEvent):void{
//sTransform.pointAt(new Vector3D(e.stageX-stage.stageWidth/2, e.stageY-stage.stageHeight/2, sTransform.position.z*0.8), new Vector3D(0, 0, -1), new Vector3D(0, -1, 0));
sTransform.identity();
sTransform.appendRotation(e.stageX-stage.stageWidth/2, Vector3D.Y_AXIS);
sTransform.appendRotation(20/*e.stageY-stage.stageHeight/2*/, Vector3D.X_AXIS);
sTransform.appendTranslation(0, 0, (W+R)*2);
sTransform.transformVectors(vertices3D, vertices3DTransformed);
draw();
}
private function onMouseWheel(e:MouseEvent):void{
sTransform.appendTranslation(0, 0, e.delta*5);
sTransform.transformVectors(vertices3D, vertices3DTransformed);
draw();
}
private function onMouseDown(e:MouseEvent):void{
stroke.thickness = 1;
draw();
}
private function onMouseUp(e:MouseEvent):void{
stroke.thickness = NaN;
draw();
}
private function createMoebius(radius:Number, width:Number, N:uint, S:uint, trianglePathOut:GraphicsTrianglePath, vertices3DOut:Vector.<Number>):void{
for(var i:uint = 0; i<N; i++){
for(var j:uint = 0; j<S; j++){
/*vertices3DOut.push((radius+(2*j/(S-1)-1)*width/2*Math.cos(Math.PI*i/N))*Math.cos(Math.PI*2*i/N),
(radius+(2*j/(S-1)-1)*width/2*Math.cos(Math.PI*i/N))*Math.sin(Math.PI*2*i/N),
(2*j/(S-1)-1)*width/2*Math.sin(Math.PI*i/N));
trianglePathOut.uvtData.push(i/N, j/(S-1), 1);*/
vertices3DOut.push(
(radius+(2*j/(S-1)-1)*width/2*Math.cos(Math.PI*i/N))*Math.sin(Math.PI*2*i/N),
(2*j/(S-1)-1)*width/2*Math.sin(Math.PI*i/N),
(radius+(2*j/(S-1)-1)*width/2*Math.cos(Math.PI*i/N))*Math.cos(Math.PI*2*i/N)
);
//vertices3DOut.push(
// (radius+(2*j/(S-1)-1)/**width/2*Math.cos(Math.PI*i/N)*/)*Math.sin(Math.PI*2*i/N),
// (2*j/(S-1)-1)*width/2/**Math.sin(Math.PI*i/N)*/,
// (radius+(2*j/(S-1)-1)/**width/2*Math.cos(Math.PI*i/N)*/)*Math.cos(Math.PI*2*i/N)
//);
trianglePathOut.uvtData.push(i/N, j/(S-1), 1);
}
}
for(i = S; i>0; i--){
vertices3DOut.push(vertices3DOut[3*i-3], vertices3DOut[3*i-2], vertices3DOut[3*i-1]);
trianglePathOut.uvtData.push(1, 1-(i-1)/(S-1), 1);
}
for(i = 0; i<N/*+1*/; i++){
for(j = 0; j<S-1; j++){
var n:uint = i*S+j;
trianglePathOut.indices.push(n, n+1, n+S+1);
trianglePathOut.indices.push(n, n+S+1, n+S);
}
}
}
private function createSphere(radius:Number, N:uint, S:uint, trianglePathOut:GraphicsTrianglePath, vertices3DOut:Vector.<Number>):void{
for(var i:uint = 0; i <= N; i++){
for(var j:uint = 0; j <= S; j++){
vertices3DOut.push(
radius*Math.cos(2*Math.PI*j/S)*Math.sin(Math.PI*i/N),
-radius*Math.cos(Math.PI*i/N),
radius*Math.sin(2*Math.PI*j/S)*Math.sin(Math.PI*i/N)
);
trianglePathOut.uvtData.push(j/S, i/N, 1);
}
}
for(i = 0; i <= N; i++){
for(j = 0; j < S; j++){
var n:uint = i*S+j;
trianglePathOut.indices.push(n, n+1+S, n+1);
trianglePathOut.indices.push(n+1+S, n+2+S, n+1);
}
}
}
}
}