Few fixes

This commit is contained in:
Thomas Forgione 2020-12-09 15:31:45 +01:00
parent cd98c29e00
commit e865bf4c6d
3 changed files with 99 additions and 40 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

17
README.md Normal file
View File

@ -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]
```

121
obja.py
View File

@ -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()