MathWorx

Object3D.js

Summary

This file defines the class for a 3D Object, which is essentially a set of vertices and an ordered list of faces.


Class Summary
Object3D Object3D is a class that defines 3D objects to displayed by Scene3D objects.

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

//Things to think about: shading (rectangles instead of lines, doable), sorting

/**@fileoverview This file defines the class for a 3D Object, which is essentially a set of vertices and an ordered list of faces. */

dependencies = ['point3D', 'Plane'];
require(dependencies);

/**Creates a new 3D Object.
@class Object3D is a class that defines 3D objects to displayed by Scene3D objects.
A 3D object as defined is a face-vertex mesh.  A face is an ordered list of 
vertex indices in the vertex array which are to be connected by lines.  This model allows lines
as well as surfaces and solids to all be Object3D objects.
@requires point3D
@requires Plane
@param {Array} vertices an array of point3D objects that are the vertices of the object
@param {Array} faces (Optional) the array (2-dimensional!) of faces (i.e. [[0,1,2],[2,3,4]] defines two faces connecting 
vertices[0],vertices[1] and vertices[2], etc.)
@constructor */
function Object3D(vertices, faces) {

	/**The list of vertices of the 3D object. An array of point3D's.  Order is EXTREMELY important.
	@type Array */
	this.vertices = new Array();
	/**The list of vertices after being projected onto a plane.  Might still be point3D objects, simply on a Plane now.
	@type Array */
	this.vertices2D = new Array();
	/**The array of faces.  A face is an ordered list of vertices to connect with line segments.  [0, 4, 2, 3] for example, connects vertices 0, 4, 2, 3 and 0.  This will be a 2-D array.
	@type Array */
	this.faces = new Array();

	if(vertices instanceof Array) {
		this.vertices = vertices;
	}
	if(faces instanceof Array) {
		this.faces = faces;
	}

}

Object3D.prototype = {

	/**Adds a face to the 3D Object.
	@param {Array} vertices the orderered list of vertex indices that should be connected to form a face
	@return {Object3D} this object, with updated faces array */
	addFace: function(vertices) {
		if(vertices instanceof Array) {
			this.faces[this.faces.length] = vertices;
		}
		return this;
	},

	/**Perform a function on each vertex of an object.  Does not change faces.
	@param {Function} func the function to perform on each vertex 
	@return {Object3D} this Object3D, with the specified function performed on each vertex */
	toEach: function(func) {
		var i = 0; 
		while(i < this.vertices.length) {
			this.vertices[i] = func(this.vertices[i]);
			i++;
		}
		return this;
	},

	/**Moves 3D object into new coordinates defined by 3D scene's camera.  Updates this.vertices2D with coordinates in new system.
	@param {Object} camera the 3D Scene camera object through which to view this object; MUST have properties theta and phi
	@return {Object3D} this object, with updated vertices2D array */
	viewIn: function(camera) {
		var i = 0;
		var T = new AffineTransform(3).newCoordinates(camera.theta, camera.phi);
		while(i < this.vertices.length) {
			this.vertices2D[i] = T.applyTo(this.vertices[i]);
			i++;
		}
		return this;
	},

	/**After object has been moved to Scene coordinates (via viewIn method), this performs a perspective transformation to put the object in the XY plane.
	@param {Number} focus the focal distance (between camera and origin)
	@return {Object3D} this object, with vertices2D now being an array of point2D's */
	to2D: function(focus) {
		var focus = focus;
		var i = 0;
		while(i < this.vertices2D.length) {
			var point = this.vertices2D[i];
			var mult = focus / (focus - point.x);
			this.vertices2D[i] = new point2D(mult*point.y, mult*point.z);
	 		i++;
		}
		return this;
	},

	/**Draws the given object.  REQUIRES jQuery SVG.  This function automatically "flips" the object because SVG's canvas goes from the bottom down.  Make sure to adjust viewBox appropriately.
	@param {Object} svg the jQuery SVG object
	@param {Object} settings the settings to apply to each line of the wireframe; settings.transform = 'scale(1,-1)' automatically applied */
	draw: function(svg, settings) {
		settings.transform = 'scale(1,-1)';
		for(i = 0; i < this.faces.length; i++) {
			for(j = 0; j < this.faces[i].length - 1; j++) {
				var p1 = this.vertices2D[this.faces[i][j]];
				var p2 = this.vertices2D[this.faces[i][j+1]];
				svg.line(null, p1.x, p1.y, p2.x, p2.y, settings);
			}
			var p1 = this.vertices2D[this.faces[i][j]];
			var p2 = this.vertices2D[this.faces[i][0]];
			svg.line(null, p1.x, p1.y, p2.x, p2.y, settings);
		}
	},

	/**Translate an object by tx, ty, and tz.  Performs the translation on every vertex.
	@param {Number} tx the x translation
	@param {Number} ty the y translation
	@param {Number} tz the z translation
	@return {Object3D} this Object3D, translated (NOT a new copy of the object) */
	translate: function(tx, ty, tz) {
		return this.toEach(function(x) { return x.translate(tx, ty, tz); });
	},

	/**Generates a string representation of the Object (a face-vertex mesh).
	@return {String} a list of all the vertices and faces */
	toString: function() {
		return "vertices: \n" + this.vertices.join("\n") + "\n\nfaces: \n" + this.faces.join("\n");
	}

} //end Object3D prototype

