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 }