Selecting edges in a script
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
Selecting edges in a script
This is a general question about selecting edges (or faces, or anything really) in a repeatable way from a script. Here's a specific case:
I have script that creates a box-like shape into which a number of channels have been cut:
I want the script to chamfer the inside edges of the top face, the vertical edges of the tabs, and the top front edge.
Clever me, I figure I'll do this manually, use ObjectsToPython to export the shape, extract a list of edges, and then code those into the script! This works... except the edges aren't assigned in the same order. I get a lovely mess. With 260 or so edges, trying to get this right by iterating through would be crazy.
Is there a way to either compute what the edge numbers would be in a case like this or to do something like "select all edges in this bounding box"?
Or is there another approach I'm just not seeing?
I have script that creates a box-like shape into which a number of channels have been cut:
I want the script to chamfer the inside edges of the top face, the vertical edges of the tabs, and the top front edge.
Clever me, I figure I'll do this manually, use ObjectsToPython to export the shape, extract a list of edges, and then code those into the script! This works... except the edges aren't assigned in the same order. I get a lovely mess. With 260 or so edges, trying to get this right by iterating through would be crazy.
Is there a way to either compute what the edge numbers would be in a case like this or to do something like "select all edges in this bounding box"?
Or is there another approach I'm just not seeing?
Re: Selecting edges in a script
Hello it depends in how you have created the shapes.
If you think of scripting a solid like you "think in the gui" you will complicate things.
as the edges seems created hollowing (subtracting a shape) multiple time, you could reduce the problem creating an hollowing shape that will subtract a portion of toroid on top and bottom so a slightly complicate "hollowing shape" will reduce many further operation.
or you could selet the wires that are on the upper face and offset them creating paths to make a sweep or a pipeshell that will subtract things.
or you could create the base, position the hokes as wires and reuse these wires directly to obtain the paths to mske the sweeps.
or ....
But if the shape is derived say from a step file you have to obtain wires, so you could obtain the upper face, use his wires and find a geometric way to select the proper edges and...
So how did you made the solid?
Plus, put the info required in the post atarting with "IMPORTANT:" in the top part of the forum so we have an idea of what version of FC you are using.
Some code is very useful if you have build the shape from scratch so maybe someone that want help you should do less guesses and be more "centered" on your problem.
Regards
Carlo D.
If you think of scripting a solid like you "think in the gui" you will complicate things.
as the edges seems created hollowing (subtracting a shape) multiple time, you could reduce the problem creating an hollowing shape that will subtract a portion of toroid on top and bottom so a slightly complicate "hollowing shape" will reduce many further operation.
or you could selet the wires that are on the upper face and offset them creating paths to make a sweep or a pipeshell that will subtract things.
or you could create the base, position the hokes as wires and reuse these wires directly to obtain the paths to mske the sweeps.
or ....
But if the shape is derived say from a step file you have to obtain wires, so you could obtain the upper face, use his wires and find a geometric way to select the proper edges and...
So how did you made the solid?
Plus, put the info required in the post atarting with "IMPORTANT:" in the top part of the forum so we have an idea of what version of FC you are using.
Some code is very useful if you have build the shape from scratch so maybe someone that want help you should do less guesses and be more "centered" on your problem.
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/
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.
Blog: https://okkmkblog.wordpress.com/
Re: Selecting edges in a script
I use chamfer to create picture frame from cubes. I select faces and search for edges instead. But I select cubes and cut pads I guess it is TNP because the faces order are different at pad and the cube no longer exists
If you want to make chamfer from selected edge it would be even simpler to do. But this is the same problem as I asking here get face number from face object. If you will select the edges you get list of objects but chamfer expect to get list of edge labels (they are strings). As I remember there is no such thing like Edge.Label
If you want to make chamfer from selected edge it would be even simpler to do. But this is the same problem as I asking here get face number from face object. If you will select the edges you get list of objects but chamfer expect to get list of edge labels (they are strings). As I remember there is no such thing like Edge.Label
Thanks
Darek
github.com/dprojects
workbench for woodworking is available at: github.com/dprojects/Woodworking
Re: Selecting edges in a script
Hi Carlo,onekk wrote: ↑Sun Jul 31, 2022 2:57 pm
So how did you made the solid?
Plus, put the info required in the post atarting with "IMPORTANT:" in the top part of the forum so we have an idea of what version of FC you are using.
Some code is very useful if you have build the shape from scratch so maybe someone that want help you should do less guesses and be more "centered" on your problem.
Good points, although what I'm really hoping for is a more generalized approach so I can solve the same kind of problem in the future.
Running FC 0.20 here's the code that creates the shape. A couple of notes:
box.insert returns a set of points that contains the XY profile of the overall shape.
h.xyz() returns a Vector.
Code: Select all
def make(self, size, width, depth, height):
box = StorageBox.StorageBox()
points = box.insert(width, depth)
margin_x = 9
count_x = int((box.size_x - 2 * margin_x + 2) // (size + 2))
extent_x = count_x * (size + 2) - 2
offset_x = (box.size_x - extent_x) / 2
margin_y = 3 + 5
range_z = height * box.unit_height - box.floor_thickness - 3
shift = range_z * math.sin(math.radians(self.tilt))
size_y = size + shift
count_y = int((box.size_y - shift - 2 *margin_y + 2) // (size + 2))
extent_y = count_y * (size + 2) - 2 + shift
offset_y = 3
# Create a solid insert
insert = h.poly_to_face(points).extrude(h.xyz(z=range_z))
# Cut the holes out of the insert
# Make a quadrilateral face in the YZ plane to represent the tilted profile,
# Extrude in X to get the tilted prism.
hole_points = [
h.xyz(), h.xyz(y=size), h.xyz(0, size_y, range_z), h.xyz(0, shift, range_z), h.xyz()
]
hole = h.poly_to_face(hole_points).extrude(h.xyz(size))
for x in range(count_x):
for y in range(count_y):
hole.Placement = Placement(h.xyz(offset_x + x * (size + 2), offset_y + y * (size + 2)), Rotation())
insert = insert.cut(hole)
# Cut Y channels out
channel_points = [
h.xyz(), h.xyz(y=extent_y - shift), h.xyz(0, extent_y, range_z), h.xyz(0, 0, range_z), h.xyz()
]
tab = size / 3
channel = h.poly_to_face(channel_points).extrude(h.xyz(size - 2 * tab))
for x in range(count_x):
channel.Placement = Placement(h.xyz(offset_x + tab + x * (size + 2)), Rotation())
insert = insert.cut(channel)
-
- Veteran
- Posts: 3106
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Selecting edges in a script
You could select edges inside a selection cube of your choice in your script this way:
Code: Select all
def edgesInBoundBox(shp, xmin, ymin, zmin, xmax, ymax, zmax, all = True, show = True):
''' return indices of edges of shp in the cube BB
all = True: completely enclosed
all = False: at least one vertex enclosed
show = True: display wireframe bounds'''
bb = App.BoundBox(xmin, ymin, zmin, xmax, ymax, zmax)
if show:
bbBox = Part.makeBox(xmax - xmin, ymax - ymin, zmax - zmin, App.Vector(xmin, ymin, zmin))
part = Part.show(bbBox)
part.ViewObject.DisplayMode = 'Wireframe'
indList = []
for i, edge in enumerate(shp.Edges):
if all:
if bb.isInside(edge.BoundBox):
indList.append(i)
else:
if bb.isInside(edge.Vertexes[0].Point) or bb.isInside(edge.Vertexes[1].Point):
indList.append(i)
return indList
Re: Selecting edges in a script
That's exactly what I'm looking for. Thanks!!edwilliams16 wrote: ↑Sun Jul 31, 2022 6:21 pm You could select edges inside a selection cube of your choice in your script this way:
Re: Selecting edges in a script
You don't have to switchApproxiamtion if you cross the axis? Also the BoundBox can be something like 1.0000004, but is normal at FreeCAD, rubbish you said right?, so I had to round it ! and convert it back to compare ! getEdgeIndexByKey(iObj, iBoundBox)edwilliams16 wrote: ↑Sun Jul 31, 2022 6:21 pmCode: Select all
bbBox = Part.makeBox(xmax - xmin, ymax - ymin, zmax - zmin, App.Vector(xmin, ymin, zmin))
Thanks
Darek
github.com/dprojects
workbench for woodworking is available at: github.com/dprojects/Woodworking
-
- Veteran
- Posts: 3106
- Joined: Thu Sep 24, 2020 10:31 pm
- Location: Hawaii
- Contact:
Re: Selecting edges in a script
The script here assumes you construct your bbBox to properly enclose the edges/vertices you want to select. Its behavior will be undefined if you nominally run your box face through the vertex, because of potential numerical error.dprojects wrote: ↑Sun Jul 31, 2022 6:48 pmedwilliams16 wrote: ↑Sun Jul 31, 2022 6:21 pmCode: Select all
bbBox = Part.makeBox(xmax - xmin, ymax - ymin, zmax - zmin, App.Vector(xmin, ymin, zmin))
I expect it to be more robust to use the provided isEqual() methods to compare faces/edges etc. than to cook up your own using Bounding Boxes and your own numerical error criteria. e. g.
Code: Select all
def getFaceIndex(iShp, iFace):
for i, face in enumerate(iShp.Faces):
if iFace.isEqual(face):
return i
return -1
Code: Select all
def getEdgeIndex(iShp, iEdge):
for i, edge in enumerate(iShp.Edges):
if iEdge.isEqual(edge):
return i
return -1
Re: Selecting edges in a script
But how do developers not have to cook if there are no basic functions in the API? This is why my question was there, why is there no such function in the API? I don't want to believe that no one has been able to figure out how to do it for 20 years? and now they invented? sorry, you invented ok so if you invented maybe you finally will add it, and all developers will be happy?edwilliams16 wrote: ↑Sun Jul 31, 2022 7:17 pm than to cook up your own using Bounding Boxes and your own numerical error criteria. e. g.
EDIT: That was the example I already gave, for edges:Code: Select all
def getFaceIndex(iShp, iFace): for i, face in enumerate(iShp.Faces): if iFace.isEqual(face): return i return -1
Code: Select all
def getEdgeIndex(iShp, iEdge): for i, edge in enumerate(iShp.Edges): if iEdge.isEqual(edge): return i return -1
Thanks
Darek
github.com/dprojects
workbench for woodworking is available at: github.com/dprojects/Woodworking
Re: Selecting edges in a script
With respect, I don't think many developers are trying to access faces (or edges) in the same way that you are. There are methods for identifying these things that are more intuitive for most... the bounding box and indexing an array method works perfectly for me, and while there is probably a "get all the faces in this bounding box" method in the Open Cascade API and the core of FreeCAD probably makes great use of it, there might not be a good argument for promoting that to the Python API.dprojects wrote: ↑Sun Jul 31, 2022 7:39 pm But how do developers not have to cook if there are no basic functions in the API? This is why my question was there, why is there no such function in the API? I don't want to believe that no one has been able to figure out how to do it for 20 years? and now they invented? sorry, you invented ok so if you invented maybe you finally will add it, and all developers will be happy?
Rather than say "no one has been able to figure it out for 20 years" when it's not clear that anyone else has ever even wanted to "figure it out", it's more helpful to say "any reason why we can't have this functionality in the Python API, I'd add it but don't have the C programming skills" and see if a positive discussion comes from it. Open source is only what people contribute to it. It's much more helpful to talk about what it could become, rather than what is isn't.