diff --git a/pyproject.toml b/pyproject.toml index 47e1a8b6c..c04cf0eec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"] [project] name = "trimesh" requires-python = ">=3.7" -version = "4.0.5" +version = "4.0.6" authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}] license = {file = "LICENSE.md"} description = "Import, export, process, analyze and view triangular meshes." diff --git a/tests/test_inertia.py b/tests/test_inertia.py index 8b96b7754..86797200a 100644 --- a/tests/test_inertia.py +++ b/tests/test_inertia.py @@ -43,7 +43,10 @@ def test_inertia(self): assert g.np.abs(g.np.dot(t1, t1.T) - g.np.eye(4)).max() < 1e-10 c = g.trimesh.primitives.Cylinder( - height=10, radius=1, sections=720, transform=t0 # number of slices + height=10, + radius=1, + sections=720, + transform=t0, # number of slices ) c0m = c.moment_inertia.copy() c0 = g.trimesh.inertia.cylinder_inertia( @@ -343,9 +346,7 @@ def parallel_axis_theorem(inertia, mass, a1, a2, a3): # CHECK FRAME 0 # analytical calculations of inertia tensor by hand inertia0 = ( - 0.083333333333 - * mass - * g.np.diag([h**2 + b**2, h**2 + d**2, b**2 + d**2]) + 0.083333333333 * mass * g.np.diag([h**2 + b**2, h**2 + d**2, b**2 + d**2]) ) a1 = -0.5 * d a2 = -0.5 * b @@ -358,9 +359,7 @@ def parallel_axis_theorem(inertia, mass, a1, a2, a3): # CHECK FRAME 1 # analytical calculations of inertia tensor by hand inertia1 = ( - 0.083333333333 - * mass - * g.np.diag([h**2 + d**2, h**2 + b**2, b**2 + d**2]) + 0.083333333333 * mass * g.np.diag([h**2 + d**2, h**2 + b**2, b**2 + d**2]) ) a1 = -0.5 * b a2 = 0.5 * d @@ -376,9 +375,7 @@ def parallel_axis_theorem(inertia, mass, a1, a2, a3): # CHECK FRAME 2 # analytical calculations of inertia tensor by hand inertia2 = ( - 0.083333333333 - * mass - * g.np.diag([h**2 + b**2, b**2 + d**2, h**2 + d**2]) + 0.083333333333 * mass * g.np.diag([h**2 + b**2, b**2 + d**2, h**2 + d**2]) ) a1 = -0.5 * d a2 = 0.5 * h diff --git a/trimesh/grouping.py b/trimesh/grouping.py index 40018937d..0c8d6fc7c 100644 --- a/trimesh/grouping.py +++ b/trimesh/grouping.py @@ -189,6 +189,29 @@ def hashable_rows(data, digits=None): if len(as_int.shape) == 1: return as_int + + # if array is 2D and smallish, we can try bitbanging + # this is significantly faster than the custom dtype + if len(as_int.shape) == 2 and as_int.shape[1] <= 4: + # time for some righteous bitbanging + # can we pack the whole row into a single 64 bit integer + precision = int(np.floor(64 / as_int.shape[1])) + + d_min, d_max = as_int.min(), as_int.max() + + # if the max value is less than precision we can do this + if abs(d_max - d_min) < 2 ** (precision - 1): + # the resulting package + hashable = np.zeros(len(as_int), dtype=np.uint64) + # offset to zero + bitbang = (as_int - d_min).astype(np.uint64).T + # loop through each column and bitwise xor to combine + # make sure as_int is int64 otherwise bit offset won't work + for offset, column in enumerate(bitbang) + # will modify hashable in place + np.bitwise_xor(hashable, column << (offset * precision), out=hashable) + return hashable + # reshape array into magical data type that is weird but hashable dtype = np.dtype((np.void, as_int.dtype.itemsize * as_int.shape[1]))