using System; using System.Diagnostics; using OpenTK; namespace Examples.Shapes { public sealed partial class SierpinskiTetrahedron: DrawableShape { public enum eSubdivisions { /// <summary>Creates a Sierpinski Tetrahedron using 4 triangles.</summary> Zero = 0, /// <summary>Creates a Sierpinski Tetrahedron using 16 triangles.</summary> One = 1, /// <summary>Creates a Sierpinski Tetrahedron using 64 triangles.</summary> Two = 2, /// <summary>Creates a Sierpinski Tetrahedron using 256 triangles.</summary> Three = 3, /// <summary>Creates a Sierpinski Tetrahedron using 1024 triangles.</summary> Four = 4, /// <summary>Creates a Sierpinski Tetrahedron using 4096 triangles.</summary> Five = 5, /// <summary>Creates a Sierpinski Tetrahedron using 16384 triangles.</summary> Six = 6, /// <summary>Creates a Sierpinski Tetrahedron using 65536 triangles.</summary> Seven = 7, /// <summary>Creates a Sierpinski Tetrahedron using 262144 triangles.</summary> Eight = 8, /// <summary>Creates a Sierpinski Tetrahedron using 1048576 triangles.</summary> Nine = 9, } /// <summary>Creates a Sierpinski Tetrahedron which is centered at (0,0,0) and fits into a sphere of radius 1f, or a diameter of 2f</summary> /// <param name="scale">Default: 1f.</param> /// <param name="subdivs">The number of subdivisions of the Tetrahedron.</param> /// <param name="useDL"></param> public SierpinskiTetrahedron( double scale, eSubdivisions subdivs, bool useDL ) : base( useDL ) { TetrahedronFace[] Triangles; switch ( subdivs ) { case eSubdivisions.Zero: CreateDefaultTetrahedron( scale, out Triangles ); break; case eSubdivisions.One: case eSubdivisions.Two: case eSubdivisions.Three: case eSubdivisions.Four: case eSubdivisions.Five: case eSubdivisions.Six: case eSubdivisions.Seven: case eSubdivisions.Eight: case eSubdivisions.Nine: CreateDefaultTetrahedron( scale, out Triangles ); for ( int i = 0; i < (int)subdivs; i++ ) { TetrahedronFace[] temp; SubdivideTetrahedron( ref Triangles, out temp ); Triangles = temp; } break; default: throw new ArgumentOutOfRangeException( "Subdivisions other than contained in the enum cause overflows and are not allowed." ); } PrimitiveMode = OpenTK.Graphics.OpenGL.BeginMode.Triangles; SierpinskiTetrahedron.GetVertexArray( ref Triangles, out VertexArray ); IndexArray = null; } internal static void GetVertexArray( ref TetrahedronFace[] input, out VertexT2dN3dV3d[] output ) { output = new VertexT2dN3dV3d[input.Length * 3]; int counter = 0; for ( int i = 0; i < input.Length; i++ ) { input[i].GetVertices( out output[counter + 0], out output[counter + 1], out output[counter + 2] ); counter += 3; } } /// <summary>Generates the lowest subdivision mesh, which consists of 4 Triangles.</summary> internal static void CreateDefaultTetrahedron( double scale, out TetrahedronFace[] array ) { Vector3d[] Points = new Vector3d[4]; Points[0] = new Vector3d( 0.0 * scale, 0.0 * scale, 1.0 * scale ); Points[1] = new Vector3d( -0.816 * scale, 0.471 * scale, -0.333 * scale ); Points[2] = new Vector3d( 0.816 * scale, 0.471 * scale, -0.333 * scale ); Points[3] = new Vector3d( 0.0 * scale, -0.943 * scale, -0.333 * scale ); Vector2d[] TexCoords = new Vector2d[4]; TexCoords[0] = new Vector2d( 0.0, 0.0 ); TexCoords[1] = new Vector2d( 1.0, 0.0 ); TexCoords[2] = new Vector2d( 0.0, 1.0 ); TexCoords[3] = new Vector2d( 1.0, 1.0 ); Vector3d Normal; array = new TetrahedronFace[4]; FindNormal( ref Points[0], ref Points[2], ref Points[1], ref Points[3], out Normal ); array[0] = new TetrahedronFace( ref Points[0], ref TexCoords[2], ref Points[2], ref TexCoords[0], ref Points[1], ref TexCoords[1], ref Points[3], ref Normal ); FindNormal( ref Points[0], ref Points[3], ref Points[2], ref Points[1], out Normal ); array[1] = new TetrahedronFace( ref Points[0], ref TexCoords[0], ref Points[3], ref TexCoords[1], ref Points[2], ref TexCoords[2], ref Points[1], ref Normal ); FindNormal( ref Points[0], ref Points[1], ref Points[3], ref Points[2], out Normal ); array[2] = new TetrahedronFace( ref Points[0], ref TexCoords[2], ref Points[1], ref TexCoords[1], ref Points[3], ref TexCoords[3], ref Points[2], ref Normal ); FindNormal( ref Points[1], ref Points[2], ref Points[3], ref Points[0], out Normal ); array[3] = new TetrahedronFace( ref Points[1], ref TexCoords[3], ref Points[2], ref TexCoords[2], ref Points[3], ref TexCoords[1], ref Points[0], ref Normal ); } /// <summary>Subdivides each triangle into 4 new ones.</summary> private void SubdivideTetrahedron( ref TetrahedronFace[] source, out TetrahedronFace[] output ) { output = new TetrahedronFace[source.Length * 4]; int counter = 0; for ( int i = 0; i < source.Length; i++ ) { source[i].SubdivideSierpinski( out output[counter + 0], out output[counter + 1], out output[counter + 2], out output[counter + 3] ); counter += 4; // every source triangle emits 4 new triangles } } /// <summary>A, B and C are the triangle whos normal is to be determined. D is the 4th Point in the Tetraeder which does not belong to the triangle.</summary> internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, ref Vector3d D, out Vector3d result ) { Vector3d temp1, temp2, temp3; Vector3d.Subtract( ref A, ref D, out temp1 ); Vector3d.Subtract( ref B, ref D, out temp2 ); Vector3d.Subtract( ref C, ref D, out temp3 ); Vector3d.Add( ref temp1, ref temp2, out result ); Vector3d.Add(ref result, ref temp3, out result); result.Normalize(); } internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, out Vector3d result ) { Vector3d temp1, temp2; Vector3d.Subtract( ref A, ref B, out temp1 ); temp1.Normalize(); Vector3d.Subtract(ref C, ref B, out temp2); temp2.Normalize(); Vector3d.Cross( ref temp1, ref temp2, out result ); result *= -1.0; result.Normalize(); } } }