Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:
  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. 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

johnsoggjohnsogg 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.


  • Options
    ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,180
    Answering your questions in order...

    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.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • Options
    johnsoggjohnsogg Member, Developers Posts: 14
    Thanks. I misunderstood qGeometry(faces, GeometryType.PLANE) to mean "give me planes", but instead it means "filter faces to give me only faces that are planar". And the visual debug is fabulous. Do you support breakpoints?

    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.
  • Options
    ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,180
    Sorry, no breakpoints yet.

    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.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • Options
    AdrianaAdriana Member, Developers Posts: 9 EDU
    I had a similar problem for traversing vertices in order around a face, but in my case I wanted to sample points on the boundary of a face and get them in order. I used qEdgeAdjacent to get all the faces as Ilya suggested but to sort I compared the end points instead of using qVertexAdjacent because I was sampling so I had already evaluated the points using evEdgeTangentLine. It worked fine for me and I'm happy to send you my code, though if you're not sampling using the qVertexAdjacent as Ilya suggested would probably be more efficient. 

    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.
  • Options
    lanalana Onshape Employees Posts: 700
    If you need to establish edge orientation in face use

    evEdgeTangentLine, it can accept face field among arguments. If face is specified  evaluated tangent line direction reflects edge orientation in face.

  • Options
    johnsoggjohnsogg Member, Developers Posts: 14
    Thanks for your help, Ilya. I've filled out the little form for API access and just waiting for that at this point.
  • Options
    johnsoggjohnsogg Member, Developers Posts: 14
    Adriana, yes to your code! I didn't see your comment when I posted last.

    And +1 for the request for some kind of "give me ordered edge paths for a face" eval function.
  • Options
    AdrianaAdriana Member, Developers Posts: 9 EDU
    edited November 2016
    Thanks Lana, this helps a lot. Solves the loop issue and makes my code much simpler.  

     John, I shared my code with you, hope it helps.
Sign In or Register to comment.