Blame |
Last modification |
View Log
| RSS feed
using System;
using System.Diagnostics;
using OpenTK;
namespace Examples
.Shapes
{
public sealed class TorusKnot
: DrawableShape
{
#region Constants
// hard minimums to make sure the created Torusknot is 3D
private const int MINShapeVertices
= 3;
private const int MINPathSteps
= 32;
private const double TwoPi
= ( 2.0 * System.Math.PI );
#endregion Constants
public TorusKnot
( int pathsteps,
int shapevertices,
double radius,
int p,
int q,
int TexCount,
bool useDL
)
: base( useDL
)
{
Trace
.Assert( pathsteps
>= MINPathSteps,
"A Path must have at least " + MINPathSteps
+ " Steps to form a volume." );
Trace
.Assert( shapevertices
>= MINShapeVertices,
"A Shape must contain at least " + MINShapeVertices
+ " Vertices to be considered valid and create a volume." );
Trace
.Assert( TexCount
> 1,
"at least 1 Texture set is required." );
PrimitiveMode
= OpenTK
.Graphics.OpenGL.BeginMode.TriangleStrip;
Vector3d
[] PathPositions
= new Vector3d
[pathsteps
];
#region Find the center Points for each step on the path
for ( int i
= 0; i
< pathsteps
; i
++ )
{
double Angle
= ( i
/ (double)pathsteps
) * TwoPi
;
double AngleTimesP
= Angle
* p
;
double AngleTimesQ
= Angle
* q
;
double r
= ( 0.5 * ( 2.0 + System.Math.Sin( AngleTimesQ
) ) );
PathPositions
[i
] = new Vector3d
( ( r
* System.Math.Cos( AngleTimesP
) ),
( r
* System.Math.Cos( AngleTimesQ
) ),
( r
* System.Math.Sin( AngleTimesP
) ) );
}
#endregion Find the center Points for each step on the path
#region Find the Torus length
Vector3d result
;
double[] Lengths
= new double[pathsteps
];
Vector3d
.Subtract( ref PathPositions
[pathsteps
- 1],
ref PathPositions
[0],
out result
);
Lengths
[0] = result
.Length;
double TotalLength
= result
.Length;
for ( int i
= 1; i
< pathsteps
; i
++ ) // skipping
{
Vector3d
.Subtract( ref PathPositions
[i
- 1],
ref PathPositions
[i
],
out result
);
Lengths
[i
] = result
.Length;
TotalLength
+= result
.Length;
}
Trace
.WriteLine( "the TorusKnot's length is: " + TotalLength
+ " " );
#endregion Find the Torus length
VertexArray
= new VertexT2dN3dV3d
[pathsteps
* shapevertices
];
#region Loft a circle Shape along the path
double TwoPiThroughVert
= TwoPi
/ shapevertices
; // precalc for reuse
for ( uint i
= 0; i
< pathsteps
; i
++ )
{
Vector3d last, next, normal, tangent
;
if ( i
== pathsteps
- 1 )
next
= PathPositions
[0];
else
next
= PathPositions
[i
+ 1];
if ( i
== 0 )
last
= PathPositions
[pathsteps
- 1];
else
last
= PathPositions
[i
- 1];
Vector3d
.Subtract( ref next,
ref last,
out tangent
); // Guesstimate tangent
tangent
.Normalize();
Vector3d
.Add( ref next,
ref last,
out normal
); // Approximate N
normal
.Normalize();
Vector3d
.Multiply( ref normal, radius,
out normal
);// scale the shape to desired radius
for ( uint j
= 0; j
< shapevertices
; j
++ )
{
uint index
= i
* (uint)shapevertices
+ j
;
// Create a point on the plane and rotate it
Matrix4d RotationMatrix
= Matrix4d
.Rotate( tangent,
-( j
* TwoPiThroughVert
) );
Vector3d point
= Vector3d
.TransformVector( normal, RotationMatrix
);
Vector3d
.Add( ref PathPositions
[i
],
ref point,
out VertexArray
[index
].Position );
// Since the used shape is a circle, the Vertex normal's heading is easy to find
Vector3d
.Subtract( ref VertexArray
[index
].Position,
ref PathPositions
[i
],
out VertexArray
[index
].Normal );
VertexArray
[index
].Normal.Normalize();
// just generate some semi-useful UVs to fill blanks
VertexArray
[index
].TexCoord = new Vector2d
( (double)( i
/ TotalLength
/ TexCount
), j
/ ( shapevertices
- 1.0 ) );
}
}
#endregion Loft a circle Shape along the path
PathPositions
= null; // not needed anymore
uint currentindex
= 0;
#region Build a Triangle strip from the Vertices
IndexArray
= new uint[pathsteps
* ( shapevertices
* 2 + 2 )]; // 2 triangles per vertex, +2 due to added degenerate triangles
for ( uint i
= 0; i
< pathsteps
; i
++ )
{
uint RowCurrent
= i
* (uint)shapevertices
;
uint RowBelow
;
if ( i
== pathsteps
- 1 )
RowBelow
= 0; // for the last row, the first row is the following
else
RowBelow
= ( i
+ 1 ) * (uint)shapevertices
;
// new ring begins here
for ( uint j
= 0; j
< shapevertices
; j
++ )
{
IndexArray
[currentindex
++] = RowCurrent
+ j
;
IndexArray
[currentindex
++] = RowBelow
+ j
;
}
// ring ends here, repeat first 2 vertices to insert 2 degenerate triangles to reach following ring
IndexArray
[currentindex
++] = RowCurrent
;
IndexArray
[currentindex
++] = RowBelow
;
}
#endregion Build a Triangle strip from the Vertices
}
}
}