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

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Particles 3D

PRESS "R" + CLICK TO ROTATE.
DRAG THE GREEN HANDLERS
package {

// PRESS "R" + CLICK TO ROTATE.
// DRAG THE GREEN HANDLERS

        import net.hires.debug.Stats;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix3D;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	public class DeformableBezier extends Sprite {

		//Variables que definen la malla...
		private var initLink : Particula = new Particula();
		private var nodos : Array = new Array();
		private var segmentsU : uint;
		private var segmentsV : uint;
		private var cantidad : Number;

		//Puntos de borde...
		private var Xt0 : Vector3D = new Vector3D();
		private var Xt1 : Vector3D = new Vector3D();
		private var Xb0 : Vector3D = new Vector3D();
		private var Xb1 : Vector3D = new Vector3D();

		//Puntos de control internos de las bezier...
		private var Cpt : Vector3D = new Vector3D();
		private var Cpb : Vector3D = new Vector3D();
		private var Cpl : Vector3D = new Vector3D();
		private var Cpr : Vector3D = new Vector3D();

		//Variable que contiene una referencia de los vectores de creación...
		private var pointsReference : Vector.<Vector3D> = new Vector.<Vector3D>;

		//Puntos que controlan el movimiento de los nodos de las curvas... 
		public var angle : Number = 0;

		//BitmapData de representación de las partículas...
		private var bmd : BitmapData;
		private var rect : Rectangle;

		//Variable que controla la rotación del objeto espacialmente....
		private var rotationMatrix : Matrix3D = new Matrix3D();
		private var rotationParentMatrix : Matrix3D = new Matrix3D();
		private const X_AXIS : Vector3D = new Vector3D(1, 0, 0);
		private const Y_AXIS : Vector3D = new Vector3D(0, 1, 0);
		private var PIVOT_POINT : Vector3D = new Vector3D(0, 0, 0);

		//Variable de colorTransform para limpiar el bitmapData...
		private var colorTransform : ColorTransform = new ColorTransform(0, 0, 0, 1, 0, 0, 0);

		//Variable que se encarga de la rotación...
		private var rotate : Boolean;
		private var mouse : Boolean;

		//Varible que contiene los distintas asas de control...
		private var asasContainer : Sprite = new Sprite();
		private var lineContainer : Sprite = new Sprite();
		private var persp : Number;

		//Variable que guarda referencia de las distintas asas de control...
		private var asas : Array = new Array();
		private var pointer : Vector3D;
		private var asasMatrix : Matrix3D;
		private var asasParentMatrix : Matrix3D;

		//Variable que guarda una referencia a la perspectiva utilizada en las transformaciones...
		private var focus : Number = 600;
		private var zoom : Number = 3;
                   
                // Variable de inicialización de la rotacion
                private var init : Boolean = false;
                   
		//Constructor...
		public function DeformableBezier() {
			
			var particle : Particula = initLink;
			Particula.focus = focus;
			Particula.zoom = zoom;
			ControlPoint.focus = focus;
			ControlPoint.zoom = zoom;
			var i : uint;
			var lado : Number = 50;
			
			//Defino los puntos de borde...
			Xt0 = new Vector3D(-lado, 0, -lado);
			Xt1 = new Vector3D(lado, 0, -lado);
			
			Xb0 = new Vector3D(-lado, 0, lado);
			Xb1 = new Vector3D(lado, 0, lado);
			
			//Defino los puntos internos de control...
			Cpt = new Vector3D(0, 0, -lado);
			Cpb = new Vector3D(0, 0, lado);
			Cpl = new Vector3D(-lado, 0, 0);
			Cpr = new Vector3D(lado, 0, 0);
			
			//Guardo los vectores en un vector de referencia...
			pointsReference[0] = Xt0;
			pointsReference[1] = Cpt;
			pointsReference[2] = Xt1;
			pointsReference[3] = Cpr;
			pointsReference[4] = Xb1;
			pointsReference[5] = Cpb;
			pointsReference[6] = Xb0;
			pointsReference[7] = Cpl;
			
			//Inserto las distintas asas en el contenedor...
			for (i = 0;i < 8; i++) {
				asas.push(new ControlPoint(i));
				asas[i].addEventListener(ControlPointEvent.CHANGE, updateControlPoints);
				asasContainer.addChild(asas[i]);
			}
			
			asasContainer.x = stage.stageWidth / 2;
			asasContainer.y = stage.stageHeight / 2;
			
			lineContainer.x = stage.stageWidth / 2;
			lineContainer.y = stage.stageHeight / 2;
			
			//Cantidad de puntos a mostrar...
			segmentsV = 60;
			segmentsU = 60;
			
			//Genero los puntos de las partículas...
			var length : uint = segmentsV * segmentsU;
			for(i = 0;i < length; i++) {
				nodos.push(new Vector3D(0, 0, 0));
			}
						
			cantidad = nodos.length - 1;
			i = 0;
			while(cantidad >= 0) {
				particle.position = nodos[i];
				particle.next = new Particula();
				particle = particle.next;
				cantidad--;
				i++;
			}
			
			bmd = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0);
			rect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);

			addChild(new Bitmap(bmd, "auto", false));
			addChild(lineContainer);
			addChild(asasContainer);
			addChild(new Stats());
			
			//Inicio la animación...
			stage.addEventListener(KeyboardEvent.KEY_DOWN, initRotation);
			stage.addEventListener(KeyboardEvent.KEY_UP, stopRotation);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownListener);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpListener);
			stage.addEventListener(MouseEvent.MOUSE_WHEEL, updateZoom);
			stage.addEventListener(Event.ENTER_FRAME, updatePoints);
		}

		//Función que se encarga de actualizar los puntos de control...
		private function updateControlPoints(e : ControlPointEvent) : void {
			switch(e.cp) {
				case 0:
					pointsReference[0] = Xt0 = e.vector;
					break;
				case 1:
					pointsReference[1] = Cpt = e.vector;
					break;
				case 2:
					pointsReference[2] = Xt1 = e.vector;
					break;
				case 3:
					pointsReference[3] = Cpr = e.vector;
					break;
				case 4:
					pointsReference[4] = Xb1 = e.vector;
					break;
				case 5:
					pointsReference[5] = Cpb = e.vector;
					break;
				case 6:
					pointsReference[6] = Xb0 = e.vector;
					break;
				case 7:
					pointsReference[7] = Cpl = e.vector;
					break;
			}
			lineContainer.graphics.clear();
			lineContainer.graphics.lineStyle(0, 0XFFFF00, 1);
			for(var i : uint = 0;i < pointsReference.length; i++) {
				if(i == 0) {
					lineContainer.graphics.moveTo(asas[i].x, asas[i].y);
				} else {
					lineContainer.graphics.lineTo(asas[i].x, asas[i].y);
				}					
			}
			lineContainer.graphics.lineTo(asas[0].x, asas[0].y);
		}

		//Función que ejecuta la animación de manera secuencial...
		private function updatePoints(e : Event) : void {			
			var particle : Particula = initLink;
			var i : uint = 0;
			
			//Defino las curvas bezier...
			//Top...
			var BT : Array = new Array(Xt0, Cpt, Xt1);
			
			//Bottom...
			var BB : Array = new Array(Xb0, Cpb, Xb1);

			//Izquierda...
			var BL : Array = new Array(Xt0, Cpl, Xb0);
			
			//Derecha...
			var BR : Array = new Array(Xt1, Cpr, Xb1);
			
			//Calculo los puntos...	
			nodos = Bezier.getPatch(Xt0, Xt1, Xb0, Xb1, BT, BB, BL, BR, segmentsU, segmentsV);
                        
                        if(!init){
                            init = true;
                            
                            rotationMatrix.identity();
				rotationParentMatrix.identity();
				rotationMatrix.appendRotation(30, Y_AXIS, PIVOT_POINT);
				rotationParentMatrix.appendRotation(30, X_AXIS, PIVOT_POINT);
				
				asasMatrix = rotationMatrix.clone();
				asasParentMatrix = rotationParentMatrix.clone();
				
				lineContainer.graphics.clear();
				lineContainer.graphics.lineStyle(0, 0XFFFF00, 1);
				asasMatrix.invert();
				asasParentMatrix.invert(); 
				
				for(i = 0;i < pointsReference.length; i++) {
					
					pointer = pointsReference[i];
					pointer = rotationMatrix.deltaTransformVector(pointer);
					pointer = rotationParentMatrix.deltaTransformVector(pointer);
					persp = zoom / (1 + pointer.z / focus);
					
					asas[i].persp = persp;
					asas[i].matrix = asasMatrix;
					asas[i].parentMatrix = asasParentMatrix;
					
					if(persp > 0) {
						asas[i].x = pointer.x * persp;
						asas[i].y = pointer.y * persp;
						if(i == 0) {
							lineContainer.graphics.moveTo(asas[i].x, asas[i].y);
						} else {
							lineContainer.graphics.lineTo(asas[i].x, asas[i].y);
						}
					} else {
						asas[i].x = asas[i].y = -10000000;
					}
				}
				lineContainer.graphics.lineTo(asas[0].x, asas[0].y);
                            }
			//Actualizo los asas de control...
			if(rotate && mouse) {
				
				rotationMatrix.identity();
				rotationParentMatrix.identity();
				rotationMatrix.appendRotation(360 * stage.mouseX / stage.stageWidth, Y_AXIS, PIVOT_POINT);
				rotationParentMatrix.appendRotation(90 * stage.mouseY / stage.stageHeight, X_AXIS, PIVOT_POINT);
				
				asasMatrix = rotationMatrix.clone();
				asasParentMatrix = rotationParentMatrix.clone();
				
				lineContainer.graphics.clear();
				lineContainer.graphics.lineStyle(0, 0XFFFF00, 1);
				asasMatrix.invert();
				asasParentMatrix.invert(); 
				
				for(i = 0;i < pointsReference.length; i++) {
					
					pointer = pointsReference[i];
					pointer = rotationMatrix.deltaTransformVector(pointer);
					pointer = rotationParentMatrix.deltaTransformVector(pointer);
					persp = zoom / (1 + pointer.z / focus);
					
					asas[i].persp = persp;
					asas[i].matrix = asasMatrix;
					asas[i].parentMatrix = asasParentMatrix;
					
					if(persp > 0) {
						asas[i].x = pointer.x * persp;
						asas[i].y = pointer.y * persp;
						if(i == 0) {
							lineContainer.graphics.moveTo(asas[i].x, asas[i].y);
						} else {
							lineContainer.graphics.lineTo(asas[i].x, asas[i].y);
						}
					} else {
						asas[i].x = asas[i].y = -10000000;
					}
				}
				lineContainer.graphics.lineTo(asas[0].x, asas[0].y);
			}
			
			i = 0;
			bmd.lock();
			bmd.colorTransform(bmd.rect, colorTransform);
			
			//Actualizo las posiciones de las partículas...
			while(particle.next != null) {
				
				pointer = nodos[i];
				pointer = rotationMatrix.deltaTransformVector(pointer);
				pointer = rotationParentMatrix.deltaTransformVector(pointer);
				particle.position = pointer;

				bmd.setPixel(Math.round(stage.stageWidth / 2 + particle.x), Math.round(stage.stageHeight / 2 + particle.y), 0XFFFFFF);
				particle = particle.next;
				i++;
			}
			
			bmd.unlock();
		}

		//Función que se encarga de iniciar la rotación...
		private function initRotation(e : KeyboardEvent) : void {
			if(e.charCode == 114) rotate = true;
		}

		//Función que para la rotación...
		private function stopRotation(e : KeyboardEvent) : void {
			if(e.charCode == 114) rotate = false;
		}

		//Función que señala que el ratón esta presionado...
		private function mouseDownListener(E : MouseEvent) : void {
			mouse = true;
		}

		//Función que señala que el ratón esta presionado...
		private function mouseUpListener(E : MouseEvent) : void {
			mouse = false;
		}

		//Función que se encarga de modificar el zoom...
		private function updateZoom(e : MouseEvent) : void {
			trace(e.delta);
			zoom += e.delta / 10;
			Particula.zoom = zoom;
			ControlPoint.zoom = zoom;
			var persp : Number;
			lineContainer.graphics.clear();
			lineContainer.graphics.lineStyle(0, 0XFFFF00, 1);
			for(var i : uint = 0;i < pointsReference.length; i++) {
				var pointer : Vector3D = pointsReference[i];
				pointer = rotationMatrix.deltaTransformVector(pointer);
				pointer = rotationParentMatrix.deltaTransformVector(pointer);
				persp = zoom / (1 + pointer.z / focus);
				asas[i].persp = persp;
				var asasMatrix : Matrix3D = rotationMatrix.clone();
				asasMatrix.invert();
				var asasParentMatrix : Matrix3D = rotationParentMatrix.clone();
				asasParentMatrix.invert(); 
				asas[i].matrix = asasMatrix;
				asas[i].parentMatrix = asasParentMatrix;
				if(persp > 0) {
					asas[i].x = pointer.x * persp;
					asas[i].y = pointer.y * persp;
					if(i == 0) {
						lineContainer.graphics.moveTo(asas[i].x, asas[i].y);
					} else {
						lineContainer.graphics.lineTo(asas[i].x, asas[i].y);
					}
				} else {
					asas[i].x = asas[i].y = -10000000;
				}
			}
			lineContainer.graphics.lineTo(asas[0].x, asas[0].y);
		}
	}
}

