PageRenderTime 1049ms CodeModel.GetById 146ms app.highlight 511ms RepoModel.GetById 247ms app.codeStats 0ms

/src/away3d/extrusions/DelaunayMesh.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 818 lines | 619 code | 159 blank | 40 comment | 135 complexity | 01cb6322e399ea8cd2b2a4ee6ca451fc MD5 | raw file
  1// The Delaunay triangulation code used in this class is adapted for Away from the work done by: 
  2// Paul Bourke's, triangulate.c (http://local.wasp.uwa.edu.au/~pbourke/papers/triangulate/triangulate.c)
  3// Zachary Forest Johnson
  4
  5package away3d.extrusions
  6{
  7	import away3d.bounds.BoundingVolumeBase;
  8	import away3d.core.base.Geometry;
  9	import away3d.core.base.SubGeometry;
 10	import away3d.core.base.SubMesh;
 11	import away3d.core.base.data.UV;
 12	import away3d.entities.Mesh;
 13	import away3d.materials.MaterialBase;
 14	import away3d.tools.helpers.MeshHelper;
 15	
 16	import flash.geom.Vector3D;
 17	
 18	public class DelaunayMesh extends Mesh
 19	{
 20		public static const PLANE_XZ:String = "xz";
 21		public static const PLANE_XY:String = "xy";
 22		public static const PLANE_ZY:String = "zy";
 23		
 24		private const LIMIT:uint = 196605;
 25		private const EPS:Number = .0001;
 26		private const MAXRAD:Number = 1.2;
 27		
 28		private var _circle:Vector3D;
 29		private var _vectors:Vector.<Vector3D>;
 30		private var _subGeometry:SubGeometry;
 31		private var _sortProp:String;
 32		private var _loopProp:String;
 33		
 34		private var _uvs:Vector.<Number>;
 35		private var _vertices:Vector.<Number>;
 36		private var _indices:Vector.<uint>;
 37		private var _normals:Vector.<Number>;
 38		private var _geomDirty:Boolean = true;
 39		
 40		private var _centerMesh:Boolean;
 41		private var _plane:String;
 42		private var _flip:Boolean;
 43		private var _smoothSurface:Boolean;
 44		
 45		private var _axis0Min:Number;
 46		private var _axis0Max:Number;
 47		private var _axis1Min:Number;
 48		private var _axis1Max:Number;
 49		
 50		private var _tmpNormal:Vector3D;
 51		private var _normal0:Vector3D;
 52		private var _normal1:Vector3D;
 53		private var _normal2:Vector3D;
 54		
 55		/*
 56		 * Class DelaunayMesh generates (and becomes) a mesh from a vector of vector3D's . <code>DelaunayMesh</code>
 57		 *@param	material				MaterialBase. The material for the resulting mesh.
 58		 *@param	vectors				Vector.<Vector3D> A series of vector3d's defining the surface of the shape.
 59		 *@param	plane					[optional] String. The destination plane: can be DelaunayMesh.PLANE_XY, DelaunayMesh.PLANE_XZ or DelaunayMesh.PLANE_ZY. Default is xz plane.
 60		 *@param	centerMesh		[optional] Boolean. If the final mesh must be centered. Default is false.
 61		 *@param	flip					[optional] Boolean. If the faces need to be inverted. Default is false.
 62		 *@param	smoothSurface	[optional] Boolean. If the surface finished needs to smooth or flat. Default is true, a smooth finish.
 63		 */
 64		public function DelaunayMesh(material:MaterialBase, vectors:Vector.<Vector3D>, plane:String = PLANE_XZ, centerMesh:Boolean = false, flip:Boolean = false, smoothSurface:Boolean = true)
 65		{
 66			var geom:Geometry = new Geometry();
 67			_subGeometry = new SubGeometry();
 68			geom.addSubGeometry(_subGeometry);
 69			super(geom, material);
 70			
 71			_vectors = vectors;
 72			_centerMesh = centerMesh;
 73			_plane = plane;
 74			_flip = flip;
 75			_smoothSurface = smoothSurface;
 76		}
 77		
 78		/**
 79		 * The "cloud" of vector3d's to compose the mesh
 80		 */
 81		public function get vectors():Vector.<Vector3D>
 82		{
 83			return _vectors;
 84		}
 85		
 86		public function set vectors(val:Vector.<Vector3D>):void
 87		{
 88			if (_vectors.length < 3)
 89				return;
 90			
 91			_vectors = val;
 92			invalidateGeometry();
 93		}
 94		
 95		/**
 96		 * Defines if the surface of the mesh must be smoothed or not. Default value is true.
 97		 */
 98		public function get smoothSurface():Boolean
 99		{
100			return _smoothSurface;
101		}
102		
103		public function set smoothSurface(val:Boolean):void
104		{
105			if (_smoothSurface == val)
106				return;
107			
108			_smoothSurface = val;
109			invalidateGeometry();
110		}
111		
112		/**
113		 * Defines the projection plane for the class. Default is xz.
114		 */
115		public function get plane():String
116		{
117			return _plane;
118		}
119		
120		public function set plane(val:String):void
121		{
122			if (_plane == val)
123				return;
124			if (val != PLANE_XZ && val != PLANE_XY && val != PLANE_ZY)
125				return;
126			
127			_plane = val;
128			invalidateGeometry();
129		}
130		
131		/**
132		 * Defines if the face orientation needs to be inverted
133		 */
134		public function get flip():Boolean
135		{
136			return _flip;
137		}
138		
139		public function set flip(val:Boolean):void
140		{
141			if (_flip == val)
142				return;
143			
144			_flip = val;
145			invalidateGeometry();
146		}
147		
148		/**
149		 * Defines whether the mesh is recentered of not after generation
150		 */
151		public function get centerMesh():Boolean
152		{
153			return _centerMesh;
154		}
155		
156		public function set centerMesh(val:Boolean):void
157		{
158			if (_centerMesh == val)
159				return;
160			
161			_centerMesh = val;
162			
163			if (_centerMesh && _subGeometry.vertexData.length > 0)
164				MeshHelper.applyPosition(this, (this.minX + this.maxX)*.5, (this.minY + this.maxY)*.5, (this.minZ + this.maxZ)*.5);
165			else
166				invalidateGeometry();
167		}
168		
169		private function buildExtrude():void
170		{
171			_geomDirty = false;
172			if (_vectors && _vectors.length > 2) {
173				initHolders();
174				generate();
175			} else
176				throw new Error("DelaunayMesh: minimum 3 Vector3D are required to generate a surface");
177			
178			if (_centerMesh)
179				MeshHelper.recenter(this);
180		
181		}
182		
183		private function initHolders():void
184		{
185			_axis0Min = Infinity;
186			_axis0Max = -Infinity;
187			_axis1Min = Infinity;
188			_axis1Max = -Infinity;
189			
190			_uvs = new Vector.<Number>();
191			_vertices = new Vector.<Number>();
192			_indices = new Vector.<uint>();
193			
194			_circle = new Vector3D();
195			
196			if (_smoothSurface) {
197				_normals = new Vector.<Number>();
198				_normal0 = new Vector3D(0.0, 0.0, 0.0);
199				_normal1 = new Vector3D(0.0, 0.0, 0.0);
200				_normal2 = new Vector3D(0.0, 0.0, 0.0);
201				_tmpNormal = new Vector3D(0.0, 0.0, 0.0);
202				_subGeometry.autoDeriveVertexNormals = false;
203				
204			} else
205				_subGeometry.autoDeriveVertexNormals = true;
206			_subGeometry.autoDeriveVertexTangents = true;
207		
208		}
209		
210		private function addFace(v0:Vector3D, v1:Vector3D, v2:Vector3D, uv0:UV, uv1:UV, uv2:UV):void
211		{
212			var subGeom:SubGeometry = _subGeometry;
213			var uvs:Vector.<Number> = _uvs;
214			var vertices:Vector.<Number> = _vertices;
215			var indices:Vector.<uint> = _indices;
216			
217			if (_smoothSurface)
218				var normals:Vector.<Number> = _normals;
219			
220			if (vertices.length + 9 > LIMIT) {
221				subGeom.updateVertexData(vertices);
222				subGeom.updateIndexData(indices);
223				subGeom.updateUVData(uvs);
224				
225				if (_smoothSurface)
226					subGeom.updateVertexNormalData(normals);
227				
228				this.geometry.addSubGeometry(subGeom);
229				
230				subGeom = _subGeometry = new SubGeometry();
231				subGeom.autoDeriveVertexTangents = true;
232				
233				uvs = _uvs = new Vector.<Number>();
234				vertices = _vertices = new Vector.<Number>();
235				indices = _indices = new Vector.<uint>();
236				
237				if (!_smoothSurface)
238					subGeom.autoDeriveVertexNormals = true;
239				else {
240					subGeom.autoDeriveVertexNormals = false;
241					normals = _normals = new Vector.<Number>();
242				}
243				
244				subGeom.autoDeriveVertexTangents = true;
245			}
246			
247			var bv0:Boolean;
248			var bv1:Boolean;
249			var bv2:Boolean;
250			
251			var ind0:uint;
252			var ind1:uint;
253			var ind2:uint;
254			
255			if (_smoothSurface) {
256				var uvind:uint;
257				var uvindV:uint;
258				var vind:uint;
259				var vindb:uint;
260				var vindz:uint;
261				var ind:uint;
262				var indlength:uint = indices.length;
263				calcNormal(v0, v1, v2);
264				var ab:Number;
265				
266				if (indlength > 0) {
267					
268					for (var i:uint = indlength - 1; i > 0; --i) {
269						ind = indices[i];
270						vind = ind*3;
271						vindb = vind + 1;
272						vindz = vind + 2;
273						uvind = ind*2;
274						uvindV = uvind + 1;
275						
276						if (bv0 && bv1 && bv2)
277							break;
278						
279						if (!bv0 && vertices[vind] == v0.x && vertices[vindb] == v0.y && vertices[vindz] == v0.z) {
280							
281							_tmpNormal.x = normals[vind];
282							_tmpNormal.y = normals[vindb];
283							_tmpNormal.z = normals[vindz];
284							ab = Vector3D.angleBetween(_tmpNormal, _normal0);
285							
286							if (ab < MAXRAD) {
287								_normal0.x = (_tmpNormal.x + _normal0.x)*.5;
288								_normal0.y = (_tmpNormal.y + _normal0.y)*.5;
289								_normal0.z = (_tmpNormal.z + _normal0.z)*.5;
290								
291								bv0 = true;
292								ind0 = ind;
293								continue;
294							}
295						}
296						
297						if (!bv1 && vertices[vind] == v1.x && vertices[vindb] == v1.y && vertices[vindz] == v1.z) {
298							
299							_tmpNormal.x = normals[vind];
300							_tmpNormal.y = normals[vindb];
301							_tmpNormal.z = normals[vindz];
302							ab = Vector3D.angleBetween(_tmpNormal, _normal1);
303							
304							if (ab < MAXRAD) {
305								_normal1.x = (_tmpNormal.x + _normal1.x)*.5;
306								_normal1.y = (_tmpNormal.y + _normal1.y)*.5;
307								_normal1.z = (_tmpNormal.z + _normal1.z)*.5;
308								
309								bv1 = true;
310								ind1 = ind;
311								continue;
312							}
313						}
314						
315						if (!bv2 && vertices[vind] == v2.x && vertices[vindb] == v2.y && vertices[vindz] == v2.z) {
316							
317							_tmpNormal.x = normals[vind];
318							_tmpNormal.y = normals[vindb];
319							_tmpNormal.z = normals[vindz];
320							ab = Vector3D.angleBetween(_tmpNormal, _normal2);
321							
322							if (ab < MAXRAD) {
323								
324								_normal2.x = (_tmpNormal.x + _normal2.x)*.5;
325								_normal2.y = (_tmpNormal.y + _normal2.y)*.5;
326								_normal2.z = (_tmpNormal.z + _normal2.z)*.5;
327								
328								bv2 = true;
329								ind2 = ind;
330								continue;
331							}
332							
333						}
334					}
335				}
336			}
337			
338			if (!bv0) {
339				ind0 = vertices.length/3;
340				vertices.push(v0.x, v0.y, v0.z);
341				uvs.push(uv0.u, uv0.v);
342				if (_smoothSurface)
343					normals.push(_normal0.x, _normal0.y, _normal0.z);
344			}
345			
346			if (!bv1) {
347				ind1 = vertices.length/3;
348				vertices.push(v1.x, v1.y, v1.z);
349				uvs.push(uv1.u, uv1.v);
350				if (_smoothSurface)
351					normals.push(_normal1.x, _normal1.y, _normal1.z);
352			}
353			
354			if (!bv2) {
355				ind2 = vertices.length/3;
356				vertices.push(v2.x, v2.y, v2.z);
357				uvs.push(uv2.u, uv2.v);
358				if (_smoothSurface)
359					normals.push(_normal2.x, _normal2.y, _normal2.z);
360			}
361			
362			indices.push(ind0, ind1, ind2);
363		}
364		
365		private function generate():void
366		{
367			getVectorsBounds();
368			
369			var w:Number = _axis0Max - _axis0Min;
370			var h:Number = _axis1Max - _axis1Min;
371			
372			var offW:Number = (_axis0Min > 0)? -_axis0Min : Math.abs(_axis0Min);
373			var offH:Number = (_axis1Min > 0)? -_axis1Min : Math.abs(_axis1Min);
374			
375			var uv0:UV = new UV();
376			var uv1:UV = new UV();
377			var uv2:UV = new UV();
378			
379			var v0:Vector3D;
380			var v1:Vector3D;
381			var v2:Vector3D;
382			
383			var limit:uint = _vectors.length;
384			
385			if (limit > 3) {
386				var nVectors:Vector.<Vector3D> = new Vector.<Vector3D>();
387				nVectors = _vectors.sort(sortFunction);
388				
389				var i:uint;
390				var j:uint;
391				var k:uint;
392				var v:Vector.<Tri> = new Vector.<Tri>();
393				var nv:uint = nVectors.length;
394				
395				for (i = 0; i < (nv*3); ++i)
396					v[i] = new Tri();
397				
398				var bList:Vector.<Boolean> = new Vector.<Boolean>();
399				var edges:Array = [];
400				var nEdge:uint = 0;
401				var maxTris:uint = 4*nv;
402				var maxEdges:uint = nv*2;
403				
404				for (i = 0; i < maxTris; ++i)
405					bList[i] = false;
406				
407				var inside:Boolean;
408				var valA:Number;
409				var valB:Number;
410				var x1:Number;
411				var y1:Number;
412				var x2:Number;
413				var y2:Number;
414				var x3:Number;
415				var y3:Number;
416				// TODO: not used
417				// var xc:Number;
418				// TODO: not used
419				// var yc:Number;
420				
421				var sortMin:Number;
422				var sortMax:Number;
423				var loopMin:Number;
424				var loopMax:Number;
425				var sortMid:Number;
426				var loopMid:Number;
427				var ntri:uint = 1;
428				
429				for (i = 0; i < maxEdges; ++i)
430					edges[i] = new Edge();
431				
432				sortMin = nVectors[0][_sortProp];
433				loopMin = nVectors[0][_loopProp];
434				sortMax = sortMin;
435				loopMax = loopMin;
436				
437				for (i = 1; i < nv; ++i) {
438					if (nVectors[i][_sortProp] < sortMin)
439						sortMin = nVectors[i][_sortProp];
440					if (nVectors[i][_sortProp] > sortMax)
441						sortMax = nVectors[i][_sortProp];
442					if (nVectors[i][_loopProp] < loopMin)
443						loopMin = nVectors[i][_loopProp];
444					if (nVectors[i][_loopProp] > loopMax)
445						loopMax = nVectors[i][_loopProp];
446				}
447				
448				var da:Number = sortMax - sortMin;
449				var db:Number = loopMax - loopMin;
450				var dmax:Number = (da > db)? da : db;
451				sortMid = (sortMax + sortMin)*.5;
452				loopMid = (loopMax + loopMin)*.5;
453				
454				nVectors[nv] = new Vector3D(0.0, 0.0, 0.0);
455				nVectors[nv + 1] = new Vector3D(0.0, 0.0, 0.0);
456				nVectors[nv + 2] = new Vector3D(0.0, 0.0, 0.0);
457				
458				var offset:Number = 2.0;
459				nVectors[nv + 0][_sortProp] = sortMid - offset*dmax;
460				nVectors[nv + 0][_loopProp] = loopMid - dmax;
461				
462				nVectors[nv + 1][_sortProp] = sortMid;
463				nVectors[nv + 1][_loopProp] = loopMid + offset*dmax;
464				
465				nVectors[nv + 2][_sortProp] = sortMid + offset*dmax;
466				nVectors[nv + 2][_loopProp] = loopMid - dmax;
467				
468				v[0].v0 = nv;
469				v[0].v1 = nv + 1;
470				v[0].v2 = nv + 2;
471				bList[0] = false;
472				
473				for (i = 0; i < nv; ++i) {
474					
475					valA = vectors[i][_sortProp];
476					valB = vectors[i][_loopProp];
477					nEdge = 0;
478					
479					for (j = 0; j < ntri; ++j) {
480						
481						if (bList[j])
482							continue;
483						
484						x1 = nVectors[v[j].v0][_sortProp];
485						y1 = nVectors[v[j].v0][_loopProp];
486						x2 = nVectors[v[j].v1][_sortProp];
487						y2 = nVectors[v[j].v1][_loopProp];
488						x3 = nVectors[v[j].v2][_sortProp];
489						y3 = nVectors[v[j].v2][_loopProp];
490						
491						inside = circumCircle(valA, valB, x1, y1, x2, y2, x3, y3);
492						
493						if (_circle.x + _circle.z < valA)
494							bList[j] = true;
495						
496						if (inside) {
497							if (nEdge + 3 >= maxEdges) {
498								maxEdges += 3;
499								edges.push(new Edge(), new Edge(), new Edge());
500							}
501							edges[nEdge].v0 = v[j].v0;
502							edges[nEdge].v1 = v[j].v1;
503							edges[nEdge + 1].v0 = v[j].v1;
504							edges[nEdge + 1].v1 = v[j].v2;
505							edges[nEdge + 2].v0 = v[j].v2;
506							edges[nEdge + 2].v1 = v[j].v0;
507							nEdge += 3;
508							ntri--;
509							v[j].v0 = v[ntri].v0;
510							v[j].v1 = v[ntri].v1;
511							v[j].v2 = v[ntri].v2;
512							bList[j] = bList[ntri];
513							j--;
514							
515						}
516					}
517					
518					for (j = 0; j < nEdge - 1; ++j) {
519						
520						for (k = j + 1; k < nEdge; ++k) {
521							
522							if ((edges[j].v0 == edges[k].v1) && (edges[j].v1 == edges[k].v0))
523								edges[j].v0 = edges[j].v1 = edges[k].v0 = edges[k].v1 = -1;
524							
525							if ((edges[j].v0 == edges[k].v0) && (edges[j].v1 == edges[k].v1))
526								edges[j].v0 = edges[j].v1 = edges[k].v0 = edges[k].v1 = -1;
527						}
528					}
529					
530					for (j = 0; j < nEdge; ++j) {
531						
532						if (edges[j].v0 == -1 || edges[j].v1 == -1)
533							continue;
534						
535						if (ntri >= maxTris)
536							continue;
537						
538						v[ntri].v0 = edges[j].v0;
539						v[ntri].v1 = edges[j].v1;
540						v[ntri].v2 = i;
541						
542						bList[ntri] = false;
543						
544						ntri++;
545					}
546				}
547				
548				for (i = 0; i < ntri; ++i) {
549					
550					if (v[i].v0 == v[i].v1 && v[i].v1 == v[i].v2)
551						continue;
552					
553					if ((v[i].v0 >= limit || v[i].v1 >= limit || v[i].v2 >= limit)) {
554						v[i] = v[ntri - 1];
555						ntri--;
556						i--;
557						continue;
558					}
559					
560					v0 = nVectors[v[i].v0];
561					v1 = nVectors[v[i].v1];
562					v2 = nVectors[v[i].v2];
563					
564					uv0.u = (v0[_loopProp] + offW)/w;
565					uv0.v = 1 - (v0[_sortProp] + offH)/h;
566					
567					uv1.u = (v1[_loopProp] + offW)/w;
568					uv1.v = 1 - (v1[_sortProp] + offH)/h;
569					
570					uv2.u = (v2[_loopProp] + offW)/w;
571					uv2.v = 1 - (v2[_sortProp] + offH)/h;
572					
573					if (_flip)
574						addFace(v0, v1, v2, uv0, uv1, uv2);
575					else
576						addFace(v1, v0, v2, uv1, uv0, uv2);
577					
578				}
579				
580				if (_smoothSurface)
581					_subGeometry.updateVertexNormalData(_normals);
582				
583				for (i = 0; i < v.length; ++i)
584					v[i] = null;
585				
586				v = null;
587				nVectors = null;
588				
589			} else {
590				
591				v0 = _vectors[0];
592				v1 = _vectors[1];
593				v2 = _vectors[2];
594				
595				_vertices.push(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
596				
597				uv0.u = (v0[_loopProp] + offW)/w;
598				uv0.v = 1 - (v0[_sortProp] + offH)/h;
599				
600				uv1.u = (v1[_loopProp] + offW)/w;
601				uv1.v = 1 - (v1[_sortProp] + offH)/h;
602				
603				uv2.u = (v2[_loopProp] + offW)/w;
604				uv2.v = 1 - (v2[_sortProp] + offH)/h;
605				
606				_uvs.push(uv0.u, uv0.v, uv1.u, uv1.v, uv2.u, uv2.v);
607				
608				if (_flip)
609					_indices.push(1, 0, 2);
610				else
611					_indices.push(0, 1, 2);
612				
613				_subGeometry.autoDeriveVertexNormals = true;
614			}
615			
616			_subGeometry.updateVertexData(_vertices);
617			_subGeometry.updateIndexData(_indices);
618			_subGeometry.updateUVData(_uvs);
619		
620		}
621		
622		private function sortFunction(v0:Vector3D, v1:Vector3D):int
623		{
624			var a:Number = v0[_sortProp];
625			var b:Number = v1[_sortProp];
626			if (a == b)
627				return 0;
628			else if (a < b)
629				return 1;
630			else
631				return -1;
632		}
633		
634		private function calcNormal(v0:Vector3D, v1:Vector3D, v2:Vector3D):void
635		{
636			var da1:Number = v2.x - v0.x;
637			var db1:Number = v2.y - v0.y;
638			var dz1:Number = v2.z - v0.z;
639			var da2:Number = v1.x - v0.x;
640			var db2:Number = v1.y - v0.y;
641			var dz2:Number = v1.z - v0.z;
642			
643			var cx:Number = dz1*db2 - db1*dz2;
644			var cy:Number = da1*dz2 - dz1*da2;
645			var cz:Number = db1*da2 - da1*db2;
646			var d:Number = 1/Math.sqrt(cx*cx + cy*cy + cz*cz);
647			
648			_normal0.x = _normal1.x = _normal2.x = cx*d;
649			_normal0.y = _normal1.y = _normal2.y = cy*d;
650			_normal0.z = _normal1.z = _normal2.z = cz*d;
651		}
652		
653		private function getVectorsBounds():void
654		{
655			var i:uint;
656			var v:Vector3D;
657			switch (_plane) {
658				case PLANE_XZ:
659					_sortProp = "z";
660					_loopProp = "x";
661					for (i = 0; i < _vectors.length; ++i) {
662						v = _vectors[i];
663						if (v.x < _axis0Min)
664							_axis0Min = v.x;
665						if (v.x > _axis0Max)
666							_axis0Max = v.x;
667						if (v.z < _axis1Min)
668							_axis1Min = v.z;
669						if (v.z > _axis1Max)
670							_axis1Max = v.z;
671					}
672					break;
673				
674				case PLANE_XY:
675					_sortProp = "y";
676					_loopProp = "x";
677					for (i = 0; i < _vectors.length; ++i) {
678						v = _vectors[i];
679						if (v.x < _axis0Min)
680							_axis0Min = v.x;
681						if (v.x > _axis0Max)
682							_axis0Max = v.x;
683						if (v.y < _axis1Min)
684							_axis1Min = v.y;
685						if (v.y > _axis1Max)
686							_axis1Max = v.y;
687					}
688					break;
689				
690				case PLANE_ZY:
691					_sortProp = "y";
692					_loopProp = "z";
693					for (i = 0; i < _vectors.length; ++i) {
694						v = _vectors[i];
695						if (v.z < _axis0Min)
696							_axis0Min = v.z;
697						if (v.z > _axis0Max)
698							_axis0Max = v.z;
699						if (v.y < _axis1Min)
700							_axis1Min = v.y;
701						if (v.y > _axis1Max)
702							_axis1Max = v.y;
703					}
704				
705			}
706		}
707		
708		/**
709		 * @inheritDoc
710		 */
711		override public function get bounds():BoundingVolumeBase
712		{
713			if (_geomDirty)
714				buildExtrude();
715			
716			return super.bounds;
717		}
718		
719		/**
720		 * @inheritDoc
721		 */
722		override public function get geometry():Geometry
723		{
724			if (_geomDirty)
725				buildExtrude();
726			
727			return super.geometry;
728		}
729		
730		/**
731		 * @inheritDoc
732		 */
733		override public function get subMeshes():Vector.<SubMesh>
734		{
735			if (_geomDirty)
736				buildExtrude();
737			
738			return super.subMeshes;
739		}
740		
741		private function invalidateGeometry():void
742		{
743			_geomDirty = true;
744			invalidateBounds();
745		}
746		
747		private function circumCircle(xp:Number, yp:Number, x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number):Boolean
748		{
749			var m1:Number;
750			var m2:Number;
751			var mx1:Number;
752			var mx2:Number;
753			var my1:Number;
754			var my2:Number;
755			var da:Number;
756			var db:Number;
757			var rsqr:Number;
758			var drsqr:Number;
759			var xc:Number;
760			var yc:Number;
761			
762			if (Math.abs(y1 - y2) < EPS && Math.abs(y2 - y3) < EPS)
763				return false;
764			
765			if (Math.abs(y2 - y1) < EPS) {
766				m2 = -(x3 - x2)/(y3 - y2);
767				mx2 = (x2 + x3)*.5;
768				my2 = (y2 + y3)*.5;
769				xc = (x2 + x1)*.5;
770				yc = m2*(xc - mx2) + my2;
771				
772			} else if (Math.abs(y3 - y2) < EPS) {
773				m1 = -(x2 - x1)/(y2 - y1);
774				mx1 = (x1 + x2)*.5;
775				my1 = (y1 + y2)*.5;
776				xc = (x3 + x2)*.5;
777				yc = m1*(xc - mx1) + my1;
778				
779			} else {
780				m1 = -(x2 - x1)/(y2 - y1);
781				m2 = -(x3 - x2)/(y3 - y2);
782				mx1 = (x1 + x2)*.5;
783				mx2 = (x2 + x3)*.5;
784				my1 = (y1 + y2)*.5;
785				my2 = (y2 + y3)*.5;
786				xc = (m1*mx1 - m2*mx2 + my2 - my1)/(m1 - m2);
787				yc = m1*(xc - mx1) + my1;
788			}
789			
790			da = x2 - xc;
791			db = y2 - yc;
792			rsqr = da*da + db*db;
793			
794			da = xp - xc;
795			db = yp - yc;
796			drsqr = da*da + db*db;
797			
798			_circle.x = xc;
799			_circle.y = yc;
800			_circle.z = Math.sqrt(rsqr);
801			
802			return Boolean(drsqr <= rsqr);
803		}
804	}
805}
806
807class Tri
808{
809	public var v0:int;
810	public var v1:int;
811	public var v2:int;
812}
813
814class Edge
815{
816	public var v0:int;
817	public var v1:int;
818}