[Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
freedman
Veteran
Posts: 3441
Joined: Thu Mar 22, 2018 3:02 am
Location: Washington State, USA

[Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Post by freedman »

I'm trying to position an object to a selected vertex; In my macro I select the object and then select a stand alone vertex that I created in Sketcher. The vertex can be seen in the 3D because it's normal geo. I'm not in Sketch-edit.

The best way I can think of is to use getGlobalPlacement() of the vertex and then make my object use that as a placement. I have some code that is 50 lines long and very hard to understand, layers of this and that for adjusted placements, offsets, Part containers; is there some simple way to perform this:

x = myVertex.getGlobalPlacement()
myObject.Placement= setGlobalPlacement(x)

Of coarse there is no command setGlobalPlacement(). It just seems like such a simple concept since we can get a global Placement.

Thanks for any ideas.
Last edited by freedman on Mon Nov 29, 2021 7:44 pm, edited 1 time in total.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: getGlobalPlacement(), how do I setGlobalPlacement()

Post by onekk »

Placement is composed by two element,
  1. "Placement"
  2. Rotation

it is almost easy to see using:

Code: Select all

print(obj.Placement)
You get info about placement and rotation

Code: Select all

Placement [Pos=(0,0,0), Yaw-Pitch-Roll=(0,0,0)]

using:

Code: Select all

print(dir(obj.Placement))
you will obtain:

Code: Select all

['Base', 'Matrix', 'Rotation', '__abs__', '__add__', '__and__', '__bool__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__xor__', 'copy', 'inverse', 'isIdentity', 'move', 'multVec', 'multiply', 'pow', 'rotate', 'sclerp', 'slerp', 'toMatrix', 'translate']
Simply use:
  1. Base for the "Translation" part
  2. Rotation for the rotation
So maybe something similar:

Code: Select all

DOC = FreeCAD.ActiveDocument  

pl1 = obj.Placement
pos1 = pl1.Base
rot1 = pl1.Rotation
pos2 = Vector() # your new placement
obj.Placement = FreeCAD.Placement (pos2, rot1)

DOC.recompute()
Hope it helps

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: getGlobalPlacement(), how do I setGlobalPlacement()

Post by ickby »

Global placement is the cummulative placement of the object itself and all its parent Containers. There cannot be a setglobal() as it would be undefined how to distribute the placement between object and parents.
openBrain
Veteran
Posts: 9034
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: getGlobalPlacement(), how do I setGlobalPlacement()

Post by openBrain »

I have to disagree with @ickby. To me your request makes sense, as I understand it as "set object placement so it maps to a vertex, both potentially being in different CS".
This is just a few calculus. Lets consider :
* obj : the object to move
* sk : the object owning the target vertex (called 'sk' because you said its a sketch, but can virtually be anything)
* id : the id of the target vertex in 'sk' shape ('id' is basically 'name-1', for example "Vertex3" has id = 2)
As you're targeting a vertex, there's no way to define a particular rotation for the object so I'll leave it unchanged

Code: Select all

skOffset = sk.getGlobalPlacement().multiply(sk.Placement.inverse()) # get sk root in GCS
targetPos = skOffset.multVec(sk.Shape.Vertexes[id].Point) # get target point coordinates in GCS
objOffset = obj.getGlobalPlacement().multiply(obj.Placement.inverse()) # get obj root in GCS
obj.Placement.Base = objOffset.inverse().multVec(targetPos) # move obj origin to sk.id
And it's done :)
freedman
Veteran
Posts: 3441
Joined: Thu Mar 22, 2018 3:02 am
Location: Washington State, USA

Re: getGlobalPlacement(), how do I setGlobalPlacement()

Post by freedman »

openBrain, Thank you very much, I could not put that together. It took me about 10 minutes to get this working since I already had the sketch, index-1, object. You made my day. :)
And you were correct about object rotation, let it be.

Here I added the code for when I pick the vertex, Stored_obj is the object I selected prior.

Code: Select all

if self.sk.TypeId == "Sketcher::SketchObject":
    self.sel = Gui.Selection.getSelectionEx()
    for so in self.sel:
        for sub in so.SubElementNames:
            if "Vertex" in sub:
                self.current_index = eval(sub.lstrip('Vertex'))
                skOffset = self.sk.getGlobalPlacement().multiply(self.sk.Placement.inverse()) # get sk root in GCS
                targetPos = skOffset.multVec(self.sk.Shape.Vertexes[self.current_index-1].Point) # get target point coordinates in GCS
                objOffset = self.stored_obj.getGlobalPlacement().multiply(self.stored_obj.Placement.inverse()) # get obj root in GCS
                self.stored_obj.Placement.Base = objOffset.inverse().multVec(targetPos) # move obj origin to sk.id
openBrain
Veteran
Posts: 9034
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: getGlobalPlacement(), how do I setGlobalPlacement()

Post by openBrain »

freedman wrote: Mon Nov 29, 2021 7:44 pm Here I added the code for when I pick the vertex, Stored_obj is the object I selected prior.
If vertex is currently selected, you can get a direct reference to it (as well as the sketch) with something like :

Code: Select all

self.sel = Gui.Selection.getSelectionEx()
for so in self.sel:
    if so.Object.isDerivedFrom("Sketcher::SketchObject"):
        for sub in so.SubObjects:
            if isinstance(sub, Part.Vertex):
                self.sk = so.Object # !!!!!!!! At this time you seem to already have 'self.sk' so you can skip this, but I wrote it just in case
                skOffset = self.sk.getGlobalPlacement().multiply(self.sk.Placement.inverse()) # get sk root in GCS
                targetPos = skOffset.multVec(sub.Point) # get target point coordinates in GCS
                objOffset = self.stored_obj.getGlobalPlacement().multiply(self.stored_obj.Placement.inverse()) # get obj root in GCS
                self.stored_obj.Placement.Base = objOffset.inverse().multVec(targetPos) # move obj origin to sk.id
                break
            pass #endif
        break
    pass #endif
[/quote]
freedman
Veteran
Posts: 3441
Joined: Thu Mar 22, 2018 3:02 am
Location: Washington State, USA

Re: [Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Post by freedman »

I don't know about the forum/FreeCAD structure, should this be turned into a method, formalized and tested. Options could be added for adoption of Rotations. Ultimately working towards being added to the API.

def setGlobalPlacement(motile_object, destination_object, Option)

Options:
0) no change to rotation
1) use motile object rotation (if possible)
2) use motile object parent rotation
3) use destination rotation
4) use destination parent rotation (if possible)

