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.

Options

Function variables

james_sleemanjames_sleeman Member, Developers Posts: 21 ✭✭
It would be super useful to be able to define a variable as a function, so that we could do something like

#myFunctionVariable(5)

where

#myFunctionVariable(x) = [equation involving x]

use case for example would be in having some standard and centrally configurable adjustment for hole sizes, to achieve dimensionally accurate holes on 3d printers without having to hard-code in your printer/filament's peculiarities we could just dimension our 3mm holes to #hole(3) such that the #hole(x) variable was defined as an equation that produces the correctly adjusted dimension. 

Comments

  • Options
    ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,185
    edited May 2016
    With FeatureScript released, you can now do basically this, just using a Feature Studio.  Create a custom feature with code like this:

    annotation { "Feature Type Name" : "Add My Functions" }
    export const addMyFunctions = defineFeature(function(context is Context, id is Id, definition is map)
        precondition
        {
        }
        {
            setVariable(context, "myFunctionVariable",
                function(x) {
                    return x + 2 * millimeter; // Function code goes here
                }
            );
            // You can make more setVariable calls here to make more functions
        });
    

    And then in your Part Studio, add the "Add My Functions" feature at the beginning of the feature list.  You can then use #myFunctionVariable(2 cm) in a subsequent expression (to get 22mm).  Eventually we'll make it possible to just set the value by defining the myFunctionVariable variable without creating a Feature Studio.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • Options
    pablo_fernandez_techpablo_fernandez_tech Member Posts: 5
    I tried this, but I get "Enter a valid expression" when I try to use the function:


  • Options
    ilya_baranilya_baran Onshape Employees, Developers, HDM Posts: 1,185
    It's impossible to debug without a link to a public document.  A possible explanation is that your function is not returning a quantity with the right units -- it needs to return a length.
    Ilya Baran \ VP, Architecture and FeatureScript \ Onshape Inc
  • Options
    chadstoltzfuschadstoltzfus Member, Developers, csevp Posts: 134 PRO
    edited September 2022
    I was very curious to try this out and it turns out that there's a lot you can do with these functions, at least a lot more than I thought. They're a pain to debug and you miss out on the great snippet inserts you get in Feature Studios, but it's cool that things like for loops work in variables.

    Here's a variable that displays a decimal as a fraction (just paste this into the Value field of a variable feature).

    function(x){var wholeNumber = floor((x + 1e-11 * meter) / inch);var remainder = x / inch - wholeNumber;var fraction = 1;for (var i = 0; i < 8; i += 1){if (abs(remainder - round(remainder)) < 1e-11) { break;}remainder *= 2;fraction *= 2;}if (fraction == 1){return wholeNumber ~ "\"";     }  var fractionalPart = round(remainder) ~ "/" ~ fraction;if (wholeNumber == 0){return fractionalPart ~ "\"";}return wholeNumber ~ " " ~ fractionalPart ~ "\""; }




    This is definitely one of those "why would you ever do this" sort of situations, as it is way more efficient and simpler to just write a custom feature, but who knows there might be some cases where it's better to just use a variable. One could imagine a variable studio of functions that one might want to use often. 
    Applications Developer at Premier Custom Built
    chadstoltzfus@premiercb.com
  • Options
    Evan_ReeseEvan_Reese Member Posts: 2,070 PRO
    One could imagine a variable studio of functions that one might want to use often. 
    This is definitely fascinating, but I agree that I can't quite picture the use-case where that's better than a feature. There probably is one somewhere though.
    Evan Reese / Principal and Industrial Designer with Ovyl
    Website: ovyl.io
  • Options
    Evan_ReeseEvan_Reese Member Posts: 2,070 PRO
    I tried this, but I get "Enter a valid expression" when I try to use the function:


    If you're using Ilya's code above you need to add units to the number since you can't add a number, and length together. Try #myFunctionVariable(2mm) instead.
    Evan Reese / Principal and Industrial Designer with Ovyl
    Website: ovyl.io
  • Options
    pablo_fernandez_techpablo_fernandez_tech Member Posts: 5
    The problem was that I didn't have a unit.
  • Options
    fstfst Member Posts: 45 ✭✭
    I cannot get this to work. Have defined a function as value of a parameter as shown by @chadstoltzfus. Now I try to call it, but it is always shown as invalid.

    Function definition: pipe_width_at: function(x){return pipe_height_at_bottom-(pipe_width_at_bottom-pipe_width_at_top)*pos/soundpipe_length;}
    ^^This still seems to work! (All variables inside this definition are defined above, they are lengths in mm. Couldn't define the function as length, it was accepted when I chose "any" though.)

    Attempts to instantiate the function:
    #pipe_width_at(#soundpipe_length+#soundhole_length)
    #pipe_width_at(245mm)
    #pipe_width_at(245)


  • Options
    fstfst Member Posts: 45 ✭✭
    edited April 2023
    I think I found the answer: It is currently apparently not possible to reference other variables in function definitions.
    So this works:
    name: increment.  value: function(x){return x + 1};

    But this doesn't:
    name: startValue.  value: 42
    name offsetFromStartValue.    value: function(x){return startValue+x;)
    ^^these two can still be defined, but #offsetFromStartValue(2.0) will fail

    Thinking now about building a bigger (Featurescript)-feature that creates essentialy the entire part programmatically - might be easier.

    --- old posting ---

    I cannot get this to work. Have defined a function as value of a parameter as shown by @chadstoltzfus. Now I try to call it, but it is always shown as invalid.

    Function definition: pipe_width_at: function(x){return pipe_height_at_bottom-(pipe_width_at_bottom-pipe_width_at_top)*pos/soundpipe_length;}
    ^^This still seems to work! (All variables inside this definition are defined above, they are lengths in mm. Couldn't define the function as length, it was accepted when I chose "any" though.)

    Attempts to instantiate the function:
    #pipe_width_at(#soundpipe_length+#soundhole_length)
    #pipe_width_at(245mm)
    #pipe_width_at(245)
    ^^ None of these seem to work.
    Any ideas?

    Removed link - not sure why my postings are not published when I post links to my public documents? Might have helped to understand the problem...

  • Options
    chadstoltzfuschadstoltzfus Member, Developers, csevp Posts: 134 PRO
    @ferdinand_strixner
    To my knowledge there isn't a way to reference Part Studio variables inside the scope of the lambda function, though it's worth noting you can send a Part Studio variable as an argument to the function.  

    Ex: 
    name: startValue.  value: 42
    name offsetFromStartValue.    value: function(x, y){return y+x * in;)

    Invoke #offsetFromStartValue(2in, #startValue)
    Will return 44



    Though you're probably right, it's going to be much more scalable and easy to manage to just make a custom feature.
    Applications Developer at Premier Custom Built
    chadstoltzfus@premiercb.com
Sign In or Register to comment.