Opentk/Source/Examples/Shapes/Old/SierpinskiTetrahedron.cs
2009-10-24 10:07:43 +00:00

174 lines
8 KiB
C#

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.Sub( ref A, ref D, out temp1 );
Vector3d.Sub( ref B, ref D, out temp2 );
Vector3d.Sub( ref C, ref D, out temp3 );
Vector3d.Add( ref temp1, ref temp2, out result );
result.Add( ref temp3 );
result.Normalize();
}
internal static void FindNormal( ref Vector3d A, ref Vector3d B, ref Vector3d C, out Vector3d result )
{
Vector3d temp1, temp2;
Vector3d.Sub( ref A, ref B, out temp1 );
temp1.Normalize();
Vector3d.Sub( ref C, ref B, out temp2 );
temp2.Normalize();
Vector3d.Cross( ref temp1, ref temp2, out result );
result.Mult( -1.0 );
result.Normalize();
}
}
}