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