class MathFunctions {

	//Función que se encarga de generar un signo aleatorio...
	public static function signo() : Number {
		return Math.random() >= 0.5 ? 1 : -1;
	}
	//Función que cambia de degrees a radianes...
	public static function radians(angle : Number) : Number {
		return angle * Math.PI / 180;
	}
	//Función que cambia de radianes  adegrees...
	public static function degrees(angle : Number) : Number {
		return angle * 180 / Math.PI;
	}

	//Función que se encarga de la combinatoria entre dos números...
	public static function combinatoria(n : Number, i : Number) : Number {
		return factorial(n) / (factorial(i) * factorial(n - i));
	}

	//Función que calcula el factorial de un número entero
	public static function factorial(n : Number) : Number {
			
		var i : Number;
		var salida : Number = 1;
		if(n != 0) {
			for(i = 1;i <= n; i++) {
				salida *= i;
			}
		} else {
			salida = 1;
		}
		
		return salida;
	}
	
	
	//Fin del programa....
}

import flash.geom.Vector3D;			

/**
 * @author hector arellano
 * Clase que se encarga de generar una parametrización
 * Bezier de trayectoria o superficie.
 * 
 */
class Bezier {
	//Variable que permite tener los datos de la combinatoria para cada grado...
	private static var combinatoriaData : Array = new Array();
	combinatoriaData[0] = [0];
	combinatoriaData[1] = [1];
	
