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.

Extrude Profile Feature

jacob_kingeryjacob_kingery Member Posts: 39 EDU
Hi everyone,

I'm one of a team of five college students who got the chance to work with FeatureScript this school year, and this is one of the features we made. Let us know what you think!

Extrude Profile is similar to the built-in extrude feature, but it uses predefined profiles from a separate Part Studio instead of requiring a sketch to be selected. To position the extrusion, sketch points or mate connectors in the Part Studio can be selected (selecting multiple creates the extrusion at each location). It sits on top of the existing extrude() feature, so it has nearly all of the same capabilities: new/add/remove/intersect, up to next/face/part, second direction, draft, and so on. With the new linked documents, you can have the Extrude Profile Feature and the profiles in one document and use it in your other documents without needing to copy anything over.

Here’s a frame built out of 80/20 aluminum extrusion made using Extrude Profile:


The full code is below:
FeatureScript 336;
export import(path : "onshape/std/geometry.fs", version : "336.0");
// The Part Studio that contains sketches of the profiles (here it is "Profiles")
// This will need to be changed if you make a copy of this document
// or want to use a different Part Studio
PROFILES::import(path : "5b738aa78b30dcacc632e732", version : "4d44e3f224a42b96e0225eb4");
// IDs for the different profiles in the imported Part Studio
// These can be found by viewing the Part Studio code and locating each profile
// This will need to be updated with your own profiles
export enum ProfileID
{
    annotation { "Name" : "Keyed Shaft"}
    FhZrcAwvpS53LxN_0,
    annotation { "Name" : "8020 1515" }
    FRq293wuvJmfxy1_0,
    annotation { "Name" : "8020 1530" }
    FNEWGsbExOTWz4f_0,
    annotation { "Name" : "8020 1545" }
    FKgkJvp8e2Xp26A_0,
    annotation { "Name" : "8020 3030" }
    Fl1OKjOr6f4slR2_0
}
export enum TransformMethod
{
    annotation { "Name" : "Sketch point" }
    SKETCHPOINT,
    annotation { "Name" : "Mate connector" }
    MATECONNECTOR
}
export function mateConnectorTransform(context is Context, mate_connector is Query)
{
    return toWorld(evMateConnector(context, {
        "mateConnector" : mate_connector
    }));
}
export function sketchPointTransform(context is Context, sketch_point is Query, xaxis is Query, angle is ValueWithUnits)
{
    var point is Vector = evVertexPoint(context, {
        "vertex" : sketch_point
    });
    var sketch_plane is Plane = evOwnerSketchPlane(context, {
        "entity" : sketch_point
    });
    // Make the point the sketch plane origin
    sketch_plane.origin = point;
    // Make the reference edge the sketch plane x-axis
    if (size(evaluateQuery(context, xaxis)) != 0)
    {
        var new_x = evLine(context, {"edge" : xaxis}).direction;
        if (!perpendicularVectors(sketch_plane.normal, new_x))
        {
            println("Selected x-axis is not perpendicular to the sketch plane's normal");
            throw regenError(ErrorStringEnum.SKETCH_PERPENDICULAR_FAILED, xaxis);
        }
        sketch_plane.x = new_x;
    }
    // Rotate the sketch plane x-axis by the specified angle
    sketch_plane.x = rotationMatrix3d(sketch_plane.normal, angle) * sketch_plane.x;
    return planeToWorld(sketch_plane);
}
annotation { "Feature Type Name" : "Extrude Profile" }
export const extrudeProfile = defineFeature(function(context is Context, id is Id, definition is map)
    precondition
    {
        // BEGINNING OF PRECONDITION FROM EXTRUDE.FS (modified to remove the SURFACE option)
        booleanStepTypePredicate(definition);
        // Entity input is replaced by our profile enum
        annotation { "Name" : "Profile" }
        definition.profile_id is ProfileID;
        annotation { "Name" : "End type" }
        definition.endBound is BoundingType;
        if (definition.endBound != BoundingType.SYMMETRIC)
        {
            annotation { "Name" : "Opposite direction", "UIHint" : "OPPOSITE_DIRECTION" }
            definition.oppositeDirection is boolean;
        }
        if (definition.endBound == BoundingType.UP_TO_SURFACE)
        {
            annotation { "Name" : "Up to face",
                "Filter" : EntityType.FACE && SketchObject.NO,
                "MaxNumberOfPicks" : 1 }
            definition.endBoundEntityFace is Query;
        }
        else if (definition.endBound == BoundingType.UP_TO_BODY)
        {
            annotation { "Name" : "Up to surface or part",
                         "Filter" : EntityType.BODY && SketchObject.NO,
                         "MaxNumberOfPicks" : 1 }
            definition.endBoundEntityBody is Query;
        }
        if (definition.endBound == BoundingType.BLIND ||
            definition.endBound == BoundingType.SYMMETRIC)
        {
            annotation { "Name" : "Depth" }
            isLength(definition.depth, LENGTH_BOUNDS);
        }
        annotation { "Name" : "Draft", "UIHint" : "DISPLAY_SHORT" }
        definition.hasDraft is boolean;
        if (definition.hasDraft == true)
        {
            annotation { "Name" : "Draft angle", "UIHint" : "DISPLAY_SHORT" }
            isAngle(definition.draftAngle, ANGLE_STRICT_90_BOUNDS);
            annotation { "Name" : "Opposite direction", "UIHint" : "OPPOSITE_DIRECTION" }
            definition.draftPullDirection is boolean;
        }
        if (definition.endBound != BoundingType.SYMMETRIC)
        {
            annotation { "Name" : "Second end position" }
            definition.hasSecondDirection is boolean;
            if (definition.hasSecondDirection)
            {
                annotation { "Name" : "End type" }
                definition.secondDirectionBound is SecondDirectionBoundingType;
                annotation { "Name" : "Opposite direction", "UIHint" : "OPPOSITE_DIRECTION", "Default" : true }
                definition.secondDirectionOppositeDirection is boolean;
                if (definition.secondDirectionBound == SecondDirectionBoundingType.UP_TO_SURFACE)
                {
                    annotation { "Name" : "Up to face",
                        "Filter" : EntityType.FACE && SketchObject.NO,
                        "MaxNumberOfPicks" : 1 }
                    definition.secondDirectionBoundEntityFace is Query;
                }
                else if (definition.secondDirectionBound == SecondDirectionBoundingType.UP_TO_BODY)
                {
                    annotation { "Name" : "Up to surface or part",
                                 "Filter" : EntityType.BODY && SketchObject.NO,
                                 "MaxNumberOfPicks" : 1 }
                    definition.secondDirectionBoundEntityBody is Query;
                }
                if (definition.secondDirectionBound == SecondDirectionBoundingType.BLIND)
                {
                    annotation { "Name" : "Depth" }
                    isLength(definition.secondDirectionDepth, LENGTH_BOUNDS);
                }
                if ((definition.secondDirectionOppositeDirection && !definition.oppositeDirection) ||
                    (!definition.secondDirectionOppositeDirection && definition.oppositeDirection))
                {
                    annotation { "Name" : "Draft", "UIHint" : "DISPLAY_SHORT" }
                    definition.hasSecondDirectionDraft is boolean;
                    if (definition.hasSecondDirectionDraft)
                    {
                        annotation { "Name" : "Draft angle", "UIHint" : "DISPLAY_SHORT" }
                        isAngle(definition.secondDirectionDraftAngle, ANGLE_STRICT_90_BOUNDS);
                        annotation { "Name" : "Opposite direction", "UIHint" : "OPPOSITE_DIRECTION" }
                        definition.secondDirectionDraftPullDirection is boolean;
                    }
                }
            }
        }
        booleanStepScopePredicate(definition);
        // END OF EXTRUDE.FS PRECONDITION
        annotation { "Name" : "Transform method" }
        definition.transform_method is TransformMethod;
        if (definition.transform_method == TransformMethod.MATECONNECTOR)
        {
            annotation { "Name" : "Mounting mate connector(s)", "Filter" : BodyType.MATE_CONNECTOR }
            definition.mounting_connectors is Query;
        }
        else if (definition.transform_method == TransformMethod.SKETCHPOINT)
        {
            annotation { "Name" : "Sketch point(s)", "Filter" : EntityType.VERTEX && SketchObject.YES }
            definition.sketch_points is Query;
            annotation { "Name" : "X-axis", "Filter" : EntityType.EDGE, "MaxNumberOfPicks" : 1 }
            definition.xaxis is Query;
            annotation { "Name" : "Rotation angle" }
            isAngle(definition.angle, ANGLE_360_ZERO_DEFAULT_BOUNDS);   
        }
    }
    {
        // Get PROFILES's context
        var contextWithProfiles is Context = PROFILES::build();
        // Delete its construction planes and origin
        opDeleteBodies(contextWithProfiles, id + "delete_default_geometry", {
            "entities" : qUnion([
                qConstructionFilter(qBodyType(qEverything(EntityType.BODY), BodyType.SHEET), ConstructionObject.YES),
                qCreatedBy(makeId("Origin"))
            ])
        });
        // Add PROFILES's context to the current Part Studio
        opMergeContexts(context, id + "add_profiles", {
            "contextFrom" : contextWithProfiles
        });
        // Calculate transforms for each position
        var transforms = [];
        if (definition.transform_method == TransformMethod.MATECONNECTOR)
        {
            const num_connectors = size(evaluateQuery(context, definition.mounting_connectors));
            for (var i = 0; i < num_connectors; i += 1)
            {
                transforms = append(transforms, mateConnectorTransform(context, qNthElement(definition.mounting_connectors, i)));
            }
        }
        else if (definition.transform_method == TransformMethod.SKETCHPOINT)
        {
            const num_points = size(evaluateQuery(context, definition.sketch_points));
            for (var i = 0; i < num_points; i += 1)
            {
                transforms = append(transforms, sketchPointTransform(context, qNthElement(definition.sketch_points, i), definition.xaxis, definition.angle));
            }
        }
        // If there are no transforms, use the original position
        if (transforms == []) {
            transforms = [identityTransform()];
        }
        // Transform profile to each location and extrude it there
        const profile = qCreatedBy(id + "add_profiles" + (definition.profile_id as string), EntityType.BODY);
        definition.entities = qSketchRegion(id + "add_profiles" + (definition.profile_id as string));
        var last_tf = identityTransform();
        var i = 0;
        for (var tf in transforms)
        {
            opTransform(context, id + ("transform" ~ i), {
                "bodies" : profile,
                "transform" : tf * inverse(last_tf)
            });
            extrude(context, id + ("extrude" ~ i), definition);
            last_tf = tf;
            i += 1;
        }
        // Delete the imported PROFILES to clean up
        opDeleteBodies(context, id + "delete_imported_geometry", {
            "entities" : qCreatedBy(id + "add_profiles")
        });
    }, {});

