From dfcd2eef41b7f786722bac0931bf767eb2681ca0 Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Wed, 30 Nov 2016 14:57:58 +0100 Subject: [PATCH] Added stl support --- d3/model/basemodel.py | 2 +- d3/model/obj.py | 2 +- d3/model/stl.py | 99 +++++++++++++++++++++++++++++++++++++++++++ d3/model/tools.py | 5 +++ 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 d3/model/stl.py diff --git a/d3/model/basemodel.py b/d3/model/basemodel.py index fb0cfe2..820148f 100644 --- a/d3/model/basemodel.py +++ b/d3/model/basemodel.py @@ -117,7 +117,7 @@ class ModelParser: If the face has a different material than the current material, it will create a new mesh part and update the current material. """ - if self.current_part is None or face.material != self.current_part.material: + if self.current_part is None or (face.material != self.current_part.material and face.material is not None): self.current_part = MeshPart(self) self.current_part.material = face.material if face.material is not None else Material.DEFAULT_MATERIAL self.parts.append(self.current_part) diff --git a/d3/model/obj.py b/d3/model/obj.py index 69f3042..105c44b 100644 --- a/d3/model/obj.py +++ b/d3/model/obj.py @@ -122,7 +122,7 @@ class OBJExporter(Exporter): faces = sum(map(lambda x: x.faces, self.model.parts), []) for face in faces: - if face.material.name != current_material: + if face.material is not None and face.material.name != current_material: current_material = face.material.name string += "usemtl " + current_material + "\n" string += "f " diff --git a/d3/model/stl.py b/d3/model/stl.py new file mode 100644 index 0000000..3ffda52 --- /dev/null +++ b/d3/model/stl.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +from .basemodel import ModelParser, Exporter, Vertex, FaceVertex, Face +from .mesh import MeshPart + +import os.path + +def is_stl(filename): + return filename[-4:] == '.stl' + +class STLParser(ModelParser): + + def __init__(self): + super().__init__() + self.parsing_solid = False + self.parsing_face = False + self.parsing_loop = False + self.current_face = None + self.face_vertices = None + + def parse_line(self, string): + + if string == '': + return + + split = string.split() + + if split[0] == 'solid': + self.parsing_solid = True + return + + if split[0] == 'endsolid': + self.parsing_solid = False + return + + if self.parsing_solid: + + if split[0] == 'facet' and split[1] == 'normal': + self.parsing_face = True + self.face_vertices = [FaceVertex(), FaceVertex(), FaceVertex()] + self.current_face = Face(*self.face_vertices) + return + + if self.parsing_face: + + if split[0] == 'outer' and split[1] == 'loop': + self.parsing_loop = True + return + + if split[0] == 'endloop': + self.parsing_loop = False + return + + if self.parsing_loop: + + if split[0] == 'vertex': + current_vertex = Vertex().from_array(split[1:]) + self.add_vertex(current_vertex) + self.face_vertices[0].vertex = len(self.vertices) - 1 + self.face_vertices.pop(0) + return + + if split[0] == 'endfacet': + self.parsing_face = False + self.add_face(self.current_face) + self.current_face = None + self.face_vertices = None + + +class STLExporter(Exporter): + def __init__(self, model): + super().__init__(model) + + def __str__(self): + string = 'solid {}\n'.format(os.path.basename(self.model.path[:-4])) + + self.model.generate_face_normals() + + faces = sum(map(lambda x: x.faces, self.model.parts), []) + + for face in faces: + + n = self.model.normals[face.a.normal] + v1 = self.model.vertices[face.a.vertex] + v2 = self.model.vertices[face.b.vertex] + v3 = self.model.vertices[face.c.vertex] + + string += "facet normal {} {} {}\n".format(n.x, n.y, n.z) + + string += "\touter loop\n" + string += "\t\tvertex {} {} {}\n".format(v1.x, v1.y, v1.z) + string += "\t\tvertex {} {} {}\n".format(v2.x, v2.y, v2.z) + string += "\t\tvertex {} {} {}\n".format(v3.x, v3.y, v3.z) + + string += "\tendloop\n" + string += "endfacet\n" + + string += 'endsolid {}'.format(os.path.basename(self.model.path[:-4])) + return string diff --git a/d3/model/tools.py b/d3/model/tools.py index 9795faa..c4548e8 100644 --- a/d3/model/tools.py +++ b/d3/model/tools.py @@ -2,6 +2,7 @@ from .obj import is_obj, OBJParser, OBJExporter from .ply import is_ply, PLYParser, PLYExporter +from .stl import is_stl, STLParser, STLExporter from .basemodel import ModelParser, Exporter def load_model(path): @@ -11,6 +12,8 @@ def load_model(path): parser = OBJParser() elif is_ply(path): parser = PLYParser() + elif is_stl(path): + parser = STLParser() else: raise Exception("File format not supported") @@ -25,6 +28,8 @@ def export_model(model, path): exporter = OBJExporter(model) elif is_ply(path): exporter = PLYExporter(model) + elif is_stl(path): + exporter = STLExporter(model) else: raise Exception("File format not supported")