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.

[featurescript] How to sweep a polyline?

maxwell_smartmaxwell_smart Member Posts: 11

I am new to featurescript. I have a json file of sequences of gcode movement paths. I plan to sweep a profile across all of the paths that my printer is extruding.

This is to recreate the printed geometry for stress analysis.

I am having trouble understanding how to call opSweep.

This is my code so far:

FeatureScript 2473;
import(path : "onshape/std/common.fs", version : "2473.0");

// Define a custom feature
annotation { "Feature Type Name" : "sweep along polyline" }
export const polyline_sweep = defineFeature(function(context is Context, id is Id, definition is map)
    precondition
    {
        // Precondition can define inputs like a plane or sketch, but in this case, we're creating our own sketch
    }
    {
        var a  =vector( 1,  1,  1)  * millimeter;
        var b = vector(-1,  1, -1)  * millimeter;
        var l = opPolyline(context, id + "polyline1", {
                "points" : [
                    a,
                    b,
                    vector( 1, -1, -1)   * millimeter,
                    vector(-1, -1,  1)   * millimeter,
                    vector( 1,  1,  1)   * millimeter 
                ]
        });
        var p = plane(a, normalize(b - a));
        var sketch1 = newSketchOnPlane(context, id + "sketch1", {
                "sketchPlane" : p
        });
        var rec = skRectangle(sketch1, "rectangle1", {
                "firstCorner" : vector(0, 0) * millimeter,
                "secondCorner" : vector(1, 1) * millimeter
        });
        
        var fs = qCreatedBy(id + "rectangle1", EntityType.FACE);
        
        debug(context, fs);
        
        opSweep(context, id + "sweep1", {
                "profiles" : fs,
                "path" : l,
                // "profileControl" : ProfileControlMode.KEEP_ORIENTATION
        });
        
        println(fs);
        debug(context, sketch1);
        skSolve(sketch1);
    });

I am able to get far enough to where I have the polyline (sweep path) showing up on the screen, as well as the rectangle (sweep profile).
This is the stacktrace
@opSweep: SWEEP_SELECT_PROFILE
1679:12
onshape/std/geomOperations.fs (const opSweep)
36:9
Feature Studio 1 (const polyline_sweep)
57:17
onshape/std/feature.fs (defineFeature)

Part Studio 1 (sweep along polyline 1)

Part Studio 1

Any help would be appreciated!

