package classes.away3d.extrusions
{
	import classes.away3d.arcane;
	import classes.away3d.core.math.*;
	import classes.away3d.core.base.*;
	import classes.away3d.materials.*;
	import classes.away3d.primitives.*;
	
	import flash.geom.*;
	
	use namespace arcane;
	
	/**
	* Class for generating meshes with axial symmetry such as donuts, pipes, vases etc.
	*/
	public class LatheExtrusion extends AbstractPrimitive
	{
		private var _profile:Array;
		private var _axis:String;
		private var _revolutions:Number;
		private var _subdivision:int;
		private var _offsetRadius:Number;
		private var _materials:Object;
		private var _coverAll:Boolean;
		private var _flip:Boolean;
		private var _centerMesh:Boolean;
		private var _thickness:Number;
		private var _omit:String;
		private var _tweek:Object;
		
		private var varr:Array = [];
		private var varr2:Array = [];
		private var uvarr:Array = [];
		
		private function closeTopBottom(pointslength:int, coverall:Boolean, matTop:*, matBottom:*, oRenderside:Object, flip:Boolean):void
		{
			//add top and bottom
			var uva:UV;
			var uvb:UV;
			var uvc:UV;
			var uvd:UV;

			var facea:Vertex;
			var faceb:Vertex;
			var facec:Vertex;
			var faced:Vertex;
			var index:int = 0;
			
			var i:int;
			var j:int;
			var a:Number;
			var b:Number;

			var total:int = varr.length - pointslength;
			var inc:int = pointslength;

			for (i = 0; i < total; i+= inc) {

				if (i!= 0) {
					
					if (coverall) {
						a = i/total;
						b = (i+inc)/total;
						uva = createUV(0, a );
						uvb = createUV(0, b );
						uvc = createUV(1, b );
						uvd = createUV(1, a );

					} else {
						uva = createUV(0, 0);//downleft
						uvb = createUV(0, 1 );//topleft
						uvc = createUV(1, 1);//topright
						uvd = createUV(1, 0);//downright
					}
					
					if (oRenderside["top"]) {
						if (_revolutions == 1 && i + inc == total) {
							facea = varr[i];
							faceb = varr[(inc)];
							facec = varr2[(inc)];
							faced =  varr2[i];
						} else {
							facea = varr[i];
							faceb = varr[i+(inc)];
							facec = varr2[i+(inc)];
							faced =  varr2[i];
						}

						if (flip) {
							addFace(createFace(facea, faceb, facec, matTop, uva, uvb, uvc ) );
							addFace(createFace(facea, facec, faced, matTop, uva, uvc, uvd ) );
						} else {
							addFace(createFace(faceb, facea, facec, matTop, uvb, uva, uvc ) );
							addFace(createFace(facec, facea, faced, matTop, uvc, uva, uvd ) );
						}
					}
					
					if (oRenderside["bottom"]) {
						j = i+inc-1;
						
						if (_revolutions == 1 && i + inc == total && _tweek == null) {
							facea = varr[j];
							faceb = varr[(2*inc) - 1];
							facec = varr2[(2*inc) - 1];
							faced =  varr2[j];
						} else {
							facea = varr[j];
							faceb = varr[j+(inc)];
							facec = varr2[j+(inc)];
							faced =  varr2[j];
						}

						if (flip) {
							addFace(createFace(faceb, facea, facec, matBottom, uvb, uva, uvc ) );
							addFace(createFace(facec, facea, faced, matBottom, uvc, uva, uvd ) );
						} else {
							addFace(createFace(facea, faceb, facec, matBottom, uva, uvb, uvc ) );
							addFace(createFace(facea, facec, faced, matBottom, uva, uvc, uvd ) );
						}
					}
				}
				
				index += pointslength;
			}
		}
		
		private function closeSides(pointcount:int, coverall:Boolean, matRight:*, matLeft:*, oRenderside:Object, flip:Boolean):void
		{
			var uva:UV;
			var uvb:UV;
			var uvc:UV;
			var uvd:UV;
			var facea:Vertex;
			var faceb:Vertex;
			var facec:Vertex;
			var faced:Vertex;

			var offset:Number = varr.length - pointcount;
			var i:int;
			var j:int;
			var a:Number;
			var b:Number;
			
			var iter:int = pointcount-1;
			var step:Number = 1/iter;
			
			for (i = 0; i<iter; ++i) {

				if (coverall) {
					a = i/iter;
					b = a+step;
					uva = createUV(0, a );
					uvb = createUV(0, b );
					uvc = createUV(1, b );
					uvd = createUV(1, a );
				} else {
					uva = createUV(0, 0);
					uvb = createUV(0, 1 );
					uvc = createUV(1, 1);
					uvd = createUV(1, 0);
				}
				
				if (oRenderside["left"]) {
					facea = varr[i+1];
					faceb = varr[i];
					facec = varr2[i];
					faced = varr2[i+1];

					if (flip) {
						addFace(createFace(facea, faceb, facec, matLeft, uva, uvb, uvc ) );
						addFace(createFace(facea, facec, faced, matLeft, uva, uvc, uvd ) );
					} else {
						addFace(createFace(faceb, facea, facec, matLeft, uvb, uva, uvc ) );
						addFace(createFace(facec, facea, faced, matLeft, uvc, uva, uvd ) );
					}
				}
				
				if (oRenderside["right"]) {
					j = offset+i;
					facea = varr[j + 1];
					faceb = varr[j ];
					facec = varr2[j];
					faced = varr2[j + 1];

					if (flip) {
						addFace(createFace(faceb, facea, facec, matRight, uvb, uva, uvc ) );
						addFace(createFace(facec, facea, faced, matRight, uvc, uva, uvd ) );
					} else {
						addFace(createFace(facea, faceb, facec, matRight, uva, uvb, uvc ) );
						addFace(createFace(facea, facec, faced, matRight, uva, uvc, uvd ) );
					}
				}
				
			}
		}

		private function generate(aPoints:Array, axis:String, offsetradius:Number, rotations:Number, subdivision:Number, tweek:Object, coverall:Boolean, inside:Boolean = false, mat:Material = null, render:Boolean = true, flip:Boolean = false):void
		{
			
			if (!tweek)
				tweek = {};
			
			
			if (isNaN(tweek["x"]) || !tweek["x"]) tweek["x"] = 0;
			if (isNaN(tweek["y"]) || !tweek["y"]) tweek["y"] = 0;
			if (isNaN(tweek["z"]) || !tweek["z"]) tweek["z"] = 0;
			if (isNaN(tweek["radius"]) || !tweek["radius"]) tweek["radius"] = 0;
			 
			var angle:Number = 0;
			var step:Number = 360 / subdivision;			 
			var j:int;
			
			var tweekX:Number = 0;
			var tweekY:Number = 0;
			var tweekZ:Number = 0;
			var tweekradius:Number = 0;
			var tweekrotation:Number = 0;
			
			var tmpPoints:Array;
			var aRads:Array = [];			
			
			var nuv1:Number;
			var nuv2:Number;
			
			for (var i:int = 0; i < aPoints.length; ++i) {
				varr.push(createVertex(aPoints[i].x, aPoints[i].y, aPoints[i].z) );
				uvarr.push(createUV(0,1%i)); 
			}
			  
			//Vertex generation
			offsetradius = -offsetradius;
			var factor:Number = 0;
			
			for (i = 0; i <= subdivision * rotations; ++i) {
				
				tmpPoints = [];
				tmpPoints = aPoints.concat();
				
				for(j = 0;j<tmpPoints.length;++j){
					
					factor = ((rotations-1)/(varr.length+1));
				
					if(tweek["x"] != 0)
						tweekX += (tweek["x"] * factor)/rotations;
						
					if(tweek["y"] != 0)
						tweekY += (tweek["y"] * factor)/rotations;
						
					if(tweek["z"] != 0)
						tweekZ += (tweek["z"] * factor)/rotations;
						
					if(tweek["radius"] != 0)
						tweekradius += (tweek["radius"]/(varr.length+1));
						
					if(tweek["rotation"] != 0)
						tweekrotation +=  360/(tweek["rotation"]*subdivision);
						 
					if (axis == "x") {
							if(i==0) aRads[j] = offsetradius-Math.abs(tmpPoints[j].z);
							 
							tmpPoints[j].z = Math.cos(-angle/180*Math.PI) * (aRads[j] + tweekradius );
							tmpPoints[j].y = Math.sin(angle/180*Math.PI) * (aRads[j] + tweekradius );
							
							if(i == 0){
								varr[j].z += tmpPoints[j].z;
								varr[j].y += tmpPoints[j].y;
							}
							 
					} else if (axis == "y") {
							if(i==0) aRads[j] = offsetradius-Math.abs(tmpPoints[j].x);
							 
							tmpPoints[j].x = Math.cos(-angle/180*Math.PI) *  (aRads[j] + tweekradius );
							tmpPoints[j].z = Math.sin(angle/180*Math.PI) * (aRads[j] + tweekradius );
							 
							if(i == 0){
								varr[j].x = tmpPoints[j].x;
								varr[j].z = tmpPoints[j].z;
							}
							 
					} else {
							if(i==0) aRads[j] = offsetradius-Math.abs(tmpPoints[j].y);
							 
							tmpPoints[j].x = Math.cos(-angle/180*Math.PI) * (aRads[j] + tweekradius );
							tmpPoints[j].y = Math.sin(angle/180*Math.PI) * (aRads[j] + tweekradius );
							
							if(i == 0){
								varr[j].x = tmpPoints[j].x;
								varr[j].y = tmpPoints[j].y;
							}
							
					}
					
					tmpPoints[j].x += tweekX;
					tmpPoints[j].y += tweekY;
					tmpPoints[j].z += tweekZ;
					
					varr.push(createVertex(tmpPoints[j].x, tmpPoints[j].y, tmpPoints[j].z) );
					
					if(coverall) {
						nuv1 =   angle/(360*rotations);
					} else {
						nuv1 =  (i%2 == 0)? 0 : 1;
					}
					nuv2 =1-(j/(tmpPoints.length-1));
					uvarr.push(createUV(nuv1, nuv2));
				 }
				 
				angle += step;
				
			}
			
			if (render) {

				var index:int;
				var inc:int = aPoints.length;
				var loop:int = varr.length - aPoints.length;

				for (i = 0; i < loop; i += inc) {
					index = 0;
					for (j = 1; j < aPoints.length; ++j) {

						if (i>0) {
							var uva:UV = uvarr[i + (index + 1)];
							var uvb:UV = uvarr[i + index];
							var uvc:UV = uvarr[i + index + aPoints.length];
							var uvd:UV = uvarr[i + index + aPoints.length + 1];
							
							var facea:Vertex;
							var faceb:Vertex;
							var facec:Vertex;
							var faced:Vertex;
							
							if (rotations == 1 && i + inc == loop && _tweek == null) {
								facea = varr[i + (index + 1)];
								faceb = varr[i + index];
								facec = varr[index + inc];
								faced = varr[index + inc + 1];
							} else {
								facea = varr[i + (index + 1)];
								faceb = varr[i + index];
								facec = varr[i + index + inc];
								faced = varr[i + index + inc + 1];
							}
							
							if (flip) {
								
								if (inside) {
									addFace(createFace(faceb, facea, facec, mat, createUV(1-uvb.u, uvb.v), createUV(1-uva.u, uva.v), createUV(1-uvc.u, uvc.v) ) );
									addFace(createFace(facec, facea, faced, mat, createUV(1-uvc.u, uvc.v), createUV(1-uva.u, uva.v), createUV(1-uvd.u, uvd.v)  ) );
								} else {
									addFace(createFace(facea, faceb, facec, mat, uva, uvb, uvc ) );
									addFace(createFace(facea, facec, faced, mat, uva, uvc, uvd ) );
								}
								
							} else {
								
								if (inside) {
									addFace(createFace(facea, faceb, facec, mat, createUV(1-uva.u, uva.v), createUV(1-uvb.u, uvb.v), createUV(1-uvc.u, uvc.v) ) );
									addFace(createFace(facea, facec, faced, mat, createUV(1-uva.u, uva.v), createUV(1-uvc.u, uvc.v), createUV(1-uvd.u, uvd.v)  ) );
								} else {
									addFace(createFace(faceb, facea, facec, mat, uvb, uva, uvc ) );
									addFace(createFace(facec, facea, faced, mat, uvc, uva, uvd ) );
								}
							}
						}
						
						index++;
					}
				}
			}
		}
		
		private function buildThicknessPoints(aPoints:Array, thickness:Number, prop1:String, prop2:String):Array
		{
			var Anchors:Array = [];
			var Lines:Array = [];
			var i:int;
			
			for( i = 0;i<aPoints.length-1;++i){
				if(aPoints[i][prop1] == 0 && aPoints[i][prop2] == 0){
					aPoints[i][prop1] = .0001;
				}
				if(aPoints[i+1][prop2] != null && aPoints[i][prop2] == aPoints[i+1][prop2]){
					aPoints[i+1][prop2] += .0001;
				}
				if(aPoints[i][prop1] != null && aPoints[i][prop1]  == aPoints[i+1][prop1]){
					aPoints[i+1][prop1] += .0001;
				}
				Anchors.push(defineAnchors(aPoints[i], aPoints[i+1], thickness, prop1, prop2 ));
			}
			
			var totallength:int = Anchors.length;
			var oPointResult:Object;
			
			if(totallength>1){
				
				for(i = 0;i<totallength;++i){
					if(i < totallength){
						oPointResult = defineLines(i, Anchors[i], Anchors[i+1], Lines);
					} else{
						oPointResult = defineLines(i, Anchors[i], Anchors[i-1], Lines);
					}
					if(oPointResult != null) Lines.push(oPointResult);
				}
				
			} else{
				Lines = [{pt1:Anchors[0]["pt1"], pt2:Anchors[0]["pt2"], pt3:Anchors[0]["pt3"], pt4:Anchors[0]["pt4"]}];
			}
 
			return  Lines;
		}
		
		
		private function defineLines(index:int, oPoint1:Object, oPoint2:Object = null, Lines:Array = null):Object
		{
			var tmppt:Object = Lines[index -1];
			if(oPoint2 == null)  return {pt1:tmppt["pt3"], pt2:tmppt["pt4"], pt3:oPoint1["pt3"], pt4:oPoint1["pt4"]}; 
			 
			var oLine1:Object = buildObjectLine(oPoint1["pt1"].x,oPoint1["pt1"].y,oPoint1["pt3"].x,oPoint1["pt3"].y);
			var oLine2:Object = buildObjectLine(oPoint1["pt2"].x,oPoint1["pt2"].y,oPoint1["pt4"].x,oPoint1["pt4"].y);
			var oLine3:Object = buildObjectLine(oPoint2["pt1"].x,oPoint2["pt1"].y,oPoint2["pt3"].x,oPoint2["pt3"].y);
			var oLine4:Object = buildObjectLine(oPoint2["pt2"].x,oPoint2["pt2"].y,oPoint2["pt4"].x,oPoint2["pt4"].y);
			
			var cross1:Point = lineIntersect (oLine3, oLine1);
			var cross2:Point = lineIntersect (oLine2, oLine4);
		
			if(cross1 != null && cross2 != null){
				
				if(index == 0)  return {pt1:oPoint1["pt1"], pt2:oPoint1["pt2"], pt3:cross1, pt4:cross2}; 
				return {pt1:tmppt["pt3"], pt2:tmppt["pt4"], pt3:cross1, pt4:cross2};
				
			} else {
				return null;
			} 
		}
		
		
		private function defineAnchors(base:Vector3D, baseEnd:Vector3D, thickness:Number, prop1:String, prop2:String):Object
		{
			
			var angle:Number =   (Math.atan2(base[prop2] - baseEnd[prop2], base[prop1] - baseEnd[prop1])* 180)/ Math.PI;
			angle -= 270;
			var angle2:Number = angle+180;
			
			var pt1:Point = new Point(base[prop1], base[prop2]);
			var pt2:Point = new Point(base[prop1], base[prop2]);
			var pt3:Point = new Point(baseEnd[prop1], baseEnd[prop2]);
			var pt4:Point = new Point(baseEnd[prop1], baseEnd[prop2]);
			
			var radius:Number = thickness*.5;
			
			pt1.x = pt1.x+Math.cos(-angle/180*Math.PI)*radius;
			pt1.y = pt1.y+Math.sin(angle/180*Math.PI)*radius;
			
			pt2.x = pt2.x+Math.cos(-angle2/180*Math.PI)*radius;
			pt2.y = pt2.y+Math.sin(angle2/180*Math.PI)*radius;
			
			pt3.x = pt3.x+Math.cos(-angle/180*Math.PI)*radius;
			pt3.y = pt3.y+Math.sin(angle/180*Math.PI)*radius;
			
			pt4.x = pt4.x+Math.cos(-angle2/180*Math.PI)*radius;
			pt4.y = pt4.y+Math.sin(angle2/180*Math.PI)*radius;
			
			return {pt1:pt1, pt2:pt2, pt3:pt3, pt4:pt4};
		}
		
		
		private function buildObjectLine(origX:Number, origY:Number, endX:Number, endY:Number):Object
		{        
			return {ax:origX, ay:origY, bx:endX - origX, by:endY - origY};
		}
		
		
		private function lineIntersect (Line1:Object, Line2:Object):Point
		{
			Line1["bx"] = (Line1["bx"] == 0)? 0.0001 : Line1["bx"];
			Line2["bx"] = (Line2["bx"] == 0)? 0.0001 : Line2["bx"];
			
			var a1:Number = Line1["by"] / Line1["bx"];
			var b1:Number = Line1["ay"] - a1 * Line1["ax"];
			var a2:Number = Line2["by"] / Line2["bx"];
			var b2:Number = Line2["ay"] - a2 * Line2["ax"];
			var nzero:Number =  ((a1 - a2) == 0)? 0.0001 : a1 - a2;
			var ptx:Number = ( b2 - b1 )/(nzero);
			var pty:Number = a1 * ptx + b1;
			
			if(isFinite(ptx) && isFinite(pty)){
				return new Point(ptx, pty);
			} else {
				trace("infinity");
				return null;
			}
		}
		
		/**
		 * @inheritDoc
		 */
    	protected override function buildPrimitive():void
    	{
    		super.buildPrimitive();
    		
			if (_profile.length > 1) {
				//_tweek = (_tweek == null)? {x:0, y:0, z:0, radius:0, rotation:0} : _tweek;

				if (_thickness != 0) {

					var prop1:String;
					var prop2:String;
					var prop3:String;

					switch (_axis) {
						case "x" :
							prop1 = "x";
							prop2 = "z";
							prop3 = "y";
							break;

						case "y" :
							prop1 = "y";
							prop2 = "x";
							prop3 = "z";
							break;

						case "z" :
							prop1 = "z";
							prop2 = "y";
							prop3 = "x";
					}
					
					var Lines:Array = buildThicknessPoints(_profile, thickness, prop1, prop2);
					
					var i:int;
					
					var aListsides:Array = ["top","bottom", "right", "left", "front", "back"];
					var oRenderside:Object = {};
					for(i = 0;i<aListsides.length;++i){
						oRenderside[aListsides[i]] = (_omit.indexOf(aListsides[i]) == -1);
					}
					
					var oPoints:Object;
					var vector:Vector3D;
					var vector2:Vector3D;
					var vector3:Vector3D;
					var vector4:Vector3D;
					var aPointlist1:Array = new Array();
					var aPointlist2:Array = new Array();
					
					for(i = 0;i<Lines.length;++i){
						
						oPoints = Lines[i];
						vector = new Vector3D();
						vector2 = new Vector3D();
						 
						if(i == 0){
							vector[prop1] = Number(oPoints["pt2"].x.toFixed(4));
							vector[prop2] = Number(oPoints["pt2"].y.toFixed(4));
							vector[prop3] = _profile[0][prop3];
							aPointlist1.push(vector);
							
							vector2[prop1] = Number(oPoints["pt1"].x.toFixed(4));
							vector2[prop2] = Number(oPoints["pt1"].y.toFixed(4));
							vector2[prop3] = _profile[0][prop3];
							aPointlist2.push(vector2);
							 
							if(Lines.length == 1) {
								vector3 = new Vector3D();
								vector4 = new Vector3D();
								
								vector3[prop1] = Number(oPoints["pt4"].x.toFixed(4));
								vector3[prop2] = Number(oPoints["pt4"].y.toFixed(4));
								vector3[prop3] = _profile[0][prop3];
								aPointlist1.push(vector3);
								
								vector4[prop1] = Number(oPoints["pt3"].x.toFixed(4));
								vector4[prop2] = Number(oPoints["pt3"].y.toFixed(4));
								vector4[prop3] = _profile[0][prop3];						
								aPointlist2.push(vector4);
								 
							} 
							 
						} else if (i == Lines.length-1) {
							 
							vector[prop1] = oPoints["pt2"].x;
							vector[prop2] = oPoints["pt2"].y;
							vector[prop3] = _profile[i][prop3];
							aPointlist1.push(vector);
							
							vector2[prop1] = oPoints["pt1"].x;
							vector2[prop2] = oPoints["pt1"].y;
							vector2[prop3] = _profile[i][prop3];
							aPointlist2.push(vector2);
							 
							vector3 = new Vector3D();
							vector4 = new Vector3D();
							
							vector3[prop1] = oPoints["pt4"].x;
							vector3[prop2] = oPoints["pt4"].y;
							vector3[prop3] = _profile[i][prop3];
							aPointlist1.push(vector3);
							
							vector4[prop1] = oPoints["pt3"].x;
							vector4[prop2] = oPoints["pt3"].y;
							vector4[prop3] = _profile[i][prop3];
							aPointlist2.push(vector4);
							
						} else {
							 
							vector[prop1] = oPoints["pt2"].x;
							vector[prop2] = oPoints["pt2"].y;
							vector[prop3] = _profile[i][prop3];
							aPointlist1.push(vector);
							
							vector2[prop1] = oPoints["pt1"].x;
							vector2[prop2] = oPoints["pt1"].y;
							vector2[prop3] = _profile[i][prop3];						
							aPointlist2.push(vector2);
						}
						
					}
					
					var mf:*;
					var mb:*;
					var mt:*;
					var mbo:*;
					var mr:*;
					var ml:*;
					
					if(_materials != null){
						mf = (_materials["front"] != null)? _materials["front"] : null;
						mb = (_materials["back"] != null)? _materials["back"] : null;
						mt = (_materials["top"] != null)? _materials["top"] : null;
						mbo = (_materials["bottom"] != null)? _materials["bottom"] : null;
						mr = (_materials["right"] != null)? _materials["right"] : null;
						ml = (_materials["left"] != null)? _materials["left"] : null;
					}
						
					varr = new Array();
					generate(aPointlist1, axis, _offsetRadius, _revolutions, _subdivision, _tweek, _coverAll, false, mf, oRenderside["front"], flip);
					varr2 = new Array();
					varr2 = varr2.concat(varr);
					varr = new Array();
					generate(aPointlist2, axis, _offsetRadius, _revolutions, _subdivision, _tweek, _coverAll, true, mb, oRenderside["back"], flip);
		
					if (_revolutions != 1) {
						closeSides(_profile.length, _coverAll, mr, ml, oRenderside, _flip);
					}
					
					closeTopBottom(_profile.length, _coverAll, mt, mbo, oRenderside, _flip);
			

				} else {
					generate(_profile, _axis, _offsetRadius, _revolutions, _subdivision, _tweek, _coverAll, _flip);

				}
				
			} else {
				trace("Lathe error: at least 2 Vector3D are required!");
			}
			
			varr = null;
			varr2 = null;
			uvarr = null;
			
			if (_centerMesh)
				centerPivot();
		}
		
		/**
    	 * Defines an Array of Vector3D objects representing the profile information to be projected along the Path object. Required.
    	 */
		public function get profile():Array
    	{
    		return _profile;
    	}
		
		public function set profile(val:Array):void
    	{
    		_profile = val;
			_primitiveDirty = true;
    	}
		
		/**
    	 * Defines the axis used for the lathe rotation. Defaults to "y".
    	 */
		public function get axis():String
    	{
    		return _axis;
    	}
		
		public function set axis(val:String):void
    	{
    		if (_axis == val)
				return;
			
    		_axis = val;
			_primitiveDirty = true;
    	}
		
		/**
    	 * Defines the number of revolutions performed by the lathe extrusion. Defaults to 1.
    	 */
		public function get revolutions():Number
    	{
    		return _revolutions;
    	}
		
		public function set revolutions(val:Number):void
    	{
    		if (_revolutions == val)
				return;
			
    		_revolutions = val;
			_primitiveDirty = true;
    	}
    	
		/**
    	 * Defines the subdivisions created in the mesh for the total number of revolutions. Defaults to 2, minimum 2.
    	 * 
    	 * @see #revolutions
    	 */ 
		public function get subdivision():int
		{
			return _subdivision;
		}
		
		public function set subdivision(val:int):void
		{
			val = (val<2)? 2 : val;
			
			if (_subdivision == val)
				return;
			
			_subdivision = val;
			_primitiveDirty = true;
		}
		
		/**
    	 * Defines an offset radius applied to the profile. Defaults to 0.
    	 */
		public function get offsetRadius():Number
    	{
    		return _offsetRadius;
    	}
		
		public function set offsetRadius(val:Number):void
    	{
    		if (_offsetRadius == val)
				return;
			
    		_offsetRadius = val;
			_primitiveDirty = true;
    	}
    	
		/**
		 * An optional object that defines left, right, front, back, top and bottom materials to be set on the resulting lathe extrusion.
    	 */
		public function get materials():Object
    	{
    		return _materials;
    	}
    	
		public function set materials(val:Object):void
    	{
    		_materials = val;
    		_primitiveDirty = true;
    	}
    	
		/**
    	 * Defines if the texture(s) should be stretched to cover the entire mesh or per step between segments. Defaults to true.
    	 */
		public function get coverAll():Boolean
		{
			return _coverAll;
		}
		
		public function set coverAll(val:Boolean):void
		{
			if (_coverAll == val)
				return;
			
			_coverAll = val;
			_primitiveDirty = true;
		}
		
		/**
    	 * Defines if the generated faces should be inversed. Default false.
    	 */
		public function get flip():Boolean
		{
			return _flip;
		}
		
		public function set flip(val:Boolean):void
		{
			if (_flip == val)
				return;
			
			_flip = val;
			_primitiveDirty = true;
		}
		    	
    	/**
    	 * Defines whether 
    	 */
    	public function get centerMesh():Boolean
    	{
    		return _centerMesh;
    	}
    	
    	public function set centerMesh(val:Boolean):void
    	{
    		if (_centerMesh == val)
    			return;
    		
    		_centerMesh = val;
    		_primitiveDirty = true;
    	}
    	
		/**
    	 * Defines the thickness of the resulting lathed geometry. Defaults to 0 (single face).
    	 */
		public function get thickness():Number
    	{
    		return _thickness;
    	}
		
		public function set thickness(val:Number):void
    	{
    		if (_thickness == val)
				return;
			
    		_thickness = val;
			_primitiveDirty = true;
    	}
    	
		/**
		 * Defines if the top, bottom, left, right, front or back of the the extrusion is left open.
    	 */
		public function get omit():String
    	{
    		return _omit;
    	}
    	
		public function set omit(val:String):void
    	{
    		_omit = val;
    		_primitiveDirty = true;
    	}
    	
		/**
		 * Allows the building of shapes such as springs. Rotation must be higher than 1 to have significant effect. Properties of the objects are x,y,z,radius and rotation
    	 */
		public function get tweek():Object
    	{
    		return _tweek;
    	}
    	
		public function set tweek(val:Object):void
    	{
    		_tweek = val;
    		_primitiveDirty = true;
    	}
		/**
		 *  Class Lathe generates circular meshes such as donuts, pipes, pyramids etc.. from a series of Vector3D's
		 *
		 * @param	profile	[optional]	Defines an Array of Vector3D objects representing the profile information to be projected along the Path object.
		 * @param	init	[optional]	An initialisation object for specifying default instance properties.
		 *
		 * properties of the init object are:
		 * material:Material, material for the Lathe object.
		 * materials:Object, if the Lathe object must have more materials: o.left, o.right, o.front, o.back, o.bottom, o.top and o.back. Default is null.
		 * axis:String, the axis to rotate around, default is "y".
		 * rotations:Number. The lath object can have less than one rotation, like 0.6 for a piechart or 3 if a tweek object is past. Default is 1, minimum is 0.01.
		 * subdivision:int, howmany segments will compose the mesh in its rotational construction. default is 2, its the minimum as well.
		 * offsetradius:Number. An offset radius for the Lathe object. Default is 0.
		 * scaling:Number. A scale value. default is 1.
		 * omit:String. If you want the bottom is not generated: omit:"bottom", both top and bottom: omit:"bottom, top"
		 * tweek:Object. default is null; to build springs like shapes, rotation must be higher than 1. properties of the objects are x,y,z,radius and rotation
		 * thickness:Number, if the shape must simulate a thickness. Default is 0.
		 * coverall:Boolean, The way the mappig is done. true covers the entire side of the geometry, false, per segments. Default is true.
		 * recenter:Boolean, If the geometry needs to be recentered in its own object space. Default is false.
		 * flip:Boolean. If the faces must be reversed depending on Vector3D's orientation. default is false.
		 */
		public function LatheExtrusion(profile:Array = null, init:Object = null)
		{
			super(init);
			
			this.profile = profile;
			
			axis = ini.getString("axis", "y");
			revolutions = ini.getNumber("revolutions", 1);
			subdivision = ini.getInt("subdivision", 2, {min:2});
			offsetRadius = ini.getNumber("offsetRadius", 0);
			materials = ini.getObject("materials", null);
			coverAll = ini.getBoolean("coverall", true);
			flip = ini.getBoolean("flip", false);
			centerMesh = ini.getBoolean("centerMesh", true);
			thickness = ini.getNumber("thickness", 0, {min:0});
			omit = ini.getString("omit", "");
			tweek = ini.getObject("tweek", null);
			
			type = "LatheExtrusion";
			url = "extrusion";
		}
		
	}
	
}