MathWorx

Plane.js

Summary

This file defines the Plane class and its methods.


Class Summary
Plane The Plane class is a very useful definition of a plane.

/**MathWorx Copyright (c) 2008 Shane Steinert-Threlkeld
Dual-licensed under the MIT and GNU GPL Licenses.
For more information, see LICENSE file */

/**@fileoverview This file defines the Plane class and its methods. */

dependencies = ['Line'];
require(dependencies);

/**The constructor function for a new Plane.
@class The Plane class is a very useful definition of a plane.  A Plane object consists of a base point and a normal vector, thus implicitly representing the infinitude of a plane.
@param {point3D} base the base point of the plane; if a Plane object, will create a duplicate of the plane
@param {point3D} v1 (can also be a 3D Vector) the normal vector if only one vector is supplied
@param {point3D} v2 (Optional) (can also be a 3D Vector) if supplied, assume that the three parameters are base point and two vectors, so the normal becomes (v1 cross v2)
@requires Line
@constructor */
function Plane(base, v1, v2) {

	if(base instanceof Plane) {
		return new Plane(base.base, base.norm);
	}

	/**The "base" point of the plane. 
	@type point3D */
	this.base = new point3D(0,0,0);
	/**The normal vector of the plane, which wholly defines the Plane along with the base point.
	@type point3D */
	this.norm = new point3D(0,0,0);

	if(!(base.dimension() && v1.dimension())) {
		return null;
	}
	if(base.n > 3 || v1.n > 3) {
		return null;
	}
	
	if(base.n == 2) {
		//handles point2D or Vector object
		this.base = new point3D(base.get(1), base.get(2), 0);
	} else {
		if(base instanceof point3D) {
			this.base = new point3D(base);
		} else if(base instanceof Vector) {
			this.base = new point3D(base.get(1), base.get(2), base.get(3));
		}
	}

	if(v2) {
		this.norm = v1.cross(v2).normalize().toPoint();
	} else {
		this.norm = v1.normalize().toPoint();
	}

}

