Get 'Transformation' from 'Plane' in Python


#1

Hello!
What’s the simplest way to derive a ‘Transform’ object from a ‘Plane’ in Python?
Thanks!!
Best regards
Eugen


#2

You’ll need to specify which transform you’re looking for. The Transform Structure has several, including Transform.Mirror and Transform.PlaneToPlane that both operate on plane(s).


#3

Ok, thanks!
I’d like to get a transform that I can apply to geometry points, so that the mesh lies in the plane’s space.

To be used like that:

import Rhino.Geometry as rg
...
verts = mesh.Vertices
trafo = ??? # get from a plane
for iVert in range(verts.Count):
    vP = verts[iVert]
    vP.Transform(trafo)
    verts.SetVertex(iVert, rg.Point3d(vP))

#4

That is not quite enough information to define a transform though, unless I’m missing something. You need to define what you mean by “lies in the plane’s space”. If the mesh is planar, you can generate a plane (A) from a vertex and a face normal, and then construct a PlaneToPlane transform from this and the target plane (B). If the mesh isn’t planar, perhaps you can fit a plane through the mesh vertices and use this as (B). Also, you can just apply the transform directly on the mesh, no need to transform each vertex individually in a loop.

Edit: Unless you’re looking to simply mirror your mesh. Again, you need to be specific about which transform you’re looking to make!


#5

A plane has an origin, an 3 orthonormal vectors (X, Y, Z). That’s enough to construct a transformation matrix from it (scale would be assumed 1.0 of course)


I’ve done it before, for another 3d program. Even 2 vectors suffice, or even one, if you assume a second one normal to it.

I’d do it myself. However, the Transform object’s help file misses the details of how the matrix is laid out.
http://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_Geometry_Transform.htm

Since it’s hard to believe such a basic thing should be missing, I thought I’d ask…

Thanks!!
Eugen


(David Rutten) #6

Ideally you’d never set up a matrix from scratch. Use one of the static creation methods to make one or more translation, or rotation, or dilation, or shearing, or tapering, or change-of-basis transforms, and then combine them together using the multiplication operator. Usually one of the static creation methods is all you need, in some cases you may need to combine two or more transforms to get your desired outcome. It is really rare that you’d have to make a matrix yourself.


#7

Understood.
However, if it’s the simplest and most straightforward approach, why not… =)
I remember it being trivial: you simply put the 3 vectors into the matrix, and the origin in the 4th column, and that’s it. Matrix magic…
I’ve put it on paper somewhere… where? ;p

Thank you!
Best regards
Eugen


#8

Tested, works.
The vectors have to be unitized and orthonormal - which the plane’s axes are.

import Rhino.Geometry as rg
def transformFromPlane(plane):
        # Create a Transform object from a Plane object.
        trafo = rg.Transform.Identity
        vX = rg.Vector3d(plane.XAxis)
        vY = rg.Vector3d(plane.YAxis)
        vZ = rg.Vector3d(plane.ZAxis)
        # row|column
        trafo.M00 = vX.X
        trafo.M10 = vX.Y
        trafo.M20 = vX.Z
        trafo.M01 = vY.X
        trafo.M11 = vY.Y
        trafo.M21 = vY.Z
        trafo.M02 = vZ.X
        trafo.M12 = vZ.Y
        trafo.M22 = vZ.Z
        trafo.M03 = plane.OriginX
        trafo.M13 = plane.OriginY
        trafo.M23 = plane.OriginZ
        return trafo

#9

Probably a matter of taste but this looks more common to me :wink:
Rhino.Geometry.Transform.PlaneToPlane(source_plane, target_plane)

Oh, and if you want to transform the entire mesh you can do that too, so you do not have to transform each vertex separately. Just in case…


#10

While were at it, here’s a method for creating the inverse of the transform described by a plane (albeit in C#). Should be significantly less expensive than inverting a 4x4 matrix.

public static Transform InvTransformFromPlane(Plane plane)
{
    var p = new Vector3d(plane.Origin);
    var x = plane.XAxis;
    var y = plane.YAxis;
    var z = plane.ZAxis;

    var m = Transform.Identity;

    m[0, 0] = x.X;
    m[0, 1] = x.Y;
    m[0, 2] = x.Z;
    m[0, 3] = -(p * x);

    m[1, 0] = y.X;
    m[1, 1] = y.Y;
    m[1, 2] = y.Z;
    m[1, 3] = -(p * y);

    m[2, 0] = z.X;
    m[2, 1] = z.Y;
    m[2, 2] = z.Z;
    m[2, 3] = -(p * z);

    return m;
}

#11

A-ha! =)
Yeah, foreign SDKs…

Jess, what would be the code that transforms a mesh then?
Mesh has a .Transform method that takes a Transform object as input - this I need. Where does .PlaneToPlane go?

Cheers!


#12

Not sure if I understand your question. If the mesh is an object in Rhino, then this is the preferred way I think:
id = scriptcontext.doc.Objects.Transform(mesh_id, xform, False)


#13

Indeed:

:wink:


#14

Ok… to conclude this:

import Rhino.Geometry as rg

plane0 = rg.Plane(rg.Point3d(0,0,0),rg.Vector3d(1,0,0),rg.Vector3d(0,1,0)) # default plane at 0,0,0
trafo = rg.Transform.PlaneToPlane(plane0, plane)
mesh.Transform(trafo)

Thanks everyone!


#15

welcome!

plane0 = Rhino.Geometry.Plane.WorldXY