	//A partír de 2 se tienen la cantidad mínima de puntos para interpolar
	combinatoriaData[2] = new Array(1, 1);
	combinatoriaData[3] = new Array(1, 2, 1);
	combinatoriaData[4] = new Array(1, 3, 3, 1);
	combinatoriaData[5] = new Array(1, 4, 6, 4, 1);
	combinatoriaData[6] = new Array(1, 5, 10, 10, 5, 1);
	combinatoriaData[7] = new Array(1, 6, 15, 20, 15, 6, 1);
	combinatoriaData[8] = new Array(1, 7, 21, 35, 35, 21, 7, 1);
	combinatoriaData[9] = new Array(1, 8, 28, 56, 70, 56, 28, 8, 1);
	combinatoriaData[10] = new Array(1, 9, 36, 84, 126, 126, 84, 36, 9, 1);
	combinatoriaData[11] = new Array(1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1);
	combinatoriaData[12] = new Array(1, 11, 56, 165, 330, 462, 462, 330, 165, 56, 11, 1);

	//Variables estáticas que permiten guardar los valores de segmentación de la malla (evita recalcular la cantidad de puntos...)
	private static var Ne : uint = 0;
	private static var Nn : uint = 0;
	private static var paramsE : Array = new Array();
	private static var paramsN : Array = new Array();

