Repository: mikedh/trimesh

Issue:
Change of behavior in parsing additional file arguments.
Thank you for the great library!

I notice that there's a change in behavior between release 3.15.8 to 3.16.0 in trimesh/exchange/ply.py. Especially in the `load_element_single(properties, data)` funciton. 

Currently when trying to load a ply mesh with face information: 
`3 0 1 2 0 0`

from what I understand, the first digit should be the number of face elements `3`, then `0 1 2` should be the vertex indices and the last two values, `0 0` should be the additional file arguments. However, in the newer version the additional file arguments starts from `2` instead of `0`. 

Changing the number of face elements to `4` solves the issue but that's not the right way to specify it. 

Is this behavior expected? 

Thank you in advance!

Discussion:

Patch:
diff --git a/models/metadata.ply b/models/metadata.ply
new file mode 100644
index 00000000..d2e58618
--- /dev/null
+++ b/models/metadata.ply
@@ -0,0 +1,16 @@
+ply
+format ascii 1.0
+element vertex 4
+property float x
+property float y
+property float z
+element face 2
+property list uchar int vertex_index
+property char face_type
+end_header
+-4 -4 0
+-4 4 0
+4 -4 0
+4 4 0
+3 0 2 1 12
+3 1 2 3 90
\ No newline at end of file
diff --git a/trimesh/exchange/ply.py b/trimesh/exchange/ply.py
index 98e38ca6..867ce165 100644
--- a/trimesh/exchange/ply.py
+++ b/trimesh/exchange/ply.py
@@ -613,14 +613,14 @@ def _elements_to_kwargs(elements,
 
     # if both vertex and face color are defined pick the one
     if 'face' in elements:
-        kwargs['face_colors'] = element_colors(elements['face'])
+        kwargs['face_colors'] = _element_colors(elements['face'])
     if 'vertex' in elements:
-        kwargs['vertex_colors'] = element_colors(elements['vertex'])
+        kwargs['vertex_colors'] = _element_colors(elements['vertex'])
 
     return kwargs
 
 
-def element_colors(element):
+def _element_colors(element):
     """
     Given an element, try to extract RGBA color from
     properties and return them as an (n,3|4) array.
@@ -645,7 +645,7 @@ def element_colors(element):
     return None
 
 
-def load_element_different(properties, data):
+def _load_element_different(properties, data):
     """
     Load elements which include lists of different lengths
     based on the element's property-definitions.
@@ -686,7 +686,7 @@ def load_element_different(properties, data):
     return squeeze
 
 
-def load_element_single(properties, data):
+def _load_element_single(properties, data):
     """
     Load element data with lists of a single length
     based on the element's property-definitions.
@@ -719,7 +719,8 @@ def load_element_single(properties, data):
             length = int(first[current])
             columns[name] = data[
                 :, current + 1:current + 1 + length].astype(dtype)
-            current += length
+            # offset by length of array plus one for each uint index
+            current += length + 1
         else:
             columns[name] = data[:, current:current + 1].astype(dt)
             current += 1
@@ -772,13 +773,13 @@ def _ply_ascii(elements, file_obj):
             # all rows have the same length and we only have at most one list
             # property where all entries have the same length. this means we can
             # use the quick numpy-based loading.
-            element_data = load_element_single(
+            element_data = _load_element_single(
                 values['properties'], data)
         else:
             # there are lists of differing lengths. we need to fall back to loading
             # the data by iterating all rows and checking for list-lengths. this is
             # slower than the variant above.
-            element_data = load_element_different(
+            element_data = _load_element_different(
                 values['properties'], data)
 
         elements[key]['data'] = element_data
diff --git a/trimesh/version.py b/trimesh/version.py
index c0be1344..badcd595 100644
--- a/trimesh/version.py
+++ b/trimesh/version.py
@@ -1,4 +1,4 @@
-__version__ = '3.18.2'
+__version__ = '3.18.3'
 
 if __name__ == '__main__':
     # print version if run directly i.e. in a CI script


Test patch:
diff --git a/tests/test_ply.py b/tests/test_ply.py
index 2f89ada0..ce926089 100644
--- a/tests/test_ply.py
+++ b/tests/test_ply.py
@@ -214,6 +214,12 @@ class PlyTest(g.unittest.TestCase):
         # correct number of vertices and has texture loaded
         g.check_fuze(m)
 
+    def test_metadata(self):
+        mesh = g.get_mesh('metadata.ply')
+
+        assert (g.np.array([[12], [90]]) == mesh.metadata[
+            '_ply_raw']['face']['data']['face_type']).all()
+
 
 if __name__ == '__main__':
     g.trimesh.util.attach_to_log()