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.

Anyone already wrote a feature script for "slotted bending" (sheet metal)?

jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
Hey,

I am currently trying to write a quick feature script to transform a sheet metal bend corner into a "slotted bend" (like described nicely over at Hackaday a while back: https://hackaday.com/2016/05/18/the-art-and-science-of-bending-sheet-metal/ ). This can already be easily done manually by drawing a sketch with a slot pattern along the bend center line onto the flattened sheet metal part in order to extrude (remove) from the part, so I thought it should be pretty easy to be automated using feature script.



Now, my practice with feature script is limited so far and it would probably take me some effort to work my way through it the hard way, that's why I'd like to kindly ask if anyone already implemented something similar? Or at least would find a feature like that useful as well and would be interested in joining me to write the script together? After all I wouldn't want to reinvent the wheel if it was already done before ;)

I assume the feature wouldn't need much more of an input rather than selecting the corresponding bend center line (the dashed construction line) and maybe additionally one of the tangent bend lines. From there I guess you can read out the related sheet metal part, the sheet thickness and then draw some slots along the center line according to your desired configuration. Llike illustrated in the Hackaday article linked above:



Looking forward to any help and/or interest in this :)

Regards,
Jonas Kühling

Best Answer

  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    Answer ✓
    @MBartlett21 @lana
    Awesome, thanks a lot for your input!

    I've come a long way in the meanwhile and had to dive a little into sparsely documented feature script terrain with regards to sheet metal functionality it seems - nonetheless, learned a ton, the feature script is done and does everything I would have hoped for.

    I decided to make the document public in case anybody would like to just use it, build on top of it or get inspiration for similar feature script projects. The feature is called "smPerforateBend" or "Perforate sheet metal bend" and can also be found via the link here:


    While I tried to comment the code where possible, it might not be the most elegant solution in every way, but it's the solution I made to work ;) In case anyone has suggestions on how to improve the feature, I'd love to hear.

    Regards,
    Jonas


    Tags: Sheet metal, Perforation, Slotted bending, hand bending, manual bending

