Functions consist of a name followed by one or more values. They perform an operation on their input values and return the result.
Functions can be used inside expressions, and can accept expressions as inputs. Unlike operators, functions have no implicit precedence, so parentheses may be needed to avoid ambiguity.
In the following example, it’s not clear if y
is intended as a second argument to the cos
function, or as the second argument to the translate command. Only the latter would technically be valid, since cos
only accepts a single argument, but ShapeScript requires you to be explicit, and will treat this as an error:
translate cos x y
The error can be resolved by using parentheses to group the cos
function with its argument:
translate (cos x) y
Lisp programmers will find this syntax quite familiar, but if you have used C-like programming languages it may seem a little strange to put the parentheses around the function name and its arguments instead of just the arguments. If you prefer, you can use a C-like syntax instead:
translate cos(x) y
Either approach is acceptable in ShapeScript.
In addition to the standard arithmetic operators, ShapeScript also includes a number of built-in arithmetic functions:
The round
function is used to round a number to the nearest integer (whole number):
round 3.2 // returns 3
round 3.9 // returns 4
round 3.5 // returns 4
The floor
function is similar, but always rounds down:
floor 3.2 // returns 3
floor 3.9 // returns 3
The ceil
function always rounds up:
ceil 3.2 // returns 4
ceil 3.9 // returns 4
The abs
function returns the magnitude of a number, ignoring the sign:
abs 4.5 // returns 4.5
abs -51 // returns 51
The sign
function (not to be confused with sin) returns 1
, -1
or 0
depending on the sign of the input:
sign 4.5 // returns 1
sign -51 // returns -1
sign 0 // returns 0
The sqrt
function returns the square root of a value:
sqrt 4 // returns 2
sqrt 2 // returns 1.414
The pow
function takes two parameters, and return the first value raised to the power of the second:
pow 2 4 // returns 16
pow 3 2 // returns 9
pow 4 0.5 // returns 2
The min
function returns the lower of two or more values:
min 2 4 // returns 2
min 5 0 -5.1 // returns -5.1
The max
function returns the higher of two or more values:
max 2 4 // returns 4
max 5 0 -5.1 // returns 5
ShapeScript also includes functions for operating on vectors:
The dot
function is used to calculate the dot product of a pair of vectors:
define up (0 1)
define right (1 0)
print dot(up right) // returns 0
The cross
function calculates the cross product:
define up (0 1)
define right (1 0)
print cross(up right) // returns 0 0 -1
The length
function calculates the magnitude of a vector (also known as the norm):
define v (3 4)
print length(v) // returns 5
The normalize
function computes a unit vector from an arbitrary vector by dividing each element by the vector length:
define v (3 4)
print normalize(v) // returns 0.6 0.8
For the most part, you can avoid the need for trigonometry in ShapeScript by using the built-in transform commands to manipulate geometry rather than manually calculating the positions of vertices.
But sometimes you may wish to do something more complex (e.g. generating a path in the shape of a sign wave) that can only be achieved through explicit calculations, and to support that, ShapeScript provides a standard suite of trigonometric functions.
While ShapeScript’s transform commands expect values in half-turns, the trigonometric functions all use radians.
For example, the sin
(sine) function takes a radian representation of an angle and returns a ratio value of that angle. In this case 0.524 radians returns 0.5 or 1/2 - an angle of 30 degrees:
sin 0.524 // returns 0.5
The acos
(arc cosine) function takes a ratio representation of an angle and returns a radians value of that angle. In this case 1/2 or 0.5 returns 1.047 radians - equivalent to an angle of 60 degrees:
acos 0.5 // return 1.047
The cos
(cosine), sin
(sine), and tan
(tangent) functions all take a radians value and return a ratio value, and the asin
(arc sine), acos
(arc cosine), and atan
(arc tangent) functions all take a ratio value and return a radians value.
Using atan
to calculate the angle of a vector is problematic because the result that it returns can be ambiguous. You need to take the vector quadrant into account, as well as the ratio of the X and Y components.
The atan2
function works like atan
, but instead of a single tangent value, it accepts separate Y and X inputs and returns the angle of the vector that they describe. The resultant angle correctly takes the vector quadrant into account.
atan2 1 -1 // returns a radian angle of the vector Y: 1, X: -1
To convert an angle in radians to a ShapeScript half-turn value, divide it by the ‘pi’ constant:
define angle acos(0.5) // returns 1.047 radians (60 degrees)
rotate angle / pi // return 0.333 (1.047 / 3.141)
To convert a ShapeScript half-turn value to radians, multiply it by pi
.
cube {
orientation 0.5
print orientation.roll * pi // prints 1.571 (0.5 * pi)
}
Angular conversion formulae:
Conversion | Formula |
---|---|
Degrees to radians | radians = degrees / 180 * pi |
Radians to degrees | degrees = radians / pi * 180 |
Degrees to half-turns | halfturns = degrees / 180 |
Half-turns to degrees | degrees = halfturns * 180 |
Radians to half-turns | halfturns = degrees / pi |
Half-turns to radians | radians = halfturns * pi |
Common values:
Angle in degrees | Angle in radians | Angle in half-turns |
---|---|---|
0 | 0 | 0 |
30 | pi / 6 (0.524) | 1 / 6 (0.167) |
45 | pi / 4 (0.785) | 1 / 4 (0.25) |
60 | pi / 3 (1.047) | 1 / 3 (0.333) |
90 | pi / 2 (1.57) | 1 / 2 (0.5) |
180 | pi (3.142) | 1 |
ShapeScript includes a number of functions for manipulating strings.
The join
function concatenates two or more strings together, with an optional separator:
define words "Hello" "World!"
define greeting join words ", "
print greeting // prints "Hello, World!"
If you don’t want a delimiter, just pass an empty string as the second argument to join:
define words "Hello" "World!"
define greeting join(words "")
print greeting // prints "HelloWorld!"
The split
function breaks a string up into a tuple of substrings by splitting it at a specified delimiter:
define input "comma,delimited,string"
define elements split input ","
print elements.second // prints "delimited"
The trim
function removes any leading or trailing white space characters from a string:
define input "comma, delimited , string,with ,spaces"
define elements split input ","
print elements.second // prints " delimited "
print trim elements.second // prints just "delimited" without spaces
Expressions can be passed as function arguments, for example:
sin pi / 2 // returns 1
Which, thanks to precedence rules, is equivalent to:
sin(pi / 2) // returns 1
You can also use function calls inside an expression, for example:
print (sqrt 9) + (sqrt 9) // prints 6
Or the equivalent form of:
print sqrt(9) + sqrt(9) // also prints 6
Note: When used inside an expression, parentheses around the function (or just its arguments) are required.
You can define your own functions using the define
command. A function definition consists of a function name followed by a list of parameter names in parentheses:
define sum(a b) {
a + b
}
define degreesToRadians(degrees) {
degrees / 180 * pi
}
Like blocks, functions can refer to constant values or other functions defined in their containing scope:
define epsilon 0.0001
define almostEqual(a b) {
abs(a - b) < epsilon
}
Unlike block options, function inputs do not have default values. Calling a function without passing a value for every input will result in an error.