Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
Traverse polygon to get projected 2D points of 3D face
johnsogg
Member, Developers Posts: 14 ✭
I'm attempting to write some FS to extract 2D shapes for laser cutting. I found an Auto Layout feature that gets me most of the way there. Unfortunately I'm stuck on my misunderstanding of seemingly basic FS concepts.
This line of code is a good place for me to point to in confusion:
var faces = evaluateQuery(context, qGeometry(qOwnedByBody(bodies[i], EntityType.FACE), GeometryType.PLANE));
Obviously the lval variable could be named anything, but this implies that the result is a collection of faces, but the call qGeometry asks for planes. Which is it?
Later on, the code identifies bodies that are essentially extruded 2D shapes with some specific thickness, and we have the largest face. I'd like to be able to traverse each vertex of the largest face (in order) and project it against its plane, so I can write an SVG file or some such. Any help would be appreciated!
I am confused about the relationship between entities, bodies, and geometry. This is a larger problem, and I hope the documentation can be improved to address that. Diagrams would help. This is all about geometry, after all.
What debugging tricks should I know about? So far I'm using println, which is better than nothing, but its output is hard to read.
This line of code is a good place for me to point to in confusion:
var faces = evaluateQuery(context, qGeometry(qOwnedByBody(bodies[i], EntityType.FACE), GeometryType.PLANE));
Obviously the lval variable could be named anything, but this implies that the result is a collection of faces, but the call qGeometry asks for planes. Which is it?
Later on, the code identifies bodies that are essentially extruded 2D shapes with some specific thickness, and we have the largest face. I'd like to be able to traverse each vertex of the largest face (in order) and project it against its plane, so I can write an SVG file or some such. Any help would be appreciated!
What debugging tricks should I know about? So far I'm using println, which is better than nothing, but its output is hard to read.
Tagged:
0
Comments
In your expression, faces is an array of queries each of which resolves to exactly one face. qGeometry is a filter; the way I read that expression is:
Construct a query for all faces owned by bodies[i] and then, of those, query for the faces whose geometry is a plane. Evaluate that query and assign the result to the variable faces.
If you want to get a plane for a face, you'll have to do an evPlane or evFaceTangentPlane on that face.
Traversing vertices in order around a face is not as simple as it sounds: a face may have one or more holes in it and the outer loop or one of the holes may be a closed edge without any vertices. Currently, I recommend getting all edges of a face (using qEdgeAdjacent(face, EntityType.EDGE)) and using qVertexAdjacent to find vertices of these edges and sort them. We hope to make this process easier in the future...
The current reference on the model structure is https://cad.onshape.com/FsDoc/modeling.html but it is admittedly short on diagrams. Basically, inside the context, a good way to think about geometry is that it is a property of faces and edges (the underlying surface or curve).
On debugging, the debug function is a "visual println" and is very useful: https://cad.onshape.com/FsDoc/output.html#debug
Hope this helps and feel free to post follow-up questions.
I've progressed to the point where I can traverse the (unordered?) set of edges related to a face. Two more things for me to do:
1. Get the parametric form for each edge (e.g. circle arc, line, spline, whatever) so I can generate the equivalent of an SVG path with actual 2D points. For lines, this is easy with `qVertexAdjacent` and `evVertexPoint`, but I'm fuzzy on how to get an edge's type. Do I need to query for each possible geometric type of edge?
2. Write a text file to contain the 2D geometry. Is this possible with FeatureScript?
Just to give some context on why I'm doing this in the first place. We're making an OnShape integration for our 2D nesting system. It does not matter if the edges are all disjoint; we already have to fix input files on our server to make smooth paths out of disjoint edges.
You can get the parametric form of each edge (splines won't work currently, only lines circles, and ellipses) using evCurveDefinition
Currently pretty much the only thing you can do with splines is sample them using evEdgeTangentLines
Writing a text file directly (or any other external output) is not possible with FS (for security reasons), but, you can print to the console to make it easy to copy/paste to a text file. Or you can make an API call that evaluates an FS function against a part studio at a given microversion and use the results of the call to write a text file.
The only issue that I had was that I couldn't guarantee a proper orientation according to the normal of the face since I started from any edge and defined the orientation based on the evEdgeTangentLine for parameters 0 and 1. Apparently this is not consistent: half of my results were oriented according to the normal and the others were not. I assumed convexity to resolve this issue but it was a bit of a hack... Maybe there's a better way to do it?
Also, I knew my face had only one loop, but I'm sure I'll have examples with multiple loops in the future and not sure how I will handle the orientation problem in that case. It would be great if we could have an eval function that got the loops of each face with the ordered edges.
evEdgeTangentLine, it can accept face field among arguments. If face is specified evaluated tangent line direction reflects edge orientation in face.
And +1 for the request for some kind of "give me ordered edge paths for a face" eval function.
John, I shared my code with you, hope it helps.