	//Variable que contiene las constantes de la curva bezier para un grado y una parametrización (cantidad de puntos) fija.
	private static var coeficientesCurva : Array = new Array(); 
	//Función que calcula los coeficientes de la curva...
	public static function bezier(t : Number, controlPoints : Array) : Vector3D {
			
		var salida : Vector3D = new Vector3D;
		var coeficientes : Array = new Array();
		var i : uint;
		var n : uint = controlPoints.length - 1;
			
		//Si los valores de la combinatoria para la cantidad de puntos no estan definidos, los defino...
		if(combinatoriaData[controlPoints.length] == undefined) {
			combinatoriaData[controlPoints.length] = setCoeficients(n);
		}
		
		//Determino los coeficientes...
		for (i = 0;i <= n; i++) {
			coeficientes[i] = combinatoriaData[controlPoints.length][i] * Math.pow(t, i) * Math.pow((1 - t), (n - i));
		}
		
		//Obtengo los valores de salida del vector3D...
		for(i = 0;i <= n; i++) {
			salida.x += coeficientes[i] * controlPoints[i].x;
			salida.y += coeficientes[i] * controlPoints[i].y;
			salida.z += coeficientes[i] * controlPoints[i].z;
		}
		salida.w = 1;
		
		return salida;
	}

	//Función que se encarga de obtener un conjunto de puntos xyz agrupados en un array para una curva bezier...
	public static function bezierPoints(m : uint, controlPoints : Array) : Vector.<Vector3D> {
		var salida : Vector.<Vector3D> = new Vector.<Vector3D>();
		var n : uint = controlPoints.length - 1;
		var i : uint;
		var j : uint;
		
		//Si los valores de la combinatoria para la cantidad de puntos no estan definidos, los defino...
		if(combinatoriaData[controlPoints.length] == undefined) {
			combinatoriaData[controlPoints.length] = setCoeficients(m);
		}
		
		//Si no hay un arreglo que guarde la referencia para un grado definido, se define...
		if(coeficientesCurva[n] == undefined) {
			coeficientesCurva[n] = new Array();
		}
		
		//Si no hay un arreglo que guarde los coeficientes para "m" puntos se define...
		//Se guarda un arreglo de cuatro dimensiones según la siguiente definición...
		//
		//coeficientes[n][m][j][i] donde:
		//n : grado,
		//m : cantidad de puntos a parametrizar,
		//j : vector de coeficientes para un valor de parametrización perteneciente al rango [0, 1]
		//i : coeficientes a multiplicar por cada punto para la parametrización anterior...
		//
		if(coeficientesCurva[n][m] == undefined) {
			coeficientesCurva[n][m] = new Array();
			for (j = 0;j < m; j++) {
				//Defino la parametrización...
				var delta : Number = j / (m - 1);
				coeficientesCurva[n][m][j] = new Array();
				for(i = 0;i <= n; i++) {
					coeficientesCurva[n][m][j].push(combinatoriaData[controlPoints.length][i] * Math.pow(delta, i) * Math.pow((1 - delta), (n - i)));
				}
			}
		}
		
		//Obtengo los distintos puntos que componen el vector de salida...
		for(j = 0;j < m; j++) {
			var pointer : Vector3D = new Vector3D();
			for(i = 0;i <= n; i++) {
				pointer.x += coeficientesCurva[n][m][j][i] * controlPoints[i].x;
				pointer.y += coeficientesCurva[n][m][j][i] * controlPoints[i].y;
				pointer.z += coeficientesCurva[n][m][j][i] * controlPoints[i].z;
			}
			pointer.w = 1;
			salida.push(pointer);
		}
		
		return salida;
	}
	//Función que se encarga de conseguir todos los puntos de una malla generada por bordes...
	//Entrega los puntos ordenados de la siguiente manera suponiendo un arreglo de 3X3...
	//
	//  0  1  2
	//  3  4  5
	//  6  7  8
	//
	public static function getPatch(Xt0 : Vector3D, Xt1 : Vector3D, Xb0 : Vector3D, Xb1 : Vector3D, BT : Array, BB : Array, BL : Array, BR : Array, Ne : uint = 10, Nn : uint = 10) : Array {
			
		var i : uint;
		var points : Array = new Array();
		
		//Obtengo los puntos de las curvas para interpolar...
		var b_top : Vector.<Vector3D> = Bezier.bezierPoints(Ne, BT);
		var b_bottom : Vector.<Vector3D> = Bezier.bezierPoints(Ne, BB);
		var b_left : Vector.<Vector3D> = Bezier.bezierPoints(Nn, BL);
		var b_right : Vector.<Vector3D> = Bezier.bezierPoints(Nn, BR);
		
		
		//Genero los parámetros si no estan definidos...
		if(Bezier.Ne != Ne && Bezier.Nn != Ne) {
			Bezier.Ne = Ne;
			Bezier.Nn = Nn;
			paramsN = [];
			paramsE = [];
			for (i = 1;i <= Nn; i++) {
				paramsN.push((i - 1) / (Nn - 1));
			}
		
			for (i = 1;i <= Ne; i++) {
				paramsE.push((i - 1) / (Ne - 1));
			}
		}
		
		//Genero el arreglo de puntos...
		var j : uint;
		var jMax : uint = paramsN.length;
		var iMax : uint = paramsE.length;
		for (j = 0;j < jMax; j++) {
			for (i = 0;i < iMax; i++) {
				points.push(TFI(paramsE[i], paramsN[j], b_top[i], b_bottom[i], b_left[j], b_right[j], Xt0, Xt1, Xb0, Xb1));
			}
		}
		
		return points;
	}
	
