Is ".getGlobalPlacement()" working correctly for body/part?

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
pablogil
Posts: 882
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Is ".getGlobalPlacement()" working correctly for body/part?

Post by pablogil »

Hi,

I'm trying to get the global coordinates of an object's vertex (AdditivePart) inside a body.
If I use:

Code: Select all

Gui.Selection.getSelection()[0].getGlobalPlacement()
it just gives me the AdditivePart origin "global coordinates" not the vertex coordinates in global coordinates... is that normal?
It works correctly for "old parts" (Part workbench) but not for the new PartDesign...

How can I get the global coordinates of a "subobject" of a body or "new part"?
Thanks
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by ickby »

Hello,

I don't fully understand your question. GlobalPlacement means the placement of a document object in the global CS. It calculates the objects own placement together with all paretn container placements, like bodies and parts. As a placement in FreeCAD is the general way of defining a transformation, it gives you the corect transformation of the document object in global CS. This works for any kind of document object in FreeCAD.

It does not calculate geometry entity placement, like a vertex. But using "Gui.Selection.getSelection()[0]" gives you a document object anyway, not a subobject.
User avatar
pablogil
Posts: 882
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by pablogil »

Sorry for my bad explanation...
Yes, you are indeed right but I'm having problems getting the global placement (document origin) of a vertex of a body/part while with that command I could get the global coordinates of a "Part workbench" part so I thought it was some kind of bug with the new Part Design workbench...
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
User avatar
pablogil
Posts: 882
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by pablogil »

For instance, how to get the placement refered to global coordinates (document origin) of the following vertex:
placement.png
placement.png (311.07 KiB) Viewed 2140 times
Knowing that the "part container" has a placement offset and rotations and the cube itself also has an offset and rotations (this time referred to the "part container")

I'm doing something like the following but it's not fully working and I really think is a crazy way to do it:

Code: Select all

angleUV = degrees(atan(Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.y/Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.x))
angleFeature = degrees(atan(Gui.Selection.getSelection()[0].Placement.Base.y/Gui.Selection.getSelection()[0].Placement.Base.x))
anglePart = Gui.Selection.getSelection()[0].getGlobalPlacement().Rotation.toEuler()[0]
angleXYFeature = angleUV + anglePart
angleXYElement = angleFeature + anglePart
posGlobalX = Gui.Selection.getSelection()[0].getGlobalPlacement().Base.x - sqrt(pow(Gui.Selection.getSelection()[0].Placement.Base.x,2)+pow(Gui.Selection.getSelection()[0].Placement.Base.y,2)) * cos(radians(angleXYElement)) + sqrt(pow(Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.x,2)+pow(Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.y,2)) * cos(radians(angleXYFeature))
posGlobalY = Gui.Selection.getSelection()[0].getGlobalPlacement().Base.y - sqrt(pow(Gui.Selection.getSelection()[0].Placement.Base.x,2)+pow(Gui.Selection.getSelection()[0].Placement.Base.y,2)) * sin(radians(angleXYElement)) + sqrt(pow(Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.x,2)+pow(Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.y,2)) * sin(radians(angleXYFeature))
posGlobalZ = Gui.Selection.getSelectionEx()[0].SubObjects[0].Point.z - Gui.Selection.getSelection()[0].Placement.Base.z + Gui.Selection.getSelection()[0].getGlobalPlacement().Base.z
Any idea?
Thanks
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by ickby »

ah well, it is simpler than your code, but unfortunately also a bit more involved than it actually should be. You need to know a few things:

1. Historically, a subshape, like a vertex, gets its value from the calculation "shapeplacement*Vertexpoint". E.g. for a default box there is a vertex at (0,0,0). If you add the placement (10,10,10) to the box, this vertex will have the value (10,10,10) afterwards (vertex.Point = (10,10,10))

