001 package physics3d; 002 003 /** 004 * LateralCylinder represents the lateral part of a cylinder in 3 space 005 * 006 * @specfield bottomCenter : Vect3 // center of bottom of cylinder 007 * @specfield topCenter : Vect3 // center of top of cylinder 008 * @specfield radius : double // radius of cylinder 009 * @specfield texture : String // texture of this object 010 */ 011 public strictfp class LateralCylinder implements PhysicsShape { 012 private final Vect3 bottomCenter; 013 014 private final Vect3 topCenter; 015 016 private final double radius; 017 018 private final Vect3 direction; 019 020 private final String texture; 021 022 // Rep. Invariant: 023 // bottomCenter != null && 024 // topCenter != null && 025 // !bottomCenter.equals(topCenter) 026 // radius >= 0.0 027 028 // Abstraction Function: 029 // The lateral surface of a cylinder with radius 'radius' and 030 // top and bottom centers 'topCenter' and 'bottomCenter' respectively 031 032 /** 033 * @requires radius >= 0 && bottomCenter != null && topCenter != null && 034 * !topCenter.equals(bottomCenter) && <code>texture</code> != null 035 * @effects creates a cylinder with radius 'radius' bottom center 036 * 'bottomCenter' and top center 'topCenter' 037 */ 038 039 public LateralCylinder(double radius, Vect3 bottomCenter, Vect3 topCenter, 040 String texture) { 041 this.radius = radius; 042 this.bottomCenter = bottomCenter; 043 this.topCenter = topCenter; 044 this.texture = texture; 045 direction = topCenter.minus(bottomCenter).unitSize(); 046 // checkrep(); 047 } 048 049 /** 050 * @requires radius >= 0 && bottomCenter != null && topCenter != null && 051 * !topCenter.equals(bottomCenter) 052 * @effects creates a cylinder with radius 'radius' bottom center 053 * 'bottomCenter' and top center 'topCenter' 054 */ 055 056 public LateralCylinder(double radius, Vect3 bottomCenter, Vect3 topCenter) { 057 this.radius = radius; 058 this.bottomCenter = bottomCenter; 059 this.topCenter = topCenter; 060 this.direction = topCenter.minus(bottomCenter).unitSize(); 061 this.texture = null; 062 // checkrep(); 063 } 064 065 @SuppressWarnings("unused") 066 private void checkRep() { 067 if (bottomCenter == null || topCenter == null || radius < 0.0 068 || bottomCenter.equals(topCenter)) { 069 throw new RuntimeException(); 070 } 071 } 072 073 /** 074 * @return the radius of this lateral cylinder 075 */ 076 public double getRadius() { 077 // checkRep(); 078 return this.radius; 079 } 080 081 /** 082 * @return the top center of this lateral cylinder 083 */ 084 public Vect3 getTopCenter() { 085 // checkRep(); 086 return this.topCenter; 087 } 088 089 /** 090 * @return the bottom center of this lateral cylinder 091 */ 092 public Vect3 getBottomCenter() { 093 // checkRep(); 094 return this.bottomCenter; 095 } 096 097 /** 098 * @return the unit vector pointing from the bottom center to the top center 099 */ 100 public Vect3 getDirection() { 101 // checkRep(); 102 return this.direction; 103 } 104 105 /** 106 * @return texture of this object 107 */ 108 public String getTexture() { 109 // checkRep(); 110 return this.texture; 111 } 112 113 /** 114 * @requires p != null 115 * @return true if 116 * <code>Vect3.isAbout(this.minDistanceToObjectFromP(p),0)</code>, 117 * false otherwise 118 */ 119 public boolean containsPoint(Vect3 p) { 120 // checkRep(); 121 if (Vect3.isAbout(this.minDistanceToObjectFromP(p), 0)) { 122 return true; 123 } 124 return false; 125 } 126 127 /** 128 * @requires <code>p</code> is not null 129 * @return the minimum distance between <code>p</code> and <code>this</code> 130 */ 131 public double minDistanceToObjectFromP(Vect3 p) { 132 // checkRep(); 133 Vect3 dir = this.getDirection(); 134 Vect3 point = this.getBottomCenter(); 135 Line line = new Line(dir, point); 136 // find point on line closest to our point 137 Vect3 pointOnNormal = line.getPointOnLineClosestToP(p); 138 139 Vect3 v = p.minus(pointOnNormal); 140 double d1 = topCenter.minus(pointOnNormal).rho(); 141 double d2 = bottomCenter.minus(pointOnNormal).rho(); 142 double d3 = bottomCenter.minus(topCenter).rho(); 143 if (Vect3.isAbout(d1 + d2, d3)) { 144 return Math.abs(v.rho() - this.radius); 145 } 146 Vect3 minCenter = topCenter; 147 if (d2 < d1) { 148 minCenter = bottomCenter; 149 } 150 151 if (minCenter.minus(p).cross(this.direction).isAbout(Vect3.ZERO)) { 152 153 double a = minCenter.minus(p).rho(); 154 double b = radius; 155 return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); 156 } 157 158 Vect3 obliqueVect = p.minus(minCenter); 159 Vect3 parallelVect = obliqueVect.projectOnToB(direction); 160 Vect3 perpVect = obliqueVect.minus(parallelVect); 161 Vect3 p1 = minCenter.plus(perpVect.unitSize().times(radius)); 162 return Math.abs(p.minus(p1).rho()); 163 } 164 165 /** 166 * @requires center != null, axis != null, axis.rho() > 0, tAngle != null. 167 * @return A LateralCylinder rotated about the line created by center and axis 168 * counterclockwise by an amount tAngle with same texture. 169 */ 170 public LateralCylinder rotateAboutCwithAxisAandAngleT(Vect3 center, 171 Vect3 axis, Angle tAngle) { 172 return new LateralCylinder(this.getRadius(), this.getBottomCenter().minus( 173 center).rotateAroundVect(axis, tAngle).plus(center), this 174 .getTopCenter().minus(center).rotateAroundVect(axis, tAngle).plus( 175 center), this.texture); 176 } 177 178 /** 179 * @requires t != null 180 * @return A LateralCylinder translated by t with same texture 181 */ 182 public LateralCylinder translateByT(Vect3 t) { 183 return new LateralCylinder(this.getRadius(), 184 this.getBottomCenter().plus(t), this.getTopCenter().plus(t), 185 this.texture); 186 } 187 188 // Object methods -------------------------------------- 189 // public boolean equals(LateralCylinder c) { 190 // if (c == null) return false; 191 // if(c.radius != radius){ 192 // return false; 193 // } 194 // if(bottomCenter.equals(c.bottomCenter)) 195 // { 196 // if(topCenter.equals(c.topCenter)) 197 // { 198 // return true; 199 // } 200 // } 201 // else if(bottomCenter.equals(c.topCenter)) 202 // { 203 // if(topCenter.equals(c.bottomCenter)) 204 // { 205 // return true; 206 // } 207 // } 208 // return false; 209 // } 210 // 211 // public boolean equals(Object o) { 212 // if (o instanceof LateralCylinder) 213 // return equals((LateralCylinder) o); 214 // else 215 // return false; 216 // } 217 // 218 public String toString() { 219 return "[Lateral Cylinder bottom center=" + bottomCenter + " top center=" 220 + topCenter + " radius=" + radius + "]"; 221 } 222 // 223 // public int hashCode() { 224 // return bottomCenter.hashCode() + topCenter.hashCode(); 225 // } 226 227 public ShapeClassification getShapeClassification() { 228 return ShapeClassification.LATERAL_CYLINDER; 229 } 230 }