/**Creates a new Cube as an Object3D object.
@param {Number} side the length of each side of the cube.
@param {point3D} center (optional) the center point of the cube, default is (0,0,0)
@return {Object3D} a new Object3D representing the specified cube */
Object3D.Cube = function(side, center) {
	if(!center) {
		var center = point3D.zero;
	}
	var cx = center.x, cy = center.y, cz = center.z;
	var length = side/2;
	var verts = new Array(), faces = new Array();
	verts[0] = new point3D(length, -length, length);
	verts[1] = new point3D(length, length, length);
	verts[2] = new point3D(-length, length, length);
	verts[3] = new point3D(-length, -length, length);
	verts[4] = new point3D(+length, -length, -length);
	verts[5] = new point3D(+length, length, -length);
	verts[6] = new point3D(-length, length, -length);
	verts[7] = new point3D(-length, -length, -length);
	faces[0] = [0, 4, 5, 1];
	faces[1] = [1, 5, 6, 2];
	faces[2] = [2, 6, 7, 3];
	faces[3] = [3, 7, 4, 0];
	faces[4] = [4, 5, 6, 7];
	faces[5] = [0, 1, 2, 3];
	return (new Object3D(verts, faces)).translate(cx, cy, cz);
}

/**Creates a new Sphere as an Object3D object.
@param {Number} rad the radius of the sphere
@param {point3D} cent (optional) the center of the sphere; defaults to (0,0,0)
@param {Number} segments (optional) the number of segments to divide the sphere into; directly relates to the number of vertices/faces 
@return {Object3D} a new Object3D that defines a sphere as outlined above */
Object3D.Sphere = function(rad, cent, segments) {

	var o = new Object3D([], []);
	var segs = 5;
	if(segments) {
		segs = segments / 2;
	}
	var radius = rad;
	var center = point3D.zero;
	if(center instanceof point3D) {
		center = cent;
	}
	var segmentRad = Math.PI / 2 / (segs + 1);
	var numSeparators = 4*segs + 4;

	for(i = -segs; i <= segs; i++) {
		var r = radius * Math.cos(segmentRad*i);
		var y = radius * Math.sin(segmentRad*i);
		for(j = 0; j < numSeparators; j++) {
			var z = -1*r*Math.sin(segmentRad*j);
			var x = r * Math.cos(segmentRad*j);
			o.vertices.push(new point3D(x, y, z));
		}
	}

	//2*segs diff y values, numSeparators points of each y value
	for(i = 0; i < 2*segs; i++) {
		var face = new Array();
		for(j = 0; j < numSeparators; j++) {
			var i1 = j + i*numSeparators;
			var i2 = (j+1) + i*numSeparators;
			var i3 = (j+1) + (i+1)*numSeparators;
			var i4 = j + (i+1)*numSeparators;
			if(j == numSeparators-1) {
				i2 = i*numSeparators;
				i3 = (i+1)*numSeparators;
			}
			face = [i1, i2, i3, i4];
			o.faces.push(face);
		}
	}

	//add the two "endpoints" and triangles to them
	o.vertices.push(new point3D(0, -radius, 0));
	o.vertices.push(new point3D(0, radius, 0));
	for(i = 0; i < numSeparators - 1; i++) {
		var i1 = i, i2 = i+1;
		var i3 = o.vertices.length - 2;
		o.faces.push([i1, i2, i3]);
		var i1 = i+(2*segs*numSeparators), i2 = (i+1)+(2*segs*numSeparators);
		var i3 = o.vertices.length - 1;
		o.faces.push([i1, i2, i3]);
	}

	if(!(cent.equalTo(point3D.zero))) {
		o.translate(cent.x, cent.y, cent.z);
	}

	return o;

}

/**Creates a new line as an Object3D
@param {Array} points an Array of point2D or point3D objects that define the line <strong>sequentially</strong>
@return {Object3D} a line through each of the points in the points array as an Object3D */
Object3D.Line = function(points) {
	if(points instanceof Array) {
		var pts = new Array();
		var segments = new Array();
		for(var i = 0; i < points.length; i++) {
			if(points[i] instanceof point2D) {
				points[i] = points[i].make3D();
			}
			if(!(points[i] instanceof point3D)) {
				return false;
			}
			pts[i] = points[i];
			if(i != points.length - 1) {
				segments[i] = [i, i+1];
			}
		}
		return new Object3D(pts, segments);
	}
	return null;
}

/**Creates a new 3D Object that is the x-axis.
@param {Number} min the minimum x value
@param {Number} max the maximum x value
@return {Object3D} the x-axis between min and max */
Object3D.Xaxis = function(min, max) {
	return Object3D.Line([Line.x.pointAt(min), Line.x.pointAt(max)]);
}

/**Creates a new 3D Object that is the y-axis.
@param {Number} min the minimum y value
@param {Number} max the maximum y value
@return {Object3D} the y-axis between min and max */
Object3D.Yaxis = function(min, max) {
	return Object3D.Line([Line.y.pointAt(min), Line.y.pointAt(max)]);
}

/**Creates a new 3D Object that is the z-axis.
@param {Number} min the minimum z value
@param {Number} max the maximum z value
@return {Object3D} the z-axis between min and max */
Object3D.Zaxis = function(min, max) {
	return Object3D.Line([Line.z.pointAt(min), Line.z.pointAt(max)]);
}

MathWorx

Documentation generated by JSDoc on Mon Aug 11 13:58:31 2008