Repository: mikedh/trimesh
Pull request #603 (2019-11-06 21:06:07)

Merge/epic
Merge fix for `face_adjacency` and test to master, as well as some doc changes. 


Patch:
diff --git a/docs/build.py b/docs/build.py
index a1294471..bbf1c54a 100644
--- a/docs/build.py
+++ b/docs/build.py
@@ -74,6 +74,7 @@ if __name__ == '__main__':
 
     # build the API doc
     api = ['sphinx-apidoc',
+           '-e',
            '-o',
            cwd,
            abspath('../trimesh')]
diff --git a/docs/conf.py b/docs/conf.py
index 69c62907..8019e180 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -26,7 +26,10 @@ def abspath(rel):
     return os.path.abspath(os.path.join(cwd, rel))
 
 
-extensions = ['sphinxcontrib.napoleon']
+extensions = [
+    'sphinx.ext.napoleon',
+    'autodocsumm',
+]
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -82,3 +85,9 @@ html_theme = 'sphinx_rtd_theme'
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'trimeshdoc'
+
+# -- Extensions configuration ----------------------------------------
+
+autodoc_default_options = {
+    'autosummary': True,
+}
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2bbfb6ad..ec5cf691 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -8,3 +8,4 @@ sphinx
 jupyter
 sphinx_rtd_theme
 pyopenssl
+autodocsumm
diff --git a/trimesh/caching.py b/trimesh/caching.py
index 74dbc8df..ed443c0d 100644
--- a/trimesh/caching.py
+++ b/trimesh/caching.py
@@ -6,7 +6,6 @@ Functions and classes that help with tracking changes in ndarrays
 and clearing cached values based on those changes.
 """
 
-import collections
 import numpy as np
 
 import zlib
@@ -15,6 +14,11 @@ import hashlib
 
 from functools import wraps
 
+try:
+    from collections.abc import Mapping
+except ImportError:
+    from collections import Mapping
+
 from .constants import log
 from .util import is_sequence
 
@@ -491,7 +495,7 @@ class Cache(object):
         self.id_current = self._id_function()
 
 
-class DataStore(collections.Mapping):
+class DataStore(Mapping):
     """
     A class to store multiple numpy arrays and track them all
     for changes.
