3d-interface/server/geo/Mesh.js

549 lines
14 KiB
JavaScript
Raw Normal View History

2015-06-22 17:12:24 +02:00
/**
* Reprensents an elementary mesh (only one material)
2015-06-22 17:12:24 +02:00
* @constructor
2015-06-29 15:41:18 +02:00
* @memberOf geo
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Mesh = function() {
/**
* @type {geo.Vertex[]}
* @description All the vertices of the mesh
* @deprecated Prefer the use of {@link geo.MeshContainer}.vertices
*/
2015-06-11 10:12:50 +02:00
this.vertices = [];
/**
* @type {geo.Face[]}
* @description All the faces of the mesh
*/
2015-06-11 10:12:50 +02:00
this.faces = [];
/**
* @type {geo.TexCoord[]}
* @description All the textures coordinates of the mesh
*/
2015-06-15 17:04:19 +02:00
this.texCoords = [];
/**
* @type {geo.Normal[]}
* @description All the normals of the mesh
*/
this.normals = [];
/**
* @deprecated You should use your own counter
*/
this.faceIndex = 0;
/**
* @type {String}
* @description Name of the material of the current mesh
*/
2015-06-15 17:04:19 +02:00
this.material = null;
/**
* @deprecated You should use your own attributes
*/
this.started = false;
/**
* @deprecated You should use your own attributes
*/
this.finished = false;
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Checks if there are normals in the mesh
* @returns {Boolean} true if there are normals in the mesh, false otherwise
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.hasNormals = function() {
return this.normals.length > 0;
};
2015-06-22 17:12:24 +02:00
/**
* Checks if there are texture coordinates in the mesh
* @returns {Boolean} true if there are texture coordinates in the mesh, false otherwise
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.hasTexCoords = function() {
return this.texCoords.length > 0;
};
2015-06-22 17:12:24 +02:00
/**
* Adds a vertex to a mesh
2015-06-29 15:41:18 +02:00
* @param {geo.Vertex|String} A Vertex object or its string representation
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.addVertex = function(vertex) {
2015-06-11 10:12:50 +02:00
2015-06-29 15:41:18 +02:00
if (vertex instanceof geo.Vertex) {
2015-06-15 17:04:19 +02:00
this.vertices.push(vertex);
} else if (typeof vertex === 'string' || vertex instanceof String) {
2015-06-29 15:41:18 +02:00
this.vertices.push(new geo.Vertex(vertex));
2015-06-11 11:05:05 +02:00
} else {
2015-06-29 15:41:18 +02:00
console.error("Can only add vertex from geo.Vertex or string");
2015-06-15 17:04:19 +02:00
return;
2015-06-11 11:05:05 +02:00
}
2015-06-15 17:04:19 +02:00
return this.vertices[this.vertices.length - 1];
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Adds a face to a mesh
2015-06-29 15:41:18 +02:00
* @param {geo.Face|String} A Face object or its string representation
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.addFaces = function(face) {
2015-06-15 17:04:19 +02:00
var faces;
2015-06-11 11:05:05 +02:00
2015-06-29 15:41:18 +02:00
if (face instanceof geo.Face) {
2015-06-15 17:04:19 +02:00
this.faces.push(face);
} else if (typeof face === 'string' || face instanceof String) {
faces = geo.parseFace(face);
2015-06-15 17:04:19 +02:00
this.faces = this.faces.concat(faces);
} else {
2015-06-29 15:41:18 +02:00
console.error("Can only add face from geo.Face or string");
2015-06-15 17:04:19 +02:00
return;
2015-06-11 11:05:05 +02:00
}
2015-06-15 17:04:19 +02:00
if (faces === undefined) {
return this.faces[this.faces.length - 1];
} else {
return faces;
2015-06-11 11:05:05 +02:00
}
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Adds a texture coordinate to a mesh
2015-06-29 15:41:18 +02:00
* @param {geo.TexCoord|String} A TexCoord object or its string representation
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.addTexCoord = function(texCoord) {
if (texCoord instanceof geo.TexCoord) {
2015-06-15 17:04:19 +02:00
this.texCoords.push(texCoord);
} else if (typeof texCoord === 'string' || texCoord instanceof String) {
2015-06-29 15:41:18 +02:00
this.texCoords.push(new geo.TexCoord(texCoord));
2015-06-15 17:04:19 +02:00
} else {
2015-06-29 15:41:18 +02:00
console.error("Can only add texCoord from geo.TexCoord or string");
2015-06-15 17:04:19 +02:00
return;
2015-06-11 11:05:05 +02:00
}
2015-06-15 17:04:19 +02:00
return this.texCoords[this.texCoords.length - 1];
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Adds a normal to a mesh
2015-06-29 15:41:18 +02:00
* @param {geo.Normal|String} A Normal object or its string representation
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.addNormal = function(normal) {
if (normal instanceof geo.Normal) {
this.normals.push(normal);
} else if (typeof normal === 'string' || normal instanceof String) {
2015-06-29 15:41:18 +02:00
this.normals.push(new geo.Normal(normal));
} else {
2015-06-29 15:41:18 +02:00
console.error("Can only add normal from geo.Normal of string");
return;
}
return this.normals[this.normals.length - 1];
};
/**
* @deprecated
*/
2015-06-29 15:41:18 +02:00
geo.Mesh.prototype.isFinished = function() {
2015-06-18 14:46:09 +02:00
return this.faceIndex === this.faces.length;
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Represent a 3D vertex
* @constructor
* @param {String} A string like in the .obj file (e.g. 'v 1.1 0.2 3.4')
2015-06-29 15:41:18 +02:00
* @memberOf geo
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Vertex = function() {
2015-06-11 10:12:50 +02:00
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
2015-06-22 17:12:24 +02:00
/**
* x coordinate of the vertex
* @type {Number}
*/
2015-06-11 10:12:50 +02:00
this.x = parseFloat(split[1]);
2015-06-22 17:12:24 +02:00
/**
* y coordinate of the vertex
* @type {Number}
*/
2015-06-11 10:12:50 +02:00
this.y = parseFloat(split[2]);
2015-06-22 17:12:24 +02:00
/**
* z coordinate of the vertex
* @type {Number}
*/
2015-06-11 10:12:50 +02:00
this.z = parseFloat(split[3]);
}
2015-06-22 17:12:24 +02:00
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
2015-06-11 10:12:50 +02:00
this.sent = false;
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Gives a list representation of the vertex
* @returns {Array} An array representing the vertex
*
* @example
2015-06-29 15:41:18 +02:00
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
2015-06-22 17:12:24 +02:00
* vertex.index = 5;
* console.log(vertex.toList()); // Prints ['v', 5, 3.5, 3.6, 3.7]
*/
2015-06-29 15:41:18 +02:00
geo.Vertex.prototype.toList = function() {
2015-06-15 17:04:19 +02:00
return ['v', this.index, this.x, this.y, this.z];
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Gives a string representation of the vertex
* @returns {string} A string representing the vertex
*
* @example
2015-06-29 15:41:18 +02:00
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
2015-06-22 17:17:56 +02:00
* console.log(vertex.toString()); // Prints v 3.5 3.6 3.7
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Vertex.prototype.toString = function() {
2015-06-11 10:12:50 +02:00
return 'v ' + this.x + ' ' + this.y + ' ' + this.z;
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Represent a 3D normal
* @constructor
2015-06-29 15:41:18 +02:00
* @memberOf geo
* @augments geo.Vertex
* @param {String} A string like in the .obj file (e.g. 'vn 1.1 2.2 3.3')
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Normal = function() {
geo.Vertex.apply(this, arguments);
};
2015-06-29 15:41:18 +02:00
geo.Normal.prototype = Object.create(geo.Vertex.prototype);
geo.Normal.prototype.constructor = geo.Normal;
2015-06-22 17:12:24 +02:00
/**
* Gives a list representation of the normal
* @returns {Array} An array representing the normal
*
* @example
2015-06-29 15:41:18 +02:00
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
2015-06-22 17:12:24 +02:00
* normal.index = 5;
* console.log(normal.toList()); // Prints ['vn', 5, 3.5, 3.6, 3.7]
*/
2015-06-29 15:41:18 +02:00
geo.Normal.prototype.toList = function() {
var superObject = geo.Vertex.prototype.toList.call(this);
superObject[0] = 'vn';
return superObject;
};
2015-06-22 17:12:24 +02:00
/**
* Gives a string representation of the normal
* @returns {string} A string representing the normal
*
* @example
2015-06-29 15:41:18 +02:00
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
2015-06-22 17:17:56 +02:00
* console.log(normal.toString()); // Prints vn 3.5 3.6 3.7
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Normal.prototype.toString = function() {
var superObject = geo.Vertex.prototype.toString.call(this);
superObject.replace('v', 'vn');
return superObject;
};
2015-06-15 17:04:19 +02:00
2015-06-22 17:12:24 +02:00
/**
* Represent a texture coordinate element
* @constructor
2015-06-29 15:41:18 +02:00
* @memberOf geo
* @param {String} a string like in the .obj file (e.g. 'vt 0.5 0.5')
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.TexCoord = function() {
2015-06-11 10:12:50 +02:00
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
2015-06-22 17:12:24 +02:00
/**
* x coordinate of the texture
* @type {Number}
*/
2015-06-11 11:05:05 +02:00
this.x = parseFloat(split[1]);
2015-06-22 17:12:24 +02:00
/**
* y coordinate of the texture
* @type {Number}
*/
2015-06-11 11:05:05 +02:00
this.y = parseFloat(split[2]);
}
2015-06-22 17:12:24 +02:00
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
2015-06-11 11:05:05 +02:00
this.sent = false;
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Gives a list representation of the texture coordinate
* @returns {Array} An array representing the texture coordinate
*
* @example
2015-06-29 15:41:18 +02:00
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
2015-06-22 17:12:24 +02:00
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['vt', 5, 3.5, 3.6]
*/
2015-06-29 15:41:18 +02:00
geo.TexCoord.prototype.toList = function() {
2015-06-15 17:04:19 +02:00
return ['vt', this.index, this.x, this.y];
};
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* Gives a string representation of the texture coordinate
* @returns {string} A string representing the texture coordinate
*
* @example
2015-06-29 15:41:18 +02:00
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
2015-06-22 17:17:56 +02:00
* console.log(texCoord.toString()); // Prints vt 3.5 3.6
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.TexCoord.prototype.toString = function() {
return 'vt ' + this.x + ' ' + this.y;
};
2015-06-11 11:05:05 +02:00
2015-06-15 17:04:19 +02:00
2015-06-22 17:12:24 +02:00
/**
* Represents a face. Only triangles are supported. For quadrangular polygons, see {@link geo.parseFace}
2015-06-22 17:12:24 +02:00
* @constructor
2015-06-29 15:41:18 +02:00
* @memberOf geo
* @param {String} A string like in a .obj file (e.g. 'f 1/1/1 2/2/2 3/3/3' or 'f 1 2 3').
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Face = function() {
var split;
2015-06-11 11:05:05 +02:00
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
if (arguments[0].indexOf('/') === -1) {
// No / : easy win : "f 1 2 3" or "f 1 2 3 4"
split = arguments[0].replace(/\s+/g, ' ').split(' ');
2015-06-11 11:05:05 +02:00
this.a = parseInt(split[1]) - 1;
this.b = parseInt(split[2]) - 1;
this.c = parseInt(split[3]) - 1;
2015-06-11 11:05:05 +02:00
} else {
// There might be textures coords
split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
2015-06-11 11:05:05 +02:00
// Split elements
var split1 = split[1].split('/');
var split2 = split[2].split('/');
var split3 = split[3].split('/');
var vIndex = 0;
var tIndex = 1;
var nIndex = 2;
2015-06-22 17:12:24 +02:00
/**
* index of the first vertex of the face
* @type {Number}
*/
this.a = parseInt(split1[vIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the second vertex of the face
* @type {Number}
*/
this.b = parseInt(split2[vIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the third vertex of the face
* @type {Number}
*/
this.c = parseInt(split3[vIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the texture coordinate of the first vertex of the face
* @type {Number}
*/
this.aTexture = parseInt(split1[tIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the texture coordinate of the second vertex of the face
* @type {Number}
*/
this.bTexture = parseInt(split2[tIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the texture coordinate of the third vertex of the face
* @type {Number}
*/
this.cTexture = parseInt(split3[tIndex]) - 1;
2015-06-11 11:05:05 +02:00
2015-06-22 17:12:24 +02:00
/**
* index of the normal of the first vertex of the face
* @type {Number}
*/
this.aNormal = parseInt(split1[nIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the normal of the second vertex of the face
* @type {Number}
*/
this.bNormal = parseInt(split2[nIndex]) - 1;
2015-06-22 17:12:24 +02:00
/**
* index of the normal of the third vertex of the face
* @type {Number}
*/
this.cNormal = parseInt(split3[nIndex]) - 1;
2015-06-11 11:05:05 +02:00
}
2015-06-11 10:12:50 +02:00
}
2015-06-22 17:12:24 +02:00
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
2015-06-11 10:12:50 +02:00
this.sent = false;
2015-06-15 17:04:19 +02:00
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Parse a face line and returns an array of faces
*
2015-06-22 17:19:37 +02:00
* @private
2015-06-22 17:12:24 +02:00
* @param {String} a string representing a face
* @returns {Face[]} a single 3-vertices face or two 3-vertices face if it was
* a 4-vertices face
*/
geo.parseFace = function(arg) {
var split = arg.trim().split(' ');
2015-06-15 17:04:19 +02:00
var ret = [];
// Face3
if (split.length >= 4) {
2015-06-29 15:41:18 +02:00
ret.push(new geo.Face(arg));
2015-06-15 17:04:19 +02:00
}
// Face3 == 2 * Face3
2015-06-15 17:04:19 +02:00
if (split.length >= 5) {
2015-06-29 15:41:18 +02:00
ret.push(new geo.Face(
2015-06-15 17:04:19 +02:00
[
split[0],
split[1],
split[3],
split[4]
].join(' ')
));
}
return ret;
};
2015-06-15 17:04:19 +02:00
2015-06-22 17:12:24 +02:00
/**
* Returns the max index of the vertices of the face
* @returns {Number} the max index of the vertices
*/
2015-06-29 15:41:18 +02:00
geo.Face.prototype.max = function() {
2015-06-15 10:01:33 +02:00
if (this.d !== undefined) {
2015-06-11 10:12:50 +02:00
return Math.max(this.a, this.b, this.c, this.d);
} else {
return Math.max(this.a, this.b, this.c);
}
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Returns the max index of the texture coordinates of the face
* @returns {Number} the max index of the texture coordinates
*/
2015-06-29 15:41:18 +02:00
geo.Face.prototype.maxTexture = function() {
if (this.dTexture) {
return Math.max(this.aTexture, this.bTexture, this.cTexture, this.dTexture);
} else {
return Math.max(this.aTexture, this.bTexture, this.cTexture);
}
};
2015-06-22 17:12:24 +02:00
/**
* Gives a list representation of the face
* @returns {Array} An array representing the texture coordinate
* <ol start=0>
* <li>'f'</li>
* <li>the index of the face</li>
* <li>a list containing the indices of the vertex of the face</li>
* <li>a list containing the indices of the texture coordinates</li>
* <li>a list containing the indices of the normals</li>
* </ol>
*
* @example
2015-06-29 15:41:18 +02:00
* var face = new geo.Face('f 1/2/3 4/5/6 7/8/9');
2015-06-22 17:12:24 +02:00
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['f', 5, [1,4,7], [2,5,8], [3,6,9]]
*/
2015-06-29 15:41:18 +02:00
geo.Face.prototype.toList = function() {
var l = ['f', this.index, this.meshIndex,
[this.a, this.b, this.c ],
isNaN(this.aTexture) ? [] : [this.aTexture, this.bTexture, this.cTexture],
isNaN(this.aNormal ) ? [] : [this.aNormal, this.bNormal, this.cNormal ]
];
2015-06-15 17:04:19 +02:00
// if (this.d !== undefined)
// l.push(this.d);
// if (this.aTexture !== undefined) {
// l.push(this.aTexture);
// l.push(this.bTexture);
// l.push(this.cTexture);
// }
2015-06-15 17:04:19 +02:00
// if (this.dTexture !== undefined)
// l.push(this.dTexture);
2015-06-11 10:12:50 +02:00
return l;
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:17:56 +02:00
/**
* Gives a string representation of the face
* @returns {string} A string representing the face
*
* @example
2015-06-29 15:41:18 +02:00
* var face = new geo.Face('f 3 5 6');
2015-06-22 17:17:56 +02:00
* console.log(face.toString()); // Prints f 3 5 6
*/
2015-06-29 15:41:18 +02:00
geo.Face.prototype.toString = function() {
2015-06-15 10:01:33 +02:00
return 'f ' + this.a + ' ' + this.b + ' ' + this.c + (this.d !== undefined ? ' ' + this.d : '');
};
2015-06-11 10:12:50 +02:00
2015-06-22 17:12:24 +02:00
/**
* Represents a material name
* @constructor
* @param {string} line the string representing the material
2015-06-29 15:41:18 +02:00
* @memberOf geo
2015-06-22 17:12:24 +02:00
*/
2015-06-29 15:41:18 +02:00
geo.Material = function() {
var split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
2015-06-22 17:12:24 +02:00
/**
* The name of the material
* @type {string}
*/
this.name = split[1];
};
2015-06-22 17:12:24 +02:00
/**
* Gives a string representation of the material
* @returns {string} obj representation of usemtl
*/
2015-06-29 15:41:18 +02:00
geo.Material.prototype.toString = function() {
return 'usemtl ' + this.name;
};
2015-06-22 17:12:24 +02:00
/**
* Gives a list representation of the material
* @returns {array} an array representing the material
* @example
2015-06-29 15:41:18 +02:00
* var material = new geo.Material('usemtl MyMaterial');
2015-06-22 17:12:24 +02:00
* console.log(material.toList()); // Logs ['u', 'MyMaterial']
*/
2015-06-29 15:41:18 +02:00
geo.Material.prototype.toList = function() {
return ['u', this.name];
};