init
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import re
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ..geometry import triangulate_quads
|
||||
from ..util import array_to_string, comment_strip, decode_text
|
||||
|
||||
|
||||
def load_off(file_obj, **kwargs) -> dict:
|
||||
"""
|
||||
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
|
||||
# comment strip will handle all cases of commenting
|
||||
text = comment_strip(decode_text(text)).strip()
|
||||
|
||||
# split the first key
|
||||
_, header, raw = re.split("(COFF|OFF)", text, maxsplit=1)
|
||||
if header.upper() not in ["OFF", "COFF"]:
|
||||
raise NameError(f"Not an OFF file! Header was: `{header}`")
|
||||
|
||||
# split into lines and remove whitespace
|
||||
splits = [i.strip() for i in str.splitlines(str(raw))]
|
||||
# remove empty lines
|
||||
splits = [i for i in splits if len(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]
|
||||
|
||||
faces = triangulate_quads(faces)
|
||||
# save data as kwargs for a trimesh.Trimesh
|
||||
kwargs = {"vertices": vertices, "faces": faces}
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
def export_off(mesh, digits=10) -> str:
|
||||
"""
|
||||
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
|
||||
)
|
||||
# the header is vertex count, face count, another number
|
||||
export = "\n".join(
|
||||
[
|
||||
"OFF",
|
||||
str(len(mesh.vertices)) + " " + str(len(mesh.faces)) + " 0",
|
||||
array_to_string(mesh.vertices, col_delim=" ", row_delim="\n", digits=digits),
|
||||
array_to_string(faces_stacked, col_delim=" ", row_delim="\n"),
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
return export
|
||||
|
||||
|
||||
_off_loaders = {"off": load_off}
|
||||
_off_exporters = {"off": export_off}
|
||||
Reference in New Issue
Block a user