Not really sure what I can do but I will probably end up close to this by the time I'm done.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Post by onekk »

It depends on what you are talking about.

Usually if you deal with Part objects you usually have only the methods exposed by OCCT, internally FreeCAD will store Placement as a quaternion.

Said so Placement in FreeCAD needs more Documentation, or to be more clear more Documentation taylored for newbies, or from people that come here from other CAD, as it deals with something that is managed by the "core libraries".

It is a complex arguments, and the question is solved in different ways by Assembly??? workbenches, as it is somewhat a matter of tastes.

I've not a very deep math background and for me dealing with vectors maths is a "bad beast", so sadly I could not give useful advice.

Having some "helper methods" is a great improvement, expecially for "complex things" but so many options maybe are confusing.

Plus "if possible" seems to open a whole range of risks, of doing something that has "no sense".

There will be a reason why pos and rot have been a property for each of them.

You could ever do some "matrix manipulation" that from what i know is translated into the internal representation, when dealing with complex and subsequent rotations an translations, i have done some helpers methods that apply transformation in sequence to the Matrix, with predictable results.

But I think my code will be not useful, I have opened a "snippets thread", maybe i will publish some method here.

Sorry if my post is not clear. (probably due to the difficult concepts and my bad English)

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
openBrain
Veteran
Posts: 9034
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: [Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Post by openBrain »

freedman wrote: Tue Nov 30, 2021 4:42 pm I don't know about the forum/FreeCAD structure, should this be turned into a method, formalized and tested. Options could be added for adoption of Rotations. Ultimately working towards being added to the API.
I'm not sure adding to API is a good idea as there can be many many different needs that API method can't cover.
But maybe if you think this can be useful to others, adding this to Code snippets can be fine. ;)
freedman
Veteran
Posts: 3441
Joined: Thu Mar 22, 2018 3:02 am
Location: Washington State, USA

Re: [Solved] getGlobalPlacement(), how do I setGlobalPlacement()

Post by freedman »

I'm having another problem. When I rotate the whole group of objects (using Part container rotations) the stored object does not stay Normal to the sketch. I had this which takes the sketch (self.sel) and assigns it's rotation to the stored object.

Code: Select all

self.stored_obj.Placement.Rotation = self.sel.getGlobalPlacement().Rotation 
And thought that I could instead use this:

Code: Select all

self.stored_obj.Placement.Rotation = self.sel.getGlobalPlacement().Rotation.multiply(self.sel.Placement.Rotation.inverse())

But, Rotation doesn't have an attribute "inverse". So, what do I need to look at to Null all of the parent rotations?
Thanks all
Last edited by freedman on Fri Dec 17, 2021 6:43 am, edited 1 time in total.
Post Reply