2022-04-14 09:25:36 +00:00
|
|
|
|
|
|
|
import java.io.*;
|
2022-04-12 10:08:58 +00:00
|
|
|
import algebra.*;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines a triangle based mesh.
|
|
|
|
* A mesh is constructed by interpretting the data given in an OFF file.
|
2022-04-14 09:25:36 +00:00
|
|
|
*
|
2022-04-12 10:08:58 +00:00
|
|
|
* @author smondet gg cdehais
|
|
|
|
*/
|
|
|
|
public class Mesh {
|
|
|
|
|
|
|
|
private Vector[] vertices;
|
2022-04-14 09:25:36 +00:00
|
|
|
private int[] faces;
|
2022-04-12 10:08:58 +00:00
|
|
|
private double[] colors;
|
|
|
|
private Vector3[] normals;
|
|
|
|
private double[] texCoords;
|
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
private static String nextLine(BufferedReader in) throws Exception {
|
|
|
|
String r = in.readLine();
|
2022-04-12 10:08:58 +00:00
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
while (r.matches("\\s*#.*")) {
|
|
|
|
r = in.readLine();
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a Mesh object by reading in an OFF file.
|
|
|
|
* Does not support non triangular meshes.
|
2022-04-14 09:25:36 +00:00
|
|
|
*
|
2022-04-12 10:08:58 +00:00
|
|
|
* @filename path to OFF file.
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public Mesh(String filename) throws Exception {
|
|
|
|
BufferedReader in = new BufferedReader(new FileReader(filename));
|
|
|
|
|
|
|
|
String r = nextLine(in);
|
|
|
|
if (!r.equals("OFF")) {
|
|
|
|
throw new IOException("Invalid OFF file !");
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = nextLine(in);
|
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
String[] sar = r.split("\\s+");
|
2022-04-12 10:08:58 +00:00
|
|
|
|
|
|
|
/* Parse object properties */
|
2022-04-14 09:25:36 +00:00
|
|
|
int verts_nb = new Integer(sar[0]).intValue();
|
|
|
|
int faces_nb = new Integer(sar[1]).intValue();
|
|
|
|
int edges_nb = new Integer(sar[2]).intValue();
|
2022-04-12 10:08:58 +00:00
|
|
|
|
|
|
|
/* Parse vertices and attributes */
|
|
|
|
vertices = new Vector[verts_nb];
|
2022-04-14 09:25:36 +00:00
|
|
|
faces = new int[3 * faces_nb];
|
|
|
|
colors = new double[3 * verts_nb];
|
|
|
|
for (int i = 0; i < verts_nb; i++) {
|
2022-04-12 10:08:58 +00:00
|
|
|
|
|
|
|
r = nextLine(in);
|
2022-04-14 09:25:36 +00:00
|
|
|
sar = r.split("\\s+");
|
2022-04-12 10:08:58 +00:00
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
vertices[i] = new Vector("v" + i, 4);
|
|
|
|
vertices[i].set(0, new Double(sar[0]).doubleValue());
|
|
|
|
vertices[i].set(1, new Double(sar[1]).doubleValue());
|
|
|
|
vertices[i].set(2, new Double(sar[2]).doubleValue());
|
|
|
|
vertices[i].set(3, 1.0);
|
2022-04-12 10:08:58 +00:00
|
|
|
colors[3 * i + 0] = new Double(sar[3]).doubleValue();
|
|
|
|
colors[3 * i + 1] = new Double(sar[4]).doubleValue();
|
|
|
|
colors[3 * i + 2] = new Double(sar[5]).doubleValue();
|
|
|
|
/* optionnal texture coordinates */
|
|
|
|
if (sar.length >= 8) {
|
|
|
|
if (texCoords == null) {
|
2022-04-14 09:25:36 +00:00
|
|
|
texCoords = new double[2 * verts_nb];
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
texCoords[2 * i] = new Double(sar[6]).doubleValue();
|
|
|
|
texCoords[2 * i + 1] = new Double(sar[7]).doubleValue();
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
|
2022-04-12 10:08:58 +00:00
|
|
|
/* Parse faces */
|
|
|
|
for (int i = 0; i < faces_nb; i++) {
|
|
|
|
|
|
|
|
r = nextLine(in);
|
|
|
|
sar = r.split("\\s+");
|
|
|
|
|
|
|
|
int en = new Integer(sar[0]).intValue();
|
|
|
|
if (en != 3) {
|
|
|
|
throw new IOException("Non-triangular meshes not supported.");
|
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
faces[3 * i + 0] = new Integer(sar[1]).intValue();
|
|
|
|
faces[3 * i + 1] = new Integer(sar[2]).intValue();
|
|
|
|
faces[3 * i + 2] = new Integer(sar[3]).intValue();
|
2022-04-12 10:08:58 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
in.close();
|
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
|
2022-04-12 10:08:58 +00:00
|
|
|
/**
|
|
|
|
* Gets the number of vertices in the mesh
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public int getNumVertices() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return vertices.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the number of faces in the mesh
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public int getNumFaces() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return faces.length / 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a normal for each vertex of the mesh
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
private Vector3[] computeNormals() {
|
|
|
|
|
2022-04-12 10:08:58 +00:00
|
|
|
normals = new Vector3[vertices.length];
|
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
// Compute per face normals and set the vertex normal to the average normals
|
|
|
|
// across faces
|
2022-04-12 10:08:58 +00:00
|
|
|
// to the vertex.
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < 3 * getNumFaces(); i += 3) {
|
|
|
|
|
2022-04-14 09:39:54 +00:00
|
|
|
Vector v0 = vertices[i + 0];
|
|
|
|
Vector v1 = vertices[i + 1];
|
|
|
|
Vector v2 = vertices[i + 2];
|
2022-04-12 10:08:58 +00:00
|
|
|
|
2022-04-14 09:39:54 +00:00
|
|
|
Vector3 bidule_gauche = new Vector3(v1);
|
|
|
|
bidule_gauche.subtract(v0);
|
|
|
|
|
|
|
|
Vector3 bidule_droite = new Vector3(v2);
|
|
|
|
bidule_droite.subtract(v0);
|
|
|
|
|
|
|
|
Vector3 n = bidule_gauche.cross(bidule_droite);
|
2022-04-12 10:08:58 +00:00
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
// ajoute la normale calculee a chq sommet de la face
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
Vector nj = normals[faces[i + j]];
|
2022-04-12 10:08:58 +00:00
|
|
|
|
|
|
|
if (nj == null) {
|
2022-04-14 09:25:36 +00:00
|
|
|
normals[faces[i + j]] = new Vector3(n);
|
|
|
|
normals[faces[i + j]].setName("n" + faces[i + j]);
|
2022-04-12 10:08:58 +00:00
|
|
|
} else {
|
2022-04-14 09:25:36 +00:00
|
|
|
nj.add(n);
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
}
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
} catch (InstantiationException e) {
|
|
|
|
System.out.println("Should not reach 1");
|
|
|
|
} catch (SizeMismatchException e) {
|
|
|
|
System.out.println("Should not reach 2");
|
|
|
|
}
|
2022-04-12 10:08:58 +00:00
|
|
|
|
2022-04-14 09:25:36 +00:00
|
|
|
// final round of normalization
|
|
|
|
for (int i = 0; i < normals.length; i++) {
|
2022-04-12 10:08:58 +00:00
|
|
|
if (normals[i] == null) { /* deals with orphans vertices */
|
2022-04-14 09:25:36 +00:00
|
|
|
normals[i] = new Vector3("n_orphan");
|
2022-04-12 10:08:58 +00:00
|
|
|
} else {
|
|
|
|
normals[i].normalize();
|
|
|
|
}
|
|
|
|
}
|
2022-04-14 09:25:36 +00:00
|
|
|
|
|
|
|
return normals;
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-04-14 09:25:36 +00:00
|
|
|
* Returns the vertices of the mesh
|
|
|
|
*/
|
|
|
|
public Vector[] getVertices() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return vertices;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the normals associated to the vertices.
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public Vector3[] getNormals() {
|
2022-04-12 10:08:58 +00:00
|
|
|
if (normals == null) {
|
2022-04-14 09:25:36 +00:00
|
|
|
normals = computeNormals();
|
2022-04-12 10:08:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return normals;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-04-14 09:25:36 +00:00
|
|
|
* Returns the faces of the mesh. The returned array contains 3*n integers, with
|
|
|
|
* n the number of faces.
|
2022-04-12 10:08:58 +00:00
|
|
|
* Each integer is an index into the array of Vector.
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public int[] getFaces() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return faces;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the colors of each vertex in the mesh.
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public double[] getColors() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return colors;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the texture coordinates of each vertex in the mesh.
|
|
|
|
*/
|
2022-04-14 09:25:36 +00:00
|
|
|
public double[] getTextureCoordinates() {
|
2022-04-12 10:08:58 +00:00
|
|
|
return texCoords;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|