DesignScript Training

Download as pdf or txt
Download as pdf or txt
You are on page 1of 45

DesignScript

INTRODUCTION
KEY LEARNING OBJECTIVES

1. 2. 3.
DesignScript Fundamentals: Data Management: Power and Control:
Syntax, Object Types, Legibility, UI and IDE Replication, List@Level, Nesting Conditional statements, Operators, Looping
and Conflicts and Custom Definitions
.

3
ds
What is DesignScript?
The foundational Legible scripting Intersection of
language of Dynamo language Design & Scripting

5
Where can I find DesignScript in Dynamo?
Authored inside a special node called a ‘Code Block’
Accessible through the Search features or Located in the Library:
• Script -> Editor -> Code Block

Note: Code Blocks have their own keyboard shortcut of double left click.
DesignScript Fundamentals
[ Exploring the Building Blocks of DesignScript ]
IDE
AUTO-COMPLETE
DesignScript is written inside a Code Block .

When typing, the integrated auto-complete help feature will prompt you to
help accelerate your code by suggesting functions and inputs. These
suggestions populate in a scrollable box underneath your typed
DesignScript line of code.

You can tab or click on the function to finish the current suggestion.

Auto-complete will limit possible options the more that you type as
showcased in the images to the right.

Note: IDE is an acronym for ‘Integrated Development Environment’ and Dynamo’s one is
simple; including auto-complete and dot-notation . Debugging happens through
warnings thrown by the node itself and outputs are checked using Watch nodes .
IDE
DOT-NOTATION
DesignScript contains a dot-notation feature that showcases available
constructors ( creators ), methods ( actions ) and properties ( queries ) of
your chosen Class.

To access dot-notation you simply put a dot ( period ) after your Class.
This will bring up a drop-down menu, aligned with your pointer, that you
can ( using auto-complete ) type in your chosen action.

Functions are demarcated by the function marker ( fx ) icon:

Constructors are demarcated by the plus ( + ) icon:

Properties do not appear inside of dot-notation.


IDE
COLOUR
The UI ( User Interface ) of DesignScript is simply colourised code
inside of a Code Block . Colour is used to differentiate various
features:

Classes are green.


Methods are blue.
Primitive Types are purple.
Numbers are a bolder blue.
Strings are brown.
NameSpaces are in Black
Variables are also in Black
All other syntax inside of DesignScript is black .
Colours can be used as a guide in helping for swift and accurate
reading of DesignScript code.
CONCEPT
CODE BLOCKS & STATEMENTS
A Code Block will automatically generate Input ports and output ports
based upon the code authored within. Output ports are generated by
terminating a line of code with a semi-colon ( ; ):

output = Our named variable.


a | b | c = Undefined variables become input ports.
> = Output ports are generated at the end of every line of code.

The value of the expression is assigned right-to-left to the variable .


The expression is evaluated according to the precedence of the operators
and brackets.
variable expression
statement
Learn more at http://designscript.io/DesignScript_user_manual_0.1.pdf

11
CONCEPT
VARIABLES
Variable - They act like containers that hold information, callable by their name*:

Str = “TEXT";
Int = 1234;
Double = 12.34;
boolean = false;
combined = str + num;

Assign using the variableName = data syntax.


Variables are used to store information in memory to then be referenced and manipulated
in DesignScript.
They allow us to label data with a descriptive name to make sense of our code.
They provide clarity when others read your code ( If you are diligent at naming! ).
Note: You can assign a variable to another variable.
Using concatenation you have to account for the spaces yourself (Refer to example image).
*Variables are not global . They are local to their own Code Block.
CONCEPT
ORGANISATION
A namespace is an abstract container to hold logical groupings of
functionality ( E.g Objects Class ). This is best illustrated with an example:

Geometry ( Namespace )
• Points ( Class )
• Point ( Class )
• ByCoordinates ( Constructor aka Create )
• Add ( Method aka Action )
• X ( Property aka Query )

They are a way to implement scope ( Define boundaries ).


Can be understood as a ‘Parent : Child’ relationship ( Inheritance ).

Note: In object-oriented programming, a Class is a template definition of the methods


