mikedh / trimesh

Python library for loading and using triangular meshes.
https://trimesh.org
MIT License
2.86k stars 569 forks source link

Give two meshes identical orientation #1311

Closed Kojon74 closed 2 years ago

Kojon74 commented 2 years ago

I have two meshes, where one is a subset of the other (sliced), however the two meshes are in completely different orientations. Is there a way to get both meshes to have identical orientation (facing the same way)?

mikedh commented 2 years ago

Hmm if they were identical you could try to use mesh.register which seeds iterative closest point from principal axis of inertia:

In [1]: import trimesh

In [2]: a = trimesh.load('models/ballA.off')

In [3]: b = trimesh.load('models/ballB.off')

In [4]: a.register?
Signature: a.register(other, **kwargs)
Docstring:
Align a mesh with another mesh or a PointCloud using
the principal axes of inertia as a starting point which
is refined by iterative closest point.

Parameters
------------
mesh : trimesh.Trimesh object
  Mesh to align with other
other : trimesh.Trimesh or (n, 3) float
  Mesh or points in space
samples : int
  Number of samples from mesh surface to align
icp_first : int
  How many ICP iterations for the 9 possible
  combinations of
icp_final : int
  How many ICP itertations for the closest
  candidate from the wider search

Returns
-----------
mesh_to_other : (4, 4) float
  Transform to align mesh to the other object
cost : float
  Average square distance per point
File:      /media/psf/Home/Dropbox/robotics/trimesh/trimesh/base.py
Type:      method

In [5]: T, d = a.register(b)

In [6]: T
Out[6]: 
array([[ 9.99999999e-01,  4.25215441e-05, -2.55502988e-05,
         8.00000122e+00],
       [-4.25191057e-05,  9.99999995e-01,  9.54283238e-05,
        -1.70247527e-04],
       [ 2.55543564e-05, -9.54272373e-05,  9.99999995e-01,
         1.01988427e-04],
       [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00,
         1.00000000e+00]])

In [7]: d
Out[7]: 1.853721583737171e-13

Though for a sliced thing I'd probably try to match the slice plane (assuming they both have faces?). The two slice planes probably have identical area, you could poke around mesh.facets_area for both, and then do a 2D fit of the slice outline.

Kojon74 commented 2 years ago

Thanks so much for your response, but sorry I should have clarified. What I meant by the 2 meshes is that one of them is the original and the second mesh is a portion (subset) of the first mesh where the rest of the mesh was sliced off. Hopefully it's still possible.

mikedh commented 2 years ago

Haha no worries. Anything is possible! But there isn't a built in function to do that. If the original mesh was watertight and the two sliced sections aren't you could try matching the boundary curves which you can get with mesh.outline and maybe try to align them with trimesh.registration.icp

Kojon74 commented 2 years ago

I was able to manage this by:

  1. Finding the triangle with the largest area in the subset mesh
  2. Taking the coordinates of the vertices of this triangle in the subset mesh
  3. Finding the corresponding triangle in the original mesh by finding the triangle with the same area *
  4. Getting the coordinates of the vertices of this triangle in the original mesh
  5. Use the two triangle coordinates to calculate the transformation matrix that maps the subset mesh triangle onto the original mesh triangle
  6. Apply this transformation to the subset mesh
  7. Apply the translation to the subset mesh so its positioned in the same coordinates as the original **

* I had trouble with this step because for some reason the two corresponding triangles across the two meshes (which should be identical) weren't Identical and had areas that were off by roughly 0.001 so I had to round the areas to the nearest tenth to compare equality.

** I don't know why this step is necessary since the transformation matrix from step 5 should have covered this but for some reason it doesn't