Answers

  • brucebartlettbrucebartlett Member, OS Professional, Mentor, User Group Leader Posts: 2,137 PRO
    @MBartlett21 is the master at sheet metal FS he might be able to help if he hasn't already got one. 
    Engineer ı Product Designer ı Onshape Consulting Partner
    Twitter: @onshapetricks  & @babart1977   
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    @MBartlett21 is the master at sheet metal FS he might be able to help if he hasn't already got one. 
    Bruce, thanks for the hint, now I'm very curious about @MBartlett21 thoughts on this ;)

    Regards,
    Jonas

  • lanalana Onshape Employees Posts: 689
    If any-one decides to work on it, I'd recommend making a perforate feature which generates a pattern for multiple bends and make cuts simultaneously. Doing this as a part of each bend would make the part too slow. 
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    lana said:
    If any-one decides to work on it, I'd recommend making a perforate feature which generates a pattern for multiple bends and make cuts simultaneously. Doing this as a part of each bend would make the part too slow. 
    Thanks for the recommendation, you're right, I already noticed some performance issues during my manual workflow for this, which lead me to do only one single sketch on the flat pattern for all bends I'd like to be perforated within the sheet metal part.

    For the feature script I am wondering, if this would be easily possible, since each bend allowance in the flat view (space between the two tangential lines) may not be equally wide depending on the bend angle and potentially individual bend radius. So I thought about selecting the dashed bend centerline to determine the position and length of the perforation, and selecting one of the tangent lines to determine the actual width of this particular bend. I guess it might be difficult to select multiple centerlines and then assign a specific corresponding tangent line to each of them - in terms of, how would I set up the feature selection dialog for this problem...

    The alternative would be to at least be able to perforate each and every bend of one sheet metal part by just selecting the whole part itself as an input. In this case I'd need to somehow query all the bend lines within a sheet metal flat pattern kind of around the back automatically.. And their individual bend allowance width.. Not sure if this can be done?

    Makes me think that it might be possible to at least query the corresponding bend parameters of a selected bend centerline? In the worst cast, I'd need to calculate the bend allowance width within the feature script from the underlying k-factor, bend radius, sheet thickness etc. Would indeed be nice to only having to select the desired bend centerlines in order to perforate those selected bends.

    Open for any hint or code snippet or some kind of similar script that may work as a starting point :#

    Regards,
    Jonas
  • lanalana Onshape Employees Posts: 689
    @jonaskuehling

    Here is a quick example of navigating from bend centerline to its geometry in flat https://cad.onshape.com/documents/31a6fe1973cd763943f93411/w/e4d5dc964f4b13c1c43380f5/e/464e02f4cf38942dbd62a644

  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    @lana Oh awesome, that's already half the job done, thank you very much! Should be pretty much a piece of cake from there, looks totally doable to me now. NICE.

    Will post my results when I got something working (or run into issues) ;) Thanks a bunch again!
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    @lana I'm working my way through step by step, but running into issues when trying to create a sketch on the flat pattern. Debugging shows, that the created plane potentially is located in the "normal" 3D space and not in the flat view area.. I couldn't yet figure out how to actually create a sketch on the flat geometry - do you have a quick hint for me what I'm missing here?


    Any input would be very much appreciated :)

  • lanalana Onshape Employees Posts: 689
    There is some trickery to creating sketch on a flat. You need to give it a face of flat pattern as a reference, not just a Plane. Use
    const sketch = newSketch(context, id + "cutPattern", {`sketchPlane` : faceInFlatQ}); 
    to create sketch. You could use the flattened bend face as faceInFlatQ. 
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    @jonaskuehling
    When you sketch on the flat, you need to use newSketch, rather than newSketchOnPlane, like @lana said above.
    To get the plane that you need to have you sketch coordinates relative to, use an evPlane on the face that you passed to newSketch

    An example of sketching on the flat is in the Calculate Bounds feature by @Jake_Rosenfeld here. The flat option on it sketches a rectangle on the flat pattern and optionally highlights it using debug.

    You could possibly look through the extrude.fs sheet metal flat code here to see how it does smFlatOperations.
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    Answer ✓
    @MBartlett21 @lana
    Awesome, thanks a lot for your input!

    I've come a long way in the meanwhile and had to dive a little into sparsely documented feature script terrain with regards to sheet metal functionality it seems - nonetheless, learned a ton, the feature script is done and does everything I would have hoped for.

    I decided to make the document public in case anybody would like to just use it, build on top of it or get inspiration for similar feature script projects. The feature is called "smPerforateBend" or "Perforate sheet metal bend" and can also be found via the link here:


    While I tried to comment the code where possible, it might not be the most elegant solution in every way, but it's the solution I made to work ;) In case anyone has suggestions on how to improve the feature, I'd love to hear.

    Regards,
    Jonas


    Tags: Sheet metal, Perforation, Slotted bending, hand bending, manual bending
  • lanalana Onshape Employees Posts: 689
    edited February 2020
    @jonaskuehling
     That looks great! 
    Couple notes:
    1. @NeilCooke pointed out that in order to be robust flatFaces query needs to be wrapped into qSheetMetalFlatFilter.
    </code> qSheetMetalFlatFilter(qParallelPlanes(qUnion(attributeQueries), vector(0, 0, 1)), SMFlatType.YES);</pre>
    
    
    
    
    
    
    
    <br>2. The way you set up sketch ids you should not need to collect region and created bodies queries qCreatedBy(id +&nbsp;"sketch", EntityType.BODY) will pick up all bodies, same for regions.<br>3. I'd recommend using `id + "sketches" + unstableIdComponent(i)` for sketches in combination with <pre class="CodeBlock"><code>setExternalDisambiguation(context, id + "sketches" + unstableIdComponent(i),&nbsp;evaluatedCenterlines[i]); 
    to ensure robustness of downstream references to perforation geometry.
    4. If you look at extrude feature definition, you'll see that it has whole bunch of default parameters 
    {           endBound : BoundingType.BLIND, oppositeDirection : false,
                bodyType : ToolBodyType.SOLID, operationType : NewBodyOperationType.NEW,
                secondDirectionBound : SecondDirectionBoundingType.BLIND,
                secondDirectionOppositeDirection : true, hasSecondDirection : false,
                hasOffset: false, hasSecondDirectionOffset: false,
                offsetOppositeDirection: false, secondDirectionOffsetOppositeDirection: false,
                hasDraft: false, hasSecondDirectionDraft: false,
                draftPullDirection : false, secondDirectionDraftPullDirection : false,
                surfaceOperationType : NewSurfaceOperationType.NEW,
                defaultSurfaceScope : true,
                domain : OperationDomain.MODEL,
               flatOperationType : FlatOperationType.REMOVE }

    that you don't need to specify when calling feature programmatically.  

    5. You don't need to make both body and centerlines parameters of the feature. You can find the body as qOwnerBody(topFace). There is a way to find all centerlines of sheet metal body as well ( if you want to have a simple ui to perforate all bends of sheet metal bodies, handling bodies from different models should be possible as well and will be an optimization). Let me know if you are interested in this option - I'll write something for you.

  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    Great feedback, much appreciated, I will try to implement your suggestions with regards to robustness soon.

    I tried finding the body via one of the selected centerlines, e.g. with qOwnerBody as you suggested, but unfortunately I didn't manage to restructure the code for finding the flatFaces without having access to the body already. topFace is currently defined after flatFaces and thus not yet available where I would put the qOwnerBody(topFace). Do you have an idea how this could be done with some elegance? :)

    And yes, at least the option to be able to just select the sheet metal body and automatically perforate all the bends at once would be very nice. I'd definitely love to see your approach on this!

    Btw. I ran into some restrictions when cutting on the bends in terms of being too close to the edge with a slot. From what I found it seems to be somewhat related to half of the bend allowance (= radius of my slots) as the limit. When cutting closer to the end, the extrude throws errors. I discovered this behaviour already when doing the perforations manually without the feature script. My solution for the moment is to force the tab width to be no smaller than "slotRadius+0.02mm" just to be safe, which works reliably for all standard bends with square edges like this:

    For diagonal edges, though, the minimum required distance from the centerline endpoint to regenerate properly needs to be larger:
    Which makes sense I guess, as the minimum distance between first slot and edge is effectively reduced. I might actively move the start point for the slot pattern further inside according to the length of the shortest result in "alignedEdges" in the future - for the moment manually increasing the tab width through my "force minimum tab width" option does it as well, but a fail-proof solution is of course always preferred..
    I couldn't finally figure out why it is a problem being close to the edge with a cutout, though. Any thoughts on this?

  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    lana said:
    1. @NeilCooke pointed out that in order to be robust flatFaces query needs to be wrapped into qSheetMetalFlatFilter.
    </code> qSheetMetalFlatFilter(qParallelPlanes(qUnion(attributeQueries), vector(0, 0, 1)), SMFlatType.YES);</pre></div></blockquote><div>Done.</div><div><blockquote class="Quote">
      <div><a rel="nofollow" href="https://forum.onshape.com/profile/lana">lana</a>&nbsp;said:<br></div>
      <div>2. The way you set up sketch ids you should not need to collect region and created bodies queries qCreatedBy(id +&nbsp;"sketch", EntityType.BODY) will pick up all bodies, same for regions.<br></div>
    </blockquote>
    Yeah, nice, so much cleaner. Done.<br><blockquote class="Quote">
      <div><a rel="nofollow" href="https://forum.onshape.com/profile/lana">lana</a>&nbsp;said:<br></div>
      <div>3. I'd recommend using `id + "sketches" + unstableIdComponent(i)` for sketches in combination with <pre class="CodeBlock"><code>setExternalDisambiguation(context, id + "sketches" + unstableIdComponent(i),&nbsp;evaluatedCenterlines[i]); 
    to ensure robustness of downstream references to perforation geometry.
    Ok, not quite sure about this one.. I kind of get the point, and I think I implemented it correctly - at least it doesn't complain  :D Would you mind having a look if I got it right?
    lana said:
     4. If you look at extrude feature definition, you'll see that it has whole bunch of default parameters 
    {           endBound : BoundingType.BLIND, oppositeDirection : false,
                bodyType : ToolBodyType.SOLID, operationType : NewBodyOperationType.NEW,
                secondDirectionBound : SecondDirectionBoundingType.BLIND,
                secondDirectionOppositeDirection : true, hasSecondDirection : false,
                hasOffset: false, hasSecondDirectionOffset: false,
                offsetOppositeDirection: false, secondDirectionOffsetOppositeDirection: false,
                hasDraft: false, hasSecondDirectionDraft: false,
                draftPullDirection : false, secondDirectionDraftPullDirection : false,
                surfaceOperationType : NewSurfaceOperationType.NEW,
                defaultSurfaceScope : true,
                domain : OperationDomain.MODEL,
               flatOperationType : FlatOperationType.REMOVE }

    that you don't need to specify when calling feature programmatically.

    Ah, I see, cleaned it up a little! Thanks

  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    @MBartlett21 @lana
    Awesome, thanks a lot for your input!
    I've come a long way in the meanwhile and had to dive a little into sparsely documented feature script terrain with regards to sheet metal functionality it seems - nonetheless, learned a ton, the feature script is done and does everything I would have hoped for.
    I decided to make the document public in case anybody would like to just use it, build on top of it or get inspiration for similar feature script projects. The feature is called "smPerforateBend" or "Perforate sheet metal bend" and can also be found via the link here:
    https://cad.onshape.com/documents/674208a5595b7aabcc344693/w/7b6d29b27c6d34d9b9aad07f/e/ebc0a97c902d811562402e8d

    While I tried to comment the code where possible, it might not be the most elegant solution in every way, but it's the solution I made to work ;) In case anyone has suggestions on how to improve the feature, I'd love to hear.
    Regards,
    Jonas

    Tags: Sheet metal, Perforation, Slotted bending, hand bending, manual bending

    Cool!
    Would you be able to try adding the code below to the precondition? It will generate a better error when either of the queries are empty
    verifyNonemptyQuery(context, definition, "bendLines", ErrorStringEnum.CANNOT_RESOLVE_ENTITIES);
    verifyNonemptyQuery(context, definition, "body", ErrorStringEnum.CANNOT_RESOLVE_ENTITIES);
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO

    Would you be able to try adding the code below to the precondition? It will generate a better error when either of the queries are empty
    verifyNonemptyQuery(context, definition, "bendLines", ErrorStringEnum.CANNOT_RESOLVE_ENTITIES);
    verifyNonemptyQuery(context, definition, "body", ErrorStringEnum.CANNOT_RESOLVE_ENTITIES);
    Just tried, but doesn't seem to work as intended - given I placed it correctly (within the precondition)...?






  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    @jonaskuehling
    Sorry. I meant to place it directly after, just before you declaration for var smattributes...
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    edited February 2020
    Got it - yes, this changes the error message from "Array index 0 out of bounds." to "throw CANNOT_RESOLVE_ENTITIES" in the feature script notices, which I guess is kind of a good (better) thing  ;)

    Not much changed from the user perspective, though.

    EDIT: I was wrong - when no sheet metal body is selected, the bend lines selection field now turns red and gives a "Cannot resolve entities." error message on hover..


  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,646
    From the user perspective, the box that they have not selected anything into will now be highlighted in red, and hovering the feature will now say "Cannot resolve entities" instead of "Error regenerating".

    Although the slightly more correct thing to do here is actually:
    if (evaluateQuery(context, definition.bendLines) == [])
    {
        throw regenError("Select bend lines", ["bendLines"]);
    }
    So that on hover, the errored feature reports to the user "Select bend lines" (which is the common grammar we use when there is a box that needs a selection).


    @MBartlett21
    I have just written a note internally to add a `verifyNonemptyQuery` overload that takes a raw string to throw instead of an ErrorStringEnum, to make it possible to do this.  I think it would be useful in custom features.
    Jake Rosenfeld - Modeling Team
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO

    if (evaluateQuery(context, definition.bendLines) == [])
    {
        throw regenError("Select bend lines", ["bendLines"]);
    }
    Ok, cool. Should I place this into the precondition or below? And should I add the same for the body selection?


  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,034 EDU
    @MBartlett21
    I have just written a note internally to add a `verifyNonemptyQuery` overload that takes a raw string to throw instead of an ErrorStringEnum, to make it possible to do this.  I think it would be useful in custom features.
    Thankyou.
    I often have used this function in my custom features. Could you also add an overload that does not take an error parameter and instead just throws ErrorStringEnum.CANNOT_RESOLVE_ENTITIES?
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,646
    @jonaskuehling
    My proposal is to use that code to replace the calls to `verifyNonemptyQuery`, and yes you would want a copy of it for each query that you want to verify.

    @MBartlett21
    Probably will not do that because it would be considered bad UX to throw CANNOT_RESOLVE_ENTITIES from a feature, instead of giving a specific string of what the user needs to select.
    Jake Rosenfeld - Modeling Team
  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    Works like a charm, thanks!

  • brucebartlettbrucebartlett Member, OS Professional, Mentor, User Group Leader Posts: 2,137 PRO
    Great work! I'll look forward to trying this feature as I do occasionally use slotted bends and this should be much quicker than manually drawing the cuts. 
    Engineer ı Product Designer ı Onshape Consulting Partner
    Twitter: @onshapetricks  & @babart1977   
  • lanalana Onshape Employees Posts: 689
    edited February 2020
    @jonaskuehling
    External disambiguation is exactly the way I'd expect it to be. I don't think you need sketchIds and sketches arrays any longer either, you can use a local variable inside the loop.  It might be easier to read if you set 
    const sketchGroupId = id + "sketch" 
    outside of the loop and use it everywhere.
    I'll need to investigate the failure close to bend end. If you can share an example of such failure with me, it'll be great.


    Here I've improved flat face query by wrapping it into qSheetMetalFlatFilter()  and written allModelCenterlineEdges() 


  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO

    lana said:
    I don't think you need sketchIds and sketches arrays any longer either, you can use a local variable inside the loop.  It might be easier to read if you set 
    const sketchGroupId = id + "sketch" 
    outside of the loop and use it everywhere.
    Absolutely, thanks for the hint, just cleaned that up.

    lana said:
    I'll need to investigate the failure close to bend end. If you can share an example of such failure with me, it'll be great.
    I've created an edge case to demonstrate the failure behavior - please have a look at the newly created Part Studio called "Edge case failure demonstration" in my feature script document.

    lana said:
    Here I've improved flat face query by wrapping it into qSheetMetalFlatFilter()  and written allModelCenterlineEdges()
    Awesome, thanks a lot for this one. I just tried to briefly implement that into my script, but was running into some trouble there.. Guess I need to invest a few more focussed minutes to figure that out properly B)
  • lanalana Onshape Employees Posts: 689
    I don't think this was the failure you've meant

  • jonaskuehlingjonaskuehling OS Professional Posts: 16 PRO
    Pardon, I accidentially broke my own demo...

    Please try again, should look like this now ;)


Sign In or Register to comment.