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