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.

String Parameter won't reference a Text Config Variable

sam_parsonssam_parsons Member Posts: 43 PRO
Hey Guys,

I'm trying to use a custom feature to assign materials to parts. But I'm getting tripped up by the string parameter. I can't seem to configure the parameter using a text config variable? Presumably because "#" becomes part of a string and loses it's ability to signify another variable?

Here is the annotation in FS:
annotation { "Name" : "Core Material", "Default" : "Default" }
definition.coreMat is string;
Any thoughts would be greatly appreciated!

Sam


Comments

  • mahirmahir Member, Developers Posts: 1,307 ✭✭✭✭✭
    edited June 2020
    Instead of defining the annotation as a string, define it as a field that accepts anything (including variables). As you said, forcing the input to be a string will just use whatever text you enter as is, including the #.

    So instead of
    definition.coreMat is string
    use
    isAnything(definition.coreMat)

    Keep in mind that this will allow just about anything to be entered - variables, functions, numbers, booleans, and of course text strings. To insure whatever is entered is treated as a string later in the FS, you may need to typecast via toString().
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,045 ✭✭✭✭✭
    Alternatively, you can use a little coding to remap the #variable to its value.
    See an example function I have for doing that below:
    
    /**
     * This function maps variables denoted by `#variable` to the appropriate variable in the context.
     */
    export function remapVariables(context is Context, text is string) returns string
    {
        // An optimisation if there is no variable references
        if (replace(text, "#", "") == text)
            return text;
    
        var variables is map = getAllVariables(context);
        variables[" "] = ""; // Replace "# " with ""
        var out is string = "";
        const chars is array = splitIntoCharacters(text);
        const charsSize is number = @size(chars);
        for (var i = 0; i < charsSize; i += 1)
        {
            const char is string = chars[i];
            if (char == "#")
            {
                if (i < charsSize - 1 && chars[i + 1] == "#")
                {
                    out ~= "#";
                    i += 1;
                    continue;
                }
                const varName = getVarName(chars, i + 1);
                if (varName != undefined && variables[varName] != undefined)
                {
                    out ~= toString(variables[varName]);
                    i += length(varName);
                }
                else
                    out ~= char;
            }
            else
                out ~= char;
        }
        return out;
    }
    
    function getVarName(chars is array, i is number)
    {
        var out = "";
        for ( ; i < @size(chars) && nonSpecial[chars[i]] == true; i += 1)
            out ~= chars[i];
    
        if (out == "" && i < @size(chars) && chars[i] == " ")
            return " ";
    
        return out == "" ? undefined : out;
    }
    
    // This uses a function to generate a constant.
    const nonSpecial is map = function()
        {
            const chars = splitIntoCharacters("1234567890_qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"); // All alphabetic characters
            var out = {};
            for (var char in chars)
                out[char] = true;
    
            return out;
        }();

    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • sam_parsonssam_parsons Member Posts: 43 PRO
    mahir said:
    Instead of defining the annotation as a string, define it as a field that accepts anything (including variables).
    Perfect! I'll try this for now.

    Alternatively, you can use a little coding to remap the #variable to its value.
    But I can see how this would be useful long term, just not sure I know enough about feature script yet to implement it. Do you just include this in the custom feature code?
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,045 ✭✭✭✭✭
    @sam_parsons

    If you put the code above in your FeatureStudio, you can then use it in your code just after the end of the precondition:
            definition.codeMat is string;
            // The rest of the precondition
        } // End of precondition
        { // Start of feature body
            definition.coreMat = remapVariables(context, definition.coreMat);
            // Continue the rest of the code

    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
  • sam_parsonssam_parsons Member Posts: 43 PRO

    If you put the code above in your FeatureStudio, you can then use it in your code just after the end of the precondition
    ok thanks, I may try this at some point. For now, I've got @mahir 's method working... however... I get the same problem when I insert that part into an assembly, I get the same issue in the change configuration in UI. Any ideas?


  • sam_parsonssam_parsons Member Posts: 43 PRO
    @MBartlett21 , would your method solve this ^ ?
  • MBartlett21MBartlett21 Member, OS Professional, Developers Posts: 2,045 ✭✭✭✭✭
    @sam_parsons
    Unfortunately not :(
    mb - draftsman - also FS author: View FeatureScripts
    IR for AS/NZS 1100
Sign In or Register to comment.