	//Función que permite liberar la memoria de la clase Bezier...
	public static function clearMemory() : void{
		coeficientesCurva = [];
		paramsN = [];
		paramsE = [];
		combinatoriaData = [];
		
		coeficientesCurva = paramsN = paramsE = combinatoriaData = null;
	}

	//Función que genera una interpolación tranfinita TFI para un grupo de cuatro curvas de borde bezier.
	//Se pasan los puntos de borde Xt0, Xt1, Xb0, Xb1 y los valores e, n definidos de 0 a 1 para pasar de
	//estado plano al definido por las cuatro curvas... se busca generar los puntos P intermedios...
	//
	// 
	//  Xt0 Xt Xt Xt Xt Xt Xt Xt1
	//  Xl                     Xr
	//  Xl                     Xr
	//  Xl   P                 Xr
	//  Xl                     Xr
	//  Xl                     Xr
	//  Xl                     Xr
	//  Xl                     Xr
	//  Xb0 Xb Xb Xb Xb Xb Xb Xb1
	//
	//
	private static function TFI(e : Number, n : Number, Xt : Vector3D, Xb : Vector3D, Xl : Vector3D, Xr : Vector3D , Xt0 : Vector3D, Xt1 : Vector3D, Xb0 : Vector3D, Xb1 : Vector3D) : Vector3D {
			
		var TFIPoint : Vector3D = new Vector3D();
			
		//Evalúo la interpolación para cada coordenada del punto, x, y, z...
		TFIPoint.x = (1 - n) * Xt.x + n * Xb.x + (1 - e) * Xl.x + e * Xr.x - (e * n * Xb1.x + e * (1 - n) * Xt1.x + n * (1 - e) * Xb0.x + (1 - n) * (1 - e) * Xt0.x);
		TFIPoint.y = (1 - n) * Xt.y + n * Xb.y + (1 - e) * Xl.y + e * Xr.y - (e * n * Xb1.y + e * (1 - n) * Xt1.y + n * (1 - e) * Xb0.y + (1 - n) * (1 - e) * Xt0.y);
		TFIPoint.z = (1 - n) * Xt.z + n * Xb.z + (1 - e) * Xl.z + e * Xr.z - (e * n * Xb1.z + e * (1 - n) * Xt1.z + n * (1 - e) * Xb0.z + (1 - n) * (1 - e) * Xt0.z);
		TFIPoint.w = 1;
		return TFIPoint;
	}

