[Solved] Get polygons or wires vertices to an array or list

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

[Solved] Get polygons or wires vertices to an array or list

Post by jfc4120 »

I can handle a single vertex if selected. But how do you select an entire polygon (or wire if downgraded) and the the coordinates of all the vertices in a multi list?

I have tried variations of this code:

Code: Select all

# -*- coding: utf-8 -*-

import FreeCAD,FreeCADGui
import Draft
import math
from PySide import QtGui

selX = FreeCADGui.Selection.getSelectionEx()
PrintMsg = FreeCAD.Console.PrintMessage
PrintMsg("Objects selected:\n")
for sel in selX:
  if sel.HasSubObjects:
    v = sel.SubObjects[0]
    if v.ShapeType == 'Vertex':
      print(f'SubObject[0] is Vertex at {v.Point}')
      X1 = v.Point.x *  .039370078
      print(X1)
    else:
      print(f'SubObject[0] is a {v.ShapeType}')
      X1 = v.Point.x *  .039370078
      print(X1)
  else:
    v = sel.Object.Shape
    if v.ShapeType == 'Vertex':
      print(f'Object is Vertex at {v.Point}')
      X1 = v.Point.x *  .039370078
      print(X1)
      print('here')
    else:
      print(f'Object is a {v.ShapeType}')
      X1 = v.Point.x *  .039370078
      print(X1)
I also tried code here: viewtopic.php?t=46435
Last edited by jfc4120 on Thu Mar 16, 2023 9:24 pm, edited 1 time in total.
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Get polygons or wires vertices to an array or list

Post by onekk »

Each Shape as a Vertexes property, it is not enough

Code: Select all

vtx_array = []
for obj in objects:
 vtx_array.append(obj.Shape.Vertexes)
Provided objects are DocumentObjects with a Shape property.

See:

Code: Select all

