FeatureScript is a deterministic language. That means it should execute the same way every time. This behavior ensures that features maintain stability and integrity in your Feature list. Because of this, there is no built-in random function in FeatureScript. That said, there are some reasons you might want to add a bit of randomness to your feature. For instance, you might want to apply a texture to a surface such as the plate below.
Or, on a more fun note, maybe you wish to generate a BINGO Board.
In this Tech Tip, we will go over the basics of making a pseudo-random number generator that makes these things possible.
Linear Congruential Generator Explanation
A linear congruential generator (LCG) is a common algorithm to achieve something close to random number generation. It is easily implemented and fast. The formula for it is:
Xi = (a * Xi−1 + c) mod m
X = seed
a = multiplier
c = increment
m = modulus
The seed would have to be something inputted by the user or a truly random number. In this case, we will use the feature’s ID to ensure randomness. Many studies have been done on the multiplier, increment, and modulus to come up with the ideal numbers for a, c, and m such that it is seemingly random. It is best to stick with values that are in common usage. A detailed explanation of the LCG and its inputs are available on Wikipedia and many other sites.
For this example, use the Microsoft implementation:
a = 214013
c = 2531011
m = 231
The FeatureScript Code
Start a new Feature Studio. Create the following function.
function lcg(seed) returns function
{
const a = 214013;
const c = 2531011;
const m = 2 ^ 31;
var state = new box(seed);
return function()
{
state[] = (a * state[] + c) % m;
return state[];
};
}
This function implements the LCG in the code. Since FeatureScript is generally pass-by-value, it is necessary to use a box. When you generate multiple numbers, the xi-1 value will continue to change because a box retains the reference. The LCG function returns another function that we can call multiple times from the Custom Feature to get pseudo-random numbers.
Assigning a Random Seed
The LCG needs a seed to make numbers. User input could provide it, or you can get it from something already in the Part Studio. A good source is the Custom Feature’s ID. Each feature in the Feature List has a random ID that is a sequence of numbers and letters. All the letters must be converted to numbers to use the feature ID as the seed.
Paste the following code to convert the ID into just numbers.
const chrMap = {
'A' : 0, 'B' : 1, 'C' : 2, 'D' : 3, 'E' : 4, 'F' : 5, 'G' : 6,
'H' : 7, 'I' : 8, 'J' : 9, 'K' : 10, 'L' : 11, 'M' : 12, 'N' : 13,
'O' : 14, 'P' : 15, 'Q' : 16, 'R' : 17, 'S' : 18, 'T' : 19, 'U' : 20,
'V' : 21, 'W' : 22, 'X' : 23, 'Y' : 24, 'Z' : 25,
'a' : 26, 'b' : 27, 'c' : 28, 'd' : 29, 'e' : 30, 'f' : 31, 'g' : 32,
'h' : 33, 'i' : 34, 'j' : 35, 'k' : 36, 'l' : 37, 'm' : 38, 'n' : 39,
'o' : 40, 'p' : 41, 'q' : 42, 'r' : 43, 's' : 44, 't' : 45, 'u' : 46,
'v' : 47, 'w' : 48, 'x' : 49, 'y' : 50, 'z' : 51,
'_' : 99, '-' : 98
};
function idToNum(input is string) returns number
{
var out is string = "";
for (var char in splitIntoCharacters(input))
{
var res = match(char, REGEX_NUMBER);
if (res.hasMatch)
{
out = out ~ toString(res.captures[0]);
}
else
{
out = out ~ toString(chrMap[char]);
}
}
return stringToNumber(out) % 10000;
}
It is important to use the modulo of 10000 to ensure the seed isn’t too large. The modulo returns the remainder when the two numbers are divided, so the result can only be between 0 and 9999.
Now, call the idToNum function from the lcg function. Change the state declaration to the following to call the new function.
var state = new box(idToNum(seed));
Create the Custom Feature
Now that the LCG is finished, you can call it from a feature. Create a new feature in the Feature Studio. Execute the lcg function and set its variable x equal to it. For the seed, use id[0] to grab the root ID of the Custom Feature.
var x = lcg(id[0]);
This statement returns a function that you can call any time you want a random number. As an easy example, use the println function.
println(x());
Commit it and execute it in a Part Studio. The result shows in the FeatureScript notices.
If you would like to reduce the number to a specific range, use the modulo operator again. For example, you can use a modulo of 100 for numbers 0 to 99.
println(x() % 100);
You can use this in a loop and append them in an array to get several numbers for use in your script. Here is the completed script. Check out the BINGO Card and Random Surface Perturbator Custom Features to see practical examples of using an LCG.
Check out the video below for more on generating pseudo-random numbers using FeatureScript.
Interested in learning more Onshape Tech Tips? You can review the most recent technical blogs here.