001 package physics3d;
002
003 /**
004 * Torus represents a torus in 3 space
005 *
006 * @specfield radiusFromCenter : double // distance from center of torus to
007 * center of circles on the tube.
008 * @specfield radiusOfTube : double // radius of tube
009 * @specfield center : Vect3 // point of center of the torus
010 * @specfield orientation : Vect3 // unit vector perpendicular to plane formed
011 * by centers of circles along the tube.
012 * @specfield texture : String // texture of this object
013 */
014 public strictfp class Torus implements PhysicsShape {
015 private final double radiusFromCenter;
016
017 private final double radiusOfTube;
018
019 private final Vect3 center;
020
021 private final Vect3 orientation;
022
023 private final String texture;
024
025 // Rep. Invariant:
026 // radiusFromCenter >= 0.0
027 // radiusOfTube >= 0.0
028 // center != null
029 // orientation != null
030 // orientation.rho() = 1.0
031
032 // Abstraction Function:
033 // The torus with a center at 'centerPoint' and orientation 'orientation'
034 // a radius from center 'radiusFromCenter' and a radius of the tume
035 // 'radiusOfTube'
036
037 /**
038 * @requires <code>radiusFromCenter</code> >= 0, <code>radiusOfTube</code> >=
039 * 0, <code>center</code> != null, <code>orientation</code> !=
040 * null, <code>orientation.rho()</code> > 0, <code>texture</code> !=
041 * null
042 * @effects Creates a new circle with the specified size and location and
043 * orientation in 3D.
044 */
045 public Torus(Vect3 center, Vect3 orientation, double radiusFromCenter,
046 double radiusOfTube, String texture) {
047 this.center = center;
048 this.orientation = orientation.unitSize();
049 this.radiusFromCenter = radiusFromCenter;
050 this.radiusOfTube = radiusOfTube;
051 this.texture = texture;
052 // checkRep();
053 }
054
055 /**
056 * @requires <code>radiusFromCenter</code> >= 0, <code>radiusOfTube</code> >=
057 * 0, <code>center</code> != null, <code>orientation</code> !=
058 * null, <code>orientation.rho()</code> > 0
059 * @effects Creates a new circle with the specified size and location and
060 * orientation in 3D.
061 */
062 public Torus(Vect3 center, Vect3 orientation, double radiusFromCenter,
063 double radiusOfTube) {
064 this.center = center;
065 this.orientation = orientation.unitSize();
066 this.radiusFromCenter = radiusFromCenter;
067 this.radiusOfTube = radiusOfTube;
068 this.texture = null;
069 // checkRep();
070 }
071
072 @SuppressWarnings("unused")
073 private void checkRep() {
074 if (radiusFromCenter < 0.0 || radiusOfTube < 0.0 || center == null
075 || orientation == null || orientation.rho() != 1.0) {
076 throw new RuntimeException();
077 }
078 }
079
080 /**
081 * @return radius from center
082 */
083 public double getRadiusFromCenter() {
084 // checkRep();
085 return this.radiusFromCenter;
086 }
087
088 /**
089 * @return radius of tube
090 */
091 public double getRadiusOfTube() {
092 // checkRep();
093 return this.radiusOfTube;
094 }
095
096 /**
097 * @return center point
098 */
099 public Vect3 getCenterPoint() {
100 // checkRep();
101 return this.center;
102 }
103
104 /**
105 * @return a unit vector perpendicular to the plane containing the center of
106 * circles along the tube.
107 */
108 public Vect3 getOrientation() {
109 // checkRep();
110 return this.orientation;
111 }
112
113 /**
114 * @return texture of this object
115 */
116 public String getTexture() {
117 // checkRep();
118 return this.texture;
119 }
120
121 /**
122 * @requires p != null
123 * @return <code>Vect3.isAbout(this.minDistanceToObjectFromP(p),0)</code>
124 */
125 public boolean containsPoint(Vect3 p) {
126 // checkRep();
127 return Vect3.isAbout(this.minDistanceToObjectFromP(p), 0);
128 }
129
130 /**
131 * @requires <code>p</code> is not null and <code>p</code> is outside the
132 * torus
133 * @return the minimum distance between <code>p</code> and <code>this</code>
134 */
135 public double minDistanceToObjectFromP(Vect3 p) {
136 // checkRep();
137 // ring through center of torus
138 Vect3 circleCenter = this.getCenterPoint();
139 Vect3 circleOrientation = this.getOrientation();
140 double radius = this.getRadiusFromCenter();
141 // find oblique vector from center to p
142 Vect3 obliqueVect = p.minus(circleCenter);
143 // find perpendicular component of oblique vector
144 Vect3 perpToPlane = obliqueVect.projectOnToB(circleOrientation);
145 // find parallel component
146 Vect3 parallelToPlane = obliqueVect.minus(perpToPlane);
147 // if directly overhead
148 if (parallelToPlane.cross(this.orientation).isAbout(Vect3.ZERO)) {
149 double a = radius;
150 double b = p.minus(this.center).rho();
151 double c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
152 return Math.abs(c - this.radiusOfTube);
153 }
154 // if not directly overhead
155 parallelToPlane = parallelToPlane.unitSize();
156 parallelToPlane = parallelToPlane.times(radius);
157 Vect3 pointOnRing = parallelToPlane.plus(circleCenter);
158 return Math.abs(pointOnRing.minus(p).rho() - this.radiusOfTube);
159 }
160
161 /**
162 * @requires center != null, axis != null, axis.rho() > 0, tAngle != null.
163 * @return A Torus rotated about the line created by center and axis
164 * counterclockwise by an amount tAngle with same texture.
165 */
166 public Torus rotateAboutCwithAxisAandAngleT(Vect3 center, Vect3 axis,
167 Angle tAngle) {
168 return new Torus(this.getCenterPoint().minus(center).rotateAroundVect(axis,
169 tAngle).plus(center), this.getOrientation().rotateAroundVect(axis,
170 tAngle), this.getRadiusFromCenter(), this.getRadiusOfTube(),
171 this.texture);
172 }
173
174 /**
175 * @requires t != null
176 * @return A Torus translated by t with same texture
177 */
178 public Torus translateByT(Vect3 t) {
179 return new Torus(this.getCenterPoint().plus(t), this.getOrientation(), this
180 .getRadiusFromCenter(), this.getRadiusOfTube(), this.texture);
181 }
182
183 // Object methods --------------------------------------
184 //
185 // public boolean equals(Torus c) {
186 // if (c == null) return false;
187 // return (radiusFromCenter == c.radiusFromCenter) &&
188 // (radiusOfTube == c.radiusOfTube) &&
189 // (center.equals(c.center)) &&
190 // (Math.abs(orientation.dot(c.orientation)) == 1);
191 // }
192 //
193 // public boolean equals(Object o) {
194 // if (o instanceof Torus)
195 // return equals((Torus) o);
196 // else
197 // return false;
198 // }
199 //
200 public String toString() {
201 return "[Torus center=" + center + " orientation=" + orientation
202 + " radius from center=" + radiusFromCenter + " radius of tube="
203 + radiusOfTube + "]";
204 }
205 //
206 // public int hashCode() {
207 // return center.hashCode();
208 // }
209
210 public ShapeClassification getShapeClassification() {
211 return ShapeClassification.TORUS;
212 }
213 }