dir(Part.Shape)
['Edges', 'Faces', ... 'Shells', 'Solids', 'SubShapes', ... , 'Vertexes', ..., 'Wires',
but also:

Code: Select all

dir(Part.Wire)
['Edges', 'Faces', ... 'Shells', 'Solids', 'SubShapes', ... , 'Vertexes', ..., 'Wires',
or even:

Code: Select all

dir(Part.Edge) 
['Edges', 'Faces', ... 'Shells', 'Solids', 'SubShapes', ... , 'Vertexes', ..., 'Wires',
You have a Vertexes list for each entity, so you could make a nested list for each Shape, Wires, Edge so you could have even a multilevel extraction of Vertexes at Shape, Wire and Edge level.

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/
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: Get polygons or wires vertices to an array or list

Post by jfc4120 »

@onekk None of the above worked, however I found an older post you had:

viewtopic.php?t=46435

You had:

Code: Select all

select=FreeCADGui.Selection.getSelection()[0]
wire = select.Shape.Wires[0]

for pts in obj.Wires[0].Vertexes:
    print(pts.Point)
Gave error on obj.Wires so I changed to:

Code: Select all

select=FreeCADGui.Selection.getSelection()[0]
wire = select.Shape.Wires[0]

for pts in wire.Vertexes:
    #print(pts.Point.x *  .039370078)
    print(pts.Point)
Works great, thanks. :D :idea: :roll:

Edit:

The funny part, I tried it yesterday and gave up, but after looking it over is when I thought to try the:

Code: Select all

for pts in wire.Vertexes:

:oops:

Output:

Code: Select all

15:08:46  Vector (-150.06994531332884, -1483.2147216796875, 0.0)
15:08:46  Vector (-1286.6182246097892, 485.34464331676486, 0.0)
15:08:46  Vector (-3559.7147832027104, 485.3446433167651, 0.0)
15:08:46  Vector (-4696.263062499171, -1483.2147216796873, 0.0)
15:08:46  Vector (-3559.7147832027113, -3451.7740866761396, 0.0)
15:08:46  Vector (-1286.618224609791, -3451.7740866761405, 0.0)
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Get polygons or wires vertices to an array or list

Post by onekk »

jfc4120 wrote: Thu Mar 16, 2023 8:14 pm ...
@onekk None of the above worked
...
above code ie the dir() thing should work as they are directly showing the property of an object.

Hovewer

Code: Select all

obj.Shape.Wires[0]
provided that obj is a DocumentObject will return a Part.Wire object so it is working, at least for a Wire.

It is all about hierarchy.

I have to check first code (I have told you tha was written using memory) in a real situation.

Let me see tomorrow as probably I have some spare time.

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/
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: [Solved] Get polygons or wires vertices to an array or list

Post by jfc4120 »

@onekk all is good, as I have working code now. But yes reply if you need to explain something as I am still learning. :?
edwilliams16
Veteran
Posts: 3107
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: [Solved] Get polygons or wires vertices to an array or list

Post by edwilliams16 »

@jfc4120

I think you are missing the point of Carlo's post. Suppose you make a number of selections - say a vertex and a face from Object1 and an edge from Object2

Code: Select all

sels = Gui.Selection.getSelection()
returns a list of "Selection Objects" in this case two of them, one for Object1 and one for Object2. Assuming they are objects that have a Shape
(ie made by Part, Part Design, Draft etc. not Meshes), then sel[0].Shape and sel[1].Shape contain the topological and geometrical information about the entire objects - BUT - DO NOT contain information about which vertices/edges/faces that were selected - only the objects that contained them.

If for instance, you wanted the location of all the vertices in Object1:

Code: Select all

for vertex in sels[0].Shape.Vertexes:
    print(vertex.Point)
Suppose you wanted the vertices on a face by face basis:

Code: Select all

for i, face in enumerate(sels[0].Shape.Faces):
    print(f'Face{i+1}')
    for v in face.Vertexes:
        print(v.Point)
 
Objects have faces, edges and vertexes
Faces have edges and vertexes
Edges have Vertexes
Vertexes have locations (point)

This is what is refered to as Topology


However, suppose you want information about the particular vertex/edge/face/objects(s) you selected - not just the object in which they were contained.
Now we need Gui.Selection.getSelectionEx(), in fact to be compatible with links, you should use Gui.Selection.getSelectionEx('', 0)

In the example above

Code: Select all

for sel in Gui.Selection.getSelectionEx('',0):
    print(f'\n{sel.Object.Name}')
    for path in sel.SubElementNames if sel.SubElementNames else ['']:
        subobj = sel.Object.getSubObject(path)
        print(f'   {subobj.ShapeType}')

     
sel.Object contains the selected object, subobj contains the selected subobject (face/edge/vertex)

replacing subobj = sel.Object.getSubObject(path) with subobj = sel.Object.getSubObject(path, retType = number) returns additional optional information about the subobj like its global Placement. Here's the help:

Code: Select all

>>> help(sel.Object.getSubObject)
Help on built-in function getSubObject:

getSubObject(...) method of Part.Feature instance
    getSubObject(subname, retType=0, matrix=None, transform=True, depth=0)
    
    * subname(string|list|tuple): dot separated string or sequence of strings
    referencing subobject.
    
    * retType: return type, 0=PyObject, 1=DocObject, 2=DocAndPyObject, 3=Placement
    
        PyObject: return a python binding object for the (sub)object referenced in
        each 'subname' The actual type of 'PyObject' is implementation dependent.
        For Part::Feature compatible objects, this will be of type TopoShapePy and
        pre-transformed by accumulated transformation matrix along the object path.  
    
        DocObject:  return the document object referenced in subname, if 'matrix' is
        None. Or, return a tuple (object, matrix) for each 'subname' and 'matrix' is
        the accumulated transformation matrix for the sub object.
    
        DocAndPyObject: return a tuple (object, matrix, pyobj) for each subname
    
        Placement: return a transformed placement of the sub-object
    
    * matrix: the initial transformation to be applied to the sub object.
    
    * transform: whether to transform the sub object using this object's placement
    
    * depth: current recursive depth
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: [Solved] Get polygons or wires vertices to an array or list

Post by jfc4120 »

@edwilliams16 thanks, I have learned a lot from both of you.

I used his code, just a minor tweak, it works.

I am still not positive when to use: getSelectionEx verses getSelection.

His code used:

Code: Select all

select = FreeCADGui.Selection.getSelection()[0]
Whereas in some code:

Code: Select all

selX = FreeCADGui.Selection.getSelectionEx()
Like:

Code: Select all

selX = FreeCADGui.Selection.getSelectionEx()  ###This top portion is from you.
PrintMsg = FreeCAD.Console.PrintMessage
PrintMsg("Objects selected:\n")
KOUNT = 0
# added
for sel in selX:
    KOUNT = KOUNT + 1
    v = sel.Object.Shape
    X = v.Point.x * .039370078
    Y = v.Point.y * .039370078
    Z = v.Point.z * .039370078
    if KOUNT == 1:
        multlist = [[X, Y, Z]]
    if KOUNT > 1:
        multlist.append([X, Y, Z])

The top portion derived from one of your answers. But as I go, I am picking up more and more. Like above, I resolved by tweaking a previous answer from @onekk .

But again I appreciate the good folks here on the forum who are willing to help. :D

I am also going to experiment with code from your answer. In this case I only wanted to get vertices of a wire and set points there., like:

Code: Select all

# -*- coding: utf-8 -*-

import FreeCAD, FreeCADGui
import Draft
import math
from PySide import QtGui

convert = 25.4

select = FreeCADGui.Selection.getSelection()[0]
wire = select.Shape.Wires[0]

KOUNT = 0
for pts in wire.Vertexes:
    KOUNT = KOUNT + 1
    X = pts.Point.x * .039370078
    Y = pts.Point.y * .039370078
    Z = pts.Point.z * .039370078
    if KOUNT == 1:
        multlist = [[X, Y, Z]]
    if KOUNT > 1:
        multlist.append([X, Y, Z])

    # print(pts.Point.x *  .039370078)
    print(pts.Point)

print(multlist)
K = KOUNT

for i in range(0, KOUNT):
    K = K - 1
    print('k', K)
    print(multlist[K][0], multlist[K][1], multlist[K][2])
    Draft.makePoint(multlist[K][0] * convert, multlist[K][1] * convert, multlist[K][2] * convert)


edwilliams16
Veteran
Posts: 3107
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: [Solved] Get polygons or wires vertices to an array or list

Post by edwilliams16 »

  • getSelection() gives info about the entire object you selected, but not about which particular subobject (vertex,edge,face) you picked.
  • getSelectionEx() also has info about the particular subObject(s) you picked
  • getSelectionEx(0,'') additionally can distinguish between linked copies of selected object/subObject. The previous methods point back to the original.
    This is required, for instance, if you need the global positioning of the linked object/face/vertex/edge.

As their use gets successively more complicated, I usually provide that minimally sufficient for the purposes of the OP.
My previous post is essential understanding for those wanting to use selections in their Macro. I assume it is documented somewhere in the wki, but I have yet to find it.
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: [Solved] Get polygons or wires vertices to an array or list

Post by onekk »

edwilliams16 wrote: Fri Mar 17, 2023 12:14 am ...
Thanks a lot, I will note down for future references.

Sadly things like these are difficult to find in the Wiki.

Kind 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/
Post Reply