001    package physics3d;
002    
003    public strictfp class Plane {
004      private final Vect3 normal;
005    
006      private final Vect3 pointOnPlane;
007    
008      // Rep. Invariant:
009      // normal != null &&
010      // pointOnPlane != null &&
011      // normal.rho() == 1.0
012    
013      // Abstraction Function:
014      // The plane with a normal 'normal' and a point on the plane
015      // 'pointOnPlane'
016    
017      /**
018       * @requires <code>normal</code> is not null, <code>pointOnPlane</code> is
019       *           not null, <code>normal.rho()</code> != 0,
020       * @effects constructs a plane
021       */
022      public Plane(Vect3 normal, Vect3 pointOnPlane) {
023        this.normal = normal.unitSize();
024        this.pointOnPlane = pointOnPlane;
025      }
026    
027      /**
028       * @requires p1, p2, p3 != null p1, p2, p3 are distinct and not collinear
029       * @return the plane that contains these three points
030       */
031      public static Plane MakePlaneFromThreePoints(Vect3 p1, Vect3 p2, Vect3 p3) {
032        return new Plane(p2.minus(p1).cross(p3.minus(p1)), p1);
033      }
034    
035      @SuppressWarnings("unused")
036      private void checkRep() {
037        if (normal == null || pointOnPlane == null || normal.rho() != 1.0) {
038          throw new RuntimeException();
039        }
040      }
041    
042      /**
043       * @requires pointOffPlane != null
044       * @return the point p such that p is on this and
045       *         p.minus(pointOffPlane).cross(normal) = <code>Vect3.Zero </code>
046       */
047      public Vect3 perpVectorFromPlaneToPoint(Vect3 pointOffPlane) {
048        // checkRep();
049        Vect3 obliqueVector = pointOffPlane.minus(pointOnPlane);
050        return obliqueVector.projectOnToB(normal);
051      }
052    
053      /**
054       * @requires pointOffPlane != null
055       * @return the perpendicular distance from pointOffPlane to <code>this</code>
056       */
057      public double perpDistanceFromPlaneToPoint(Vect3 pointOffPlane) {
058        // checkRep();
059        Vect3 obliqueVector = pointOffPlane.minus(pointOnPlane);
060        return obliqueVector.projectOnToB(normal).rho();
061      }
062    
063      /**
064       * @return a unit vector perpendicular to <code>this</code>
065       */
066      public Vect3 getNormal() {
067        // checkRep();
068        return normal;
069      }
070    
071      /**
072       * @return a point on the plane
073       */
074      public Vect3 getPointOnPlane() {
075        // checkRep();
076        return pointOnPlane;
077      }
078    
079      /**
080       * @requires v != null
081       * @return true if the distance from v to this is less than
082       *         GameConstants.TOLERANCE
083       */
084      public boolean containsPoint(Vect3 v) {
085        return Vect3.isAbout(perpDistanceFromPlaneToPoint(v), 0);
086      }
087    }