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.

Cut a line in the middle of a face

DavidXDavidX Member Posts: 4

I'm trying to write a script that cuts a line in the middle of a face, but doesn't really know how to draw the right rectangle that matches in all cases

That's the end result

I have the face
I have the 1 of the long edges I should be parallel with

What I have is
- I create the sketch along the face
- I draw a basic rectangle <- that's the missing part
- I extrude it
- And do the boolean operation to cut

My problem is to draw the tiny rectangle that is centered, parallel to the long edge

There is may be a better algorithm altogether

It's probably really simple, but I'm struggling with the different "dimensions" between the sketch and my part



  • robert_scott_jr_robert_scott_jr_ Member Posts: 104 ✭✭
    Hello David. I'm sure there are numerous methods to accomplish your task. This document: https://cad.onshape.com/documents/e5298a87308b8812f956e709/w/e8dd1fddab4b2ba5a95db76f/e/badf06f662888fbcdc4699da shows two of the methods I used. In the first sketch I used a construction line from the outside perimeter to the inside perimeters previously drawn. When adding that line I hovered my cursor along the top of the outer perimeter to urge the midpoint constraint to appear and drew a vertical line from the outer perimeter to the inside perimeter. Using the center rectangle tool I selected the center of that line to start the rectangle and move the cursor out toward the outer (or inner) perimeter until the perimeter edge was highlighted. I then use two symmetric extrudes; one for the shell and one for the body.

    For the bottom slot I used the same rectangle method in creating a sketch on the edge face of the shell. I used Extrude-remove-up to face to create the slot.

    Not sure what you mean by:
    I'm struggling with the different "dimensions" between the sketch and my part

    If it's still an issue , please explain and provide a link to your document.

    - Scotty
  • Evan_ReeseEvan_Reese Member Posts: 1,420 PRO

    Look into using fCuboid() instead of making a sketch and extruding it (assuming the cut shape is always a box, albeit a long skinny one). It just makes box shapes with two opposite corners as the input. To find the center of the face you could consider using evTangentPlane with the parameters of vector(0.5, 0.5). You might also consider evApproximateCentroid to find the face center, but I'd try the other way first. I'm glossing over some details for brevity, but let me know if you get stumped and I'll see if I can help more later.
    Evan Reese / Principal and Industrial Designer with Ovyl
    Website: ovyl.io
  • MichaelPascoeMichaelPascoe Member Posts: 875 PRO
    edited September 2021
    As Evan suggested, fCuboid() would work great for this. For a more robust feature, you want to make sure to reference the face you have chosen as much as possible, rather than relying on world coordinates or directions.

    Here is an example similar to Evan's idea:


    Example code:

    There are more efficient ways to write this code, this is simply a quick example.
            // Define the parameters of the feature type
            annotation { "Name" : "Face to cut", "Filter" : EntityType.FACE, "MaxNumberOfPicks" : 1 }
            definition.face is Query;
            annotation { "Name" : "Parallel edge", "Filter" : EntityType.EDGE, "MaxNumberOfPicks" : 1 }
            definition.edge is Query;
            annotation { "Name" : "Gap" }
            isLength(definition.gap, { (inch) : [-1e5, 0.125, 1e5] } as LengthBoundSpec);
            annotation { "Name" : "Cut depth" }
            isLength(definition.cutDepth, { (inch) : [-1e5, 0.25, 1e5] } as LengthBoundSpec);
            // Define the function's action
            const gapWidth = definition.gap;
            const cutThickness = definition.cutDepth;
            const evalPlane = evFaceTangentPlaneAtEdge(context, {
                    "edge" : definition.edge,
                    "face" : definition.face,
                    "parameter" : 0.5
            const parallelDirection = extractDirection(context, definition.edge);
            const facePlane = plane(evalPlane.origin, evalPlane.normal, parallelDirection);
            const edges = qAdjacent(definition.face, AdjacencyType.EDGE, EntityType.EDGE);
            const parallelEdges = qParallelEdges(edges, facePlane.x);
            const perpendicularEdges = qSubtraction(edges, parallelEdges);
            const perpEdge1 = evaluateQuery(context, perpendicularEdges)[0];
            const perpEdge2 = evaluateQuery(context, perpendicularEdges)[1];
            const evalPlaneEdge1 = evFaceTangentPlaneAtEdge(context, {
                    "edge" : perpEdge1,
                    "face" : definition.face,
                    "parameter" : .5
            const edgePlane1 = plane(evalPlaneEdge1.origin, facePlane.normal, facePlane.x);
            const evalPlaneEdge2 = evFaceTangentPlaneAtEdge(context, {
                    "edge" : perpEdge2,
                    "face" : definition.face,
                    "parameter" : .5
            const edgePlane2 = plane(evalPlaneEdge2.origin, facePlane.normal, facePlane.x);
            fCuboid(context, id + "cuboid1", {
                    "corner1" : worldToPlane3D(edgePlane1, edgePlane1.origin) + (planeToWorld3D(edgePlane1) * vector(0* inch, gapWidth, 0* inch)),
                    "corner2" : worldToPlane3D(edgePlane2, edgePlane2.origin) + (planeToWorld3D(edgePlane2) * vector(0* inch, -gapWidth, - cutThickness))
            opBoolean(context, id + "boolean1", {
                    "tools" : qCreatedBy(id + "cuboid1", EntityType.BODY),
                    "targets" : qOwnerBody(definition.face),
                    "operationType" : BooleanOperationType.SUBTRACTION

  • DavidXDavidX Member Posts: 4
    You guys are amazing!! Thank you so much for all these answers and that wonderful example. It helped me A LOT.

    I started with fCuboid(), it was working great until I added more use cases and realized I could have some rotations...

    I'm not sure I can make it work with fCuboid() and the rotations I have?

    Meanwhile I came back to a sketch and reused parts of the example. By reading it I found what I was missing, "worldToPlane"! (What I explained pretty badly with different "dimensions", the right term is different "coordinates"! :blush:)

    By adding more and more use cases, I realized it still doesn't work in some cases. If the side edge isn't flat, it behaves incorrectly. (the red case on my sample bellow) That should be good enough for my project, but would have liked to make it work for others.

    Here is the feature I built, and why I asked. I have some beams to cut with complex angles that are joined by pipes. I want to print paper templates to make it simpler.
    I found online that wrapping a sheet metal should permit me to flatten the beam. I tried manually, it worked but took me forever, so I decided to script it

    And here is a real use case (here the seam is too wide, but should be ok)

    Now that I have a demo project, let me know if you have ideas on how to make it more reliable (I have no doubt it can be more performant, but yeah, reliability is my main focus for now)

Sign In or Register to comment.