Comments

  • emerson_botteroemerson_bottero Member, Developers Posts: 37 ✭✭
    Hi there.

    Congratulations for the FS, It looks very nice. Reminds me the weldment profile used in Solidworks, the main difference is that you make a 3d sketch and use the lines to extrude the profile, I think is faster with the 3D sketch but yours have the same functionality with a different approach.
    I'm trying to make something that can use most of your code, I'm developing something like New Extrude based on Raw Material, like a Round Bar, Rectangular tube , angle and etc. The basic ones I can draw a sketch, I already made those the problem is when I you have a specific profile. Could you share your document with me so I can see how do you link the profiles? I will have other issues like re-sizing them but is a good start.
  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    Sure thing!  I just made the document public now that FeatureScript is released.  It's called 'Extrude Profile Feature' - I think this link should work:  https://cad.onshape.com/documents/58c744412ee9d1263156ca68.

    The profiles are located in the Part Studio titled 'Profiles' and the ProfileID enum near the top of the script is what contains the IDs that identify the different sketches of the profiles.  Let me know if you have any questions, and good luck with your feature!
  • joe_dunnejoe_dunne Onshape Employees, Developers Posts: 149
    Thanks Jacob,

    this is soooo cool. 
    Joe Dunne / Onshape, Inc.
  • billy2billy2 Member, OS Professional, Mentor, Developers Posts: 1,322 PRO
    Nice job, I use a lot of 8020 and your script will be very useful.

    Thanks for sharing,


  • billy2billy2 Member, OS Professional, Mentor, Developers Posts: 1,322 PRO
    edited June 2016
    Jacob-
    you should put your name in your code:



    I'm not sure what the copy write laws are for featurescripts and the ramification for posting the source code on a public forum. I know I use a lot of javascript from all over the place and if someone has added their name to the code, I don't remove it. Even after it's been obfuscated the name still appears. Give credit where credit is due.

     
  • billy2billy2 Member, OS Professional, Mentor, Developers Posts: 1,322 PRO
    BTW-
    When I copied your shared document, I didn't have to edit the profile links. The "Frame" part studio pointed to "Profiles" just fine. I double checked to make sure it wasn't pointing to your shared document and it wasn't. All references were inside my document and nothing was broke.

    Seems like copying the document would have regenerated all new part studio & sketch id's but that didn't happen.

    Your copied document worked fine for me.


  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 455
    @billy
    Yep! "Copy workspace" repoints intra-workspace references to the right things. Same goes if you derive a part within a workspace and copy.

    I think Jacob's comments were intended for before he added the public link, since he made this feature before FeatureScript documents could be public. If just copy-pasted his code, the imports would not resolve correctly.

    If you want to add your own new profiles to the feature, you will have to modify the FS by adding the new sketch id to the ProfileID enum.

  • emerson_botteroemerson_bottero Member, Developers Posts: 37 ✭✭
    I need to Group the profiles in three leves, like square bars, SAE 1020, 1/2" 
    Round bars, SAE 1045, 1"
    How would you do that to chose the profile?


  • billy2billy2 Member, OS Professional, Mentor, Developers Posts: 1,322 PRO
    edited June 2016
    I'm trying to figure this out and working with the revision system. Not sure about putting everything in a document called "library" as it's revision would go nuts. 

    I'm thinking about library names beginning with "library" or "lib" so I can perform a quick search in the document manager.

    How I would group things:

    document named "lib SAE shapes"
    part studio named "square bars"
    part studio named "round bars"
    part studio named "angles"
    part studio named "tees"
    part studio named "I-beams"

    I think this might work. If you build it, please let me know.

    You'll have to maintain your enum's to match your part studios. Too bad a featurestudio can't write a featurestudio, this way you could write an app that updates your enum's based on your part studio's in the document.

    I also know the app store, I'm thinking libraries really belong over there but it's not for everyone. App Store requires an SSL certificate which isn't cheap. It does give you your own database and your own programming languages. Not sure you can eval(featurescript) and get a featurescript to run from the app store. That's a question for Ilya or kevin. I know I could query "lib SAE shapes" from an app store app and I might be to edit a featurescript. This way I could maintain an index of your libraries and also provide search capabilities down to the sketch in a part studio. At least to the part studio, don't remember if I can get to the sketch. 








  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    @kevin_o_toole_1 is right about the comment and adding new profiles.

    @billy, that's probably how I'd do it; make a few separate Part Studios for the different  
  • ritchie_ritchie_ Member Posts: 11
    @jacob_kingery thanks for sharing, nice solution. I started to write a simple parameterized tubing extruder (e.g., radiused corner rectangular 1/8" wall) but using a sketch in another Part Studio is a great idea. Looking forward to trying it out!

    Couple of questions for the Onshape team: I see I can copy a FeatureScript to a new private document. Is it possible to copy it to an existing document? If we can only copy to a new document, how would we use multiple 'external' FeatureScripts? Manually cut-and-paste the code into a document?

    Also do you foresee a github/npm style package manager for FeatureScripts so we can always use the latest (or fixed) version of a published script?

    Thanks!
  • NeilCookeNeilCooke Moderator, Onshape Employees Posts: 2,616
    @ritchie_ take a look at the videos on https://www.onshape.com/featurescript that show you how to use scripts with versions and linked documents. 
  • franco_otaolafranco_otaola Member Posts: 23
    hello jacob

    i am dont know how to create feature scripts but the other day i needed some profiles for a proyect and i made the sketchs for 45X45 ,40X80 and 40X160 here you have the link for the sketchs maybe they could help you to add to the list.

    https://cad.onshape.com/documents/15230bf73e3e7c1ddbc2cc75/w/3310b0b6b8d8fbd172557c7d/e/1844e8d099c480cfce3f691d

    wish it helps!
  • Jake_RosenfeldJake_Rosenfeld Moderator, Onshape Employees, Developers Posts: 1,419
    Hi @franco_otaola

    More recently than this thread, we've created a "Beams" feature that has more documentation about how to add your own profiles.  Check out this blog post:
    https://www.onshape.com/cad-blog/custom-feature-spotlight-using-the-beam-feature-to-create-weldments

    The post also links to a webinar that shows how to create custom profiles for the feature step-by-step.

    Hope this helps!
    Jake Rosenfeld - Modeling Team
  • franco_otaolafranco_otaola Member Posts: 23
    Hi @franco_otaola

    More recently than this thread, we've created a "Beams" feature that has more documentation about how to add your own profiles.  Check out this blog post:
    https://www.onshape.com/cad-blog/custom-feature-spotlight-using-the-beam-feature-to-create-weldments

    The post also links to a webinar that shows how to create custom profiles for the feature step-by-step.

    Hope this helps!
    hi jake,

    i saw it but i didnt have a look at it. it is a great feauture! but is there any possibility to add our sketches to the main feature like send it to the creator or something? so everybody has them with the principal feature.... i am askig because for the moment i didnt beging working with the features myself but i thought i could give my little grain of sand to this community
  • ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 952
    @franco_otaola
    There are instructions there for how to add your own profiles.
    Ilya Baran \ Director, Architecture and FeatureScript \ Onshape Inc
Sign In or Register to comment.