2. With the introduction of stacked CS (Parts and bodies etc.) the system of point 1 is still in place, but referes not to the global CS anymore, but always to the CS one level higher. E.g. if the box is in a Part, our Vertex of point 1 will still have the value (10,10,10), but this relates to the Parts origin. If the Part is moved too, this is not the global point of the vertex.

3. getGlobalPlacement() calculates you the correct placement of a hirarchy of containers like Parts and bodies. Normally one would get this placement, and simply transforms the Vertex point with this placement by box.getGlobalPlacement().multVec(vertex.Point). HOWEVER, as shown in point 1, the vertex point already includes the box placement. Hence doing that would include this placement twice. So to get the correct placement which you can multiply with the vertex you need to remove the box placement from the global one. this works like this:

Code: Select all

p = Box.getGlobalPlacement().multiply(Box.Placement.inverse())
value = p.multVec(Box.Shape.Vertexes[0])
4. Alternative way: To avoid this hassle, simply make a copy of the box and assign it the correct global placement.

Code: Select all

newBox = Box
newBox.Placement = Box.getGlobalPlacement()
value = newBox.Shape.Vertexes[0]

Additional comment: What you see here is the result of an unfortunate mix of concepts (stack of local CS vs. global geometry values). This results from the fact, that the placement hirarchy was introduced later, and that it works different than what was available before. However, changing the how the parts work would break just too many things. Hence we need to live with that.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by DeepSOIC »

ickby wrote: Wed Apr 04, 2018 6:59 am

Code: Select all

newBox = Box     #does not copy anything
newBox.Placement = Box.getGlobalPlacement()     #moves the original box
value = newBox.Shape.Vertexes[0]
You probably wanted to write this:

Code: Select all

box_shape = Box.Shape.copy()
box_shape.Placement = Box.getGlobalPlacement()
vertex_global_pos = box_shape.Vertexes[0].Point
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by ickby »

DeepSOIC wrote: Wed Apr 04, 2018 11:03 am You probably wanted to write this:
ah thanks for the correction, you are right, that was what I intended.
User avatar
pablogil
Posts: 882
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by pablogil »

Hi guys,

I've been trying hard but it doesn't work for me... with your snippets I cannot get the real global placement of a vertex inside a body/part object. I have created an example so that you, if have time, can test it out:
example.png
example.png (297.78 KiB) Viewed 2026 times
The target is to get the "project coordinates" of the vextex in green. As for reference, I have applied a transformation to:
  • the Body itself: [Pos=(10,10,10), Yaw-Pitch-Roll=(0,-15,0)]
  • the Box inside the Body: [Pos=(10,10,10), Yaw-Pitch-Roll=(0,-15,0)] (relative to Body, of course)
Any idea?
Thanks!
Attachments
example.FCStd
(16.45 KiB) Downloaded 40 times
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by ickby »

Hello,

with your axample I can calculate the global placement as expected.

1. If you preselect the vertex in FreeCAD, you see in the task bar it global value: (25.7, 20, 27.2). That is the value you want.
2. The taskbar also shows you the name as Vertex6. This gives you the information that this is the 6th vertex in the box, hence the index will be 5
3. You use the code snippet we dicsussed

Code: Select all

b = App.ActiveDocument.Box.Shape.copy()
b.Placement = App.ActiveDocument.Box.getGlobalPlacement()
b.Vertexes[5].Point
>>> Vector (25.731, 20.0, 27.247)
The value matches the one of the taskbar. Everything seems fine.
User avatar
pablogil
Posts: 882
Joined: Wed Nov 26, 2014 3:19 pm
Location: Badajoz (Spain)
Contact:

Re: Is ".getGlobalPlacement()" working correctly for body/part?

Post by pablogil »

Oh yes!
I see my error now... I was trying to get the vertex with:

Code: Select all

Gui.Selection.getSelection()[0].Shape.Vertexes[0].Point
and it was giving me the first vertex but not the one I was selecting...
Then, how could I get that selected vertex index programatically?

Thanks!!
Dark and Light stylesheets v2.0 to theme your FreeCAD UI, more information here
Post Reply