	//Función que realiza un set de los coeficientes en caso que cantidad de puntos sean distintos a los valores almacenados...
	private static function setCoeficients(n : Number) : Array {
		var datos : Array = new Array();
		var i : Number;
		for (i = 0;i <= n; i++) {
			datos.push(MathFunctions.combinatoria(n, i));
		}
		return datos;
	}
		
		
	//fín del programa....
}

import flash.geom.Point;
import flash.geom.Vector3D;
class Particula {

	public var next : Particula = null;
	public var x : Number;
	public var y : Number;
	public static var focus : Number = 300;
	public static var zoom : Number = 0;

	private var persp : Number;

	public function Particula() {
		//En la posición w del vector se define la modificación por la música....
	}
	public function set position(vector : Vector3D) : void {
		persp = zoom * focus / (focus + vector.z);
		if(persp > 0) {
			this.x = vector.x * persp;
			this.y = vector.y * persp;
		} else {
			this.x = this.y = -10000000;
		}
	}
	public function get XY() : Point {
		return new Point(this.x, this.y);
	}
		
	//Fín del programa...
}

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;	
class ControlPoint extends Sprite {

	public var persp : Number;
	public var matrix : Matrix3D;
	public var parentMatrix : Matrix3D;

	//Variable que guarda la referencia al punto ...
	private var id : uint;
	private var lado : uint = 7;
	//Variable que guarda una referencia a la perspectiva utilizada en las transformaciones...
	public static var focus : Number = 0;
	public static var zoom : Number = 0;

