2009-10-24 10:07:43 +00:00
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 ;
2009-11-04 20:48:31 +00:00
Vector3d . Subtract ( ref A , ref D , out temp1 ) ;
Vector3d . Subtract ( ref B , ref D , out temp2 ) ;
Vector3d . Subtract ( ref C , ref D , out temp3 ) ;
2009-10-24 10:07:43 +00:00
Vector3d . Add ( ref temp1 , ref temp2 , out result ) ;
2009-11-04 20:48:31 +00:00
Vector3d . Add ( ref result , ref temp3 , out result ) ;
2009-10-24 10:07:43 +00:00
result . Normalize ( ) ;
}
internal static void FindNormal ( ref Vector3d A , ref Vector3d B , ref Vector3d C , out Vector3d result )
{
Vector3d temp1 , temp2 ;
2009-11-04 20:48:31 +00:00
Vector3d . Subtract ( ref A , ref B , out temp1 ) ;
2009-10-24 10:07:43 +00:00
temp1 . Normalize ( ) ;
2009-11-04 20:48:31 +00:00
Vector3d . Subtract ( ref C , ref B , out temp2 ) ;
2009-10-24 10:07:43 +00:00
temp2 . Normalize ( ) ;
Vector3d . Cross ( ref temp1 , ref temp2 , out result ) ;
2009-11-04 20:48:31 +00:00
result * = - 1.0 ;
2009-10-24 10:07:43 +00:00
result . Normalize ( ) ;
}
}
}