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.

Editing logic breaking reference to variables in array parameter?

MichaelPascoeMichaelPascoe Member Posts: 875 PRO
edited October 2021 in FeatureScript
Both of these custom features have array parameters: Texture & Freeform Spline. Input variables are lost when a new array item is added. Is there a way to fix this?

@Evan_Reese, you may be interested in the solution to this if there is one.


Best Answer

  • Alex_KempenAlex_Kempen Member Posts: 219 EDU
    Answer ✓
    The value of sortXReturned (and sortYReturned and so on) should have no bearing on whether your variables are getting overridden. Rather, it's the statement definition.groups[g].sizeX = storeSizes.x that's tripping you up, since that's setting the value of definition.groups[g].sizeX to the saved value of definition.groups[g].sizeX, which doesn't include the necessary variable information, even if the values are technically the same. The solution, therefore, is only to override the variables when the override value is actually different from the input value:
    // if definition.groups[g].sizeX is already the correct value, leave it alone!
    // if storeSizes.x is zero and autoScale.x is different from definition.groups[g].sizeX:
    if (storeSizes.x == 0 && !tolerantEquals(definition.groups[g].sizeX, autoScale.x))
    {
       definition.groups[g].sizeX = autoScale.x;
    }
    else if (!tolerantEquals(definition.groups[g].sizeX, storeSizes.x))
    {
        definition.groups[g].sizeX = storeSizes.x; 
    }
    Don't forget to repeat the following code for sizeY and sizeZ as well.

Answers

  • Evan_ReeseEvan_Reese Member Posts: 1,420 PRO
    yes! this is pretty important and I've not found a solution if there is one. Thanks for asking about it. 
    Evan Reese / Principal and Industrial Designer with Ovyl
    Website: ovyl.io
  • MichaelPascoeMichaelPascoe Member Posts: 875 PRO
    edited October 2021
    I think it has something to do with edit logic. Multi Variable also contains an array parameter, however it works as expected.
  • Alex_KempenAlex_Kempen Member Posts: 219 EDU
    I would imagine its the result of setting a new value of the parameter that matches the value of the old parameter unnecessarily. Depending on your conditions, running the editing logic with a sufficient condition (like adding a new array parameter) is enough to break the references.
    To prevent this from happening, add conditions to shield parameters from being updated unless they actually need a new value:
    if (!tolerantEquals(newValue, oldValue))
    {
       // arrayParameter = newValue;
    }
    I suppose this behavior could actually be used desirably to selectively break variable references or move variables to an internal parameter. Of course, that's a very specific use case, but you never know.
  • MichaelPascoeMichaelPascoe Member Posts: 875 PRO
    edited October 2021
    Perhaps I used it improperly, or it didn't work. @Alex_Kempen

    Near line 3201 in the Texture feature:
                 if (!tolerantEquals(definition.groups[g].sizeX, oldDefinition.groups[g].sizeX))
                        {
                            if (oldDefinition.groups[g].sizeX == .999 * inch || definition.groups[g].sortX == Sort.PLUS_Y)
                            {
                                if (storeSizes.x == 0) // if scale has not been used, use auto scale
                                {
                                    definition.groups[g].sizeX = autoScale.x;
                                }
                                else // if scale has been used, use the last stored value
                                {
                                    definition.groups[g].sizeX = storeSizes.x;
                                }
                            }
                        }

  • Alex_KempenAlex_Kempen Member Posts: 219 EDU
    So basically, you don't want to set definition.groups[g].sizeX to anything unless that change is actually required (i.e. the user has dragged a manipulator, so the variable needs to be overridden). So I would put the tolerant condition around definition.groups[g].sizeX = storeSizes.x specifically, comparing definition.groups[g].sizeX and storeSizes.x. You could also just not have that condition at all, since storeSizes.x is presumably always the same as definition.groups[g].sizeX in the first place. 

    Also, as a more general note, using 0.999 * inch as the indicator for whether the feature has been scaled is low key not great. I would recommend using a hidden map to store that information instead - it should be more reliable and silent to the user.
  • MichaelPascoeMichaelPascoe Member Posts: 875 PRO
    Turns out it's breaking it in 3 different spots. line 3158, 3195, and 3206. All of these are in the editing logic function.

    I don't care too much about the name of the config so I can simply delete code at line 3158. However, I do not want to get rid of the functionality from lines 3195 and 3206. I have tried placing them in an if statement so that they only return if something has changed, however if they return at all, they break the previous groups reference to the users variables.

    Line 3158, name is changed in edit logic then returned to the hidden parameter above.
                            for (var g = 0; g < size(definition.groups); g += 1)
                            {
                                definition.groups[g].name = "Configuration" ~ " " ~ toString(g + 1);
                            }

    Line 3195
                            if (oldDefinition.groups[g].sizeX == .999 * inch || definition.groups[g].sortX == Sort.PLUS_Y)
                            {
                                if (storeSizes.x == 0) // if scale has not been used, use auto scale
                                {
                                    definition.groups[g].sizeX = autoScale.x;
                                }
                                else // if scale has been used, use the last stored value
                                {
                                    definition.groups[g].sizeX = storeSizes.x;
                                }
                            }<br>

    Line 3206
                            if (oldDefinition.groups[g].sortX != definition.groups[g].sortX)
                            {
                                definition.groups[g].sortXReturned = definition.groups[g].sortX;
                            }

  • Alex_KempenAlex_Kempen Member Posts: 219 EDU
    Answer ✓
    The value of sortXReturned (and sortYReturned and so on) should have no bearing on whether your variables are getting overridden. Rather, it's the statement definition.groups[g].sizeX = storeSizes.x that's tripping you up, since that's setting the value of definition.groups[g].sizeX to the saved value of definition.groups[g].sizeX, which doesn't include the necessary variable information, even if the values are technically the same. The solution, therefore, is only to override the variables when the override value is actually different from the input value:
    // if definition.groups[g].sizeX is already the correct value, leave it alone!
    // if storeSizes.x is zero and autoScale.x is different from definition.groups[g].sizeX:
    if (storeSizes.x == 0 && !tolerantEquals(definition.groups[g].sizeX, autoScale.x))
    {
       definition.groups[g].sizeX = autoScale.x;
    }
    else if (!tolerantEquals(definition.groups[g].sizeX, storeSizes.x))
    {
        definition.groups[g].sizeX = storeSizes.x; 
    }
    Don't forget to repeat the following code for sizeY and sizeZ as well.
  • MichaelPascoeMichaelPascoe Member Posts: 875 PRO
    edited October 2021
    Thanks @Alex_Kempen for your patience and all of the troubleshooting and teaching!

    Here is the code that seems to be working, I will need to tweak it some more:
    if (storeSizes.x == 0 && !tolerantEquals(definition.groups[g].sizeX, autoScale.x))
    {
         definition.groups[g].sizeX = autoScale.x;
    }
    else if (oldDefinition.groups[g].sizeX == .999 * inch && !tolerantEquals(definition.groups[g].sizeX, storeSizes.x))
    {
         definition.groups[g].sizeX = storeSizes.x;
    }

Sign In or Register to comment.