Hey @datamilch,
Thank you for reaching out to us. In general we prefer if users open new threads for their questions. You are of course welcome to link to an existing topic and say that your question relates to that. The reason for that is that even when the question of another user is right on-topic as it is here the case with your question (which in the most other cases will not be true), it still tends to derail a thread. I have not forked your question since you are on-topic.
About your Question
I think this thread can be a bit opaque for beginners as @Cairyn and @m_adam have approached this topic on a very technical level.
The important thing to understand, is that both BaseObject.GetMg() and the fields of a c4d.Matrix, i.e., off, v1, v2, and v3 return a copy of the requested object, not an instance. In plain terms this means that the matrix/vector one retrieves is not the one used by the object/matrix but a copy of it.
So, we can totally do this:
>>> mg
Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0))
>>> mg.off.x = 5
but it does not do what we think it would do, we changed the x-value of the returned copy, not the off vector used by the mg instance.
>>> mg.off.x
0.0
>>> mg
Matrix(v1: (1, 0, 0); v2: (0, 1, 0); v3: (0, 0, 1); off: (0, 0, 0))
But we can certainly set the x-component of the global offset of an object in one line.
import c4d
cube: c4d.BaseObject = c4d.BaseObject(c4d.Ocube)
# ONE: Using parameter access
# We set the the x component of the global position and the global rotation using parameter access.
# There are also parameters for the relative, aka local, transform values, as well as special things
# like a frozen transform. There are also functions on BaseObject which do the same thing but at
# least I never use them.
# See: https://developers.maxon.net/docs/py/2024_3_0/classic_resource/base_list/obase.html
cube[c4d.ID_BASEOBJECT_GLOBAL_POSITION,c4d.VECTOR_X] = 9.9
cube[c4d.ID_BASEOBJECT_GLOBAL_ROTATION] = c4d.Vector(0, 0, c4d.utils.DegToRad(45))
# TWO: Use matrix and vector constructors
# In three steps ...
mg: c4d.Matrix = cube.GetMg()
mg.off = c4d.Vector(9.9, mg.off.y, mg.off.z)
cube.SetMg(mg)
# ... or in two steps, although this is a bit stupid.
mg: c4d.Matrix = cube.GetMg()
cube.SetMg(c4d.Matrix(c4d.Vector(9.9, mg.off.y, mg.off.z), mg.v1, mg.v2, mg.v3))
# THREE: Using transforms
# This is not exactly the same as the two other cases, but it is the most common operation. Here we
# do not set the global x-position of #cube to 9.9, but we move it 9.9 units in the x-direction.
# In code we often operate on objects with the identity transform/matrix, i.e., which "sit at origin
# with the standard size and orientation". In that case transforms act the same as if we would just
# set these values. The other case is that you have an object at (1, 2, 3) and then move it (3, 2, 1)
# units, transforms also work for this. For the case where the object is at (1, 2, 3) and you want
# to _set_ it to (9.9, 2, 3) a transform won't work unless you do the math.
# Freshly instantiated objects have the identity transform, we can just pile transforms on top of
# that to "set" the values.
sphere: c4d.BaseObject = c4d.BaseObject(c4d.Osphere)
# Just move it 9.9 units in the x-direction.
sphere.SetMg(sphere.GetMg() * c4d.utils.MatrixMove(c4d.Vector(9.9, 0, 0)))
# Or first move it 9.9 units in the x-direction and then rotate it 45 degrees around the z-axis. This
# would also "pile" onto the previous transform we have already applied. Note that matrix
# multiplication is also not commutative, i.e., first moving something and then rotating it (might)
# yield something different than first rotating and then moving.
sphere.SetMg(sphere.GetMg() * c4d.utils.MatrixMove(c4d.Vector(9.9, 0, 0)) *
c4d.utils.MatrixRotZ(c4d.utils.DegToRad(45)))
Cheers,
Ferdinand