and variables in a particular kind of object. An Object is an instance of a class that
contains real values instead of variables.
CONCEPT
COMMENTS
In DesignScript there are two commenting methods; Single Line and
Multi-Line ; Single line comments are initialised by a double backslash ( // ),
multi-line comments are initialised by a back-slash and asterisk ( /* ) and
closed by an asterisk and back-slash ( */ ):

// I’m a Single Line comment


/* I’m a multi
Line
Comment */ ;

Single line comments will not ‘wrap’ to the next line.


Multi-line comments will wrap until closed.
Single line comments do not need to be terminated by a semi-colon.
Multi-line comments do.
OBJECT TYPES
BOOLEAN
Boolean - DesignScript for ‘true / false’. Boolean values are constant
objects and are used to represent truth values:

boolTrue = true ;
boolFalse = false ;

In numeric contexts booleans behave like the integers 0 and 1.


Boolean values can also be referenced as Yes or No.
OBJECT TYPES
NUMBERS
Int ( Integer ) - Whole number:
intVar = 10 ;
Double ( Float / Number ) - Decimal placed number:
doubleVar = 20.27 ;

As both int and double are reserved keywords we can’t use them
as variable names.
Code Blocks only return the final result of the line of code ( As
shown in the image exemplar ).

You can cast ( Change the type of ) a String representation of a


number to a number using:

String . ToNumber ( number );


OBJECT TYPES
STRINGS
String - DesignScript for ‘Text’. Enclose inside of quotation marks:

str = “Quotation marks to create a String.”


multiLineStr = “We can use ‘return’ to split up our string
which allows your text to span across multiple
lines ( i.e. it wraps )!!!”;

You can cast ( Change the type of ) any object to a String by


concatenating empty quotations to that type:

lne = Point . ByCoordinates ();


strLne = lne + "" ;

Note: There is a graphical inconsistency with the wrapped line text that fails to
colour the subsequent lines. The code will correctly execute however.
Not to be confused with text objects inside of Revit
EXPLORE
VARIABLES, STRINGS & NUMBERS
Create your own variable(s) now by assigning a string or number value to each of
the following inside a fresh Code Block , ( And replacing my information with your
own ):

name = “Name: “ ;
myName = “Kumar“ ;
country = “Country: “ ;
originCountry = “India“;
age = “Age: “ ;
myAge = 31.5 ;

Check the preview bubble ( Or use a Watch node ) to see the results!
OBJECT TYPES
LISTS
List - A changeable ( mutable ) ordered container of elements:

emptyList = [ ];
numberList = [ 1 , 2 , 3 ];
stringList = [ “BILT EUR”, “2018” ];
mixedList = [ 1 , 2.5 , “Learning” , stringList];

Lists are declared by a named variable ( var ) followed by equals ( = )


and square brackets ( [ ] ).

Note: The way I am naming my variables is called Camel Case, where the first
word is all lowercase and all subsequent words have their first letter capitalised.
This is the preferred naming convention for the Dynamo team.

Square braces exist in Dynamo 2.0 onwards - Previously lists were initialised by curly
braces.
EXPLORE
LISTS
Exploring Lists using our previous Code Block data, we can pair our
data together using concatenation ( + ). Write the following inside your
existing Code Block :

data = [
name + myName,
country + originCountry,
age + myAge
];

Check the preview bubble ( Or use a Watch node ) to see the results!

Note: I am lavishly using returns here, but if you prefer you can write your data all
on one single line. Using returns like the above example increases code clarity.
OBJECT TYPES
DICTIONARY
Dictionary ( Dictionary.ByKeysValues ) - A collection of ‘key : value’
paired objects:

emptyDictionary = { };
newDictionary = Dictionary . ByKeysValues ( keys, values );

Dictionaries are declared by a named variable ( var ) followed by


equals ( = ) and curly braces ( { } ).
Dictionaries are unordered lists. They will ‘shuffle’. You get correct
values by calling their respective ‘keys’.
Values are only returned when you query the ‘key’ index using square
braces or the correct function:

newDictionary[ “ Room 01” ];


[ returns ] 100 ;
EXPLORE
DICTIONARIES
However, a better data container for general demographic
information is Dictionaries . We need a list of ‘keys’ and a list of
‘values’:

keyList = [ name, country, age ];


valueList = [ myName, originCountry, myAge ];

personData = Dictionary . ByKeysValues ( keys, values );

Type in the above 2.0 Dictionary syntax and see your results after
generating ‘key’ and ‘value’ lists. Then check the preview bubble (
Or use a Watch node ) to see the results!

Note: The image to the left is the Dynamo 1.X version when Lists and
Dictionaries both shared the Curly Braces syntax.
OPERATORS
ARITHMETIC
In DesignScript we have Operators which manipulate a value / variable.
Arithmetic covers the mathematical operations and are as follows
syntactically:

addition = 10 + 10 ;
subtraction = 10 – 5 ;
multiplication = 2 * 4 ;
division = 10 / 2.75 ;
modulus = 10 % 3 ;

Modulus is the division remainder - After the first number is divided by the
second and rounded down - what is left? ( 3 goes into 10 three times, with
1 as the remainder)

Note: Addition ( + ) can also be used for string concatenation.


OPERATORS
COMPARISON
Comparison Operators allows us to check relationships
between things ( variables ) and result in either a True or a
False boolean. Syntactically they are:

greaterThan = 10 > 15 ;
greaterThanOrEqualTo = 10 >= 10 ;
lessThan = 5 < 10 ;
lessThanOrEqualTo = 5 <= 3 ;
equality = 5 == 8 ;
notEquals = 5 != 10 ;
OPERATORS
MEMBERSHIP & BOOLEAN
DesignScript has two primary membership operators (Whether or not
something is inside a container ( list )):

List . Contains (list, object) = Evaluates to true if it finds a


thing ( variable ) inside the container, false if it does not.
! List . Contains (list, object) = Evaluates to true if it does
not find a thing ( variable ) inside the container, false if it does.

Boolean operators will check a value against multiple True / False


queries and will evaluate as follows:

and ( && ) = Evaluates to true if all expressions are True, false if it


does not.
or ( || ) = Evaluates to true if any expression is True, False if it
does not.
EXPLORE
ARITHMETIC, COMPARISON & BOOLEAN
A common comparison use case is an ‘If’ statement. Syntactically
this is represented inside of DesignScript as follows:

item comparison item ? doThisIfTrue : doThisIfFalse ;

range = 11..15;
(range % 3) > 1 ? “Greater” : “Lesser”;

We can use this syntax to build complex Masks for the


List.FilterByBoolMask function that pass through compliant objects:

area > 10 && area < 20 ? area : null;

Note: Parenthesis are only needed with complex equations as BEDMAS


algebraic order of operations apply. We use parenthesis in the above example
but not below. Both will function without but for clarity can be used.
SYNTAX
RESERVED KEYWORDS
Some words in DesignScript are reserved – which means you cannot break class constructor continue def
use them inside the Dynamo integration of DesignScript. else elseif extends false for
from if import in null
All Classes are also reserved and cannot be used as keywords ( E.g.
‘List’, ‘Point’, ‘Area’ etc. ). return static true while
Data Management
[ Managing data through powerful DesignScript features ]
CONCEPT
USING FUNCTIONS AS ARGUMENTS
DesignScript allows for the use of functions as arguments. For example
you can call two Point.ByCoordinates() functions inside of a
Line.ByStartPointEndPoint() . To call a function multiple times inside a
singular Code Block you would want to write each function on it’s own
line:

startPoint = Point . ByCoordinates ( );


endPoint = Point . ByCoordinates ( 10 , 0 , 0 );
newLine = Line . ByStartPointEndPoint ( startPoint, endPoint );

However, if the function will not be called more than once, you can write
your code more concisely by calling the function directly inside of
another function:

newLine = Line . ByStartPointEndPoint ( Point . ByCoordinates ( ),


Point . ByCoordinates ( 10 , 0 , 0 ) );
CONCEPT
STATIC VS. INSTANCE METHODS
DesignScript allows for two different ways to call a function: static and instance.
Static methods are called in full ( verbose ) and are the preferred way ( safest ) to
call a function in DesignScript. Creating Surface Points statically is initialized as
follows:

Surface . PointAtParameter ( srf, u, v );

Creating an instance of Surface Points is called as follows:

srf. PointAtParameter ( u, v );

Static methods include all arguments inside of the parenthesis.


Instance methods skip use the first argument to use before dot-notation and then
omit it from within the parenthesis.

Note: Some functions ( Typically properties ) do not have a static method or constructor and only
use their instance method. When in doubt, use Node2Code to see how a function converts a
Nodal implementation to DesignScript.
CONCEPT
CLASS CONFLICTS
When you have custom packages installed ( Zero-touch ) that contain a Class
Namespace that is the same as an out-of-the-box version then you may have to
specify the full class path to correctly initialise your chosen function. If you are
using a custom package that contains its own ‘List’ class, then using the Clean
method inside of Dynamo could return a warning:

List . Clean ( list01 );

In this instance, we will have to specify the full Class path ( Based on the .dll it
comes from ):

DSCore. List . Clean ( list01 );

DSCore will remain black rather than colour.


All tab-finished dot notation will finalise DSCore. DateTime as default ( So you’ll
have to manually delete that portion ).
FEATURE
RANGE
A range in DesignScript is a series of numbers from a start to an end point
with a designated step ( Spacing typology ) and is initialised in the following
ways:

start..end..step;
start..end..#amount;
start..end..~approximate;

Ranges can be either numeric or alphabetic .


Alphabetic ranges vary depending on capitalisation.
The start..end..#amount range ( E.g 0..1..#20 ) is harder to reproduce in nodal
form due to rounding - the DesignScript variant is swifter.
A range using the # ( amount ) spacing will always return the start value at
index 0 and the end value at index -1 ( last index ).
If you omit the step there is a default value of 1 ( 0..10 is the same as 0..10..1 ).
FEATURE
SEQUENCE
A sequence in DesignScript is a series of numbers from a start value, to a
chosen amount and incremented by a step . Sequences are initialised in
the following ways:

start..amount..step;
start..#amount..step;

Sequences can be either numeric or alphabetic .


Alphabetic sequences vary depending on capitalisation.
Special characters can be found in sequences.

Note: For sequences, we prefix the middle variable inside the initilisation syntax.
Sequences are not compatible with the tilde ( ~ ) approximation.
EXPLORE
NESTED RANGE & SEQUENCES
Let’s explore the range or sequence features through nesting. You
can put a nested range or sequences at any point of our
DesignScript syntax with the exception of the start value:

0 .. 5 ..( 1 .. 3 );
0 ..( 1 .. 5 )..# 2 ;

0 ..#( 1 .. 3 ).. 1 ;

Have a play with the alphabetic versions of ranges and sequences


and check the preview bubble ( Or use a Watch node ) to see the
results!
FEATURE
GET ITEM AT INDEX
DesignScript has a textual version of the node List.GetItemAtIndex( index )
and a shorthand version which is initialised by square brackets ( [ ] ) after a
list with a number inside, such as list[ number ] :

firstItem = list[ 0 ];
lastItem = list[ -1 ];
*middleItem = list[ Count (list) / 2 - 1 ];
itemRange = list[ 0 .. 3 ];
reverseItemRange = list[ -2 .. -3 ];

If you put a variable inside, you can attach an integer slider to the newly
generated input port to dynamically get items at index.

dynamicIndex = list[ slider ];

Note: *Middle Item will only work if there is an odd number of items in your list.
EXPLORE
GET ITEM AT INDEX
Let’s explore the Get Item At Index shorthand features in DesignScript:

dataList = [
[ “a” , “b” , “c” ],
0..3 ,
[ 1.5 , 2.7 , 5.5 ]
];

firstItem = dataList[ 0 ];
lastItem = dataList[ -1 ];
itemRange = dataList[ 0 .. 3 ];
reverseItemRange = dataList[ -2 .. -3 ];

To get items out of nested lists, you double-up ( Or triple and so on ) the Get
Item At Index syntax:

nestedLastItem = dataList[ -1 ][ -1 ];
FEATURE
REPLICATION: BASICS
DesignScript uses Replication instead of Lacing which allows you to feed in a
collection of objects instead of a single value to any input and specify how that data
interacts.

Replication is initiated by an Integer inside angle brackets ( <#> ). These are called
replication guides :

Point . ByCoordinates ( x< 1 >, y< 2 >, z< 3 > );

Replication is hierarchical, not proximical. The numbers inside of the greater-than and
less-than replication signs have a hierarchical relationship to each other when called
inside the same function:

x< 1 >, y< 2 >, z< 3 > == x< 1 >, y< 34 >, z< 120 >

Note: The number hierarchy also stipulates what collection has dominance ( i.e. governs the
replication relationship ).
FEATURE
REPLICATION: LACING TYPES
Replication can cover all of the possibilities of data matching that lacing
can in a Node based workflow. Replication is used to control data
matching otherwise Dynamo approximates the matching using auto
lacing :

list01 = [ “a” , “b” , “c” , “d” ];


list02 = [ 1 , 2 , ];

shortestLacing = list01< 1 > + list02< 1 >;


longestLacing = list01< 1 L > + list02< 1 L >;
crossProductLacing = list01< 1 > + list02< 2 >;
reversedCrossProduct = list01< 2 > + list02< 1 >;

Note: If you have three lists you are replicating across, you’ll need to use three tiers
of replication number to specify dominance ( I.e. list01<1>, list02<2>, list03<3> ) etc. If
we switch the number dominance inside the replication guides, the data changes as
shown in the preview bubble of the code block.

38
FEATURE
REPLICATION: LIST LEVELS
Replication can also be chained together to deal with multi-level
data matching. Each replication guide is paired with its
counterpart - starting from the outer list:

function( argument <1L> <1> , argument <1L> <2> );

Each replication guide that follows an argument indicates a level.


Each replication set only matters hierarchically in relation to other
members of that set.

Point.ByCoordinates( x<1> <1> , y<2> <2> ); ==


Point.ByCoordinates( x<3> <11> , y<7> <22> );

Rank dominance of each multi-level data matching matters only


in relation to each paired replication set .

39
EXPLORE
REPLICATION
Let’s explore replication with a simple use case - pairing
alphabetic and numeric characters in non-homogenous lists:

list01 = [ [ “a” , “b” , “c” ] , [ “d” , “e” ] ] ;


list02 = [ [ 1 , 2 ] , [ 3 , 4 , 5 ], [ 6 , 7 , 8 ] ];

Explore the following in a new Code Block :

Shortest lacing: list01< 1 > + list02< 1 >;


Longest lacing: list01< 1 L> + list02< 1 L>;
Cross Product: list01< 1 > + list02< 2 >;
Multi-Tier: list01< # >< # > + list02< # >< # >;

Note: list01<1> + list02<1> is the same as list01 + list02 is the same as


list01<2> + list02<2> and so on ( Any equal number across the same paired
replication sets will function this way ).

40
FEATURE
LIST @ LEVEL: CONCEPT
DesignScript uses List@Level to specify the level of list you want to
work with right at the argument. List@Level is NOT the Rank of a list, but
the location of a list. List@Level uses the following syntax:

List@Level: @L#
List@Level ( Keeping List Structure ): @@L#

Point . ByCoordinates ( x@L2, y@L2 );

List@Level is in essence a for loop running across the chosen level.


List@Level can be used in place of replication ( lacing ) in most cases.
List@Level pairs data from a level to another chosen level ( level
indicators match List@Level syntax ) .
The most useful level option is the same as the nodal default: @L2

Note: In the 1.X versions of Dynamo, the syntax for List@Level was: @-# using a
negative ( - ) prefix in lieu of an uppercase ‘L’ : E.G @-2 .

41
FEATURE
LIST @ LEVEL
List@Level can allow us to pair data in a logical format. In the visual
example here we firstly pair the roomsList at location level 1 with the
alphaRange at location level 1:

roomsList@L 1 + alphaRange@L 1 ;

Notice how changing the Level that you are operating on changes the
output values.

Note: All of these are being matched with auto lacing .

42
FEATURE
LIST @ LEVEL & REPLICATION
List@Level can allow us to pair data in a logical format. This logic can be
manipulated further by appending replication guides to the data. In the
visual example, as previous, we pair the roomsList with the alphaRange
at various location levels to achieve different lacing formats:

autoLacing = roomsList @L1 + alphaRange@L1


shortestLacing = roomsList@L1< 1 > + alphaRange@L1< 1 >;
longestLacing = roomsList@L1< 1 L> + alphaRange@L1< 1 L>;
crossProductLacing = roomsList@L1< 1 > + alphaRange@L1< 2 >;

43
EXPLORE
LIST @ LEVEL
Let’s explore List@Level by using 3x lists of data to pair ( With
various data counts ).

name = "Room";
delimeter = [ "-" , "_", ":" , "" , " " , " " ];
numberList = [ [ 0 .. 2 , 1 .. 3 ], [ 2 .. 3 , 3 .. 5 ] ];

Pair them using any combination of List@Level and


Replication Guides - or try omitting the replication guides
altogether.

Remember you can also use the special ‘L’ for longest lacing
and check the preview bubble ( Or use a Watch node ) to see
the results!

44
Power and Control
[ Using conditions, flow control and looping ]

45
CONCEPT
ASSOCIATIVE VS. IMPERATIVE
Associative programming uses the concept of graph dependencies to establish ‘flow control.’
Associative is the default mode inside of Code Blocks.

Imperative programming is characterized by explicit flow control using ‘For’ and ‘While’ loops
(for iteration) and if/elseif/else statements (for conditional statements). To initialise
Imperative code you use the following syntax:

[ Imperative ] { code };

Imperative code is executed line by line - Associative code executes based on relationships.
In basic terms, you use Imperative for conditional statements, looping and function passing.

Note; These two modes differ from 1.X to 2.X versions. Changes to ‘upstream’ variables are automatically
propagated to ‘downstream’ variables in 1.X but you can no longer utilise the same variable name multiple
times inside a Code Block in 2.X.

46

You might also like