From e865bf4c6d9227f858f80f72c81802b4fee93ab0 Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Wed, 9 Dec 2020 15:31:45 +0100 Subject: [PATCH] Few fixes --- .gitignore | 1 + README.md | 17 ++++++++ obja.py | 121 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf6dd0b --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# OBJ Parser + +### Exemple + +```python +import obja +model = obja.parse_file("path_to_model.obj") + +# model.vertices est la liste des sommets du modèle (coordonnées x, y, et z) +# model.faces est la liste des faces du modèle (indices des sommets a, b, et c) + +# Exemple d'accès au sommets des faces du modele. +for face in model.faces: + v1 = model.vertices[face.a] + v2 = model.vertices[face.b] + v3 = model.vertices[face.c] +``` diff --git a/obja.py b/obja.py index 62a6f7e..9af4985 100755 --- a/obja.py +++ b/obja.py @@ -6,50 +6,78 @@ import sys obja model for python. """ -class Vertex: +class Vector: """ - The class that holds the x, y, and z coordinates of a vertex. + The class that holds the x, y, and z coordinates of a vector. """ - def __init__(self, array): + def __init__(self, x, y, z): """ - Initializes a vertex from an array of string representing floats. + Initializes a vector from values. """ - self.set(array) + self.x = x + self.y = y + self.z = z + + def from_array(array): + """ + Creates a vector from an array of string representing floats. + """ + return Vector(0, 0, 0).set(array) def set(self, array): """ - Sets a vertex from an array of string representing floats. + Sets a vector from an array of string representing floats. """ self.x = float(array[0]) self.y = float(array[1]) self.z = float(array[2]) + return self def translate(self, array): """ - Translates a vertex from an array of string representing floats. + Translates a vector from an array of string representing floats. """ self.x += float(array[0]) self.y += float(array[1]) self.z += float(array[2]) + def __str__(self): + return "({}, {}, {})".format(self.x, self.y, self.z) + + def __add__(self, other): + return Vector(self.x + other.x, self.y + other.y, self.z + other.z) + + def __sub__(self, other): + return Vector(self.x - other.x, self.y - other.y, self.z - other.z) + + def __mul__(self, other): + return Vector(self.x * other, self.y * other, self.z * other) + + def __truediv__(self, other): + return Vector(self.x / other, self.y / other, self.z / other) + + def __repr__(self): + return str(self) + class Face: """ The class that holds a, b, and c, the indices of the vertices of the face. """ def __init__(self, array): """ - Initializes a face from an array of strings representing vertex indices (starting at 1) + Initializes a face from an array of strings representing vector indices (starting at 1) """ self.set(array) self.visible = True def set(self, array): """ - Sets a face from an array of strings representing vertex indices (starting at 1) + Sets a face from an array of strings representing vector indices (starting at 1) """ self.a = int(array[0].split('/')[0]) - 1 self.b = int(array[1].split('/')[0]) - 1 self.c = int(array[2].split('/')[0]) - 1 + return self def test(self, vertices, line = "unknown"): """ @@ -62,6 +90,12 @@ class Face: if self.c >= len(vertices): raise VertexError(self.c + 1, line) + def __str__(self): + return "Face({}, {}, {})".format(self.a, self.b, self.c) + + def __repr__(self): + return str(self) + class VertexError(Exception): """ An operation references a vertex that does not exist. @@ -78,7 +112,7 @@ class VertexError(Exception): """ Pretty prints the error. """ - return f'There is no vertex {self.index} (line {self.line})' + return f'There is no vector {self.index} (line {self.line})' class FaceError(Exception): """ @@ -100,11 +134,11 @@ class FaceError(Exception): class FaceVertexError(Exception): """ - An operation references a face vertex that does not exist. + An operation references a face vector that does not exist. """ def __init__(self, index, line): """ - Creates the error from index of the referenced face vertex and the line where the error occured. + Creates the error from index of the referenced face vector and the line where the error occured. """ self.line = line self.index = index @@ -114,7 +148,7 @@ class FaceVertexError(Exception): """ Pretty prints the error. """ - return f'Face has no vertex {self.index} (line {self.line})' + return f'Face has no vector {self.index} (line {self.line})' class UnknownInstruction(Exception): """ @@ -146,18 +180,22 @@ class Model: self.faces = [] self.line = 0 - def get_vertex(self, string): + def get_vector_from_string(self, string): """ - Gets a vertex from a string representing the index of the vertex, starting at 1. + Gets a vector from a string representing the index of the vector, starting at 1. + + To get the vector from its index, simply use model.vertices[i]. """ index = int(string) - 1 if index >= len(self.vertices): raise FaceError(index + 1, self.line) return self.vertices[index] - def get_face(self, string): + def get_face_from_string(self, string): """ Gets a face from a string representing the index of the face, starting at 1. + + To get the face from its index, simply use model.faces[i]. """ index = int(string) - 1 if index >= len(self.faces): @@ -184,18 +222,19 @@ class Model: return if split[0] == "v": - self.vertices.append(Vertex(split[1:])) + self.vertices.append(Vector.from_array(split[1:])) elif split[0] == "ev": - self.get_vertex(split[1]).set(split[2:]) + self.get_vector_from_string(split[1]).set(split[2:]) elif split[0] == "tv": - self.get_vertex(split[1]).translate(split[2:]) + self.get_vector_from_string(split[1]).translate(split[2:]) - elif split[0] == "f": - face = Face(split[1:]) - face.test(self.vertices, self.line) - self.faces.append(face) + elif split[0] == "f" or split[0] == "tf": + for i in range(1, len(split) - 2): + face = Face(split[i:i+3]) + face.test(self.vertices, self.line) + self.faces.append(face) elif split[0] == "ts": for i in range(1, len(split) - 2): @@ -206,30 +245,24 @@ class Model: face.test(self.vertices, self.line) self.faces.append(face) - elif split[0] == "tf": - for i in range(1, len(split) - 2): - face = Face(split[i:i+3]) - face.test(self.vertices, self.line) - self.faces.append(face) - elif split[0] == "ef": - self.get_face(split[1]).set(split[2:]) + self.get_face_from_string(split[1]).set(split[2:]) elif split[0] == "efv": - face = self.get_face(split[1]) - vertex = int(split[2]) + face = self.get_face_from_string(split[1]) + vector = int(split[2]) new_index = int(split[3]) - 1 - if vertex == 1: + if vector == 1: face.a = new_index - elif vertex == 2: + elif vector == 2: face.b = new_index - elif vertex == 3: + elif vector == 3: face.c = new_index else: - raise FaceVertexError(vertex, self.line) + raise FaceVertexError(vector, self.line) elif split[0] == "df": - self.get_face(split[1]).visible = False + self.get_face_from_string(split[1]).visible = False elif split[0] == "#": return @@ -238,14 +271,22 @@ class Model: return # raise UnknownInstruction(split[0], self.line) +def parse_file(path): + """ + Parses a file and returns the model. + """ + model = Model() + model.parse_file(path) + return model + def main(): if len(sys.argv) == 1: print("obja needs a path to an obja file") return - model = Model() - model.parse_file(sys.argv[1]) - + model = parse_file(sys.argv[1]) + print(model.vertices) + print(model.faces) if __name__ == "__main__": main()