Plane.prototype = {

	/**Tests whether two planes are equal.
	@param {Plane} plane the plane to test for equality
	@return {Boolean} true if planes are equal, false otherwise */
	equalTo: function(plane) {
		return (this.contains(plane.base) && this.isParallel(plane));
	},

	/**Translates a plane by dx, dy and dz (normal does not change, only the base)
	@param {Number} dx the x translation
	@param {Number} dy the y translation
	@param {Number} dz the z translation
	@return {Plane} the translated plane */
	translate: function(dx, dy, dz) {
		var base = new point3D(this.base.x + dx, this.base.y + dy, this.base.z + dz);
		return new Plane(base, this.norm);
	},

	/**Tests to see if the plane is parallel to a given Plane or Line.
	@param {Object} obj the plane or line to check to see if parallel
	@return {Boolean} true if parallel, false otherwise */
	isParallel: function(obj) {
		if(obj instanceof Plane) {
			var theta = this.norm.angleBetween(obj.norm);
			return (Math.abs(theta) < Zero || Math.abs(theta - Math.PI) < Zero);
		} else if(obj instanceof Line) {
			return this.norm.isPerpendicular(obj.direction);
		} else {
			return null;
		}
	},

	/**Tests to see if two planes are perpendicular to each other.
	@return {Boolean} true iff planes are perpendicular, false otherwise */
	isPerpendicular: function(plane) {
		return (Math.abs(this.norm.dot(plane.norm)) < Zero);
	},

	/**Gets the distance of a plane, line or point from the plane.
	@param {Object} obj the plane, line, or point from which to find the distance
	@return {Number} the distance between the plane and obj */
	distanceFrom: function(obj) {
		if(this.inersects(obj) || this.contains(obj)) {
			return 0;
		}
		if(obj.base) {
			return Math.abs(this.norm.dot(this.base.subtract(obj.base)));
		} else {
			return Math.abs(this.norm.dot(this.base.subtract(obj)));
		}
	},

	/**Tests if a line or point lies in the plane.
	@param {Object} obj the line or point to test
	@return {Boolean} true if plane contains line or point (also true if obj is an equivalent plane) */
	contains: function(obj) {
		if(obj.norm) {
			return this.equalTo(obj);
		}
		if(obj.direction) {
			return (this.contains(obj.base) && this.contains(obj.base.add(obj.direction)));
		} else { //obj is a point
			return (this.distanceFrom(obj) < Zero);
		}
	},

	/**Tests to see if a line or plane intersects with this plane.
	@param {Object} obj the line or plane to test
	@return {Boolean} true iff an intersection exists, false otherwise */
	intersects: function(obj) {
		if(typeof(obj.direction) == 'undefined' && typeof(obj.base) == 'undefined') {
			return null;
		}
		return (!this.isParallel(obj));
	},

	/**Gets the intersection of a plane with a given Line or Plane.
	@param {Object} obj the Line or Plane with which to find the intersection
	@return {Object} the intersection of this and obj: point3D (aka Vector) if obj is a Line, a Line if obj is a Plane */
	intersection: function(obj) {
		if(!this.intersects(obj)) {
			return null;
		}
		if(obj instanceof Line) { //obj is a line
			var mult = this.norm.dot(this.base.subtract(obj.base)) / this.norm.dot(obj.direction);
			var vec = obj.base.add(obj.direction.multiplyBy(mult));
			return new point3D(vec.get(1),vec.get(2),vec.get(3));
		}
		if(obj instanceof Plane) {
			var direction = this.norm.cross(obj.norm).normalize();
			var B = this.base, N = this.norm, O = obj.norm, C = obj.base;
			//To find a base point, find one coordinate that has a value of 0
			//somewhere on the intersection, and remember which one we picked
			var solver = Matrix.zero(2,2), i = 0;
			while(solver.isSingular()) {
				i++;
				solver = new Matrix([
					[ N.get((i%3)+1), N.get((i+1)%3 +1) ],
					[ O.get((i%3)+1), O.get((i+1)%3 +1) ]
				]);
			}
			//Then we solve the simultaneous equations in the remaining dimensions
			var inverse = solver.invert();
			var x = N.dot(B), y = O.dot(C);
			var intersection = [
				inverse.get(1,1)*x + inverse.get(1,2)*y,
				inverse.get(2,1)*x + inverse.get(2,2)*y
			];
			var base = new Array();
			for(var j = 1; j <=3; j++) {
				//This formula picks the right element from intersection by
				//cycling depending on which element we set to 0 above
				base.push((i == j) ? 0 : intersection[(j + (5-i)%3)%3]);
			}
			return new Line(new Vector(base), direction);
		}
	},

	/**Finds the point in the plane closest to the given point.
	@param {point3D} point (can also be a 3D Vector) the point to which to find the closest point in the plane
	@return {Object} point3D or Vector (depending on type of point above) that is the closest point on the plane to point */
	pointClosestTo: function(point) {
		if(!(point instanceof point3D || point instanceof Vector)) {
			return null;
		}
		var P = point, B = this.base, N = this.norm;
		var dot = B.subtract(P).dot(N);
		var vec = P.add(N.muliplyBy(dot));
		if(point instanceof point3D) {
			return new point3D(vec.get(1), vec.get(2), vec.get(3));
		} else if(point instanceof Vector) {
			return new Vector(vec);
		}
	},

	/**Rotates a plane through deg degrees about an arbitrary line.
	@param {Number} deg the number of degrees (in radians) to rotate the plane
	@param {Line} the Line about which to rotate the plane
	@return {Plane} a new Plane that is the old rotated deg about line */
	rotate: function(deg, line) {
		var C = line.pointClosestTo(this.base), B = this.base, N = this.norm;
		var P = B.subtract(C);
		var newB = C.add(P.rotate(deg, line));
		var newN = N.rotate(deg, line);
		return new Plane(newB, newN);
	},

	/**Returns a string representation of the Plane.
	@return {String} the string version of the plane */
	toString: function() {
		return "base: " + this.base + ", normal: " + this.norm;
	}

} //end Plane prototype

/**The XY-plane.  Base = (0,0,0), Direction = Vector.k
@type Plane */
Plane.XY = new Plane(point3D.zero, Vector.k);
/**Same as Plane.XY
@type Plane */
Plane.YX = Plane.XY;
/**The YZ-plane.  Base = (0,0,0), Direction = Vector.i
@type Plane */
Plane.YZ = new Plane(point3D.zero, Vector.i);
/**Same as Plane.YZ
@type Plane */
Plane.ZY = Plane.YZ;
/**The ZX-plane.  Base = (0,0,0), Direction = Vector.j
@type Plane */
Plane.ZX = new Plane(point3D.zero, Vector.j);
/**Same as Plane.ZX
@type Plane */
Plane.XZ = Plane.ZX;

MathWorx

Documentation generated by JSDoc on Tue Aug 5 10:22:22 2008