# Emulating Axis Mode

• On 27/03/2013 at 04:54, xxxxxxxx wrote:

Matrix maths is still not my favorite topic. I can't get this to work properly. I want to emulate the Axis Mode in Cinema, a function that
moves the object's axis to a specific point (and rotation) without changing the polygon-object's
points and children's global position (and rotation). It won't work properly, see this video.

Can someone pls point out what's wrong or maybe even explain how to do it?
Thanks!

>
> import c4d
>
> def move_axis(obj, new_matrix=c4d.Matrix()) :
> mat = obj.GetMl() * new_matrix
> if obj.CheckType(c4d.Opoint) :
> points = obj.GetAllPoints()
> for i, p in enumerate(points) :
> obj.SetPoint(i, p * mat)
> obj.Message(c4d.MSG_UPDATE)
>
> for child in obj.GetChildren() :
> child.SetMl(child.GetMl() * mat)
>
> obj.SetMl(new_matrix)
>
> def main() :
> if not op:
> return
>
> move_axis(op)
>
> main()
~~
~~
Edit: Video comes in a few seconds.

• On 27/03/2013 at 05:00, xxxxxxxx wrote:

Interesting. I just switched the matrices that are to be multiplied for the children and it seems to
work. Isn't the order un-important for matrix multiplication?

>
> import c4d
>
> def move_axis(obj, new_matrix=c4d.Matrix()) :
> mat = obj.GetMl() * new_matrix
> if obj.CheckType(c4d.Opoint) :
> points = obj.GetAllPoints()
> for i, p in enumerate(points) :
> obj.SetPoint(i, p * mat)
> obj.Message(c4d.MSG_UPDATE)
>
> for child in obj.GetChildren() : child.SetMl(mat * child.GetMl())
>
> obj.SetMl(new_matrix)
>
> def main() :
> if not op:
> return
>
> move_axis(op)
>
> main()

Thanks,
-Niklas

• On 27/03/2013 at 05:09, xxxxxxxx wrote:

Hm it still doesn't work when moving the axis to another position but the origin:

>     move_axis(op, c4d.Matrix(off=c4d.Vector(100)))

• On 27/03/2013 at 05:29, xxxxxxxx wrote:

This seems to work:

>
> import c4d
>
> def move_axis(obj, new_matrix=c4d.Matrix()) :
> mat = obj.GetMl() * ~ new_matrix
> if obj.CheckType(c4d.Opoint) :
> points = obj.GetAllPoints()
> for i, p in enumerate(points) :
> obj.SetPoint(i, p * mat)
> obj.Message(c4d.MSG_UPDATE)
>
> for child in obj.GetChildren() :
> child.SetMl(mat * child.GetMl())
> obj.SetMl(new_matrix)
>
> def main() :
> if not op:
> return
>
> move_axis(op, c4d.Matrix(off=c4d.Vector(100)))
>
> main()

Any reasons why this should not work?

Btw, I'm aware that saving the global matrix, then offseting the parent object and then
resetting the children to their previous global matrix works as well, but it is much less performant.

>
> def move_axis(obj, new_matrix=c4d.Matrix()) :
> mat = obj.GetMl() * ~new_matrix
> if obj.CheckType(c4d.Opoint) :
> points = obj.GetAllPoints()
> for i, p in enumerate(points) :
> obj.SetPoint(i, p * mat)
> obj.Message(c4d.MSG_UPDATE)
>
> children = obj.GetChildren()
> matrices = [x.GetMg() for x in children]
> obj.SetMl(new_matrix)
> [x.SetMg(m) for x, m in zip(children, matrices)]

-Niklas

• On 27/03/2013 at 06:08, xxxxxxxx wrote:

Damn Matrix Maths! New version, just switched operands. I'll try to find some information about matrix multiplication..

>
> def move_axis(obj, new_matrix=c4d.Matrix()) :
> mat = ~new_matrix * obj.GetMl()
> if obj.CheckType(c4d.Opoint) :
> points = obj.GetAllPoints()
> for i, p in enumerate(points) :
> obj.SetPoint(i, p * mat)
> obj.Message(c4d.MSG_UPDATE)
>
> for child in obj.GetChildren() :
> child.SetMl(mat * child.GetMl())
> obj.SetMl(new_matrix)

Pretty sure this won't work in all cases, again.

PS: The changed line above must also be adjusted for the other way when storing the childrens
matrix before changing the objects matrix.

• On 27/03/2013 at 08:16, xxxxxxxx wrote:

I'm puzzled why you are using local matrices throughout your code?

I don't have an example of moving just the axis handy. But I do have an example of moving the parent object without moving it's children.
It's in C++. But i think you can handle that:

``````//Freeze Children
//This code allows the parent object to move without moving it's children

{
BaseDocument *doc = GetActiveDocument();  //Get the active document
BaseObject *obj = doc->GetActiveObject(); //Get the active object
if(!obj)return FALSE;

Matrix mg_old = obj->GetMg();             //Save the parent's old matrix

Matrix mg_new;                            //This will be the parent's new matrix - set it to your liking(world Zero by default)
obj->SetMg(mg_new);                       //Apply the new matrix to the parent object
obj->Message(MSG_UPDATE);

mg_new != mg_new;                         //Invert new matrix - needed later

//Cycle through children
for (obj = obj->GetDown(); obj; obj = obj->GetNext())
{
Matrix ml_child = obj->GetMl();    //Get child's local matrix

//Bring it into the child's old global space by multiplying
//with the parent's old global matrix
Matrix mg_old_child = mg_old * ml_child;

//Set the child's new local matrix by multiplying
//with the parent's inverted new global matrix
obj->SetMl(mg_new * mg_old_child);
obj->Message(MSG_UPDATE);
}

return TRUE;
}
``````

-ScottA

• On 28/03/2013 at 15:05, xxxxxxxx wrote:

Some time ago I asked the question "I have e.g. a plane I want to rotate, not from the center, but from a specific side. So, I need to change the object axis."

Cesar did help me with the following:
"I think you can do it by change the position of the object and all his points to keep their global position."

He also provided some code that worked well for me.
Perhaps it is of interest for you.