GameLib.D3.Vector4 = function(x, y, z, w) { this.x = 0; this.y = 0; this.z = 0; this.w = 0; if (x) { this.x = x; } if (y) { this.y = y; } if (z) { this.z = z; } if (w) { this.w = w; } }; GameLib.D3.Vector4.prototype.translate = function (v) { this.x += v.x; this.y += v.y; this.z += v.z; return this; }; GameLib.D3.Vector4.prototype.copy = function () { return new GameLib.D3.Vector4( this.x, this.y, this.z, this.w ); }; GameLib.D3.Vector4.prototype.multiply = function (s) { if (s instanceof GameLib.D3.Vector3) { this.x *= s.x; this.y *= s.y; this.z *= s.z; } else if (s instanceof GameLib.D3.Matrix4) { var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w * this.w; var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w * this.w; var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w * this.w; var w = s.rows[3].x * this.x + s.rows[3].y * this.y + s.rows[3].z * this.z + s.rows[3].w * this.w; this.x = x; this.y = y; this.z = z; this.w = w; } else { console.log("functionality not implemented - please do this"); throw new Error("not implemented"); } }; GameLib.D3.Vector4.prototype.normalize = function () { // note - leave w untouched var EPSILON = 0.000001; var v2 = this.x * this.x + this.y * this.y + this.z * this.z; if (v2 < EPSILON) { return this; //do nothing for zero vector } var invLength = 1 / Math.sqrt(v2); this.x *= invLength; this.y *= invLength; this.z *= invLength; return this; }; GameLib.D3.Vector4.prototype.subtract = function (v) { if (v instanceof GameLib.D3.Vector3) { this.x -= v.x; this.y -= v.y; this.z -= v.z; } if (v instanceof GameLib.D3.Vector4) { this.x -= v.x; this.y -= v.y; this.z -= v.z; this.w -= v.w; } return this; }; GameLib.D3.Vector4.Points = function () { this.vectors = []; }; GameLib.D3.Vector4.Points.prototype.add = function (vector) { if (vector instanceof GameLib.D3.Vector3) { vector = new GameLib.D3.Vector4( vector.x, vector.y, vector.z, 1 ) } if (!vector instanceof GameLib.D3.Vector4) { console.warn("Vector needs to be of type Vector4"); throw new Error("Vector needs to be of type Vector4"); } this.vectors.push(vector); return this; }; GameLib.D3.Vector4.Points.prototype.copy = function () { var vectors = []; for (var i = 0; i < this.vectors.length; i++) { vectors.push(this.vectors[i].copy()); } return vectors; }; GameLib.D3.Vector4.Points.prototype.maximizeXDistance = function (grain) { // console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); var multiplier = 0; var rotationMatrixY = new GameLib.D3.Matrix4().rotationMatrixY(grain); var totalRadians = 0; var backupVectors = this.copy(); var maxXDistance = 0; for (var i = 0; i < Math.PI * 2; i += grain) { multiplier++; for (var j = 0; j < this.vectors.length; j++) { this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]); } var distances = this.distances(); if (distances.x > maxXDistance) { maxXDistance = distances.x; totalRadians = multiplier * grain; } } this.vectors = backupVectors; // console.log("distance: " + maxXDistance + " radians : " + totalRadians); var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixY(totalRadians); for (var k = 0; k < this.vectors.length; k++) { this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]); } // console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2)); }; GameLib.D3.Vector4.Points.prototype.maximizeYDistance = function (grain) { // console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2)); var multiplier = 0; var rotationMatrixX = new GameLib.D3.Matrix4().rotationMatrixX(grain); var totalRadians = 0; var backupVectors = this.copy(); var maxYDistance = 0; for (var i = 0; i < Math.PI * 2; i += grain) { multiplier++; for (var j = 0; j < this.vectors.length; j++) { this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]); } var distances = this.distances(); if (distances.y > maxYDistance) { maxYDistance = distances.y; totalRadians = multiplier * grain; } } this.vectors = backupVectors; // console.log("distance: " + maxYDistance + " radians : " + totalRadians); var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixX(totalRadians); for (var k = 0; k < this.vectors.length; k++) { this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]); } // console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2)); }; GameLib.D3.Vector4.Points.prototype.lookAt = function (at, up) { var polyCenter = this.average(); console.log("poly center : " + JSON.stringify(polyCenter)); var lookAtMatrix = new GameLib.D3.Matrix4().lookAt(polyCenter, at, up); lookAtMatrix.rows[0] = new GameLib.D3.Vector4(1, 0, 0, 0); lookAtMatrix.rows[1] = new GameLib.D3.Vector4(0, 0, 1, 0); lookAtMatrix.rows[2] = new GameLib.D3.Vector4(0, 1, 0, 0); console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2)); for (var i = 0; i < this.vectors.length; i++) { console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i])); this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]); console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i])); } }; GameLib.D3.Vector4.Points.prototype.distances = function () { var minX = this.vectors[0].x; var minY = this.vectors[0].y; var minZ = this.vectors[0].z; var maxX = this.vectors[0].x; var maxY = this.vectors[0].y; var maxZ = this.vectors[0].z; for (var i = 0; i < this.vectors.length; i++) { if (this.vectors[i].x < minX) { minX = this.vectors[i].x; } if (this.vectors[i].y < minY) { minY = this.vectors[i].y; } if (this.vectors[i].z < minZ) { minZ = this.vectors[i].z; } if (this.vectors[i].x > maxX) { maxX = this.vectors[i].x; } if (this.vectors[i].y > maxY) { maxY = this.vectors[i].y; } if (this.vectors[i].z > maxZ) { maxZ = this.vectors[i].z; } } return new GameLib.D3.Vector3( Math.abs(maxX - minX), Math.abs(maxY - minY), Math.abs(maxY - minZ) ) }; GameLib.D3.Vector4.Points.prototype.average = function () { var averageX = 0; var averageY = 0; var averageZ = 0; for (var i = 0; i < this.vectors.length; i++) { averageX += this.vectors[i].x; averageY += this.vectors[i].y; averageZ += this.vectors[i].z; } return new GameLib.D3.Vector3( averageX / this.vectors.length, averageY / this.vectors.length, averageZ / this.vectors.length ); }; GameLib.D3.Vector4.Points.prototype.negative = function () { for (var i = 0; i < this.vectors.length; i++) { this.vectors[i].x *= -1; this.vectors[i].y *= -1; this.vectors[i].z *= -1; } return this; }; GameLib.D3.Vector4.Points.prototype.toOrigin = function () { var distanceFromOrigin = this.average().negative(); for (var i = 0; i < this.vectors.length; i++) { this.vectors[i].translate(distanceFromOrigin); } };