import os import sys import PIL import struct from ..basemodel import ModelParser, TextModelParser, Exporter, Vertex, Face, FaceVertex, TexCoord, Material class UnkownTypeError(Exception): def __init__(self, message): self.message = message def is_ply(filename): return filename[-4:] == '.ply' # List won't work with this function def _ply_type_size(type): if type == 'char' or type == 'uchar': return 1 elif type == 'short' or type == 'ushort': return 2 elif type == 'int' or type == 'uint': return 4 elif type == 'float': return 4 elif type == 'double': return 8 else: raise UnkownTypeError('Type ' + type + ' is unknown') def ply_type_size(type): split = type.split() if len(split) == 1: return [_ply_type_size(type)] else: if split[0] != 'list': print('You have multiple types but it\'s not a list...', file=sys.stderr) sys.exit(-1) else: return list(map(lambda a: _ply_type_size(a), split[1:])) def bytes_to_element(type, bytes, byteorder = 'little'): if type == 'char': return ord(struct.unpack(' len(bytes): self.previous_bytes = bytes[beginning_byte_index:] # self.current_byte -= len(self.previous_bytes) return if len(size) == 1: size = size[0] current_property_bytes = bytes[current_byte_index:current_byte_index+size] property_values.append(bytes_to_element(property[1], current_property_bytes)) current_byte_index += size # self.current_byte += size elif len(size) == 2: types = property[1].split()[1:] current_property_bytes = bytes[current_byte_index:current_byte_index+size[0]] number_of_elements = bytes_to_element(types[0], current_property_bytes) current_byte_index += size[0] # self.current_byte += size[0] property_values.append([]) # Parse list for i in range(number_of_elements): if current_byte_index + size[1] > len(bytes): self.previous_bytes = bytes[beginning_byte_index:] # self.current_byte -= len(self.previous_bytes) return current_property_bytes = bytes[current_byte_index:current_byte_index+size[1]] property_values[-1].append(bytes_to_element(types[1], current_property_bytes)) current_byte_index += size[1] # self.current_byte += size[1] else: print('I have not idea what this means', file=sys.stderr) # Add element if self.current_element.name == 'vertex': self.parent.add_vertex(Vertex().from_array(property_values)) elif self.current_element.name == 'face': # Create texture coords for i in range(0,6,2): tex_coord = TexCoord(*property_values[1][i:i+2]) self.parent.add_tex_coord(tex_coord) face = Face(\ FaceVertex(property_values[0][0], len(self.parent.tex_coords)-3), \ FaceVertex(property_values[0][1], len(self.parent.tex_coords)-2), \ FaceVertex(property_values[0][2], len(self.parent.tex_coords)-1)) face.material = self.parent.materials[property_values[2]] self.parent.add_face(face) pass self.counter += 1 if self.counter == self.current_element.number: self.next_element() def next_element(self): self.counter = 0 self.element_index += 1 if self.element_index < len(self.parent.elements): self.current_element = self.parent.elements[self.element_index] class PLYBigEndianContentParser(PLYLittleEndianContentParser): def __init__(self, parent): super().__init__(self, parent) def parse_bytes(self, bytes): # Reverse bytes, and then super().parse_bytes(self, bytes) class PLYExporter(Exporter): def __init__(self, model): super().__init__(model) def __str__(self): faces = sum([part.faces for part in self.model.parts], []) # Header string = "ply\nformat ascii 1.0\ncomment Automatically gnerated by model-converter\n" # Types : vertices string += "element vertex " + str(len(self.model.vertices)) +"\n" string += "property float x\nproperty float y\nproperty float z\n" # Types : faces string += "element face " + str(len(faces)) + "\n" string += "property list uint8 int32 vertex_indices\n" # End header string += "end_header\n" # Content of the model for vertex in self.model.vertices: string += str(vertex.x) + " " + str(vertex.y) + " " + str(vertex.z) + "\n" for face in faces: string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + "\n" return string