001/*
002
003*/
004
005package renderer.models;
006import  renderer.scene.*;
007
008/**
009   Create a wireframe model of a torus.
010<p>
011   See <a href="https://en.wikipedia.org/wiki/Torus" target="_top">
012                https://en.wikipedia.org/wiki/Torus</a>
013<p>
014   This torus is the surface of revolution generated by revolving
015   the circle in the xy-plane with radius {@code r2} and center
016   {@code (r1,0,0)} around the y-axis. We are assuming that {@code r1 > r2}.
017<p>
018   Here are parametric equations for the circle in the xy-plane with
019   radius {@code r2} and center {@code (r1,0,0)} and parameterized
020   starting from the top, with parameter {@code 0 <= phi <= 2*PI}.
021   <pre>{@code
022      x(phi) = r1 + r2 * sin(phi)
023      y(phi) =      r2 * cos(phi)
024      z(phi) = 0
025   }</pre>
026   Here is the 3D rotation matrix that rotates around the y-axis
027   by {@code theta} radians with {@code 0 <= theta <= 2*PI}.
028   <pre>{@code
029      [ cos(theta)   0   sin(theta)]
030      [     0        1       0     ]
031      [-sin(theta)   0   cos(theta)]
032   }</pre>
033   If we multiply the rotation matrix with the circle parameterization,
034   we get a parameterization of the torus.
035   <pre>{@code
036      [ cos(theta)   0   sin(theta)]   [r1 + r2 * sin(phi)]
037      [     0        1       0     ] * [     r2 * cos(phi)]
038      [-sin(theta)   0   cos(theta)]   [        0         ]
039
040      = ( r1*cos(theta) + r2*cos(theta)*sin(phi).
041          r2*cos(phi),
042         -r1*sin(theta) - r2*sin(theta)*sin(phi) )
043
044      = ( (r1 + r2*sin(phi)) * cos(theta),
045                r2*cos(phi),
046         -(r1 + r2*sin(phi)) * sin(theta) )
047   }</pre>
048   See
049     <a href="http://en.wikipedia.org/wiki/Torus#Geometry" target="_top">
050              http://en.wikipedia.org/wiki/Torus#Geometry</a>
051
052   @see TorusSector
053*/
054public class Torus extends Model
055{
056   /**
057      Create a torus with a circle of revolution with radius 3/4
058      and a cross section circle (circle of longitude)
059      with radius 1/4.
060   */
061   public Torus( )
062   {
063      this(0.75, 0.25, 12, 16);
064   }
065
066
067   /**
068      Create a torus with a circle of revolution with radius {@code r1}
069      and a cross section circle (circle of longitude) with radius
070      {@code r2}.
071
072      @param r1  radius of the circle of revolution
073      @param r2  radius of the cross section circle (circle of longitude)
074   */
075   public Torus(double r1, double r2)
076   {
077      this(r1, r2, 12, 16);
078   }
079
080
081   /**
082      Create a torus with a circle of revolution with radius {@code r1}
083      and a cross section circle (circle of longitude) with radius
084      {@code r2}.
085   <p>
086      The last two parameters determine the number of circles of
087      longitude and the number of circles of latitude in the model.
088   <p>
089      Notice that if there are {@code n} circles of latitude, then each
090      circle of longitude will have {@code n} line segments. If there
091      are {@code k} circles of longitude, then each circle of latitude
092      will have {@code k} line segments.
093   <p>
094      There must be at least three circles of longitude and at least
095      three circles of latitude.
096
097      @param r1  radius of the circle of revolution
098      @param r2  radius of the cross section circle (circle of longitude)
099      @param n   number of circles of latitude
100      @param k   number of circles of longitude
101   */
102   public Torus(double r1, double r2, int n, int k)
103   {
104      super();
105
106      if (n < 3) n = 3;
107      if (k < 3) k = 3;
108
109      // Create the torus's geometry.
110
111      double deltaPhi = (2 * Math.PI) / n;
112      double deltaTheta = (2 * Math.PI) / k;
113
114      // An array of vertices to be used to create line segments.
115      Vertex[][] v = new Vertex[n][k];
116
117      // Create all the vertices.
118      for (int j = 0; j < k; j++) // choose a rotation around the y-axis
119      {
120         double c1 = Math.cos(j * deltaTheta);
121         double s1 = Math.sin(j * deltaTheta);
122         for (int i = 0; i < n; i++)  // go around a cross section circle
123         {
124            double c2 = Math.cos(i * deltaPhi);
125            double s2 = Math.sin(i * deltaPhi);
126            v[i][j] = new Vertex( (r1 + r2*s2) * c1,
127                                        r2*c2,
128                                 -(r1 + r2*s2) * s1 );
129         }
130      }
131
132      // Create the vertical cross-section circles.
133      for (int j = 0; j < k; j++) // choose a rotation around the y-axis
134      {
135         for (int i = 0; i < n - 1; i++) // go around a cross section circle
136         {
137            addLineSegment(new LineSegment(new Vertex(v[i][j]),
138                                           new Vertex(v[i+1][j])));
139         }
140         // close the circle
141         addLineSegment(new LineSegment(new Vertex(v[n-1][j]),
142                                        new Vertex(v[0][j])));
143      }
144
145      // Create all the horizontal circles around the torus.
146      for (int i = 0; i < n; i++) //choose a rotation around the cross section
147      {
148         for (int j = 0; j < k - 1; j++) // go around a horizontal circle
149         {
150            addLineSegment(new LineSegment(new Vertex(v[i][j]),
151                                           new Vertex(v[i][j+1])));
152         }
153         // close the circle
154         addLineSegment(new LineSegment(new Vertex(v[i][k-1]),
155                                        new Vertex(v[i][0])));
156      }
157   }
158}//Torus