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.

Importing Part Studios and Feature Studios

kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 551
edited April 2016 in FeatureScript
One powerful feature of Onshape's FeatureScript-based architecture is the ability to freely import Part Studios and Feature Studios into one another.

Importing a Feature Studio into a Part Studio is what happens under the hood when you add FeatureScript features:


Importing a Part Studio into a Part Studio is what happens under the hood when you use the "Derived part":



Importing a Feature Studio into a Feature Studio
Importing into Feature Studios will eventually have a GUI too, but in the meantime, you can perform these imports by typing the import text directly into your Feature Studio, as shown below:

 

  1. Get the element id of the imported Feature Studio by copying the 24-character string following "/e/" from your URL (e.g. a4b15a1a4bba13206e42cd64).

  2. On a line after or before the Onshape Standard Library import, type an import for that Feature Studio:
    import(path : "a4b15a1a4bba13206e42cd64", version : "");
    
    You can alternatively import this module into its own namespace by adding a namespace prefix:
    MY_MODULE::import(path : "a4b15a1a4bba13206e42cd64", version : "");
    

  3. Commit the Feature Studio. Onshape will automagically populate the version field with the latest microversion (and continue to update it as you make changes to the imported Feature Studio):
    import(path : "a4b15a1a4bba13206e42cd64", version : "e679dc5c60bcb740e22a115e");
    

  4. Make sure any feature, function, type, or enum you want to use from the imported module is exported, e.g.
    export function myFunction(...
    export const myFeature = defineFeature(...
    

  5. Now you can call the exported symbols directly, like this:
            myFunction("foo");
            myFeature(context, id, {
                "bar": "bar"
            });
    
    Or, if you used a namespace, like this:
            MY_MODULE::myFunction("foo");
            MY_MODULE::myFeature(context, id, {
                "bar": "bar"
            });
    
Importing a Part Studio into a Feature Studio:

You can build geometry from a Part Studio right inside your feature by importing the Part Studio. You can import the Part Studio by the element id, just as above.


When typing the import, you'll notice an error when first importing the Part Studio without a version, as in the gif above. This is a known bug, but it can be worked around by refreshing the page and immediately pressing commit.  This has been fixed in Onshape version 1.41

The function you need from the Part Studio is named "build", which returns a context containing the Part Studio's geometry. 

Here's an example feature using this method:
FeatureScript 275;
import(path : "onshape/std/geometry.fs", version : "275.0");
THING::import(path : "7cc954522dbc4ce38424d920", version : "");

annotation { "Feature Type Name" : "Add thing" }
export const addThing = defineFeature(function(context is Context, id is Id, definition is map)
    precondition
    {
        annotation { "Name" : "Mounting mate connector", "Filter" : BodyType.MATE_CONNECTOR, "MaxNumberOfPicks" : 1 }
        definition.mountingConnector is Query;
    }
    {
        // Build a thing in a separate context
        var contextWithThing is Context = THING::build();

        // Delete its construction planes and origin
        opDeleteBodies(contextWithThing, id + "deleteDefaultGeometry", {
            "entities" : qUnion([
                qConstructionFilter(qBodyType(qEverything(EntityType.BODY), BodyType.SHEET), ConstructionObject.YES),
                qCreatedBy(makeId("Origin"))
            ])
        });
        
        // Add thing's context to the current Part Studio
        opMergeContexts(context, id + "addThing", {
            "contextFrom" : contextWithThing
        });

        // Move the thing to the mate connector
        var transform is Transform = toWorld(evMateConnector(context, {
               "mateConnector" : definition.mountingConnector
        }));
        opTransform(context, id + "transformThing", {
               "bodies" : qCreatedBy(id + "addThing", EntityType.BODY),
               "transform" : transform
        });
    }, { /* default parameters */ });
This feature adds the bodies of a Part Studio, and transforms them. You could imagine adding other steps in the feature too (boolean, modify, create more geometry, etc.).

Imports collectively open up some powerful methods of defining reusable geometry. Our hope is for FeatureScript users to find a style of working where geometry best defined with traditional, interactive modeling lives inside a Part Studio, and geometry best defined with code and logic lives in a Feature Studio.

Comments

  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    Great post, thanks Kevin!

    If you want to isolate something from the imported Part Studio, say a specific sketch, how would you go about doing that? I tried looking in the imported Part Studio's code and copying the sketch's id (which looked like id + 'autogeneratedcharacters') and putting it in a qSketchRegion, but that didn't seem to work. This makes sense since the id variable is different between the imported Part Studio and the Part Studio where the feature is doing the importing. Is it possible to target something by id from the imported Part Studio?
  • kevin_o_toole_1kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 551
    Great question.

    The opMergeContexts performs an operation in the context. All geometry created by the merge is a child of the merge operation.

    In your case, the id pointing to the sketch in question will be id + 'idOfMergeOperation' + 'autogeneratedIdOfSketchInPartStudio'  
  • jacob_kingeryjacob_kingery Member Posts: 39 EDU
    That did it, thanks Kevin!
  • otaolafrotaolafr Member Posts: 108 EDU
    One powerful feature of Onshape's FeatureScript-based architecture is the ability to freely import Part Studios and Feature Studios into one another.

    Importing a Feature Studio into a Part Studio is what happens under the hood when you add FeatureScript features:


    Importing a Part Studio into a Part Studio is what happens under the hood when you use the "Derived part":



    Importing a Feature Studio into a Feature Studio
    Importing into Feature Studios will eventually have a GUI too, but in the meantime, you can perform these imports by typing the import text directly into your Feature Studio, as shown below:

     

    1. Get the element id of the imported Feature Studio by copying the 24-character string following "/e/" from your URL (e.g. a4b15a1a4bba13206e42cd64).

    2. On a line after or before the Onshape Standard Library import, type an import for that Feature Studio:
      import(path : "a4b15a1a4bba13206e42cd64", version : "");
      
      You can alternatively import this module into its own namespace by adding a namespace prefix:
      MY_MODULE::import(path : "a4b15a1a4bba13206e42cd64", version : "");
      

    3. Commit the Feature Studio. Onshape will automagically populate the version field with the latest microversion (and continue to update it as you make changes to the imported Feature Studio):
      import(path : "a4b15a1a4bba13206e42cd64", version : "e679dc5c60bcb740e22a115e");
      

    4. Make sure any feature, function, type, or enum you want to use from the imported module is exported, e.g.
      export function myFunction(...
      export const myFeature = defineFeature(...
      

    5. Now you can call the exported symbols directly, like this:
              myFunction("foo");
              myFeature(context, id, {
                  "bar": "bar"
              });
      
      Or, if you used a namespace, like this:
              MY_MODULE::myFunction("foo");
              MY_MODULE::myFeature(context, id, {
                  "bar": "bar"
              });
      
    Importing a Part Studio into a Feature Studio:

    You can build geometry from a Part Studio right inside your feature by importing the Part Studio. You can import the Part Studio by the element id, just as above.


    When typing the import, you'll notice an error when first importing the Part Studio without a version, as in the gif above. This is a known bug, but it can be worked around by refreshing the page and immediately pressing commit.  This has been fixed in Onshape version 1.41

    The function you need from the Part Studio is named "build", which returns a context containing the Part Studio's geometry. 

    Here's an example feature using this method:
    FeatureScript 275;
    import(path : "onshape/std/geometry.fs", version : "275.0");
    THING::import(path : "7cc954522dbc4ce38424d920", version : "");
    
    annotation { "Feature Type Name" : "Add thing" }
    export const addThing = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
            annotation { "Name" : "Mounting mate connector", "Filter" : BodyType.MATE_CONNECTOR, "MaxNumberOfPicks" : 1 }
            definition.mountingConnector is Query;
        }
        {
            // Build a thing in a separate context
            var contextWithThing is Context = THING::build();
    
            // Delete its construction planes and origin
            opDeleteBodies(contextWithThing, id + "deleteDefaultGeometry", {
                "entities" : qUnion([
                    qConstructionFilter(qBodyType(qEverything(EntityType.BODY), BodyType.SHEET), ConstructionObject.YES),
                    qCreatedBy(makeId("Origin"))
                ])
            });
            
            // Add thing's context to the current Part Studio
            opMergeContexts(context, id + "addThing", {
                "contextFrom" : contextWithThing
            });
    
            // Move the thing to the mate connector
            var transform is Transform = toWorld(evMateConnector(context, {
                   "mateConnector" : definition.mountingConnector
            }));
            opTransform(context, id + "transformThing", {
                   "bodies" : qCreatedBy(id + "addThing", EntityType.BODY),
                   "transform" : transform
            });
        }, { /* default parameters */ });
    
    This feature adds the bodies of a Part Studio, and transforms them. You could imagine adding other steps in the feature too (boolean, modify, create more geometry, etc.).

    Imports collectively open up some powerful methods of defining reusable geometry. Our hope is for FeatureScript users to find a style of working where geometry best defined with traditional, interactive modeling lives inside a Part Studio, and geometry best defined with code and logic lives in a Feature Studio.

    hello kevin,
    first of all, thanks a lot for the information, and it is great as information,
    one thing I wanted to point out (seen that you make part of Onshape staff), is it would be great to add the path and version (the 1. up to 3. steps) in the documentation when we are reading https://cad.onshape.com/FsDoc/imports.html#importing-external-data I spent a lot of time trying to find how to do this for a custom icon and at least I have not seen it (for the path and version), thanks to god i found this post.
    either way, thank you a lot!
  • Alex_KempenAlex_Kempen Member Posts: 213 EDU
    You no longer need this post since you can simply use the import button in FeatureStudios, then simply select the part studio/feature studio you want to use. That's what the Direct FeatureScript Imports part of the documentation is telling you to do. It's actually quite intuitive, once you know it exists.
  • Kyler_WalkerKyler_Walker Member Posts: 64 PRO
    I am trying to derive a sketch using importDerived().  I can't figure out how to address my sketch.  I have tried performing the derive manually, then copying and pasting the code into my Feature Studio. When I do this, it throws "IMPORT_DERIVED_NO_PARTS." How can I address the sketch I want to derive?
  • Alex_KempenAlex_Kempen Member Posts: 213 EDU
    If you've made a sketch in a Feature Studio and wish to use it elsewhere by saving it into a FeatureScript, you can do so by importing the part studio your sketch resides in into your code using the import button in your Feature Studio, then using the instantiator module of the FS Library to place it into part studios wherever your FeatureScript is used. You can also at that point include things like a transform to place the sketch in an appropriate location. Notably, if you want to import only a single sketch, then you might have to do some querying so that only sketch objects or the like are brought in. The instantiator has methods to do this, but plucking a single sketch from a complex part studio with several different sketches could be challenging.

    You can also use a reference parameter to allow users to choose whatever geometry they wish in a manner akin to Onshape's derive feature or Ilya Baran's super derive feature. However, since you have a single sketch in mind, this probably isn't necessary for your purpose.
  • Kyler_WalkerKyler_Walker Member Posts: 64 PRO
    If you've made a sketch in a Feature Studio and wish to use it elsewhere by saving it into a FeatureScript, you can do so by importing the part studio your sketch resides in into your code using the import button in your Feature Studio, then using the instantiator module of the FS Library to place it into part studios wherever your FeatureScript is used. You can also at that point include things like a transform to place the sketch in an appropriate location. Notably, if you want to import only a single sketch, then you might have to do some querying so that only sketch objects or the like are brought in. The instantiator has methods to do this, but plucking a single sketch from a complex part studio with several different sketches could be challenging.

    You can also use a reference parameter to allow users to choose whatever geometry they wish in a manner akin to Onshape's derive feature or Ilya Baran's super derive feature. However, since you have a single sketch in mind, this probably isn't necessary for your purpose.
    Thanks for the response. Is the instantiator method better than importDerived? What is the difference between the two functions?

    I am trying the instantiator method and have successfully brought in sketches.  I'm not sure of a good way to filter for the one I want.  I thought I could just use qCreatedBy(), but that doesn't seem to work.   
  • Alex_KempenAlex_Kempen Member Posts: 213 EDU
    importDerived is the Onshape derive feature - it's the user facing version you use in part studios. Instantiator is a purpose built FS solution for importing bodies, and is better when bringing in multiple instances - if there's duplicates, it will automatically pattern the instances, rather than importing the same body multiple times. It also has useful features like the ability to specify a transform to apply to imported bodies, which makes it easy to bring them in at a specified location. 

    The easiest way to bring in a specific sketch is to configure your part studio such that there's only one unsuppressed sketch, then use the configuration options of the instantiator to select the correct configuration when importing (configuration values can be viewed using the change FeatureScript Id option of the configuration menu). Depending on how your part studio is set up, this could be fairly straightforward. qCreatedBy and similar id based query methods are tricky to get working since the way ids work when importing a context isn't very clear - plus those methods tend to be not very robust.
  • Kyler_WalkerKyler_Walker Member Posts: 64 PRO
    The easiest way to bring in a specific sketch is to configure your part studio such that there's only one unsuppressed sketch, then use the configuration options of the instantiator to select the correct configuration when importing (configuration values can be viewed using the change FeatureScript Id option of the configuration menu). 
    This was helpful.  Thanks. My part studio wasn't set up for me to suppress other sketches.  The one I needed was at the end of the feature tree, converted from part geometry.  I just made a new part studio and used a derived in the necessary parts to reproduce the my sketch.
  • mortezaPourmohamadimortezaPourmohamadi Member Posts: 7 PRO
    edited January 6
    Just a quick note on the code you have shared: The "Transform" variable is called "transform", which happens to be the name of the function for defining a transform also. FS shouldn't really allow the reserved function names to be used as local variable names.
    // Move the thing to the mate connector
            var transform is Transform = toWorld(evMateConnector(context, {
                   "mateConnector" : definition.mountingConnector
            }));
    Anyway, If people use snippets of this code without changing the variable name, it is going to mess up with any consecutive transform function definitions, unfortunately. So the following example with through an error if it comes after the above snippet:
          
            var t1 is Transform = transform (vector(1, 1, 1) * millimeter);

    The error message would be something like below:

           Called value must be function, value is Transform (map)

    @[email protected]_Rosenfeld mentions the bug in this post from 2019: 

    https://forum.onshape.com/discussion/11462/transform-help-request


    - Morteza




Sign In or Register to comment.