	public function ControlPoint(id : uint) {
		this.id = id;
		graphics.lineStyle(0, 0X00FF00, 1);
		graphics.beginFill(0);
		graphics.drawRect(-lado / 2, -lado / 2, lado, lado);
		this.buttonMode = true;
		
		this.addEventListener(MouseEvent.MOUSE_DOWN, update3DPosition);
	}
	//Función que se encarga de actualizar la posición 3D del asa de tangencia en base a su posición 2D...
	private function update3DPosition(e : MouseEvent) : void {
		this.startDrag();
		trace(id);
		this.addEventListener(Event.ENTER_FRAME, updatePosition);
		stage.addEventListener(MouseEvent.MOUSE_UP, stopDragEvent);
	}
		
		
	//Función que se encarga de actualizar la posición...
	private function updatePosition(e : Event) : void {
		
		var salida : Vector3D = new Vector3D();
		salida.x = this.x / persp;
		salida.y = this.y / persp;
		salida.z = focus * (zoom - persp) / persp;
		
		salida = parentMatrix.deltaTransformVector(salida);
		salida = matrix.deltaTransformVector(salida);
		dispatchEvent(new ControlPointEvent(ControlPointEvent.CHANGE, salida, id));
		
	}
	
	//Función que se encarga de parar el arrastre...
	private function stopDragEvent(e : MouseEvent) : void {
		this.stopDrag();
		this.removeEventListener(Event.ENTER_FRAME, updatePosition);
		stage.removeEventListener(MouseEvent.MOUSE_UP, stopDragEvent);
	}
	//Fín del programa...
}

import flash.events.Event;
import flash.geom.Vector3D;
class ControlPointEvent extends Event {
	
	//Variable estática del tipo de evento..
	public static const CHANGE : String = "CHANGE";
	
	//Puntos del arreglo...
	public var vector : Vector3D;
	public var cp : uint;
	
	//Constructor...
	public function ControlPointEvent(type : String, vector : Vector3D, cp : uint, bubbles : Boolean = false, cancelable : Boolean = false) : void {
		super(type, bubbles, cancelable);
		this.cp = cp;
		this.vector = vector;
	}
	
	//Función que devuelve un clon del evento...
	public override function clone() : Event {
		return new ControlPointEvent(type, vector, cp, bubbles, cancelable);
	}
}