File: TorusKnot.cs

package info (click to toggle)
opentk 1.1.4c%2Bdfsg-2.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 68,640 kB
  • sloc: cs: 525,501; xml: 277,501; ansic: 3,597; makefile: 41
file content (128 lines) | stat: -rw-r--r-- 5,891 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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.PrimitiveType.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
        }

    }
}