<filename>trimesh/exchange/off.py<gh_stars>1-10
import re
import numpy as np

from .. import util


def load_off(file_obj, **kwargs):
    """
    Load an OFF file into the kwargs for a Trimesh constructor


    Parameters
    ----------
    file_obj : file object
      Contains an OFF file

    Returns
    ----------
    loaded : dict
      kwargs for Trimesh constructor
    """
    text = file_obj.read()
    # will magically survive weird encoding sometimes
    text = util.decode_text(text).lstrip()
    # split the first key
    _, header, raw = re.split('(COFF|OFF)', text, 1)
    if header.upper() not in ['OFF', 'COFF']:
        raise NameError(
            'Not an OFF file! Header was: `{}`'.format(header))

    # split into lines and remove whitespace
    splits = [i.strip() for i in str.splitlines(str(raw))]
    # remove empty lines and comments
    splits = [i for i in splits if len(i) > 0 and i[0] != '#']

    # the first non-comment line should be the counts
    header = np.array(splits[0].split(), dtype=np.int64)
    vertex_count, face_count = header[:2]

    vertices = np.array([
        i.split()[:3] for i in
        splits[1: vertex_count + 1]],
        dtype=np.float64)

    # will fail if incorrect number of vertices loaded
    vertices = vertices.reshape((vertex_count, 3))

    # get lines with face data
    faces = [i.split() for i in
             splits[vertex_count + 1:vertex_count + face_count + 1]]
    # the first value is count
    faces = [line[1:int(line[0]) + 1] for line in faces]

    # convert faces to numpy array
    # will fail on mixed garbage as FSM intended -_-
    faces = np.array(faces, dtype=np.int64)

    # save data as kwargs for a trimesh.Trimesh
    kwargs = {'vertices': vertices,
              'faces': faces}

    return kwargs


def export_off(mesh, digits=10):
    """
    Export a mesh as an OFF file, a simple text format

    Parameters
    -----------
    mesh : trimesh.Trimesh
      Geometry to export
    digits : int
      Number of digits to include on floats

    Returns
    -----------
    export : str
      OFF format output
    """
    # make sure specified digits is an int
    digits = int(digits)
    # prepend a 3 (face count) to each face
    faces_stacked = np.column_stack((np.ones(len(mesh.faces)) * 3,
                                     mesh.faces)).astype(np.int64)
    export = 'OFF\n'
    # the header is vertex count, face count, another number
    export += str(len(mesh.vertices)) + ' ' + str(len(mesh.faces)) + ' 0\n'
    export += util.array_to_string(
        mesh.vertices, col_delim=' ', row_delim='\n', digits=digits) + '\n'
    export += util.array_to_string(
        faces_stacked, col_delim=' ', row_delim='\n')
    return export


_off_loaders = {'off': load_off}
_off_exporters = {'off': export_off}

<filename>trimesh/exchange/off.py<gh_stars>1-10
import re
import numpy as np

from .. import util


def load_off(file_obj, **kwargs):
    """
    Load an OFF file into the kwargs for a Trimesh constructor


    Parameters
    ----------
    file_obj : file object
      Contains an OFF file

    Returns
    ----------
    loaded : dict
      kwargs for Trimesh constructor
    """
    text = file_obj.read()
    # will magically survive weird encoding sometimes
    text = util.decode_text(text).lstrip()
    # split the first key
    _, header, raw = re.split('(COFF|OFF)', text, 1)
    if header.upper() not in ['OFF', 'COFF']:
        raise NameError(
            'Not an OFF file! Header was: `{}`'.format(header))

    # split into lines and remove whitespace
    splits = [i.strip() for i in str.splitlines(str(raw))]
    # remove empty lines and comments
    splits = [i for i in splits if len(i) > 0 and i[0] != '#']

    # the first non-comment line should be the counts
    header = np.array(splits[0].split(), dtype=np.int64)
    vertex_count, face_count = header[:2]

    vertices = np.array([
        i.split()[:3] for i in
        splits[1: vertex_count + 1]],
        dtype=np.float64)

    # will fail if incorrect number of vertices loaded
    vertices = vertices.reshape((vertex_count, 3))

    # get lines with face data
    faces = [i.split() for i in
             splits[vertex_count + 1:vertex_count + face_count + 1]]
    # the first value is count
    faces = [line[1:int(line[0]) + 1] for line in faces]

    # convert faces to numpy array
    # will fail on mixed garbage as FSM intended -_-
    faces = np.array(faces, dtype=np.int64)

    # save data as kwargs for a trimesh.Trimesh
    kwargs = {'vertices': vertices,
              'faces': faces}

    return kwargs


def export_off(mesh, digits=10):
    """
    Export a mesh as an OFF file, a simple text format

    Parameters
    -----------
    mesh : trimesh.Trimesh
      Geometry to export
    digits : int
      Number of digits to include on floats

    Returns
    -----------
    export : str
      OFF format output
    """
    # make sure specified digits is an int
    digits = int(digits)
    # prepend a 3 (face count) to each face
    faces_stacked = np.column_stack((np.ones(len(mesh.faces)) * 3,
                                     mesh.faces)).astype(np.int64)
    export = 'OFF\n'
    # the header is vertex count, face count, another number
    export += str(len(mesh.vertices)) + ' ' + str(len(mesh.faces)) + ' 0\n'
    export += util.array_to_string(
        mesh.vertices, col_delim=' ', row_delim='\n', digits=digits) + '\n'
    export += util.array_to_string(
        faces_stacked, col_delim=' ', row_delim='\n')
    return export


_off_loaders = {'off': load_off}
_off_exporters = {'off': export_off}

Load an OFF file into the kwargs for a Trimesh constructor       Parameters     ----------     file_obj : file object       Contains an OFF file      Returns     ----------     loaded : dict       kwargs for Trimesh constructor # will magically survive weird encoding sometimes # split the first key # split into lines and remove whitespace # remove empty lines and comments # the first non-comment line should be the counts # will fail if incorrect number of vertices loaded # get lines with face data # the first value is count # convert faces to numpy array # will fail on mixed garbage as FSM intended -_- # save data as kwargs for a trimesh.Trimesh Export a mesh as an OFF file, a simple text format      Parameters     -----------     mesh : trimesh.Trimesh       Geometry to export     digits : int       Number of digits to include on floats      Returns     -----------     export : str       OFF format output # make sure specified digits is an int # prepend a 3 (face count) to each face # the header is vertex count, face count, another number