diff --git a/trimesh/graph.py b/trimesh/graph.py
index 4d5487f1..edc1eea9 100644
--- a/trimesh/graph.py
+++ b/trimesh/graph.py
@@ -113,7 +113,7 @@ def face_adjacency(faces=None,
         adjacency_edges = edges[edge_groups[:, 0][nondegenerate]]
         assert len(adjacency_edges) == len(adjacency)
         return adjacency, adjacency_edges
-    return face_adjacency
+    return adjacency
 
 
 def face_adjacency_unshared(mesh):
diff --git a/trimesh/util.py b/trimesh/util.py
index cd65ea99..eedbe178 100644
--- a/trimesh/util.py
+++ b/trimesh/util.py
@@ -45,6 +45,11 @@ else:
     StringIO.__exit__ = lambda a, b, c, d: a.close()
     BytesIO = StringIO
 
+try:
+    from collections.abc import Mapping
+except ImportError:
+    from collections import Mapping
+
 # create a default logger
 log = logging.getLogger('trimesh')
 
@@ -2058,7 +2063,7 @@ def allclose(a, b, atol):
     return np.all(np.abs(a - b).max() < atol)
 
 
-class FunctionRegistry(collections.Mapping):
+class FunctionRegistry(Mapping):
     """
     Non-overwritable mapping of string keys to functions.
 
diff --git a/trimesh/version.py b/trimesh/version.py
index e3b71ec6..f6310076 100644
--- a/trimesh/version.py
+++ b/trimesh/version.py
@@ -1,1 +1,1 @@
-__version__ = '3.3.9'
+__version__ = '3.4.0'


Test patch:
diff --git a/tests/test_dae.py b/tests/test_dae.py
index 320a66bb..719f2ca1 100644
--- a/tests/test_dae.py
+++ b/tests/test_dae.py
@@ -7,6 +7,11 @@ try:
     import collada
 except ImportError:
     collada = None
+except BaseException:
+    # TODO : REMOVE WHEN UPSTREAM RELEASE FIXED
+    # https://github.com/pycollada/pycollada/pull/92
+    g.log.error('DAE fix not pushed yet!')
+    collada = None
 
 
 class DAETest(g.unittest.TestCase):
@@ -32,6 +37,15 @@ class DAETest(g.unittest.TestCase):
         assert len(scene.geometry) == 3
         assert len(scene.graph.nodes_geometry) == 3
 
+    def test_export(self):
+        if collada is None:
+            g.log.error('no pycollada to test!')
+            return
+
+        a = g.get_mesh('ballA.off')
+        r = a.export(file_type='dae')
+        assert len(r) > 0
+
 
 if __name__ == '__main__':
     g.trimesh.util.attach_to_log()
diff --git a/tests/test_graph.py b/tests/test_graph.py
index eca7b5cd..91cfeee8 100644
--- a/tests/test_graph.py
+++ b/tests/test_graph.py
@@ -203,6 +203,24 @@ class GraphTest(g.unittest.TestCase):
                     m.faces[0][2] = m.faces[0][0]
                 # degenerate faces should be filtered
                 assert g.np.not_equal(*m.face_adjacency.T).all()
+
+                # check the various paths of calling face adjacency
+                a = g.trimesh.graph.face_adjacency(
+                    m.faces.view(g.np.ndarray).copy(),
+                    return_edges=False)
+                b, be = g.trimesh.graph.face_adjacency(
+                    m.faces.view(g.np.ndarray).copy(),
+                    return_edges=True)
+                c = g.trimesh.graph.face_adjacency(
+                    mesh=m, return_edges=False)
+                c, ce = g.trimesh.graph.face_adjacency(
+                    mesh=m, return_edges=True)
+                # make sure they all return the expected result
+                assert g.np.allclose(a, b)
+                assert g.np.allclose(a, c)
+                assert len(be) == len(a)
+                assert len(ce) == len(a)
+
                 # package properties to loop through
                 zips = zip(m.face_adjacency,
                            m.face_adjacency_edges,
diff --git a/tests/test_packing.py b/tests/test_packing.py
index 470a06af..7534e379 100644
--- a/tests/test_packing.py
+++ b/tests/test_packing.py
@@ -2,12 +2,12 @@ try:
     from . import generic as g
 except BaseException:
     import generic as g
-from shapely.geometry import Polygon
 
 
 class PackingTest(g.unittest.TestCase):
 
     def setUp(self):
+        from shapely.geometry import Polygon
         self.nestable = [Polygon(i) for i in g.data['nestable']]
 
     def test_obb(self):
diff --git a/tests/test_proximity.py b/tests/test_proximity.py
index 35b8a5da..b00ab313 100644
--- a/tests/test_proximity.py
+++ b/tests/test_proximity.py
@@ -198,6 +198,12 @@ class NearestTest(g.unittest.TestCase):
                 g.np.all(faceIdxsB == faceIdxsB[0]) and
                 faceIdxsA[0] != faceIdxsB[0])
 
+    def test_candidates(self):
+        mesh = g.trimesh.creation.random_soup(2000)
+        points = g.np.random.random((2000, 3))
+        g.trimesh.proximity.nearby_faces(
+            mesh=mesh, points=points)
+
 
 if __name__ == '__main__':
     g.trimesh.util.attach_to_log()
diff --git a/tests/test_util.py b/tests/test_util.py
index d4c267db..43c187d4 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -141,13 +141,6 @@ class UtilTests(unittest.TestCase):
         assert a.md5() == hA
 
 
-class IOTest(unittest.TestCase):
-
-    def test_dae(self):
-        a = g.get_mesh('ballA.off')
-        r = a.export(file_type='dae')  # NOQA
-
-
 class ContainsTest(unittest.TestCase):
 
     def test_inside(self):