Repository: mikedh/trimesh

Issue:
Indexing Error in remesh.subdivide when using face_index
faces are re-indexed in the beginning of the function
https://github.com/mikedh/trimesh/blob/82a2acda892e82e9c727ea8ba81c301bbfca5d70/trimesh/remesh.py#L50

which causes indexing error here
https://github.com/mikedh/trimesh/blob/82a2acda892e82e9c727ea8ba81c301bbfca5d70/trimesh/remesh.py#L81-L83

This is because new_faces are made of faces corresponding to face_index instead of the original faces

I think having reference to the original array would fix this, i.e., on L50
faces_old = faces
faces = faces[face_index]

and on the line linked on L81
new_faces = np.vstack((faces_old, f[len(face_index):]))

BTW. having face_index is a very useful feature especially for adaptive subdivision in visualization.

Discussion:

Patch:
diff --git a/.travis.yml b/.travis.yml
index 3bc26766..3781de8f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -101,9 +101,7 @@ script:
 - if [[ "$PYTHON_VERSION" == "3.6" ]]; then conda install pyembree scikit-image; fi;
 - if [[ "$PYTHON_VERSION" == "3.6" ]]; then pip install python-fcl; fi;
 # lxml stopped supporting EOL Python
-- if [[ "$PYTHON_VERSION" == "3.4" ]]; then pip install lxml==4.3.5; fi;
-# sdist for released shapely has issues on 3.8
-- if [[ "$PYTHON_VERSION" == "3.8" ]]; then pip install shapely==1.7a2; fi;
+- if [[ "$PYTHON_VERSION" == "3.4" ]]; then pip install lxml==4.3.5 shapely==1.6.4; fi;
 
 # install most deps here
 - pip install -q .[easy]
diff --git a/trimesh/remesh.py b/trimesh/remesh.py
index e2c8d4b9..7b93260e 100644
--- a/trimesh/remesh.py
+++ b/trimesh/remesh.py
@@ -46,10 +46,11 @@ def subdivide(vertices,
     else:
         face_index = np.asanyarray(face_index)
 
-    # the (c,3) int set of vertex indices
-    faces = faces[face_index]
+    # the (c, 3) int array of vertex indices
+    faces_subset = faces[face_index]
+
     # the (c, 3, 3) float set of points in the triangles
-    triangles = vertices[faces]
+    triangles = vertices[faces_subset]
     # the 3 midpoints of each triangle edge
     # stacked to a (3 * c, 3) float
     mid = np.vstack([triangles[:, g, :].mean(axis=1)
@@ -57,27 +58,27 @@ def subdivide(vertices,
                                [1, 2],
                                [2, 0]]])
 
-    # for adjacent faces we are going to be generating
+    # for adjacent faces_subset we are going to be generating
     # the same midpoint twice so merge them here
     mid_idx = (np.arange(len(face_index) * 3)).reshape((3, -1)).T
     unique, inverse = grouping.unique_rows(mid)
     mid = mid[unique]
     mid_idx = inverse[mid_idx] + len(vertices)
 
-    # the new faces with correct winding
-    f = np.column_stack([faces[:, 0],
+    # the new faces_subset with correct winding
+    f = np.column_stack([faces_subset[:, 0],
                          mid_idx[:, 0],
                          mid_idx[:, 2],
                          mid_idx[:, 0],
-                         faces[:, 1],
+                         faces_subset[:, 1],
                          mid_idx[:, 1],
                          mid_idx[:, 2],
                          mid_idx[:, 1],
-                         faces[:, 2],
+                         faces_subset[:, 2],
                          mid_idx[:, 0],
                          mid_idx[:, 1],
                          mid_idx[:, 2]]).reshape((-1, 3))
-    # add the 3 new faces per old face
+    # add the 3 new faces_subset per old face
     new_faces = np.vstack((faces, f[len(face_index):]))
     # replace the old face with a smaller face
     new_faces[face_index] = f[:len(face_index)]
@@ -87,7 +88,7 @@ def subdivide(vertices,
     if vertex_attributes is not None:
         new_attributes = {}
         for key, values in vertex_attributes.items():
-            attr_tris = values[faces]
+            attr_tris = values[faces_subset]
             attr_mid = np.vstack([
                 attr_tris[:, g, :].mean(axis=1)
                 for g in [[0, 1],
diff --git a/trimesh/version.py b/trimesh/version.py
index f78b7205..90bbb877 100644
--- a/trimesh/version.py
+++ b/trimesh/version.py
@@ -1,1 +1,1 @@
-__version__ = '3.5.16'
+__version__ = '3.5.17'


Test patch:
diff --git a/tests/test_remesh.py b/tests/test_remesh.py
index 974e36b6..9d5f83d3 100644
--- a/tests/test_remesh.py
+++ b/tests/test_remesh.py
@@ -35,6 +35,20 @@ class SubDivideTest(g.unittest.TestCase):
 
             assert (edge_len < max_edge).all()
 
+    def test_sub(self):
+        # try on some primitives
+        meshes = [g.trimesh.creation.box(),
+                  g.trimesh.creation.icosphere()]
+
+        for m in meshes:
+            s = m.subdivide(face_index=[0, len(m.faces) - 1])
+            # shouldn't have subdivided in-place
+            assert len(s.faces) > len(m.faces)
+            # area should be the same
+            assert g.np.isclose(m.area, s.area)
+            # volume should be the same
+            assert g.np.isclose(m.volume, s.volume)
+
     def test_uv(self):
         # get a mesh with texture
         m = g.get_mesh('fuze.obj')