Move object axis problem in python



  • Hi, guys! i'm a new python guy and i want to move my object axis only, like center axis tool .and now i can move the axis on Y axis like this:
    it's work fine
    Work Fine.gif
    but if i rotate the object , it's have a problem(I don't know why i can't upload my next GIF).

    I think this is a matrix problem, but matrix a little bit hard for me ,i have no idea how to fix it.
    Hope you guys can help me.☹

    This is my code:

    import c4d
    
    
    def main():
        obj = doc.GetActiveObject()
        axis_offset = c4d.Vector(0,100,0)
        
        points = obj.GetAllPoints()
        count = obj.GetPointCount()
        obj_pos = obj.GetAbsPos()
        
        doc.AddUndo(c4d.UNDOTYPE_CHANGE,obj)
        for i in xrange(len(points)):
            points[i] = points[i] + (axis_offset*-1)
            obj.SetAllPoints(points)
            obj.SetAbsPos(obj_pos+axis_offset)
            
        obj.Message(c4d.MSG_UPDATE)
        c4d.EventAdd()
        
    if __name__=='__main__':
        main()
    


  • Hi Harry, thanks for reaching out us.

    With regard to your topic, as suggested by @zipit - thanks a lot dude -, I strongly recommend in having a look at geometry fundamentals as presented in ScratchPixel or in our documentation at Matrix Fundamentals.

    Taking in consideration the global object orientation in space you could reconsider your code to use the inverse global matrix directly applied to your offset vector.

        # set the offset vector
        myOff = c4d.Vector(0,-100,0)
        
        # check op is valid and assume it's already a mesh
        if op is None:
            return
        
        # retrieve object global inverse matrix
        invOpMg = ~(op.GetMg())   
        
        #get the mesh points 
        points = op.GetAllPoints()
        
        # browse over them and add the offset vector left multiplied by the inverse global matrix
        for i,p in enumerate(points):
            points[i] = p + invOpMg*myOff
            
        # set points and update
        op.SetAllPoints(points)
        op.Message(c4d.MSG_UPDATE)
        c4d.EventAdd()
    

    Best, Riccardo



  • Hi,

    I am a bit confused regarding what your actual question is, since your code does not contain any matrix operations. I assume you want to know how matrix transforms work, so that you can construct one? You can check the ScratchPixel section on matrices, they have a pretty good explanation on how you can define transforms with matrices (if you don't already know what vectors are you should probably read that chapter too, especially regarding the geometric meaning of the cross product). Note that practically every software has a slightly different interpretation of transformation matrices, so read ScratchPixel more as a general guide.

    c4d.utils defines three functions to construct a rotation matrix axis by axis, the example also modifies the offset component of the final rotation matrix so that it also translates points by 100 units along the y axis.

    90_DEGREE = math.pi * .5
    # construct a rotation matrix for each axis.
    mg_x = c4d.utils.MatrixRotX(90_DEGREE)
    mg_y = c4d.utils.MatrixRotY(0)
    mg_z = c4d.utils.MatrixRotZ(-90_DEGREE)
    
    # multiplying matrices will give you a matrix which combines all transformations
    my_final_transform = mg_x * mg_y * mg_z
    # set the offset
    my_final_transform.off = c4d.Vector(0, 100, 0)
    
    # transform a point in global space
    some_point_in_global_space = c4d.Vector(100, 0, 0)
    transformed_point = my_final_transform * some_point_in_global_space 
    

    You can also construct matrices manually if you have one or multiple normals (or vectors if you also want to scale stuff), using the cross product:

    # note that the x and y components are switched, so we rotate by 90 degree on
    # the axis orthogonal to the xy-plane (the z axis).
    x_component = c4d.Vector(0, 1, 0)
    # the y component is not an unit vector so we scale by 2 on that axis
    y_component = c4d.Vector(2, 0, 0)
    # define the z axis manually
    z_component = c4d.Vector(0, 0, 1)
    # or construct it using the x and y component
    z_component = x_component.Cross(y_component).GetNormaliezd()
    # the offset (the translation component) for the matrix
    off_component = c4d.Vector(100, 0, 0)
    # build the matrix
    my_transform = c4d.Matrix(off_component, x_component, y_component, z_component)
    
    #do stuff with it
    transformed = []
    for p in points:
        transformed.append(my_transform * p)
    

    Cheers
    zipit



  • @zipit
    Thank you very much for your reply. Maybe I did not describe the problem clearly. Actually, the problem I encountered is like this:

    For example : if i use rotate tool rotate my object and click my script.
    1.the axis can move correctly.
    2.but the object moves with it.(this is my problem)

    I don't want my objects to move,and I want my object to stay in place and only move the object axis

    thank you again.
    Cheers
    harry



  • Hi,

    well then you have to apply the invers of the translation you have applied to your points also to your object. Something like this:

    my_vector = c4d.Vector(0, 100, 0)
    
    for i, p in enumerate(points):
        points[i] = p + my_vector
    
    my_object.SetAllPoints(points)
    my_object.SetRelPos(my_object.GetRelPos() - my_vector)
    

    Cheers
    zipit



  • @zipit
    yes it works. but if you object is rotated on X axis 90 degrees, and click the script ,something is wrong...



  • @gheyret said in Move object axis problem in python:

    @zipit
    yes it works. but if you object is rotated on X axis 90 degrees, and click the script ,something is wrong...

    I do not have C4D here, so i cannot run your code, also "something is wrong" is a rather vague description.

    However, if you rotate your object you have to respect the matrix of that object when reapplying the invers of your vector (since you are operating in local coordinates for vertices). See my examples on matrices above. There are methods to get and set global and local matrices of objects in c4d.BaseObject.

    Cheers
    zipit



  • @zipit
    Thanks for everything. You're really been a big help for me.
    It works!!!

    Cheers
    Harry



  • Hi Harry, thanks for reaching out us.

    With regard to your topic, as suggested by @zipit - thanks a lot dude -, I strongly recommend in having a look at geometry fundamentals as presented in ScratchPixel or in our documentation at Matrix Fundamentals.

    Taking in consideration the global object orientation in space you could reconsider your code to use the inverse global matrix directly applied to your offset vector.

        # set the offset vector
        myOff = c4d.Vector(0,-100,0)
        
        # check op is valid and assume it's already a mesh
        if op is None:
            return
        
        # retrieve object global inverse matrix
        invOpMg = ~(op.GetMg())   
        
        #get the mesh points 
        points = op.GetAllPoints()
        
        # browse over them and add the offset vector left multiplied by the inverse global matrix
        for i,p in enumerate(points):
            points[i] = p + invOpMg*myOff
            
        # set points and update
        op.SetAllPoints(points)
        op.Message(c4d.MSG_UPDATE)
        c4d.EventAdd()
    

    Best, Riccardo



  • @r_gigante
    Yes! It's really helpful.🍻


Log in to reply