Skip to content

Commit b51069f

Browse files
committed
load face-free PLY files
1 parent eb8a286 commit b51069f

4 files changed

Lines changed: 58 additions & 29 deletions

File tree

trimesh/io/load.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from .. import util
66

77
from ..base import Trimesh
8+
from ..points import PointCloud
89
from ..scene.scene import Scene, append_scenes
910
from ..constants import _log_time, log
1011

@@ -331,9 +332,15 @@ def handle_scene():
331332
return scene
332333

333334
def handle_trimesh_kwargs():
335+
"""
336+
Load information with vertices and faces into a mesh
337+
or PointCloud object.
338+
"""
334339
if (isinstance(kwargs['vertices'], dict) or
335340
isinstance(kwargs['faces'], dict)):
336341
return Trimesh(**misc.load_dict(kwargs))
342+
elif kwargs['faces'] is None:
343+
return PointCloud(**kwargs)
337344
else:
338345
return Trimesh(**kwargs)
339346

trimesh/io/ply.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ def load_ply(file_obj, *args, **kwargs):
4141
4242
Returns
4343
---------
44-
mesh_kwargs : dictionary of mesh info which can be passed to
45-
Trimesh constructor, eg: a = Trimesh(**mesh_kwargs)
44+
mesh_kwargs : dict
45+
Data which can be passed to
46+
Trimesh constructor, eg: a = Trimesh(**mesh_kwargs)
4647
"""
4748

4849
# OrderedDict which is populated from the header
@@ -237,13 +238,22 @@ def elements_to_kwargs(elements):
237238
kwargs: dict, with keys for Trimesh constructor.
238239
eg: mesh = trimesh.Trimesh(**kwargs)
239240
"""
240-
vertices = np.column_stack([elements['vertex']['data'][i] for i in 'xyz'])
241+
vertices = np.column_stack([elements['vertex']['data'][i]
242+
for i in 'xyz'])
241243
if not util.is_shape(vertices, (-1, 3)):
242244
raise ValueError('Vertices were not (n,3)!')
243245

246+
try:
247+
face_data = elements['face']['data']
248+
except KeyError:
249+
# some PLY files only include vertices
250+
face_data = None
251+
faces = None
252+
253+
# what keys do in-the-wild exporters use for vertices
244254
index_names = ['vertex_index',
245255
'vertex_indices']
246-
face_data = elements['face']['data']
256+
247257
if util.is_shape(face_data, (-1, (3, 4))):
248258
faces = face_data
249259
elif isinstance(face_data, dict):
@@ -254,8 +264,8 @@ def elements_to_kwargs(elements):
254264
elif isinstance(face_data, np.ndarray):
255265
blob = elements['face']['data']
256266
# some exporters set this name to 'vertex_index'
257-
# and some others use 'vertex_indices', but we really
258-
# don't care about the name unless there are multiple properties
267+
# and some others use 'vertex_indices' but we really
268+
# don't care about the name unless there are multiple
259269
if len(blob.dtype.names) == 1:
260270
name = blob.dtype.names[0]
261271
elif len(blob.dtype.names) > 1:
@@ -264,33 +274,35 @@ def elements_to_kwargs(elements):
264274
name = i
265275
break
266276
faces = elements['face']['data'][name]['f1']
267-
else:
268-
raise ValueError('Couldn\'t extract face data!')
269-
270-
if not util.is_shape(faces, (-1, (3, 4))):
271-
raise ValueError('Faces weren\'t (n,(3|4))!')
272277

273-
result = {'vertices': vertices,
274-
'faces': faces,
278+
# kwargs for Trimesh or PointCloud
279+
result = {'faces': faces,
280+
'vertices': vertices,
275281
'ply_data': elements}
276282

277-
# if both vertex and face color are defined, pick the one
283+
# if both vertex and face color are defined pick the one
278284
# with the most going on
279-
f_color, f_signal = element_colors(elements['face'])
280-
v_color, v_signal = element_colors(elements['vertex'])
281-
colors = [{'face_colors': f_color},
282-
{'vertex_colors': v_color}]
283-
colors_index = np.argmax([f_signal,
284-
v_signal])
285-
result.update(colors[colors_index])
285+
colors = []
286+
signal = []
287+
if result['faces'] is not None:
288+
f_color, f_signal = element_colors(elements['face'])
289+
colors.append({'face_colors': f_color})
290+
signal.append(f_signal)
291+
if result['vertices'] is not None:
292+
v_color, v_signal = element_colors(elements['vertex'])
293+
colors.append({'vertex_colors': v_color})
294+
signal.append(v_signal)
295+
296+
# add the winning colors to the result
297+
result.update(colors[np.argmax(signal)])
286298

287299
return result
288300

289301

290302
def element_colors(element):
291303
"""
292-
Given an element, try to extract RGBA color from its properties
293-
and return them as an (n,3|4) array.
304+
Given an element, try to extract RGBA color from
305+
properties and return them as an (n,3|4) array.
294306
295307
Parameters
296308
-------------

trimesh/ray/ray_util.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ def contains_points(intersector,
5353
(inside_aabb.sum(), 1))
5454
else:
5555
# if a direction is passed use it
56-
ray_directions = np.tile(np.array(check_direction).reshape(3),
57-
(inside_aabb.sum(), 1))
56+
ray_directions = np.tile(
57+
np.array(check_direction).reshape(3),
58+
(inside_aabb.sum(), 1))
5859

5960
# cast a ray both forwards and backwards
6061
location, index_ray, c = intersector.intersects_location(
@@ -116,11 +117,20 @@ def contains_points(intersector,
116117

117118
# run a contains check again on the broken points with a
118119
# new random direction but only once and assign it to our results
119-
contains[mask] = contains_points(intersector,
120-
points[inside_aabb][broken],
121-
check_direction=new_direction)
120+
contains[mask] = contains_points(
121+
intersector,
122+
points[inside_aabb][broken],
123+
check_direction=new_direction)
124+
122125
constants.log.debug(
123126
'detected %d broken contains test, attempted to fix',
124127
broken.sum())
125128

129+
# we had unrecoverable points
130+
if broken.any() and check_direction is not None:
131+
constants.log.error(
132+
'ray contains tests had %d unrecoverable!' +
133+
'try loading mesh with use_embree=False!',
134+
broken.sum())
135+
126136
return contains

trimesh/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2.35.17'
1+
__version__ = '2.35.18'

0 commit comments

Comments
 (0)