Comments

  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,671
    var fs = qCreatedBy(id + "sketch1", EntityType.FACE);
    

    Senior Director, Technical Services, EMEAI
  • maxwell_smartmaxwell_smart Member Posts: 11

    Thanks for the fast reply, but that doesn't seem to get rid of the error

    FeatureScript 2473;
    import(path : "onshape/std/common.fs", version : "2473.0");
    
    // Define a custom feature
    annotation { "Feature Type Name" : "sweep along polyline" }
    export const polyline_sweep = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
            // Precondition can define inputs like a plane or sketch, but in this case, we're creating our own sketch
        }
        {
            var a  =vector( 1,  1,  1)  * millimeter;
            var b = vector(-1,  1, -1)  * millimeter;
            var l = opPolyline(context, id + "polyline1", {
                    "points" : [
                        a,
                        b,
                        vector( 1, -1, -1)   * millimeter,
                        vector(-1, -1,  1)   * millimeter,
                        vector( 1,  1,  1)   * millimeter 
                    ]
            });
            var p = plane(a, normalize(b - a));
            var sketch1 = newSketchOnPlane(context, id + "sketch1", {
                    "sketchPlane" : p
            });
            var rec = skRectangle(sketch1, "rectangle1", {
                    "firstCorner" : vector(0, 0) * millimeter,
                    "secondCorner" : vector(1, 1) * millimeter
            });
            
            var fs = qCreatedBy(id + "sketch1", EntityType.FACE);
            
            debug(context, fs);
            opSweep(context, id + "sweep1", {
                    "profiles" : fs,
                    "path" : l,
                    // "profileControl" : ProfileControlMode.KEEP_ORIENTATION
            });
            println(fs);
            debug(context, sketch1);
            skSolve(sketch1);
        });
    
    

    Still gives me a:

    	
    @opSweep: SWEEP_SELECT_PROFILE
    1679:12
    onshape/std/geomOperations.fs (const opSweep)
    35:9
    Feature Studio 1 (const polyline_sweep)
    57:17
    onshape/std/feature.fs (defineFeature)

    Part Studio 1 (sweep along polyline 1)

    Part Studio 1
    debug: Query resolves to nothing
    Result: Regeneration complete

  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,671

    I only gave it a quick scan, so apologies. Unfortunately, this is what happens when you trust ChatGPT 😅

    FeatureScript 2473;
    import(path : "onshape/std/common.fs", version : "2473.0");
    
    annotation { "Feature Type Name" : "sweep along polyline" }
    export const polyline_sweep = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
        }
        {
            const a = vector(1, 1, 1) * millimeter;
            const b = vector(-1, 1, -1) * millimeter;
    
            opPolyline(context, id + "polyline1", {
                        "points" : [
                            a,
                            b,
                            vector(1, -1, -1) * millimeter,
                            vector(-1, -1, 1) * millimeter,
                            vector(1, 1, 1) * millimeter
                        ]
                    });
    
            const sketch1 = newSketchOnPlane(context, id + "sketch1", {
                        "sketchPlane" : plane(a, normalize(b - a))
                    });
    
            skRectangle(sketch1, "rectangle1", {
                        "firstCorner" : vector(0, 0) * millimeter,
                        "secondCorner" : vector(1, 1) * millimeter
                    });
    
            skSolve(sketch1);
    
            opSweep(context, id + "sweep1", {
                        "profiles" : qCreatedBy(id + "sketch1", EntityType.FACE),
                        "path" : qCreatedBy(id + "polyline1", EntityType.EDGE),
                    });
    
            opDeleteBodies(context, id + "deleteBodies1", {
                        "entities" : qCreatedBy(id + "sketch1", EntityType.BODY)
                    });
        });
    

    Senior Director, Technical Services, EMEAI
  • maxwell_smartmaxwell_smart Member Posts: 11

    Incredible thank you!

    I'm getting pretty close, but some of the sweeps are failing due to SWEEP_BAD_LOCK_DIRECTION which I don't fully understand.

    I thought maybe the profile is intersecting itself, so I changed the sweep profile to match the geometry that the printer lies down (commented out in the below code). If I use that profile, it still fails but with another error just saying SWEEP_FAILED

    If you want to try this you'll probably need this (I have uploaded the json data in this document):

    https://cad.onshape.com/documents/8629ed9c99271b8c5770c576/w/f1f4e71325d5c6599c3a0336/e/9de52ef251f95a1dcd1edd62

    @opSweep: SWEEP_FAILED
    1679:12
    onshape/std/geomOperations.fs (const opSweep)
    58:13
    Feature Studio 1 (const polyline_sweep)
    57:17
    onshape/std/feature.fs (defineFeature)

    Part Studio 1 (sweep along polyline 1)

    Part Studio 1

    FeatureScript 2473;
    import(path : "onshape/std/common.fs", version : "2473.0");
    MyData::import(path : "04f18c2bd4d77ea252e2bb45", version : "0b988dd1b884296c4cd94bff");
    
    function wire_to_list(p is array)
    {
        var arr = [p[0][0]];
        for (var cp in p)
        {
            arr = append(arr, cp[1]);
        }
        return arr;
    }
    
    
    annotation { "Feature Type Name" : "sweep along polyline" }
    export const polyline_sweep = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
        }
        {
            const ws = MyData::BLOB_DATA.jsonData;
            var all_p = [];
            for (var w in ws)
            {
                var p = [];
                for (var coord_pair in w)
                {
                    p = append(p, [vector(coord_pair[0]) * millimeter, vector(coord_pair[1]) * millimeter]);
                }
                all_p = append(all_p, p);
            }
    
            var i = 0;
            for (var cpl in all_p)
            {
                println(cpl);
                var wire = wire_to_list(all_p[2]);
                var a = wire[0];
                var b = wire[1];
                opPolyline(context, id + ("polyline" ~ i), {
                            "points" : wire
                        });
    
                const sketch1 = newSketchOnPlane(context, id + ("sketch" ~ i), {
                            "sketchPlane" : plane(a, normalize(b - a))
                        });
    
                skRectangle(sketch1, "rectangle" ~ i, {
                            // "firstCorner" : vector(-.2, 0) * millimeter,
                            // "secondCorner" : vector(.2, -.2) * millimeter
                            "firstCorner" : vector(0, 0) * millimeter,
                            "secondCorner" : vector(1, 1) * millimeter
                        });
    
                skSolve(sketch1);
    
                opSweep(context, id + ("sweep" ~ i), {
                            "profiles" : qCreatedBy(id + ("sketch" ~ i), EntityType.FACE),
                            "path" : qCreatedBy(id + ("polyline" ~ i), EntityType.EDGE),
                        });
    
                opDeleteBodies(context, id + ("deleteBodies" ~ i), {
                            "entities" : qCreatedBy(id + ("sketch" ~ i), EntityType.BODY)
                        });
                println(i);
                i = i + 1;
                break;
    
            }
        });
    
    
    

    Thank you very much for your help so far!

  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 5,671
    edited October 8

    Deleted or not public? If the sweep is self intersecting then it will fail. You might have to do a sweep per segment rather than the whole polyline. Also keep opDeleteBodies out of the loop - it will kill performance. If you add your sketches to an array toDelete = append(toDelete, qCreatedBy(id + ("sketch" ~ i))); then at the end you can do

     opDeleteBodies(context, id + "deleteBodies", {
                            "entities" : qUnion(toDelete)
                        });
    

    There's also no need for the i on the sketch rectangle since it is a child of the sketch.

    Senior Director, Technical Services, EMEAI
  • maxwell_smartmaxwell_smart Member Posts: 11

    Sorry about that, I just got an education license so I thought it was public by default. It should be public now.
    https://cad.onshape.com/documents/8629ed9c99271b8c5770c576/w/f1f4e71325d5c6599c3a0336/e/9de52ef251f95a1dcd1edd62

    Also thank you for the help. I am looking forward to doing some benchmarking. I tried this in FreeCAD and the performance was too slow to be usable. Hopefully decently sized prints can be reconstructed in onshape.

  • maxwell_smartmaxwell_smart Member Posts: 11

    I've spent some time on sweeping each segment but I'm running into an issue regarding joining the individual segments.

    Here is the code:

    https://cad.onshape.com/documents/8629ed9c99271b8c5770c576/w/f1f4e71325d5c6599c3a0336/e/26e30ac94fac2e5f327bfe53

    Naively Unioning all of the parts generated by the sweeps fails because the brim generated by the slicer is truly a disjoin part.

    However, I think the central square body should be able to be unioned into a single part but fails in the GUI.

    I did a little test by defining a Graph where the vertices are the bodies/sweeps, and edges are created where the end point of a previous segment is equal to the start point of the current segment. Unioning the connected components of this graph works, but doesn't result in 2 bodies, but 15. This is fine because the printer doesn't follow a single continuous path, even for a solid body part. I just wanted to cut down the body count to see if there really is an overlap, and it seems like there is.

    And visually inspecting this I can see that it seems like I should be able to just union the whole thing. I'm not sure how to proceed.

    I would really love some help as this is the final stretch before I can start to do some simulations. Thanks again Neil

  • Chris_D_Mentes_001Chris_D_Mentes_001 Member, csevp Posts: 102 PRO

    Looks like you just need to delete faces with the "Heal" option.

Sign In or Register to comment.