Solved Get World Position of Obj A's position and Set it to Obj B's position

Hi,

I want to get the world position of Obj A's position and set it into the world position of Obj B's positions. As a background, I cannot directly constraint Obj A and Obj B since they have different pivot axis.

The `Get World Position` is okay. Thanks to this thread.
I'm having trouble with the `Set World Position`. I initially thought that I can get it by reverse engineer in the previous code but I get errors.

Specifically, `TypeError: unsupported operand type(s) for /: 'c4d.Vector' and 'c4d.Matrix'` in the GlobalToLocal function.
which make sense, but, uhm, I really don't know how to solve it.

Here is the code so far

``````import c4d

# Declare object variables
newObject = doc.SearchObject("newObj")
oldObject = doc.SearchObject("oldObj")
totalPoints = len(newObject.GetAllPoints())

'''
Get the new position
'''

def LocalToGlobal(obj, local_pos):
"""
Returns a point in local coordinate in global space.
"""
obj_mg = obj.GetMg()
return obj_mg * local_pos

def GetPointGlobal(point_object, point_index):
"""
Return the position of a point in Global Space
"""
ppos = point_object.GetPoint(point_index)  # Get the point in local coords
return LocalToGlobal(point_object, ppos)  # Return the point in global space

# Get the new world position
newPos = []

for idx in range(totalPoints):
newPos.append(GetPointGlobal(newObject, idx))

'''
Assign the new position
'''
# Set the new world position

def GlobalToLocal(obj, global_pos):
"""
Returns a point in local coordinate in global space.
"""
obj_mg = obj.GetMg()
return (global_pos / obj_mg)

newLocalPos = []

for idx in newPos:
newPos.append(GlobalToLocal(oldObject, idx))
print (newLocalPos)

oldObject.SetAllPoints(newLocalPos)
oldObject.Message(c4d.MSG_UPDATE)

``````

Thank you for looking at my problem.

You can't divide by a matrix, you need to multiply by the inverted matrix (unary prefix operator ~).
Note that the multiplication in matrix calculations is not commutative.

@Cairyn

Thanks for the response. For some reason, C4D freezes. I guess it should not since I only have 8 points. I'm doing it with a simple cube.

I tried both of these codes

`return (global_pos * (-1*obj_mg))`
or
`return (~obj_mg * global_pos)`

Should I modify other parts of my code?

Hi @Bentraje,

Before providing a more complete answer, we were not sure of your final goal.
You want to define the axis of obj A to axis of obj B but the point shouldn't move in the global space, is it correct?

Cheers,
Maxime.

MAXON SDK Specialist

Sorry for the confusion.
I'm not after the axis of Obj A and Obj B. I just want them to stay as it. I'm after the world position of Object of A's points and directly plug it into Object B's points.

For better understanding,
please see a simple illustration image here:
https://www.dropbox.com/s/v3fxji8z1ct536c/c4d079_get_set_world_position.jpg?dl=0

If you need more details, please let me know. Thank you.

So regarding your script why it crashes, it's simply because you make an infinite loop with this code since you add each time something more to iterate.

``````for idx in newPos:
newPos.append(GlobalToLocal(oldObject, idx))
``````

Just to make it cleaner I've called objA and objB.
Then the needed steps are:

1. Get World Position from points of objB.
2. Convert these World Position in the local space of objA.

So as you may be already aware regarding our Matrix Fundamentals where is how to achieve both operations.

• Local Position to World Position corresponds to the obj global matrix where the position is locals to multiplied by the local position.
• World Position to Local Position corresponds to the inverse obj global matrix where the position will be locals multiplied by the world position.

Finally, before providing with the solution I would like to remind you to please always execute your code in the main function. The main reason is that if you transform your script as a button in the Dialog, every code that is in the global scope of your script is executed for each redraw of the Cinema 4D GUI (which is pretty intensive!). Moreover please always check for objects, if they exist or not try to adopt a defensive programming style in order to avoid any issues.

``````import c4d

def main():
# Declares object variables
ObjA = doc.SearchObject("A")
ObjB = doc.SearchObject("B")

# Checks if objects are found
if ObjA is None or ObjB is None:
raise ValueError("Can't found a and b object")

# Checks if they are polygon object
if not isinstance(ObjA, c4d.PolygonObject) or not isinstance(ObjB, c4d.PolygonObject):
raise TypeError("Objects are not PolygonObject")

# Checks Point count is the same for both obj
allPtsObjA = ObjA.GetAllPoints()
allPtsObjB = ObjB.GetAllPoints()
if len(allPtsObjA) != len(allPtsObjB):
raise ValueError("Object does not get the same pount count")

# Retrieves all points of B in World Position, by multipling each local position of ObjB.GetAllPoints() by ObjB.GetMg()
allPtsObjBWorld = [pt * ObjB.GetMg() for pt in allPtsObjB]

# Retrieves All points of B from World to Local Position of ObjA, by multipling each world position of ObjB by the inverse objA.GetMg()
allPtsObjANewLocal = [pt * ~ObjA.GetMg() for pt in allPtsObjBWorld]

# Sets New points position
ObjA.SetAllPoints(allPtsObjANewLocal)
ObjA.Message(c4d.MSG_UPDATE)

# Updates Cinema 4D

# Execute main()
if __name__=='__main__':
main()
``````

If you have any questions, please let me know.
Cheers,
Maxime.

MAXON SDK Specialist

Thanks for the code. The script works as expected. It's also cool that you managed to bring it to essentially three lines of codes with the list comprehension.

RE: matrix fundamentals
I was able to read that page but I kinda passed it thinking that Going Backwards section `SetMl(ml)` and `SetMg(mg) ` is only applicable to the object level and not on the component level.

RE: main function
Just wondering does it have to be in a main function (like literally the name of the function is main) or just inside the `if __name__=='__main__':`? Does C4D places special treatment to the word "main"?

I was confused at that previously and later realized that `if __name__=='__main__':` is not specific to C4D but used in python in general in checking if the script is referenced to other script, which I don't do at the moment. So I just skip it.

So would this code be just fine?

``````if __name__=='__main__':
executeMe()
``````

RE: main function
Just wondering does it have to be in a main function (like literally the name of the function is main) or just inside the `if __name__=='__main__':`? Does C4D places special treatment to the word "main"?

I was confused at that previously and later realized that `if __name__=='__main__':` is not specific to C4D but used in python in general in checking if the script is referenced to other script, which I don't do at the moment. So I just skip it.

So would this code be just fine?

``````if __name__=='__main__':
executeMe()
``````

Yes this is correct.

MAXON SDK Specialist