Source code for plugins.export

#
##
##  This file is part of pyFormex 1.0.7  (Mon Jun 17 12:20:39 CEST 2019)
##  pyFormex is a tool for generating, manipulating and transforming 3D
##  geometrical models by sequences of mathematical operations.
##  Home page: http://pyformex.org
##  Project page:  http://savannah.nongnu.org/projects/pyformex/
##  Copyright 2004-2019 (C) Benedict Verhegghe (benedict.verhegghe@ugent.be)
##  Distributed under the GNU General Public License version 3 or later.
##
##  This program is free software: you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  This program is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with this program.  If not, see http://www.gnu.org/licenses/.
##

"""Classes and functions for exporting geometry in various formats.

- ObjFile: wavefront .obj format
- PlyFile: .ply format

These classes do not necessarily implement all features of the specified
formats. They are usually fitted to export and sometimes imports simple
mesh format geometries.
"""
from __future__ import absolute_import, division, print_function

import sys
import pyformex as pf
import numpy as np


[docs]class ObjFile(object): """Export a mesh in OBJ format. This class exports a mesh in Wavefront OBJ format (see `<https://en.wikipedia.org/wiki/Wavefront_.obj_file>`_). The class instantiator takes a filename as parameter. Normally, the file name should end in '.obj', but anything is accepted. The ObjFile instance is a context manager. Usage:: with ObjFile(PATH_TO_OBJFILE) as fil: fil.write(MESH) """ def __init__(self, filename): self.filename = filename def __enter__(self): self.fil = open(self.filename, 'w') self.fil.write("# .obj file written by %s\n" % pf.Version()) return self def __exit__(self, *args): self.fil.write('# End\n') self.fil.close()
[docs] def write(self, mesh, name=None): """Write a mesh to file in .obj format. `mesh` is a Mesh instance or another object having compatible coords and elems attributes. `name` is an optional name of the object. """ if name is not None: self.fil.write("o %s\n" % str(name)) for v in mesh.coords: self.fil.write("v %s %s %s\n" % tuple(v)) # element code: p(oint), l(ine) or f(ace) nplex = mesh.elems.shape[1] code = {1: 'p', 2: 'l'}.get(nplex, 'f') s = code+(' %s'*nplex)+'\n' for e in mesh.elems+1: # .obj format starts at 1 self.fil.write(s % tuple(e))
[docs]class PlyFile(object): """Export a mesh in PLY format. This class exports a mesh in Polygon File Format (see `<https://en.wikipedia.org/wiki/PLY_(file_format)>`_). The class instantiator takes a filename as parameter. Normally, the file name should end in '.ply', but anything is accepted. The PlyFile instance is a context manager. Usage:: with PlyFile(PATH_TO_PLYFILE) as fil: fil.write(MESH) """ def __init__(self, filename, binary=False): self.filename = filename self.binary = binary def __enter__(self): self.fil = open(self.filename, 'w') if self.binary: fmt = 'binary_' + sys.byteorder + '_endian 1.0' else: fmt = 'ascii 1.0' self.fil.write("""ply format %s comment .ply file written by %s """ %(fmt, pf.Version())) return self def __exit__(self, *args): self.fil.close()
[docs] def write(self, mesh, comment=None, color_table= None): """Write a mesh to file in .ply format. Parameters: - `mesh`: a Mesh instance or another object having compatible coords and elems attributes. - `comment`: an extra comment written into the output file. - `color_table`: BEWARE! THIS IS SUBJECT TO CHANGES! color_table currentlyis a list of 2 elements. The first entry is a string that can assume 2 values 'v' or 'e', to indicate whether the color table represents nodal or element values. The second entry is an array of shape (ncoords,3) or (nelems,3) of interger RGB values between 0 and 255. If RGB values are passed as float between 0 and 1, they will be converted to RGB integers. """ if comment is not None: self.fil.write("comment %s\n" % str(comment)) coords = mesh.coords.astype('object') els = mesh.elems.astype('object') nplex = mesh.elems.shape[1] el_type = {2: 'edge'}.get(nplex, 'face') vcol_type = ecol_type = '' if el_type == 'edge': eprop_type = """property int vertex1 property int vertex2 """ else: eprop_type = """property list uchar int vertex_indices """ if color_table is not None: color_location, color_table = color_table if not(np.issubclass_(color_table.dtype.type, np.integer)): color_table = (255*color_table.clip(0., 1.)).astype(np.integer) # float can be added but they are implemented yet cprop_type = {}.get(color_table.dtype, 'uchar') cprop_types = """property %s red property %s green property %s blue """%((cprop_type,)*3) if color_location == 'v': vcol_type = cprop_types coords = np.hstack([coords, color_table]) if color_location == 'e': ecol_type = cprop_types els = np.hstack([els, color_table]) self.fil.write("""element vertex %s property float x property float y property float z %selement %s %s %s%send_header """ % (mesh.ncoords(), vcol_type, el_type, mesh.nelems(), eprop_type, ecol_type)) for v in coords: self.fil.write('%s '*coords.shape[1]%tuple(v) +'\n') code = {2: ''}.get(nplex, '%s '%nplex) s = code+('%s '*els.shape[1])+'\n' for e in els: self.fil.write(s % tuple(e))
# End