-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rotation of meshes around different origins #186
Comments
|
yes, sorry u was unit vector version on n so they are the same, unfortunately I need this case to work but I am unsure of the proper conversion of an arbitrary angle to a normal vector. I don't see this as a blocker for finding a solution to this question so the provided angle should be fine. |
Yes, it was more of a debugging suggestion. Like how debugging linear algebra is easier if you use 2d arrays with non-equal dimensions, because then it's obvious when some sizes don't match up so mistakes are louder. |
I'll review some of my linear algebra, I think given a normal vector and a vector defining the typical coordinate space there are ways of determining the rotation matrix between them, I think the "base" vector would just be 0,0,1 ... maybe one of these will work https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d |
Personally, I usually use Rodrigues' rotation formula for contructing rotation matrices. Then it's a matter of finding the two vectors (one for the normal, one for the dataset, and rotating one into the other around the cross product of these two vectors). As for the translation, if you have a 3d rotation matrix P -> R @ (P - O) + O is the transformed point (which is the transformation you have to apply to each point). That being said, this is just the pure math background, and odds are PyVista already has high-level functionality that helps with these tasks ( |
The following is close... I used this implementation for the formula https://github.com/robEllenberg/comps-plugins/blob/master/python/rodrigues.py, but it looks like opencv also has it implemented from numpy import sin,cos,dot,eye
from numpy.linalg import norm
def rodrigues(r):
def S(n):
Sn = np.array([[0,-n[2],n[1]],[n[2],0,-n[0]],[-n[1],n[0],0]])
return Sn
theta = norm(r)
if theta > 1e-30:
n = r/theta
Sn = S(n)
R = eye(3) + sin(theta)*Sn + (1-cos(theta))*dot(Sn,Sn)
else:
Sr = S(r)
theta2 = theta**2
R = eye(3) + (1-theta2/6.)*Sr + (.5-theta2/24.)*dot(Sr,Sr)
return R
# above from https://github.com/robEllenberg/comps-plugins/blob/master/python/rodrigues.py, but I removed the mat call
p = pv.Plotter()
n = np.array([2.38485370e-06, 2.41350030e-08, 1.14723631e-04])
u = n /np.linalg.norm(n)
c = np.array([-1213.76492667191, 524216.7597523882, -2476.815087890625])
b = np.array([-1214.26492667191,
-1213.26492667191,
524216.2597523882,
524217.2597523882,
-2496.715087890625,
-2456.915087890625])
d= pv.Cube(bounds=b)
p.add_mesh(d, opacity=0.4, color='red') # origional mesh
RM = rodrigues(u)
RM
f = pv.PolyData((RM @ (d.points-c).T).T+c)
p.add_mesh(f.delaunay_3d(), opacity=0.4, color='lightgreen') # new mesh I want to be correct
p.add_mesh(pv.Plane(c, u, j_size=40, i_size=40), color='orange') # perpendicular plane
p.add_mesh(pv.Arrow(c, u, scale=12), color='blue') # normal direction I want the cube to be rotated to be parrelel to (perpendicular to plane)
p.view_xz()
p.show(height=800)
|
Since you mentioned opencv, I'd sooner use scipy. You could construct a |
that seems to work well/even better, for the align_vectors case since I have the full scalar field I could also pass in the vector for each point on the A side, with a corresponding [0,0,1] for the B side, I just tried it and it works, but I don't know if it is necessary or even smart to do yet I suspect that the scalar field gradient is mostly the same in my grid, so I think it should be safe to do... if it makes sense mathematically I don't know. from scipy.spatial.transform import Rotation
p = pv.Plotter()
n = np.array([2.38485370e-06, 2.41350030e-08, 1.14723631e-04])
u = n /np.linalg.norm(n)
c = np.array([-1213.76492667191, 524216.7597523882, -2476.815087890625])
b = np.array([-1214.26492667191,
-1213.26492667191,
524216.2597523882,
524217.2597523882,
-2496.715087890625,
-2456.915087890625])
d= pv.Cube(bounds=b)
p.add_mesh(d, opacity=0.4, color='red') # original mesh
R, _ = Rotation.align_vectors([u], [[0,0,1]])
f = pv.PolyData((R.as_matrix() @ (d.points-c).T).T+c)
p.add_mesh(f.delaunay_3d(), opacity=0.4, color='lightgreen') # new mesh I want to be correct
p.add_mesh(pv.Plane(c, u, j_size=40, i_size=40), color='orange') # perpendicular plane
p.add_mesh(pv.Arrow(c, u, scale=12), color='blue') # normal direction I want the cube to be rotated to be parallel to (perpendicular to plane)
p.view_xz()
p.show(height=800)
|
I should emphasize that I'm not familiar with the PyVista aspect of the problem, so I'm just musing about the brute-force solution. Depends on what you mean by "passing in the full scalar field". Hearing that I'd think you're passing in a set of spatial points that correspond to your long rectangle (or something close enough), in which case passing those for an aligning rotation probably makes sense (assuming the point mesh is shifted to the origin first). Anyway, one point of the |
So.. the problem here boils down to:
I did something like this when implementing the also, there is HTH... maybe? |
Also, #149 |
I think for axis_rotation, which I didn't know about as it is not listed in the docs, I would need to know the angles in degrees which I didn't have in hand (but I am sure is possible to find). I like the scipy solution (as I also get an error metric which is always fun to have just in case), maybe it makes sense to add the solution from the cylinderstructured/#149 into a new filter |
I'll close this issue for now as I think It is now working for me |
Description
I am trying to figure out how to rotate a mesh around an arbitrary center point (ideally the center point of the mesh) given a normal vector. Specifically I calculate a scalar field in a narrow column that is straight up and down relative to the xyz axes, I then use pyvista to get the gradient of the scalar field for that mesh and I want to rotate the mesh such that it points in the same direction as the gradient of the scalar field.
Example Data
The text was updated successfully, but these errors were encountered: